-
-
Notifications
You must be signed in to change notification settings - Fork 20
数据库容灾能力的探讨(一)
本文作于2020年6月,最初发布在本人的知乎专栏:https://zhuanlan.zhihu.com/p/150320689 此处根据当前昆仑数据库的实际情况做了少量修改。
在过去十多年在Oracle,腾讯等公司的数据库系统内核开发工作中,笔者的大量工作就是确保数据库系统在各种环境故障情况下,能够保持数据一致性和持续可用地提供数据读写服务。
2020年3-6月,我们花了大量时间精力解决了昆仑数据库使用的存储节点的容灾问题。昆仑分布式数据库必须使用我们改进后的Percona-MySQL-8.0 --- 命名为Kunlun-Storage --- 才能确保容灾和高可靠性。社区版本的MySQL-8.0和 Percona-MySQL-8.0的group replication和分布式事务处理(即XA)有很多个容灾能力方面的缺陷,导致各种分库分表方案如果使用社区版mysql-8.0的话,是不具备容灾能力的,在节点故障,断电,网络故障等情况下,可能发生丢失已提交的事务的更新,数据不一致,主备复制卡住等一系列问题。这些缺陷有一些是在mysql-5.7时代就已经存在的了。
在Kunlun-Storage中,我们的改进填补了MGR在处理XA事务方面的诸多缺陷和空白。笔者在FOSDEM 2021 年会关于这部分工作内容作了技术分享,总结了MySQL XA事务处理方面的容灾缺陷和漏洞,以及其他问题。地址在https://fosdem.org/2021/schedule/event/mysql_xa/,国内视频网站链接:https://www.bilibili.com/video/BV1zo4y1d7pu。在本文中,我希望基于过往工作历程中积累的经验,给读者分享一下我对分布式数据库系统的容灾能力和需求的理解,并介绍Kunlun-Percona-MySQL-8.0.18-9修复的容灾缺陷。
本文内容包括数据库系统需要应对的故障(即灾难)类型和环境可靠性模型,灾难可能造成的损害,以及容灾的方法和手段,包括数据库事务处理,数据备份和恢复,数据复制与高可用性,两阶段提交和分布式事务处理等数据库容灾相关的内容。
本文不含盖或者针对特定的数据模型(比如关系模型)和查询语言(比如SQL),因此本文内容对于关系数据库管理系统,json/xml 数据库管理系统,对象数据库管理系统,key-value数据库管理系统和图数据库管理系统都适用。
分布式数据库系统的环境可靠性模型
生产中运行的分布式数据库集群通常由运行在一个或者多个数据中心的计算机服务器联网构成,这些计算机服务器硬件以及网络,以及硬件和网络中运行的软件,以及操作所有这些软硬件的人员执行的操作和行为,就是分布式数据库集群运行的环境。这个环境可能出现的错误和故障就是分布式数据库系统需要处理的故障来源。
集群中任何节点的软硬件故障,或者任何节点之间的网络连接故障,都可能影响集群的正常工作。由于其天然的复杂性,这个环境发生故障的几率并不低,因此分布式数据库系统需要将节点软硬件故障和网络故障当作常见情况来处理,而不是当作极低概率的事件来处理。
分布式数据库集群需要处理的软件环境故障包括计算机服务器的操作系统自身的bug导致的工作故障和系统管理员人为错误导致的运行错误等,还包括网络节点的控制软件自身的bug以及网络管理员人为错误导致的网络连接故障,以及数据库操作人员使用和管理分布式数据库集群时误操作导致的分布式数据库集群节点故障等,比如误杀进程,误删数据文件等;需要处理的硬件环境故障包括服务器或者网络设备短暂断电,服务器的持久存储设备损坏,服务器短暂重启,服务器硬件永久损坏或者停止工作,以及部分或者全部网络连接短暂失效和长期失效等。
容灾能力对于一个数据库系统来说是非常关键的能力,特别是对于分布式数据库集群来说,其多节点的架构导致构成集群的软硬件和网络发生故障的几率更高,因此必须有绝对可靠的容灾能力,确保在任何节点发生软硬件故障情况下都不会导致数据一致性问题,或者丢失已提交的事务的改动,或者导致系统不可用。为了展现不同规模的分布式数据库集群环境故障几率,下面我们就量化上述故障的概率。
首选我们定义分布式数据库的‘集群环境可靠性’为组成该集群的软硬件节点及其间的网络连接都不发生故障的概率。然后我们计算在不同的集群规模和软硬件预期可靠性情况下这个‘集群环境可靠性’的值。
以昆仑分布式数据库集群为例,假设集群有 N个存储shard,每个shard一主两备,同时还有N个计算节点与每个shard的主节点相连接。每个存储和计算节点运行在独立的硬件计算机上面;同时这些节点之间还有至少2N+NN条网络连接(不考虑读备机的情况下)。这样一共有NN+6N 个可能发生故障的点。我们假设每个点在一定时间范围内,比如1个月内,可以以一个稳定的概率保持正常工作。在这个时间范围内只要集群中有1个节点发生了故障,就认定集群环境就发生了故障。这样就可以计算在一定时间范围内集群环境的可靠性概率。表1显示了在不同的N和单个点可靠性情况下‘集群环境可靠性’。
从这个表中可以看出,对于一个分布式数据库集群来说,在时间足够长(比如一年),范围足够广(比如有多个集群)的情况下, 某个集群环境出现故障的几率很大,随着时间不断增长,这个概率是趋近100%的。假如分布式数据库集群没有滴水不漏的毫无破绽的容灾能力的话,那么在实际生产中分布式数据库集群长期不出现系统故障或者数据一致性错误几乎是不可能的。
不同的分布式数据库集群的总可能故障点数计算方法未必完全相同,但是肯定时随着N的增加而增加的,集群环境可靠性随着时间的增长以及N的增大而降低也是必然的,因此无论对于哪一种分布式数据库,都会有类似的结论。 可见分布式数据库集群必须具备完备的坚不可摧的容灾能力,否则一定会出现数据不一致,数据损坏丢失或者数据库服务停止等严重的问题。
下面我们回顾一下数据库管理系统(DBMS)发展的50多年以来,在不同的发展阶段所面临的灾难或者故障类型,故障的可能损害以及故障处理的方法。
不同时代的数据库管理系统面对的灾难的范围和容灾需求
经典数据库时代(单机)
单机数据库时代,DBMS实现了单机数据库事务处理,和单机事务的ACID保障。不过一旦数据库服务器故障,则数据库服务会停止,直到故障被排除,数据库服务器重新启动。
需要应对的灾难
硬件故障:
-
数据库服务器硬件部件损坏;
-
服务器断电或者其他原因导致服务器在数据库服务器运行期间退出
-
数据文件所在的存储介质损坏或丢失
软件故障:
-
操作系统bug或者人为错误导致操作系统异常退出,或者系统调用失败
-
软件bug或者人为错误导致DBMS进程异常退出(也就是DBMS进程crash,被kill掉等情况)
-
写入存储介质或者从其中读出的页面数据错误
可能产生的错误
-
已提交的事务的数据或者修改丢失
-
数据库系统的数据文件不可用导致数据全部或者部分丢失
-
没有直接修改DBMS的数据文件的情况下,其数据文件的内容损坏导致无法被 数据库服务器程序使用,从而丢失部分或者全部数据
对容灾能力的要求
1.如果存储介质未损坏,那么数据库服务器进程可以正常重新启动,并且重新启动后,所有已提交的事务的修改不丢失(durability),可以正常使用。
2.能够确保DBMS不会在任何情况下损坏其数据文件(首选),或者损坏后可以完全修复(比如mysql myisam引擎的repair工具)其数据文件。
3.能够发现数据文件页面的发生的数据错误并报告给数据库管理员,以便DBA使用备份的数据来恢复数据文件到最新备份的版本。
容灾能力的实现方法
单机数据库实现容灾能力最重要的方法就是经典的数据库事务处理技术,也就是write ahead logging(WAL)。通过为每个事务记录redo log和undo log,在数据库服务器启动时使用redo log做事务恢复,使用undo log回滚掉未提交的事务。刷任何数据页面P到数据文件之前必须将记录了修改这个页面的redo日志R先刷到事务日志文件。并且日志R与页面P通过P头部的lsn关联起来,即P.lsn = R.lsn,这样恢复机制就可以把每一个数据页面恢复到系统上次退出前最后一次刷redo log时的状态。 同时,在回滚段中记录每个修改了的数据行的前镜像变动(before image delta),也就是使用当前行数据得到修改之前的行数据的变化。这样数据库恢复机制就可以恢复已提交的事务,并回滚问提交的事务。
为了应对存储介质损坏和丢失,以及数据文件页面发生数据错误,DBMS需要发现并报告这样的数据错误,以便DBA使用最新的全量备份和增量备份恢复到最新备份的一致的数据版本。
单机数据库时代一旦服务器软硬件故障则数据库服务就会在一段时间内不可用。为了解决这个问题,在上世纪90年代开始业界逐步进入了高可用(high availability, HA) 时代。通过建立主备节点集群,从主节点持续传输对数据的增删改操作数据到备机节点并在备机实施这些操作,就可以将同样的数据存储多个copy到多个备机节点上面。一旦主节点发生故障无法工作,具备HA 能力的DBMS可以自动发现主节点故障并把合适的备机节点升级为新的主节点,从而不间断数据读写服务。
不过HA时代由于引入了更多的计算机服务器和网络来构成集群,因而可能出现故障的点也更多了,也就需要处理更多的故障情形。