mythmgn(笔者)是此篇旧文的作者, 曾发布在其他平台, 从本月开始在博客园连载自己的技术文章和思考 (觉得 markdown 的支持好用!) . 转载请注明出处, 谢谢.
欢迎大家左侧关注我的公号, 一起在技术领域互动和讨论.
一 分布式存储系统背景
副本是分布式存储系统中的常见概念:将一定大小的数据按照一定的冗余策略存储,以保障系统在局部故障情况下的可用性。
副本间的冗余复制方式有多种,比较常用有两类:
- Pipeline:像个管道,a->b->c,通过管道的方式进行数据的复制。该方式吞吐较高,但有慢节点问题,某一节点出现拥塞,整个过程都会受影响
- 分发:client -> a client ->b client ->c。系统整体吞吐较低,但无慢节点问题
对于冗余副本数目,本文选择常见的三副本方案。
分布式存储系统一般拥有自动恢复副本的功能,在局部存储节点出错时,其他节点(数据副本的主控节点或者client节点,依副本复制协议而定)自动发起副本修复,将该宕机存储节点上的数据副本恢复到其他健康节点上。在少量宕机情况下,集群的副本自动修复策略会正常运行。但依照大规模存储服务运维经验,月百分之X的磁盘故障率和月千分之X的交换机故障率有很大的可能性导致一年当中出现几次机器数目较多的宕机。另外,批量升级过程中若出现了升级bug,集群按照宕机处理需要进行副本修复,导致原本正常时间内可以完成的升级时间延长,也容易出现数目较多的宕机事件。
二 雪崩效应的产生
在一段时间内数目较多的宕机事件有较大可能性诱发系统的大规模副本补全策略。目前的分布式存储系统的两个特点导致这个大规模副本补全策略容易让系统产生雪崩效应:
a. 集群整体的free空间较小:通常整体<=30%, 局部机器小于<=20% 甚至10%
b. 应用混布:不同的应用部署在同一台物理/虚拟机器上以最大化利用硬件资源
今年火起来的各种网盘、云盘类服务就是a的典型情况。在各大公司拼个人存储容量到1T的背后,其实也在拼运营成本、运维成本。现有的云存储大多只增不减、或者根据数据冷热程度做数据分级(类似Facebook的数据分级项目)。云存储总量大,但增量相对小,为了减少存储资源和带宽资源浪费,新创建的文件若原有的存储数据中已有相同的md5或者sha1签名则当做已有文件做内部链接,不再进行新文件的创建。但即使这样,整体的数据量还是很大。
目前云存储相关业务未有明显的收入来源,每年却有数万每台的服务器成本,为运营成本的考虑,后端分布式存储系统的空闲率很低。而瞬间的批量宕机会带来大量的副本修复,大量的副本修复很有可能继而打满原本就接近存储quota的其他存活机器,继而让该机器处于宕机或者只读状态。如此继续,整个集群可能雪崩,系统残废。
三 预防雪崩
本节主要讨论如何在系统内部的逻辑处理上防止系统整体雪崩的发生。预防的重要性大于事故之后的处理,预测集群状态、提前进行优化也成为预防雪崩的一个方向。
下面选取曾经发生过的几个实际场景与大家分享。
1. 跨机架副本选择算法和机器资源、用户逻辑隔离
某天运维同学发现某集群几十台机器瞬间失联,负责触发修复副本的主控节点开始进行疯狂的副本修复。大量用户开始反馈集群变慢,读写夯住。
现场应对:
优先解决——副本修复量过大造成的集群整体受影响。
a. 处理的工程师当机立断,gdb到进程更改修复副本的条件为副本<2,而非原本的3(replicas_num),让主控节点这个时候仅修复副本数小于2个的文件,即保证未丢失的文件有至少一个冗余副本,防止只有一个副本的数据因可能再次发生的挂机造成文件丢失。
b. 紧急解决这批机器失联问题,发现是交换机问题,a.b.c.d ip网段的c网段机器批量故障。催促网络组尽快修复。
c. 副本修复到>=2之后,Gdb更改检测副本不足周期,将几十秒的检测时间推迟到1天。等待网络组解决交换机问题。
d. 网络恢复,原有的机器重新加入集群。大量2副本文件重新变为3副本,部分3副本全丢失文件找回。
e. 恢复主控节点到正常参数设置状态,系统开始正常修复。
改进措施:
在改进措施前,先分析下这次事件暴露的系统不足:
1) Master参数不支持热修正,Gdb线上进程风险过大。
2) 一定数量但局域性的机器故障影响了整体集群(几十台相对一个大集群仍属于局域性故障)。如上所述,月千分之几的故障率总有机会让你的存储系统经历一次交换机故障带来的集群影响。
案例分析后的改进措施出炉:
1) Master支持热修正功能排期提前,尽早支持核心参数的热修改。
热修改在上线后的效果可观,后续规避过数次线上问题。
2) 在选择数据副本存储宿主机器的pickup算法中加入跨交换机(机架位)策略,强制——或者尽量保证——副本选择时跨机架位。这种算法底下的副本,至少有1个副本与其他两个副本处于不同的交换机下(IP a.b.c.d的c段)。该措施同时作用于新的存储数据副本选择和副本缺失后的副本补全策略,能在副本宿主选择上保证系统不会因为交换机的宕机而出现数据丢失,进而避免一直处于副本补全队列/列表的大量的丢失副本节点加重主控节点负载。
3) 机器按region划分隔离功能提上日程;用户存储位置按照region进行逻辑划分功能提上日程;Pickup算法加入跨region提上日程。
a) 机器按照物理位置划分region、用户按照region进行逻辑存储位置划分,能让集群在局部故障的情况下仅影响被逻辑划分进使用这部分机器的用户。
这样一来,最坏情况无非是这个region不可用,导致拥有这个region读写权限的用户受影响。Pickup算法跨region的设计进一步保证被划分region的用户不会因为一个region不可用而出现数据丢失,因为其他副本存到其他region上了。于是,核心交换机故障导致一个region数百台机器的宕机也不会对集群造成范围过大的影响了。
b) 增加region可信度概念,将机器的稳定性因素加入到副本冗余算法中。
当集群规模达到一定量后,会出现机器稳定性不同的问题(一般来说,同一批上线的机器稳定性一致)。通过标记region的稳定性,能强制在选择数据副本的时候将至少一个副本至于稳定副本中,减少全部副本丢失的概率。
c) Region划分需要综合考虑用户操作响应时间SLA、物理机器稳定情况、地理位置等信息。
合理的region划分对提升系统稳定性、提升操作相应时间、预防系统崩溃都有益处。精巧的划分规则会带来整体的稳定性提升,但也增加了系统的复杂度。这块如何取舍,留给读者朋友深入思考了。
2. 让集群流控起来
流控方面有个通用且符合分布式存储系统特点的原则:任何操作都不应占用过多的处理时间。这里的“任何操作”包含了在系统出现流量激增、局部达到一定数量的机器宕机时进行的操作。只有平滑且成功的处理这些操作,才能保证系统不因为异常而出现整体受影响,甚至雪崩。
现场还原:
1) 场景1 某天运维同学发现,集群写操作在某段时间大增。通过观察某个存储节点,发现不仅是写、而且是随机写!某些产品线的整体吞吐下降了。
2) 场景2 某集群存储大户需要进行业务调整,原有的数据做变更,大量数据需要删除。
运维同学发现,a. 整个集群整体上处于疯狂gc垃圾回收阶段 b. 集群响应速度明显变慢,特别是涉及到meta元信息更新的操作。
3) 场景3 某天运维同学突然发现集群并发量激增,单一用户xyz进行了大量的并发操作,按照原有的用户调研,该用户不应该拥有如此规模的使用场景。
此类集群某些操作预期外的激增还有很多,不再累述。
现场应对:
1) 立刻电联相关用户,了解操作激增原因,不合理的激增需要立刻处理。
我们发现过如下不合理的激增:
a. 场景1类:通过Review代码发现,大量的操作进行了随机读写更改。建议用户将随机读写转换为读取后更改+写新文件+删除旧文件,转换随机读写为顺序读写。
b. 场景3类:某产品线在线上进行了性能测试。运维同学立刻通知该产品线停止了相关操作。所有公有集群再次发通过邮件强调,不可用于性能测试。如有需要,联系相关人员在独占集群进行性能场景测试。
2) 推动设计和实现集群各个环节的流控机制功能并上线。
改进措施:
1) 用户操作流控
a. 对用户操作进行流控限制
可通过系统内部设计实现,也可通过外部的网络限流等方式实现,对单用户做一定的流控限制,防止单个用户占用过多整个集群的资源。
b. 存储节点操作流控
可按照对集群的资源消耗高低分为High – Medium – Low三层,每层实现类似于抢token的设计,每层token数目在集群实践后调整为比较适合的值。这样能防止某类操作过多消耗集群负载。若某类操作过多消耗负载,其他操作类的请求有较大delay可能,继而引发timeout后的重试、小范围的崩溃,有一定几率蔓延到整个集群并产生整体崩溃。
c. 垃圾回收gc单独做流控处理。删除操作在分布式存储系统里面常用设计是:接收到用户删除操作时,标记删除内容的meta信息,直接回返,后续进行策略控制,限流的删除,防止大量的gc操作消耗过多单机存储节点的磁盘处理能力。具体的限流策略和token值设置需要根据集群特点进行实践并得出较优设置。
2) 流控黑名单
用户因为对线上做测试类的场景可以通过人为制度约束,但无法避免线上用户bug导致效果等同于线上测试规模的场景。这类的场景一般在短时间内操作数严重超过限流上限。
对此类场景可进行流控黑名单设置,当某用户短时间内(e.g. 1小时)严重超过设置的上限时,将该用户加入黑名单,暂时阻塞操作。外围的监控会通知运维组同学紧急处理。
3) 存储节点并发修复、创建副本流控
大量的数据副本修复操作或者副本创建操作如果不加以速度限制,将占用存储节点的带宽和CPU、内存等资源,影响正常的读写服务,出现大量的延迟。而大量的延迟可能引发重试,加重集群的繁忙程度。
同一个数据宿主进程需要限制并发副本修复、副本创建的个数,这样对入口带宽的占用不会过大,进程也不会因为过量进行这类操作而增加大量其他操作的延迟时间。这对于采用分发的副本复制协议的系统尤其重要。分发协议一般都有慢节点检查机制,副本流控不会进一步加重系统延迟而增大成为慢节点的可能。如果慢节点可能性增大,新创建的文件可能在创建时就因为慢节点检查机制而缺少副本,这会让集群状况更加恶化。
3. 提前预测、提前行动
1) 预测磁盘故障,容错单磁盘错误。
场景复现:
某厂商的SSD盘某批次存在问题,集群上线运行一段时间后,局部集中出现数量较多的坏盘,但并非所有的盘都损坏。当时并未有单磁盘容错机制,一块磁盘坏掉,整个机器就被置成不可用状态,这样导致拥有这批坏盘的机器都不可用,集群在一段时间内都处于副本修复状态,吞吐受到较大影响。
改进措施:
a) 对硬盘进行健康性预测,自动迁移大概率即将成为坏盘的数据副本
近年来,对磁盘健康状态进行提前预测的技术越来越成熟,技术上已可以预判磁盘健康程度并在磁盘拥有大概率坏掉前,自动迁移数据到其他磁盘,减少磁盘坏掉对系统稳定性的影响。
b) 对单硬盘错误进行容错处理
存储节点支持对坏盘的异常处理。单盘挂掉时,自动迁移/修复单盘的原有数据到其他盘,而不是进程整体宕掉,因为一旦整体宕掉,其他盘的数据也会被分布式存储系统当做缺失副本,存储资源紧张的集群经历一次这样的宕机事件会造成长时间的副本修复过程。在现有的分布式存储系统中, 也有类似淘宝TFS那样,每个磁盘启动一个进程进行管理,整机挂载多少个盘就启动多少个进程。
2) 根据现有存储分布,预测均衡性发展,提前进行负载均衡操作。
这类的策略设计越来越常见。由于分布式存储集群挂机后的修复策略使得集群某些机器总有几率成为热点机器,我们可以对此类的机器进行热点预测,提前迁移部分数据到相对负载低的机器。
负载均衡策略和副本选择策略一样,需要取舍复杂度和优化程度问题。复杂的均衡策略带来好的集群负载,但也因此引入高复杂度、高bug率问题。如何取舍,仍旧是个困扰分布式存储系统设计者的难题。
四 安全模式
安全模式是项目实践过程中产生的防分布式存储系统雪崩大杀器,因此我特别将其单独列为一节介绍。其基本思路是在一定时间内宕机数目超过预期上限则让集群进入安全模式,按照策略配置、情况严重程度,停止修复副本、停止读写,直到停止一切操作(一般策略)。
在没有机器region概念的系统中,安全模式可以起到很好的保护作用。我过去参与的一个项目经历的某次大规模宕机,由于没有安全模式,系统进行正常的处理副本修复,生生将原本健康的存储节点也打到残废,进而雪崩,整个集群都陷入疯狂副本修复状态。这种状态之后的集群修复过程会因为已发生的副本修复导致的元信息/实际数据的更改而变的困难重重。 该事件最后结局是数据从冷备数据中恢复了一份,丢失了冷备到故障发生时间的数据。
当然,安全模式并非完美无缺。“一段时间”、“上限”该如何设置、什么时候停副本修复、什么时候停读、什么时候停写、是自己恢复还是人工干预恢复到正常状态、安全模式力度是否要到region级别,这些问题都需要安全模式考虑,而此类的设计一般都和集群设计的目标用户息息相关。举例,如果是低延迟且业务敏感用户,可能会选择小规模故障不能影响读写,而高延迟、高吞吐集群就可以接受停读写。
五 思考
由于分布式存储系统的复杂性和篇幅所限,本文仅选择有限个典型场景进行了分析和讨论, 真实的分布式存储系统远比这数个案例复杂的多、细节的多。如何平衡集群异常自动化处理和引入的复杂度,如何较好的实现流控和避免影响低延迟用户的响应时间,如何引导集群进行负载均衡和避免因负载均衡带来的过量集群资源开销,这类问题在真实的分布式存储系统设计中层出不穷。如果设计者是你,你会如何取舍呢?