TLS/SSL asyncio/uvloop leaks memory
rojamit opened this issue · 1 comments
rojamit commented
python3.9 or uvloop seems to leak smaller, but python3.11 (and others?) leaks A LOT OF memory under load
test command: ab -n15000 -c15000 -r https://127.0.0.1/
(apt install apache2-utils)
import asyncio, ssl, uvloop
class HTTP(asyncio.Protocol):
def __init__(self):
self.transport = None
def connection_made(self, transport) -> None:
self.transport = transport
def data_received(self, data) -> None:
self.transport.write(
b'HTTP/1.1 200 OK\r\nContent-Length: 0\r\nConnection: keep-alive\r\n\r\n'
)
self.transport.close()
def connection_lost(self, _=0) -> bool | None:
self.transport.close()
def make_tls_context():
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ctx.load_cert_chain('cert.crt', 'cert.key')
return ctx
tls_context = make_tls_context()
loop = uvloop.new_event_loop()
loop.set_debug(True)
async def start_server(loop):
return await loop.create_server(
HTTP, '127.0.0.1', 443, backlog=65535,
ssl=tls_context)
loop.run_until_complete(start_server(loop))
loop.run_forever()
loop.close()
CPython versions tested on:
3.9, 3.11
Operating systems tested on:
Linux
ljluestc commented
import asyncio
import ssl
import uvloop
class HTTP(asyncio.Protocol):
def __init__(self):
self.transport = None
def connection_made(self, transport) -> None:
self.transport = transport
def data_received(self, data) -> None:
print(data)
self.transport.write(
b'HTTP/1.1 200 OK\r\nContent-Length: 0\r\nConnection: keep-alive\r\n\r\n'
)
self.transport.close()
def connection_lost(self, exc) -> None:
if self.transport is not None:
self.transport.close()
self.transport = None
def make_tls_context():
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ctx.load_cert_chain('cert.crt', 'cert.key') # Adjust paths to your certificates
return ctx
async def start_server():
loop = asyncio.get_running_loop()
server = await loop.create_server(
lambda: HTTP(), '127.0.0.1', 443, backlog=65535, ssl=make_tls_context()
)
async with server:
await server.serve_forever()
uvloop.install()
asyncio.run(start_server())