案例研究:将结帐系统拆分为太多服务
内容提要
该项目计划用现代、可扩展、松散耦合的实现替代现有的难以扩展的结账系统。选择微服务架构作为目标架构,但微服务之间的复杂性增加,导致系统不稳定。解决方案是将结账系统实现为使用本地交易的模块,这样可以更容易维护和扩展,并解决分层主义问题。错误的决定是由炒作驱动的开发造成的。
延伸解读
微服务拆分过细的代价
文章显示,团队为每个小功能调整多个服务,且多数服务相互依赖,导致每次调用至少需要五个HTTP或MQTP连接才能访问遗留系统。这种细粒度拆分使变更成本急剧上升:一个小功能需要同时部署多个服务,开发人员要在不同仓库间切换。这提醒我们,服务边界应围绕业务能力而非技术潮流划分,否则拆分越细,协调成本越高。
中央编排服务成为单点故障
中央编排服务被描述为整个应用的单点故障,既不可扩展,实现方式也不适合该系统。许多必要功能无法在所选框架中实现,且核心服务与其他服务或遗留系统之间的数据格式不一致、连接不稳定,使通信更易出错。系统故障大多由该核心服务引发。这说明编排层若缺乏弹性设计,会成为系统稳定性的瓶颈,而非助力。
最终一致性不适合结账场景
结账系统需要一致的状态,但团队将其实现为具有最终一致性的分布式系统。文章指出,实现最终一致性很难正确,通常导致容易出错且难以维护的代码。这揭示了架构选型必须匹配业务的一致性需求:对于状态一致性要求高的核心流程,本地事务比分布式最终一致性更可靠,也更易维护。
模块化单体作为替代方案
文章提出的解决方案是将结账系统实现为使用本地事务的“模块”。这样模块间不再需要网络调用,可解决“分层主义”问题,系统更易维护和扩展,还能通过单个适配器抽象对遗留系统的访问。这一思路表明,在遗留系统仍承担关键计算的情况下,模块化单体可能比微服务更务实,能避免过度设计和过度模块化。
Q&A
为什么将结账系统拆分为微服务后系统变得不稳定?
微服务之间的复杂性显著增加,每个小功能都需要调整多个服务,且服务间高度依赖。中央编排服务成为单点故障,既不可扩展也不适合该软件系统。核心服务与其他服务或遗留系统之间的数据格式不一致和连接不稳定,导致通信容易出错。系统作为分布式系统实现最终一致性困难,容易产生错误且难以维护。
中央编排服务在结账系统中扮演什么角色,为什么成为问题?
中央编排服务负责编排核心服务,但它是整个应用程序的单点故障。它既不可扩展,也不以最适合此类软件系统的方式实现。许多必要的功能无法在所选框架中实现,且由于数据格式不一致和连接不稳定,与该服务的通信更容易出错。每当系统故障时,大多数时候都是这个核心服务造成的。
结账系统为什么需要一致的状态,而微服务架构难以满足?
结账系统需要一致的状态,但微服务架构将其实现为具有最终一致性的分布式系统。实现最终一致性很难正确,并且通常会导致容易出错且难以维护的代码。因此,分布式系统难以满足结账系统对一致状态的需求。
针对微服务拆分带来的问题,文章提出了什么解决方案?
文章建议将结账系统实现为使用本地交易的“模块”。这样新系统将更容易维护和扩展,并且“分层主义”问题也将得到解决,因为应用程序的模块之间不再需要网络调用。此外,还可以通过使用单个适配器而不是独立的服务来抽象对遗留系统的访问。
文章中提到“炒作驱动的开发”导致了哪些具体问题?
“炒作驱动的开发”导致结账系统的功能和非功能需求被部分忽视。具体问题包括:过度设计、过度模块化、会议驱动开发和分层主义。这些模式使得系统复杂且难以维护。
微服务之间的通信方式是什么,带来了哪些挑战?
服务之间的通信要么通过HTTP进行同步,要么在某些情况下通过MQTP进行异步。这种通信方式带来的挑战包括:每次调用至少需要五个HTTP或MQTP连接才能访问遗留系统中的数据;服务之间存在高度依赖性,任何“基本”服务或遗留系统适配器的更改都会导致大量其他服务更改;数据格式不一致和连接不稳定增加了错误发生的可能性。