系统拆分是单体程序向分布式系统演变的关键一步,也是很重要的一步,拆分的好坏直接关系到未来系统的扩展性、可维护性和可伸缩性等,拆分工作不难理解,但是如何正确拆分、有什么样的方法和原则能帮助我们拆分得到一个我们理想中的系统:高可用、可扩展、可维护、可伸缩的分布式系统。
拆分中的挑战
模块化在开发大型复杂的应用的时候是非常有必要的。现在互联网中的许多应用是无法靠一个人去独立完成的。这种情况下,应用就必须被拆分成一个个模块。每个服务对应一个业务能力,这个业务能力是组织为了创造价值而需要的。每个服务都有一个不可渗透且很难违反的边界。也就是每个微服务要提供一种单独而独立的能力。这样的话,应用程序的模块化就更容易随时间保存。不幸的是,拆分并没有听起来那么容易。
在添加更多的微服务时,必须确保这些微服务能够一起扩展。颗粒度更细致,代表着可移动的部件更多,从而导致系统更加复杂。
参与交互的服务越多,可能的故障点就越多。
将功能从单一整体化架构向微服务架构迁移时,会有很多持续通讯的小型组件产生,追踪单个业务事务在不同层面中的性能问题可能非常困难。
由于微服务是无状态的、分布式的、独立的,因此传统的日志记录方式不再实用,要定位某个问题,微服务的日志需要做到与跨平台的事件相关联。
拆分的原则
网上找到一张特别好的图,可以清晰简单的说明拆分的原则:
(截图来源于网络)
x轴:水平复制,即在负载均衡服务器后增加多台服务器;
z轴扩展:是对数据库的扩展,即sharding(分库关注垂直方向是将关系紧密的表放在一台DB,分表关注水平方向将一张数据量大表通过hash等策略放在多台DB);
y轴扩展:是功能分解,将不同职能的模块分成不同的服务。例如订单服务、用户服务、商品服务。
拆分方法与策略
拆分方法需要根据现有系统的状态,通常分为“推倒重来”与“修复改进”两种方案。
其基本原理来自Martin Fowler的branch by abstraction的重构方法,如下图所示:
(截图来自与Martin的个人主页)
如上图所示,通过梳理内部被拆模块的功能,对其增加接口层,将旧的引用改为新接口调用;随后将接口封装为API,并将对接口的引用改为本地API调用;最后将新服务部署为新进程,调用改为真正的服务API调用。
拆分建议从业务相对独立、耦合度最小的地方开始。待团队配合及获取相应经验和基础设施平台构建完善后,再进行核心功能的拆分和更大范围的重构。
总结
系统拆分的核心部分包括以下几点:
小, 且专注于做⼀件事情
轻量级的通信机制
松耦合、独立部署
高内聚低耦合的模块化代码内部质量是架构演进的基础。系统拆分之前需要弄清背后的拆分动因与价值,探索性前进,及时反馈验证,持续优化。
扫描二维码或手动搜索微信公众号【架构栈】: ForestNotes
欢迎转载,带上以下二维码即可
点击“阅读原文”,所有【架构栈】近期的架构文章汇总
↓↓↓