Kafka 入门(一):消息队列和 zookeeper

消息队列

消息队列的作用

在这里插入图片描述

  • 把数据放到消息队列叫做生产者
  • 从消息队列里边取数据叫做消费者

主要作用有两个:

  • 1、解耦: 添加消息队列,让消费者需要数据时,不再强依赖于生产者。
  • 2、异步: 消费者直接发送请求然后进行排队即可,不必阻塞等待.

队列的两种模式

  • 点对点模式(一对一,消费者主动拉取数据,消息收到后消息清除)
  • 发布/订阅模式(一对多,消费者消费数据之后不会清除消息)
    消息生产者(发布)将消息发布到 topic 中,同时有多个消息消费者(订阅)消费该消息。和点对点方式不同,发布到 topic 的消息会被所有订阅者消费。

削峰和限流

我们再来一个场景,现在我们每个月要搞一次大促,大促期间的并发可能会很高的,比如每秒3000个请求。假设我们现在有两台机器处理请求,并且每台机器只能每次处理1000个请求。
在这里插入图片描述
那多出来的 1000 个请求,可能就把我们整个系统给搞崩了…所以,有一种办法,我们可以写到消息队列中:
在这里插入图片描述

JDK中的队列没有考虑到的问题

高可用

  • 无论是我们使用消息队列来做解耦、异步还是削峰,消息队列肯定不能是单机的。
  • 试着想一下,如果是单机的消息队列,万一这台机器挂了,那我们整个系统几乎就是不可用了。
  • 所以,当我们项目中使用消息队列,都是得集群/分布式的。要做集群/分布式就必然希望该消息队列能够提供现成的支持,而不是自己写代码手动去实现。

数据丢失问题

我们将数据写到消息队列上,系统 B 和 C 还没来得及取消息队列的数据,就挂掉了。如果没有做任何的措施,我们的数据就丢了。
在这里插入图片描述
因此需要将数据进行持久化操作,进而减少数据的丢失。持久化可以存在:

  • 磁盘
  • 数据库
  • Redis
  • 分布式文件系统
  • 同步存储还是异步存储

获得数据队列的方法

  • push: 生产者将数据放到消息队列中,消息队列有数据了,主动叫消费者
  • pull: 消费者不断去轮训消息队列,看看有没有新的数据,如果有就消费

Zookeeper

简介

  • ZooKeeper主要服务于分布式系统,可以用ZooKeeper来做:统一配置管理、统一命名服务、分布式锁、集群管理。
  • 使用分布式系统就无法避免对节点管理的问题 (需要实时感知节点的状态、对节点进行统一管理等等) ,而由于这些问题处理起来可能相对麻烦和提高了系统的复杂性,ZooKeeper作为一个能够通用解决这些问题的中间件就应运而生了

zookeeper的内部结构

ZooKeeper的数据结构,跟Unix文件系统非常类似,可以看做是一颗树,每个节点叫做 ZNode。每一个节点可以通过路径来标识,结构图如下:
在这里插入图片描述
ZooKeeper的节点我们称之为Znode,Znode分为两种类型:

  • 持久节点: 默认的节点类型。创建节点的客户端与zookeeper断开连接后,该节点依旧存在 。
  • 持久节点顺序节点: 所谓顺序节点,就是在创建节点时,Zookeeper根据创建的时间顺序给该节点名称进行编号:
  • 临时节点: 和持久节点相反,当创建节点的客户端与zookeeper断开连接后,临时节点会被删除:
  • 临时顺序节点: 结合和临时节点和顺序节点的特点:在创建节点时,Zookeeper根据创建的时间顺序给该节点名称进行编号;当创建节点的客户端与zookeeper断开连接后,临时节点会被删除。

利用 zookeeper 实现分布锁

获取锁

  • 在 Zookeeper 当中创建一个持久节,当第一个客户端 Client1 想要获得锁时,需要在这个节点下面创建一个临时顺序节点。
  • Client1查找持久节点下面所有的临时顺序节点并排序,判断自己所创建的节点是不是顺序最靠前的一个。如果是第一个节点,则成功获得锁。
  • 如果再有一个客户端 Client2 前来获取锁,则在持久节点下面再创建一个临时顺序节点Lock2。
  • Client2查找持久节点下面所有的临时顺序节点并排序,判断自己所创建的节点Lock2是不是顺序最靠前的一个,结果发现节点Lock2并不是最小的。于是,Client2向排序仅比它靠前的节点Lock1注册Watcher,用于监听Lock1节点是否存在。这意味着Client2抢锁失败,进入了等待状态。
  • 如果又有一个客户端Client3前来获取锁,则在持久节点下载再创建一个临时顺序节点Lock3。
  • Client3查找持久节点下面所有的临时顺序节点并排序,判断自己所创建的节点Lock3是不是顺序最靠前的一个,结果同样发现节点Lock3并不是最小的。于是,Client3向排序仅比它靠前的节点Lock2注册Watcher,用于监听Lock2节点是否存在。这意味着Client3同样抢锁失败,进入了等待状态。

释放锁
释放锁就比较简单了,因为前面创建的临时顺序节点,所以在出现下面两种情况时,都会自动释放锁:

  • 任务完成后,Client 会释放锁。
  • 任务没完成,Client 就崩溃了,也会自动释放锁。

监听器 watcher

常见的监听场景有以下两项:

  • 监听Znode节点的数据变化
    在这里插入图片描述

  • 监听子节点的增减变化

在这里插入图片描述

zookeeper 实现统一配置管理

比如我们现在有三个系统 A、B、C,他们有三份配置,分别是ASystem.ymlBSystem.ymlCSystem.yml,然后,这三份配置又非常类似,很多的配置项几乎都一样。

  • 此时,如果我们要改变其中一份配置项的信息,很可能其他两份都要改。并且,改变了配置项的信息很可能就要重启系统

于是,我们希望把ASystem.ymlBSystem.ymlCSystem.yml 相同的配置项抽取出来成一份公用的配置common.yml,并且即便common.yml改了,也不需要系统A、B、C重启
在这里插入图片描述
我们可以将common.yml这份配置放在ZooKeeper的Znode节点中,系统A、B、C监听着这个Znode节点有无变更,如果变更了,及时响应。
在这里插入图片描述

zookeeper 实现统一的命名服务

在这里插入图片描述

集群状态

以我们三个系统A、B、C为例,在 ZooKeeper 中创建临时节点:
在这里插入图片描述

  • 只要系统 A挂了,那/groupMember/A这个节点就会删除,通过监听groupMember下的子节点,系统B和C就能够感知到系统A已经挂了。
  • 除了能够感知节点的上下线变化,ZooKeeper 还可以实现动态选举Master的功能。(如果集群是主从架构模式下)
    • 原理也很简单,如果想要实现动态选举Master的功能,Znode节点的类型是带顺序号的临时节点(EPHEMERAL_SEQUENTIAL)就好了。
    • Zookeeper会每次选举最小编号的作为Master,如果Master挂了,自然对应的Znode节点就会删除。然后让新的最小编号作为Master,这样就可以实现动态选举的功能了

猜你喜欢

转载自blog.csdn.net/Mr_tianyanxiaobai/article/details/121036891
今日推荐