近年来,微服务在互联网应用开发和部署层面已经非常流行,而在此之前的相当长的一段时间里,市场上都流行笨重的单体的应用。
随着近年来互联网应用和需求爆发式的增长,快速迭代,高并发,高业务复杂度也是开发人员需要面临的难题。同时,服务器技术也迅速革新, 微服务,云计算,容器管理,负载均衡,持续集成 等技术的兴起,也改变了最初的开发模式。微服务架构已经成为了一种趋势,应用开发或者重构成微服务,通过API的方式来交互,使得应用开发变得快捷且容易管理,可以更快更高效地部署。
在传统开发模式下,我们都会简单实现一个应用,这个应用包含了所有模块功能,经过多年的开发和迭代之后,应用会变得 很臃肿,依赖多,逻辑分支多 ,逐渐变成一个复杂而庞大的单体。
首先,这会让开发人员陷入一个非常痛苦的境地,不仅仅在重构和新业务开发上会有困难,就连应用启动时间都变得冗长。
其次,所有模块都发布在同一个应用里,由于不同模块的职责不同,服务器CPU和内存的选型难以确定。例如有模块是计算密集型会需要高性能CPU,有些模块是存储型需要大内存,会 挤压 其他模块甚至其他进程的剩余 系统资源 ,为了应对应用需求去购置高性能计算机,扩容,升级换代也意味着成本升高,是很不现实的。
同时,想要让这种单体应用支持 持续部署,分布式部署 等。就比较麻烦了,因为只是修改应用其中一个模块,但是 却需要发布整个应用 。且发布后是否会对其他模块产生影响也是未知的,需要 手工测试 去跑完整个应用的case。
另外,单体应用的可靠性也难以保证,这些模块都在同一个进程中,任何一个模块出现bug,比如 cpu占用率超标,内存泄露,都会拖垮 整个进程 。
最后,单体应用的 可迁移性 不佳,单体应用想要采用新的框架/中间件,也变得极为困难,即使新框架的性能非常好,但是大量的历史业务逻辑,想要 迁移就基本等于重建 。
举个全局实例,比如一个"打车应用",主要有用户端模块,司机端模块,支付模块,订单模块,行程模块等。
而在微服务架构里,模块职责拆分明确,模块 单独作为一个应用 ,必要时,按照数据存储需求给应用分配不同的数据库。
接下来我们对比和分析一下这两种模型的实例表现
该模型是典型的模块化六边形架构的模型,至少做了模块化,有统一的REST入口,已经是单体应用中表现比较好的种类了。
应用核心是有核心业务服务,领域对象和消息事件等,同时伴随着UI组件和外部接口适配器。
尽管有了完善的逻辑化模型,但是应用还是需要作为一个单体应用进行打包部署,独立部署到服务器上时,我们就将面临"单体噩梦"中提到的所有弊端。
我们用现在流行的微服务架构模式去代替臃肿的单体应用,思路是通过 业务拆分 ,将每个有自己特定的功能的模块都作为一个微服务,每个微服务 单独部署 ,并且各个微服务之间能够 互联 。例如将乘客管理,订单管理等等业务模块作为单独的服务,每个服务有自己的REST访问入口,供其他服务调用。
分析
实例中,我们已经将应用拆分为用户管理,账单,用户UI,司机管理,支付,司机UI,行程管理,通知等多个微服务,每一个微服务都暴露了API供其他微服务调用。例如乘客UI可以通过REST API调用乘客管理,乘客管理又可以通过REST API调用支付模块,这样就让乘客业务流程完成,使相关微服务互联了。同理司机也能调用支付模块,甚至是通知。每个业务流程可以通过应用之间的 API调用 完成自己的 闭环 。这里我们还可以注意到有个 API网关(Gateway) ,整个模块里,相关API是通过API网关暴露给移动端,移动端访问API,就能访问所有相关接口,对于移动端来说,这就实现了前后分离。
在模型中,大部分服务可以作为消费者,例如司机使用通知服务来告知司机有新的订单,再例如乘客UI服务调用了订单服务的数据来作为渲染页面的依据。
值得一提的是,服务间的通信,可以使用 响应式,注册/订阅式 等异步手段,也可以使用消息队列。另外API网关(GateWay)不仅仅是负责微服务的通信中介,还负责 访问控制,监控,埋点,日志,负载均衡 等功能。
关键词
部署: 为了实现高可用,微服务一般使用 Docker部署 ,且每个微服务一般部署 多个实例 ,每个Docker承载一个实例。用户请求时,使用 Nginx反向代理服务器 ,去分发请求到不同的实例去。因此,乘客,司机等模块化的微服务的测试/发布流程,就没有关联性,让持续部署成为可能。
分布式: 微服务可以 解决复杂问题 ,将庞大的单体应用分解成一套包含多个子服务的体系,实现了 强制模块化 。这样的好处是,子服务可以被快速开发,并且 单一职责 也便于维护。同时,分布式部署也能很好地应对 高并发需求 ,减少部署开销。例如,乘客模块是并发量特别大的,因此也需要大量实例,而其他模块可能没有很大的并发量。以往的单体服务,就需要根据最大需求量也就是乘客模块的需求量去部署实例,而换做具有分布式特性的微服务架构了以后,其他模块并 不需要去适配 乘客模块的实例部署量。
松耦合: 微服务架构拆分了业务模型,影响到了应用和数据库的关系,其实应用之间的耦合,也都是因为数据依赖造成的。之前的单体应用中,所有模块可以共用一个mysql数据库。但到了微服务架构,都是分开部署的,就不得不将数据库也拆分了,并且利用 数据冗余 , 解除 掉单体数据库中的 数据耦合 。
例如之前的
乘客表Passenger(ID,NAME)
司机表Driver(ID,NAME)
行程表Trip(ID,NAME,PID,DID)
它们在同一个数据中,当然是可以用PID和DID外键进行关联。但是换做微服务部署后,这三张表其实是分别部署到不同的服务器上的,这样就没法使用传统的外键进行关联。所以要引进数据冗余,比如在Passenger表和Driver表中,把他们相关的trip记录,作为json存入,变为
Passenger(ID,NAME,TRIP)
Driver(ID,NAME,TRIP)
这种做法和传统的企业级关系型数据库的数据模型相违背,甚至是 反范式 的。
技术选型: 上文得知,持久化数据库我们已经分开部署。每个服务拥有自己的数据库,我们在这里就可以根据微服务的特性 选择最适合 该应用的 数据库/持久化框架 ,比如乘客数据量比较大,我们选择可以高效查询Mysql作为持久化数据库,而假如订单服务涉及大量查询要求快速响应,我们就可以选择Redis作为存储手段。
同理,根据不同需求,微服务可以具有各种特性,也可以驱动我们选用的RPC策略,使用消息队列,甚至引入搜索引擎。以此来达到性能的最大化。
独立扩展: 我们之前说过单体应用的扩展, 受限于 整个应用的 "长板定理" ,假如其中一个模块功能需要更多的硬件指标来满足,那么我需要对整个服务器进行换代。而换做微服务模式以后,每个模块独立部署,我们可以依据各个微服务的特点来选择服务器。例如,行程管理中,可能涉及大量的地理信息估测和预算,是一种计算密集型,我们就可以把行程管理单独部署到CPU性能比较强的计算机上。订单模块,对内存要求比较高,那么我们就可以部署在内存比较大的服务器上,且日后可以根据订单的体量 自由扩容/缩容 。
复杂度较高: 由于微服务是分布式系统,整体会变得比较复杂,开发者需要去选择基于消息或者RPC的进程间通信机制。相较于进程内通信,会显得复杂一些,因为要处理各个微服务之间的由于调用链产生的极端情况,这其中就包括要 保证 各个微服务都 高可用 ,如果不可用或者响应非常慢,怎么做备选和降级措施。
网络和高可用性要求高: 微服务分布式部署,是比较 分散 的,如果各个核心功能的机房不在一个地方,网络就会成为 瓶颈因素或者隐患因素 。比如核心订单服务部署在上海,而支付服务部署在北京,这样,网络传输可能会成为系统影响调用效率的一个重要因素。且各个地方的机房都有掉电宕机的风险,又部署了核心模块,这就是很大的隐患。当然,可以有容灾备份的手段去缓解这种突发情况,但是这又是另外一个问题了。
分区数据库架构: 分布式事务 在微服务中是很 难实现 的,在单体应用中,只存在一个单独的数据库,事务很容易实现。但是在微服务中,一般不会选择分布式事务,根据CAP定理,数据一致性,可用性,和分区容错性,只能三选二,要舍弃哪个就显得很痛苦。另外,分布式事务根本不支持高度可扩展的NoSQL数据库和消息代理。只能使用“最终一致性”的办法来进行折中。
作业复杂度: 微服务架构拆分出了很多小粒度的微服务,且部分微服务还要求多实例部署。这就给增加了埋点,配置,监控,负载均衡等作业的 工作量 。与此同时,接口自动化测试、手工测试等任务量也相应增加。
其实两种架构是比较相像的,都属于分布式组件化的结构,且都有松耦合的目标。
SOA更注重集成复用性,强调服务的综合治理,架构水平划分为前端,服务层,数据层。
微服务剔除了ESB企业服务总线,强调独立部署组件化,架构垂直划分,按照业务能力,每个服务完成自己特定的功能,服务即产品。
功能 |
SOA |
微服务 |
组件大小 |
大块业务逻辑 |
单独任务或小块业务逻辑 |
耦合 |
通常松耦合 |
总是松耦合 |
公司架构 |
任何类型 |
小型、专注于功能交叉团队 |
管理 |
着重中央管理 |
着重分散管理 |
目标 |
确保应用能够交互操作 |
执行新功能、快速拓展开发团队 |
通过解读了推进微服务架构演变的因素,以及微服务架构的优缺点,以及同类架构的横向比较,我们发现,微服务架构还是有运用场景的范围的,微服务比较适合业务比较复杂,模块划分多样,且存在高并发,计算密集,存储密集等多种类特性的场景。而简单的小规模服务,其实单体应用更加适合。换句话说,就是不能滥用微服务。
其实现有技术发展,已经衍生出了很多和微服务架构配合度很高的技术,比如微服务的自动化部署,可使用现成的平台即服务(PaaS),亦可开发自己的 PaaS集群方案 ,配合K8s和Docker的使用。当然还有高性能RPC框架,消息中间件等。
回归开头抛出的问题,微服务架构的出现,还是为了迎合快速迭代的互联网产品,架构只是一个基础要素,要把产品做好,其实还有更多的环节,包括服务层面分布式服务的高可用,监控,负载均衡。数据层面的数据冗余方案,缓存方案,最终一致性方案。甚至是运维层面的DevOps,容灾备份。产品一直走在迭代,技术一直在革新,以后也许会有功能更强性能更好的架构出现,只要我们的探索永不停止!
·end·
技术学习,一起进步
关注我,定期推送技术文章