Percona XtraDB Cluster пробрасываем ip клиента

от автора

Доброго времени суток. На хабре много писали (поиск) про то, как поднять MySQL кластер на основе решения Percona XtraDB Cluster. Но вот на днях ко мне подошёл программер и попросил сделать так, чтобы в MySQL можно было назначать хосты пользователям для разграничения доступа. Тут я вспомнил, что ip-то там отображаются далеко не клиентские, тут всё и началось :). В интернете было найдено решение аж 2009 года, которое заключалось в использовании tproxy патча, iproute2 и iptables. Вот что было сделано:

Я использую CentOS7.1.1503 (Core) с ядром 3.10.0-229.4.2.el7.x86_64.

1. Скачиваем исходники haproxy 1.5 haproxy-1.5.12-src.
2. Правим spec файл, который заботливо был подготовлен разработчиками, добавляем флаг USE_LINUX_TPROXY=1.
3. Собираем rpm пакет.
4. Устанавливаем на сервера, в моём случае это 3 сервера.
5. Убедиться, что haproxy собран с поддержкой tproxy, можно, набрав haproxy -vv.

Далее стандартная схема: на трёх нодах стоят keepalived для VIP (виртуальный ip, к которому будут подключаться клиенты), haproxy, MySQL.

Идея в слудующем: клиент использует для подключения один ip адрес (192.168.99.99) и 2 порта, порт 3306 для чтения и записи, порт 3307 только для чтения.

На каждом сервере делаем следующее:

iptables -t mangle -N DIVERT iptables -t mangle -A PREROUTING -p tcp -m socket -j DIVERT iptables -t mangle -A DIVERT -j MARK --set-mark 111 iptables -t mangle -A DIVERT -j ACCEPT ip rule add fwmark 111 lookup 100 ip route add local 0.0.0.0/0 dev lo table 100 
net.ipv4.ip_nonlocal_bind = 1 net.ipv4.ip_forward = 1 net.ipv4.conf.default.rp_filter = 0 net.ipv4.conf.all.rp_filter = 0 net.ipv4.conf.p4p2.rp_filter = 0 

Конфиг haproxy node1:

global   log 127.0.0.1 local0 notice   maxconn 4096   chroot /var/lib/haproxy   pidfile /var/run/haproxy.pid   #user haproxy   #group haproxy   daemon  defaults   log global   mode http   option dontlognull   retries 3   option redispatch   maxconn 3000   retries                 3   timeout http-request    10s   timeout queue           1m   timeout connect         10s   timeout client          1m   timeout server          1m   timeout http-keep-alive 10s   timeout check           10s  frontend status   bind 192.168.99.99:80   mode http   default_backend mysql-status  backend mysql-status   mode http   balance roundrobin   stats hide-version   stats scope mysql-backend-rw-3306   stats scope mysql-backend-ro-3307   stats scope mysql-backend-ro-end-3307   stats refresh 5s   stats show-node   stats uri /haproxy/stats   stats auth pwd:pwd  frontend mysql-rw   bind 192.168.99.99:3306   mode tcp   default_backend mysql-backend-rw-3306  frontend mysql-ro   bind 192.168.99.99:3307   mode tcp   default_backend mysql-backend-ro-3307  frontend mysql-ro-end   bind 192.168.99.28:3307 accept-proxy   mode tcp   default_backend mysql-backend-ro-end-3307  backend mysql-backend-rw-3306   mode tcp   source 0.0.0.0 usesrc clientip   balance leastconn   option httpchk   server node1 192.168.99.28:3306 check port 9200 inter 12000 rise 3 fall 3  backend mysql-backend-ro-3307   mode tcp   balance leastconn   option httpchk   server node2 192.168.99.29:3307 send-proxy check port 9200 inter 12000 rise 3 fall 3   server node3 192.168.99.30:3307 send-proxy check port 9200 inter 12000 rise 3 fall 3  backend mysql-backend-ro-end-3307   mode tcp   source 0.0.0.0 usesrc clientip   balance leastconn   option httpchk   server node1 192.168.99.28:3306 check port 9200 inter 12000 rise 3 fall 3 

Конфиг haproxy node2 (только отличия от node1):

frontend mysql-ro-end   bind 192.168.99.29:3307 accept-proxy   mode tcp   default_backend mysql-backend-ro-end-3307  backend mysql-backend-rw-3306   mode tcp   source 0.0.0.0 usesrc clientip   balance leastconn   option httpchk   server node2 192.168.99.29:3306 check port 9200 inter 12000 rise 3 fall 3  backend mysql-backend-ro-3307   mode tcp   balance leastconn   option httpchk   server node1 192.168.99.28:3307 send-proxy check port 9200 inter 12000 rise 3 fall 3   server node3 192.168.99.30:3307 send-proxy check port 9200 inter 12000 rise 3 fall 3  backend mysql-backend-ro-end-3307   mode tcp   source 0.0.0.0 usesrc clientip   balance leastconn   option httpchk   server node2 192.168.99.29:3306 check port 9200 inter 12000 rise 3 fall 3 

Конфиг haproxy node3 (только отличия от node1):

frontend mysql-ro-end   bind 192.168.99.30:3307 accept-proxy   mode tcp   default_backend mysql-backend-ro-end-3307  backend mysql-backend-rw-3306   mode tcp   source 0.0.0.0 usesrc clientip   balance leastconn   option httpchk   server node3 192.168.99.30:3306 check port 9200 inter 12000 rise 3 fall 3  backend mysql-backend-ro-3307   mode tcp   balance leastconn   option httpchk   server node1 192.168.99.28:3307 send-proxy port 9200 inter 12000 rise 3 fall 3   server node2 192.168.99.29:3307 send-proxy port 9200 inter 12000 rise 3 fall 3  backend mysql-backend-ro-end-3307   mode tcp   source 0.0.0.0 usesrc clientip   balance leastconn   option httpchk   server node3 192.168.99.30:3306 check port 9200 inter 12000 rise 3 fall 3 

Работает это всё следующим образом:
клиент соединяется c VIP 192.168.99.99:3306 и работает и на чтение, и на запись только на хосте с VIP. Если же он соединится с 192.168.99.99:3307, тогда он пойдёт на чтение на 2 другие ноды, отличные от той, где VIP.

Изначально проблема была именно с пробросом ip клиента при чтении. При порте 3306 всё заработало сразу.
Решением оказалось использование протокола «proxy protocol» (строки send-proxy и accept-proxy в конфиге haproxy), написанного одним из разработчиков haproxy.
Я и подумал, а почему бы для проброса данных о src ip не использовать именно это решение. Жаль, что такие вещи как exim, postfix, nginx поддерживают протокол proxy, а PerconaCluster нет.

P.S. Статью накидал по-быстрому, дабы не забыть.
P.P.S Пробовал сделать DirectRouting, но странным образом не менялся src ip.

ссылка на оригинал статьи http://habrahabr.ru/post/261103/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *