我有一个从RabbitMQ代理获取消息的reactor,并触发工作方法在进程池中处理这些消息,如下所示:
这是使用python asyncio
,loop.run_in_executor()
和concurrent.futures.ProcessPoolExecutor
实现的。
现在我想使用SQLAlchemy访问worker方法中的数据库。大多数情况下,处理过程非常简单快捷。
反应堆在开始时每秒处理10-50条消息,因此不能为每个请求打开新的数据库连接。相反,我想为每个进程维护一个持久连接。
我的问题是:我该怎么做?我可以将它们存储在全局变量中吗? SQA连接池是否会为我处理这个问题?当反应堆停止时如何清理?
[更新]
为什么选择带有流程池的模式?
当前实现使用不同的模式,其中每个使用者在其自己的线程中运行。不知何故,这不是很好。已经有大约200个消费者在他们自己的线程中运行,并且系统正在快速增长。为了更好地扩展,我们的想法是分离关注点并在I / O循环中使用消息并将处理委托给池。当然,整个系统的性能主要是I / O绑定。但是,处理大型结果集时CPU是一个问题。
另一个原因是“易用性”。虽然消息的连接处理和消耗是异步实现的,但是worker中的代码可以是同步且简单的。
很快就会发现,通过工作人员内部的持久网络连接访问远程系统是一个问题。这就是CommunicationChannels的用途:在worker中,我可以通过这些通道向消息总线发出请求。
我目前的一个想法是以类似的方式处理数据库访问:将语句通过队列传递到事件循环,然后将它们发送到数据库。但是,我不知道如何使用SQLAlchemy执行此操作。
入口点在哪里?
对象在通过队列时需要为pickled
。如何从SQA查询中获取此类对象?
与数据库的通信必须异步工作,以免阻塞事件循环。我可以使用例如aiomysql作为SQA的数据库驱动程序?
答案 0 :(得分:6)
如果您对如何实例化# db.py
engine = create_engine("connection_uri", pool_size=1, max_overflow=0)
DBSession = scoped_session(sessionmaker(bind=engine))
进行实例化,假设您正在使用orm,则可以轻松满足每个进程池进程一个数据库连接的要求工人进程。
一个简单的解决方案是拥有一个全局session,您可以在请求中重复使用它:
# task.py
from db import engine, DBSession
def task():
DBSession.begin() # each task will get its own transaction over the global connection
...
DBSession.query(...)
...
DBSession.close() # cleanup on task end
关于工人任务:
pool_size
参数max_overflow
和pool_size
customize create_engine。DBSession.remove()
使用的默认QueuePool将确保您的进程仅在每个进程中保持1个连接处于活动状态进程池。
如果您希望重新连接,可以使用recycle
,它将从注册表中删除会话,并在下次使用DBSession时重新连接。您还可以使用Pool的$(function() {
alert('step1');
$("button.delete-category").click(function() {
alert('step3');
console.log("sss");
return false;
});
alert('step2');
});
参数在指定的时间后重新连接。
在开发/部署期间,您可以使用AssertionPool,如果从池中签出多个连接,则会引发异常,请参阅switching pool implementations了解如何执行此操作。
答案 1 :(得分:1)
@roman:你有很好的挑战。
之前我的情况类似,所以这里是 2美分:除非此消费者"阅读" 和&# 34;写" 消息,不做任何实际处理,你可以重新设计这个消费者作为消费者/生产者消费消息,它将处理消息,然后将结果放入另一个队列,该队列(例如处理过的消息)可以被1..N非池化的异步进程读取,这些异步进程将打开其中的数据库连接'自己的整个生命周期。
我可以扩展我的答案,但我不知道这种方法是否符合您的需求,如果是这样,我可以为您提供有关扩展设计的更多细节。
答案 2 :(得分:0)
一种非常适合我的方法是使用网络服务器来处理和扩展流程池。 flask-sqlalchemy即使在其默认状态下也将保留连接池,并且不会在每个请求响应周期关闭每个连接。
asyncio执行程序只需调用url端点即可执行您的功能。额外的好处是因为所有进行工作的进程都在一个url后面,你可以轻松地跨多个机器扩展你的工作池,通过gunicorn或其他一些方法添加更多进程来扩展一个简单的wsgi服务器。另外,你获得了所有的容错能力。
缺点是您可能会通过网络传递更多信息。但是,正如您所说,问题是CPU绑定的,您可能会向数据库传递更多数据。