一、Redis 概述

1.1 基本定义

Redis 全称 Remote Dictionary Server(远程字典服务器),是一款高性能的键值对(Key/Value)分布式内存数据库,支持数据持久化(定期把内存里的数据存储到硬盘),同时支持多种数据类型与主从复制备份。
官方中文站点:www.redis.cn

1.2 核心特点

在大数据、高并发场景下应用广泛,核心特性如下:

  1. 高性能:数据全部存储在内存中,读写速度极快
  2. 持久化:支持 RDB 快照、AOF 日志两种持久化方式,保障数据安全可靠
  3. 多数据类型支持:包含字符串(string)、哈希(hash)、列表(list)、集合(set)等,适配不同业务场景
  4. 分布式部署:支持集群模式,实现数据高可用与负载均衡
  5. 丰富的功能:支持事务、发布订阅、Lua 脚本、管道(pipeline)等高级功能

缓存的作用是提升读写速度。并非所有数据都适合缓存,仅热点数据需要做缓存

1.3 典型应用场景

  1. 计数器与排行榜:利用 Redis 原子递增命令实现高性能计数器;通过有序集合实现排行榜功能
  2. 分布式锁:通过 SETNX 命令配合过期时间实现分布式锁,避免多线程/多节点同时修改资源
  3. 实时消息系统:基于发布/订阅模式、Stream 数据结构实现轻量级实时消息,适配在线聊天、消息推送等场景
  4. 日志收集:利用 List 数据结构作为消息队列,实现日志收集与异步消费
  5. 会话管理:基于高性能内存存储实现 Web 应用的 Session 统一管理,提升访问性能

1.4 实验环境说明

本次实验使用单台 Redis 主机完成所有部署与操作。

主机名IP地址
redis-1192.168.8.122

二、Redis 安装与基础服务管理

本次实验使用源码包 redis-4.0.8.tar.gz 进行编译安装。

2.1 编译安装步骤

  1. 安装编译依赖
[root@redis-1 ~]# yum -y install gcc make
  1. 解压源码包并进入目录
[root@redis-1 ~]# tar -xf redis-4.0.8.tar.gz
[root@redis-1 ~]# cd redis-4.0.8/
  1. 编译并安装
[root@redis-1 redis-4.0.8]# make
[root@redis-1 redis-4.0.8]# make install

2.2 服务初始化(官方脚本)

Redis 源码提供 install_server.sh 初始化脚本,可一键配置服务、设置开机自启。
执行脚本后可自定义端口、配置文件路径等,全部回车则使用默认值:

[root@redis-1 ~]# cd redis-4.0.8/
[root@redis-1 redis-4.0.8]# ./utils/install_server.sh #执行初始化脚本

交互流程与默认配置:

Welcome to the redis service installer
This script will help you easily set up a running redis server

Please select the redis port for this instance: [6379]                  #监听端口
Selecting default: 6379
Please select the redis config file name [/etc/redis/6379.conf]         #配置文件名
Selected default - /etc/redis/6379.conf
Please select the redis log file name [/var/log/redis_6379.log]         #日志位置
Selected default - /var/log/redis_6379.log
Please select the data directory for this instance [/var/lib/redis/6379] #文件存储位置
Selected default - /var/lib/redis/6379
Please select the redis executable path [/usr/local/bin/redis-server]   #主程序位置
Selected config:
Port           : 6379
Config file    : /etc/redis/6379.conf
Log file       : /var/log/redis_6379.log
Data dir       : /var/lib/redis/6379
Executable     : /usr/local/bin/redis-server
Cli Executable : /usr/local/bin/redis-cli
Is this ok? Then press ENTER to go on or Ctrl-C to abort.
Copied /tmp/6379.conf => /etc/init.d/redis_6379
Installing service...
Successfully added to chkconfig!        #设置开机自启动
Successfully added to runlevels 345!    #在345级别开机自启动
Starting Redis server...                #启动Redis服务
Installation successful!
[root@redis-1 redis-4.0.8]# cd          #回到家目录

2.3 服务管理命令

  1. 查看端口监听状态
[root@redis-1 ~]# ss -antpu | grep redis
tcp  LISTEN  0    128    127.0.0.1:6379    :   users:(("redis-server",pid=4335,fd=6))
  1. 服务脚本路径
[root@redis-1 ~]# ls /etc/init.d/redis_6379
/etc/init.d/redis_6379
  1. 启停与状态查看
[root@redis-1 ~]# /etc/init.d/redis_6379 stop       # 停止服务
[root@redis-1 ~]# /etc/init.d/redis_6379 start      # 启动服务
[root@redis-1 ~]# /etc/init.d/redis_6379 status     # 查看服务状态
Redis is running (4361)

2.4 Redis 连接方式

客户端工具为 redis-cli,支持多种连接形式:

  • 格式:redis-cli -h 主机地址 -p 端口号 -a "密码"
  1. 标准连接(指定地址、端口、密码)
[root@redis-1 ~]# redis-cli -h localhost -p 6379 -a ""
localhost:6379> PING
PONG
localhost:6379> EXIT
  1. 默认本地连接
[root@redis-1 ~]# redis-cli
127.0.0.1:6379> PING
PONG
127.0.0.1:6379> EXIT
  1. 非交互模式直接执行命令
[root@redis-1 ~]# redis-cli PING
PONG

2.5 常用基础操作指令

1. Key 通用操作

Redis 基础命令整理表

命令示例功能说明返回结果说明
KEYS *查询当前数据库中所有键名无数据返回 (empty list or set);有数据列出全部key
KEYS a*模糊匹配:查询以 a 开头的所有键仅输出前缀匹配成功的key
KEYS ???模糊匹配:查询名称为3个字符的键? 代表单个任意字符
SET name zhangsan单个String键值写入,覆盖原有值OK 代表设置成功
MSET age 25 gender male class class1批量一次性写入多组String键值(原子操作)OK 代表全部设置成功
GET name获取单个key对应的value返回对应字符串,键不存在返回 (nil)
MGET name age批量查询多个key的值按输入顺序依次返回对应value
EXISTS name判断指定key是否存在(integer) 1=存在;(integer) 0=不存在
TTL age查看key剩余过期时间-1=永久不过期;正数=剩余秒数;-2=键已过期/不存在
EXPIRE age 10给指定key设置过期时间(单位:秒)(integer) 1=设置成功;0=键不存在设置失败
LPUSH students tom jim bob左侧插入数据(列表的开头位置即索引为 0 的位置),创建/操作List列表类型返回列表当前元素总个数
TYPE name查看指定key的数据类型输出 string/list/hash/set 等类型名
MOVE students 10将当前库的key移动到指定编号数据库(integer) 1=移动成功;0=键不存在或目标库已有同名键
SELECT 10切换Redis数据库(默认0号,范围0~15)OK 切换完成,提示符后缀显示库编号
SAVE同步持久化,将内存数据写入RDB磁盘文件OK 持久化完成
DEL class删除指定单个key返回成功删除的键数量
FLUSHDB清空当前所选数据库全部键OK 清空完成
FLUSHALL清空所有16个数据库全部键OK 清空完成
SHUTDOWN关闭Redis服务进程断开客户端连接,提示符变为 not connected>
EXIT退出 redis-cli 客户端连接直接退回服务器终端
redis-cli服务器终端登录Redis客户端进入 127.0.0.1:6379> 交互界面

补充注意点:

  1. KEYS 命令线上环境禁止使用,海量键会阻塞Redis,生产使用 SCAN 迭代遍历;
  2. MSET 是原子命令,批量写入要么全部成功,要么全部不生效;
  3. FLUSHDB / FLUSHALL 属于高危删除命令,操作前务必备份数据;
  4. Redis 默认提供 0~15 共16个独立数据库,库之间数据完全隔离。
[root@redis-1 ~]# redis-cli
# 查看当前库所有key
127.0.0.1:6379> KEYS *
(empty list or set)

# 查看以a开头的key
127.0.0.1:6379> KEYS a*
"age"

# 查看名称长度为3个字符的key
127.0.0.1:6379> KEYS ???
"age"

# 判断key是否存在,返回1存在,0不存在
127.0.0.1:6379> EXISTS name
(integer) 1
127.0.0.1:6379> EXISTS hahaha
(integer) 0

# 查看key剩余生命周期,-1表示永久有效,-2表示key不存在/已过期
127.0.0.1:6379> TTL age
(integer) -1

# 给key设置过期时间(单位:秒)
127.0.0.1:6379> EXPIRE age 10
(integer) 1
127.0.0.1:6379> TTL age
(integer) 9
127.0.0.1:6379> TTL age
(integer) 1
127.0.0.1:6379> TTL age
(integer) -2

# 查看key的数据类型
127.0.0.1:6379> TYPE name
string
127.0.0.1:6379> TYPE students
list

# 删除指定key
127.0.0.1:6379> DEL class
(integer) 1
2. String 字符串类型操作
# 存储单个字符串key
127.0.0.1:6379> SET name zhangsan
OK

# 批量存储多个字符串key
127.0.0.1:6379> MSET age 25 gender male class class1
OK

# 获取单个字符串值
127.0.0.1:6379> GET name
"zhangsan"

# 批量获取多个值
127.0.0.1:6379> MGET name age
"zhangsan"
"25"
3. List 列表类型操作
# 从左侧向列表插入元素(创建列表)
127.0.0.1:6379> LPUSH students tom jim bob
(integer) 3
4. 数据库切换与移动

Redis 默认提供 16 个数据库(编号 0-15),默认操作 0 号库:

# 将key移动到指定编号的库
127.0.0.1:6379> MOVE students 10
(integer) 1

# 切换到指定编号的库
127.0.0.1:6379> SELECT 10
OK
127.0.0.1:6379[10]> KEYS *
"students"

# 切回0号库
127.0.0.1:6379[10]> SELECT 0
OK
5. 持久化与清空操作
# 手动触发RDB持久化,将内存数据保存到磁盘
127.0.0.1:6379> SAVE
OK

# 清空当前库所有数据
127.0.0.1:6379> FLUSHDB
OK

# 清空所有库的所有数据,需慎重
127.0.0.1:6379> FLUSHALL
OK

# 关闭Redis服务
127.0.0.1:6379> SHUTDOWN
not connected> EXIT

三、Redis 常用配置与进阶设置

配置文件默认路径:/etc/redis/6379.conf

3.1 核心配置项说明

常用配置项与示例:

配置项作用示例值
bind监听的IP地址,默认127.0.0.1仅本地访问192.168.8.122
protected-mode保护模式,开启后限制远程访问no
port服务监听端口6351
pidfilePID文件路径/var/run/redis_6379.pid
loglevel日志级别notice
logfile日志文件路径/var/log/redis_6379.log
databases数据库数量16
dir数据持久化文件存储目录/var/lib/redis/6379
requirepass连接认证密码123456

配置文件快速查看命令:

[root@redis-1 ~]# vim /etc/redis/6379.conf 
[root@redis-1 ~]# cat -n /etc/redis/6379.conf | sed -rn '70p;89p;93p;159p;167p;172p;187p;264p;501p'
    70  bind 192.168.8.122                          #修改监听地址
    89  protected-mode no                           #关闭保护模式
    93  port 6351                                   #监听端口修改为6351
   159  pidfile /var/run/redis_6379.pid
   167  loglevel notice
   172  logfile /var/log/redis_6379.log
   187  databases 16
   264  dir /var/lib/redis/6379
   501  requirepass 123456                          #设置连接密码为12345 

3.2 修改配置后启动与连接测试

  1. 启动服务并验证端口
[root@redis-1 ~]# /etc/init.d/redis_6379 start  #如果服务已在运行就使用restart(restart只能在运行时使用)
[root@redis-1 ~]# ss -pantul | grep redis
tcp LISTEN 0  128    192.168.8.122:6351   : users:(("redis-server",pid=4486,fd=6))
  1. 连接测试(两种认证方式)
  • 方式1:登录时直接携带密码
[root@redis-1 ~]# redis-cli -h 192.168.8.122 -p 6351 -a "123456"
192.168.8.122:6351> PING
PONG
192.168.8.122:6351> EXIT
  • 方式2:登录后手动认证
[root@redis-1 ~]# redis-cli -h 192.168.8.122 -p 6351
192.168.8.122:6351> AUTH 123456
OK
192.168.8.122:6351> PING
PONG
192.168.8.122:6351> exit

3.3 服务管理脚本Bug处理

问题现象

修改监听地址与端口后,使用默认脚本停止服务失败:

[root@redis-1 ~]# /etc/init.d/redis_6379 stop
Stopping ...
Could not connect to Redis at 127.0.0.1:6379: Connection refused
Waiting for Redis to shutdown ...
Waiting for Redis to shutdown ...

原因:脚本默认使用 127.0.0.1:6379 连接服务执行shutdown,修改地址/端口后连接失败,无法正常停止。

解决方案
  • 方案1:直接用redis-cli连接真实地址执行关闭
[root@redis-1 ~]# redis-cli -h 192.168.8.122 -p 6351 -a "123456" shutdown
  • 方案2:修改服务脚本,改用pkill结束进程
[root@redis-1 ~]# vim /etc/init.d/redis_6379
# 注释原有的cli关闭命令,添加pkill命令
# $$CLIEXEC -p $$REDISPORT shutdown
pkill redis-server

修改后测试启停:

[root@redis-1 ~]# /etc/init.d/redis_6379 start
Starting Redis server...

[root@redis-1 ~]# /etc/init.d/redis_6379 stop
Stopping ...
Waiting for Redis to shutdown ...
Redis stopped

[root@redis-1 ~]# /etc/init.d/redis_6379 status
cat: /var/run/redis_6379.pid: No such file or directory
Redis is running ()

3.4 内存管理与数据淘汰策略

核心概念

当 Redis 内存使用达到 maxmemory 设置的上限时,再写入新数据,Redis 会按照 maxmemory-policy 指定的策略自动淘汰已有key,腾出内存空间。若不配置maxmemory,Redis默认无内存上限,不会触发淘汰。

配置项说明
[root@redis-1 ~]# vim /etc/redis/6379.conf 
[root@redis-1 ~]# sed -rn '560p;565,572p;591p' /etc/redis/6379.conf 
#将配置文件中第560行,565到572行,591行行首的#去掉
maxmemory <bytes>        #配置Redis的最大可用内存,不配置默认无限占用,不会触发淘汰
volatile-lru -> Evict using approximated LRU among the keys with an expire set.
allkeys-lru -> Evict any key using approximated LRU.
volatile-lfu -> Evict using approximated LFU among the keys with an expire set.
allkeys-lfu -> Evict any key using approximated LFU.
volatile-random -> Remove a random key among the ones with an expire set.
allkeys-random -> Remove a random key, any key.
volatile-ttl -> Remove the key with the nearest expire time (minor TTL)
noeviction -> Don't evict anything, just return an error on write operations.
maxmemory-policy noeviction  # 内存淘汰策略,默认noeviction
8种淘汰策略详解(了解)
策略分类策略名称作用范围淘汰规则
LRU(删除最近最少使用)volatile-lru仅设置了过期时间的key淘汰最近最少使用的key
allkeys-lru所有key淘汰最近最少使用的key
LFU(删除使用频率最低)volatile-lfu仅设置了过期时间的key淘汰使用频率最低的key
allkeys-lfu所有key淘汰使用频率最低的key
RANDOM(随机删除)volatile-random仅设置了过期时间的key随机删除key
allkeys-random所有key随机删除key
volatile-ttl删除即将过期的key
noeviction (不淘汰)不删除任何key

四、LNMP+Redis 架构部署(重点)

4.1 LNMP 基础环境搭建

需要注意的是,连接redis和数据库的都是php代码

4.1.1 部署 MySQL 服务
# 安装MySQL服务
[root@redis-1 ~]# dnf -y install mysql mysql-server
# 设置开机自启并立即启动
[root@redis-1 ~]# systemctl enable mysqld --now

# 连接数据库并修改root密码
[root@redis-1 ~]# mysql
mysql> ALTER USER root@'localhost' IDENTIFIED BY "123qqq...A";
mysql> EXIT

# 验证密码登录
[root@redis-1 ~]# mysql -uroot -p'123qqq...A'
4.1.2 部署 Nginx 服务

使用源码包 nginx-1.22.1.tar.gz 编译安装:

# 安装编译依赖
[root@redis-1 ~]# yum -y install gcc pcre-devel openssl-devel

# 解压源码包
[root@redis-1 ~]# tar -xf nginx-1.22.1.tar.gz
# 创建运行用户
[root@redis-1 ~]# useradd -s /sbin/nologin nginx

# 编译配置
[root@redis-1 ~]# cd nginx-1.22.1/
[root@redis-1 nginx-1.22.1]# ./configure --prefix=/usr/local/nginx \
> --user=nginx --group=nginx --with-http_ssl_module

# 编译并安装
[root@redis-1 nginx-1.22.1]# make
[root@redis-1 nginx-1.22.1]# make install
[root@redis-1 nginx-1.22.1]# ls /usr/local/nginx/
conf  html  logs  sbin
[root@redis-1 nginx-1.22.1]# cd

启动服务并测试:

# 启动Nginx
[root@redis-1 ~]# /usr/local/nginx/sbin/nginx
# 验证80端口监听
[root@redis-1 ~]# ss -pantu | grep 80
tcp    LISTEN     0      128       *:80                    :                   users:(("nginx",pid=7523,fd=6),("nginx",pid=7522,fd=6))

# 创建自定义首页
[root@redis-1 ~]# echo "nginx" >  /usr/local/nginx/html/index.html
# 访问测试
[root@redis-1 ~]# curl http://localhost/
nginx
4.1.3 部署 PHP 与动静分离
  1. 安装PHP与扩展
[root@redis-1 ~]# yum -y install php php-fpm php-mysqlnd

说明:php-mysqlnd 是PHP的MySQL原生驱动扩展,提供PHP连接MySQL数据库的能力。

  1. 修改PHP-FPM配置
[root@redis-1 ~]# vim /etc/php-fpm.d/www.conf
# 修改为TCP端口监听,注释默认的sock文件
listen = 127.0.0.1:9000
;listen = /run/php-fpm/www.sock
  1. 启动PHP-FPM并验证端口
[root@redis-1 ~]# systemctl enable php-fpm --now
[root@redis-1 ~]# ss -pantul | grep 9000
tcp    LISTEN     0      128    127.0.0.1:9000                  : users:(("php-fpm",pid=7618,fd=0),("php-fpm",pid=7617,fd=0),("php-fpm",pid=7616,fd=0),("php-fpm",pid=7615,fd=0),("php-fpm",pid=7614,fd=0),("php-fpm",pid=7613,fd=6))
  1. 配置Nginx动静分离
[root@redis-1 ~]# vim /usr/local/nginx/conf/nginx.conf
# 找到PHP配置段,修改为如下内容
        location ~ \.php$ {
            root           html;
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            include        fastcgi.conf;
        }

# 重载Nginx配置
[root@redis-1 ~]# /usr/local/nginx/sbin/nginx -s reload
  1. PHP功能测试
# 编写测试文件
[root@redis-1 ~]# vim /usr/local/nginx/html/test.php
<?PHP
    echo "hello\n";
?>

# 命令行验证语法
[root@redis-1 ~]# php /usr/local/nginx/html/test.php
hello

# 网页访问测试
[root@redis-1 ~]# curl http://localhost/test.php
hello
4.1.4 LNMP 连通性测试

编写PHP页面连接MySQL并查询数据:

[root@redis-1 ~]# cp /root/mysql.php /usr/local/nginx/html/
[root@redis-1 ~]# vim /usr/local/nginx/html/mysql.php
<?php
$mysqli = new mysqli('localhost','root','123qqq...A','mysql');
if (mysqli_connect_errno()){
        die('Unable to connect!'). mysqli_connect_error();
}
$sql = "select * from user";
$result = $mysqli->query($sql);
while($row = $result->fetch_array()){
        printf("Host:%s",$row[0]);
        printf("</br>");
        printf("Name:%s",$row[1]);
        printf("</br>");
}
?>

访问测试:

[root@redis-1 ~]# curl http://localhost/mysql.php
Host:localhost</br>Name:mysql.infoschema</br>Host:localhost</br>Name:mysql.session</br>Host:localhost</br>Name:mysql.sys</br>Host:localhost</br>Name:root</br>

4.2 PHP Redis 扩展安装

4.2.1 扩展编译安装

使用 redis-6.0.0.tgz 源码包编译PHP扩展:

# 安装PHP开发依赖
[root@redis-1 ~]# dnf -y install php-devel php-json

# 解压扩展包
[root@redis-1 ~]# tar -xf redis-6.0.0.tgz
[root@redis-1 ~]# cd redis-6.0.0/

# 使用phpize文件生成configure配置文件
[root@redis-1 redis-6.0.0]# phpize
Configuring for:
PHP Api Version:         20200930
Zend Module Api No:      20200930
Zend Extension Api No:   420200930
configure.ac:18: warning: $as_echo is obsolete; use AS_ECHO(["message"]) instead
build/php.m4:2072: PHP_CONFIG_NICE is expanded from...
configure.ac:18: the top level
configure.ac:161: warning: The macro `AC_PROG_LIBTOOL' is obsolete.
You should run autoupdate.
build/libtool.m4:100: AC_PROG_LIBTOOL is expanded from...
configure.ac:161: the top level

# 编译配置,关联当前PHP环境
[root@redis-1 redis-6.0.0]# ./configure --with-php-config=/usr/bin/php-config

# 编译并安装
[root@redis-1 redis-6.0.0]# make
[root@redis-1 redis-6.0.0]# make install

# 验证扩展文件生成
[root@redis-1 redis-6.0.0]# cd
[root@redis-1 ~]# ls /usr/lib64/php/modules/redis.so
/usr/lib64/php/modules/redis.so
4.2.2 启用 Redis 扩展
  1. 配置模块加载路径
[root@redis-1 ~]# cp /etc/php.ini  /opt/  #备份文件
[root@redis-1 ~]# vim /etc/php.ini   #修改php配置文件
# 添加扩展目录配置,#指定模块路径
737 extension_dir = "/usr/lib64/php/modules/"
  1. 创建扩展配置文件

注意:Redis扩展依赖json扩展,需确保json扩展先加载(先加载json再加载redis),因此命名为99-redis.ini保证加载顺序。

[root@redis-1 ~]# vim /etc/php.d/99-redis.ini
extension = redis.so    #指定模块名
  1. 重启PHP-FPM并验证扩展
[root@redis-1 ~]# systemctl restart php-fpm
[root@redis-1 ~]# php -m | grep redis   #检查php已支持redis
redis

4.3 PHP 操作 Redis 功能测试

4.3.1 基础读写测试

编写测试页面验证PHP连接Redis、读写数据:

[root@redis-1 ~]# cat /usr/local/nginx/html/redis.php 
<?php
    #实例化连接Redis对象
    $redis = new redis();
    #给实例传递参数
    $redis->connect("192.168.8.122",6351);
    $redis->auth("123456");
    #调用set方法存变量
    $redis->set("school","hopeschool");
    echo "save ok\n";
    #调用get方法取变量
    echo $redis->get("school");
    echo "\n";
?>

访问测试与数据验证:

# 网页访问测试
[root@redis-1 ~]# curl http://localhost/redis.php
save ok
hopeschool

# 登录Redis验证数据
[root@redis-1 ~]# redis-cli -h 192.168.8.122 -p 6351 -a "123456"
192.168.8.122:6351> KEYS *
"school"
192.168.8.122:6351> GET school
"hopeschool"
4.3.2 缓存联动测试(MySQL+Redis)

实现逻辑:php先查询Redis缓存,缓存存在则直接返回;缓存不存在,php直接查询MySQL,将结果写入Redis并设置5秒过期。

[root@redis-1 ~]# vim /usr/local/nginx/html/time.php
<?PHP
    #实例化Redis连接对象,修改为自己的IP地址!
    $redis = new Redis();
    $redis->connect('192.168.8.122',6351);
    $redis->auth("123456");
    
    #调用查询方法查询Redis中是否有个time变量
    $time = $redis->get('time');
    #判断查询结果,如果为空则进入MySQL查询,如果不空则直接返回结果
    if(empty($time)){
        echo "Query From \033[31mMySQL\033[0m:\t";
        #实例化MySQL连接对象
        $mysqli = new mysqli('127.0.0.1','root','123qqq...A','mysql');
        if (mysqli_connect_errno()){
                die('Unable to connect!'). mysqli_connect_error();
        }
        $sql = "SELECT time(now())";
        $result = $mysqli->query($sql);
        $rs = $result->fetch_array();
        $r=$rs[0];
        #将结果存入Redis并设置该变量生命周期为5s
        $redis->set("time",$r);
        $redis->expire("time",5);
        echo "$r";
        echo "\n";
    }else{
        echo "Query From \033[32mRedis\033[0m:\t";
        echo $time;
        echo "\n";
    }
?>

访问测试效果:

# 第一次访问,缓存未命中,查询MySQL
[root@redis-1 ~]# curl 192.168.8.122/time.php
Query From MySQL:       19:14:54

# 5秒内访问,缓存命中,查询Redis
[root@redis-1 ~]# curl 192.168.8.122/time.php
Query From Redis:       19:14:54

[root@redis-1 ~]# curl 192.168.8.122/time.php
Query From Redis:       19:14:54

# 5秒后缓存过期,重新查询MySQL
[root@redis-1 ~]# curl 192.168.8.122/time.php
Query From MySQL:       19:15:00

我们会发现命中缓存时,时间是不变的


五、缓存核心概念与面试考点

5.1 缓存击穿

定义

热点Key过期失效,同一时间大量并发请求无法命中缓存,瞬间全部直接访问后端数据库,导致数据库压力骤增甚至宕机。

典型场景

电商秒杀活动中,热门商品的详情缓存设置了5秒过期,过期瞬间成千上万的请求无法命中缓存,全部打到MySQL数据库。

解决方案
  1. 互斥锁方案
    缓存失效时,只放行1个请求去数据库查询并更新缓存,其余请求等待重试,避免大量并发同时打数据库。
    逻辑:查缓存为空 → 尝试获取分布式锁 → 拿到锁的请求查库并更新缓存 → 未拿到锁的请求循环重试读缓存。

  2. 热点Key永不过期
    对高频访问的热点数据不设置过期时间,由后台定时任务主动异步更新缓存,从根源上避免热点Key过期导致的击穿问题。

5.2 缓存雪崩

定义

大量缓存Key在同一时间集体过期失效,或者Redis服务整体宕机不可用,导致海量请求同时直接访问后端数据库,引发数据库压力过载甚至崩溃。

典型场景

商品系统批量设置所有商品缓存的过期时间为10分钟,第10分钟时所有缓存同时失效,全量商品查询请求瞬间涌入MySQL。

解决方案
  1. 过期时间打散
    给缓存的过期时间增加随机偏移量(如基础10分钟 + 随机0-300秒),让不同Key的过期时间错开,避免同一时间大量Key集体失效。

  2. Redis高可用集群
    搭建Redis主从集群、哨兵或集群模式,避免单节点故障导致整个缓存服务不可用,保障缓存服务的高可用性。


学习总结

  1. 掌握Redis内存数据库的存储特点与核心应用场景
  2. 掌握Redis常用数据类型的基础操作命令
  3. 掌握LNMP环境的部署方法,以及PHP加载Redis扩展的流程
  4. 掌握LNMP与Redis联动实现缓存的架构逻辑与实现方式
  5. 理解缓存击穿、缓存雪崩的场景与解决方案
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐