乐高式微服务化改造(上)

1,023 阅读7分钟
原文链接: mp.weixin.qq.com

作者 | Emac

杏仁医生架构师兼平台组负责人,关注微服务、DevOps领域。

技术圈流行一句话,凡脱离业务谈架构的,都是耍流氓。当新需求响应越来越慢,当加班成为家常便饭,你可曾怀念当年一下午徒手写一千行代码的爽快?面对一个不断吞噬团队时间的庞然大物(单体应用),分而治之往往是最有效的方法。今天我就和大家聊聊我对小公司如何进行微服务化改造的理解和一手经验。

1. 微服务简介

有关微服务的定义,最权威的版本莫属微服务之父 Martin Fowler 在 Microservices Resource Guide 一文中所述:

In short, the microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. -- James Lewis and Martin Fowler

注意其中有3个关键词:smallindependently deployable 和 automated deployment。Small 对应的就是微服务的微,很多初次接触微服务的同学对微的理解往往会停留在实现层面,以为代码少就是微,但实际上,这里的微更多的是体现在逻辑层面。微服务的一个重要设计原则是 share as little as possible,什么意思呢?就是说每个微服务应该设计成边界清晰不重叠,数据独享不共享,也就是我们常说的高内聚、低耦合。保证了 small,才能做到 independently deployable。而实现 automated deployment 的关键是 DevOps 文化,可参见 Fowler 另一篇谈 DevOps 的文章。需要提醒的是,随着业务复杂度的上升,一个微服务可能需要拆分为更多更细粒度的微服务,比方说,一开始只是一个简单的订单服务,后面逐步拆分出清算,支付,结算,对账等其他服务。

从本质上来看,相对单体应用,微服务是以牺牲强一致性、提高部署复杂性为代价,换取更彻底的分布式特性,比如异构性和强隔离性。对应 CAP 理论,就是用 Consistency 换 Partition。异构性比较容易理解,通过定义统一的 API 规范(一般采用 REST 风格),每个微服务团队可以根据各自的能力矩阵选用最适合的技术栈,而不是所有人必须使用相同的技术栈。强隔离性指的是,对于一个典型的单体应用,隔离性最高只能体现到模块级别,由于共享同一个代码仓库,模块的边界往往比较模糊,需要人为定义很多规范来保证良好的隔离性,但无论如何强调,稍一疏忽,就会产生“越界”行为,时间愈长,维护隔离性的成本愈高。而到了微服务阶段,自带应用级别的隔离性,“越界”的成本大大提升,无需任何规范,架构本身就保证了隔离性。

另一方面,由于采用了分布式架构,微服务无法再简单的通过数据库事务来保证强一致性,而是通过消息中间件或者某种事务补偿机制来保证最终一致性,比如微信朋友圈的点赞,淘宝订单的物流状态。其次,在微服务阶段,随着应用数量的激增,一次发布往往涉及多个应用,加上异构性带来的部署方式的多样性,对团队的运维水平尤其是自动化水平提出了更高的要求,运维和开发的边界进一步模糊。

讲完这些有关微服务的背景知识之后,现在就切入今天的正题,面对快速增长的业务需求,小公司如何进行微服务化改造?下面就以我在杏仁主导实施的微服务化改造的全过程为背景,给大家简单说一下我们微服务化改造的总体思路和核心中间件的技术选型过程。

2. 项目背景

首先介绍一下微服务化改造的背景。去年年初,在历经2年多的产品迭代之后,整个后台应用越来越庞大,已经成为一个典型意义上的 monolithic application:1. 各个业务模块犬牙交错,重复代码随处可见,补丁代码越打越多。2. 任何一个改动都需要一次全量发布,哪怕是修改一句文案,极大的拖慢了迭代速度。

与此同时,由于公司电商业务变得越来越复杂,老的业务模型越来越难以满足新的需求,急需对原有的订单模块进行重构,或者抽取一个独立的订单服务来进行支撑。反复考量之后,我们选择了后者。由于是团队第一次试水微服务,并且初期人员有限(一人主导,多人配合),最后我们决定走一条比较实用的改良式路线:

1. 最小化对已有应用的侵入性

2. 偏好主流的微服务框架

3. 只做必要的微服务治理

第一条定下了此次改造的基调,降低了方案无法落地的风险,确保了项目的整体可行性。第二条让我们站在巨人的肩膀上,不重复造轮子,聚焦在问题本身,而不是工具。第三条缩减项目范围,避免过度工程,以战养兵,不打无用之仗。

下图展示了目前杏仁微服务的整体架构。

3. 基本框架

基本框架我们选择的是 Spring Boot。Spring Boot 是 Spring开源社区提供的一个去容器、去XML配置的应用框架。和标准的基于 war 包的 Web 应用相比,Spring Boot 应用可以直接以 java -jar 的方式运行,也就是说不再需要部署到一个独立的 Web 容器(比如 Tomcat)中才能运行。其背后的运行机制简单来说就是,当一个 Spring Boot 应用启动时,在加载完核心框架类之后,会启动一个内嵌的 Web 容器(默认是 Tomcat),然后再加载应用本身的各种配置类和 Bean。也就是说不再是容器包应用,而是应用包容器。正是由于这个特性,Spring Boot 非常适用于开发微服务,毫不夸张的说 Spring Boot 就是为微服务而生。

有同学可能会问,不是还有 Dubbo 和 Spring Cloud 吗?Dubbo 是阿里开源的第一代 RPC 框架,早在 2011 年就已经发布了 2.0 版本,三年后也就是 2014 年,Martin Fowler 才提出了微服务的概念。虽然用 Dubbo 也能开发微服务,但这就好比用EJB的规范去开发 Spring Bean,怎么用怎么别扭。Dubbo 最大的问题是升级缓慢,最近一次发布还是 2014 年 10 月,支持的 Spring 版本是 2.5.6.SEC03,要知道 Spring 5 都快出来了。

Spring Cloud 可以说是目前 Java 社区最好最完整的微服务框架(没有之一),底层用的也是 Spring Boot,照着 Spring Cloud 的新手指南,分分钟就可以搭建出一整套微服务应用,非常适合改革式但不是改良式的微服务改造,因为非 Spring 应用难以集成。

作为硬币的另一面,选用 Spring Boot,意味着我们需要做大量的自定义工作,以弥补 Spring Boot 在微服务治理方面所欠缺的能力,比如即将在下篇介绍的注册中心、配置中心和授权中心。欢迎留言交流你的心得和见解。