Комментарии 125
278,9% CPU это интересно…
Каждые 100% — это полная загрузка одного ядра процессора.
Статью не читай, комментируй!
Статью не читал, — не комментируй!
Набросились на человека, может он просто виндузятник?
Всем спасибо, я всё понял. Даю до свидания…
Быстрый рост node.js очень радует.
Еще недавно подобные результаты были непосильной планкой.
Еще недавно подобные результаты были непосильной планкой.
Почему закрытие сокетов нагружает процессор гораздо больше, чем их открытие?
Отсылаются данные клиенту — TCP graceful shutdown
Как это ни странно, обеспечить необходимую нагрузку было сложнее, чем создать сервер. Дело в том, что TCP-соединение уникально определяется четверкой [source ip, source port, dest ip, dest port], таким образом с одной машины на 1 порт сервера можно создать не более 64 тыс одновременных соединений (по количеству source ports).
А сколько можно принять в себя соединений?
вообще, оно ограничивается памятью системы, памятью выделенной сетевому стеку и количеством файловых дескрипторов в системе. Предел последнего определяется типом int в С:
root@oxpa-desk:~# sysctl fs.file-max=2147483648
fs.file-max = 2147483648
root@oxpa-desk:~# grep -i dhc /var/log/messages*^C
root@oxpa-desk:~# sysctl -a | grep file-max
error: "Invalid argument" reading key "fs.binfmt_misc.register"
error: permission denied on key 'net.ipv4.route.flush'
error: permission denied on key 'net.ipv6.route.flush'
fs.file-max = -18446744071562067968
root@oxpa-desk:~# sysctl fs.file-max=2147483647
fs.file-max = 2147483647
root@oxpa-desk:~# sysctl -a | grep file-max
error: "Invalid argument" reading key "fs.binfmt_misc.register"
fs.file-max = 2147483647
дополню сам себя: ядро выделяет структуру sk_buf для кадого соединения. В эту структуру входят указатели на буферы. Но размер самой структуры зависит от архитектуры и не превышает 250 байт. так что можно считать, что для каждого соединения выделяется 2 буфера (чтение и запись) + 250 байт. Разделите объём своей памяти на эти настройки и получите максимальное количество соединений для своей машины. Однако учтите, что софту так же требуется память ;)
А как заранее узнать размер этих «два буфера»? Размер буфера на передачу не может быть меньше TCP-окна (которое неизвестно до согласования этого параметра в конкретном соединении), т.е. 8Кб, к примеру, но на практике размер этих буферов в Linux вроде бы десятки килобайт (?) на каждое соединение. Т.е. 250 байт вообще погоды не делают в подсчете.
oxpa@oxpa-desktop:~$ sysctl -a 2>/dev/null| grep tcp_[rw]mem
net.ipv4.tcp_wmem = 4096 16384 4194304
net.ipv4.tcp_rmem = 4096 87380 4194304
Первые значения — сколько байт будет выделено под буферы при любых условиях.
Второе — при обычном течении «жизни».
Третье — сколько максимум может занять буфер.
Дополнительно можете почитать про tcp_mem, станет ясно, что значит «при любых условиях».
250 байт на 1 миллионе соединений превращаются в 238 мегабайт памяти ;) Буферы, как минимум, — в
7 с половиной гигабайт
. Мне кажется, это сопоставимые цифры. ((((4096 * 2) * 1 000 000) / 1024) / 1024) / 1024 = 7.62939453
Понятно, что максимальный размер буфера может быть больше. Но для записи слова ping хватит и 4к ;)
Можно легко сделать через IPv6 на одном сервере.
Благо адресов IPv6 можно сделать дофига. Тот же Hetzner дает /64 подсети всем желающим.
Благо адресов IPv6 можно сделать дофига. Тот же Hetzner дает /64 подсети всем желающим.
Хотелось бы сравнений с фреймворками питона и расхваливаемым Erlang'ом.
А зачем фреймворкам питона участвовать в таком соревновании? Они, вроде бы, не для этого…
twisted и tornado вполне себе для этого
О, черт, забыл про них…
Gevent в догонку.
Но, вообще, недавно было хорошее сравнение 10к вебсокет — соединений eric.themoritzfamily.com/websocket-demo-results-v2.html
Но, вообще, недавно было хорошее сравнение 10к вебсокет — соединений eric.themoritzfamily.com/websocket-demo-results-v2.html
Интересно. 2 миллиона на более мощном железе (24 cpu). CPU и памяти занимает больше чем в два раза. Но непонятно, это продакшн или синтетический тест.
Судя по всему, это продакшн. Используется FreeBSD и Эрланг.
Я видел эту ссылку, но, к сожалению, слишком мало информации о том, что конкретно они делают а также какие конкретно оптимизации они провели.
Я видел эту ссылку, но, к сожалению, слишком мало информации о том, что конкретно они делают а также какие конкретно оптимизации они провели.
Тесты тестами, а по ссылке данные с продакшна whatsapp.com (см. их предшествующую статью, указанную в начале этой, посвященную 1млн. blog.whatsapp.com/?p=170). Подобных продакшнов с нодой что-то я пока не видал =)
За эрлангом далеко ходить не надо — habrahabr.ru/post/111600/
Да, я упомянул английский оригинал этой статьи. К сожалению, для достижения миллиона соединений в 2008 году автору пришлось дописывать к эрлангу отдельный модуль на C++, иначе по его подсчетам ему было необходимо 36 Гб памяти.
А в целом я тоже с удовольствием посмотрел бы на поведение современного эрланга под такой нагрузкой. К сожалению, я сам в нём не очень разбираюсь.
А в целом я тоже с удовольствием посмотрел бы на поведение современного эрланга под такой нагрузкой. К сожалению, я сам в нём не очень разбираюсь.
Вот старая статья: fprog.ru/2010/issue6/dmitry-demeshchuk-node.js-vs-erlang/
>fprog
>node.js
> 2010
Сильно сомневаюсь в объективности статьи. При этом автор практически не затронул проблемы ерланга (сообщество, библиотеки, среда разработки)
>node.js
> 2010
Сильно сомневаюсь в объективности статьи. При этом автор практически не затронул проблемы ерланга (сообщество, библиотеки, среда разработки)
хотелось бы сравнения с boost.asio.
Не преувеличивайте. Отрезать из трафика даже 40 серверов с фиксированными IP — ничего сложного. реальным DDoS тут не пахнет.
Потом будет эпичный Bill-check от амазона))
Очень интересно :)
Цифры огромные, но если задуматься, то не так уж и удивительно. Это по сути и есть самый оптимальный случай для event-based фреймворков: когда обработка запроса — это всего лишь отравка простого сообщения.
В жизни такое вряд ли встретится. А интересно, например, что будет если для отправки сообщения нужно залезть в базу, или сделать syscall, или обратиться к данным, защищенным мьютексом. И отдельным случаем рассмотреть ситуацию, когда выполняется какое-то ресурсоемкое вычисление.
Цифры огромные, но если задуматься, то не так уж и удивительно. Это по сути и есть самый оптимальный случай для event-based фреймворков: когда обработка запроса — это всего лишь отравка простого сообщения.
В жизни такое вряд ли встретится. А интересно, например, что будет если для отправки сообщения нужно залезть в базу, или сделать syscall, или обратиться к данным, защищенным мьютексом. И отдельным случаем рассмотреть ситуацию, когда выполняется какое-то ресурсоемкое вычисление.
Обработка запроса, правда, не совсем корректный термин в данном контексте. Надеюсь понятно, что я говорил про вот эту анонимную функцию:
var pingInterval = setInterval(function() {
res.write('ping');
}, 20*1000);
Отправка простого сообщения — это тоже syscall, если что :) Прочитать же данные нужно.
Ресурсоёмкие вычисления заведомо не для event loop.
При нагрузке в 300% из 800% вполне можно позволить иметь пул на 1000 соединений в базу и делать туда read/write. Миллион на реальных условиях не выжать, но всё равно цифры будут достаточные.
Ресурсоёмкие вычисления заведомо не для event loop.
При нагрузке в 300% из 800% вполне можно позволить иметь пул на 1000 соединений в базу и делать туда read/write. Миллион на реальных условиях не выжать, но всё равно цифры будут достаточные.
Отправка простого сообщения — это тоже syscall, если что :)
Не спорю, но в ноде же асинхронное I/O по умолчанию. Нет сомнений, что тут с производительностью вопрос решен, и не надо ждать, пока данные отправятся :)
При нагрузке в 300% из 800% вполне можно позволить иметь пул на 1000 соединений в базу и делать туда read/write.
Так вот цифры как раз интересны. Я ж не критикую :)
Райан (тот, который эту самую ноду написал), в твиттер линк запостил на эту статью: twitter.com/ryah/status/235765301940191232
>В качестве интересного реального применения хорошо было бы построить аналог jabber-сервера и потестить его на таких же объемах.
У вконтакте xmpp-сервер написан на nodejs.
У вконтакте xmpp-сервер написан на nodejs.
А мастер случайно не ограничивает всю эту грядку? Может, если вместо него воткнуть haproxy, то ещё полегчает?
Вроде нет. Мастер практически не грузит процессор и занимает всего 50 мб памяти. Как я понимаю, он просто передаёт открытые дескрипторы и через себя никаких данных не пропускает.
Другой вопрос — можно ли открытые дескрипторы между воркерами передавать, это бы сильно помогло в реальных приложениях в сокращении межпроцессного взаимодействия.
Другой вопрос — можно ли открытые дескрипторы между воркерами передавать, это бы сильно помогло в реальных приложениях в сокращении межпроцессного взаимодействия.
открытые дескрипторы между воркерами передаватьЕсли он на самом деле акцептит подключения в мастере и передает воркерам каждый сокет, то я сильно удивлён…
Предполагаю все же, что воркерам передается слушающий сокет и каджый форк акцептит подключения самостоятельно
В линуксе открытые дескрипторы между процессами передавать можно.
Код клиентов на разных языках/framework'ах для теста схожей функциональности можно найти по ссылкам из этой статьи: blog.virtan.com/2012/07/million-rps-battle.html
Простите, а чем вы так красиво мониторили нагрузку?
А что будет если появятся медленные соединения?
Ж!
С чего? Главное чтобы количество медленных соединений не превышало лимита одновременных соединений (заданного явно или наличием свободной памяти/запасом по CPU — не суть). Каждому соединению сразу выделяется буфер и серверу всё равно быстрое оно или медленное, лишь бы памяти на буфера хватило. Проблемы возникают когда не соединения медленные, а медленная обработка запросов, когда сервер может держать миллион соединений, но выполнять только 10 000 запросов в секунду. Тогда при одновременном миллионе соединений одно из них закроется, то есть получит ответ (если брать открыли-послали запрос-получили ответ-закрыли, а-ля http без keep-alive ) только через 100 секунд, а если будет миллион один запрос одновременно, то один из них просто отвалится.
Медленные соединения вообще-то требуют меньше ресурсов, чем быстрые.
Главная проблема медленных соединений — их количество, но тут и так миллион соединений, куда уж больше?
Главная проблема медленных соединений — их количество, но тут и так миллион соединений, куда уж больше?
>Медленные соединения вообще-то требуют меньше ресурсов, чем быстрые.
поясни
поясни
Медленное соединение требует ресурсы только на поддержку самого соединения. Быстрое — еще и на обработку поступающих запросов.
Держать миллион соединений гораздо проще, чем отвечать одновременно на миллион запросов.
Держать миллион соединений гораздо проще, чем отвечать одновременно на миллион запросов.
Медленным-то что, отвечать не требуется?
Требуется. Но только гораздо реже.
Если до сих пор не понятно, приведу формулы.
Пусть по некоторому соединению поступают запросы с периодом T.
Тогда стоимость обработки одного запроса составляет a + bT, где a — ресурсы, требуемые на саму обработку запроса, а b — ресурсы, требуемые на поддержание соединения.
Стоимость же самого соединения в единицу времени составляет a/T + b.
Вообще говоря, a и b — не совсем константы, но общей тенденции это не меняет.
А она такова: чем медленнее соединение (чем больше T), тем больше ресурсов уходит на каждый запрос, но в единицу времени тратится меньше ресурсов.
Если до сих пор не понятно, приведу формулы.
Пусть по некоторому соединению поступают запросы с периодом T.
Тогда стоимость обработки одного запроса составляет a + bT, где a — ресурсы, требуемые на саму обработку запроса, а b — ресурсы, требуемые на поддержание соединения.
Стоимость же самого соединения в единицу времени составляет a/T + b.
Вообще говоря, a и b — не совсем константы, но общей тенденции это не меняет.
А она такова: чем медленнее соединение (чем больше T), тем больше ресурсов уходит на каждый запрос, но в единицу времени тратится меньше ресурсов.
T в обоих случаях одинаковое. Количество принятых запросов никак на зависит от того «медленные» они или «быстрые».
«Медленные» — это, к примеру, запрос к базе данных. Web-сервер будет в цикле отдавать эти запросы драйверу БД. Драйвер базы будет обрабатывать запросы по мере их поступления. Сервер-то ладно, примет 1000000 запросов, так как он — супер-пупер Node.js, а вот драйвер БД не думаю, что ответит так быстро. Поэтому front-end сервер будет ждать, поэтому клиенты будут ждать. Поэтому, я считаю, пост из двух символов чуть выше, был справедлив.
«Медленные» — это, к примеру, запрос к базе данных. Web-сервер будет в цикле отдавать эти запросы драйверу БД. Драйвер базы будет обрабатывать запросы по мере их поступления. Сервер-то ладно, примет 1000000 запросов, так как он — супер-пупер Node.js, а вот драйвер БД не думаю, что ответит так быстро. Поэтому front-end сервер будет ждать, поэтому клиенты будут ждать. Поэтому, я считаю, пост из двух символов чуть выше, был справедлив.
Не забывайте: T — это период поступления запросов по одному соединению! А если клиент «медленный», то и запросы он будет отдавать реже (ведь ему нужно дождаться ответа от сервера по прошлому запросу, прежде чем выдавать новый).
В этом случае я не спорю, запросы он будет отдавать реже, но реже он будет отдавать всем клиентам, так как event loop — это единственный поток.
Каждый клиент в данном случае зависит от запросов других клиентов. Вот придет очень медленный клиент — все будут ждать ответы на свои запросы очень долго, хотя и все соединены с сервером.
В данном случае автор поста держал 1000000 одновременных соединений, весь смысл в которых — передача одинаковых строк. Если будут медленные клиенты — да, потребление памяти увеличится незначительно, но время отклика сервера очень сильно возрастет.
Каждый клиент в данном случае зависит от запросов других клиентов. Вот придет очень медленный клиент — все будут ждать ответы на свои запросы очень долго, хотя и все соединены с сервером.
В данном случае автор поста держал 1000000 одновременных соединений, весь смысл в которых — передача одинаковых строк. Если будут медленные клиенты — да, потребление памяти увеличится незначительно, но время отклика сервера очень сильно возрастет.
Не верно.
Если придет медленный клиент — его запрос не попадет в event loop до тех пор, пока не будет прочитан полностью.
Весь смысл асинхронного программирования в том и заключается, что никто ничего никогда не ждет. Нет работы — ставь коллбэки и уступай очередь.
Если придет медленный клиент — его запрос не попадет в event loop до тех пор, пока не будет прочитан полностью.
Весь смысл асинхронного программирования в том и заключается, что никто ничего никогда не ждет. Нет работы — ставь коллбэки и уступай очередь.
Могу ошибаться, но e2e4 имеел ввиду другое (просто неудачно использовал термин «медленный клиент»). Проблемой для event-loop будет если control flow задержиться на обработке какого-то запроса. Не важно по какой причине: затянувшийся computation, блокирующий запрос к базе, или еще что-то. Для одного клиента это может быть незаметно, ну на 1 сек сервер задумался — с кем не бывает. Но в данном случае получается, что 1 млн клиентов ждали эту одну секунду — а это совокупно более 11 суток потраченного времени ваших клиентов. И это даст очень резкий пик на графике среднего времени ответа (потому что эта 1 сек пойдет в плюс всем).
Синтетичность теста в том, что он делает достоверно простую операцию независимо ни от каких факторов. В продакшин системах, выполняющих какую-то полезную логику, все намного сложнее.
Синтетичность теста в том, что он делает достоверно простую операцию независимо ни от каких факторов. В продакшин системах, выполняющих какую-то полезную логику, все намного сложнее.
Да, в event loop web-сервера не попадает, но драйверу БД, к примеру, придется обработать все запросы всех этих клиентов. Если он также будет асинхронный, то у меня вопросов нет, хотя любой ввод/вывод — это блокирующая операция.
> никто ничего никогда не ждет. Нет работы — ставь коллбэки и уступай очередь.
Если эти коллбэки и коллбэки этих коллбэков также будут асинхронными, то да. Но такого не бывает. По крайней мере не слышал.
P.S. Асинхронная модель — она как паразит — должна заразить весь продукт. Иначе — задержки отклика.
> никто ничего никогда не ждет. Нет работы — ставь коллбэки и уступай очередь.
Если эти коллбэки и коллбэки этих коллбэков также будут асинхронными, то да. Но такого не бывает. По крайней мере не слышал.
P.S. Асинхронная модель — она как паразит — должна заразить весь продукт. Иначе — задержки отклика.
Именно в этом сила экосистемы Node.js — там всё асинхронное по умолчанию. И ввод-вывод тоже асинхронный, как файловый, так и сетевой (по крайней мере до уровня операционной системы, а дальше нам не прыгнуть).
С базами данных — все драйвера БД в Node.js асинхронные, насколько я знаю. Т.е. сама база может быть и синхронная, но взаимодействие с ней — нет. Event Loop никогда не ждёт ответа, операционная система сама оповещает когда нужно, что ответ пришёл.
Вот с долгими вычислениями — может быть проблема, но есть предположение, что в большинстве веб-серверов они не возникают, а если и возникают, то можно опять же асинхронно передать задачу другому воркеру или серверу.
С базами данных — все драйвера БД в Node.js асинхронные, насколько я знаю. Т.е. сама база может быть и синхронная, но взаимодействие с ней — нет. Event Loop никогда не ждёт ответа, операционная система сама оповещает когда нужно, что ответ пришёл.
Вот с долгими вычислениями — может быть проблема, но есть предположение, что в большинстве веб-серверов они не возникают, а если и возникают, то можно опять же асинхронно передать задачу другому воркеру или серверу.
> Event Loop никогда не ждёт ответа
Зато все клиенты ждут, пока БД выполнит запросы.
Будет время — попробую сделать тест (как вы это любите), но не с простым «ping — pong», а с обработкой запросов.
Модель может быть на 100% асинхронной неблокирующей, но от нее будет толку 0: никто работать не хочет, а только перекладывают задачи с одного на другого.
Зато все клиенты ждут, пока БД выполнит запросы.
Будет время — попробую сделать тест (как вы это любите), но не с простым «ping — pong», а с обработкой запросов.
Модель может быть на 100% асинхронной неблокирующей, но от нее будет толку 0: никто работать не хочет, а только перекладывают задачи с одного на другого.
Просто тут нет ситуации, когда БД выполняет 1 секунду запрос от 1 клиента, а остальные 999999 клиентов эту секунду ждут из-за того, что Event Loop заблокирован. В реальности сразу после посылки запроса БД (например, записи в TCP сокет БД) управление возвращается Event Loop-у. Далее идет обработка событий от других клиентов в штатном режиме, а через секунду от операционной системы приходит событие, что в TCP сокете БД появились данные, они обрабатываются и возвращаются клиенту. То, что сама БД синхронная или асинхронная — совершенно не важно. Важно, что работа с ней асинхронная, через асинхронный механизм TCP сокетов.
Совершенно другой вопрос, если, например, веб-сервер может обрабатывать 10 тыс запросов в секунду, каждый запрос генерирует 1 запрос в БД, а БД может обрабатывать только 1 тыс в секунду. Тогда очевидно, что все очереди переполнятся и скорость упадёт до скорости БД. Но, я так понимаю, вы не этот случай имели в виду.
Совершенно другой вопрос, если, например, веб-сервер может обрабатывать 10 тыс запросов в секунду, каждый запрос генерирует 1 запрос в БД, а БД может обрабатывать только 1 тыс в секунду. Тогда очевидно, что все очереди переполнятся и скорость упадёт до скорости БД. Но, я так понимаю, вы не этот случай имели в виду.
Кирилл,
судя по описанию, много открытых соединений появилось именно из-за того что node.js не успевал их обрабатывать, хотя обработка одного соединения довольно-таки быстрая.
т.е. интересен график скорости реакции (зависимость скорости обработки соединения от кол-во соединений).
судя по описанию, много открытых соединений появилось именно из-за того что node.js не успевал их обрабатывать, хотя обработка одного соединения довольно-таки быстрая.
т.е. интересен график скорости реакции (зависимость скорости обработки соединения от кол-во соединений).
akalend, вы ошиблись.
Если внимательно посмотреть на код клиента, то будет видно, что клиенты поддерживают заданную нагрузку на сервер, независимо от того, как быстро сервер работает.
Если внимательно посмотреть на код клиента, то будет видно, что клиенты поддерживают заданную нагрузку на сервер, независимо от того, как быстро сервер работает.
Akalend, здесь задача ставилась другая. Сервер принимает соединения (ок 10000 в сек если интересно), но не закрывает их. Это дает возможность инициировать события с сервера. Посмотрите в интернетах термин HTTP Comet.
Вроде ничего страшного не предвидится. В текущем тесте передается один пакет в 20 секун, мне кажется это уже достаточно медленно. Возможно, если вы опишете подробнее что вы имеете в виду, тогда можно будет сделать тест.
Под медленными клиентами, я понимал в первую очередь людей у которых плохой или ненадежный интернет.
Как работает ваш асинхронный сервер — вы сказали send и отправили буфер (фактически скопировали память с userspace в память которая уйдет уже в сокет). Интересный факт в том, что если вы оправляете большой ответ, скажем два пакета, пока не придет два подтверждения от клиента. Т.е. если у вас много медленных клиентов, то ядро своими буферами с ответами съест какую-то память.
Далее, вы в примере используете ip conntrack, судя по настройкам в тесте, что увеличит время в пессимистичном раскладе которое будет использоваться больший объем памяти.
Т.е. в этих тестах вы совершенно не следили за памятью ядра — а она тоже будет расходоваться.
Как работает ваш асинхронный сервер — вы сказали send и отправили буфер (фактически скопировали память с userspace в память которая уйдет уже в сокет). Интересный факт в том, что если вы оправляете большой ответ, скажем два пакета, пока не придет два подтверждения от клиента. Т.е. если у вас много медленных клиентов, то ядро своими буферами с ответами съест какую-то память.
Далее, вы в примере используете ip conntrack, судя по настройкам в тесте, что увеличит время в пессимистичном раскладе которое будет использоваться больший объем памяти.
Т.е. в этих тестах вы совершенно не следили за памятью ядра — а она тоже будет расходоваться.
Действительно, пока не придёт подтверждения, вся отправленная информация хранится в буфере ядра.
На графиках в статье суммарный объём памяти, используемой ядром, обозначается серой полосой (разница между Total Netto и RSS Sum), это около 4 Гб в пике, по 4 кб на соединение. Думаю, этого должно хватить для обслуживания совсем медленных клиентов если их будет не большинство.
К тому же, т.к. в тесте клиентские машины были равномерно в 3-х датацентрах AWS, два из них в США, а сервер — в Германии, а, думаю, пинг у них был не менее 200-300 мс, то это можно считать вполне реалистичной пользовательской нагрузкой (если, конечно, не целиться на мобильные клиенты — там, конечно, всё по другому).
На графиках в статье суммарный объём памяти, используемой ядром, обозначается серой полосой (разница между Total Netto и RSS Sum), это около 4 Гб в пике, по 4 кб на соединение. Думаю, этого должно хватить для обслуживания совсем медленных клиентов если их будет не большинство.
К тому же, т.к. в тесте клиентские машины были равномерно в 3-х датацентрах AWS, два из них в США, а сервер — в Германии, а, думаю, пинг у них был не менее 200-300 мс, то это можно считать вполне реалистичной пользовательской нагрузкой (если, конечно, не целиться на мобильные клиенты — там, конечно, всё по другому).
Тогда тут мой пардон, я не смог интерпретировать Total Netto как ядерную память.
Да, 4kb современный линукс выделяет на одно соединение, это правда.
Если данное решение ориентировано на сервис, у которого 80% пользователей будут иметь стабильное (тут скорее вопрос не в latency, а именно в bandwish) соединение с сервером — то вопросов нет.
Если там будут мобильные клиенты, то я бы закладывался что total netto будет выше.
Так же я бы закладывался что total netto будет выше, в случае если вы будете посылать более большие ответы.
Да, 4kb современный линукс выделяет на одно соединение, это правда.
Если данное решение ориентировано на сервис, у которого 80% пользователей будут иметь стабильное (тут скорее вопрос не в latency, а именно в bandwish) соединение с сервером — то вопросов нет.
Если там будут мобильные клиенты, то я бы закладывался что total netto будет выше.
Так же я бы закладывался что total netto будет выше, в случае если вы будете посылать более большие ответы.
В свою очередь извиняюсь, что не сделал это очевидным) С остальным полностью согласен!
Честного говоря не понимаю какая разница медленное соединение или быстрое, если их одновременное количество одинаково, а сообщения влезают в минимальный буфер и всё же успевают отдаваться не переполняя и не вызывая роста буфера. Грубо говоря, если сервер генерирует по килобайту в секунду для каждого клиента, а скорость сервер-клиент не ниже 9600 бит в секунду.
Другое дело, если мы говорим не о количестве одновременных соединений, а о постоянном количестве запросов за период, при этом некоторые клиенты за этот период не будут успевать выбирать ответ (latency или bandwish — не суть, если речь о протоколе с подтверждением доставки) — тогда, да, рано или поздно количество соединений достигнет такого числа, что у сервера будет исчерпан лимит на количество соединений и/или размер буферов. Грубо говоря он будет держать миллион медленных соединений, а для миллион первого уже не сможет выделить буфер, даже если оно будет быстрым и общая скорость запросов невелика относительно возможностей сервера.
Другое дело, если мы говорим не о количестве одновременных соединений, а о постоянном количестве запросов за период, при этом некоторые клиенты за этот период не будут успевать выбирать ответ (latency или bandwish — не суть, если речь о протоколе с подтверждением доставки) — тогда, да, рано или поздно количество соединений достигнет такого числа, что у сервера будет исчерпан лимит на количество соединений и/или размер буферов. Грубо говоря он будет держать миллион медленных соединений, а для миллион первого уже не сможет выделить буфер, даже если оно будет быстрым и общая скорость запросов невелика относительно возможностей сервера.
Т.к. у нас TCP нам нужно держать буфер пока не придет ACK.
4кб расходы системы на буфер (на самом деле их несколько, просто тут не секундная летенси и получается как будто 4кб, в реальности будет где-то 12-16).
Если у нас идет поток 10,000 запросов в секунду, то мы будем потреблять как минимум буфера на эти соеденения + дельту на передачу данных. Если буфер передается за 1 секунду до клиента, то нам нужно ~100 мегабайт памяти. Если начинаются потери и идут всякие ретрансмиты, то у нас требования по памяти вырастают.
Я не говорю что невозможно сделать 1М соединений с сервером. У меня пока рекорд около 4,5М на amazon :), тут просто надо понимать, что есть ограничения другого уровня и их тоже надо учитывать.
4кб расходы системы на буфер (на самом деле их несколько, просто тут не секундная летенси и получается как будто 4кб, в реальности будет где-то 12-16).
Если у нас идет поток 10,000 запросов в секунду, то мы будем потреблять как минимум буфера на эти соеденения + дельту на передачу данных. Если буфер передается за 1 секунду до клиента, то нам нужно ~100 мегабайт памяти. Если начинаются потери и идут всякие ретрансмиты, то у нас требования по памяти вырастают.
Я не говорю что невозможно сделать 1М соединений с сервером. У меня пока рекорд около 4,5М на amazon :), тут просто надо понимать, что есть ограничения другого уровня и их тоже надо учитывать.
да, с мобильными клиентами у нас сервер вылетает по памяти на лонгпуле…
думаю как решить эту проблему
думаю как решить эту проблему
Можно было бы создать 16 сетевых интерфейсов с разными IP
А что мешало на один интерфейс повесить 16 IP адресов?
Очевидно, отсутствие этих самых дополнительных адресов.
Я, конечно, отродясь не пользовался услугами подобного рода хостеров, но если они могут выдать две машины в одном броадкастовом сегменте и без фильтрации на порту, то можно назначить интерфейсам абсолютно произвольную адресацию, хоть из сети 1.1.1.0/24. Оно не будет маршрутизироваться вне сегмента, но в пределах его — без проблем.
Проблемы начнутся, если подобное кто-нибудь заметит…
А это запрещено? Никто ведь не собирается маршрутизировать пакеты с этими адресами наружу. А что творится в VLANе клиента — дело клиента. Хостеру это никак не повредит.
Если клиенту предоставлен VLAN — то действительно, никаких проблем нет.
А вот если клиенту выдано всего лишь «две машины в одном броадкастовом сегменте и без фильтрации на порту», то подобное поведение может быть расценено как попытка нарушения работы сети.
А вот если клиенту выдано всего лишь «две машины в одном броадкастовом сегменте и без фильтрации на порту», то подобное поведение может быть расценено как попытка нарушения работы сети.
А вот если клиенту выдано всего лишь «две машины в одном броадкастовом сегменте и без фильтрации на порту», то подобное поведение может быть расценено как попытка нарушения работы сети.
В любом случае, Хецнер выдает /64 сеть IPv6. Это чертовски много адресов. И можно назначить на один интерфейс много-много v6 адресов, по ним и создавать нагрузку.
Проще и более масштабируемо было отдать 80 центов амазону) Не нужно доп машины и переписки с хостером. Плюс, географически распределенные клиенты создают более реалистичные условия.
Тут мне в голову пришла безумная идея: генерить коннекты к серверу на самом сервере. То есть, скажем, 16 воркеров, каждый цепляется со своего адреса на лупбек. Памяти это выжрет немерено…
> Можно ли передавать открытый дескриптор между процессами, группируя их по комнатам,
у меня получилось передать ссылку на открытый дескриптор через shmem (У Стивенсона описано про передачу ресурсов через системную очередь),
но проблема в том, что принимающий процесс не должен открывать/закрывать другие файлы, иначе ссылка в процессе может сбиться.
у меня получилось передать ссылку на открытый дескриптор через shmem (У Стивенсона описано про передачу ресурсов через системную очередь),
но проблема в том, что принимающий процесс не должен открывать/закрывать другие файлы, иначе ссылка в процессе может сбиться.
По алгоритму нагла можно почитать тут — en.wikipedia.org/wiki/Nagle's_algorithm
Если коротко, то это дополнительная буферизация, которая дает выигрыш, если приложение часто отправляет маленькие куски данных по сети. Это будет работать в том случае, если вы отправляете постоянно данные в сокет размером заметно меньшим половине MTU (в этом случае несколько пакетов можно отправить один TCP-пакетом и сэкономить на передаче заголовков TCP-пакетов). В случае HTTP-сервера этот алгоритм не имеет смысла использовать.
Если коротко, то это дополнительная буферизация, которая дает выигрыш, если приложение часто отправляет маленькие куски данных по сети. Это будет работать в том случае, если вы отправляете постоянно данные в сокет размером заметно меньшим половине MTU (в этом случае несколько пакетов можно отправить один TCP-пакетом и сэкономить на передаче заголовков TCP-пакетов). В случае HTTP-сервера этот алгоритм не имеет смысла использовать.
Выглядит круто. Но пугает одно Но: допустим у меня есть нагрузка в 2кк клиентов и она распределена между 2мя серверами. Что будет если один из них внезапно умрёт? Ведь 1кк клиентов придут на 2й сервер, причём сразу — 1кк одновременных попыток соединений. На установку соединения ведь необходимо время, а значит второй сервер будет не доступен до тех пор, пока все соединения не будут установлены/отброшены. Что будет в продакшене? 1кк соединений конечно хорошо, но может лучше 10 по 100к и равномерное размазывание нагрузки с упавшего сервера?
А для приема 1kk соединений вам не требовалось писать Хецнеру? Я знаю, что на VPS их файервол ограничивает количество одновременных соединений до ~100/сек. На dedicated они это не делают?
Я правильно понял что вы на 1IP и 1 порту(8888) смогли обслуживать одновременно 1кк постоянных коннектов? Ведь кол-во одновременных TCP соеденений для 1IP:port ограничено net.ipv4.ip_local_port_range(максимально 65535).
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Миллион одновременных соединений на Node.js