当前位置:网站首页>正在考虑微服务架构的松耦合?小心这些陷阱
正在考虑微服务架构的松耦合?小心这些陷阱
2022-04-21 17:19:00 【wx61d83844dd579】
微服务是一种新的架构,它使用简单、轻量、松耦合的服务来构建系统,这些服务彼此可以独立开发和发布。
如果你还不了解这些基础概念,请阅读 Martin Fowler的文章 。如果你想拿它和SOA进行比较,请看Don Ferguson的演讲 。Martin Fowler还写了“ 微服务的权衡 ”和“ 何时使用微服务 ”,让你决定什么情况下微服务是有用的。
本文假定你听说或阅读过微服务相关文章,并认同微服务理念。如果你正在实践微服务架构,你会碰到很多挑战。本文试图讨论如何处理这些挑战。
没有共享的数据库

每个微服务都应该有自己的数据库,而不是在同一个数据库中共享数据。这条规则可消除常见的导致微服务紧耦合的问题。比如两个服务共享同一个数据库,一旦其中一个改变了数据库的模式(schema),另一个就会无法工作。因此这两个微服务所在项目组必须事先沟通。
我认为这是一条很好的规则,不应该被破坏。然而这里有个问题。如果两个服务共享相同的数据(比如银行账户,购物车),且数据需要被事务性地更新,最简单的方法是将数据存储在同一数据库中,并利用数据库的事物来确保一致性。任何其它的方法都是很困难的。
方案1:如果更新只发生在一个微服务(比如贷款批准中的余额核对流程),可以使用异步消息机制(消息队列)共享数据。

方案1:如果两个微服务都有更新,可以考虑合并它们,或者使用事务机制。文章“ 微服务:不止服务的规模,也包括你如何使用服务 ”描述了合并的方法,下一节我们详细讨论事务机制。
处理更新的一致性
考虑多个地方都有对同一数据进行更新的场景。我们在上一节中讨论了一个例子(如果只有一处地方更新,我们已经讨论过如何处理)。
请注意这个典型得使用事务来解决的用例。然而有时你也可以不用事务来解决。这里有一些其它的选项。
所有更新放在同一微服务中
只要有可能,都要避免多个跨越微服务边界的更新。然而有时候这么做,你会碰到更大的问题,因此这不通用。
使用补偿和其它更小的抵押物
正如著名文章“ 星巴克不使用两阶段的提交 ”中描述的,普通的生活中不需要用到事务。例如星巴克的咖啡师不会等到你的事务完成才继续其它的事务。相反,他们会同时服务多个客户,一旦有错误立即显式补偿。如果你愿意稍微多做点工作,你也可以像他们这样做。
一个简单的想法是,如果一个选项失败了,你可以做些补偿并继续前进。例如你正在运送书本,首先要扣钱,才能运送,假如运送失败,你退还货款,然后继续。
有时候你也会专注于最终的一致性或者超时。另一个简单的想法是,给一个按钮,假如这个按钮能区分超时,那就让它强制刷新页面。另一些时候,只能忍痛考虑少一点的一致性了(例如 Vogel 的文章 就是个好的起点)。
最后,“ 分布式事务以外的生活:一个背叛者的观点 ”详细讨论了以上所有技巧。
话虽如此,仍旧存在你必须使用事务才能获取正确结果的情况。这时候就必须使用事务了。可参考“ 微服务和事务(更新篇) ”。考虑各种方法的优缺点,明智得选择最合适你的那个。
微服务安全
早期的做法是,当一个服务接收到请求时,调用数据库或者身份认证服务器来做认证。

这里身份认证服务器也可以用一个微服务来替代。在我看来,那样做会生成一个巨大且复杂的依赖图。
相反,我喜欢如下图所描述的基于token的方法。这个想法在“构造微服务”这本书中有描述。首先客户端(或者网关)告诉身份认证服务器谁将过来认证用户,服务器返回给客户端一个token,它描述了这个用户和它对应的角色(你可以用SAML或者OpenIDConnect来达到这个目的)。每个微服务验证这个token,根据token所描述的用户角色来授权访问。
例如,用这种模型,对同一个请求,一个“发布者”角色的用户和一个“管理员”角色的用户可能看到不同的结果,因为他们有不同的权限。

你可以在“ 如何在微服务中控制用户身份 ”这篇文章中找到关于这种方法的更多信息。
微服务组合
这里,“组合”指的是,“如何连接多个微服务为一条工作流,来获取终端用户想要的东西”。
大多数SOA的组合看起来如下所示。中心思想是有个中央服务器来运行整条工作流。

不提倡微服务中使用企业服务总线(ESB)(例如, 第5章DevOps团队关于反对ESB的争论 )。同时,你也可以在“ 好的微服务架构诅咒ESB的死亡? ”中找到某些相反的辩论。
本文不打算深入研究ESB。然而我想讨论是否我们需要一个中央服务器来组合微服务。有很多方法来组合微服务。
方法1:客户端驱动流程
下图展示了一个不用中央服务器来组合微服务的方法。客户端浏览器处理这个工作流。文章“ 域服务的聚合:一种构造微服务组合的结构化方法 ”就是这种方法的一个例子。

这个方法存在一些问题:
1. 如果客户端在一个很慢的网络里,而这往往是最常见的情况,流程的执行就会变得很慢,因为现在多个调用都需要由客户端来触发。
2. 可能需要加强安全考虑(我可以侵入我的应用让它给我贷款)。
3. 以上的例子只考虑了网站。然而,大多数复杂的组合通常来自于其它的用例。因此其它用例下客户端的组合的通用性还需要被证明。
4. 哪里可以保存状态?客户端可以被信任用来保存工作流的状态吗?用REST模型来保存,是可行的,但是也是复杂的。
方法2:编排
从中心位置来驱动流程称为编制(orchestration)。然而那不是协调多个合作方共同完成任务的唯一方式。例如在舞蹈中,就没有一个指挥整个表演的人,相反,每个跳舞者都跟随她旁边的人并保持同步。编排(choreography)就是把这个想法应用到业务流程中。
事件系统就是编排的一个典型实现。该系统中每个参与者监听不同的事件并执行它所对应的那些事件。每个动作都会生成异步事件,这些事件又触发下游参与者生成对应的动作。这就是RxJava和Node.js等环境使用的编程模型。
例如,我们假定一个贷款过程包括一个请求,信用核查,其它外部贷款核查,领导审批,以及最终结果的通知。下图展示如何使用编排实现这一过程。请求将被放在当前队列中。它的下个阶段处理完结果并将结果放到该阶段所对应的队列后,再从当前队列中取出一个请求继续处理。这个过程会一直持续到请求结束。

就像舞蹈需要排练一样,编排也是复杂的。例如你不知道某个过程什么时候结束,也不知道它是否发生了错误或者被阻塞了。编排需要一个监控系统来追踪过程并恢复或者通知某些错误。
另一方面,编排的优点是,它能创建非常送耦合的系统。例如,你可以频繁添加一个新的参与者,而不需要修改已有的参与者。你可以在“ 使用事件流伸缩微服务 ”中找到更多详细信息。
方法3:集中式服务器
最后一个,也是最简单的一个选项,是使用集中式服务器(也称作编制)。
SOA通常用两种方法来实现集中式服务器:企业服务总线(ESB)或者业务流程。微服务偏好者们建议使用API网关(例如文章“ 微服务:分解应用提高可部署性和可扩展性 ”)。我猜API网关是更轻量级的并且使用REST或者JSON等技术。但是从架构的角度来说,它们都使用编制的风格。
另一个集中式服务器的变种是“backend for frontends”(BEF),它为每种客户端都构造一个服务端的API(如桌面应用的服务端API,iOS应用的服务API等)。这种模式为每种客户端类型都创建不同的API,在每种场景下都最优化。详情请参考:“ backends for frontends ”。
我在这里就不把所有选项都介绍一遍了,仅以API网关为例,因为这是最直白的一种方法。如果你有需求,可以切到更复杂的方法。
避免过度依赖
我们使用微服务架构就是为了使每个服务都能独立发布和部署,因此必须避免过度依赖。
假定微服务A有一个API“A1”要升级成API“A2”。现在有两种情况:
1.微服务B能将发送给“A1”的消息发送给“A2”。这是后向兼容。
2.微服务A可能必须回退到“A1”,微服务C要求可以继续将发送给“A2”的消息发送给“A1”。
你必须能够处理上述场景,并使得微服务能独立演进和部署。如果不行,你所有的努力都将付诸东流。
处理这些场景,通常就是添加可选参数,并且不重命名或者删除已有的参数。然而更复杂的场景也是有可能的。文章“ 微服务中改善过度依赖 ”详细描述了这些可能,“ 如何对微服务进行版本控制 ”也是一个很好的例子。
最终,后向和前向兼容的支持都应以时间为界。例如,你可以规定,所有微服务都不应再依赖超过三个月时常的API。这可以让微服务的开发者最终清除某些代码。
最后我将再强调一下,在微服务架构中,你的依赖图应该长啥样。
一种是一旦需要,尽情得调用其它微服务。这将创建一个意大利细面的结构。我不支持这种模型。
另一个极端是微服务不应调用其它微服务,所有连接都应通过API网关或者消息总线来完成。这将生成一棵只有一个层次的树。例如我们不是让微服务A直接调用B,而是让A通过API网关来获取调用B的结果。这其实就是编制模型。如此一来,大部分的商业逻辑都将储存在API网关中,从而使得API网关异常庞大。
我的意见是,要么使用编制模型,要么通过艰苦的工作合理地实现编排模型。是的,不要用意大利细面的结构。
结论
微服务的目标是松耦合。仔细设计微服务架构允许你实现一个使用微服务集合的工程,每个微服务都可以被独立管理,开发和发布。
当你设计微服务的时候,你必须一直盯着那个奖品,既“松耦合”。这将会碰到许多挑战。本文回答了下列问题:
1. 如何处理两个微服务间需要共享数据的场景。
2. 如何在保持松耦合的前提下演进微服务API。
3. 如何处理安全。
4. 如何组合微服务。
谢谢大家。非常希望听到大家的想法。
欢迎关注“互联网架构师”,我们分享最有价值的互联网技术干货文章,助力您成为有思想的全栈架构师,只聊架构,不聊其他!打造最有价值的架构师圈子和社区。
长按下方的二维码可以快速关注我们

版权声明
本文为[wx61d83844dd579]所创,转载请带上原文链接,感谢
https://blog.51cto.com/u_15486212/5238985
边栏推荐
- R语言使用Hmisc包的label函数为dataframe中的特定变量(数据列)添加变量标签、将dataframe的数据列名称修改为数据说明标签、而通过数值索引访问dataframe数据列
- NFT板块第二春——关于提前布局 Solana 正在崛起的 NFT 生态系统你需要知道的一切
- R language uses qbern function to generate Bernoulli distribution (0-1 distribution) quantile function data, and uses plot function to visualize Bernoulli distribution
- Control @ schedule on in different environments
- Fault analysis | federated storage engine table causes the monitoring thread to be in the opening table state
- 【ACM/webank】#491.递增子序列(使用HashSet来记录并防止重复子序列)
- No more simple intention lock
- Database Principle -- library management system
- 【面试普通人VS高手系列】b树和b+树的理解
- 关于内推想说的
猜你喜欢

【一篇文章帮你打好路由基础】

338-Leetcode 同构字符串

idea装杯小技巧——实现鼠标滑动导包

ls -al各字段意思

Extensive reading of alexnet papers: landmark papers in the field of deep learning CV neurips2012

基于SSM的美容院管理系统(附源码+项目展示)

. net core enterprise wechat web page authorization login

The first five chapters are thought maps
![[interview ordinary people vs Expert Series] can you talk about CAS mechanism?](/img/ec/2c96667f79f72872e0dd0169516446.png)
[interview ordinary people vs Expert Series] can you talk about CAS mechanism?
![[interview ordinary people vs Expert Series] understanding of B tree and B + tree](/img/b9/d648a0da059713ba5ac139dbfad2cd.png)
[interview ordinary people vs Expert Series] understanding of B tree and B + tree
随机推荐
R语言使用grepl函数检查子字符串是否存在于指定的字符串中、字符串匹配,负责搜索给定字符串对象中是否包含特定表达式
idea装杯小技巧——实现鼠标滑动导包
No more simple intention lock
ROS2放弃指南5:创建ros2的topic
结构体malloc bug
IO view command
我用Ehcache把查询性能提升了100倍,真香
Common problems and solutions of redis distributed lock
幹貨 | 實戰演練基於加密接口測試測試用例設計
When you encounter technical problems
Vitis HLS 构建项目并生成IP核(Vivado HLS)
The R language uses the plot function to visualize the data scatter diagram. The col parameter is set as factor variable and custom color list. The data points in different groups are displayed in dif
1、 Overview of database system of database Series
Precautions for MySQL aliasing database tables
Using Jetson nano as an environmental weather station
Summary of Wu Enda's course of machine learning (5)
【免费】某平台19860元编程课程资料下载,仅此1次
R language uses the label function of hmisc package to add variable labels for specific variables (data columns) in dataframe, modify the data column name of dataframe to data description label, and a
R语言使用dplyr包中的select函数基于数据列的索引数值删除dataframe中数据列
169. 多数元素