近年来,微服务在互联网应用开发和部署层面已经非常流行,而在此之前的相当长的一段时间里,市场上都流行笨重的单体的应用。
随着近年来互联网应用和需求爆发式的增长,快速迭代,高并发,高业务复杂度也是开发人员需要面临的难题。同时,服务器技术也迅速革新,微服务,云计算,容器管理,负载均衡,持续集成等技术的兴起,也改变了最初的开发模式。微服务架构已经成为了一种趋势,应用开发或者重构成微服务,通过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性能比较强的计算机上。订单模块,对内存要求比较高,那么我们就可以部署在内存比较大的服务器上,且日后可以根据订单的体量自由扩容/缩容。
独立扩展:我们之前说过单体应用的扩展,受限于整个应用的"长板定理",假如其中一个模块功能需要更多的硬件指标来满足,那么我需要对整个服务器进行换代。而换做微服务模式以后,每个模块独立部署,我们可以依据各个微服务的特点来选择服务器。例如,行程管理中,可能涉及大量的地理信息估测和预算,是一种计算密集型,我们就可以把行程管理单独部署到CPU性能比较强的计算机上。订单模块,对内存要求比较高,那么我们就可以部署在内存比较大的服务器上,且日后可以根据订单的体量自由扩容/缩容。
微服务的不足
复杂度较高:由于微服务是分布式系统,整体会变得比较复杂,开发者需要去选择基于消息或者RPC的进程间通信机制。相较于进程内通信,会显得复杂一些,因为要处理各个微服务之间的由于调用链产生的极端情况,这其中就包括要保证各个微服务都高可用,如果不可用或者响应非常慢,怎么做备选和降级措施。
网络和高可用性要求高:微服务分布式部署,是比较分散的,如果各个核心功能的机房不在一个地方,网络就会成为瓶颈因素或者隐患因素。比如核心订单服务部署在上海,而支付服务部署在北京,这样,网络传输可能会成为系统影响调用效率的一个重要因素。且各个地方的机房都有掉电宕机的风险,又部署了核心模块,这就是很大的隐患。当然,可以有容灾备份的手段去缓解这种突发情况,但是这又是另外一个问题了。
分区数据库架构:分布式事务在微服务中是很难实现的,在单体应用中,只存在一个单独的数据库,事务很容易实现。但是在微服务中,一般不会选择分布式事务,根据CAP定理,数据一致性,可用性,和分区容错性,只能三选二,要舍弃哪个就显得很痛苦。另外,分布式事务根本不支持高度可扩展的NoSQL数据库和消息代理。只能使用“最终一致性”的办法来进行折中。
作业复杂度:微服务架构拆分出了很多小粒度的微服务,且部分微服务还要求多实例部署。这就给增加了埋点,配置,监控,负载均衡等作业的工作量。与此同时,接口自动化测试、手工测试等任务量也相应增加。
延伸:和SOA的区别
其实两种架构是比较相像的,都属于分布式组件化的结构,且都有松耦合的目标。
SOA更注重集成复用性,强调服务的综合治理,架构水平划分为前端,服务层,数据层。微服务剔除了ESB企业服务总线,强调独立部署组件化,架构垂直划分,按照业务能力,每个服务完成自己特定的功能,服务即产品。
功能 | SOA | 微服务 |
组件大小 | 大块业务逻辑 | 单独任务或小块业务逻辑 |
耦合 | 通常松耦合 | 总是松耦合 |
公司架构 | 任何类型 | 小型、专注于功能交叉团队 |
管理 | 着重中央管理 | 着重分散管理 |
目标 | 确保应用能够交互操作 | 执行新功能、快速拓展开发团队 |
总结:回归
通过解读了推进微服务架构演变的因素,以及微服务架构的优缺点,以及同类架构的横向比较,我们发现,微服务架构还是有运用场景的范围的,微服务比较适合业务比较复杂,模块划分多样,且存在高并发,计算密集,存储密集等多种类特性的场景。而简单的小规模服务,其实单体应用更加适合。换句话说,就是不能滥用微服务。
其实现有技术发展,已经衍生出了很多和微服务架构配合度很高的技术,比如微服务的自动化部署,可使用现成的平台即服务(PaaS),亦可开发自己的PaaS集群方案,配合K8s和Docker的使用。当然还有高性能RPC框架,消息中间件等。
回归开头抛出的问题,微服务架构的出现,还是为了迎合快速迭代的互联网产品,架构只是一个基础要素,要把产品做好,其实还有更多的环节,包括服务层面分布式服务的高可用,监控,负载均衡。数据层面的数据冗余方案,缓存方案,最终一致性方案。甚至是运维层面的DevOps,容灾备份。产品一直在迭代,技术一直在革新,以后也许会有功能更强性能更好的架构出现,只要我们的探索永不停止!
·end·
技术学习,一起进步
关注我,定期推送技术文章
