解析CEPH: 存储引擎实现之一 filestore
Ceph作为一个高可用和强一致性的软件定义存储实现,去使用它非常重要的就是了解其内部的IO路径和存储实现。这篇文章主要介绍在IO路径中最底层的ObjectStore的实现之一FileStore。 ObjectStoreObjectStore是Ceph OSD中最重要的概念之一,它封装了所有对底层存储的IO操作。从上图中可以看到所有IO请求在Clieng端发出,在Message层统一解析后会被OSD层分发到各个PG,每个PG都拥有一个队列,一个线程池会对每个队列进行处理。 当一个在PG队列里的IO被提出后,该IO请求会被根据类型和相关附带参数进行处理。如果是读请求会通过ObjectStore提供的API获得相应的内容,如果是写请求也会利用ObjectStore提供的事务API将所有写操作组合成一个原子事务提交给ObjectStore。ObjectStore通过接口对上层提供不同的隔离级别,目前PG层只采用了Serializable级别,保证读写的顺序性。 ObjectStore主要接口分为三部分,第一部分是Object的读写操作,类似于POSIX的部分接口,第二部分是Object的属性(xattr)读写操作,这类操作的特征是kv对并且与某一个Object关联。第三部分是关联Object的kv操作(在Ceph中称为omap),这个其实与第二部分非常类似,但是在实现上可能会有所变化。 目前ObjectStore的主要实现是FileStore,也就是利用文件系统的POSIX接口实现ObjectStore API。每个Object在FileStore层会被看成是一个文件,Object的属性(xattr)会利用文件的xattr属性存取,因为有些文件系统(如Ext4)对xattr的长度有限制,因此超出长度的Metadata会被存储在DBObjectMap里。而Object的omap则直接利用DBObjectMap实现。因此,可以看出xattr和omap操作是互通的,在用户角度来说,前者可以看作是受限的长度,后者更宽泛(API没有对这些做出硬性要求)。 FileJournal为了缩小写事务的处理时间,提高写事务的处理能力并且实现事务的原子性,FileStore引入了FileJournal,所有写事务在被FileJournal处理以后都会立即返回(上图中的第二步)。FileJournal类似于数据库的writeahead日志,使用O_DIRECT和O_DSYNC每次同步写入到journal文件,完成后该事务会被塞到FileStore的op queue。事务通常有若干个写操作组成,当在中间过程进程crash时,journal会OSD recover提供了完备的输入。FileStore会存在多个thread从op queue里获取op,然后真正apply到文件系统上对应的Object(Buffer IO)。当FileStore将事务落到disk上之后,后续的该Object的读请求才会继续(上图中的第五步)。当FileStore完成一个op后,对应的Journal可以丢弃这部分日志。 实际上并不是所有的文件系统都按照这个顺序,一般来说如Ceph推荐的Ext4和XFS文件系统会先写入Journal,然后再写入Filesystem,而COW(Copy on Write)文件系统如Btrfs和ZFS会同时写入Journal和FileSystem。 DBObjectMapDBObjectMap是FileStore的一部分,利用KeyValue数据库实现了ObjectStore的第三部分API,DBObjectMap主要复杂在其实现了clone操作的no-copy。因为ObjectStore提供了clone API,提供对一个Object的完全clone(包括Object的属性和omap)。DBObjectMap对每一个Object有一个Header,每个Object联系的omap(kv pairs)对会与该Header联系,当clone时,会产生两个新的Header,原来的Header作为这两个新Header的parent,这时候无论是原来的Object还是cloned Object在查询或者写操作时都会查询parent的情况,并且实现copy-on-write。那么Header如何与omap(kv pairs)联系呢,首先每个Header有一个唯一的seq,然后所有属于该Header的omap的key里面都会包含该seq,因此,利用KeyValueDB的提供的有序prefix检索来实现对omap的遍历。 上面提到FileStore会将每个Object作为一个文件,那么Object的一些属性会与Object Name一起作为文件名,Object 所属的PG会作为文件目录,当一个PG内所包含的文件超过一定程度时(在目录内文件太多会造成文件系统的lookup性能损耗),PG会被分裂成两个PG。 |
解析CEPH SNAPSHOT
经常有开发者在邮件列表中会问到Ceph Snapshot的实现方式,受限于目前有限的实现文档和复杂的代码结构和代码量,弄清楚Ceph Snapshot并不是一件容易的事。正好最近在重构Ceph存储引擎层的DBObjectMap,涉及到处理Snapshot间clone的问题,重新梳理了一次在Ceph IO路径中占了非常大比重的snapshot相关代码流程,在这里并不会重点展现里面的代码或者数据结构,而是从高层设计角度展现Snapshot的实现。
在阅读下文前务必先了解Ceph的基本情况和使用场景。什么是ceph怎样使用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://kernal.blog.51cto.com/8136890/1540535
解析CEPH: 存储引擎实现之一 filestore的更多相关文章
- ceph存储引擎bluestore解析
原文链接:http://www.sysnote.org/2016/08/19/ceph-bluestore/ ceph后端支持多种存储引擎,以插件式的方式来进行管理使用,目前支持filestore,k ...
- 解析Ceph: Snapshot
经常有开发者在邮件列表中会问到Ceph Snapshot的实现方式,受限于目前有限的实现文档和复杂的代码结构和代码量,弄清楚Ceph Snapshot并不是一件容易的事.正好最近在重构Ceph存储引擎 ...
- Ceph Newstore存储引擎介绍
在Ceph被越来越多地应用于各项存储业务过程中,其性能及调优策略也成为用户密切关注讨论的话题,影响性能表现关键因素之一即OSD存储引擎实现:Ceph基础组件RADOS是强一致.对象存储系统,其OSD底 ...
- [ ceph ] BlueStore 存储引擎介绍
为什么需要 BlueStore 首先,Ceph原本的FileStore需要兼容Linux下的各种文件系统,如EXT4.BtrFS.XFS.理论上每种文件系统都实现了POSIX协议,但事实上,每个文件系 ...
- MySQL存储引擎之Spider内核深度解析
作者介绍 朱阅岸,中国人民大学博士,现供职于腾讯云数据库团队.研究方向主要为数据库系统理论与实现.新硬件平台下的数据库系统以及TP+AP型混合系统. Spider是为MySQL/MariaDB开发 ...
- MySQL InnoDB存储引擎undo redo解析
本文介绍MySQL数据库InnoDB存储引擎重做日志漫游 00 – Undo Log Undo Log 为了实现事务原子,在MySQL数据库InnoDB存储引擎,还使用Undo Log(简称:MVCC ...
- 第二课——解析mysqldump命令和mysqlbinlog命令+innodb和Myisam存储引擎简介
环境说明 mysql版本:Percona-Server-5.6.30 IP:10.7.15.167 端口:3306 安装目录:/httx/run/mysql 数据目录:/httx/run/mysql/ ...
- 图文实例解析,InnoDB 存储引擎中行锁的三种算法
前文提到,对于 InnoDB 来说,随时都可以加锁(关于加锁的 SQL 语句这里就不说了,忘记的小伙伴可以翻一下上篇文章),但是并非随时都可以解锁.具体来说,InnoDB 采用的是两阶段锁定协议(tw ...
- 解析 Ceph: FileJournal 的作用
很多的用户在提到 Ceph 性能的时候都会提到“写放大”这点,实际上就是 FileJournal 在起作用.只要使用默认的 FileStore,所有数据包括 metadata 都会在 FileJo ...
随机推荐
- 回顾.NET Remoting分布式开发
记得在下第一次接触.NET Remoting分布式开发是在2003年,那时候是Framework1.0初次亮相之时,Remoting分布式开发是Framework1.0其中一个亮点.经过多年的发展,在 ...
- mysql 使用命令执行外部sql文件
语句 source e:\\phpPro\\fileName.sql 注意,不需要再后面加 分号 !!!!!
- SQL 时间函数 Datepart()与DateName()
1.Datepart() 返回代表指定日期的指定日期部分的整数 语法 Datepart(datepart,date) 返回类型 int datepart: 日期部分 缩写 year yy, yyyy ...
- vc判断当前用户是否具有administrator 权限代码
BOOL IsAdmin() { HANDLE hAccessToken; BYTE * InfoBuffer = ]; PTOKEN_GROUPS ptgGroups; DWORD dwInfoBu ...
- Leetcode注意
List<List<Integer>> res = new ArrayList<>();
- html5.js让IE(包含IE6)支持HTML5元素方法
原文地址:http://blog.sina.com.cn/s/blog_62a36ec401018oqb.html html5.js让IE(包含IE6)支持HTML5元素方法 微软的最新浏览器IE8及 ...
- 001-es6变量声明、解构赋值、解构赋值主要用途
一.基本语法 1.1.声明变量的六种方法 参看地址:http://es6.ruanyifeng.com/#docs/let let:局部变量,块级作用域,声明前使用报错 var:全局变量,声明前使用 ...
- JS连等赋值的坑
cnblogs标题: JS连等赋值的坑 关于JS连等赋值有个经典的笔试题: var a = {n: 1}; var b = a; a.x = a = {n: 2}; console.log(a.x); ...
- 推荐系统第2周--itemCF和userCF
推荐系统分类 基于应用领域分类:电子商务推荐,社交好友推荐,搜索引擎推荐,信息内容推荐基于设计思想:基于协同过滤的推荐,基于内容的推荐,基于知识的推荐,混合推荐基于使用何种数据:基于用户行为数据的推荐 ...
- Jupyter Notebook修改目标文件
默认的路径 如果没有修改配置文件,那么一般就在用户目录下面: 下面各处默认起始目标地址,以防有一天想改回来 I:\shujufenxi\python.exe I:\shujufenxi\cwp.py ...