转载请注明出处 陈小跑 http://www.cnblogs.com/chenxianpao/p/5878159.htmlhtml
本文只梳理了大体流程,细节部分还没搞的太懂,有时间再看,再补充,有错误请指正,谢谢。服务器
Ceph 的主要一大特色是强一致性,这里主要指端到端的一致性。众所周知,传统存储路径上从应用层到内核的文件系统、通用块层、SCSI层到最后的HBA和磁盘控制器,每层都有发生错误的可能性,所以传统的端到端解决方案会以数据块校验为主来解决。而在 Ceph 方面,更是加入了 Ceph 本身的客户端和网络、存储逻辑、数据迁移,势必致使更高的错误几率。网络
由于 Ceph 做为一个应用层的路径,它利用了 POSIX 接口进行存储并支持 Parity Read/Write,这时候若是封装固定数据块而且加入校验数据会致使较严重的性能问题,所以 Ceph 在这方面只是引入 Scrub 机制(Read Verify)来保证数据的正确性。并发
简单来讲,Ceph 的 OSD 会定时启动 Scrub 线程来扫描部分对象,经过与其余副本进行对比来发现是否一致,若是存在不一致的状况,Ceph 会抛出这个异常交给用户去解决。app
2、Scrub 函数流程:从PG::chunky_scrub开始进行scrub的状态机
NEW_CHUNK状态_request_scrub_map函数发送new MOSDRepScrub消息给replicas,replicas处理流程:
Primary接收到MOSDSubOp消息后的处理流程:
将收到的replicas的scrubmap写入到scrubber.received_maps中;
对于全部replicas都返回scrubmap,则调用PG::requeue_scrub()函数从新进入scrub操做
3、Scrub 状态机
① INACTIVE
开始进行scrub;更新osd的状态;设置scrubber的状态信息,好比start、state、epoch_start等,将state设置成NEW_CHUNK
② NEW_CHUNK
初始化scrubber.primary_scrubmap、received_maps;根据osd_scrub_chunk_min和osd_scrub_chunk_max获取指定数量个object(具体如何获取,从何获取?);向全部的actingbackfill副本发送new MOSDRepScrub()消息,获取scrub_map信息,将状态设置成WAIT_PUSHES
③ WAIT_PUSHES
等待PUSH(push什么?)完成,若是active_pushes为0则把状态设置成WAIT_LAST_UPDATE
④ WAIT_LAST_UPDATE
等待update(update什么?)完成,若是last_update_applied大于scrubber.subset_last_update把状态设置成BUILD_MAP
⑤ BUILD_MAP
创建一个scrub_map,读取对象的大小和属性信息,若是是deep模式,根据EC和replicate两种pool计算不一样的CRC32校验码,repicate类型以omap_header计算CRC值,EC类型的CRC值为object的hash值;scrubmap包括 object size, attr 和omap attr, 历史版本信息;把状态设置成WAIT_REPLICAS
⑥ WAIT_REPLICAS
等待收到replicas返回的信息,把状态设置成COMPARE_MAPS
⑦ COMPARE_MAPS
根据scrubber.primary_scrubmap建立权威authmap;创建包含全部object的master set;遍历master set,选择一个没发生异常的权威的osd做为比较对象,比较文件大小、属性信息以及digest信息(digest and omap_digest);记录错误对象和丢失对象,后续recovery恢复;将状态设置成WAIT_DIGEST_UPDATES。
⑧ WAIT_DIGEST_UPDATES
ReplicatedPG::_scrub()函数完成(作了什么);若是还有obj未校验完,则继续回到NEW_CHUNK流程,重复以上动做;若是所有校验完则进去FINISH状态
⑨ FINISH
Scrub结束
注:
1. OSD 会以 PG 为粒度触发 Scrub 流程,触发的频率能够经过选项指定,而一个 PG 的 Scrub 启动都是由该 PG 的 Master 角色所在 OSD 启动
2. 一个 PG 在普通的环境下会包含几千个到数十万个不等的对象,由于 Scrub 流程须要提取对象的校验信息而后跟其余副本的校验信息对比,这期间被校验对象的数据是不能被修改的。所以一个 PG 的 Scrub 流程每次会启动小部分的对象校验,Ceph 会以每一个对象名的哈希值的部分做为提取因子,每次启动对象校验会找到符合本次哈希值的对象,而后进行比较。这也是 Ceph 称其为 Chunky Scrub 的缘由。
3. 在找到待校验对象集后,发起者须要发出请求来锁定其余副本的这部分对象集。由于每一个对象的 master 和 replicate 节点在实际写入到底层存储引擎的时间会出现必定的差别。这时候,待校验对象集的发起者会附带一个版本发送给其余副本,直到这些副本节点与主节点同步到相同版本。
4. 在肯定待校验对象集在不一样节点都处于相同版本后,发起者会要求全部节点都开始计算这个对象集的校验信息并反馈给发起者。
5. 该校验信息包括每一个对象的元信息如大小、扩展属性的全部键和历史版本信息等等,在 Ceph 中被称为 ScrubMap。
6. 发起者会比较多个 ScrubMap并发现不一致的对象,不一致对象会被收集最后发送给 Monitor,最后用户能够经过 Monitor 了解 Scrub 的结果信息
用户在发现出现不一致的对象后,能够经过 “ceph pg repair [pg_id]” 的方式来启动修复进程,目前的修复仅仅会将主节点的对象全量复制到副本节点,所以目前要求用户手工确认主节点的对象是”正确副本”。另外,Ceph 容许 Deep Scrub 模式来全量比较对象信息来指望发现 Ceph 自己或者文件系统问题,这一般会带来较大的 IO 负担,所以在实际生产环境中很难达到预期效果。
4、Scrub 测试
Scrubbing 是 Ceph 保持数据完整性的一个机制,相似于文件系统中的 fsck,它会发现存在的数据不一致。scrubbing 会影响集群性能。它分为两类:
· 一类是默认天天进行的,称为 light scrubbing,其周期由配置项 osd scrub min interval (默认24小时)和 osd scrub max interval (默认7天)决定。它经过检查对象的大小和属性来发现数据轻度不一致性问题。
· 另外一种是默认每周进行的,称为 deep scrubbing,其周期由配置项 osd deep scrub interval (默认一周)决定。它经过读取数据并作 checksum 检查数据来发现数据深度不一致性问题。
下面是默认的 osd scrub 的配置项:
root@ceph2:~# ceph --admin-daemon /var/run/ceph/ceph-osd.5.asok config show | grep scrub"osd_scrub_thread_timeout": "60","osd_scrub_thread_suicide_timeout": "60","osd_scrub_finalize_thread_timeout": "600","osd_scrub_finalize_thread_suicide_timeout": "6000","osd_scrub_invalid_stats": "true","osd_max_scrubs": "1","osd_scrub_load_threshold": "0.5","osd_scrub_min_interval": "86400","osd_scrub_max_interval": "604800","osd_scrub_chunk_min": "5","osd_scrub_chunk_max": "25","osd_scrub_sleep": "0","osd_deep_scrub_interval": "604800","osd_deep_scrub_stride": "524288",
实验过程:
0:找到对象的 PG acting set
osdmap e334 pool 'pool1' (9) object 'Evernote_5.8.6.7519.exe' -> pg 9.6094a41e (9.1e) -> up ([5,3,0], p5) acting ([5,3,0], p5)
1:删除对象的文件
根据 pg id,osd id 以及 object name,找到 osd.5 上文件路径为 /var/lib/ceph/osd/ceph-5/current/9.1e_head/Evernote\u5.8.6.7519.exe__head_6094A41E__9,将它删除
2:设置 light scrub 周期
为了避免等一天,将osd_scrub_min_interval 和 osd_scrub_max_interval 都设为4分钟:
root@ceph2:/var/run/ceph# ceph --admin-daemon ceph-osd.5.asok config set osd_scrub_max_interval 240
{ "success": "osd_scrub_max_interval = '240' "}
root@ceph2:/var/run/ceph# ceph --admin-daemon ceph-osd.5.asok config get osd_scrub_max_interval
{ "osd_scrub_max_interval": "240"}
root@ceph2:/var/run/ceph# ceph --admin-daemon ceph-osd.5.asok config set osd_scrub_min_interval 240
{ "success": "osd_scrub_min_interval = '240' "}
root@ceph2:/var/run/ceph# ceph --admin-daemon ceph-osd.5.asok config get osd_scrub_min_interval
{ "osd_scrub_min_interval": "240"}
3:尝试 light scrub,发现问题
能看到 light scrub 按计划进行了,并且发现了 pg 9.1e 的问题,即有文件丢失了:
2016-06-06 18:15:49.798236 osd.5 [INF] 9.1d scrub ok
2016-06-06 18:15:50.799835 osd.5 [ERR] 9.1e shard 5 missing 6094a41e/Evernote_5.8.6.7519.exe/head//92016-06-06 18:15:50.799863 osd.5 [ERR] 9.1e scrub 1 missing, 0 inconsistent objects2016-06-06 18:15:50.799866 osd.5 [ERR] 9.1e scrub 1 errors2016-06-06 18:15:52.804444 osd.5 [INF] 9.20 scrub ok
pgmap 呈现 inconsistent 状态:
2016-06-06 18:15:58.439927 mon.0 [INF] pgmap v5752: 64 pgs: 63 active+clean, 1 active+clean+inconsistent; 97071 kB data, 2268 MB used, 18167 MB / 20435 MB avail
此时集群状态是 ERROR 状态:
health HEALTH_ERR 1 pgs inconsistent; 1 scrub errors;
除了定时的清理外,管理员也能够经过命令启动清理过程:
root@ceph1:~# ceph pg scrub 9.1einstructing pg 9.1e on osd.5 to scrub
从输出能看出来,scrubbing 是由 PG 的主 OSD 发起的。
4:尝试 deep scrub,结果相同。
手工运行命令 ceph pg deep-scrub 9.1e,它会启动深度清理,结果相同。
5:尝试 pg repair,成功
运行 ceph pg repair 9.1e,启动 PG 修复过程,结果修复成功(1 errors, 1 fixed),被删除的文件回来了,集群从新回到 OK 状态。
结论:
· PG scrubbing 能发现文件丢失的问题
· PG scrubbing 对集群性能有负面影响,能够适当下降其优先级以及所须要的资源。
注意:PG repair 目前还有很多问题,根据这篇文章,它会将 primary osd 上的数据复制到其它osd上,这可能会致使正确的数据被错误的数据覆盖,所以使用须要谨慎。下面的实验将验证这个问题。
0:建立一个对象,其内容是一个含有字符串 1111 的文本文件,其PG分布在 [2,0,3] 上。
1:修改 osd.2 上文件内容为 1122
2:启动 light scrub,9.2e scrub ok,没法发现问题。这不是蛮奇怪的么??light scrub 应该会检查文件属性和大小,属性应该包括修改时间吧,应该能检查出来啊。。
3. 启动 deep scrub,9.2e deep-scrub ok,没法发现问题。这不是蛮奇怪的么??deep scrub 应该会检查对象数据的啊,数据变了,应该能检查出来啊。。。
4. 启动 pg repair,内容不变。对不在 inconsistent 状态的 PG 看来作repair 不会作什么。
5. 继续修改 osd.2 上的文件,增长内容,致其 size 改变。
6. 启动 light scrub,终于发现 shard 2: soid b2e6cb6e/text/head//9 size 931 != known size 5, 1 inconsistent objects,集群状态也变为 HEALTH_ERR。
7. 启动 deep scrub,它也一样地终于发现了问题。
8. 运行 rados get 命令,能正确获取原始文件。这说明即便集群处于HEALTH_ERR 状态,处于 active+clean+inconsistent 状态的 PG 的 IO 能正常进行。
9. 启动 pg repari,osd.2 上的文件被覆盖,回到原始内容。这说明 pg repair 也不是从主osd 向别的 osd 拷贝嘛。。
结论:
· 两种 scrubbing 只是根据不一样的方法来发现数据一致性上的不一样类型的问题,修复的事情它无论;不是全部的问题它们都能发现;通过验证,size 的变化会被发现,可是在size不变内容改变的时候不能被发现。
· pg repair 也不是像 Re: [ceph-users] Scrub Error / How does ceph pg repair work? 所说的简单地将 primary osd 上的数据拷贝到其它 osd 上,这种作法很明显这可能会致使正确的数据被损坏。文章是写于 2015 年,个人ceph 版本是 0.8.11,也许二者有不一致。
5、Scrub 问题
正如流程所述,目前的 Scrub 有如下问题:
1. 在发现不一致对象后,缺乏策略来自动矫正错误,好比若是多数副本达成一致,那么少数副本对象会被同化
2. Scrub 机制并不能及时解决存储系统端到端正确的问题,颇有可能上层应用早已经读到错误数据
对于第一个问题,目前 Ceph 已经有 Blueprint 来增强 Scrub 的修复能力,用户启动 Repair 时会启动多数副本一致的策略来替代目前的主副本同步策略。
对于第二个问题,传统端到端解决方案会更多采用固定数据块附加校验数据的“端到端校验”方案,可是 Ceph 由于并非存储设备空间实际的管理和分配者,它依赖于文件系统来实现存储空间的管理,若是采用对象校验的方式会严重损耗性能。所以在从文件系统到设备的校验须要依赖于文件系统,而 Ceph 包括客户端和服务器端的对象正确性校验只能更多的依赖于 Read Verify 机制,在涉及数据迁移时须要同步的比较不一样副本对象的信息来保证正确性。目前的异步方式会容许期间发生错误数据返回的可能性。
参考文档:
本文的测试参考于刘世民(Sammy Liu) http://www.cnblogs.com/sammyliu/p/5568989.html ,后续有空再结合代码作个测试