微服务-入门


微服务-入门

​ 前期后端团队规模也不大业务采用了单体应用的架构。因为求快,不同功能模块的代码耦合在一起,编译打包部署也都在一起。后来业务规模不断扩大,单体应用架构的开发模式就开始暴露出问题了。每一次功能发布和上线都需要一个上线负责人来收集上线列表,并协调所有相关的开发人员合并代码到主干,然后编译打包,修改工程依赖的 JAR 包版本。 后端架构经历了单体应用 - 微服务架构 - 容器化应用 - DevOps 的发展历程。小团队需要的不是一个大而全的东西而是一套可以快速落地的方法论。

什么是微服务体系呢?

当前移动互联网时代最先进的业务架构解决方案,能够更好的迎合移动互联网业务快速迭代的要求.

理清微服务的脉络,并在恰当的时候,也可以主导自己公司的服务化进程

关于微服务我们需要知道什么?

(1)微服务架构的基本原理。什么是微服务?什么时候适合微服务改造?微服务架构到底是什么样的?

(2)微服务架构改造过程可能回遇到的问题和解决方案。搭建微服务框架时,如何做技术选型

(3)微服务,容器化,DevOps三者之间的关系。如何运用这三种技术给业务的架构带来质的飞跃

(4)下一代微服务体系可能的发展方向

一、到底什么是微服务?

维基百科中如何定义微服务

微服务的概念最早是在 2014 年由 Martin Fowler 和 James Lewis 共同提出,他们定义了微服务是由单一应用程序构成的小服务,拥有自己的进程与轻量化处理,服务依业务功能设计,以全自动的方式部署,与其他服务使用HTTP API 通讯。同时,服务会使用最小规模的集中管理 (例如 Docker)技术,服务可以用不同的编程语言与数据库等。

(1)单体应用

各大互联网公司的应用技术栈大致可分为 LAMP(Linux + Apache + MySQL + PHP)和 MVC(Spring + iBatis/Hibernate + Tomcat)两大流派。

无论是 LAMP 还是 MVC,都是为单体应用架构设计的,其优点是学习成本低,开发上手快,测试、部署、运维也比较方便,甚至一个人就可以完成一个网站的开发与部署。 然而随着业务规模的不断扩大,团队开发人员的不断扩张,单体应用架构就会开始出现问题。 部署效率低下、团队协作开发成本高、系统高可用性差、线上发布变慢

想要解决上面这些问题,服务化的思想也就应运而生.

(2)什么是服务化?

服务化就是把传统的单机应用中通过 JAR 包依赖产生的本地方法调用,改造成通过 RPC 接口产生的远程方法调用。

一般在编写业务代码时,对于一些通用的业务逻辑,我会尽力把它抽象并独立成为专门的模块,因为这对于代码复用和业务理解都大有裨益。 通过服务化,可以解决单体应用膨胀、团队开发耦合度高、协作效率低下的问题

(3)什么是微服务?

从 2014 年开始,得益于以 Docker 为代表的容器化技术的成熟以及 DevOps 文化的兴起,服务化的思想进一步演化,演变为今天我们所熟知的微服务。

那么微服务相比服务化又有什么不同呢?

服务拆分粒度更细、服务独立部署、服务独立维护、服务治理能力要求高

微服务化给服务的发布和部署,以及服务的保障带来了诸多的好处

总结来说,微服务架构是将复杂臃肿的单体应用进行细粒度的服务化拆分,每个拆分出来的服务各自独立打包部署,并交由小团队进行开发和运维,从而极大地提高了应用交付的效率,并被各大互联网公司所普遍采用。

服务化最难的是在数据库层,因为数据库中很多数据都是相互关联的,比如用户用户跟订单,订单和商品等等这些数据之间都是有关联的,服务拆分之后会面临以下问题:

  1. 当需要读取关联数据时,如果采用表连接的方式查询数据会出现跨数据库查询的可能
  2. 如果是通过RPC的方式多次调用(比如要查订单,就需要查询商品及订单详细信息),也会出现多次调用导致的频繁多次的数据库连接,
  3. 如果使用缓存,也会面临数据库与缓存之间的数据…

二、从单体应用走向服务化

微服务就是将庞杂臃肿的单体应用拆分成细粒度的服务,独立部署,并交给各个中小团队来负责开发、测试、上线和运维整个生命周期。那么到底什么时候应该拆分单体应用?拆分单体应用有哪些标准可依呢?单体应该拆分成微服务的正确姿势是什么呢?

(1)什么时候进行服务化拆分?

项目第一阶段的主要目标是快速开发和验证想法,证明产品思路是否可行。这个阶段功能设计一般不会太复杂,开发采取快速迭代的方式,架构也不适合过度设计。所以将所有功能打包部署在一起,集中地进行开发、测试和运维,对于项目起步阶段,是最高效也是最节省成本的方式。当可行性验证通过,功能进一步迭代,就可以加入越来越多的新特性。

一旦单体应用同时进行开发的人员超过 10 人,就会遇到上面的问题,这个时候就该考虑进行服务化拆分了。

(2)服务化拆分的两种姿势

那么服务化拆分具体该如何实施呢?一个最有效的手段就是将不同的功能模块服务化,独立部署和运维。

纵向拆分: 是从业务维度进行拆分。标准是按照业务的关联程度来决定,关联比较密切的业务适合拆分为一个微服务,而功能相对比较独立的业务适合单独拆分为一个微服务

横向拆分: 是从公共且独立功能维度拆分。标准是按照是否有公共的被多个其他服务调用,且依赖的资源独立不与其他业务耦合。

(3)服务化拆分的前置条件

业务系统引入新技术就必然会带来架构的复杂度提升,在具体决策前,你先要认识到新架构会带来哪些新的问题,这些问题你和你的团队是否能够解决?如何解决?是自己投入人力建设,还是采用业界开源方案? 以下几个问题从单体应用迁移到微服务架构时必将面临也必须解决的

  • 服务如何定义?

    • 单体应用: 不同功能模块之前相互交互时,通常是以类库的方式来提供各个模块的功能

    • 微服务: 接口,无论采用哪种通讯协议,是 HTTP 还是 RPC,服务之间的调用都通过接口描述来约定,约定内容包括接口名、接口参数以及接口返回值

  • 服务如何发布和订阅?

    • 单体应用: 由于部署在同一个 WAR 包里,接口之间的调用属于进程内的调用
    • 微服务: 能够记录每个服务提供者的地址以供服务调用者查询,在微服务架构里,这个地方就是注册中心
  • 服务如何监控?

    • 通常对于一个服务,我们最关心的是 QPS(调用量)、AvgTime(平均耗时)以及 P999(99.9% 的请求性能在多少毫秒以内)这些指标。这时候你就需要一种通用的监控方案,能够覆盖业务埋点、数据收集、数据处理,最后到数据展示的全链路功能
  • 服务如何治理?

    • 可以想象,拆分为微服务架构后,服务的数量变多了,依赖关系也变复杂了。比如一个服务的性能有问题时,依赖的服务都势必会受到影响。可以设定一个调用性能阈值,如果一段时间内一直超过这个值,那么依赖服务的调用可以直接返回,这就是熔断,也是服务治理最常用的手段之一。
  • 故障如何定位?

    • 在单体应用拆分为微服务之后,一次用户调用可能依赖多个服务,每个服务又部署在不同的节点上,如果用户调用出现问题,你需要有一种解决方案能够将一次用户请求进行标记,并在多个依赖的服务系统中继续传递,以便串联所有路径,从而进行故障定位。

无论是纵向拆分还是横向拆分,都是将单体应用庞杂的功能进行拆分,抽离成单独的服务部署。并不是说功能拆分的越细越好,过度的拆分反而会让服务数量膨胀变得难以管理,因此找到符合自己业务现状和团队人员技术水平的拆分粒度才是可取的。我建议的标准是按照每个开发人员负责不超过 3 个大的服务为标准,毕竟每个人的精力是有限的,所以在拆分微服务时,可以按照开发人员的总人数来决定。

三、初探微服务架构

了解微服务的各个组成部分

不管你是采用开源方案还是自行研发,都必须吃透每个组件的工作原理并能在此基础上进行二次开发。

(1)微服务模块架构图

image-20200727210206336

首先服务提供者(就是提供服务的一方)按照一定格式的服务描述,向注册中心注册服务,声明自己能够提供哪些服务以及服务的地址是什么,完成服务发布。

接下来服务消费者(就是调用服务的一方)请求注册中心,查询所需要调用服务的地址,然后以约定的通信协议向服务n提供者发起请求,得到请求结果后再按照约定的协议解析结果。

而且在服务的调用过程中,服务的请求耗时、调用量以及成功率等指标都会被记录下来用作监控,调用经过的链路信息会被记录下来,用于故障定位和问题追踪。在这期间,如果调用失败,可以通过重试等服务治理手段来保证成功率

微服务架构下,服务调用主要依赖下面几个基本组件: 服务描述、注册中心、服务框架、服务监控、服务追踪服务治理

(2)服务描述

服务调用首先要解决的问题就是服务如何对外描述。比如,你对外提供了一个服务,那么这个服务的服务名叫什么?调用这个服务需要提供哪些信息?调用这个服务返回的结果是什么格式的?该如何解析?这些就是服务描述要解决的问题

常用的服务描述方式包括 RESTful API、XML 配置以及 IDL 文件三种。

1. RESTful API

其中,RESTful API 方式通常用于 HTTP 协议的服务描述,并且常用 Wiki 或者Swagger来进行管理。下面是一个 RESTful API 方式的服务描述的例子。

image-20200727210618830

2. XML配置

XML 配置方式多用作 RPC 协议的服务描述,通过 *.xml 配置文件来定义接口名、参数以及返回值类型等。下面是一个 XML 配置方式的服务描述的例子。

image-20200727210706680

3. IDL 文件

IDL 文件方式通常用作 Thrift 和 gRPC 这类跨语言服务调用框架中,比如 gRPC 就是通过Protobuf 文件来定义服务的接口名、参数以及返回值的数据结构,示例如下:

image-20200727210751706

(3)注册中心

有了服务的接口描述,下一步要解决的问题就是服务的发布和订阅,就是说你提供了一个服务,如何让外部想调用你的服务的人知道。这个时候就需要一个类似注册中心的角色,服务供者将自己提供的服务以及地址登记到注册中心,服务消费者则从注册中心查询所需要调用的服务的地址,然后发起请求。

一般来讲,注册中心的工作流程是:

      1. 服务提供者在启动时,根据服务发布文件中配置的发布信息向注册中心注册自己的服务。
   2. 服务消费者在启动时,根据消费者配置文件中配置的服务信息向注册中心订阅自己所需要的服务。
      3. 注册中心返回服务提供者地址列表给服务消费者。
         4. 当服务提供者发生变化,比如有节点新增或者销毁,注册中心将变更通知给服务消费者。  

image-20200727211004794

(4)服务框架

通过注册中心,服务消费者就可以获取到服务提供者的地址,有了地址后就可以发起调用。但在发起调用之前你还需要解决以下几个问题。

(1)服务通信采用什么协议?就是说服务提供者和服务消费者之间以什么样的协议进行网络通信,是采用四层 TCP、UDP 协议,还是采用七层 HTTP 协议,还是采用其他协议?
(2)数据传输采用什么方式?就是说服务提供者和服务消费者之间的数据传输采用哪种方式,是同步还是异步,是在单连接上传输,还是多路复用。
(3)数据压缩采用什么格式?通常数据传输都会对数据进行压缩,来减少网络传输的数据量,从而减少带宽消耗和网络传输时间,比如常见的 JSON 序列化、Java 对象序列化以及 Protobuf 序列化等

(5)服务监控

一旦服务消费者与服务提供者之间能够正常发起服务调用,你就需要对调用情况进行监控,以了解服务是否正常。通常来讲,服务监控主要包括三个流程。

(1)指标收集。就是要把每一次服务调用的请求耗时以及成功与否收集起来,并上传到集中的数据处理中心。
(2)数据处理。有了每次调用的请求耗时以及成功与否等信息,就可以计算每秒服务请求量、平均耗时以及成功率等指标。
(3)数据展示。数据收集起来,经过处理之后,还需要以友好的方式对外展示,才能发挥价值。通常都是将数据展示在 Dashboard 面板上,并且每隔 10s 等间隔自动刷新,用作业务监控和报警等。

(6)服务追踪

除了需要对服务调用情况进行监控之外,你还需要记录服务调用经过的每一层链路,以便进行问题追踪和故障定位。
服务追踪的工作原理大致如下:

(1)服务消费者发起调用前,会在本地按照一定的规则生成一个 requestid,发起调用时,将requestid 当作请求参数的一部分,传递给服务提供者。
(2)服务提供者接收到请求后,记录下这次请求的 requestid,然后处理请求。如果服务提供者继续请求其他服务,会在本地再生成一个自己的 requestid,然后把这两个 requestid 都当作请求参数继续往下传递。

以此类推,通过这种层层往下传递的方式,一次请求,无论最后依赖多少次服务调用、经过多少服务节点,都可以通过最开始生成的 requestid 串联所有节点,从而达到服务追踪的目的。

(7)服务治理

服务监控能够发现问题,服务追踪能够定位问题所在,而解决问题就得靠服务治理了。服务治理就是通过一系列的手段来保证在各种意外情况下,服务调用仍然能够正常进行。

在生产环境中,你应该经常会遇到下面几种状况。

(1)单机故障。通常遇到单机故障,都是靠运维发现并重启服务或者从线上摘除故障节点。然而集群的规模越大,越是容易遇到单机故障,在机器规模超过一百台以上时,靠传统的人肉运维显然难以应对。而服务治理可以通过一定的策略,自动摘除故障节点,不需要人为干预,就能保证单机故障不会影响业务。
(2)单 IDC 故障。你应该经常听说某某 App,因为施工挖断光缆导致大批量用户无法使用的严重故障。而服务治理可以通过自动切换故障 IDC 的流量到其他正常 IDC,可以避免因为单 IDC 故障引起的大批量业务受影响。
(3)依赖服务不可用。比如你的服务依赖依赖了另一个服务,当另一个服务出现问题时,会拖慢甚至拖垮你的服务。而服务治理可以通过熔断,在依赖服务异常的情况下,一段时期内停止发起调用而直接返回。这样一方面保证了服务消费者能够不被拖垮,另一方面也给服务提供者减少压力,使其能够尽快恢复。

上面是三种最常见的需要引入服务治理的场景,当然还有一些其他服务治理的手段比如自动扩缩容,可以用来解决服务的容量问题。

四、如何发布和引用服务?

服务提供者如何发布一个服务,服务消费者如何引用这个服务?

服务发布和引用的方式有三种

  • RESTful API
  • XML 配置
  • IDL 文件

(1)RESTful API

首先来说说 RESTful API 的方式,主要被用作 HTTP 或者 HTTPS 协议的接口定义,即使在非微服务架构体系下,也被广泛采用。
下面是开源服务化框架Motan发布 RESTful API 的例子,它发布了三个 RESTful 格式的API,接口声明如下

image-20200727211851321

具体的服务实现如下:

image-20200727211913321

(2)XML 配置

(3)IDL 文件

五、如何注册和发现服务?

(1)注册中心原理

(2)注册中心实现方式

1. 注册中心 API

2. 集群部署

3. 目录存储

4. 服务健康状态检测

5. 服务状态变更通知

6. 白名单机制

六、如何实现RPC远程服务调用

(1)客户端和服务端如何建立网络连接?

1. HTTP 通信

2. Socket 通信

(2)服务端如何处理请求?

(3)数据传输采用什么协议?

(4)数据该如何序列化和反序列化?

七、如何监控微服务调用?

(1)监控对象

(2)监控指标

(3)监控维度

(4)监控系统原理

1. 数据采集

2. 数据传输

3. 数据处理

4. 数据展示

八、如何追踪微服务调用?

(1)服务追踪的作用

(2)服务追踪系统原理

(3)服务追踪系统实现

1. 数据采集层

2. 数据处理层

3. 数据展示层

九、微服务治理的手段有哪些?

(1)节点管理

1. 注册中心主动摘除机制

2. 服务消费者摘除机制

(2)负载均衡

1. 随机算法

2. 轮询算法

3. 最少活跃调用算法

4. 一致性 Hash 算法

(3)服务路由

1. 业务存在灰度发布的需求

2. 多机房就近访问的需求

(4)路由规则该如何配置呢?

1. 静态配置

2. 动态配置

(5)服务容错

十、Dubbo框架里的微服务组件

(1)服务发布与引用

(2)服务注册与发现

(3)服务调用

(4)服务监控

(5)服务治理

(6)一次服务调用的流程


文章作者: 韩思远
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 韩思远 !
评论
 上一篇
微服务-落地 微服务-落地
微服务-落地一、服务发布和引用的实践XML 配置方式的服务发布和引用流程1. 服务提供者定义接口2. 服务提供者发布接口3. 服务消费者引用接口服务发布和引用的那些坑1. 服务发布预定义配置 二、如何将注册中心落地?三、开源服务注册中心如何
2020-09-08
下一篇 
MySQL实战总结 MySQL实战总结
MySQL实战总结十五、答疑文章(一):日志和索引相关问题(1)日志相关问题(2)业务设计问题(3)小结 三十、答疑文章(二):用动态的观点看加锁(1)不等号条件里的等值查询(2)等值查询的过程(3)怎么看死锁?(4)怎么看锁等待?(
2020-09-08
  目录