专栏首页TopCoder高可用的本质: 复制

高可用的本质: 复制

服务和数据的高可用性本质上是靠“复制”来解决的,比如服务通过集群部署多台机器来完成,数据通过冗余的多副本机制来完成。对于服务来说,只需要部署多个实例即可,特别是无状态服务,常见的微服务(dubbo/spring cloud)几乎都是通过集群部署对外提供服务能力,更进一步的还可使用k8s+docker技术自动管理服务的副本容量;对于数据来说,需要通过数据复制来保证数据节点的一致性,由于数据是有状态的,因此实现难度较服务复制成本要高。

复制除了提高可用性之外(多机房数据复制提高机房容错性),还可以提高性能,比如读写分离、使数据副本离用户更近等,用户可优先就近读取数据。对于数据来说,常见的复制策略有主从复制、多主复制和无主复制,除了这些之外,还有一种常见的广义上“复制”策略-快照,比如Redis快照等。本文就针对上述几种复制策略展开分析,话不多少,Let's go~

本文后续讨论的复制无特殊说明都是针对数据复制来分析的,这里的复制讨论都是基于一个节点能保存所有数据为前提,因为数据量过大需要使用分区机制,而分区机制不在本文讨论范围之内 :(

主从复制

如果数据不随着时间而变化,那么只需复制一次即可,复制的难处在于数据始终在变化,因此复制时有很多权衡,比如是否同步,复制失败的副本如何处理等。主从复制是常见的复制策略,写操作发生在主节点,然后将更新的数据同步到从节点。基于主从的复制模型如下:

主从复制是许多数据库的内置功能,比如PostgreSQL(从9.0版本开始),MySQL,Oracle Data Guard和SQL Server等,当然也有一些非关系型数据库也支持此类功能,比如MongoDB等,不仅仅是数据库,像kafka(分区的多副本)和rabbitmq的队列为了实现高可用,也实现了主从复制功能,甚至一些存储设备本身也具有复制机制。

同步复制和异步复制

复制中一个重要的细节是同步复制还是异步复制,同步复制拥有更强的数据一致性保证,如果主库失效可以保证能在从库中找到对应数据;但是缺点也很突出,那就是从库会拖慢复制性能,如果从库故障或者网络原因,主库无法处理请求直到从库或者网络正常为止。在多从库场景中,针对网络异常或者单个从库故障的异常场景,可以使用quorum机制来保证大多数节点复制OK即可(比如zookeeper的主从同步机制),或者广播复制只要有一个从库复制OK即可(比如MySQL的半同步机制)。

异步复制拥有更好的性能保证,异步不影响请求的处理,主节点请求处理之后可以继续处理下一个请求,但是异步复制由于是最终一致性的体现,所以存在一定的数据不一致时期。如果主库失效,所有尚未同步给从库的数据会丢失。大多数场景下使用异步复制策略就能满足业务场景,如果业务对数据一致性有较高的要求,可以使用同步复制机制或者将请求发给主节点处理。

新从库

有时候需要替换故障从库或者新增从库,如何确保新从库和主库数据一致呢?简单的从主节点快照数据复制到新从库是不行的,因为数据始终可能发生更新;锁定主库然后进行快照复制也不值得推荐,因此这违背了高可用原则。启动新从库,理论上可以做到不停机,过程如下:

  1. 某个时刻获取主库快照,大多数数据库都具备该功能;
  2. 将快照复制到新从库节点并应用;
  3. 从库连接到主库,开始拉取快照触发之后发生变更的数据,这要求快照与主库复制日志中的位置可以精确关联,比如MySQL中的⼆进制⽇志坐标(binlog coordinates);
  4. 当从库追上主库之后,二者达到一致状态,可以继续处理后续数据变更了。

并不是所有场景都能不停机起新从库,比如升级从库时有的数据库复制协议不能向后兼容,还有分区扩容场景下的复制等。

复制日志

主从复制底层由以下几种实现方案,比如基于语句、基于WAL(预写日志)、基于行日志和基于触发器等,不同方案有不同的优缺点,下面简要分析下:

  • 基于语句:最简单的同步方式,主库将每个更新语句(udpate/delete/create)都转发给从库,从库解析之后应用到本地,这种方式看上去很合理,不过如果sql中包含非确定值函数的语句,则会造成主从库不一致,比如NOW()获取当前时间;
  • 基于WAL:数据库的数据故障恢复能力,一般都是基于预写日志实现,因为直接写到数据页或索引中相当于随机写,而预写日志是追加方式的顺序写,性能较高;PostgreSQL和Oracle等使⽤这种复制⽅法,主要缺点是⽇志记录的数据⾮常底层:WAL包含哪些磁盘块中的哪些字节发⽣了更改(比如Mysql redo日志),这使复制与存储引擎紧密耦合。如果数据库将其存储格式从⼀个版本更改为另⼀个版本,通常不可能在主库和从库上运⾏不同版本的数据库软件;
  • 基于行日志:也称为逻辑日志,关系型数据库通常是基于行粒度来描述数据的写入序列,对于插入的行,行日志包含所有列的值;对于更新操作,行日志包含列更新前后的值,MySQL的binlog日志就是基于这种方式实现的(statement模式下);
  • 基于触发器:上面几种复制策略都是数据库本身提供的机制,而基于触发器机制涉及到应用程序代码,当数据有更新操作时触发对应的用户程序进行对应的复制逻辑。

复制延时问题

异步复制模式下存在复制延时问题,当网络异常或者服务异常时延时问题更严重,有的业务对数据延时容忍度较大,比如用户信息更新对于其他用户可见来说,延时一定时间无所谓。在读写分离场景中,如果读都是走从库并且存在延时较长时,会出现用户刚更新完信息查看信息还是老的,好像刚才更新的数据丢失了,也就是说 ⽤户写⼊后从旧副本中读取数据,这种情况需要读写一致性来保证。这是⼀个保证,如果⽤户重新加载⻚⾯,他们总会看到他们⾃⼰提交的任何更新。它不会对其他⽤户的写⼊做出承诺:其他⽤户的更新可能稍等才会看到。它保证⽤户⾃⼰的输⼊已被正确保存。

在主从复制场景中,应该如何实现读写一致性呢?首先可以明确的是,在可能存在复制延时场景中需要从主库读取数据,比如当前用户查看更新自己的信息都走主库,或者用户更新完成之后读取数据都走主库等。如果是公共信息(多个用户可以同时编辑)的更新操作,可以在客户端增加更新时间戳,在时间戳最近一定时间内的所有读取操作都走主库。

多主复制

主从复制要求更新操作都走主库,如果客户端无法连接到主库则不能进行更新,而基于多主复制的策略中,允许多个节点接收写入操作。复制仍然以同样的⽅式发⽣:处理写⼊的每个节点都必须将该数据更改转发给所有其他节点, 称之为多领导者配置(也称多主、多活复制,比如多机房的异地多活)。在这种情况下,每个领导者同时扮演其他领导者的追随者。

多主复制场景

比较常见的多主复制场景是多数据中心,要求每个数据中心都有一个主库,每个数据中心内部使用主从同步,数据中心之间是多主复制,也就是一个数据中心的主库会复制其他数据中心主库的数据,多数据中心的多主复制如下图:

多数据中心对于公司服务运维能力要求较高,一般只有较大公司才玩的转,毕竟是有一定成本的。多数据中心对于服务来说,需要进行挺大的改造的,比如主键ID就需要接入分布式ID方案,不能采用单机数据库的ID自增方案;多数据中心的多主复制方案可以容忍数据中心停机而不中断服务,大大提高公司对外服务高可用性。

写入冲突

讨论多数据中心的写入冲突之前,先看下协同编辑场景中存在的写入冲突问题,协同编辑比如google docs允许多人同时对一个文件进行编辑操作,为了解决冲突,可以采取用户在编辑前锁定文档,然后编辑之后另一个用户才能编辑,但是这种方案锁粒度太大,因此可以使用更小粒度的方案,比如针对文档中的一个单元格进行锁定操作。

多领导者复制的最⼤问题是可能发⽣写冲突,这意味着需要解决冲突,常见的冲突解决可以采用版本思想,比如按照最新时间戳,最大版本号等,但是这种方案可能导致数据覆盖丢失问题;除了版本思路之外,还可以保留冲突数据,当用户再次查看数据时,让用户选择使用哪一个冲突版本的数据,比如git的merge冲突等。

无主复制

⼀些数据存储系统采⽤不同的⽅法,放弃主库的概念,并允许任何副本直接接受来⾃客户端的写⼊。由于无主复制没有主库概念,但是也要保证多副本机制,因此需要在客户端向多个从节点进行写操作,比如bookkeeper的写入策略,就是客户端并发些,只要收到大多数数据节点的ack就认为此次数据写入成功,这样就能保证数据的“一致性”。

快照技术

快照技术就是将当前数据状态存储到文件,便于存档,当故障发生时可以使用最近一次的快照恢复数据,由于快照执行一次的成本相对较大,但是为了保证快照数据具有实时性,因此会折中在多少次更新操作或者多长时间后触发一次快照操作,比如Redis会默认当900s内有一次更新操作,或者300s内有10次更新操作,或者60s内有10000次更新操作,就会触发RDB持久化(Redis数据快照)。常说的快照技术也就是全量数据保存,还有一种是增量数据保存,比如Redis中的AOF持久化策略。

小结

俗话说,要想提高可用性就进行一次复制操作;如果再想提高可用性,那就再复制一次。复制的本质是冗余数据,提高可用性,注意,复制也不是冗余越多越好,毕竟越多网络开销更大,从而影响整体服务性能,需要根据特定场景特定考虑,一般针对数据来说,冗余3份即可。

复制可分为同步复制和异步复制两种模式,一般来说前者有较高的数据一致性保证,后者有更好的性能保证。复制策略常见的有主从同步、多主同步和无主复制等,主从同步模式容易理解,无主复制需要应用程序多做一些额外的操作保证数据一致性。快照技术也是一种复制模式,常见于本地数据的归档保存,比如于故障恢复场景。复制是为了解决高可用问题,如果数据量更大,往往会使用分区+复制的策略来保证高性能和高可用性。

本文分享自微信公众号 - TopCoder(gh_12e4a74a5c9c)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-12-30

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • mysql用户管理

    服务器上mysql的用户有两种: 1.  本地用户   从本机连接mysql,例如: mysql部署在A服务器上,从A上连接mysql的用户 2.  远程用户 ...

    似水的流年
  • 反应式架构(1):基本概念介绍 顶

           淘宝从2018年开始对整体架构进行反应式升级, 取得了非常好的成绩。其中『猜你喜欢』应用上限 QPS 提升了 96%,同时机器数量缩减了一半;另一...

    joymufeng
  • 精准测试及其工具(连载3)

    1,将星云提供的lanyuan_v_3.sql导入到数据库中(右键新建lanyuan_v_3),如图29所示。

    小老鼠
  • 模糊测试(fuzzing)是什么

    大学时两个涉及“模糊”的概念自己感觉很模糊。一个是学数据库出现的“模糊查询”,后来逐渐明白是指sql的like语句;另一个是学专业课时出现的“模糊测试”。

    小老鼠
  • 警告:MySQL-server-5.6.21-1.linux2.6.x86_64.rpm

    摘要: CentOS安装rpm安装MySQL时爆出警告: 警告:MySQL-server-5.6.21-1.linux2.6.x86_64.rpm: 头V3 D...

    似水的流年
  • Oracle 的安装与基本操作

    在计算机信息安全领域中,数据库系统无疑有着举足轻重的地位。例如,微软的SQL server、IBM的DB2,以及甲骨文公司的Oracle、MySQL等,都是比较...

    小手冰凉
  • centos下完全卸载mysql

    1、yum remove mysql mysql-server mysql-libs compat-mysql51

    似水的流年
  • SAP错误消息调试之七种武器:让所有的错误消息都能被定位

    Jerry在2018年开始用中文在微信公众号平台上写作之前,在SAP官方社区上总共写了639篇英文博客。

    Jerry Wang
  • 我对单元测试和测试驱动开发的见解

    (废话想说一些:如果我们听到一个陌生的概念,不去追问它是什么,它有什么用?直接进行任务去完成这个概念描述的事,那么,我们可能很难理解我们为什么要这么做,也可能做...

    小老鼠
  • 安全测试工具(连载5)

    SQL Map是一款自动化的SQL注入工具,其主要功能是扫描,发现并利用给定的URL的SQL注入漏洞,目前支持的数据库是MySQL、Oracle、Postgre...

    小老鼠

扫码关注云+社区

领取腾讯云代金券