微服务架构中的数据一致性:解决方案与实践| 得物技术

news2024/11/27 11:52:00

1 为什么要做服务之间的数据一致性

作为互联网公司的研发工程师,微服务的架构思想对于各位读者朋友来说,已经不是陌生东西。我们当中的大多数人,或多或少经历过从单体应用到微服务化的系统拆分和演进过程。我们按照庞大系统的业务功能和特征,将其从一个单体的大应用,逐渐地拆分成很多的子系统的协同配合完成业务功能,甚至拆分后的某些子系统服务,还可能再拆分出来更多的更细颗粒度的子系统服务。拆分后的服务之间,采用PRC调用方式的通信,也就越来越多。随之而来的,跨系统服务之间的数据一致性的问题就会越来越突出了。比如电商系统中营销活动系统的积分和优惠券的发放和扣减,比如电商系统的核心下单核心链路上,首页瀑布流,商详页,下单页等等商品价格全链路一致性等等,支撑这些业务功能的实现,往往可能需要依赖来自N个不同的业务系统服务提供的数据读写服务能力来完成。

2 如何实现服务之间的数据一致性

说到数据一致性这个话题,我们可以想到的最常用最熟悉的解决问题的方式就是事务处理了。它存在的意义是为了保证系统中所有的数据都是符合预期的,并且存在关联关系的数据之间不会产生矛盾,即数据状态一致性。事务的概念,起源于数据库,发展到今天,几乎在每一个业务系统中都会涉及到。尤其在一些大型复杂的分布式系统中,事务的概念已经不仅局限于数据库,还可以延伸为一切需要保证数据一致性的应用场景,包括但不限于数据库、事务内存、缓存、消息队列、分布式存储等等,这些都有可能会用到事务处理。

今天我们探讨的主题是服务之间数据一致性问题。当然,实际生产落地中,在不同业务背景下,具备可行性的方案也是非常多的,各有优劣和适用场景。我们从中选择一两个具体实现,聊一些相关的设计和实践。

3 几个核心名词

为了方便正在阅读本篇文章的同学对后续内容的阅读和理解,我们先对文章中使用到的几个名词的语义做一些解释和约定:

业务侧系统:指的是发起执行业务操作的一方系统服务,可以简单理解为消费方。

平台侧系统:指的是为发起执行业务操作而提供基础能力的一方系统服务,可以简单理解为服务方。

执行业务操作:指的是对数据的读写操作需要依赖多个系统服务的协同完成,业务侧系统发起,平台侧系统执行最终的数据读写操作。这样场景中就普遍存在着服务之间的数据一致性问题(备注 :业务侧系统和平台侧系统是一个逻辑概念,并非一定要存在具体的应用服务与之对应)。

业务操作标识:指的是业务操作应该归属的业务类型或者业务场景的标识,它是平台侧系统创建并且统一管理的,然后发放给业务侧系统,在业务侧系统的服务调用平台侧系统提供服务能力的身份信息。业务标识可以设计为单层结构,也可以设计为多层结构,符合当前系统和业务的需求即可。

业务操作唯一ID:指的是某个具体业务操作在某一次或者多次重复执行的唯一性标识。生产实践中,它一般是由业务侧系统的服务自定义实现和管理的,也可以是基于平台侧系统提供有约束性质和方便管理的规则限制下,再由业务侧系统的服务自定义实现,后者是比较推荐的方式。

业务操作记录表:指的是记录业务操作的日志流水表。生产实践中,一般是由业务侧系统的服务创建并且管理。

4 方案一:业务侧系统保证最终一致性

4.1 核心思想

通过业务侧系统的服务保证数据的最终一致性,其核心思想就是业务侧系统记录下来每一次具体业务操作的执行流水日志信息,并且对没有全部成功的变更结果,触发执行数据一致性的校验核对工作。

4.2 设计原则

平台侧系统服务,提供支持执行业务操作的基础服务能力的接口。特别强调一点,这里是需要根据业务操作标识和业务操作唯一ID来实现接口的幂等设计。为什么我们有了唯一ID,同时还是需要有业务操作标识?因为在实际的生产实践中,在各种内因和外因的背景下,需要兼顾系统的稳定性和业务迭代的灵活性,很难做到绝对的全局性唯一ID的生成。更多时候,只需要在某个业务侧系统的内部,保证全局唯一性即可,这也是符合实际情况的系统设计。类似的解决问题的思路,在其他的系统设计场景,也是有非常高的借鉴价值的。

平台侧系统服务,提供执行业务操作后的结果查询接口,支持根据业务操作标识和业务操作的唯一性ID查询能力。

业务操作记录表,支持记录和识别业务操作的标识和每次执行的唯一ID。
业务侧系统服务,触发对业务操作记录表的数据一致性的检查核对工作,执行核对的方式,比如实时的同步检查核对、准实时的异步检查核对、定时任务的异步检查核对等等,为了保证自己和平台侧系统的数据最终一致性。

4.3 流程图

4.3.1 数据一致性的校验核对同步执行流程

1.png

4.3.2 数据一致性的校验核对异步核对链路

2.png

5 方案二:平台侧系统保证最终一致性

5.1 核心思想

通过平台侧系统的服务保证数据的最终一致性,核心思想是平台侧系统的每一次的数据变更,都主动地寻找业务侧系统,来确认本次数据变更结果是否符合预期。

5.2 设计的基本原则:

平台侧系统,提供支持业务操作执行的基础服务能力的接口,需要根据业务操作标识和唯一ID做幂等设计。它和方案一的一致性原则类似,省略不再赘述。

平台侧系统,提供业务操作的执行结果确认的回调SPI,可以方便业务侧系统来实现,根据业务操作标识和业务操作的唯一ID。
业务侧系统,提供根据业务操作标识和业务操作的唯一ID,来判断两边的数据是否具备一致性的回调实现。

5.3 流程图

5.3.1 数据一致性的校验核对同步核对链路

3.png

5.3.2 数据一致性的校验核对异步核对链路

4.png

6 实践过程中一些经验分享

这一部分,我将会对平台侧系统和业务侧系统的接口设计的部分细节,做一些简单的扩展阐述。希望为大家后续的研发工作提供一些思路。后续的文章中,将会针对其中一些具体的解决方案,做更详细的阐述。

首先,接口幂等性设计,将从如下角度进行阐述: 数据结构,状态存储,异常处理,返回结果唯一等等角度做一些总结分享。

6.1 数据结构设计

接口幂等性设计,是基于业务操作的标识(这里是称之为Tag)和业务操作的唯一ID来实现的。业务操作标识的设计,可以是单层的设计,也可以是多层的设计。其中,多层的设计是为了满足业务侧系统的存在复杂并且多业务场景的诉求。业务操作的唯一ID的生成方式,可以是没有任何业务含义的自增趋势的不可重复的ID,比如MySQL的自增主键ID,分布式ID生成器等等方式,也可以是业务侧系统的某些特定的业务字段 ,比如用户的userId,订单的orderId,商品的spuId,skuId等等。在实际实践中,后者是我们比较推荐的常用方式,可以实现在不增加系统复杂度和额外依赖资源的同时,又可以和业务侧系统达到高度的契合。

6.2 状态存储设计

在一般情况下,建议把MySQL存储当做我们首选的存储,MySQL提供非常完善的数据一致性保证能力,最简单的方式是基于数据库的联合唯一索引设计,多次层Tag + 唯一ID的业务唯一键。但是也是有缺陷的,比如MySQL自身的性能瓶颈和昂贵的存储成本。性能上的瓶颈,可以通过访问MySQL的幂等校验之前,增加访问Redis的幂等校验,校验不通过抛出异常,在MySQL幂等校验通过以后,异步刷数据到Redis中,这样保证Redis校验通过的同时MySQL校验一定是通过的。我们可以接受Redis的幂等校验的不准确性,仅仅是期望它成为流量漏斗的上层,为MySQL承担起流量过滤作用,当然你可以有其他的更多的方案来做这件事,甚至组合起来使用。也可以增加分库分表的策略,来解决MySQL的性能瓶颈。在MySQL的存储成本是相对比较高的,我们可以对历史的数据做归档处理,只保留一部分的热数据,原则上保持单表的数据行数在500w~1000w之间,同时也可以有能支持一定量的历史数量查询。同时这个过程也需要考虑无锁处理问题和MySQL空间碎片的问题等等。

6.3 异常处理设计

第一步,明确导致发生异常的原因有哪些?一般可以归为几个分类,网路异常,数据格式错误,业务逻辑异常。第二步,针对特定类型的问题,我们做出相应处理方案。比如我们重试机制,控制重试频次,重试周期的衰减时间执行控制,处理数据处理的终态的异常数据的兜底处理机制等等方式。

6.4 返回结果唯一

我需要保证接口的返回的数据,再多次重复调用执行,依旧保证完全相同。我们可以基于状态机的流转控制,返回相同的状态码,也可以对一些核心业务参数做核对校验,如果不通过返回特定的异常码等等。
此外,平台侧系统的提供给基础能力接口的设计要求我们研发同学思考和考虑的更多,比如一致性延迟问题,状态机的设计,并发问题处理,接口不可用解决等等。

6.5 延迟问题的容忍度

能否在业务侧系统服务期望的时间点,完成数据一致性的校验核对工作?若有延迟,延迟是多少?尤其是极端场景下的延迟是多少?

案例:如果使用定时任务,做数据一致性校验核对工作。比如一个周期(假设1min),还有很多数据未完成核对工作,剩余多少,以及对业务侧系统的影响。解决思路:1. 评估和设计一个合理的周期大小;2. 选择全量核对和增量核对的选择;3. 增加核对的扫描的数据范围的策略;4. 增量核对确保不丢失未核对过的数据,等等。

案例:如果使用MQ消息,我们可能面临的问题是消息堆积,消息丢失等等场景MQ问题带来的数据不一致问题。

案例:如果使用同步等待方式,是可以将数据一致性的延迟降低为0,但是系统吞吐能力和可用性等等,都是无法保证,这也是选择权衡的结果。

6.6 基于状态机的设计

基于状态机的设计中,一定是有初始态和终态的,代表数据的核对工作,有始有终。至于中间态,可以有多个中间态,也可以是仅有一个中间态,这个和实际的需求和背景相关联的,可以灵活地控制。其中的终态,一般情况下都不会只有一种,而是有两大类,一种是成功的终态表示数据实现最终一致性,一种是失败的终态表示不因为不可抗拒的因素导致的数据不一致产生。失败的终态,也是可以设计出多种状态,根据实际需要来设计。比如多次重试从初始态到终态的耗时和处于失败态的数据核对检测工作的占比,一定程度上代表着业务侧系统对数据一致性延迟的容忍度。这应该是我们必须关注的核心指标信息。

6.7 并发问题

我们在创建一个初始化态的流水日志记录的时候,是一个MySQL的insert操作(假设你选择了MySQL作为存储),需要避免创建多条的业务操作唯一ID的记录。最简单粗暴的方式,依赖DB的联合唯一索引是可以实现的。但是需要考虑在并发比较多的时候,带来的性能和吞吐问题,甚至导致创建初始化态就失败的问题。

对于相同数据并发写的问题,我们成功执行一条insert语句,大多数情况可以满足我们业务侧系统的预期。我们可以采用加锁,排队等待,分组等待排队等等手段,限制类似场景的并发数来解决。这种方式,随着业务的发展扩张,可能会面临系统的吞吐量不足以支撑业务的问题。

解决上述的吞吐量下降的问题,我们可能又会想到采用MQ的方式来削峰填谷,因为实际生产实践中,并发写问题的往往都是一个特点 瞬时性发生的系统尖刺。采用MQ的方式,可以保证平台侧系统创建初始化态的流水日志的系统吞吐量。

在以上的基础之上,我们还是可以采用隔离拆分的方式,比如服务接口拆分层面的隔离,MQ的topic拆分的隔离等等,配合不同的限流熔断等等系统保护策略的方式以及不同的系统资源倾斜等等,解决平台侧系统的性能问题。

6.8 需要解决不可用

熔断限流,资源隔离,多元化的降级策略等等,这些是大家都非常熟悉的系统可用性保障的手段,这部分相关的内容,就不再展开叙述了。

6.9 需要提供可视化和可观测

完善告警机制,比如异常状态告警,超出阈值告警等等,让相关的业务侧系统和平台侧系统同学可以快速感知到问题并且介入解决问题。

建设监控大盘,比如 MySQL,Redis,MQ,以及数据核对工作的状态的监控等等,都是需要我们去一步一步建设起来的。

定位和排查问题的工具,拆分后的系统,其系统的复杂度是指数增长的,这个方面也是非常重要的。

7 总结

在本篇文章中,阐述了两种处理数据一致性问题的解决方案,从核心思想,设计原则,系统交互流程等等做了详细的阐述,比对两种方案,各有优劣和各自的适用场景。方案一,业务侧系统来保证数据的一致性,更适用于对数据的一致性有相对比较强的耦合依赖关系的业务场景,需要依赖业务操作的执行结果做出判断,执行不同后续业务逻辑分支的执行。 案例: 同一个商品在不同修改商品信息(变更不同的字段,变更不同表的字段)的入口触发异步更新C端缓存的单品维度的商品全量缓存数据构建,变更的事务是在成功完成提交以后,方可执行本次变更对应的后续缓存构建。方案二,平台侧系统来保证数据的一致性,更适用于业务侧系统,关注点是数据的最终执行结果的业务场景,案例: 不同业务场景入口的库存扣减和库存回滚执行结果。最后,提到在生产实践过程中一些经验和解决方案的总结分享,每个点都是值得继续深入探讨。

线下活动推荐

时间:2023年6月10日(周六)14:00-18:00

主题:得物技术沙龙总第18期-无线技术第4期

地点:杭州·西湖区学院路77号得物杭州研发中心12楼培训教室(地铁10号线&19号线文三路站G口出)

活动亮点:本次无线沙龙聚焦于最新的技术趋势和实践,将在杭州/线上为你带来四个令人期待的演讲话题,包括:《抖音创作工具-iOS功耗监控与优化》、《得物隐私合规平台建设实践》、《网易云音乐-客户端大流量活动的日常化保障方案实践》、《得物Android编译优化》。相信这些话题将对你的工作和学习有所帮助,我们期待着与你共同探讨这些令人兴奋的技术内容!

报名方式:点击报名 无线技术沙龙

在这里插入图片描述

扫码添加小助手微信

如有任何疑问,或想要了解更多技术资讯,请添加小助手微信:

6.jpeg

文: kof wang

本文属得物技术原创,来源于:得物技术官网

未经得物技术许可严禁转载,否则依法追究法律责任!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/627096.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

都说网络安全渗透工程师前景好,好在哪?

渗透工程师前景非常好,网络安全发展规模不断扩大,未来行业类的人才需求也会越来越多。就目前看来在网络安全方向上就业的薪资待遇也十分可观。 其就业方向有很广泛,如网络安全工程师,渗透测试工程师等。 渗透测试人员通常对网络…

keras搭建轻量级卷积神经网络CNN开发构建国家一级保护动物识别分析系统,集成开发GradCAM实现热力图分析可视化

动物识别相关的项目本质上属于图像识别,在我之前的博文中已经有过不少实践了,感兴趣的话可以自行移步阅读即可,这里不是说想要单纯地去做一个动物识别的项目,昨晚在玩手机的时候突然被小孩问到一个动物是不是国家保护动物&#xf…

SpringBoot 事件监听处理(五十一)

当死亡笼罩在脑海,请用生的信念打败它 上一章简单介绍了Retry重试机制(五十), 如果没有看过,请观看上一章 参考文章: https://blog.csdn.net/qq_37758497/article/details/118863308 一. Spring 事件监听 Spring的事件监听(也叫事件驱动)是观察者模式的一种实现&…

Windows 10磁盘碎片整理:含义和操作方法

什么是Windows磁盘碎片? 随着电脑硬盘使用时间的增长,磁盘上会产生大量的垃圾碎片。这些碎片会分布在磁盘的各个角落,严重影响磁盘的响应速度。为了在一定程度上提高系统性能,定期使用Windows10的磁盘碎片整理工具来进行碎片整…

Vue.js中的Mixin和组件插槽

Vue.js中的Mixin和组件插槽 介绍 在Vue.js中,Mixin和组件插槽是两个非常有用的概念。Mixin是一种可重用Vue组件的方式,而组件插槽则提供了一种在组件之间共享内容的方式。虽然这两个概念在功能上有所不同,但它们对于Vue.js应用程序的开发都非…

Vue 中的数据请求如何进行拦截与错误处理

Vue 中的数据请求拦截与错误处理 在 Vue.js 中,我们经常需要向后端服务器发送数据请求,以获取或提交数据。在这个过程中,我们可能会遇到一些问题,例如无效的请求参数、网络连接错误、服务器错误等。为了更好地处理这些问题&#…

优化和扩展:处理不同操作和参数的数字列表

引言 在编程中,我们有时需要根据输入执行不同的操作,而这些操作涉及到数字列表,并且每个操作可能具有不同数量的参数。本文将介绍如何优化和扩展代码,以便更好地处理这种情况。 问题描述 当前遇到的问题是需要根据输入执行不同…

Mysql中的Buffer pool

Buffer Pool在数据库里的地位 1、回顾一下Buffer Pool是个什么东西? 数据库中的Buffer Pool是个什么东西?其实他是一个非常关键的组件,数据库中的数据实际上最终都是要存放在磁盘文件上的,如下图所示。 但是我们在对数据库执行增…

2023最新Java面试八股文,阿里/腾讯 / 美团 / 字节 1 000道 Java 中高级面试题

企业调薪、裁员、组织架构调整等等,坏消息只多不少,最近也有很多来咨询跳槽的朋友,都是因为之前的公司出现了比较大的薪资和组织变动 近期有许多粉丝非常关注最新的面试题!于是小编去各大平台搜罗了一份近期大厂面试的一些内容&a…

基础工程(cubeide串口调试,printf实现,延时函数)

0.基础工程(cubeide串口调试,printf实现,延时函数) 文章目录 0.基础工程(cubeide串口调试,printf实现,延时函数)外部时钟源CLOCK(RCC)系统时钟SYS与DEBUG设置UART串口设置cubeide设置…

世界研发管理组织在美国成立,中国籍研发管理专家江新安当选总干事

World R&D Management Organization世界研发管理组织(WRDMO)由来自世界各地的研发管理研究组织,创新技术研究机构,院校以及研发管理咨询机构联合发起。是一个具有开放性,无党派性,非营利性的国际先进研…

如从亿点点失误,到一点点失误,我是如何做的【工作失误怎么办】

前言 只要我们还在做事,或者说还活着,就没有不犯错的时候。作为一名前端搬砖工,哪怕工作中再仔细小心,也免不了一些失误。 那这是不是说,失误很正常,改了就是嘛? 这么说好像没错。作为失误本…

【计算机组成与体系结构Ⅰ】知识点整理

第一章 计算机系统概论 1.1 从源文件到可执行文件 .c源程序、.i源程序、.s汇编语言程序、.o可重定位目标程序、可执行目标程序;后两个为二进制,前面为文本 1.2 可执行文件的启动和执行 冯诺依曼结构计算机模型的5大基本部件:运算器、控制…

【ChatGLM】使用ChatGLM-6B-INT4模型进行P-Tunning训练记录及参数讲解

文章目录 模型训练步骤参数含义名词解释欠拟合泛化能力收敛性梯度爆炸 初步结论 小结 模型训练 首先说明一下训练的目的:提供本地问答知识文件,训练之后可以按接近原文语义进行回答,类似一个问答机器人。 步骤 安装微调需要的依赖&#xf…

C++【哈希表封装unordered_map/set】—含有源代码

文章目录 (1)修改原哈希表(2)迭代器(3)最后一步(4)关于key是自定义类型的额外补充(面试题)(5)源代码 (1)修改原哈希表 和红黑树封装一…

【链表Part01】| 203.移除链表元素、707.设计链表、206.反转链表

目录 ✿LeetCode203.移除链表元素❀ ✿LeetCode707.设计链表❀ ✿LeetCode206.反转链表❀ ✿LeetCode203.移除链表元素❀ 链接:203.移除链表元素 给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val val 的节点&#xff…

python数据分析

一、数据处理 1.爬取数据 我们将使用Python的requests和BeautifulSoup库来爬取数据。在这个示例中,我们将爬取豆瓣电影Top250的数据。 import requests from bs4 import BeautifulSoup url https://movie.douban.com/top250 headers {User-Agent: Mozilla/5.0 …

策略设计模式解读

目录 问题引进 鸭子问题 传统方案解决鸭子问题的分析和代码实现 传统的方式实现的问题分析和解决方案 策略模式基本介绍 基本介绍 策略模式的原理类图 策略模式解决鸭子问题 策略模式的注意事项和细节 问题引进 鸭子问题 编写鸭子项目,具体要求如下: 1) 有…

【GlobalMapper精品教程】059:基于las点云创建数字高程地形并二三维着色显示

本文讲述在globalmapper免费中文版中基于地形点云las数据创建数字高程地形、数字高程二三维联动可视化并进行数字高程着色显示。 文章目录 一、加载地形点云las数据二、创建数字高程地形三、数字高程二三维联动可视化四、数字高程着色显示相关阅读:ArcGIS实验教程——实验二十…

如何看待 Facebook 上线支付功能?

随着科技的不断进步,电子支付在我们的生活中变得越来越普遍。最近,Facebook宣布推出自己的支付功能,这引起了广泛的关注和讨论。作为世界上最大的社交媒体平台之一,Facebook进入支付领域的举措无疑具有重要意义。那么,…