系统设计笔记

作为分类目录的一个补充,在这里按照功能类别对系统设计开发中的一点心得和笔记作一个索引。其中部分是根据自己在查找网络资料时找到的内容的整理与演绎,在此感谢所有那些无私分享经验的人们。

分布式系统

最终一致性(eventual consistency)引

一致性设计在分布式系统中是一个重要问题。如果一个系统同时使用多个子数据系统来存储与读取数据,就必须设计满足功能需求的一致性定义。如果系统对不同数据子系统进行操作的结果不一致,不但可能会使用户困惑,更可能引发更严重的数据问题或系统错误。一致性有多种级别,适用于不同的业务场景。对于金融等对数据一致性要求较高的行业,传统的事务可以提供较高的一致性保证。对于分布式系统等对性能(performance)和可用性(availability)要求较高的场景,牺牲一定的强一致性来换取更好的用户体验也可接受。最终一致性的具体行为根据实际需求不同,并无严格而精确的定义。本文仅作为一个引子,介绍最终一致性及与其相关的一些基本概念,方便读者对最终一致性有初步的认识,以便进一步阅读其他文章与资料,设计适合自身业务需求的系统数据一致性。

衍生数据系统

衍生数据(derived data)指的是可以由另一些数据通过某种可以复现的处理来再次生成的数据。通常,衍生数据用于加速读取数据库中的某些数据。索引(index)和缓存(cache)都是典型的衍生数据。如果衍生数据丢失,仍可以通过原始数据再次生成。

单个数据库系统中的索引属于其所存储数据的衍生数据。有时,数据库的索引可能会由于性能或成本考量而被维护在另一个系统之中,此时,该索引系统即为一种衍生数据系统。该索引系统中的数据可以通过数据库中存储的数据重新生成(即使往往开销过大而不实际),反之则不行。这种情况下,如何维护源数据库数据与索引数据库系统之间数据的一致性,值得系统设计者考虑。

事务与 ACID

事务(transaction)是一种传统的确保数据一致性的方式。在一个系统中,各种类型的错误都可能会破坏数据的一致性。网络问题、硬件故障、远程服务不可用等原因都会导致数据操作部分或彻底失败。

事务可以将一组数据读写操作合并为一组,构成一个逻辑单元,作为一个单独的数据操作执行。一次事务操作要么完全成功(提交),要么彻底失败(中止并回滚)。如果事务失败,它能被安全地再次执行。

ACID 是原子性(atomicity)、一致性(consistency)、隔离性(isolation)与持久性(durability)的首字母缩写,它通常用来描述事务的性质。

原子性减轻了多步操作中途出错时造成的问题。如果一此事务失败,原子性将确保没有数据发生变化,事务可以被安全地重新提交。

一致性事实上不是数据库的一种属性,而由具体的应用需求定义。一个应用程序可以借助原子性与隔离性来实现一致性,而这可能不仅仅是单个数据库系统的问题。一致性有多种等级,在此不具体展开介绍。

隔离性与竞争(race condition)及并发(concurrency)有关,用于解决多个事务同时执行时的相互干涉。

持久性在数据库系统中指数据应当在事务提交成功后能安全而长久地被保存,且不会因系统故障而丢失。

事务可以在很大程度上确保数据质量。然而,最近流行的 NoSQL 数据库大多不提供事务支持,以免它过高的性能开销损害它们试图提供的高可用性。 从事务的角度来看,数据存储与索引是不同的数据库对象。 许多数据库系统,包括微软 Azure Cosmos DB 等分布式数据库都提供了单对象事务支持,但并未提供完全的多对象事务支持。

异构分布式事务

异构分布式事务( heterogeneous distributed transaction)指的是事务的参与者可能由两种或多种不同的技术组成。例如,由不同供应商提供的数据库,各司其职的数据库与索引系统,甚至是消息分发系统等非数据库系统。异构分布式事务也需要满足提交(commit)的原子性,这比实现数据库内部的事务更为困难。

两阶段提交(2PC,Two-Phase Commit)是一种著名的强一致性保证。对于一次事务请求,所有子系统都将确保数据被写入或最新的数据被读取。对于由一个索引系统和一个数据库系统构成的异构分布式系统,在完成一次两阶段提交后,索引系统中存储的数据必然能反映数据库系统的最新情况,对数据库系统的更新操作也总会反应在索引系统中。

重试策略

重试(retry)即再次执行某一操作。在设计数据系统时,重试策略也是一个需要考虑的问题。不恰当的重试可能会导致以下问题:

  • 如果重试请求的响应因网络问题而没能返回,再次重试可能会使开销倍增
  • 如果问题在于系统超负载,重试可能会导致问题进一步恶化
  • 重试只能解决暂时性问题(如死锁、隔离性被违反/isolation violation,或短暂的网络故障等),因此在重试前有必要判断重试是否可能解决问题

因此,在设计重试策略时,超时、最大重试次数、两次重试之间的间隔等都需要纳入考虑。

最终一致性与BASE

与事务提供的 ACID 属性不同,最终一致性提供的一致性保证也被称为 BASE(Basic Available, Soft state, Eventual consistency)。BASE 确保如果系统之后没有更多的数据操作,最终对系统的所有访问都将返回相同的结果。BASE 更多地是确保系统使用可用,但在系统数据收敛之前,它可能返回不同的结果。 最终一致性的实际行为由具体应用定义,无法统一阐述。

采用最终一致性的数据系统通常不要求数据操作失败时执行回滚(rollback)。用户或系统日志将得知操作失败,但在另一次成功的操作之前,数据的不一致问题并不会被自动修复。

之所以最终一致性会出现,很大程度上是因为如今的网路应用常常要处理规模巨大的数据与请求。此时,更强的一致性往往并不现实,高可用性反而是更系统更核心的设计目标。

_

以上是讨论最终一致性之前可能需要了解的一些前置概念的简述,以帮助读者快速了解系统数据一致性设计时的一些主题,并能有目标地查阅更多资料与文献。水平有限,如果纰漏,欢迎批评指正。