集成cherrypywebframework、SQLAlchemy会话和lighttpd以服务于高负载web服务的最佳实践

2024-10-03 04:30:08 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在lighttpd后面开发一个CherryPy FastCGI服务器,其设置如下,以支持在CherryPy控制器内使用ORM SQLAlchemy会话。然而,当我用大约500个循环的14个并发请求运行压力测试时,它会在一段时间后开始给出诸如open_dbsession()中的AttributeError: '_ThreadData' object has no attribute 'scoped_session_class'或{}中的{}。总的错误率在50%左右。在

只有在lighttpd后面运行服务器时才会发生这种情况,而不是直接通过cherrypy.engine.start()运行服务器。已确认connect()没有引发异常。在

我还尝试将scoped_session的返回值赋给GlobalSession(就像它是here),但是它给出了像UnboundExceptionError这样的错误和其他SA级错误。(并发:10,循环:1000,错误率:16%。即使直接运行时也发生。)

有一些可能的原因,但我缺乏足够的知识来选择一个。
1在FastCGI环境下,start_thread订阅是否不可靠?似乎open_dbsession()是在connect()
之前调用的 2cherrypy.thread_data是否因某种原因被清除?在

服务器代码

import sqlalchemy as sa  
from sqlalchemy.orm import session_maker, scoped_session

engine = sa.create_engine(dburi, strategy="threadlocal")  
GlobalSession = session_maker(bind=engine, transactional=False)

def connect(thread_index):  
    cherrypy.thread_data.scoped_session_class = scoped_session(GlobalSession)

def open_dbsession():  
    cherrypy.request.scoped_session_class = cherrypy.thread_data.scoped_session_class

def close_dbsession():  
    cherrypy.request.scoped_session_class.remove()


cherrypy.tools.dbsession_open = cherrypy.Tool('on_start_resource', open_dbsession)  
cherrypy.tools.dbsession_close = cherrypy.Tool('on_end_resource', close_dbsession)  
cherrypy.engine.subscribe('start_thread', connect)

lighttpd fastcgi配置

^{pr2}$

编辑

  • 从原始源代码恢复了代码示例中缺少的thread_index参数(感谢注释)
  • 澄清错误不会立即发生
  • 把条件缩小到最轻

Tags: 服务器datasessionconnect错误openthreadstart
2条回答

I also tried assigning the return value of scoped_session to GlobalSession (like it does here), but then it gave out errors like UnboundExceptionError and other SA-level errors. (Concurrency: 10, loops: 1000, error rate: 16%)

如果没有显式实例化作用域的\u session类,则不会发生此错误。在

GlobalSession = scoped_session(session_maker(bind=engine, transactional=False))

def connect(thread_index):  
    cherrypy.thread_data.scoped_session_class = GlobalSession

def open_dbsession():  
    cherrypy.request.scoped_session_class = cherrypy.thread_data.scoped_session_class

def close_dbsession():  
    cherrypy.request.scoped_session_class.remove()

如果您查看plugins.ThreadManager.acquire_thread,您将看到self.bus.publish('start_thread', i),其中i是所见线程的数组索引。订阅start_thread通道的任何侦听器都需要接受该i值作为位置参数。所以重写connect函数如下:def connect(i):

我想它是在默默地失败;我会看看我是否能找到它,测试并修复它。在

相关问题 更多 >