【AICon】 如何构建高效的 RAG 系统?RAG 技术在实际应用中遇到的挑战及应对策略?>>> 了解详情
写点什么

提到数据库一致性,每个开发人员都应该知道这些

  • 2020-09-09
  • 本文字数:2844 字

    阅读完需:约 9 分钟

提到数据库一致性,每个开发人员都应该知道这些

数据存储提供的一致性保证往往有悖于你的直觉,分布式存储尤是如此。有许多一致性模型对各种一致性保证给出了定义,本文将借助这些模型探讨这些一致性保证的区别是什么,你需要结合自己的需要做出怎样的权衡。


本文最初发布于Roberto Vitillo个人博客,InfoQ 中文站翻译并分享。


设象一下,如果给一个变量赋了值,然后立即读取,却发现读不到它,会不会很是让人抓狂呀!


x = 42assert(x == 42)  # 抛出异常
复制代码


然而,使用具有弱一致性保证的分布式数据存储时还真有可能发生这样的情况。“但是等等,难道不应该由数据库为我处理一致性问题吗?”你可能会提出这样的问题。答案是,能够尽早读取到更新的值取决于数据库提供的保证。


为了提供高可用性和性能,一些数据库所提供的一致性保证与你的直觉并不相符。还有一些软件(比如Azure的Cosmos DBCassandra)则将选择权交给你,由你自己选择是想要更好的性能还是更强的保证。因此,你应该知道需要做哪些权衡。

剖析数据库请求

让我们看看,当你向数据库发出一个请求时会发生什么。在理想的世界中,你的请求会被立即执行:



但现实是残酷的,我们的真实世界可没那么理想——你的请求需要先发到数据存储,由数据存储进行处理,最终向你返回一个响应。所有这些动作都需要时间,而且都不是瞬时发生的:



数据库能够提供的最佳保证是在调用时和完成时之间执行这个请求。你可能会认为这似乎没什么大不了的(毕竟,你常常写的是一些单线程应用程序),如果你给 x 赋值为 1 然后读取它,那么你希望得到的就是 1,前提是没有其他线程也给 x 赋值。但是,一旦你开始与数据存储打交道,为了实现高可用性和可伸缩性而把它们复制到多台机器上,那么读取到什么值就真的很难预测了。为了搞明白为什么会这样,我们将探讨一下,设计师在实现分布式数据库的简化模型时需要做出哪些权衡。


假设我们有一个分布式的键-值存储,它由一组副本组成。副本之间选举出了一个 leader,这是一个唯一可以接受写操作的节点。当这个 leader 接收到一个写请求时,它会将其异步广播给其他副本。尽管所有副本以相同的顺序接收相同的更新,但它们接收到更新的时间会有所不同。


现在要求你想一个策略来处理读请求,你会怎么做呢?嗯……,读取可以由 leader 负责,也可以由副本负责。如果所有读取都要通过 leader,那么吞吐量将受到单一节点处理能力的限制。或者,任何副本都可以负责任何读取请求——这样肯定是可伸缩的,但是两个客户端(或观察者)对系统状态的看法可能不同,因为副本可能落后于 leader,或者介乎各复本之间。


直觉告诉我们,观察者对系统的看法是否一致与系统的性能和可用性之间需要进行权衡。要理解这种关系,我们需要来精确地定义什么是一致性。我们将借助于一些一致性模型,它们就观察者能够体验到的对系统状态看法给出了正式的定义。

强一致性

如果客户端仅向 leader 发送写和读,那么每个请求似乎都是以原子的方式发生于一个非常特定的时间点,就好像只有一个数据副本一样。无论有多少副本,或者落后多少,只要客户端总是直接询问 leader,以它们的视角来看,就只有一个数据副本。


因为请求不是即时提供服务的,而且只有一个节点为其提供服务,所以请求它是在调用和完成之间的某一时刻执行的。换一种方式来思考,一旦某一请求完成,它的副作用对所有观察者都是可见的:



由于请求在其调用和完成之间的时间内对所有其他参与者都可见,因此必须实施实时保证——这种保证被定义为一种称为线性化或强一致性的一致性模型。线性化是系统能够为单对象请求提供的最强的一致性保证。


如果客户端向 leader 发送了一个读请求,当请求到达时,接收请求的服务器认为它仍然是 leader,而实际上已经被废黜了呢?如果是前任 leader 来处理这个请求,系统将不再是强一致的。为了防止这种情况,这个假定的 leader 首先需要与大多数副本取得联系,以确认它是否仍然是 leader。只有当它还是 leader 的时候,才被允许执行请求并将响应发送回客户端。这大大增加了读取服务所需的时间。

顺序一致性

现在,我们已经讨论了通过 leader 序列化所有读取操作。但是这么做会产生一个单一的阻塞点,从而限制系统的吞吐量。其中最重要的一点是,为了处理读取,leader 需要与大多数副本交互。为了提高读取性能,我们也可以允许副本来处理请求。


尽管某个副本的版本可能会落后于 leader,但它总是会以与 leader 相同的顺序接收新的更新。如果客户端 a 只查询副本 1,而客户端 B 只查询副本 2,两个客户端会看到状态是在不同的时间演变的,因为副本并不完全同步:



这个一致性模型称为顺序一致性,在此,操作对于所有观察者而言都是以相同的顺序发生的,但就操作的副作用何时对观察者可见不提供任何实时保证。缺乏实时保证是顺序一致性与线性化的不同。


保持与队列同步的生产者/消费者系统是该模型的一种简单应用——生产者节点将条目写入队列,消费者读取队列。生产者和消费者以相同的顺序查看这些条目,但是消费者落后于生产者。

最终一致性

尽管我们设法提高了读取吞吐量,但我们不得不把客户端与副本绑定在一起,如果副本宕机了怎么办?我们可以通过允许客户端查询任一副本来提高商店的可用性。但是,这会在一致性方面付出高昂的代价。假设有副本 1 和副本 2 两个副本,其中副本 2 落后于副本 1。如果客户端查询了副本 1,然后再查询副本 2,它将看到过去的状态,这可能会令人非常困惑。客户端的唯一保证是,当对系统的写操作停止时,所有副本最终将收敛到最终状态。这种一致性模型称为最终一致性。


在最终一致性的数据存储之上构建应用程序是一项挑战,因为其行为与你在编写单线程应用程序时所习惯的行为不同。有一些小错误可能会出现,它们难以调试和重现。然而,若要保证最终一致性,并不需要线性化所有的应用程序。你需要自主做出选择,判断数据存储所提供的一致性保证是否满足应用程序的需求。如果你想要跟踪你的网站的访问用户数,那么最终一致性的存储则非常合适,因为查询返回的数字稍微有些过时并不重要。但如果是支付处理,则肯定需要强一致性。

PACELC 定理

除本文提到的之外,还有很多其他的一致性模型。但无论是哪个模型,其背后的规律均不会与直觉相违背:一致性保证越强,单个操作的延迟就越高,出现故障时存储的可用性就越低。


PACELC定理已经明确阐述了这一关系。它指出,如果分布式计算机系统存在网络分区§,则必须在可用性(a)和一致性©之间做出权衡;反之(E)如果没有,也必须在时延(L)和一致性©之间做出权衡。


我编写了《系统设计》一书,在这本书中我探讨了为保证高可用性和性能还可以做哪些数据存储的权衡,比如隔离保证,即防止一个事务内的操作干扰并发运行的其他事务。


原文链接:


https://robertovitillo.com/what-every-developer-should-know-about-database-consistency


译者简介:冬雨,小小技术宅一枚,从事研发过程改进及质量改进方面的工作,关注编程、软件工程、敏捷、DevOps、云计算等领域,非常乐意将国外新鲜的 IT 资讯和深度技术文章翻译分享给大家,已翻译出版《深入敏捷测试》、《持续交付实战》。


2020-09-09 13:361286
用户头像
陈思 InfoQ编辑

发布了 576 篇内容, 共 259.9 次阅读, 收获喜欢 1291 次。

关注

评论

发布
暂无评论
发现更多内容

消息队列存储消息数据的MySQL表格

Pengfei

JavaScript高级程序设计(第4版)-生成器

掘金安东尼

JavaScript 前端 7月月更

【云驻共创】【HCSD大咖直播】亲授大厂面试秘诀

恒山其若陋兮

7月月更

数据中台建设(七):数据资产管理

Lansonli

数据中台 8月月更

elasticsearch安装和使用ik分词器

程序员欣宸

Java Elastic Search 8月月更

Unity 之 图集属性详解和代码示例 -- 拓展一键自动打包图集工具

陈言必行

7月月更 签约计划第三季

架构实战营模块 8 作业

Naoki

架构实战营

《ArchSummit:时代的呐喊,技术人听得到》

后台技术汇

后台开发 架构师 ArchSummit

从RabbitMQ平滑迁移到RocketMQ技术实战

vivo互联网技术

RocketMQ RabbitMQ 消息队列 消息中间件 Apache RocketMQ

面试突击69:TCP 可靠吗?为什么?

王磊

Java面试题

如何设计高可用高性能中间件 - 作业

阿拉阿拉幽幽

elasticsearch实战三部曲之三:搜索操作

程序员欣宸

Java elasticsearch 7月月更

一文带你了解 Grafana 最新开源项目 Mimir 的前世今生

Grafana 爱好者

Mimir Observability

Prometheus 监控什么时候可以使用 PushGateway

耳东@Erdong

Prometheus PushGateway 7月月更

研发过程中的文档管理与工具

Java 文档 构架 文档管理

架构实战营模块八作业

融冰

新书上市 |《谁在掷骰子?》在“不确定性时代”中确定前行

图灵教育

如何撰写出一篇优质的数码类好物推荐文

石头IT视角

内核对设备树的处理

贾献华

7月月更

Web3.0:构建 NFT 市场(一)

devpoint

区块链 NFT 7月月更

leetcode 665. Non-decreasing Array 非递减数列(中等)

okokabcd

LeetCode 贪心算法 算法与数据结构

阿里技术大牛耗时几个月整理出这份Spring Cloud Alibaba学习笔记

了不起的程序猿

程序员 java\ SpringCloud Alibaba

【PIMF】OpenHarmony 啃论文俱乐部—盘点开源鸿蒙三方库【3】

离北况归

OpenHarmony

一文概述:VPN的基本模型及业务类型

穿过生命散发芬芳

vpn 7月月更

消息队列消息存储设计(架构实战营 模块八作业)

Gor

基于mysql的消息队列设计

Geek_e8bfe4

设计消息队列存储消息数据的MySQL表格

Geek_7a789a

学习Java的网站

玄兴梦影

Java core

国内市场上的BI软件,到底有啥区别

石臻臻的杂货铺

7月月更

Apache EventMesh 分布式事件驱动多运行时

老周聊架构

云原生 事件驱动架构 全球架构师峰会 ArchSummit 8月月更

我从Vuejs中学到了什么(一)

真嗣

前端 vuejs

提到数据库一致性,每个开发人员都应该知道这些_语言 & 开发_Roberto Vitillo_InfoQ精选文章