ceph crush算法不一样的理解,和一致性哈希没关系
来源:互联网 发布:卫龙工厂淘宝直播视频 编辑:程序博客网 时间:2024/06/10 08:23
1,ceph怎么做到的每次down掉一个osd或者新增一个osd后,只有少量的数据迁移?而不是所有数据都在osd之间来回迁移?(据说sheepdog是大量迁移,所以这个就别拿来和ceph比性能了,连弹性扩容都做不到。)
2,一块数据A写入pg1(osd1),现在新增osd了,导致pg1迁移到osd2上,那么下次需要读数据A,还能找到数据位置吗?
3,一个oid映射到pgid,是怎么哈希映射的?一个文件名真的可以哈希后得到文件夹的名字?真像网上说的那样,是文件名哈希后,用哈希值value除以文件夹总数取余数(oid%pg_num) ?
让我们走进科学!。
一,怎么把一个文件名映射到文件夹?(也就是object怎么映射到pg)
假如我有1个文件,需要哈希映射到1000个文件夹。 拿ceph来说,就是1个object怎么映射到1000个pg。
网上的说法:
1,hash(object) 得到一个哈希值 value 。
2,用这个value除以10000,取余数。
这样的做法确实也可以让object随机映射到1000个pg中的一个。但是只是知道了1000个pg的第几个pg,还要根据算出的序号,去1000个pg中查询出pgid。这样做效率是不行的。ceph一贯履行不需查找,算算就好的承诺。
ceph的做法:
1,每次创建一个pool的时候让pg的id变得连续。如果16个pg,那pgid就从0~f 。如果1024个pg,那么pdid就从0~3ff。
下图中0.3ff 前面的0 表示 poolid。
0。
2,通过object取得的哈希值value &mask运算,得出pgid的值。
mask为pg数量-1,因为pgid是从0开始的,所以需要-1
这样无论怎么计算pgid始终为0~mask之间。也就是pg总数里的任意一个值。这样object会被均匀的分配到任意一个pg
二,crush算法怎么做到每次有osd新增和删除,只有少量的pg产生迁移,而不是所有的pg在osd之间重新定位?
1,一个pg请求的定位,会选择一个机房,然后在机房里选择一个机架,机架上选择一个服务器,服务器上选择一个osd。完成pgid-->osdid的映射。
2, 以上的机房,机架,服务器,osd。我们都可以认为是一个item。那怎么在10个item中选择一个,是通过哈希值处于10取余数的方式吗?
当然不是,如果这样做。就会导致新增,删除osd,集群里的所有pg都需要迁移。因为新增osd后,哈希的范围变了,ceph集群里所有的pg都需要重新哈希选择位置。
3,ceph提供了多种选择一个item的算法,这些算法统称bucket算法。下面比较多种bucket算法对于osd变动,造成的数据迁移量。
横轴代表osd新增和删除的数量,纵轴代表pg发生的迁移率。可以发现RUSH_P在新增和删除上呈现2个极端,新增osd的时候pg迁移率很小。
而删除osd的时候迁移率很大,我们平常默认使用的straw是比较这种的方案。为图中的黄色线条。也就是说pg的迁移率和bucket算法有关。
4,那bucket算法为什么在新增删除osd的时候呈现少量的迁移率?下面我们把crush straw算法的代码提取出来测试研究。
#include <stdio.h>
#include <time.h>
using namespace std;
typedef unsigned int __u32;
#define crush_hash_seed 1315423911
a = a - b; a = a - c; a = a ^ (c >> 13); \
b = b - c; b = b - a; b = b ^ (a << 8); \
c = c - a; c = c - b; c = c ^ (b >> 13); \
a = a - b; a = a - c; a = a ^ (c >> 12); \
b = b - c; b = b - a; b = b ^ (a << 16); \
c = c - a; c = c - b; c = c ^ (b >> 5); \
a = a - b; a = a - c; a = a ^ (c >> 3); \
b = b - c; b = b - a; b = b ^ (a << 10); \
c = c - a; c = c - b; c = c ^ (b >> 15); \
} while (0)
//crush straw算法,参数1为pgid,参数2为一组item,参数3为副本数
static __u32 crush_hash32_rjenkins1_3(__u32 a, __u32 b, __u32 c)
{
__u32 hash = crush_hash_seed ^ a ^ b ^ c;
__u32 x = 231232;
__u32 y = 1232;
crush_hashmix(a, b, hash);
crush_hashmix(c, x, hash);
crush_hashmix(y, a, hash);
crush_hashmix(b, x, hash);
crush_hashmix(y, c, hash);
return hash;
}
int main() //对straw算法进行测试
{
int testpgid[1000];
srand((unsigned)time(NULL));
for (int i = 0; i < 1000; i++) //选取1000个pg进行测试,pgid取一个随机数
{
testpgid[i] = rand();
}
//int testpgid[10] = {432879,32189,8879,3871,1048390,73167,46104,32169,34791,31280};
for (int n = 0; n < 1000; n++) //对1000个pg进行1000次item选举测试
{
int i;
unsigned int weight = 1;
int item[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; //针对10个item来模拟
int high = 0;
unsigned long long high_draw = 0;
unsigned long long draw;
int result;
for (i = 0; i <10; i++)
{
draw = crush_hash32_rjenkins1_3(testpgid[n], item[i], 3);
draw &= 0xffff;
draw *= weight;
if (i == 0 || draw > high_draw) {
high = i;
high_draw = draw;
}
}
result = high;//result为最终在10个item中选出的item号
int item_del[9] = { 1, 2, 3, 4, 5, 6, 8, 9, 10 }; //模拟删掉一个item 7
int high1 = 0;
unsigned long long high_draw1 = 0;
unsigned long long draw1;
int result1;
for (j = 0; j <9; j++)
{
draw1 = crush_hash32_rjenkins1_3(testpgid[n], item_del[j], 3);
draw1 &= 0xffff;
draw1 *= weight;
if (j == 0 || draw1 > high_draw1) {
high1 = j;
high_draw1 = draw1;
}
}
result1 = high1;//result1为最终在9个item中选出的item号
int item_add[11] = { 1, 2, 3, 4, 5, 6, 7,8, 9, 10,11 }; //模拟新增一个item11
int high2 = 0;
unsigned long long high_draw2 = 0;
unsigned long long draw2;
int result2;
for (k = 0; k <11; k++)
{
draw2 = crush_hash32_rjenkins1_3(testpgid[n], item_add[k], 3);
draw2 &= 0xffff;
draw2 *= weight;
if (k == 0 || draw2 > high_draw2) {
high2 = k;
high_draw2 = draw2;
}
}
result2 = high2;//result2为最终在11个item中选出的item号
cout << testpgid[n] << " " << result << " " << result1 << " "<< result2<< endl;
} //打印的内容为:pgid号,没有osd变动时候选出的item, 删除一个osd后选出的item, 新增一个osd后选出的item
return 0;
}
对1000个pg进行测试,每个pg在10个item里选一个,先后删除一个item,新增一个item测试。测试结果发现,不管是新增还是删除item。
straw算法对某个item的选择一直在坚持,只有少数时候会由于新增和删除item产生变化,大部分时候不管删除还是新增item,都坚持选择原来的item。
下面为测试结果。
可以看到大部分时候,不管新增删除osd,straw算法都是坚持原来的选择,只有少数时候会改变。
所以这就决定了。新增osd的时候,只有一小部分的pg需要重新定位。迁移位置。
5, 我们通过算法的原理来分析下原因。straw算法如下:
static __u32 crush_hash32_rjenkins1_3(__u32 a, __u32 b, __u32 c)
从10个item里选取一个哈希值最大item的作为入选的item。
如果你新增一个item,影响10个item中最大值的那个可能性并不大。
你是班里最高的,班里来了一个新同学,新同学比你高的可能性并不大。绝大部分可能你还是最高的。
删除一个item也是同样的道理。
- ceph crush算法不一样的理解,和一致性哈希没关系
- 一致性hash算法和CEPH CRUSH
- Ceph的基石CRUSH算法与一致性哈希( by quqi99 )
- ceph的CRUSH算法
- 理解Ceph CRUSH数据定位算法
- Ceph剖析:数据分布之CRUSH算法与一致性Hash
- Ceph剖析:数据分布之CRUSH算法与一致性Hash
- Ceph剖析:数据分布之CRUSH算法与一致性Hash
- ceph的CRUSH算法的源码分析
- ceph的CRUSH数据分布算法介绍
- ceph的CRUSH数据分布算法介绍
- ceph的CRUSH数据分布算法介绍
- Ceph-CRUSH算法的具体实现
- ceph存储 ceph的CRUSH算法的源码分析
- ceph存储 ceph中对crush算法的认知
- Ceph Crush 算法源码分析
- ceph crush map 和 crushtool
- CEPH CRUSH
- Android之拍照
- git--Feature分支
- [usaco gold 2016.1]无线电通信
- 大于N的最小回文数
- Java中使用poi导入、导出Excel
- ceph crush算法不一样的理解,和一致性哈希没关系
- How to read a paper?
- RH124-第五节-用户管理
- STL lower_bound()
- 元素出栈、入栈顺序的合法性/计算一个整数二进制位中1的个数。
- 利用Nginx解决跨域问题
- LogisticRegression相关
- linux查看和修改PATH环境变量的方法
- Android传感器指南针(真机实现)