39-41-Linux学习之旅之redis缓存基础与NFS基础

Linux学习之旅之redis缓存基础

一、redis基础

1、redsi特性

bash 复制代码
1. 丰富的数据结构
不止简单字符串 String,内置多种结构:String、Hash、List、Set、ZSet、BitMap、HyperLogLog、Geo、Stream。
String:普通 KV、计数器
Hash:对象存储,局部字段更新
ZSet:排行榜、延时任务
Stream:消息队列
BitMap:签到、状态标记
不用自己封装复杂结构,业务直接使用。

2. 内存存储,支持持久化
主数据全部放在内存,读写极快;
支持两种持久化,防止宕机数据丢失:
RDB:快照,定时全量 dump 内存到磁盘文件,适合备份,恢复速度快
AOF:日志追加,记录每一条写命令,数据安全性更高,可配置刷盘策略 always/everysec/no
缓存场景可以关闭持久化;需要落地数据建议开启 AOF。

3. 高性能网络模型:单线程 + IO 多路复用
Redis 的 "单线程" 指命令执行线程是单线程;RDB/AOF、集群同步是额外子线程。
使用 epoll/kqueue IO 多路复用,一个线程处理大量客户端 socket 连接;
没有多线程锁竞争、上下文切换开销;
命令串行执行,单个命令是原子性。
⚠️注意:大 key、慢命令会阻塞整个 Redis,所以禁止 keys、hgetall 等高危命令线上裸跑。

4. 过期淘汰机制
TTL 过期:支持 key 设置过期时间,惰性删除 + 定期删除清理过期数据
maxmemory‑policy内存淘汰策略:内存满了自动淘汰 key,非常适合缓存场景。

5. 原子操作 & 事务 & Lua 脚本
单条 Redis 命令天然原子;
MULTI/EXEC 简单事务,不支持回滚;
Lua 脚本:多条命令打包原子执行,减少网络往返,常用于分布式锁、复杂计数逻辑。

6. 高可用与分布式能力
主从复制:主节点写,从节点同步数据,读请求可以分摊到从库;
Sentinel 哨兵:监控、自动故障转移,主节点宕机自动提升从节点为主;
Redis‑Cluster 集群:分片,数据分散到多个节点,横向扩容,突破单机内存、QPS 上限。

2、redis性能优势

bash 复制代码
1. 内存读写,速度极高
数据主要在内存,访问速度远高于磁盘数据库。单机 QPS 可达几万~十几万,简单 GET/SET 可达 10w+ QPS。

2. IO 多路复用模型,高并发连接
单进程可以维持数万客户端连接,连接开销小。

3. 命令执行无锁开销
单线程串行执行命令,不存在多线程锁冲突,内部不需要复杂锁,实现简单高效。

4. 序列化开销小
原生处理字符串、二进制,可以直接存 JSON、字节流,对比磁盘数据库解析开销低。

5. 丰富内置能力,减少业务代码开发
计数器、排行榜、分布式锁、限流、去重,直接使用 Redis 能力,不用业务自己造轮子。

6. 支持水平扩展
哨兵实现高可用;Cluster 集群分片,可扩容内存和并发能力。

7. 灵活:缓存 + 持久化两用
可以当纯缓存(关闭持久化),也可以做持久化存储,保存业务数据。

3、QPS和TPS

bash 复制代码
1. QPS:Queries Per Second 每秒查询数
每秒查询请求数,侧重读请求。
接口、Redis、HTTP:每秒收到多少个查询请求
Redis:get 就是一次 query
QPS = 总查询次数 / 统计时间 (秒)
示例:1 秒内 1000 次 get 查询 → QPS=1000

2. TPS:Transactions Per Second 每秒事务数
每秒事务数,侧重业务事务。
TPS 代表每秒完成多少个完整业务事务 / 交易。
MySQL 数据库场景
一个事务可以包含多条 SQL(select、insert、update)
比如下单事务:查询库存、扣库存、生成订单,这一整套算1 个 TPS,但会产生多条 SQL,对应多个 QPS。
👉 TPS ≠ QPS,通常 QPS > TPS
Redis 中很少用 TPS
Redis 单条命令是原子,但没有数据库事务的 ACID 事务概念,Redis 一般不说 TPS,用 OPS/QPS。
误区:很多人把 TPS 当成每秒 SQL 数,这是错误叫法。

4、redis常见数据类型

类型 底层结构 特点 典型应用场景 常用命令
String(字符串) SDS 简单动态字符串 最基础类型,二进制安全,value 最大 512MB 缓存对象 JSON、计数器、分布式锁、Session 存储 SET GET INCR DECR SETEX MSET
Hash(哈希) 哈希表 / 压缩列表 field-value 键值对集合,适合存对象,可局部更新字段 用户信息、商品属性、配置项 HSET HGET HGETALL HDEL HMSET HINCRBY
List(列表) 双向链表 / 压缩列表 有序、可重复,支持两端插入弹出,按索引访问 消息队列、最新消息列表、任务队列、时间线 LPUSH RPUSH LPOP RPOP LRANGE BLPOP
Set(集合) 哈希表 / 整数集合 无序、不重复,支持交集并集差集运算 标签系统、共同好友、去重、抽奖 SADD SMEMBERS SISMEMBER SINTER SUNION SDIFF
ZSet(有序集合) 跳表 + 哈希表 不重复,每个元素带 score 分数,按分数排序 排行榜、延时队列、权重任务、热搜榜 ZADD ZRANGE ZREVRANGE ZSCORE ZRANK ZINCRBY

二、redis安装与基础配置

1、官方源安装

bash 复制代码
root@Redis-13:~# apt update
root@Redis-13:~# apt-get install lsb-release curl gpg
root@Redis-13:~# apt update
root@Redis-13:~# apt install -y redis
root@Redis-13:~# systemctl status redis
● redis-server.service - Advanced key-value store
     Loaded: loaded (/usr/lib/systemd/system/redis-server.service; enabled; preset: enabled)
     Active: active (running) since Mon 2026-09-07 07:22:19 UTC; 18s ago
       Docs: http://redis.io/documentation,
             man:redis-server(1)
   Main PID: 4520 (redis-server)
     Status: "Ready to accept connections"
      Tasks: 7 (limit: 2130)
     Memory: 5.5M (peak: 5.8M)
        CPU: 162ms
     CGroup: /system.slice/redis-server.service
             └─4520 "/usr/bin/redis-server 127.0.0.1:6379"

Sep 07 07:22:19 Redis-13 systemd[1]: Starting redis-server.service - Advanced key-value store>
Sep 07 07:22:19 Redis-13 systemd[1]: Started redis-server.service - Advanced key-value store.

root@Redis-13:~# netstat -tnlp | grep redis
tcp        0      0 127.0.0.1:6379          0.0.0.0:*               LISTEN      4520/redis-ser     ver 1
tcp6       0      0 ::1:6379                :::*                    LISTEN      4520/redis-ser     ver 1
root@Redis-13:~#

2、二进制包安装

bash 复制代码
root@Redis-13:~# apt update
apt install -y --no-install-recommends ca-certificates wget gcc g++ libc6-dev libssl-dev make automake autoconf libtool build-essential libsystemd-dev pkg-config


root@ubuntu2404ser:~# cd /usr/local/src

root@ubuntu2404ser:/usr/local/src# wget -O redis-$version.tar.gz http://download.redis.io/releases/                       redis-$version.tar.gz
root@ubuntu2404ser:/usr/local/src# ls
redis-8.4.0.tar.gz
root@ubuntu2404ser:/usr/local/src# tar xf redis-8.4.0.tar.gz
root@ubuntu2404ser:/usr/local/src# ls
redis-8.4.0  redis-8.4.0.tar.gz
root@ubuntu2404ser:/usr/local/src# cd redis-8.4.0/


root@ubuntu2404ser:/usr/local/src/redis-8.4.0# export BUILD_TLS=no
root@ubuntu2404ser:/usr/local/src/redis-8.4.0# export BUILD_WITH_MODULES=no
root@ubuntu2404ser:/usr/local/src/redis-8.4.0# export INSTALL_RUST_TOOLCHAIN=no
root@ubuntu2404ser:/usr/local/src/redis-8.4.0# export DISABLE_WERRORS=yes
root@ubuntu2404ser:/usr/local/src/redis-8.4.0# make -j "$(nproc)" all USE_SYSTEMD=yes


root@ubuntu2404ser:/usr/local/src/redis-8.4.0# make install


root@ubuntu2404ser:/usr/local/src/redis-8.4.0# ls /usr/local/bin/
redis-benchmark  redis-check-aof  redis-check-rdb  redis-cli  redis-sentinel  redis-server
root@ubuntu2404ser:/usr/local/src/redis-8.4.0# echo 'vm.overcommit_memory = 1' | sudo tee -a /etc/s                       ysctl.conf



root@ubuntu2404ser:/usr/local/src/redis-8.4.0# cp utils/systemd-redis_server.service /etc/systemd/s                       ystem/redis.service
root@ubuntu2404ser:/usr/local/src/redis-8.4.0# vim /etc/systemd/system/redis.service
[Service]
#ExecStart=/usr/local/bin/redis-server --supervised systemd --daemonize no
## Alternatively, have redis-server load a configuration file:
ExecStart=/usr/local/bin/redis-server /etc/redis/redis-6379.conf
LimitNOFILE=10032
NoNewPrivileges=yes
OOMScoreAdjust=-900
PrivateTmp=yes
Type=notify
TimeoutStartSec=infinity
TimeoutStopSec=infinity
UMask=0077
#User=redis
#Group=redis
WorkingDirectory=/var/lib/redis

root@ubuntu2404ser:/usr/local/src/redis-8.4.0# useradd -s /sbin/nologin redis
root@ubuntu2404ser:/usr/local/src/redis-8.4.0# mkdir -p /var/{lib,log,run}/redis /etc/redis
root@ubuntu2404ser:/usr/local/src/redis-8.4.0# cp redis.conf /etc/redis/redis-6379.conf
root@ubuntu2404ser:/usr/local/src/redis-8.4.0# chown -R redis:redis /var/{lib,log,run}/redis /etc/redis
root@ubuntu2404ser:/usr/local/src/redis-8.4.0# vim /etc/redis/redis-6379.conf
daemonize no
supervised systemd
pidfile /var/run/redis/redis_6379.pid


root@ubuntu2404ser:/usr/local/src/redis-8.4.0# systemctl daemon-reload
root@ubuntu2404ser:/usr/local/src/redis-8.4.0# systemctl restart redis.service
root@ubuntu2404ser:/usr/local/src/redis-8.4.0# systemctl status redis.service
     Active: active (running) since Mon 2026-09-07 08:43:23 UTC; 8s ago


root@ubuntu2404ser:/usr/local/src/redis-8.4.0# netstat -tnlp | grep redis
tcp        0      0 127.0.0.1:6379          0.0.0.0:*               LISTEN      26765/redis-server
tcp6       0      0 ::1:6379                :::*                    LISTEN      26765/redis-server
root@ubuntu2404ser:/usr/local/src/redis-8.4.0#

3、脚本安装

bash 复制代码
root@ubuntu2404ser:~# vim redis_install.sh
#!/bin/bash
# *************************************
# * 功能: Redis部署脚本
# * 作者: 马哥教育王树森老师
# * 联系: wangshusen@sswang.com
# * 版本: 2026-06-11
# *************************************

# ====================== 颜色定义 ======================
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # 恢复默认颜色

# ====================== 全局配置 ======================
REDIS_VERSION="8.4.0"
REDIS_URL="https://download.redis.io/releases/redis-${REDIS_VERSION}.tar.gz"
SRC_BASE="/usr/local/src"
REDIS_SRC="${SRC_BASE}/redis-${REDIS_VERSION}"
CONF_DIR="/etc/redis"
REDIS_PORT="6379"
DATA_DIR="/var/lib/redis"
LOG_DIR="/var/log/redis"
RUN_DIR="/var/run/redis"
RUN_USER="redis"
MAIN_CONF="${CONF_DIR}/redis-${REDIS_PORT}.conf"
SYSTEMD_SVC="/etc/systemd/system/redis.service"

# ====================== 工具函数 ======================
info() {
  echo -e "${GREEN}[INFO] $1${NC}"
}
warn() {
  echo -e "${YELLOW}[WARN] $1${NC}"
}
error() {
  echo -e "${RED}[ERROR] $1${NC}"
}
title() {
    echo -e "\n${BLUE}==================================== $1 ====================================${NC}"
}

# ====================== 功能函数 ======================
# 1. 安装编译依赖
install_deps() {
    title "安装编译依赖包"
    apt update -y
    apt install -y --no-install-recommends ca-certificates wget gcc \
        g++ libc6-dev libssl-dev make  automake autoconf libtool
    apt install -y --no-install-recommends \
        build-essential pkg-config libssl-dev libjemalloc-dev libsystemd-dev
    info "基础编译依赖安装完成"
}

# 2. 下载&解压源码
download_extract() {
    title "下载并解压 Redis 源码"
    mkdir -p ${SRC_BASE}
    cd ${SRC_BASE}

    if [ ! -f "redis-${REDIS_VERSION}.tar.gz" ]; then
        info "开始下载 Redis ${REDIS_VERSION} 源码包"
        wget -q ${REDIS_URL}
    else
        warn "源码包已存在,跳过下载"
    fi

    tar -xf redis-${REDIS_VERSION}.tar.gz
    cd ${REDIS_SRC}
    info "源码解压完成,当前目录: $(pwd)"
}

# 3. 编译 Redis(关闭模块/TLS,开启 systemd)
compile_redis() {
    title "编译 Redis"
    export BUILD_TLS=no
    export BUILD_WITH_MODULES=no
    export INSTALL_RUST_TOOLCHAIN=no
    export DISABLE_WERRORS=yes

    make -j "$(nproc)" all USE_SYSTEMD=yes
    if [ $? -eq 0 ]; then
        info "Redis 编译成功"
    else
        error "Redis 编译失败,退出脚本"
        exit 1
    fi
}

# 4. 安装二进制程序
install_bin() {
    title "安装 Redis 二进制文件"
    make install
}

# 5. 创建运行用户 & 目录
create_user_dir() {
    title "创建运行用户与数据目录"
    useradd -s /sbin/nologin ${RUN_USER} 2>/dev/null || warn "用户 ${RUN_USER} 已存在"
    mkdir -p ${CONF_DIR} ${DATA_DIR} ${LOG_DIR} ${RUN_DIR}
    chown -R ${RUN_USER}:${RUN_USER} ${CONF_DIR} ${DATA_DIR} ${LOG_DIR} ${RUN_DIR}
    info "用户与目录创建&授权完成"
}

# 6. 初始化配置文件
init_config() {
    title "初始化 Redis 配置文件"
    cp ${REDIS_SRC}/redis.conf ${MAIN_CONF}

    # 适配 systemd、关闭后台运行、修改pid文件
    sed -i 's/^# supervised auto/supervised systemd/' ${MAIN_CONF}
    sed -i "s|^pidfile.*|pidfile ${RUN_DIR}/redis_${REDIS_PORT}.pid|" ${MAIN_CONF}

    info "主配置文件已生成: ${MAIN_CONF}"
}

# 7. 系统内核参数优化
sysctl_optimize() {
    title "配置内存 overcommit 参数"
    if ! grep -q 'vm.overcommit_memory = 1' /etc/sysctl.conf; then
        echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf
    fi
    sysctl -p >/dev/null 2>&1
    info "vm.overcommit_memory=1 已生效"
}

# 8. 配置 systemd 服务
config_systemd() {
    title "配置 systemd 系统服务"
    cat > ${SYSTEMD_SVC} <<-EOF
[Unit]
Description=Redis Data Structure Server
Documentation=https://redis.io/documentation
Wants=network-online.target
After=network-online.target

[Service]
ExecStart=/usr/local/bin/redis-server ${MAIN_CONF}
LimitNOFILE=10032
NoNewPrivileges=yes
OOMScoreAdjust=-900
PrivateTmp=yes
Type=notify
TimeoutStartSec=infinity
TimeoutStopSec=infinity
UMask=0077
User=${RUN_USER}
Group=${RUN_USER}
WorkingDirectory=${DATA_DIR}

[Install]
WantedBy=multi-user.target
EOF
    systemctl daemon-reload
    systemctl enable redis
    info "systemd 服务配置完成,已设置开机自启"
}

# 9. 启动服务 & 验证
start_and_check() {
    title "启动 Redis 服务并验证"
    systemctl restart redis
    sleep 1

    if systemctl is-active --quiet redis; then
        info "Redis 服务启动成功!"
        echo -e "\n${BLUE}--- 服务状态 ---${NC}"
        systemctl status redis --no-pager

        echo -e "\n${BLUE}--- 连通性测试 ---${NC}"
        redis-cli ping
    else
        error "Redis 服务启动失败,请检查日志"
        systemctl status redis --no-pager
        exit 1
    fi
}

# ====================== 主执行入口 ======================
main() {
    if [ $(id -u) -ne 0 ]; then
        error "请使用 root 权限执行此脚本!"
        exit 1
    fi

    info "====== 开始执行 Redis ${REDIS_VERSION} 编译安装 ======"
    install_deps
    download_extract
    compile_redis
    install_bin
    create_user_dir
    init_config
    sysctl_optimize
    config_systemd
    start_and_check

    echo -e "\n${GREEN}==================== 全部安装流程执行完毕 ====================${NC}"
}

# 调用主函数
main

root@ubuntu2404ser:~# bash redis_install.sh
root@ubuntu2404ser:~# systemctl status redis.service

     Active: active (running) since Mon 2026-09-07 09:28:35 UTC; 22s ago
       Docs: https://redis.io/documentation

root@ubuntu2404ser:~# netstat -tnlp | grep redis
tcp        0      0 127.0.0.1:6379          0.0.0.0:*               LISTEN      21534/redis-server
tcp6       0      0 ::1:6379                :::*                    LISTEN      21534/redis-server
root@ubuntu2404ser:~#

三、基础配置

1、登录方式

bash 复制代码
root@Redis-13:~# redis-cli
127.0.0.1:6379> ping    #测试连通性
PONG        #正常
127.0.0.1:6379>exit        #退出


#选项:
    -h redis服务器地址
    -a redis登录密码
    -p 端口号
    --no-auth-warning 消除登陆时明文密码警告

2、监听端口号配置

bash 复制代码
#redis默认监听6379
root@Redis-13:~# vim /etc/redis/redis-6379.conf
#修改配置文件
root@Redis-13:~# grep -E "^port" /etc/redis/redis-6379.conf
port 6389
root@Redis-13:~# systemctl restart redis.service

root@Redis-13:~# netstat -tnlp | grep redis
tcp        0      0 127.0.0.1:6389          0.0.0.0:*               LISTEN      2012/redis-server 1
tcp6       0      0 ::1:6389                :::*                    LISTEN      2012/redis-server 1
root@Redis-13:~#

3、监听地址配置

bash 复制代码
#默认监听127.0.0.1,
root@Redis-13:~# vim /etc/redis/redis-6379.conf
root@Redis-13:~# grep "^bind" /etc/redis/redis-6379.conf
bind 10.0.0.13 127.0.0.1 -::1
root@Redis-13:~# systemctl restart redis.service
root@Redis-13:~# netstat -tnlp | grep redis
tcp        0      0 10.0.0.13:6379          0.0.0.0:*               LISTEN      2088/redis-server 1
tcp        0      0 127.0.0.1:6379          0.0.0.0:*               LISTEN      2088/redis-server 1
tcp6       0      0 ::1:6379                :::*                    LISTEN      2088/redis-server 1
root@Redis-13:~#

#连接测试
root@Redis-13:~# redis-cli -h 10.0.0.13
10.0.0.13:6379> ping
(error) DENIED Redis is running in protected mode because protected mode is enabled and no password is set for the default user. In this mode connections are only accepted from the loopback interface. If you want to connect from external computers to Redis you may adopt one of the following solutions: 1) Just disable protected mode sending the command 'CONFIG SET protected-mode no' from the loopback interface by connecting to Redis from the same host the server is running, however MAKE SURE Redis is not publicly accessible from internet if you do so. Use CONFIG REWRITE to make this change permanent. 2) Alternatively you can just disable the protected mode by editing the Redis configuration file, and setting the protected mode option to 'no', and then restarting the server. 3) If you started the server manually just for testing, restart it with the '--protected-mode no' option. 4) Set up an authentication password for the default user. NOTE: You only need to do one of the above things in order for the server to start accepting connections from the outside.
10.0.0.13:6379>
#报错是因为redis默认开启了安全模式,使用远程连接需要设置密码

4、安全模式与密码配置

bash 复制代码
#关闭安全模式,非必要不要关闭
root@Redis-13:~# vim /etc/redis/redis-6379.conf
root@Redis-13:~# grep "^protected-mode" /etc/redis/redis-6379.conf
protected-mode no
root@Redis-13:~# systemctl restart redis.service
root@Redis-13:~# redis-cli -h 10.0.0.13
10.0.0.13:6379> ping
PONG
10.0.0.13:6379> exit

#创建密码并恢复安全模式
root@Redis-13:~# vim /etc/redis/redis-6379.conf
root@Redis-13:~# grep "^protected-mode|^requirepass" /etc/redis/redis-6379.conf
root@Redis-13:~# grep -E "^protected-mode|^requirepass" /etc/redis/redis-6379.conf
protected-mode yes
requirepass Redis@2026            #默认没有需要添加一行
root@Redis-13:~# systemctl restart redis.service
#验证测试
root@Redis-13:~# redis-cli -h 10.0.0.13 -a Redis@2026
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
10.0.0.13:6379> ping
PONG
10.0.0.13:6379> exit
root@Redis-13:~#



root@Redis-13:~# redis-cli -h 10.0.0.13 -a Redis@2026 --no-auth-warning               #登录时添加--no-auth-warning可以消除登录告警
10.0.0.13:6379> ping
PONG
10.0.0.13:6379> exit
root@Redis-13:~#


#先登录后认证
root@Redis-13:~# redis-cli -p 6379 -h 10.0.0.13
10.0.0.13:6379> ping
(error) NOAUTH Authentication required.
10.0.0.13:6379> auth Redis@2026
OK
10.0.0.13:6379> ping
PONG
10.0.0.13:6379> exit
root@Redis-13:~#

5、daemonize 后台运行

bash 复制代码
#daemonize默认前台运行,no是前台运行,yes后台运行,生产推荐后台运行
root@Redis-13:~# grep "^daemonize" /etc/redis/redis-6379.conf
daemonize no
root@Redis-13:~# grep Type /etc/systemd/system/redis.service
Type=notify
root@Redis-13:~# system
systemctl                       systemd-cryptsetup              systemd-path
systemd                         systemd-delta                   systemd-repart
systemd-ac-power                systemd-detect-virt             systemd-run
systemd-analyze                 systemd-escape                  systemd-socket-activate
systemd-ask-password            systemd-firstboot               systemd-stdio-bridge
systemd-cat                     systemd-hwdb                    systemd-sysext
systemd-cgls                    systemd-id128                   systemd-sysusers
systemd-cgtop                   systemd-inhibit                 systemd-tmpfiles
systemd-confext                 systemd-machine-id-setup        systemd-tty-ask-password-agent
systemd-creds                   systemd-mount                   systemd-umount
systemd-cryptenroll             systemd-notify
root@Redis-13:~# systemctl status redis.service
● redis.service - Redis Data Structure Server
     Loaded: loaded (/etc/systemd/system/redis.service; enabled; preset: enabled)
     Active: active (running) since Tue 2026-09-08 01:11:58 UTC; 24min ago
       Docs: https://redis.io/documentation
   Main PID: 2257 (redis-server)
     Status: "Ready to accept connections"
      Tasks: 6 (limit: 2130)
     Memory: 2.7M (peak: 3.3M)
        CPU: 6.151s
     CGroup: /system.slice/redis.service
             └─2257 "/usr/local/bin/redis-server 10.0.0.13:6379"

Sep 08 01:11:58 Redis-13 redis-server[2257]: 2257:M 08 Sep 2026 01:11:58.631 # Failed to write PID file: >
Sep 08 01:11:58 Redis-13 redis-server[2257]: 2257:M 08 Sep 2026 01:11:58.631 * Running mode=standalone, p>
Sep 08 01:11:58 Redis-13 redis-server[2257]: 2257:M 08 Sep 2026 01:11:58.633 * Server initialized
Sep 08 01:11:58 Redis-13 redis-server[2257]: 2257:M 08 Sep 2026 01:11:58.633 * Loading RDB produced by ve>
Sep 08 01:11:58 Redis-13 redis-server[2257]: 2257:M 08 Sep 2026 01:11:58.633 * RDB age 0 seconds
Sep 08 01:11:58 Redis-13 redis-server[2257]: 2257:M 08 Sep 2026 01:11:58.633 * RDB memory usage when crea>
Sep 08 01:11:58 Redis-13 redis-server[2257]: 2257:M 08 Sep 2026 01:11:58.633 * Done loading RDB, keys loa>
Sep 08 01:11:58 Redis-13 redis-server[2257]: 2257:M 08 Sep 2026 01:11:58.633 * DB loaded from disk: 0.000>
Sep 08 01:11:58 Redis-13 redis-server[2257]: 2257:M 08 Sep 2026 01:11:58.633 * Ready to accept connection>
Sep 08 01:11:58 Redis-13 systemd[1]: Started redis.service - Redis Data Structure Server.
#可以观察到大量的日志在前台显示
root@Redis-13:~#


#修改为后台运行

root@Redis-13:~# vim /etc/redis/redis-6379.conf
root@Redis-13:~# vim /etc/systemd/system/redis.service
root@Redis-13:~# grep "^daemonize" /etc/redis/redis-6379.conf
daemonize yes
root@Redis-13:~# grep Type /etc/systemd/system/redis.service
Type=forking
root@Redis-13:~# systemctl daemon-reload
root@Redis-13:~# systemctl restart redis.service
root@Redis-13:~# systemctl status redis.service
● redis.service - Redis Data Structure Server
     Loaded: loaded (/etc/systemd/system/redis.service; enabled; preset: enabled)
     Active: active (running) since Tue 2026-09-08 01:39:28 UTC; 7s ago
       Docs: https://redis.io/documentation
    Process: 2496 ExecStart=/usr/local/bin/redis-server /etc/redis/redis-6379.conf (code=exited, status=0>
   Main PID: 2497 (redis-server)
      Tasks: 6 (limit: 2130)
     Memory: 2.5M (peak: 3.0M)
        CPU: 57ms
     CGroup: /system.slice/redis.service
             └─2497 "/usr/local/bin/redis-server 10.0.0.13:6379"

Sep 08 01:39:28 Redis-13 systemd[1]: Starting redis.service - Redis Data Structure Server...
Sep 08 01:39:28 Redis-13 redis-server[2496]: 2496:C 08 Sep 2026 01:39:28.171 # systemd supervision error:>
Sep 08 01:39:28 Redis-13 systemd[1]: Started redis.service - Redis Data Structure Server.

#可以观察到日志少了很多,那日志存放在哪?向下看

6、logfile 日志路径

bash 复制代码
#默认为空
root@Redis-13:~# grep "^logfile" /etc/redis/redis-6379.conf
logfile ""
#修改日志路径
root@Redis-13:~# vim /etc/redis/redis-6379.conf
root@Redis-13:~# grep "^logfile" /etc/redis/redis-6379.conf
logfile "/var/log/redis/redis-6379.log"
root@Redis-13:~# systemctl restart redis.service
root@Redis-13:~# ls /etc/redis/redis-6379.conf
/etc/redis/redis-6379.conf

root@Redis-13:~# tail -f /var/log/redis/redis-6379.log
2576:M 08 Sep 2026 01:43:44.889 * Running mode=standalone, port=6379.
2576:M 08 Sep 2026 01:43:44.890 * Server initialized
2576:M 08 Sep 2026 01:43:44.890 * Loading RDB produced by version 8.4.0
2576:M 08 Sep 2026 01:43:44.890 * RDB age 0 seconds
2576:M 08 Sep 2026 01:43:44.890 * RDB memory usage when created 0.64 Mb
2576:M 08 Sep 2026 01:43:44.890 * Done loading RDB, keys loaded: 0, keys expired: 0.
2576:M 08 Sep 2026 01:43:44.891 * DB loaded from disk: 0.000 seconds
2576:M 08 Sep 2026 01:43:44.891 * Ready to accept connections tcp
2576:M 08 Sep 2026 01:43:44.891 # systemd supervision error: NOTIFY_SOCKET not found!
2576:M 08 Sep 2026 01:43:44.891 # systemd supervision error: NOTIFY_SOCKET not found!
^C
root@Redis-13:~#



# 可选值:debug/verbose/notice/warning,默认 notice
root@Redis-13:~# grep "^loglevel" /etc/redis/redis-6379.conf
loglevel notice

debug :最详细,适合调试,生产环境不推荐;
notice :适中,记录关键信息,是生产环境推荐值;
warning :仅记录警告和错误,日志量最小。

7、持久化相关基础配置

bash 复制代码
#redis是内存数据类型,所有数据都运行在内存中,如意外服务关闭数据怎么办?

1. dir数据目录:RDB
#默认存放路径
root@Redis-13:~# grep '^dir' /etc/redis/redis-6379.conf
dir ./       
root@Redis-13:~# grep 'WorkingDirectory' /etc/systemd/system/redis.service
WorkingDirectory=/var/lib/redis

root@Redis-13:~# ls /var/lib/redis/
dump.rdb

#修改数据存放路径
root@Redis-13:~# vim /etc/redis/redis-6379.conf
root@Redis-13:~# grep '^dir' /etc/redis/redis-6379.conf
dir /data/redis
root@Redis-13:~# mkdir -p /data/redis
root@Redis-13:~# chown -R redis:redis /data/redis/
root@Redis-13:~# systemctl restart redis.service
root@Redis-13:~# ls /data/redis/
#为什么没有文件,因为在配置启动的下一次关闭
root@Redis-13:~# systemctl restart redis.service
root@Redis-13:~# ls /data/redis/
dump.rdb
root@Redis-13:~#

2. 修改数据文件名
#默认名称
root@Redis-13:~# grep '^dbfilename' /etc/redis/redis-6379.conf
dbfilename dump.rdb
root@Redis-13:~# vim /etc/redis/redis-6379.conf
root@Redis-13:~# grep '^dbfilename' /etc/redis/redis-6379.conf
dbfilename dump-6379.rdb
root@Redis-13:~# systemctl restart redis.service
root@Redis-13:~# ls /data/redis/
dump.rdb
#配置生效的下一次
root@Redis-13:~# systemctl restart redis.service
root@Redis-13:~# ls /data/redis/
dump-6379.rdb  dump.rdb
root@Redis-13:~#

3. AOF格式数据存储配置

root@Redis-13:~# vim /etc/redis/redis-6379.conf
root@Redis-13:~# vim /etc/redis/redis-6379.conf
root@Redis-13:~# grep '^appendfilename' /etc/redis/redis-6379.conf
appendfilename "appendonly-6379.aof"
root@Redis-13:~# grep '^appendonly' /etc/redis/redis-6379.conf
appendonly yes
root@Redis-13:~# systemctl restart redis.service
root@Redis-13:~# ls /data/redis/
appendonlydir  dump-6379.rdb  dump.rdb
root@Redis-13:~# ls /data/redis/appendonlydir/
appendonly-6379.aof.1.base.rdb  appendonly-6379.aof.1.incr.aof  appendonly-6379.aof.manifest
root@Redis-13:~#

四、RDB 持久化详解

1、定时快照机制

bash 复制代码
RDB(Redis Database)是 Redis 基础持久化方案,核心是满足修改条件时生成内存瞬时完整二进制快照:Redis 持续统计"键修改次数",当滑动时间窗口内键修改量达到配置阈值,Redis 通过 fork 子进程,将当前全量内存数据写入二进制快照文件 dump.rdb 落盘。

# 默认规则(Redis 出厂配置)
save 900 1 # 15分钟(900s)内累计至少1个键修改,触发bgsave
save 300 10 # 5分钟内累计至少10个键修改,触发bgsave
save 60 10000# 1分钟内累计至少10000个键修改,触发bgsave

2、命令保存save和bgsave

bash 复制代码
1. save

在 Redis 主进程内执行,没有子进程。
执行期间阻塞所有客户端请求,Redis 完全不可用。
把内存全部数据写入 dump.rdb。
执行完返回 OK,Redis 恢复服务。

特点
✅ 不需要 fork,没有额外内存开销;
❌ 全量阻塞,数据量大时阻塞时间很长,生产环境严禁使用;
适合:测试、数据量很小的本地环境。
如果 Redis 内存几十 GB,执行 save,业务直接卡死。


2. bgsave

主进程调用 fork() 创建子进程;fork 瞬间短暂阻塞。
fork 完成后,主进程继续处理客户端命令,不阻塞业务。
子进程负责把内存快照写入临时 rdb 文件。
写完后替换旧的 dump.rdb,子进程退出。

特点
✅ 绝大部分时间不阻塞业务;生产 RDB 都用 bgsave;
⚠️ fork () 那一瞬间会短暂阻塞;内存越大,fork 耗时越长;
⚠️ 写时复制 COW:fork 之后如果大量写,内存占用会上涨;
❗bgsave 执行期间,不能再执行第二个 bgsave(Redis 会拒绝,返回 Background save already in progress)。
redis.conf 里面 save 900 1 这种自动快照规则,底层实际调用的就是 bgsave,不是 save。

3、bgsave和save测试

bash 复制代码
1. bgsave
#先禁用AOF
root@Redis-13:~# vim /etc/redis/redis-6379.conf
root@Redis-13:~# grep '^appendonly' /etc/redis/redis-6379.conf
appendonly no
root@Redis-13:~# systemctl stop redis.service
root@Redis-13:~# rm -rf /data/redis/*
root@Redis-13:~# ls /data/redis/
root@Redis-13:~# systemctl start redis.service


root@Redis-13:~# redis-cli -a Redis@2026
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> bgsave
Background saving started
root@Redis-13:~# ll /data/redis/dump-6379.rdb
-rw------- 1 redis redis 88 Sep  8 03:00 /data/redis/dump-6379.rdb

127.0.0.1:6379> set nihao wobuhao
OK
127.0.0.1:6379> get nihao
"wobuhao"
127.0.0.1:6379> bgsave
Background saving started
root@Redis-13:~# ll /data/redis/dump-6379.rdb
-rw------- 1 redis redis 108 Sep  8 03:02 /data/redis/dump-6379.rdb
#文件大小变化

2. save
#配置自动保存
root@Redis-13:~# vim /etc/redis/redis-6379.conf
root@Redis-13:~# grep -C 1 '^save 300 100' /etc/redis/redis-6379.conf
save 3600 1
save 300 100
save 60 10000
root@Redis-13:~# systemctl restart redis.service
root@Redis-13:~# ll /data/redis/dump-6379.rdb
-rw------- 1 redis redis 108 Sep  8 03:06 /data/redis/dump-6379.rdb
#for循环测试保存效果
root@Redis-13:~# for i in {1..10200}; do redis-cli -a Redis@2026 set high$i $i >/dev/null 2>&1; done
root@Redis-13:~# redis-cli -a Redis@2026 info persistence | grep rdb_saves:
rdb_saves:1            #查看保存次数
root@Redis-13:~# redis-check-rdb /data/redis/dump-6379.rdb
[offset 0] Checking RDB file /data/redis/dump-6379.rdb
[offset 26] AUX FIELD redis-ver = '8.4.0'
[offset 40] AUX FIELD redis-bits = '64'
[offset 52] AUX FIELD ctime = '1788836936'
[offset 67] AUX FIELD used-mem = '1234344'
[offset 79] AUX FIELD aof-base = '0'
[offset 81] Selecting DB ID 0
[offset 129016] Checksum OK
[offset 129016] \o/ RDB looks OK! \o/
[info] 10011 keys read                    #查看保存的key数量
[info] 0 expires
[info] 0 already expired
[info] 0 subexpires

#手动保存一次
root@Redis-13:~# redis-cli -a Redis@2026 bgsave
Background saving started

root@Redis-13:~# redis-check-rdb /data/redis/dump-6379.rdb
[offset 0] Checking RDB file /data/redis/dump-6379.rdb
[offset 26] AUX FIELD redis-ver = '8.4.0'
[offset 40] AUX FIELD redis-bits = '64'
[offset 52] AUX FIELD ctime = '1788837161'
[offset 67] AUX FIELD used-mem = '1284336'
[offset 79] AUX FIELD aof-base = '0'
[offset 81] Selecting DB ID 0
[offset 131676] Checksum OK
[offset 131676] \o/ RDB looks OK! \o/
[info] 10201 keys read                #保存key数量
[info] 0 expires
[info] 0 already expired
[info] 0 subexpires
root@Redis-13:~#

4、RDB使用场景和优缺点

优缺点

类别 内容
✅优点 1. 二进制压缩,RDB 文件体积小,节省磁盘 2. 恢复速度快,直接加载二进制文件,无需回放命令 3.bgsave 后台执行,仅 fork 瞬间短暂阻塞,业务基本不受影响 4. 适合冷备份、数据迁移、主从全量同步,方便异地归档 5. 灾难恢复介质,可拷贝 rdb 文件到其他服务器恢复
❌缺点 1. 快照机制,两次快照之间宕机会丢失该时间段数据 2.bgsave 需要 fork,内存越大 fork 阻塞时间越长 3.fork 后大量写会触发 COW 写时复制,内存占用上涨,可能 OOM 4. 二进制格式,Redis 版本不兼容,高版本 rdb 低版本无法读取 5.rdb 文件损坏会直接导致数据不可用,启动失败

RDB 适用 / 不适用场景

类别 内容
✅优点 1. 二进制压缩,RDB 文件体积小,节省磁盘 2. 恢复速度快,直接加载二进制文件,无需回放命令 3.bgsave 后台执行,仅 fork 瞬间短暂阻塞,业务基本不受影响 4. 适合冷备份、数据迁移、主从全量同步,方便异地归档 5. 灾难恢复介质,可拷贝 rdb 文件到其他服务器恢复
❌缺点 1. 快照机制,两次快照之间宕机会丢失该时间段数据 2.bgsave 需要 fork,内存越大 fork 阻塞时间越长 3.fork 后大量写会触发 COW 写时复制,内存占用上涨,可能 OOM 4. 二进制格式,Redis 版本不兼容,高版本 rdb 低版本无法读取 5.rdb 文件损坏会直接导致数据不可用,启动失败

save vs bgsave

对比项 save bgsave
执行进程 Redis 主进程 fork 子进程
阻塞情况 全程阻塞 Redis,所有请求挂起 仅 fork 瞬间短暂阻塞,之后不阻塞
内存开销 无额外内存开销 fork+COW,大量写会增加内存占用
并发执行 可多次调用 同一时刻只能运行 1 个 bgsave
生产环境 禁止使用 生产 RDB 底层都是 bgsave
底层调用 手动命令 手动 bgsave;配置 save 规则底层调用 bgsave

五、AOF持久化详解

1、AOF基础知识

bash 复制代码
AOF(Append Only File)采用增量日志持久化思路:不存储全量数据快照,而是把客户端执行的所有写操作命令以 Redis RESP 协议格式追加写入磁盘日志文件。
当 Redis 进程异常崩溃、服务器断电重启时,读取 AOF 文件内全部命令逐条重放,即可还原崩溃前内存数据集,弥补 RDB 定时快照存在固定数据丢失窗口的缺陷。

-------------------------------------
这是 Redis RESP 协议(Redis 序列化协议),AOF 文件内部存的不是人类可读的普通文本命令,而是 RESP 格式。

*3
$3
SET
$4
name
$3
xyx

#*3

* 代表数组,3 = 数组里面有 3 个元素
SET name xyx 这条命令拆成数组:[SET, name, xyx],一共 3 个元素,所以写 *3

#$3

$ 代表字符串(Bulk String),3 = 后面字符串字节长度是 3
下一行就是字符串内容:SET(正好 3 个字符 S‑E‑T)

#SET
真正的字符串内容。

#$4
下一个字符串,长度 4;后面内容:name(n‑a‑m‑e,4 字符)

#name

#$3
下一个字符串,长度 3;后面内容:xyx(x‑y‑x,3 字符)
xyx
-------------------------------------

若同时开启 RDB + AOF:优先加载 AOF 文件(数据完整性更高),忽略 dump.rdb;
仅开启 RDB:加载 RDB 快照恢复;仅开启 AOF:仅读取 appendonly.aof;
两者都关闭:启动后为空库

-------------------------------------

AOF 重放机制
AOF 文件保存的是 RESP 格式的写命令序列。AOF 重放:Redis 启动时,读取 AOF 文件,把里面每一条 RESP 命令,模拟成客户端发来的请求,逐条执行,把数据恢复到内存。
RDB:加载二进制快照直接还原内存;
AOF 重放:逐条回放命令重建内存数据。


完整重放流程
1.Redis 启动,判断开启appendonly yes,优先加载 AOF,不再加载 RDB。
2.打开appendonly.aof文件。
3.按 RESP 协议解析 AOF 文件,读取一条条命令。
4.将解析出来的写命令,交给 Redis 命令执行器,像接收客户端命令一样执行。
5.全部命令执行完毕,数据恢复完成,开始对外提供服务。

2、与 RDB 快照机制核心对比

对比维度 RDB(快照) AOF(日志)
核心机制 快照机制:保存某一瞬间完整内存数据集,二进制 dump 文件 日志追加机制:记录每一条写命令,RESP 协议文本日志
数据表达 某一个时间点的完整状态 一系列变更操作命令序列
生成数据方式 bgsave fork 子进程,拷贝内存视图输出二进制快照 写命令到来,追加 RESP 格式命令;bgrewriteaoffork 根据内存生成精简日志
数据恢复原理 直接加载二进制快照,还原内存状态 AOF 重放:逐条解析执行 AOF 中的写命令,重建内存数据
数据丢失风险 两次快照之间宕机,丢失该区间全部数据;丢失窗口较大 appendfsync everysec最多丢失 1 秒数据;数据安全性更高
文件内容 二进制,不可直接阅读 RESP 协议文本,可以 cat 查看
文件体积 压缩后体积小 同等数据量文件远大于 RDB
恢复速度 非常快,直接加载镜像 慢,逐条执行命令,大数据实例启动耗时久
阻塞来源 1.fork 瞬间短暂阻塞主进程 2.save 命令全程阻塞 3. 大量写触发 COW,内存上涨 1.bgrewriteaof fork 瞬间短暂阻塞 2.appendfsync=always 刷盘阻塞
内存开销 bgsave:COW 写时复制,大量写内存会升高 bgrewriteaof:重写缓冲区占用部分内存
文件损坏后果 RDB 损坏,整个快照数据全部丢失,启动失败 AOF 损坏,可用redis‑check‑aof --fix截断修复,损失尾部少量数据
版本兼容性 二进制格式,版本强绑定,高版本 rdb 低版本读不了 RESP 文本协议,版本兼容性好
启动加载优先级 RDB+AOF 同时开启,优先加载 AOF,忽略 RDB 开启 AOF 则优先重放 AOF 文件恢复数据
主要用途 冷备份、数据迁移、主从全量同步 在线持久化,保障宕机数据安全
冗余问题 无冗余,本身就是完整状态 存在大量冗余命令,需要 AOF 重写压缩文件
生产最佳实践 一般不单独使用,配合 AOF 做定时备份 核心业务开启;搭配 RDB 做灾难兜底

3、开启AOF持久化

bash 复制代码
root@Redis-13:~# vim /etc/redis/redis-6379.conf
root@Redis-13:~# grep '^appendonly' /etc/redis/redis-6379.conf
appendonly yes
root@Redis-13:~# systemctl restart redis.service

root@Redis-13:~# ls /data/redis/appendonlydir/
appendonly-6379.aof.1.base.rdb  appendonly-6379.aof.manifest
appendonly-6379.aof.1.incr.aof
root@Redis-13:~#

appendonly.aof  主 AOF 文件
appendonly.aof.temp 重写过程临时文件(子进程输出)
appendonly.aof.rewriteaof 重写缓冲区溢出临时文件
#加载顺序rdb→aof
root@Redis-13:~# cat /data/redis/appendonlydir/appendonly-6379.aof.manifest
file appendonly-6379.aof.1.base.rdb seq 1 type b
file appendonly-6379.aof.1.incr.aof seq 1 type i startoffset 0


root@Redis-13:~# grep -E '^(dir|append)' /etc/redis/redis-6379.conf
dir /data/redis        #工作路径
appendonly yes        #开启AOF
appendfilename "appendonly-6379.aof"        #AOF文件名
appenddirname "appendonlydir"        #AOF目录名
appendfsync everysec                    #AOF默认每秒保存
root@Redis-13:~#


#临时开启
CONFIG SET appendonly yes

#AOF 文件损坏修复工具,当命令未保存意外断开时
redis-check-aof --fix /data/redis/appendonly.aof

#手动触发 AOF 重写压缩日志(解决文件膨胀),落地到AOF的RDB文件中
BGREWRITEAO

#修改环境变量不需要输入密码
export REDISCLI_AUTH="Redis@2026"

4、AOF小测试

bash 复制代码
root@Redis-13:~# vim /etc/profile.d/redis.sh
root@Redis-13:~# source /etc/profile.d/redis.sh
root@Redis-13:~# cat /etc/profile.d/redis.sh
export REDISCLI_AUTH="Redis@2026"


127.0.0.1:6379> FLUSHALL    #生产禁用会清除所有数据
127.0.0.1:6379> EVAL "for i=1,5000 do redis.call('SET','demo_aof_'..i,math.random(1,9999)) end" 0 

root@Redis-13:~# redis-cli INFO persistence | grep -E "aof_current_size"
aof_current_size:426848
root@Redis-13:~# du -sh /data/redis/appendonlydir/
432K    /data/redis/appendonlydir/
root@Redis-13:~# ls /data/redis/appendonlydir/ -l
total 428
-rw------- 1 redis redis     88 Sep  8 04:37 appendonly-6379.aof.1.base.rdb
-rw------- 1 redis redis 426760 Sep  8 04:51 appendonly-6379.aof.1.incr.aof
-rw------- 1 redis redis    112 Sep  8 04:55 appendonly-6379.aof.manifest


127.0.0.1:6379> BGREWRITEAOF
Background append only file rewriting started
#空间缩小了很多
root@Redis-13:~# ll /data/redis/appendonlydir/
-rw------- 1 redis redis 88925 Sep  8 04:57 appendonly-6379.aof.2.base.rdb
-rw------- 1 redis redis     0 Sep  8 04:57 appendonly-6379.aof.2.incr.aof
-rw------- 1 redis redis   116 Sep  8 04:57 appendonly-6379.aof.manifest
root@Redis-13:~# du -sh /data/redis/appendonlydir/
96K     /data/redis/appendonlydir/

六、Redis 基础命令

6.1、全局通用命令

6.1.1、 键生命周期管理

SET:set key名 value值 EX 秒数 NX\|XX

功能:设置字符串 key‑value,覆盖原有 key 的值

key :自定义键名; value :键对应存储的值

EX seconds :可选,写入同时设置过期时间(秒)

NX :仅当 key 不存在时才写入,存在则不执行

XX :仅当 key 已存在时覆盖更新,不存在不执行

bash 复制代码
root@Redis-13:~# redis-cli
127.0.0.1:6379> set name01 xyy
OK
127.0.0.1:6379> set name02 myy
OK
127.0.0.1:6379> set name03 lyy
OK
127.0.0.1:6379> set name04 htl
OK

GET:GET key

功能:获取 key 对应的 value。

key 存在:返回对应的 value;

key 不存在:返回 (nil) 。

bash 复制代码
127.0.0.1:6379> get name01
"xyy"
127.0.0.1:6379> get name06
(nil)
127.0.0.1:6379>

EXISTS:EXISTS key key2 key3...

功能:判断 key 是否存在。

返回 1:目标 key 存在;

返回 0:目标 key 不存在。

bash 复制代码
127.0.0.1:6379> exists name01
(integer) 1
127.0.0.1:6379> exists name06
(integer) 0

DEL:DEL key key ...

功能:删除 key,支持批量删除。

返回数字,代表成功删除的 key 数量。

bash 复制代码
127.0.0.1:6379> del name01
(integer) 1
127.0.0.1:6379> del name02 name03
(integer) 2
6.1.2、有效期数据

EXPIRE: EXPIRE key seconds

作用:给已有 Key 设置过期时间(单位:秒

1 :设置过期时间成功

0 :Key 不存在,设置失败

bash 复制代码
127.0.0.1:6379> set jine 2345
OK
127.0.0.1:6379> set name ftl
OK


127.0.0.1:6379> EXPIRE jine 60
(integer) 1

TTL:TTL key

作用:查看 Key 剩余过期时间

正数:剩余存活秒数

-1 :Key 存在,永久无过期时间

-2 :Key 已不存在

bash 复制代码
127.0.0.1:6379> ttl jine
(integer) 53

127.0.0.1:6379> ttl jine
(integer) 52

PERSIST:PERSIST key

作用: 移除 Key 过期规则,改为永久有效

1 :成功清除过期时间

0 :Key 不存在或本身无过期时间

bash 复制代码
127.0.0.1:6379> PERSIST jine
(integer) 1
127.0.0.1:6379> ttl jine
(integer) -1
127.0.0.1:6379> ttl name1
(integer) -2
127.0.0.1:6379> PERSIST name
(integer) 0
127.0.0.1:6379>
6.1.3、局遍历所有键

KEYS:全量遍历(仅测试环境)

语法: KEYS 匹配通配符

通配符规则

*:匹配任意长度任意字符

? :匹配单个任意字符

bash 复制代码
127.0.0.1:6379> set name01 hhh
OK
127.0.0.1:6379> set name02 yyy
OK
127.0.0.1:6379> set name03 kkk
OK
127.0.0.1:6379> set user01 qqq
OK
127.0.0.1:6379> set user02 www
OK
127.0.0.1:6379> set user03 eee
OK
127.0.0.1:6379> keys *1
1) "name01"
2) "user01"
127.0.0.1:6379> keys us*
1) "user03"
2) "user01"
3) "user02"
127.0.0.1:6379> keys name0?
1) "name01"
2) "name02"
3) "name03"
127.0.0.1:6379> keys *
1) "name01"
2) "user03"
3) "jine"
4) "user01"
5) "name02"
6) "user02"

SCAN:游标迭代分批遍历(生产推荐)

语法: SCAN 游标 MATCH 匹配规则 COUNT 单次扫描数量

参数说明

  1. 游标:首次查询固定填 0 ;每次执行会返回新游标,循环传入直到游标返回 0 代表遍历完成;

  2. MATCH:可选,后跟模糊匹配规则,过滤目标 key;

  3. COUNT:可选,单次遍历预估扫描条目,取值必须 ≥1,不能填 0。

  4. COUNT 只管扫多少个槽,不管槽里面藏了多少 key,所以输出条数不受 COUNT 约束。

  5. 哈希槽是存放 key 的容器格子,一个槽可以容纳任意多个 key,理论上每个槽的key存储数量

没有上限。

bash 复制代码
127.0.0.1:6379> SCAN 0 match user* count 10
1) "0"            #观察输出的数值,0则是完成,其他数值可以继续向下查询
2) 1) "user03"
   2) "user02"
   3) "user01"
6.1.4、清理数据

SELECT 数据库切换命令

语法: SELECT dbindex

dbindex :数据库编号,Redis 单机默认提供 0 ~ 15 共 16 个逻辑数据库;

客户端连接 Redis 后,默认自动进入 0 号库。

bash 复制代码
127.0.0.1:6379> SELECT 1
OK
127.0.0.1:6379[1]> SELECT 4
OK
127.0.0.1:6379[4]> SELECT 16
(error) ERR DB index is out of range
127.0.0.1:6379[4]> SELECT 0
OK
127.0.0.1:6379>

FLUSHDB:清空当前数据库所有 Key

语法:

复制代码
    同步清理(阻塞主线程)

            FLUSHDB

    异步后台清理(Redis4.0+推荐,不阻塞业务) 

            FLUSHDB ASYNC

作用范围:仅清空当前 SELECT 切换后的目标数据库,不影响实例内其他数据库。

bash 复制代码
127.0.0.1:6379> SELECT 1
OK
127.0.0.1:6379[1]> set a c
OK
127.0.0.1:6379[1]> set c d
OK
127.0.0.1:6379[1]> set d f
OK
127.0.0.1:6379[1]> set g e
OK
127.0.0.1:6379[1]> KEYS *
1) "c"
2) "g"
3) "d"
4) "a"
127.0.0.1:6379[1]> FLUSHDB ASYNC
OK
127.0.0.1:6379[1]> keys *
(empty array)
127.0.0.1:6379[1]> SELECT 0
OK
127.0.0.1:6379> KEYS *
1) "name01"
2) "user03"
3) "jine"
4) "user01"
5) "name02"
6) "user02"
7) "name03"
8) "name"
127.0.0.1:6379>

FLUSHALL:清空实例全部数据库所有 Key

语法

复制代码
    同步清理:主线程一次性遍历、回收所有 Key 内存,海量数据场景会长时间阻塞 Redis,所有业务请求

超时,线上严禁直接使用。

FLUSHALL

异步清理(生产必用):主线程仅标记数据待删除,由后台子线程分步回收内存,不会阻塞主线程,生产环

境标准用法。

F LUSHALL ASYNC

作用范围:清空当前 Redis 实例下全部 16 个数据库(0~15) 的所有数据,风险极高。

bash 复制代码
127.0.0.1:6379> SELECT 3
OK
127.0.0.1:6379[3]> set nihao 111
OK
127.0.0.1:6379[3]> set buhao 222
OK
127.0.0.1:6379[3]> set haha 333
OK
127.0.0.1:6379[3]> KEYS *
1) "nihao"
2) "haha"
3) "buhao"
127.0.0.1:6379[3]> FLUSHALL ASYNC
OK
127.0.0.1:6379[3]> KEYS *
(empty array)
127.0.0.1:6379[3]> SELECT 0
OK
127.0.0.1:6379> KEYS *
(empty array)
127.0.0.1:6379>
bash 复制代码
注:线上生产环境操作规范

1. 禁止在线上业务运行时执行 FLUSHALL ,会造成全业务缓存雪崩;
2. 执行清空操作强制添加 ASYNC 参数,避免主线程阻塞;
3. 运维权限管控:普通业务账号禁用 FLUSH 系列高危命令;
4. 无 FLUSH 执行权限时,替代方案:使用 SCAN 游标分批遍历 + DEL 批量删除数据;
5. 执行前务必确认当前数据库编号,防止误删其他业务库缓存。

6.2、常用数据类型

6.2.1、字符串 string

MSET:批量写入多组字符串键值对

语法: MSET key1 value1 key2 value2 key3 value3 ...

特点

  1. 原子操作:所有 key 同时写入,要么全部成功,不存在部分写入;

  2. 重复 key 会覆盖:传入重复 key 时,后面的值覆盖前面;

  3. 无需提前判断 key 是否存在,直接覆盖更新。

bash 复制代码
root@Redis-13:~# redis-cli
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> MSET id 1001 name xyy gender female score 95
OK

MGET:批量读取多个字符串 key 的值

语法: MGET key1 key2 key3 ...

特点

  1. 一次性传入多个 key,一次性返回对应 value 数组;

  2. 某个 key 不存在时,该位置返回 (nil) ,不会中断整体查询;

bash 复制代码
127.0.0.1:6379> MGET id name gender score
1) "1001"
2) "xyy"
3) "female"
4) "95"
127.0.0.1:6379> MGET id hhh gender
1) "1001"
2) (nil)
3) "female"
127.0.0.1:6379>

使用注意事项

  1. 批量 key 不宜过多,单次建议控制在百个以内,避免命令数据包过大阻塞 Redis;

  2. MSET 无 NX/XX 分支判断,如需批量不存在才写入使用 MSETNX ;

  3. 仅支持 String 类型,List/Hash 等其他数据类型 key 读取会返回 nil。

6.2.2、文本信息查询

STRLEN:获取字符串 Value 的字节长度

语法: STRLEN key

说明

  1. 返回数字:代表该 key 对应 value 占用的字节数量,不是字符个数;

  2. 中文 UTF-8 一个汉字占 3 字节,数字、字母、符号占 1 字节;

  3. key 不存在时,返回 0。

bash 复制代码
root@Redis-13:~# redis-cli --raw    #加--raw可以中文显示
127.0.0.1:6379> set content "你好xyy123"
OK
127.0.0.1:6379> STRLEN content
12

APPEND:在字符串尾部追加内容

语法 : APPEND key content

说明

  1. key 已存在:在原有字符串末尾拼接传入内容,返回拼接后的总字节长度;

  2. key 不存在:自动新建 key,等同于 SET key content ;

  3. 原子操作,适合日志、增量文本拼接场景。

bash 复制代码
127.0.0.1:6379> APPEND content "你瞅啥"
21
127.0.0.1:6379> STRLEN content
21

GETSET:原子设置新值并返回旧值

语法: GETSET key new_value

说明

  1. 原子操作:一步完成「读取旧值 + 覆盖写入新值」;

  2. key 存在:返回修改前的原始 value;

  3. key 不存在:返回 (nil) ,同时创建 key 存入新值;

  4. 经典用途:计数器重置、分布式锁取值更新。

bash 复制代码
127.0.0.1:6379> GETSET content "我服了"
你好xyy123你瞅啥
127.0.0.1:6379>

使用注意事项

  1. STRLEN 统计字节而非字符,处理中文、多语言文本长度计算需注意;

  2. APPEND 适合增量拼接,不适合频繁超大文本追加,会产生内存碎片;

  3. GETSET 是原子操作,多并发场景下比先 GET 再 SET 更安全,无中间状态;

  4. 三条命令仅支持 String 类型,List/Hash 等其他类型 Key 执行会报错。

6.2.3、数字自增运算

INCR:数值自增 1

语法: INCR key

规则

  1. Key 不存在:自动创建,默认初始值为 0,执行后变成 1;

  2. Key 存在且为数字:原值 +1,返回计算后结果;

  3. Value 非纯数字字符串:直接报错。

bash 复制代码
root@Redis-13:~# redis-cli
127.0.0.1:6379> SET order_num 100
OK
127.0.0.1:6379> INCR order_num
(integer) 101
127.0.0.1:6379> INCR order_num
(integer) 102
127.0.0.1:6379> INCR order_num
(integer) 103

DECR:数值自减 1

语法: DECR key

规则

  1. Key 不存在:自动创建,默认初始值为 0,执行后变成 -1;

  2. Key 存在且为数字:原值 -1,返回计算后结果;

  3. Value 非数字则报错。

bash 复制代码
127.0.0.1:6379> DECR order_num
(integer) 122
127.0.0.1:6379> DECR order_num
(integer) 121

INCRBY:指定步长整数自增

语法: INCRBY key 增量数值

规则

  1. 第二个参数必须是整数,支持正数;

  2. Key 不存在,默认从 0 开始累加;

  3. 返回运算完成后的最终数值。

bash 复制代码
127.0.0.1:6379> INCRBY order_num 10
(integer) 113
127.0.0.1:6379> INCRBY order_num 10
(integer) 123

DECRBY:指定步长整数自减

语法: DECRBY key 减量数值

规则

  1. 第二个参数为整数,代表要减去的大小;

  2. Key 不存在,默认从 0 开始递减;

  3. 返回运算完成后的最终数值。

bash 复制代码
127.0.0.1:6379> DECRBY order_num 5
(integer) 116
127.0.0.1:6379> DECRBY order_num 5
(integer) 111
127.0.0.1:6379> GET order_num
"111"
127.0.0.1:6379>
6.3.1、列表 list
6.3.1.1、创建与追加数据

LPUSH:从列表 左侧(头部)插入元素

语法: LPUSH key value1 value2 value3 ...

核心规则

  1. key 不存在:自动创建空列表,再插入数据;

  2. 支持一次性传入多个值,后写的值排在更靠左(头部);

  3. 返回值:插入完成后列表总元素个数;

  4. 若 key 存在但不是 List 类型,直接报类型错误。

bash 复制代码
127.0.0.1:6379> LRANGE list_order 0 -1
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"
127.0.0.1:6379> LPUSH list_order 000
(integer) 6

RPUSH:从列表 右侧(尾部)插入元素

语法: RPUSH key value1 value2 value3 ...

核心规则

  1. key 不存在:自动创建列表;

  2. 多值插入时,书写顺序就是列表从左到右的顺序;

  3. 返回值:插入后列表总长度;

  4. 非 List 类型 key 执行会报错。

bash 复制代码
127.0.0.1:6379> RPUSH list_order a b c d e
(integer) 5

LRANGE: 列表区间查询命令

语法: LRANGE key start stop

作用:根据索引区间截取 List 列表,返回区间内所有元素。

索引规则(正数 + 负数双索引)

bash 复制代码
127.0.0.1:6379> LRANGE list_order 0 -1
1) "000"
2) "a"
3) "b"
4) "c"
5) "d"
6) "e"
127.0.0.1:6379> LRANGE list_order 0 -3
1) "000"
2) "a"
3) "b"
4) "c"
127.0.0.1:6379> LPUSH list_order a c
(integer) 8
127.0.0.1:6379> LRANGE list_order 0 -1
1) "c"
2) "a"
3) "000"
4) "a"
5) "b"
6) "c"
7) "d"
8) "e"
127.0.0.1:6379>
6.3.1.2、列表元素操作

LLEN:获取列表总元素长度

语法: LLEN key

规则

  1. key 不存在:返回 0 ;

  2. key 为 List:返回列表当前元素总个数;

  3. 非 List 类型 key,报类型错误。

bash 复制代码
127.0.0.1:6379> RPUSH list_demo a b c d e
(integer) 5
127.0.0.1:6379> LLEN list_demo
(integer) 5
127.0.0.1:6379> LLEN no_list
(integer) 0

LINDEX:根据索引读取单个元素

语法: LINDEX key index

索引规则

正数索引: 0 表头第一个元素,向后依次递增;

负数索引: -1 表尾最后一个元素,向前依次递减;

索引超出列表范围,返回 (nil) 。

bash 复制代码
127.0.0.1:6379> LINDEX list_demo 0
"a"
127.0.0.1:6379> LINDEX list_demo 3
"d"
127.0.0.1:6379> LINDEX list_demo -1
"e"
127.0.0.1:6379> LINDEX list_demo 10086
(nil)

LRANGE:按索引区间批量读取元素

语法: LRANGE key start stop

核心用法

  1. LRANGE key 0 -1 :查询列表全部元素(最常用);

  2. start、stop 支持正负索引,索引越界不会报错,仅返回存在元素;

bash 复制代码
127.0.0.1:6379> LRANGE list_demo 0 -1
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"
127.0.0.1:6379> LRANGE list_demo 0 10086
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"

LSET:修改指定索引元素

语法: LSET key index new_value

规则

  1. 修改列表指定索引位置的元素,覆盖原值;

  2. 索引超出列表范围直接报错;

  3. key 不存在时报错,必须先创建列表。

bash 复制代码
127.0.0.1:6379> LSET list_demo 2 888
OK
127.0.0.1:6379> LRANGE list_demo 0 -1
1) "a"
2) "b"
3) "888"
4) "d"
5) "e"
127.0.0.1:6379>
6.3.1.3、删除列表内元素

LPOP/RPOP:弹出删除表头/表尾单个元素

语法:

删除并返回头部第一个元素

LPOP key

删除并返回尾部最后一个元素

RPOP key

规则

  1. 列表为空 /key 不存在,返回 (nil) ;

  2. 弹出后列表长度自动减 1。

bash 复制代码
127.0.0.1:6379> RPUSH listdel a b c d e f g a a d  c  d we  a sf
(integer) 15
127.0.0.1:6379> LRANGE listdel 0 -1
 1) "a"
 2) "b"
 3) "c"
 4) "d"
 5) "e"
 6) "f"
 7) "g"
 8) "a"
 9) "a"
10) "d"
11) "c"
12) "d"
13) "we"
14) "a"
15) "sf"
127.0.0.1:6379> LPOP listdel
"a"
127.0.0.1:6379> LRANGE listdel 0 -1
 1) "b"
 2) "c"
 3) "d"
 4) "e"
 5) "f"
 6) "g"
 7) "a"
 8) "a"
 9) "d"
10) "c"
11) "d"
12) "we"
13) "a"
14) "sf"
127.0.0.1:6379> RPOP listdel
"sf"
127.0.0.1:6379> LRANGE listdel 0 -1
 1) "b"
 2) "c"
 3) "d"
 4) "e"
 5) "f"
 6) "g"
 7) "a"
 8) "a"
 9) "d"
10) "c"
11) "d"
12) "we"
13) "a"
127.0.0.1:6379> RPOP list_del
(nil)

LREM:根据值批量删除匹配元素

语法: LREM key count value

count 参数规则:

count > 0 :从表头向表尾,删除前 count 个匹配 value;

count < 0 :从表尾向表头,删除后 |count| 个匹配 value;

count = 0 :删除列表中所有匹配 value 的元素;

返回值:实际删除的元素数量。

bash 复制代码
127.0.0.1:6379> LREM listdel 2 c
(integer) 2
127.0.0.1:6379> LRANGE listdel 0 -1
 1) "b"
 2) "d"
 3) "e"
 4) "f"
 5) "g"
 6) "a"
 7) "a"
 8) "d"
 9) "d"
10) "we"
11) "a"
127.0.0.1:6379> RPUSH listdel a v a c d d  b b d e
(integer) 21
127.0.0.1:6379> LREM listdel 2 a
(integer) 2
127.0.0.1:6379> LRANGE listdel 0 -1
 1) "b"
 2) "d"
 3) "e"
 4) "f"
 5) "g"
 6) "d"
 7) "d"
 8) "we"
 9) "a"
10) "a"
11) "v"
12) "a"
13) "c"
14) "d"
15) "d"
16) "b"
17) "b"
18) "d"
19) "e"
127.0.0.1:6379> LREM listdel -2 b
(integer) 2
127.0.0.1:6379> LRANGE listdel 0 -1
 1) "b"
 2) "d"
 3) "e"
 4) "f"
 5) "g"
 6) "d"
 7) "d"
 8) "we"
 9) "a"
10) "a"
11) "v"
12) "a"
13) "c"
14) "d"
15) "d"
16) "d"
17) "e"
127.0.0.1:6379> LREM listdel 0 d
(integer) 6
127.0.0.1:6379> LRANGE listdel 0 -1
 1) "b"
 2) "e"
 3) "f"
 4) "g"
 5) "we"
 6) "a"
 7) "a"
 8) "v"
 9) "a"
10) "c"
11) "e"

LTRIM:区间保留删除(裁剪列表,只保留指定区间元素)

语法: LTRIM key start stop

规则: 仅保留 start~stop 区间内元素,区间外所有元素直接删除;常用来实现固定长度队列。

bash 复制代码
127.0.0.1:6379> LTRIM listdel 4 7
OK
127.0.0.1:6379> LRANGE listdel 0 -1
1) "we"
2) "a"
3) "a"
4) "v"
127.0.0.1:6379>
6.2.4、集合 set
6.2.4.1、创建、新增、查询、删除元素

SADD:创建集合/批量新增元素

语法: SADD key member1 member2 member3 ...

特点

  1. key 不存在则自动创建新集合;

  2. 集合内自动去重,重复元素写入无效;

  3. 返回值:本次真正新增成功的元素个数;

  4. 纯新增、无覆盖逻辑(和 String 覆盖不同)。

bash 复制代码
127.0.0.1:6379> SADD student_set tom jerry jack jack lucy
(integer) 4

SMEMBERS:查询集合所有元素

语法: SMEMBERS key

特点

  1. 返回集合全部元素;

  2. 输出无序,每次展示顺序可能不一样;

  3. key 不存在返回空集合。

bash 复制代码
127.0.0.1:6379> SMEMBERS student_set
1) "tom"
2) "jerry"
3) "jack"
4) "lucy"

SCARD:获取集合元素总数

语法: SCARD key

特点

  1. 统计集合有效元素个数(自动去重后数量);

  2. key 不存在返回 0。

bash 复制代码
127.0.0.1:6379> SCARD student_set
(integer) 4

SISMEMBER:判断元素是否存在集合

语法: SISMEMBER key member

特点

  1. 元素存在返回 1 ;

  2. 元素不存在 /key 不存在返回 0 。

bash 复制代码
127.0.0.1:6379> SISMEMBER student_set jack
(integer) 1
127.0.0.1:6379> SISMEMBER student_set mali
(integer) 0

SRANDMEMBER:随机获取集合元素

语法: SRANDMEMBER key count

特点

  1. 随机取出若干元素,不会删除原集合数据;

  2. 不写 count 默认随机 1 个;

  3. 支持一次随机多个元素。

bash 复制代码
127.0.0.1:6379>
127.0.0.1:6379> SRANDMEMBER student_set 1
1) "tom"
127.0.0.1:6379> SRANDMEMBER student_set 1
1) "tom"
127.0.0.1:6379> SRANDMEMBER student_set 10
1) "tom"
2) "jerry"
3) "jack"
4) "lucy"
127.0.0.1:6379> SRANDMEMBER student_set
"jerry"
127.0.0.1:6379> SRANDMEMBER student_set
"lucy"
127.0.0.1:6379> SRANDMEMBER student_set
"lucy"

SREM:删除集合指定元素

语法: SREM key member1 member2 ...

特点

  1. 按值删除,不需要索引;

  2. 支持批量删除多个元素;

  3. 返回值:实际删除成功的元素个数;

  4. 删除不存在元素不报错,直接忽略。

bash 复制代码
127.0.0.1:6379> SREM student_set jack tom
(integer) 2
127.0.0.1:6379> SMEMBERS student_set
1) "jerry"
2) "lucy"
127.0.0.1:6379>
6.2.4.2、集合运算:交集、并集、差集

SINTER:求取多个集合交集

语法: SINTER key1 key2 key3 ...

特点

  1. 取出所有传入集合同时拥有的公共元素;

  2. 支持一次性传入 2 个及以上集合;

  3. 无公共元素时返回空集合;

  4. 仅做查询,不会修改原有集合数据。

bash 复制代码
127.0.0.1:6379> SADD class1 tom jerry jack lucy
(integer) 4
127.0.0.1:6379> SADD class2 jack lucy mike lily
(integer) 4

SUNION:求取多个集合并集

语法: SUNION key1 key2 key3 ...

特点

  1. 合并全部集合的所有元素,自动去重;

  2. 整合多组数据,相同元素只保留一份;

  3. 纯查询操作,不改动原始集合。

bash 复制代码
127.0.0.1:6379> SUNION class1
1) "jerry"
2) "lucy"
3) "jack"
4) "tom"
127.0.0.1:6379> SUNION class1 class2
1) "tom"
2) "lucy"
3) "lily"
4) "jerry"
5) "mike"
6) "jack"
127.0.0.1:6379> SINTER class1 class2
1) "jack"
2) "lucy"

SDIFF:求取多个集合差集

语法: SDIFF key1 key2 key3 ...

特点

  1. 以第一个集合为基准,剔除后面所有集合中存在的元素;

  2. 只保留基准集合独有的元素;

  3. 命令顺序直接影响最终结果,前后调换结果不同;

  4. 仅查询,不修改原集合。

bash 复制代码
127.0.0.1:6379> SDIFF class1 class2
1) "jerry"
2) "tom"
127.0.0.1:6379> SDIFF class2 class1
1) "lily"
2) "mike"
127.0.0.1:6379>
6.2.5、哈希 hash
6.2.5.1、创建、批量设置字段 field

HSET:创建哈希 / 单个 / 批量设置字段

语法: HSET key field1 value1 field2 value2 ...

特点

  1. key 不存在自动创建哈希表;

  2. 字段 field 存在则覆盖原值;

  3. 字段不存在则新增字段;

  4. 返回值:本次新增成功的字段数量,更新覆盖不计入;

  5. 支持单字段、多字段混合写入,原子批量操作。

bash 复制代码
127.0.0.1:6379> HSET user:1001 name zhangsan age 20 gender male
(integer) 3
127.0.0.1:6379> HSET user:1001 age 21 address rongcheng
(integer) 1
127.0.0.1:6379> HGETALL user:1001
1) "name"
2) "zhangsan"
3) "age"
4) "21"
5) "gender"
6) "male"
7) "address"
8) "rongcheng"

HMSET:批量设置哈希字段(兼容旧命令)

语法: HMSET key field1 value1 field2 value2 ...

特点

  1. 专门用于批量设置字段,功能与 HSET 完全一致;

  2. Redis4.0+ 官方推荐统一使用 HSET 替代 HMSET;

  3. 为兼容老旧项目,依然保留可用。

bash 复制代码
127.0.0.1:6379> HMSET user:1001 name lisi age 25
OK
127.0.0.1:6379> HGETALL user:1001
1) "name"
2) "lisi"
3) "age"
4) "25"
5) "gender"
6) "male"
7) "address"
8) "rongcheng"
127.0.0.1:6379>
6.2.5.2、单/全量字段、值、键值对查询

HGET:查询单个字段的值

语法: HGET key field

特点

  1. 只获取哈希中单个 field 对应的 value;

  2. field 不存在 /key 不存在返回 (nil) ;

  3. 轻量化单点查询,性能极高。

bash 复制代码
127.0.0.1:6379> HSET user:1001 name zhangsan age 21 gender male address beijing
(integer) 0

127.0.0.1:6379> HGET user:1001 name
"zhangsan"
127.0.0.1:6379> HGET user:1001 phone
(nil)

HMGET:批量查询多个字段值

语法: HMGET key field1 field2 field3 ...

特点

  1. 一次性查询多个字段,一次网络 IO;

  2. 部分字段不存在,对应位置返回 (nil) ,不中断查询;

  3. 返回顺序与传入字段顺序完全一致。

bash 复制代码
127.0.0.1:6379> HMGET user:1001 name age phone
1) "zhangsan"
2) "21"
3) (nil)

HGETALL:查询全部字段 + 全部值

语法: HGETALL key

特点

  1. 返回哈希所有 field 和 value,成对展示;

  2. 顺序:字段、值、字段、值交替返回;

  3. key 不存在返回空列表。

bash 复制代码
127.0.0.1:6379> HGETALL user:1001
1) "name"
2) "zhangsan"
3) "age"
4) "21"
5) "gender"
6) "male"
7) "address"
8) "beijing"
127.0.0.1:6379>

HKEYS:只查询所有字段名(只取 key)

语法: HKEYS key

特点

  1. 仅返回哈希中所有 field 字段名称,不返回值;

  2. 适合遍历对象属性。

bash 复制代码
127.0.0.1:6379> HKEYS user:1001
1) "name"
2) "age"
3) "gender"
4) "address"

HVALS:只查询所有字段值(只取 value)

语法: HVALS key

特点

  1. 仅返回哈希中所有 value 数据,不返回字段名;

  2. 单独提取结构化数据值列表。

bash 复制代码
127.0.0.1:6379> HVALS user:1001
1) "zhangsan"
2) "21"
3) "male"
4) "beijing"

HLEN:获取哈希字段总数量

语法: HLEN key

特点

  1. 返回当前哈希拥有的有效字段总数;

  2. key 不存在直接返回 0。

bash 复制代码
127.0.0.1:6379> HLEN user:1001
(integer) 4
6.2.5.3、删除单个 field 或整个 hash

HDEL:删除哈希内一个或多个 field 字段

语法: HDEL key field1 field2 field3 ...

特点

  1. 精准删除哈希中指定字段,支持一次性传入多个字段批量删除;

  2. 返回值:成功删除的字段数量;

  3. 删除不存在的字段不会报错,直接忽略不计;

  4. 仅删除字段,不会删除哈希本身,字段全部删完后哈希 key 依然存在(空哈希)。

bash 复制代码
127.0.0.1:6379> HSET user:1001 name zhangsan age 21 gender male address beijing
(integer) 0
127.0.0.1:6379> HGETALL user:1001
1) "name"
2) "zhangsan"
3) "age"
4) "21"
5) "gender"
6) "male"
7) "address"
8) "beijing"
127.0.0.1:6379> HLEN user:1001
(integer) 4
127.0.0.1:6379> HDEL user:1001 age
(integer) 1
127.0.0.1:6379> HLEN user:1001
(integer) 3
127.0.0.1:6379> HGETALL user:1001
1) "name"
2) "zhangsan"
3) "gender"
4) "male"
5) "address"
6) "beijing"

DEL:删除整条 Hash 键(清空全部字段)

语法: DEL key

特点

  1. 直接删除整个哈希 key,内部所有 field-value 全部销毁;

  2. 返回值:1 代表删除成功,0 代表 key 不存在;

  3. 适用于整个对象废弃、无需再使用的场景。

bash 复制代码
127.0.0.1:6379> DEL user:1001
(integer) 1
127.0.0.1:6379> HGETALL user:1001
(empty array)
127.0.0.1:6379>

Linux学习之旅之redis主从复制

一、主从复制基础认知

1.1、主从复制的有点

bash 复制代码
1. 数据副本,实现数据冗余
主节点的数据会同步到从节点,相当于多份数据备份。当主库磁盘损坏、数据丢失时,可以用从库的数据恢复,提升数据安全性。

2. 读写分离,分担主库压力
写请求全部走主库;读请求可以分发到多个从库。适合读多写少业务,横向扩展读能力,降低主库 CPU、内存压力。

3. 故障基础能力,为高可用打下基础
主库宕机后,可以手动把从库提升为主库;搭配哨兵(Sentinel)就能实现自动故障转移,自动选主,完成故障切换。主从是哨兵和 Redis 集群的底层基础。

4. 方便做数据备份与运维操作
RDB/AOF 备份可以在从库执行,避免备份时 BGSAVE 对主库造成 fork 卡顿;也可以在从库做数据校验、压力测试,不影响线上主业务。

5. 架构简单,部署维护成本低
相比 Redis Cluster 集群,主从复制配置简单,命令少,容易上手,适合中小规模业务。

1. 2、主从复制的基本流程

bash 复制代码
1. 从库连上主库,完成鉴权,发送PSYNC ? -1请求同步。
2. 主库执行BGSAVE生成 RDB,期间写命令存入复制缓冲区。
3. 主库推送 RDB 给从库;从库清空本地数据,加载 RDB。
4. 主库再推送缓冲区增量命令,从库执行,主从数据一致。
5. 正常运行时,主库持续异步转发写命令,维护复制偏移量。
6. 断线重连:从库携带 replid 和 offset 执行PSYNC;匹配且 offset 在 backlog 内则增量同步,否则重新全量同步。


流程图
从库启动 → TCP 连接 → PSYNC ? -1
→ 主库 BGSAVE 生成 RDB → 传输 RDB → 从库加载 RDB
→ 推送缓冲区命令(repl-backlog-size默认值1MB) → 正常增量同步(主转发写命令,维护 offset)
→ 断线重连 → PSYNC replid offset
→ 判断:满足条件增量同步,否则走全量同步

二、主从复制配置

2.1、前提环境

bash 复制代码
操作系统:Ubuntu 24.04.4 LTS
redis版本:redis-cli 8.4.0
主:10.0.0.23
从:10.0.0.26
环境详解上一章脚本部署:

2.2、配置主从复制与常见问题处理

2.2.1、主从同步配置
bash 复制代码
#查看当前节点
[root@Redis-23:~#] redis-cli INFO replication | grep role
role:master

[root@Redis-26:~#] redis-cli INFO replication | grep role
role:master

#26配置主从认证信息
[root@Redis-26:~#] vim /etc/redis/redis-6379.conf
[root@Redis-26:~#] grep -C 1 '^masterauth' /etc/redis/redis-6379.conf
# masterauth <master-password>
masterauth Redis@2026
replicaof 10.0.0.23 6379

#重启生效并验证
[root@Redis-26:~#] systemctl restart redis.service
[root@Redis-26:~#] redis-cli INFO replication
# Replication
role:slave
master_host:10.0.0.23
master_port:6379
master_link_status:up
master_last_io_seconds_ago:9
master_sync_in_progress:0
slave_read_repl_offset:28
slave_repl_offset:28
replica_full_sync_buffer_size:0
replica_full_sync_buffer_peak:0
master_current_sync_attempts:1
master_total_sync_attempts:1
master_link_up_since_seconds:14
total_disconnect_time_sec:0
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:ccce0145a7160d5e4c186733bf0156b6a0949ffa
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:28
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:15
repl_backlog_histlen:14
[root@Redis-26:~#]

[root@Redis-23:~#] redis-cli INFO replication
# Replication
role:master
connected_slaves:1
slave0:ip=10.0.0.26,port=6379,state=online,offset=308,lag=0
master_failover_state:no-failover
master_replid:ccce0145a7160d5e4c186733bf0156b6a0949ffa
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:308
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:308
[root@Redis-23:~#]


#全量同步:创建key验证同步
[root@Redis-23:~#] redis-cli
127.0.0.1:6379> set name xiyangyang
OK
127.0.0.1:6379> KEYS *
1) "name"
127.0.0.1:6379>


[root@Redis-26:~#] redis-cli
127.0.0.1:6379> KEYS *
1) "name"
127.0.0.1:6379>


#增量同步:创建key验证同步
#断开同步
[root@Redis-26:~#] redis-cli replicaof no one
OK
[root@Redis-26:~#] redis-cli INFO replication | grep role
role:master

#主库创建新key
[root@Redis-23:~#] redis-cli INFO replication | grep role
role:master
[root@Redis-23:~#] redis-cli -h 10.0.0.23 SET test1:num 100
OK
[root@Redis-23:~#] redis-cli -h 10.0.0.23 MSET k11 v1 k12 v2 k13 v3
OK


#从库连接主库测试同步
[root@Redis-26:~#] redis-cli
127.0.0.1:6379> REPLICAOF 10.0.0.23 6379
OK
127.0.0.1:6379> KEYS *
1) "name"
2) "test1:num"
3) "k12"
4) "k13"
5) "k11"
127.0.0.1:6379>



#查看状态
[root@Redis-23:~#] redis-cli INFO replication
# Replication
role:master
connected_slaves:1
slave0:ip=10.0.0.26,port=6379,state=online,offset=1201,lag=1
master_failover_state:no-failover
master_replid:ccce0145a7160d5e4c186733bf0156b6a0949ffa
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1201
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:1201


127.0.0.1:6379> INFO replication
# Replication
role:slave
master_host:10.0.0.23
master_port:6379
master_link_status:up
master_last_io_seconds_ago:5
master_sync_in_progress:0
slave_read_repl_offset:1187
slave_repl_offset:1187
replica_full_sync_buffer_size:0
replica_full_sync_buffer_peak:0
master_current_sync_attempts:1
master_total_sync_attempts:1
master_link_up_since_seconds:121
total_disconnect_time_sec:162
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:ccce0145a7160d5e4c186733bf0156b6a0949ffa
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1187
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1020
repl_backlog_histlen:168
2.2.2、主从同步常见问题
2.2.2.1、replication backlog 调优
bash 复制代码
复制缓冲区(repl-backlog)是 Redis 主从增量同步(Partial Resync) 的核心内存区域。
    主节点写入的所有写命令会同时写入 backlog 环形缓冲区
    从节点断连重连后,通过 offset 比对直接回放断连期间缺失指令
    backlog 没被覆盖 → 增量同步
    backlog 被覆盖 → 强制全量 RDB 同步
默认:repl-backlog-size 1MB


[root@Redis-23:~#] redis-cli INFO replication | grep backlog
repl_backlog_active:1          # 1=backlog缓冲区已激活(当前有从库连接)
repl_backlog_size:1048576      # backlog总大小:1048576 bytes = 1MB(默认值)
repl_backlog_first_byte_offset:1 # backlog内最早一条数据对应的主库offset=1
repl_backlog_histlen:1691      # backlog当前有效数据长度:1691字节


#测试
[root@Redis-26:~#] redis-cli replicaof no one
OK
[root@Redis-26:~#] redis-cli INFO replication | egrep 'role|conn'
role:master
connected_slaves:0

[root@Redis-23:~#] for i in {1..20000};do redis-cli SET test_$i $i >/dev/null;done
[root@Redis-23:~#]

[root@Redis-26:~#] redis-cli INFO replication | egrep 'role|conn'
role:slave
total_disconnect_time_sec:162
connected_slaves:0
[root@Redis-26:~#] tail /var/log/redis/redis-6379.log -n20
1878:S 09 Sep 2026 07:02:50.114 * Loading RDB produced by version 8.4.0
1878:S 09 Sep 2026 07:02:50.114 * RDB age 1 seconds
1878:S 09 Sep 2026 07:02:50.114 * RDB memory usage when created 2.56 Mb
1878:S 09 Sep 2026 07:02:50.145 * Done loading RDB, keys loaded: 20005, keys expired: 0.
1878:S 09 Sep 2026 07:02:50.146 * MASTER <-> REPLICA sync: Finished with success
1878:S 09 Sep 2026 07:02:50.146 # systemd supervision error: NOTIFY_SOCKET not found!
1878:S 09 Sep 2026 07:02:50.146 * MASTER <-> REPLICA sync: Starting AOF after a successful sync
1878:S 09 Sep 2026 07:02:50.146 * Creating AOF incr file temp-appendonly-6379.aof.incr on background rewrite
1878:S 09 Sep 2026 07:02:50.147 * Background append only file rewriting started by pid 2733
1878:S 09 Sep 2026 07:02:50.148 * MASTER <-> REPLICA sync: Starting to stream replication buffer into the db (0 bytes).
1878:S 09 Sep 2026 07:02:50.148 * MASTER <-> REPLICA sync: Successfully streamed replication buffer into the db (0 bytes in total)
2733:C 09 Sep 2026 07:02:50.165 * BGSAVE done, 20005 keys saved, 0 keys skipped, 288918 bytes written.
2733:C 09 Sep 2026 07:02:50.169 * Successfully created the temporary AOF base file temp-rewriteaof-bg-2733.aof
2733:C 09 Sep 2026 07:02:50.171 * Fork CoW for AOF rewrite: current 0 MB, peak 0 MB, average 0 MB
1878:S 09 Sep 2026 07:02:50.175 * Background AOF rewrite terminated with success
1878:S 09 Sep 2026 07:02:50.175 * Successfully renamed the temporary AOF base file temp-rewriteaof-bg-2733.aof into appendonly-6379.aof.4.base.rdb
1878:S 09 Sep 2026 07:02:50.175 * Successfully renamed the temporary AOF incr file temp-appendonly-6379.aof.incr into appendonly-6379.aof.4.incr.aof
1878:S 09 Sep 2026 07:02:50.180 * Removing the history file appendonly-6379.aof.3.incr.aof in the background
1878:S 09 Sep 2026 07:02:50.180 * Removing the history file appendonly-6379.aof.3.base.rdb in the background
1878:S 09 Sep 2026 07:02:50.184 * Background AOF rewrite finished successfully
[root@Redis-26:~#]

#同步20005个key全量同步
1878:S 09 Sep 2026 07:02:50.146 * MASTER <-> REPLICA sync: Finished with success



#扩容backlog缓冲区
                           #动态调整                 
root@Redis-23:~#] redis-cli CONFIG SET repl-backlog-size 16777216
OK
[root@Redis-23:~#] redis-cli INFO replication | grep repl_backlog_size
repl_backlog_size:16777216

#持久化配置
[root@Redis-23:~#] vi /etc/redis/redis-6379.conf
[root@Redis-23:~#] grep '^repl-backlog-size' /etc/redis/redis-6379.conf
repl-backlog-size 64mb
[root@Redis-23:~#] systemctl restart redis.service

#测试
[root@Redis-23:~#] redis-cli INFO replication | egrep 'role|backlog_s'
role:master
repl_backlog_size:67108864
[root@Redis-23:~#]


[root@Redis-26:~#] redis-cli INFO replication | egrep 'role|backlog_s'
role:slave
repl_backlog_size:1048576
2.2.2.2、主从数据一致性校验方法
bash 复制代码
[root@Redis-23:~#] redis-cli INFO replication | grep role
role:master
[root@Redis-23:~#] redis-cli set biz_test_no 2026061801
OK
[root@Redis-23:~#] redis-cli set biz_name redis_sync_check
OK
[root@Redis-23:~#] redis-cli hset user:1001 id 1001 name test age 24
(integer) 3
[root@Redis-23:~#] redis-cli rpush order:list 10001 10002 10003
(integer) 3
[root@Redis-23:~#] redis-cli dbsize
(integer) 20009
[root@Redis-23:~#]




[root@Redis-26:~#] redis-cli INFO replication | grep role
role:slave
[root@Redis-26:~#] redis-cli
127.0.0.1:6379> get biz_test_no
"2026061801"
127.0.0.1:6379> get biz_name
"redis_sync_check"
127.0.0.1:6379> HGETALLuser:1001
(error) ERR unknown command 'HGETALLuser:1001', with args beginning with:
127.0.0.1:6379> HGETALL user:1001
1) "id"
2) "1001"
3) "name"
4) "test"
5) "age"
6) "24"
127.0.0.1:6379> lrange order:list 0 -1
1) "10001"
2) "10002"
3) "10003"
127.0.0.1:6379> DBSIZE
Error: Broken pipe
not connected>
not connected> exit
[root@Redis-26:~#] redis-cli dbsize
(integer) 20009
[root@Redis-26:~#]

三、redis哨兵(Sentinel)高可用架构

3.1、哨兵基础

bash 复制代码
1. 哨兵集群持续监控 master 和 replica,定期发送 PING 心跳。

2. master 网络 / 进程异常,某个哨兵收不到回复,标记 SDOWN(主观下线)。

3. 该哨兵询问其他哨兵;若满足quorum数量哨兵都判定 SDOWN → ODOWN 客观下线。

4.哨兵集群内部投票选出领头哨兵 Leader,由 Leader 执行故障转移。

5. Leader 在所有从库中挑选新 Master,筛选规则:
① 剔除下线、断连的从库
② 优先replica-priority值最小
③ 优先复制偏移量最大(数据最新)
④ 优先 runid 最小

6. Leader 发送命令,把选中的副本提升为新主。

7. Leader 向剩余从库发送REPLICAOF,让它们改为复制新主。

8. 更新配置:哨兵自动修改配置文件,记录新 master 信息;持续监控新主。

9. 通知客户端:客户端通过哨兵获取 Redis 节点地址,感知主节点变更。

3.2、架构组成

bash 复制代码
1. 主节点(Master):负责写,数据同步到从节点
2. 从节点(Replica):读,复制主库数据;主宕机后可被哨兵选为新主
3. Sentinel 哨兵节点(至少 3 个,奇数):哨兵本身是特殊 Redis 进程,不存储数据,核心职责:
    监控:持续心跳检测主、从节点存活状态
    通知:节点异常时,通知其他哨兵和客户端
    自动故障转移:主库宕机,哨兵投票选出新主,修改其余从库指向新主;通知客户端新主地址
    哨兵集群奇数个(3/5)目的:选举需要 quorum(法定票数),防止脑裂

3.3、核心概念

bash 复制代码
1. 主观下线 SDOWN:单个哨兵探测到主节点无响应,标记 SDOWN,只是该哨兵单方面认为挂了。
2. 客观下线 ODOWN:多个哨兵(≥quorum 数量)都认为主 SDOWN,才判定客观下线,才启动故障转移。
    quorum:配置文件sentinel monitor mymaster 127.0.0.1 6379 2最后的 2,表示至少 2 个哨兵认为主下线,才判定 ODOWN。
3. Raft 投票算法:哨兵之间选举领头哨兵(leader),只有 leader 负责执行故障转移操作。
4. 优先级 replica-priority:选新主时优先选数值小的从库;0 代表永远不能选为 master。
5. 复制偏移量:候选从库对比 offset,优先选择数据最完整的从库。

3.4、角色

bash 复制代码
1. 监控者(Monitor):持续心跳检测主节点、从节点在线状态,实时采集集群运行信息。
2. 仲裁者(Judge):多个哨兵节点共同投票判定节点是否真正故障,避免误判。
3. 故障转移执行者(Failover):当集群判定主节点客观下线后,选举领头哨兵完成自动主从切换、从节点重置、架构重构等操作。

3.5、哨兵高可用配置

bash 复制代码
!!!增加一台从节点:10.0.0.29


[root@Redis-23:~#] redis-cli INFO replication
# Replication
role:master
connected_slaves:2
slave0:ip=10.0.0.26,port=6379,state=online,offset=795653,lag=1
slave1:ip=10.0.0.29,port=6379,state=online,offset=795653,lag=1
master_failover_state:no-failover
master_replid:32ab7842b4fcc5a021132d11cbd2ca0bef574bff
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:795653
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:67108864
repl_backlog_first_byte_offset:792280
repl_backlog_histlen:3374
[root@Redis-23:~#]


[root@Redis-26:~#]
redis-cli INFO replication
# Replication
role:slave
master_host:10.0.0.23
master_port:6379
master_link_status:up
master_last_io_seconds_ago:5
master_sync_in_progress:0
slave_read_repl_offset:795779
slave_repl_offset:795779
replica_full_sync_buffer_size:0
replica_full_sync_buffer_peak:0
master_current_sync_attempts:3
master_total_sync_attempts:4
master_link_up_since_seconds:2502
total_disconnect_time_sec:7
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:32ab7842b4fcc5a021132d11cbd2ca0bef574bff
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:795779
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:792280
repl_backlog_histlen:3500


[root@Redis-29:~#] redis-cli INFO replication
# Replication
role:slave
master_host:10.0.0.23
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_read_repl_offset:795653
slave_repl_offset:795653
replica_full_sync_buffer_size:0
replica_full_sync_buffer_peak:0
master_current_sync_attempts:1
master_total_sync_attempts:1
master_link_up_since_seconds:259
total_disconnect_time_sec:0
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:32ab7842b4fcc5a021132d11cbd2ca0bef574bff
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:795653
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:795290
repl_backlog_histlen:364
[root@Redis-29:~#]
-------------------------------------------------------

##23/26/29操作以下步骤
#床架所需目录
[root@Redis-23:~#] mkdir -p /apps/redis/e                                                                   tc /apps/redis/log /apps/redis/data

#创建哨兵配置文件
[root@Redis-23:~#] cat /apps/redis/etc/redis-sentinel.conf
# 监听本机所有网卡,允许其他服务器访问哨兵
bind 0.0.0.0
# 关闭保护模式,支持跨机哨兵互相通信自动发现
protected-mode no
# 三台哨兵统一端口26379,不同主机不存在端口冲突
port 26379
# 设定登录哨兵的认证密码
requirepass "Redis@2026"
# 后台守护进程运行哨兵
daemonize yes
pidfile "/var/run/redis-sentinel.pid"
loglevel notice
logfile "/apps/redis/log/sentinel.log"
dir "/apps/redis/data"
# 设定登录哨兵的认证密码

# 核心监控配置:集群名mymaster、初始主库地址、法定票数2
sentinel monitor mymaster 10.0.0.23 6379 2
# Redis集群统一鉴权密码,和所有节点requirepass保持一致
sentinel auth-pass mymaster Redis@2026
# PING超时3000毫秒标记节点主观下线sdown,修改改值为3s
sentinel down-after-milliseconds mymaster 3000
# 故障切换时,并行同步新主库的从节点数量

# 完整故障切换最大超时时间180000毫秒

# 安全限制
sentinel deny-scripts-reconfig yes
sentinel resolve-hostnames no
sentinel announce-hostnames no

# Generated by CONFIG REWRITE
latency-tracking-info-percentiles 50 99 99.9
user default on sanitize-payload #11ac9b0d1980f1c618b15fe515c4c20410c985e59ad2396a5eb594a8ffc9f6c2 ~* &* +@all
sentinel myid 93fa143e11de5f1c22cfeaa571eb83c64582608d
sentinel config-epoch mymaster 0
sentinel leader-epoch mymaster 0
sentinel current-epoch 0

#创建systemd文件
[root@Redis-23:~#] cat /etc/systemd/system/redis-sentinel.service
[Unit]
Description=Redis Sentinel Service
Documentation=https://redis.io/docs/manual/sentinel/
After=network.target

[Service]
Type=forking
# 编译安装的哨兵二进制程序路径
ExecStart=/usr/local/src/redis-8.4.0/src/redis-sentinel /apps/redis/etc/redis-sentinel.conf
# 优雅停止哨兵
ExecStop=/usr/local/src/redis-8.4.0/src/redis-cli -p 26379 -a Redis@2026 shutdown
ExecReload=/bin/kill -USR2
# PID文件,和sentinel.conf内pidfile保持一致
PIDFile=/var/run/redis-sentinel.pid
# 进程异常自动重启
Restart=on-failure
RestartSec=3

# 安全权限限制(生产推荐)
PrivateTmp=true
LimitNOFILE=65535

[Install]
# 开机自启
WantedBy=multi-user.target

#设置开机自启动
[root@Redis-23:~#] systemctl daemon-reload
[root@Redis-23:~#] systemctl enable --now redis-sentinel.service

-----------------------------------------------------------------


#查看masters和slaves
[root@Redis-23:~#] redis-cli -p 26379 -a Redis@2026
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:26379> SENTINEL masters
1)  1) "name"
    2) "mymaster"
    3) "ip"
    4) "10.0.0.23"
    5) "port"
    6) "6379"
    7) "runid"
    8) "2402762d9a94a923aa45b40f2e375613fc2c6e16"
    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) "759"
   19) "last-ping-reply"
   20) "759"
   21) "down-after-milliseconds"
   22) "3000"
   23) "info-refresh"
   24) "7840"
   25) "role-reported"
   26) "master"
   27) "role-reported-time"
   28) "38005"
   29) "config-epoch"
   30) "0"
   31) "num-slaves"
   32) "2"
   33) "num-other-sentinels"
   34) "0"
   35) "quorum"
   36) "2"
   37) "failover-timeout"
   38) "180000"
   39) "parallel-syncs"
   40) "1"
127.0.0.1:26379> SENTINEL slaves mymaster
1)  1) "name"
    2) "10.0.0.29:6379"
    3) "ip"
    4) "10.0.0.29"
    5) "port"
    6) "6379"
    7) "runid"
    8) "5e941303a627f5a53915b5a0687a46698c6e4cdf"
    9) "flags"
   10) "slave"
   11) "link-pending-commands"
   12) "0"
   13) "link-refcount"
   14) "1"
   15) "last-ping-sent"
   16) "0"
   17) "last-ok-ping-reply"
   18) "50"
   19) "last-ping-reply"
   20) "50"
   21) "down-after-milliseconds"
   22) "3000"
   23) "info-refresh"
   24) "6006"
   25) "role-reported"
   26) "slave"
   27) "role-reported-time"
   28) "56327"
   29) "master-link-down-time"
   30) "0"
   31) "master-link-status"
   32) "ok"
   33) "master-host"
   34) "10.0.0.23"
   35) "master-port"
   36) "6379"
   37) "slave-priority"
   38) "100"
   39) "slave-repl-offset"
   40) "801066"
   41) "replica-announced"
   42) "1"
2)  1) "name"
    2) "10.0.0.26:6379"
    3) "ip"
    4) "10.0.0.26"
    5) "port"
    6) "6379"
    7) "runid"
    8) "8c2d7b31f1114678b35655e3247082e4f661a0a5"
    9) "flags"
   10) "slave"
   11) "link-pending-commands"
   12) "0"
   13) "link-refcount"
   14) "1"
   15) "last-ping-sent"
   16) "0"
   17) "last-ok-ping-reply"
   18) "50"
   19) "last-ping-reply"
   20) "50"
   21) "down-after-milliseconds"
   22) "3000"
   23) "info-refresh"
   24) "6007"
   25) "role-reported"
   26) "slave"
   27) "role-reported-time"
   28) "56331"
   29) "master-link-down-time"
   30) "0"
   31) "master-link-status"
   32) "ok"
   33) "master-host"
   34) "10.0.0.23"
   35) "master-port"
   36) "6379"
   37) "slave-priority"
   38) "100"
   39) "slave-repl-offset"
   40) "801066"
   41) "replica-announced"
   42) "1"
127.0.0.1:26379>
-------------------------------------------
#主节点观察哨兵配置文件自动出现的内容
[root@Redis-23:~#] vim /apps/redis/etc/redis-sentinel.conf

# Generated by CONFIG REWRITE
latency-tracking-info-percentiles 50 99 99.9
user default on sanitize-payload #11ac9b0d1980f1c618b15fe515c4c20410c985e59ad2396a5eb594a8ffc9f6c2 ~* &* +@all
sentinel myid 93fa143e11de5f1c22cfeaa571eb83c64582608d
sentinel config-epoch mymaster 0
sentinel leader-epoch mymaster 0
sentinel current-epoch 0

sentinel known-replica mymaster 10.0.0.29 6379

sentinel known-replica mymaster 10.0.0.26 6379


--------------------------------------------

#关闭主节点测试,主是否会自动切换,可以观察到住在29上面
[root@Redis-26:~#] redis-cli -p 26379 -a Redis@2026 SENTINEL masters
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
1)  1) "name"
    2) "mymaster"
    3) "ip"
    4) "10.0.0.29"
    5) "port"
    6) "6379"
    7) "runid"
    8) "4244a9edc681763726a6278e0c4529ce6b982baa"
    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) "865"
   19) "last-ping-reply"
   20) "865"
   21) "down-after-milliseconds"
   22) "3000"
   23) "info-refresh"
   24) "5948"
   25) "role-reported"
   26) "master"
   27) "role-reported-time"
   28) "257866"
   29) "config-epoch"
   30) "1"
   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"
[root@Redis-26:~#]


[root@Redis-26:~#] redis-cli info replication
# Replication
role:slave
master_host:10.0.0.29
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_read_repl_offset:1189771
slave_repl_offset:1189771
replica_full_sync_buffer_size:0
replica_full_sync_buffer_peak:0
master_current_sync_attempts:1
master_total_sync_attempts:1
master_link_up_since_seconds:314
total_disconnect_time_sec:132
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:49ab840d2dd7a3d5791d45ca268c9aa54af4a0ad
master_replid2:e8eb09f208d86b1bac9663f49d766a8c2cefd077
master_repl_offset:1189771
second_repl_offset:1128037
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:828392
repl_backlog_histlen:361380



[root@Redis-29:~#] redis-cli -p 26379 -a Redis@2026 SENTINEL slaves mymaster
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
1)  1) "name"
    2) "10.0.0.26:6379"
    3) "ip"
    4) "10.0.0.26"
    5) "port"
    6) "6379"
    7) "runid"
    8) "8c2d7b31f1114678b35655e3247082e4f661a0a5"
    9) "flags"
   10) "slave"
   11) "link-pending-commands"
   12) "0"
   13) "link-refcount"
   14) "1"
   15) "last-ping-sent"
   16) "0"
   17) "last-ok-ping-reply"
   18) "592"
   19) "last-ping-reply"
   20) "592"
   21) "down-after-milliseconds"
   22) "3000"
   23) "info-refresh"
   24) "9984"
   25) "role-reported"
   26) "slave"
   27) "role-reported-time"
   28) "351381"
   29) "master-link-down-time"
   30) "0"
   31) "master-link-status"
   32) "ok"
   33) "master-host"
   34) "10.0.0.29"
   35) "master-port"
   36) "6379"
   37) "slave-priority"
   38) "100"
   39) "slave-repl-offset"
   40) "1195091"
   41) "replica-announced"
   42) "1"
2)  1) "name"
    2) "10.0.0.23:6379"
    3) "ip"
    4) "10.0.0.23"
    5) "port"
    6) "6379"
    7) "runid"
    8) ""
    9) "flags"
   10) "s_down,slave,disconnected"
   11) "link-pending-commands"
   12) "3"
   13) "link-refcount"
   14) "1"
   15) "last-ping-sent"
   16) "351381"
   17) "last-ok-ping-reply"
   18) "351381"
   19) "last-ping-reply"
   20) "351381"
   21) "s-down-time"
   22) "348346"
   23) "down-after-milliseconds"
   24) "3000"
   25) "info-refresh"
   26) "0"
   27) "role-reported"
   28) "slave"
   29) "role-reported-time"
   30) "351381"
   31) "master-link-down-time"
   32) "0"
   33) "master-link-status"
   34) "err"
   35) "master-host"
   36) "?"
   37) "master-port"
   38) "0"
   39) "slave-priority"
   40) "100"
   41) "slave-repl-offset"
   42) "0"
   43) "replica-announced"
   44) "1"
[root@Redis-29:~#]

3.6、Redis Cluster核心知识点

bash 复制代码
Redis Cluster 采用哈希槽分片 + Gossip 协议 + 主从复制 + 过半投票故障转移实现分布式高可用;总共 16384 槽,key 通过 CRC16 取模分配槽;节点间 Gossip 同步集群状态;主观下线 PFAIL,过半 master 确认后客观下线 FAIL;slave 选举新 master 接管槽;去中心化,无中心代理;异步复制,最终一致性,不支持跨槽多 key 操作;生产推荐 3 主 3 从,主从跨物理机部署防止单点机房故障。

四、Redis 大 Key 治理与缓存问题处理

4.1、什么是大key和测试

bash 复制代码
1. String 类型:单键内存 ≥ 100KB 判定为大 Key;

2. List/Set 集合:元素数量 ≥ 10000 条 判定为大 Key;

3. Hash/ZSet:字段 / 有序成员 ≥ 5000 条 判定为大Key;

4. 内存兜底标准:任意类型键内存占用超过 512KB,统一纳入大 Key 治理清单。
bash 复制代码
1. 大key的判断原由
    String:单键内存 ≥100KB 判定大 Key 
原理:单条 100KB 字符串单次传输会占用大量网卡带宽,批量读取极易造成接口超时;RDB 
fork、内存淘汰时开销明显;
边界兜底:第 4 条 512KB 兜底规则做双重防护,即使少量 String 不到 100KB 但膨胀到 512KB 依
然纳入治理,无漏洞。

    List/Set:元素 ≥10000 条判定大 Key 
List:一次性 LRANGE 全量读取万条数据会阻塞主线程、耗带宽;删除 / 裁剪同步遍历阻塞;
Set:SMEMBERS、差集 / 交集运算遍历全部元素,万级集合 CPU 消耗陡增;
生产通用阈值就是 8000~10000,取 10000 作为红线完全合理。

    Hash/ZSet:字段 / 成员 ≥5000 条判定大 Key 
Hash:HGETALL、HKEYS 会遍历所有字段,5000 字段以上查询耗时明显;
ZSet:排序、范围查询、排名计算时间复杂度 O (logN+M),5000 成员后延迟肉眼可见;
Hash/ZSet 底层结构比 List 复杂,阈值设得更低,区分了结构性能差异,逻辑严谨。兜底规则:任意键内存>512KB 全部治理

    解决两类遗漏场景:
短元素极多的集合:比如每条仅 10 字节,6000 条 Hash 仅 60KB,不触发条数阈值,但后期膨胀
到 512KB;
特殊编码结构、二进制数据、压缩字符串,条数不超标但内存超标;
双重校验(条数 + 内存)避免漏判,是成熟生产规范。


查询命令
# 1. 查看String内存
MEMORY USAGE big:string:profile
# 2. 统计Hash字段数量
HLEN big:hash:order
# 3. 统计List长度
LLEN big:list:msg
# 4. 全节点批量扫描大key
redis-cli -h 10.0.0.13 -p 6379 -a Redis@2026 --bigkeys
----------------------

#主库测试大kes
[root@Redis-26:~#] redis-cli role
1) "master"
2) (integer) 2296561
3) 1) 1) "10.0.0.29"
      2) "6379"
      3) "2296561"

[root@Redis-26:~#]  redis-cli EXPIRE big:string:userprofile 86400
(integer) 1
[root@Redis-26:~#]  redis-cli EVAL "for i=1,6000 do redis.call('HSET',KEYS[1],'field_'..i,'value_data') end" 1 big:hash:orderlist
(nil)
[root@Redis-26:~#] redis-cli EVAL "for i=1,12000 do redis.call('LPUSH',KEYS[1],'msg_'..i) end" 1 big:list:message
(nil)
[root@Redis-26:~#]  redis-cli EVAL "for i=1,8000 do redis.call('ZADD',KEYS[1],i,'rank_'..i) end" 1 big:zset:hotrank
(nil)
[root@Redis-26:~#]  redis-cli STRLEN big:string:userprofile
(integer) 0
[root@Redis-26:~#] redis-cli printf 'a%.0s' {1..10000} | redis-cli -x SET big:string:userprofile
OK
[root@Redis-26:~#] redis-cli STRLEN big:string:userprofile
(integer) 187
[root@Redis-26:~#] redis-cli HLEN big:hash:orderlist
(integer) 6000
[root@Redis-26:~#] redis-cli LLEN big:list:message
(integer) 12000
[root@Redis-26:~#] redis-cli ZCARD big:zset:hotrank
(integer) 8000
[root@Redis-26:~#]  redis-cli --bigkeys

# Scanning the entire keyspace to find biggest keys as well as
# average sizes per key type.  You can use -i 0.1 to sleep 0.1 sec
# per 100 SCAN commands (not usually needed).

100.00% ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Keys sampled: 20013

-------- summary -------

Total key length in bytes is 189026 (avg len 9.45)

Biggest   list found "big:list:message" has 12000 items
Biggest   hash found "big:hash:orderlist" has 6000 fields
Biggest string found "big:string:userprofile" has 187 bytes
Biggest   zset found "big:zset:hotrank" has 8000 members

2 lists with 12003 items (00.01% of keys, avg size 6001.50)
2 hashs with 6003 fields (00.01% of keys, avg size 3001.50)
0 streams with 0 entries (00.00% of keys, avg size 0.00)
20008 strings with 89126 bytes (99.98% of keys, avg size 4.45)
0 sets with 0 members (00.00% of keys, avg size 0.00)
1 zsets with 8000 members (00.00% of keys, avg size 8000.00)

4.2、大kes的危害:fork 耗时、网络延迟、内存不均衡

bash 复制代码
1. RDB/AOF 持久化 fork COW 阻塞
Redis 做 RDB 持久化时会调用 fork() 创建子进程,fork 本身仅拷贝页表、耗时极短;
但系统采用写时复制 (COW) 机制:fork 之后主进程如果修改几十 MB/GB 级大 Key,内核需要完整复制该内存页,产生大量内存拷贝开销,主线程被阻塞,所有 Redis 读写请求全部卡死,引发服务不可用。

2. 网络 IO 延迟,接口超时、连接断开
客户端读取大 Key 时,Redis 需要一次性将全部数据通过网络传输:单 key 几十 MB 数据会占用大量带宽;
传输时间拉长,前端业务接口响应超时,大量请求堆积;
若返回数据超出 client-output-buffer-limit 客户端缓冲区阈值,Redis 会强制断开 TCP 连接,业务直接报连接异常。

3. 集群内存分片不均衡
Redis Cluster 按 slot 分片存储 key,大 key 整体只存于单一主节点:
1. 该节点内存占用远高于其他分片,内存资源分配失衡;
2. 内存高负载节点更容易触发 swap、OOM 宕机;
3. 集群扩容、槽位迁移时,大 key 迁移为同步阻塞流程,迁移速度极慢,扩容缩容耗时暴增,迁移期间对应 slot 分片业务完全不可读写。

4. 删除阻塞风险
使用 DEL 删除Hash/List/ZSet/Set 超大集合类大 Key 时,Redis 主线程同步循环遍历、释放全部元素内存,会造成长时间主线程阻塞,业务读写全部卡住;
普通 String 类型大 Key 执行 DEL 仅释放单块内存,阻塞影响极小。

拆分

bash 复制代码
拆分统一执行标准(生产强制规范)
1. String 类型:单键内存上限 50KB,超过则按业务维度垂直拆分;
2. Hash 类型:单个 Hash 字段上限 1000 个,超出则水平分片;
3. List/Set:单集合元素上限 5000 条;
4. ZSet:单有序集合成员上限 3000 个;
5. 拆分收益:规避大 Key 网络传输、fork 阻塞、集群内存不均、DEL 同步阻塞四大风险。
String 大 Key 垂直拆分(维度拆分)
业务场景:原始键 user:info:1001 ,存储完整用户 JSON, MEMORY USAGE 检测为 224KB,属于超标
大 String。

压缩

bash 复制代码
数据压缩降低内存体积
1. 文本 JSON 数据使用 Gzip 压缩后存入 String,读取后客户端解压;
2. 整数列表采用 Redis Listpack 紧凑编码,避免冗余存储;
3. 业务层精简无用字段,从源头减少 key 体积。
4. 优化后必须用 MEMORY USAGE 、 OBJECT ENCODING 验证内存与编码效果。

异步删除

bash 复制代码
异步删除 UNLINK 替代 DEL
1. DEL 同步删除:主线程同步释放内存,超大集合直接阻塞;
2. UNLINK 异步删除:仅在主线程移除 key 元数据,内存释放交给后台子线程异步执行,无阻塞;

UNLINK big_hash_key        #推荐

DEL big_hash_key            #不推荐

4.4 、Redis 内存治理

maxmemory 配置(物理内存 70%-80% 预留原则)

bash 复制代码
作用
maxmemory 限制 Redis 实例最大可用内存,内存达到阈值后,触发淘汰策略清理 key,防止 Redis 占满
整机内存导致系统 OOM、服务被 kill。
配置规范(运维初学者标准)
1 推荐阈值:整机物理内存的 70%~80%
2 预留 20%~30% 空闲内存,专门给持久化 fork 、缓冲区、副本复制使用;
3 配置示例(redis.conf)
    # 机器总内存16G,设置maxmemory为12G(75%)
    maxmemory 12gb

maxmemory-policy 淘汰策略详解(LRU/LFU/volatile 系列)

bash 复制代码
内存打满后,Redis 按照该策略自动清理 Key,一共 7 种策略,分 3 类通俗讲解

前置基础名词
    LRU:淘汰最长时间没有被访问的数据
    LFU:淘汰访问次数最少的数据
分类 0:高危禁用策略(Redis 默认值 noeviction )
内存达到上限不删除任何 Key,所有写入命令直接报错 OOM;
仅本地测试、纯只读配置库可用,线上缓存业务禁止配置。

分类 1:只淘汰带过期 TTL 的 key(volatile 开头)
volatile-lru (线上最常用): 只在设置了过期时间的 key 里,淘汰最久没访问的数据;
适用:混合业务(永久配置 key + 短期缓存 key 共存),不会删掉永不过期的热点配置。
volatile-lfu : 过期 key 里淘汰访问次数最少的数据;
适用:热点区分明显,想保留高频访问缓存。
volatile-random : 过期 key 里随机删,几乎不推荐,无法优先保热点。
volatile-ttl : 过期 key 里优先删剩余存活时间最短的。
适用:批量同步缓存、统一过期业务,优先清理马上失效的缓存。

分类 2:全部 key 都参与淘汰(allkeys 开头,包含永不过期 key)
allkeys-lru : 所有 key(含永久 key)淘汰最久未访问数据;
适用:全业务都是短期缓存,无永久配置类数据。
allkeys-lfu : 所有 key 淘汰访问频次最低的,缓存热点区分极强场景。
适用:热点区分极强、长期稳定访问的缓存业务。
新手选型建议
绝大多数业务选: volatile-lru ;
纯临时缓存、无永久配置数据: allkeys-lru ;
生产禁止: noeviction 、 volatile-random 。

持久化 fork 场景的内存预留优化

bash 复制代码
核心原理
执行 RDB 持久化时,Redis 调用 fork() 生成独立子进程做备份:
操作系统采用写时复制 COW机制:子进程刚创建时和父进程共享全部内存;
父进程有新增 /修改数据时,被改动的内存页才会复制一份,内存占用上涨。
如果 maxmemory 设置过高,整机无空闲内存, fork 创建子进程直接失败,RDB 持久化中断,日志报
错。
运维优化方案
    1. 内存上限规范:maxmemory 限制为整机物理内存70%~80%,预留 20%~30% 空闲内存应对内存页复制;
    2. 超大实例(32G/64G 内存):下调至 70%,减少 fork 内存溢出风险;
    3. 错峰持久化:RDB 定时备份放在凌晨业务低峰,减少业务写操作带来的内存拷贝;
    4. RDB+AOF 混合持久化调优:
aof 刷盘策略改为 appendfsync everysec (每秒刷盘),平衡磁盘 IO 与父进程内存修改频
率;禁止 always 高频刷盘;
大集群备份方案:在从节点执行 RDB 备份,主节点完全不触发 fork,无内存压力;
    5. 监控告警:定时采集 INFO persistence ,监控 rdb_last_bgsave_status ,一旦出现 RDB 失败立即告警;fork 报错时调低 maxmemory 或扩容机器内存。

Linux学习之旅之redis主从复制

一、主从复制基础认知

1.1、主从复制的有点

bash 复制代码
1. 数据副本,实现数据冗余
主节点的数据会同步到从节点,相当于多份数据备份。当主库磁盘损坏、数据丢失时,可以用从库的数据恢复,提升数据安全性。

2. 读写分离,分担主库压力
写请求全部走主库;读请求可以分发到多个从库。适合读多写少业务,横向扩展读能力,降低主库 CPU、内存压力。

3. 故障基础能力,为高可用打下基础
主库宕机后,可以手动把从库提升为主库;搭配哨兵(Sentinel)就能实现自动故障转移,自动选主,完成故障切换。主从是哨兵和 Redis 集群的底层基础。

4. 方便做数据备份与运维操作
RDB/AOF 备份可以在从库执行,避免备份时 BGSAVE 对主库造成 fork 卡顿;也可以在从库做数据校验、压力测试,不影响线上主业务。

5. 架构简单,部署维护成本低
相比 Redis Cluster 集群,主从复制配置简单,命令少,容易上手,适合中小规模业务。

1. 2、主从复制的基本流程

bash 复制代码
1. 从库连上主库,完成鉴权,发送PSYNC ? -1请求同步。
2. 主库执行BGSAVE生成 RDB,期间写命令存入复制缓冲区。
3. 主库推送 RDB 给从库;从库清空本地数据,加载 RDB。
4. 主库再推送缓冲区增量命令,从库执行,主从数据一致。
5. 正常运行时,主库持续异步转发写命令,维护复制偏移量。
6. 断线重连:从库携带 replid 和 offset 执行PSYNC;匹配且 offset 在 backlog 内则增量同步,否则重新全量同步。


流程图
从库启动 → TCP 连接 → PSYNC ? -1
→ 主库 BGSAVE 生成 RDB → 传输 RDB → 从库加载 RDB
→ 推送缓冲区命令(repl-backlog-size默认值1MB) → 正常增量同步(主转发写命令,维护 offset)
→ 断线重连 → PSYNC replid offset
→ 判断:满足条件增量同步,否则走全量同步

二、主从复制配置

2.1、前提环境

bash 复制代码
操作系统:Ubuntu 24.04.4 LTS
redis版本:redis-cli 8.4.0
主:10.0.0.23
从:10.0.0.26
环境详解上一章脚本部署:

2.2、配置主从复制与常见问题处理

2.2.1、主从同步配置
bash 复制代码
#查看当前节点
[root@Redis-23:~#] redis-cli INFO replication | grep role
role:master

[root@Redis-26:~#] redis-cli INFO replication | grep role
role:master

#26配置主从认证信息
[root@Redis-26:~#] vim /etc/redis/redis-6379.conf
[root@Redis-26:~#] grep -C 1 '^masterauth' /etc/redis/redis-6379.conf
# masterauth <master-password>
masterauth Redis@2026
replicaof 10.0.0.23 6379

#重启生效并验证
[root@Redis-26:~#] systemctl restart redis.service
[root@Redis-26:~#] redis-cli INFO replication
# Replication
role:slave
master_host:10.0.0.23
master_port:6379
master_link_status:up
master_last_io_seconds_ago:9
master_sync_in_progress:0
slave_read_repl_offset:28
slave_repl_offset:28
replica_full_sync_buffer_size:0
replica_full_sync_buffer_peak:0
master_current_sync_attempts:1
master_total_sync_attempts:1
master_link_up_since_seconds:14
total_disconnect_time_sec:0
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:ccce0145a7160d5e4c186733bf0156b6a0949ffa
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:28
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:15
repl_backlog_histlen:14
[root@Redis-26:~#]

[root@Redis-23:~#] redis-cli INFO replication
# Replication
role:master
connected_slaves:1
slave0:ip=10.0.0.26,port=6379,state=online,offset=308,lag=0
master_failover_state:no-failover
master_replid:ccce0145a7160d5e4c186733bf0156b6a0949ffa
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:308
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:308
[root@Redis-23:~#]


#全量同步:创建key验证同步
[root@Redis-23:~#] redis-cli
127.0.0.1:6379> set name xiyangyang
OK
127.0.0.1:6379> KEYS *
1) "name"
127.0.0.1:6379>


[root@Redis-26:~#] redis-cli
127.0.0.1:6379> KEYS *
1) "name"
127.0.0.1:6379>


#增量同步:创建key验证同步
#断开同步
[root@Redis-26:~#] redis-cli replicaof no one
OK
[root@Redis-26:~#] redis-cli INFO replication | grep role
role:master

#主库创建新key
[root@Redis-23:~#] redis-cli INFO replication | grep role
role:master
[root@Redis-23:~#] redis-cli -h 10.0.0.23 SET test1:num 100
OK
[root@Redis-23:~#] redis-cli -h 10.0.0.23 MSET k11 v1 k12 v2 k13 v3
OK


#从库连接主库测试同步
[root@Redis-26:~#] redis-cli
127.0.0.1:6379> REPLICAOF 10.0.0.23 6379
OK
127.0.0.1:6379> KEYS *
1) "name"
2) "test1:num"
3) "k12"
4) "k13"
5) "k11"
127.0.0.1:6379>



#查看状态
[root@Redis-23:~#] redis-cli INFO replication
# Replication
role:master
connected_slaves:1
slave0:ip=10.0.0.26,port=6379,state=online,offset=1201,lag=1
master_failover_state:no-failover
master_replid:ccce0145a7160d5e4c186733bf0156b6a0949ffa
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1201
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:1201


127.0.0.1:6379> INFO replication
# Replication
role:slave
master_host:10.0.0.23
master_port:6379
master_link_status:up
master_last_io_seconds_ago:5
master_sync_in_progress:0
slave_read_repl_offset:1187
slave_repl_offset:1187
replica_full_sync_buffer_size:0
replica_full_sync_buffer_peak:0
master_current_sync_attempts:1
master_total_sync_attempts:1
master_link_up_since_seconds:121
total_disconnect_time_sec:162
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:ccce0145a7160d5e4c186733bf0156b6a0949ffa
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1187
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1020
repl_backlog_histlen:168
2.2.2、主从同步常见问题
2.2.2.1、replication backlog 调优
bash 复制代码
复制缓冲区(repl-backlog)是 Redis 主从增量同步(Partial Resync) 的核心内存区域。
    主节点写入的所有写命令会同时写入 backlog 环形缓冲区
    从节点断连重连后,通过 offset 比对直接回放断连期间缺失指令
    backlog 没被覆盖 → 增量同步
    backlog 被覆盖 → 强制全量 RDB 同步
默认:repl-backlog-size 1MB


[root@Redis-23:~#] redis-cli INFO replication | grep backlog
repl_backlog_active:1          # 1=backlog缓冲区已激活(当前有从库连接)
repl_backlog_size:1048576      # backlog总大小:1048576 bytes = 1MB(默认值)
repl_backlog_first_byte_offset:1 # backlog内最早一条数据对应的主库offset=1
repl_backlog_histlen:1691      # backlog当前有效数据长度:1691字节


#测试
[root@Redis-26:~#] redis-cli replicaof no one
OK
[root@Redis-26:~#] redis-cli INFO replication | egrep 'role|conn'
role:master
connected_slaves:0

[root@Redis-23:~#] for i in {1..20000};do redis-cli SET test_$i $i >/dev/null;done
[root@Redis-23:~#]

[root@Redis-26:~#] redis-cli INFO replication | egrep 'role|conn'
role:slave
total_disconnect_time_sec:162
connected_slaves:0
[root@Redis-26:~#] tail /var/log/redis/redis-6379.log -n20
1878:S 09 Sep 2026 07:02:50.114 * Loading RDB produced by version 8.4.0
1878:S 09 Sep 2026 07:02:50.114 * RDB age 1 seconds
1878:S 09 Sep 2026 07:02:50.114 * RDB memory usage when created 2.56 Mb
1878:S 09 Sep 2026 07:02:50.145 * Done loading RDB, keys loaded: 20005, keys expired: 0.
1878:S 09 Sep 2026 07:02:50.146 * MASTER <-> REPLICA sync: Finished with success
1878:S 09 Sep 2026 07:02:50.146 # systemd supervision error: NOTIFY_SOCKET not found!
1878:S 09 Sep 2026 07:02:50.146 * MASTER <-> REPLICA sync: Starting AOF after a successful sync
1878:S 09 Sep 2026 07:02:50.146 * Creating AOF incr file temp-appendonly-6379.aof.incr on background rewrite
1878:S 09 Sep 2026 07:02:50.147 * Background append only file rewriting started by pid 2733
1878:S 09 Sep 2026 07:02:50.148 * MASTER <-> REPLICA sync: Starting to stream replication buffer into the db (0 bytes).
1878:S 09 Sep 2026 07:02:50.148 * MASTER <-> REPLICA sync: Successfully streamed replication buffer into the db (0 bytes in total)
2733:C 09 Sep 2026 07:02:50.165 * BGSAVE done, 20005 keys saved, 0 keys skipped, 288918 bytes written.
2733:C 09 Sep 2026 07:02:50.169 * Successfully created the temporary AOF base file temp-rewriteaof-bg-2733.aof
2733:C 09 Sep 2026 07:02:50.171 * Fork CoW for AOF rewrite: current 0 MB, peak 0 MB, average 0 MB
1878:S 09 Sep 2026 07:02:50.175 * Background AOF rewrite terminated with success
1878:S 09 Sep 2026 07:02:50.175 * Successfully renamed the temporary AOF base file temp-rewriteaof-bg-2733.aof into appendonly-6379.aof.4.base.rdb
1878:S 09 Sep 2026 07:02:50.175 * Successfully renamed the temporary AOF incr file temp-appendonly-6379.aof.incr into appendonly-6379.aof.4.incr.aof
1878:S 09 Sep 2026 07:02:50.180 * Removing the history file appendonly-6379.aof.3.incr.aof in the background
1878:S 09 Sep 2026 07:02:50.180 * Removing the history file appendonly-6379.aof.3.base.rdb in the background
1878:S 09 Sep 2026 07:02:50.184 * Background AOF rewrite finished successfully
[root@Redis-26:~#]

#同步20005个key全量同步
1878:S 09 Sep 2026 07:02:50.146 * MASTER <-> REPLICA sync: Finished with success



#扩容backlog缓冲区
                           #动态调整                 
root@Redis-23:~#] redis-cli CONFIG SET repl-backlog-size 16777216
OK
[root@Redis-23:~#] redis-cli INFO replication | grep repl_backlog_size
repl_backlog_size:16777216

#持久化配置
[root@Redis-23:~#] vi /etc/redis/redis-6379.conf
[root@Redis-23:~#] grep '^repl-backlog-size' /etc/redis/redis-6379.conf
repl-backlog-size 64mb
[root@Redis-23:~#] systemctl restart redis.service

#测试
[root@Redis-23:~#] redis-cli INFO replication | egrep 'role|backlog_s'
role:master
repl_backlog_size:67108864
[root@Redis-23:~#]


[root@Redis-26:~#] redis-cli INFO replication | egrep 'role|backlog_s'
role:slave
repl_backlog_size:1048576
2.2.2.2、主从数据一致性校验方法
bash 复制代码
[root@Redis-23:~#] redis-cli INFO replication | grep role
role:master
[root@Redis-23:~#] redis-cli set biz_test_no 2026061801
OK
[root@Redis-23:~#] redis-cli set biz_name redis_sync_check
OK
[root@Redis-23:~#] redis-cli hset user:1001 id 1001 name test age 24
(integer) 3
[root@Redis-23:~#] redis-cli rpush order:list 10001 10002 10003
(integer) 3
[root@Redis-23:~#] redis-cli dbsize
(integer) 20009
[root@Redis-23:~#]




[root@Redis-26:~#] redis-cli INFO replication | grep role
role:slave
[root@Redis-26:~#] redis-cli
127.0.0.1:6379> get biz_test_no
"2026061801"
127.0.0.1:6379> get biz_name
"redis_sync_check"
127.0.0.1:6379> HGETALLuser:1001
(error) ERR unknown command 'HGETALLuser:1001', with args beginning with:
127.0.0.1:6379> HGETALL user:1001
1) "id"
2) "1001"
3) "name"
4) "test"
5) "age"
6) "24"
127.0.0.1:6379> lrange order:list 0 -1
1) "10001"
2) "10002"
3) "10003"
127.0.0.1:6379> DBSIZE
Error: Broken pipe
not connected>
not connected> exit
[root@Redis-26:~#] redis-cli dbsize
(integer) 20009
[root@Redis-26:~#]

三、redis哨兵(Sentinel)高可用架构

3.1、哨兵基础

bash 复制代码
1. 哨兵集群持续监控 master 和 replica,定期发送 PING 心跳。

2. master 网络 / 进程异常,某个哨兵收不到回复,标记 SDOWN(主观下线)。

3. 该哨兵询问其他哨兵;若满足quorum数量哨兵都判定 SDOWN → ODOWN 客观下线。

4.哨兵集群内部投票选出领头哨兵 Leader,由 Leader 执行故障转移。

5. Leader 在所有从库中挑选新 Master,筛选规则:
① 剔除下线、断连的从库
② 优先replica-priority值最小
③ 优先复制偏移量最大(数据最新)
④ 优先 runid 最小

6. Leader 发送命令,把选中的副本提升为新主。

7. Leader 向剩余从库发送REPLICAOF,让它们改为复制新主。

8. 更新配置:哨兵自动修改配置文件,记录新 master 信息;持续监控新主。

9. 通知客户端:客户端通过哨兵获取 Redis 节点地址,感知主节点变更。

3.2、架构组成

bash 复制代码
1. 主节点(Master):负责写,数据同步到从节点
2. 从节点(Replica):读,复制主库数据;主宕机后可被哨兵选为新主
3. Sentinel 哨兵节点(至少 3 个,奇数):哨兵本身是特殊 Redis 进程,不存储数据,核心职责:
    监控:持续心跳检测主、从节点存活状态
    通知:节点异常时,通知其他哨兵和客户端
    自动故障转移:主库宕机,哨兵投票选出新主,修改其余从库指向新主;通知客户端新主地址
    哨兵集群奇数个(3/5)目的:选举需要 quorum(法定票数),防止脑裂

3.3、核心概念

bash 复制代码
1. 主观下线 SDOWN:单个哨兵探测到主节点无响应,标记 SDOWN,只是该哨兵单方面认为挂了。
2. 客观下线 ODOWN:多个哨兵(≥quorum 数量)都认为主 SDOWN,才判定客观下线,才启动故障转移。
    quorum:配置文件sentinel monitor mymaster 127.0.0.1 6379 2最后的 2,表示至少 2 个哨兵认为主下线,才判定 ODOWN。
3. Raft 投票算法:哨兵之间选举领头哨兵(leader),只有 leader 负责执行故障转移操作。
4. 优先级 replica-priority:选新主时优先选数值小的从库;0 代表永远不能选为 master。
5. 复制偏移量:候选从库对比 offset,优先选择数据最完整的从库。

3.4、角色

bash 复制代码
1. 监控者(Monitor):持续心跳检测主节点、从节点在线状态,实时采集集群运行信息。
2. 仲裁者(Judge):多个哨兵节点共同投票判定节点是否真正故障,避免误判。
3. 故障转移执行者(Failover):当集群判定主节点客观下线后,选举领头哨兵完成自动主从切换、从节点重置、架构重构等操作。

3.5、哨兵高可用配置

bash 复制代码
!!!增加一台从节点:10.0.0.29


[root@Redis-23:~#] redis-cli INFO replication
# Replication
role:master
connected_slaves:2
slave0:ip=10.0.0.26,port=6379,state=online,offset=795653,lag=1
slave1:ip=10.0.0.29,port=6379,state=online,offset=795653,lag=1
master_failover_state:no-failover
master_replid:32ab7842b4fcc5a021132d11cbd2ca0bef574bff
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:795653
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:67108864
repl_backlog_first_byte_offset:792280
repl_backlog_histlen:3374
[root@Redis-23:~#]


[root@Redis-26:~#]
redis-cli INFO replication
# Replication
role:slave
master_host:10.0.0.23
master_port:6379
master_link_status:up
master_last_io_seconds_ago:5
master_sync_in_progress:0
slave_read_repl_offset:795779
slave_repl_offset:795779
replica_full_sync_buffer_size:0
replica_full_sync_buffer_peak:0
master_current_sync_attempts:3
master_total_sync_attempts:4
master_link_up_since_seconds:2502
total_disconnect_time_sec:7
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:32ab7842b4fcc5a021132d11cbd2ca0bef574bff
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:795779
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:792280
repl_backlog_histlen:3500


[root@Redis-29:~#] redis-cli INFO replication
# Replication
role:slave
master_host:10.0.0.23
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_read_repl_offset:795653
slave_repl_offset:795653
replica_full_sync_buffer_size:0
replica_full_sync_buffer_peak:0
master_current_sync_attempts:1
master_total_sync_attempts:1
master_link_up_since_seconds:259
total_disconnect_time_sec:0
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:32ab7842b4fcc5a021132d11cbd2ca0bef574bff
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:795653
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:795290
repl_backlog_histlen:364
[root@Redis-29:~#]
-------------------------------------------------------

##23/26/29操作以下步骤
#床架所需目录
[root@Redis-23:~#] mkdir -p /apps/redis/e                                                                   tc /apps/redis/log /apps/redis/data

#创建哨兵配置文件
[root@Redis-23:~#] cat /apps/redis/etc/redis-sentinel.conf
# 监听本机所有网卡,允许其他服务器访问哨兵
bind 0.0.0.0
# 关闭保护模式,支持跨机哨兵互相通信自动发现
protected-mode no
# 三台哨兵统一端口26379,不同主机不存在端口冲突
port 26379
# 设定登录哨兵的认证密码
requirepass "Redis@2026"
# 后台守护进程运行哨兵
daemonize yes
pidfile "/var/run/redis-sentinel.pid"
loglevel notice
logfile "/apps/redis/log/sentinel.log"
dir "/apps/redis/data"
# 设定登录哨兵的认证密码

# 核心监控配置:集群名mymaster、初始主库地址、法定票数2
sentinel monitor mymaster 10.0.0.23 6379 2
# Redis集群统一鉴权密码,和所有节点requirepass保持一致
sentinel auth-pass mymaster Redis@2026
# PING超时3000毫秒标记节点主观下线sdown,修改改值为3s
sentinel down-after-milliseconds mymaster 3000
# 故障切换时,并行同步新主库的从节点数量

# 完整故障切换最大超时时间180000毫秒

# 安全限制
sentinel deny-scripts-reconfig yes
sentinel resolve-hostnames no
sentinel announce-hostnames no

# Generated by CONFIG REWRITE
latency-tracking-info-percentiles 50 99 99.9
user default on sanitize-payload #11ac9b0d1980f1c618b15fe515c4c20410c985e59ad2396a5eb594a8ffc9f6c2 ~* &* +@all
sentinel myid 93fa143e11de5f1c22cfeaa571eb83c64582608d
sentinel config-epoch mymaster 0
sentinel leader-epoch mymaster 0
sentinel current-epoch 0

#创建systemd文件
[root@Redis-23:~#] cat /etc/systemd/system/redis-sentinel.service
[Unit]
Description=Redis Sentinel Service
Documentation=https://redis.io/docs/manual/sentinel/
After=network.target

[Service]
Type=forking
# 编译安装的哨兵二进制程序路径
ExecStart=/usr/local/src/redis-8.4.0/src/redis-sentinel /apps/redis/etc/redis-sentinel.conf
# 优雅停止哨兵
ExecStop=/usr/local/src/redis-8.4.0/src/redis-cli -p 26379 -a Redis@2026 shutdown
ExecReload=/bin/kill -USR2
# PID文件,和sentinel.conf内pidfile保持一致
PIDFile=/var/run/redis-sentinel.pid
# 进程异常自动重启
Restart=on-failure
RestartSec=3

# 安全权限限制(生产推荐)
PrivateTmp=true
LimitNOFILE=65535

[Install]
# 开机自启
WantedBy=multi-user.target

#设置开机自启动
[root@Redis-23:~#] systemctl daemon-reload
[root@Redis-23:~#] systemctl enable --now redis-sentinel.service

-----------------------------------------------------------------


#查看masters和slaves
[root@Redis-23:~#] redis-cli -p 26379 -a Redis@2026
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:26379> SENTINEL masters
1)  1) "name"
    2) "mymaster"
    3) "ip"
    4) "10.0.0.23"
    5) "port"
    6) "6379"
    7) "runid"
    8) "2402762d9a94a923aa45b40f2e375613fc2c6e16"
    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) "759"
   19) "last-ping-reply"
   20) "759"
   21) "down-after-milliseconds"
   22) "3000"
   23) "info-refresh"
   24) "7840"
   25) "role-reported"
   26) "master"
   27) "role-reported-time"
   28) "38005"
   29) "config-epoch"
   30) "0"
   31) "num-slaves"
   32) "2"
   33) "num-other-sentinels"
   34) "0"
   35) "quorum"
   36) "2"
   37) "failover-timeout"
   38) "180000"
   39) "parallel-syncs"
   40) "1"
127.0.0.1:26379> SENTINEL slaves mymaster
1)  1) "name"
    2) "10.0.0.29:6379"
    3) "ip"
    4) "10.0.0.29"
    5) "port"
    6) "6379"
    7) "runid"
    8) "5e941303a627f5a53915b5a0687a46698c6e4cdf"
    9) "flags"
   10) "slave"
   11) "link-pending-commands"
   12) "0"
   13) "link-refcount"
   14) "1"
   15) "last-ping-sent"
   16) "0"
   17) "last-ok-ping-reply"
   18) "50"
   19) "last-ping-reply"
   20) "50"
   21) "down-after-milliseconds"
   22) "3000"
   23) "info-refresh"
   24) "6006"
   25) "role-reported"
   26) "slave"
   27) "role-reported-time"
   28) "56327"
   29) "master-link-down-time"
   30) "0"
   31) "master-link-status"
   32) "ok"
   33) "master-host"
   34) "10.0.0.23"
   35) "master-port"
   36) "6379"
   37) "slave-priority"
   38) "100"
   39) "slave-repl-offset"
   40) "801066"
   41) "replica-announced"
   42) "1"
2)  1) "name"
    2) "10.0.0.26:6379"
    3) "ip"
    4) "10.0.0.26"
    5) "port"
    6) "6379"
    7) "runid"
    8) "8c2d7b31f1114678b35655e3247082e4f661a0a5"
    9) "flags"
   10) "slave"
   11) "link-pending-commands"
   12) "0"
   13) "link-refcount"
   14) "1"
   15) "last-ping-sent"
   16) "0"
   17) "last-ok-ping-reply"
   18) "50"
   19) "last-ping-reply"
   20) "50"
   21) "down-after-milliseconds"
   22) "3000"
   23) "info-refresh"
   24) "6007"
   25) "role-reported"
   26) "slave"
   27) "role-reported-time"
   28) "56331"
   29) "master-link-down-time"
   30) "0"
   31) "master-link-status"
   32) "ok"
   33) "master-host"
   34) "10.0.0.23"
   35) "master-port"
   36) "6379"
   37) "slave-priority"
   38) "100"
   39) "slave-repl-offset"
   40) "801066"
   41) "replica-announced"
   42) "1"
127.0.0.1:26379>
-------------------------------------------
#主节点观察哨兵配置文件自动出现的内容
[root@Redis-23:~#] vim /apps/redis/etc/redis-sentinel.conf

# Generated by CONFIG REWRITE
latency-tracking-info-percentiles 50 99 99.9
user default on sanitize-payload #11ac9b0d1980f1c618b15fe515c4c20410c985e59ad2396a5eb594a8ffc9f6c2 ~* &* +@all
sentinel myid 93fa143e11de5f1c22cfeaa571eb83c64582608d
sentinel config-epoch mymaster 0
sentinel leader-epoch mymaster 0
sentinel current-epoch 0

sentinel known-replica mymaster 10.0.0.29 6379

sentinel known-replica mymaster 10.0.0.26 6379


--------------------------------------------

#关闭主节点测试,主是否会自动切换,可以观察到住在29上面
[root@Redis-26:~#] redis-cli -p 26379 -a Redis@2026 SENTINEL masters
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
1)  1) "name"
    2) "mymaster"
    3) "ip"
    4) "10.0.0.29"
    5) "port"
    6) "6379"
    7) "runid"
    8) "4244a9edc681763726a6278e0c4529ce6b982baa"
    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) "865"
   19) "last-ping-reply"
   20) "865"
   21) "down-after-milliseconds"
   22) "3000"
   23) "info-refresh"
   24) "5948"
   25) "role-reported"
   26) "master"
   27) "role-reported-time"
   28) "257866"
   29) "config-epoch"
   30) "1"
   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"
[root@Redis-26:~#]


[root@Redis-26:~#] redis-cli info replication
# Replication
role:slave
master_host:10.0.0.29
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_read_repl_offset:1189771
slave_repl_offset:1189771
replica_full_sync_buffer_size:0
replica_full_sync_buffer_peak:0
master_current_sync_attempts:1
master_total_sync_attempts:1
master_link_up_since_seconds:314
total_disconnect_time_sec:132
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:49ab840d2dd7a3d5791d45ca268c9aa54af4a0ad
master_replid2:e8eb09f208d86b1bac9663f49d766a8c2cefd077
master_repl_offset:1189771
second_repl_offset:1128037
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:828392
repl_backlog_histlen:361380



[root@Redis-29:~#] redis-cli -p 26379 -a Redis@2026 SENTINEL slaves mymaster
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
1)  1) "name"
    2) "10.0.0.26:6379"
    3) "ip"
    4) "10.0.0.26"
    5) "port"
    6) "6379"
    7) "runid"
    8) "8c2d7b31f1114678b35655e3247082e4f661a0a5"
    9) "flags"
   10) "slave"
   11) "link-pending-commands"
   12) "0"
   13) "link-refcount"
   14) "1"
   15) "last-ping-sent"
   16) "0"
   17) "last-ok-ping-reply"
   18) "592"
   19) "last-ping-reply"
   20) "592"
   21) "down-after-milliseconds"
   22) "3000"
   23) "info-refresh"
   24) "9984"
   25) "role-reported"
   26) "slave"
   27) "role-reported-time"
   28) "351381"
   29) "master-link-down-time"
   30) "0"
   31) "master-link-status"
   32) "ok"
   33) "master-host"
   34) "10.0.0.29"
   35) "master-port"
   36) "6379"
   37) "slave-priority"
   38) "100"
   39) "slave-repl-offset"
   40) "1195091"
   41) "replica-announced"
   42) "1"
2)  1) "name"
    2) "10.0.0.23:6379"
    3) "ip"
    4) "10.0.0.23"
    5) "port"
    6) "6379"
    7) "runid"
    8) ""
    9) "flags"
   10) "s_down,slave,disconnected"
   11) "link-pending-commands"
   12) "3"
   13) "link-refcount"
   14) "1"
   15) "last-ping-sent"
   16) "351381"
   17) "last-ok-ping-reply"
   18) "351381"
   19) "last-ping-reply"
   20) "351381"
   21) "s-down-time"
   22) "348346"
   23) "down-after-milliseconds"
   24) "3000"
   25) "info-refresh"
   26) "0"
   27) "role-reported"
   28) "slave"
   29) "role-reported-time"
   30) "351381"
   31) "master-link-down-time"
   32) "0"
   33) "master-link-status"
   34) "err"
   35) "master-host"
   36) "?"
   37) "master-port"
   38) "0"
   39) "slave-priority"
   40) "100"
   41) "slave-repl-offset"
   42) "0"
   43) "replica-announced"
   44) "1"
[root@Redis-29:~#]

3.6、Redis Cluster核心知识点

bash 复制代码
Redis Cluster 采用哈希槽分片 + Gossip 协议 + 主从复制 + 过半投票故障转移实现分布式高可用;总共 16384 槽,key 通过 CRC16 取模分配槽;节点间 Gossip 同步集群状态;主观下线 PFAIL,过半 master 确认后客观下线 FAIL;slave 选举新 master 接管槽;去中心化,无中心代理;异步复制,最终一致性,不支持跨槽多 key 操作;生产推荐 3 主 3 从,主从跨物理机部署防止单点机房故障。

四、Redis 大 Key 治理与缓存问题处理

4.1、什么是大key和测试

bash 复制代码
1. String 类型:单键内存 ≥ 100KB 判定为大 Key;

2. List/Set 集合:元素数量 ≥ 10000 条 判定为大 Key;

3. Hash/ZSet:字段 / 有序成员 ≥ 5000 条 判定为大Key;

4. 内存兜底标准:任意类型键内存占用超过 512KB,统一纳入大 Key 治理清单。
bash 复制代码
1. 大key的判断原由
    String:单键内存 ≥100KB 判定大 Key 
原理:单条 100KB 字符串单次传输会占用大量网卡带宽,批量读取极易造成接口超时;RDB 
fork、内存淘汰时开销明显;
边界兜底:第 4 条 512KB 兜底规则做双重防护,即使少量 String 不到 100KB 但膨胀到 512KB 依
然纳入治理,无漏洞。

    List/Set:元素 ≥10000 条判定大 Key 
List:一次性 LRANGE 全量读取万条数据会阻塞主线程、耗带宽;删除 / 裁剪同步遍历阻塞;
Set:SMEMBERS、差集 / 交集运算遍历全部元素,万级集合 CPU 消耗陡增;
生产通用阈值就是 8000~10000,取 10000 作为红线完全合理。

    Hash/ZSet:字段 / 成员 ≥5000 条判定大 Key 
Hash:HGETALL、HKEYS 会遍历所有字段,5000 字段以上查询耗时明显;
ZSet:排序、范围查询、排名计算时间复杂度 O (logN+M),5000 成员后延迟肉眼可见;
Hash/ZSet 底层结构比 List 复杂,阈值设得更低,区分了结构性能差异,逻辑严谨。兜底规则:任意键内存>512KB 全部治理

    解决两类遗漏场景:
短元素极多的集合:比如每条仅 10 字节,6000 条 Hash 仅 60KB,不触发条数阈值,但后期膨胀
到 512KB;
特殊编码结构、二进制数据、压缩字符串,条数不超标但内存超标;
双重校验(条数 + 内存)避免漏判,是成熟生产规范。


查询命令
# 1. 查看String内存
MEMORY USAGE big:string:profile
# 2. 统计Hash字段数量
HLEN big:hash:order
# 3. 统计List长度
LLEN big:list:msg
# 4. 全节点批量扫描大key
redis-cli -h 10.0.0.13 -p 6379 -a Redis@2026 --bigkeys
----------------------

#主库测试大kes
[root@Redis-26:~#] redis-cli role
1) "master"
2) (integer) 2296561
3) 1) 1) "10.0.0.29"
      2) "6379"
      3) "2296561"

[root@Redis-26:~#]  redis-cli EXPIRE big:string:userprofile 86400
(integer) 1
[root@Redis-26:~#]  redis-cli EVAL "for i=1,6000 do redis.call('HSET',KEYS[1],'field_'..i,'value_data') end" 1 big:hash:orderlist
(nil)
[root@Redis-26:~#] redis-cli EVAL "for i=1,12000 do redis.call('LPUSH',KEYS[1],'msg_'..i) end" 1 big:list:message
(nil)
[root@Redis-26:~#]  redis-cli EVAL "for i=1,8000 do redis.call('ZADD',KEYS[1],i,'rank_'..i) end" 1 big:zset:hotrank
(nil)
[root@Redis-26:~#]  redis-cli STRLEN big:string:userprofile
(integer) 0
[root@Redis-26:~#] redis-cli printf 'a%.0s' {1..10000} | redis-cli -x SET big:string:userprofile
OK
[root@Redis-26:~#] redis-cli STRLEN big:string:userprofile
(integer) 187
[root@Redis-26:~#] redis-cli HLEN big:hash:orderlist
(integer) 6000
[root@Redis-26:~#] redis-cli LLEN big:list:message
(integer) 12000
[root@Redis-26:~#] redis-cli ZCARD big:zset:hotrank
(integer) 8000
[root@Redis-26:~#]  redis-cli --bigkeys

# Scanning the entire keyspace to find biggest keys as well as
# average sizes per key type.  You can use -i 0.1 to sleep 0.1 sec
# per 100 SCAN commands (not usually needed).

100.00% ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Keys sampled: 20013

-------- summary -------

Total key length in bytes is 189026 (avg len 9.45)

Biggest   list found "big:list:message" has 12000 items
Biggest   hash found "big:hash:orderlist" has 6000 fields
Biggest string found "big:string:userprofile" has 187 bytes
Biggest   zset found "big:zset:hotrank" has 8000 members

2 lists with 12003 items (00.01% of keys, avg size 6001.50)
2 hashs with 6003 fields (00.01% of keys, avg size 3001.50)
0 streams with 0 entries (00.00% of keys, avg size 0.00)
20008 strings with 89126 bytes (99.98% of keys, avg size 4.45)
0 sets with 0 members (00.00% of keys, avg size 0.00)
1 zsets with 8000 members (00.00% of keys, avg size 8000.00)

4.2、大kes的危害:fork 耗时、网络延迟、内存不均衡

bash 复制代码
1. RDB/AOF 持久化 fork COW 阻塞
Redis 做 RDB 持久化时会调用 fork() 创建子进程,fork 本身仅拷贝页表、耗时极短;
但系统采用写时复制 (COW) 机制:fork 之后主进程如果修改几十 MB/GB 级大 Key,内核需要完整复制该内存页,产生大量内存拷贝开销,主线程被阻塞,所有 Redis 读写请求全部卡死,引发服务不可用。

2. 网络 IO 延迟,接口超时、连接断开
客户端读取大 Key 时,Redis 需要一次性将全部数据通过网络传输:单 key 几十 MB 数据会占用大量带宽;
传输时间拉长,前端业务接口响应超时,大量请求堆积;
若返回数据超出 client-output-buffer-limit 客户端缓冲区阈值,Redis 会强制断开 TCP 连接,业务直接报连接异常。

3. 集群内存分片不均衡
Redis Cluster 按 slot 分片存储 key,大 key 整体只存于单一主节点:
1. 该节点内存占用远高于其他分片,内存资源分配失衡;
2. 内存高负载节点更容易触发 swap、OOM 宕机;
3. 集群扩容、槽位迁移时,大 key 迁移为同步阻塞流程,迁移速度极慢,扩容缩容耗时暴增,迁移期间对应 slot 分片业务完全不可读写。

4. 删除阻塞风险
使用 DEL 删除Hash/List/ZSet/Set 超大集合类大 Key 时,Redis 主线程同步循环遍历、释放全部元素内存,会造成长时间主线程阻塞,业务读写全部卡住;
普通 String 类型大 Key 执行 DEL 仅释放单块内存,阻塞影响极小。

拆分

bash 复制代码
拆分统一执行标准(生产强制规范)
1. String 类型:单键内存上限 50KB,超过则按业务维度垂直拆分;
2. Hash 类型:单个 Hash 字段上限 1000 个,超出则水平分片;
3. List/Set:单集合元素上限 5000 条;
4. ZSet:单有序集合成员上限 3000 个;
5. 拆分收益:规避大 Key 网络传输、fork 阻塞、集群内存不均、DEL 同步阻塞四大风险。
String 大 Key 垂直拆分(维度拆分)
业务场景:原始键 user:info:1001 ,存储完整用户 JSON, MEMORY USAGE 检测为 224KB,属于超标
大 String。

压缩

bash 复制代码
数据压缩降低内存体积
1. 文本 JSON 数据使用 Gzip 压缩后存入 String,读取后客户端解压;
2. 整数列表采用 Redis Listpack 紧凑编码,避免冗余存储;
3. 业务层精简无用字段,从源头减少 key 体积。
4. 优化后必须用 MEMORY USAGE 、 OBJECT ENCODING 验证内存与编码效果。

异步删除

bash 复制代码
异步删除 UNLINK 替代 DEL
1. DEL 同步删除:主线程同步释放内存,超大集合直接阻塞;
2. UNLINK 异步删除:仅在主线程移除 key 元数据,内存释放交给后台子线程异步执行,无阻塞;

UNLINK big_hash_key        #推荐

DEL big_hash_key            #不推荐

4.4 、Redis 内存治理

maxmemory 配置(物理内存 70%-80% 预留原则)

bash 复制代码
作用
maxmemory 限制 Redis 实例最大可用内存,内存达到阈值后,触发淘汰策略清理 key,防止 Redis 占满
整机内存导致系统 OOM、服务被 kill。
配置规范(运维初学者标准)
1 推荐阈值:整机物理内存的 70%~80%
2 预留 20%~30% 空闲内存,专门给持久化 fork 、缓冲区、副本复制使用;
3 配置示例(redis.conf)
    # 机器总内存16G,设置maxmemory为12G(75%)
    maxmemory 12gb

maxmemory-policy 淘汰策略详解(LRU/LFU/volatile 系列)

bash 复制代码
内存打满后,Redis 按照该策略自动清理 Key,一共 7 种策略,分 3 类通俗讲解

前置基础名词
    LRU:淘汰最长时间没有被访问的数据
    LFU:淘汰访问次数最少的数据
分类 0:高危禁用策略(Redis 默认值 noeviction )
内存达到上限不删除任何 Key,所有写入命令直接报错 OOM;
仅本地测试、纯只读配置库可用,线上缓存业务禁止配置。

分类 1:只淘汰带过期 TTL 的 key(volatile 开头)
volatile-lru (线上最常用): 只在设置了过期时间的 key 里,淘汰最久没访问的数据;
适用:混合业务(永久配置 key + 短期缓存 key 共存),不会删掉永不过期的热点配置。
volatile-lfu : 过期 key 里淘汰访问次数最少的数据;
适用:热点区分明显,想保留高频访问缓存。
volatile-random : 过期 key 里随机删,几乎不推荐,无法优先保热点。
volatile-ttl : 过期 key 里优先删剩余存活时间最短的。
适用:批量同步缓存、统一过期业务,优先清理马上失效的缓存。

分类 2:全部 key 都参与淘汰(allkeys 开头,包含永不过期 key)
allkeys-lru : 所有 key(含永久 key)淘汰最久未访问数据;
适用:全业务都是短期缓存,无永久配置类数据。
allkeys-lfu : 所有 key 淘汰访问频次最低的,缓存热点区分极强场景。
适用:热点区分极强、长期稳定访问的缓存业务。
新手选型建议
绝大多数业务选: volatile-lru ;
纯临时缓存、无永久配置数据: allkeys-lru ;
生产禁止: noeviction 、 volatile-random 。

持久化 fork 场景的内存预留优化

bash 复制代码
核心原理
执行 RDB 持久化时,Redis 调用 fork() 生成独立子进程做备份:
操作系统采用写时复制 COW机制:子进程刚创建时和父进程共享全部内存;
父进程有新增 /修改数据时,被改动的内存页才会复制一份,内存占用上涨。
如果 maxmemory 设置过高,整机无空闲内存, fork 创建子进程直接失败,RDB 持久化中断,日志报
错。
运维优化方案
    1. 内存上限规范:maxmemory 限制为整机物理内存70%~80%,预留 20%~30% 空闲内存应对内存页复制;
    2. 超大实例(32G/64G 内存):下调至 70%,减少 fork 内存溢出风险;
    3. 错峰持久化:RDB 定时备份放在凌晨业务低峰,减少业务写操作带来的内存拷贝;
    4. RDB+AOF 混合持久化调优:
aof 刷盘策略改为 appendfsync everysec (每秒刷盘),平衡磁盘 IO 与父进程内存修改频
率;禁止 always 高频刷盘;
大集群备份方案:在从节点执行 RDB 备份,主节点完全不触发 fork,无内存压力;
    5. 监控告警:定时采集 INFO persistence ,监控 rdb_last_bgsave_status ,一旦出现 RDB 失败立即告警;fork 报错时调低 maxmemory 或扩容机器内存。

Linux学习之旅只NFS分布式共享存储

一、NFS基础

1.1、存储类型

1.1.1、DAS直连存储
bash 复制代码
直连在服务器本地的存储,磁盘 / 存储设备直接接服务器,不通过网络。
连接方式:SATA、SAS、SCSI、USB、PCIe、HBA 卡直连
特点:
    服务器独占,别的服务器不能直接访问这块存储
    架构最简单,速度快,延迟低
    无共享能力,多服务器无法同时读写同一份数据
例子:服务器本地硬盘、外接硬盘柜、SSD 盘阵直接插服务器 HBA 卡
1.1.2、SAN存储区域网络
bash 复制代码
专门的存储专网,块存储,给服务器提供裸磁盘块。
连接协议:FC 光纤通道(主流)、iSCSI(IP SAN)
访问形态:服务器识别到的是一块裸磁盘(块设备),需要服务器自己格式化、建文件系统
特点:
    独立存储网络,和业务网络分开
    多台服务器可以连接同一套存储,可做集群、数据库、虚拟化
    高性能、低延迟,适合数据库、VMware 虚拟化、Oracle RAC
分类
    FC-SAN:光纤交换机 + HBA 卡,性能高,成本贵
    IP-SAN(iSCSI):走普通以太网,成本更低
1.1.3、NAS网络附加存储
bash 复制代码
走业务以太网,文件存储,对外直接共享文件夹。
协议:NFS(Linux)、SMB/CIFS(Windows)
访问形态:客户端 / 服务器直接访问共享目录,NAS 本身管理文件系统
特点:
    使用普通局域网,不用单独存储交换机
    多台电脑 / 服务器同时访问共享文件
    部署简单,适合文件共享、文档、备份、图片视频存储
    性能一般弱于 SAN,不适合高 IO 数据库
1.1.4、对比表
项目 DAS SAN NAS
存储类型 块存储 块存储 文件存储
访问对象 单台服务器独占 多服务器识别裸盘 多客户端访问共享文件
网络 无独立存储网络,直连 独立存储专网 (FC/iSCSI) 普通以太网
文件系统 服务器本地 服务器端管理 FS NAS 设备自带文件系统
典型协议 SATA/SAS/PCIe FC、iSCSI SMB、NFS
适用场景 单机应用、本地扩容 数据库、虚拟化、RAC 文件共享、备份、非结构化数据

1.2、存储方式

1.2.1、块存储
bash 复制代码
最小单元:块(Block),类似硬盘扇区,固定大小的数据块(通常 512B/4KB)
对外表现:给主机提供裸磁盘,操作系统识别成一块硬盘
文件系统:由客户端(服务器 OS)管理,存储设备只负责存块,不懂文件、目录、权限
协议:FC、iSCSI、Ceph RBD、本地 SAS/SATA 盘
优点:低延迟,支持随机读写,可格式化、建分区,适合数据库、虚拟化
缺点:元数据少,不适合海量非结构化文件;多机共享需要集群锁(如 RAC)
典型产品:SAN 存储、云盘(阿里云 ECS 云盘)、DAS 本地盘
1.2.2、文件存储
bash 复制代码
最小单元:文件 + 目录树,有文件夹、文件名、权限
对外表现:共享目录,客户端直接挂载文件夹,不用格式化磁盘
文件系统:存储设备本身管理文件系统
协议:NFS (Linux)、SMB/CIFS (Windows)
优点:多主机同时共享访问,自带目录权限,部署简单
缺点:海量小文件场景,目录检索慢;高随机 IO 性能弱于块存储
典型产品:传统 NAS、CephFS、OceanStor 文件存储
1.2.3、对象存储
bash 复制代码
最小单元:对象 (Object) = 数据内容 + 唯一对象 ID + 元数据(标签、大小、创建时间)
没有目录树(兼容模拟目录只是前缀),没有分区、没有文件系统
访问方式:RESTful HTTP API,通过唯一 Key 访问,不挂载磁盘
特点:扁平命名空间,无限扩容,天然多副本,适合海量非结构化数据;不支持随机修改文件中间某一段,只能整体上传 / 覆盖
优点:成本低,横向无限扩展,适合图片、视频、日志、备份、静态资源
缺点:延迟偏高,不支持传统文件读写 API,不适合数据库、虚拟机系统盘
典型产品:S3、阿里云 OSS、腾讯 COS、MinIO
1.2.4、分布式存储
bash 复制代码
把多台普通服务器的本地磁盘,组成一个大存储池,统一对外提供存储服务。
分布式存储可以对外提供:分布式块、分布式文件、分布式对象三种接口。
核心原理:数据分片 / 分块,打散存到多个节点,多副本保证高可用;无单点,横向扩容(加服务器就扩容量)
代表产品:Ceph(同时支持 RBD 块、CephFS 文件、RGW 对象)、MinIO(分布式对象)、OceanStor 分布式存储
对比传统集中式存储(SAN/NAS 整机):
    集中式:机头 + 磁盘框,机头是单点(双控冗余),扩容上限有限
    分布式:多节点,无集中机头,可横向扩到上千节点
1.2.5、对比表
类型 访问形态 文件系统在哪 访问接口 典型场景
块存储 裸磁盘 客户端操作系统 iSCSI/FC/RBD 虚拟机、数据库、Oracle RAC
文件存储 共享文件夹 存储端 NFS/SMB 文档共享、日志、HPC 集群
对象存储 对象,HTTP 访问 存储内置对象元数据 REST(S3 API) 图片视频、备份归档、静态资源
分布式存储 架构概念 看对外提供的接口 可同时支持块 / 文件 / 对象 海量存储、云平台、超融合

1.3、NFS特点和工作原理

1.3.1、NFS特点
bash 复制代码
1 基于TCP/IP传输:
 NFS通过网络文件系统协议,允许远程计算机像访问本地文件一样访问和操作远程文件,从而方便了多台计算机之间的文件共享和协作。

2 跨平台性:
 NFS被广泛用于UNIX和Linux操作系统中,同时也可以支持在不同类型的系统之间通过网络进行文件共享,如FreeBSD、SCO、Solaris等异构操作系统平台。

3 简单易操作:
 NFS提供了透明文件访问以及文件传输的功能,容易扩充新的资源或软件,而不需要改变现有的工作环境。

4 安全性:
 NFS的安全性相对较低,因为它主要基于IP进行认证,且默认配置下对远程访问的用户(如root用户)会进行权限压缩(如映射为nfsnobody用户),以提高系统的安全性。但这也意味着需要额外的安全措施来确保数据的安全。
1.3.2、工作原理
bash 复制代码
┌───────────客户端──────────┐
│ mount命令                 │
│ 1.连接rpcbind:111         │
│ 2.获取mountd端口          │
│ 3.连接mountd拿到文件句柄  │
│ 4.使用句柄访问nfsd:2049   │
└───────────┬───────────────┘
            │
            ▼
┌────────────────────────────服务端────────────────────────────┐
│ rpcbind(111) ←注册端口→ mountd ←授权返回句柄→ nfsd(2049)     │
│                               ↓                              │
│                           本地磁盘/文件系统                   │
└───────────────────────────────────────────────────────────────┘

二、NFS实践

2.1、环境部署

bash 复制代码
[root@Mysql-13:~#] apt update

[root@Mysql-13:~#] apt install -y nfs-kernel-server

[root@Mysql-13:~#] apt install nfs-common

[root@Mysql-13:~#] dpkg -l rpcbind
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name           Version        Architecture Description
+++-==============-==============-============-=======================================>
ii  rpcbind        1.2.6-7ubuntu2 amd64        converts RPC program numbers into unive>
lines 1-6/6 (END)
[root@Mysql-13:~#]
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name           Version        Architecture Description
+++-==============-==============-============-=======================================>
ii  rpcbind        1.2.6-7ubuntu2 amd64        converts RPC program 


[root@Mysql-13:~#] netstat -tnlp | grep rpc
tcp        0      0 0.0.0.0:42583           0.0.0.0:*               LISTEN      6178/rpc.mountd
tcp        0      0 0.0.0.0:60351           0.0.0.0:*               LISTEN      6178/rpc.mountd
tcp        0      0 0.0.0.0:45563           0.0.0.0:*               LISTEN      6171/rpc.statd
tcp        0      0 0.0.0.0:37167           0.0.0.0:*               LISTEN      6178/rpc.mountd
tcp6       0      0 :::48801                :::*                    LISTEN      6178/rpc.mountd
tcp6       0      0 :::56215                :::*                    LISTEN      6178/rpc.mountd
tcp6       0      0 :::51629                :::*                    LISTEN      6178/rpc.mountd
tcp6       0      0 :::42333                :::*                    LISTEN      6171/rpc.statd
[root@Mysql-13:~#]

#进程解读
    rpcbind(也称为portmapper)是RPC服务的核心组件,它监听TCP和UDP的111端口,用于将RPC程序编号转换为网络地址和端口号。当客户端想要调用远程RPC服务时,它会首先联系rpcbind来获取服务的实际位置。在您的系统中,rpcbind正在正常运行,监听111端口。
    rpc.statd是NFS(网络文件系统)状态监视守护进程的一部分,它用于跟踪NFS客户端和服务器之间的挂载状态,并维护锁和状态信息。虽然它通常不直接监听外部网络(在这里监听的是127.0.0.1,即本地回环地址),但它对于NFS服务的正常运行至关重要。
    rpc.mountd是NFS挂载守护进程,它处理来自NFS客户端的挂载请求。rpc.mountd似乎正在监听随机的、高编号的UDP端口58332。这是正常的,因为NFS的rpc.mountd服务可以配置为监听动态分配的端口,以增加安全性。客户端在尝试挂载NFS文件系统时,会首先联系rpcbind来获取rpc.mountd的实际端口号。

2.2、基础命令

2.2.1、exportfs
bash 复制代码
exportfs 命令用于管理本机 NFS 文件系统,默认配置文件是 /etc/exports
[root@Mysql-13:~#] cat /etc/exports
# /etc/exports: the access control list for filesystems which may be exported
#               to NFS clients.  See exports(5).
#
# Example for NFSv2 and NFSv3:
# /srv/homes       hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check)
#
# Example for NFSv4:
# /srv/nfs4        gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check)
# /srv/nfs4/homes  gss/krb5i(rw,sync,no_subtree_check)
#

命令格式
 exportfs [-adfhioruvs] [host:/path]
常用选项
    -a #全部挂载或者全部卸载
    -r #重新挂载
    -u #卸载
    -v #显示本机共享

#修改配置文件后,加载配置
[root@Mysql-13:~#] exportfs -r

#查看加载配置的效果
[root@Mysql-13:~#] exportfs -v

#卸载操作
[root@Mysql-13:~#] exportfs -au
2.2.2、showmount
bash 复制代码
shoumount 可以查看远程主机的共享设置

命令格式
 showmount [ -opt... ] [ host ]
常用选项
    -h|--help #显示帮助
    -a|--all #显示己连接的客户端
    -e|--exports #显示指定NFS服务器上的配置列表

#客户端,查看远程共享服务主机
[root@Mysql-13:~#] showmount -e 10.0.0.13
Export list for 10.0.0.13:

2.3、共享实践

2.3.1、共享配置
bash 复制代码
[root@Mysql-13:~#] mkdir /data/dir{a,b}
[root@Mysql-13:~#] cp /etc/fstab /data/dira/
[root@Mysql-13:~#] echo '/data/dira *' >> /etc/exports
[root@Mysql-13:~#] tail -1 /etc/exports
/data/dira *
[root@Mysql-13:~#] exportfs -r

[root@Mysql-13:~#] exportfs -v
/data/dira      <world>(sync,wdelay,hide,no_subtree_check,sec=sys,ro,secure,root_squash,no_all_squash)

[root@Mysql-13:~#] showmount -e 10.0.0.13
Export list for 10.0.0.13:
/data/dira *
2.3.2、共享挂载
bash 复制代码
[root@Mysql-13:~#] mkdir -pv /data/dir{1,2}
mkdir: created directory '/data/dir1'
mkdir: created directory '/data/dir2'
[root@Mysql-13:~#] mount 10.0.0.13:/data/dira /data/dir1

[root@Mysql-13:~#] mount | grep dira
10.0.0.13:/data/dira on /data/dir1 type nfs4 (rw,relatime,vers=4.2,rsize=262144,wsize=262144,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=10.0.0.13,local_lock=none,addr=10.0.0.13)
[root@Mysql-13:~#]

[root@Mysql-13:~#] df -h /data/dir1/
Filesystem            Size  Used Avail Use% Mounted on
10.0.0.13:/data/dira   47G  5.9G   39G  14% /data/dir1
[root@Mysql-13:~#] ls /data/dir1/ -l
total 4
-rw-r--r-- 1 root root 657 Sep 20 02:09 fstab

#当前没有写权限
[root@Mysql-13:~#] echo "123abc" >> /data/dir1/fstab
-bash: /data/dir1/fstab: Read-only file system
[root@Mysql-13:~#] touch /data/dir1/test.txt
touch: cannot touch '/data/dir1/test.txt': Read-only file system


[root@Mysql-13:~#] vim /etc/exports
[root@Mysql-13:~#] tail -1 /etc/exports
/data/dira 10.0.0.13(rw)
[root@Mysql-13:~#] exportfs -r
exportfs: /etc/exports [1]: Neither 'subtree_check' or 'no_subtree_check' specified for export "10.0.0.13:/data/dira".
  Assuming default behaviour ('no_subtree_check').
  NOTE: this default has changed since nfs-utils version 1.0.x

[root@Mysql-13:~#] touch /data/dir1/text.txt
touch: cannot touch '/data/dir1/text.txt': Permission denied

#上面添加写权限我为什么还是不行,因为共享的目录其他人没有这个写权限
[root@Mysql-13:~#] ll -d /data/dira/
drwxr-xr-x 2 root root 4096 Sep 20 02:09 /data/dira//

#添加其他人权限并测试
[root@Mysql-13:~#] chmod o+w /data/dira/
[root@Mysql-13:~#] touch /data/dir1/text
[root@Mysql-13:~#] ls /data/dir1/
fstab  text
[root@Mysql-13:~#]

2.4、NFSv4进阶

2.4.1、NFSv3和NFSv4对比
对比项 NFSv3 NFSv4
RPC/rpcbind ✅ 需要,依赖 rpcbind (111 端口)、mountd、lockd、statd ❌ 不需要 rpcbind/mountd,全部功能内置协议
端口 主服务 2049;mountd/lockd 随机端口,防火墙难配置 TCP 2049 单端口,防火墙简单,支持跨网段
协议状态 无状态协议 服务端不保存客户端连接状态;服务重启,挂载不用重连 有状态协议 服务端维护客户端会话、文件锁状态
文件锁 依赖独立 lockd+statd 服务,锁容易异常、宕机难释放 协议原生内置文件锁,锁机制更稳定
挂载流程 客户端先连 rpcbind 查 mountd 端口 → mountd 校验返回文件句柄 → nfsd 读写 直接 TCP 2049 连接,协议内完成挂载授权,没有独立 mount 阶段
传输协议 支持 TCP、UDP 只支持 TCP
showmount 命令 可用,依赖 rpcbind,用来查询共享目录 不推荐用 showmount(v4 不需要 rpcbind,经常查询失败)
权限模型 UID/GID 映射;不支持原生 ACL 支持 NFSv4 ACL,权限更丰富
pNFS 并行读写 不支持 v4.1 新增 pNFS,分布式存储多节点并行 IO,大文件性能提升
一致性 close-to-open 一致性 关闭文件才同步,多客户端并发写容易覆盖 增强锁机制,但多机同文件并发写仍需业务层控制
跨广域网 差,端口多,容易被防火墙阻断 优秀,单 2049 端口,适合跨机房
海量小文件 元数据压力大 优化更好,v4.2 支持稀疏文件、server-side-copy
适用场景 局域网传统 NAS,老业务,需要 showmount 查询共享 云环境、跨网段、K8s、分布式存储、pNFS 场景
2.4.2、NFSv4目录标准
bash 复制代码
NFSv4 要求统一根共享目录【关键!!!】,不能直接共享 /data/dira 、 /data/dirb ,需要做绑定挂载:
2.4.3、NFSv4实践
bash 复制代码
[root@Mysql-13:~#] mkdir /nfs4sshare
[root@Mysql-13:~#] mv /nfs4sshare /nfs4share
[root@Mysql-13:~#] mkdir -p /nfs4share/dira /nfs4share/dirb
[root@Mysql-13:~#] tree /nfs4share/
/nfs4share/
├── dira
└── dirb
[root@Mysql-13:~#] vim /etc/fstab
[root@Mysql-13:~#] tail -2 /etc/fstab
/data/dira   /nfs4share/dira   none   bind   0 0
/data/dirb   /nfs4share/dirb   none   bind   0 0
[root@Mysql-13:~#] mount -a
mount: (hint) your fstab has been modified, but systemd still uses
       the old version; use 'systemctl daemon-reload' to reload.
[root@Mysql-13:~#] systemctl daemon-reload
[root@Mysql-13:~#] mount | grep nfs
nfsd on /proc/fs/nfsd type nfsd (rw,relatime)
/dev/mapper/ubuntu--vg-ubuntu--lv on /nfs4share/dira type ext4 (rw,relatime)
/dev/mapper/ubuntu--vg-ubuntu--lv on /nfs4share/dirb type ext4 (rw,relatime)
[root@Mysql-13:~#] tree /nfs4share/
/nfs4share/
├── dira
└── dirb

3 directories, 0 files
[root@Mysql-13:~#] vim /etc/exports
[root@Mysql-13:~#] tail -1 /etc/exports
/nfs4share 10.0.0.0/24(rw)


[root@Mysql-13:~#] vim /etc/nfs.conf
[root@Mysql-13:~#] systemctl restart nfs-server.service
[root@Mysql-13:~#] cat /etc/nfs.conf

[nfsd]
# debug=0
# threads=8
# host=
# port=0
# grace-time=90
# lease-time=90
# udp=n
# tcp=y
# vers3=y
vers4=y
vers4.0=y
vers4.1=y
vers4.2=y
# rdma=n
# rdma-port=20049

[root@Mysql-13:~#]


--------------------------------------------
[root@Mysql-16:~#] nc -zv 10.0.0.13 2049
Connection to 10.0.0.13 2049 port [tcp/nfs] succeeded!
[root@Mysql-16:~#] showmount -e 10.0.0.13
Export list for 10.0.0.13:
/nfs4share 10.0.0.0/24
[root@Mysql-16:~#] mkdir /mnt/client_dir{a,b}
[root@Mysql-16:~#] tree /mnt/
/mnt/
├── client_dira
└── client_dirb

3 directories, 0 files
[root@Mysql-16:~#] mount 10.0.0.13:/dira /mnt/client_dira
[root@Mysql-16:~#] mount 10.0.0.13:/dirb /mnt/client_dirb
[root@Mysql-16:~#] mount | grep nfs
10.0.0.13:/dira on /mnt/client_dira type nfs4 (rw,relatime,vers=4.2,rsize=262144,wsize=262144,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=10.0.0.16,local_lock=none,addr=10.0.0.13)
10.0.0.13:/dirb on /mnt/client_dirb type nfs4 (rw,relatime,vers=4.2,rsize=262144,wsize=262144,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=10.0.0.16,local_lock=none,addr=10.0.0.13)
[root@Mysql-16:~#]

三、NFS综合实验

3.1、java环境准备

bash 复制代码
[root@Mysql-13:~#] apt install openjdk-17-jdk -y

[root@Mysql-13:~#] java -version
[root@Mysql-13:~#] echo "export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64" >> ~/.bashrc

[root@Mysql-13:~#] source .bashrc

[root@Mysql-13:~#] echo $JAVA_HOME
/usr/lib/jvm/java-17-openjdk-amd64

[root@Mysql-13:~#]

3.2、MYSQL环境准备

bash 复制代码
[root@Mysql-13:~#] apt install mysql-server -y
[root@Mysql-13:~#] netstat -tnlp | grep mysql
tcp6       0      0 :::3306                 :::*                    LISTEN      4258/mysqld
tcp6       0      0 :::33060                :::*                    LISTEN      4258/mysqld
[root@Mysql-13:~#]mysql

mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'Xyx@1234';
Query OK, 0 rows affected (0.07 sec)

mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE DATABASE ry_vue DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
Query OK, 1 row affected (0.06 sec)

mysql> CREATE USER 'ruoyi'@'%' IDENTIFIED BY 'Ruoyi@123';
Query OK, 0 rows affected (0.17 sec)

mysql> GRANT ALL ON ry_vue.* TO 'ruoyi'@'%';
Query OK, 0 rows affected (0.01 sec)

mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.01 sec)

mysql> exit
Bye
[root@MySql-19:~#] vim /etc/mysql/mysql.conf.d/mysqld.cnf
[root@MySql-19:~#] tail -2 /etc/mysql/mysql.conf.d/mysqld.cnf
bind-address = 10.0.0.19
mysqlx-bind-address = 10.0.0.19
[root@MySql-19:~#] systemctl restart mysql.service

3.3、redis环境准备

bash 复制代码
[root@Redis-26:~#] apt install redis-server -y
#修改redis密码
[root@Redis-26:~#] grep -E "^requirepass|Redis@2026|protected-mode yes" /etc/redis/redis-6379.conf
protected-mode yes
masterauth "Redis@2026"
requirepass "Redis@2026"
[root@Redis-26:~#]

3.4、NFS准备

bash 复制代码
[root@Redis-26:~#] apt install -y nfs-kernel-server nfs-common

[root@Redis-26:~#] systemctl status nfs-server.service
● nfs-server.service - NFS server and services
     Loaded: loaded (/usr/lib/systemd/system/nfs-server.service; enabled; preset: enabled)
     Active: active (exited) since Sun 2026-09-20 06:06:13 UTC; 35s ago
   Main PID: 2571 (code=exited, status=0/SUCCESS)
        CPU: 57ms

Sep 20 06:06:13 Redis-26 systemd[1]: Starting nfs-server.service - NFS server and services...
Sep 20 06:06:13 Redis-26 exportfs[2570]: exportfs: can't open /etc/exports for reading
Sep 20 06:06:13 Redis-26 systemd[1]: Finished nfs-server.service - NFS server and services.
[root@Redis-26:~#]

[root@Redis-26:~#]  mkdir -p /nfs/ruoyi_web /nfs/ruoyi_uploadPath
[root@Redis-26:~#]  chmod 777 /nfs/ruoyi_web /nfs/ruoyi_uploadPath
[root@Redis-26:~#]  chown nobody:nogroup /nfs/ruoyi_web
[root@Redis-26:~#]  vim /etc/exports
[root@Redis-26:~#] tail -2 nfs-server.service
tail: cannot open 'nfs-server.service' for reading: No such file or directory
[root@Redis-26:~#] tail -2 /etc/exports
/nfs/ruoyi_web        10.0.0.0/24(rw,sync,no_subtree_check,no_root_squash)
/nfs/ruoyi_uploadPath 10.0.0.0/24(rw,sync,no_subtree_check,no_root_squash)


[root@Redis-26:~#] showmount -e 10.0.0.26
Export list for 10.0.0.26:
/nfs/ruoyi_uploadPath 10.0.0.0/24
/nfs/ruoyi_web        10.0.0.0/24

3.5、部署Webu依赖环境

bash 复制代码
[root@Mysql-13:~#] apt install maven -y

[root@Mysql-13:~#] mvn -v
Apache Maven 3.8.7
Maven home: /usr/share/maven
Java version: 17.0.20, vendor: Ubuntu, runtime: /usr/lib/jvm/java-17-openjdk-amd64
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "6.8.0-139-generic", arch: "amd64", family: "unix"
[root@Mysql-13:~#]  mkdir -p ~/.m2
[root@Mysql-13:~#] cat > ~/.m2/settings.xml <<-eof
<?xml version="1.0" encoding="UTF-8"?>
<settings>
  <mirrors>
    <mirror>
      <id>aliyun</id>
      <mirrorOf>central</mirrorOf>
      <url>https://maven.aliyun.com/repository/public</url>
    </mirror>
  </mirrors>
</settings>
eof
[root@Mysql-13:~#]  curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -


[root@Mysql-13:~#]  apt install nodejs -y

[root@Mysql-13:~#]  node -v
v20.20.2
[root@Mysql-13:~#]  npm -v
10.8.2
[root@Mysql-13:~#] npm config set registry https://registry.npmmirror.com
[root@Mysql-13:~#]  npm config get registry
https://registry.npmmirror.com
[root@Mysql-13:~#]
[root@Mysql-13:~#] apt install nginx nfs-common -y

[root@Mysql-13:~#]  systemctl enable --now nginx
Synchronizing state of nginx.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.
Executing: /usr/lib/systemd/systemd-sysv-install enable nginx

[root@Mysql-13:~#] rm -rf /etc/nginx/sites-enabled/default
[root@Mysql-13:~#]

3.6、Web端NFS配置

bash 复制代码
[root@Mysql-13:~#] tree /data/
/data/
├── mysql
│   └── logs
│       ├── binlog.000001
│       └── binlog.index
└── softs

4 directories, 2 files
[root@Mysql-13:~#]  mkdir -p /data/ruoyi/web /data/ruoyi/uploadPath
[root@Mysql-13:~#] showmount -e 10.0.0.26
Export list for 10.0.0.26:
/nfs/ruoyi_uploadPath 10.0.0.0/24
/nfs/ruoyi_web        10.0.0.0/24

[root@Mysql-13:~#]  mount 10.0.0.26:/nfs/ruoyi_web /data/ruoyi/web
[root@Mysql-13:~#] df -h | grep ruoyi
10.0.0.26:/nfs/ruoyi_web            47G  5.9G   39G  14% /data/ruoyi/web
[root@Mysql-13:~#] vim /etc/fstab
[root@Mysql-13:~#] tail -2 /etc/fstab
10.0.0.26:/nfs/ruoyi_web        /data/ruoyi/web    nfs    defaults,_netdev    0 0
10.0.0.26:/nfs/ruoyi_uploadPath /data/ruoyi/uploadPath  nfs     defaults,_netdev 0 0
[root@Mysql-13:~#]

3.7、后端部署ruoyi-amdin

bash 复制代码
[root@Mysql-13:~#] apt install git
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
git is already the newest version (1:2.43.0-1ubuntu7.3).
git set to manually installed.
0 upgraded, 0 newly installed, 0 to remove and 54 not upgraded.
[root@Mysql-13:~#] git clone  https://gitee.com/y_project/RuoYi-Vue.git
Cloning into 'RuoYi-Vue'...
remote: Enumerating objects: 22145, done.
remote: Total 22145 (delta 0), reused 0 (delta 0), pack-reused 22145 (from 1)
Receiving objects: 100% (22145/22145), 4.64 MiB | 577.00 KiB/s, done.
Resolving deltas: 100% (11320/11320), done.
[root@Mysql-13:~#] cd RuoYi-Vue/
[root@Mysql-13:~/RuoYi-Vue#] ls
bin  LICENSE  README.md    ruoyi-common     ruoyi-generator  ruoyi-system  ry.sh
doc  pom.xml  ruoyi-admin  ruoyi-framework  ruoyi-quartz     ry.bat        sql
[root@Mysql-13:~/RuoYi-Vue#] git fetch --tags; git checkout -b ruoyi-3.9.2 tags/v3.9.2
Switched to a new branch 'ruoyi-3.9.2'
[root@Mysql-13:~/RuoYi-Vue#] ls
bin  LICENSE  README.md    ruoyi-common     ruoyi-generator  ruoyi-system  ry.bat  sql
doc  pom.xml  ruoyi-admin  ruoyi-framework  ruoyi-quartz     ruoyi-ui      ry.sh
[root@Mysql-13:~/RuoYi-Vue#] apt install mysql-client-core-8.0
[root@Mysql-13:~/RuoYi-Vue#] cd sql/
[root@Mysql-13:~/RuoYi-Vue/sql#] ls
quartz.sql  ry_20260320.sql

[root@Mysql-13:~/RuoYi-Vue/sql#] mysql -uruoyi -pRuoyi@123 -h10.0.0.19 ry_vue < ry_20260320.sql
mysql: [Warning] Using a password on the command line interface can be insecure.
[root@Mysql-13:~/RuoYi-Vue/sql#] mysql -uruoyi -pRuoyi@123 -h10.0.0.19 ry_vue < quartz.sql
mysql: [Warning] Using a password on the command line interface can be insecure.
[root@Mysql-13:~/RuoYi-Vue/sql#]


mysql> use ry_vue;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+--------------------------+
| Tables_in_ry_vue         |
+--------------------------+
| QRTZ_BLOB_TRIGGERS       |
| QRTZ_CALENDARS           |
| QRTZ_CRON_TRIGGERS       |
| QRTZ_FIRED_TRIGGERS      |
| QRTZ_JOB_DETAILS         |
| QRTZ_LOCKS               |
| QRTZ_PAUSED_TRIGGER_GRPS |
| QRTZ_SCHEDULER_STATE     |
| QRTZ_SIMPLE_TRIGGERS     |
| QRTZ_SIMPROP_TRIGGERS    |
| QRTZ_TRIGGERS            |
| gen_table                |
| gen_table_column         |
| sys_config               |
| sys_dept                 |
| sys_dict_data            |
| sys_dict_type            |
| sys_job                  |
| sys_job_log              |
| sys_logininfor           |
| sys_menu                 |
| sys_notice               |
| sys_notice_read          |
| sys_oper_log             |
| sys_post                 |
| sys_role                 |
| sys_role_dept            |
| sys_role_menu            |
| sys_user                 |
| sys_user_post            |
| sys_user_role            |
+--------------------------+
31 rows in set (0.01 sec)



[root@Mysql-13:~/RuoYi-Vue/sql#] cd ../
[root@Mysql-13:~/RuoYi-Vue#] ls ruoyi-admin/src/main/resources/
application-druid.yml  application.yml  banner.txt  i18n  logback.xml  META-INF  mybatis
[root@Mysql-13:~/RuoYi-Vue#] vim ruoyi-admin/src/main/resources/application-druid.yml

[root@Mysql-13:~/RuoYi-Vue#] grep -A 3 "10.0.0.19" ruoyi-admin/src/main/resources/application-druid.yml
                url: jdbc:mysql://10.0.0.19:3306/ry_vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
                username: ruoyi
                password: Ruoyi@123
            # 从库数据源
[root@Mysql-13:~/RuoYi-Vue#]

[root@Mysql-13:~/RuoYi-Vue#] vim ruoyi-admin/src/main/resources/application.yml
[root@Mysql-13:~/RuoYi-Vue#] grep -A 6 -E '10.0.0.26' ~/RuoYi-Vue/ruoyi-admin/src/main/resources/application.yml
      host: 10.0.0.26
      # 端口,默认为6379
      port: 6379
      # 数据库索引
      database: 0
      # 密码
      password: Redis@2026

[root@Mysql-13:~/RuoYi-Vue#]  mvn clean package -Dmaven.test.skip=true


[root@Mysql-13:~/RuoYi-Vue#] ls ruoyi-admin/target/ruoyi-admin.jar
ruoyi-admin/target/ruoyi-admin.jar
[root@Mysql-13:~/RuoYi-Vue#] mkdir -p /data/ruoyi/server
[root@Mysql-13:~/RuoYi-Vue#] cp ruoyi-admin/target/ruoyi-admin.jar /data/ruoyi/server
[root@Mysql-13:~/RuoYi-Vue#] cd /data/ruoyi/server
[root@Mysql-13:/data/ruoyi/server#] cat > /etc/systemd/system/ruoyi-admin.service <<-eof
[Unit]
Description=RuoYi-Vue Backend Admin Service
After=network.target mysql.service redis-server.service

[Service]
User=root
WorkingDirectory=/data/ruoyi/server
# JDK17启动参数,内存可根据服务器配置调整
ExecStart=/usr/lib/jvm/java-17-openjdk-amd64/bin/java -Xms256m -Xmx512m -jar ruoyi-admin.jar
SuccessExitStatus=143
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
eof
[root@Mysql-13:/data/ruoyi/server#] systemctl daemon-reload
[root@Mysql-13:/data/ruoyi/server#] systemctl enable --now ruoyi-admin.service
Created symlink /etc/systemd/system/multi-user.target.wants/ruoyi-admin.service → /etc/systemd/system/ruoyi-admin.service.
[root@Mysql-13:/data/ruoyi/server#] systemctl status ruoyi-admin.service
● ruoyi-admin.service - RuoYi-Vue Backend Admin Service
     Loaded: loaded (/etc/systemd/system/ruoyi-admin.service; enabled; preset: enabled)
     Active: active (running) since Sun 2026-09-20 07:41:24 UTC; 14s ago
   Main PID: 14323 (java)
      Tasks: 22 (limit: 2128)
     Memory: 321.2M (peak: 321.6M)
        CPU: 28.366s
     CGroup: /system.slice/ruoyi-admin.service
             └─14323 /usr/lib/jvm/java-17-openjdk-amd64/bin/java -Xms256m -Xmx512m -jar ruoyi-admin.jar

Sep 20 07:41:28 Mysql-13 java[14323]: //                           `=---='                              //
Sep 20 07:41:28 Mysql-13 java[14323]: //      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        //
Sep 20 07:41:28 Mysql-13 java[14323]: //             佛祖保佑       永不宕机      永无BUG               //
Sep 20 07:41:28 Mysql-13 java[14323]: ////////////////////////////////////////////////////////////////////
Sep 20 07:41:29 Mysql-13 java[14323]: 07:41:29.118 [main] INFO  c.r.RuoYiApplication - [logStarting,54] - Starting >
Sep 20 07:41:29 Mysql-13 java[14323]: 07:41:29.128 [main] DEBUG c.r.RuoYiApplication - [logStarting,55] - Running w>
Sep 20 07:41:29 Mysql-13 java[14323]: 07:41:29.133 [main] INFO  c.r.RuoYiApplication - [logStartupProfileInfo,658] >
Sep 20 07:41:38 Mysql-13 java[14323]: 07:41:38.298 [main] INFO  o.a.c.h.Http11NioProtocol - [log,168] - Initializin>
Sep 20 07:41:38 Mysql-13 java[14323]: 07:41:38.308 [main] INFO  o.a.c.c.StandardService - [log,168] - Starting serv>
Sep 20 07:41:38 Mysql-13 java[14323]: 07:41:38.310 [main] INFO  o.a.c.c.StandardEngine - [log,168] - Starting Servl>
lines 1-20/20 (END)

[root@Mysql-13:/data/ruoyi/server#]  journalctl -u ruoyi-admin -f
Sep 20 07:41:54 Mysql-13 java[14323]: (♥◠‿◠)ノ゙  若依启动成功   ლ(´ڡ`ლ)゙
Sep 20 07:41:54 Mysql-13 java[14323]:  .-------.       ____     __
Sep 20 07:41:54 Mysql-13 java[14323]:  |  _ _   \      \   \   /  /
Sep 20 07:41:54 Mysql-13 java[14323]:  | ( ' )  |       \  _. /  '
Sep 20 07:41:54 Mysql-13 java[14323]:  |(_ o _) /        _( )_ .'
Sep 20 07:41:54 Mysql-13 java[14323]:  | (_,_).' __  ___(_ o _)'
Sep 20 07:41:54 Mysql-13 java[14323]:  |  |\ \  |  ||   |(_,_)'
Sep 20 07:41:54 Mysql-13 java[14323]:  |  | \ `'   /|   `-'  /
Sep 20 07:41:54 Mysql-13 java[14323]:  |  |  \    /  \      /
Sep 20 07:41:54 Mysql-13 java[14323]:  ''-'   `'-'    `-..-'
^C


[root@ProxySql-10:~#] curl http://10.0.0.13:8080
欢迎使用RuoYi后台管理框架,当前版本:v3.9.2,请通过前端地址访问。[root@ProxySql-10:~#]
[root@ProxySql-10:~#]

3.8、若依前端配置

bash 复制代码
[root@Mysql-13:/data/ruoyi/server#] cd ~/RuoYi-Vue/ruoyi-ui/
[root@Mysql-13:~/RuoYi-Vue/ruoyi-ui#] ls
babel.config.js  bin  build  package.json  public  README.md  src  vue.config.js
[root@Mysql-13:~/RuoYi-Vue/ruoyi-ui#] npm install
[root@Mysql-13:~/RuoYi-Vue/ruoyi-ui#]  npm run build:prod
[root@Mysql-13:~/RuoYi-Vue/ruoyi-ui#] ls dist/
favicon.ico  html  index.html  index.html.gz  robots.txt  static  styles
[root@Mysql-13:~/RuoYi-Vue/ruoyi-ui#] ls /data/ruoyi/web/
[root@Mysql-13:~/RuoYi-Vue/ruoyi-ui#] ls /data/ruoyi/web/ -d
/data/ruoyi/web/
[root@Mysql-13:~/RuoYi-Vue/ruoyi-ui#]  cp -r dist /data/ruoyi/web/
[root@Mysql-13:~/RuoYi-Vue/ruoyi-ui#] vim /etc/nginx/conf.d/ruoyi.conf
[root@Mysql-13:~/RuoYi-Vue/ruoyi-ui#] cat /etc/nginx/conf.d/ruoyi.conf
server {
    listen 80;
    server_name ruoyi.magedu.com;
    # 前端静态资源根目录
    root /data/ruoyi/web/dist;
    index index.html;

    # 解决Vue History模式刷新页面404问题
    location / {
        try_files $uri $uri/ /index.html;
    }

    # 接口请求转发至后端8080端口,适配前端 /prod-api 接口前缀
    location ^~ /prod-api/ {
        proxy_pass http://127.0.0.1:8080/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # 本地文件上传访问路由
    location /profile/ {
        proxy_pass http://127.0.0.1:8080/profile/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    # 静态资源缓存优化
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires 1d;
        add_header Cache-Control "public";
    }
}
[root@Mysql-13:~/RuoYi-Vue/ruoyi-ui#]



[root@Mysql-13:~/RuoYi-Vue/ruoyi-ui#] nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@Mysql-13:~/RuoYi-Vue/ruoyi-ui#] systemctl restart nginx.service








[root@ProxySql-10:~#] curl http://10.0.0.13
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><metar content=webkit><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=nicon href=/favicon.ico><title>若依管理系统</title><!--[if lt IE 11]><script>window.location.href='/html/ie.html'endif]--><style>html,
    body,
    #app {
      height: 100%;
      margin: 0px;



[root@Redis-26:~#] ls /nfs/ruoyi_web/
dist
相关推荐
于平安1 小时前
MySQL-变量,流程控制与游标
数据库·mysql
不吃香菜kkk、1 小时前
CI/CD(GitOps)学习与部署手册
运维·云原生·容器·kubernetes·云计算·jenkins·argocd
whyutianict_vv2 小时前
云计算运维培训课程技术栈拆解:从 Linux 网络到 AI 推理的五层能力分层
linux·云计算
pt10432 小时前
面向AI的Cisco UCS X-Series设计-2:Cisco UCS AI规格选型
运维·人工智能
元岳数字人小元2 小时前
无惧网络受限:数字人私有化部署打造离线全域服务能力
运维·人工智能·开源·人机交互·交互
徐子童2 小时前
介绍MVCC机制
java·mysql·面试题·秋招·并发·mvcc
xiaoye-duck2 小时前
《Linux 网络编程》深入理解数据链路层:从MAC帧到ARP协议的底层原理详解
linux·网络
thefool1122662 小时前
库和表基本操作、表的增删改查
mysql
QQ14220784492 小时前
2012 年的老 ThinkPad E430 改装 Ubuntu 24.04全程翻车排查实录
ubuntu·项目复盘