Dubbo面经

  • 1. Dubbo是什么?
  • 2. 为什么要用Dubbo?
  • 3. dubbo 能做什么?
  • 4. 默认使用的是什么通信框架,还有别的选择吗?
  • 5. 服务调用是阻塞的吗?
  • 6. Dubbo 有些哪些注册中心?
  • 7. 默认使用什么序列化框架,你知道的还有哪些?
  • 8. Dubbo内置了哪几种服务容器?
  • 9. Dubbo 核心的配置有哪些?(11个)
  • 10. Dubbo有哪几种集群容错方案,默认是哪种?(6种)
  • 11. Dubbo有哪几种负载均衡策略,默认是哪种?
  • 12. 你觉得用Dubbo好还是SpringCloud好?
  • 13. Dubbo服务调用超时问题怎么解决?
  • 14. Dubbo启动时如果依赖的服务不可用会怎样?
  • 15. Dubbo SPI 和 Java SPI 区别?
  • 16. Dubbo 支持分布式事务吗?
  • 17. Dubbo的管理控制台能做什么?
  • 18. Dubbo 服务暴露的过程?
  • 19. Dubbo服务引用过程?
  • 20. Dubbo服务调用过程?
  • 21. 当一个服务接口有多种实现时怎么做?
  • 22. 服务上线怎么兼容旧版本?
  • 23. dubbo服务注册与发现的流程?
  • 24. Dubbo 的整体架构设计有哪些分层?
  • 25. Dubbo Monitor 实现原理?
  • 26. Dubbo 中的 Invoker 概念了解么?
  • 26. Dubbo 的微内核架构了解吗?
  • 27. 服务提供者宕机后,注册中心会做什么?
  • 28. 监控中心的作用呢?
  • 29. 注册中心和监控中心都宕机的话,服务都会挂掉吗?
  • 30. Dubbo 架构中的核心角色有哪些?
  • <font color='red' size=5>===============Zookeeper ======================
  • 1. ZooKeeper 是什么?
  • 2. ZooKeeper可以实现哪些功能?
  • 3. Zookeeper 文件系统?
  • 4. Zookeeper 怎么保证主从节点的状态同步?
  • 5. 四种类型的数据节点 Znode?
  • 6. Zookeeper Watcher 机制 -- 数据变更通知?
  • 7. 客户端注册 Watcher 实现?
  • 8. 服务端处理 Watcher 实现?
  • 9. 客户端回调 Watcher?
  • 10. 一个客户端修改了某个节点的数据,其他客户端能够马上获取到这个最新数据吗?
  • 11. ZooKeeper 对节点的 watch 监听是永久的吗?为什么?
  • 12. ZooKeeper 中使用 watch 的注意事项有哪些?
  • 13. 能否收到每次节点变化的通知?
  • 14. 能否为临时节点创建子节点?
  • 15. 在 getChildren(String path, boolean watch)是注册了对节点子节点的变化,那么子节点的子节点变化能通知吗?
  • 16. 创建的临时节点什么时候会被删除,是连接一断就删除吗?延时是多少?
  • 17. ZooKeeper 集群中服务器之间是怎样通信的?
  • 18. ZooKeeper 是否会自动进行日志清理?如何进行日志清理?
  • 19. ZooKeeper 的监听原理是什么?
  • 20. 请说明 ZooKeeper 使用到的各个端口的作用?
  • 21. ZooKeeper 的部署方式有哪几种?集群中的角色有哪些?集群最少需要几台机器?
  • 22. CAP理论?
  • 23. BASE理论?
  • 24. Paxos 算法?
  • 25. ZAB 协议
  • 26. raft协议
  • 27. 2PC(两阶段提交)
  • 28. 3PC(phase-commit)(三阶段提交)
  • 29. Zookeeper数据模型
  • 30. Zookeeper会话
  • 31. ACL
  • 32. Watcher机制
  • 33. 选主
  • 34. zookeeper实现 分布式锁
  • 35. zookeeper实现 共享锁和独占锁
  • 36. 命名服务
  • 37. 集群管理和注册中心


=======================Dubbo ======================

1. Dubbo是什么?

  • Dubbo 是一个分布式、高性能、透明化的 RPC 服务框架,提供服务自动注册、自动发现等高效服务治理方案。RPC 指的是远程调用协议,也就是说两个服务器交互数据。

2. 为什么要用Dubbo?

  • 随着服务化的进一步发展,服务越来越多,服务之间的调用和依赖关系也越来越复杂,诞生了面向服务的架构体系(SOA)。
  • 也因此衍生出了一系列相应的技术,如对服务提供、服务调用、连接处理、通信协议、
    序列化方式、服务发现、服务路由、日志输出等行为进行封装的服务框架。
    就这样为分布式系统的服务治理框架就出现了,Dubbo 也就这样产生了。

3. dubbo 能做什么?

  1. 透明化的远程方法调用,就像调用本地方法一样调用远程方法,只需简单配置,没有任何 API 侵入。
  2. 软负载均衡及容错机制,可在内网替代 F5 等硬件负载均衡器,降低成本,减少单点。
  3. 服务自动注册与发现,不再需要写死服务提供方地址,注册中心基于接口名查询服务提供者的 IP 地址,并且能够平滑添加或删除服务提供者。
  4. Dubbo采用全Spring配置方式,透明化接入应用,对应用没有任何API侵入,只需用Spring加载Dubbo的配置即可,Dubbo基于Spring的Schema扩展进行加载。

4. 默认使用的是什么通信框架,还有别的选择吗?

  • Dubbo 默认使用 Netty 框架,也是推荐的选择,另外内容还集成有Mina、Grizzly。

5. 服务调用是阻塞的吗?

  • 默认是阻塞的,可以异步调用,没有返回值的可以这么做。
    Dubbo 是基于 NIO 的非阻塞实现并行调用,客户端不需要启动多线程即可完成并行
    调用多个远程服务,相对多线程开销较小,异步调用会返回一个 Future 对象。

6. Dubbo 有些哪些注册中心?

  • Nacos注册中心:Nacos 是 Dubbo 生态系统中重要的注册中心实现。
  • Zookeeper 注册中心: 基于分布式协调系统 Zookeeper 实现,采用Zookeeper 的 watch 机制实现数据变更;(官方推荐)
  • Multicast 注册中心: Multicast 注册中心不需要任何中心节点,只要广播地址,就能进行服务注册和发现。基于网络中组播传输实现;
  • Redis 注册中心: 基于 redis 实现,采用 key/Map 存储,住 key 存储服务名和类型,Map 中 key 存储服务 URL,value 服务过期时间。基于 redis 的发布/订阅模式通知数据变更;
  • Simple 注册中心:一个普通的 Dubbo 服务,可以减少第三方依赖,使整体通讯方式一致,不支持集群

7. 默认使用什么序列化框架,你知道的还有哪些?

  • Dubbo内部的序列化默认实现是用hessian2的序列化框架实现,同时叶预留SPI的扩展点给开发者去实现。

Dubbo 设置 Zookeeper的timeourt dubbo,zookeeper_服务调用

8. Dubbo内置了哪几种服务容器?

  • Spring Container
  • Jetty Container
  • Log4j Container

9. Dubbo 核心的配置有哪些?(11个)

配置

配置说明

dubbo:service

服务配置

dubbo:reference

引用配置

dubbo:protocol

协议配置

dubbo:application

应用配置

dubbo:module

模块配置

dubbo:registry

注册中心配置

dubbo:monitor

监控中心配置

dubbo:provider

提供方配置

dubbo:consumer

消费方配置

dubbo:method

方法配置

dubbo:argument

参数配置

10. Dubbo有哪几种集群容错方案,默认是哪种?(6种)

集群容错方案

说明

Failover Cluster

失败自动切换,自动重试其它服务器(默认

Failfast Cluster

快速失败,立即报错,只发起一次调用

Failsafe Cluster

失败安全,出现异常时,直接忽略

Failback Cluster

失败自动恢复,记录失败请求,定时重发

Forking Cluster

并行调用多个服务器,只要一个成功即返回

Broadcast Cluster

广播逐个调用所有提供者,任意一个报错则报错

11. Dubbo有哪几种负载均衡策略,默认是哪种?

  • 我们的系统中的某个服务的访问量特别大,我们将这个服务部署在了多台服务器上,当客户端发起请求的时候,多台服务器都可以处理这个请求。那么,如何正确选择处理该请求的服务器就很关键。假如,你就要一台服务器来处理该服务的请求,那该服务部署在多台服务器的意义就不复存在了。负载均衡就是为了避免单个服务器响应同一请求,容易造成服务器宕机、崩溃等问题,我们从负载均衡的这四个字就能明显感受到它的意义。
  • 在集群负载均衡时,Dubbo 提供了多种均衡策略,默认为 random 随机调用。我们还可以自行扩展负载均衡策略(参考Dubbo SPI机制)
  • Random LoadBalance: 随机选取提供者策略,有利于动态调整提供者权重。截面碰撞率高,调用次数越多,分布越均匀;
  • RoundRobin LoadBalance: 轮循选取提供者策略,平均分布,但是存在请求累积的问题;
  • LeastActive LoadBalance: 最少活跃调用策略,Dubbo 就认为谁的活跃数越少,谁的处理速度就越快,性能也越好,这样的话,我就优先把请求给活跃数少的服务提供者处理。
  • ConstantHash LoadBalance: 一致性 Hash 策略,使相同参数请求总是发到同一提供者,一台机器宕机,可以基于虚拟节点,分摊至其他提供者,避免引起提供者的剧烈变动;

12. 你觉得用Dubbo好还是SpringCloud好?

  • 没有好坏,只有适合不适合。

dubbo的优势

  • 单一应用架构,当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。此时,用于简化增删改查工作量的 数据访问框架(ORM)是关键。
  • 垂直应用架构,当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率。此时,用于加速前端页面开发的 Web框架(MVC)是关键。
  • 分布式服务架构,当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的 分布式服务框架(RPC)是关键。
  • 流动计算架构当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。此时,用于提高机器利用率的 资源调度和治理中心(SOA)是关键。

SpringCloud优势

  1. 约定优于配置
  2. 开箱即用、快速启动
  3. 适用于各种环境
  4. 轻量级的组件
  5. 组件支持丰富,功能齐全

Dubbo

Spring Cloud

服务注册中心

Zookeeper

Spring Cloud Netflix Eureka

服务调用方式

RPC

REST API

服务网关


Spring Cloud Netflix Zuul

断路器

不完善

Spring Cloud Netflix Hystrix

分布式配置


Spring Cloud Config

服务跟踪


Spring Cloud Sleuth

消息总线


Spring Cloud Bus

数据流


Spring Cloud Stream

批量任务


Spring Cloud Task

13. Dubbo服务调用超时问题怎么解决?

  • dubbo在调用服务不成功时,默认是会重试两次的。这样在服务端的处理时间超过了设定的超时时间时,就会有重复请求,比如在发邮件时,可能就会发出多份重复邮件,执行注册请求时,就会插入多条重复的注册数据,那么怎么解决超时问题呢?如下
  1. 对于核心的服务中心,去除dubbo超时重试机制,并重新评估设置超时时间。
  2. 业务处理代码必须放在服务端,客户端只做参数验证和服务调用,不涉及业务流程处理
<!-- 延迟到Spring初始化完成后,再暴露服务,服务调用超时设置为6秒,超时不重试-->    
   <dubbo:provider delay="-1" timeout="6000" retries="0"/>

14. Dubbo启动时如果依赖的服务不可用会怎样?

  • Dubbo缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,默认check=“true”,可以通过 check=“false” 关闭检查。

15. Dubbo SPI 和 Java SPI 区别?

JDK SPI

  • JDK 标准的 SPI 会一次性加载所有的扩展实现,如果有的扩展吃实话很耗时,但也没
    用上,很浪费资源。
  • 所以只希望加载某个的实现,就不现实了
DUBBO SPI

Dubbo 设置 Zookeeper的timeourt dubbo,zookeeper_Cloud_02

  • SPI(Service Provider Interface) 机制被大量用在开源项目中,它可以帮助我们动态寻找服务/功能(比如负载均衡策略)的实现。
  • SPI 的具体原理是这样的:我们将接口的实现类放在配置文件中,我们在程序运行过程中读取配置文件,通过反射加载实现类。这样,我们可以在运行的时候,动态替换接口的实现类。和 IoC 的解耦思想是类似的。
  • Java 本身就提供了 SPI 机制的实现。不过,Dubbo 没有直接用,而是对 Java原生的 SPI机制进行了增强,以便更好满足自己的需求。
  1. 对 Dubbo 进行扩展,不需要改动 Dubbo 的源码
  2. 延迟加载,可以一次只加载自己想要加载的扩展实现。
  3. 增加了对扩展点 IOC 和 AOP 的支持,一个扩展点可以直接 setter 注入其它扩
    展点。
  4. Dubbo 的扩展机制能很好的支持第三方 IoC 容器,默认支持 Spring Bean。

16. Dubbo 支持分布式事务吗?

  • 目前暂时不支持,可与通过 tcc-transaction 框架实现
  • 介绍:tcc-transaction 是开源的 TCC 补偿性分布式事务框架
  • TCC-Transaction 通过 Dubbo 隐式传参的功能,避免自己对业务代码的入侵。

17. Dubbo的管理控制台能做什么?

  • 管理控制台主要包含:路由规则,动态配置,服务降级,访问控制,权重调整,负载均衡,等管理功能。

18. Dubbo 服务暴露的过程?

  • 服务转化成Invoker -> Invoker转化成Exporter -> Transporter使用具体的Server启动服务监听端口 -> 使用具体的Registry将服务注册到注册中心。
  • 开始暴露服务,调用ServiceConfig的export方法导出服务,ServiceConfig使用ProxyFactory将我们要暴露的服务转化成一个Invoker。服务转化成Invoker后,需要通过具体的协议(比如Dubbo)将Invoker转化成Exporter(比如DubboExporter)。Exporter中使用Transporter来初始化一个具体的Server(比如Netty),并绑定服务端口,此时服务就被暴露出去了。服务暴露之后会调用具体的Registry(比如Zookeeper)将服务注册到注册中心去。

代码的流程来看大致可以分为三个步骤

  1. 第一步是检测配置,如果有些配置空的话会默认创建,并且组装成 URL 。
  2. 第二步是暴露服务,包括暴露到本地的服务和远程的服务
  3. 第三步是注册服务至注册中心。

对象构建转换的角度看可以分为两个步骤。

  • 第一步是将服务实现类转成 Invoker。(ServiceBean -> Invoker)
  • 第二步是将 Invoker 通过具体的协议转换成 Exporter。(Invoker -> Exporter)
  • Dubbo 设置 Zookeeper的timeourt dubbo,zookeeper_服务调用_03

  • 服务转化成Invoker -> Invoker转化成Exporter -> Transporter使用具体的Server启动服务监听端口 -> 使用具体的Registry将服务注册到注册中心。
  • 开始暴露服务,调用ServiceConfig的export方法导出服务,ServiceConfig使用ProxyFactory将我们要暴露的服务转化成一个Invoker。服务转化成Invoker后,需要通过具体的协议(比如Dubbo)将Invoker转化成Exporter(比如DubboExporter)。Exporter中使用Transporter来初始化一个具体的Server(比如Netty),并绑定服务端口,此时服务就被暴露出去了。服务暴露之后会调用具体的Registry(比如Zookeeper)将服务注册到注册中心去。

19. Dubbo服务引用过程?

服务的引入时机有两种,第一种是饿汉式,第二种是懒汉式。

  • 饿汉式是通过实现 Spring 的InitializingBean接口中的 afterPropertiesSet方法,容器通过调用 ReferenceBean的 afterPropertiesSet方法时引入服务。
  • 懒汉式是只有当这个服务被注入到其他类中时启动引入流程,也就是说用到了才会开始服务引入。
  • 默认情况下,Dubbo 使用懒汉式引入服务,如果需要使用饿汉式,可通过配置 dubbo:reference 的 init 属性开启。

服务的引入又分为了三种

  • 第一种是本地引入
  • 第二种是直接连接引入远程服务
  • 第三种是通过注册中心引入远程服务。
  • Dubbo 设置 Zookeeper的timeourt dubbo,zookeeper_服务调用_04

  • 本地引入走 injvm 协议(当然你要是 scope = remote 就没本地引用了),因为存在一个服务端既是 Provider 又是 Consumer 的情况,然后有可能自己会调用自己的服务,因此就弄了一个本地引入,这样就避免了远程网络调用的开销。
  • 直连远程引入服务,这个其实就是平日测试的情况下用用,不需要启动注册中心,由 Consumer 直接配置写死 Provider 的地址,然后直连即可。
  • 注册中心引入远程服务,这个就是重点了,Consumer 通过注册中心得知 Provider 的相关信息,然后进行服务的引入,这里还包括多注册中心,同一个服务多个提供者的情况,如何抉择如何封装,如何进行负载均衡、容错并且让使用者无感知,这就是个技术活。

Dubbo 设置 Zookeeper的timeourt dubbo,zookeeper_Cloud_05

  • 服务订阅 -> 服务转化成Invoker -> Transporter使用具体的Client启动服务准备连接 -> 使用Cluster并继续初始化Invoker -> 封装成一个代理返回。
  • 开始引用服务,调用ReferenceConfig的get方法引用服务,ReferenceConfig调用RegistryProtocol并使用具体的Registry(比如Zookeeper)来订阅服务,Registry会通知Directory开始引用服务(异步),也就是将要引用的服务转化成一个Invoker。Directory会使用具体的Protocol(如Dubbo)将引用的服务转化成一个Invoker。Invoker中使用Transporter来初始化一个具体的Client(比如Netty)用来准备和服务端提供者进行通信。RegistryProtocol调用Cluster的合并方法来初始化Invoker,然后ReferenceConfig在Invoker生成之后返回一个服务的代理。

20. Dubbo服务调用过程?

  • 服务调用过程分为两部分:服务消费者调用服务服务提供者接受服务请求

服务消费者Consumer调用服务

  • 获取到代理 -> 调用Invoker -> Exchange调用远程服务
  • 服务开始调用,首先获取到在服务引用过程中生成的代理,获取到代理后先执行一些过滤器链,比如:缓存、mock等等。接下来会根据Cluster来选择一个具体的Invoker,比如:failover、failsave、failfast、failback、forking、broadcast等,同时使用Directory从Registry中获取所有的invokers,然后使用LoadBalance(random、roundRobin、leastActive、consistentHash)选中具体调用的服务。选中服务之后会先执行过滤器链,再使用具体的Protocol(比如DubboProtocol)调用Transporter并使用具体的Client(比如Netty)来进行服务的调用。发送的请求会进行Codec编码和Serialzation序列化。

服务提供者Provider接受服务请求

  • 服务提供者接收到请求后,会进行反序列化和Decodec解码,然后从线程池中获取一个线程交给具体的Server(比如Netty)进行处理,然后会交给具体的Protocol(比如Dubbo)来根据参数获取具体的Exporter,继续执行一系列的过滤器链,然后使用ProxyFactory来获取具体的Invoker(比如Dubbo),Invoker就会调用真正的服务实现类,然后将结果返回。

21. 当一个服务接口有多种实现时怎么做?

  • 针对每个服务提供者一个分组,以实现区分同一接口的不同实现类

22. 服务上线怎么兼容旧版本?

  • 可以用版本号(version)过渡,多个不同版本的服务注册到注册中心,版本号不同的服务相互间不引用。这个和服务分组的概念有一点类似。

23. dubbo服务注册与发现的流程?

Dubbo 设置 Zookeeper的timeourt dubbo,zookeeper_负载均衡_06

  1. 服务容器Container负责启动,加载,运行服务提供者。必须。
  2. 服务提供者Provider在启动时,向注册中心注册自己提供的服务。必须。
  3. 服务消费者Consumer在启动时,向注册中心订阅自己所需的服务。必须。
  4. 注册中心Registry返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。非必须。
  5. 服务消费者Consumer,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
  6. 服务消费者Consumer和提供者Provider,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心Monitor。

24. Dubbo 的整体架构设计有哪些分层?

Dubbo 设置 Zookeeper的timeourt dubbo,zookeeper_Cloud_07

  • 接口服务层(Service):该层与业务逻辑相关,根据 provider 和 consumer 的业务设计对应的接口和实现
  • 配置层(Config):对外配置接口,以 ServiceConfig 和 ReferenceConfig 为中心
  • 服务代理层(Proxy):调用远程方法像调用本地的方法一样简单的一个关键,真实调用过程依赖代理类,以 ServiceProxy 为中心。
  • 服务注册层(Registry):封装服务地址的注册和发现,以服务 URL 为中心,扩展接口为 RegistryFactory、Registry、RegistryService
  • 路由层(Cluster):封装多个提供者的路由和负载均衡,并桥接注册中心,以Invoker 为中心,扩展接口为 Cluster、Directory、Router 和 LoadBlancce
  • 监控层(Monitor):RPC 调用次数和调用时间监控,以 Statistics 为中心,扩展接口为 MonitorFactory、Monitor 和 MonitorService
  • 远程调用层(Protocal):封装 RPC 调用,以 Invocation 和 Result 为中心,扩展接口为 Protocal、Invoker 和 Exporter
  • 信息交换层(Exchange):封装请求响应模式,同步转异步。以 Request 和Response 为中心,扩展接口为 Exchanger、ExchangeChannel、ExchangeClient 和 ExchangeServer
  • 网络传输层(Transport):抽象 mina 和 netty 为统一接口,以 Message 为中心,扩展接口为 Channel、Transporter、Client、Server 和 Codec
  • 数据序列化层(Serialize):可复用的一些工具,扩展接口为 Serialization、ObjectInput、ObjectOutput 和 ThreadPool

25. Dubbo Monitor 实现原理?

  • Consumer 端在发起调用之前会先走 filter 链;provider 端在接收到请求时也是先走 filter 链,然后才进行真正的业务逻辑处理。默认情况下,在 consumer 和 provider 的 filter 链中都会有 Monitorfilter。
  1. MonitorFilter 向 DubboMonitor 发送数据
  2. DubboMonitor 将数据进行聚合后(默认聚合 1min 中的统计数据)暂存到ConcurrentMap<Statistics, AtomicReference> statisticsMap,然后使用一个含有 3 个线程(线程名字:DubboMonitorSendTimer)的线程池每隔 1min 钟,调用 SimpleMonitorService 遍历发送 statisticsMap 中的统计数据,每发送完毕一个,就重置当前的 Statistics 的 AtomicReference
  3. SimpleMonitorService 将这些聚合数据塞入 BlockingQueue queue 中(队列大写为 100000)
  4. SimpleMonitorService 使用一个后台线程(线程名为:DubboMonitorAsyncWriteLogThread)将 queue 中的数据写入文件(该线程以死循环的形式来写)
  5. SimpleMonitorService 还会使用一个含有 1 个线程(线程名字:DubboMonitorTimer)的线程池每隔 5min 钟,将文件中的统计数据画成图表

26. Dubbo 中的 Invoker 概念了解么?

  • 简单来说,Invoker 就是 Dubbo 对远程调用的抽象。

Dubbo 设置 Zookeeper的timeourt dubbo,zookeeper_dubbo_08

  • 假如我们需要调用一个远程方法,我们需要动态代理来屏蔽远程调用的细节吧!我们屏蔽掉的这些细节就依赖对应的 Invoker 实现, Invoker 实现了真正的远程服务调用。

26. Dubbo 的微内核架构了解吗?

  • 微内核架构包含两类组件:核心系统(core system) 和 插件模块(plug-in modules)。
  • Dubbo 设置 Zookeeper的timeourt dubbo,zookeeper_服务调用_09

  • 核心系统提供系统所需核心能力,插件模块可以扩展系统的功能。因此, 基于微内核架构的系统,非常易于扩展功能。
  • 我们常见的一些IDE,都可以看作是基于微内核架构设计的。绝大多数 IDE比如IDEA、VSCode都提供了插件来丰富自己的功能。
  • 正是因为Dubbo基于微内核架构,才使得我们可以随心所欲替换Dubbo的功能点。比如你觉得Dubbo 的序列化模块实现的不满足自己要求,没关系啊!你自己实现一个序列化模块就好了啊!
  • 通常情况下,微核心都会采用 Factory、IoC、OSGi 等方式管理插件生命周期。Dubbo 不想依赖 Spring 等 IoC 容器,也不想自已造一个小的 IoC 容器(过度设计),因此采用了一种最简单的 Factory 方式管理插件 :JDK 标准的 SPI 扩展机制 (java.util.ServiceLoader)。

27. 服务提供者宕机后,注册中心会做什么?

  • 注册中心会立即推送事件通知消费者。

28. 监控中心的作用呢?

  • 监控中心负责统计各服务调用次数,调用时间等。

29. 注册中心和监控中心都宕机的话,服务都会挂掉吗?

  • 不会。两者都宕机也不影响已运行的提供者和消费者,消费者在本地缓存了提供者列表。注册中心和监控中心都是可选的,服务消费者可以直连服务提供者。
  • 启动dubbo时,消费者会从zk拉取注册的生产者的地址接口等数据,缓存在本地。每次调用时,按照本地存储的地址进行调用。但是在注册中心全部挂掉后增加新的提供者,则不能被消费者发现。

30. Dubbo 架构中的核心角色有哪些?

Dubbo 设置 Zookeeper的timeourt dubbo,zookeeper_服务调用_10

  • Container: 服务运行容器,负责加载、运行服务提供者。必须。
  • Provider: 暴露服务的服务提供方,会向注册中心注册自己提供的服务。必须。
  • Consumer: 调用远程服务的服务消费方,会向注册中心订阅自己所需的服务。必须。
  • Registry: 服务注册与发现的注册中心。注册中心会返回服务提供者地址列表给消费者。非必须。
  • Monitor: 统计服务的调用次数和调用时间的监控中心。服务消费者和提供者会定时发送统计数据到监控中心。 非必须。

===============Zookeeper ======================

1. ZooKeeper 是什么?

  • Zookeeper 作为一个分布式的服务框架,主要用来解决分布式集群中应用系统的一致性问题。
  • ZooKeeper 提供的服务包括:分布式消息同步和协调机制、服务器节点动态上下线统一配置管理、负载均衡、集群管理等。
  • ZooKeeper 提供基于类似于 Linux 文件系统的目录节点树方式的数据存储,空间。Zookeeper 并不是用来专门存储数据的,它的作用主要是用来维护和监控你存储的数据的状态变化,通过监控这些数据状态的变化,从而可以达到基于数据的集群管理
  • ZooKeeper 节点的数据上限是 1MB。
  • 我们可以认为 Zookeeper=文件系统+通知机制。

2. ZooKeeper可以实现哪些功能?

  • 数据发布/订阅
  • 负载均衡
  • 命名服务
  • 分布式协调/通知
  • 集群管理
  • Master 选举
  • 分布式锁
  • 分布式队列

Dubbo 设置 Zookeeper的timeourt dubbo,zookeeper_负载均衡_11

3. Zookeeper 文件系统?

  • Zookeeper 提供一个多层级的节点命名空间(节点称为 znode)。与文件系统不同的是,这些节点都可以设置关联的数据,而文件系统中只有文件节点可以存放数据而目录节点不行。
  • Zookeeper 为了保证高吞吐和低延迟,在内存中维护了这个树状的目录结构,这种特性使得 Zookeeper 不能用于存放大量的数据,每个节点的存放数据上限为1M。

4. Zookeeper 怎么保证主从节点的状态同步?

  • Zookeeper 的核心是原子广播机制,这个机制保证了各个 server 之间的同步。实现这个机制的协议叫做 Zab 协议。Zab 协议有两种模式,它们分别是恢复模式和广播模式。

恢复模式(选主)

  • 当服务启动或者在领导者Leader崩溃后,Zab就进入了恢复模式,当领导者Leader被选举出来,且大多数 server 完成了和 leader 的状态同步以后,恢复模式就结束了。状态同步保证了 leader 和 server 具有相同的系统状态。

广播模式(同步)

  • 一旦 leader 已经和多数的 follower 进行了状态同步后,它就可以开始广播消息了,即进入广播状态。这时候当一个 server 加入 ZooKeeper 服务中,它会在恢复模式下启动,发现 leader,并和 leader 进行状态同步。待到同步结束,它也参与消息广播。ZooKeeper 服务一直维持在 Broadcast 状态,直到 leader 崩溃了或者 leader 失去了大部分的 followers 支持。

5. 四种类型的数据节点 Znode?

PERSISTENT-持久节点

  • 除非手动删除,否则节点一直存在于 Zookeeper 上

EPHEMERAL-临时节点

  • 临时节点的生命周期与客户端会话绑定,一旦客户端会话失效(客户端与zookeeper 连接断开不一定会话失效),那么这个客户端创建的所有临时节点都会被移除。

PERSISTENT_SEQUENTIAL-持久顺序节点

  • 基本特性同持久节点,只是增加了顺序属性,节点名后边会追加一个由父节点维护的自增整型数字。

EPHEMERAL_SEQUENTIAL-临时顺序节点

  • 基本特性同临时节点,增加了顺序属性,节点名后边会追加一个由父节点维护的自增整型数字。

6. Zookeeper Watcher 机制 – 数据变更通知?

  • Zookeeper 允许客户端向服务端的某个 Znode 注册一个 Watcher 监听,当服务端的一些指定事件触发了这个 Watcher,服务端会向指定客户端发送一个事件通知来实现分布式的通知功能,然后客户端根据 Watcher 通知状态和事件类型做出业务上的改变。

工作机制:

  • (1)客户端注册 watcher
  • (2)服务端处理 watcher
  • (3)客户端回调 watcher

7. 客户端注册 Watcher 实现?

  1. 调用 getData()/getChildren()/exist()三个 API,传入 Watcher 对象
  2. 标记请求 request,封装 Watcher 到 WatchRegistration
  3. 封装成 Packet 对象,发服务端发送 request
  4. 收到服务端响应后,将 Watcher 注册到 ZKWatcherManager 中进行管理
  5. 请求返回,完成注册。

8. 服务端处理 Watcher 实现?

1. 服务端接收 Watcher 并存储

  • 接收到客户端请求,处理请求判断是否需要注册 Watcher,需要的话将数据节点的节点路径和 ServerCnxn(ServerCnxn 代表一个客户端和服务端的连接,实现了 Watcher 的 process 接口,此时可以看成一个 Watcher 对象)存储在WatcherManager 的 WatchTable 和 watch2Paths 中去。

2. Watcher 触发

  • 以服务端接收到 setData() 事务请求触发 NodeDataChanged 事件为例:
  1. 封装 WatchedEvent
  • 将通知状态(SyncConnected)、事件类型(NodeDataChanged)以及节点路径封装成一个 WatchedEvent 对象
  1. 查询 Watcher
  • 从 WatchTable 中根据节点路径查找 Watcher
  1. 没找到;说明没有客户端在该数据节点上注册过 Watcher
  2. 找到;提取并从 WatchTable 和 Watch2Paths 中删除对应 Watcher(从这里可以看出 Watcher 在服务端是一次性的,触发一次就失效了)

3. 调用 process 方法来触发 Watcher

  • 这里 process 主要就是通过 ServerCnxn 对应的 TCP 连接发送 Watcher 事件通知。

9. 客户端回调 Watcher?

  • 客户端 SendThread 线程接收事件通知,交由 EventThread 线程回调 Watcher。
  • 客户端的 Watcher 机制同样是一次性的,一旦被触发后,该 Watcher 就失效了。

10. 一个客户端修改了某个节点的数据,其他客户端能够马上获取到这个最新数据吗?

  • ZooKeeper 不能确保任何客户端能够获取(即 Read Request)到一样的数据,除非客户端自己要求,方法是客户端在获取数据之前调用 sync。通常情况下(这里所说的通常情况满足:1. 对获取的数据是否是最新版本不敏感,2. 一个客户端修改了数据,其它客户端是否需要立即能够获取最新数据),可以不关心这点。在其它情况下,最清晰的场景是这样:ZK 客户端 A 对 /my_test 的内容从 v1->v2, 但是 ZK 客户端 B 对 /my_test 的内容获取,依然得到的是 v1. 请注意,这个是实际存在的现象,当然延时很短。解决的方法是客户端 B 先调用 sync(), 再调用 getData()。

11. ZooKeeper 对节点的 watch 监听是永久的吗?为什么?

  • 不是。
  • 官方声明:一个 Watch 事件是一个一次性的触发器,当被设置了 Watch 的数据发生了改变的时候,则服务器将这个改变发送给设置了 Watch 的客户端,以便通知它们。为什么不是永久的,举个例子,如果服务端变动频繁,而监听的客户端很多情况下,每次变动都要通知到所有的客户端,这太消耗性能了。一般是客户端执行 getData(“/节点 A”,true),如果节点 A 发生了变更或删除,客户端会得到它的 watch 事件,但是在之后节点 A 又发生了变更,而客户端又没有设置 watch 事件,就不再给客户端发送。在实际应用中,很多情况下,我们的客户端不需要知道服务端的每一次变动,我只要最新的数据即可。

12. ZooKeeper 中使用 watch 的注意事项有哪些?

  1. Watches 通知是一次性的,必须重复注册.
  2. 发生 CONNECTIONLOSS 之后,只要在 session_timeout 之内再次连接上(即不发生
    SESSIONEXPIRED),那么这个连接注册的 watches 依然在。
  3. 对某个节点注册了 watch,但是节点被删除了,那么注册在这个节点上的 watches 都会被移除。
  4. 同一个 zk 客户端对某一个节点注册相同的 watch,只会收到一次通知。
  5. Watcher 对象只会保存在客户端,不会传递到服务端。

13. 能否收到每次节点变化的通知?

  • 如果节点数据的更新频率很高的话,不能。原因在于:当一次数据修改,通知客户端,客户端再次注册 watch,在这个过程中,可能数据已经发生了许多次数据修改,因此,千万不要做这样的测试:”数据被修改了 n 次,一定会收到 n 次通知”来测试 server 是否正常工作。

14. 能否为临时节点创建子节点?

  • ZooKeeper 中不能为临时节点创建子节点,如果需要创建子节点,应该将要创建子节点的节点创建为永久性节点。

15. 在 getChildren(String path, boolean watch)是注册了对节点子节点的变化,那么子节点的子节点变化能通知吗?

  • 不能通知。

16. 创建的临时节点什么时候会被删除,是连接一断就删除吗?延时是多少?

  • 连接断了之后,ZK 不会马上移除临时数据,只有当 SESSIONEXPIRED 之后,才会把这个会话建立的临时数据移除。因此,用户需要谨慎设置 Session_TimeOut。

17. ZooKeeper 集群中服务器之间是怎样通信的?

  • Leader 服务器会和每一个 Follower/Observer 服务器都建立 TCP 连接,同时为每个 F/O都创建一个叫做 LearnerHandler 的实体。LearnerHandler 主要负责 Leader 和 Follower/Observer 之间的网络通讯,包括数据同步,请求转发和 Proposal 提议的投票等。Leader 服务器保存了所有 Follower/Observer 的 LearnerHandler。

18. ZooKeeper 是否会自动进行日志清理?如何进行日志清理?

  • zk 自己不会进行日志清理,需要运维人员进行日志清理。

19. ZooKeeper 的监听原理是什么?

  • 在应用程序中,mian()方法首先会创建 zkClient,创建 zkClient 的同时就会产生两个进程,即Listener 进程(监听进程)和connect 进程(网络连接/传输进程),当zkClient 调用getChildren()等方法注册监视器时,connect 进程向 ZooKeeper 注册监听器,注册后的监听器位于ZooKeeper 的监听器列表中,监听器列表中记录了 zkClient 的 IP,端口号以及要监控的路径,一旦目标文件发生变化,ZooKeeper 就会把这条消息发送给对应的zkClient 的Listener()进程,Listener 进程接收到后,就会执行 process()方法,在 process()方法中针对发生的事件进行处理。

Dubbo 设置 Zookeeper的timeourt dubbo,zookeeper_Cloud_12

20. 请说明 ZooKeeper 使用到的各个端口的作用?

  • 2888:Follower 与 Leader 交换信息的端口。
  • 3888:万一集群中的 Leader 服务器挂了,需要一个端口来重新进行选举,选出一个新的Leader,而这个端口就是用来执行选举时服务器相互通信的端口。

21. ZooKeeper 的部署方式有哪几种?集群中的角色有哪些?集群最少需要几台机器?

  • ZooKeeper 的部署方式有单机模式和集群模式,集群中的角色有 Leader 和 Follower,集群最少 3(2N+1)台,根据选举算法,应保证奇数。

22. CAP理论?

  • C : Consistency 一致性,数据在多个副本之间似否能够保持一致的特性。
  • A: Availability 可用性,系统服务必须一直处于可用状态,对每个请求总是在指定的时间返回结果。
  • P:Partition tolerance 分区容错性,遇到分区网络故障时,仍能对外提供一致性和可用性的服务。

Dubbo 设置 Zookeeper的timeourt dubbo,zookeeper_dubbo_13

  • 不能同时满足3个要求,只能满足其中的两个。

23. BASE理论?

  • Basically Available(基本可用)、Soft state(软状态) 和 Eventuanlly consistent (最终一致性)3个短语的简写。
  • 基本可用:系统出现不可预知的故障时,允许损失部分可用性。
  • 弱(软)状态:数据的中间状态,并认为改状态存在不会一项系统整体可用性,允许不同节点数据副本数据同步过程中的延时。
  • 最终一致性:系统中所有数据副本,在一段时间的同步后,最终数据能够到一致性的状态。

24. Paxos 算法?

  • Paxos 算法是基于消息传递且具有高度容错特性的一致性算法,是目前公认的解决分布式一致性问题最有效的算法之一,其解决的问题就是在分布式系统中如何就某个值(决议)达成一致 。
  • 在 Paxos 中主要有三个角色,分别为 Proposer提案者、Acceptor表决者、Learner学习者。Paxos 算法和 2PC 一样,也有两个阶段,分别为 Prepare 和 accept 阶段。
  • 一句话解释就是:发起者将提议发到所有的接收者,包括自己,如果有超过半数获得批准,最终获得一致性的取值,且后序不允许更改。

具体的操作包括两个阶段一个是准备阶段,一个是提议者选择值阶段。

  1. prepare 阶段
  • Proposer提案者:负责提出 proposal,每个提案者在提出提案时都会首先获取到一个 具有全局唯一性的、递增的提案编号N,即在整个集群中是唯一的编号 N,然后将该编号赋予其要提出的提案,在第一阶段是只将提案编号发送给所有的表决者。
  • Acceptor表决者:每个表决者在 accept 某提案后,会将该提案编号N记录在本地,这样每个表决者中保存的已经被 accept 的提案中会存在一个编号最大的提案,其编号假设为 maxN。每个表决者仅会 accept 编号大于自己本地 maxN 的提案,在批准提案时表决者会将以前接受过的最大编号的提案作为响应反馈给 Proposer 。

Dubbo 设置 Zookeeper的timeourt dubbo,zookeeper_dubbo_14

  1. 提议者accept 阶段
  • 当一个提案被 Proposer 提出后,如果 Proposer 收到了超过半数的 Acceptor 的批准(Proposer 本身同意),那么此时 Proposer 会给所有的 Acceptor 发送真正的提案(你可以理解为第一阶段为试探),这个时候 Proposer 就会发送提案的内容和提案编号。
  • 表决者收到提案请求后会再次比较本身已经批准过的最大提案编号和该提案编号,如果该提案编号 大于等于 已经批准过的最大提案编号,那么就 accept 该提案(此时执行提案内容但不提交),随后将情况返回给 Proposer 。如果不满足则不回应或者返回 NO 。
  • Dubbo 设置 Zookeeper的timeourt dubbo,zookeeper_Cloud_15

paxos 算法的死循环问题

  • 比如说,此时提案者 P1 提出一个方案 M1,完成了 Prepare 阶段的工作,这个时候 acceptor 则批准了 M1,但是此时提案者 P2 同时也提出了一个方案 M2,它也完成了 Prepare 阶段的工作。然后 P1 的方案已经不能在第二阶段被批准了(因为 acceptor 已经批准了比 M1 更大的 M2),所以 P1 自增方案变为 M3 重新进入 Prepare 阶段,然后 acceptor ,又批准了新的 M3 方案,它又不能批准 M2 了,这个时候 M2 又自增进入 Prepare 阶段。。。
  • 就这样无休无止的永远提案下去,这就是 paxos 算法的死循环问题。

25. ZAB 协议

  • Zab协议 的全称是 Zookeeper Atomic Broadcast (Zookeeper原子广播)。
  • Zookeeper 是通过 Zab 协议来保证分布式事务的最终一致性。
  • Zab协议是为分布式协调服务Zookeeper专门设计的一种 支持崩溃恢复 的 原子广播协议 ,是Zookeeper保证数据一致性的核心算法。Zab借鉴了Paxos算法,但又不像Paxos那样,是一种通用的分布式一致性算法。它是特别为Zookeeper设计的支持崩溃恢复的原子广播协议。

ZAB 中的三个角色

  • Leader :集群中 唯一的写请求处理者 ,能够发起投票(投票也是为了进行写请求)。
  • Follower:能够接收客户端的请求,如果是读请求则可以自己处理,如果是写请求则要转发给 Leader 。在选举过程中会参与投票,有选举权和被选举权 。
  • Observer :就是没有选举权和被选举权的 Follower 。

Zab 协议的特性:

  • Zab 协议需要确保那些已经在 Leader 服务器上提交(Commit)的事务最终被所有的服务器提交。
  • Zab 协议需要确保丢弃那些只在 Leader 上被提出而没有被提交的事务。

Zab协议原理

  • Zab协议要求每个 Leader 都要经历三个阶段:发现,同步,广播。
  • 发现:要求zookeeper集群必须选举出一个 Leader 进程,同时 Leader 会维护一个 Follower 可用客户端列表。将来客户端可以和这些 Follower节点进行通信。
  • 同步:Leader 要负责将本身的数据与 Follower 完成同步,做到多副本存储。这样也是提现了CAP中的高可用和分区容错。Follower将队列中未处理完的请求消费完成后,写入本地事务日志中。
  • 广播:Leader 可以接受客户端新的事务Proposal请求,将新的Proposal请求广播给所有的 Follower。

26. raft协议

  • raft协议也有3种角色,leader整个集群中只有 Leader 可以处理 client 发送过来的请求,其他非 Leader 节点即使接收到请求也必须将其转发到 Leader 节点进行处理,follower类似于选民,完全被动;candidate候选者,参与选举leader。

整个过程包括两个阶段,选举和数据同步

  1. 选举阶段
  • 任何一个节点都能成为一个候选者Candidate,它向其他节点发出选自己的为leader的请求,其他节点同意,就返回Ok,包括自己如果有超过半数的同意,那就成为新的leader。如果两个候选者的票数相同,那就等待一段时间后,再重新选举leader
  1. 数据同步阶段
  • Raft中的事务消息是通过的RPC来完成的,通过心跳来维持。leader接收到事务数据后,同步给follower,follower当把数据写入磁盘文件之后,返回commit ok,当大多数都返回成功之后,在下一次心跳中会通知follower提交事务。

27. 2PC(两阶段提交)

  • 两阶段提交是一种保证分布式系统数据一致性的协议,现在很多数据库都是采用的两阶段提交协议来完成 分布式事务 的处理。
  • 在两阶段提交中,主要涉及到两个角色,分别是协调者和参与者。
  • 第一阶段:当要执行一个分布式事务的时候,事务发起者首先向协调者发起事务请求,然后协调者会给所有参与者发送 prepare 请求(其中包括事务内容)告诉参与者你们需要执行事务了,如果能执行我发的事务内容那么就先执行但不提交,执行后请给我回复。然后参与者收到 prepare 消息后,他们会开始执行事务(但不提交),并将 Undo 和 Redo 信息记入事务日志中,之后参与者就向协调者反馈是否准备好了。
  • 第二阶段:第二阶段主要是协调者根据参与者反馈的情况来决定接下来是否可以进行事务的提交操作,即提交事务或者回滚事务。
  • 比如这个时候 所有的参与者 都返回了准备好了的消息,这个时候就进行事务的提交,协调者此时会给所有的参与者发送 Commit 请求 ,当参与者收到 Commit 请求的时候会执行前面执行的事务的 提交操作 ,提交完毕之后将给协调者发送提交成功的响应。
  • 而如果在第一阶段并不是所有参与者都返回了准备好了的消息,那么此时协调者将会给所有参与者发送 回滚事务的 rollback 请求,参与者收到之后将会 回滚它在第一阶段所做的事务处理 ,然后再将处理情况返回给协调者,最终协调者收到响应后便给事务发起者返回处理失败的结果。

Dubbo 设置 Zookeeper的timeourt dubbo,zookeeper_dubbo_16

两阶段提交产生的问题

  • 单点故障问题,如果协调者挂了那么整个系统都处于不可用的状态了。
  • 阻塞问题,即当协调者发送 prepare 请求,参与者收到之后如果能处理那么它将会进行事务的处理但并不提交,这个时候会一直占用着资源不释放,如果此时协调者挂了,那么这些资源都不会再释放了,这会极大影响性能。
  • 数据不一致问题,比如当第二阶段,协调者只发送了一部分的 commit 请求就挂了,那么也就意味着,收到消息的参与者会进行事务的提交,而后面没收到的则不会进行事务提交,那么这时候就会产生数据不一致性问题。

28. 3PC(phase-commit)(三阶段提交)

  1. CanCommit阶段:协调者向所有参与者发送 CanCommit 请求,参与者收到请求后会根据自身情况查看是否能执行事务,如果可以则返回 YES 响应并进入预备状态,否则返回 NO 。
  2. PreCommit阶段:协调者根据参与者返回的响应来决定是否可以进行下面的 PreCommit 操作。如果上面参与者返回的都是 YES,那么协调者将向所有参与者发送 PreCommit 预提交请求,参与者收到预提交请求后,会进行事务的执行操作,并将 Undo 和 Redo 信息写入事务日志中 ,最后如果参与者顺利执行了事务则给协调者返回成功的响应。如果在第一阶段协调者收到了 任何一个 NO 的信息,或者 在一定时间内 并没有收到全部的参与者的响应,那么就会中断事务,它会向所有参与者发送中断请求(abort),参与者收到中断请求之后会立即中断事务,或者在一定时间内没有收到协调者的请求,它也会中断事务。
  3. DoCommit阶段:这个阶段其实和 2PC 的第二阶段差不多,如果协调者收到了所有参与者在 PreCommit 阶段的 YES 响应,那么协调者将会给所有参与者发送 DoCommit 请求,参与者收到 DoCommit 请求后则会进行事务的提交工作,完成后则会给协调者返回响应,协调者收到所有参与者返回的事务提交成功的响应之后则完成事务。若协调者在 PreCommit 阶段 收到了任何一个 NO 或者在一定时间内没有收到所有参与者的响应 ,那么就会进行中断请求的发送,参与者收到中断请求后则会 通过上面记录的回滚日志 来进行事务的回滚操作,并向协调者反馈回滚状况,协调者收到参与者返回的消息后,中断事务。

Dubbo 设置 Zookeeper的timeourt dubbo,zookeeper_Cloud_17

- 这里是 3PC 在成功的环境下的流程图,你可以看到 3PC 在很多地方进行了超时中断的处理,比如协调者在指定时间内为收到全部的确认消息则进行事务中断的处理,这样能 减少同步阻塞的时间

29. Zookeeper数据模型

  • zookeeper 数据存储结构与标准的 Unix 文件系统非常相似,都是在根节点下挂很多子节点(树型)。但是 zookeeper 中没有文件系统中目录与文件的概念,而是 使用了 znode 作为数据节点 。znode 是 zookeeper 中的最小数据单元,每个 znode 上都可以保存数据,同时还可以挂载子节点,形成一个树形化命名空间。
  • Dubbo 设置 Zookeeper的timeourt dubbo,zookeeper_负载均衡_18

  • 每个 znode 都有自己所属的 节点类型 和 节点状态。
  • 其中节点类型可以分为 持久节点、持久顺序节点、临时节点 和 临时顺序节点。
  • 持久节点:一旦创建就一直存在,直到将其删除。
  • 持久顺序节点:一个父节点可以为其子节点 维护一个创建的先后顺序 ,这个顺序体现在 节点名称 上,是节点名称后自动添加一个由 10 位数字组成的数字串,从 0 开始计数。
  • 临时节点:临时节点的生命周期是与 客户端会话 绑定的,会话消失则节点消失 。临时节点 只能做叶子节点 ,不能创建子节点。
  • 临时顺序节点:父节点可以创建一个维持了顺序的临时节点(和前面的持久顺序性节点一样)。
  • 节点状态中包含了很多节点的属性比如 czxid 、mzxid 等等,在 zookeeper 中是使用 Stat 这个类来维护的。下面我列举一些属性解释。
  • czxid:Created ZXID,该数据节点被 创建 时的事务ID。
  • mzxid:Modified ZXID,节点 最后一次被更新时 的事务ID。
  • ctime:Created Time,该节点被创建的时间。
  • mtime: Modified Time,该节点最后一次被修改的时间。
  • version:节点的版本号。
  • cversion:子节点 的版本号。
  • aversion:节点的 ACL 版本号。
  • ephemeralOwner:创建该节点的会话的 sessionID ,如果该节点为持久节点,该值为0。
  • dataLength:节点数据内容的长度。
  • numChildre:该节点的子节点个数,如果为临时节点为0。
  • pzxid:该节点子节点列表最后一次被修改时的事务ID,注意是子节点的 列表 ,不是内容。

30. Zookeeper会话

  • zk 客户端和服务端是通过 TCP 长连接 维持的会话机制,其实对于会话来说你可以理解为 保持连接状态 。
  • 在 zookeeper 中,会话还有对应的事件,比如 CONNECTION_LOSS 连接丢失事件 、SESSION_MOVED 会话转移事件 、SESSION_EXPIRED 会话超时失效事件 。

31. ACL

  • ACL 为 Access Control Lists ,它是一种权限控制。在 zookeeper 中定义了5种权限,它们分别为:
  • CREATE :创建子节点的权限。
  • READ:获取节点数据和子节点列表的权限。
  • WRITE:更新节点数据的权限。
  • DELETE:删除子节点的权限。
  • ADMIN:设置节点 ACL 的权限。

32. Watcher机制

  • Watcher 为事件监听器,是 zk 非常重要的一个特性,很多功能都依赖于它,它有点类似于订阅的方式,即客户端向服务端 注册 指定的 watcher ,当服务端符合了 watcher 的某些事件或要求则会 向客户端发送事件通知 ,客户端收到通知后找到自己定义的 Watcher 然后 执行相应的回调方法 。

33. 选主

  • 让其他不是 master 的节点监听节点的状态 ,比如说我们监听这个临时节点的父节点,如果子节点个数变了就代表 master 挂了,这个时候我们 触发回调函数进行重新选举 ,或者我们直接监听节点的状态,我们可以通过节点是否已经失去连接来判断 master 是否挂了等等。

Dubbo 设置 Zookeeper的timeourt dubbo,zookeeper_负载均衡_19

  • 总的来说,我们可以完全 利用 临时节点、节点状态 和 watcher 来实现选主的功能,临时节点主要用来选举,节点状态和watcher 可以用来判断 master 的活性和进行重新选举。

34. zookeeper实现 分布式锁

  • 分布式锁的实现方式有很多种,比如 Redis 、数据库 、zookeeper 等。
  • zk在高并发的情况下保证节点创建的全局唯一性。
  • 首先肯定是如何获取锁,因为创建节点的唯一性,我们可以让多个客户端同时创建一个临时节点,创建成功的就说明获取到了锁 。然后没有获取到锁的客户端也像上面选主的非主节点创建一个 watcher 进行节点状态的监听,如果这个互斥锁被释放了(可能获取锁的客户端宕机了,或者那个客户端主动释放了锁)可以调用回调函数重新获得锁。
  • zk 中不需要向 redis 那样考虑锁得不到释放的问题了,因为当客户端挂了,节点也挂了,锁也释放了

35. zookeeper实现 共享锁和独占锁

  • 这个时候我规定所有创建节点必须有序,当你是读请求(要获取共享锁)的话,如果 没有比自己更小的节点,或比自己小的节点都是读请求 ,则可以获取到读锁,然后就可以开始读了。若比自己小的节点中有写请求 ,则当前客户端无法获取到读锁,只能等待前面的写请求完成。
  • 如果你是写请求(获取独占锁),若 没有比自己更小的节点 ,则表示当前客户端可以直接获取到写锁,对数据进行修改。若发现 有比自己更小的节点,无论是读操作还是写操作,当前客户端都无法获取到写锁 ,等待所有前面的操作完成。

36. 命名服务

  • Zookeeper 是通过 树形结构 来存储数据节点的,那也就是说,对于每个节点的 全路径,它必定是唯一的,我们可以使用节点的全路径作为命名方式了。而且更重要的是,路径是我们可以自己定义的,这对于我们对有些有语意的对象的ID设置可以更加便于理解。

37. 集群管理和注册中心

  • Zookeeper 天然支持的 watcher 和 临时节点能很好的实现这些需求。我们可以为每条机器创建临时节点,并监控其父节点,如果子节点列表有变动(我们可能创建删除了临时节点),那么我们可以使用在其父节点绑定的 watcher 进行状态监控和回调。

Dubbo 设置 Zookeeper的timeourt dubbo,zookeeper_Cloud_20

  • 至于注册中心也很简单,我们同样也是让 服务提供者 在 zookeeper 中创建一个临时节点并且将自己的 ip、port、调用方式 写入节点,当 服务消费者 需要进行调用的时候会 通过注册中心找到相应的服务的地址列表(IP端口什么的) ,并缓存到本地(方便以后调用),当消费者调用服务时,不会再去请求注册中心,而是直接通过负载均衡算法从地址列表中取一个服务提供者的服务器调用服务。
  • 服务提供者的某台服务器宕机或下线时,相应的地址会从服务提供者地址列表中移除。同时,注册中心会将新的服务地址列表发送给服务消费者的机器并缓存在消费者本机

Dubbo 设置 Zookeeper的timeourt dubbo,zookeeper_服务调用_21