分布式存储的架构、隐患及解决方法

Raid和副本

把磁盘们相同偏移量的一块空间横向进行分割,组成一条逻辑上存储空间。

数据是先写满一条条带,再写下一条条带。一个卷可以有很多条条带组成。条带的划分应该的磁盘配置初级就完成。条带包含扇区(或块)的个数叫条带长度;每个磁盘内包含属于这个条带的扇区(或块)的个数叫条带深度。

为什么要引入条带的概念呢,是因为要解决单个磁盘一次只能同时并发一个IO和保证数据完整性。

本文福利, 免费领取Linux C/C++ 开发学习资料包、技术视频/代码,1000道大厂面试题,内容包括(C++基础,网络编程,数据库,中间件,后端开发,音视频开发,Qt开发,游戏开发,Linux内核等进阶学习资料和最佳学习路线图)↓↓↓↓有需要的可以进企鹅裙927239107领取哦~↓↓

我们知道磁盘的IO实际上是磁盘寻找对应扇区地址的过程,是在磁片旋转和磁头在机械臂的控制下横向寻道的结果,而且一个磁盘一次只能完成一个IO申请,而通过条带的方式可以让多个磁盘一起协同完成任务,这种方法叫做raid0。

从理论上看磁盘越多,条带深度越小,速度就越快。

但是也不是条带深度越小速度就越快,因为深度太小,并发的概率就降低了。没有了并发,就不会提高速度了。所以一般来说当随机的小块IO多,就适当加大条带深度,当顺序的大块多,就减小条带的深度。Raid0体现的是人多力量大的哲理。

但是如果raid0的方式下有一块磁盘出现故障了,那数据的完整性被破坏了,数据不可用了。为了确保数据完整性,所以就有了raid1。

raid1就是将一份数据写到2个物理磁盘上,即数据有镜像,二数据副本。就算坏了一块盘也不会导致数据不可用。和单块盘比Raid1方式写的慢,读快,道理很明显。

将raid0和raid1组合起来,就可以吸取各自的优点,但是要注意组合的顺序,raid10比raid01冗余度高、数据更安全,如图:

当左边的raid10系统有一块故障,底层数据是做raid1镜像的,数据的完整性没有被破坏,还可以再坏一块另外raid1组的一个磁盘。

而raid01,当底层的raid0组的磁盘坏掉一块,整个raid0组数据就无效了,所有的IO都会到剩下的raid0组,并且如果再坏一块盘,整个数据就无效了。

Raid5和raid6也是常用的raid方法。

  • Raid5最少需要3块盘,有1个数据副本和1个数据校验;即最多可以坏1块盘;
  • Raid6最少需要4块盘,有1个数据副本和2个数据校验,即最多可以坏2块盘。

这些数据副本和数据校验都均匀的打散在磁盘中。Raid5和raid6的磁盘利用率最低为66.7%和50%,是兼顾利用率和性能的方案。Raid6的安全性比raid5更好,性能差别不大。

Raid都有一定的计算量,来决定这些数据块存放的磁盘、计算出校验数据,或根据校验数据计算出数据。这些都需要CPU和内存资源。为了减少对主机CPU和内存的压力。现在一般在主机的PCI总线上配置raid卡,硬盘都连接在raid卡下。

Raid 卡其实就是一台小型的计算机,有CPU、内存和缓存,减轻了主机的负担。但是raid卡不能跨越主机,所以在分布式存储中,网络raid就不能利用本地的raid卡,只能用主机的CPU和内存。

综合各种因素,分布式存储一般都采用副本的方法。

分布式存储的架构

一般来说,分布式存储不管是文件存储、对象存储还是块存储的基本架构都是大同小异的。即客户端或应用端、元数据(MDS)服务器和数据节点服务器。

客户端和元数据服务器之间交互是“信令交互”,而客户端到数据节点是“媒体交互”。元数据服务器或通过数据节点服务器获取各节点服务器的基本配置情况和状态信息。

比如,客户端需要读取某一个文件的信息,客户端会将相应的要求发给元数据服务器:“喂!我需要XXX,存在哪里了”,元数据服务器查询后回答“你到xxx服务器的xxx地址+xxx服务器的xxx地址取”。

客户端拿到这个指示后,向这2台服务器发出指令,数据节点获得指令后,将相应的数据返回给客户端。

大家可能都会奇怪,为什么块存储、对象和文件的架构都是一样的。有什么区别呢?

我们在前面基础知识讲述中,块存储是一种裸设备,它是将存储设备以“块”的方式直接提供给客户,由客户自己的操作系统里的文件系统进行管理。

  • 分布式块存储里是没有文件系统的,是通过客户端直接将最简单明了的命令传递给存储的“块”来执行。
  • 对象存储和文件存储虽然结构类似,但并不将存储底层的“块”直接提供出来,而是通过隐藏着一个文件系统,包装成为“文件”或“对象”提供出来。

这些存储“不挑”操作系统或终端,最终执行命令的是存储里面的文件系统操控存储执行的,所以共享性很好。

文件存储通过“目录+文件名+偏移量”来检索,文件间有目录层次的;

而对象存储采用“唯一对象ID+偏移量”来检索,对象扁平存储的,是没有层次的。而且块、对象、文件存储是可以相互转换的,这个问题以后单独讲。

华为的FusionStorage是一个典型的“块”存储,我们来了解一下结构。

FusionStorage也分成了MDC、OSD和Client三部分。和其他分布式存储重大的差别是:

MDC是记录、更新OSD服务器、磁盘等的状态,并把这些状态数据实时同步给Vbs,由Vbs计算出来数据所落的位置。MDC可以单独部署,也可以集中部署,也可以分布部署。

如果MDC全出现故障,并不会影响存储的正常运行。

但是如果在MDC故障期间OSD的状态发生了改变,比如某块磁盘故障,就会导致部分IO访问不正常。所以一般MDC部署在3台OSD上,确保安全。

一般分布式存储的MDC采用的是数据库或内存储数据库来记录数据块和物理位置关系。客户端向MDC发出询问位置的请求,MDC查询数据库后返回请求数据的存储位置。

这种方法存储访问的速度较慢,而且MDC作为交通的“枢纽”,绝对是整个存储的核心,当MDC发生故障,会导致整个存储都不能使用。但是采取这个方式,也有好处,比如可以根据不同需求设置不同的副本策略等。

VBS是计算数据块存储位置的重要网元。一个VBS就是一个“机头”。VBS部署很灵活,有很多种部署方法,可以根据不同的需求进行选择。

比如,在VMWARE虚拟机中,可以在物理机上开设一台虚拟机部署VBS,在XEN/KVM部署在domain0上;或者部署在每台OSD服务器上,或专门设置VBS服务器群。

VBS采取一致性哈希算法,如图3,将数据块的逻辑地址计算出KEY值。并将计算出来的KEY映射到哈希环上,在哈希环上划分了N段(Partition),每个Partition对应一个硬盘,并根据出partition主和osd节点的映射关系ioview,和partitio主备对应的osd关系,得到该数据块的路由,如图4。

在写入的时候,采用强一致性,即当主和备副本都返回写成功后,才认为这个IO写成功了。读IO时只读主副本,当主副本故障的时候,会在备副本中选举出主副本。目前,一个资源池可以支持2000块硬盘。

操作系统看到的连续的数据逻辑地址(LBA),实际上被打散到资源池内所有硬盘上了,类似所有硬盘都做了raid0,这样就利用了所有磁盘的性能,提高了存储的性能。

操作系统实际是直接读写物理磁盘的块,并没有封装额外的文件系统,是一个raw设备。

OSD是一台插了较多硬盘的X86服务器,我们采用的是12块SATA 3T的硬盘作为数据的持久化存储介质。

如果VBS不承载在OSD上,那么OSD服务器的计算压力实际上很小,也没有必要配置计算能力很强、内存配置很高的服务器。

上一篇文章计算过,12块SATA盘提供的iops或吞吐量其实很有限,需要配置SSD作为缓存,加速存储的性能。由此看来,分布式存储的性能是由SSD的性能和热点数据计算算法决定的。

和一般存储不同,一般分布式存储的写性能会好于读性能。主要是主和备副本写入SSD就返回成功了,而SSD什么时候写入硬盘,怎么写入硬盘,客户端是不知道的。

而读数据的时候,如果数据是热点数据,已经在缓存在SSD上,性能会很好,如果没有在缓存中,就需要到硬盘中直接读取,那性能就很差了。

这也是当分布式存储在初始化的时候,测试性能指标不如运行一段时间后的指标。所以测试分布式存储有很多陷阱,大家要注意。

为了提高存储的安全性,达到6个9以上的安全性,我们采取的是通行的3副本(2副本在96块盘以下,可以达到6个9)。副本可以根据实际情况设置成为在不同机架、不同服务器、不同硬盘的安全级别。

当磁盘或主机故障,会被MDC监控到,会选举主副本、踢出故障点、重构副本等操作。为了确保数据的安全,副本重构的时间很关键,我们要求,每T数据重构时间不超过30分钟。

为了确保数据重构流量不影响正常存储IO访问流量,实现快速数据重构。我们没有采取华为推荐的网络方案,而是采用环形虚拟化堆叠的方案,交换机间的堆叠链路采用40G光路,如图

将存储的重构流量都压制在存储环形网络中。交换机到服务器采用2*10G连接,可以根据情况采用主备或分担的模式。

说过了“块”存储,再简单了解一下“对象存储”。

对象存储是在同样容量下提供的存储性能比文件存储更好,又能像文件存储一样有很好的共享性。实际使用中,性能不是对象存储最关注的问题,需要高性能可以用块存储,容量才是对象存储最关注的问题。

所以对象存储的持久化层的硬盘数量更多,单盘的容量也更大。对象存储的数据的安全性保障也各式各样,可以是单机raid或网络raid,也可以副本。

对性能要求不高,可以直接用普通磁盘,或利用raid卡的缓存,也可以配些SSD作为缓存。我们现在使用单机35块7200转4T SATA盘+raid卡缓存加速的自研对象存储,并计划在今年使用60块7200转8T SATA盘。即每台服务器提供480T的裸容量。

Ceph和google基于GFS的存储就是典型的对象存储。

Ceph是目前最为热门的存储,可以支持多种接口。Ceph存储的架构和华为的FusionStorage异曲同工,都是靠“算”而不是“查”。

  • 一种是为数众多的、负责完成数据存储和维护功能的OSD。
  • 另一种则是若干个负责完成系统状态检测和维护的monitor。

OSD和monitor之间相互传输节点状态信息,共同得出系统的总体工作状态,并形成一个全局系统状态记录数据结构,即所谓的cluster map。这个数据结构与特定算法相配合,便实现了Ceph“无需查表,算算就好”的核心机制以及若干优秀特性。

但数据的的组织方法是不同的。首先ceph的核心是一个对象存储,是以对象为最小组织单位。

1、首先文件是被映射成为一个或多个对象。

2、然后每个对象再被映射到PG(Placement Group)上,PG和对象之间是“一对多”映射关系。

3、而PG会映射到n个OSD上,n就是副本数,OSD和PG是“多对多”的关系。

由若干个monitor共同负责整个Ceph集群中所有OSD状态的发现与记录,并且共同形成cluster map的master版本,然后扩散至全体OSD以及客户端。

OSD使用cluster map进行数据的维护,而客户端使用cluster map进行数据的寻址。

Google三大宝之一的“GFS”是google对象存储的基础。

核心不同是数据的组织架构:master服务器(即元数据服务器)保存了文件名和块的名字空间、从文件到块的映射、副本位置,由客户端来查询。是一个典型的信令和媒体分开的架构。

分布式存储存在的问题

分布式存储一般情况下都是靠“副本”来确保数据的安全性和完整性。每块盘记录的数据内容都不一样,当某一块盘出现问题,都需要从其他不同盘内的数据块中进行快速的数据重构。

数据重构是需要时间的,如果大量盘同时故障,将会发生什么?另外,OSD的扩容,也会导致数据的迁移,也会影响存储。

分布式存储一般都采用副本的方式来确保数据的安全性。写入磁盘前不需要进行额外复杂的计算,就可以将数据写入磁盘,是最快速的方式。是一种空间换时间的方法,即想得到较好的存储性能,就采用副本的方式。

当有副本出现丢失的情况,系统就会启动数据重构。一般情况下,用于生产的分布式存储采用的是3副本。副本一般放置在不同机架、不同服务器主机的硬盘上。3副本就是放置在3台不同的服务器的硬盘上。

而每个用户的数据是由很多个副本均匀的分布在存储资源池内的所有主机上的。所以,可以认为任意一台服务器会存储着所有用户数据的某些数据副本,一台服务器出现故障,会影响所有用户。

从理论上来说,副本方式可以允许n-1台的服务器出现故障,n是副本数。比如3副本,不管这个分布式存储资源池内有几台服务器组成,就只能允许2台服务器出现故障。2台服务器出现故障,其实这个存储就很危险了。

当数据的持久化层OSD出现故障的时候,必须启动副本的恢复工作,即要在短时间内恢复完整的副本数。不同存储的结构、算法不同恢复的时间长短也不一样。

但从副本恢复所使用到的磁盘、网络等基础设备是一样的。今天我们从基础角度上来分析,看看副本的恢复到底需要多少时间和当新增加OSD节点需要多长时间,并看看因为采用了X86服务器带来的隐患。

我们在实验室内做了实验,具体了解一下:

试验环境:2台万兆交换机、4台X86服务器(12块3T 7200转 SATA盘+1块1.2G PCIeSSD)。包括所有副本在内,每块磁盘有1T数据,共有48T数据。

实验一:无IO情况在,拔出一个磁盘

实验二:在存储上建立了4个360G的虚拟卷,加载少量的IO,即8K随机读写,队列深度为1,总iops为2600左右。

在拔出一个磁盘后,在15分钟后(可配,延迟15分钟是为了防止无操作、无报警等),系统开始对缺失的副本进行重构,得出结果:

分析:

在实验分布式存储中,原来共有数据48块1T数据,拔出1块磁盘数据重构完成后,还是48T数据,即每块盘增加了(1T/47)1000=21.28GB的数据。

  • 在无IO情况下12分钟内重构了1T的数据:

网络速度:(11000 )/(1260)=1.39GB/s*8=11Gb/s,也就是说在无IO的情况下,网络的总的流量是11Gb/s。其中3台服务器网络速度是2.84Gb/s,1台被拔出硬盘的服务器流量是2.57Gb/s。为了计算方便,平均每台服务器为2.75Gb/s,网络利用率是27.5%。

磁盘写入速度:21.281000/(1260)=29.56MB/s。

  • 在少量IO情况下24分钟内重构了1T的数据:

网络速度:(11000 )/(2460)=1.39GB/s*8=5.5Gb/s,也就是少量IO的情况下,网络的总的流量是5.5Gb/s。

平均每台服务器为是1.38Gb/s。

磁盘写入速度:21.281000/(2460)=15MB/s。

实验现象:

1、无流量压力情况下数据重构速度即每块盘最大写速度为30MB/s。但随着IO的增加,写的速度也会越来越慢。

2、虽然每个服务器接入网络是10Gb/s,但受到存储软件的控制,重构时最大网络利用率近30%。

在有IO的情况下,重构时间迅速增加。主要是为了不影响正常IO的处理,软件对副本重构的速度进行了控制。

在实际生产中,用于副本重构的网络利用率控制在5%以下,对存储正常的IO不会产生影响。

由此计算:

29.56M/(27.5%/5%)=5.37M,即在10G接入网络下,每台服务器重构流量在0.5Gb/s( 62.5MB/s)和每块磁盘读写数据在5MB/s以下,数据重构是安全的。

副本恢复的过程,实际上是从现有的磁盘中读取需要重构的副本,再根据一定的规则写入某些磁盘的过程。每块盘承担了读取副本,也承担了写入副本的职责。也就是说平均每块磁盘读2.5M,写也是2.5M。

从这个角度上看,每台服务器配置12块硬盘(60MB/s)是能产生读写能力和网络( 62.5MB/s)能力匹配。服务器接入带宽越大,可以配置的硬盘数量就越大。

小结:

1、如果主机和磁盘比大于等于12:

1TB数据重构时间=10008/(0.25n) n: 服务器数量

比如 57台12块磁盘的2P资源池重构1T数据的最短时间=(10008)/(0.2557)=560秒。

2、如果主机和磁盘比小于12:

1TB数据重构时间=10001000/(2.5m) m:参与重构磁盘数量

如果1台12块盘的服务器故障,最大重构36T数据,需要最短时间是342分钟,5.7小时。

结论:服务器或参与重构的磁盘数量越多,重构的速度就越快

我们继续实验,在数据重构完成后,重新插入这块盘,我们会发现,副本又开始重构了,但这次数据是搬家,并不生成新的副本。是因为系统认为插入了新盘,数据需要均衡导致的。

分布式存储采用的是“共产主义”,扩容服务器的数量可以线性的增加存储的能力,但新扩容的磁盘并不是只接受新的副本数据,而是需要搬迁写入平均值大小的“老”副本数据。

实际上每次非正常IO的副本的写入,都伴随着其他节点副本的删除。频繁的写入、删除对磁盘的寿命有较大的影响。

我们再看看实验结果:

在无io时,磁盘写入的速度是68MB/s,68MB/s其实也已经达到SATA磁盘平均写入速度的最大值的正常范围。这样,平均每台服务器网络中平均贡献68*8/4=136Mb/s流量。

数据副本的搬迁是一个动态过程。磁盘里的数据副本一定有1/3的数据是主副本,可能会被正常的IO读取到,所以新加入的磁盘也不是全力进行数据搬迁,也和其他磁盘一样,只能用有限的能力应付副本迁移。

测试结果上看,在少量IO业务下测试磁盘写速度为45MB/s, 平均每台服务器网络中平均贡献90Mb/s。在无IO的情况下,数据完成重新部署居然需要4.3小时了。

大家一定没有想到吧,因为这次是47块盘共1T的数据搬到1块磁盘上,就像47个人喂1个人吃饭,饭总得一口一口吃,所以增加磁盘的时候,在大部分情况下和网络的速度无关,和磁盘写入的速度直接相关。

上面提过,为了不让副本迁移不影响正常IO,每台服务器可以提供主机网络的5%的带宽,即62.5MB/s,磁盘读写为5MB/s来处理副本的迁移。

3、如果主机和磁盘比大于等于12:

一起重构的磁盘数量=62.5*n/m n:服务器的数量 m:磁盘写入速度

4、如果主机和磁盘比小于12:

一起重构的磁盘数量=5*n/m n:磁盘的数量 m:磁盘写入速度

如果m=5M,n= 57, 可以一起写入磁盘=712块

1-712块磁盘,1T数据迁移完成最长需要55.56个小时。可以这样认为,在目前2PB容量的分布式存储,在不影响业务情况下,如果扩容在2PB以下,数据副本迁移1TB需要56个小时。

大家一直在问我,分布式存储的风险在哪里。风险就是因为多副本特性所引起的。

首先不管这个集群有多大,最多可以有n-1台服务器出现故障。一般是3副本,就是允许有2台服务出现故障。

当出现故障的时候,就进行了数据重构,重构副本的时间相对较短,在2P的存储,每T数据恢复需要10分钟,恢复时间是以小时计。但是2台服务器同时出现故障,本身存在的风险就很大了,应尽量避免。

当故障的服务器恢复了,重新加入存储资源池,副本就需要迁移,那恢复的时间需要用天计算。所以当存储的OSD出现故障到完全恢复的时间很长。但在正常情况下,还是能接受的。

但非正常情况呢?怎么会出现非正常情况呢?

因为分布式存储常用的是X86服务器,x86服务器是有正常使用周期,大约是5年。同一批次的服务器的寿命是差不多的,在使用寿命的末期,服务器出现故障的概率是很大的。

1台服务器发生故障,副本重构,可能会是最后一根稻草,导致服务器群的“老太太们”压力发生变化,也出现故障。

一旦发生2台以上的同时故障,存储就会出现严重故障,存储就只能停止服务,运气好可以离线恢复数据,运气不好,副本完全丢失,数据完全不可用了。

大家知道,在资源池里,存储一旦停止服务,整个资源池就瘫痪了。这种情况一定会发生,只是早晚的问题,所以要提前干预,不能让这样的事情发生。

解决的办法

于是定期更换服务器,别让服务器变成“老太太”,不断补充新鲜血液。但是,更换服务器和扩容不一样,扩容的时候可以一下子增加几十台服务器,用个2天时间就可以静悄悄的完成扩容。

更换服务器的过程是先将服务器退出服务,再增加服务器的过程。原来服务器上有多少数据,就需要搬迁多少数据,比如原来服务器每块有2T数据了,就需要搬迁12*2T的数据。为了确保存储的正常使用,最好只能同时退出n-2台服务器,并增加相应的服务器。

比如3副本,就只能先退出1台服务器,再增加1台服务器。换1台服务器需要2*2=4天时间。最多同时换2台,但风险很大,万一更换的过程中出现1台故障,那这个存储系统就挂了。

所以一台一台更替是最妥当的方法,57台服务器全部替换完成,不停的干,顺利的话,也需要大半年时间,算上节假日1年可能都做不完。这个过程漫长而复杂,充满的变数,却一定是可行的。

当然划小分布式存储的故障域,在一个故障域的服务器减少,对应替代服务器的工作时间相应减少了,风险也相应减小。但是分布式存储是云计算快速发展后对存储性能、容量带来新需求发展起来的。

几百台服务器共享一个存储,运行几千、上万台虚拟机,从这个角度考虑,分布式块存储最好是一个可以无限线性扩容的存储系统。但是就是因为有了上面的问题,只能将存储资源池划分成为一个一个较小的故障域。

这个故障域的大小我们认为在裸容量在2P(有效容量666T)、IOPS在100万次以上是可以满足资源池的需要,即在60台服务器左右。

分布式块存储实际上是来替代所谓高端FCSAN存储的。小集群替代低端小容量的FCSAN在价格上、性能上都没有优势。

如果只是服务器出故障,而磁盘是正常的,还有一种比较快速的人工介入办法。这个办法是一种应急方案的延伸。实现的原理就是利用检测到磁盘故障后15分钟后才启动副本的重建。

如果15分钟内磁盘又恢复了,那在故障时间内原来需要写入的副本是需要追溯的。也就是说在这15分钟内,其实有些副本只写了2个,还有一个1副本原来要写到这个磁盘中的。

如果15分钟内原磁盘恢复了,就将增量数据补充进去,如果15分钟不恢复,就进行副本重构。当然这个时间长短是可以配置,但不是所有的分布式存储系统都有这个功能。

不少存储系统一检测到磁盘或服务器不在线,就会立即启动副本重构,本质上就是没有“追溯”。知道这个原理了,下面的事情就简单了。

发现整台服务器发生故障后,将服务器设置成为“维护/更换”模式,就不受15分钟的限制了(可能需要新开发这模式)。准备好装了系统的服务器(不插入持久化层的磁盘),当主机发生故障或更换的时候,人工将故障服务器里的磁盘插入备用服务器里,加入存储系统中,提供服务。

这个服务器,在写入新数据的同时,还要追溯故障时间段的数据。

这种方法是应急方案的延伸,可以快速解决非磁盘故障的情况,但并不根本解决问题。因为如果这插拔磁盘的过程中,如果有一块盘损坏了,又回到以前数据搬迁慢的问题上了。而且只换主机,不换磁盘,老化问题还是存在,还是不能高枕无忧。

全SSD分布式存储的拥护者会兴奋了,因为用全SSD的好像可以提高速度,加快这个过程。用全SSD的同时,最好也提高服务器接入的带宽,比如用40G网卡或用IB网络,不要让网络成为新的瓶颈,但分布式存储带来的隐患不可能根除,只是快了,问题还是一样。

其实还有一个比较严重的老化问题——作为缓存的SSD。SSD作为整个存储“性能担当”在存储中起到核心作用。但SSD的写寿命是一个突出问题,怎么样在线更换SSD也是一个需要解决的问题。

分布式“块”存储存在这样的风险,服务器加载更多磁盘的对象存储和文件存储类似的问题更突出,风险更大。

存储内的数据一定要有价值,因为存储他们的代价很大。但是现在存储的使用是一种多多益善的观念,只管写,不管删,不管什么需求都往块存储里写等等。存储按需选择类型和容量是目前存储使用中遇到的最普遍问题,这个问题将来详谈。

本文福利, 免费领取Linux C/C++ 开发学习资料包、技术视频/代码,1000道大厂面试题,内容包括(C++基础,网络编程,数据库,中间件,后端开发,音视频开发,Qt开发,游戏开发,Linux内核等进阶学习资料和最佳学习路线图)↓↓↓↓有需要的可以进企鹅裙927239107领取哦~↓↓