携程Dynamo风格存储的落地实践

作者|根泰,携程高级后端开发工程师,关注数据存储和数据库领域;遐龄,携程研发总监,关注大数据存储、性能调优。

Dynamo风格数据库来源于亚马逊的Dynamo: Amazon’s Highly Available Key-value Store 论文,在该论文中论述了一种无主复制的数据库,受此启发,携程酒店开发了多存储介质预定库Hare和高可用性高性能的动态信息存储服务InfoKeeper。本文将介绍Dynamo风格的无主复制数据库,及其在携程酒店的实践。

一、Dynamo风格数据库

在分布式系统中,为了提高数据的可用性和性能,通常会将同样的数据复制多份,分担读写请求和主备切换,在复制形式上,主要有单主复制、多主复制、无主复制。

1.1 单主复制

在单主复制中,只有一个主节点可以写入,数据从主节点复制到从节点,从节点可以承担读请求,单主复制的结构简单,易于实现,没有数据冲突。但是写入依赖主节点,写入性能由主节点的性能决定,主从节点之间存在复制延迟(在从节点上读取到的数据不一定是最新的数据),在主节点发生故障进行主从切换的时候存在数据丢失或者写入的不可用。

1.2 多主复制

在多主复制中,有多个主节点承担写入的请求,相比于单主复制,数据的写入请求被多个主节点分担,但主从节点之间的复制延迟问题依然存在。除此之外,两个主节点对同一份数据的并发写入需要冲突解决机制决定以哪次写入为准。

1.3 无主复制

Dynamo风格的数据库就是无主复制,写入的请求不会经过特定的主节点复制到从节点,所有的节点都可以承担读取和写入,容忍写入时的不一致,在读取时解决不一致。

假设一个数据库中有三个节点,存储的键值对X=1。在下面的示意图中,三个节点都收到了同一个写入的请求,C节点写入失败。

此时,三个节点内键值X对应的value是不一样的,收到读请求后自然会返回不同的值。

从上帝视角看,此时此刻,键值X对应的value应该是100,但对于一个运行的系统,需要一个机制解决下面两个问题,这个机制称为仲裁。

对于读取到的不同的值,哪个值为正确的值?

读取多少个节点才能保证读取到正确的值?显然,如果只从C节点上读取,那不管问题1的答案是什么,都得不到正确的值。

1.4 严格仲裁

使用时间戳或者版本号判定哪个值为正确的值:时间戳最大的或者版本号最大的,代表数据是最新的,最新的数据就是正确的数据。

R+W>N,N:​总的节点个数,W: 判断写入成功所需的节点个数,R:读取时至少需要读取成功的节点个数,W+R>N时总会读到最新的数据。如下图所示,蓝色的节点表示写入成功的节点,即W=3,当R=3时,读取成功的节点和写入成功的节点一定会有交集。W越小,写入的可用性更高,写性能越好,R越小,读的可用性更高,读性能越好。

假设单个节点的可用性P=99.9%,以此来计算无主复制时的读和写的可用性,不同的R、W的可用性情况如下表所示,以N=3举例,R=1时读的可用性等于。

节点的数量

R、W

读可用性

写可用性

2

R=2 W=1

99.8%

99.9999%

R=1 W=2

99.9999%

99.8%

3

R=2 W=2

99.999%

99.999%

R=3 W=1

99.7%

99.9999999%

R=1 W=3

99.9999999%

99.7%

根据表中所示,在N=3,R=W=2时,读和写的可用性都比单个节点的读写可用性高,这也是Dynamo风格数据库使用的推荐配置。

1.5  宽松仲裁

在严格仲裁时,如果达不到严格仲裁的R+W>N时会返回调用端错误码,假设N=5,W=R=3,读取的时候读了5个节点,但是三个节点读失败了,只有两个节点读成功了,此时如果以两个节点的结果比较版本号或者时间戳,得到的数据有可能是错误的,也有可能是正确的。

如果我们的系统能够忍受返回不新鲜的数据的可能性,那么使用宽松仲裁是提高系统可用性的一种办法。我们来定义宽松仲裁:在系统达不到严格仲裁的条件时,利用仅有的条件返回调用端结果,注意,必须是先尝试满足严格仲裁,达不到严格仲裁时使用仅有的条件返回调用端结果,比如,N=5,R=W=3,在读取数据时先读取三个节点,两个节点读取失败,为了满足严格仲裁,再读取剩余的两个节点,但是一个成功,一个失败,此时一共有两个节点读取成功,使用两个节点的数据宽松仲裁,得出结果,而不是一开始就只读两个节点,这两种方式读取到错误数据的概率差别很大。

使用宽松仲裁时得到正确数据的概率如下表所示,假设单个节点的可用性P=99.9%,N=1,R=W=1时,读和写的可用性是,N=3,R=1,W=1时读到错误数据的概率

节点的数量

R、W

读可用性

写可用性

读到正确数据的概率

2

R=1 W=1

99.9999%

99.9999%

99.9998%

3

R=1 W=2

99.9999999%

99.999%

99.9999997%

R=2 W=1

99.999%

99.9999999%

99.9999997%

R=1 W=1

99.9999999%

99.9999999%

99.9999994%

无主复制的数据库在写入的时候容忍了部分节点的不一致,但是我们希望每个节点上的数据尽可能的完整,这就需要节点版本补齐。

1.6 节点间的版本补齐

1)写修复,节点写失败在写入的时候已经是被感知到的,可以通过消息队列等方式异步的在写入失败之后补偿修复。

2)读修复,在读取数据的时候,已经知道了节点间的数据不一致,此时可以根据仲裁得出的数据来修复版本滞后的节点上的数据。

3)巡检,主动的扫描介质间的数据,根据仲裁的结果修复数据。

二、由无主复制向多介质存储扩展

前面介绍无主复制数据库的时候一直在使用“节点”这个概念,这里对节点做一个定义:运行同一套代码的、拥有完全相同功能的进程,比如Redis的master和slave节点。

在携程酒店的预定订单和价态信息存储中,选择合适的存储介质一直是一个核心的技术问题,我们希望数据不仅在介质内有互备(Redis的master和slave),还能有介质间的互备(比如Redis和Trocks),因为同一个存储介质总是拥有相似的运作机制,同时出问题的概率更高。

在多介质数据存储中,我们对前面理论部分用存储介质代替“节点”后的语义就是:数据同时写到多个存储介质中,容忍部分存储介质的写入失败,在读出数据时,仲裁决定整个系统中数据最终的值,整个系统能够容忍单一存储介质级别不可用的情况,系统的稳定性从容忍单个节点故障提升到了存储介质级别。

三、Hare:多存储介质的预定库

Hare的名称来源于成语“狡兔三窟”,数据存储在多个介质中,以保证数据的安全。Hare承担携程酒店预定库的功能,主要用于存储在用户下单的各个环节(创单、支付、提交)中产生的订单相关数据。在订单完成提交后从Hare同步到订单库,进入订单处理环节。Hare的架构图如下图所示,应用层代码管理底层的Redis、Trocks、Hbase的写入和读取,以及仲裁返回给调用端的数据。介质间版本补齐使用写修复。

Hare内部采用宽松仲裁,N=3,W=1,R=1,使用版本号判断最新版本。需要特别指出的是,W=1并非任何一个介质写入成功就算成功,Hare内部“期望”的写入成功个数为2,但是当所有介质写入完成后,写入成功的介质个数依然没有达到2,就会优先考虑可用性,写入成功的个数等于1也算写入成功。

当W=1时,严格仲裁的R应该等于3,Hare内部会读所有的3个介质并比较版本号,返回版本号最大的数据。但如果读完所有数据,依然只有一个介质读成功,还是会以成功的这个介质的数据返回给调用方。所以宽松仲裁的含义是,在使用严格仲裁但达不到严格仲裁的条件时,优先保证可用性。写入和读取时的流程图如下所示。

四、InfoKeeper:高可用高性能的动态信息存储

InfoKeeper是对Hare架构在酒店价态量存储场景下的改进,Hare作为下单场景用,对性能要求较低,但对数据的可靠性要求更高。但在酒店的价态量存储中,对性能要求更高,数据可靠性要求较下单场景低,所以InfoKeeper中存储介质的个数较Hare更少,选择了Redis和Trocks两个存储介质,仲裁的N=2,W=1,R=1。

我们将InfoKeeper中参与仲裁的介质称为主介质(图中绿色),将只会写入但是不参与仲裁的介质称为从介质(图中淡蓝色),从介质的写入是否成功都不会影响对客户端的响应。介质间的版本补齐使用写修复。在酒店价态量存储中架构图如下。

InfoKeeper写入的流程图如下。

InfoKeeper现在支持的存储介质有redis、trocks、mysql、es、hbase、oceanbase、Tikv、qmq、kafka、soa。qmq通常作为推送增量的方式,kafka用于推送离线数据,soa用于通过soa接口调用的方式更新服务端的缓存。因为接口较消息队列延时更低,所以soa面向对缓存新鲜程度要求很高的使用方,比如酒店查询服务,在InfoKeeper中将消息队列和soa接口当作一种存储介质看待,只是这种存储介质不能提供读功能。

InfoKeeper中存储的数据目前在百亿级别,InfoKeeper完成了这些数据的存储、承担了40万QPS的读能力,以及数据从存储方到各个使用方的高效流转。得益于强大的读能力(强大的读写能力主要是因为选择了性能更好的KV型存储介质为主介质,可以根据数据读取方对性能和数据新鲜度的要求,选择对应的存储介质和仲裁的方式),一些散落在各个使用方的缓存废弃,改为直接从InfoKeeper读。根据统计,InfoKeeper节省了20%的硬件成本,数据的流转效率较以往使用关系型数据库存储,使用方从关系型数据库拉取的方式大大提高,还消除了关系型数据库的单点性能限制。

建立缓存的一种新模式

在InfoKeeper前面的架构图中,如果将主介质改为关系型数据库,从介质改为redis,就实现了为DB建缓存的目的,只是把从DB拉数据改为了主动往redis写数据,减轻了DB的压力。如果需要建多份缓存,只需要多挂几个从介质就可以实现。目前酒店的房型通用缓存就是使用这种方式。

五、设计目标的验证

怎么确认多介质存储系统符合设计预期,能够容忍存储介质级别的故障?Hare上线6个季度,InfoKeeper上线4个季度以来,我们在每个季度都会对Hare和InfoKeeper做单个介质注入故障的演练,在演练期间应用和上下游正常,在注入故障恢复之后,写修复最终追赶成功,可以确认系统符合设计预期。

六、展望

现在InfoKeeper和Hare还在应用代码层面,没有形成通用的组件,新的业务的加入需要在现有代码的基础上增加业务逻辑,开发者对底层的多介质存储的代码是有感的,也可能需要修改多介质存储层的代码以更好的贴合新的业务。

我们计划对Infokeeper和Hare的代码进行合并,形成一个通用的组件,让新的使用方能对多介质存储层无感,做到开箱即用,降低多介质存储的使用门槛,使得使用方能更专注于业务代码。

文章来源网络,作者:运维,如若转载,请注明出处:https://shuyeidc.com/wp/275976.html<

(0)
运维的头像运维
上一篇2025-05-10 10:53
下一篇 2025-05-10 10:55

相关推荐

  • 个人主题怎么制作?

    制作个人主题是一个将个人风格、兴趣或专业领域转化为视觉化或结构化内容的过程,无论是用于个人博客、作品集、社交媒体账号还是品牌形象,核心都是围绕“个人特色”展开,以下从定位、内容规划、视觉设计、技术实现四个维度,详细拆解制作个人主题的完整流程,明确主题定位:找到个人特色的核心主题定位是所有工作的起点,需要先回答……

    2025-11-20
    0
  • 社群营销管理关键是什么?

    社群营销的核心在于通过建立有温度、有价值、有归属感的社群,实现用户留存、转化和品牌传播,其管理需贯穿“目标定位-内容运营-用户互动-数据驱动-风险控制”全流程,以下从五个维度展开详细说明:明确社群定位与目标社群管理的首要任务是精准定位,需明确社群的核心价值(如行业交流、产品使用指导、兴趣分享等)、目标用户画像……

    2025-11-20
    0
  • 香港公司网站备案需要什么材料?

    香港公司进行网站备案是一个涉及多部门协调、流程相对严谨的过程,尤其需兼顾中国内地与香港两地的监管要求,由于香港公司注册地与中国内地不同,其网站若主要服务内地用户或使用内地服务器,需根据服务器位置、网站内容性质等,选择对应的备案路径(如工信部ICP备案或公安备案),以下从备案主体资格、流程步骤、材料准备、注意事项……

    2025-11-20
    0
  • 如何企业上云推广

    企业上云已成为数字化转型的核心战略,但推广过程中需结合行业特性、企业痛点与市场需求,构建系统性、多维度的推广体系,以下从市场定位、策略设计、执行落地及效果优化四个维度,详细拆解企业上云推广的实践路径,精准定位:明确目标企业与核心价值企业上云并非“一刀切”的方案,需先锁定目标客户群体,提炼差异化价值主张,客户分层……

    2025-11-20
    0
  • PS设计搜索框的实用技巧有哪些?

    在PS中设计一个美观且功能性的搜索框需要结合创意构思、视觉设计和用户体验考量,以下从设计思路、制作步骤、细节优化及交互预览等方面详细说明,帮助打造符合需求的搜索框,设计前的规划明确使用场景:根据网站或APP的整体风格确定搜索框的调性,例如极简风适合细线条和纯色,科技感适合渐变和发光效果,电商类则可能需要突出搜索……

    2025-11-20
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注