微服务架构实践感悟
从去年初开始接触微服务架构的一些理念,然后到今年开始实施系统第四个大版本的架构升级决定采用这套架构理念。 最近关于微服务架构的讨论还是多起来,因为国外一些著名互联网公司(如:Amazon、Netflix 等)从实践中摸索出了一套新的大型系统架构方法论,并取得了成功,树立了很好的示范,然后这套方法论渐渐就被一些技术理论派 人士命名为微服务架构(Microservices)。
在微服务架构(Microservices)这个命名被正式提出来之前,我们做系统也有一套著名的思想理论,叫做面向服务架构(SOA)。 去年初我就写过一篇文章 《面向服务与微服务架构》 来阐述面向服务和微服务架构的关系,当时并没有给出明确定义,只是有个模糊认知,而在近一年的实践过程中两者的关系越发清晰起来, 我们就从定义两者的关系这里开始吧。
微服务(Microservices)与 面向服务(SOA)架构
You should instead think of microservices as a specific approach for SOA in the same way that XP or Scrum are specific approaches for Agile software development.
上面这段引用自 《Building Microservices》 一书, 通过过去一年的实践认知,我对这个定义是认同的,面向服务架构(SOA)的概念已有十多年,它提出了一种架构设计思想, 但没有给出标准参考实现,而早期企业软件业界自己摸索了一套实践方式 —— 企业服务总线(ESB)。 但历史证明 ESB 的实现方案甚至在传统企业软件行业也未取得成功,Martin Fowler 说正是因为 ESB 当年搞砸了很多项目, 投入几百万美金,产出几乎为 0,因此 SOA 这个概念也蒙上了不详的标签,所以当微服务架构出现时, 其拥护者开始拒绝使用包裹着失败阴影的 SOA 这个标签,而直接称其为微服务架构(Microservices Architecture Style), 让人以为是一套全新的架构思想,我也因此困惑了一段时间,但事实上它的本质依然是 SOA 的一种实现。 正如上面引文所说,就像早年流行的 XP(极限编程)和近年流行的 Scrum(好像没有标准的中文说法)实际都是敏捷软件开发思想 的具体实践方法而已。
为什么选择微服务架构
首先,当然是该套架构方法有著名的成功经验才导致我去了解与学习它。 微服务架构中的 “微” 体现了其核心要素,即服务的微型化,就是每个服务微小到只需专注做好一件事。 这件事紧密围绕业务领域,形成高度内聚的自治性。
以前我做过的一些大型应用系统,采用模块化的分层式架构,所有的业务逻辑代码最终会打进一个代码库中统一部署。 这种应用架构的问题是,全部开发人员会共享一个代码库,不同模块的边界模糊,实现高内聚、松耦合极其困难。 如果你接手过这类应用的遗留系统,尝试去做重构改进时,肯定碰到过这类场景,改了一个地方好几个其他模块也需要同步改动, 模块的边界轻易被穿透,这种应用的架构有一个很形象的名字叫 “洋葱架构”,洋葱的特点就是一层又一层的粘连, 重构这样的系统就像切洋葱一样让人忍不住飙泪。
微服务架构强调 “微”,但之前有些采用了 SOA 服务化架构思想的系统会搞出很多胖服务来,一点也不微,这依然带来耦合。 这一点只能依赖系统架构师的服务化建模能力了,但微服务架构强调每个服务一个进程, 使用进程为边界来隔离代码库至少让同一应用系统不同层次的开发人员享有自己完全自治的领地,每个微服务都有一个掌控者。 从某种程度上让不小心做错事,例如:跨出服务边界的代码耦合依赖,变得没那么容易。
去年对我们应用系统的代码行数做了个统计,有超过 40 万行。 一个 20 人的团队维护一个 40 万行共享代码库的单一应用,在里面修改 bug 和添加功能都将十分困难。 有一篇文章 《程序员的成长和代码行数的关系》 里提到大部分普通程序员成长生涯的瓶颈在 2 万行代码左右, 超过这个代码行数的应用系统维护起来将倍感吃力,所以我们系统这两年的高速发展膨胀,已让团队维护起来倍感吃力了。 所以我们想要把一个大系统拆分成许多不同的微服务,每个微服务的规模大小控制在一个普通程序员的舒适维护区能力范围内。
微服务架构实施
把 1 个应用进程部署到 1 台主机,部署复杂度是 1 x 1 = 1,我们有 200 台主机,那么部署复杂度是 1 x 200 = 200。 把 1 个应用进程拆分成了 50 个微服务进程,则部署复杂度变成了 50 x 200 = 10000。 部署变得复杂和麻烦多了,同时监控的进程数也大幅增加,监控的复杂度也上升了很多。
所以实施微服务架构是有很高成本的,只有系统的规模到了一定程度才适合,这也是为什么微服务架构实践诞生于大型互联网公司。 微服务推崇一切自动化的文化,这也是因为其运维复杂度的乘数级飙升, 从开发之后的构建、测试、部署都需要一个高度自动化的环境来支撑才能有效降低边际成本。
《Building Microservices》 一书对实施微服务架构有系统性的描述和很多业界案例的简单引用描述,这里不展开讲实施细节,那样就太长了。 我们这里简单总结下实施的要点:
- 自动化文化与环境:自动构建、自动测试、自动部署。
- 围绕业务能力建模服务,松耦合、高内聚、暴露接口而隐藏实现细节。
- 服务协作模型:中心化(乐队模型:中心指挥)和去中心化(舞蹈模型:群舞自组织),各自场景不同。
- 服务交互方式:RPC/REST/WS 技术很多但考虑统一。
- 服务部署的独立性、失败隔离性、可监控性。
- 服务流控:降级、限流
- 服务恢复:多考虑故障发生如何快速恢复而非如何避免发生故障。
- 服务发布:灰度。
- 服务部署:一服务一主机模型,需要虚拟化(Hypervisor)、容器化(LXC, Docker)等技术支持,实现硬件资源隔离。
- 服务配置:中心化配置服务支持
- 康威定律:任何设计系统的组织,最终产生的设计等同于组织之内、之间的沟通结构。系统架构的设计符合组织沟通结构取得的收益最大。
- 伯斯塔尔法则:服务健壮性原则 —— 发送时要保守,接收时要开放。
自进化的微服务架构
早期人们把软件开发和建筑学作类比,Architect 这个词来就源于建筑学,但软件产品和建筑物的性质完全不同。 建筑物本身一旦建成则几无变化了,唯有老化后被替代了。 软件系统会在其生命周期中不断变化,唯一不变的就是变化,拥抱变化,需用进化的观点看待架构演进。 与此类似的是城市,城市的演进发展总是渐进式的,我们不会在一座旧城旁建一座新城,然后把旧城的居民迁到新城然后再把旧城废弃了。 但经常我们会用这样的方法重写一个新系统并替换掉旧系统,付出高昂的成本。
而微服务架构思路是不鼓励这种方式的,系统的演进是通过局部的新增、改进或替换微服务来实现的。 而微服务本身的变化周期是不同步的,从整体上就形成了一种渐进式的、符合自然进化的系统演进道路。 所以 Architect(架构师)更像是城市规划师而非建筑师,对软件系统进行类似城市划分区域的规划。 从常识上我们知道把学校和住宅放在一个区域内是合理的,但如果再放一个垃圾处理厂则不合理。 学校和住宅就是提供两种不同能力的服务,垃圾处理厂是另一种服务,但现实中软件系统的规划其实不像城市规划那么有常识性, 这是架构师能力和经验发挥作用的地方,前期规划的不合理会在后期带来维护成本的放大。
每个历史悠久的城市都有各自不同的味道,城市中的人、时间、技术进步共同决定了今天城市的面貌。 微服务架构的妙处就在于它符合城市历史演进规律,随着人员变化、时间、技术改进而引发自然渐进式的进化。
微服务架构与架构师
架构师的一个角色是技术决策者,技术决策涉及很多权衡取舍(trade-off),而微服务架构给了架构师更多权衡取舍的空间。 每个微服务实现层面的技术决策更多由服务负责人决定,服务的分拆伴随着决策权和责任的分拆,这也减轻了整体应用负责人的责任负担。 架构师解放出来从整体和全局上将更加关注服务之间是如何交互,并确保能正确的监控系统全局的健康性。
分拆了服务实现的技术决策权,那何时又该适当的介入以避免服务实现不当危及整体系统的安全? 就像教孩子骑车,你无法代替它们去骑,你小心的看着他们骑的歪歪扭扭,担心他们摔倒。 事实上,孩子骑车摔倒的次数比你担心的要少,但如果每次快摔倒时都去扶住,那么他们也许永远学不会骑车。 当孩子骑车失控时冲向了繁忙的马路或要冲下路边的深沟,那时才有必要介入去稳住他们。
架构师工作在抽象和具体两个层面:
- 架构是一项技术工作,技术工作要服务于组织的战略目标。
- 大量的工程实践在每日的工作中不断变化,而渐渐稳定的实践方式被抽象提炼为一系列原则。
- 原则的普及带来整体效率的提升和边际成本的下降,以更有效的支持组织战略目标的快速达成。
- 另外也要确保这些原则不是让开发人员的生活变得更凄惨而是更美好。
- 跟踪新技术发展确保能在合适的时候做出正确的取舍折衷。
- 让开发人员理解某项技术决策的影响和制约以便最有效的执行,甚至在特定情形下深入到代码的实现层面。
文章开头说了,这是我们实施系统的第四个大版本,而之前每一个大版本升级都是一次旧城到新城的整体搬迁。 而微服务架构天然的自然进化属性是否预示着这应该是最后一个大版本升级了? 微服务架构述说着没有永恒的架构,只有进化的架构,但微服务架构不是银弹,也没有银弹。