Scott's world.

微服务那点事

Word count: 6.9kReading time: 23 min
2019/08/20 Share

微服务那点事

“微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间相互协调、互相配合,为用户提供最终价值。每个服务运行在其独立的进程中,服务和服务之间采用轻量级的通信机制相互沟通(通常是基于HTTP的Restful API).每个服务都围绕着具体的业务进行构建,并且能够被独立的部署到生产环境、类生产环境等。另外,应尽量避免统一的、集中的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构”

—— Martin Fowler

什么是微服务

在过去几年中,“微服务架构”这一术语如雨后春笋般涌现出来,它描述了一种将软件应用程序设计为一组可独立部署的服务的特定方式。虽然这种架构风格没有明确的定义,但在组织、业务能力上有一些共同的特征:自动化部署,端点智能化,语言和数据的去中心化控制

与单体风格作对比有助于开始解释微服务风格,下面我们通过这种比较来帮助大家理解

微服务与单体的区别

单体应用程序被构建为单一单元。企业级应用程序通常由三部分组成:客户端侧用户接口(由运行于开发机上的浏览器里的HTML页面和Javascript组成),数据库(由插入到通用关系型数据库管理系统中的许多数据表格组成),服务端应用程序。服务端应用程序处理HTTP请求,执行领域逻辑,从数据库中检索、更新数据,选择、填充将要发送到浏览器的HTTP视图。服务端应用程序是一个单一的逻辑可执行单体。系统的任何改变都将牵涉到重新构建和部署服务端的一个新版本。

  • 这样的单体服务器是构建这样一个系统最自然的方式。

单体应用程序可以是成功的,但人们日益对他们感到挫败,尤其是随着更多的应用程序被部署在云上。变更周期被捆绑在一起 —— 即使只变更应用程序的一部分,也需要重新构建并部署整个单体。长此以往,通常将很难保持一个良好的模块架构,这使得很难变更只发生在需要变更的模块内。程序扩展要求进行整个应用程序的扩展而不是需要更多资源的应用程序部分的扩展。

总结下来就是

系统复杂:内部多个模块紧耦合,关联依赖复杂,牵一发而动全身

运维困难:变更或升级的影响分析困难,任何一个小修改都可能导致单体应用整体运行出现故障

无法扩展:无法拆分部署,出现性能瓶颈后往往只能够增加服务器或增加集群节点,但是DB问题难以解决

这些挫败导向了微服务架构风格:构建应用程序为服务套件。除了服务是可独立部署、可独立扩展的之外,每个服务都提供一个固定的模块边界。甚至允许不同的服务用不同的的语言开发,由不同的团队管理。

微服务风格其实并不是新颖的或者说是创新的,其本质可以回溯到Unix的设计哲学,比如模块原则,清晰原则,组合原则等


  • 看到这里你应该会发现这一架构风格概念有点类似于SOA(也就是我们常说的面向服务的体系结构)

    《微服务设计》

    SOA是一种设计方法,其中包含多个服务,而服务之间通过配合最终会提供一系列功能。一个服务通常以独立的形式存在于操作系统进程中。服务之间通过网络调用,而非采用进程内调用方式进行通信

    • 我的理解就是把系统按照实际业务,拆分成刚刚好大小的、合适的、独立部署的模块,每个模块之间相互独立。

    那么接下来我们就来说说微服务与SOA的区别

微服务与SOA的区别

微服务是SOA发展出来的产物,它是一种比较现代化的细粒度的SOA实现方式

微服务就是这样的一个「概念」,说白了,它不过就是近些年火起来的有一个名词而已,一时间仿佛整个行业都在讨论它,仿佛终于找到了银弹。

所以讨论[微服务和SOA的差别]的意义远不如讨论[微服务和单体系统的差别]更大,因为他们的区别实在是有点微妙。而且微服务和SOA并没有一个权威的定义,来说明它们各自包含了什么东西,是使用什么样的方法进行系统的构建。

如果一句话来谈SOA和微服务的区别,即微服务不再强调传统SOA架构里面比较重的ESB企业服务总线,同时SOA的思想进入到单个业务系统内部实现真正的组件化。

  • 无论哪种方式,事实上,SOA意味着如此不同的事情,这意味着有一个术语来更清晰地定义这种架构风格是有价值的。

ESB(enterprise service bus)

ESB曾经着实跟随着SOA火了一阵子

从名称就能知道,它的概念借鉴了计算机组成原理中的通信模型——总线,所有需要和外部系统通信的系统,统统接入ESB,岂不是完美地兼容了现有的互相隔离的异构系统,可以利用现有的系统构建一个全新的松耦合的异构的分布式系统。

但,实际使用中,它还是会有很多的缺点,首先就是ESB的本身就很复杂,大大增加了系统的复杂性和可维护性。其次就是由于ESB想要做到所有服务都通过一个通路通信,直接降低了通信速度。

微服务架构特征

我们通过下面这一张图来简单了解一下微服务架构的特征

通过服务组件化

只要我们一直从事软件行业,一个愿望就是通过把组件插在一起构建系统,如同我们看到的现实世界中事物的构造方式一样。

而谈到组件的时候,我们的定义是

组件是一个可独立替换和独立升级的软件单元。

微服务架构将使用库,但组件化软件的主要方式是分解成服务。我们把库定义为链接到程序并使用内存函数调用来调用的组件,而服务是一种进程外的组件,它通过web服务请求或rpc(远程过程调用)机制通信(这和很多面向对象程序中的服务对象的概念是不同的。)

使用服务作为组件而不是使用库的一个主要原因是服务是可独立部署的

如果你有一个应用程序是由单一进程里的多个库组成,任何一个组件的更改都导致必须重新部署整个应用程序。但如果应用程序可分解成多个服务,那么单个服务的变更只需要重新部署该服务即可。当然这也不是绝对的,一些变更将会改变服务接口导致一些协作,但一个好的微服务架构的目的是通过内聚服务边界和按合约演进机制来最小化这些协作。

使用服务作为组件的另一个结果是一个更加明确的组件接口。大多数语言没有一个好的机制来定义一个明确的发布接口。

围绕业务能力组织

当想要把大型应用程序拆分成部件时,通常管理层聚焦在技术层面,导致各个团队的划分。当团队按这些技术路线划分时,即使是简单的更改也会导致跨团队的时间和预算审批。一个聪明的团队将围绕这些优化,两害取其轻-只把业务逻辑强制放在它们会访问的应用程序中。

  • 换句话说,也就是根据逻辑划分,逻辑无处不在,这是Conway法则在起作用的一个例子

任何设计系统(广泛定义的)的组织将产生一种设计,他的结构就是该组织的通信结构。

— Melvyn Conway1967

也就是如图

而我们的微服务则采用依据业务能力去组织的服务。这些服务采取该业务领域软件的宽栈实现,包括用户接口、持久化存储和任何外部协作。因此,团队都是跨职能的,包括开发需要的全方位技能:用户体验、数据库、项目管理。

微服务有多大?

虽然,“微服务”已成为这种架构风格的代称,这个名字确实会导致不幸的聚焦于服务的大小,并为“微”由什么组成争论不休。在与微服务实践者的对话中,我们发现有各种大小的服务。最大的服务报道遵循亚马逊两匹萨团队(也就是,整个团队吃两个披萨就吃饱了)的理念,这意味着团队不超过12个人。在更小的规模大小上,我们看到这样的安排,6人团队将支持6个服务。

这导致这样一个问题,在服务每12个人和服务每1个人的大小范围内,是否有足够大的不同使他们不能被集中在同一微服务标签下。目前,我们认为最好把它们组合在一起。但随着深入探索这种风格,我们一定有可能改变我们的看法。

是产品不是项目

我们看到大多数应用程序开发工作使用一个项目模式:目标是交付将要完成的一些软件。完成后的软件被交接给维护组织,然后它的构建团队就原地解散。

而微服务支持者倾向于避免这一模式

  • 它们认为一个团队应该负责产品的整个生命周期。

    也就是亚马逊的理念

    “you build,you run it”

产品思想与业务能力紧紧联系在一起。要持续关注软件如何帮助用户提升业务能力,而不是把软件看成是将要完成的一组功能。

没有理由说为什么同样的方法不能用在单体应用程序上,但服务的粒度更小,使得它更容易在服务开发者和用户之间建立个人关系。

智能端点和哑管道

当在不同进程间创建通信结构时,我们已经看到了很多的产品和方法,把显著的智慧强压进通信机制本身。一个很好的例子就是企业服务总线(ESB),在ESB产品中通常为消息路由、编排(choreography)、转化和应用业务规则引入先进的设施。

  • 微服务社区主张另一种方法:智能端点和哑管道

基于微服务构建的应用程序的目标是尽可能的解耦和尽可能的内聚 - 他们拥有自己的领域逻辑

他们的行为更像经典UNIX理念中的过滤器 - 接收请求,应用适当的逻辑并产生响应。使用简单的REST风格的协议来编排他们,而不是使用像WS-Choreography或者BPEL或者通过中心工具编制(orchestration)等复杂的协议。

接下来我们来看最常用的两种协议

使用资源API的HTTP请求

本身就是web,而不是隐藏在web的后面。

                                                                                                --Ian Robinson

这或许就是最好的表述

轻量级消息总线上传递消息

选择的基础设施是典型的哑的(哑在这里只充当消息路由器) - 像RabbitMQ或ZeroMQ这样简单的实现仅仅提供一个可靠的异步交换结构 - 在服务里,智能仍旧存活于端点中,生产和消费消息。

单体应用中,组件都在同一进程内执行,它们之间通过方法调用或函数调用通信。把单体变成微服务最大的问题在于通信模式的改变。一种幼稚的转换是从内存方法调用转变成RPC,这导致频繁通信且性能不好。相反,你需要用粗粒度通信代替细粒度通信。

去中心化治理

集中治理的一个后果是单一技术平台的标准化发展趋势。

在工作中或者说在项目里,我们更喜欢用正确的工具来完成工作,而单体应用程序在一定程度上可以利用语言的优势,这是不常见的

把单体的组件分裂成服务,在构建这些服务时可以有自己的选择。

假如现在我们在正着手与某一个项目,你想使用Node.js开发一个简单的报告页面?十分轻松。用golang来简单实现一个处理高并发的组建?那是真香。你想换用一个更适合组件读操作数据的不同风格的数据库?我们有技术来重建它。因为我们是按服务划分的团队,所以越适合的工具往往是效率最高的

许多语言,许多选项

JVM作为平台的成长就是在一个共同平台内混合语言的最新例子。几十年来,破壳到高级语言利用高层次抽象的优势已成为一种普遍的做法。如同下拉到机器硬件,用低层次语言写性能敏感的代码一样。然而,很多单体不需要这个级别的性能优化和常见的更高层次的抽象,也不是DSL的。相反,单体通常是单一语言的并趋向于限制使用的技术的数量。

  • 我们用这种方式划分系统意味着我们可以选择,而不意味着你应该这样做。

团队在构建微服务时也更喜欢用不同的方法来达标。他们更喜欢生产有用的工具这种想法,而不是写在纸上的标准,这样其他开发者可以用这些工具解决他们所面临的相似的问题。

比如git和github意见成为事实上的版本控制系统的选择,在内部开放源代码的实践也正变得越来越常见

去中心化数据管理

数据管理的去中心化有许多不同的呈现方式。

  • 微服务的理念也应用去中心化数据存储决策中

虽然单体应用程序更喜欢用单一的逻辑数据库做持久化存储,但企业里面往往倾向于一系列应用程序共用一个单一的数据库。所以微服务中更倾向与每个服务管理自己的数据库,或者说用统一数据库技术的不同实例,或完全不同的数据库系统——这就是所谓的混合持久化(Polyglot Persistence)。你当然可以应用在单体应用程序中,但它更常出现在微服务里

但是像这样使用事务有助于一致性,但会显著地产生临时耦合,这在横跨多个服务时是有问题的。

大家都知道分布式事务难度是极大的,因此微服务强调服务间的无事务协作。同时这中方式管理不一致性也是下一个新的挑战,但这通常与业务实践相匹配。

其中的权衡还是需要根据具体的情况来判断,如果修复错误的代价小于更大一致性下损失业务的代价,我想这种权衡应该是值得的

基础设施自动化

云和AWS的演化已经降低了此构建、部署和运维微服务的操作复杂度。

其中DevOps云计算基础设施自动化就已经说明使用正确的工具,现在可以进行从配置、代码部署到服务器配置和自动化的所有工作。而其中我们运用比较多的工具也就是Docker

基础设施自动化就如下面的构建管线图所示

只要一个应用程序的部署仍然枯燥重复就适合持续部署

因此单体应用程序和微服务都可以使用基础设施自动化,差别是在于各自的运营场景可以明显不同

为失效设计

使用服务作为组件的一个结果是,应用程序需要被设计成能够容忍服务失效。

这与单体应用设计相比下来就是一个劣势,因为这可能会提高极大的复杂性来处理这些失败,而其微服务团队也要不断反思服务失效如何影响用户体验。

因为服务随时可能失败,所以微服务应用程序投入大量比重来进行应用程序的实时监测,既检查构形要素(每秒多少次数据请求),又检查业务相关指标(例如每分钟收到多少订单)。

进化式设计

微服务从业者,通常有进化式设计背景并且把服务分解看做是进一步的工具,使应用程序开发者能够控制他们应用程序中的变更而不减缓变更。变更控制并不一定意味着变更的减少 - 用正确的态度和工具,你可以频繁、快速且控制良好的改变软件

  • 组件放在服务中,为更细粒度的发布计划增加了一个机会。

对单体来说,任何变更都需要完整构建和部署整个应用程序。而对微服务来说,你只需要重新部署你修改的服务。这可以简化和加速发布过程。坏处是,你必须担心一个服务的变化会阻断其消费者。

微服务应用4个设计原则

目前构建微服务应用我比较推荐的四种常见原则

  • AKF拆分原则
  • 前后端分离
  • 无状态服务
  • Restful通信风格

AKF拆分原则

AKF扩展立方体(参考《The Art of Scalability》),是一个叫AKF的公司的技术专家抽象总结的应用扩展的三个维度。理论上按照这三个扩展模式,可以将一个单体系统,进行无限扩展。

  • X 轴 :指的是水平复制,很好理解,就是讲单体系统多运行几个实例,做个集群加负载均衡的模式。
  • Z 轴 :是基于类似的数据分区,比如一个互联网打车应用突然或了,用户量激增,集群模式撑不住了,那就按照用户请求的地区进行数据分区,北京、上海、四川等多建几个集群。
  • Y 轴 :就是我们所说的微服务的拆分模式,就是基于不同的业务拆分。

场景说明:比如打车应用,一个集群撑不住时,分了多个集群,后来用户激增还是不够用,经过分析发现是乘客和车主访问量很大,就将打车应用拆成了三个乘客服务、车主服务、支付服务。三个服务的业务特点各不相同,独立维护,各自都可以再次按需扩展。

前后端分离

前后端技术分离的几个好处:

  • 可以由各自的专家来对各自的领域进行优化,这样前端的用户体验优化效果会更好。
  • 分离模式下,前后端交互界面更加清晰,就剩下了接口和模型,后端的接口简洁明了,更容易维护。
  • 前端多渠道集成场景更容易实现,后端服务无需变更,采用统一的数据和模型,可以支撑前端的web UI 移动App等访问。

无状态服务

对于无状态服务,首先说一下什么是状态:如果一个数据需要被多个服务共享,才能完成一笔交易,那么这个数据被称为状态。进而依赖这个“状态”数据的服务被称为有状态服务,反之称为无状态服务。
那么这个无状态服务原则并不是说在微服务架构里就不允许存在状态,表达的真实意思是要把有状态的业务服务改变为无状态的计算类服务,那么状态数据也就相应的迁移到对应的“有状态数据服务”中。

场景说明:例如我们以前在本地内存中建立的数据缓存、Session缓存,到现在的微服务架构中就应该把这些数据迁移到分布式缓存中存储,让业务服务变成一个无状态的计算节点。迁移后,就可以做到按需动态伸缩,微服务应用在运行时动态增删节点,就不再需要考虑缓存数据如何同步的问题。

Restful通信风格

我们目前在很多框架中也都看见了这一种风格

在Web框架中Restful风格通俗地来说也就是URL定位资源,用HTTP动词(GET,POST,DELETE,DETC)描述操作。

  • REST描述的是在网络中client和server的一种交互形式;REST本身不实用,实用的是如何设计 RESTful API(REST风格的网络接口);
  • Server提供的RESTful API中,URL中只使用名词来指定资源,原则上不使用动词。“资源”是REST架构或者说整个网络处理的核心。

  • Server和Client之间传递某资源的一个表现形式,比如用JSON,XML传输文本,或者用JPG,WebP传输图片等。当然还可以压缩HTTP传输时的数据(on-wire data compression)。

  • 用 HTTP Status Code传递Server的状态信息。比如最常用的 200 表示成功,500 表示Server内部错误等。

主要信息也就是这些,这一通信风格实际是上为了解放思想,Web端就改为前段渲染和附带处理简单的商务逻辑。

未来的微服务

虽然微服务最近这么火,也有出现很多的拥护者,但是我并不认为微服务是以后软件架构的未来发展方向。虽然目前来看,我们得到的经验大多都是正面的,而还没有足够的时间来做出正确的判断。

每一个技术或者是思想我想都需要经过时间的磨练,我们在目前说它很好,但不能确定在过后的时间里它们会衰败,最后失败;或者说它的想法很好,但只有在理想条件会做到,只有适合和不适合的问题。所以我们只有怀着谨慎的态度慢慢摸索,去慢慢实践。

最后分享一下在知乎上看到的一篇比较好的文章,这位知友就很现实地看待了如今微服务的热潮,提出了一个残酷的观点

以下摘自知乎用户-铁原

而当年很火的SOA就是一个例子,SOA当时最火的是ESB这种模式,DUBBO这种P2P模式的在当时显然是不够高大上。ESB这种模式显然具有极大的魅惑性。它避免业务系统之间陷入迷宫般的调用拓扑,整个业务架构围绕在ESB总线旁边,条理清晰;所以业务系统之间无需处理其他系统的协议、报文等差异性,只需要关注自己的核心业务,ESB总线能帮业务系统处理各种通讯协议,报文协议的差异性。但是现在有哪个人见过ESB系统呢?

历史终究选择了Dubbo这种模式的SOA,而不是ESB这种模式

任何一个技术发展的早期,都不能避免各种试错——不同的是,有些技术方向就是错误的,有些仅仅是道路是曲折的。

SOA的曲折路程不仅仅是ESB,还有更大的弊病。
淘宝、阿里、支付宝、……所有这些推行SOA的公司进展是非常迅速的,仅仅在1-2年时间就完成了系统的SOA化,系统迅速膨胀到了几百几千个(小公司的大部分在1000-,部分有3000,,大公司多数在5000-)

然后就发现随便做个事情,都关联到几十个系统,不说开发光协调工作都非常费劲。开发起来联调、部署、日志查询等更是困难重重。

这个时候,有些公司清醒的架构师们提出了系统合并。14年左右的时候,支付宝架构组鲁肃等人是强烈推这个事的,记得当时有论断说:全支付宝的系统20个以内是绝对够用的,现在3000个左右,要合。

后来的事情大家其实都知道了,马云爸爸去supercell逛了以后回来以后说:我们过去创业的时候几个人几个月就弄个淘宝出来了,现在随便一点小事都几百号人半年看不见个水花。于是有了中台。

当我们来理性考虑其复杂度:

  • 当业务复杂度提升的时候,团队必然存在一个无法cover的极限。势必需要拆分。
  • 拆分的越多,总体复杂度增加的越多。
  • 表现形式提升的越高,总体复杂度增加的越多。

微服务是一种应对复杂性的产物,只有当问题复杂到一定程度的时候,他才是有益的。相比简单的问题,它本身就是复杂度过剩的。是不值得的。当前的技术方案,前一阶段的技术债都是存在的,正确的微服务微更应该是上一个阶段SOA的优化,是一种更节制、更加拥抱技术深层次内核——概念/领域问题/复杂性问题等产物。

参考

https://www.cnblogs.com/stulzq/p/8573828.html

https://www.zhihu.com/question/65502802

https://www.zhihu.com/question/37808426

http://blog.cuicc.com/blog/2015/07/22/microservices/

https://zhuanlan.zhihu.com/p/48760074

CATALOG
  1. 1. 微服务那点事
    1. 1.1. 什么是微服务
      1. 1.1.1. 微服务与单体的区别
      2. 1.1.2. 微服务与SOA的区别
    2. 1.2. 微服务架构特征
      1. 1.2.1. 通过服务组件化
      2. 1.2.2. 围绕业务能力组织
      3. 1.2.3. 是产品不是项目
      4. 1.2.4. 智能端点和哑管道
        1. 1.2.4.1. 使用资源API的HTTP请求
        2. 1.2.4.2. 轻量级消息总线上传递消息
      5. 1.2.5. 去中心化治理
      6. 1.2.6. 去中心化数据管理
      7. 1.2.7. 基础设施自动化
      8. 1.2.8. 为失效设计
      9. 1.2.9. 进化式设计
    3. 1.3. 微服务应用4个设计原则
      1. 1.3.1. AKF拆分原则
      2. 1.3.2. 前后端分离
      3. 1.3.3. 无状态服务
      4. 1.3.4. Restful通信风格
    4. 1.4. 未来的微服务
    5. 1.5. 参考