rbd-mirror 技术内幕 (这篇文章在微信号发过,搬过来)

众所周知,ceph在Jewel版本发布的时候,release了一个块存储的重要特性,那就是rbd mirroring。rbd mirroring 是一种两个集群之间,异步镜像的机制。通过一个rbd-mirror的服务,依赖于image的journaling特性,来实现集群间的crash-consistent的image复制。

(1)      rbd-mirror 介绍

如上图所示,每个cluster都有一个RBD MIRROR 模块,这个模块可以将远端的cluster里面image的变动同步到本地。其中 RBD MIRROR模块是一个新的服务,叫做rbd-mirror服务。

(2)      rbd mirroring 配置管理

rbd mirroring的配置是通过rbd mirror的子命令来完成的,如下所示。

现在可以看到localcluster的rbd pool 已经启动了mirror 模式。Info 结果里面有两个信息比较重要。

a)             Mode:pool。

在rbd mirror里面,现在支持两种模式的mirroring,一个是image模式,这种模式下,用户需要手动指定需要mirror的image。第二个是pool模式,这种模式会对pool里面的所有image自动启动mirror。以后rbd引入了namespace之后,可能还会出现新的mirror 模式,只做一个namespace的mirror。

b)             Peers: 0ba36216-787c-4085-9272-bf1e50516129

这个UUID是remote的cluster作为local cluster的peer的UUID,它记录了远端的信息。比如上图,当我们启动rbd-mirror 服务的时候,rbd-mirror进程就会去找remote.conf,并将其作为remote的configuration文件,而且以client.admin的用户去获取信息并进行同步。

为了更彻底的了解这个过程,我们必须dive到code里面看得更清楚。

由上图可知,当我们做mirror pool enable的时候,实际上我们进行了大概六个步骤的操作。

l  USER:执行命令“rbd mirror pool enable POOL pool”

我们在命令行执行shell命令,调用rbd 可执行文件。这个过程和其他所有linux命令执行过程没有区别。

l  rbd command:调用api: rbd.mirror_mode_set();

当rbd 可执行文件开始执行,解析参数之后,会走到代码文件src/tools/rbd/action/MirrorPool.cc ,这个文件会处理所有的rbd mirrorpool 子命令。然后会解析到下一个参数:enable。于是会执行到函数:execute_enable_disable();这个函数会处理enable和disable操作。在这个函数中我们会调用librbd的api:

至此,整个流程的处理从rbd command转交到了librbd。

l  3. librbd:发起mirror_mode_set()请求:cls_client::mirror_mode_set();

在librbd中,我们首先接受到api请求的是RBD类。然后RBD类调用librbd内部相应的处理函数(src/librbd/librbd.cc):

接下来librbd的内部函数会检查当前的mirror mode,如果和我们要设置的mode相同,直接返回:

如果mode需要修改,然后进行mode的修改。中间有很多准备和检查操作,但是最重要的是下面这段代码。

通过调用cls_client模块的接口进行mode的设置。

l  4. cls_client:发送远程调用请求:OSDOp(CEPH_OSD_OP_CALL)

首先,需要介绍一下cls模块。cls/cls_client 实现了一种远程调用机制。client端通过cls_client模块将需要执行的操作进行封装,然后发送CEPH_OSD_OP_CALL 的OSDOp给osd,osd接收到命令后,执行需要调用的函数进行相应的处理。

在我们这个实际应用场景中,我们需要做的是mode_set操作。话不多说,直接来看cls_client是怎么实现的。

总共做了两件事:

第一:1378行,把输入放到in_bl中,也就是我们想设置的mode。这个in_bl会跟随OSDOp传到osd端,osd才能根据in_bl得到我们想要设置的mode值。

第二:1382行,调用ioctx的exec()。Ioctx 是一个连接到指定pool的io上下文。Ioctx的exec()函数接受五个参数:第一个参数指明需要作用的object名字,在这里是RBD_MIRRORING,实际上是一个在rbd_types.h中的宏定义:

所以我们这次的请求是作用在rbd_mirroring这个object当中的。这个object是mirror相关的所有元数据对象。第二个参数指明是哪个模块的请求,我们这里是rbd,第三个参数指明需要调用的函数名,这里是"mirror_mode_set"。第四个参数是输入的bufferlist,这里的in_bl包含了我们想要设置的mode值。第五个参数是out_bl,表示返回值的bufferlist。

exec()函数接受这五个参数之后,会做这么几件事情,新建一个::ObjectOperationrd;然后构造成一个Objecter::Op,通过objecter->submit_op()提交这个op给osd。并且等待结果返回。

这个过程涉及到client和osd 交互的设计,也是很有意思,不过不是本文的重点,可以另外开一个主题进行详细分析。这里我们只需要知道,ioctx->exec() 将远程调用的请求发送给了osd,并等待执行结果,就行了。

l  5. cls:根据远程调用请求,执行操作:

mirror_mode_set() {

cls_cxx_map_set_val();

}

在osd端,osd接收到OSDOp,分发到PrimaryPG进行处理:

do_osd_ops()就做了一件事,打开我们指定的class(4993行),也就是rbd,然后找到我们指定的method(4996行),也就是mirror_mode_set,然后执行这个method(5011行)。

那osd端cls的mirror_mode_set()又做了些什么呢?在src/cls/rbd/cls_rbd.cc中,可以看到,函数mirror_mode_set();

操作很简单,调用cls_cxx_map_set_val()设置了rbd_mirroring这个object的一个key-value值,ceph里面这种值叫做omap值。

至此,rbd_mirroring的mode值已经修改结束了。我们可以看到通过rados命令确认一下修改结果:

可以看到 mirror_mode的结果是2,也就是我们设置的pool 模式。

以上就是命令rbd mirror pool enable rbd pool 的整个执行过程,这样我们就已经将rbdpool的mirror 模式改成了pool 模式。现在我们还需要通过命令:rbd --cluster local mirror pool peer add rbdclient.admin@remote 给rbd pool 添加一个peer。这个过程和上面类似,区别就在于enable是修改mirror_mode的值,add peer是添加一个omap值到rbd_mirroring的object里面。

至此,一个pool的mirroring 配置就结束了,接下来需要做的就是启动rbd-mirror服务,执行mirroring事务了。

(3)      rbd-mirror 服务

下面我们来看看rbd-mirror服务。

上图列出了rbd-mirror里面几个非常重要的类以及他们之间的关系,包括Mirror,ClusterWather,Replayer,PoolWather,ImageReplayer。下面我们来看看这几个类是怎样相互配合完成rbd mirroring的。

Class Mirror: 这是rbd-mirror 服务的主类,一个rbd-mirror服务其实可以看做就是一个Mirror类的实例。Mirror里面有几个很重要的成员,m_local_cluster_watcher,这是一个ClusterWatcher的实例,用来watch本地cluster的mirror状态的,包括mirrormode和peer变化。m_replayers,这是一个std::map<PoolPeer,std::unique_ptr<Replayer> > 类型的成员变量。用来记录所有的PoolPeer和Replayer的对应关系。除了这两个重要的成员变量,Mirror类还有一个很重要的函数:update_replayers()。这个函数用来更新m_replayers变量,当m_local_cluster_watcher发现我们需要更新replayers,就会调用update_replayers()。

Class ClusterWatcher: 这个类顾名思义是用来watch 一个cluster的,他通过读取cluster里面每个pool的mirror相关元数据(如前文所述,这些元数据都存放在rbd_mirroring的object里面),得到我们需要做mirroring的所有pool以及这个pool的peer信息。他有两个很重要的函数值得注意,refresh_pools()用来刷新最新的pool和peer的关系。get_pool_peers()得到最新的pool和peer的关系列表。

Class Replayer: 这个类是用来做replay操作的。一个replayer对应一个pool。实际上,在最新的ceph里面,我们已经将replayer重命名为PoolReplayer。Replayer有两个很重要的成员变量,m_pool_watcher,这是一个PoolWatcher的实例,用来watch这个pool里面的image情况。m_image_replayers这是一个std::map<std::string,std::unique_ptr<ImageReplayer<> > >类型的实例。保存了这个pool里面所有image和image对应的ImageReplayer的关系。除了这两个成员变量,Replayer里面还有一个线程,m_replayer_thread。这个线程用来执行这个pool的watch和update操作。

Class PoolWatcher: 这个类是用来watch一个pool的。他通过定时做refresh()来更新m_images,m_images表示pool里面需要做mirror的image列表。这个类中有两个很重要的函数:refresh_images()和get_images()。 refresh_images()会定时去访问rbd_mirroring读取现在这个pool里面需要做mirror的image,然后更新到m_images。get_images()直接返回m_images,也就是最新的需要做mirror的image列表。

Class ImageReplayer: 这是最终执行replay操作的类,这个类很重要。他有一个m_remote_journaler,这个成员变量用来连接到remote cluster里面我们需要mirror的那个image的journal。m_local_journal这是local image的journal。 m_local_replay,这是 m_local_journal的replayer,用来将remote的journal event在本地的journal做replay。我们会定时调用bootstrap()函数对这个image 进行replay操作。

那么到底ImageReplayer是怎样对一个image进行replay操作的呢?

实际上有两种同步方式,event和image。event表示对这个image的一些操作,比如resize,会记录到journal里面,然后event通过librbd的journal/replay机制来实现同步。Image方式是通过sync point来实现。在每次同步的时候做一个snapshot,作为sync point,然后进行数据拷贝。当remote 的image没有完整的journal来做replay的时候,我们就必须使用sync point的方式来做image 同步。比如我们将一个使用了很久的image加入到mirroring里面。

关于这个设计,可以参考https://www.spinics.net/lists/ceph-devel/msg24169.html, 这是Josh Durgin在设计rbd-mirror的时候发出来的邮件。里面说明了为什么使用这种journaling的方式来做mirroring。邮件里面列出了三种方式, snapshot, log-structed rbd,和现在使用的journaling。最终选择了journaling,主要原因是journaling综合了snapshot和log-structed rbd两种方式的优点。对于event,使用log-struct的方式来记录并replay,对于没有event的image数据,使用snapshot做sync point的方式来同步。

那下面从两个方面来介绍一下ImageReplayer是怎样工作的。

第一,  event replay。首先我们需要知道,现在有哪些event我们会放到journal里面?

如上,这是我们现在所支持的所有event,以resize为例我们来看看rbd-mirror是怎样让remote的image resize 也发生到local的image上的。

当用户执行resize操作将image做resize的时候,remote cluster的librbd会在journal里面记录一个ResizeEvent。之后,local cluster的replayer会定期唤起ImageReplayer去做image 同步操作。ImageReplayer会通过m_remote_journaler去获取remote cluster里面对应image的journal的entry。然后通过m_local_replay去decode并且调用local cluster的librbd来处理。其实就是librbd里面的journal/replay机制。这样remote cluster里面的resize操作就同步到local cluster里面来了。

第二,  image 同步。除了event的同步,当image没有完整的journal保存所有的event的时候,就需要使用syncpoint的方式来同步了。

当我们将一个image 通过rbd mirror image enable test 的方式加入到mirror中时,我们localcluster的PoolWatcher会发现这个image,并放到m_images里面。Replayer拿到images为这个image起动ImageReplayer,ImageReplayer会调用create_local_image()创建一个新的image来作为mirrored image。然后使用image_sync()来做image的同步。大概过程如下:

可以看到,这个过程将一个image的所有数据都进行了同步。

(4)      rbd-mirror TODO

至此,我们已经了解了rbd-mirror的基本实现原理。包括rbd-mirror的架构设计,rbd mirroring的配置,以及rbd-mirror数据同步。下面我们再来看看rbd mirroring的发展计划。

(1)      update notify

根据上文我们可以看到,rbd-mirror是通过polling的模式来进行数据同步的,这种方式简单但不够高效且消耗太多资源。我们需要一种notification的机制来让rbd-mirror知道什么时候需要更新。

(2)      rbd-mirror HA

我们可以看到rbd-mirror这个服务是独立的,没有提供高可用机制。那么这个容灾方案就不够安全,所以我们需要rbd-mirror的HA方案,包括Active/Passive 或者Active/Active。

以上所有的分析和代码都是基于ceph最新的stable版本Karen的。实际上我提到的这两个问题,在upstream里面已经有了设计,期待下一个release的ceph里面能够解决这些问题。

rbd-mirror 技术内幕相关推荐

  1. 世界级Linux技术大师首次公开大量技术内幕

    媒体评论 "这是我读过的最全面的Linux设备驱动程序著作." --Alan Cox,Linux内核维护者 "这本书涵盖了各种Linux设备驱动程序,全面而翔实.&quo ...

  2. Google和Yahoo专家联手揭秘世界顶尖公司的技术内幕

    JavaScript设计模式 媒体评论 本书道前人所未道,引导你从编写代码转变为设计代码.书中绝大部分示例代码都来自YUI等实战项目,并进行了深入剖析.强烈推荐. --Nicholas C.Zakas ...

  3. 《WCF技术内幕》翻译2:《WCF技术内幕》绪论

    绪论 总述     服务是现代软件架构的一个主要部分,WCF是构建基于Microsoft Windows系统的服务程序平台.WCF编写的服务可以与其它供应商的服务交互(例如, IBM, BEA, an ...

  4. android技术内幕心得

    2019独角兽企业重金招聘Python工程师标准>>> 这本书开头就介绍了android的初始化过程 执行流程是这样的 --Linux基础系统, --Linux Kernel(lin ...

  5. MySQL必知必会教程:深入理解MySQL技术内幕

    2019独角兽企业重金招聘Python工程师标准>>> MySQL必知必会教程:深入理解MySQL技术内幕 作为最流行的开源数据库软件之一,MySQL数据库软件已经是广为人知了.当前 ...

  6. 《WCF技术内幕》翻译1:《WCF技术内幕》目录和作者简介

    翻译序言: 我现在推荐一本很好的WCF学习书籍:<Inside Microsoft Windows Communication Foundation>.Justin Smith先生所著.2 ...

  7. 读书笔记之MySQL技术内幕

    前言 本文内容基本摘抄自<MySQL技术内幕 InnoDB存储引擎>,以供复习之用,没有多少参考价值.想要更详细了解请参考原书. 第一章.MySQL体系结构和存储引擎 数据库是物理操作系统 ...

  8. 赠书:一本书揭开 Spring Boot 技术内幕

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 新书速递 经过几年的发展,Spring Boot几乎已成 ...

  9. jQuery技术内幕:深入解析jQuery架构设计与实现原理

    为什么80%的码农都做不了架构师?>>>    jQuery技术内幕:深入解析jQuery架构设计与实现原理 本书由阿里巴巴资深前端开发工程师撰写,从源代码角度全面而系统地解读了jQ ...

最新文章

  1. Chapter 2 Open Book——16
  2. 【Android 应用开发】Android 网络编程 API笔记 - java.net 包相关 接口 api
  3. SpringCloud SpringBoot 推荐
  4. Java中的命名参数
  5. 且谈关于最近软件测试的面试
  6. 何恺明一作,刷新7项检测分割任务,无监督预训练完胜有监督
  7. 图解TCPIP-传输层 UDP
  8. 小白的springboot之路(十)、全局异常处理
  9. 嵌入式系统硬件原理设计与审核
  10. dw33d最新固件openwrt_【矿渣们的救赎】の 小米路由器mini刷OpenWrt
  11. 银行卡查询银行卡类型查询及归属地查询
  12. 《东周列国志》第六十五回 弑齐光崔庆专权 纳卫衎宁喜擅政
  13. 轻应用框架, Clouda先行
  14. 标签云的实现(使用jQuery插件jqcloud)
  15. WhatsAPP营销详细攻略,带你一镜到底的了解WhatsAPP营销
  16. 人工智能发展如何,未来有哪些就业方向?
  17. python爬取bilibili弹幕_用Python爬取B站视频弹幕
  18. wps 根据单元格值 设置单元格所在行 颜色(大于0 行红色 小于0 行xx色)
  19. java计算机毕业设计景区失物招领平台演示录像源程序+mysql+系统+lw文档+远程调试
  20. FreeNAS家庭工作存储搭建指南(一)——硬件篇

热门文章

  1. ffmpeg录制桌面视频和麦克风音频(音视频同步)
  2. Pytorch之torch.nn.functional.pad函数详解
  3. python-转存文件
  4. 秒杀,在社群团购中这样玩……
  5. DCANet: Learning Connected Attentions for Convolutional Neural Networks
  6. 逻辑编排在优酷可视化搭建中的实践之上
  7. 小区宽带当前ONU类型简介
  8. 湖南大学超级计算机天河,基础科学研究
  9. 笔记本(ThinkPad)怎样关闭触摸板
  10. ISO三体系认证有哪些意义和好处?