我们有一个基于以下内容构建的服务器:
它在以下平台上运行:
在过去的几个月里,我们遇到过几个实例,其中cherypy服务器没有响应。第一个症状是ajax请求超时,在浏览器中重新加载页面超时,然后最终Apache将返回502,因为cherrypy将不再接受任何连接。重新启动python服务可以解决问题。有时它会在10分钟内从超时到达502,有时它可以在我们意识到并且必须重新启动之前保持超时半小时。
服务器可以运行数周而不会出现问题,但有几天问题可能会在几个小时内发生5次。
我们已经对所有请求实施了一些额外的记录以识别模式。首先它似乎没有被任何一种特定类型的请求,时间,负载,用户等触发。但是我们偶尔会遇到SQL死锁错误,有时我们会得到樱桃请求超时错误。 SQL死锁似乎与请求清理时无关,并且它们与服务器冻结的时间无关。请求超时确实发生在类似的时间,但我只看过几次,每次都不会发生。
在每个模块的每个入口点内,我们添加了以下日志记录:
util.write_to_debuglog("ajax", "START", _path)
# Call AJAX target providing the session object
_args.update(session=session)
result=target(**_args)
util.write_to_debuglog("ajax", "FINISH", _path)
return result
在调试日志中,我们还打印出会话ID和用户名,以便我可以确切地看到请求的来源。
昨天当它发生故障时,这就是调试日志显示的内容(向后工作):
在11:23:11到11:59:08之间,如果你试图访问服务器,浏览器最终会超时,而有时候它最终会达到你从Apache获得立即502坏网关的程度。这告诉我cherrypy在此期间仍然接受套接字连接,但日志显示请求不会到来。即使是cherrypy访问日志也没有显示任何内容。
127.0.0.1 - - [05/Jan/2017:11:23:04] "GET /***/get_joblist HTTP/1.1" 200 18 "" "***/2.0"
127.0.0.1 - - [05/Jan/2017:11:59:09] "GET /***/upload_printer HTTP/1.1" 200 38 "" "***/2.0"
在这一天,错误日志文件中有两个请求超时,但这并不常见。
[05/Jan/2017:11:22:04] Traceback (most recent call last):
File "c:\python27\lib\site-packages\cherrypy\_cpwsgi.py", line 169, in trap
return func(*args, **kwargs)
File "c:\python27\lib\site-packages\cherrypy\_cpwsgi.py", line 96, in __call__
return self.nextapp(environ, start_response)
File "c:\python27\lib\site-packages\cherrypy\_cpwsgi.py", line 379, in tail
return self.response_class(environ, start_response, self.cpapp)
File "c:\python27\lib\site-packages\cherrypy\_cpwsgi.py", line 222, in __init__
self.run()
File "c:\python27\lib\site-packages\cherrypy\_cpwsgi.py", line 320, in run
request.run(meth, path, qs, rproto, headers, rfile)
File "c:\python27\lib\site-packages\cherrypy\_cprequest.py", line 603, in run
raise cherrypy.TimeoutError()
TimeoutError
[05/Jan/2017:11:22:05] Traceback (most recent call last):
File "c:\python27\lib\site-packages\cherrypy\_cpwsgi.py", line 169, in trap
return func(*args, **kwargs)
File "c:\python27\lib\site-packages\cherrypy\_cpwsgi.py", line 96, in __call__
return self.nextapp(environ, start_response)
File "c:\python27\lib\site-packages\cherrypy\_cpwsgi.py", line 379, in tail
return self.response_class(environ, start_response, self.cpapp)
File "c:\python27\lib\site-packages\cherrypy\_cpwsgi.py", line 222, in __init__
self.run()
File "c:\python27\lib\site-packages\cherrypy\_cpwsgi.py", line 320, in run
request.run(meth, path, qs, rproto, headers, rfile)
File "c:\python27\lib\site-packages\cherrypy\_cprequest.py", line 603, in run
raise cherrypy.TimeoutError()
TimeoutError
我们没有更改响应超时,因此默认值为5分钟。基于此假设,错误与任何挂起的请求无关。在11:22:04超时意味着在11:18:04发出请求,但当时的所有请求都是成功的。虽然挂起的8个请求的时间远远超过5分钟,但从未超时。
为什么一种类型的请求会为一个用户挂起,但继续为其他用户成功运行?
如果他们之前已经工作了几天或几周,为什么他们会挂起?
为什么请求超时没有清除所有这些?
为什么服务器达到不接受任何请求的程度?肯定有8个并发请求不是服务器最大值?
为什么服务器仍然接受套接字连接但不处理请求?
对于如何诊断或解决这些问题的任何建议都将不胜感激。
谢谢, 帕特里克。
答案 0 :(得分:0)
我相信我们最终追踪了这一点。
在一组非常特定的条件下,它正在对从事务中调用的单独数据库游标执行查询(即第二个查询不在事务中)。因此,一个连接在SQL中持有表锁,第二个连接正在等待该锁,但两者都来自同一个Python线程。在数据库连接上也没有设置超时(默认为无限),因此它将永久保留在自己的死锁中。只要没有人查询交易中保存的相同表格,系统仍然可以工作。最终,当其他用户/线程试图访问数据库的同一个锁定区域时,他们也将成为女仆永远等待。
我不认为SQL认为这是一个死锁,因为它期望一个连接完成事务并释放锁。我不认为CherryPy可以终止线程,因为SQL连接具有控制权。