10

我对 Python Kazoo库有一个非常奇怪的案例。我在下面的代码中所做的是 -

一旦我使用 kazoo 库连接到 Zookeeper,我就创建了一个临时节点,然后监视其他节点,然后我继续在无限循环中永远运行程序。我还向 Zookeeper 添加了一个监听器这也将监视状态。

一切对我来说都运行良好,临时节点已启动,在我的 znode 上观看也运行良好......

有时,由于连接中断或断开,我会看到非常奇怪的行为。正如我上面提到的,我已经向 zookeeper 添加了一个监听器,它将监视状态,我也有一个 print 语句。我总是看到,那些 print 语句被打印为Lost, Suspended, Connected,我相信是因为连接中断和之后我的临时节点死了,我在 znode 上的手表也不能正常工作。

下面是我永远运行的代码 -

#!/usr/bin/python

from kazoo.client import KazooClient
from kazoo.client import KazooState
from kazoo.protocol.states import EventType


def watch_host(event):
    print event


def my_listener(state):
    if state == KazooState.LOST:
    # Register somewhere that the session was lost
        print "Lost"
    elif state == KazooState.SUSPENDED:
    # Handle being disconnected from Zookeeper
        print "Suspended"
    else:
    # Handle being connected/reconnected to Zookeeper
    # what are we supposed to do here?
    print "Being Connected/Reconnected"


zk = KazooClient(hosts='127.0.0.1:2181')
zk.start()

zk.add_listener(my_listener)

# start an ephemeral node
zk.create("/my/example/h0", b"some value", None, True)

# put a watch on my znode
children = zk.get_children("/my/example/test1", watch=watch_host)


while True:
    time.sleep(5)

有没有办法克服这个问题?每当我的 Zookeeper 状态更改为LostorSuspended或时,我都希望这样做Connected。我想通过再次创建它来启动我的临时节点(如果这是正确的方法),并且我在 znode 上的手表也能正常工作。

因为我将永远运行我的程序,所以无论出于何种原因,如果 Zookeeper 状态由于连接中断而发生变化并且它会自动重新连接,那么我需要确保我的临时节点也已启动并且我在 znode 上的手表也开始工作自动地..

目前,如果状态自动更改,我的短暂死机和手表也不起作用..

知道如何克服这个问题吗?

4

2 回答 2

7

事情是这样的,当连接发生状态变化时,你的观察者也会被触发。有一个事件被给予观察者。它可以是 nodeDataChanged 或 nodeChildrenChanged 之类的东西。但是,由于在会话终止或存在连接问题时不可能收到您感兴趣的事件的通知,因此您的观察者将收到有关这些会话问题的通知。我相信这个事件类型是“无”。

来自http://zookeeper.apache.org/doc/trunk/zookeeperProgrammers.html#ch_zkWatches

关于手表要记住的事情

  • 手表是一次性触发器;如果您收到手表事件并希望收到有关未来更改的通知,则必须设置另一个手表。
  • 由于 watch 是一次性触发器,并且在获取事件和发送新请求以获取 watch 之间存在延迟,因此您无法可靠地看到 ZooKeeper 中节点发生的每一次更改。准备好处理 znode 在获取事件和再次设置手表之间多次更改的情况。(你可能不在乎,但至少意识到它可能会发生。)
  • 对于给定的通知,监视对象或函数/上下文对只会被触发一次。例如,如果为同一个文件注册了相同的监视对象和 getData 调用,然后删除了该文件,则监视对象只会被调用一次,并带有文件的删除通知。
  • 当您与服务器断开连接时(例如,当服务器发生故障时),在重新建立连接之前,您将无法获得任何监视。出于这个原因,会话事件被发送到所有未完成的监视处理程序。使用会话事件进入安全模式:在断开连接时您将不会收到事件,因此您的进程应该在该模式下谨慎行事。

因此,长话短说,您的观察者应该打开事件以查看它是什么类型,并通过进入某种故障转移模式来适当地响应 None 类型。

我通常做的是我的 Watcher 对象也是监听器。当重新连接发生时,我通过重置我的手表来响应,确保检查是否存在适当的 znode 并在必要时创建它们。

于 2014-01-24T01:38:16.580 回答
5

我对Python一无所知,但我想我会强调一些关于ZNodes
Znodes两种类型的基本点:ephemeralpersistent

  • ephemeral znode一旦创建客户端的会话结束,ZooKeeper 就会删除一个。仅当客户端(不一定是创建它的客户端)显式删除时才会删除一次创建的
    persistent znode
  • Anephemeral znode永远不会有任何关联的孩子,甚至不会有关联的孩子ephemeral
  • 节点上的观察者仅触发一次(在 Java API 版本中),因此您需要重新注册事件,以便获得节点上未来更新的触发器

在 Java 版本(Java API)中,如果客户端连接到多个服务器,并且如果它与连接的服务器断开连接,那么我们会触发事件,KeeperState.Disconnected但它会重新尝试并连接到另一台服务器,在这段时间ephemeral znode和所有手表之间完好无损,即它们没有被破坏 ,但是一旦KeeperState.Expired调用事件(当客户端无法在指定时间内与任何服务器建立连接时)就会ephemeral znode被破坏,如果我们需要,我们必须创建一个新的客户端连接(实例化一个新ZooKeeper 实例)访问 ensemble,然后重新建立一切,即节点创建和添加手表。

因此,我认为在您的情况下,这也可能适用,如了解 Kazoo 状态部分所述

当连接转换为 LOST 时,已创建的任何临时节点都将被 Zookeeper 删除。这会影响所有创建临时节点的配方,例如 Lock 配方。在状态再次转换为 CONNECTED 后,需要重新获取锁。当会话到期或停止客户端连接时,会发生此转换。

希望此信息可以帮助您了解各种状态以及何时重新配置所有内容。

于 2014-01-23T12:44:08.323 回答