LINUX.ORG.RU
решено ФорумAdmin

Посоветуйте стек технологий для задачи

 , , ,


1

3

Задача очень простая, вроде бы:

  • Нужно реализовать HTTP-сервер
  • На него будут приходить простые GET-запросы вида http://x.x.x.x/?a=1&b=2
  • В процессе обработки запроса нужно будет сделать ряд запросов к MySQL, обработать их результаты простой if{}else{} логикой и отдать ответ.
  • Язык не важен
  • Каждый запрос должен гарантированно выполниться за 1-2 секунды

Петрушка в том, что запросов одновременно может приходить много, на данный момент чуть меньше тысячи в секунду, потенциально - больше, поэтому хочется запас. И выполняться каждый запрос, потенциально, может 100-200мсек.

Что пробовал:

  • Банальный nginx + php-fpm. После долгого насилия над конфигами этих двух софтин, MySQL и sysctl.conf оно кое-как научилось держать 1000 одновременных коннектов, при этом php-fpm форкнул, соответственно, 1000 воркеров и сожрал 13Гб памяти. Как-то, мягко говоря, не оптимально. При этом при тестах через wrk и ab были таймауты в процессе получения URL, но они скорее всего связаны с MySQL. Тестил простым скриптом типа (подключиться к mysql, select столбец from table с двумя строками, print столбец, отключиться от mysql).
  • nodejs. Оно однопоточное, поэтому особого толку нет, плюс всякие непонятные глюки - в начале теста идёт ровно, под конец сервер дико напрягается ksoftirq и нода падает с ошибкой в духе «too many open files». Либо глючт mysql-модуль, коих там море в ноде и все разной степени кривзины, либо ещё что... разбираться лень. Скорость, в любом случае, достаточно низкая. Скрипт аналогичный.
  • Perl в виде PSGI приложения и разных серверов для его исполнения, как форкающихся (starman), так и на базе event loop (twiggy). Форкающиеся работали хорошо, но проблемы аналогичные php-fpm - каждый форк жрёт кучу памяти. event-овые опять таки однопоточные, да и доступ в SQL их блокирует.
  • Python + twisted. Оно event-овое, один поток. Проблемы аналогичные.

В результате пришёл к выводу, что мне нужно что-то тредовое т.к. каждый запрос к SQL выполняется какое-то время и если использовать event loop реализации - блокирует остальных. Форкающиеся сервера хороши, но памяти жрут мама не горюй.

Можно, конечно, написать свой HTTP-сервер с тредами и танцовщицами, на том же перле, но велосипед изобретать не хочется. Есть перл-модуль HTTP::Daemon::Threaded, но я его пока что-то не до конца осилил. Всякие apache+mpm_worker+mod_perl пока не смотрел, но выглядит достаточно вкусно.

Может я чего-то элементарного не вижу? Или просто дохрена хочу?

Если не ошибаюсь, даже Джаннга умеет городить отдельные потоки для клиентов. Но если даже твистед не подошел, возможно стоит смотреть в сторону celery

Dred ★★★★★
()

Глянь в сторону cowboy на erlang.

ptah_alexs ★★★★★
()
Ответ на: комментарий от disarmer

Кто мешает форкать event-driven сервер?

Да, в общем-то, никто не мешает, конечно. nginx это доказывает :) Но готовых event-driven серверов, которые нормально форкаются, я не нашёл, вероятно плохо искал.

Ты видимо используешь синхронный драйвер для общения с базой.

Да, синхронный. Этот модуль, конечно, видел, но callback-и для работы с базой, на мой взгляд, крайне не удобны. По крайней мере в моём алгоритме я не очень понимаю как их правильно применить. Поэтому мне был бы удобнее именно многопоточный сервер без этой асинхронной мороки :)

blind_oracle ★★★★★
() автор топика
Ответ на: комментарий от Dred

Я пробовал твистед в тредах, примерно такой:

#!/usr/bin/python

from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
from SocketServer import ThreadingMixIn
import threading

class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.end_headers()
        self.wfile.write('Hello world!')
        return

    def log_message(self, format, *args):
        return

class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
    """ blah """

if __name__ == '__main__':
    server = ThreadedHTTPServer(('', 5001), Handler)
    server.serve_forever()
Но больше 140% CPU оно не скушало даже при 1000 коннектов, скорость всего около 1000 запросов в сек. Celery попробую, спасибо.

blind_oracle ★★★★★
() автор топика
Последнее исправление: blind_oracle (всего исправлений: 1)
Ответ на: комментарий от borisych

О какая красота, спасибо! Прям глаза разбегаются :)

blind_oracle ★★★★★
() автор топика
Ответ на: комментарий от blind_oracle

Поэтому мне был бы удобнее именно многопоточный сервер без этой асинхронной мороки :)

Даже если запросы будут приходить равномерно, при 1000rps*0.2s = 200 одновременно исполняющихся запросов в каждый момент времени. В реальности, с неравномерным распределением по времени можно ожидать и 400-500. Просто шедулить такое количество процессов/тредов - уже неплохая нагрузка и задержки. И это на первое время, без запаса и подтупливаний mysql

disarmer ★★★
()
Ответ на: комментарий от nullb0t

Да, уже положил в бенчмарке на него глаз вкупе с LuaJIT. Попробую.

blind_oracle ★★★★★
() автор топика
Ответ на: комментарий от r0ck3r

Вот с жабой связываться не очень хочется, уж лучше Go. Не люблю как-то ея, хотя плюсов у неё много.

blind_oracle ★★★★★
() автор топика
Ответ на: комментарий от disarmer

Это да, шедулинг оверхед будет приличный, но такие пики будут достаточно редко, да и сервер будет мощный. Просто для асинхронного программирования я, наверное, не готов, да и не программер йа, в общем :) Мускуль потенциально заменим на что-то более производительное типа Redis.

blind_oracle ★★★★★
() автор топика
Последнее исправление: blind_oracle (всего исправлений: 1)
Ответ на: комментарий от anonymous

В общем, попробовал Go с fasthttp-routing модулем - красота! 170к запросов в секунду хеллоуворолдовых выдал, 20 ядер занял на ура. Похоже это то, что нужно. Тут скорее СУБД загнётся, а не мидлварь.

blind_oracle ★★★★★
() автор топика
Ответ на: комментарий от nullb0t

OpenResty как-то не порадовал :( На hello-world-е:

worker_processes 6;

pid /tmp/nginx.pid;
error_log stderr error;

events {
    worker_connections  16384;
}

http {
    resolver 127.0.0.1;
    access_log off;

    server {
        listen 5001;

        location / {
            content_by_lua 'ngx.print("Hello!")';
        }
    }
}
выдал всего 10к запросов в секунду, при этом процессы nginx-а как-то не особо кушали ядра, при любом concurrency. Вероятно, я что-то не так делаю.

blind_oracle ★★★★★
() автор топика

Переписал логику на Go, производительность более чем устраивает, scalability просто супер. Всем спасибо! Тему, думаю, можно считать закрытой.

blind_oracle ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.