有什么办法可以通过asyncio在预先创建的多进程TCP服务器上进行负载平衡?

时间:2019-06-03 09:45:57

标签: python multiprocessing python-asyncio epoll uvloop

在前面的回答中对大家的提示,现在我可以构建一个多进程TCP服务器,每个进程分别运行一个异步服务器,但所有进程都绑定到一个端口。 (Could not use os.fork() bind several process to one socket server when using asyncio

从理论上讲?当每个进程均等地处理传入消息时,该模型将实现其最佳性能。好处可能像更低的延迟或更高的tps?我不确定。

这是问题所在。我创建了一个四进程服务器,并统计了每个进程将接受多少tcp请求(由不断发出新连接请求的循环客户端)的结果。{p1:20000次,p2:16000次,p3:13000次,p4:10000次} <-这个。可能不是某种好结果。

我正在弄清楚锁是否有帮助(让获得锁的进程接受请求,而不是让进程直接竞争地接受请求)。但是事实证明,只有父进程才能获得锁。而另一个完全不能。

试图找出解决方案,需要您的帮助。


这是一个简单的示例服务器代码(预分叉的模型,其中的进程直接竞争性地接受请求):

# sample_server.py
import asyncio
import os
from socket import *

def create_server():
    sock = socket(AF_INET , SOCK_STREAM)
    sock.setsockopt(SOL_SOCKET , SO_REUSEADDR ,1)
    sock.bind(('',25000))
    sock.listen()
    sock.setblocking(False)
    return sock

async def start_serving(loop , server):
    while True:
        client ,addr = await loop.sock_accept(server)
        loop.create_task(loop ,client)

async def handler(loop ,client):
    with client:
        while True:
            data = await loop.sock_recv(client , 64)
            if not data: break
            print(f"Incoming message {data} at pid {pid}")
            await loop.sock_sendall(client , data)

server = create_server()

for i in range(4 - 1):
    pid = os.fork()
    if pid <= 0:
        break
pid = os.getpid()

loop = asyncio.get_event_loop()
loop.create_task(start_serving(loop , server))
loop.run_forever()

然后我们可以将其输出重定向到这样的文件中:

python3 sample_server.py > sample_server.output

下一步,我们可能会大致处理以下数据:

import re
from collections import Counter

with open('./sample_server.output','r') as f:
    cont = file.read()

pat = re.compile('[\d]{4}')
res = pat.findall(cont)
print(Counter(res))

获取这样的输出(其中key表示端口号,而value表示它们处理的回声数):

Counter({'3788': 23136, '3789': 18866, '3791': 18263, '3790': 10817})

不平等。


当我这样引入多处理锁时,情况变得更加糟糕:

from multiprocessing import Lock
l = Lock()

async def start_serving(loop , server):
    while True:
        with l:
            client ,addr = await loop.sock_accept(server)
        loop.create_task(loop ,client)

↑然后唯一可以接受请求的进程是父进程。而子进程完全被阻塞。好像您在进程被阻止之前获得了一个锁,那么它将始终像这样。口译员只是在忠实地按照我们的指示去做。


总而言之,这是我的两个问题:

  • 1 \,如果有任何方法可以让此预分支的异步服务器负载平衡?
  • 2 \有什么方法可以引入锁来解决此问题?

谢谢!

PS:是否有人可以告诉我如何在pypy的解释器中使用uvloop drive eventloop?非常感谢!

0 个答案:

没有答案