Есть ли способ балансировки нагрузки на сборке предварительно обработанного многопроцессорного TCP-сервера asyncio? - PullRequest
0 голосов
/ 03 июня 2019

Благодарю парней в предыдущем ответе. Теперь я могу создать многопроцессный TCP-сервер, в котором каждый процесс работает соответственно с асинхронным сервером, но все они привязаны к одному порту.( Не удалось использовать os.fork () привязать несколько процессов к одному серверу сокетов при использовании asyncio )

Теоретически?эта модель достигла своей максимальной производительности, когда каждый процесс обрабатывал входящие сообщения одинаково.Преимущества могут как более низкая задержка или более высокая скорость передачи?Я не уверен.

Вот проблема.Я создал сервер из четырех процессов и выполнил статистику того, сколько запросов tcp будет принимать каждый процесс (зацикленным клиентом, который непрерывно делает новый запрос на соединение). Результат равен {p1: 20000 раз, p2: 16000 раз, p3: 13000раз, p4: 10000 раз} <- это.Вероятно, не какой-то хороший результат. </p>

Я выясняю, поможет ли блокировка (пусть процесс, который получает блокировку, принимает запрос, а не позволяет процессам конкурентно принимать запрос напрямую). Но получаетсятаким образом, только родительский процесс может получить блокировку, а другой вообще не может.

Чтобы найти решение, нужна ваша помощь.


Вот наивный примеркод сервера (предварительно разветвленная модель, в которой процессы непосредственно конкурируют с запросом):

# 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))

Получить вывод следующим образом (где ключ означает номер порта, а значение означает, сколько эхо-сигналов они обработали):

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: если кто-нибудь может сказать мне, как использовать uvloop drive eventloop в интерпретаторе pypy?большое спасибо!

...