Вопрос или проблема
Описание
Кластер из двух виртуальных машин был развернут для HA на основе множества крутых руководств от профессионалов.
например: https://grimoire.carcano.ch/blog/high-available-ha-proxy-tutorial-with-keepalived/
Стек технологий
HAproxy + Keepalived
Более детально
Хосты:
haproxy1.mycompany.com (10.10.199.101 Master)
haproxy2.mycompany.com (10.10.199.102 Slave)
Плавающий IP-адрес:
myservice.mycompany.com (10.10.199.150)
Ожидаемое поведение
Использование VIP через Keepalived не приведет к потерям.
Тестирование HA через сервисы
- R/W операции S3 объектного хранилища (minio)
- Запросы в Postgresql
Конфигурации
Keepalived MASTER
global_defs {
router_id haproxya1
enable_script_security
script_user root
}
vrrp_script haproxy_check {
script "/usr/libexec/keepalived/haproxy_check.sh"
interval 2
weight 100
}
vrrp_instance VI_1 {
interface enp6s18
state MASTER
priority 100
virtual_router_id 101
advert_int 1
unicast_src_ip 10.10.199.101
unicast_peer {
10.10.199.102
}
virtual_ipaddress {
10.10.199.150
}
track_script {
haproxy_check
}
}
Keepalived BACKUP
global_defs {
router_id haproxya2
enable_script_security
script_user root
}
vrrp_script haproxy_check {
script "/usr/libexec/keepalived/haproxy_check.sh"
interval 2
weight 100
}
vrrp_instance VI_1 {
interface enp6s18
state BACKUP
priority 50
virtual_router_id 101
advert_int 1
unicast_src_ip 10.10.199.102
unicast_peer {
10.10.199.101
}
virtual_ipaddress {
10.10.199.150
}
track_script {
haproxy_check
}
}
Общая конфигурация HAproxy
global
maxconn 100000
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
stats timeout 30s
user haproxy
group haproxy
daemon
defaults
mode tcp
log global
retries 10
option redispatch
timeout client 30m
timeout connect 30s
timeout server 30m
timeout check 5s
option http-keep-alive
no option http-server-close
http-reuse always
listen hapserver
mode http
bind 10.10.199.150:7000
stats enable
stats uri /
# PostgreSQL
listen postgres
bind 10.10.199.150:5000
server postgres 10.10.199.123:5430 check
# S3 MinIO
listen s3minioWEB
bind myservice.mycompany.com:9001 ssl crt /etc/haproxy/ssl/myservice.mycompany.com.pem
mode http
balance leastconn
server minio1 minio1.mycompany.com:9001 check inter 2s
server minio2 minio2.mycompany.com:9001 check inter 2s
server minio3 minio3.mycompany.com:9001 check inter 2s
server minio4 minio4.mycompany.com:9001 check inter 2s
listen s3minioAPI
bind myservice.mycompany.com:9000 ssl crt /etc/haproxy/ssl/myservice.mycompany.com.pem
mode http
balance leastconn
server minio1 minio1.mycompany.com:9000 check inter 2s
server minio2 minio2.mycompany.com:9000 check inter 2s
server minio3 minio3.mycompany.com:9000 check inter 2s
server minio4 minio4.mycompany.com:9000 check inter 2s
Во время тестирования выполнялась длительная задача одного из сервисов (Postgresql, S3) (с другого компьютера в той же локальной корпоративной сети). Пока задача выполнялась, MASTER (haproxy1) был остановлен. Как и ожидалось, VIP был поднят на другом хосте.
Однако при тестировании S3 minio всегда соединение разрывалось.
Но при тестировании Postgresql ошибка появлялась через раз.
Тестирование запросов проводилось с помощью скрипта:
#!/bin/bash
export DB_HOST="10.10.199.14"
export DB_PORT="5000"
export DB_NAME="db"
export DB_USER="user"
export PGPASSWORD='password'
# ------------------------------------
start_time=$(date +%s)
end_time=$(( start_time + 50 ))
iterator=1
echo "Start"
while [[ $(date +%s) -le $end_time ]]; do
echo "cur: $iterator"
psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -c "INSERT INTO haptest (num, timest) VALUES ("$iterator", CURRENT_TIMESTAMP)"
iterator=$((iterator+1))
done
iterator=$((iterator-1))
echo "Made records: $iterator"
echo "End"
Ребята, можете помочь, возможно, я где-то ошибся или неправильно провел тестирование?
Ответ или решение
Теория
Ваша ситуация с потерей транзакций при переключении между главным и резервным узлом в кластере HAproxy + Keepalived является довольно распространённой проблемой в системах высокой доступности. Основной целью использования Keepalived в таких сетапах является минимизация времени простоя и обеспечивание непрерывности сервиса путем автоматического переключения на резервный узел в случае сбоя. Однако наиболее уязвимым временем является переходной период, когда происходит переключение от мастера к резервному узлу.
Такие проблемы обычно связаны с тем, что открытые соединения на момент переключения могут неожиданно закрываться, идущие транзакции – теряться. Потери транзакций связаны с тем, что текущие операции не всегда могут быть корректно завершены и переотправлены, что особенно существенно для долгих, критических операций с базами данных и хранением данных S3 MinIO.
Пример
Рассмотрим вашу конфигурацию: у вас есть две виртуальные машины, на одной из которых HAproxy установлен в режиме мастера, а на другой – в режиме резервного. Переключение выполняется с помощью Keepalived, и виртуальный IP адрес используется для маршрутизации трафика.
Вы используете следующую конфигурацию:
- Постоянное подключение к PostgreSQL на порту
5000
. - Подключение к серверам MinIO через HTTP с использованием SSL на портах
9000
и9001
. - Используется стратегия балансировки нагрузки
leastconn
для MinIO.
Применение
-
Убедитесь, что все подключения корректно реплицируются. Когда происходит переключение, все существующие подключения будут потеряны, если не используется технология для поддержания состояния соединений. Для PostgreSQL это может означать использование конфигураций репликации данных и т. д.
-
Настройте разрывы соединений и переключения:
- HAproxy: Убедитесь, что параметры
timeout client
,timeout server
иtimeout connect
правильно настроены для минимизации вероятности разрыва соединений. - Keepalived: Возможно, вам стоит протестировать разные значения
priority
иadvert_int
, чтобы достичь более гладкой передачи ролей между узлами.
- HAproxy: Убедитесь, что параметры
-
Проверьте скрипты проверки. Скрипт состояния HAproxy может оказаться критичным. Убедитесь, что ваш скрипт
/usr/libexec/keepalived/haproxy_check.sh
чётко и быстро определяет состояние HAproxy. Быстрое обнаружение проблем может помочь в более оперативной передаче ролей. -
Используйте устойчивые алгоритмы переключения и инструментальные средства:
- При работах с PostgreSQL, рассмотрите возможность использования инструментов, которые поддерживают автоматическое переподключение и повтор транзакций, таких как PgBouncer или Patroni для лучшего управления состоянием кластеров.
- Для S3 MinIO, проверьте наличие поддерживаемых конфигураций, которые могут удерживать (persist) состояния транзакций на каких-либо промежуточных уровнях, чтобы предотвратить их потерю.
-
Логи и мониторинг. Настройте логирование и мониторинг, чтобы получать детализированную информацию о причинах переключений и потерях соединений. Это поможет вам не только в диагностике проблемы, но и в том, чтобы научиться предсказывать и предотвращать её в будущем.
-
Постепенное переключение нагрузки. Для более мягкого переключения, рассмотрите возможность постепенного переключения трафика от мастера к резерву, что позволит завершить текущие транзакции прежде, чем узел потеряет статус мастера.
-
Временные окнах блокировок. Если операции критичны, рассмотрите возможность установки временных окон для выполнения переключений, когда нет активных длительных транзакций.
Используйте данную стратегию совместно с подробным тестированием, чтобы минимизировать потенциальные точки отказа и гарантировать сохранность данных в вашей HA конфигурации.