Zookeeper 高级打开方式

我录制了一份 Zookeeper 高级应用的视屏,主要内容有 3 点

 1、如何通过 Zookeeper 实现 master 选举
2、如何通过 Zookeeper 实现分布式锁
3、如何通过 Zookeeper 实现服务注册中心

这边文章是我录制之前的手稿,视屏地址是

https://www.bilibili.com/video/av57218448

点击这里观看视屏

视屏分为 5 集,详细分析和实战 上面三个问题,欢迎大家观看

---------------------------------下面是手稿正文---------------------------------------------------------------

大家好,今天给大家分享一下 Zookeeper 的高级应用。

先给大家分享一个面试过程
我:简历上说用过dubbo,想问一下 dubbo 是如何实现注册中心的?
求职者:dubbo 的注册中心是通过 zookeeper 实现的
我:dubbo 是如何通过 zookeeper 实现注册中心的呢?
求职者:……(答不出来)
我:我们知道 dubbo 服务启动的时候,会自己去注册服务,也就是说 dubbo 是自己做服务注册的,那么 zookeeper 在服务注册里面发挥着怎样的作用呢?
求职者:……(答不出来)


我在面试的过程中,发现很多同学对于 zookeeper 只是下载安装配置过,并不知道它在系统中是一个什么样的位置,发挥着什么作用,可以用来做哪些事情。这节课就是来让大家明白这三个为什么。

做过大数据的人都知道,zookeeper 在 Hadoop、HBase、Kafka 中都发挥着重要的作用。深入了解过 dubbo 的也都了解 zookeeper 的作用。今天我带大家深入了解一下 zookeeper 常见的的三种应用场景
1. 如何通过 zookeeper 实现 master 选举
2. 如何通过 zookeeper 实现分布式锁
3. 如何通过 zookeeper 实现服务注册中心

 

好,进入正题,我们来看一下一家电商网站发展路线。
作为一家电商网站,要有用户模块,订单模块,物流模块、定时任务模块等等。我们就先关注这 4 个模块

上面三个模块很容易理解。第四个 定时任务模块的作用:
1、用户下单之后 30 分钟没付款,关闭这样的订单
2、可以实现各种预警(发短信)
      1、10 分钟没有产生新订单,请检查系统是否存在异常
      2、截止 8 点,用户注册量 100,少于昨天同一时间注册数 500
            请及时检查系统是否存在异常(整点统计)
      3、截止 11 点,超时关闭的订单数量 186,大于昨天同一时间 50
            请及时检查系统是否存在异常(整点统计)
 


随着用户的增多,流量的增大,单台机器已经不能满足业务需要,于是开始引入集群,于是架构图变成了这个样子:


变成这样以后,也引入了新的问题
1. 由于分成了多台,如果让客户端直接访问服务的话,会存在很多问题,比如说
    1.1 客户端变复杂,需要根据规则判断要调用哪台服务
    1.2 如果服务端某一台宕机了,那么一部分用户就不可用了,需要客户端动态判断可用的服务
    -- 这两条还在可接受范围内,但是第三个问题就不能忍了 --
    1.3 如果流量继续增多,后台决定增加一台机器。由于客户端并不知道这台机器的存在,所以需要重新发版,让用户升级 app

    所以需要引入负载均衡服务,最常用的是 Nginx

好,现在架构变成了这样。我们再来看看,现在多台机器运行同一个服务,会不会对业务有影响?

 

先来看看定时任务模块,现在有两台机器,也就是说两台机器都在跑定时任务,这是不合理的,
    1. 一个是资源浪费,那些统计短信在多台机器上运行,造成重复统计,短信重复发送
    2. 另一个是导致数据不准确。我们举个例子。关闭订单的任务 1 分钟跑一次。
    在 10:59:50有 100 个 30 分钟没有付款的订单被机器 A 读取,经过计算之后,在 10:59:59秒的时候,把这 300 个订单 的状态改为超时关闭,关闭时间为。
    在 10:59:55这 100 个 30 分钟没有付款的订单被机器 B' 读取,经过计算之后,在 11:00:01秒的时候,把这 300 个订单 的状态改为超时关闭。

    这个时候数据已经不准确了,会带来什么影响呢?我们继续看,统计短信在 11:00:00运行了一次,这 100 单被算进去了,然后 12:00:00又运行了一次,这一百单又被算进去了


所以我们产生了这样的需求:
1. 在集群中,只允许其中一台去跑定时任务
2. 当这台机器宕机的时候,需要从其他机器中挑选一台继续运行


怎么去解决呢?这个时候就可以利用 zookeeper 来实现 master 选举
在 zookeeper 的根节点下创建一个 /timedtask 永久节点,

然后定时任务启动以后,就去 /timedtask 节点下创建一个名为 lock 的临时子节点。
zookeeper 能保证全局唯一性,也就是说,只有一台定时任务 能够成功创建 /timedtask/lock 节点。我们让创建节点成功的那台机器作为 master,让这台机器去跑定时任务即可。这样就满足了我们的第一个需求

现在的问题是,当 master 挂掉以后,如何从存活的机器中挑选一台出来呢?
方案是这样的,让之前创建 lock 节点失败的机器去监听 /timedtask/lock 节点是否被删除,
如果被删除,就再次尝试创建 lock 节点

 

下面来搭建一个伪分布式模式的 Zookeeper 集群(视屏中有详细过程,这里记一下关键操作)

tar -xzvf zo
mkdir dataDir1 dataDir2 dataDir3

/Users/kano/temp/dataDir1

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/Users/kano/temp/dataDir{1}
clientPort=218{1}
server.1=127.0.0.1:2881:3881
server.2=127.0.0.1:2882:3882
server.3=127.0.0.1:2883:3883


echo 1 > dataDir{1}/myid

cp 2 3
修改 zoo.cfg

编写启动脚本 
bash /Users/kano/temp/zookeeper-3.4.14/bin/zkServer.sh start
bash /Users/kano/temp/zookeeper-3.4.14-2/bin/zkServer.sh start
bash /Users/kano/temp/zookeeper-3.4.14-3/bin/zkServer.sh start

nc 127.0.0.1 2181
stat


bash zookeeper-3.4.14/bin/zkCli.sh -server 127.0.0.1:2181
create /timedtask test-123


/timedtask/lock


---进入代码环节(视屏中有详细操作)


我们通过引入 zookeeper,解决了集群中机 master 选举的问题
现在集群中只会有一台机器运行定时任务

 


接下来继续看,还有一些地方存在问题
用户支付成功的订单 被改为 超时关闭

这个问题如果在单台机器上,可以通过加锁解决。


当变成集群的时候,当然也是需要锁,只不过这个锁需要第三方组件来做
最常用的解决方案是用 Redis,也可以用 zookeeper 或者数据库来实现
zookeeper 虽然并发不如 Redis 高,但是zookeeper 有自己独有的优点
1. 如果获取锁的服务挂掉了,锁直接就释放了,不像Redis只能等待锁超时
2. zookeeper 提供了更稳定的高可用。而在 Redis 中,如果主节点挂掉,从节点还没有来得及同步的话,就会发生一些意想不到的事情

好了,现在我们来基于 zookeeper 实现分布式锁(视屏中有实战代码)
create /timeOutOrderLock ""


这是最简单的场景。其实 zookeeper 还可以实现更复杂的分布式锁,比如读写锁。
我在这里说一下思路,大家可以自己下去尝试实现一下


1. 注册临时顺序节点
2. 判断自己是否可以执行。如果可以执行,就执行;如果不可以执行,则监听父节点(/readWriteLock)
3. 如果子节点发生变化,监听父节点的 节点会收到通知
4. 收到通知后,回到 步骤 2


可以执行的规则:
    如果自己是读操作,只要比自己小的没有写操作,就可以开始执行
    如果自己是写操作,当且仅当自己是最小的时候,才可以开始执行

如果机器不多,可以用这种方式,但如果有成百上千台机器,这种方式的效率就比较低下。
为什么会低下呢?我们来看看
上面的执行情况,由于没有执行权限的子节点监听的是当子节点发生变化的时候,父节点会通知所有监听它的子节点。问题就在这里,真的需要通知所有监听它的子节点吗?所有的通知中,只有给 write03 的通知有作用。所以改进方案如下:

1. 注册临时顺序节点
2. 判断自己是否可以执行。如果可以执行,就执行;如果不可以执行,则监听比它小的上一个节点
3. 如果上一个节点发生变化,那么自己会收到通知
4. 收到通知后,回到 步骤 2

这样一来,性能大大提升

 

接下来,这家电商公司发展的很好。流量进一步扩大,然后出现了这样的一些问题
1、代码难以维护。经过很多人之手,逻辑不清晰,注释和日志不规范。导致开发速度越来越慢。新增的功能还好,如果是修改以前的功能,就需要冥思苦想前辈们的代码,生怕改出 bug
2、可靠性不高。某一个模块出现异常,可能会导致整个工程挂掉
3、扩展能力受限。比如 物流模块需要更多的内存,这个时候 集群中所有的机器都要扩展内存,导致成本越来越高
4、测试工程师工作量大。由于代码难以维护,往往改一个方法,就需要测试所有跟此方法相关的业务,很多测试都是不必要的

于是团队决定把服务拆分开来,

当架构变成这个样子以后,遇到的问题就更多了,我们今天主要关注服务间的调用,来看一下
1、用户模块如果需要调用订单,需要记住所有订单服务的地址,并且需要自己判断其他模块是否存活
模块拆分成服务遇到的问题:
1、Nginx 配置大量增加,运维压力增大
      增加服务,下线服务
2、一个服务如果需要调用其他服务,必须自己维护地址
     这意味着,增加一台机器。不仅运维要配置 Nginx
     用户服务也需要 增加新订单服务的地址,然后重新发布
3、如果一个服务依赖其他的服务。那么需要自己动态感知所依赖服务的
      宕机、新增等等情况

这些问题有没有似曾相识?是的,当我们从单机 变化成 集群的时候,就遇到了这样的问题,当时我们引入了反向代理,那现在能不能用这种方案呢?我们来看一下


我们来想一下,这种方案会不会有什么问题这种情况下会存在什么问题呢?
1、虽然减少了开发人员的难度,但是运维的工作量进一步增加了
      服务的增加,需要配置该服务对应的 Nginx
      由于有多个服务,所以运维要维护多组 Nginx
2、目前服务的可用性 严重依赖于 Nginx。
      即使服务可用,但 Nginx 不可用的话,服务依然无法访问


那该怎么办呢?主要问题在于业务的变动导致配置的复杂性成倍增加,而且都是体力劳动
我们能不能把节点的增加和宕机 交给程序去做?
能不能把服务的上线和下线交给程序去做?


于是,就产生了现在正流行的 微服务架构。
我们来看一下微服务架构中的服务注册中心是如何解决这个问题的

注册中心的引入 让我们内网间的调用变得自动化,服务可以把自己提供出去,也可以发现自己需要的服务,无需人工介入

其实微服务遇到的问题有很多,比如外网到内网的服务网关如何设计?大量服务的配置如何管理?
现在一个请求要经过多台机器,怎样有效监控系统中的流量走向?怎样查询日志?
这些问题都不在本课的范围内,大家要是有性趣的话,我后续可以录一下我对 spring cloud 的理解和使用


现在来看服务注册中心这块
我们现在已经知道了服务注册中心的作用和工作方式,那要怎么实现呢?我们先来分析一下需求

1、必须高可用。如果这个挂掉了,整个内网服务都瘫痪了
2、我们需要的数据结构是树
3、当某台机器宕机了,那么需要通知到 依赖这个服务的 服务
4、如果某台机器上线了,也需要通知到 依赖这个服务的 服务

zookeeper 能满足这些需求吗?
1、zookeeper 天生高可用
2、天生就是树状结构
3、可以通过 watcher 监听
4、可以通过 watcher 监听

那,通过 zookeeper,要如何实现呢?

好了,我们现在来模拟一下服务的注册和发现。
为了方便演示,我这里先把服务节点手动创建了。在工作中,一般通过代码创建

(视屏中有通过代码实现服务注册中心的例子)
create /services ""
create /services/user ""
create /services/order ""


create -e /services/order/192.168.101.10 ""
create -e /services/order/192.168.101.11 ""


delete /services/order/192.168.101.10 
delete /services/order/192.168.101.11 

bash /Users/kano/temp/zookeeper-3.4.14/bin/zkServer.sh stop
bash /Users/kano/temp/zookeeper-3.4.14-2/bin/zkServer.sh stop
bash /Users/kano/temp/zookeeper-3.4.14-3/bin/zkServer.sh stop
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值