@lucifer_jr

Почему падает производительность request per second?

В общем, есть сервис, переписанный на jappronto, если в нем ничего нет кроме возвращаемого "Hello world" условно, то при 48 потоках получаю ~132 000 req\sec. Затем добавляю два запроса к api (tensorflow serving), причем сам tensorflow serving спокойно выдерживает 3000-4000 req\sec. Запросы реализуются через либу requests. Получаю 150 запросов в секунду!!! Такая дикая просадка. Переписал запрос к API через pycurl, ситуация улучшилась несильно - 170 req/sec.

Как такое может получаться? Как ускорить работу сервиса? В чем может быть архитектурная ошибка?

Сейчас многое в коде не имеет смысла и забито хардкодом, но суть проблемы в производительности. Пробовал flask, sanic.

def calulate_response(request):
    X_main = <большой np.array, пока хардкодом>
    X_rnn_addi = <небольшой np.array, пока хардкодом>
    curl = pycurl.Curl()
    curl.setopt(pycurl.URL, 'http://localhost/v1/models/model_name:predict')
    curl.setopt(pycurl.HTTPHEADER, ['Accept: application/json',
                                'Content-Type: application/json'])
    curl.setopt(pycurl.POST, 1)
    data = json.dumps({
        "inputs": {
            "X_main": X_main,
            "X_rnn_addi": X_rnn_addi
        }
    })
    body_as_file_object = StringIO(data)
    response_as_file_object = BytesIO()
    curl.setopt(curl.WRITEDATA, response_as_file_object)
    curl.setopt(pycurl.READDATA, body_as_file_object) 
    curl.setopt(pycurl.POSTFIELDSIZE, len(data))
    curl.perform()
    resp = response_as_file_object.getvalue()

    X_spmts = <небольшой np.array, пока хардкодом>
    lnzspmts = np.array([[0.123]])
    lnzimobs = np.array([[-0.123]])
    data = json.dumps({
        "inputs": {
            "X_rnn_addi": np.append(lnzspmts, lnzimobs)[np.newaxis, :].tolist(),
            "X_spmts": X_spmts[np.newaxis, :, np.newaxis].tolist()
        }
    })
   
    curl.setopt(pycurl.URL, 'http://localhost/v1/models/model_name:predict')
    body_as_file_object = StringIO(data)
    response_as_file_object = BytesIO()
    curl.setopt(curl.WRITEDATA, response_as_file_object)
    curl.setopt(pycurl.READDATA, body_as_file_object) 
    curl.setopt(pycurl.POSTFIELDSIZE, len(data))
    curl.perform()
    resp = response_as_file_object.getvalue()
    curl.close()
    response = request.Response(json={
            "rec_id": 'lsdkf1213',
        }, code=200 if ((0.5 > 0) | (0.5 < 1)) else 202)
    return response


Вот результаты бенчмарка при пустом сервисе:
(base) [root@dell07 tmp]# bombardier -c 48 -n 10000 --method=POST --body-file=/tmp/body_file.txt http://localhost:4229
Bombarding http://localhost:4229 with 10000 request(s) using 48 connection(s)
 10000 / 10000 [============================================================================================================================] 100.00% 49025/s 0s
Done!
Statistics        Avg      Stdev        Max
  Reqs/sec    132600.72   63939.29  182236.34
  Latency      357.94us   709.83us    17.01ms
  HTTP codes:
    1xx - 0, 2xx - 10000, 3xx - 0, 4xx - 0, 5xx - 0
    others - 0
  Throughput:   363.68MB/s


Результаты с двумя запросами к API (коды выше)
(base) [root@dell07 tmp]# bombardier -c 48 -n 10000 --method=POST --body-file=/tmp/body_file.txt http://localhost:4229
Bombarding http://localhost:4229 with 10000 request(s) using 48 connection(s)
 10000 / 10000 [=============================================================================================================================] 100.00% 170/s 58s
Done!
Statistics        Avg      Stdev        Max
  Reqs/sec       171.05     125.58    1150.73
  Latency      280.16ms    92.62ms      1.27s
  HTTP codes:
    1xx - 0, 2xx - 10000, 3xx - 0, 4xx - 0, 5xx - 0
    others - 0
  Throughput:   497.85KB/s
  • Вопрос задан
  • 267 просмотров
Решения вопроса 2
sergey-gornostaev
@sergey-gornostaev Куратор тега Python
Седой и строгий
Нужно использовать асинхронные хэндлеры и асинхронную библиотеку для запросов к внешним сервисам. Вы просто останавливаете цикл событий блокирующим вызовом, вот и получаете просадку.
Ответ написан
tumbler
@tumbler Куратор тега Python
бекенд-разработчик на python
Вам поступило 100 запросов: Вы с помощью japronto дновременно взяли их все в обработку, а теперь фокус: первый же вызов requests.get заблокировал обработку оставшихся 99 запросов, так что весь ваш сервис тупо простаивает. По мере получения результатов вы выплёвываете по 1 ответу, как будто никакой асинхронности у вас в коде нет. Замените requests на клиент aiohttp и избавитесь от блокировки.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
dimonchik2013
@dimonchik2013
non progredi est regredi
замените Japronto на Flask / django
или клиент на aiohttp
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы