擦除编码
擦除码类型的pool是以K+M块的方式来存储每个对象的,每个对象都可以被分成K+M个块。它将对象分成K个数据块和M和编码块。pool被配置为拥有K+M的尺寸,所以每个块存储在acting set的一个osd里。块的顺序存储为对象的属性。
例如,创建一个擦出码类型的pool,使用了5个osd,(K+M=5),并且有两个osd丢失的情况下可继续维持集群运行。(M=2) 读写编码块
当对象NYAN包含内容ABCDEFGHI写入到pool,擦除编码功能简单的分解内容为三个数据块:第一个块的内容为ABC,第二个块的内容为DEF,第三个块的内容为GHI。如果内容长度不够K的倍数的花,会给内容加填补。编码功能也会创建两个编码块:第四个块的内容为YXY,以及第五个块的内容为QGC。每个块存储在acting set的一个不同的osd里。对象分解成的每个块在不同的osd里的名字都是NYAN。除了块的名字以外,每个块的顺序也必须保存。块的顺序存储为对象的属性(shard_t)。如下图所示,块1包含内容为ABC存储在osd5里面,块4包含内容为YXY存储在osd3里面。 当从擦除编码类型的pool中读取对象NYAN的时候,解码功能读取三个块:块1包含ABC,块3包含GHI,块4包含YXY。然后,解码功能重新建立对象的原始内容ABCDEFGHI。解码功能被告知块2和块5缺失(这里叫做‘擦除’)。块5不能读取是因为osd4处于集群外面。解码功能在有三个块能够读取的情况下就可以被调用:osd2目前过于缓慢所以它的块目前不属于考虑范围。 写入故障
在一个擦除编码类型的pool里面,up set里面的primary osd接受全部的写操作。primaryosd负责编码接受到的写请求为K+M块并且发送它们到其他osd。primary osd还负责维护pg组日志的权威版本。
在下图中,擦除编码pg组以K=2+M=1方式创建,它支持三个osd,其中两个存放K数据块,一个存放M编码块。pg组的acting set由osd1,osd2和osd3组成。一个对象被编码和存储:块D1v1(数据块版本1)存储在osd1上,D2v1存放在osd2上,C1v1(编码块1版本1)存放在osd3上。每个osd的pg组日志完全相同(例如,log1,1表示epoch1,版本1) osd1是primary osd,它从client接受全部的写请求,这意味着osd1上要完整的分解对象而不是只接受对象的一部分。对象的第二版本(v2)被建立并且覆盖了第一版本。osd1编码对象的第二版本为三个块:D1v2(数据块1版本2)存储在osd1上,D2v2存储在osd2上,C1v2(编码块1版本2)存储在osd3上。每个块都被发目的osd,包括primary osd,primary osd除了处理写操作和维护pg组日志的权威版本之外,还要负责存储块。当一个osd收到信息命令它写入块时,它也会在pg组日志里面创建新项反应改变。例如,osd3存储C1v2时,它添加日志项1,2(epoch 1,版本2)到它自己的日志。因为osd是异步刷新方式工作的,某些块正在传输过程中(类似D2v2),其他块已经写入磁盘了(类似C1v1和D1v1)。 如果一切顺利的话,块会到达actingset里的每一个osd,并且每个osd的pg组日志的last_complete指针从1,1移动到1,2。 最后,用于存储对象的之前版本的块的文件会被删除:osd1上是D1v1,osd2上是D2v1,osd3上是C1v1。 但是发生了事故。如果osd1故障,D2v2仍在传输过程中,这时对象的版本2只有一部分被写入磁盘:只有osd3的一个块,但这并不足够进行恢复。丢失的两个块分别是:D1v2和D2v2,擦除编码参数K=2,M=1要求至少两个块可用才能重建第三个块。osd4成为新的primary osd并且查看pg组日志的last_complete日志项(例如,在之前的acting set里所有的osd上的所有在这个日志项之前的对象是已知可用的),last_complete日志项是1,1,这将会成为新的权威日志开头。 在osd3上可以找到的日志项1,2不同于osd4提供的新的权威日志:它是不在使用的并且包含块C1v2的文件也已经被删除。由擦除编码库的解码功能在清洗期间重新建立D1v1块并且存储在新的primary osd4上。 |