您当前的位置:首页 > 电脑百科 > 程序开发 > 架构

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

时间:2023-06-14 00:50:43  来源:  作者:OSC开源社区

1

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

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

2

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

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

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

3

几个核心名词

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

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

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

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

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

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

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

4

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

  • 4.1 核心思想

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

    4.2 设计原则

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

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

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

5

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

  • 5.1 核心思想

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

5.2 设计的基本原则:

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

平台侧系统,提供业务操作的执行结果确认的回调SPI,可以方便业务侧系统来实现,根据业务操作标识和业务操作的唯一ID。

业务侧系统,提供根据业务操作标识和业务操作的唯一ID,来判断两边的数据是否具备一致性的回调实现。

5.3 流程图5.3.1 数据一致性的校验核对同步核对链路

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

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端缓存的单品维度的商品全量缓存数据构建,变更的事务是在成功完成提交以后,方可执行本次变更对应的后续缓存构建。 方案二,平台侧系统来保证数据的一致性,更适用于业务侧系统,关注点是数据的最终执行结果的业务场景,案例: 不同业务场景入口的库存扣减和库存回滚执行结果。最后,提到在生产实践过程中一些经验和解决方案的总结分享,每个点都是值得继续深入探讨。

*文/ kof wang



Tags:微服务   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
对于微服务架构监控应该遵守的原则
随着软件交付方式的变革,微服务架构的兴起使得软件开发变得更加快速和灵活。在这种情况下,监控系统成为了微服务控制系统的核心组成部分。随着软件的复杂性不断增加,了解系统的...【详细内容】
2024-04-03  Search: 微服务  点击:(5)  评论:(0)  加入收藏
PHP+Go 开发仿简书,实战高并发高可用微服务架构
来百度APP畅享高清图片//下栽のke:chaoxingit.com/2105/PHP和Go语言结合,可以开发出高效且稳定的仿简书应用。在实现高并发和高可用微服务架构时,我们可以采用一些关键技术。首...【详细内容】
2024-01-14  Search: 微服务  点击:(115)  评论:(0)  加入收藏
九条微服务最佳实践,你学会了哪条?
微服务之间连贯一致的代码库对于可维护性至关重要。保持代码成熟度相似,可确保系统统一演进,防止服务间出现性能、安全性和功能差异。在开发微服务时,我们需要遵循哪些最佳实践...【详细内容】
2024-01-05  Search: 微服务  点击:(99)  评论:(0)  加入收藏
Go微服务入门到容器化实践
Go微服务入门到容器化实践Go 是一门高效、现代化、快速增长的编程语言,非常适合构建 Web 应用程序。而 Docker 是一种轻量级的容器化技术,能够使得您的应用程序在任何地方运行...【详细内容】
2024-01-01  Search: 微服务  点击:(63)  评论:(0)  加入收藏
微服务全做错了!谷歌提出新方法,成本直接降为1/9!
2023,微服务“水逆”之年。长期以来,不管大厂还是小厂,微服务都被认为是云原生服务应用程序架构的事实标准,然而2023,不止那位37signals的DHH决心下云,放弃微服务,就连亚马逊和谷歌...【详细内容】
2023-12-29  Search: 微服务  点击:(120)  评论:(0)  加入收藏
微服务架构中的数据一致性
在微服务中,一个逻辑上原子操作可以经常跨越多个微服务。即使是单片系统也可能使用多个数据库或消息传递解决方案。使用多个独立的数据存储解决方案,如果其中一个分布式流程参...【详细内容】
2023-12-27  Search: 微服务  点击:(143)  评论:(0)  加入收藏
监控 Spring Cloud 微服务的实践方案
一、简介Spring Cloud是一个基于Spring Boot实现的微服务框架,它提供了丰富的微服务功能,如分布式配置、服务注册与发现、服务熔断、负载均衡等。为了更好地管理和监控这样复...【详细内容】
2023-12-19  Search: 微服务  点击:(144)  评论:(0)  加入收藏
聊聊微服务链路服务
微服务架构图片如果有用户反馈某个页面很慢,我们知道这个页面的请求调用链是 A -----> C -----> B -----> D(图片有误),怎么来定位是由哪个服务引起的问题呢? 更进一步,如果...【详细内容】
2023-12-15  Search: 微服务  点击:(126)  评论:(0)  加入收藏
选择适合微服务的编程语言,让你的工作事半功倍!
讨论编程语言就像是一场政治辩论。每个开发者都会过分捍卫他/她所使用的编程语言。然而,编程语言应该被看作是它们真正是的东西,即一种工作工具。每种编程语言都有特定的目的...【详细内容】
2023-12-14  Search: 微服务  点击:(178)  评论:(0)  加入收藏
Eureka: 微服务架构中不可或缺的服务治理工具
Eureka是Netflix开源的一款用于服务治理的工具,它是NetflixOSS(OpenSourceSoftware)项目的一部分,主要用于实现微服务架构中的服务注册与发现。在当今庞大而复杂的微服务系统中,E...【详细内容】
2023-12-14  Search: 微服务  点击:(192)  评论:(0)  加入收藏
▌简易百科推荐
对于微服务架构监控应该遵守的原则
随着软件交付方式的变革,微服务架构的兴起使得软件开发变得更加快速和灵活。在这种情况下,监控系统成为了微服务控制系统的核心组成部分。随着软件的复杂性不断增加,了解系统的...【详细内容】
2024-04-03  步步运维步步坑    Tags:架构   点击:(5)  评论:(0)  加入收藏
大模型应用的 10 种架构模式
作者 | 曹洪伟在塑造新领域的过程中,我们往往依赖于一些经过实践验证的策略、方法和模式。这种观念对于软件工程领域的专业人士来说,已经司空见惯,设计模式已成为程序员们的重...【详细内容】
2024-03-27    InfoQ  Tags:架构模式   点击:(13)  评论:(0)  加入收藏
哈啰云原生架构落地实践
一、弹性伸缩技术实践1.全网容器化后一线研发的使用问题全网容器化后一线研发会面临一系列使用问题,包括时机、容量、效率和成本问题,弹性伸缩是云原生容器化后的必然技术选择...【详细内容】
2024-03-27  哈啰技术  微信公众号  Tags:架构   点击:(10)  评论:(0)  加入收藏
DDD 与 CQRS 才是黄金组合
在日常工作中,你是否也遇到过下面几种情况: 使用一个已有接口进行业务开发,上线后出现严重的性能问题,被老板当众质疑:“你为什么不使用缓存接口,这个接口全部走数据库,这怎么能扛...【详细内容】
2024-03-27  dbaplus社群    Tags:DDD   点击:(12)  评论:(0)  加入收藏
高并发架构设计(三大利器:缓存、限流和降级)
软件系统有三个追求:高性能、高并发、高可用,俗称三高。本篇讨论高并发,从高并发是什么到高并发应对的策略、缓存、限流、降级等。引言1.高并发背景互联网行业迅速发展,用户量剧...【详细内容】
2024-03-13    阿里云开发者  Tags:高并发   点击:(6)  评论:(0)  加入收藏
如何判断架构设计的优劣?
架构设计的基本准则是非常重要的,它们指导着我们如何构建可靠、可维护、可测试的系统。下面是这些准则的转换表达方式:简单即美(KISS):KISS原则的核心思想是保持简单。在设计系统...【详细内容】
2024-02-20  二进制跳动  微信公众号  Tags:架构设计   点击:(36)  评论:(0)  加入收藏
详解基于SpringBoot的WebSocket应用开发
在现代Web应用中,实时交互和数据推送的需求日益增长。WebSocket协议作为一种全双工通信协议,允许服务端与客户端之间建立持久性的连接,实现实时、双向的数据传输,极大地提升了用...【详细内容】
2024-01-30  ijunfu  今日头条  Tags:SpringBoot   点击:(15)  评论:(0)  加入收藏
PHP+Go 开发仿简书,实战高并发高可用微服务架构
来百度APP畅享高清图片//下栽のke:chaoxingit.com/2105/PHP和Go语言结合,可以开发出高效且稳定的仿简书应用。在实现高并发和高可用微服务架构时,我们可以采用一些关键技术。首...【详细内容】
2024-01-14  547蓝色星球    Tags:架构   点击:(115)  评论:(0)  加入收藏
GraalVM与Spring Boot 3.0:加速应用性能的完美融合
在2023年,SpringBoot3.0的发布标志着Spring框架对GraalVM的全面支持,这一支持是对Spring技术栈的重要补充。GraalVM是一个高性能的多语言虚拟机,它提供了Ahead-of-Time(AOT)编...【详细内容】
2024-01-11    王建立  Tags:Spring Boot   点击:(124)  评论:(0)  加入收藏
Spring Boot虚拟线程的性能还不如Webflux?
早上看到一篇关于Spring Boot虚拟线程和Webflux性能对比的文章,觉得还不错。内容较长,抓重点给大家介绍一下这篇文章的核心内容,方便大家快速阅读。测试场景作者采用了一个尽可...【详细内容】
2024-01-10  互联网架构小马哥    Tags:Spring Boot   点击:(115)  评论:(0)  加入收藏
站内最新
站内热门
站内头条