设为首页 收藏本站
查看: 964|回复: 0

[经验分享] 别让bug跑了,通过问题理解ceph的克隆过程

[复制链接]

尚未签到

发表于 2019-2-1 13:49:50 | 显示全部楼层 |阅读模式
写在前面

     刚刚过去的9月,人工智能、云计算和物联网界热闹非凡,接连迎来了世界物联网博览会、世界人工智能大会和阿里云栖大会。2018世界物联网博览会就在家门口举行,抓了空去现场看展览,外行人看看热闹,有感于科技的日新月异给生活带来的便利。

     话题扯远了,回到这篇文章,文章的标题包含“复盘”,顾名思义,是对以前的发生的现象或问题进行回顾,学而不思则罔,目的第一是从问题中总结经验,最大化发掘它的价值;第二是不断锻炼自己分析问题的能力;最后是希望强化在某项知识上的运用能力,毕竟以今天分析昨天,有思维就ok了,但是以今天设想未来,需要长期深厚的积累才行。

1 背景

    云硬盘的快照、克隆,属于块存储RBD基本功能,之前我并没有太多关注这两块,保证功能能用、好用就过去了。

    不过在最近遇到几个与克隆或快照相关联的问题,涉及到rbd clone、rbd flatten等,正好是之前未遇到过,因此找了时间对产生的问题复盘,也是希望借bug观察ceph对克隆和快照的处理流程。

    整篇文章分以下几小章节:

    1 、背景

    2 、bug回顾

    3、 利用rbd_max_clone_depth触发flatten

    4 、cinder和ceph层面对clone、flatten的实现

2 bug回顾

  2.1  bug1 通过快照创建云硬盘,删除父快照失败

      这个问题复现步骤很简单,如下流程图所示:



     遇到的问题就是在删除快照时发生失败,禁止该删除操作。

     由快照创建出的云硬盘,一般情况与快照是父子关系,在ceph下通过rbd info或rbd children可以查询到链的关系。 如下图红色框中所示,在parent一项中,可以看到volume-8e81a7b0-4fdc-49b0-a9ed-4124c8e61f7d是volume-117078c1-c724-44b5-a271-e0f708e9d6b3下的快照克隆得来:



                                                                                                                                              图1

     既然克隆盘与快照存在父子关系,要删除父快照的首要条件是斩断这种依赖关系,这个就需要通过rbd_flatten_volume_from_snapshot配置项来实现,见/etc/cinder/cinder.conf配置文件,如下图中:



     在我们的存储下,rbd_flatten_volume_from_snapshot=false,在false条件下volume和snapshot之间的关系是什么?

     在解决问题之前,先来了解下rbd_flatten_volume_from_snapshot在true、false下的不同作用,见下表:



     一目了然,在false条件下,volume和snapshot存在依赖,要想解决该bug,只要开启为true即可。

      不过先别急着改/etc/cinder/cinder.conf,在此之前我们通过flatten手动解除依赖关系,再重复bug的步骤看是否能够成功,这个小实验分5个步骤复现,如下图3中:

     




  
       (1)创建volume和快照   PASS

       (2)执行克隆    PASS

       (3)删除父快照   FAILED

                错误提示需要对快照先去除保护,unprotect后再执行删除快照,错误提示:cannot unprotect: at least 2 child(ren) [1a5e266b8b4567,1aa62d6b8b4567] in pool

       (4)执行flatten操作,解除依赖   PASS

       (5)再次删除父快照     PASS

     小实验OK,证明了解除克隆盘与snapshot的依赖后再删除快照成功。如果在控制节点的cinder配置文件中,开启了rbd_flatten_volume_from_snapshot = true,则 由快照创建出的云硬盘,会自动合并,清除依赖关系,这样一来这个云硬盘就变为扁平的没有层级的volume。最后记得重启cinder服务,使其生效!

  2.2  bug2 大容量的空盘创建快照,再通过该快照创建云硬盘,耗时过长

     这个bug提的比较优秀,功能本身属于正常流程,但之前遗漏了大容量云硬盘这个场景,比如1T、2T。

     问题复现步骤同bug1,只是少了删除快照的步骤,如下流程图所示:

   




     通常,我们在云平台上对云硬盘创建快照后,会同时创建快照卷,由于精简配置的属性,只需分配相对少量的存储空间即可,当再通过该快照clone出云硬盘,快照处于只读保护, 在cow的机制下,克隆操作会很迅速。下面引用一张ceph官方的图来解释:



   上图4中,parent是指源云硬盘的快照,而child是从快照克隆出来的云硬盘。

   这个bug 2与“2.1 bug 1”对比,相同点都是由rbd_flatten_volume_from_snapshot造成的bug,不同的地方在于true和false。

   在bug 2 的云环境下,rbd_flatten_volume_from_snapshot=true,在上文的bug1中曾说过解除volume和snapshot的依赖关系,取消这种依赖关系叫做flatten,这个flatten花费的时间和源云硬盘(volume)的大小成正比。

   回到bug本身,内部在做排查时,依照以下的顺序:

     (1)检查volume qos

        眼光先放在了volume qos上,在有数据条件下,qos速率大小(比如write=100MB/S)肯定是会影响到快照创建云硬盘的速度的。转念一想,云硬盘是空盘,并不存在任何object,因此克隆速度应该是很快的。

     (2)检查父云硬盘、快照、子云硬盘的实际容量

        我们环境中云硬盘是空盘,不存在任何数据,同样的由快照创建出的新盘也不会有任何数据。实际是否如此,通过下面的验证步骤来证实一下:


  • 创建云硬盘和快照,并获取真实存储空间



                                                                                           图5

       图5中,新建1G的volume,并创建该盘的快照后,rados查询实际存在的object,找不到任何数据,这是正确的。


  • 由快照创建云硬盘,并获取真实存储空间


                                                                                                                 图6

    图6中,快照创建出新的云硬盘,叫volume-d7199f3d-ed96-446a-83c8-25083a752e23,可以看到在云硬盘创建过程中,新的云硬盘和快照时父子关系,创建成功后,新的云硬盘和快照时父子关系被解除。


   图7所示是获取新的云硬盘的实际数据对象,发现已经存在256个object(父云硬盘总容量为1GB,根据order 22 (4096 kB objects)来切分)


     图8中,随机抽查几个object,发现其实这些object的容量都是0,并不存在真实的数据。一般而言,从快照创建云硬盘,代码实现很简单,先克隆再flatten,Fill clone with parent data (make it independent),此时flatten会将所有块从父节点复制到child,但父云硬盘中没有数据,flatten操作是不应该产生object的。

     这个bug问题就在于flatten会对新建云盘的每一个对象进行一个写操作,从而创建无数个大小为0的对象,又在qos的限制下,所以耗时较长。

3 利用rbd_max_clone_depth触发flatten

      麦子迈在《解析Ceph: Librbd 的克隆问题》一文中提到 “Librbd 在卷的克隆时会形成子卷对父卷的依赖,在产生较长的克隆依赖链后会有严重的性能损耗”。这个理论其实和cow下多快照产生的性能衰减是一样的,对ceph的云硬盘做快照,每次做完快照后再对云硬盘进行写入时就会触发COW操作, 即1次读操作、2次写操作,volume→volume的克隆本质上就是将 volume 的某一个 Snapshot 的状态复制变成另一个volume。

      为解决在产生较长的克隆依赖链后会有严重的性能损耗问题,在OpenStack Cinder 的/etc/cinder/cinder.conf中提供一个参数,可以解除父子依赖关系,在超过自定义设置的阀值后选择强制 flatten。



    在图9中,通过 rbd_max_clone_depth来控制最大可克隆的层级。

    rbd_max_clone_depth = 5 这个参数控制卷克隆的最大层数,超过的话则使用 fallten。设为 0 的话,则禁止克隆。

    为了验证这个过程,下面我们做个实验,创建1个volume,命名为01,依次复制下,即由01复制成02,02复制为03,03复制为04,04复制为05,05复制为06,06复制为07,如下图流程图:



   实验预期结果,就是当从06复制到07时,满足rbd_max_clone_depth > 5,此时触发flatten操作。


图10


图11

   图10、图11是 复制云硬盘后的查询到克隆盘信息


图12

   图12中, 上面的log记录了复制07时,触发了flatten操作,对上级云硬盘06执行flatten操作,开始执行合并。


图13

   图13所示是Flatten成功后,可以看到云硬盘06 的parent一项消失,此时在页面上可以删除云硬盘06

4 cinder和ceph层面对clone、flatten的实现

     现在市面上很多讲ceph的书(大多数翻译自ceph中国社区之手),在RBD块存储章节都会对快照、克隆等操作花很多篇幅去描述,基本都是在rbd层通过命令一步步分解rbd clone过程来讲原理。

     对于类似我这样的刚接触ceph不久的人来说,知识点分散在各处,看了前面忘了后面,很难在脑子里建立完整的概念,当然主要原因还是自己太菜了,迷雾重重看不透!



    言归正传,我只是想大概的了解下对云硬盘执行操作在底层是如何实现的,因此还是由上文中提到的小处(bug)来入手,自顶向下先设计一个思考流程,带着目标按照这个从上到下的顺序去理解,如下图所示:



  注:以下涉及的代码均来自GitHub开源,如有雷同,纯属巧合!
4.1  从快照克隆卷的流程

     (1)openstack cinder

         自顶向下,先从cinder层入手,通过代码可以看到从快照克隆出volume的思路,从本质上讲,快照克隆出新的卷,也是volume create的性质,所以先来了解下volume create过程

         cinder:/cinder/volumes.py


     volumes.py中def create方法我省略了很多,主要就是通过req、body的参数来获取创建volume所需要的参数,根据不同参数来发送具体的创建volume请求,因为我是从快照来创建,snapshot id自然必不可少,在 volumes.py最后实际调用new_volume = self.volume_api.create()去实现。

cinder:/cinder/volume/api.py

     经过volume_api.create(),在/cinder/volume/api.py来处理前端发来的卷相关的所有请求,通过create_what{}表示volume的实现参数,然后分别就调用cinder.scheduler的scheduler_rpcapi,cinder.volume的volume_rpcapi建立创建volume的工作流:create_volume.get_flow


    注:关于create volume flow的流程及具体实现,见/cinder/volume/rpcapi.py:def create_volume(),/cinder/volume/flows/api/create_volume.py,本篇省略过程

cinder:/cinder/volume/manager.py

    对于api来讲,只是做到处理前端发来的卷相关的所有请求,具体实现交由manager下的去完成,rpcapi调用inder/volume/manager.py:def create_volume()去操作


     执行中发现crate voluem 有snapshot id,然后调用/cinder/volume/flows/manager/create_volume.py下的私有方法_create_volume_from_snapshot()


   最后根据配置文件指定的RBD后端请求/cinder/volume/drivers/rbd.py的create_volume_from_snapshot()

cinder:/cinder/volume/drivers/rbd.py

     众所周知,一般cinder使用RBD驱动来对接底层的后端存储(比如ceph、xsky),在openstack cinder层面最终交由create_volume_from_snapshot()实现,因为是通过快照来创建volume,还需要调用私有方法_clone(),满足条件的话,还要调用_flatten()和_resize()。


(2)librbd

     经历多方接力才结束在cinder层面的流程,这还不算完,真正要实现create volume from snapshot的创建,核心在调用ceph执行。

    ceph:/src/pybind/rbd/rbd.pyx


/ceph/blob/v10.2.3/src/librbd/librbd.cc


    在librbd中对外提供api在class RBD中,从librbd.cc函数中看到有多个clone()、clone2()、clone3()函数,区别在于根据传入的不同参数来调用对应的函数,但这些函数都不像是具体的功能实现,只是一些相关参数传值。

    再看看/ceph/blob/v10.2.3/src/librbd/internal.cc函数,同librbd.cc一样,对应的clone()也是3种,因为篇幅如下展示的是clone3()函数(实际命名并不如此,通过参数来区分得知是clone2):


    将librbd.cc、internal.cc两个函数联系起来看,librbd.cc只是定义了对外的各种函数接口,接口的具体实现,调用的还是internal.cc中定义的函数内容。

    总结一下,根据自己的理解将整个流程绘成图,如下图所示中,需要一提的是,我没有涉及到librados的实现过程,因为clone等volume的操作,librbd可以说就是rbd的完整实现,rados只是作为后端的存储


4.2  flatten的流程

     在前文“ 利用rbd_max_clone_depth触发flatten”小节中,我们描述了一个volume clone的过程,通过cinder.conf的一个参数,当满足rbd_max_clone_depth最大层数后,触发flatten操作,下面我们通过代码去看一看具体实现的流程。

     (1)openstack cinder

     对于上层云平台而言,从云硬盘1克隆出云硬盘2,或者从快照创建云硬盘,一般是能够触发flatten操作的主要场景,其实两者实现原理基本一致。

     因此,和之前的由snapshot来实现创建新的云硬盘一样,首要都是从create()开始,只是参数不同,克隆盘在create过程先要获取parent volume id


    之后也是一样经历api→manager→driver的过程,这里省掉重复的过程,直接看cinder调用rbd驱动对克隆云硬盘的实现代码,如下图中/cinder/volume/drivers/rbd.py:


     调用了私有方法_get_clone_depth()来判断depth,调用_flatten()来实现flatten操作,当然flatten过程经历一系列过程,在parent volume上创建snapshot,对snapshot加保护、再执行clone,然后flatten,这个过程一样可以通过rbd 命令来完成。

(2)librbd

      创建RADOSClient,连接到ceph rados,这里也是先调用clone()去执行,再触发flatten()操作,和我预期不同,flatten的过程比想象中还要复杂,才疏学浅,对整个过程的了解还需要更多的时间,只能先用根据自己的理解画出一张流程图表示一下:






运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-670510-1-1.html 上篇帖子: Ceph添加新节点 下篇帖子: 【Ceph】手动搭建ceph集群
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表