понедельник, 30 января 2012 г.

Потеря сообщений в jabber при проблемах с сетью

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

Один из вариантов решения - тонкая настройка keep-alive соединений на сервере, чтобы "отстреливание" клиента происходило быстрее. TCP Keepalive HOWTO - настройка tcp keep-alive в Linux. Чтобы не менять настройки всего сервера можно использовать библиотеку libkeepalive.

$ export KEEPIDLE=1 #net.ipv4.tcp_keepalive_time
$ export KEEPINTVL=1 #net.ipv4.tcp_keepalive_intvl
$ export KEEPCNT=5 #net.ipv4.tcp_keepalive_probes
$ LD_PRELOAD=./libkeepalive.so nc jabber.local 5222

При таких настройках интервал между keep-alive запросами будет 1 секунда и при отсутствии ответа будет предпринято 5 попыток после чего соединение будет разорвано на application layer. Чтобы видеть передачу пакетов через соединение, использовался tcpdump

sudo tcpdump -i eth0 -n -p -v host jabber.local and port 5222
...
17:48:34.032178 IP (tos 0x0, ttl 64, id 3461, offset 0, flags [DF], proto TCP (6), length 40)
    client > server: Flags [.], cksum 0x37eb (incorrect -> 0xf46c), ack 1, win 913, length 0
17:48:34.032435 IP (tos 0x0, ttl 63, id 0, offset 0, flags [DF], proto TCP (6), length 40)
    server > client: Flags [.], cksum 0xe12c (correct), ack 1, win 5840, length 0
17:48:35.031257 IP (tos 0x0, ttl 64, id 3462, offset 0, flags [DF], proto TCP (6), length 40)
    client > server: Flags [.], cksum 0x37eb (incorrect -> 0xf46c), ack 1, win 913, length 0
17:48:35.031540 IP (tos 0x0, ttl 63, id 0, offset 0, flags [DF], proto TCP (6), length 40)
    server > client: Flags [.], cksum 0xe12c (correct), ack 1, win 5840, length 0
...

Для эмуляции разрыва связи я использовал iptables

$ sudo iptables -I INPUT -p tcp -s jabber.local -j DROP

При желании настройки TCP keep-alive можно применить ко всему серверу, а не только определенному приложению. Для этого в файл /etc/sysctl.conf (или /etc/sysctl.d/keep-alive.conf) добавить

net.ipv4.tcp_keepalive_time = 1
net.ipv4.tcp_keepalive_intvl = 1
net.ipv4.tcp_keepalive_probes = 5

И применить настройки

sudo sysctl -p

Недостаток этого варианта в том, что он не гарантирует доставку сообщений, которые отправляются в промежутке между keep-alive запросами сервера. И в дополнение в сети создается служебный траффик, объемом 80B/s на каждое подключение.

Вторым вариантом стало подтверждение доставки сообщений. Для этих целей существует расширение XMPP протокола XEP-0184: Message Delivery Receipts. В случае поддержки этого расширения у обоих собеседников появляется возможность видель статус доставки а также просмотра отправленного сообщения. Если один из собеседников не поддерживает расширение, то оно отключается и у второго собеседника.

Клиенты, поддерживающие XEP-0184: Miranda, Psi+, Tkabber, Gajim и некоторые другие. К сожалению Pidgin в данный момент не поддерживает Message Receipts и похоже в ближайшее время поддерживать не будет.

Комментариев нет:

Отправить комментарий