从零开始学微服务(一)

从零开始学微服务(一)

Scroll Down
cropped-1366-768-1084984
cropped-1366-768-1084984

知识提炼来源于极客时间专栏《从0开始学微服务》,会加入自己的理解和当前的业务思考

近期准备入职新公司,在此期间正好有点空闲时间,在找房子的同时,打算把微服务相关知识学习下,方便自己快速融入新团队。

单体服务

在了解微服务前,可以先看看单体服务的痛点。有一个大WAR包,这个WAR包糅杂了各式各样的业务,然后一起部署到同一个 Tomcat 下,这就是我理解的单体应用。随着业务规模的扩大,团队成员的扩充,单体服务就会出现以下几个问题:

  • 部署效率低下。从编译打包到部署测试,需要花费比较多的时间,如果编译打包时候,某部分出现异常,那就得重新再来一次,是真蛋疼,这点深有体会。
  • 团队协作成本高。全部成员都要对一个单体应用进行修改,测试功能时,都要合并打包代码,麻烦。
  • 系统高可用性差。这点就很容易理解了,某段代码出严重问题,会导致进程不可用。
  • 线上发布变慢。代码庞大起来后,服务启动时间就会更长。
weipa
weipa

服务化

针对单体应用的痛点,服务化的思想应运而生。服务化就是把传统的单机应用中通过 JAR 包依赖产生的本地方法调用,改造成通过 RPC 接口产生的远程方法调用。像以前做的数据中心的运维平台项目,可以拆出来资源管理模块、用户模块、告警模块等,以RPC方式来调用接口。不同模块,交给不同的业务团队负责,一个模块出了问题,不会导致其他模块不可用。

微服务

微服务可以看作是服务化的进一步演进,那它和服务化有哪些不同点呢?

  • 服务粒度拆分更细。像上面说的资源管理模块,又可以拆分出建筑资源和设备资源。
  • 服务独立部署。一台物理机上可以部署多个 Docker 实例,每一个 Docker 可以部署一个微服务代码。我以前还纳闷,服务这么多,如果每台机器就部署一个服务,那不是需要很多机器?原来有Docker……
  • 服务独立维护。一个服务可以交给一个团队负责,开发、测试、发布、运维。
  • 服务治理能力要求高。因为拆分为微服务之后,服务的数量变多,因此需要有统一的服务治理平台,来对各个服务进行管理。

服务化拆分的前置条件

单体应用拆分为微服务的过程,我们需要去考虑一个以下几个重要的问题,而且都是必须先想清楚,才能去实际动手。

  • 服务之间如何通信。是通过 HTTP 还是 RPC , 服务于服务之间的接口定义要详细。
  • 服务如何发布和订阅。服务调用者要如何知道服务提供者的地址呢?那就需要一个注册中心了。
  • 服务如何监控。要想知道服务的 QPS,就需要监控。监控能够覆盖业务埋点、数据收集、数据处理,最后到数据展示的全链路功能。
  • 服务如何治理。服务于服务之间的调用,如果存在一方有问题,就会导致调用方接口性能收到影响,这时候我们需要对服务进行熔断。
  • 故障如何定位。一次用户调用依赖多个服务,我们得知道问题出现在哪个服务上。
touteng
touteng

微服务架构

微服务架构下,服务调用需要经过以下几个组件:

  • 服务描述。就是说你对外提供了一个什么服务,参数是什么,返回值是什么。常用的服务描述方式包括 Restful API、XML 配置以及 IDL 文件三种,HTTP 用 Restful API ,RPC用XML较多,gRPC用IDL文件较多。
  • 注册中心。服务提供方往注册中心注册服务,服务消息者就订阅注册中心的服务,启动时候,就会去获取订阅的服务列表缓存到自己本地,假如有新服务,注册中心会通知服务消费者去重新获取服务的。
  • 服务框架。服务消费者拿到地址后,应该干什么?应该决定用什么协议去调用请求,用什么样的方式去传输数据,用什么格式来压缩数据。
  • 服务监控。服务监控主要是看服务正不正常,服务监控主要包括三个流程:1. 指标收集,收集接口耗时与成功与否。2.数据处理,利用收集好的数据,可以计算出平均耗时,每秒请求量等数据。3.数据展示,用 Dashboard 面板。
  • 服务追踪。用于问题追踪和故障定位的,服务消费者发起请求时,会生成一个 request id,带到给服务提供者,如果该服务内部还去调用其他服务,那就该服务继续生成一个 request id,以此类推,用这个 id 来组成一个调用链。
  • 服务治理。服务治理就是通过一系列的手段来保证在各种意外情况下,服务调用仍然能够正常进行。

服务监控能够发现问题,服务追踪能够定位问题所在,而解决问题就得靠服务治理了。

补充一下,关于服务描述的选择问题,如果服务是对外的,用 Restful API 最好。如果是企业内部 Java 语言的,用 XML 就可以了,如果是企业内部跨语言的,用 IDL 好点。

如何监控微服务调用

监控对象

微服务的监控,从上到下的维度来看,需要监控以下几大对象:

  • 用户端监控。这块文章说的不是很让人理解,用户端监控的是用户功能,用户功能不也还是由接口组成的吗,监控接口不就完事了?这一块保留一下看法。(极客时间《从0开始学微服务》第七节)
  • 接口监控。
  • 资源监控。这一块是指接口依赖的资源,比如用到了 Redis,那就得监控 Redis 资源。
  • 基础监控。这指服务器的一些关键资源,比如带宽、I/O、内存、CPU。

监控指标

监控对象我们了解后,还需要知道监控对象的哪些指标才合适。

  • 请求量。请求量监控分为两个维度,一个是实时请求量,一个是统计请求量。QPS 代表每秒的请求量,是实时请求的体现,PV 是统计服务的访问量,这是统计指标。
  • 响应时间。可以用一段时间的请求平均耗时来表示请求的快慢,要想知道慢请求的数量,可以通过划分区间的方式来,观察慢请求落在区间的数量。
  • 错误率。失败请求的数量占总请求的数量的比例就是错误率。

监控系统的原理

监控系统的整个数据处理流程应该是下面描述的那样:

监控数据处理链
监控数据处理链

服务追踪系统原理

在了解追踪原理之前,先了解下服务追踪的作用:

  1. 优化系统瓶颈。这个比较好理解,就是说看看调用链是哪个地方出了问题,然后解决这个问题就好了。
  2. 优化链路调用。看调用的链路是否是多余的。
  3. 生成网络拓扑。这个我就不太好理解了,文章说是从全局的角度来生成拓扑,那我的理解是从上帝视角先定位哪个服务出问题,再去排查接口。
  4. 透明传输数据。除了服务追踪,业务上经常有一种需求,期望能把一些用户数据,从调用的开始一直往下传递,以便系统中的各个服务都能获取到这个信息。这个和追踪系统有啥关系?不理解。

理解原理前,还需要了解三个核心概念:

  1. traceId。表示某一次请求的具体id,这个id会在服务间流转。
  2. spanId。用于标识一次 RPC 调用在分布式请求中的位置。简单点说,就是一次请求中,所调用的服务,每个服务都会有个spanId,来标明自己的身份。
  3. annotation。用于业务自定义埋点数据,可以是业务感兴趣的想上传到后端的数据,比如一次请求的用户 UID。

服务追踪的核心理念就是调用链:通过一个全局唯一的 ID 将分布在各个服务节点上的同一次请求串联起来,从而还原原有的调用关系,可以追踪系统问题、分析调用数据并统计各种系统指标。

现在有名的追踪系统有Twitter 的 Zipkin、阿里的鹰眼、美团的 MTrace。

sleep
sleep

微服务治理手段

一次服务调用,可能因为网络,或者服务提供者本身宕机等问题,会导致服务不成功,这种情况下,在微服务系统中,就需要一些治理手段来保证调用的成功。

以下是常见的微服务治理手段,大致分为三类:

  1. 节点管理角度。
  2. 请求均衡的角度。
  3. 服务容错角度。

节点管理

节点管理有两种方案:

  • 注册中心主动摘除机制。如果服务提供方最后一次与注册中心的通信时间的时间间隔超过了指定值,那么注册中心就会认为这个服务不可用,从而摘除了。
  • 服务消费者摘除机制。服务消费者本身有缓存可用节点,如果服务调不通了,就在服务消费者方把这个节点移除掉。这种方案是考虑到服务提供方与注册中心的网络出了问题,但是实际上,服务依然可用的。如果采取第一种方案的化,注册中心的可用节点估计就都被摘除了。

请求均衡

于服务消费者而言,在内存中的可用服务节点列表中选择哪个节点,由两个方面决定的,分别为负载均衡算法和路由规则。

负载均衡算法就有以下常见的4中策略:

  1. 随机算法
  2. 按权重轮询
  3. 最小连接数(最小活跃数)
  4. 一致性hash算法

路由规则是指通过一定的规则如条件表达式或者正则表达式来限定服务节点的选择范围。

制定路由规则是有实际业务需求的,比如以下两个方面:

  1. 业务存在灰度发布的需求。这个意思是说,上线新代码时候,先上线到部分机器,测试没问题后,再全量同步。既然如此,那路由部分用户到这部分机器,就是顺理成章的。
  2. 多机房就近访问的需求。广州的服务访问广州的机房,当然是最合适的。跨区域的机房访问,需要耗费不少时间,对于性能要求比较高的服务请求,这是不能容忍的。

服务容错

对于服务调用失败的情况,我们需要有手段自动恢复,来保证调用成功。常见的手段有以下几种:

  • FailOver。失败后,重试,或者选择下一个可用节点,重试的情况下,就要求服务是幂等操作。
  • FailBack。失败后,不重试,看看失败原因,再采取其他方式,如果是非幂等操作,那就先去查询一下数据,没有再重新发送。
  • FailCache。失败后,隔一段时间再重试,避免当时的重试导致服务提供方的压力增大。
  • FailFast。失败后,不再重试,简单记录下日志,一般用与非核心业务。