微服务架构下的数据一致性微服务架构的流行源于它能够带来更快的变化响应能力,比如独立部署,每个服务的能力职责是独立的 , 可以按需独立发布;再比如每个服务可以由不同的开发团队负责,每个服务的技术栈也可以不同,可以选择更快捷合理的方式实现不同的服务 。
然而 , 微服务架构作为分布式架构,躲不开的一个问题就是数据一致性的问题,特别是在技术异构和数据源类型不同的情况下,传统的分布式事务(2PC或3PC)也很难解决微服务架构下的一致性问题 。
在微服务架构下,多个服务之间通常会定义明确上下游关系,下游系统可以依赖上游系统 , 下游系统可以通过API查询或修改上游系统的数据;反过来则不然,上游系统不应该知道下游系统的存在,也就是说上游系统不能依赖下游系统 , 上游系统的变化只能通过异步事件的方式发出,下游系统监听事件并基于事件做对应的数据状态变化 。
在基于上面原则的微服务架构下(见上面图示 , 本文不考虑服务间循环依赖的场景),在上下游服务间的数据通信(图示中的每个箭头表示一种数据通信)一旦发生问题,都会产生数据不一致的场景,下面我们逐一说明:
举个例子,订单服务是下游服务,库存服务是上游服务,在订单确认时要锁定库存 , 实现上订单服务在状态变化同时通过同步API修改库存的状态 , 为了保证数据一致性,在调用库存服务API异常后订单服务会回滚当前的数据状态变更 。
在这个场景下 , 同一个业务流程 , 需要同时修改两个服务的数据,在以下两种情况下会发生数据不一致的问题:
上游服务每个关键状态变更都可能触发下游服务的一些逻辑链,因此上游服务发布的事件对于下游服务是非常重要的 , 但这些事件并不影响上游服务自身逻辑 , 也不影响自身数据状态的变化 , 因此通常不会设计成阻碍业务流程,那么在事件服务或事件载体(通常是消息队列)与上游服务之间的通信异常,就会导致上游服务的事件发布失败 。
这种场景下,上游服务的业务流程已经成功,不可能有再次触发事件的场景 , 这个事件就丢失了,下游服务因为没有收到上游服务的事件,数据没有做对应的变化而导致数据一致性问题 。
同样,下游服务在消费事件时也很有可能因为一些原因,导致事件的消费失败,这些原因可能包括:
上游服务并不关心下游的消费者 , 所以对于发布出去的事件,上游系统也不关心下游服务是否消费成功,更不会有因某个下游服务消费失败而重发事件的逻辑,这同样会导致类似于场景二的数据一致性问题 。
根据CAP理论,分区容错性、可用性和一致性里面必须要牺牲掉一个,而在实际实现过程中,分区容错性和可用性是很难舍弃的 , 所以通常会舍弃一致性 , 取而代之会用最终一致性保证数据在可容忍的时长内达到最终一致 。
微服务架构也不例外,在服务内部,可以通过本地事务保证数据的强一致性;而当业务发生在多个服务中,我们追求最终一致性 。那么都有哪些措施可以保证跨服务的最终一致性呢?
这是个业务问题,在微服务的架构下,每个服务都是独立的,如果有一个业务功能需要同时修改两个服务的数据,往往这个业务可以拆分成两个步骤,比如场景一种提到的订单和库存的例子 , 如果我们可以先锁定库存 , 然后再确认订单看上去这个问题就迎刃而解了 。
因此在业务中发现一个功能需要同时修改两个服务的数据,我们首先可以来讨论这个业务设计是否合理;如果业务上很多场景都要求两个服务的数据保持强一致,那可能我们需要看看微服务的划分是否合理 。
为了解决场景二和场景三的不一致性问题,需要上游服务和下游服务的共同努力:
上游服务需要尽可能将事件发送出去,比如:先同步发送 , 如果失败改为异步重试 , 重试多次仍然失败可以先持久化,通过定时任务来重发或者人工干预重发 。
下游服务也要尽可能的把事件处理掉,收到事件后可以考虑先将事件持久化,消费成功后标记事件,如果消费失败可以通过定时任务重试消费 。
当我们提到重试 , 就不得不考虑幂等性的问题 , 这里的幂等性包括以下两个场景:
即便我们做了很多我们认为万全的准备 , 在分布式系统的执行链路上 , 每个节点都有可能失败 , 加上业务的复杂度 , 数据不一致的情景也很难彻底解决 , 而对于那些小概率发生但技术解决起来成本昂贵的问题,我们可以尝试通过对业务的深刻理解设计一些后台的数据维护功能,保证在核心业务数据异常时,可以在一定的规则内进行修复 , 从而保证业务的顺利进行
数据一致性问题首先是个业务问题,其次才是个技术问题 。在微服务架构下,我们期望每个服务职责单一,这种职责单一体现的是业务价值,如果微服务的拆分过小而导致业务难以实现,那这种拆分是不合理的 , 业务专家们非常有必要了解系统,从业务侧给出服务拆分的建议 。
在数据一致性问题上,我们首先要思考业务设计的合理性,其次是当前架构设计的合理性,然后在一定的约束下,通过最终一致性保证业务价值,除非迫不得已,不建议引入分布式事务框架,一方面成本较高,另一方面也会引入性能等新的问题 。
php redis高并发rpush是数据一致性吗不会 , 这里的原子性不要从php的角度看 , 应该从redis的角度看,同一个redis节点对并发的请求都是序列化处理的,所以单操作不存在你担心的并发问题,但如果是readwrite的形式到哪里都不行了,切记 。
有人问到readwrite是啥,其实就是并发的一个经典问题,代码如下
$v = $redisClient-get('v');
$v;
$redisClient-set('v', $v);
就是先读取数据,再修改数据,在写回修改,这里是希望每次访问都递增v的值 , 但在并发情况下,两个进程都读取到了一样的初始值,比如3,然后都加1变为4,最后把4写回Redis,这种情况就会统计数据比实际的少 。尽量都用Redis的原子操作就好,比如incr 。
如何成为一个PHP方向的架构师作为一名十年PHP老司机来讲下,刚开始1-2年都是都是CODER,知道项目版本如何控制,用一些基本框架就可以完成项目 。
工作三年PHP不仅仅是只完成码农工作,还需要深入学习PHP优化,Swoole接口,微服务,Mysql底层优化等,才能拥有一份25K左右的薪资,让自己有一些市场竞争力度!
等你有一定经验,4-5年这个阶段后,想要进阶CTO、架构师的话,高并发分流,分布式缓存、RPC、API架构设计等技术都必将掌握!
如果你想要往架构师或TL的方向发展的话,那或许你可以看一下我分享给你的这份进阶路线图,主要针对1到5年及以上的PHP开发人员,里面的技术包涵了PHP高并发、分布式、微服务、框架内核、高性能等技术?。』棺急噶艘惶字懈呒督籽敖坛?,分享tp,laravel,Swoole,swoft微服务等教程,想要进阶的PHPer请戳网页链接
PHP架构师体系
如何保证session的一致性session.savephp的在页面载入时或调用session_start()时从数据源中读取session数据到$_SESSION变量 。
当页面执行完毕或调用session_write_close()时把$_SESSION变量写入数据源 。
php默认的session.save_handler=files,可以通过文件锁来实现读写同步,保证session数据的一致性,不会产生问题 。然而当使用sqlite作为session handler时,由于没有同步机制,会产生bug 。如下代码:
test1.php
PHP code?
session_start();
$_SESSION['data1'] = 'data1';
sleep(10);
session_write_close();
test2.php
PHP code?
session_start();
$_SESSION['data2'] = 'data2';
session_write_close();
在同一浏览器进程里(保证使用相同的session_id),先访问test1.php,再访问test2.php,会发现data2根本没有写入sqlite数据库中 。session.save_handler=memcache还没有测试,估计也有这个问题 。如果采用默认的files handler会发现test2.php的请求会被挂起直至test1.php执行完毕,这就是文件锁同步机制造成的 。
我想到了两种解决方案:
1、实现互斥锁,保证同一session_id访问session数据是同步的,这样会产生一个阻塞的问题(php默认的session实现也会有这个问题) 。
2、写入session数据时进行数据合并 , 不过这样仍然不能完全保证数据一致性 。
微服务测试的思考与实践 最近几年,微服务架构越来越火爆,逐渐被企业所采用 。随着软件架构的变化,对应的软件测试策略需要作何调整呢?本文将介绍微服务架构下的测试策略,并结合分享在业务和架构演变过程中,一个历经九年的项目测试策略的演进 。
微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务 , 每个服务运行在其独立的进程中,服务间采用轻量级通信机制互相沟通(通常是基于HTTP协议的RESTful API) 。每个服务都围绕着具体的业务进行构建,并且能够被独立部署到生产环境、预生产环境 。
从微服务的概念可以看出它有如下好处:
同时,独立开发导致技术上的分离,HTTP通信加上Queue的机制增加了问题诊断的复杂度,对系统的功能、性能和安全方面的质量保障带来了很大的挑战 。另外,服务间的复杂依赖关系带来了很多的不确定性,要实现独立部署 , 对运维也提出了更高的要求 。微服务架构的系统要特别关注这几个方面:
谈到微服务的测试策略 , 很容易就想到了老马推荐的文章《 Microservices Testing 》,该文推荐的微服务框架下的测试策略是这样的:
(经典策略模型)
这个策略模型强调测试分层以及每一层的恰当覆盖,整体符合金字塔结构 。它是最优的吗?
有人对此提出了质疑...认为策略模型应该是蜂巢形状的(请参考 文章 ):
(蜂巢模型)
这个模型重点关注服务间的集成测试,两端的单元测试和UI层E2E测试较少 。
也有同事提出微服务下的测试结构应该是钻石形状的,服务间的集成依然是重点,单元测试较少,而顶层增加了安全和性能等非功能测试 。
(钻石模型)
好像都有道理,到底选择什么样的策略模型好呢?不禁陷入了困境…...怎么办?不妨先来听听我们项目的故事吧!
还是那个蓝鲸项目 , 不知不觉进入了第九个年头 。在这九年里,随着业务的不断发展,系统架构也进行了多次演进和调整 。相应的,测试策略也发生了有意思的演进变化 。
(测试策略的演进)
最初单一用户系统、单体架构的时候 , 严格按照测试金字塔来组织各层的自动化测试 。随着功能的扩展,大量mock的单元测试给重构带来了很大的不便 。
企业系统开始开发的时候,我们调整了策略,减少单元测试的编写,增加UI层E2E测试的覆盖 , 测试结构由原来的金字塔演变成上面梯形下面倒三角的形式 。
后来,架构调整,开始服务化 。此时 , 大量的E2E测试渐渐暴露出问题:
因此,项目引入契约测试,停止编写新的E2E测试,将测试下移,分别用API测试和契约测试取代 。
随着功能的不断增加,虽然E2E测试的量并不增加,但是其不稳定性、维护难、定位难的问题有增无减 , 此时已经很难由自动化测试来保证产品的质量 。为了平衡成本和收益,项目考虑去掉大部分E2E测试,只保留少量的Smoke测试,将更多的测试下移 。
同时,技术雷达上新的技术“生产环境下的QA”出现 , 项目也开始关心生产环境,并且在QA测试阶段结合微服务的特点进行对应的探索式测试 。
前文提到过微服务带来的挑战,下面来看项目是如何应对这些挑战的 。
服务间的依赖、连通性
微服务架构下 , 独立开发的服务要整合起来最具挑战,如何保证服务间的依赖关系和连通性非常关键 。前面已经讲过E2E集成测试有很大的挑战,并不适合 , 而消费端驱动的契约测试是个不错的选择 。项目正是利用契约测试去保证服务间的连通性,取代一部分E2E集成测试 。
服务的容错、可用性
在系统负荷达到一定程度或者某个服务出现故障的时候,微服务架构有两种技术来确保系统的可用性:服务的熔断和降级 。服务的熔断是指当某个服务出现故障时,为了保证系统整体的可用性,会关闭掉出现故障的服务;服务的降级则是当系统整体负荷过载的时候,考虑关闭某些外围服务来保证系统的整体可用性 。
对应的测试包括:
数据的最终一致性
(数据一致性)
数据一致性是微服务特别需要关注的 。举个例子,电商平台某个订单支付成功以后 , 需要更新积分和订单状态,当订单服务或者积分服务其中有一个出现故障的时候,就会导致最终的数据不一致性 。
测试这种情况,从业务的角度分析哪些服务会导致数据不一致性,制造对应的异常情况去测试数据的最终一致性 。
独立部署
微服务的独立部署需要有CI、CD的支持 , 跟DevOps实践分不开 。同时,更为关键的是需要契约测试来验证独立部署后服务行为的正确性 。项目在这方面的工作,请参考王健的文章: 你的微服务敢独立交付吗?
不确定性
微服务架构使得系统复杂度增加不少,很多的事情发生都是不可预测的,只能在其发生以后找到产生的原因 。因此 , 也就没法在预生产环境通过测试去发现在真实生产环境才会发生的issue,我们需要把目光转移到生产环境,利用生产环境的不确定性、微服务的不可预测性来构建反脆弱的系统 。
项目在这方面主要采用的技术是生产环境下的QA , 请参考文章: 生产环境下的QA
从前面介绍的演进过程可以看到,项目测试策略在不同阶段结合参考了不同的策略模型:金字塔-近似钻石(除非功能测试外,类似于钻石模型)-蜂巢 。后期全面服务化的时候,我们认为蜂巢模型是比较适合的 。
当然,光有符合这个策略模型的自动化测试是远远不够的,我们项目还采用了针对微服务特点的探索式测试,保持持续交付节奏,践行DevOps实践,结合生产环境下的QA等技术把关注点右移到生产环境 。
现在,项目整体测试策略演变成下图的形式:
(项目测试策略)
项目上多次测试策略的调整,看似很简单,其实每次调整并不是一个轻松的过程,都是平衡利弊、综合考虑多个因素才做出的决定 。
分析整个调整过程 , 最后突然发现:当我们面对多个策略模型不知道如何选择的时候,其实我们陷入了一个太过于关注测试结构的误区 , 忘记了最初的目标是什么 。
跳出误区,回到原点 , 重新思考测试策略的目标 。影响策略的最关键因素是业务价值、质量要求、痛点 。
(影响测试策略的因素)
业务价值
带来更大的业务价值、帮企业赢得更多的利润,是软件系统的目标;软件测试是软件系统成功的保障之一,业务价值也是测试策略的终极目标 。所有测试活动都要围绕这个目标开展,考虑业务优先级,有效规避业务风险 。
质量要求
不同的系统、同一系统的不同利益干系人(参与的不同角色)对于质量的定义和要求都可能是不同的,这毫无疑问是影响测试策略的一个关键因素 。
对于仅有内部用户的系统,关注的重心可能是系统的功能;而对外发布的产品,则要求更高,一个按钮位置的不恰当都可能带来大量用户的流失 。
痛点
真正的痛点往往也是优先级最高,迫切需要解决的 。那些可以通过测试策略的调整来解决的痛点,自然成为了关键的影响因素之一 。比如 , CI Pipeline出包太慢,为了提高出包的效率 , 一方面在Pipeline本身想办法,另一方面调整自动化测试的比例、执行频率等也是解决方案之一 。
处在不同阶段的项目,在业务价值这个大目标下 , 其他影响因素也是会不一样的,跟技术架构的演进一样,测试策略也应该是演进式的 。
从目标出发,综合所处阶段各个方面的影响因素,制定出适合当时的测试策略 。随着时间的推移,对策略进行评估和度量,并进一步改进、提高,以更好的满足需求 。这就是目标驱动的演进式测试策略 。
(演进式测试策略)
微服务架构下多个服务的整合是最具有挑战的,对此最重要的是契约测试 。契约测试有效保证服务间的契约关系不被破坏,确保服务的连通性,有助于实现真正的独立部署和独立交付 。
微服务架构引入的不确定性并不是坏事,可以利用这些不确定性,采用生产环境下的QA等技术,增强系统的反脆弱性,从中获益 。
测试策略的影响因素不是唯一的,技术架构并不是最关键的因素 。微服务架构下的测试策略跟其他架构下的并不会有本质的区别 。
业务价值始终是我们的终极目标 。在这个终极目标的驱动下,测试策略不是制定完了就可以束之高阁的,需要在整个软件系统构建过程中不断的度量和改进,是演进式的 。
文/ThoughtWorks 林冰玉
【php微服务数据一致性 php微服务架构swoole】关于php微服务数据一致性和php微服务架构swoole的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站 。
推荐阅读
- 牛股王ios怎么没有,下载牛股王
- 华为安卓应用隐藏,华为安卓应用隐藏怎么设置
- 12周快速学会go语言 零基础学go语言多久
- php是否get到数据,php判断get参数返回数据
- 服务端安装oracle,oracle服务端安装步骤
- 电商衣服如何上品,电商上面卖的品牌衣服都是从哪拿的
- python继承虚函数 继承虚函数调用
- 包含拉萨苹果手机怎么扩容存储的词条
- ecg远程监测软件的设计毕业设计,远程监控系统设计