redis服务介绍
基础概念
Remote Dictionary Server(Redis)远程字典服务器是完全开源免费的,用C语言编写的,遵守BSD开源协议,是一个高性能的(key/value)分布式内存数据库,基于内存运行,并支持持久化的NoSQL(非关系型)数据库,它也通常被称为数据结构服务器,因为值(value)可以是字符串(String),哈希(Map),列表(list), 集合(sets)和有序集合(sorted sets)等类型。。
Redis的主要特点:
- 高性能:Redis通过将数据存储在内存中,提供了极快的读写速度。
- 多种数据类型:支持丰富的数据类型,如字符串、列表、集合、有序集合和哈希。
- 持久化:虽然Redis主要是内存数据库,但它提供了多种持久化选项,包括RDB快照和AOF(Append Only File)日志。
- 高可用性:通过主从复制和Redis Sentinel实现高可用性,确保数据的可靠性和服务的连续性。
- 分布式:支持Redis Cluster,允许数据分布在多个节点上,实现水平扩展。
常见应用场景:
- 缓存:由于其高性能,Redis常用于缓存层,加速应用的响应速度。
- 会话存储:许多网站使用Redis来存储用户会话信息。
- 排行榜和计数器:利用有序集合和其他数据结构,Redis可以方便地实现排行榜和计数器功能。
- 发布/订阅:Redis的发布/订阅功能可以用于实时消息传递。
- 队列:通过列表和集合,Redis可以实现高效的队列管理。
redis可以在特定应用场景下作为rabbimq和memcached的替代。
-
使用Redis而不是memcached来解决问题,不仅可以让代码变得更简短、更易懂、更易维护,而且还可以使代码的运行速度更快(因为用户不需要通过读取数据库来更新数据)。除此之外,在其他许多情况下,Redis的效率和易用性也比关系数据库要好得多。
-
什么数据会存到Redis数据库中?主要是热点数据,不会经常改变的,一般是常量。比如登录验证的Cookie,购物车,历史浏览记录。(只要具有一定时间的生命周期)比如首页的商品信息,一般不会变。比如秒杀的商品信息,一般也不会变。比如地图的经纬度信息,一般也不会变。
Redis作为高性能的内存开源数据库,其主要目的是解决以下几类问题:
- 1.高速缓存问题
场景:数据库查询速度慢,无法满足高并发场景下的快速请求需求。
:通过将常用的数据存储在内存中,Redis 提供极低的延迟(通常在微秒级别)来加速数据提升的读取和写入,从而显着解决系统性能。 - 2.高发问题
场景:传统关系型数据库在高并发的场景很容易成为系统瓶颈。
解决:Redis支持高并发访问,能够承载负载万到百万级的QPS(每秒请求数),非常适合在高并发场景中数据库作为或存储层使用。 - 3.数据结构特别
场景:某些应用需要支持复杂的数据结构,比如数组、排行榜、队列等。
解决:Redis提供丰富的数据结构支持,如字符串(String)、哈希(Hash)、列表(List)、集合(Set)、群体集合(Sorted Set)等,可以高效地解决这些场景需求。 - 4.分布式锁和任务队列
场景:多个系统中需要确保资源的独占访问,或者需要高效的管理任务队列。
解决:Redis 提供了简单且高效的分配SETNX和 Lua 脚本实现)和消息(通过列表或发布/订阅模式实现),用于协调和管理整个系统的资源。 - 5.持久化与数据恢复
场景:需要兼顾内存数据的性能和数据的持久化存储,防止意外宕机导致数据丢失。
解决:Redis提供了多种持久化机制(RDB快照、AOF日志),可以根据需要配置数据的存储策略,在性能和可靠性之间取得平衡。 - 6.实时分析和统计
场景:需要实时对数据进行高频统计和分析,比如访问统计、热点数据识别。
解决:Redis的内存操作极快,可以用于实时统计页面访问量、操作频次等,并结合其他数据结构(如位图、HyperLogLog)实现高效复杂的统计功能。 - 7.高可用和扩展性
场景:需要保证服务的稳定性和可扩展性,应对突发流量和节点故障。
解决:Redis提供了主从复制(Replication)、哨兵模式(Sentinel)和集群模式(Cluster),支持高可用和多元化扩展,保证系统的可用性和扩展能力。
安装使用
ubuntu2404环境:使用apt安装
apt install -y redis
systemctl enable --now redis-server
Centos7.9源码编译安装
- 安装依赖
yum -y install wget gcc make tcl
- 下载解压源码包
wget http://download.redis.io/releases/redis-5.0.9.tar.gz
tar -xf redis-5.0.9.tar.gz
- 编译安装:默认会安装到 /usr/local/bin/ 目录
cd redis-5.0.9
make;make install
[root@localhost redis-5.0.9]# ls /usr/local/bin/
redis-benchmark redis-check-aof redis-check-rdb redis-cli redis-sentinel redis-server
- 创建 Redis 用户和组
groupadd redis
useradd -r -g redis -s /bin/false redis
- 创建Redis工作目录
mkdir -p /etc/redis
mkdir -p /var/lib/redis
mkdir -p /var/log/redis
mkdir -p /var/run/redis
- 设置目录权限
chown -R redis:redis /var/lib/redis
chown -R redis:redis /var/log/redis
chown -R redis:redis /var/run/redis
chown -R redis:redis /etc/redis
chmod 755 /var/lib/redis
chmod 755 /var/log/redis
chmod 755 /var/run/redis
chmod 755 /etc/redis
touch /var/log/redis/redis.log
chown redis:redis /var/log/redis/redis.log
chmod 644 /var/log/redis/redis.log
- 复制配置文件
cp redis.conf /etc/redis/
chown redis:redis /etc/redis/redis.conf
- 配置 Redis
vi /etc/redis/redis.conf
daemonize yes # 后台运行
bind 127.0.0.1 # 绑定地址
port 6379 # 端口号
dir /var/lib/redis # 数据目录
logfile "/var/log/redis/redis.log" # 日志文件
- 创建 Systemd 服务文件
vi /etc/systemd/system/redis.service
[Unit]
Description=Redis persistent key-value database
After=network.target
[Service]
Type=forking
ExecStart=/usr/local/bin/redis-server /etc/redis/redis.conf
ExecStop=/usr/local/bin/redis-cli shutdown
Restart=always
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
- 启动 Redis 服务
# 重新加载 systemd
systemctl daemon-reload
# 启动 Redis 服务
systemctl start redis
# 设置开机自启
systemctl enable redis
# 检查服务状态
systemctl status redis
redis数据库不区分大小写,并且输入命令会有提示!!
基础操作命令
连接到Redis服务器:
redis-cli -h 127.0.0.1 -p 6379
root@huhy:~# redis-cli -h 127.0.0.1 -p 6379
127.0.0.1:6379>
字符串
设置键值对并获取:key是键,huhy就是值对
127.0.0.1:6379> set key "huhy"
OK
127.0.0.1:6379> get key
"huhy"
127.0.0.1:6379>
删除值对;
127.0.0.1:6379> del key
(integer) 1
127.0.0.1:6379> get key
(nil)
查看所有键:,*表示所有
127.0.0.1:6379> keys *
(empty array)
数据类型操作命令
列表
设置键值及过期时间:10是秒为单位,十秒后mykey就会消失,内容为空
127.0.0.1:6379> setex mykey 10 "setkey"
OK
127.0.0.1:6379> get mykey
"setkey"
127.0.0.1:6379>
获取键的剩余生存时间:
127.0.0.1:6379> setex hu 20 "test"
OK
127.0.0.1:6379> ttl hu
(integer) 11
127.0.0.1:6379> ttl hu
(integer) 8
127.0.0.1:6379> ttl hu
(integer) 6
127.0.0.1:6379> ttl hu
(integer) 5
127.0.0.1:6379>
追加值到键:如果追加到设置有过期的键中可能会导致过期时间失效
127.0.0.1:6379> get hu
"hy"
127.0.0.1:6379> append hu "hy"
(integer) 4
127.0.0.1:6379> get hu
"hyhy"
127.0.0.1:6379>
左侧推入元素:从而形成一个列表
127.0.0.1:6379> lpush mylist "test1"
(integer) 1
127.0.0.1:6379> lpush mylist "test2"
(integer) 2
127.0.0.1:6379> lpush mylist "test3"
(integer) 3
查看列表中的元素:可以理解成test1是第一个,从左边推入一个元素后,就变成了第二个
127.0.0.1:6379> lrange mylist 0 -1
1) "test3"
2) "test2"
3) "test1"
获取列表长度:
127.0.0.1:6379> llen mylist
(integer) 3
127.0.0.1:6379>
右侧推出元素:从而删除列表中的一个元素
127.0.0.1:6379> rpop mylist
"test1"
127.0.0.1:6379> rpop mylist
"test2"
127.0.0.1:6379> rpop mylist
"test3"
127.0.0.1:6379> rpop mylist
(nil)
127.0.0.1:6379>
集合
添加元素到集合:
127.0.0.1:6379> sadd jihe "member1"
(integer) 1
获取集合所有成员:
127.0.0.1:6379> smembers jihe
1) "member1"
127.0.0.1:6379>
管理和维护命令
查看数据库信息:
127.0.0.1:6379> info
查看连接客户端列表:
127.0.0.1:6379> client list
id=3 addr=127.0.0.1:38112 laddr=127.0.0.1:6379 fd=8 name= age=3098 idle=0 flags=N db=0 sub=0 psub=0 ssub=0 multi=-1 qbuf=26 qbuf-free=20448 argv-mem=10 multi-mem=0 rbs=1024 rbp=0 obl=0 oll=0 omem=0 tot-mem=22298 events=r cmd=client|list user=default redir=-1 resp=2
127.0.0.1:6379>
清空当前数据库:
127.0.0.1:6379> flushdb
OK
清空所有数据库:
127.0.0.1:6379> flushall
OK
保存数据到磁盘:
127.0.0.1:6379> save
OK
后台异步保存数据到磁盘:
127.0.0.1:6379> bgsave
Background saving started
查看Redis服务器配置:
127.0.0.1:6379> config get parameter
(empty array)
127.0.0.1:6379> config get maxmemory
1) "maxmemory"
2) "0"
127.0.0.1:6379>
搭建一主二从集群
在一主二从架构中,包含一个主节点(Master)和两个从节点(Slave)。
- 主节点(Master):它负责接收客户端的读写请求,是数据写入的源头,对数据进行更新等操作,并且会将自身的数据变更信息传递给从节点,以此来保证数据的一致性。例如,当有新的数据被写入到主节点中时,后续它会通知从节点进行相应的数据更新。
- 从节点(Slave):主要作用是复制主节点的数据,它们会定期从主节点获取数据更新的内容,并应用到自身的数据集上,从而保持和主节点的数据同步。从节点通常只负责处理读请求,分担主节点的读压力,通过这种方式可以提高整个系统的读性能以及可用性。在有两个从节点的情况下,能更好地分摊读负载,满足更多的读操作需求。
工作原理
- 建立连接:从节点启动后,会主动向主节点发起连接请求,建立起通信链路,便于后续的数据同步等交互操作。
数据同步: - 首次同步时,从节点会向主节点发送 PSYNC 命令(在旧版本中是 SYNC 命令),主节点接收到命令后,会开始执行 BGSAVE 命令生成 RDB 文件(Redis 的一种数据持久化文件格式),并在生成过程中把期间接收到的写命令缓存起来。
- 当 RDB 文件生成完毕后,主节点会将其发送给从节点,从节点接收后会进行加载,把数据恢复到自身内存中。之后主节点再将缓存的写命令发送给从节点执行,这样就完成了首次的数据同步,使得从节点的数据与主节点初始状态保持一致。
- 在首次同步完成后,主节点后续每执行一个写命令,都会以异步的方式将写命令发送给从节点,从节点接收到命令后会在本地执行,从而持续保持数据同步,时刻让自身的数据与主节点一致。
节点信息:Ubuntu2404
| 主机名 | IP |
|---|---|
| redis1 (主) | 192.168.200.160 |
| redis2(从) | 192.168.200.161 |
| redis3(从) | 192.168.200.163 |
三台节点初始化环境
vi init.sh
#!/bin/bash
# 定义节点信息
NODES=("192.168.200.160 redis1 root" "192.168.200.161 redis2 root" "192.168.200.162 redis3 root")
# 定义当前节点的密码(默认集群统一密码)
HOST_PASS="000000"
# 时间同步的目标节点
TIME_SERVER=redis1
# 时间同步的地址段
TIME_SERVER_IP=192.160.200.0/24
# 欢迎界面
cat > /etc/motd <<EOF
################################
# Welcome to redis #
################################
EOF
# 修改主机名
for node in "${NODES[@]}"; do
ip=$(echo "$node" | awk '{print $1}')
hostname=$(echo "$node" | awk '{print $2}')
# 获取当前节点的主机名和 IP
current_ip=$(hostname -I | awk '{print $1}')
current_hostname=$(hostname)
# 检查当前节点与要修改的节点信息是否匹配
if [[ "$current_ip" == "$ip" && "$current_hostname" != "$hostname" ]]; then
echo "Updating hostname to $hostname on $current_ip..."
hostnamectl set-hostname "$hostname"
if [ $? -eq 0 ]; then
echo "Hostname updated successfully."
else
echo "Failed to update hostname."
fi
break
fi
done
# 遍历节点信息并添加到 hosts 文件
for node in "${NODES[@]}"; do
ip=$(echo "$node" | awk '{print $1}')
hostname=$(echo "$node" | awk '{print $2}')
# 检查 hosts 文件中是否已存在相应的解析
if grep -q "$ip $hostname" /etc/hosts; then
echo "Host entry for $hostname already exists in /etc/hosts."
else
# 添加节点的解析条目到 hosts 文件
sudo sh -c "echo '$ip $hostname' >> /etc/hosts"
echo "Added host entry for $hostname in /etc/hosts."
fi
done
if [[ ! -s ~/.ssh/id_rsa.pub ]]; then
ssh-keygen -t rsa -N '' -f ~/.ssh/id_rsa -q -b 2048
fi
# 检查并安装 sshpass 工具
if ! which sshpass &> /dev/null; then
echo "sshpass 工具未安装,正在安装 sshpass..."
sudo apt-get install -y sshpass
fi
# 遍历所有节点进行免密操作
for node in "${NODES[@]}"; do
ip=$(echo "$node" | awk '{print $1}')
hostname=$(echo "$node" | awk '{print $2}')
user=$(echo "$node" | awk '{print $3}')
# 使用 sshpass 提供密码,并自动确认密钥
sshpass -p "$HOST_PASS" ssh-copy-id -o StrictHostKeyChecking=no -i /root/.ssh/id_rsa.pub "$user@$hostname"
done
# 时间同步
apt install -y chrony
if [[ $TIME_SERVER_IP == *$(hostname -I)* ]]; then
# 配置当前节点为时间同步源
sed -i '20,23s/^/#/g' /etc/chrony/chrony.conf
echo "server $TIME_SERVER iburst maxsources 2" >> /etc/chrony/chrony.conf
echo "allow $TIME_SERVER_IP" >> /etc/chrony/chrony.conf
echo "local stratum 10" >> /etc/chrony/chrony.conf
else
# 配置当前节点同步到目标节点
sed -i '20,23s/^/#/g' /etc/chrony/chrony.conf
echo "pool $TIME_SERVER iburst maxsources 2" >> /etc/chrony/chrony.conf
fi
# 重启并启用 chrony 服务
systemctl restart chronyd
systemctl enable chrony
echo "###############################################################"
echo "################# 集群初始化成功 #####################"
echo "###############################################################"
bash init.sh
- 安装软件包
apt install -y redis
systemctl restart redis
配置redis1文件
vi /etc/redis/redis.conf
#注释
#bind 127.0.0.1 -::1
#修改关闭保护
protected-mode no
#添加
requirepass "000000"
#添加
masterauth "000000"
#修改开启AOF持久化
appendonly yes
重启redis1节点服务
systemctl restart redis
配置redis2文件
root@redis1:~# scp /etc/redis/redis.conf redis2:/etc/redis/redis.conf
redis.conf 100% 104KB 18.4MB/s 00:00
root@redis1:~# scp /etc/redis/redis.conf redis3:/etc/redis/redis.conf
redis.conf
vi /etc/redis/redis.conf
#添加主节点信息
replicaof 192.168.200.160 6379
重启redis2节点服务
systemctl restart redis
配置redis3文件
scp /etc/redis/redis.conf redis3:/etc/redis/redis.conf
重启redis3节点服务
systemctl restart redis
主节点验证
root@redis1:~# redis-cli -h 192.168.200.160 -p 6379 -a 000000 info replication
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.200.161,port=6379,state=online,offset=14,lag=0
slave1:ip=192.168.200.162,port=6379,state=online,offset=14,lag=1
master_failover_state:no-failover
master_replid:19972c43e4830f38f594806bc26b3443f2568c74
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:14
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:14
root@redis1:~#
redis2节点
root@redis2:~# redis-cli -h 192.168.200.161 -p 6379 -a 000000 info replication
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
# Replication
role:slave
master_host:192.168.200.160
master_port:6379
master_link_status:up
master_last_io_seconds_ago:5
master_sync_in_progress:0
slave_read_repl_offset:70
slave_repl_offset:70
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:19972c43e4830f38f594806bc26b3443f2568c74
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:70
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:70
root@redis2:~#
redis3节点
root@redis3:~# redis-cli -h 192.168.200.162 -p 6379 -a 000000 info replication
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
# Replication
role:slave
master_host:192.168.200.160
master_port:6379
master_link_status:up
master_last_io_seconds_ago:2
master_sync_in_progress:0
slave_read_repl_offset:126
slave_repl_offset:126
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:19972c43e4830f38f594806bc26b3443f2568c74
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:126
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:126
搭建一主二从三哨兵集群
哨兵(Sentinel) 是 Redis 官方提供的高可用性解决方案。它能够自动监控主从节点,并在主节点故障时自动完成故障转移(不是实时转移需要几十秒),选举新的 Master,实现 Redis 集群的高可用。
简单理解:哨兵就是一个"监工",时刻盯着Redis主从集群,一旦发现 Master 挂了,立即从 Slave 中选出一个新的 Master,并通知所有客户端连接新的 Master。
┌─────────────────────────────────────────────────────────┐
│ 哨兵的三项任务 │
├─────────────────────────────────────────────────────────┤
│ 1. 监控(Monitoring) │
│ - 定时向 Master、Slave、其他 Sentinel 发送 PING 命令 │
│ - 检查所有节点是否"活着" │
│ │
│ 2. 通知(Notification) │
│ - 当节点状态变化时,通知其他 Sentinel 和客户端 │
│ │
│ 3. 自动故障转移(Automatic Failover) │
│ - Master 故障时,选举新 Master │
│ - 将其他 Slave 指向新 Master │
│ - 通知客户端新的 Master 地址 │
└─────────────────────────────────────────────────────────┘
| 组件 | 角色 | 数量 | 职责 |
|---|---|---|---|
| Master | 主节点 | 1 个 | 处理写请求,数据写入主库 |
| Slave | 从节点 | N 个 | 同步主库数据,处理读请求,故障时参与选举 |
| Sentinel | 哨兵 | 奇数个(≥3) | 监控、通知、自动故障转移 |
推荐使用 Redis 6.2.x 系列(如 6.2.6)或 7.0.x 系列
原因如下:
| 版本 | 推荐程度 | 说明 |
|---|---|---|
| 6.2.x | ✅ 首选 | 稳定性经过充分验证,与 CentOS 7.9 兼容性最佳,gcc 4.8.5 可正常编译 |
| 7.0.x | ✅ 可选 | 性能更好,多线程 I/O 改进明显,但需要较新版本的 gcc |
| 7.2.x | ⚠️ 谨慎 | CentOS 7.9 默认 gcc 4.8.5 无法编译,需要升级 gcc |
| 5.x | ❌ 不推荐 | 已进入维护末期,存在已知安全漏洞 |
注:CentOS 7.9默认的gcc版本是 4.8.5,而Redis 7.2.x 需要gcc 9以上才能编译。如果使用 7.2 版本,需要先升级 gcc,会增加部署复杂度。6.2.x 系列是最稳妥的选择。
节点环境信息如下:
| 节点 | IP 地址 | 角色 | Redis 端口 | Sentinel 端口 |
|---|---|---|---|---|
| redis01(centos7.9) | 192.168.200.100 | Master + Sentinel1 | 6379 | 26379 |
| redis02(centos7.9) | 192.168.200.101 | Slave1 + Sentinel2 | 6379 | 26379 |
| redis03(centos7.9) | 192.168.200.102 | Slave2 + Sentinel3 | 6379 | 26379 |
- 安装依赖
yum -y install wget gcc make tcl
- 下载解压源码包
wget http://download.redis.io/releases/redis-6.2.6.tar.gz
tar -xf redis-6.2.6.tar.gz
- 编译安装:默认会安装到 /usr/local/bin/ 目录
cd redis-6.2.6
make;make install
[root@localhost redis-6.2.6]# ls /usr/local/bin/
redis-benchmark redis-check-aof redis-check-rdb redis-cli redis-sentinel redis-server
- 创建 Redis 用户和组
groupadd redis
useradd -r -g redis -s /bin/false redis
- 创建Redis工作目录
mkdir -p /etc/redis
mkdir -p /var/lib/redis
mkdir -p /var/log/redis
mkdir -p /var/run/redis
- 设置目录权限
chown -R redis:redis /var/lib/redis
chown -R redis:redis /var/log/redis
chown -R redis:redis /var/run/redis
chown -R redis:redis /etc/redis
chmod 755 /var/lib/redis
chmod 755 /var/log/redis
chmod 755 /var/run/redis
chmod 755 /etc/redis
touch /var/log/redis/redis.log
chown redis:redis /var/log/redis/redis.log
chmod 644 /var/log/redis/redis.log
- 复制配置文件
cp redis.conf /etc/redis/
chown redis:redis /etc/redis/redis.conf
- 配置 Redis
vi /etc/redis/redis.conf
daemonize yes # 后台运行
bind 0.0.0.0 # 绑定地址
port 6379 # 端口号
dir /var/lib/redis # 数据目录
logfile "/var/log/redis/redis.log" # 日志文件
- 创建 Systemd 服务文件
vi /etc/systemd/system/redis.service
[Unit]
Description=Redis persistent key-value database
After=network.target
[Service]
Type=forking
ExecStart=/usr/local/bin/redis-server /etc/redis/redis.conf
ExecStop=/usr/local/bin/redis-cli shutdown
Restart=always
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
- 启动 Redis 服务
# 重新加载 systemd
systemctl daemon-reload
# 启动 Redis 服务
systemctl start redis
# 设置开机自启
systemctl enable redis
# 检查服务状态
systemctl status redis
配置主从
- 修改redis01主节点文件
vi /etc/redis/redis.conf
# 客户端访问密码
requirepass 000000
# 主从复制认证密码,主从节点的密码一致!
masterauth 000000
# 主节点读写!
replica-read-only no
#############################################################################
# 持久化(可选)
# RDB 触发条件:多少秒内有多少个 key 变化就保存快照
#
# save 900 1 : 900秒(15分钟)内至少有 1 个 key 变化
# save 300 10 : 300秒(5分钟)内至少有 10 个 key 变化
# save 60 10000 : 60秒(1分钟)内至少有 10000 个 key 变化
#
# 优点:文件小,恢复快,适合备份
# 缺点:宕机可能丢失最后一次快照后的数据
save 900 1
save 300 10
save 60 10000
# 开启 AOF,每条写命令(set、hset等)都追加到AOF日志,重启时重放恢复数据。不开启断电则丢数据(可选)
# yes: 开启,每条写命令追加到 AOF 文件
# no: 关闭,仅使用 RDB
#
# 优点:数据更安全(最多丢失 1 秒数据)
# 缺点:文件大,恢复慢
appendonly yes
# 最大内存限制
# 当 Redis 内存达到 2GB 时,触发内存淘汰策略
# 生产环境必须设置,否则可能耗尽系统内存
maxmemory 2gb
# 内存淘汰策略
# allkeys-lru: 在所有 key 中淘汰最近最少使用的
#
# 常用策略对比:
# allkeys-lru → 适合缓存场景,淘汰最少使用的
# allkeys-lfu → 适合热数据,淘汰最不常用的
# volatile-lru → 只淘汰设置了过期时间的 key
# allkeys-random → 随机淘汰(不推荐)
# noeviction → 不淘汰,内存满时写入报错(不推荐)
#
# 注意:allkeys-lru 是最通用的选择
maxmemory-policy allkeys-lru
# ===== 性能优化 =====
# 关闭 THP(透明大页)会提高性能
# 执行命令:echo never > /sys/kernel/mm/transparent_hugepage/enabled
# 客户端连接数限制
maxclients 10000
# 设置数据库数量(默认 16)
databases 16
tcp-backlog 511 # 增加 TCP 连接队列
timeout 0 # 不超时断开客户端连接
tcp-keepalive 300 # 每 300 秒检测 TCP 连接
- 修改redis02从节点文件
vi /etc/redis/redis.conf
requirepass 000000
masterauth 000000
replicaof 192.168.200.100 6379
replica-read-only yes
save 900 1
save 300 10
save 60 10000
appendonly yes
maxmemory 2gb
maxmemory-policy allkeys-lru
# 主从复制专用优化
replica-serve-stale-data yes # 同步期间可以提供服务
replica-priority 100 # 优先级,越小越可能被选为新主节点
# 复制缓冲区大小(建议调大,避免全量同步)
# 根据数据量调整,这里假设 2GB 数据
# repl-backlog-size 64mb # 默认 1MB,建议 64-256MB
# 从节点不主动写,可以关闭 AOF(节省磁盘)
appendonly no # 从节点可以不开启 AOF
- 修改redis03从节点文件
vi /etc/redis/redis.conf
requirepass 000000
masterauth 000000
replicaof 192.168.200.100 6379
replica-read-only yes
save 900 1
save 300 10
save 60 10000
appendonly yes
maxmemory 2gb
maxmemory-policy allkeys-lru
- 关闭防火墙(或者放通端口)
systemctl stop firewalld && getenforce 0
- 重启三台节点
systemctl restart redis
- 节点1主节点进行查看
[root@redis01 ~]# redis-cli -a 000000 info replication
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
# Replication
role:master # master角色
connected_slaves:2 # 从节点信息
slave0:ip=192.168.200.102,port=6379,state=online,offset=140,lag=0
slave1:ip=192.168.200.101,port=6379,state=online,offset=140,lag=0
master_failover_state:no-failover
master_replid:d72ea5ed2792cc15c8870f1247531c5dd0df4fd5
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:140
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:140
[root@redis01 ~]#
- 节点2从节点查看
[root@redis02 ~]# redis-cli -a 000000 info replication
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
# Replication
role:slave # 从节点角色
master_host:192.168.200.100
master_port:6379
master_link_status:up
master_last_io_seconds_ago:8
master_sync_in_progress:0
slave_read_repl_offset:210
slave_repl_offset:210
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:d72ea5ed2792cc15c8870f1247531c5dd0df4fd5
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:210
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:15
repl_backlog_histlen:196
[root@redis02 ~]#
- 验证从节点是否只读
[root@redis02 ~]# redis-cli -a 000000 set test_readonly "should_fail"
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
(error) READONLY You can't write against a read only replica.
[root@redis02 ~]#
- 验证主从
[root@redis01 ~]# redis-cli -a 000000 set test_key "hello"
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
OK
[root@redis01 ~]#
------------------------------------------------------------------------------------------
[root@redis02 ~]# redis-cli -a 000000 -h 192.168.200.101 get test_key
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
"hello"
[root@redis02 ~]#
搭建哨兵
- 复制配置文件
cp redis-6.2.6/sentinel.conf /etc/redis/
chown redis:redis /etc/redis/sentinel.conf
- 修改哨兵配置文件(三台节点一致)
vi /etc/redis/sentinel.conf
bind 0.0.0.0
# 端口默认
port 26379
# 允许远程访问
protected-mode no
# 后台运行模式
daemonize yes
logfile ""/var/log/redis/sentinel.log"
# 工作目录
dir /var/lib/redis
# 参数详解:
# mymaster: 主节点的名称(自定义,所有哨兵必须一致)
# 192.168.200.100:6379: 被监控的 Redis 主节点地址
# 2: quorum(法定票数),需要多少个哨兵同意才判定主节点下线
#
# quorum 的重要作用:
# - 判定客观下线(ODOWN)需要至少 quorum 个哨兵同意
# - 建议设置为哨兵总数的一半以上(如 3 个哨兵设 2)
# - 不能超过哨兵总数
sentinel monitor mymaster 192.168.200.100 6379 2
# 主节点密码,如果Redis设置了requirepass,这里必须配置相同的密码
sentinel auth-pass mymaster 000000
# 主观下线判定时间(毫秒)建议10000
sentinel down-after-milliseconds mymaster 30000
# 故障转移超时时间(毫秒)建议90000
sentinel failover-timeout mymaster 180000
# 故障转移后,允许多少个从节点同时向新主节点同步数据
sentinel parallel-syncs mymaster 1
[root@redis01 ~]# scp /etc/redis/sentinel.conf redis02:/etc/redis/
sentinel.conf 100% 14KB 9.3MB/s 00:00
[root@redis01 ~]# scp /etc/redis/sentinel.conf redis03:/etc/redis/
sentinel.conf 100% 14KB 12.2MB/s 00:00
[root@redis01 ~]#
- 创建 Systemd 服务
cat > /etc/systemd/system/redis-sentinel.service << 'EOF'
[Unit]
Description=Redis Sentinel
After=network.target
[Service]
Type=forking
ExecStart=/usr/local/bin/redis-sentinel /etc/redis/sentinel.conf
ExecStop=/usr/local/bin/redis-cli -p 26379 shutdown
Restart=always
User=root
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
- 所有节点启动服务
systemctl start redis-sentinel
[root@redis01 ~]# systemctl status redis-sentinel
● redis-sentinel.service - Redis Sentinel
Loaded: loaded (/etc/systemd/system/redis-sentinel.service; disabled; vendor preset: disabled)
Active: active (running) since Mon 2026-06-01 21:05:14 EDT; 6s ago
Process: 3149 ExecStart=/usr/local/bin/redis-sentinel /etc/redis/sentinel.conf (code=exited, status=0/SUCCESS)
Main PID: 3150 (redis-sentinel)
CGroup: /system.slice/redis-sentinel.service
└─3150 /usr/local/bin/redis-sentinel 0.0.0.0:26379 [sentinel]
Jun 01 21:05:14 redis01 systemd[1]: Starting Redis Sentinel...
Jun 01 21:05:14 redis01 systemd[1]: Started Redis Sentinel.
- 主节点查看
[root@redis01 ~]# redis-cli -p 26379 info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.200.100:6379,slaves=2,sentinels=3
[root@redis01 ~]# redis-cli -p 26379 sentinel master mymaster
1) "name"
2) "mymaster"
3) "ip"
4) "192.168.200.100"
5) "port"
6) "6379"
7) "runid"
8) "14bd73adec4528feb1d653bcade387d7531d5879"
9) "flags"
10) "master"
11) "link-pending-commands"
12) "0"
13) "link-refcount"
14) "1"
15) "last-ping-sent"
16) "0"
17) "last-ok-ping-reply"
18) "192"
19) "last-ping-reply"
20) "192"
21) "down-after-milliseconds"
22) "30000"
23) "info-refresh"
24) "9887"
25) "role-reported"
26) "master"
27) "role-reported-time"
28) "50047"
29) "config-epoch"
30) "0"
31) "num-slaves"
32) "2"
33) "num-other-sentinels"
34) "2"
35) "quorum"
36) "2"
37) "failover-timeout"
38) "180000"
39) "parallel-syncs"
40) "1"
故障测试
- 一台节点对redis脚本写入测试
bash redis_sentinel_write_test.sh
- 停止主节点
[root@redis01 ~]# systemctl stop redis
- 查看故障转移
[root@redis02 ~]# redis-cli -p 26379 info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.200.100:6379,slaves=2,sentinels=3
[root@redis02 ~]# redis-cli -p 26379 info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.200.102:6379,slaves=2,sentinels=3
[root@redis02 ~]# redis-cli -p 26379 info sentinel
- 查看脚本
[root@redis03 ~]# bash redis_sentinel_write_test.sh
=========================================
Redis Sentinel 写入测试
=========================================
Sentinel 节点: 192.168.200.100 192.168.200.101 192.168.200.102
写入间隔: 0.1秒
=========================================
获取 Master 地址... 192.168.200.100:6379
测试 Redis 连接... ✅
开始写入数据,按 Ctrl+C 停止
----------------------------------------
[22:12:58] 🔄 Master 变更: 192.168.200.100:6379
[22:12:59] ✅ 写入成功 #10 | Master: 192.168.200.100
[22:13:01] ✅ 写入成功 #20 | Master: 192.168.200.100
[22:13:02] ✅ 写入成功 #30 | Master: 192.168.200.100
[22:13:03] ✅ 写入成功 #40 | Master: 192.168.200.100
[22:13:04] ✅ 写入成功 #50 | Master: 192.168.200.100
[22:13:06] ✅ 写入成功 #60 | Master: 192.168.200.100
[22:13:07] ✅ 写入成功 #70 | Master: 192.168.200.100
[22:13:08] ✅ 写入成功 #80 | Master: 192.168.200.100
[22:13:08] ❌ 写入失败 #1 | Master: 192.168.200.100
[22:13:09] ❌ 写入失败 #2 | Master: 192.168.200.100
[22:13:09] ❌ 写入失败 #3 | Master: 192.168.200.100
[22:13:10] ❌ 写入失败 #4 | Master: 192.168.200.100
[22:13:11] ❌ 写入失败 #5 | Master: 192.168.200.100
[22:13:11] ❌ 写入失败 #6 | Master: 192.168.200.100
[22:13:12] ❌ 写入失败 #7 | Master: 192.168.200.100
[22:13:13] ❌ 写入失败 #8 | Master: 192.168.200.100
[22:13:13] ❌ 写入失败 #9 | Master: 192.168.200.100
[22:13:14] ❌ 写入失败 #10 | Master: 192.168.200.100
[22:13:14] ❌ 写入失败 #11 | Master: 192.168.200.100
[22:13:15] ❌ 写入失败 #12 | Master: 192.168.200.100
[22:13:16] ❌ 写入失败 #13 | Master: 192.168.200.100
[22:13:16] ❌ 写入失败 #14 | Master: 192.168.200.100
[22:13:17] ❌ 写入失败 #15 | Master: 192.168.200.100
[22:13:18] ❌ 写入失败 #16 | Master: 192.168.200.100
[22:13:18] ❌ 写入失败 #17 | Master: 192.168.200.100
[22:13:19] ❌ 写入失败 #18 | Master: 192.168.200.100
[22:13:19] ❌ 写入失败 #19 | Master: 192.168.200.100
[22:13:20] ❌ 写入失败 #20 | Master: 192.168.200.100
[22:13:21] ❌ 写入失败 #21 | Master: 192.168.200.100
[22:13:21] ❌ 写入失败 #22 | Master: 192.168.200.100
[22:13:22] ❌ 写入失败 #23 | Master: 192.168.200.100
[22:13:23] ❌ 写入失败 #24 | Master: 192.168.200.100
[22:13:23] ❌ 写入失败 #25 | Master: 192.168.200.100
[22:13:24] ❌ 写入失败 #26 | Master: 192.168.200.100
[22:13:24] ❌ 写入失败 #27 | Master: 192.168.200.100
[22:13:25] ❌ 写入失败 #28 | Master: 192.168.200.100
[22:13:26] ❌ 写入失败 #29 | Master: 192.168.200.100
[22:13:26] ❌ 写入失败 #30 | Master: 192.168.200.100
[22:13:27] ❌ 写入失败 #31 | Master: 192.168.200.100
[22:13:28] ❌ 写入失败 #32 | Master: 192.168.200.100
[22:13:28] ❌ 写入失败 #33 | Master: 192.168.200.100
[22:13:29] ❌ 写入失败 #34 | Master: 192.168.200.100
[22:13:29] ❌ 写入失败 #35 | Master: 192.168.200.100
[22:13:30] ❌ 写入失败 #36 | Master: 192.168.200.100
[22:13:31] ❌ 写入失败 #37 | Master: 192.168.200.100
[22:13:31] ❌ 写入失败 #38 | Master: 192.168.200.100
[22:13:32] ❌ 写入失败 #39 | Master: 192.168.200.100
[22:13:33] ❌ 写入失败 #40 | Master: 192.168.200.100
[22:13:33] ❌ 写入失败 #41 | Master: 192.168.200.100
[22:13:34] ❌ 写入失败 #42 | Master: 192.168.200.100
[22:13:34] ❌ 写入失败 #43 | Master: 192.168.200.100
[22:13:35] ❌ 写入失败 #44 | Master: 192.168.200.100
[22:13:36] ❌ 写入失败 #45 | Master: 192.168.200.100
[22:13:36] ❌ 写入失败 #46 | Master: 192.168.200.100
[22:13:37] ❌ 写入失败 #47 | Master: 192.168.200.100
[22:13:38] ❌ 写入失败 #48 | Master: 192.168.200.100
[22:13:38] ❌ 写入失败 #49 | Master: 192.168.200.100
[22:13:39] ❌ 写入失败 #50 | Master: 192.168.200.100
[22:13:39] 🔄 Master 变更: 192.168.200.102:6379
[22:13:40] ✅ 写入成功 #90 | Master: 192.168.200.102
[22:13:42] ✅ 写入成功 #100 | Master: 192.168.200.102
[22:13:43] ✅ 写入成功 #110 | Master: 192.168.200.102
[22:13:44] ✅ 写入成功 #120 | Master: 192.168.200.102
[22:13:45] ✅ 写入成功 #130 | Master: 192.168.200.102
[22:13:47] ✅ 写入成功 #140 | Master: 192.168.200.102
[22:13:48] ✅ 写入成功 #150 | Master: 192.168.200.102
[22:13:49] ✅ 写入成功 #160 | Master: 192.168.200.102
[22:13:50] ✅ 写入成功 #170 | Master: 192.168.200.102
[22:13:52] ✅ 写入成功 #180 | Master: 192.168.200.102
-
其中30s受参数影响
主观下线判定时间(毫秒)
sentinel down-after-milliseconds mymaster 30000
[22:13:08] ✅ 最后一次成功写入 (Master: 192.168.200.100)
[22:13:08] ❌ 第一次写入失败 - 故障开始
[22:13:08] ~ [22:13:39] 持续失败约 31 秒
[22:13:39] 🔄 Master 变更: 192.168.200.102:6379 ← 切换完成
[22:13:40] ✅ 写入恢复成功
- 测试脚本
#!/bin/bash
# 文件名: redis_sentinel_write_test_fixed.sh
# ========== Sentinel 配置 ==========
SENTINEL_HOSTS=(
"192.168.200.100"
"192.168.200.101"
"192.168.200.102"
)
SENTINEL_PORT="26379"
MASTER_NAME="mymaster"
REDIS_PASSWORD="000000"
# ========== 测试参数 ==========
WRITE_INTERVAL=0.1
# ========== 颜色 ==========
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m'
counter=0
success=0
fail=0
current_master=""
echo "========================================="
echo " Redis Sentinel 写入测试"
echo "========================================="
echo "Sentinel 节点: ${SENTINEL_HOSTS[*]}"
echo "写入间隔: ${WRITE_INTERVAL}秒"
echo "========================================="
# ========== 从任意 Sentinel 获取 Master ==========
get_master_from_sentinel() {
for sentinel in "${SENTINEL_HOSTS[@]}"; do
# 测试 Sentinel 是否存活
if redis-cli -h "$sentinel" -p "$SENTINEL_PORT" ping 2>/dev/null | grep -q PONG; then
# 获取 Master 地址
master_info=$(redis-cli -h "$sentinel" -p "$SENTINEL_PORT" \
SENTINEL get-master-addr-by-name "$MASTER_NAME" 2>/dev/null)
if [ -n "$master_info" ] && [ "$master_info" != "nil" ]; then
master_ip=$(echo "$master_info" | head -1)
master_port=$(echo "$master_info" | tail -1)
echo "$master_ip:$master_port"
return 0
fi
fi
done
echo ""
return 1
}
# ========== 测试 Redis 连接==========
test_redis_connection() {
local host=$1
local port=$2
redis-cli -a "${REDIS_PASSWORD}" -h "${host}" -p "${port}" ping 2>/dev/null | grep -q PONG
return $?
}
# ========== 写入数据==========
write_data() {
local host=$1
local port=$2
local key=$3
local value=$4
redis-cli -a "${REDIS_PASSWORD}" -h "${host}" -p "${port}" \
set "${key}" "${value}" > /dev/null 2>&1
return $?
}
# ========== 初始化 - 获取 Master ==========
echo -n "获取 Master 地址... "
master_info=$(get_master_from_sentinel)
if [ -z "$master_info" ]; then
echo -e "${RED}❌ 失败${NC}"
echo "无法从任何 Sentinel 获取 Master 地址"
exit 1
fi
master_host=${master_info%:*}
master_port=${master_info#*:}
echo -e "${GREEN}$master_info${NC}"
# 测试 Redis 连接
echo -n "测试 Redis 连接... "
if test_redis_connection "$master_host" "$master_port"; then
echo -e "${GREEN}✅${NC}"
else
echo -e "${RED}❌${NC}"
echo "无法连接 Redis,请检查密码"
exit 1
fi
echo ""
echo "开始写入数据,按 Ctrl+C 停止"
echo "----------------------------------------"
# ========== 主循环 ==========
while true; do
counter=$((counter + 1))
# 每次写入前重新获取 Master
master_info=$(get_master_from_sentinel)
if [ -z "$master_info" ]; then
echo -e "[$(date '+%H:%M:%S')] ${YELLOW}⚠️ 无法获取 Master${NC}"
sleep 1
continue
fi
master_host=${master_info%:*}
master_port=${master_info#*:}
# 生成唯一 key
key="test:$(date +%s%N)"
value="val_$counter"
# 写入数据
if write_data "$master_host" "$master_port" "$key" "$value"; then
success=$((success + 1))
# Master 变化时打印
if [ "$master_info" != "$current_master" ]; then
current_master="$master_info"
echo -e "[$(date '+%H:%M:%S')] 🔄 Master 变更: ${GREEN}$current_master${NC}"
fi
# 每 10 次成功打印一次
if [ $((success % 10)) -eq 0 ]; then
echo -e "[$(date '+%H:%M:%S')] ${GREEN}✅${NC} 写入成功 #$success | Master: $master_host"
fi
else
fail=$((fail + 1))
echo -e "[$(date '+%H:%M:%S')] ${RED}❌${NC} 写入失败 #$fail | Master: $master_host"
sleep 0.5
fi
sleep "$WRITE_INTERVAL"
done
更多推荐


所有评论(0)