Russian Qt Forum

Qt => Работа с сетью => Тема начата: RedDog от Январь 19, 2011, 10:16



Название: Алгоритм высоконагруженного сервера
Отправлено: RedDog от Январь 19, 2011, 10:16
Прочитал много тем о высоконагруженных серверах, но так и не понял ничего.
Ситуация у меня следующая:
Есть TCP сервер, который по запросу от клиента должен выслать ему файл 20-150мб.
Одномоментно клиентов может быть сотни/тысячи.
На сегодняшний момент на каждого клиента создается свой сокет, по которому пересылается файл.
Код:
class NetworkServer : public QObject
{
    Q_OBJECT
...
private:
...
    QTcpServer *server;
    QList<QTcpSocket*>connections;

private:
    void sendFileToClient(int socketIndex);

public slots:
    void on_newConnection();
    void on_recieveCommand();
};

Добавление нового подключения в массив сокетов:
Код:
void NetworkServer::on_newConnection()
{
    QTcpSocket *socket = server->nextPendingConnection();
    connect(socket, SIGNAL(readyRead()),
            this, SLOT(on_recieveCommand()));
    connections.push_back(socket);   
    emit newConnection(socket->peerAddress().toString());
}
Отправка файла клиенту:
Код:
void NetworkServer::on_recieveCommand()
{
    QTcpSocket *socket = qobject_cast<QTcpSocket*>(sender());
    if (socket == 0)
        return;
    sendFileToClient(connections.indexOf(socket));
}

void NetworkServer::sendFileToClient(int socketIndex)
{
    QTcpSocket *sock = connections[socketIndex];
    QByteArray outBuf;
    QDataStream out(&outBuf, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_6);
    QFile file(m_SendingFileName);
    file.open(QIODevice::ReadOnly);
    quint32 fileSize = file.size();
    out<<fileSize;
    out<<file.readAll();
    sock->write(outBuf);
    sock->flush();
    sock->close();
    connections.removeAt(socketIndex);
}

Но на каждого клиента создавать свой сокет накладно.
Как быть? Как на один сокет повесить несколько клиентов?


Название: Re: Алгоритм высоконагруженного сервера
Отправлено: merke от Январь 19, 2011, 10:27
Тут уж надо уже смотреть не в сторону как повесить на один сокет несколько клиентов, хотя такое мне кажется невозможным, а курить в сторону многопоточности.


Название: Re: Алгоритм высоконагруженного сервера
Отправлено: RedDog от Январь 19, 2011, 10:30
Тут уж надо уже смотреть не в сторону как повесить на один сокет несколько клиентов, хотя такое мне кажется невозможным, а курить в сторону многопоточности.
Допустим, я сделаю, что каждый отдельный сокет будет висеть в своем потоке (либо по 10 сокетов на поток), тогда при 1000 клиентах получится 1000 открытых сокетов, думаю система от такого количества заткнется.


Название: Re: Алгоритм высоконагруженного сервера
Отправлено: merke от Январь 19, 2011, 10:38
Нет не заткнется) Иначе ни как...


Название: Re: Алгоритм высоконагруженного сервера
Отправлено: BRE от Январь 19, 2011, 10:38
думаю система от такого количества заткнется.
А ты не думай - ты проверь. :)



Название: Re: Алгоритм высоконагруженного сервера
Отправлено: RedDog от Январь 19, 2011, 10:45
Итого получается:
1. При старте сервера создается отдельный поток, в котором слушается порт
2. При подключении нового клиента создается новый сокет, и новый поток, в который сокет перемещается
3. При подключении N-нного (N<M) клиента создается новый сокет, который помещается в работающий отдельный поток
4. При подключении N-нного (N>M) клиента создается новый сокет, и новый поток, сокет перемещается в новый поток
5. "Сканируем" M потоков на количество работающих клиентов, и при отключении одного из них помещаем в этот поток нового N+1 клиента

Я на верном пути?


Название: Re: Алгоритм высоконагруженного сервера
Отправлено: brankovic от Январь 19, 2011, 11:42
Итого получается:
1. При старте сервера создается отдельный поток, в котором слушается порт
2. При подключении нового клиента создается новый сокет, и новый поток, в который сокет перемещается
3. При подключении N-нного (N<M) клиента создается новый сокет, который помещается в работающий отдельный поток
4. При подключении N-нного (N>M) клиента создается новый сокет, и новый поток, сокет перемещается в новый поток
5. "Сканируем" M потоков на количество работающих клиентов, и при отключении одного из них помещаем в этот поток нового N+1 клиента

Я на верном пути?

В целом да, только пункты 3-5 лучше убрать. Один сокет -- один поток.


Название: Re: Алгоритм высоконагруженного сервера
Отправлено: RedDog от Январь 19, 2011, 11:48
Один сокет -- один поток.
10 000 потоков сервер выдержит!?


Название: Re: Алгоритм высоконагруженного сервера
Отправлено: BRE от Январь 19, 2011, 11:53
10 000 потоков сервер выдержит!?
Некоторые выдерживают.
http://ru.wikipedia.org/wiki/Проблема_10000_соединений (http://ru.wikipedia.org/wiki/Проблема_10000_соединений)

Упс. Это я про соединения.
10 000 потоков не надо. Модель - на каждого клиента свой поток - скорее подходит для лабораторной работы, чем для боевых условий.
Посмотри на алгоритм работы, например, nginx.
Кстати, мы здесь несколько раз обсуждали подобные темы. Поищи.


Название: Re: Алгоритм высоконагруженного сервера
Отправлено: ufna от Январь 19, 2011, 12:00
Мне кажется, при таком числе соединений, работает не один сервер, а кластер.


Название: Re: Алгоритм высоконагруженного сервера
Отправлено: brankovic от Январь 19, 2011, 12:55
Упс. Это я про соединения.
10 000 потоков не надо. Модель - на каждого клиента свой поток - скорее подходит для лабораторной работы, чем для боевых условий.

На работе по 2000 тредов демона отлично работали (под линукс). Но балансировщик nginx стоял и да, кластер.

Посмотри на алгоритм работы, например, nginx.

Если задача просто отдать файл, то можно выпилить а-ля nginx по асинхронной схеме. Как только задача усложняется, то сразу лучше создавать тред на коннект, так удобнее в разы. А ресурсов треды не так много жрут (опять в линуксе).

Мне кажется, при таком числе соединений, работает не один сервер, а кластер.

Согласен, т.к. непонятно, как этот один сервер с 10k коннектами будет отдавать 10k файлов по 150 мб. Какой же канал нужен, чтобы от такой отдачи толк был?


Название: Re: Алгоритм высоконагруженного сервера
Отправлено: BRE от Январь 19, 2011, 13:36
Как только задача усложняется, то сразу лучше создавать тред на коннект, так удобнее в разы.
Удобнее для кого, для разработчика? Согласен, реализуется проще.
Эффективней в работе? Сомневаюсь.

А ресурсов треды не так много жрут (опять в линуксе).
Не так много, по сравнению с чем?
Попробуй по-запускать не 2 000 потоков, а 5 000, 10 000. И не на кластере.


Название: Re: Алгоритм высоконагруженного сервера
Отправлено: Sahab от Январь 19, 2011, 13:55
каждый поток - на каждый клиент (соединение) - это бред
Цитировать
Нет не заткнется) Иначе ни как...
- улыбнуло

[added]
Кстати подобная тема уже поднималась.


Название: Re: Алгоритм высоконагруженного сервера
Отправлено: brankovic от Январь 19, 2011, 14:42
Удобнее для кого, для разработчика?

Да. Когда задача всё время усложняется, то тащить за собой асинхронную архитектуру становится очень тяжело.

Эффективней в работе? Сомневаюсь.

Не эффективнее, а "не на много хуже". Тред пулу, например, уступает на копейки. Асинхронный же вариант  ещё чуть шустрее, но учитывая возню с разработкой оно того не стоит.

А ресурсов треды не так много жрут (опять в линуксе).
Не так много, по сравнению с чем?
Попробуй по-запускать не 2 000 потоков, а 5 000, 10 000. И не на кластере.

Не так много, как top пишет. Большая часть памяти маппится, но не используется. 10000 тредов на тестах тянет легко, но реальный сервер под нагрузкой просто не отрабатывал больше 1000-2000 коннектов.

edit: т.е. накладные расходы cpu на создание треда были << логики треда, а накладные расходы памяти на тред << размера базы данных в памяти

каждый поток - на каждый клиент (соединение) - это бред

зависит от задачи, но ладно, в данной может и бред. Просто реально прежде чем выпилить убер-асинк-сервер, может попробовать простой вариант и посмотреть, во что упираемся? В гигабитную сетевушку, например, или в неприемлимую скорость для каждого из 10000 клиентов.


Название: Re: Алгоритм высоконагруженного сервера
Отправлено: BRE от Январь 19, 2011, 18:15
Не эффективнее, а "не на много хуже". Тред пулу, например, уступает на копейки. Асинхронный же вариант  ещё чуть шустрее, но учитывая возню с разработкой оно того не стоит.

Не так много, как top пишет. Большая часть памяти маппится, но не используется. 10000 тредов на тестах тянет легко...

А ты сам пробовал запускать или так думаешь?  ;)

Вот для примера такая программа:
Код
C++ (Qt)
#include <QCoreApplication>
#include <QThread>
 
 
class Thread : public QThread
{
public:
explicit Thread() : QThread( 0 )
{
setStackSize( 64000 );
}
 
protected:
virtual void run()
{
for(;;)
sleep( 1 );
}
 
};
 
int main( int argc, char **argv )
{
QCoreApplication app( argc, argv );
 
for( int i = 0; i < 10000; ++i )
{
Thread *th = new Thread();
th->start();
}
 
return app.exec();
}
 

У меня она откушала 92 Мб реальной (не виртуальной!) памяти и почти 20% процессорного времени (по мнению top'а).
Заметь, проверял это на не самой последней машине (4 ядра x86_64, память DDR3 и т.д.).

Только на переключения контекста между 10 000 потоков мы потратили почти пятую часть процессорного времени, ну и немного памяти на стеки.  ;)


Название: Re: Алгоритм высоконагруженного сервера
Отправлено: JamS007 от Январь 20, 2011, 20:45
Как сказал один человек на этом форуме: "потоки не плодят ядра в системе".

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

По моему лучший вариант в таком случае - количество тредов = количество ядер в системе. Сервер в таком случае функционирует приблизительно так:
В главном потоке обрабатываются все соединения. Каждое новое соединение проверяется в бан-листе и если его там нет - передается дескриптор сокета в наименее загруженный рабочий поток, в котором осуществляется последующая обработка клиента.

Коэффициент загруженности потоков определять каждый раз, когда нужно передать нового клиента.


Название: Re: Алгоритм высоконагруженного сервера
Отправлено: _govorilka от Январь 21, 2011, 08:44
А почему если надо всего лишь отдавать файлики в сеть просто не взять nginx? Чем существующие решения не устраивают?

Писать высоко нагруженный сервер на Qt... Мне, кажется, что вместо решение проблемы с нитями, тут надо подумать: "а нужны ли в данном проекте сигналы и слоты, которые в 10-100 медленнее обычных вызовов функций"...

Интересно, а кто-нибудь когда-нибудь вообще писал демоны на Qt, с такой нагрузкой, как здесь описано?.. Только не ради курсовой или диплома, написать и использовать не одно и тоже...


Название: Re: Алгоритм высоконагруженного сервера
Отправлено: RedDog от Январь 21, 2011, 09:52
А почему если надо всего лишь отдавать файлики в сеть просто не взять nginx? Чем существующие решения не устраивают?

Писать высоко нагруженный сервер на Qt... Мне, кажется, что вместо решение проблемы с нитями, тут надо подумать: "а нужны ли в данном проекте сигналы и слоты, которые в 10-100 медленнее обычных вызовов функций"...

Интересно, а кто-нибудь когда-нибудь вообще писал демоны на Qt, с такой нагрузкой, как здесь описано?.. Только не ради курсовой или диплома, написать и использовать не одно и тоже...
Сказали написать, хозяин - барин :)


Название: Re: Алгоритм высоконагруженного сервера
Отправлено: _govorilka от Январь 21, 2011, 12:15
Сказали написать, хозяин - барин :)

Но если сказали...

Очень много зависит от задачи: протокол, платформа, количество клиентов. Если протокол должен быть HTTP/HTTPS то всё-таки лучше взять готовый сервер, например nginx и завернуть его в обёртки на Qt, если уж сказали. Если протокол и безопасность передачи не имеет значения, то можно попробывать P2P, тогда у тебя получиться бесплатный кластер, пример использования torrent есть в Qt.


Название: Re: Алгоритм высоконагруженного сервера
Отправлено: brankovic от Январь 21, 2011, 19:23
Не так много, как top пишет. Большая часть памяти маппится, но не используется. 10000 тредов на тестах тянет легко...

А ты сам пробовал запускать или так думаешь?  ;)

Только без кьют, примерно такой код под pthread, машина такая же (intel 4x core, 8Gb), плюс на чистом C. На счёт памяти сколько съела, так не надо setStackSize делать. В любом случае 92 мега это копейки для сервера.

У меня она откушала 92 Мб реальной (не виртуальной!) памяти и почти 20% процессорного времени (по мнению top'а).

Ну так это 10000 тредов _только_ переключающихся, и съела всего 20% core cpu time / 4 cores = 5% cpu time, не так и много, учитывая, что полезной нагрузки нет. А как только полезная нагрузка появляется, то 5% превращаются в 0.5%, просто треды не будут успевать отрабатывать.

Сказали написать, хозяин - барин :)

Я так думал, что задача учебная, для практики лучше nginx трудно сделать.


Название: Re: Алгоритм высоконагруженного сервера
Отправлено: BRE от Январь 21, 2011, 20:10
Только без кьют, примерно такой код под pthread, машина такая же (intel 4x core, 8Gb), плюс на чистом C.
А ты думаешь в Qt какие-то особые потоки? Или их как то "утолстили"? QThread это просто врапер над pthread (это под linux).

На счёт памяти сколько съела, так не надо setStackSize делать. В любом случае 92 мега это копейки для сервера.
На самом деле не важно использовал я setStackSize или нет. Установка размера стека влияет в первую очередь на виртуальную память выделяемую для процесса, реально же для стека каждого потока все равно выделилось по одной странице (4 Кб) физической памяти. А расширятся стеки будут при необходимости. Поэтому, для оценки затрат физической памяти и не важно какой использовался размер стека в потоке: 64000 байт как установил его я или 10 Мб (!) как установила бы его система по умолчанию.
Кстати, на стеки для 10 тысяч потоков нужно реальной памяти:
стек 4 Кб - 40 Мб
стек 8 Кб - 80 Мб
...
стек 64 Кб - 640 Мб
...

Ну так это 10000 тредов _только_ переключающихся, и съела всего 20% core cpu time / 4 cores = 5% cpu time, не так и много, учитывая, что полезной нагрузки нет. А как только полезная нагрузка появляется, то 5% превращаются в 0.5%, просто треды не будут успевать отрабатывать.
Нууу. Если программа, которая ничего не делая отъедает 5% процессорного времени, считается нормальной...  :)

Все таки как современные ресурсы компьютеров расслабляют разработчиков.  :)
Вместо того, что бы искать эффективные решения, можно просто попросить заказчика купить железо по-мощней, а если мощнее нет - то предложить подождать пару лет, пока оно появиться.   ;)


Название: Re: Алгоритм высоконагруженного сервера
Отправлено: brankovic от Январь 21, 2011, 22:44
Нууу. Если программа, которая ничего не делая отъедает 5% процессорного времени, считается нормальной...  :)

Не совсем так. Как только даём полезную нагрузку, число тредов упадёт (скажем, до 2000 -- просто упрёмся в мощность цпу), после этого доля переключений станет 0.01%. Т.е. в тесте 5%, в реальной задаче меньше.

Все таки как современные ресурсы компьютеров расслабляют разработчиков.  :)
Вместо того, что бы искать эффективные решения, можно просто попросить заказчика купить железо по-мощней, а если мощнее нет - то предложить подождать пару лет, пока оно появиться.   ;)

Ну да. Только один момент: железо по-мощнее уже есть всегда, поскольку есть кластера. А вопрос только в том, стОит ли платить 120 штук супер-программисту или дешевле платить 50 и на сэкономленные покупать по серваку в месяц. Тут чистая экономика.


Название: Re: Алгоритм высоконагруженного сервера
Отправлено: BRE от Январь 21, 2011, 23:12
Не совсем так. Как только даём полезную нагрузку, число тредов упадёт (скажем, до 2000 -- просто упрёмся в мощность цпу), после этого доля переключений станет 0.01%. Т.е. в тесте 5%, в реальной задаче меньше.
Ээээ... Что значит упрется в мощность цпу? А если нужно реально обслужить 5000 клиентов, пусть и с меньшей скоростью? А если 10000? Выход твой подход с этим не справиться? ;)
А еще совсем недавно, каких нибудь 10 лет назад, вычислительная мощность компьютеров была послабей, а сервера были и клиентов обслуживали...  :)

Ну да. Только один момент: железо по-мощнее уже есть всегда, поскольку есть кластера. А вопрос только в том, стОит ли платить 120 штук супер-программисту или дешевле платить 50 и на сэкономленные покупать по серваку в месяц. Тут чистая экономика.
Да это все понятно.
Все идет к тому, что скоро хомячки будут сервера писать, на java.


Название: Re: Алгоритм высоконагруженного сервера
Отправлено: developer от Январь 22, 2011, 11:08
Цитировать
Ну да. Только один момент: железо по-мощнее уже есть всегда, поскольку есть кластера. А вопрос только в том, стОит ли платить 120 штук супер-программисту или дешевле платить 50 и на сэкономленные покупать по серваку в месяц. Тут чистая экономика.

Интересно, а что потом говорить клиентам которие будут пользоваться вашим софтом (очень глючным, поскольку секономили на программисте). Им просто глубоко в носу количество ваших серваком, им нужен качественный сервис.

Тут нужно найти золотую середину, или убедить супер-программиста работать за те деньги которие вы можете платить.


Название: Re: Алгоритм высоконагруженного сервера
Отправлено: brankovic от Январь 22, 2011, 12:16
А если нужно реально обслужить 5000 клиентов, пусть и с меньшей скоростью? А если 10000?

Тогда кластер + разбиение клиентов по слоям и будет хоть миллион клиентов. Ну хорошо, допустим випилен сервер на 10к клиентов, а завтра нужно держать 100к, так всё равно придётся разносить по машинам. Тут опять вопрос: сколько времени понадобилось на выпиливание (+отладка, сервер-то сложный), сколько это стоило? Не дешевле ли было прикупить компов для тривиальной реализации, а потом выпиливать сложный сервер? А если функциональность с низким траффиком, но нетривиальной логикой, насколько просто будет добавить новую фичу в сложный сервер?

Да это все понятно.
Все идет к тому, что скоро хомячки будут сервера писать, на java.

не совсем, просто супер-программисты научатся своё время ценить больше, чем ресурсы и да, перейдут на какой-нибудь питон. Это неизбежно, рано или поздно память и ресурсы процессора станут (почти) бесконечными. Уже сейчас есть такая тенденция: пишем по-быстрому на perl/php/python, потом переписываем на C, чтобы урезать расходы, в то время, как бизнес уже работает. Постепенно этап переписывания отпадёт.


Название: Re: Алгоритм высоконагруженного сервера
Отправлено: Igors от Январь 22, 2011, 13:27
Тогда кластер + разбиение клиентов по слоям и будет хоть миллион клиентов. Ну хорошо, допустим випилен сервер на 10к клиентов, а завтра нужно держать 100к, так всё равно придётся разносить по машинам. Тут опять вопрос: сколько времени понадобилось на выпиливание (+отладка, сервер-то сложный), сколько это стоило? Не дешевле ли было прикупить компов для тривиальной реализации, а потом выпиливать сложный сервер? А если функциональность с низким траффиком, но нетривиальной логикой, насколько просто будет добавить новую фичу в сложный сервер?
Я далек от всего этого веба (и слава богу), но мне было бы интересно узнать что то за волшебный "кластер". То есть можно написать "тупо" (1 коннект на 1 клиента) и потом "кластер" решит все проблемы? Если несложно, "на пальцах" поясните основные идеи

Спасибо


Название: Re: Алгоритм высоконагруженного сервера
Отправлено: ufna от Январь 22, 2011, 13:44
А первая ссылка в гугле не? )


Название: Re: Алгоритм высоконагруженного сервера
Отправлено: brankovic от Январь 22, 2011, 13:57
Я далек от всего этого веба (и слава богу), но мне было бы интересно узнать что то за волшебный "кластер".

Кластеры бывают разные, я имею ввиду не суперкомпьютерный кластер, а множество машин соединённых по лану в датацентре. Схема примерно такая:

Есть некий сервер, пусть отдающий файлы. Есть N машин, на каждой стоит такой сервер. Есть M "внешних" машин, на которых стоит nginx. Клиент обращается на одну из внешних M машин, nginx, в зависимости от слоя клиента, проксирует запрос на один из несколько из N серверов. Существуют нюансы, но в целом всё примитивно.