微服务是系统架构上的一种设计风格, 它的主旨是将一个原本独立的系统拆分成多个小型服务,这些小型服务都在各自独立的进程中运行,服务之间通过基于HTTP 的RESTful API进行通信协作。 被拆分成的每一个小型服务都围绕着系统中的某一项或一 些耦合度较高的业务功能进行构建, 并且每个服务都维护着自身的数据存储、 业务开发、 自动化测试案例以及独立部署机制。 由于有了轻量级的通信协作基础, 所以这些微服务可以使用不同的语言来编写。
在实施微服务之前, 我们必须要知道, 微服务虽然有非常多吸引人的优点, 但是也因为服务的拆分引发了诸多原本在单体应用中没有的问题。
在微服务架构中, 运维人员需要维护的进程数量会大大增加。 有条不紊地将这些进程编排和组织起来不是一件容易的事, 传统的运维人员往往很难适应这样的改变。这就需要运维人员有更多的技能来应对这样的挑战, 运维过程需要更多的自动化, 这就要求运维人员具备一定的开发能力来编排运维过程并让它们能自动运行起来。
虽然拆分了服务, 但是业务逻辑上的依赖并不会消除, 只是从单体应用中的代码依赖变为了服务间的通信依赖。 而当我们对原有接口进行了一些修改, 那么交互方也需要协调这样的改变来进行发布, 以保证接口的正确调用。 这就需要更完善的接口和版本管理, 或是严格地遵循开闭原则。
由于拆分后的各个微服务都是独立部署并运行在各自的进程内, 它们只能通过通信来进行协作, 所以分布式环境的问题都将是微服务架构系统设计时需要考虑的重要因素, 比如网络延迟、 分布式事务、 异步消息等。
微服务面临的这些问题经过多年的发展,MartinFowler在Microservices 一文中, 提炼出了微服务架构的九大特性,用于指导大家设计架构。
组件,是一个可以独立更换和升级的单元。 就像 PC 中的 CPU、内存、 显卡、 硬盘一 样,独立且可以更换升级而不影响其他单元。 在微服务架构中,需要我们对服务进行组件化分解。 服务,是一种进程外的组件,它通过 HTTP 等通信协议进行协作,而不是像传统组件那样以嵌入的方式协同工作。 每一个服务都独立开发、 部署,可以有效避免一个服务的修改引起整个系统的重新部署。 打一个不恰当的比喻,如果我们的 PC 组件以服务的方式构建,那么只维护主板和一些必要外设之后,计算能力通过一组外部服务实现,我们只需要告诉 PC 从哪个地址来获得计算能力,通过服务定义的计算接口来实现我们使用过程中的计算需求,从而实现 CPU 组件的服务化。 这样原本复杂的 PC 服务得到了轻量化的实现,我们甚至只需要更换服务 地址就能升级PC 的计算能力。
当决定如何划分微服务时,通常也意味着我们要开始对团队进行重新规划与组织。 按以往的方式,我们往往会从技术的层面将团队划分为多个,比如DBA团队、运维团队、后端团队、 前端团队、 设计师团队等。 若我们继续按这种方式组织团队来实施微服务架构开发,当有一个服务出现问题需要更改时,可能是一个非常简单的变动,比如对人物描述增加一个字段,这需要从数据存储开始考虑一直到设计和前端, 虽然大家的修改都非常小, 但这会引起跨团队的时间耗费和预算审批。 在实施微服务架构时,需要采用不同的团队分割方法。 由于每一个微服务都是针对特定业务的宽栈或是全栈实现,既要负责数据的持久化存储, 又要负责用户的接口定义等各种跨专业领域的职能。 因此,面对大型项目的时候,对于微服务团队的拆分更加建议按业务线的方式进行拆分, 一方面可以有效减少服务内部修改所产生的内耗; 另一方面,团队边界可以变得更为清晰。
在实施微服务架构的团队中,每个小团队都应该以做产品的方式,对其产品的整个生命周期负责。 而不是以项目的模式,以完成开发与交付并将成果交接给维护者为最终目标。开发团队通过了解服务在具体生产环境中的情况, 可以增加他们对具体业务的理解, 比如, 很多时候, 一些业务中发生的特殊或异常情况, 很可能产品经理都并不知晓, 但细心的开发者很容易通过生产环境发现这些特殊的潜在问题或需求。 所以, 我们需要用做 “产品” 的态度来对待每一个微服务, 持续关注服务的运作情况, 并不断分析以帮助用户来改善业务功能。
在单体应用中, 组件间直接通过函数调用的方式进行交互协作。 而在微服务架构中, 由于服务不在一个进程中, 组件间的通信模式发生了改变, 若仅仅将原本在进程内的方法调用改成RPC方式的调用, 会导致微服务之间产生烦琐的通信, 使得系统表现更为糟糕, 所以, 我们需要更粗粒度的通信协议。 在微服务架构中, 通常会使用以下两种服务调用方式:
第一种, 使用 HTTP的 RESTful API或轻量级的消息发送协议, 实现信息传递与服 务调用的触发。
第二种, 通过在轻量级消息总线上传递消息, 类似 RabbitMQ 等一些提供可靠异步 交换的中间件。
当我们采用集中化的架构治理方案时, 通常在技术平台上都会制定统一的标准, 但是每一种技术平台都有其短板, 这会导致在碰到短板时, 不得不花费大力气去解决, 并且可能因为其底层原因解决得不是很好, 最终成为系统的瓶颈。 在实施微服务架构时, 通过采用轻量级的契约定义接口, 使得我们对于服务本身的具体技术平台不再那么敏感, 这样整个微服务架构系统中的各个组件就能针对其不同的业务特点选择不同的技术平台, 终千不会出现杀鸡用牛刀或是杀牛用指甲钳的尴尬处境了。
我们在实施微服务架构时, 都希望让每一个服务来管理其自有的数据库, 这就是数据管理的去中心化。
在去中心化过程中, 我们除了将原数据库中的存储内容拆分到新的同平台的其他数据库实例中之外(如把原本存储在MySQL中的表拆分后,存储到多个不同的MySQL实例中), 也可以将一些具有特殊结构或业务特性的数据存储到一些其他技术的数据库实例中(如把日志信息存储到 MongoDB 中或把用户登录信息存储到 Redis中)。 虽然数据管理的去中心化可以让数据管理更加细致化, 通过采用更合适的技术可让数 据存储和性能达到最优。 但是, 由于数据存储于不同的数据库实例中后, 数据一致性也成为微服务架构中亟待解决的问题之一。分布式事务本身的实现难度就非常大, 所以在微服务架构中, 我们更强调在各服务之间进行 “无事务” 的调用, 而对于数据一致性, 只要求数据在最后的处理状态是一致的即可;若在过程中发现错误, 通过补偿机制来进行处理, 使得错误数据能够达到最终的一致性。
近年来云计算服务与容器化技术的不断成熟,运维基础设施的工作变得越来越容易。 但是, 当我们实施微服务架构时, 数据库、 应用程序的个头虽然都变小了, 但是因为拆分的原因, 数量成倍增长。 这使得运维人员需要关注的内容也成倍增长, 并且操作性任务也会成倍增长, 这些问题若没有得到妥善解决, 必将成为运维人员的噩梦。 所以, 在微服务架构中, 务必从一开始就构建起 “待续交付” 平台来支撑整个实施过程, 该平台需要两大内容, 缺一不可。
自动化测试:每次部署前的强心剂, 尽可能地获得对正在运行的软件的信心。
自动化部署:解放烦琐枯燥的重复操作以及对多环境的配置管理。
在单体应用中, 一般不存在单个组件故障而其他部件还在运行的情况, 通常是一挂全挂。 而在微服务架构中, 由于服务都运行在独立的进程中, 所以存在部分服务出现故障, 而其他服务正常运行的情况。 比如, 当正常运作的服务B调用到故障服务A时, 因故障服务A没有返回, 线程挂起开始等待, 直到超时才能释放, 而此时若触发服务B调用服务A 的请求来自服务C, 而服务C频繁调用服务B 时, 由于其依赖服务A, 大量线程被挂起等待, 最后导致服务A也不能正常服务, 这时就会出现故障的蔓延。 所以, 在微服务架构中, 快速检测出故障源并尽可能地自动恢复服务是必须被设计和考虑的。 通常, 我们都希望在每个服务中实现监控和日志记录的组件, 比如服务状态、 断路器状态、 吞吐量、 网络延迟等关键数据的仪表盘等。
通过上面的几点特征, 我们已经能够体会到, 要实施一个完美的微服务架构, 需要考虑的设计与成本并不小, 对于没有足够经验的团队来说, 甚至要比单体应用付出更多的代价。 所以, 在很多情况下, 架构师都会以演进的方式进行系统的构建。 在初期, 以单体系统的方式来设计和实施, 一方面系统体量初期并不会很大, 构建和维护成本都不高。 另一方面, 初期的核心业务在后期通常也不会发生巨大的改变。 随着系统的发展或者业务的需 要, 架构师会将一些经常变动或是有一定时间效应的内容进行微服务处理, 并逐渐将原来在单体系统中多变的模块逐步拆分出来, 而稳定不太变化的模块就形成一个核心微服务存在于整个架构之中。
近几年很多入对于微服务架构的热情非常高, 但是回头看 “微服务” 被提及也有很多 年了。 无数的架构师和开发者在实际项目中实践该设计理念并为此付出了诸多努力, 同时 也分享了他们在微服务架构中针对不同应用场景出现的各种问题的各种解决方案和开源框架, 其中也不乏国内互联网企业的杰出贡献。
• 服务治理:阿里巴巴开源的Dubbo和当当网在其基础上扩展的DubboX、 Netflix的 Eureka、Apache的Consul等。
• 分布式配置管理:百度的Disconf、 Netflix的Archaius、360的QConf、SpringCloud 的Config、 淘宝的Diamond等。
• 批量任务:当当网的Elastic-Job、 Linkedln的Azkaban、 SpringCloud的Task等。
• 服务跟踪:京东的Hydra、SpringCloud的Sleuth、Twitter的Zipkin等。 .......
上面列举了一些在实施微服务架构初期, 就需要被我们考虑进去的问题, 以及针对这些间题的开源解决方案。 可以看到国内、 国外的技术公司都在贡献着他们的智慧。 我们搜索微服务架构的实施方案时会发现, 几乎大部分的分享主要以理论或是一个粗轮廓框架为 主, 整合了来自不同公司或组织的诸多开源框架, 并加入针对自身业务的一些优化, 所以 找不到一个完全相同的架构方案。
前面我们介绍了一些关于微服务的理念以及特性, 分析了实施微服务的优点和缺点,而这些缺点通常就是这些框架出现的源头,大家都是为了解决或弥补业务拆分后所引出的 诸多词题来设计出这些解决方案。而当我们作为一个新手,准备实施微服务架构时,为了避免踩前辈们踩过的坑,我们不得不在这些核心问题上做出选择,而选择又是如此之多, 这必然会导致在做技术选型的初期, 需要花费巨大的调研、 分析与实验精力。
Spring Cloud的出现,可以说是对微服务架构的巨大支持和强有力的技术后盾。它不像我们之前所列举的框架那样, 只是解决微服务中的某一个问题,而是一个解决微服务架构 实施的综合性解决框架,它整合了诸多被广泛实践和证明过的框架作为实施的基础部件, 又在该体系基础上创建了一些非常优秀的边缘组件。 打个不太恰当的比喻:我们自己对各个问题选择框架来实施微服务架构就像在DIY电脑一样,我们对各环节的选择自由度很高, 但是最终结果很有可能因为一条内存质量不行就点不亮了,总是让人不怎么放心。当然,如果你是一名高手,这些自然都不是问题,然 而千军易得 、 良将难求。而使用Spring Cloud来实施就像直接购买品牌机一样,在Spring 社区的整合之下,做了大量的兼容性测试,保证了其拥有更好的稳定性,如果要在Spring Cloud架构下使用非原装组件时,就需要对其基础有足够的了解。 Spring Cloud也许对很多已经实施微服务并自成体系的团队不具备足够的吸引力,但是对于还未实施微服务或是未成体系的团队,这必将是一个非常有吸引力的框架选择。不论其项目的发展目标,还是 Spring的强大背景, 亦或其极高的社区活跃度,都是未来企业架 构师必须了解和接触的重要框架,有一天成为微服务架构的标准解决方案也并非不可能。