После многих исследований выяснилось, что после обслуживания сотен тысяч HTTP-запросов POST происходит утечка памяти. Странная часть заключается в том, что утечка памяти возникает только при использовании PyPy.Использование Twisted + Cyclone + PyPy для обработки запросов POST вызывает утечку памяти?
Вот пример код:
from twisted.internet import reactor
import tornado.ioloop
do_tornado = False
port = 8888
if do_tornado:
from tornado.web import RequestHandler, Application
else:
from cyclone.web import RequestHandler, Application
class MainHandler(RequestHandler):
def get(self):
self.write("Hello, world")
def post(self):
self.write("Hello, world")
if __name__ == "__main__":
routes = [(r"/", MainHandler)]
application = Application(routes)
print port
if do_tornado:
application.listen(port)
tornado.ioloop.IOLoop.instance().start()
else:
reactor.listenTCP(port, application)
reactor.run()
Вот тестовый код, я использую для создания запросов:
from twisted.internet import reactor, defer
from twisted.internet.task import LoopingCall
from twisted.web.client import Agent, HTTPConnectionPool
from twisted.web.iweb import IBodyProducer
from zope.interface import implements
pool = HTTPConnectionPool(reactor, persistent=True)
pool.retryAutomatically = False
pool.maxPersistentPerHost = 10
agent = Agent(reactor, pool=pool)
bid_url = 'http://localhost:8888'
class StringProducer(object):
implements(IBodyProducer)
def __init__(self, body):
self.body = body
self.length = len(body)
def startProducing(self, consumer):
consumer.write(self.body)
return defer.succeed(None)
def pauseProducing(self):
pass
def stopProducing(self):
pass
def callback(a):
pass
def error_callback(error):
pass
def loop():
d = agent.request('POST', bid_url, None, StringProducer("Hello, world"))
#d = agent.request('GET', bid_url)
d.addCallback(callback).addErrback(error_callback)
def main():
exchange = LoopingCall(loop)
exchange.start(0.02)
#log.startLogging(sys.stdout)
reactor.run()
main()
Обратите внимание, что этот код не попадал с CPython, ни с Tornado и PyPy! Код протекает только при использовании Twisted и Pypy вместе, и ТОЛЬКО при использовании запроса POST.
Чтобы увидеть утечку, вы должны отправить сотни тысяч запросов.
Обратите внимание, что при установке PYPY_GC_MAX процесс в конечном итоге сбой.
Что происходит?
Что вы заметили, что заставляет вас думать, что есть утечка памяти? Вы уверены, что размер программы на PyPy не больше размера на CPython? –
Трудно быть на 100% уверенным, но вы можете продолжить и дважды проверить мои заявления. Тесты проводились в течение очень длительного периода времени. Например, отвечая на сотни тысяч запросов GET с помощью Cyclone, выгружает память, используемую процессом, в 63 мегабайта, тогда как использование одного и того же теста с запросом POST заставило процесс использовать 400 мегабайт и продолжать брать все больше и больше памяти. Мы запускаем серверы производства, которые обрабатывают тысячи запросов в секунду с помощью кода Cyclone, который работает в течение нескольких дней без проблем с памятью, используя Python 2.7. Эта проблема возникает только с PyPy. –
Использование пакетов в Debian нестабильно, поведение, которое я получаю, заключается в том, что PyPy запускается с использованием 120 МБ, переходит на 125 МБ после первых 1000 запросов и остается на этом уровне использования памяти для следующих 5000 запросов. Я не позволял ему работать сотнями тысяч запросов, так как использование памяти, казалось, достигло стабильного уровня после всего тысячи запросов. Возможно, версия пакетов PyPy или Cyclone (или другой зависимости) в Debian нестабильна сейчас более новая или более старая, чем версии, с которыми вы тестировали, и проблема была исправлена или введена? –