每天净瞎搞

关注:CS/AI/数学/自我提升等

0%

《从0开始学微服务》模块一:入门微服务的学习笔记

03丨初探微服务架构

  • gt3:微服务架构的模块图和一次正常的服务调用的流程
    • 1.服务提供者按照一定格式的服务描述,向注册中心注册服务,声明自己能够提供哪些服务以及服务的地址是什么,完成服务发布
    • 2.来服务消费者请求注册中心,查询所需要调用服务的地址,然后以约定的通信协议向服务提供者发起请求,得到请求结果后再按照约定的协议解析结果
    • 3.在服务的调用过程中,服务的请求耗时、调用量以及成功率等指标都会被记录下来用作监控,调用经过的链路信息会被记录下来,用于故障定位和问题追踪。在这期间,如果调用失败,可以通过重试等服务治理手段来保证成功率
  • gt3:微服务架构下,服务调用主要依赖的几个基本组件及其作用
    • 服务描述
      • 服务调用首先要解决的问题就是服务如何对外描述
      • 常用的服务描述方式包括
        • RESTful API:通常用于 HTTP 协议的服务描述,并且常用 Wiki 或者Swagger 来进行管理
        • XML 配置:多用作 RPC 协议的服务描述,通过 *.xml 配置文件来定义接口名、参数以及返回值类型等
        • IDL 文件:通常用作 Thrift 和 gRPC 这类跨语言服务调用框架中
    • 注册中心
      • 作用
        • 有了服务的接口描述,下一步要解决的问题就是服务的发布和订阅,这时需要注册中心,服务提供者将自己提供的服务以及地址登记到注册中心,服务消费者则从注册中心查询所需要调用的服务的地址,然后发起请求
      • 工作流程
        • 服务提供者在启动时,根据服务发布文件中的发布信息向注册中心注册自己的服务
        • 服务消费者在启动时,根据消费者配置文件中配置的服务信息向注册中心订阅自己所需要的服务
        • 注册中心返回服务提供者地址列表给服务消费者
        • 当服务提供者发生变化,比如有节点新增或者销毁,注册中心将变更通知给服务消费者
    • 服务框架
      • 通过注册中心,服务消费者就可以获取到服务提供者的地址,有了地址后就可以发起调用,但发起调用前还需解决:服务通信的协议、数据传输的格式、数据压缩的格式
    • 服务监控
      • 一旦服务消费者与服务提供者之间能够正常发起服务调用,你就需要对调用情况进行监控,以了解服务是否正常。通常服务监控主要包括三个流程
        • 指标收集。就是要把每一次服务调用的请求耗时以及成功与否收集起来,并上传到集中的数据处理中心
        • 数据处理。有了每次调用的请求耗时以及成功与否等信息,就可以计算每秒服务请求量、平均耗时以及成功率等指标
        • 数据展示。数据收集起来,经过处理之后,还需要以友好的方式对外展示,才能发挥价值。通常都是将数据展示在 Dashboard 面板上,并且每隔 10s 等间隔自动刷新,用作业务监控和报警等
    • 服务追踪
      • 作用:记录服务调用经过的每一层链路,以便进行问题追踪和故障定位
      • 工作原理
        • 服务消费者发起调用前,会在本地按照一定的规则生成一个 requestid,发起调用时,将 requestid 当作请求参数的一部分,传递给服务提供者
        • 服务提供者接收到请求后,记录下这次请求的 requestid,然后处理请求。如果服务提供者继续请求其他服务,会在本地再生成一个自己的 requestid,然后把这两个 requestid 都当作请求参数继续往下传递
        • 以此类推,通过这种层层往下传递的方式,一次请求,无论最后依赖多少次服务调用、经过多少服务节点,都可以通过最开始生成的 requestid 串联所有节点,从而达到服务追踪的目的
    • 服务治理
      • 作用:通过一系列的手段来保证在各种意外情况下,服务调用仍然能够正常进行
      • 作用场景:
        • 单机故障:通过一定策略,自动摘除故障节点,不需要人为 干预,就能保证单机故障不会影响业务
        • 单 IDC 故障:通过自动切换故障 IDC 的流量到其他正常 IDC,可以避免因 为单 IDC 故障引起的大批量业务受影响
        • 依赖服务不可用:通过熔断,在依赖服务异常的情况下,一段时期内停止发起调用而直接返回。这样一方面保证了服务消费者能够不被拖垮,另一方面也给服务提供者减少压力,使其能够尽快恢复

04 | 如何发布和引用服务?

  • gt4:服务的发布和引用是指什么?
    • 服务提供者如何发布一个服务,服务消费者如何引用这个服务
    • 具体来说,就是这个服务的接口名是什么?调用这个服务需要传递哪些参数?接口的返回值是什么类型?以及一些其他接口描述信息
  • gt4:常见的服务发布和引用的三种方式
    • RESTful API
      • 主要被用作 HTTP 或者 HTTPS 协议的接口定义
      • 优点:因为 HTTP 协议本身是一个公开的协议,对于服务消费者来说几乎没有学习成本,所以比较适合用作跨业务平台之间的服务协议
    • XML 配置
      • 服务发布和引用的三个步骤
        • 服务提供者定义接口,并实现接口
        • 服务提供者进程启动时,通过加载 server.xml 配置文件将接口暴露出去
        • 服务消费者进程启动时,通过加载 client.xml 配置文件来引入要调用的接口
      • 优点
        • 一般是私有 RPC 框架会选择 XML 配置这种方式来描述接口,因为私有 RPC 协议的性能要比 HTTP 协议高,所以在对性能要求比较高的场景下,采用 XML 配置的方式比较合适
      • 缺点
        • 对业务代码侵入性比较高,XML 配置有变更的时候,服务消费者和服务提供者都要更新,所以适合公司内部联系比较紧密的业务之间采用。如果要应用到跨部门之间的业务调用,一旦有 XML 配置变更,需要花费大量精力去协调不同部门做升级工作
    • IDL 文件(Interface Description Language,接口描述语言)
      • 通过一种中立的方式来描述接口,使得在不同的平台上运行的对象和不同语言编写的程序可以相互通信交流,主要用作跨语言跨平台的服务之间的调用
      • 最常用的两种 IDL:Facebook 开源的Thrift 协议和 Google 开源的 gRPC 协议
      • 注意的是,在描述接口定义时,IDL 文件需要对接口返回值进行详细定义。如果接口返回值的字段比较多,并且经常变化时,采用 IDL 文件方式的接口定义就不太合适了。一方面可能会造成 IDL 文件过大难以维护,另一方面只要 IDL 文件中定义的接口返回值有变更,都需要同步所有的服务消费者都更新,管理成本就太高了

05 | 如何注册和发现服务?

  • gt5:注册中心的原理(微服务框架下的三种角色和交互关系)
    • 微服务架构下的三种角色
      • 服务提供者(RPC Server)
      • 服务消费者(RPC Client)
      • 服务注册中心(Registry)
    • 三种角色的交互关系
      • RPC Server 提供服务,在启动时,根据服务发布文件 server.xml 中的配置的信息,向 Registry 注册自身服务,并向 Registry 定期发送心跳汇报存活状态
      • RPC Client 调用服务,在启动时,根据服务引用 client.xml 中的配置信息,向 Registry 订阅服务,把 Registry 返回的服务节点列表缓存在本地内存中,并与 RPC Server 建立连接
      • 当 RPC Server 节点发生变更时,Registry 会同步变更,RPC Client 感知后会刷新本地内存中缓存的服务节点列表
      • RPC Client 从本地缓存的服务节点列表中,基于负载均衡算法选择一台 RPC Server 发起调用
  • gt5:注册中心的实现:提供的 API、部署方式、存储方式、服务健康状态检测、服务状态变更通知、白名单机制
    • 注册中心提供的 API
      • 服务注册接口:服务提供者通过调用服务注册接口来完成服务注册
      • 服务反注册接口:服务提供者通过调用服务反注册接口来完成服务注销
      • 心跳汇报接口:服务提供者通过调用心跳汇报接口完成节点存活状态上报
      • 服务订阅接口:服务消费者通过调用服务订阅接口完成服务订阅,获取可用的服务提供者节点列表
      • 服务变更查询接口:服务消费者通过调用服务变更查询接口,获取最新的可用服务节点列表
      • 后台管理的 API 如:
      • 服务查询接口:查询注册中心当前注册了哪些服务信息
      • 服务修改接口:修改注册中心中某一服务的信息
    • 部署方式
      • 采用集群部署来保证高可用性,并通过分布式一致性协议来确保集群中不同节点之间的数据保持一致
      • 以开源注册中心 ZooKeeper 为例,ZooKeeper 集群中包含多个节点,服务提供者和服务消费者可以同任意一个节点通信,因为它们的数据一定是相同的
    • 存储方式
      • 以 ZooKeeper 为例,注册中心存储服务信息一般采用层次化的目录结构
      • 每个目录在 ZooKeeper 中叫作 znode,并且有一个唯一的路径标识
      • znode 可以包含数据和子 znode
      • znode 中的数据可以有多个版本,如某一个 znode 下存有多个数据版本,那么查询这个路径下的数据需带上版本信息
    • 服务健康状态检测
      • 以 ZooKeeper 为例,它是基于 ZooKeeper 客户端和服务端的长连接和会话超时控制机制,来实现服务健康状态检测的
      • 在 ZooKeeper 中,客户端和服务端建立连接后,会话也随之建立,并生成一个全局唯一的 Session ID。服务端和客户端维持的是一个长连接,在 SESSION_TIMEOUT 周期内,服务端会检测与客户端的链路是否正常,具体方式是通过客户端定时向服务端发送心跳消息(ping 消息),服务器重置下次 SESSION_TIMEOUT 时间。如果超过 SESSION_TIMEOUT 后服务端都没有收到客户端的心跳消息,则服务端认为这个 Session 就已经结束了,ZooKeeper 就会认为这个服务节点已经不可用,将会从注册中心中删除其信息
      • 注:如果摘除的节点占到了服务集群节点数一定阈值,就停止摘除服务节点,并且给服务的开发同学和运维同学报警处理
    • 服务状态变更通知
      • 一旦注册中心探测到有服务提供者节点新加入或者被剔除,就必须立刻通知所有订阅该服务的服务消费者,刷新本地缓存的服务节点信息,确保服务调用不会请求不可用的服务提供者节点
      • 以 ZooKeeper 为例,基于 ZooKeeper 的 Watcher 机制,来实现服务状态变更通知给服务消费者的。服务消费者在调用 ZooKeeper 的 getData 方法订阅服务时,还可以通过监听器 Watcher 的 process 方法获取服务的变更,然后调用 getData 方法获取变更后的数据,刷新本地缓存的服务节点信息
    • 白名单机制
      • 在实际的微服务测试和部署时,通常包含多套环境,比如生产环境一套、测试环境一套。开发在进行业务自测、测试在进行回归测试时,一般都是用测试环境,部署的 RPC Server 节点注册到测试的注册中心集群。但经常会出现开发或者测试在部署时,错误的把测试环境下的服务节点注册到了线上注册中心集群,这样的话线上流量就会调用到测试环境下的 RPC Server 节点,可能会造成意想不到的后果
      • 注册中心可以提供一个白名单机制,只有添加到注册中心白名单内的 RPC Server,才能够调用注册中心的注册接口,这样的话可以避免测试环境中的节点意外跑到线上环境中去

06丨如何实现RPC远程服务调用?

  • gt6:RPC的定义和原理
    • 在进行服务化拆分之后,服务提供者和服务消费者运行在两台不同物理机上的不同进程内,它们之间的调用称之为远程方法调用,简称 RPC(Remote Procedure Call)
    • 习惯上把服务消费者叫作客户端,服务提供者叫作服务端,两者要完成一次 RPC 调用,必须先建立网络连接,双方按照约定的通信协议进行网络通信。双方正常通信后,服务端接收到请求后进行处理,处理成功后把请求结果返回给客户端。为了减少传输的数据大小,还要对数据进行序列化
  • gt6:RPC调用中客户端和服务端建立网络连接的两种方式?
    • HTTP 通信
    • Socket 通信
  • gt6:客户端和服务端建立连接后,遇到网络闪断、连接超时、服务器宕机等异常时的两种处理手段是什么?
    • 链路存活检测
      • 客户端需要定时地发送心跳检测消息(一般是通过 ping 请求)给服务端,如果服务端连续 n 次心跳检测或者超过规定的时间都没有回复消息,则认为此时链路已经失效,这时客户端就需要重新与服务端建立连接
    • 断连重试
      • 通常有多种情况会导致连接断开,如客户端主动关闭、服务端宕机或者网络故障等。这个时候客户端就需要与服务端重新建立连接,但一般不能立刻完成重连,而是要等待固定的间隔后发起重连,避免服务端的连接回收不及时,而客户端瞬间重连的请求太多而把服务端的连接数占满
  • gt6:服务端处理客户端请求的三种处理方式
    • 同步阻塞方式(BIO)
      • 适用于连接数比较小的业务场景,这样的话不至于系统中没有可用线程去处理请求。这种方式写的程序也比较简单直观,易于理解
    • 同步非阻塞方式 (NIO)
      • 适用于连接数比较多并且请求消耗比较轻的业务场景,比如聊天服务器。这种方式相比 BIO,相对来说编程比较复杂
    • 异步非阻塞方式(AIO)
      • 适用于连接数比较多而且请求消耗比较重的业务场景,比如涉及 I/O 操作的相册服务器。这种方式相比另外两种,编程难度最大,程序也不易于理解

07丨如何监控微服务调用?

  • gt7:微服务系统要监控哪些对象?
    • 用户端监控。指业务直接对用户提供的功能的监控
    • 接口监控。指业务提供的功能所依赖的具体 RPC 接口的监控
    • 资源监控。指某个接口依赖的资源的监控,如监控 redis 服务
    • 基础监控。值服务器本身的监控状况的监控。如 CPU 利用率、内存使用量、I/O 读写量、网卡带宽等
  • gt7:微服务系统要监控哪些指标?
    • 可用RED+饱和度记忆,,R 代表请求量(Request rate),E 代表错误(Error),D 代表响应时间(Duration)
    • 请求量(吞吐量、通信量)
      • 实时请求量用 QPS(Queries Per Second)即每秒查询次数来衡量
      • 统计请求量一般用 PV(Page View)即一段时间内用户的访问量来衡量
    • 错误率
      • 用一段时间内调用失败的次数占调用总次数的比率来衡量
    • 请求的响应时间(延迟)
      • 还可以从 P90、 P95、P99、P999 角度来监控请求的响应时间,如 P99 = 500ms,意思是 99% 的请求响应时间在 500ms 以内
    • 饱和度
      • 服务或资源到达上限的程度(也可说服务或资源的利用率),如CPU 的使用率,内存使用率,磁盘使用率,缓存数据库的连接数等等
  • gt7:微服务系统有哪些监控维度
    • 全局维度
      • 从整体角度监控对象的的请求量、平均耗时以及错误率,全局维度的监控一般是为了让你对监控对象的调用情况有个整体了解
    • 分机房维度
      • 一般为了业务的高可用性,服务通常部署在不止一个机房,因为不同机房地域的不同,同一个监控对象的各种指标可能会相差很大,所以需要深入到机房内部去了解
    • 单机维度
      • 即便是在同一个机房内部,可能由于采购年份和批次的不同,位于不同机器上的同一个监控对象的各种指标也会有很大差异
    • 时间维度
    • 核心维度
      • 业务上一般会依据重要性程度对监控对象进行分级,最简单的是分成核心业务和非核心业务。核心业务和非核心业务在部署上必须隔离,分开监控
  • gt7:监控系统的 4 个环节是?
    • 数据采集:收集到每一次调用的详细信息,包括调用的响应时间、调用是否成功、调用的发起者和接收者分别是谁
      • 两种数据采集方式
        • 服务主动上报(代码埋点),这种处理方式通过在业务代码或者服务框架里加入数据收集代码逻辑,在每一次服务调用完成后,主动上报服务的调用信息
        • 代理收集,这种处理方式通过服务调用后把调用的详细信息记录到本地日志文件中,然后再通过代理去解析本地日志文件,然后再上报服务的调用信息
      • 采样率
        • 采样频率决定了监控的实时性与精确度,但同时也对系统本身的性能也会有一定的影响
        • 最好可以动态控制采样率
    • 数据传输:把数据通过一定的方式传输给数据处理中心进行处理
      • 两种数据传输方式
        • UDP 传输,数据处理单元提供服务器的请求地址,数据采集后通过 UDP 协议与服务器建立连接,然后把数据发送过去
        • Kafka 传输,数据采集后发送到指定的 Topic,然后数据处理单元再订阅对应的 Topic,就可以从 Kafka 消息队列中读取到对应的数据
      • 两种传输时采用的数据格式
        • 二进制协议,最常用的就是 PB 对象,它的优点是高压缩比和高性能,可以减少传输带宽并且序列化和反序列化效率特别高
        • 文本协议,最常用的就是 JSON 字符串,它的优点是可读性好,但相比于 PB 对象,传输占用带宽高,并且解析性能也要差一些
    • 数据处理:数据传输过来后,数据处理中心再按照服务的维度进行聚合,计算出不同服务的请求量、响应时间以及错误率等信息并存储起来
      • 两个数据聚合维度
        • 接口维度聚合,这个维度是把实时收到的数据按照接口名维度实时聚合在一起,这样就可以得到每个接口的实时请求量、平均耗时等信息
        • 机器维度聚合,这个维度是把实时收到的数据按照调用的节点维度聚合在一起,这样就可以从单机维度去查看每个接口的实时请求量、平均耗时等信息
      • 两种持久化的数据库存储
        • 索引数据库,比如 Elasticsearch,以倒排索引的数据结构存储,需要查询的时候,根据索引来查询
        • 时序数据库,比如 OpenTSDB,以时序序列数据的方式存储,查询的时候按照时序如 1min、5min 等维度来查询
    • 数据展示:通过接口或者 Dashboard 的形式对外展示服务的调用情况
      • 曲线图、饼状图、格子图

08丨如何追踪微服务调用?

  • gt8:微服务追踪系统的 traceId、spanId 和 annotation 的意思
    • traceId,用于标识某一次具体的请求 ID。当用户的请求进入系统后,会在 RPC 调用网络的第一层生成一个全局唯一的 traceId,并且会随着每一层的 RPC 调用,不断往后传递,这样的话通过 traceId 就可以把一次用户请求在系统中调用的路径串联起来
    • spanId,用于标识一次 RPC 调用在分布式请求再系统调用中所处的位置,以及上下游的依赖分别是谁
    • annotation,用于业务自定义埋点数据,可以是业务感兴趣的想上传到后端的数据,如一次请求的用户 UID
  • gt8:微服务追踪系统的架构的三层
    • 数据采集层,负责数据埋点并上报
    • 数据处理层,负责数据的存储与计算
      • 实时计算需求:对计算效率要求比较高,一般要求对收集的链路数据能够在秒级别完成聚合计算,以供实时查询
        • 针对实时数据处理,一般采用 Storm 或者 Spark Streaming 来对链路数据进行实时聚合加工,存储一般使用 OLTP 数据仓库,比如 HBase,使用 traceId 作为 RowKey,能天然地把一整条调用链聚合在一起,提高查询效率
      • 离线计算需求:对计算效率要求就没那么高了,一般能在小时级别完成链路数据的聚合计算即可,一般用作数据汇总统计
        • 针对离线数据处理,一般通过运行 MapReduce 或者 Spark 批处理程序来对链路数据进行离线计算,存储一般使用 Hive
    • 数据展示层,负责数据的图形化展示
      • 调用链路图
      • 调用拓扑图

09丨微服务治理的手段有哪些?

  • gt9:有哪些服务治理手段?
    • 节点管理
      • 服务调用失败的两类原因
        • 服务提供者自身出现问题,如服务器宕机、进程意外退出等
        • 网络问题,如服务提供者、注册中心、服务消费者这三者任意两者之间的网络出现问题
      • 两种管理手段
        • 注册中心主动摘除机制
        • 服务消费者摘除机制
    • 负载均衡
      • 随机算法
      • 轮询算法
      • 最少活跃调用算法
      • 一致性 Hash 算法
    • 服务路由
      • 路由规则,就是通过一定的规则如条件表达式或者正则表达式来限定服务节点的选择范围
      • 制定路由规则的两个原因
        • 业务存在灰度发布的需求
        • 多机房就近访问的需求
      • 路由规则的两种配置方式
        • 静态配置
        • 动态配置
    • 服务容错:对服务调用失败的情况,常用的几种自动恢复的手段
      • FailOver:失败自动切换。服务消费者发现调用失败或者超时后,自动从可用的服务节点列表总选择下一个节点重新发起调用,也可以设置重试的次数。这种策略要求服务调用的操作必须是幂等的,也就是说无论调用多少次,只要是同一个调用,返回的结果都是相同的,一般适合服务调用是读请求的场景
      • FailCache:失败缓存。就是服务消费者调用失败或者超时后,不立即发起重试,而是隔一段时间后再次尝试发起调用。比如后端服务可能一段时间内都有问题,如果立即发起重试,可能会加剧问题,反而不利于后端服务的恢复。如果隔一段时间待后端节点恢复后,再次发起调用效果会更好
      • FailBack:失败通知。就是服务消费者调用失败或者超时后,不再重试,而是根据失败的详细信息,来决定后续的执行策略。比如对于非幂等的调用场景,如果调用失败后,不能简单地重试,而是应该查询服务端的状态,看调用到底是否实际生效,如果已经生效了就不能再重试了;如果没有生效可以再发起一次调用
      • FailFast:快速失败。就是服务消费者调用一次失败后,不再重试。实际在业务执行时,一般非核心业务的调用,会采用快速失败策略,调用失败后一般就记录下失败日志就返回了