服务化的关键是服务治理。

服务发现、负载均衡、限流、熔断、超时、重试、服务追踪。

  4.1 服务发现

    如果服务少,可以通过硬编码或配置文件提供服务地址。但是面对大量服务实例和频繁的上线部署,服务之间如果想知道彼此的服务地址和运行状态,这时候就需要服务发现组件来实现。

    4.1.1 服务发现概述

      使用一个注册中心来记录分布式系统中全部服务信息,以便让其他服务能快速找到这些已经注册的服务。要尽量做到高可用。

服务注册、服务查找、服务健康检查和服务变更通知等关键功能。

      可以通过服务名称来查找和使用服务,而不需要提供网络地址和端口号。

DNS可以说是最早的服务发现实例。

      微服务更新、发布频繁,并且常根据负载情况进行弹性伸缩,因此微服务IP地址变化是常态。

      服务发现基本机制:

  • 名称、IP地址、访问端口以及其他服务的元数据信息注册到注册中心。
  • 心跳探测时会将服务从注册中心剔除。
  • 定期拉取和事件通知两种方式。

    CAP定理

一致性(Consistency),可用性(Availability)、和分区容错性(Partition tolerance),中的两个,这就是CAP定理。

              分区容错性: 服务期间的通信即使在一定时间内无法保持畅通也不会影响系统继续运行。分布式系统中,分区容错性是必须的。

    对于分布式系统:AP和CP之间抉择;

    业界提供的用于服务发现的注册中心,本质上都满足AP或CP系统。

    高可用:

      为了保证注册中心的可用性,要多节点部署,而且还需要自愈和调整的能力。注册中心需要具备判断集群内节点健康状况的能力,可以将访问超时节点剔除,恢复的节点重新加入。

    4.1.2 Zookeeper

高可用(因为zk是一个集群,单点故障下仍然可以恢复)且具备严格顺序访问控制能力(一定要保证事件的因果顺序)的分布式协调系统,它是一个分布式数据一致性(保证分布式情况下,数据一致)的解决方案。

      zk提供了分布式通知和协调、配置管理、命名服务、主节点选举、分布式锁、分布式队列等解决方案。

分布式通知和协调被广泛用于服务发现(是服务发现领域历史最悠久、使用最广泛的产品)。

      ZK也是Hadoop和HBased分布式协调组件。

强一致性的产品,在集群发生分区时它会保证一致性而舍弃可用性,它是一个基于CP的系统。

ZK的每个服务端(Server)存储的数据都是一致的,存在唯一一个leader。客户端(Client)连接到任意一个ZK的服务端都能得到一致的最新数据副本。

      Paxos算法和Zab协议:

       zk是如何保证多个服务端的数据一致性呢:(就是说多个ZK server是为了高可用,但是如何保证多个server之间的数据一致性呢?在kafka中,kafka brokers就是clients,它们连到多个ZK server上,必须要保证这些ZK server数据一致。)

消息传递保持分布式节点之间的数据一致性。zab是专门针对ZK而设计的支持崩溃恢复的原子广播协议

       ZK的客户端是随机连接到zk集群的某个节点上的。read请求直接从连接的ZK server上读取;write请求,会由收到的server向leader server 提交事务,再由leader节点广播事务。只有超过半数的节点都写入成功,write请求才会被提交。

                    zab协议规定,消息传递需要遵循三个规则: 可靠递交、完全有序、和因果有序。

       在主节点崩溃的情况下,zab协议通过主节点快速选举、初始化、同步从节点、广播这几个阶段来保证数据的一致性和主节点选举的高效性:  

  • 要超过半数的节点投票就可以生效。不需要等所有节点都投票就可以选举出leader。
  •  阶段1: 初始化 -  从节点根据主节点新生成的“年号”更新它们的Epoch。
  •  阶段2: 同步从节点 - 从节点与主节点同步最近接收的事务提议。
  •  阶段3: 广播 - zk集群正式对外提供服务。

  核心概念

    1 集群角色:主节点(leader)、从节点(Follower)、和观察者(Observer ), 

服务器数量是奇数被认为是最佳实践( zk集群对外可用的必要条件是:超过半数的服务器正常工作。

          )  2台的宕机容忍度为0; 3台的宕机容忍度是1;4台的宕机容忍度也是1.

    2 会话:zk集群中,客户端与服务端是通过TCP建立长连接的。客户端和服务端通过心跳来保持连接。断了后可以在会话允许时间内再建立连接不影响工作。

    3 数据节点:zk中数据节点的英文名字是Znode,树形结构。

zk允许客户端在其感兴趣的Znode上注册监听器,该Znode的状态发生变更时,服务端将直接通知客户端处理。

    

              使用zk实现服务发现:

      每个服务启动时,在zk中注册。这是zk是一个注册中心的角色。服务使用方通过Znode快速查找相应的服务。如果服务宕机,那么这个服务节点会与ZK在超过会话时间后失效,那么这个Znode会被删除,而监听它们的客户端监听器得到宕机消息,进而得到最新的服务列表。

    客户端:zk提供了命令行(shell界面查询Znode数据)以及基于java和C的原生客户端,可以对ZK节点执行增删改查。

        可以通过java开发出具有服务发现功能的应用程序(包括连接ZK的API/注册服务的API/监听服务变化的API等)

        原生API太底层,需要实现的东西太多,一般不自己用。

                              有一些定三方的ZK客户端对原生API进行封装,比如ZkClient, Curator。

                         

              zk的优势与不足:

         zk是使用最为广泛的分布式协调组件,最大的优点是使用广泛。

  zk不是服务发现领域的最佳选择了,它的优势是选举和分布式锁等分布式强一致性的场景。

这是因为强一致性导致的不可用)。       

    4.1.3 Erueka: 与ZK不同的是,zk是基于CP的,Erueka是基于AP的。

          专门是Java语言的服务注册工具。

          Eureka比ZK更加适合服务发现,优先保证可用性,去中心化,服务集群由对等节点组成。

  4.2 负载均衡

               实现高可用、网络流量疏导、和扩容的重要手段。

    本质是通过算法将请求分摊到多个服务节点。

    4.2.1 服务端负载均衡

      负载均衡器会维护一个可用服务列表,并通过心跳检测将发生故障而无法及时响应心跳的服务移除。当负载均衡器接收到客户端请求时,通过轮询、权重或流量负载等负载均衡算法将请求转发到相应的服务器。

 传输层(第四层)负载均衡:基于IP地址和端口号进行负载均衡。

                   通过修改报文中的目标地址和端口号,转发请求。

四层负载均衡的性能强于七层负载均衡。

      应用层(第七层)负载均衡:基于URL和请求头。解析应用层的内容,转发请求。

                   七层的优势是充分理解应用层协议的意义,转发更加灵活。Nginx是七层的。

 

      服务端负载均衡的:

                                                 优势:对业务开发无侵入性;不影响应用代码。

                                            缺点:服务端负载均衡器是整个系统处理的瓶颈。

                                                       另外需要经过负载均衡器进行转发,效率低。

      服务端负载均衡多用于前端与后端交互、应用与数据库交互等场景。

      对于应用后端服务之间的调用,还是通过客户端负载均衡实现的方案居多。

    4.2.2 客户端负载均衡

      与服务端负载均衡的区别是,客户端来选择连接到哪个服务器,而不是由客户端连接到一个服务端再由服务端分发请求。

      优点:由客户端内部程序实现,并且直接连到服务端,而不是经过中间负载均衡器转发。

                 绕过了中心化的负载均衡和代理节点,不用考虑中心节点的高可用。

      缺点: 应用程序更加复杂。

         无法做到异构语言之间的负载均衡透明化。

         客户端和服务端的连接多。

些都是侵入式治理方案)。

      Ribbon提供了客户端的负载均衡算法,并可以与服务发现和注册中心(Eureka)有效的整合到一起(Ribbon会通过Eureka注册中心获取服务列表)。另外,Ribboon还提供了连接超时和重试的能力。

      Ribbon提供了五个核心接口:

  •   1 ILoadBalancer: 
  •   2 IRule:  负载均衡规则 :并发请求最小优先/ 过滤掉总失败的/ 根据响应时间/ 重试 / 轮询 / 随机 /  衡量性能和可用性。
  •   3 IPing:   定义与服务端的通信方式, 判断服务是否存在
  •   4 ServerList:  服务器对象的集合
  •  5 ServerListFilter: 

               

 

  4.3 限流

    保护服务不会被突然的流量洪峰冲垮。对一个时间窗口内的请求流量进行限速来实施对系统的保护。一旦达到限速阈值,则进入限流的处理流程:

  •  拒绝服务: 定向到错误页面,或返回失败。
  •  排队等待:将请求放入队列,等有时间再处理,客户端通常有超时等待时间。适用于 “秒杀”或抢购。
  •  应用降级:提供默认行为或数据,比如默认显示无任何评论、库存有货。

    4.3.1 限流算法

      计数器限流算法: 统计一段时间窗口之内的请求数量来进行限流。

      漏桶算法:容量固定的桶,桶底有一个洞,入桶速度任意,但是出桶速度固定。这个方法主要是控制其他系统的回调洪峰。

      令牌桶算法:使用存放固定数量的令牌的桶,按照固定速率向桶中添加令牌,如果有请求需要被处理,就从桶中取出令牌,当令牌用光了,就将请求放入队列或直接被拒绝。

其允许一定程度上的流量突发。

    4.3.2 限流实现方案

      客户端限流:只能控制单个客户端对服务端的访问。

      服务端限流:服务端需要根据自身的的状态进行限流保护。

             Tomcat 和 Dubbo都提供了过载保护。

             各种中间件和数据库产品有又限流配置。

             Zuul是开源的网管,有限流功能。

                                           zuul功能:

安全校验 -  

精确路由 - 

精准限流 - 

压力测试 - 

Metrics统计 - 

 zuul定义了四种过滤器:

     Pre:请求被路由前调用

     Routing:请求被路由到业务应用时调用

     post: 请求执行完调用

    error: 出错时调用

      接入端限流:通常使用负载均衡器实现。

             四层负载均衡和七层负载均衡器限流有很大的区别: 四层的只能无差别的限流,无法根据业务需要灵活的限流;

    4.3.3 限流的维度与粒度

       限流维度:IP地址、URL、用户令牌、用户组、设备信息等。

          限流粒度: 集群粒度、服务粒度、接口粒度。

  4.4 熔断

    4.4.1 概述: 

                         流量过载时,禁止客户端对服务端访问。比如当大量响应超时,熔断可以让对该服务的调用快速返回,防止目标服务宕机。

                   熔断可以防止雪崩。

    4.4.2 熔断器模式

  •  关闭状态:对应用无干涉,仅仅计算时间窗口内的失败次数。
  •  开启状态:对服务的访问立即返回错误。
  • 半开启状态:只允许少量请求调用服务,如果调用结果符合预期,就认为服务端问题已经修复,这样熔断器会关闭;否则认为熔断器仍然有问题,转换到开启状态,并重新计时。

    4.4.3 Hystrix

        提供了熔断、隔离、失效转义、缓存和监控等功能。