服务粒度的艺术 - 简化架构与避免服务泛滥
01 背景
在今年的敏捷团队建设中,我通过Suite执行器实现了一键自动化单元测试。Juint除了Suite执行器还有哪些执行器呢?由此我的Runner探索之旅开始了!
前些时间小组有个需求上线牵扯9个应用(小组当时维护了26个服务,由于团队系统业务属性特征基于高可用、高性能原则拆分,有些是合理的,有些不是很合理的),同时上周OpsReview的一个微服务滥用典范案例(Promise服务A调用服务B,服务B只是读个配置数据返回,无具体业务逻辑),OpsReview会上也看到过其他微服务泛滥等案例,这些事情引发了我对服务泛滥和服务粒度的深入思考,接下来在稳定性的前提下,基于成本收益维度思考,小组哪些应用(先从2级开始)应该合并治理。
在当今软件开发的舞台上,微服务架构因其所灵活性以及独立部署等优势而广受推崇。然而,随着服务的过度细分,我们面临着服务数量激增所带来的管理复杂性和分布式通用问题挑战性等。
本文通过Promise后端现有服务探讨服务粒度的合理划分与有效合并的关键因素。本文的观点源自我在学习与实践过程中的思考,尚处于不断探索和验证的阶段。希望能“抛砖引玉”,引发大家的思考与讨论,让我们共同进步,从而优化我们的系统设计。
目前团队服务泛滥的影响如下:
1、维护成本增加:服务数量的增加直接导致了维护工作量的增加。这不仅包括服务器维护,还包括代码维护依赖管理,比如Promise时效内核升级、中间件JSF等版本升级、安全漏洞工单log4j版本改造等都需求部署上线N个(最多26)应用。当服务数量过多时,即使是小的变更也可能需要协调多个服务,从而增加了工作量。
2、团队协作难度:在服务泛滥的环境中,团队成员可能需要跨多个服务进行协作,比如本次需求上线牵扯9个应用。这不仅需要更多的沟通和协调,而且还需要确保所有相关人员对服务的改动和更新都有清晰的认识。这种跨服务的依赖关系可能会导致团队间的沟通混乱和效率低下。
3、资源利用效率低:服务泛滥可能导致资源分配不均,一些服务可能过度使用资源,而其他服务则可能闲置。这种不平衡的资源分配会导致整体成本的上升。
名词解释:
模块化:是指将一个复杂的系统分解成若干个相互独立且可集成的部分,这样可以简化系统的设计、开发和管理。模块化的目的是通过创建高内聚、低耦合的模块来提高软件的可维护性、可复用性和可扩展性。在模块化的过程中,每个模块都是一个独立的单元,可以单独开发、测试和优化,同时通过定义良好的接口与其他模块通信。
粒度:在软件架构中,粒度通常用来描述组件或模块的大小和层次。较小的粒度意味着系统更加灵活,因为它允许更精细的控制,但可能会带来性能问题,如增加硬件资源和通信开销。较大的粒度则可能提高效率,但会牺牲一定的灵活性。
02
Promise服务粒度问题
理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将
简单描述下各应用作用:
1.A:订单履约控制中心
2.B:promise时效服务,主要提供订单下传库房时效、订单妥投时效
3.C:promise产能服务,主要用于仓库产能查询、产能占用
4.D:promise消息服务,主要用于订单时效异步处理,其中包括发送全程跟踪,订单时效缓存等。
对应用户在京东APP购买商品流程如下:
1.北京用户4月1号22点购买了一件衣服,库存中台定位的是北京的仓。
2.A服务通过JSF调用Promise计算这个订单下传库房时间是4月2号0点01分(对应B应用)。
3.JSF调用占用4月2号的仓库产能(对应C应用)。
4.然后通过MQ方式给用户发送全程跟踪话术,告知用户订单时效环节(对应D应用)。
5.最后把订单时效数据进行保存持久化,用于业务进行数据分析和履约绩效考核(对应E-mysql持久化应用)
那么问题来了:
接下来针对这个问题,进行分析。
03
服务粒度
理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将
模块化关心系统分解成单独的部分。而粒度则处理这些单独部分的大小。粒度才是分布式各种挑战的问题关键。那如何来度量粒度大小呢?看里面java文件数、class类数量、代码行数?其实并不是的,而是看服务的职责,服务范围包含哪些,另外一个指标是看服务对外提供的公共API接口或者MQ的数量。虽然这2个指标也是存在变化和主观因素,但这应该是目前最接近客观度量和评估服务粒度的方法。
1、拆分因素
粒度拆分因素解决的是什么时候应该将服务拆分为更小部分。为服务拆分为更小的部分提供了指导和依据。其中粒度拆分因素的主要因素如下:
1.1 服务职责&业务边界
第一个维度是内聚性,即服务内部的行为关联的紧密度,每个服务应该只负责一个业务能力或业务领域。
第二个维度是组件的整体大小,服务的大小和职责范围需要平衡,既不能过于庞大,也不能过于细碎。一般根据服务对外提供的入口数来度量。
1.2 容错性&稳定性&高可用
容错性和服务可用性也是很好的分解因素之一,分析如何通过服务拆分提高系统的容错性和高可用性。
将系统中的业务模块按照业务优先级排序,可靠性要求高(0/1级应用)的核心服务和可靠性要求低(2级应用)的非核心服务拆分开来,重点保证核心服务的高可用。这样可以避免非核心服务故障影响核心服务。
服务的粒度越大,故障发生时带来的影响面也越大,识别出系统中脆弱的部分将其拆分出去,可以有效的减少故障时带来的连带影响。拆分为更小的服务,以便于在不同的节点上实现容错和故障转移。
1.3 性能&吞吐量
基于性能拆分和基于可靠性拆分类似,将性能要求高或者性能压力大的模块拆分出来,避免性能压力大的服务影响其他服务。
1.4 可扩展性
服务拆分需要考虑可扩展性。其实很多设计方案都会多度设计扩展性。其实通常很难去猜测未来上下文功能是否可能会扩展(比如额外的数据持久化方式hbase、jdq等)。
做过太多需求,说某种业务场景未来可能会用,但根据历史经验,业务基本不会有这种场景。
建议是等待,直到持续可扩展性被确认,然后让可扩展性这个因素成为判断粒度分解的主要因素。
1.5 团队大小和稳定性
考虑开发、维护团队的能力和组织结构。服务拆分应便于团队协作和沟通。
2、合并因素
上面的拆分因素为何时将服务分解为更小的部分提供指导和依据,那粒度合并因素则相反,为服务重新重合在一起提供指导和参考依据。粒度集成的几个主要因素如下:
2.1 服务原子性
考虑不同服务之间是否需要事务?需要原子操作或事务性的业务流程可能不适合拆分成多个服务,因为分布式事务管理通常是复杂且成本较高的。
具有原子操作的单独服务具有更好的安全访问控制
如果服务之间需要频繁同步数据以保持一致性,这可能表明它们应该被集成合并为单个服务。
具有组合操作的单独服务间不支持数据库事务,微服务应该追求数据自治,每个服务拥有自己的数据库,以避免分布式事务的复杂性。
2.2 成本效益
硬件成本:如果拆分后,硬件成本更高,可能更倾向更粗粒度,减少资源消耗
变更成本:如果服务经常一起变更(开发、测试、部署、上线),可能更倾向更粗粒度。
维护成本:维护多个服务,比如服务通用治理版本升级等,成本较高
2.3 网络开销
考虑服务之间是否有交互?服务间的通信会带来额外的延迟。如果服务拆分导致大量的远程调用,这可能会对性能造成影响。在某些情况下,集成合并服务以减少网络通信可能更有利
2.4 共享代码
是否有共享代码,在分布式服务架构中处理共享代码,事情会变得复杂,有时候会影响服务粗粒度。如果共享代码太多,合并则可能更合适
2.5 数据关系
数据库表的关系影响服务粗粒度,服务之间的数据是否也可以拆分?
假设服务底层数据并不共享,而是在每个服务内形成紧密的限界上下文,则适合拆解
如果底层数据共享相同表,可能更适合一个服务
2.6 代码变更&部署频率
代码变更的频率是服务分解的另一个考虑因素,如果服务之间变更频率是一样的,可能不适合拆分
如果一组服务总是一起更新,这可能表明它们是高度耦合的,应该作为一个单独的服务部署
2.7 测试和监控
考虑服务划分对测试策略和监控体系的影响。更细的服务粒度会带来更复杂的链路监控和日志管理需求。
微服务的监控和日志管理可能会变得复杂。如果服务拆分导致难以追踪问题和性能监控,这可能是一个合并服务的理由。
Q: 关于持久化,目前包括两个应用:E-mysql和E-es。是将它们设计为一个服务更合理,还是作为两个独立的服务?A: 综合前述的分析,将这两个应用设计成一个服务显得更为合理。这样的设计可以充分利用两者之间的协同效应,同时简化系统架构,提高维护效率。通过统一的服务接口,我们可以更加灵活地管理数据持久化的过程,无论是对MySQL还是Elasticsearch的操作,都可以确保一致性和高效性。这种一体化的服务设计,既可以减少系统复杂性,也便于在需要时对服务进行扩展和优化,但需要做好es容错性,即es有问题不能影响mysql业务。
04
总结
理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将
在微服务架构的世界里,服务粒度的艺术不仅仅是技术上的划分,更是对业务理解的体现,对系统复杂性的把控,对团队协作和效率的考量。我们不能忽视服务粒度选择对系统性能、可维护性和可扩展性的深远影响。正如我们通过Promise系统的探索所见(Promise业务属性是下单前商详结算黄金链路、下单后订单控制节奏,一切的拆分原则优先考虑高可用、高并发出发),恰当的服务粒度能够带来清晰的职责边界,提升系统的响应性和可靠性,同时降低维护的复杂性和成本。
在决定服务如何拆分或合并时,我们不仅要考虑技术因素,还要考虑团队结构、业务需求和未来的可扩展性。这需要我们深入理解业务逻辑,预见潜在的变化,并且勇于对现有架构进行调整。服务粒度的选择不是一成不变的,而是随着业务的发展和技术的进步而不断演化的。
我们不要简单地追求服务数量的增加,而是追求每个服务能够在正确的时间做正确的事情。通过精心设计服务粒度,构建出既强大又灵活的系统,这些系统能够支持我们的业务成长,应对未来的挑战。
如果您的团队面临服务泛滥,您会如何权衡服务的粒度呢?欢迎大家指正和完善,谢谢!
本文的观点源自我在学习与实践过程中的思考,尚处于不断探索和验证的阶段。希望能“抛砖引玉”,引发大家的思考与讨论,让我们共同进步,从而优化我们的系统设计。
附:软件架构第一定律:软件架构中的一切都是在权衡
面向AI的开发:从大模型(LLM)、检索增强生成(RAG)到智能体(Agent)的应用
营销权益平台春晚技术探究京东中台化底层支撑框架技术分析及随想