现状
Ceph的目标是提供一个general-purpose的并行文件系统,设计目标是也是在廉价的存储介质上构建具有 high performance, high scalibility, high available, 其目标是应用在科学计算等HPC领域。目前其已经被纳入处于linux内核之中,用c++开发。但是,无论从架构和其工程实现来看,都很不成熟,难以在production environment 中使用,其更接近于一个原型系统的升级版。
架构设计
特点
Ceph最大的特点是分布式的元数据服务器 通过CRUSH,一种拟算法来分配文件的locaiton,其核心是 RADOS(resilient automatic distributed object storage),一个对象集群存储,本身提供对象的高可用,错误检测和修复功能。其设计思想有一些创新点:
第一,数据的定位是通过CRUSH算法来实现的。
传统的,或者通常的并行文件系统,数据的定位的信息是保存在文件的metadata 中的, 也就是inode结构中,通过到metadata server上去获取数据分布的信息。而在Ceph中,是通过CRUSH 这个算法来提供数据定位的。
这和GlusterFS的思想是相同的,GlusterFS 是通过Elastic Hash,类似于DHT的算法实现的。这就有点像P2P存储,所谓的完全对称的存储,这种设计架构最大的优点是,其理论上可以做到 线性扩展的能力(line scale)。
在GlusterFS架构中,是完全去掉了metadata server,这就导致GlusterFS文件系统上的元数据操作,例如ls, stat操作非常慢,要去各个stripe的节点上收集相关的元数据信息后聚合后的结果。在Ceph中,为了消除完全的p2p设计,提供了metadata server 服务,提供文件级别的元数据服务,而元数据服务中的文件数据定位由CRUSH算法代替。
第二,元数据服务器可以提供集群metadata server 服务。
只要当我们了解了其结构后,感觉并没有太大的特点。元数据服务器一般就用来存储文件和目录的信息,提供统一的命名服务。 在Ceph中,元数据 的存储inode 和 dentry的,以及日志都是在 对象存储集群RADOS中存储,这就使得 metadata的 持久化都是在远程的RADOS中完成,metadata server 不保存状态,只是缓存最近的inode 和 dentry项,当metadata server 失效后,其所所有信息都可以从RADOS中获取,可以比较容易恢复。
其实, 也上两点,并没有什么特别的地方。 我觉得,CEPH最核心的,就是RADOS就是RADOS(resilient automatic distributed object storage). 其resilient 指的是可以轻松扩展,automatic 指的是其对象存储集群可以处理failover, failure recovery。RADOS 对象集群其对外提供了一个高可用的,可扩展的,对象集群,从客户端的角度看,就是一个统一命名空间的对象存储。
下面我们重点介绍一下RADOS这个Ceph的核心系统。
RADOS对象存储集群
Ceph 的Monitor
用来监控集群中所有节点的状态信息,完成类似配置服务的功能。在Ceph里,配置主要就是cluster map ,其保存集群所有节点信息,并和所有的节点保持心跳,来监控所有的节点状态。
其通过Paxos算法实现实现自身的高可用,也就是说,这个Ceph Monitor是不会有单点问题的。目前流行的zookeeper 的功能,以及实现都类似。
对象存储
Ceph文件系统中的数据和元数据都保存在对象中。 对于对象存储,通常的定义是:一个Object,由三部分组成(id,metadata,data),id是对象的标识,这个不必多说。所谓的metadata,就是key/value的键值存储,至于用来保存什么信息,由文件系统的语义定义。data就是实际存储的数据。
Ceph的对象,包括四个部分(id,metadata,attribute,data),在Ceph里,一个Object,实际就对应本地文件系统的一个文件,一个对象的attribute,也是key/value的键值对,其保存在本地文件系统的文件的扩展属性中。对象的metadata就是key/value的键值对,目前Ceph保存在google开源的一个key/value存储系统leveldb中,或者自己写的一个key/value 存储系统中。数据就保存在对象的文件中。对于一个对象的更新,都需要写日志中来保持一个Object数据的一致性(consistence),日志有一个单独的设备或者文件来保存。
副本存储
一个PG(placement group)由一个OSD列表组成,OSD的个数,就是对象的副本数,一个三副本的PG就是一个主,两个副本的OSD列表组成。
一个PG和OSD列表的映射关系,是通过CRUSH算法计算的,知道PG的id,和当前的cluster map,就可以通过CRUSH算法,计算出OSD列表。特别强调的是,一个PG是逻辑层概念,也就是说,一个OSD,可能同时是一个或者多个PG的主,同时是另一个PG的从。一个OSD处于多个PG组中。一个PG就是复制和修复的基本单位。每个OSD本地保存其所在的PG列表就可以了,其它OSD可以通过输入当前的该OSD保存的cluster map 和 PG 的id ,通过CRUSH计算得出。
Ceph的容错处理
对于Ceph文件系统,错误分两类:一类是磁盘错误或者数据损坏( disk error or corruptted data), 这类错误OSD会自己报告和处理。(self report ); 第二类是OSD失去网络连接导致该OSD不可达(unreachable on the network)这种情况下需要主动检测(active monitor),在同一个PG组中的其它OSD会发心跳信息互相检测。 这种检测的一个优化的方法就是,当replication复制操作时,就可以顺带检测,不用发单独的消息来检测,只有一段时间没有replication 操作时,才发ping消息里检测。
OSD的失效状态有两种:一种是down状态,这种状态下,被认为是临时错误。 在这种情况下,如果是primay,其任务由下一个replicate接手。如果该OSD没有迅速恢复(quickly recovery),那么就被标记为out状态,在这种状态下,将有新的osd加入这个PG中。
如何标记一个OSD 从down状态 标记为out状态?由于网络分区的问题,需要通过 Ceph Monitor 来裁定。
Ceph 的写流程
客户端先写主副本,然后同步到两个从副本。主副本等待从副本的ack消息和apply消息。当主副本收到ack消息,说明写操作已经写在内存中完成,收到apply 消息,说明已经apply到磁盘上了。
如果在写的过程中,主副本失效,按顺序下一个从副本接管主副本的工作,这个时候是否返回给客户端写正确?在这种情况下,客户端只是判断正常工作的(acting)的 OSD的返回结果,只要所有正常工作的OSD返回即认为成功,虽然这时候可能只有两副本成功。同时该临时primay必须保存所有操作的recovey队列里,如果原primay恢复,可以replay所有recovery队列里的操作,如果主副本从down到out状态,也即是永久失效,临时primay转正,由临时primay为正式primay,只是需要加入一个新的OSD到该PG中。
如果是从副本失效,就比较简单。临时失效,主replay所有写操作,如过永久失效,新加入一个OSD到PG中就可以了。
恢复
当有OSD失效,恢复或者增加一个新的OSD时,导致OSD cluster map的变换。Ceph处理以上三种情况的策略是一致的。为了恢复,ceph保存了两类数据,一个是每个OSD的一个version,另一个是PG修改的log,这个log包括PG修改的object 的名称和version。
当一个OSD接收到cluster map的更新时:
1)检查该OSD的所属的PG,对每个PG,通过CRUSH算法,计算出主副本的三个OSD
2)如何该PG里的OSD发生了改变,这时候,所有的replicate向主副本发送log,也就是每个对象最后的version,当primay 决定了最后各个对象的正确的状态,并同步到所有副本上。
3)每个OSD独立的决定,是从其它副本中恢复丢失或者过时的(missing or outdated)对象。 (如何恢复? 好像是整个对象全部拷贝,或者基于整个对象拷贝,但是用了一些类似于rsync的算法?目前还不清楚)
4)当OSD在恢复过程中,delay所有的请求,直到恢复成功。