微服务架构一条龙:DevOps+数据库+Service Mesh+容器+云

xingqinstar 2018-09-15

微服务架构一条龙:DevOps+数据库+Service Mesh+容器+云

微服务架构思想经由 Martin Fowler 阐述后,在近几年持续受到重视。微服务架构的优点很多,比如它解耦业务,提供更高的灵活性,允许在服务频繁发版的同时保持系统其它部分的可用性与稳定性;解耦编程语言,针对不同业务可以使用更加合适的语言进行开发;解耦开发团队,不同团队各自负责一个微服务,互不影响,加速交付。

人们之所以推崇微服务架构,一方面是看上了它的优势,必然地,另一方面也是因为在业务快速迭代、集成,系统不断变得更加复杂的过程中,其原先的基于单体架构或 SOA 架构模式那一套理论在实践中出现了各种各样的问题,使得无法满足业务发展快速变化的需求。

在大家爆发式地谈论微服务架构的时候,技术理论上,容器、敏捷、DevOps 与云等相关领域在不断发展,相关思想、方法论与经验之谈也经由各社区得到一步步传播;落地过程中,以业务量大而杂的公司为主,各个组织在实践中纷纷采用微服务架构,中小型公司、团队也或转型,或从零开始去部署微服务;具体到相关技术实现上,诸如 Spring Cloud、Kubernetes、Eureka、Dubbo、Envoy 与 Istio 等各种微服务架构框架与组件在开源中不断得到完善。各方面的成熟使得微服务架构变得人人触手可即,并逐渐形成了一个健全稳定的架构生态,目前其已然成为当下最流行的架构模式。

然而,对于非架构师的大多数还未体验微服务架构的开发者来说,除了微服务架构本身跟 SOA 能找到一些相似这点认知外,对于其相关细节概念,比如“为何微服务跟容器就扯上了关系?”、“Service Mesh 是怎么来的?”却不甚了解。

另一方面,在实践微服务架构的过程中,有一些细节是值得考究的,比如“数据库随着业务拆分而拆分吗?”、“业务拆分又应该拆到什么程度?”、“微服务架构中的反模式如何避免?”……

因此我们邀请了具有 13 年研发经验的架构师张锋针对这一系列问题进行分享,从微服务架构讲起,谈一圈与之相关的 DevOps、数据库、Service Mesh、容器和云,希望给到读者一个微服务架构生态整体的概念。

  • 很多人觉得微服务架构的要点是业务拆分,并认为微服务架构相较于 SOA 的最大区别就在于对服务的拆分粒度,那么在您看来服务的粒度细到什么样才叫微呢?实际架构实践中您又是怎么去衡量的?具体又有哪些拆分依据呢?

业务拆分是微服务中非常重要的一点,如果拆分不基于业务,可能导致后期对于需求的变化响应非常慢,不合理的拆分有可能导致指定的微服务模块不能够响应业务需求,当需求发生变化时,不能够灵活应对,甚至会导致整个微服务模块重构。这也是产生微服务反模式“沙粒陷阱”的关键。

关于拆分粒度的问题,可能回答会虚一些,一直有一句话叫做适合的就是最好的,因为每个公司的业务不同,服务的规模不同,无法使用统一的标准来约定,而且这个还跟团队的默契程度、稳定性等都有关系,不是单纯的一个技术问题。

我觉得一个可以遵循的原则就是在业务拆分完成后能够快速响应需求变化、满足并发、能够快速迭代、支持复用。可以从分析服务的范围和功能、分析数据库事务、分析服务调用顺序入手去考虑。

首先前后端分离是必要的,因为现在的系统不单单是一个端,可以是网页、手机或者客户端,所以前端和后端分离是非常必要的。AKF 扩展立方体是一个非常不错的拆分方法,它讲的是通过三个维度上的扩展,可以快速提高产品的扩展能力,适应不同场景下产品的快速增长。同时,服务就尽量设计成无状态的,方便横向扩展。

而具体到我们现有的系统的经验来看,首先是根据业务部门提供的业务需求,利用领域驱动设计的思想,将业务进行领域划分,然后提炼出公共模块。

这些公共模块一般复用性都比较高,由专门的团队进行维护,关于实际的业务模块,我们公司使用统一的开发框架,各层分层都有严格的约定,相当于每个业务只需要按照需求方提出的业务需求进行开发,然后将服务暴露在注册中心。

关于接口文档,开始的时候我们使用 WIKI 整理文档的方式,后来顺应潮流,统一使用 Swagger,这样接口完成就能够自测,发布到测试或者线上都能够第一时间发现问题,并且有效地降低了沟通成本。

  • 在整个微服务架构过程中,包含了多个环节、多个功能模块的参与,拆分业务、网关、部署、数据库、文档、上线……这些环节和功能模块具体是如何协调起来的?

其实不管是 SOA 还是微服务都是软件工程中的一部分,都需要包含需求分析、概要设计、详细设计、编码、测试、交付这样的过程,可能针对不同的行业会有所增减,而针对开发人员来说,最关注的是从产品团队收集需求后,将其实现并且最终上线的过程。

具体到微服务架构上来说,首先,所有的业务会首先经过网关进行调度,网关的调度有专门的操作界面,请求发送到网关后,由调度模块发送到指定的微服务上。

因为微服务的数量庞大,不可能运用同步的方式来处理,所以,微服务模块也是按照小组的单位来进行的,每个组都设有组长进行相应的协调和调度,在工期能够保证的情况下,组长一般是不参与到开发过程的。

当某些微服务完成后,由组长负责发起申请,向测试团队申请资源,进行微服务模块的测试,测试完成后,由开发团队通过自动发布将服务推到线上。只有在发布过程中出现问题不能解决的时候,才会向运维团队申请资源。

数据库建议在资源允许的情况下,尽量由专业的 DBA 团队进行处理,比如:数据脚本的审核、数据结构设计的合理性、数据迁移以及基础的数据分析等。我们的团队对于数据库部分,要求是必须通过 PowerDesigner 进行建模,当数据结构有任何变化时,必须由相关团队负责人进行确认,确认无误后以邮件方式通知相关模块负责人版本升级结果。

关于数据库这一块可能采用了不敏捷的方式,但是这是必需的,因为数据是公司的重要资产。

  • DevOps 这两年变得很火,联合国 ITU 也在最近正式立项 DevOps 国际标准。上一个问题可能是涉及到了团队协作模式和软件工程相关的内容,那么作为一种与微服务紧密联系在一起的敏捷方式 DevOps 在微服务架构实施中具体是怎样执行的呢?

DevOps 为什么受到重视,这其实是一个必然的结果,软件发展这么多年,无论是 BOSS、管理人员还是使用方,都会对开发的速度和质量提出更高的要求,而自动化可以说是一个有效的提高团队协作的方式。DevOps 就是拥有这种能力的自动化,可以把它看作开发、技术运营和质量保障三者的交集。

而微服务架构作为一种新兴架构模式,正好处在 DevOps 必然发展起来的这个时间节点上,两相一拍即合。具体到它在微服务架构中有别于其它架构模式的特别之处,应该是它有针对容器进行一些相应的处理。

在很多企业中,应用程序发布是一项涉及多个团队、压力很大、风险很高的活动。然而在具备 DevOps 能力的组织中,应用程序发布的风险很低,因为当发现问题时,能够快速回滚。

DevOps 标准强调实践和技术对 DevOps 的关键作用,主要是Management、Practice 和 Technology,并进一步突出容器与微服务对 DevOps 的重要性。

DevOps 不是一个一蹴而就的事情,需要对整个架构以及人员进行调整,以适应新的工作方式。

在我们的实践当中,首先需要理解 DevOps,并且让团队中能够影响到决策的人理解它的好处,并且意识到这个不是一个简单的过程,可能需要变革。越是大的团队,这种变革的作用越明显。所以实践中,我们首先是通过自动化部署、自动化测试和自动化质量检查进行 DevOps 的实践。

自动化部署的过程还包括持续部署、高可用保障以及成本优化等多个方面。

在我们团队中,自动化部署是首先被运用到团队中的。

  1. 开发人员完成需求的功能后,提交代码到代码仓库(SVN 或者 Git),Jenkins 从代码仓库拉取项目分支代码。
  2. 执行构建,一般使用 Maven 进行项目的构建,当然也可以采用其他的构建工具。Maven 从 Nexux 私服摘取需要的 jar 包信息,完成编译。
  3. 编译完成后会自动触发单元测试,测试所有应用的单元测试代码。
  4. 单元测试通过后,触发 sonarcube 客户端执行静态代码检查,并且生成检查报告。
  5. 编译和构建完成后,需要生成 Docker 镜像。
  6. 将镜像发送到测试环境进行发布,触发自动化测试流程。
  7. 如果测试不通过,则触发回归流程,测试通过,将已经打包好的镜像推送到预发布环境。
  8. 预发布环境测试没有问题后,就可以进行灰度发布,将系统发布到线上环境。

在持续构建的过程中,能实时查看构建进度、构建状态、构建结果等详细信息。

  • 微服务架构有一些反模式,在实际操作中,比较普遍的反模式有哪些呢?如何避免?

数据驱动的反模式

单体应用迁移到微服务架构有两个主要目标:

  • 第一个目标是单体应用程序的功能分割成小的、单一用途的服务。
  • 第二个目标是单体应用的数据迁移到每个服务自己独占的小数据库。

第二种很容易导致的一个问题就是数据库的拆分不明确,可能粒度过粗,也可能粒度过细;还有一个问题就是数据的迁移。所以在微服务拆分的时候,功能分割优先,数据迁移最后。

超时反模式

分布式应用的挑战之一就是如何管理远程服务的可用性和它们的响应。一般情况下服务消费者可以选择无限期等待或者设置超时时间,使用超时时间看起来是个好办法,但是它会导致超时反模式。

所以一般使用断路器模式来处理,这种设计模式就像家里电器的保险丝一样,当负载过大,或者电路发生故障或异常时,电流会不断升高,为防止升高的电流损坏电路中的某些重要器件或贵重器件,烧毁电路甚至造成火灾,保险丝会在电流异常升高到一定的高度和热度的时候,自身熔断切断电流,从而起到保护电路安全运行的作用。

断路器模式相比设置超时的优点是,使用者可以立即知道服务已变得不响应,而不必等待超时,使用者将在毫秒内服务不响应。

另外断路器可以通过几种方式进行监控,最简单的方法是对远程服务进行简单的心跳检查,这种方式只是告诉断路器服务是活的,但是要想获取服务存活的详细信息,就需要定期(比如 10 秒)获取一次服务的详细信息。还有一种方式是实时用户监控,这种方式可以动态调整,一旦达到阈值,断路器可以进入半开放状态,可以设置一定数量的请求时通过。

共享反模式

微服务是一种无共享的架构,但因为总有一些代码会在微服务之间共享,这种共享不仅破坏了每个服务的限界上下文 (Bounded Context),而且还引入了几个问题,包括整体可靠性、更改控制、可测试性和部署能力。

代码的共享通常会带来很多问题,微服务架构的主要目标就是共享要尽可能地少,这有助于维护服务的限界上下文,使我们能够快速的测试和布署。服务之间依赖越强,服务隔离也就越困难,因此也就越难单独进行测试和布署。

解决方法是在需要共享的部分通过复制和服务合并的方式来处理。

报表处理中的反模式

其实微服务中有 4 种方式处理报表类业务,分别是:

  • database pull model,从数据库中直接拉取
  • HTTP pull model,HTTP 拉取
  • batch pull model,批量拉取
  • event-based push model,基于事件推送

前三种是从服务的数据库中拉取数据,第 4 种方式是通过事件的方式生成数据。

database pull model 就是从数据库中直接拉取,虽然这看似乎是个好主意,但它导致了服务之间的明显依赖关系,会带来数据库的非独立性

HTTP pull model 是 HTTP 拉取模型,使用此模型不需要直接访问每个服务的数据库,使用者只需要对每个服务发出一个 REST HTTP 调用就可以访问其数据。但是这种方式又太慢,无法满足复杂以及数据量较大数据获取需求。

batch pull model 是批量拉取模式,这种方式是独立出一个报表数据库或者数据仓库,通过批处理作业将不同服务数据库的数据拉取这个新独立的数据库中,这种模型的问题在于依然是强依赖数据库,如果拉取服务的数据库进行了更新,那么这个批量数据拉取过程也必将修改。

event-based push model 是避免报表处理反模式的一种有可取模式。当各微服务所拥有的数据库发生变更时,便会产生一个事件,此事件会使得生成报表的服务去处理此事件,到发生数据库变更的微服务中获取所变更的数据,并写入其所拥有的数据库或数据仓储中。

此设计方案不仅维持了各微服务的界限上下文,更使得生成报表的服务所拥有的数据库或数据仓储,获得实时的各微服务所拥有的数据库中的数据。

沙粒陷阱

架构师和开发人员在采用微服务架构的时候最大的挑战之一就是服务粒度的问题。服务粒度至关重要,它会影响应用的性能、健壮性、可靠性、可测性、设置发布模型。

这种陷阱的主要原因之一是开发人员常常将服务与类混淆,往往一个类就是一个服务,在这种情况下会很容易遇到沙粒陷阱。

服务应该被看成是一个服务组件,服务组件应该有一个清晰简明的角色和责任定义,并有一组明确的操作。由开发人员决定服务组件应该如何实现以及服务需要多少个实现类。

要避免沙粒陷阱,主要就是看如何衡量微服务的粒度,像前边说的,可以从这几个角度来考虑:

  • 分析服务的范围和功能
  • 分析数据库事务
  • 分析服务调用顺序

所以建议服务粒度拆分的时候,将团队中架构以及相关人员聚集到一起,来平衡各个服务拆分的粒度,以最终确认服务拆分的合理性。

  • 在微服务架构中,数据库可以是分布式的,每个服务带一个库,也可以是集中式地只有一个,现在通用的模式是哪种呢?具体是怎么样的?分别有什么优劣?与 Database Mesh 又有什么关系?

就我们的业务而言,鼓励在不拆分能够满足业务的情况下,就不进行拆分,当无法支撑业务并发时,才进行拆分。

我们直接看微服务的设计模式,从中可以得到关于数据库设计的一些相关信息。

微服务的设计模式主要有以下几种:

链式设计模式

链式设计模式是常见的一种设计模式,用于微服务之间的调用,应用请求通过网关到达第一个微服务,微服务经过基础业务处理,发现不能满足要求,则继续调用第二个服务,然后将多个服务的结果统一返回到请求中。这是一服一库的设计。

微服务架构一条龙:DevOps+数据库+Service Mesh+容器+云

微服务架构一条龙:DevOps+数据库+Service Mesh+容器+云

聚合器设计模式

聚合器设计模式是将请求统一由网关路由到聚合器,聚合器向下路由到指定的微服务中获取结果,并且完成聚合。首页展现、分类搜索和个人中心等通常都使用这种设计。这是一服一库的设计。

微服务架构一条龙:DevOps+数据库+Service Mesh+容器+云

数据共享模式

数据共享模式也是微服务设计模式的一种。应用通过网关调用多个微服务,微服务之间的数据共享通过同一个数据库,这样能够有效地减少请求次数,并且对于某些数据量小的情况非常适合。很显然,这是多服一库的模式。

微服务架构一条龙:DevOps+数据库+Service Mesh+容器+云

微服务架构一条龙:DevOps+数据库+Service Mesh+容器+云

异步消息设计模式

异步消息设计模式乍看起来跟聚合器的设计方式很像,唯一的区别就是网关和微服务之间的通信是通过消息队列而不是通过聚合器的方式来进行的,采用的是异步交互的方式。这也是一服一库的模式。

微服务架构一条龙:DevOps+数据库+Service Mesh+容器+云

微服务架构一条龙:DevOps+数据库+Service Mesh+容器+云

Database Mesh 的关注重点在于如何将分布式的数据访问应用与数据库有机串联起来,它更加关注的是交互,是将杂乱无章的应用与数据库之间的交互有效地梳理。其实在这个概念没提出之前,一直都存在数据治理,而 Database Mesh 目前来看,更多的还是在概念阶段。

  • 讲完微服务架构,我们来讲讲它的延申。讲微服务离不开容器(容器技术和容器编排)与云(函数计算、无服务架构、云原生等),从微服务到容器,又再联系到云,似乎它们就是一体的,那具体它们是什么关系,怎么联系起来的?

容器技术可以说是微服务和云的最佳结合。国外的 Google,国内的京东都已经高调地宣称其业务在容器内完成。而提到这个,就一定要说一下 Kubernetes。以前的虚拟化技术更多是使用 OpenStack,而目前更多使用基于 Kubernetes 的容器取代 OpenStack。

我们知道,云从概念上来说可以分为 IaaS、PaaS 和 SaaS,有关云计算“水煤电”的比喻似乎预示了 IaaS 的未来。换句话说,电厂赚钱吗?答案是肯定的,但前提是垄断。

另一方面,对于很多中小企业来说,相比于 IaaS 的部署复杂性和不可避免的运维成本,基于 IaaS 的 PaaS 和 SaaS 似乎更符合自己的胃口。而从历年的调研数据来看,IaaS 的同比增长呈现出不断下滑的趋势,而 SaaS 和 PaaS 的增长态势要更加良性。

在这场关乎 IaaS 市场地位的争夺中,两个比较出众的技术就是微服务架构和 Docker。而以 Docker 为技术又兼顾微服务优势的容器云,开始被称之为新一代云计算模式。

IaaS 的建立可以看作是从 0 到 1,而容器的出现则是从 1 到 10 的结果。

举一个电商的例子来说,电商业务中购物车、订单、用户信息、配送、库存都能够提取成独立服务,研发团队可高频度独立更新各个微服务,从而能够控制变更范围,极大加速产品的迭代。

按照这个思路,IaaS 提升了资源的交付形式,容器则改变了产品的迭代方式,提高了产品迭代的速度,在这个唯快不破的时代,这一特性的颠覆意义不言而喻。

在 2014 年之前,我们公司的应用程序都部署在物理机器上,这有许多问题:在物理机器时代,为了给即将上线的应用程序分配物理机器,我们平均需要等上一周的时间;由于缺乏隔离机制,应用程序会彼此影响,导致了许多潜在风险;那时候,每个物理机器上的 Tomcat 实例的平均数量至多 9 个;物理机器的资源严重浪费,而且调度缺乏灵活性;由于物理机器的故障,应用程序迁移的时间要花数小时;无法实现自动扩展。

为了提高应用程序部署的效率,我们开发了编译-包装、自动化部署、日志收集、资源监控及其他一些系统。

2014 年,我们开始关注 Docker,最开始的时候是将容器当成虚拟机来使用。所有应用程序在容器里面运行,而不是在物理机器里面运行。开发人员在生产环境请求计算资源所花的时间由原来的一周缩短到了短短几分钟

之后随着 Kubernetes 的开源,我们在其基础之上进行定制化开发,提供了一站式服务,比如日志、监控、故障排除、终端和编排。

  • 再来看看另外一个相关的东西:Service Mesh。现在谈微服务架构是无法不谈及 Service Mesh 的,作为服务通信流量的调控层,Service Mesh 带来了极大的好处。能否讲一讲,在最开始没有 Service Mesh 的情况下,服务间是如何通信,又如何被管理的呢?

Service Mesh 是一个专用的软件基础设施层,用于控制和监控微服务应用中服务之间的内部通信,让服务相互间通信变得快速、安全和可靠。它通常表现为“数据平面”和“控制平面”。

作为 Sidecar 运行,Service Mesh 对应用程序来说是透明,所有应用程序间的流量都会通过它,所以对应用程序流量的控制都可以在 Serivce Mesh 中实现,这样也就无需关注服务之间的那些原来是通过应用程序或者其它框架实现的事情,比如 Spring Cloud、OSS,现在只要交给 Service Mesh 就可以了。

Service Mesh 的来龙去脉:

  1. 从最原始的主机之间直接使用网线相连
  2. 网络层的出现
  3. 集成到应用程序内部的控制流
  4. 分解到应用程序外部的控制流
  5. 应用程序的中集成服务发现和断路器
  6. 出现了专门用于服务发现和断路器的软件包/库,如 Twitter 的 Finagle 和 Facebook 的 Proxygen,这时候还是集成在应用程序内部
  7. 出现了专门用于服务发现和断路器的开源软件,如 Netflix OSS、Airbnb 的 synapse 和 nerve
  8. 像上边的专用于服务发现和断路器的软件等往往是各公司基于自己的基础设施开发的,没有通用性,这就促使了最后作为微服务的通用中间层的 Service Mesh 的出现

具体到我们自己的实践中,经历了这么一个过程。在最开始,我们做服务化的时候,那个时候还没有微服务的概念,更多的谈及的是 SOA,还主要停留在 Web Service 和 ESB 总线等技术和规范上。

而在开源的领域,可选的方案并不多,所以服务间的通信什么的我们是直接选择的阿里开源的 Dubbo。Dubbo 提供高性能和透明化的 RPC 远程服务调用方案,以及 SOA 服务治理方案,使得应用可通过高性能 RPC 实现服务的输出和输入功能,和 Spring 框架可以无缝集成。

Dubbo 包含远程通讯、集群容错和自动发现三个核心部分。提供透明化的远程方法调用,实现像调用本地方法一样调用远程方法,只需简单配置,没有任何 API 侵入。同时具备软负载均衡及容错机制,可在内网替代F5等硬件负载均衡器,降低成本,减少单点。可以实现服务自动注册与发现,不再需要写死服务提供方地址,注册中心基于接口名查询服务提供者的 IP 地址,并且能够平滑添加或删除服务提供者。

之后我们使用的是微服务套件 Spring cloud 来进行整体的微服务管理。Spring Cloud 作为一个微服务的开发框架,包括了很多组件,包括:Spring Cloud Netflix(Eureka、Hystrix、Zuul、Archaius)、Spring Cloud Config、Spring Cloud Cluster、Spring Cloud Consul、Spring Cloud Sleuth 等。

相关推荐