Zookeeper经典应用场景实战

Zookeeper经典应用场景实战

ZK的不足之处

  • watcher检测是一次性的,每次触发之后都需要重新注册
  • 会话超时之后没有实现重连机制
  • 异常处理繁琐
  • 仅提供byte数组类型的接口,没提供java实体序列化级接口
  • 创建节点时如果抛出异常,需要自行检查节点是否存在
  • 无法实现级联删除节点

ZK在分布式命名服务中的实战

分布式API目录

  • 借助于ZK的树形分成结构为分布式系统中各种API接口服务的名称、链接地址,提供类似JNDI(Java命名和目录接口)中的文件系统的功能
  • 在Dubbo中使用ZK维护全局服务接口API的地址列表,大致思路如下
    • 服务提供者启动时,向ZK上的指定节点写入自己的API地址
    • 服务消费者启动时,订阅节点下的服务提供者的URL地址获取所有服务提供者的API

分布式节点命名

  • 常规情况可以采用DB的自增特性、机器的MAC地址、IP进行分布式节点命名维护
  • 使用ZK的持久顺序节点的顺序特性进行分布式节点命名维护,基本流程如下
    • 启动节点服务,连接ZK,检查命名服务根节点是否存在,如果不存在,就创建系统的根节点
    • 在根节点下创建一个临时顺序节点,取回该节点的编号把它作为分布式系统中的节点ID,如果临时节点太多,可以根据需要删除临时顺序节点

分布式ID生成器

  • 在分布式环境下,全局唯一ID系统需要满足全局唯一、高可用
  • 常见实现方案
    • Java的UUID
    • 基于Redis的原子操作incr和incrby生产更全局唯一ID
    • 基于Twitter的雪花算法
      • 4个部分
        • 首位占用1bit,值为0,无实际作用
        • 时间戳占用41bit,精确到ms,可以容纳约69年的时间
        • 工作机器id占用10bit,最多可以容纳1024个节点
        • 序列号占用12bit,这个值在同一ms同一节点上从0开始不断累加,最多可以累加到4095,在工作节点1024个满载情况下,同一毫秒最多可生成1024 * 4095个ID,满足绝大多数并发场景
      • 优点
        • 生成ID不依赖于数据库,完全在内生成,高性能、高可用性
        • 容量大,每秒可以生成几百万个ID
        • ID呈递增,后续插入数据库索引树,性能高
      • 缺点
        • 依赖于系统时钟的一致性,如果出现系统时钟回拨,可能会造成ID冲突或者ID乱序
          • 在启动之前,如果这台机器的系统时间回拨过,那么有可能出现ID重复的危险
    • 基于ZK的顺序节点生成全局唯一ID
    • 基于MongoDB的object_id,每插入一条记录会自动生成全局唯一的一个"_id"字段值,它是一个12字节的字符串,可以作为分布式系统中全局唯一的ID

分布式队列

  • ZK作为一个小文件分布式管理系统,对于吞吐量不高的小型系统可以作为分布式队列使用
    • 设计思路
      • 创建队列根节点: 在ZK中创建一个持久节点,用作队列的根节点,所有队列元素的节点放在这个根下
      • 实现入队: 当需要将一个入队时,可以在队列的根下创建一个临时顺序节点,节点的数据可以包含队列元素的信息
      • 实现出队: 当需要从队列中取出元素时,执行操作
        • 获取根下所有子节点
        • 找到最小序号的节点
        • 获取该节点数据
        • 删除该节点数据
        • 返回节点数据

分布式锁

  • 在单体的应用开发场景中涉及并发同步的时候,往往采用synchronized或lock机制来解决多线程之间的同步问题
  • 在分布式集群工作的开发场景中,就需要分布式锁
基于数据库的分布式锁
  • db操作性能较差,并且有锁表的风险,一般不考虑
  • *可以利用数据库的唯一索引来实现,唯一索引天然具有排他性
  • 问题: 基于数据库实现分布式锁存在什么问题
    • 当遇到数据库宕机时,无法进行及时删除导致死锁问题
      • 无法实现监听机制,当释放锁时无法通知其他线程去获取锁
基于Redis的分布式锁
  • 适用于并发量很大、性能要求很高而且可靠性问题可以通过其他方案去弥补的场景
  • 使用setnx命令实现分布式锁,为了避免服务宕机死锁需要加一个过期时间可以使用set ...ex ...nx
基于ZK的分布式锁
  • 适用于高可用,而并发量不太高的场景
基于ZK非公平锁设计思路
  • 多个线程在同一时刻去创建临时节点,只能有一个线程会成功,未创建成功的线程会去监听该节点,该节点一旦被删除,这些等待的线程会继续去竞争
  • 问题: 非公平锁的机制会有什么问题
    • 当竞争激烈的时候,会导致性能下降,出现惊群效应
      • 因为只有一个线程能成功抢到锁,如果在大量线程的情况下,由于这些未抢到锁的线程都会去监听那个锁节点,一旦通知释放之后,都会一起去竞争,导致性能损耗
基于ZK公平锁设计思路
  • 会先创建一个容器节点,需要持锁的线程会在该容器节点下去创建临时顺序节点,每个子节点都会监听它前面的兄弟节点,当线程删除序号最小的节点释放锁后,后面监听该节点的节点会成为最小序号的节点保证当前线程持锁
  • 问题:为什么公平锁创建的是容器节点来保持临时顺序节点
    • 因为容器节点会定期检查有无子节点,如果没有会删除,可以有效避免手动删除的操作

服务的注册与发现

基于ZK实现注册中心
  • 优点
    • 高可用性: ZK是一个高可用分布式系统,可以通过配置多个服务实例来提供容错能力,如果其中一个实例出现故障,其他实例仍然能继续提供服务
    • 强一致性: ZK保证了数据的强一致性,当一个写操作完成时,所有服务都具有相同的数据视图,所以这样可以确保所有客户端看到的服务状态是一致的
    • 实时性: ZK的watch机制允许客户端监听节点的变化,当服务上线、下线时,客户端会实时收到通知,这样确保服务动态发现
  • 缺点
    • 性能限制: ZK在大量的读写操作或大规模集群下会出现性能瓶颈
相关推荐
无所不在的物质3 小时前
Jenkins基础教程
运维·云原生·自动化·jenkins
是芽芽哩!6 小时前
【Kubernetes 指南】基础入门——Kubernetes 基本概念(二)
云原生·容器·kubernetes
SelectDB6 小时前
Apache Doris 创始人:何为“现代化”的数据仓库?
大数据·数据库·云原生
m0_663234016 小时前
云原生是什么
云原生
weisian1517 小时前
Redis篇--常见问题篇7--缓存一致性2(分布式事务框架Seata)
redis·分布式·缓存
不能只会打代码7 小时前
Java并发编程框架之综合案例—— 分布式日志分析系统(七)
java·开发语言·分布式·java并发框架
Elastic 中国社区官方博客7 小时前
如何通过 Kafka 将数据导入 Elasticsearch
大数据·数据库·分布式·elasticsearch·搜索引擎·kafka·全文检索
马剑威(威哥爱编程)8 小时前
分布式Python计算服务MaxFrame使用心得
开发语言·分布式·python·阿里云
运维小文9 小时前
K8S中的服务质量QOS
云原生·容器·kubernetes