1. 第一步:停止让单体式应用继续变大 相反,应该采取逐步迁移单体式应用的策略,通过逐步生成微服务新应用,与旧的单体式应用集成,随着时间推移,单体式应用在整个架构中比例逐渐下降直到消失或者成为微服务架构一部分。
当开发新功能时不应该为旧单体应用添加新代码,应该是将新功能开发成独立微服务。
除了新服务和传统应用,还有两个模块:
其一是请求路由器,负责处理入口(http)请求,有点像之前提到的API网关。路由器将新功能请求发送给新开发的服务,而将传统请求还发给单体式应用。
其二是胶水代码(glue code),将微服务和单体应用集成起来,微服务很少能独立存在,经常会访问单体应用的数据。胶水代码,可能在单体应或者为服务或者二者兼而有之,负责数据整合。微服务通过胶水代码从单体应用中读写数据,单体应用需要提供的远程API。
胶水代码也被称为容灾层(anti-corruption layer),这是因为胶水代码保护微服务全新域模型免受传统单体应用域模型污染。胶水代码在这两种模型间提供翻译功能。
将新功能以轻量级微服务方式实现由很多优点,例如可以阻止单体应用变的更加无法管理。微服务本身可以开发、部署和独立扩展。
然而,这方法并不解决任何单体式本身问题,为了解决单体式本身问题必须深入单体应用做出改变。
2. 第二步:将前端和后端分离减小单体式应用复杂度的策略是将表现层和业务逻辑、数据访问层分开。典型的企业应用至少有三个不同元素构成:
- 表现层 处理HTTP请求,要么响应一个RESTAPI请求,要么是提供一个基于HTML的图形接口。对于一个复杂用户接口应用,表现层经常是代码重要的部分。
- 业务逻辑层 完成业务逻辑的应用核心
- 数据访问层 访问基础元素,例如数据库和消息代理。
前端和后端分离后,表现层逻辑应用远程调用业务逻辑层应用,下图表示迁移前后架构不同:
3. 第三步:抽取模块成为独立微服务 一个巨大的复杂单体应用由成十上百个模块构成,每个都是被抽取对象。
(1)可以先抽取容易的模块,让开发者积累足够经验,这些经验可以为后续模块化工作带来巨大好处。可以抽取经常变化的模块,这样获益较大。
(2)可以抽取资源消耗大的模块,例如,将内存数据库抽取出来成为一个微服务会非常有用,可以将其部署在大内存主机上。同样的,将对计算资源很敏感的算法应用抽取出来也是非常有益的,这种服务可以被部署在有很多CPU的主机上。
(3)可以抽取有有粗粒度边界的模块,例如,只与其他应用异步同步消息的模块。
那么,该如何抽取模块呢? (1)定义好模块和单体应用之间粗粒度接口
由于单体应用需要微服务的数据,反之亦然,因此更像是一个双向API。
因为必须在负责依赖关系和细粒度接口模式之间做好平衡,因此开发这种API很有挑战性,尤其对使用域模型模式的业务逻辑层来说更具有挑战,因此经常需要改变代码来解决依赖性问题。
在本例中,准备抽取使用Y模块的Z模块,X模块引用了Z模块的对象,第一步是定义一套粗粒度APIs,第一个接口应该是被X模块使用的内部接口,用于激活Z模块;第二个接口是被Z模块使用的外部接口,用于激活Y模块。
(2)将模块转换成独立服务。
一旦完成粗粒度接口,也就将此模块转换成独立微服务。为了实现,必须写代码使得单体应用和微服务之间通过使用进程间通信(IPC)机制的API来交换信息。
在本例中,将Z模块整合成一个微服务基础框架,例如服务发现。
参考文献:
1. http://dockone.io/article/1266