聂同学

一个程序员和架构师的实践与思考

译:迁移至云架构(五)

接前文

迁移指南

现在我们已经定义了云架构,简短讨论了企业如果要使用云架构需要些什么转变。现在我们谈谈具体的技术。这里更多的是提供简短介绍和进一步阅读的链接。

分解指南

我们已经讨论了分解数据、服务、团队,那么,我们怎么才能实现这些呢?好问题,我们如何打破现存的巨大的一切,前进到云架构呢?

我已经看到一些公司成功地进行了渐进式迁移,有一些可以借鉴的模式。这里有一些公开的例子:KarmaSoundCloud

下面我们将一步一步看看如何将单体上的服务迁移到云。

新特性作为微服务

有点意外的是,第一步并不是打碎单体。我们现在假设在单体上你有一些待实现的特性。事实上,如果你的单体根本没打算实现新功能,那恐怕根本没有必要去分解它。我们首要的目的是快速变化,如果你的系统根本没打算要变化,谈何快速变化呢?

团队认为改变架构的好办法并不是立即分拆单体,而是不再在上面增加任何新东西,新东西都建立为微服务——Phil Calcado, SoundCloud

这个策略显然的好处就是我们建立新的微服务的难度很低,毕竟从头开始建立要比从一个大泥球上动刀要容易得多。

当然不可避免的,我们的微服务需要跟单体沟通,我们如何处理这个问题呢?

反腐层

因为我们的逻辑还在Rails写的单体中,所有的微服务都还得这样或那样地跟它沟通。——Phil Calcado, SoundCloud

DDD讨论了反腐层,它的目的是让两个不同领域模型的系统可以相互沟通,而不必让一个系统的领域模型同化另一个。当你在新的微服务中实现新的功能的时候,你肯定不希望新功能耦合在既有单体的内部业务知识上。反腐层是一种建立API合同的办法,让单体看起来就像是另一个微服务。

Evans 将反腐层的实现划分为三个子层:

  • Facade —— 在这里Facade的目的是简单地集成单体的接口,因为很可能单体的接口并不是按照现行集成原则来设计的。重要的是,这里不要改变单体的领域模型,不要把集成和翻译耦合在一起了。
  • Adapter —— Adapter中我们定义我们需要的“服务”。Adapter知道如何从我们的系统接收一个请求,然后将请求转发给单体。
  • Translator —— Translator的任务就是为我们的服务和单体之间的请求和响应转换领域模型。

这三个松耦合的部件解决三个问题:

  • 系统集成
  • 协议翻译
  • 模型翻译

现在剩下的问题是在哪一层进行通信。DDD中Evans讨论了两种办法:第一种,facade to system,当你无法改变遗留系统的时候使用。在这里我们假定我们是可以修改遗留单体的,那么我们主要讨论第二种,adapter to facade,也就是我们将Facade放进到遗留单体中,所以通信在Adapter和Facade之间进行。因为显然两个专门现写的部件通信起来容易些。

最后值得注意的是,防腐层也能促进双向沟通,毕竟遗留单体有时候也是需要跟新建立的微服务沟通的。

扼杀单体

随着架构变化的进行,团队得以在一个灵活得多的环境里构建新特性和改进,剩下的问题是,我们如何从单体中提取已有特性?——Phil Calcado, SoundCloud

我从Martin Fowler的文章StranglerApplication中借用了“扼杀单体”的说法。在这篇文章中Fowler介绍:在老系统的周边逐渐建立一个新系统,让老系统生长缓慢,几年后最终被扼杀。我们要做的正是如此:通过一系列的微服务和反腐层,我们在老系统周边逐渐建立新的云中系统。

两个原则帮助我们选择要提取的特性:

  • SoundCloud制订了第一个原则:在单体中识别界限上下文。正如我们前面讨论的,界限上下文要求内部一致的领域模型。遗留单体的领域模型显然不会是内部一致的,现在我们就开始从中识别内部一致的子模型。这些就是我们提取的候选。
  • 第二个原则讨论了优先级:哪些候选先提取?我们可以通过回顾迁移到云的意义来回答这个问题:快速创新。哪个特性提取后最有助于快速创新?我们显然选择那些些现有业务需要它快速变化的特性。

怎么才算完成?

我们怎么知道我们完成了?一般有两个完成标志:

  • 单体完全被扼杀了。所有的界限上下文都被提取成了微服务。最后一步就是识别出并干掉那些不再需要的防腐层。
  • 单体被扼杀到了一定程度:要继续提取特征的话,成本已经超过了收益。有时候单体的一部分很稳定,它们几年都不变,工作得也很好。那么提取这些部分就没有什么价值,如果同时维护相关的反腐层成本也够低,那我们就让它们长期保留好了。

后文继续,分布式系统指南

, 架构, 翻译

分享 -