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 не будет опубликован. Обязательные поля помечены *