基于 haproxy 的健康检查实现 Redis 主从架构下多读实例的负载均衡
mhr18 2024-12-05 14:38 14 浏览 0 评论
概述
在 redis 高可用主从(Master-Replica)架构下, 通过 sentinel 实现 master 故障的自动切换, redis client 如何将写操作正确分发到 master 节点? 如何将读操作正确分发到多个 replica 节点以实现读负载均衡? 现提供如下基于 haproxy 自定义健康检查(tcp-check)的代理实现方案:
- haproxy 将写命令发送到 master 节点,将读命令根据权重发送到 master 或 replica 节点实现读负载均衡
- haproxy 自动下线异常的只读节点,待节点恢复后再重新启用
- haproxy 端口 16379 负责写, 端口 26379 负责读负载均衡
环境规划
主机名 Ip 地址 节点类型 c2 192.168.31.12 haproxy c7 192.168.31.17 redis-server 6381 (Master), redis-sentinel(26379) c8 192.168.31.18 redis-server 6381 (Replica), redis-sentinel(26379) c9 192.168.31.19 redis-server 6381 (Replica), redis-sentinel(26379)
本方案主要涉及的技术细节:
- Redis 主从环境
- Redis Sentinel 哨兵集群
- Haproxy 自定义健康检查(tcp-check)
编译安装
1、下载解压、编译安装 redis
wget http://download.redis.io/releases/redis-5.0.9.tar.gz
tar zxvf redis-5.0.9.tar.gz
# 默认 redis 相关二进制执行文件安装到 /usr/bin 目录内
cd redis-5.0.9.tar.gz && make && make install
# 创建 redis 数据及配置文件目录
mkdir -p /opt/redis/{6379,6381} && /etc/redis/{6379,6381}
cp redis.conf /etc/redis/{6379,6381}
# 创建 redis 运行用户及设置权限
useradd -r redis && chown redis.redis -R /opt/redis/6381
2、Redis Server Systemd 启动脚本
cat > /usr/lib/systemd/system/redis.service << EOF
[Unit]
Description=Redis persistent key-value database
After=network.target
[Service]
LimitNOFILE=infinity
LimitNOFILE=102400
LimitNOFILE=102400
WorkingDirectory=/opt/redis/6381
ExecStart=/usr/bin/redis-server /etc/redis/6381/redis.conf --supervised systemd
ExecStop=/usr/bin/redis-cli shutdown
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
EOF
Redis 主从
1、Master 节点 Redis Server 配置
# cat /etc/redis/6381/redis.conf
# general config
daemonize yes
protected-mode no
port 6381
bind 0.0.0.0
databases 16
loglevel notice
pidfile "/opt/redis/6381/redis-server.pid"
logfile "/opt/redis/6381/redis-server.log"
timeout 0
maxmemory 128mb
tcp-keepalive 0
tcp-backlog 511
lua-time-limit 5000
slowlog-log-slower-than 1000
slowlog-max-len 128
requirepass "pass123"
# rdb 持久化 config
dir "/opt/redis/6381"
dbfilename "dump.rdb"
save 900 1
save 300 10
save 60 1000
rdbcompression yes
rdbchecksum yes
stop-writes-on-bgsave-error yes
# aof 持久化 config
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
aof-use-rdb-preamble yes
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-rewrite-incremental-fsync yes
# replication config
replica-priority 100
masterauth "pass123"
# replicaof 192.168.31.18 6381
replica-serve-stale-data yes
replica-read-only yes
repl-diskless-sync yes
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
repl-timeout 60
repl-backlog-ttl 600
repl-backlog-size 10mb
2、Replica(Slave) 节点 Redis Server 配置, 基于 Master 配置添加或修改如下配置项
replica-priority 80
# 指定副本连接 master 时的验证密码
masterauth "pass123"
# 指定该副本的 master ip 及 port
replicaof 192.168.31.17 6381
3、确认 Redis 主从环境运行正常
redis-cli -p 6381 -h 192.168.31.17
192.168.31.17:6381> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.31.18,port=6381,state=online,offset=39771,lag=1
slave1:ip=192.168.31.19,port=6381,state=online,offset=39771,lag=1
master_replid:b090f53b06d56ba3145709f6dde72b7e820c3935
master_replid2:f39d8c822c424308c27e2a47599ed2cb685004c4
master_repl_offset:39905
second_repl_offset:26123
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1230
repl_backlog_histlen:38676
Redis 哨兵
1、Redis Sentinel 所有节点配置
# cat /etc/redis/6379/redis.conf
port 26379
protected-mode no
dir /opt/redis/26379
logfile sentinel_26379.log
# 是否为守护进程
daemonize yes
# 至少 2 个 sentinel 节点检测到 master 失效, 才确认 master 客观下线; m1 标识一个主从复制组
# 192.168.31.17 6381 为 redis master 节点 Ip 及 Port
sentinel monitor m1 192.168.31.17 6381 2
# 指定故障切换允许的毫秒数,超过这个时间,就认为故障切换失败
sentinel failover-timeout m1 180000
# 若 redis master 在 15s 内没有回应 PONG 或者是回复了一个错误消息, 则当前 sentinel 任务该 master 挂了(SDOWN)
sentinel down-after-milliseconds m1 15000
# 指定最多可以有多少个 replica 同时对新的 master 进行同步
sentinel parallel-syncs m1 1
# sentinel 连接 redis 时的密码验证
sentinel auth-pass m1 pass123
# 发生切换之后执行的一个自定义脚本
# sentinel notification-script <master-name> <script-path>
# sentinel client-reconfig-script <master-name> <script-path>
2、设置哨兵启动脚本
# cat /usr/lib/systemd/system/redis-sentinel.service
[Unit]
Description=Redis persistent key-value database
After=network.target
[Service]
LimitNOFILE=infinity
LimitNOFILE=102400
LimitNOFILE=102400
WorkingDirectory=/opt/redis/6379
ExecStart=/usr/bin/redis-sentinel /etc/redis/6379/redis.conf --supervised systemd
ExecStop=/usr/bin/redis-cli -p 26379 shutdown
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
EOF
3、确定 Redis Sentinel 运行是否正常
# linux shell 启动 sentinel 节点
systemctl start redis-sentinel
redis-cli -p 26379
127.0.0.1:26379> info sentinel
# 输出如下信息, 标识 master 地址 192.168.31.17, 有 2 个副本, 共有三个 sentinel 节点
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=m1,status=ok,address=192.168.31.17:6381,slaves=2,sentinels=3
Redis 读写分离
1、haproxy 配置文件 haproxy_redis.cfg
global
daemon
maxconn 30000
defaults
mode tcp
log global
option tcplog
option dontlognull
maxconn 30000
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
# HAProxy stats page
listen stats
bind *:8888
mode http
stats enable
# stats uri /status # 默认路径 /haproxy?stats
stats auth admin:admin
# redis 读负载均衡
listen redis-read
bind *:26379
mode tcp
balance roundrobin
option tcp-check
# redis 密码认证
tcp-check send AUTH\ pass123\r\n
tcp-check expect string +OK
# 读操作仅分发到 slave
tcp-check send info\ replication\r\n
tcp-check expect string role:slave
# 读操作分发到 slave 和 master
#tcp-check send PING\r\n
#tcp-check expect string +PONG
tcp-check send QUIT\r\n
tcp-check expect string +OK
server redis-1 192.168.31.17:6381 maxconn 5000 check inter 2s
server redis-2 192.168.31.18:6381 maxconn 5000 check inter 2s
server redis-3 192.168.31.19:6381 maxconn 5000 check inter 2s
# redis 写流量到 redis master
frontend redis-write
bind *:16379
mode tcp
option tcplog
# 通过自己(redis-server)和 2 个 sentinel 确认本身是否为 master 节点
use_backend redis-master-1 if { srv_is_up(redis-master-1/redis) } { nbsrv(mastercheck-redis-1) ge 2 }
use_backend redis-master-2 if { srv_is_up(redis-master-2/redis) } { nbsrv(mastercheck-redis-2) ge 2 }
use_backend redis-master-3 if { srv_is_up(redis-master-3/redis) } { nbsrv(mastercheck-redis-3) ge 2 }
# 如果未找到有效的 master 时的默认后端选择
default_backend redis-legacy
# 询问 redis-1(192.168.31.17:6381) 是否认为自己是 Master
backend redis-master-1
mode tcp
balance first
option tcp-check
#comment following 2 lines if your redis server doesn't requirepass
tcp-check send AUTH\ pass123\r\n
tcp-check expect string +OK
tcp-check send info\ replication\r\n
tcp-check expect string role:master
tcp-check send QUIT\r\n
tcp-check expect string +OK
server redis 192.168.31.17:6381 maxconn 5000 check inter 2s
backend redis-master-2
mode tcp
balance first
option tcp-check
tcp-check send AUTH\ pass123\r\n
tcp-check expect string +OK
tcp-check send info\ replication\r\n
tcp-check expect string role:master
tcp-check send QUIT\r\n
tcp-check expect string +OK
server redis 192.168.31.18:6381 maxconn 5000 check inter 2s
backend redis-master-3
mode tcp
balance first
option tcp-check
tcp-check send AUTH\ pass123\r\n
tcp-check expect string +OK
tcp-check send info\ replication\r\n
tcp-check expect string role:master
tcp-check send QUIT\r\n
tcp-check expect string +OK
server redis 192.168.31.19:6381 maxconn 5000 check inter 2s
# 询问三个 Sentinel节点当前 redis-1是否为 Master
backend mastercheck-redis-1
mode tcp
option tcp-check
tcp-check send SENTINEL\ master\ m1\r\n
tcp-check expect string 192.168.31.17
tcp-check send QUIT\r\n
tcp-check expect string +OK
server sentinel-1 192.168.31.17:26379 check inter 2s
server sentinel-2 192.168.31.18:26379 check inter 2s
server sentinel-3 192.168.31.19:26379 check inter 2s
backend mastercheck-redis-2
mode tcp
option tcp-check
tcp-check send SENTINEL\ master\ m1\r\n
tcp-check expect string 192.168.31.18
tcp-check send QUIT\r\n
tcp-check expect string +OK
server sentinel-1 192.168.31.17:26379 check inter 2s
server sentinel-2 192.168.31.18:26379 check inter 2s
server sentinel-3 192.168.31.19:26379 check inter 2s
backend mastercheck-redis-3
mode tcp
option tcp-check
tcp-check send SENTINEL\ master\ m1\r\n
tcp-check expect string 192.168.31.19
tcp-check send QUIT\r\n
tcp-check expect string +OK
server sentinel-1 192.168.31.17:26379 check inter 2s
server sentinel-2 192.168.31.18:26379 check inter 2s
server sentinel-3 192.168.31.19:26379 check inter 2s
# 通过 redis server 本身确定自己是否为 master 节点; 脑裂情况下存在多个 master 节点 该方式会导致数据混乱!!
backend redis-legacy
mode tcp
balance first
option tcp-check
tcp-check send AUTH\ pass123\r\n
tcp-check expect string +OK
tcp-check send info\ replication\r\n
tcp-check expect string role:master
tcp-check send QUIT\r\n
tcp-check expect string +OK
server redis-1 192.168.31.17:6381 maxconn 5000 check inter 2s
server redis-2 192.168.31.18:6381 maxconn 5000 check inter 2s
server redis-3 192.168.31.19:6381 maxconn 5000 check inter 2s
测试验证
# 1、验证读写分离,可通过 redis server 的进程 id 可判断连接到哪个 redis 后端
redis-cli -h 192.168.31.12 -p 26379 -a pass123 info | grep process_id
# 2、通过 haproxy 状态页查看后端 redis 状态
http://192.168.31.12:8888/haproxy?stats
# 3、读写分离
haproxy 端口 16379 负责写(对应后端 master 节点), 端口 26379 负责读负载均衡(对应后端 replica 节点)
- 上一篇:常用的负载均衡算法及其特点
- 下一篇:每个Java程序员都必须知道的四种负载均衡算法
相关推荐
- 一文读懂Prometheus架构监控(prometheus监控哪些指标)
-
介绍Prometheus是一个系统监控和警报工具包。它是用Go编写的,由Soundcloud构建,并于2016年作为继Kubernetes之后的第二个托管项目加入云原生计算基金会(C...
- Spring Boot 3.x 新特性详解:从基础到高级实战
-
1.SpringBoot3.x简介与核心特性1.1SpringBoot3.x新特性概览SpringBoot3.x是建立在SpringFramework6.0基础上的重大版...
- 「技术分享」猪八戒基于Quartz分布式调度平台实践
-
点击原文:【技术分享】猪八戒基于Quartz分布式调度平台实践点击关注“八戒技术团队”,阅读更多技术干货1.背景介绍1.1业务场景调度任务是我们日常开发中非常经典的一个场景,我们时常会需要用到一些不...
- 14. 常用框架与工具(使用的框架)
-
本章深入解析Go生态中的核心开发框架与工具链,结合性能调优与工程化实践,提供高效开发方案。14.1Web框架(Gin,Echo)14.1.1Gin高性能实践//中间件链优化router:=...
- SpringBoot整合MyBatis-Plus:从入门到精通
-
一、MyBatis-Plus基础介绍1.1MyBatis-Plus核心概念MyBatis-Plus(简称MP)是一个MyBatis的增强工具,在MyBatis的基础上只做增强不做改变,为简化开发、提...
- Seata源码—5.全局事务的创建与返回处理
-
大纲1.Seata开启分布式事务的流程总结2.Seata生成全局事务ID的雪花算法源码3.生成xid以及对全局事务会话进行持久化的源码4.全局事务会话数据持久化的实现源码5.SeataServer创...
- Java开发200+个学习知识路线-史上最全(框架篇)
-
1.Spring框架深入SpringIOC容器:BeanFactory与ApplicationContextBean生命周期:实例化、属性填充、初始化、销毁依赖注入方式:构造器注入、Setter注...
- OpenResty 入门指南:从基础到动态路由实战
-
一、引言1.1OpenResty简介OpenResty是一款基于Nginx的高性能Web平台,通过集成Lua脚本和丰富的模块,将Nginx从静态反向代理转变为可动态编程的应用平台...
- 你还在为 Spring Boot3 分布式锁实现发愁?一文教你轻松搞定!
-
作为互联网大厂后端开发人员,在项目开发过程中,你有没有遇到过这样的问题:多个服务实例同时访问共享资源,导致数据不一致、业务逻辑混乱?没错,这就是分布式环境下常见的并发问题,而分布式锁就是解决这类问题的...
- 近2万字详解JAVA NIO2文件操作,过瘾
-
原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处。从classpath中读取过文件的人,都知道需要写一些读取流的方法,很是繁琐。最近使用IDEA在打出.这个符号的时候,一行代...
- 学习MVC之租房网站(十二)-缓存和静态页面
-
在上一篇<学习MVC之租房网站(十一)-定时任务和云存储>学习了Quartz的使用、发邮件,并将通过UEditor上传的图片保存到云存储。在项目的最后,再学习优化网站性能的一些技术:缓存和...
- Linux系统下运行c++程序(linux怎么运行c++文件)
-
引言为什么要在Linux下写程序?需要更多关于Linux下c++开发的资料请后台私信【架构】获取分享资料包括:C/C++,Linux,Nginx,ZeroMQ,MySQL,Redis,fastdf...
- 2022正确的java学习顺序(文末送java福利)
-
对于刚学习java的人来说,可能最大的问题是不知道学习方向,每天学了什么第二天就忘了,而课堂的讲解也是很片面的。今天我结合我的学习路线为大家讲解下最基础的学习路线,真心希望能帮到迷茫的小伙伴。(有很多...
- 一个 3 年 Java 程序员 5 家大厂的面试总结(已拿Offer)
-
前言15年毕业到现在也近三年了,最近面试了阿里集团(菜鸟网络,蚂蚁金服),网易,滴滴,点我达,最终收到点我达,网易offer,蚂蚁金服二面挂掉,菜鸟网络一个月了还在流程中...最终有幸去了网易。但是要...
- 多商户商城系统开发全流程解析(多商户商城源码免费下载)
-
在数字化商业浪潮中,多商户商城系统成为众多企业拓展电商业务的关键选择。这类系统允许众多商家在同一平台销售商品,不仅丰富了商品种类,还为消费者带来更多样的购物体验。不过,开发一个多商户商城系统是个复杂的...
你 发表评论:
欢迎- 一周热门
-
-
Redis客户端 Jedis 与 Lettuce
-
高并发架构系列:Redis并发竞争key的解决方案详解
-
redis如何防止并发(redis如何防止高并发)
-
开源推荐:如何实现的一个高性能 Redis 服务器
-
redis安装与调优部署文档(WinServer)
-
Redis 入门 - 安装最全讲解(Windows、Linux、Docker)
-
一文带你了解 Redis 的发布与订阅的底层原理
-
Redis如何应对并发访问(redis控制并发量)
-
oracle数据库查询Sql语句是否使用索引及常见的索引失效的情况
-
Java SE Development Kit 8u441下载地址【windows版本】
-
- 最近发表
- 标签列表
-
- oracle位图索引 (63)
- oracle批量插入数据 (62)
- oracle事务隔离级别 (53)
- oracle 空为0 (50)
- oracle主从同步 (55)
- oracle 乐观锁 (51)
- redis 命令 (78)
- php redis (88)
- redis 存储 (66)
- redis 锁 (69)
- 启动 redis (66)
- redis 时间 (56)
- redis 删除 (67)
- redis内存 (57)
- redis并发 (52)
- redis 主从 (69)
- redis 订阅 (51)
- redis 登录 (54)
- redis 面试 (58)
- 阿里 redis (59)
- redis 搭建 (53)
- redis的缓存 (55)
- lua redis (58)
- redis 连接池 (61)
- redis 限流 (51)