https://mp.weixin.qq.com/s?__biz=MzAxOTc0NzExNg==&mid=2665514106&idx=1&sn=e54aae8cf68f5afcc2978585170df0b8&chksm=80d67c39b7a1f52fe0d51d81464a979d50778ebbcd81159345599f21f8789f2cbf8d7044a174&scene=21#wechat_redirect

原创 2017-12-04 老刘 码农翻身

张大胖所在的公司这几年发展得相当不错,业务激增,人员也迅速扩展,转眼之间,张大胖已经成为公司的“资深”员工了,更重要的是,经过这些年的不懈努力,他终于坐上了架构师的宝座。

但是大胖很快发现,这架构师真不是好当的,技术选型、架构设计,尤其是大家搞不定的技术难点,最终都得自己扛起来。沟通、说服、妥协、甚至争吵都是家常便饭,比自己之前单纯做开发的时候难多了。

公司的IT系统早已经从单机转向了分布式,分布式系统带来了巨大的挑战。这周一刚上班,张大胖的邮箱里已经塞满了紧急邮件。

1小梁的邮件

小梁的邮件里说了一个RPC调用的问题,本来公司的架构组开发了一个RPC框架让各个组去使用,但是各开发小组纷纷抱怨:这个RPC框架不支持动态的服务注册和发现。

张大胖一看这个图就明白怎么回事了,为了支持高并发,OrderService被部署了4份,每个客户端都保存了一份服务提供者的列表,但是这个列表是静态的(在配置文件中写死的),如果服务的提供者发生了变化,例如有些机器down了,或者又新增了OrderService的实例,客户端根本不知道,可能还在傻乎乎地尝试那些已经坏掉的实例呢!

想要得到最新的服务提供者的URL列表,必须得手工更新配置文件才行,确实很不方便。

对于这样的问题,大胖马上就意识到,这就是客户端和服务提供者的紧耦合啊。

想解除这个耦合,非得增加一个中间层不可!

张大胖想到,应该有个注册中心,首先给这些服务命名(例如orderService),其次那些OrderService 都可以在这里注册一下,客户端就到这里来查询,只需要给出名称orderService,注册中心就可以给出一个可以使用的url, 再也不怕服务提供者的动态增减了。

不知道是不是下意识的行为,张大胖把这个注册中心的数据结构设计成为了一个树形结构

/orderService 表达了一个服务的概念, 下面的每个节点表示了一个服务的实例。 例如/orderService/node2表示的order service 的第二个实例, 每个节点上可以记录下该实例的url , 这样就可以查询了。

当然这个注册中心必须得能和各个服务实例通信,如果某个服务实例不幸down掉了,那它在树结构中对于的节点也必须删除, 这样客户端就查询不到了。

嗯,可以在注册中心和各个服务实例直接建立Session, 让各个服务实例定期地发送心跳,如果过了特定时间收不到心跳,就认为这个服务实例挂掉了,Session 过期, 把它从树形结构中删除。

张大胖把自己的想法回复了小梁,接着看小王的邮件。

2小王的Master选举

小王邮件中说的是三个Batch Job的协调问题,这三个Batch Job 部署在三台机器上,但是这三个Batch Job同一个时刻只能有一个运行,如果其中某个不幸down掉,剩下的两个就需要做个选举,选出来的那个Batch Job 需要“继承遗志”,继续工作。

其实这就是一个Master的选举问题,张大胖一眼就看出了本质。

只是为了选举出Master, 这三个Batch Job 需要互通有无,互相协调才行,这就麻烦了!

要不弄个数据库表? 利用数据库表主键不能冲突的特性,让这三个Batch Job 都向同一个表中插入同样的数据,谁先成功谁就是Master !

可是如果抢到Master的那个Batch Job挂掉了,别人永远就抢不到了! 因为记录已经存在了, 别的Batch Job 没法插入数据了!

嗯,还得加上定期更新的机制,如果一段时间内没有更新就认为Master死掉了,别的Batch Job可以继续抢.....  不过这么做好麻烦!

换个思路,让他们也去一个注册中心去大吼一声:“我是master!”, 谁的声音大谁是Master 。

其实不是吼一声,三个Batch Job启动以后,都去注册中心争抢着去创建一个树的节点(例如/master ),谁创建成功谁就是Master (当然注册中心必须保证只能创建成功一次,其他请求就失败了),其他两个Batch Job就对这个节点虎视眈眈地监控,如果这个节点被删除,就开始新一轮争抢,去创建那个/master节点。

什么时候节点会被删除呢? 对,就是当前Master的机器down掉了 ! 很明显,注册中心也需要和各个机器通信,看看他们是否活着。

等等,这里还有一个复杂的情况, 如果机器1并没有死掉,只是和注册中心长时间连接不上,注册中心会发现Session超时,会把机器1创建的/master删除。 让机器2和机器3去抢,如果机器3成为了master, 开始运行Batch Job,   但是机器1并不知道自己被解除了Master的职务, 还在努力的运行Batch Job,这就冲突了!

看来机器1必须得能感知到和注册中心的连接断开了,需要停止Batch Job才行,等到和注册中心再次连接上以后,才知道自己已经不是master了,老老实实地等下一次机会吧。

无论哪种方案,实现起来都很麻烦,这该死的分布式!

先把思路给小王回复一下吧。接着看小蔡的邮件。

3小蔡的分布式锁

小蔡的邮件里说的问题更加麻烦,有多个不同的系统(当然是分布在不同的机器上!),要对同一个资源操作。

这要是在一个机器上,使用某个语言内置的锁就可以搞定,例如Java的synchronized , 但是现在是分布式啊,程序都跑在不同机器的不同进程中, synchcronized一点用都没有了!

这是个分布式锁的问题啊!

能不能考虑下Master选举问题中的方式,让大家去抢? 谁能抢先在注册中心创建一个/distribute_lock的节点就表示抢到这个锁了,然后读写资源,读写完以后就把/distribute_lock节点删除,大家再来抢。

可是这样的话某个系统可能会多次抢到,不太公平。

如果让这些系统在注册中心的/distribute_lock下都创建子节点, 然后给每个系统一个编号,会是这个样子:

然后各个系统去检查自己的编号,谁的编号小就认为谁持有了锁, 例如系统1。

系统1持有了锁,就可以对共享资源进行操作了, 操作完成以后process_01这个节点删除, 再创建一个新的节点(编号变成process_04了):

其他系统一看,编号为01的删除了,再看看谁是最小的吧,是process_02,那就认为系统2持有了锁,可以对共享资源操作了。 操作完成以后也要把process_02节点删除,创建新的节点。这时候process_03就是最小的了,可以持有锁了。

这样循环往复下去......  分布式锁就可以实现了!

看看,我设计的这个集中式的树形结构很不错吧,能解决各种各样的问题! 张大胖不由得意起来。

好,先把这个想法告诉小蔡,实现细节下午开个会讨论。

4Zookeeper

正准备回复小蔡的时候,大胖突然意识到,自己漏了一个重要的点,那就是注册中心的高可用性,如果注册中心只有那么一台机器,一旦挂掉,整个系统就玩完了。

这个注册中心也得有多台机器来保证高可用性,那个自己颇为得意的树形结构也需要在多个机器之间同步啊,要是有机器挂掉怎么办? 通信超时怎么办? 树形结构的数据怎么在各个机器之间保证强一致性?

小王、小梁、小蔡的原始问题没有解决,单单是这个注册中心就要了命了。 以自己公司的技术实力,搞出一套这样的注册中心简直是Mission Impossible !

大胖赶紧上网搜索,看看有没有类似的解决方案,让大胖感到万分幸运的是,果然有一个,叫做Zookeeper

Zookeeper 所使用的树形结构和自己想象的非常类似,更重要的是,人家实现了树形结构数据在多台机器之间的可靠复制,达到了数据在多台机器之间的一致性。并且这多台机器中如果有部分挂掉了/或者由于网络原因无法连接上了, 整个系统还可以工作。

大胖赶快去看Zookeeper的关键概念和API:

1.  Session : 表示某个客户系统(例如Batch Job)和ZooKeeper之间的连接会话,  Batch Job连上ZooKeeper以后会周期性地发送心跳信息, 如果Zookeepr在特定时间内收不到心跳,就会认为这个Batch Job已经死掉了, Session 就会结束。

2. znode :  树形结构中的每个节点叫做znode, 按类型可以分为永久的znode(除非主动删除,否则一直存在),临时的znode(Session结束就会删除)和 顺序znode(就是小蔡的分布式锁中的process_01,process_02.....)。

3.  Watch : 某个客户系统(例如Batch Job)可以监控znode, znode节点的变化(删除,修改数据等)都可以通知Batch Job, 这样Batch Job可以采取相应的动作,例如争抢着去创建节点。

嗯,这些概念和接口应该可以满足我们的要求了, 就是它了,下午召集大家开会开始学习Zookeeper吧。

后记:本文从使用者的角度描述了Zookeeper有什么用处,至于它内部是如何工作,那是另外一个Big topic了,我们以后再讲。

(完)

你看到的只是冰山一角, 更多精彩文章,请移步《2016文章精华》或者《2017上半年文章精华

码农翻身

用故事讲述技术

 
 

微信扫一扫
关注该公众号

什么是Zookeeper?的更多相关文章

  1. 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)

    一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...

  2. [译]ZOOKEEPER RECIPES-Leader Election

    选主 使用ZooKeeper选主的一个简单方法是,在创建znode时使用Sequence和Ephemeral标志.主要思想是,使用一个znode,比如"/election",每个客 ...

  3. zookeeper源码分析之六session机制

    zookeeper中session意味着一个物理连接,客户端连接服务器成功之后,会发送一个连接型请求,此时就会有session 产生. session由sessionTracker产生的,sessio ...

  4. zookeeper源码分析之五服务端(集群leader)处理请求流程

    leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...

  5. zookeeper源码分析之四服务端(单机)处理请求流程

    上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...

  6. zookeeper源码分析之三客户端发送请求流程

    znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...

  7. zookeeper源码分析之二客户端启动

    ZooKeeper Client Library提供了丰富直观的API供用户程序使用,下面是一些常用的API: create(path, data, flags): 创建一个ZNode, path是其 ...

  8. zookeeper源码分析之一服务端启动过程

    zookeeper简介 zookeeper是为分布式应用提供分布式协作服务的开源软件.它提供了一组简单的原子操作,分布式应用可以基于这些原子操作来实现更高层次的同步服务,配置维护,组管理和命名.zoo ...

  9. zookeeper集群的搭建以及hadoop ha的相关配置

    1.环境 centos7 hadoop2.6.5 zookeeper3.4.9 jdk1.8 master作为active主机,data1作为standby备用机,三台机器均作为数据节点,yarn资源 ...

  10. 如何编译Zookeeper源码

    1. 安装Ant Ant下载地址:http://ant.apache.org/bindownload.cgi 解压即可. 2. 下载Zookeeper源码包 https://github.com/ap ...

随机推荐

  1. [转帖]xserver相关知识汇总

    xserver相关知识汇总 https://blog.csdn.net/QTVLC/article/details/81739984   本文主要是从以下几个方面介绍xorg-xserver 相关的知 ...

  2. laravel实现批量添加数据

    在使用laravel eloquent进行数据库操作的时候惊讶的发现这货居然不支持批量添加,看到网上很多人在循环里进行数据库插入操作来实现批量添加,我想说这样做是很损失性能滴!好在框架的DB门面里的i ...

  3. maven+springmvc项目启动时,request mapping not found……

    springmvc项目跑的好好的,跑着跑着,出现request mapping not found的问题. 第一波,网上查问题,stackoverflow上面的各种配置说明,但是我本地就是没查出问题 ...

  4. 【转】使用 lsof 查找打开的文件

      在 UNIX® 环境中,文件无处不在,这便产生了一句格言:“任何事物都是文件”.通过文件不仅仅可以访问常规数据,通常还可以访问网络连接和硬件.在有些情况下,当您使用 ls 请求目录清单时,将出现相 ...

  5. spring程序打包war,直接通过-jar启动,并指定spring.profiles.active参数控制多环境配置

    备注:spring boot有内嵌tomcat,jar项目可以用java -jar命令启动,war包也可以,且可以直接指定spring.profiles.active参数控制多环境配置 直接指定传参, ...

  6. mvc 按钮权限控制

    需要开发一个按钮权限的控制,思路:拦截所有按钮路径,和用户拥有的3级按钮权限对比, 所有验证都一个方法解决,只需要修改js后的参数,参数就是按钮对应的权限码 如果有什么问题请提醒,谢谢! xml: & ...

  7. 导出数据到EXL表格中

    项目使用的是SSI框架,通过struts访问到action xml文件: <action name="fabAttributedaochu" class="com. ...

  8. DotNetty 实现 Modbus TCP 系列 (一) 报文类

    本文已收录至:开源 DotNetty 实现的 Modbus TCP/IP 协议 Modbus TCP/IP 报文 报文最大长度为 260 byte (ADU = 7 byte MBAP Header ...

  9. Using MongoDB with Web API and ASP.NET Core

    MongoDB is a NoSQL document-oriented database that allows you to define JSON based documents which a ...

  10. 开始一个简单的ASP.NET Web API 2 (C#)

    创建一个Web API 项目 在本教程中,你将使用ASP.NET Web API 来创建一个web API 并返回产品列表. 网页前端使用jQuery 显示结果. 选择ASP.NET Web Appl ...