3

我有一个实时 web 应用程序,客户端从多个 Redis PubSub 频道接收更新,这些频道使用 gevent-socketio 和 redis-py 构建。

我正在查看django-tictactoe示例中的views.py, l.26 。当客户端为频道发送订阅消息时,它会生成一个新的 greenlet。然后,greenlet 订阅 Redis PubSub 频道并阻塞,直到收到消息。

class GameNamespace(BaseNamespace):
    def listener(self, chan):
            red = redis.StrictRedis(REDIS_HOST)
            red = red.pubsub()
            red.subscribe(chan)

            print 'subscribed on chan ', chan

            while True:
                for i in red.listen():
                    self.send({'message': i}, json=True)

    def recv_message(self, message):
        action, pk = message.split(':')

        if action == 'subscribe':
            Greenlet.spawn(self.listener, pk)

据我了解,如果不产生新的 Greenlets 或取消订阅,就不可能添加订阅。

您将如何以有效的方式处理频繁的订阅和取消订阅?

更新:我正在构建的是一个理论上无限的 2D 地图上的 HTML5 实时 MMO 游戏。由于地图的大小,无法将整个地图的状态发送到浏览器。因此,地图被划分为在玩家拖动地图时动态加载的图块(想想谷歌地图)。

每当拖动地图时,客户端/浏览器都会订阅刚刚变得可见的图块的更新,并在短暂延迟后取消订阅变得不可见的图块的更新。订阅的更改应该每名玩家每秒发生一次,所以频繁是相对的。

客户的数量(希望)会很大。理论上,所有玩家都可以查看地图的同一部分,这使得SUBSCRIBEUNSUBSCRIBE非常昂贵,因为它们是“ O(N) where N is the number of clients already subscribed to a channel”。在实践中,它会均匀分布在世界各地,所以这应该不是问题。

但是,我的主要问题是 Python Redis PubSub 实现在监听时阻塞。在上面的示例中调用 red.listen() 后,在消息到达之前,我无法再更改订阅。上面的示例代码启动了一个新的 Greenlet,每个订阅都有一个到 Redis 的新连接,这可能是个坏主意。

4

1 回答 1

0

您没有说明订阅之间的分区原理/要求是什么,即哪些信息流经订阅必须与其他订阅分开,因此很难明确回答。我会带着一些假设去......

如果您有少量或固定数量的客户端管理多个订阅,最好通过单个长期订阅多路复用多个不同的事件,该 Redis 客户端对最终的事件消费者进行多路复用。从 Redis 的角度来看,这种方法可能比为每个消费者重复设置和取消订阅更有效。

像这样的方案需要发布者方面的一些额外智能,以便他们可以为每条消息选择正确的队列,但这有时很容易实现,例如通过散列客户端 ID 模 N,其中 N 是 pub/ 的数量子队列。

我希望这与您所问的有关...

于 2012-04-19T21:45:47.557 回答