💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# ZooKeeper 一个分布式的开放源码的分布式应用程序协调服务(保证分布式服务更加稳健),是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性(强一致性)服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。 1、配置说明 tickTime=2000 initLimit=10 syncLimit=5 dataDir=/home/hadoop/software/zookeeper-3.4.10/data dataLogDir=/Users/apple/zookeeper/logs clientPort=2181 server.1=master:2888:3888 server.2=slave1:2888:3888 server.3=slave2:2888:3888 tickTime:这个时间是作为 Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳。 initLimit::zookeeper集群中的包含多台server,,其中一台为leader,,集群中其余的server为follower.。initLimit参数配置初始化连接时, follower和leader之间的最长心跳时间.。此时该参数设置为10, 说明时间限制为10倍tickTime, 即10*2000=20000ms=20s。 syncLimit::该参数配置leader和follower之间发送消息, 请求和应答的最大时间长度.。此时该参数设置为5,说明时间限制为5倍tickTime,即10s。 server.X=A:B:C 其中X是一个数字,表示这是第几号server。A是该server所在的IP地址。B配置该server和集群中的leader交换消息所使用的端口。 C配置选举leader时所使用的端口。 如果配置的是伪集群模式,则各个server的B、C参数必须不同。 dataDir:就是把内存中的数据存储成快照文件snapshot的目录,同时myid也存储在这个目录下(myid中的内容为本机server服务的标识)。写快照不需要单独的磁盘,而且是使用后台线程进行异步写数据到磁盘,因此不会对内存数据有影响。默认情况下,事务日志也会存储在这里。建议同时配置参数dataLogDir,事务日志的写性能直接影响zk性能。 dataLogDir:事务日志输出目录。尽量给事务日志的输出配置单独的磁盘或是挂载点,这将极大的提升ZK性能。 由于事务日志输出时是顺序且同步写到磁盘,只有从磁盘写完日志后才会触发follower和leader发回事务日志确认消息(zk事务采用两阶段提交),因此需要单独磁盘避免随机读写和磁盘缓存导致事务日志写入较慢或存储在缓存中没有写入。 clientPort:这个端口就是客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求。 minSessionTimeout~maxSessionTimeout:Session超时时间限制,如果客户端设置的超时时间不在这个范围,那么会被强制设置为最大或最小时间。 注意:Session超时时间由服务器和ZK客户端共同决定,建议最大超时时间不要太短,以避免频繁连接超时情况(HBase使用的3分钟)。 2、 Zookeeper通知机制 客户端注册监听它关心的目录节点,当目录节点发生变化(数据改变、被删除、子目录节点增加删除)时,zookeeper会通知客户端。 ZooKeeper是以Fast Paxos算法为基础的,Paxos 算法存在活锁的问题,即当有多个proposer交错提交时,有可能互相排斥导致没有一个proposer能提交成功,而Fast Paxos作了一些优化,通过选举产生一个leader (领导者),只有leader才能提交proposer,具体算法可见Fast Paxos。因此,要想弄懂ZooKeeper首先得对Fast Paxos有所了解。ZooKeeper的基本运转流程: * 1. 选举Leader。 * 2. 同步数据。 * 3. 选举Leader过程中算法有很多,但要达到的选举标准是一致的。 * 4.Leader要具有最高的执行ID,类似root权限。 * 5. 集群中大多数的机器得到响应并接受选出的Leader。 ![](https://box.kancloud.cn/bc8a40bf8a151c1b72b96e5cac4871e9_573x257.png) 3、 分布式锁 分布式锁,这个主要得益于ZooKeeper为我们保证了数据的一致性。锁服务可以分为两类,一个是 保持独占,另一个是 控制时序。 所谓保持独占,就是所有试图来获取这个锁的客户端,最终只有一个可以成功获得这把锁。通常的做法是把zk上的一个znode看作是一把锁,通过create znode的方式来实现。所有客户端都去创建 /distribute_lock 节点,最终成功创建的那个客户端也即拥有了这把锁。 控制时序,就是所有视图来获取这个锁的客户端,最终都是会被安排执行,只是有个全局时序了。做法和上面基本类似,只是这里 /distribute_lock 已经预先存在,客户端在它下面创建临时有序节点(这个可以通过节点的属性控制:CreateMode.EPHEMERAL_SEQUENTIAL来指定)。如果我们在指定的路径上创建顺序节点,则Zookeeper会自动的在我们给定的path上加上一个顺序编号。这个特性就是实现分布式锁的关键。假设我们有几个节点共享一个资源,我们这几个节点都想争用这个资源,那我们就都向某个路径创建临时顺序节点。然后顺序最小的那个就获得锁,然后如果某个节点释放了锁,那顺序第二小的那个就获得锁,以此类推,这样一个分布式的公平锁就实现了。 4、分布式队列 队列方面,简单地讲有两种,一种是常规的先进先出队列,另一种是要等到队列成员聚齐之后的才统一按序执行。对于第一种先进先出队列,和分布式锁服务中的控制时序场景基本原理一致,这里不再赘述。 第二种队列其实是在FIFO队列的基础上作了一个增强。通常可以在 /queue 这个znode下预先建立一个/queue/num 节点,并且赋值为n(或者直接给/queue赋值n),表示队列大小,之后每次有队列成员加入后,就判断下是否已经到达队列大小,决定是否可以开始执行了。这种用法的典型场景是,分布式环境中,一个大任务Task A,需要在很多子任务完成(或条件就绪)情况下才能进 行。这个时候,凡是其中一个子任务完成(就绪),那么就去 /taskList 下建立自己的临时时序节点(CreateMode.EPHEMERAL_SEQUENTIAL),当 /taskList 发现自己下面的子节点满足指定个数,就可以进行下一步按序进行处理了。 5、负载均衡 这里说的负载均衡是指软负载均衡。在分布式环境中,为了保证高可用性,通常同一个应用或同一个服务的提供方都会部署多份,达到对等服务。而消费者就须要在这些对等的服务器中选择一个来执行相关的业务逻辑,其中比较典型的是消息中间件中的生产者,消费者负载均衡。 消息中间件中发布者和订阅者的负载均衡,linkedin开源的KafkaMQ和阿里开源的 metaq都是通过zookeeper来做到生产者、消费者的负载均衡。这里以metaq为例如讲下: 生产者负载均衡:metaq发送消息的时候,生产者在发送消息的时候必须选择一台broker上的一个分区来发送消息,因此metaq在运行过程中,会把所有broker和对应的分区信息全部注册到ZK指定节点上,默认的策略是一个依次轮询的过程,生产者在通过ZK获取分区列表之后,会按照brokerId和partition的顺序排列组织成一个有序的分区列表,发送的时候按照从头到尾循环往复的方式选择一个分区来发送消息。 **HBase和ZooKeeper** HBase内置有ZooKeeper,也可以使用外部ZooKeeper。 让HBase使用一个已有的不被HBase托管的Zookeep集群,需要设置 conf/hbase env sh文件中的HBASE_MANAGES_ZK 属性为 false... # Tell HBase whether it should manage it's own instance of Zookeeper or not. export HBASE_MANAGES_ZK=false 接下来,指明Zookeeper的host和端口。可以在 hbase-site.xml中设置, 也可以在HBase的CLASSPATH下面加一个zoo.cfg配置文件。 HBase 会优先加载 zoo.cfg 里面的配置,把hbase-site.xml里面的覆盖掉. 当HBase托管ZooKeeper的时候,Zookeeper集群的启动是HBase启动脚本的一部分。但你需要自己去运行。你可以这样做${HBASE_HOME}/bin/hbase-daemons sh {start,stop} zookeeper你可以用这条命令启动ZooKeeper而不启动HBase. HBASE_MANAGES_ZK 的值是 false, 如果你想在HBase重启的时候不重启ZooKeeper,你可以这样做