当前位置: 首页 > 科技观察

如何优雅解决分布式数据库复杂故障

时间:2023-03-16 15:18:49 科技观察

故障介绍ACID是事务的四大特征,其中D(Duration)指的是持久化。数据库的一个很大的价值在于可以有效处理故障,保证数据不会丢失。随着分布式数据库的发展,部署的复杂性增加,数据库面临的故障场景也越来越多。常见的硬件故障接下来我们来看一下常见的数据中心的故障概率《Designs, Lessons and Advice from Building Large Distributed Systems》,Jeffdean网络故障对于分布式系统设计来说,除了以上故障之外,还有一些额外的网络故障需要考虑脑裂。顾名思义,脑裂是指最主要的是由于网络故障,系统被分割成多个独立的区域;在多个网络平面的情况下,部分网络平面出现故障,这种错误一般很难出现,因为每个网络平面往往都是逻辑性的,不与网卡绑定。当然,如果用户配置调整不当,也可能导致此类故障。如果系统跨越多个网络平面,则需要考虑该故障;脆弱的数据中心其实并没??有想象中的那么稳定。下图是笔者2017年11月22日截取的cloudharmony监测数据,监测了300多个数据中心的可靠性。可见即使是大名鼎鼎的azure也未能达到号称的99.95%。那些有兴趣了解更多信息的人可以在这里阅读。故障的北欧数据中心部分在定期例行灭火系统维护期间发生事故,释放灭火剂。这导致专用于密封和安全的空气处理单元(AHU)自动关闭。受影响地区的一些系统关闭并重新启动了一些机器,以防止系统过热。35分钟后AHU手动恢复。由于系统突然停机,需要恢复部分数据,7小时后系统恢复正常。该事故导致部分用户的存储服务无法使用。2017年2月28日,amazons3故障运维工程师定位计费系统变慢时,想删除少量服务器。结果,由于命令输入错误导致大量服务器被删除,包括索引子系统和放置子系统中的服务器,导致S3服务从上午9点37分一直到下午1点54分不可用。最有意思的是AWSServiceHealthDashboard系统依赖S3,所以从故障到11:37AM,监控页面都没有显示故障。据说这个故障已经摧毁了墙外一半的互联网世界。2016年4月13日,GoogleComputeEngine停止为全球所有地区提供服务。GoogleComputeEngine停止服务并在18分钟后恢复。故障原因是运维工程师删除了一个无用的ip块,删除ip的操作没有正确同步配置。该操作触发了网络配置系统的一致性检测。当网络配置系统检测到不一致时,它执行重启,导致服务中断。2015年5月27日,杭州电信切断阿里网线和光纤,部分用户无法使用,2小时后恢复。2014年7月1日,宁夏银行核心数据库系统出现故障。行二(2014)187号文正式下发国家文件。该行(含异地分行)已全部中断存取款、转账支付、借记卡、网上银行、ATM和POS业务。经初步分析,在季末大量结算业务的情况下,由于备份系统异常,导致备份存储盘的读写处理严重延迟,备份和主存数据不一致。在采取中断数据备份视频操作后,生产数据库损坏并崩溃。由于宁夏银行严重缺乏应急恢复处置机制,系统恢复工作进展缓慢。核心系统直到7月3日5时40分才恢复服务,业务系统中断37小时40分钟,期间业务完全由人工处理。故障分类看数据中心网络互联图。图中任何硬件设备都可能发生故障,从每台主机,切换到网线。我们尝试按故障域对故障进行简单的分类。所谓故障域就是一组由于故障而会同时不可用的组件。常见故障域包括:物理机,包括本地磁盘、网卡故障、内存故障等。数据中心共用一套电源。一个机柜数据中心共享一个网络设备的几个机柜受一根光纤的影响。位于同一地区多组数据中心中的一个数据中心由同一城市供电或受同一自然灾害影响。不同部件发生故障的概率是不同的。谷歌研究表明,在36°C和47°C之间运行的磁盘故障率最高。随着时间的发展,磁盘的故障率逐渐增加。第一年只有1.7%,第三年达到8.6%。现在也有很多研究,将大数据和人工智能引入磁盘故障预测领域,取得了不错的效果。数据库故障处理日志系统数据库会记录数据修改的日志。日志记录数据变化。根据日志用途的不同,可以分为redologs、.undologs、redo/undologs。现在流行重做日志。看一下postgresql日志的结构:根据日志记录方式的不同,可以分为以下两种:物理日志,上图是物理日志,回放速度快,但是日志量大大,实现逻辑比较简单,不会出错;logicallog,replay速度比较慢,日志量小,对于MVCC机制的数据库还有一个额外的好处。备机可以独立gced,与宿主机无关;数据库日志系统有两个重要的原则:WAL原则,即日志应该在刷新页面之前被刷新,仅仅调用write是不够的,还需要调用sync操作。在合适的时候,通常是事务提交的时候,刷新日志,调用sync同步到磁盘,保证断电数据可以恢复。除了在事务提交时刷新日志,当涉及到元数据操作时,往往会调用sync来刷新数据,以保证元数据的一致性。通过日志系统进行恢复,不仅需要完整的日志,还需要完整的(可能是过时的)数据作为起点。日志系统是系统软件中广泛使用的技术。它不仅仅是一个数据库。日志代表系统的变化。它可以用于恢复/备份,也可以用作通知系统。掌握了系统的日志流就相当于掌握了系统的整个状态,日志可以更抽象的理解为日志+状态机。通过不断地重新访问日志,可以改变状态机的状态,并且可以通过日志将状态变化传递到整个系统的各个角落。关于日志系统,作者我看过的最好的文章是TheLog:Whateverysoftwareengineershouldknowaboutreal-timedata'sunifyingabstraction。强烈推荐阅读,日志就是一切。日志恢复日志代表了系统中的所有变化。如果数据大小从0扩展到100G,那么日志至少要有100G,甚至更多,而且日志的增长与用户所做的修改是正相关的,任何系统都无法存储增长最多的日志.回收日志占用的存储空间是必然的选择。日志回收有两个好处:减少日志占用的磁盘空间,减少系统恢复所需的时间。实际上,对于MVCC机制实现的数据库,由于日志回收与事务提交无关,因此可以严格控制日志到指定大小,方便系统运维。如上所述,数据恢复需要以完整的数据为起点。其实原因是初始日志被回收了。如果能保留从初始状态到最新状态的所有日志,仅靠日志就可以恢复系统。但很显然,没有一个系统可以保存所有的日志。checkpointcheckpoint用于回收日志。Checkpoint的流程如下:Checkpoint:记录当前日志位置;flush当前系统内存中的所有数据,并调用sync同步到磁盘。这时候还是应该遵循WAL原则;写入检查点日志,或者使用检查点信息作为元数据来刷新磁盘;回收checkpoint起点前的log;以上是一种常见的做检查点的方式,也称为全检查点(fullcheckpoint)。这种方法实现简单,但显然checkpoint是一个IOPeak,会造成性能抖动。还有一种做检查点的方式,叫做增量检查点(incrementalcheckpoints),过程如下:后台写进程按照页面最后修改的顺序刷盘;检查点日志可以作为元数据刷盘;这种方式将checkpoint变成了后台写操作,只需要在做checkpoint的时候检查,消除IO峰值,有助于稳定数据库性能。tornpage数据库页面大小往往与磁盘扇区大小不同,所以刷新页面时,如果系统断电,可能只会刷新部分页面。这种现象称为撕裂页面,这种页面相当于完全损坏,而日志重放需要一个完整的数据作为起点,此时无法恢复。half-write的处理方式有几种:innodb中doublewrite,pg中fullpagewrite,这两种方式原理类似,都是在pageflushed之前,先在其他地方写page,sync之后,然后覆盖页面。从备份中恢复,从备份中单独恢复一个页面。有一些例外:追加写入系统没有这个问题;如果页面大小与扇区大小相同,则不会出现此问题,并且许多元数据设计都考虑到了这一点;许多文件系统或分布式文件系统、raid卡或磁盘本身也可以处理此故障。如果使用可以处理半写故障的硬件,数据库不需要开启该功能;磁盘满的问题只能通过运维的方式来解决,因为数据库事务提交必须写入,如果日志写不出来,就不能提交事务,相当于停止数据库。因此,磁盘故障的应对一般是通过监控,在磁盘空间即将耗尽时进行预警。磁盘损坏如上所述,数据库恢复需要数据和日志的完整副本。因此,如果数据或日志遇到磁盘损坏,日志系统无法恢复,只能依靠其他方法。备份按级别分类,常见的备份方式有:全量备份:传统数据库的全量备份通常的做法是先做一个检查点,然后复制检查点之后的所有数据和日志。如果有很多数据,这是一个很长的时间。繁重的操作;增量备份:增量备份还需要做一个checkpoint,然后把上次备份后变化的pages和checkpoint点后的logs拷贝过来,如何找到上次备份后变化的pages,做全页对比是一个方法,通过位图文件记录页面变化也是一种方法。Percona实现了第二种方法;增量备份往往可以叠加或合并,全量备份和增量备份也可以按时间顺序排列。合并。日志归档:日志归档是指定期对指定的日志进行归档;显然,上述操作的开销从大到小的顺序是,全量备份>增量备份>日志归档。这三种方式在数据库运维时往往会结合使用,以达到降低故障RPO的目的。AmazonAurora实现近乎实时备份的功能,备份时间不超过5分钟。多机热备份如果某台机器由于各种原因出现故障,比如cpu烧坏、内存故障、操作系统bug,甚至炸毁,都可以通过备份来恢复。但是,通过备份进行恢复往往耗时较长,不能满足业务连续性(BusinessContinuity)的需要。除了备份,数据库还支持单机热备份和只读查询的备用。显然,备机应该根据故障域和客户要求进行反亲和部署。master-slave(-级联)每台主机可以连接多台备机,每台备机可以连接多台级联备份。这是传统数据库常用的部署方式。Postgres甚至支持多级级联备份(secondarycascading)等,但不是很常用。这种部署方式可以有效处理单机故障。作为支持只读操作的备机,可以有效分担读负载。这是一个延时读操作,也满足相应的隔离级别。但是和主机一起考虑,完全没有一致性可言。事务提交时机根据master事务的提交时机,有几种事务提交级别:master日志放在磁盘上,此时RTO<1min,RPO>0master日志在此时发送到备机同时,此时RTO<1min,当RPO=0时,将主机日志发送到磁盘,同时将master的日志发送到备机,并写入日志到磁盘。此时RTO<1min,RPO=0这三个提交级别,主机的性能越来越差。一般来说,同城备机使用第二种方式异地备机使用第一种方式。共享磁盘共享磁盘方案依赖于共享存储,备机只读不写。备机虽然不写磁盘,但还是需要在内存中不断的重放日志,以便master在故障后能够快速升为主。很明显,共享盘方案的性能和数据单机差不多,RTO<1min,RPO=0。但是由于硬件限制,分片方案只适用于同城。技术正在以螺旋方式发展。在分布式计算中,共享磁盘的思想也很流行。很多系统都依赖分布式文件系统/存储系统构建基于共享磁盘的计算系统,比如大数据领域知名度很高的Hadoop,还有OLTP领域的新势力aurora,newsql领域的tidb+tikv。还有很多master-master-master-master架构的服务,逐渐成为主流。目前几乎所有低一致性的大数据系统都是多主架构。作者对大数据不熟悉。这里我们只列举一些强一致性的数据库系统的传统领域。OracleRAC、IBMpurescale;分片中间件,很多互联网公司都开发了自己的中间件,比如腾讯tdsql,阿里DRDS,中兴GoldenDB,也有很多开源方案,比如pg-xc,pg-xl,mycat等,中间件方案符合互联网场景,技术门槛低,用户限制大;fdw(foreign-datawrapper),也是一种sharding-like的方案,目前oracle和pg采用的是直接将外部数据源映射到本地,对表也有很多限制,比如外部表的统计很难提取物等;mysql组复制,以paxos为复制协议,结合传统数据库进行新的探索;类spanner架构,商业数据库有spanner和oceanbase,开源数据库有tidb和cockroach;在master-master架构体系中,总有数据可以提供服务,所以可靠性更高。这是目前分布式系统的主流方案。paxos/raftPaxos/raft是目前主流的分布式复制协议。paxos协议精确定义了在分布式系统中达成共识的最低条件。关于paxos的原理可以参考这篇文章《一步一步理解Paxos算法》。Paxos是分布式系统的核心之一,对这个算法赞不绝口。paxos协议的变种很多,其应用也有一些要注意的要点。?中的第23章讨论了paxos应用的一些场景和情况。如果你有兴趣,你可以了解更多。一些工程可靠性意味着系统调用什么样的系统调用是可靠的?几乎没有,C语言中最有问题的系统调用就是malloc,因为它的使用范围太广,而且在一些深层次的代码逻辑中,一旦申请内存失败,处理起来相当困难。在一个重要的封闭模块中,最好先申请足够的内存,相当于半自管内存。其次,容易出错的系统调用都是IO相关的调用。比如IO调用错误,因为IO变慢,所以比较难处理。出现故障时,读写操作的速度根本无法预料,几十秒、几分钟甚至更长时间都是正常的,所以自旋锁如果包含IO操作,系统离崩溃不远了。对于跨网操作,不要对网络抱有任何期望。操作前,释放所有不需要的资源,并做好调用错误的准备,并为其设置超时时间。改为异步模式是个好主意。选择。Checksum如果数据由于外部损坏或错误而损坏,您可以使用校验和方法来检测它。Checksum一般应用在以下两种情况:数据烧录时,同时计算并记录在磁盘上;当数据被读取时,它被验证;heartbeat/connectionheartbeat进程卡住是难免的。当系统cpu被占满时,或者由于一些bug,可能导致一些关键进程没有被调度,导致某些信息无法传递。一些故障可能会影响整个系统是致命的。如何检测进程/线程cass,常见的有两种方法:维持磁盘心跳,比如定期去摸某个文件,如果文件的时间戳长时间没有变化,说明程序卡住了;提供外部程序访问的接口,外部程序定时访问进程。如果长时间没有反应,可以认为程序卡住了;对于bug导致的程序卡死,杀掉进程重启往往可以解决问题。调度/队列/优先级/流控系统的性能很难线性提升,数据库更不可能。对于大多数数据库系统来说,性能首先随着连接数的增加而增加到一定程度,如果继续增加连接数,性能往往会下降。上图是mysql8.0.3CATS特性的性能测试结果。很明显,超过64个连接后,性能会随着连接数的增加而下降。这也是数据库系统一般做连接池的原因。压力过大可能会导致系统崩溃。比如上图中,在FIFO调度方式下,512个连接,性能下降近5倍。因此,在大型系统中,连接池和优先级队列是一个很好的设计,可以方便有效地控制系统压力。同时,通过监控队列长度,可以直观的看到这部分系统的压力和处理能力。异地备份目前主流的高可用方案有两种,一种是两地三中心,一种是异地多活。两地三中心对于传统数据库来说,两地三中心的解决方案是比较常见的。常见的部署是同城两个中心,异地一个中心。难上加难,只能起到冷备份的作用:一般来说,应用距离主库较近,远程网络延迟大,性能往往不如主库;远程中心的硬件条件往往比本地中心差,无论是带宽还是时延都可能无法满足应用的需求;异地中心无法提供服务,浪费资源;如果不经常进行主备倒换,一旦发生故障,异地中心往往会出现各种问题,上面提到宁夏银行在故障发生前一年就进行了故障演练,但是如果不实践一年,当真正出现故障时,就会出现各种问题。公有云上也有比较靠谱的方案,如下图。当然,大规模部署公有云可以摊销成本,但在私有云上,这种方案的成本更高。Paxos不适合两地三中心部署。Paxos协议需要三个等价的故障域,可以处理一个故障域的故障。两地三中心的故障域并不相等。同城复制快,异地复制慢,性能受到很大影响;同城两个center在地质灾害时会同时失效,paxos无法处理;远程多活方案主要需要考虑以下问题:不同情况下系统资源的分配是否存在问题;任何一个数据中心网络断断续续造成的区域分区是否会导致系统不可用,尤其是当一个数据中心发生故障时,流控系统往往会立即对其他可用区域引入压力,可能立即导致系统过载;数据中心数据间同步性能是否满足需求;数据中心非常昂贵。一旦整个数据中心发生故障,服务的整体服务质量不可能不下降。如何优雅降级,保证尽可能多的数据可用,这是分布式系统需要考虑的问题。以GoogleSpanner为例,时间戳分发是分布式的,不需要中心节点。数据可以由用户部署。跨数据中心越多,性能越差,可靠性越强。影响其他部位。多地异地活动是一项系统工程。在这个庞大的工程中,数据库只需要做好自己的事情即可。参考资料《SRE: google运维解密》来自谷歌的高可用架构概念与实践《the tail at scale》硬盘故障CAP理论TheLog:Whateverysoftwareengineershouldknowaboutreal-timedata'sunifyingabstractionWALInternalsOfPostgreSQLAWSre:Invent2016:GettingStartedwithAmazonAurora(DAT203)一步步看懂Paxos算法cloudharmony数据中心监控