7-从单体应用迁移到微服务
来源:吴起辉     阅读:603
动风网络
发布于 2018-12-25 22:43
查看主页

7-从单体应用迁移到微服务

本文出自Nginx官网,是微服务详情系列文章的第七篇,也是最后一篇。原文地址:https://www.nginx.com/blog/refactoring-a-monolith-into-microservices/

1.详情

这是微服务系列文章的最后一篇,在第一篇文章中我们比较了微服务架构应用和单体应用的差异,探讨了微服务架构的优点与缺点;随后又探讨了使用API网关、进程间通信、服务发现、解决分布式数据管理、微服务部署等内容;在本篇文章中我们探讨将单体应用迁移到微服务的策略。

希望这个系列能让你理解微服务的架构、微服务的好处和缺点、什么时候选用微服务;微服务架构在很多情况下是更好的选择,可你很可能正工作于巨大、复杂的单体应用,每天的开发、维护、部署工作,效率低下、充满痛苦;而微服务看起来像是遥不可及的美梦。所幸,从单体应用迁移到微服务架构,有可以遵循的策略,这篇文章中,我们就探讨这些策略。

2.迁移工作概述

将单体应用迁移到微服务的过程,是应用现代化的过程,这是全世界开发人员十几年来一直努力在做的事情,有少量好的思想可以借鉴。

不推荐使用“大爆炸”式的将原单体应用推倒重写的策略,“大爆炸”听起来很美好,实际上风险很大,最终很可能失败。就像Martin Fowler所说的,“大爆炸式的推倒重来,唯一能保证的就是大爆炸式的灾难后果”。

应该采用渐进式重构的方式进行迁移,逐渐构建由微服务构成的新应用,让它跟单体应用协同工作;慢慢的,单体应用实现的功能越来越少,直至完全消失或者者变成另外一个微服务。这种策略相似于向在高速公路上以70英里时速行驶的汽车提供服务,具备挑战性,但风险远低于大爆炸式的重写。

Martin Fowler将这种应用现代化的策略称为“Strangler Application”,这个名字来自于热带雨林的一种植物“strangler vine”。strangler vine沿着树干向上生长,以获取阳光;最后大树死去,只剩下树形的strangler vine。应用现代化的过程相似于这种模式,我们在单体应用的附近构建由微服务组成的新应用,直至原有应用死去。接下来,我们探讨不同的迁移策略。

3.策略1-中止挖坑

深坑法则告诉我们,掉进深坑后第一件要做的事情,就是别再继续挖坑。当单体应用已经大到不可维护时,这个建议非常有价值;换句话说,别让单体应用更大了。这意味着不要向单体应用增加新的代码,应该将新代码放到独立的微服务中,下图展现了这种结构:


在上图中,除了遗留的单体应用和新构建的服务之外,还有两部分内容:第一部分是解决HTTP请求的请求路由器,有点儿相似于之前形容的API网关;路由器将新服务的请求转发给服务,将老请求转发给遗留的单体应用。另外一部分是将服务和单体应用组合在一起的胶水代码,通常新服务不会独立存在,它依赖单体应用的数据。胶水代码可能存在于微服务、单体应用,或者者两者都有,它负责组合数据;微服务使用胶水代码读写单体应用拥有的数据。

服务使用三种策略访问单体应用的数据:使用单体应用的API远程调用;直接访问单体应用的数据库;维护单体应用数据的一份拷贝。

胶水代码也被称作反腐败层,它防止服务自身领域模型受到单体应用领域模型的污染;胶水代码在两个不同的模型之间进行翻译。假如你想从单体应用的地狱中走出,胶水代码是至关重要的工作。

将新功能构建成服务有很多好处:它阻止单体应用变得更大;服务可以独立于单体应用进行开发、部署和扩展。你能体验到使用微服务架构创立的每一个服务带来的好处。

中止挖坑的做法没有让事情变得更坏,但它没有处理原有单体应用的任何疑问,为理解决问题,需要拆分单体应用,接下来将形容单体应用拆分的策略。

4.策略2-拆分前台和后台

这种策略通过将表示层从业务逻辑层和数据层中拆分,实现单体应用规模的缩减。通常企业应用至少包括三层:

表示层:解决HTTP请求,实现REST风格API或者者Web UI。假如应用有比较复杂的客户界面,表示层一般会有很多代码。

业务逻辑层:是应用的核心,实现业务逻辑。

数据访问层:访问相似数据库和消息中间件等基础实施。

一般情况下,表示层和另外两层有比较显著的区分。业务逻辑层会使用一个或者者几个fa?ade模式封装业务逻辑,对外提供粗粒度的API;这些API就是拆分应用的天然接缝。你可以沿着API将应用拆分,一个应用包含表示层代码,另外一个包含业务逻辑和数据访问代码,表示层应用远程调用业务逻辑应用提供的服务。以下图示展现了拆分前和拆分后的架构:


通过上述策略拆分单体应用有两个好处:两个应用可以独立的开发、部署、扩展,允许开发人员在客户界面上快速迭代并轻松执行A/B测试;应用暴露了远程访问的接口,可以供后续开发的其余服务调用。

当然,经过上述拆分之后依然没有从根本上处理问题,原应用很可能变成两个同样无法维护的单体应用,那就需要使用第三个策略进行进一步拆分。

5.策略3-服务抽取

这个策略是将单体应用的板块抽取成服务,每抽取出一个服务,单体应用就缩减一点儿;当你抽取出足够多的服务时,单体应用就会完全消失或者者转化为另外一个服务,问题就会完全处理。

确定服务抽取的优先级

大型应用通常有数十个甚至数百个板块,所有板块都可以进行服务抽取,如何确定服务抽取的优先级是个有挑战的工作。一个好的办法是从容易进行服务抽取的板块开始,这能让你积累微服务构建和服务抽取的经验,接下来应该抽取那些能带来最大好处的板块。

将应用板块转化成服务是耗费时间的工作,应该根据转换工作能带来的好处确定优先级。通常来说,抽取经常变化的板块能带来较大的好处,一旦你将板块抽取成服务,它就能独立的开发和部署,从而提高开发和部署效率。

将与其余板块资源需求显著不同的板块抽取成服务,也能带来很大好处。比方,将使用内存数据库的板块抽取成服务,它就能部署在有大内存的主机上;同样,将需要大量计算资源的板块抽取成服务,就能将它部署到有优异计算性能的主机上;通过将不同资源需求的板块抽取成服务,可以让应用更容易扩展。

当确定要抽取哪些板块时,查找粗粒度的板块边界很有用,能简化服务抽取工作。比方,假如有个板块的边界是仅通过异步消息跟其余板块通信,那将该板块抽取成服务就相对简单。

如何进行服务抽取

第一步是抽取出候选板块和单体应用的接口,既然单体应用和候选板块都需要对方的数据,这个接口很可能是双向依赖的;因为候选板块和单体应用之间复杂的依赖关系,且往往存在细粒度的交互,抽取接口通常是困难的。重构使用领域模型实现的业务逻辑板块更加困难,由于在领域模型的不同类之间往往存在大量复杂的交互,需要改动很多代码来减少相互依赖。

一旦实现了粗粒度的接口,候选板块就变成了独立服务,候选板块和单体应用之间采用进程间通信机制。以下图示展现了重构前、重构中、重构后的架构:


在这个例子中,计划将Z板块抽取成服务,它调用Y板块,又被X板块调用。第一步是定义一对接口,一个接口是入站接口,X板块用来调用Z板块;另外一个接口是出站接口,Z板块用来调用Y板块。

第二步是将Z板块转化为独立的服务:使用进程间通信机制实现出站、入站两个接口;组合微服务基础框架和Z板块,实现服务发现等功能。

一旦你抽取出一个板块,你即可以开发、部署、扩展独立于应用和其余服务的另一个服务;你甚至可以重写服务;在这种情况下,例子中的两个接口起到了防止腐败的作用,它们集成候选板块和单体应用,并在两者的领域模型之间进行翻译。每抽取出一个服务,应用就朝微服务迈出一步,慢慢的,微服务会逐步壮大,单体应用会逐步缩减。

6.总结

将单体应用迁移到微服务是应用现代化的过程,不要从头重写应用,应该逐渐重构。有三种策略可以使用:将新功能构建成服务,将表示层构建成服务,将已有板块抽取成服务,随着微服务数量的不断添加,开发团队的敏捷性和开发效率会不断提升。

免责声明:本文为用户发表,不代表网站立场,仅供参考,不构成引导等用途。 系统环境 服务器应用
相关推荐
使用ConvNet的实用建议
Matlab安装步骤
docker中以挂载配置文件、日志、首页的方式安装apache
前台常见面试题(十一)@郝晨光
StringBuffer和StringBuilder
首页
搜索
订单
购物车
我的