$30 off During Our Annual Pro Sale. View Details »
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Comet-сервер своими руками
Search
Dmitry Demeshchuk
October 24, 2012
Programming
7
1.2k
Comet-сервер своими руками
Мой и Макса Лапшина доклад на Highload++ 2012.
Dmitry Demeshchuk
October 24, 2012
Tweet
Share
More Decks by Dmitry Demeshchuk
See All by Dmitry Demeshchuk
Untitled.pdf
doubleyou
0
120
Other Decks in Programming
See All in Programming
【CA.ai #3】ワークフローから見直すAIエージェント — 必要な場面と“選ばない”判断
satoaoaka
0
250
バックエンドエンジニアによる Amebaブログ K8s 基盤への CronJobの導入・運用経験
sunabig
0
160
TUIライブラリつくってみた / i-just-make-TUI-library
kazto
1
390
AIコードレビューがチームの"文脈"を 読めるようになるまで
marutaku
0
360
AIコーディングエージェント(Manus)
kondai24
0
190
エディターってAIで操作できるんだぜ
kis9a
0
730
ローターアクトEクラブ アメリカンナイト:川端 柚菜 氏(Japan O.K. ローターアクトEクラブ 会長):2720 Japan O.K. ロータリーEクラブ2025年12月1日卓話
2720japanoke
0
730
sbt 2
xuwei_k
0
300
テストやOSS開発に役立つSetup PHP Action
matsuo_atsushi
0
160
Github Copilotのチャット履歴ビューワーを作りました~WPF、dotnet10もあるよ~ #clrh111
katsuyuzu
0
110
ZOZOにおけるAI活用の現在 ~モバイルアプリ開発でのAI活用状況と事例~
zozotech
PRO
9
5.7k
ハイパーメディア駆動アプリケーションとIslandアーキテクチャ: htmxによるWebアプリケーション開発と動的UIの局所的適用
nowaki28
0
420
Featured
See All Featured
We Have a Design System, Now What?
morganepeng
54
7.9k
Git: the NoSQL Database
bkeepers
PRO
432
66k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
9.8k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
9
1k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
48
9.8k
Large-scale JavaScript Application Architecture
addyosmani
515
110k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.6k
The Art of Programming - Codeland 2020
erikaheidi
56
14k
Fireside Chat
paigeccino
41
3.7k
How to train your dragon (web standard)
notwaldorf
97
6.4k
Fashionably flexible responsive web design (full day workshop)
malarkey
407
66k
Transcript
Comet-сервер своими руками Макс Лапшин Дмитрий Демещук
Эволюция веба
Никакого real-time
Немного real-time
Сплошной real-time
После загрузки, современная страница продолжает жить своей жизнью.
Данные поступают по инициативе сервера
Возможные реализации • Периодические запросы на сервер • Comet: •
Long polling • Websockets • Server Sent Events • Прочее гуано (Flash sockets)
• Много запросов впустую • Постоянная загрузка • Задержки Периодические
запросы
• Не требует немедленного ответа • Совместим с keepalive •
Моментальное обновление • Много одновременных подключений • Требуется переподключение Long-polling
• Постоянное соединение • Намного быстрее, чем HTTP • Не
везде поддерживаются • Еще не устоялись как стандарт
Выбор очевиден:* * часто в сочетании с таймером
• Ruby EventMachine • Python Twisted • Node.JS • Erlang
“Стойте, я же могу просто сделать это на чистом PHP!”
None
• CGI - ~1000-2000 • Apache - 1000-5000 • Node.JS
- 1000000 (?) • Erlang - 2277845 Лимит одновременных подключений
None
Хранение внутреннего состояния • MySQL — надежно и очень медленно
• Redis/memcached — ненадежно и медленно • Внутри VM — быстро и опасно • Репликация
Внутреннее состояние хочется реплицировать
Почти всегда нужна доставка сообщений
А еще, очень хочется failover
Нет решений для распределенного комета из коробки • Redis -
master-slave репликация • Memcached - нет сообщений • Postgres - медленно и без репликации
RabbitMQ • Возможность хранения истории • Возможность использования вебсокетов •
Нет long polling из коробки
Все приходится делать самим
Нельзя просто так взять и написать распределенный comet-сервер Нельзя просто
так взять и написать распределенный comet-сервер
Почему Erlang • Феноменальная для веба производительность • Феноменальная для
веба многоядерность • Распределенность из коробки • Асинхронный IO в последовательном виде • Изоляция данных • Горячее обновление кода
DPS - distributed pub/sub https://github.com/doubleyou/dps
Желаемые фичи • In-memory • История сообщений в канале •
Горячий бэкап нод • Zero-conf, no-ops сервер
Хроника событий 1. Реализация pub/sub-механизма 2. Написание тестов 3. Прикручивание
веб-сервера 4. Доработка напильником 5. Бенчмарки 6. ... 7. PROFIT!
• Распределенный • Автоматический failover • Написан за 2.5 часа
• Меньше 300 строк кода • Один race condition • Один баг-опечатка Первый рабочий pub/sub
dps:subscribe("Channel"). dps:publish("Channel", “Message”).
Тесты • Выявили race condition • Очень помогли в дальнейшей
разработке • Отняли несколько часов • Покрыли примерно 80% кода pub/sub-части • По размеру сравнимы с кодом
Comet добавляется за час http://levgem.livejournal.com/409755.html
Прикрутили чатик на JS. Попутно оказалось, что кроссдоменный long-poll не
работает в Safari.
Все круто, все работает.
Спасибо за внимание!
И тут пришли они Бенчмарки
Попытка №0: подозрительно хорошие результаты
Мы просто слали сообщения 300 000 publishes per second
Вывод: бенчмарки должны соответствовать продакшну
Разные профили нагрузки • Whatsapp: 2M online, 12k pps •
Ejabberd: 40k online, 40k pps
Попытка №1 • Amazon EC2 large instances • 1000 клиентских
подключений • 1 rps с каждого клиента
На этот раз, бенчмарк-процессы работают приближенно к живым клиентам
• 20-140% CPU на одной машине • 2000 deliveries per
second Мы посовещались и решили, что Amazon не очень
Структура на одной ноде
Репликация между нодами
• Асинхронная репликация • Messages discarding • Replication dropping Sacrificial
degradation
Асинхронный publish на соседние ноды облегчил ситуацию, но не решил
проблему.
10 000 deliveries per second с асинхронной репликацией, работает
20 000 deliveries per second - через некоторое время обсыпается
с timeout
Интроспекция в Erlang как она есть
Все дело в очередях
Низкое время ответа может быть вредно
Long polling рассчитан на редкие ответы с сервера. У нас
же он превратился в short-polling.
Выходы* • Таймаут на клиенте • Таймаут на сервере •
Пользовательские сессии * лучше - в комбинации
Сессии - почти те же каналы
7500 publishes per second 150 000 deliveries per second
200 000 deliveries per second обсыпается с timeout
• Клиент шлет сообщение в полную очередь • Отваливается с
таймаутом • Перепосылает в ещё более полную очередь • OOM Killer In Da House Замкнутый круг
Вывод: надо тщательно продумывать rate limit control
• Перед публикацией проверяем длину очередей • Если большая, шлем
HTTP 429 • Клиент сам перепошлет завтра позже Power of Erlang
Итого
Сервер написан и протестирован за несколько человеко-дней
Неплохая производительность: WhatsApp - ~11500 pps DPS - ~7500 pps
Функциональность и железо разные, но порядок цифр похожий.
Важные моменты • Не следует хранить всю историю в памяти
• Следите, какие процессы перегружаются • Избегайте избыточных сообщений • Не делайте запросы слишком часто • Используйте пользовательские сессии • Старайтесь не гонять лишние данные
Erlang - не серебряная пуля, но позволяет фокусироваться на более
высокоуровневых задачах
Тесты и бенчмарки с лихвой окупили себя.
Что дальше? • DHT Ring для распределения каналов • Персистентность
• Регулировка consistency/availability
Технические компромиссы могут заметно ускорить работу сервера. • Не хранить
очереди • Терять сообщения • Отказаться от сессий (в некоторых случаях) • Посылать все в /dev/null
Вопросы? Макс Лапшин
[email protected]
Дмитрий Демещук
[email protected]