收藏学习七篇微服务系列的博文,点击标题查看原文内容。
优势与不足
- 单体应用的主要缺陷
随着应用不断地开发迭代、更新版本,单体应用的体量越来越大,造成以下问题:- 启动时间长:应用越大启动服务的时间越长,影响生产
- 部署困难:以往大版本发布大多是在每月固定时间,临时性的小版本应急发布也需要审批,发布一个功能修改却需要停掉整个应用,并且需要事前事后大量的人工测试,无法实现单日内的多次修改上线,持续部署
- 扩展性差:“如果单体应用的不同模块在资源需求方面有冲突的话,那应用的扩展也很难。”
- 可靠性低:只要一处代码的bug,就有可能把整个应用拖垮
- 代码架构修改困难
总的来说,很难适应敏捷开发和交付
-
微服务出现
将一个应用分为一整套体量小且相互关联的服务,为每个微服务提供独立的数据库,每个服务可以选择自己所需要的特定类型的数据库
-优势- 复杂性降低:单体应用被分解成多个小型服务
- 方便开发:每个服务可以单独团队开发,团队内部自行选择技术
- 独立部署:每个服务可以单独部署,服务之间的部署互不影响
- 独立扩展:每个服务可以独立使用各类资源进行功能扩展
-不足
- 分布式应用造成各服务之间的通信机制较单体服务复杂
- 每个微服务独立数据库造成数据重复或同步问题
- 测试需启动所有相关服务
- “微服务架构模式应用的改变将会波及多个服务”
- 众多服务的部署其实也是一个不小的工作,并不是很简单的事情(但也是复杂应用的首选)
比较优势和不足,微服务应用和单体应用各有千秋,前者适合大体量的应用,后者适合小体量的应用。
API 网关
本篇聚焦客户端对微服务的访问方式,提出了两种可能的访问方式:
- 客户端直接访问微服务:这种方法会面临1:N的访问,如果一个web页面包含N个服务,那就需要从客户端向N条请求(每条都要根据服务的不同,选择不同的适配协议),每个服务从众多的实例中分配一个相应,此种方法不仅请求响应耗时,同时不利于后续服务的重构(拆分/合并),并且部分服务对于http请求并不是特别友好,不是所有服务都适合从客户端直接发起请求
- 由API代表众多微服务统一对外提供访问接口:通过统一的API网关,封装后面各个服务,对客户端形成的一种请求,自动完成转换(“服务请求路由、组合及协议转换”)。它的优点是对外封装了应用的各个服务,缺点是必须新,开发这样的API,但是相比优势,这样的缺点是可接受。
之后还需要考虑API与各个服务之间的通信,即如何让API发现这些服务,在微服务应用中,很难想传统应用那样直连,“应用程序服务的位置是动态分配的,而且,单个服务的一组实例也会随着自动扩展或升级而动态变化。”。
进程间通信
微服务之间的通信是基于进程的(Inter-process communication,IPC),从两个维度去理解服务之间的交互问题,一个是1对1/1对多,另一个是同步/异步。具体的IPC技术,文章描述了三种方式:
-
基于消息的异步通信:因为是异步的,所以消息机制下客户端不需要等待服务端的及时响应,但是这样服务端在回复的时候需要指定特定的客户端id
-
基于请求/响应的同步通信:因为是同步的,所以客户端需要等待服务端的及时响应,典型的例子就是REST API,存在阻塞的可能性,客户端也必须知道服务端的位置,即要有服务实例发现机制
-
消息格式的选择
- 文本:JSON和XML
- 二进制
服务发现
本篇主要关注服务发现问题。在微服务应用中,客户端向服务端发起通信的前提是需要知道服务实例的地址,而基于云的微服务中,服务实例的地址通常是动态分配的,因此需要有特定的服务实例发现机制。有两种方式:
- 客户端发现模式:客户端查询服务注册表,由后者完成服务位置的提供。这种方法对客户端要求较高,需要和服务注册绑在一起,“要针对服务端用到的每个编程语言和框架,实现客户端的服务发现逻辑”
- 服务端发现模式:客户端通过一个负载均衡器再连接服务注册表,将请求转到相应的服务实例。这种方法相对于客户端发现模式,对客户端要求较低,“只需要简单地向负载均衡器发送请求,这减少了编程语言框架需要完成的发现逻辑”,但是对于负载均衡器又有了较高的要求。
上述两种模式都提到了服务注册表。服务注册表通过心跳机制,定时更新服务。服务注册由自注册模式和第三方注册模式,区别在于是否使用服务注册器。
数据管理
微服务存在每个服务使用和管理自己的数据库,相互之间访问受限,因此就涉及到了服务之间数据的协同管理问题:
- 如何实现业务事务,保持多个服务的一致性
- 如何从多个服务中检索数据,实现查询
使用事件驱动的架构来解决,服务之间发送各类事件,进而实现各自内部数据的更新
部署策略
本文关注微服务应用的部署。相比于单体应用的部署,微服务部署相对复杂,不再是把应用直接部署到一个或多个主机上那么简单。微服务应用一般会有很多个相互独立的服务,每个服务的开发技术、对资源的需求可能是不同的,同时每个服务所需的服务实例数目也是不同的,如何部署这些服务是本文所关注的。
- 单主机多服务实例模式:一台主机(虚拟机)部署多个服务实例,其他主机(虚拟机)部署和这台相同服务的其他实例,即一台主机(虚拟机)上部署多个服务,一个服务的多个实例分布在多台主机(虚拟机)上。此种方式和传统的应用将多个实例部署在多个主机上差别不大,部署速度快,但无法限制主机内实例之间对资源的使用,并且运维团队需要提前了解主机中服务实例的部署情况。
- 单主机单服务实例模式
- 单虚拟机单服务实例模式:每个服务实例完全隔离运行,独占各自的资源,对外完全封装成为“黑盒”,但是每个服务实例依托的虚拟机需要额外给操作系统分配资源,同时虚拟机体量大,构建缓慢。
- 单容器单服务实例模式:典型的代表技术Docker。“不同于虚拟机,容器技术更为轻量,容器镜像构建速度更快。由于没有冗长的操作系统启动机制,容器启动也非常迅速。容器启动,服务立刻运行。”
- 无服务器部署:举AWS Lambda为例
应用的微服务改造
总的原则:逐步重构,先将微服务与单体应用的功能共存,之后将后者逐步替代。
先对新功能开发微服务,对于旧功能,提出拆分前后端的方法,但是也不是一个最终的办法,需要一种策略,即提取微服务,将单体应用的模块转化为微服务。为此,文章建议先确定好转化优先级,优先处理频繁更改的模块、资源需求(有的要求大内存/有的要求高计算量)大不相同的模块。
总的来说,还是需要具体项目的实践才更加直观。