Доброго времени суток!
Небольшое предисловие: не так давно увидели свет 13-я, а за ней в этом году и 14-я версии ejabberd. Process One решили сменить схему версионирования в силу ряда причин и версии 2.x сейчас уже считаются устаревшими. Новый ejabberd поделился на две ветки — ejabberd Community Server и ejabberd Business Edition и начал довольно активно развиваться.
В нашем случае, в качестве системы была выбрана FreeBSD, так как требуется поддерживать довольно большое количество соединений на ноду (~100k).
На установке системы смысла останавливаться не вижу, поэтому под катом сразу перейдем к настройке.
Часть своих данных ejabberd будет хранить в mysql, поэтому в системе должны быть установлены библиотеки odbc. Так же мы используем скрипт внешней авторизации на php, поэтому нужен и php.
Этап 1:
Ставим пререквизиты (git, fop, libyaml, wget, unixODBC, expat, wx30-gtk2, php5, etc):
pkg install git fop libyaml wget unixODBC-2.3.2 expat wx30-gtk2 php5 ... (+ все что вам нужно)
cd /usr/ports/java/openjdk7/
make install clean
Качаем последнюю версию эрланга (на момент написания статьи 17.2.2):
mkdir /usr/local/src && cd /usr/local/src
git clone git://github.com/erlang/otp.git
Собираем, ставим его:
cd /usr/local/src/otp
autoconf -f
./configure --prefix=/usr/local --enable-kernel-poll --with-ssl --enable-threads --with-odbc --enable-smp-support
gmake
gmake install
Далее качаем ejabberd и ejabberd-contrib:
cd /usr/local/src
git clone git://github.com/processone/ejabberd.git
git clone git://github.com/gamenet/ejabberd-contrib.git
Создаем пользователя ejabberd, в качестве домашней директории указываем /var/lib/ejabberd.
Собираем и ставим ejabberd:
cd /usr/local/src/ejabberd
autoconf -f
./configure --enable-mysql=yes --enable-odbc=yes --enable-lager=yes --prefix=/usr/local --localstatedir=/var --enable-user=ejabberd
gmake && gmake install
При сборке erlang и ejabberd могут возникнуть различного рода нюансы, аля потребуется создать ряд симлинков из /usr/local/lib | include в /usr/lib | include или «поиграться» с LDFLAGS / CPPFLAGS.
Собираем mod_admin_extra, для расширения списка доступных команд в ejabberdctl и через xmlrpc:
cd /usr/local/src/ejabberd-contrib/mod_admin_extra
./build.sh
cp ./ebin/mod_admin_extra.beam /usr/local/lib/ejabberd/ebin/
Этап 2:
Основной конфигурационный файл ejabberd.yml изобилует примерами и комментариями разработчиков, поэтому настроить его не сложно. В yaml-конфигурационных файлах важна табуляция, редактор хабра у меня её съел, поэтому будьте внимательны! Остановлюсь лишь на некоторых параметрах:
hosts:
- "youserver.com"
В секции ejabberd_c2s:
backlog: 1024
Для внешней авторизации:
auth_method: external
extauth_program: "/usr/local/bin/<ваш_скрипт>.php"
extauth_instances: 12
extauth_cache: 72000
Для подключения к mysql:
odbc_type: mysql
odbc_server: "mysql_server_ip"
odbc_database: "dbname"
odbc_username: "username"
odbc_password: "password"
odbc_pool_size: 16
odbc_keepalive_interval: 600
Прописываем «админа»:
admin:
user:
- "admin": "yourserver.com"
Переключаем часть модули на работу с mysql:
mod_last:
db_type: odbc
mod_muc:
db_type: odbc
mod_offline:
db_type: odbc
mod_privacy:
db_type: odbc
mod_private:
db_type: odbc
mod_roster:
db_type: odbc
mod_shared_roster:
db_type: odbc
mod_vcard:
db_type: odbc
Подключаем mod_admin_extra:
mod_admin_extra: {}
Правим ejabberdctl.cfg (параметры индивидуальны, но я привожу те, что прописаны у нас):
ERL_MAX_PORTS=524288
FIREWALL_WINDOW=4200-4210
ERL_PROCESSES=5000000
ERL_MAX_ETS_TABLES=262144
ERLANG_NODE=ejabberd@node1
Идем на mysql-сервер, создаем там базу и заливаем в неё дамп из mysql.sql из папки sql исходников ejabberd.
Запускаем!
su - ejabberd
ejabberdctl start
Создаем пользователя admin:
ejabberdctl register admin yourserver.com password
Этап 3:
Для создания кластера берем еще один сервер и проделываем процедуры, описанные выше.
Чтобы репликация между нодами работала корректно (да и вообще чтобы собрать кластер) нужно, чтобы ноды могли соединяться друг с другом по порту 4369 и теми портами, что вы указали в FIREWALL_WINDOW.
Копируем файл /var/lib/ejabberd/.erlang_cookie c первой ноды на вторую и если проблем с соединениями между нодами нет, то собираем кластер:
su - ejabberd
erl -sname ejabberd@node2 -mnesia dir '"/var/lib/ejabberd/"' -mnesia extra_db_nodes "['ejabberd@node1']" -s mnesia
Вызываем mnesia:info().
Если все хорошо, то в списке running db nodes у вас будут обе ноды.
Меняем схему сохранения таблиц, выходим и запускаем:
mnesia:change_table_copy_type(schema, node(), disc_copies).
q().
ejabberdctl start
Этап 4:
Немного о параметрах системы:
kern.ipc.maxsockets=2400000.
kern.ipc.nmbclusters=0
net.inet.tcp.reass.maxsegments=2048
vm.pmap.shpgperproc=400
hw.em.rxd=4096
hw.em.txd=4096
hw.em.rx_int_delay=100
hw.em.tx_int_delay=100
hw.em.rx_abs_int_delay=1000
hw.em.tx_abs_int_delay=1000
dev.em.rx_processing_limit=-1
net.inet.tcp.hostcache.hashsize=4096
net.inet.tcp.hostcache.bucketlimit=100
net.inet.tcp.hostcache.cachelimit=65536
net.inet.tcp.syncache.hashsize=4096
net.inet.tcp.syncache.bucketlimit=120
net.inet.tcp.syncache.cachelimit=131072
net.inet.tcp.tcbhashsize=524288
net.isr.defaultqlimit=4096
net.isr.bindthreads=1
net.isr.maxthreads=4
net.link.ifqmaxlen=1024
kern.ipc.shm_use_phys=1
kern.ipc.somaxconn=8192
kern.maxfiles=3000000
kern.maxfilesperproc=2700000
kern.maxvnodes=256000
kern.random.sys.harvest.ethernet=0
kern.random.sys.harvest.interrupt=0
kern.sync_on_panic=1
net.inet.icmp.bmcastecho=0
net.inet.icmp.drop_redirect=1
net.inet.icmp.maskrepl=0
net.inet.ip.intr_queue_maxlen=256
net.inet.ip.maxfragpackets=1024
net.inet.ip.portrange.first=1024
net.inet.ip.portrange.last=65535
net.inet.ip.portrange.randomized=0
net.inet.ip.redirect=0
net.inet.ip.sourceroute=0
net.inet.ip.accept_sourceroute=0
net.inet.tcp.blackhole=2
net.inet.tcp.drop_synfin=1
net.inet.tcp.fast_finwait2_recycle=1
net.inet.tcp.finwait2_timeout=3000
net.inet.tcp.hostcache.expire=1200
net.inet.tcp.keepinit=5000
net.inet.tcp.maxtcptw=65536
net.inet.tcp.msl=5000
net.inet.tcp.recvbuf_auto=0
net.inet.tcp.recvspace=65536
net.inet.tcp.sendbuf_auto=0
net.inet.tcp.sendspace=131072
net.inet.tcp.syncookies=1
net.inet.tcp.tso=0
net.inet.udp.blackhole=1
net.inet.udp.recvspace=32768
net.isr.direct=1
net.route.netisr_maxqlen=1024
vfs.ufs.dirhash_maxmem=100000000
Если все прошло нормально, то зайдя в админку youserver.com:5280/admin/nodes/ в Running Nodes будут обе ноды.
mod_admin_extra значительно расширяет список команд, которые можно передать через ejabberdctl. Если вы оставили активным модуль ejabberd_xmlrpc (который стал встроен в ejabberd с 13-й версии), то команды jabber-серверу можно передавать и через XmlRPC. Мы, к примеру, управляем ростером, группами, vcard'ами и прочим через специальные worker'ы, написанные на php. Но, по сути, подключаться к xmlrpc можно из чего угодно.
Что касается потребляемых ресурсов, то для 100 тысяч подключенных пользователей требуется где-то под 25-30 Gb памяти (это при хранении большинства данных в mysql, т.е. чисто на обслуживание подключенных клиентов). Если хранить данные в mnesia, то цифра легко может дойти до 100 Gb и больше, но тут все зависит от количества пользователей и данных в базе.
К сожалению, в сети очень мало примеров успешных инсталляций ejabberd, которые работают с десятками тысяч подключенных пользователей. Лично я натыкался лишь на «слухи» о том, что значительно патченный ejabberd — основа сервисов WhatsApp. Да и, сам по себе, erlang — отдельная песня, к которой бывает не так просто найти подход :) Mailing-листы ejabberd тоже в полумертвом состоянии, и проконсультироваться с кем-то о возможных проблемах на high-load проблемно, поэтому многое приходится изучать с горьким опытом. Радует, что ejabberd сейчас довольно активно развивается (по сравнению с периодом до второй половины 2013 года), появляется новый функционал. В этом году появились несколько major-контрибуторов из сообщества, которые регулярно правят баги, оставшиеся с 2.х версий или вновь приобретенные.
Рад буду найти «сообщников», которые используют ejabberd в своих сервисах — быть может сможем продуктивно поделиться опытом друг с другом!
P.S. Буду благодарен за указание недочетов (желательно в личку) и рад любым комментариям. Спасибо!
Автор: vstaf