《深入理解分布式系统》之分布式数据基础

本文是阅读深入理解分布式系统第三章分布式数据基础时的笔记。

业务系统的成长初期,大都简单而美好,专心交付需求,补齐特性短板,追赶竞品,满足客户诉求。此时由于业务不太复杂,业务量还不足,因此系统规模较小,性能压力不大。

随着业务的发展,度过了萌芽期,坚持了下来,存活的时间足够长,此时逐渐遇到了幸福的烦恼,除了要满足客户各种各样的需求,同时随着业务量的增加,系统需要满足客户对性能的诉求。

此时系统中的存储系统的压力逐步增加,开始不堪重负,宕机、故障、性能优化成为了日常谈资和团队的改进方向。

对于使用MySQL来承载互联网业务的业务交付团队来说,读写分离、分表分库成为了优秀实践,在不同的业务上反复使用,百战百胜。

当年的InfoQ等大型技术会议上,类似的话题是热门话题,各大厂的技术专家热情分享相关主题的经验和教训,而听众如痴如醉,沉醉其中不可自拔。

首先,从硬件的能力讲,单机的硬件设备,处理能力方面存在天花板,而提升硬件的规格,可以一定程度上提升天花板,但不能消除天花板。随着业务量的快速暴涨,提升硬件从而提升处理能力的收益越来越低,而单机带来的缺陷越来越让人无法容忍,比如单点故障、启动慢、恢复数据耗时长等。

于是专家想了很多办法,比如:

  • 从业务的I/O特征出发,将读和写操作分别由不同的DB来处理,业务称之为读写分离。
  • 从业务场景出发,将数据划分为当前业务数据和历史业务数据,分别由不同的系统承载。
    • 对于历史业务数据,只提供受控的查询能力。
    • 对于当前业务数据,提供完整的访问能力。
  • 从处理特征出发,划分为OLAP和OLTP。
    • OLTP,联机事务处理,适合交易类业务,可以选型使用行式关系型库。
    • OLAP,联机分析处理,适合报表、分析类的业务,可以选型使用列式关系型数据库或者行式关系型数据库或者Hive等。
  • 从业务自身的特征出发,使用分库分表的方式,切割业务数据。比如:
    • 使用用户的归属位置,不同省市的用户放到不同的表里。
    • 使用用户的电话号码,将不同的号码段的用户放到不同的表里。
    • 将访问量大的字段,放到一张表里,其它不常用字段放到另外的表里。
    • 将经常一起访问的字段,放到一张表里,其它字段放到另外的表里。

数据的分区

面对更大规模的数据集,不同子集具备相同的处理逻辑,采用分治的思路,划分为多个子集合,分而治之。使用增加节点、扩大集群规模的方式来增加处理能力,从而规避提升设备的硬件规格时遇到的天花板问题。

通过分区,提升数据的可管理性、可用性、可扩展性。

将数据分区的前提,数据的处理方式相同,针对分区的处理结果,经合并后,可以得到整体的处理结果。

常见的分区方案:

  • 水平分区,按照一定方式,将数据分布到不同的表里,理论上可以无限拆分。
  • 垂直分区,按列拆分,受限于表的列的数量有限,因此使用时相对受限。

分区查询的前提:

  • 查询条件中必须有分区键。

分区的常见难题:

  • 拆分后,处理数据时的事务性。
  • 多个分区之间的数据关联查询。
  • 对多个分区的数据进行排序。
  • 对数据进行范围查询,包括翻页查询。
  • 热点问题,比如:
    • 存储位置的热点。
    • 存储量大导致的热点。
    • 访问位置的热点。

分区的实现方案,比如:

  • 基于业务特征,比如用户的归属位置、号码段等。
  • 基于Hash算法,比如使用Hash算法来用户标识的Hash值,进而选择用户标识对应的存储位置。
    • 依赖Hash算法来提供访问效率、计算成本、散列效果的保证。
    • 通常适合指定条件的读写操作,不适合范围遍历。
    • 当节点出现故障时,涉及相当规模的数据的迁移操作。
    • 更换Hash算法时,可能导致所有数据的迁移操作。
  • 基于一致性Hash算法,改善Hash算法引入的问题。

数据的复制

通过分区,将数据集划分为不同集合,保存在集群的不同节点上,可以提供可管理性、可用性、可扩展性,但并没有解决可靠性。

对于提升数据的可靠性,常规的思路为相同的数据,增加多个副本,当出现意外时,只要有一个副本存在,则依然可以提供访问能力。

多副本同时引入了一些新的问题,比如:

  • 副本的数据。
  • 复制的内容,比如:
    • 复制操作本身。
    • 复制受影响的数据本身。
  • 复制操作的粒度,比如:
    • 完整的数据,大小可能不固定。
    • 数据的一部分,数据的大小固定,边界对齐。
  • 复制操作的时机。
  • 复制失败时策略,比如失败的判定原则、重试、更换节点等。
  • 复制的时间模型,比如同步、异步、半同步等。
  • 多副本之间的一致性。
    • 一致性检测。
    • 不一致现象出现后,修复异常副本。
  • 副本之间的关系,比如:
    • 一个为主副本,其余为从副本。主失效且无法恢复,则由从副本替换。
    • 多个主副本,其余为从副本。
    • 副本之间地位平等,对等替换。
  • 多副本对业务的影响,比如:
    • 性能的影响。
    • 存储空间的影响。
    • 占用的带宽。
    • 读、写的访问顺序。
    • 访问模式,比如:
      • 只有主副本支持读、写操作,从副本只支持同步数据。
      • 只有主副本支持写操作,从副本提供读操作。
      • 所有副本均支持读、写操作。
      • 所有副本同时写入和读出。
  • 副本相关的元数据,如何管理。

提升性能的常见策略,比如:

  • 就近访问。
  • 提升吞吐量,比如:
    • 多副本同时支持读、写。
    • 多节点支持同时读、写。
      • 同一份数据的不同部分,支持同时读、写。
      • 不同数据,支持同时读、写。

对于单主复制,注意点:

  • 选主的逻辑。
  • 主、从承载的业务。
    • 主承载读、写操作,从作为备份,仅在失效时启用。
    • 主承载写操作,从承载读操作。
  • 写操作的流程,比如:
    • 先写主,成功之后,由主向从复制。
    • 先写主,同时写从,写主成功即成功,由主完成其余的写操作。
    • 同时写主、从,都成功,才成功。
  • 读操作的流程,比如:
    • 主处理读操作。
    • 从处理读操作。
    • 主、从都响应读操作。

对于多主复制,注意点:

  • 选主的逻辑
    • 当主失效后,从副本竞选为主副本。
    • 当主失效后,在容忍范围内继续工作,从副本不竞选为新的主副本。
  • 写操作的流程,比如:
    • 先写一个主,成功之后,由主向其余副本复制。
    • 同时写主,一定量的主成功,即成功。
    • 同时写主,所有主都成功,才成功。
  • 读操作的流程,比如:
    • 主处理读操作。
    • 从处理读操作。
    • 主、从都响应读操作。

对于无主复制,注意点:

  • 写操作的流程,比如:
    • 先写一个副本,成功之后,向其余副本复制。
    • 同时写所有副本,一定量的副本成功,即成功。
    • 同时写所有副本,所有副本都成功,才成功。
  • 读操作的流程,比如:
    • 任意一个副本响应读操作。
    • 所有副本都响应读操作。

常见的业务指标,比如:

  • 操作时延。
  • 吞吐量。

常见的问题,比如:

  • 热点问题。
  • 单点问题。
  • 数据冲突。
  • 脑裂问题。