Flask / RabbitMQ:在与应用

时间:2017-10-22 20:27:53

标签: python multithreading flask rabbitmq thread-safety

我有一个Flask微服务,可以为端点提供用户请求(比如说):/getdata

数据可以通过以下两种方式之一获取:1)缓存或2)直接从数据库获取 - 如果缓存正在更新中

另一项服务更新数据库(从而使缓存失效)。一旦服务更新完成数据库,它就会向rabbitmq发布一条消息:“update done”

回到微服务:我希望它有两个线程: 线程1:运行app.run()

线程2:订阅队列 - 发布“更新完成”消息

鉴于这两个线程,我不希望/getdata在更新时从缓存中获取数据库。同时,我不想在从端点获取数据时更新缓存。

这是我能想到的一个解决方案:

1)将threading.Lock()作为“全球”

2)/getdata检查锁是否可用;如果是这样,它将获取,从缓存中获取数据并释放锁。如果锁不可用,它将直接从数据库中获取数据,从而导致性能损失 - 但仍然获得“最新”数据

3)RabbitMQ“subscriber”检查锁的状态;如果是这样,它获取锁,从数据库更新缓存并释放锁。如果没有,它会将请求添加到本地“队列”,并在尝试再次获取锁之前等待一分钟。如果是,它将从队列中弹出第一个项目并从数据库更新缓存。

我的问题:

  1. 鉴于Python / Flask中的众多库和选项 - 是 有一个图书馆,允许我以“安全”的方式完成这样的任务 (我正在使用pika进行rabbitmq访问)

  2. 是否可以通过一个线程启动烧瓶app.run()     通过另一个队列订阅用户(即在if __name__ == "main"中:     )

  3. 如何声明可以协调的“全局”threading.Lock()         两个线程?
  4. 注意:

    我希望在更糟糕的情况下,锁定不会超过一分钟。

1 个答案:

答案 0 :(得分:3)

  1. Pika不是线程安全的。您应该避免在Flask的上下文中共享连接对象。编写自己的Flask插件不会占用那么多样板。它与the documentation example plugin非常相似。否则,您可以在搜索引擎上使用flask pika进行快速搜索,然后您会找到一些用于此目的的现有插件。我没有试过它们,它们似乎不太受欢迎,但也许你应该给它们一个去吧?

  2. 我不明白为什么不可能。 Flask知道如何处理这个问题。但是,我认为它会严重降低性能。此外,如果你使用的插件写得不完整,你可能会碰到一些角落。

  3. 就像你要为线程声明任何锁定一样。没什么。你把它放在模块级别(不是在Flask的上下文中),这样它就是全局的,就是这样。

  4. 话虽如此,我认为你不应该这样做。您应该在与Web服务器不同的进程中运行update-job(如果需要重新使用某些函数,则使用Flask CLI或其他任何操作)。这将是更好的性能,它更容易推理,它更松散耦合。

    此外,您应该尽可能避免遇到锁定头痛。相信我,这是一个真正的问题来源。在实际生产用例中,正确测试,调试,维护和风险很大,这是一场噩梦。如果你真的需要锁定,不要持有它一分钟,这太长了。

    我不知道您的确切要求,但肯定有一个解决方案是可以的,并且不会涉及这种复杂性。