【翻译】RADOS: A Scalable, Reliable Storage Service for Petabyte-scale Storage Clusters




RADOS:Reliable Autonomic Distributed Object Store

论文原文地址:https://ceph.com/wp-content/uploads/2016/08/weil-rados-pdsw07.pdf

翻译动机:看一遍没感觉,看两遍有点理解,翻译出来加上自己的思考才是真的有意义。

摘要

原文翻译略,简单写下自己对这篇论文的理解。

这篇论文主要介绍了RADOS存储系统的原理和设计思路,以及各个组件的用途和一批专用名词的概念,最后大概介绍了后续工作方向。这是一篇学术论文,所以比较格式化。

阅读这篇文章可以学到RADOS存储系统的基本原理和相关概念,配合其他Ceph相关文章或书籍(比如learning ceph)来学习,效果更佳。

1. 简介

对存储系统设计师来说,研发一套高可靠、高性能的存储系统一直都是一个巨大的挑战。文件系统、数据库及其他相关系统依赖的高吞吐、低时延的存储系统是保证各类应用性能的关键基础设施。构建于块、对象存储设备的新兴存储集群架构通过将底层块的分配决策、安全增强能力分散到智能的存储设备上,并让客户端直接访问数据,简化了数据布局并消除了IO瓶颈。对象存储设备通常都是由常见的CPU、网卡、带缓存的硬盘(或RAID)等组件构成,它提供的是用来存储可命名的变长对象接口,而非传统的块存储层接口(注:也即对象存储替换了传统的硬盘或SAN设备)。

但是,采用这种架构的系统大部分都不能很好的发挥底层存储设备的潜力(注:存储节点的计算能力)。传统存储系统(本地或SAN)甚至是符合T10 OSD标准的存储节点只用来响应读写命令,并读取或写入数据到存储器,尽管存储节点有很多的计算潜力。当一个存储集群增长到上千台甚至更多设备时,数据放置的一致性管理、故障检测、故障恢复等问题会给客户端、控制节点、元数据目录节点带来巨大的负担,从而限制住了集群的可伸缩性。

我们设计实现了RADOS–一个可靠的自动化分布式对象存储系统,它旨在利用设备智能,来分散围绕在由数以千计的设备组成的存储集群周围的一致性数据访问、冗余存储、错误检测、错误恢复等的复杂性。RADOS是Ceph分布式文件系统的一部分(注:RADOS是Ceph的核心),它使一个动态的异构存储集群中不断增长的数据和工作负载二者之间的均衡变得容易,同时它能给应用提供一个单一的对象存储视角(注:节点增加、退出对应用无感),并且还能提供定义良好的安全语义(注:IO接口比较规范的意思)和强一致性保证(注:数据一致性保证,任何情况下不会读取错误脏数据,但可能无法响应IO,根据CAP理论牺牲了可用性)。

PB级的存储系统必须是动态的,系统容量是逐步扩容上去的,或者各种原因导致的缩容,也会因为旧设备的故障、退役进行设备替换,因此会有大量数据的创建和销毁。RADOS通过带版本的集群地图(注:cluster map,我这里简单的翻译成集群地图,它是用来指引各方包括client、monitor、osd等找到数据对象存放位置的)来确保数据分布和对象读写的一致性(注:可理解为通过cluster map可确定对象的分布,找到并进行读写)。cluster map被各方复制(存储系统组件、客户端等),通过惰性传播来进行小步增量更新。

通过为存储节点提供完整的数据在系统中的分布信息,设备可以半自主地使用点对点协议来自我管理数据复制,持续安全地处理更新,参与故障检测,并对设备故障和由此产生的数据分布变化做出响应,并重新复制或迁移数据对象。这简化了管理主cluster map副本的monitor集群的负担,并通过它(注:monitor?)使系统无缝地从几十扩展到上千个设备。

我们的原型实现公开了一个对象接口,使用其可以以类似文件读写的方式读取或写入字节内容,这是Ceph的最基本需求。 数据对象在多个OSD中以n个副本保存以防止节点故障。 但是,RADOS的可扩展性决不依赖于特定的对象接口或冗余策略; 存储键/值对的对象和基于奇偶校验(RAID)的冗余方案都在考虑之中(注:当前Ceph中使用RAID貌似不推荐,应该没实现)。

2. 集群伸缩管理

RADOS系统由大量的OSD和少量的monitor节点组成,monitor节点是负责管理OSD集群成员资格的(该哪些OSD加进来、踢出去等)(图1)。每个OSD通常包含CPU、内存、网卡、磁盘(或RAID),monitor则是单独的进程,只需要少量的存储空间(注:实际上还需要占用少量CPU和内存资源)。

图1
图1

2.1  Cluster Map

管理存储集群的唯一方式是通过monitor集群修改cluster map,cluster map指明了集群中包含哪些OSD,并详细记录了数据在存储设备上的分布信息,每个存储节点(OSD)以及客户端(clients)都会复制一份cluster map(注:还要保持更新)。由于cluster map完整的指明了数据分布,客户端暴露的接口就可以对调用方屏蔽集群内部包含的成千上万的存储节点的复杂性和分布式特征,使调用方可以认为在跟一个对象存储系统打交道。

每次cluster map发生变化都会导致epoch增加,map发生变化的原因可能是由于OSD状态变化(设备故障)或者其他影响数据分布的事件(注:手工修改CRUSH rule、扩容OSD等)。map的epoch可以让互相通信的各方对系统当前的数据分布达成一致,还能确定谁的信息是过期的(相对其他节点来说)。cluster map变更会比较频繁,因为大型系统中OSD故障和恢复是非常常见的,更新也是与增量map类似的分布式进行的,两次成功的epoch的差异只需要很少量的信息就可以描述。尽管通常更新中会包含许多OSD,但大多数情况下,更新简单的记录OSD错误或恢复信息,并且相距较远的两次epoch的差异会进行更新信息的打包聚合,以减少更新消息的数量。

表1
表1

2.2  Data Placement

数据存放位置。

RADOS采用了一种伪随机分配对象到存储设备的数据分布策略(注:类似hash映射,但不是完全随机的),每当添加新的存储设备时,会随机选择现有的部分数据迁移到新设备以保存均衡。这种策略是健壮(鲁棒)的,因为它保持了数据在存储设备上的概率均衡分布,通常它可以保持所有设备的负载比较接近,因而可以使得系统在任何潜在的工作负载下运行良好[22]。更重要的是,对象数据存放位置的计算是分两步进行的,不需要大量复杂的中心化位置分配表(注:不需要专门的元数据节点来管理数据存放位置,使用CRUSH算法即可解决)。

系统中存储的每个对象都首先被映射到一个PG(placement group),PG是一个逻辑上的对象集合,PG中的对象会被复制多份保存到不同的存储设备上(注:以实现副本功能,保证数据可靠性,PG是管理副本的最小单元)。每个对象所在的PG由公式pgid = (r, hash(o)&m)确定,其中o为对象名称,r为副本数量,m可以控制系统中PG总数(m = 2^k – 1),&为按位与操作,将系统中PG总数限制为2的倍数。随着系统的容量伸缩,需要定期修改m的值以调整PG总数,这个过程是逐步完成的,这样就能保证每次伸缩后需要在不同存储设备间迁移的数据量可控。

根据cluster map设置,PG会分配到OSD,每个PG对应r个排序的OSD(r为副本数量)用来实现对象的副本存储。我们利用CRUSH(一种稳定的副本分布算法)计算出一个稳定的伪随机映射(注:从PG到OSD的映射),其他数据存放策略也是可行的,即使是用明确的表来管理每个PG到OSD的映射关系,在一个相当大的集群情况下这个表也是很小的(MB级别)。从高层次抽象来看,CRUSH与hash函数的行为非常类似:PG映射关系是确定的,但是符合伪随机分布。与hash函数不同的是,CRUSH的计算结果是稳定的:即使有一个或多个设备加入或离开集群,大部分PG到OSD的映射关系是不变的,CRUSH仅移动足够的数据来维持数据分布的均衡性。作为对比,hash方法则通常需要强制重组所有之前的映射关系。CRUSH还支持设置权重来控制每个存储设备上分配的数据量,权重的设置依据可以是设备的容量或性能等方面。

注:CRUSH是另一篇论文《CRUSH: Controlled, scalable, decentralized placement of replicated data》,后面有时间会翻译。

2.3 设备状态

OSD状态

cluster map包含设备的当前状态以及设备上的数据分布的描述,描述信息包含所有在线可连通的OSD的网络地址(up状态的OSD),也包含当前离线的OSD信息。RADOS还将另外一个OSD是否存活的维度考虑在内:in状态的OSD会映射到PG,out的不会。

CRUSH会给每个PG生成一个包含r(副本数量)个OSD的列表的映射关系,RADOS之后会把down状态的OSD过滤掉,只保留活跃的OSD给PG使用。如果活跃的OSD列表为空,那么PG里面包含的数据就处于临时不可用状态,所有访问这些数据的IO操作都被阻塞(注:处于IO hang状态)。

OSD通常都处于up/in状态,可以正常提供IO服务,或者出于down/out状态,从而生成包含r个OSD的精确列表。

OSD也可能处于down/in状态,这种状态意味着OSD处于不可连通状态,但是PG里面的数据还没来得及重新映射到其他OSD(与RAID的降级模式类似)。同样的,OSD也可能处于up/out状态,意味着OSD在线但是空闲(注:未真正加入集群,没有PG分配过来)。OSD之所以有这些状态值,是为了让集群应对网络波动、OSD重启等场景时,可以不执行数据迁移操作,还可以在新存储节点上线时不必立即启用他们(比如为了提前测试网络连通性等),也可以帮助实现旧设备下线过程中安全的数据转移。

2.4 map传播

由于RADOS集群可能包含上千个OSD甚至更多,所以简单的广播cluster map的更新到各个OSD是不现实的。幸运的是,只有同一个PG内的OSD或者OSD和client之间才需要互相就cluster map的epochs达成一致,这是因为同一PG内的r个OSD需要选出一个主OSD来处理IO请求。从这方面来说RADOS可以利用OSD之间通信的机制来进行cluster map的惰性更新,从而将cluster map更新相关的负载下放到各个OSD上。

每个OSD都维护一份cluster map增量更新的历史记录,所有消息都带有最新的epoch标记,当OSD与其他OSD通信时都会对最近的epoch进行跟踪。如果一个OSD接收到另外的OSD消息时发现其map的epoch版本比较老,则当前OSD会把增量更新分享给它以便让他同步到新版map。类似地,当主动发消息给其他OSD时,如果发现对端map的epoch版本比较老,也会触发cluster map的增量更新流程(注:不管是主动还是被动通信,如果发现对端版本较老都会同步cluster map)。同时,用于错误检测(见3.3节)的OSD定时心跳消息也会携带map信息,以确保map更新以O(log n)的收敛速度快速扩散到整个集群的n个OSD。

举例来说,当一个OSD第一次启动时,它会发送一个OSD启动的通知给一个monitor(见第4节)表示它上线了,这个启动消息包含了OSD本地最新的map epoch版本号。之后monitor集群会把这个OSD置为up状态,并把cluster map的增量更新信息发送给OSD,以便确保它获取的是最新的版本。当这个新的OSD开始与和他共享数据的OSD建立联系时(见3.4.1节,注:新的OSD分配了PG,其他OSD是一起保存对象的多个副本),受这个新OSD的状态变更影响的精确OSD集合会学习到恰当的cluster map更新(注:同一个PG的多个OSD副本之间互相建立关系时保持一致的map版本)。由于OSD启动时不清楚对端的OSD保存的map epoch,所以它会分享至少最近30秒的增量更新历史版本给对端。

这种抢占式的map共享策略是保守的:一个OSD会一直跟对端(注:对端表示同一个PG的多个副本所在的OSD)共享map更新,除非它确信对端已经获取到这个更新,这就导致OSD会接收到重复的map更新信息(注:相同的map更新信息一个OSD收到多次)。但是,一个OSD接收到的重复信息的数量会受到对端数量的限制(注:也即副本数量),因此也受限于一个OSD上包含的PG数量(注:副本数量一定的情况下,一个OSD上PG数量越多,接收到的重复消息越多)。在具体实践中我们发现OSD真正接收的重复更新消息数量是比上述理论值要少很多的(见5.1节)。

3. INTELLIGENT STORAGE DEVICES

智能存储设备(注:意思赋予了OSD计算能力,可以用来处理数据副本、错误检测、错误恢复)

cluster map包含的数据分布信息可以让RADOS将数据冗余备份、错误检测、错误恢复等方面的能力分散到组成存储集群的各个OSD上。在一个高性能的集群环境中,通过点对点类似的协议可以很好的利用OSD的计算能力。

RADOS当前为每个PG实现了n路复制(注:多副本功能)、对象版本和短期日志(注:应该是指journal功能)功能。复制是有OSD自身负责执行的:客户端提交一个单独的写操作到主OSD,之后主OSD会负责一致、安全地更新到所有副本(注:同一个PG内的其他OSD)。这个设计将副本相关的带宽转移到了存储集群内部网络,并且简化了客户端的设计(注:不需要考虑副本问题)。对象版本和短期日志功能则使存储节点间歇性故障场景(如网络断开或节点宕机/重启)下的恢复变得更快。

我们在这一大节内容中会主要描述RADOS的架构,特别是cluster map相关的架构,因为它是实现分布式副本和恢复操作,以及这些能力可以适用于其他副本机制(如基于奇偶校验的RAID)的关键。

3.1 副本

RADOS实现了3种副本方案:primarycopy [3],chain [26],以及一个我们称之为splay的混合方案。图2展示了一次更新操作(注:写IO)的消息交换流程,在所有方案场景下,客户端发送IO操作到一个OSD(每次IO操作对应的OSD可能是不同的),存储集群会确保副本被安全的更新并且读写语义的一致性(如经过序列化)会被保留。当所有副本都被更新之后,会返回一个通知消息给客户端。

图2
图2

Primary-copy副本方案会并行更新所有副本,并且读和写请求都在主OSD上处理。Chain副本方案则是顺序更新所有副本:写操作发送到主OSD处理,读操作则在最后的副本上进行(注:更新顺序是从主到从,从头到尾),以此来确保读操作总是获取完整更新过的副本内容(注:所有副本都更新过了才放行读操作)。splay副本方案则简单的把primary-copy方案的并行更新机制以及chain方案的读写角色分离结合在一起,其主要优点是2路镜像场景(注:应该是说2副本情况)下的消息交换数量比较少。

3.2 Strong Consistency

强一致性

包括client以及其他OSD生成的所有的RADOS消息都会被加上map的epoch标记,以此来确保所有更新操作都能被完整一致的实施(注:这句话没太理解,感觉应该是说有了版本号才知道最新的数据分布,不会导致数据更新不一致)。如果一个客户端由于其拥有的map是过时的而发送了一个IO请求到错误的OSD上,OSD会把map的增量更新返回给客户端,之后客户端就可以重新发送请求到正确的OSD。这就避免了主动推送cluster map更新到客户端的需求,因为客户端可以在与存储集群交互过程中获取到map的更新。大部分情况下客户端都可以在不影响当前IO操作的同时把之后的IO重定向到正确的OSD。

如果cluster map的主副本已经更新并影响到一个PG的成员关系,PG的成员还没有得知map的更新,对象更新可能被PG的旧成员处理。如果map的变更首先被PG中的某个非主副本得知,则当主副本所在的OSD转发更新IO操作到次副本或其他副本时,次副本会把新的map更新返回给主副本。这个流程是安全的,因为map更新后PG对应的新OSD集合需要首先与PG之前对应的旧OSD集合建立联系,以便确定PG正确的数据内容,这就确保了之前的OSD可以得知map更新,并停止执行IO操作直到新的OSD启动。

让读操作达到与更新操作类似的一致性会更加复杂,在类似网络断开导致一个OSD只能被部分节点连通的场景下,这个OSD不应该为可以连通它的使用旧的map的客户端提供PG读操作。同时,更新后的cluster map会指定一个新的OSD来替换这个异常的OSD,为了在更新操作被新OSD接管后阻止任何读操作被旧的OSD处理,我们需要在PG的OSD之间保持周期性的心跳消息,以便确认OSD是否存活从而保证PG是可读的,具体策略是,当一个提供读操作的OSD超过H秒都没有收到PG内其他副本的心跳消息,则它会暂停提供读操作(注:因为写操作需要从主OSD转发到各个从OSD,已经保证了各个OSD都要在线才能执行,而读操作则不然,可以在PG的任何OSD上执行,因此需要叠加OSD心跳机制来保证PG的读操作可执行)。在一个OSD接管PG的主OSD角色之前,它必须要么获取到旧OSD主动发送的确认消息(确保旧OSD知道他们的角色变化),要么继续等待H秒。在当前的实现中,我们设置了一个比较短的心跳间隔(2秒),这保证了错误检测周期很短,也保证了PG的主OSD异常时PG里数据不可访问的持续时间较短。

3.3 Failure Detection

错误检测

RADOS实现了一个异步的、顺序的点对点消息传递库用来传递消息,TCP错误导致的消息传递失败会进行有限次数的重连尝试,重试无效会将错误信息上报到monitor集群(注:消息传递的一端网络异常、节点异常等场景会进行消息重发)。同一个PG内的存储节点(OSD)之间周期性的交换心跳消息以确保OSD异常可以被检测到,当OSD发现它被标记为down状态之后,会在执行数据落盘操作之后自杀,以确保数据一致性。

3.4 Data Migration and Failure Recovery

数据迁移和错误恢复

RADOS数据迁移和错误恢复是完全由cluster map的更新以及由此引发的PG到OSD映射变化驱动的,这种变化可能是由于设备(注:此处设备指代OSD)故障、恢复、集群扩缩容,甚至是由于CRUSH副本分布策略更新导致的整体数据重新分布引发,有众多可能原因会导致存储集群建立新的数据分布,设备错误是其中最简单的一个。

RADOS不对两个map之间的数据分布做任何连续性假设(注:map更新前后可能导致数据分布变更),在所有情况下,RADOS采用健壮的对等算法来建立PG数据一致性视图,也是用该算法来恢复数据的恰当分布和副本。这种策略依赖一个基本的设计前提:即使本地对象副本丢失,OSD可以主动复制PG的日志,这个日志记录了PG的当前应该保存的内容(例如保存的对象版本为何)。因此即使恢复比较慢、对象的安全性在一段时间内降级,PG的元数据是会小心保管的,这就简化了恢复算法,并且使得系统可以可靠地检测出数据丢失。

3.4.1 Peering

结对(注:同属一个PG的各OSD之间进行结对)

当一个OSD接收到cluster map的更新后,它从远及近地遍历所有新的增量更新,检查并可能会调整PG状态值,所有本地保存的PG的在线OSD列表发生变化后都会被标记为需要重新结对。顾及到所有map epoch而不是最近一个是为了确保所有中间数据分布的变化也被考虑在内:如一个OSD被从PG中移除后又再次加入该PG,了解PG内容中间更新过程可能已经发生是很重要的(注:这部分没太理解,应该是说cluster map多次更新可能导致数据分布发生了变化,但cluster map最终并没有发生变化,所以为了保证数据一致性,需要确保每次map的更新都被正确处理)。类似副本过程,结对过程以及随后的数据恢复过程也是在每个PG中各自处理的。

结对过程是由PG的主OSD发起的,对于OSD保存的每个PG来说(注:一个OSD上有多个PG,OSD在一个PG里可能是一个副本OSD,也可能是一个已经离线的OSD),如果OSD不是PG的主OSD,那么它就会发送一个通知消息给PG当前的主OSD,消息内容包括OSD本地保存的PG的基本状态信息,最新的map更新,PG log的边界,以及PG成功结对后最近获知的epoch。通知消息确保PG里一个新的主OSD可以发现它的新角色,而不必为每次map变化考虑所有可能的PG(可能是数百万个)(注:这段应该是说map变化只影响涉及到的PG,而与其他PG无关)。一旦意识到角色变化,主OSD会生成一个优先集合,集合包含了参与PG的所有已成功结对的OSD,通过显式查询优先集合之后会给集合中的每个OSD请求一次通知消息,以避免无限等待一个实际没保存这个PG的OSD(例如对于中间状态的PG映射结对永远无法完成)(注:这部分没太看懂,是说主OSD会主动发消息给PG内其他OSD并让他们回复,以便完成结对?结对过程是要两方都确认才算真正结对成功?)。

有了整个优先OSD集合的PG元数据,主OSD可以确定已应用到每个副本的最近更新,并且向优先OSD请求任何PG日志的片段以便使得所有在线副本OSD的PG日志同步到最新。如果可用的PG日志不足(例如一个或多个OSD没有任何PG的数据),则会生成一个完整PG内容的列表(注:这句没看明白,生成这个列表有啥用?是说数据不完整的也会记录起来?之后怎么处理呢?)。但是对于节点重启或者其他短时间的中断情况来说,这个流程是不需要的,最近的PG日志就足以快速地重新同步所有副本。

最后,主OSD会将丢失的日志片段共享给副本OSD,之后所有副本就都知道了PG应该包含的对象(即使这些对象可能在OSD上不存在),并且在后台进行数据恢复的同时开始处理IO请求。

3.4.2 Recovery

分组副本(declustered replication)一个关键优势是可以进行并行故障恢复,一个故障OSD的相关副本是分散到多个其他OSD的,故障OSD加入的每个PG会独立的选择一个替代品,让副本重新复制到替代OSD。一般来说,在一个大型系统中,介入一次故障恢复过程的OSD只会在一个PG上获取或推送数据内容,这使得恢复过程非常快速。(注:这段是说一个OSD挂了,则PG会找一个新的OSD替代它,这个OSD会把挂了的OSD的数据副本同步过来,同步过程是从挂了的OSD加入的所有PG包含的其他OSD上获取数据,而其他OSD则是推送数据给替代OSD,因此每个介入恢复过程的OSD–非替代OSD–都只负责一个PG的数据恢复,大型系统的PG比较分散,参与恢复过程的两个OSD包含同一PG的概率比较低)

RADOS的故障恢复是在观察到IO操作经常性被读吞吐量限制后激发的(注:上面讲过,OSD心跳超时后读操作会被block,但为啥不是观察写入被限制呢?)。尽管每个独立的OSD配合PG元数据都可以单独的获取丢失的对象,这个策略仍然有两个局限性,首先是同一PG的多个OSD独立恢复对象过程中,它们不一定会同时在同一批OSD拉取同样的对象,这就引出了恢复过程代价最大的问题:寻址和读数据;其次是当副本OSD丢失了被修改的对象时,副本更新协议(见3.1节)就变的更加复杂(注:IO写入过程要在每个副本OSD完成后才返回给客户端,如果一个副本OSD没有这个写IO操作的对象,则需要进行特殊处理才行,比如要先把副本同步过来才能继续执行写操作,本次写IO返回执行失败结果给客户端?)。

基于上述原因,RADOS的PG数据恢复是由主OSD协调的,如前所述,操作主OSD丢失的对象时会被阻塞直到主OSD同步对象数据到本地,由于主OSD通过结对过程已经知道所有副本OSD丢失的对象信息,所以它就可以主动推送丢失任何即将被修改对象到副本OSD,这就简化了副本同步逻辑,同时也保证了存活的副本只需要被读取一次(注:被主OSD读取一次之后主动推送到副本OSD)。在主OSD推送对象(注:客户端通过主OSD获取对象)或者为自己拉取对象过程中,它会在对象还在内存中时将对象推送给所有需要这个对象的副本OSD,因而总体上每个被恢复副本的对象仅会被读取一次。

4. MONITORS

一个小的monitor集群通过保存cluster map的主副本,并定期更新以响应配置更改或OSD状态更改(例如,设备故障或恢复),来共同负责管理存储系统。该集群部分基于Paxos part-time parliament[14],旨在支持一致性和持久性,而不是可用性和更新延迟。 值得注意的是,必须在多数monitor可用时才能读取或更新cluster map,并保证做出的更改的持久性。

4.1 Paxos Service

monitor集群是基于Paxos算法实现的分布式状态机服务,其中cluster map是当前机器状态,map每次成功更新都会产生新的epoch。我们的实现通过一次只允许一个并发map变更来简化标准Paxos(与[17]类似),同时将基本算法与租约机制相结合,允许将IO请求发给任何monitor节点并且仍能确保IO读取和更新操作的一致性。(这个功能已经被实现为通用服务,它还被用来管理Ceph的全局数据结构,其中包括用来协调客户端访问存储系统的MDS的cluster map和状态)

monitor集群会初始选举出一个leader并由它来负责序列化cluster map的更新和管理一致性。leader一旦被选举出来就会向每个monitor节点请求map的epoch,monitor节点需要在固定时间T内(目前T为2秒)做出回应并加入选举的法定人数。如果存活的monitor占多数,Paxos算法的第一阶段保证每个monitor拥有最近提交的cluster map epoch(可以向其他monitor按需请求cluster map的增量更新),之后开始给每个monitor发布短期租约(注:意思是每个monitor都是最新的map了,就可以开始对外服务了,但是为了保证map的时效性、对象数据的一致性,需要增加租约有效期限制,租约过期了就需要重新获取map和续租)。

在每个租约有效期内的存活monitor被允许分发cluster map的副本给请求cluster map的OSDs或者客户端,如果超出租约有效时间T都没完成续约,则认为leader monitor已经死亡,然后发起新的选举。每个monitor的租约都需要通过发送收据通知给leader monitor来确认,如果一个租约发布后leader没有及时接收到某个monitor节点的确认消息,leader节点会假设这个monitor节点已经死亡,并发起一次新的选举(建立新的选举法定人数)。当一个monitor第一次启动时,或者发现之前发起的选举在合理时间段内没有结束,就会发起新的选举。

当一个正常的monitor节点接收到一个更新请求(如有错误发生)(注:更新请求是指请求获取map更新),它会先检查这个请求是不是新的,举例,如果发送更新请求的OSD已经被标记为down,那么monitor会简单的恢复必要的增量map更新给OSD让它保存的map保持最新版本,而如果是有新的错误发生则会转发给leader monitor节点,由它负责聚合多次更新。leader monitor会通过增加map epoch来定期发起map更新,并利用Paxos更新协议将更新提案分发给其他monitor节点,与此同时还会撤销之前的租约。如果更新被多数monitor节点确认,leader节点最终提交map信息并生成一个新的租约(注:Paxos协议的第二个阶段)。

同步两阶段提交和探测间隔T的组合使用可以确保如果monitor的存活集合发生变化,所有之前的租约(还在有效期T内)都会在任何后续的map更新发生之前过期。因而,只要多数monitor节点可用,任何顺序的map查询和更新会导致map版本的一致性前进(持续增加版本号),无论消息发给哪个monitor、不管monitor发生什么故障,版本号都不会倒退。

4.2 Workload and Scalability

工作负载和可扩展性

一般情况下,monitor做的事情非常少:大部分map分发都是OSD节点处理的(见2.4节,注:通过PG的OSD结对机制来搞定),而OSD状态变化(如由于设备故障)通常都不频繁。

monitor集群内部使用的租约机制可以允许任何monitor节点处理来自OSD的读IO请求或者来自客户端的获取最新的cluster map请求,这些请求很少由OSD发起,因为它们有主动map共享机制,而客户端请求map更新仅会在检测到OSD发生操作超时错误时才会执行,对于大型存储集群,可以通过扩容monitor集群来分散它们的工作负载。

获取新map的请求(如OSD启动通知或首次上报故障)会被转发到leader monitor,leader会聚合多次map变更到一个map更新,因此map更新的频率是可调的,并且与存储集群的大小无关。尽管如此,最严重的负载会发生在短时间内大量OSD出错场景下,如果每个OSD上面有µ个PG,同时有f个OSD出错,则在一个大型OSD集群经历一次部分网络中断故障时,最多会有µ*f个错误报告会产生(注:每个OSD上的PG都完全不同的场景),这个数字可能非常庞大。为了防止这种消息泛滥问题,OSD在半随机间隔内发送心跳用来将检测到OSD故障的时间错开,之后对错误上报消息进行限流和批量化处理,这样就可以让monitor集群的负载与存储集群大小成比例关系。非leader monitor节点之后仅转发一次错误报告消息(注:转发前会检查是否已经转发过,只转发那些没转过的消息),因此leader节点的负载与f*m成比例关系(m为monitor节点数量)。

5. PARTIAL EVALUATION

这是一个专有名词,不知道怎么翻译,参考资料:

利用起来每个OSD的对象存储层的性能在Ceph那篇文章[27]中已经被测量过,类似地,CRUSH的数据分配性能以及他们对集群吞吐量的影响也被评估过[27,28]。在本篇文章中我们仅聚焦在map分发性能方面,因为这个问题对集群伸缩能力有直接影响,尽管我们在架构上对系统的可扩展性有信心,但我们还没有通过实验评估monitor集群的性能表现。

5.1 Map Propagation

RADOS map分发算法(见2.4节)确保map的更新可以在logn跳内到达所有OSD,然而随着存储集群扩容,设备故障以及与此相关的集群更新的频率也会增加,由于map更新仅在同一PG内的OSD之间交换,一个OSD能接受到的同一个map更新的次数上限与µ成比例关系(µ是OSD上PG数量)。

在定期进行map更新情况下的接近最差map传播环境的模拟场景下,我们发现即使在指数级集群扩容场景下map重复更新(注:传播的更新数与实际更新数的比值)也是接近稳态的,在模拟实验中,monitor会分享map到一个随机的OSD,之后OSD会把map分享给PG里的其它OSD。图3展示了我们通过调整集群大小x以及每个OSD上的PG数量(对应每个OSD有几个对端),得出的一个OSD接收的重复map更新消息数量y。map更新的重复消息量接近一个常量,少于µ的20%,即使集群大小成指数级扩展,也只会产生固定的map分发开销。我们还考虑了一种最差场景,让一个OSD频繁的上下线,导致其获取map更新非常慢(更新已经被它的对端获取),这种情况下map分发的开销只依赖于map更新频率限流情况,而这种限流monitor集群已经做了。

图3

图3

6. FUTURE WORK

我们当前已经实现了一个工作良好的对象存储系统,这个系统是Ceph分布式文件系统的基础,但这个对象存储系统提供的可伸缩集群管理服务不仅能满足Ceph的需求,而且还更加通用,我们还有很多额外的方向需要进一步研究。

注:第6节内容与RADOS关系不太大,就简单的翻译下。作者提到了一些考虑到的后续研究方向,实际上应该很多都没做,这也是写论文的常见套路,主要是为了说明论文内容的普适性和可持续性。

6.1 Key-value Storage

这里应该是说RADOS当前只用来存储对象,实际上它还可以用来保存key-value键值对,实现类似mongodb、memcache、redis等NoSQL数据库的功能。

6.2 Scalable FIFO Queues

基于RADOS实现一个可伸缩的先进先出队列服务。

6.3 Object-granularity Snapshot

对象粒度的快照功能。这个需求是Ceph需要的。

6.4 Load Balancing

热点对象的负载均衡,场景是大量客户端同时访问同一个对象,会导致这个保存这个对象的OSD节点负载很高。这确实是一个值得研究的方向,问题很有现实意义。

6.5 Quality of Service

QoS,保证故障恢复期间客户端的IO操作性能不受大的影响或者受影响的程度可控制,这也是一个值得研究的方向,也是Ceph社区当前的重点改进方向。

6.6 Parity-based Redundancy

基于奇偶校验的冗余,我理解应该是研究除了副本冗余策略之外的其他策略,Ceph当前已经实现了EC纠删码冗余策略

第7节是相关工作,第8节是小结,都是科研论文的一般讨论,就不再翻译了。另外还有最后的参考文献也不列出来了,有需要可以参考论文原文。

后面有时间我会把剩下的两篇论文也翻译下:

  • CRUSH: Controlled, scalable, decentralized placement of replicated data
  • Ceph: A scalable, high-performance distributed file system(2018-04-24更新:这篇看了下,只讲了MDS相关的,感兴趣的rbd相关的没看到,就不翻译了)