解析Ceph: Snapshot
经常有开发者在邮件列表中会问到Ceph Snapshot的实现方式,受限于目前有限的实现文档和复杂的代码结构和代码量,弄清楚Ceph Snapshot并不是一件容易的事。正好最近在重构Ceph存储引擎层的DBObjectMap,涉及到处理Snapshot间clone的问题,重新梳理了一次在Ceph IO路径中占了非常大比重的snapshot相关代码流程,在这里并不会重点展现里面的代码或者数据结构,而是从高层设计角度展现Snapshot的实现。
在阅读下文前务必先了解Ceph的基本情况和使用场景。Why Ceph and how to use Ceph?
Ceph Snapshot使用场景
多数人尝试Ceph的Snapshot往往从Ceph的RBD库入手,也就是所谓的块存储。利用librbd通过简单的命令可以快速创建卷和Snapshot。
rbd create image-name –size 1024 -p pool
rbd snap create pool/image-name –snap snap-name
第一条命令创建了一个名为”image-name”的卷,在这个过程中librbd库只是创建了一个metadata而没有实际向Ceph申请空间。关于librbd如何利用Rados实现块存储和管理更多的细节会在以后的文章中讲到,这里先留个坑。
第二条命令对”image-name”卷创建了一个名为”snap-name”的Snapshot,创建以后,对”image-name”卷的任意写操作之后都可以在任意时间回滚到创建”snap-name”的Snapshot时的数据。如下面这条命令
rbd snap rollback pool/image-name –snap snap-name
在用户实际尝试过程中,会发现Ceph对于卷的操作和管理非常轻量,任意时刻,任意卷大小,任意集群大小的卷创建都是相同的操作量级,在其背后实质上也是完全相同的操作。开发者会对如何实现Snapshot更敢兴趣,因为Snapshot的实现方式决定了如何有效的使用Snapshot。
Ceph Snapshot实现
在阐述之前,首先要了解Ceph有Pool的概念,也就是上面命令上涉及到的-p pool。一个Ceph Cluster可以创建多个Pool,每个Pool是逻辑上的隔离单位,不同的Pool可以有完全不同的数据处理方式。如Replication Size(副本数),Placement Groups(PG),CRUSH Rules,Snapshots,Ownership都是利用Pool进行隔离的。
因此,对Ceph的任意操作都需要先指定Pool才能进行,上面的image操作都是在一个名为”pool”的Pool上进行,名为”image-name”的Image也是存储在”pool”中。
除了Pool概念外,Ceph实质上有两种Snapshot模式,并且两种Snapshot是不能同时应用到同一个Pool中。
- Pool Snapshot: 对整个Pool打一个Snapshot,该Pool中所有的对象都会受影响
- Self Managed Snapshot: 用户管理的Snapshot,简单的理解就是这个Pool受影响的对象是受用户控制的。这里的用户往往是应用如librbd。
我们在前面利用rbd命令的操作实质上是使用第二种模式,因此我们先首先介绍第二种模式的实现。
在前面提到,Snapshot也是利用Pool隔离的,两种Snapshot mode的实现是基本相似的,如何使用是造成两种模式分离的重要原因。每个Pool都有一个snap_seq字段,该字段可以认为是整个Pool的Global Version。所有存储在Ceph的Object也都带有snap_seq,而每个Object会有一个Head版本的,也可能会存在一组Snapshot objects,不管是Head版本还是snapshot object都会带有snap_seq,那么接下来我们看librbd是如何利用该字段创建Snapshot的。
- 用户申请为”pool”中的”image-name”创建一个名为”snap-name”的Snapshot
- librbd向Ceph Monitor申请得到一个”pool”的snap sequence,Ceph Monitor会递增该Pool的snap_seq,然后返回该值给librbd。
- librbd将新的snap_seq替换原来image的snap_seq中,并且将原来的snap_seq设置为用户创建的名为”snap-name”的Snapshot的snap_seq
从上面的操作中,对于版本控制实现熟悉的同学们可能就大致猜测出Ceph对于Snapshot的实现了。每个Snapshot都掌握者一个snap_seq,Image可以看成一个Head Version的Snapshot,每次IO操作对会带上snap_seq发送给Ceph OSD,Ceph OSD会查询该IO操作涉及的object的snap_seq情况。如”object-1″是”image-name”中的一个数据对象,那么初始的snap_seq就”image-name”的snap_seq,当创建一个Snapshot以后,再次对”object-1″进行写操作时会带上新的snap_seq,Ceph接到请求后会先检查”object-1″的Head Version,会发现该写操作所带有的snap_seq大于”object-1″的snap_seq,那么就会对原来的”object-1″克隆一个新的Object Head Version,原来的”object-1″会作为Snapshot,新的Object Head会带上新的snap_seq,也就是librbd之前申请到的。
Ceph的实现当然比上面提到的要复杂很多,要考虑更多的异常情况还有管理Object Snaps上。
上述提到的是第二种Snapshot Mode,那么第一种模式实际上更简单。既然第二种方式是应用(librbd)自己申请snap_seq,然后进行管理,那么第一种是的场景可以是命令如”rados mksnap snap-name -p pool”进行全局pool的Snapshot,应用是不需要知道snap_seq的。这条命令会递增”pool”的snap_seq,然后接下来所有”pool”下的objects对会受影响,因为所有的接下来的IO操作都会自动继承”pool”的snap_seq,对object进行clone。在CephFS里用到这个模式管理全局的Snapshot。
所以,更简单的讲,这两者mode的区别就在于应用进行IO请求时是否附带snap_seq。
Object Snapshot的存储管理
上面提到的都是如何利用snap_seq向底层存储查找相应的对象然后返回,那么底层的存储引擎是如何管理一个Object的不同版本的呢。
首先,任一个Object都是通过ObjectStore接口进行访问,目前Ceph Master分支支持MemStore和FileStore两种,FileStore是默认的存储接口实现。以后的文章也会介绍具体的FileStore实现。
在Ceph中,每一个Object都有三种类型的存储接口,分别是最主要的Object存储,xattr存储和omap存储。Object存储就是用户实际数据的存放,xattr主要用来给CephFS提供XATTR数据存放,omap存储可以理解成一个k/v存储并且与某一个object相关联。而一个Object的元数据(pool,PG,name等等)都有一个object_info_t的结构进行管理,有一个SnapSetContext结构管理Snapshots,两者都作为一个object的k/v存储持久化。默认的FileStore是利用LevelDB作为键值存储,然后通过DBObjectMap类对LevelDB进行映射管理。
在Snapshot的实现上,最重要的其实就是Clone操作,那么在FileStore层面,Object数据存储是实际上就是一个文件,Object间克隆依赖OSD数据目录的文件系统,如Ext4或者XFS会直接完全拷贝数据,使用Btrfs会利用ioctl的BTRFS_IOC_CLONE_RANGE命令,kv数据克隆通过一个巧妙的KeyMapping实现COW策略(略微复杂,后面文章解读),而xattr则完全copy实现(xattr在Ceph中较少用到)。
来自:http://www.ustack.com/blog/ceph-snapshot/
解析Ceph: Snapshot的更多相关文章
- 解析CEPH: 存储引擎实现之一 filestore
Ceph作为一个高可用和强一致性的软件定义存储实现,去使用它非常重要的就是了解其内部的IO路径和存储实现.这篇文章主要介绍在IO路径中最底层的ObjectStore的实现之一FileStore. Ob ...
- 解析Ceph: RBDCache 背后的世界
转自:https://www.ustack.com/blog/ceph-internal-rbdcache/ RBDCache 是Ceph的块存储接口实现库 Librbd 的用来在客户端侧缓存数据的目 ...
- 解析 Ceph: FileJournal 的作用
很多的用户在提到 Ceph 性能的时候都会提到“写放大”这点,实际上就是 FileJournal 在起作用.只要使用默认的 FileStore,所有数据包括 metadata 都会在 FileJo ...
- 解析Ceph: 数据的端到端正确性和 Scrub 机制
转自:https://www.ustack.com/blog/ceph-internal-scrub/ Ceph 的主要一大特点是强一致性,这里主要指端到端的一致性.众所周知,传统存储路径上从应用层到 ...
- 解析Ceph: 恢复与数据一致性
转自:https://www.ustack.com/blog/ceph-internal-recovery-and-consistency/ 作为一个面向大规模的分布式存储系统,故障处理是作为一个常态 ...
- Ceph源码解析:读写流程
转载注明出处,整理也是需要功夫的,http://www.cnblogs.com/chenxianpao/p/5572859.html 一.OSD模块简介 1.1 消息封装:在OSD上发送和接收信息. ...
- ceph 初始化函数解析
global_pre_init 预初始化函数,解析ceph.conf配置文件, 初始化定义global_context 和 config的全局变量. 全局预初始化函数 CINIT_FLAG_UNPRI ...
- 理解 QEMU/KVM 和 Ceph(1):QEMU-KVM 和 Ceph RBD 的 缓存机制总结
本系列文章会总结 QEMU/KVM 和 Ceph 之间的整合: (1)QEMU-KVM 和 Ceph RBD 的 缓存机制总结 (2)QEMU 的 RBD 块驱动(block driver) (3)存 ...
- Ceph 的用户管理与认证
目录 文章目录 目录 前言 Ceph 的用户管理 用户管理常规操作 CephX 认证系统 身份认证原理 使用 ceph-authtool 进行密钥环管理 注意事项 前言 常规的身份认证系统无非三点: ...
随机推荐
- 加密app.config
EncryptConnection.EncryptConnectionString(true); public static class EncryptConnection { public stat ...
- PHP中设置、使用、删除Cookie方法
1.设置Cookie PHP用SetCookie函数来设置Cookie.必须注意的一点是:Cookie是HTTP协议头的一部分,用于浏览器和服务器之间传递信息,所以必须在任何属于HTML文件本身的内容 ...
- 关于TCP/UDP缓存
1.修订单个socket的缓冲区大小:通过setsockopt使用SO_RCVBUF来设置接收缓冲区,该参数在设置的时候不会与rmem_max进行对比校验,但是如果设置的大小超过rmem_max的话, ...
- js函数内嵌函数的整体跳出 .
stop=false; $.ajax({success:function(){ 这里面不能用return false跳出整个<script></script>,只能跳出该处的f ...
- 【LeetCode】88 - Merge Sorted Array
Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array. Note:Yo ...
- 你可能不知道的30个Python语言的特点技巧
1 介绍 从我开始学习Python时我就决定维护一个经常使用的“窍门”列表.不论何时当我看到一段让我觉得“酷,这样也行!”的代码时(在一个例子中.在StackOverflow.在开源码软件中,等等), ...
- String内存陷阱简介
String 方法用于文本分析及大量字符串处理时会对内存性能造成一些影响.可能导致内存占用太大甚至OOM. 一.先介绍一下String对象的内存占用 一般而言,Java 对象在虚拟机的结构如下:•对象 ...
- macos+apache+php+phpmyadmin 的整合过程梳理
启动Apache 有两种方法: 打开“系统设置偏好(System Preferences)” -> “共享(Sharing)” -> “Web共享(Web Sharing)”. 打开“终端 ...
- android开发中遇到的bug
这种NullPointerException这么解决啊 Activity.dispatchTouchEvent 里try catch一下 参考:http://www.eoeandroid.com/th ...
- STL源码剖析读书笔记--第四章--序列式容器
1.什么是序列式容器?什么是关联式容器? 书上给出的解释是,序列式容器中的元素是可序的(可理解为可以按序索引,不管这个索引是像数组一样的随机索引,还是像链表一样的顺序索引),但是元素值在索引顺序的方向 ...