简谈RGW的index shard计算

在RGW里面每个存储到rados的Object都需要先计算出对应元数据存储的shard number,之后再将元数据信息更新到shard number对应的Object里面。代码如下所示

int RGWRados::get_bucket_index_object(const string& bucket_oid_base, const string& obj_key,
    uint32_t num_shards, RGWBucketInfo::BIShardsHashType hash_type, string *bucket_obj, int *shard_id)
{
  int r = 0;
  switch (hash_type) {
    case RGWBucketInfo::MOD:
      if (!num_shards) {
        // By default with no sharding, we use the bucket oid as itself
        (*bucket_obj) = bucket_oid_base;
        if (shard_id) {
          *shard_id = -1;
        }
      } else {                 uint32_t sid = ceph_str_hash_linux(obj_key.c_str(), obj_key.size());
         uint32_t sid2 = sid ^ ((sid & 0xFF) << 24);
        sid = sid2 % MAX_BUCKET_INDEX_SHARDS_PRIME % num_shards;
        char buf[bucket_oid_base.size() + 32];
        snprintf(buf, sizeof(buf), "%s.%d", bucket_oid_base.c_str(), sid);
        (*bucket_obj) = buf;
        if (shard_id) {
          *shard_id = (int)sid;
        }
      }
      break;
    default:
      r = -ENOTSUP;
  }
  return r;
}

有同学提问,为什么不直接写成 sid = sid %num_shards,而是获取到对应sid以后再做一次sid2 = sid ^ ((sid & 0xFF) << 24),下面把这段代码截取出来说明原因。

编辑头文件 hash_shard.h,内容如下

#ifndef hash_shard_h
#define hash_shard_h

#ifndef _UINT32_T
#define _UINT32_T
typedef unsigned int uint32_t;
#endif /* _UINT32_T */

#endif /* hash_shard_h */
unsigned ceph_str_hash_linux(const char *str, unsigned long length)
{
    unsigned long hash = 0;

    while (length--) {
        unsigned char c = *str++;
        hash = (hash + (c << 4) + (c >> 4)) * 11;
    }
    return hash;
}

编辑 main.cpp,内容如下

#include <iostream>
#include "hash_shard.h"

void hash_obj(std::string obj_key){
    uint32_t sid = ceph_str_hash_linux(obj_key.c_str(), obj_key.size());
    uint32_t sid1 = sid ^ ((sid & 0xFF) << 24);
    uint32_t sid2 = sid1 % 7877 % 8;
    uint32_t sid3 = sid % 7877 % 8;
    std::cout << "hash2=" << sid2 <<std::endl;
    std::cout << "hash1="<< sid3 <<std::endl;
}

int main(int argc, const char * argv[]) {
    std::string obj_key1 = "aa2";
    hash_obj(obj_key1);
    std::string obj_key2 = "aa1";
    hash_obj(obj_key2);
    std::string obj_key3 = "aa0";
    hash_obj(obj_key3);
    std::string obj_key4 = "aa3";
    hash_obj(obj_key4);
    std::string obj_key5 = "aa3";
    hash_obj(obj_key5);
    return 0;
}
root@demohost:/home/demouser/hash_shard# g++ main.cpp -o hash_shard
root@demohost:/home/demouser/hash_shard# ./hash_shard
hash2=7hash1=1hash2=7hash1=1hash2=7hash1=1hash2=4hash1=1hash2=4hash1=1

从裁剪出来的代码运行结果来看,直接sid = sid %num_shards会导致hash计算出来的结果不够离散,最终导致数据都集中写到一个shard文件上造成写入上的单点热数据(hash1计算出来的结果都是1)。

另外MAX_BUCKET_INDEX_SHARDS_PRIME为什么是7877,可以是其他数吗?答案是可以的,但是这个最好是质数,从而保障取余得到的结果足够随机。

原文发布于微信公众号 - Ceph对象存储方案(cephbook)

原文发表时间:2017-10-13

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Aloys的开发之路

一个比较全面的java随机数据生成工具包

        最近,由于一个项目的原因需要使用一些随机数据做测试,于是写了一个随机数据生成工具,ExtraRanom。可以看成是Java官方Random类的扩...

31690
来自专栏吉浦迅科技

TensorFlow版本号升至1.0,正式版即将到来

2015年11月份,谷歌宣布开源了深度学习框架TensorFlow,一年之后,TensorFlow就已经成长为了GitHub上最受欢迎的深度学习框架,尽管那时候...

39290
来自专栏每日一篇技术文章

OpenGL ES _ 高级03_调试工具

11010
来自专栏一个会写诗的程序员的博客

《一切皆是映射》 一致性哈希算法(consistent hashing)

按照常用的hash算法来将对应的key哈希到一个具有232次方个桶的空间中,即0~(232)-1的数字空间中。现在我们可以将这些数字头尾相连,想象成一个闭合的环...

14140
来自专栏DOTNET

ASP.NET MVC编程——模型

1 ViewModel 是一种专门提供给View使用的模型,使用ViewModel的理由是实体或领域模型所包含的属性比View使用的多或少,这种情况下实体或领域...

34180
来自专栏软件测试经验与教训

Python学习笔记(文件)

36490
来自专栏大数据挖掘DT机器学习

文本分类中语料库的获取——搜狗语料库

这次主要总结搜过语料库的获取,因为老师要求20万数据,而我自己只爬了2万多,所以用到了搜狗的语料库. ? 在这个页面中,我选择的是一个月的数据,别小看一个月...

71280
来自专栏机器学习从入门到成神

Pandas使用DataFrame进行数据分析比赛进阶之路(二):日期数据处理:按日期筛选、显示及统计数据

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_35512245/articl...

1.2K10
来自专栏程序员的诗和远方

30分钟QUnit入门教程

30分钟让你了解Javascript单元测试框架QUnit,并能在程序中使用。 QUnit是什么 QUnit是一个强大,易用的JavaScript单元测试框架,...

59590
来自专栏北京马哥教育

Python入门之生成海贼王云图

本教程适合于有一定编程经验的同学,使用Python3,在Jupyter进行调试开发。 涉及的Python基础包括: 变量和函数的定义和使用 列表和字典等数据结构...

367100

扫码关注云+社区

领取腾讯云代金券