Distributed pub-sub на erlang

Oct 06, 2012 12:57

В продолжение темы comet-серверов

Какой комет-сервер выбрать программисту, который делает интерактивный современный сайт? Такой, который легко поставить, не надо настраивать (вообще), который умеет реплицировать себя на соседний сервер, что бы можно было не роняя весь сайт, перезапустить один комет из кластера.

Так же комет-сервер обязан хранить минимальную историю сообщений для того, что бы сгладить следующие эффекты:

  • между моментом генерации страницы и первым comet-запросом могут прийти сообщения, которые не хочется потерять
  • между двумя последовательными long-poll запросами могут прийти сообщения

Без истории комет-сервер может сильно испортить user experience от сайта. Разумная глубина истории - 100 сообщений. Всё, что глубже уже относится к истории и должно вычитываться с диска отдельными механизмами. Важно, что бы все ответы комет-сервера были гарантированно быстрыми и маленькими, либо блокирующими на ожидание.

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

Репликация между серверами может быть полная. Если количество каналов превышает 100 000, имеет смысл шардить набор каналов по кластерам. Этот подход видится более простым, чем организация кольца комет-серверов.

Мы с demmonoid написали предварительную версию зеркалируемой системы рассылки сообщений для комета. Система рассчитана для обслуживания среднего размера сайтов с двух-трехкратным резервированием сервера и уже работает.

https://github.com/doubleyou/dps



Что эта штука может:

1) создавать каналы
2) посылать сообщения в каналы
3) получать последние N сообщений из канала
4) лимитировать количество сообщений в истории канала
5) подписываться на события в канале и в нескольких каналах сразу

Рассчитана на использование с long-poll или websocket сервером.

К коду приложен пример с ковбоем.

В makefile прописано несколько запускаемых нод:

./rebar get-deps
make
make 1

и в соседних окнах make 2, make 3, make 4

Потом в браузерах открыть: http://localhost:9201/ http://localhost:9202/ http://localhost:9203/

Можно початиться и увидеть, что подключенные к разным серверам браузеры видят общие сообщения. Потом отключить две ноды из трех, запустить заново.

Перезагрузить окно браузера и увидеть, что с новой ноды скачалась старая история.

Дальше по плану надо:

1) приделать удаление каналов, в том числе и принудительное
2) побенчмаркать это и сравнить с редисом pub/sub

Немного деталей про кишки:

1) все данные копируются между нодами
2) используется синхронная репликация
3) после рестарта нода реплицируется с соседей
4) каналы умышленно ограниченного размера, потому что больше 100 сообщений - это уже история, требующая отдельной персистентности
5) код написан за два вечера

Бенчмарки

Сравнивать я решил с редисом с его pub/sub командами.

Начнём с простого теста: dps с сохранением истории и с реплицированием на 2 ноды против руби клиента, публикующего в редис. В оба пишется сообщением с JSON с числами от 1 до 512 (около 2 килобайт).



Запуск бенчмарка dps происходит так:

maxbp:dps max$ make bench
./rebar compile skip_deps=true
==> dps (compile)
erl -pa ebin -pa deps/*/ebin -smp enable -s dps_benchmark run1 -sname bench@localhost -setcookie cookie
Erlang R15B02 (erts-5.9.2) [source] [64-bit] [smp:4:4] [async-threads:0] [hipe] [kernel-poll:false] [dtrace]

Eshell V5.9.2 (abort with ^G)
(bench@localhost)1> Send: 0 msg/s
Send: 31236 msg/s
Send: 43068 msg/s
Send: 66458 msg/s
Send: 54695 msg/s
Send: 57312 msg/s
Send: 57570 msg/s
Send: 57843 msg/s
Send: 58531 msg/s

Здесь замеряется количество сообщений, которое получилось синхронно опубликовать в канал. Переполнения канала не происходит, потому как используется gen_server:call, а не cast.

Теперь запустим клиент редиса (при этом ожидая увидеть минимум 150 000 msg/s). Какое же было моё удивление, когда я увидел очень странные цифры:

maxbp:dps max$ ./bench_redis/redis.rb
8710 msg/s
9043 msg/s
9063 msg/s
8971 msg/s
8972 msg/s
8885 msg/s
8852 msg/s

С чем связаны такие тормоза пока неясно. В руби вроде персистентное соединение с редисом, JSON генерируется один раз, почему так мало - непонятно.

UPD2: добавлены сравнительные бенчмарки между dps и redis

fp, comet, erlang

Previous post Next post
Up