前言
Redis Sentinel是Redis官方建议的高可用(HA)解决方案,在我们搭建Redis集群时,Redis本身并未集成主备切换功能,sentinel本身是独立运行的,能够监控多个Redis集群,发现master宕机后能够自动切换,选举一个slave成为新的master,当原master恢复之后,sentinel会自动将其作为slave加入到集群中,整个过程不需要人工参与,完全自动化。
主要介绍
-
sentinel主要功能
- 定期监控Redis服务是否运行正常
- 定期监控其他sentinel服务是否正常
- 能够自动切换master节点
- sentinel节点不存储数据
-
sentinel集群
这个不难理解,如果我们用一个非高可用的sentinel去实现Redis的高可用,明显是不科学的,当这一台sentinel宕机之后,Redis显然无法继续保持它的高可用,所以我们在部署sentinel的时候也会采用集群的方式
优势:
即使有sentinel服务宕机,只要还有一台sentinel运行正常,就可以使Redis继续保持高可用
-
sentinel版本问题
sentinel在Redis2.6版本中引入的,当时是sentinel 1,貌似有蛮多问题,毕竟初版
在Redis2.8版本中升级到sentinel 2,之后就非常稳定了
不过现在Redis已经发展了很久,版本也越来越高,sentinel已经非常值得信赖了
-
sentinel中的定时任务
- 每隔10秒向各个Redis服务器(master和slave节点)发送INFO命令,根据回应获取master和slave信息,通过master的回复可以获取到新增的slave节点
- 每隔02秒向Redis的master服务器发送命令(hello消息),用于发现和监视其他sentinel,sentinel之间的监控不在额外创建订阅
- 每隔01秒向Redis和sentinel所有服务发送PING消息(sentinel本身的ip、端口、id等内容),通过回复PONG判断服务是否在线
-
下线判断
- 主观下线:当前sentinel断定master下线
- 客观下线:满足sentinel配置文件中quorum数量的sentinel均断定master下线
-
配置文件解读
# sentinel运行的端口,默认为26379 port 26377 dir "/private/tmp" logfile "/var/log/redis/sentinel_26377.log" # 以守护进程执行 daemonize yes # 守护进程运行的pid保存文件 pidfile "/var/run/redis-sentinel.pid" # 格式:sentinel monitor <master-name> <ip> <redis-port> <quorum> # 该行的意思是:<master-name>:自定义 # <ip>:master主机的IP # <redis-port>:master的端口 # <quorum>:表示在sentinel集群中,使master由主观下线变为客观下线的sentinel数量。 sentinel monitor cc_master 127.0.0.1 6379 2 # 格式:sentinel down-after-milliseconds <master-name> <milliseconds> # sentinel会向master发送心跳PING来确认master是否存活,如果master在<milliseconds>时间内回应的不是PONG,那么这个sentinel会主观地认为这个master下线了。<milliseconds>的单位是毫秒,默认30秒。 sentinel down-after-milliseconds cc_master 15000 # 格式:sentinel failover-timeout <master-name> <milliseconds> # failover过期时间,当failover开始后,在此时间内仍然没有触发任何failover操作,当前sentinel将会认为此次failoer失败。默认180秒,即3分钟。 sentinel failover-timeout cc_master 60000 # sentinel parallel-syncs <master-name> <numreplicas> # 在发生failover主备切换时,这个选项指定了最多可以有多少个slave同时对新的master进行同步,这个数字越小,完成failover所需的时间就越长,但是如果这个数字越大,就意味着越多的slave因为replication而不可用。可以通过将这个值设为1来保证每次只有一个slave处于不能处理命令请求的状态。 sentinel parallel-syncs cc_master 1 # 格式:sentinel auth-pass <master-name> <password> # sentinel连接的master节点的登录密码 sentinel auth-pass cc_master redis
-
故障转移
- sentinel使用Raft投票选举出一个leader去执行故障转移
- 每一个将master标记为主观下线的sentinel节点发起投票
- 其他sentinel节点收到投票后,若尚未参与投票(也就是尚未投票给其他sentinel),则同意,否则拒绝
- 最终收到过半同意的sentinel节点作为leader
- 若有两个sentinel收到了过半投票,那么就再重新选举
- 选举新的master节点
- 选择replica-priority配置数字最高的slave节点为master,默认为100
- 若replica-priority相同,则选择偏移量最大的slave节点,偏移量是指slave从master同步的进度,偏移量越大说明数据越完整,可以通过Redis的info命令查看(slave_repl_offset)当前slave的偏移量
- 若偏移量相同,则选择最先启动的slave作为master
- 更改master后,通知其他slave节点同步为新的master节点的slave节点
- 原master节点恢复之后自动加入到集群中,成为新master的slave节点
- sentinel使用Raft投票选举出一个leader去执行故障转移
实战
在本机上启动3个Redis实例,采用1主2从的模式,以下只记录redis.conf和sentinel.conf中关键内容
-
redis.conf
-
redis-master.conf配置
# 默认端口 port 6379
-
redis-slave1.conf配置
# 端口 port 63791 # 格式:replicaof <masterip> <masterport> # 从节点归属的master节点 replicaof 127.0.0.1 6379
-
redis-slave2.conf配置
# 端口 port 63792 # 格式:replicaof <masterip> <masterport> # 从节点归属的master节点 replicaof 127.0.0.1 6379
-
-
sentinel.conf
-
sentinel0.conf
# 端口 port 26379 sentinel myid 842c9102c48eb0cedeb06fe55e7d2258595ac267 # 监控master sentinel monitor cc_master 127.0.0.1 6379 2
-
sentinel1.conf
# 端口 port 26378 sentinel myid 842c9102c48eb0cedeb06fe55e7d2258595ac266 # 监控master sentinel monitor cc_master 127.0.0.1 6379 2
-
sentinel2.conf
# 端口 port 26377 sentinel myid 842c9102c48eb0cedeb06fe55e7d2258595ac265 # 监控master sentinel monitor cc_master 127.0.0.1 6379 2
-
-
启动
-
启动sentinel
redis-sentinel ~/Documents/develop_tools/tools/redis-5.0.5/sentinel0.conf redis-sentinel ~/Documents/develop_tools/tools/redis-5.0.5/sentinel1.conf redis-sentinel ~/Documents/develop_tools/tools/redis-5.0.5/sentinel2.conf
-
启动Redis
redis-server ~/Documents/develop_tools/tools/redis-5.0.5/redis-master.conf redis-server ~/Documents/develop_tools/tools/redis-5.0.5/redis-slave1.conf redis-server ~/Documents/develop_tools/tools/redis-5.0.5/redis-slave2.conf
-
Redis通过info查看信息
127.0.0.1:6379>info all
# Server服务器信息
redis_version:5.0.5 # Redis 服务器版本
redis_git_sha1:00000000 # Git SHA1
redis_git_dirty:0 # Git dirty flag
redis_build_id:6c6e38af7cea0726 # Redis构建ID
redis_mode:standalone # Redis运行模式
os:Darwin 19.3.0 x86_64 # 运行环境操作系统版本
arch_bits:64 # 架构(32 或 64 位)
multiplexing_api:kqueue # Redis 所使用的事件处理机制
atomicvar_api:atomic-builtin
gcc_version:4.2.1 # 编译的GCC版本
process_id:61985 # 服务器进程的 PID
run_id:433b78ec513c8b782f3a46ba6b4ade1f12439aca # Redis 服务器的随机标识符(用于Sentinel和集群)
tcp_port:6379 # Redis端口
uptime_in_seconds:108 # Redis运行时长,秒
uptime_in_days:0 # Redis运行市场,天
hz:10
configured_hz:10
lru_clock:8363059 # 以分钟为单位进行自增的时钟,用于 LRU 管理
executable:/Users/chuan/redis-server # 运行命令
config_file: # 启动使用的配置文件
# Clients
connected_clients:7 # 已连接客户端的数量
client_recent_max_input_buffer:2 # 当前连接的客户端当中,最长的输出列表
client_recent_max_output_buffer:0 # 当前连接的客户端当中,最大输入缓存
blocked_clients:0 # 正在等待阻塞命令(BLPOP、BRPOP、BRPOPLPUSH)的客户端的数量
# Memory (太多了,不做解释了)
used_memory:2235920 # 由 Redis 分配器分配的内存总量,以字节(byte)为单位
used_memory_human:2.13M # 以可读的格式返回 Redis 分配的内存总量
used_memory_rss:3153920 # 从操作系统的角度,返回 Redis 已分配的内存总量(俗称常驻集大小)。这个值和top 、 ps 等命令的输出一致。
used_memory_rss_human:3.01M # 以可读的格式返回rss
used_memory_peak:2317840 # Redis 的内存消耗峰值(以字节为单位)
used_memory_peak_human:2.21M
used_memory_peak_perc:96.47%
used_memory_overhead:2221526
used_memory_startup:987776
used_memory_dataset:14394
used_memory_dataset_perc:1.15%
allocator_allocated:2271808
allocator_active:3116032
allocator_resident:3116032
total_system_memory:17179869184
total_system_memory_human:16.00G
used_memory_lua:37888
used_memory_lua_human:37.00K
used_memory_scripts:0
used_memory_scripts_human:0B
number_of_cached_scripts:0
maxmemory:0
maxmemory_human:0B
maxmemory_policy:noeviction
allocator_frag_ratio:1.37
allocator_frag_bytes:844224
allocator_rss_ratio:1.00
allocator_rss_bytes:0
rss_overhead_ratio:1.01
rss_overhead_bytes:37888
mem_fragmentation_ratio:1.39
mem_fragmentation_bytes:882112
mem_not_counted_for_evict:0
mem_replication_backlog:1048576
mem_clients_slaves:33844
mem_clients_normal:151226
mem_aof_buffer:0
mem_allocator:libc
active_defrag_running:0
lazyfree_pending_objects:0
# Persistence
loading:0 # 服务器是否正在载入持久化文件
rdb_changes_since_last_save:1 # 距离最后一次成功创建持久化文件之后,改变了多少个键值
rdb_bgsave_in_progress:0 # 服务器是否正在创建RDB文件
rdb_last_save_time:1585421263 # 最近一次成功创建RDB文件的UNIX时间
rdb_last_bgsave_status:ok # 最后一次创建RDB文件的结果是成功还是失败
rdb_last_bgsave_time_sec:0 # 最后一次创建RDB文件耗费的秒数
rdb_current_bgsave_time_sec:-1 # 记录当前创建RDB操作已经耗费了多长时间(单位为秒)
rdb_last_cow_size:0
aof_enabled:0 # AOF是否处于打开状态
aof_rewrite_in_progress:0 # 服务器是否正在创建AOF文件
aof_rewrite_scheduled:0 # 是否需要执行预约的AOF重写操作
aof_last_rewrite_time_sec:-1 # 最后一次重启AOF的秒数
aof_current_rewrite_time_sec:-1 # 记录当前正在重写AOF的秒数
aof_last_bgrewrite_status:ok # 最后一次重写AOF文件的结果
aof_last_write_status:ok # 最后一次写入结果
aof_last_cow_size:0
# Stats (可以不做了解)
total_connections_received:9
total_commands_processed:720
instantaneous_ops_per_sec:6
total_net_input_bytes:34197
total_net_output_bytes:229238
instantaneous_input_kbps:0.34
instantaneous_output_kbps:1.19
rejected_connections:0
sync_full:2 # 主从完全同步成功次数
sync_partial_ok:0 # 主从部分同步成功次数
sync_partial_err:0 # 主从部分同步失败次数
expired_keys:0 # 运行以来过期的key的数量
expired_stale_perc:0.00 # 过期的比率
expired_time_cap_reached_count:0 # 过期计数
evicted_keys:0
keyspace_hits:1
keyspace_misses:1
pubsub_channels:1
pubsub_patterns:0
latest_fork_usec:278
migrate_cached_sockets:0
slave_expires_tracked_keys:0
active_defrag_hits:0
active_defrag_misses:0
active_defrag_key_hits:0
active_defrag_key_misses:0
# Replication(master节点)
role:master # 角色 master和slave
connected_slaves:2 # slave节点数
slave0:ip=127.0.0.1,port=63791,state=online,offset=20163,lag=1 # 从节点1
slave1:ip=127.0.0.1,port=63792,state=online,offset=20163,lag=0 # 从节点2
master_replid:895f219aa1e7ed5ecda50dcb1f77eea9f1ef9c3d # 主实例启动随机字符串
master_replid2:0000000000000000000000000000000000000000 # 主实例启动随机字符串2
master_repl_offset:20163 # 主从同步偏移量,此值如果和上面的offset相同说明主从一致没延迟,与master_replid可被用来标识主实例复制流中的位置。
second_repl_offset:-1 # 主从同步偏移量2,此值如果和上面的offset相同说明主从一致没延迟
repl_backlog_active:1 # 复制积压缓冲区是否开启
repl_backlog_size:1048576 # 复制积压缓冲大小
repl_backlog_first_byte_offset:1 # 复制缓冲区里偏移量的大小
repl_backlog_histlen:20163 # 此值等于 master_repl_offset - repl_backlog_first_byte_offset,该值不会超过repl_backlog_size的大小
# Replication(slave节点)
role:slave # 角色 master和slave
master_host:127.0.0.1 # master节点IP
master_port:6379 # master节点端口
master_link_status:up # master通信
master_last_io_seconds_ago:1 # 主库多少秒未发送数据到从库
master_sync_in_progress:0 # 从服务器是否在与主服务器进行同步
slave_repl_offset:42262 # slave复制偏移量
slave_priority:100 # slave优先级
slave_read_only:1 # 从库是否设置只读
connected_slaves:0 # 连接的slave实例个数
master_replid:895f219aa1e7ed5ecda50dcb1f77eea9f1ef9c3d
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:42262 # master偏移量,与slave_repl_offset相同则表示同步完整
second_repl_offset:-1
repl_backlog_active:1 # 复制积压缓冲区是否开启
repl_backlog_size:1048576 # 复制积压缓冲大小
repl_backlog_first_byte_offset:1 # 复制缓冲区里偏移量的大小
repl_backlog_histlen:42262 # 此值等于 master_repl_offset - repl_backlog_first_byte_offset,该值不会超过repl_backlog_size的大小
# CPU
used_cpu_sys:0.104404 # 将所有redis主进程在核心态所占用的CPU时求和累计起来
used_cpu_user:0.079472 # 将所有redis主进程在用户态所占用的CPU时求和累计起来
used_cpu_sys_children:0.002037 # 将后台进程在核心态所占用的CPU时求和累计起来
used_cpu_user_children:0.000648 # 将后台进程在用户态所占用的CPU时求和累计起来
# Cluster
cluster_enabled:0 # 实例是否启用集群模式
# Keyspace
db0:keys=1,expires=0,avg_ttl=0 # db0的key的数量,以及带有生存期的key的数,平均存活时间