Как стать автором
Обновить

Комментарии 30

Вот это просто идеальная задача для Go.
Простой сервис, один бинарник. Хорошая производительность.
Было бы интересно увидеть ваш вариант на Go.
Всегда восхищали люди, у которых без конфликтов в голове уживается столько разных технологий, позволяющих легко получать оптимальный результат.
НЛО прилетело и опубликовало эту надпись здесь
Два вопроса:
  1. Зачем смешивать асинхронный цикл событий с блокирующей очередью и потоками? Раз уж подключили библиотеку с асинхронный циклом (ev), логично написать всё в асинхронном стиле.
  2. Мы можем модифицровать процесс работы сервера и отдавать клиенту файл политики безопасности сразу же после подключения

    Я правильно понимаю, отдаём всем клиентам статический файл? Если так, то почему бы не поднять nginx на нужном порту и не отдавать статический xml с диска?
    UPD: кажется, понял. Протокол не HTTP.

То, что время обработки не сильно улучшилось (и даже по некоторым характеристикам ухудшилось) по сравнению с Java-сервером, вызывает подозрения. Или тесты проводились криво, или в сервере что-то не так. Отдавать статический файл из памяти 151мс — подозрительно.
1. Необходим менеджмент очереди, т.е. если использовать только libev, то надо писать какой то балансировщик который правильно распределит между обработчиками нагрузку. Использование же блокирующей очереди является вполне классическим решением для подобной задачи.
2. Да nginx можно использовать, об этом написали в комментарии ниже.

По-поводу тестов, делал несколько замеров тем, что есть. Цифры выложил те, которые получились, безусловно есть вероятность, что где то может быть косяк.
балансировщик который правильно распределит между обработчиками нагрузку

Вот это я не совсем понял. При подключении клиента вызовется ваш коллбэк, который пошлёт один блок данных клиенту, после чего закроет сокет. Псевдокодом:

endpoint.async_accept(acceptSocket, [](socket& s) {
    s.async_write(globalBuffer, [](socket& s){ s.close() });
});


Задача балансировщика в том, чтобы клиенты, пришедшие раньше, обслуживались быстрее? Мне кажется, операционная система сама об этом позаботится.
В libev есть асинхронный вызов async. Вопрос в том, что произойдет, если будет много одновременных запросов? Нам в любом случае надо аггрегировать клиентов, и ни в коем случае не терять их. Причем в документации даже написано, что очереди в async никакой нет, поэтому делать ее самим — ссылка.
Вопрос в том, что произойдет, если будет много одновременных запросов?


Они будут лежать в очереди операционной системы, man listen

async

ev_async, как я понял, нужен для того, чтобы разбудить цикл из другого потока, например, для завершения цикла по приходу SIGTERM. Очередь там, как я понял, нужна для того, чтобы не терять эти самые сигналы, пришедшие в другом потоке. Никакого отношения к обработке множества tcp-клиентов, кмк, это не имеет.

К слову, в Boost.Asio всё это можно сделать гораздо проще. Там из коробки идёт signal_set, который складывает сигналы в очередь, и можно обойтись вообще без дополнительных потоков. Впрочем, увеличить число потоков при желании будет очень просто.
Да, я как раз об этом и говорю, что при большом количестве запросов будет срабатывать метод async_accept, при этом он сразу же будет вызывать s.async_write, и мы будем терять сигналы-обработчики. Клиенты будут просто висеть на подключении и не получат файл политики.

Насчет Boost.Asio возможно, надо поглядеть. Как вернусь из поездки сразу гляну.
Клиенты будут просто висеть на подключении и не получат файл политики.

Да счего это вдруг? async_write он на то и async, что не блокируется. Он говорит ОС «запиши данные», не дожидаясь завершения, и цикл сразу возвращается к обработке других клиентов.
мы будем терять сигналы-обработчики

Я говорил о UNIX-сигналах, которые посылаются при перезапуске сервиса или при запросе обновления конфигурации.
Кстати, у вас в коде обработки сигналов я не нашёл. Неплохо бы уметь релодить xml-файл по SIGHUP и завершать обработку клиентов по SIGTERM / SIGQUIT.
А я нашел: Server.cpp:38
	this->sigint.set<&Server::on_terminate_signal>();
	this->sigint.start(SIGINT);

	this->sigterm.set<&Server::on_terminate_signal>();
	this->sigterm.start(SIGTERM);

	this->sigkill.set<Server::on_terminate_signal>();
	this->sigkill.start(SIGKILL);


Да, правда SIGHUP нет, но обновление xml — настолько редкое событие, что можно и просто перезапустить демон )
Ага, спасибо, не там искал. SIGKILL нельзя перехватить :)
Свой C++ демон это хорошо. Без этой идеи не было бы статьи. Только зачем изобретать велосипед? Первая же ссылка nginx crossdomain.xml
Да, вы правы, использовать nginx c модулем — неплохое решение. В свое время, когда встретился с задачей не особо над этим задумывался и написал свое решение за 30 минут на Java+Netty. Позже поделился с коллегами из других студий. Они попросили сделать демон на C++.

Плюс, по первой ссылке в гугле народ ругается на модуль для nginx.
Весьма странно. Там нечему не работать или плохо работать. nginx из коробки отдает статические файлы без каких либо модулей. Все что нужно — объявить новую секцию server и повесить ее на 843 порт.
    # Add this to your nginx.conf under http { }
    server {
        listen 843;
        server_name localhost;
        
        location / {
	    rewrite ^(.*)$ /crossdomain.xml;
	}

	error_page 400 /crossdomain.xml;

	location = /crossdomain.xml {
	    root /var/www/crossdomain;
	}
    }

Это решение работает максимально быстро. Тяжело найти или придумать что-нибудь более производительное. В наших играх много лет пользуемся именно таким решением. Хотя начинал я аналогичным образом со своего с++ демона году эдак в 2008.
[offtop]А почему чары на КДПВ здороваются левыми руками?[/offtop]
Хороший вопрос, так решила фантазия художника. Как вариант — он когда рисует часто зеркалит изображение, возможно где то там кроется ответ.
Если б отзеркалил, то было бы ++) вместо С++.

Если только слои отдельно друг от друга зеркалились… Однако логотип Unity наклонен в правильную сторону. Странновато.
Хорошая, годная статья, хоть и народ пишет что можно в десять строк накатать на других языках.
У нас был аналогичный сервер на C#, как только мы получали сокет, сразу туда толкали байты из памяти через Async API и после закрывали. Без явных менеджеров и очередей. Думаю на питоне можно накатать еще проще.

на злобу дня:
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
> Это идеальная задача для С. Обычного, без плюсов.

Для сферического программизма в вакууме, да. Так и есть.
А для реального мира, это странно.
В 2015 году выбирать язык, в котором можно очередями бахать себе и всем окружающим по ногам.
В котором куча заморочек, которые знают немногие на этой планете.
Будет только отчаянный бородатый дядька, который кроме С ничего не знает и не хочет знать))
Тем более для задачи, с которой любой PHP справится на ура.
Это решение перепишут на Go или аналог, при любой необходимости внести изменения, сразу после увольнения бородатого дядьки или перед этим)))
НЛО прилетело и опубликовало эту надпись здесь
Вы говорите так, будто я адепт Go ))
Мне лично он не нравится, если что. Считаю его недотехнологией.
Но вот такие маленькие сервисы, это именно то для чего он подходит идеально.

Он кроскмпилится, ни от чего не зависит, на выходе один бинарник, производительность достаточная для 99.99% задач. Весь тулинг для него тоже простой. Сам язык простой как палка.
Это все как раз вот для таких простых случаев.

>Си позволяет в данном случае работать максимально быстро с минимум накладных расходов, сложность/объём кода не большие, более того, можно даже прикинуть полный путь данных от железа до железа через весь код, включая ядерный, там не так уж и много.

А вот это реально смешно. Вот эта фигня очень хорошо характеризует этих самых упоротых бородатых дядек. У которых весь мир построен на С. В задаче, в которой производительность вообще никому не уперлась, которую успешно решают даже на PHP в 5 строчек, они будут тащить слои вплоть до ядерного уровня…

Такие смешные дядьки… и эти их детские потуги, как они важно раздувают щеки, что на них весь мир крутится))

>Бородатым дядькам хватит работы ещё на долго, покуда GOвённые программы работают на не GOвённых ОС

Открою тебе один большой секрет… все эти говеные ОС написали эти самые бородатые дядьки на С. Дырка на дырке и дыркой погоняет. Одни баги, все глючит, сыпется. Из-за этих вот криворучек с завышеным самомением… мол мы тут крутые-бородатые и щас на уровне ядра все разрулим, одни проблемы. Ибо понтов много, а софт в итоге говно. Но да, они таки лезут своими кривыми руками на уровеь ядра, и кичатся этим.

Языки типа Go, как раз и позволяют так как ты, крутых ядерщиков, держать подальше от этого саого ядра.
НЛО прилетело и опубликовало эту надпись здесь
Да я с этим не спорю.
Просто люди кичатся, что они на С тут щас все красиво сделают, а результат… Оно конечно в целом работает, но баг на баге и дырка на дырке. Все эти Go, Rust и иже с ними, они не просто по приколу появляются. Это борьба с человеческим фактором. Если бы все люди были идеальны, то можно было на С остановиться)) А так косячат люди с завидной регулярностью и с этим надо что-то делать.
НЛО прилетело и опубликовало эту надпись здесь
>Дядьки: 2
>солвер: 0

Омг… Детский сад, штаны на лямках…

P.S. Приходи, когда дядек приведешь. А пока смотри, что-бы песочек в ботиночки не попал, когда куличики лепить будешь)
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории