Zookeeper开发(04)注册从节点

现在我们已经有了主节点,我们需要配置从节点,以便主节点可以发号施令。根据我们的设计,每个从节点会在/workers下创建⼀个临时性的znode节点,很简单,我们通过以下代码就可以实现。我们将使⽤znode节点中的数据,来指⽰从节点的状态:

3673891-131ef73c074cea0c.png
3673891-7f130269d9937577.png

①我们将从节点的状态信息存⼊代表从节点的znode节点中。

②如果进程死掉,我们希望代表从节点的znode节点得到清理,所以我们使用了EPHEMERAL标志,这意味着,我们简单地关注/workers就可以得到有效从节点的列表。

③因为这个进程是唯⼀创建表示该进程的临时性znode节点的进程,如果创建节点时连接丢失,进程会简单地重试创建过程。


正如我们之前所看到的,因为我们注册了⼀个临时性节点,如果从节点死掉,表⽰这个从节点znode节点也会消失,所以这是我们在从节点组成管理上所有需要做的事情。我们将从节点状态信息存⼊了代表从节点的znode节点,这样我们就可以通过查询ZooKeeper来获得从节点的状态。当前,我们只有初始化和空闲状态,但是,⼀旦从节点开始处理某些事情,我们还需要设置其他状态信息。

以下为setStatus的实现,这个⽅法与之前我们看到的⽅法有些不同,我们希望异步⽅式来设置状态,以便不会延迟常规流程的操作:

3673891-4fe1f8dc56e96657.png


①如果我们收到连接丢失的事件,我们需要用我们想要更新的状态再次调用updateStatus⽅法(通过setData的上下⽂参数传递参数),因为在updateStatus⽅法中进⾏了竞态条件的检查,所以我们在这里就不需要再次检查。

②重新处理异步请求连接丢失时有个小问题:处理流程可能变得⽆序,因为ZooKeeper对请求和响应都会很好地保持顺序,但如果连接丢失,我们又再发起⼀个新的请求,就会导致整个时序中出现空隙。因此,我们进⾏⼀个状态更新请求前,需要先获得当前状态,否则就要放弃更新。我们通过同步⽅式进⾏检查和重试操作。

③我们执⾏⽆条件更新(第三个参数值为-1,表示禁⽌版本号检查),通过上下⽂对象参数传递状态。

④我们将状态信息保存到本地变量中,万⼀更新失败,我们需要重试。

⑤我们并未在setStatus进⾏更新,⽽是新建了⼀个updateStatus⽅法,我们在setStatus中使用它,并且可以在重试逻辑中使用。


为了更多地理解连接丢失时补发操作的问题,考虑以下场景:

1.从节点开始执⾏任务task-1,因此设置其状态为working on task-1。

2.客户端库尝试通过setData来实现,但此时遇到了⽹络问题。

3.客户端库确定与ZooKeeper的连接已经丢失,同时在statusUpdateCallback调⽤前,从节点完成了任务task-1并处于空闲状态。

4.从节点调⽤客户端库,使⽤setData⽅法置状态为Idle。

5.之后客户端处理连接丢失的事件,如果updateStatus⽅法未检查当前状态,setData调⽤还是会设置状态为working on task-1。

6.当与ZooKeeper连接重新建⽴时,客户端库会按顺序如实地调⽤这两个setData操作,这就意味着最终状态为working on task-1。


在updateStatus⽅法中,在补发setData之前,先检查当前状态,这样我们就可以避免以上场景。

注意:顺序和ConnectionLossException异常,ZooKeeper会严格地维护执⾏顺序,并提供了强有⼒的有序保障,然⽽,在多线程下还是需要小⼼面对顺序问题。多线程下,当回调函数中包括重试逻辑的代码时,⼀些常见的场景都可能导致错误发⽣。当遇到ConnectionLossException异常⽽补发⼀个请求时,新建立的请求可能排序在其他线程中的请求之后,⽽实际上其他线程中的请求应该在原来请求之后。

猜你喜欢

转载自blog.csdn.net/weixin_34218579/article/details/87336191