非关系型数据库 Redis 基础
一、背景描述及其方案设计
1. 业务背景描述
时间:2021.9.-2022.6
发布产品类型:互联网动态站点商城
用户数量: 60000(用户量猛增)
PV : 200000-300000(24小时访问次数总和)
DAU: 20000(每日活跃用户数)
2. 模拟运维设计方案
根据以上业务需求,准备加入Redis缓存中间件服务器,可以使用到Redis更加丰富的功能
在商城业务中实现:
① 实现活跃用户数的统计(使用set集合)
② Session存储到Redis
③ Openresty(Nginx+Lua)动态限制IP访问WAF(Web Application Firewalld)
二、Redis 概述
1. 什么是Redis
NoSQL 非关系数据库 key => value 键值对
Redis是Remote Dictionary Server(远程数据服务)的缩写
由意大利人Antirez(Salvatore Sanfilippo萨尔瓦托桑菲利波) 开发的一款内存高速缓存数据库
该软件使用C语言编写,它的数据模型为 key-value
它支持丰富的数据结构,比如 string list(双向链表) hash(哈希) set(集合) sorted set(zset有序集合)
可持久化(保存数据到磁盘中),保证了数据安全
2. 业务使用场合
**① [Sort Set]**排行榜应用,取top n操作,例如Sina微博热门话题(取最热的前10个话题)
**② [List]**获得最新N个数据 或 某个分类的最新数据
**③ [String]**计数器应用
**④ [Set]**SNS(social network site)获得共同好友
**⑤ [Set]**防攻击系统(IP判断)黑白名单等等
三、Redis 安装与配置
官方网址:https://redis.io/
github:https://github.com/antirez/redis
1. CentOS Stream 9 阿里源
cat >/etc/yum.repos.d/aliyun.repo<<EOF
[baseos]
name=CentOS Stream \$releasever - BaseOS
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/BaseOS/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1
[baseos-debug]
name=CentOS Stream \$releasever - BaseOS - Debug
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/BaseOS/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[baseos-source]
name=CentOS Stream \$releasever - BaseOS - Source
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/BaseOS/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[appstream]
name=CentOS Stream \$releasever - AppStream
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/AppStream/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1
[appstream-debug]
name=CentOS Stream \$releasever - AppStream - Debug
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/AppStream/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[appstream-source]
name=CentOS Stream \$releasever - AppStream - Source
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/AppStream/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[crb]
name=CentOS Stream \$releasever - CRB
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/CRB/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[crb-debug]
name=CentOS Stream \$releasever - CRB - Debug
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/CRB/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[crb-source]
name=CentOS Stream \$releasever - CRB - Source
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/CRB/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[highavailability]
name=CentOS Stream \$releasever - HighAvailability
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/HighAvailability/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[highavailability-debug]
name=CentOS Stream \$releasever - HighAvailability - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/HighAvailability/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[highavailability-source]
name=CentOS Stream \$releasever - HighAvailability - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/HighAvailability/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[nfv]
name=CentOS Stream \$releasever - NFV
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/NFV/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[nfv-debug]
name=CentOS Stream \$releasever - NFV - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/NFV/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[nfv-source]
name=CentOS Stream \$releasever - NFV - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/NFV/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[rt]
name=CentOS Stream \$releasever - RT
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/RT/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[rt-debug]
name=CentOS Stream \$releasever - RT - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/RT/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[rt-source]
name=CentOS Stream \$releasever - RT - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/RT/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[resilientstorage]
name=CentOS Stream \$releasever - ResilientStorage
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/ResilientStorage/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[resilientstorage-debug]
name=CentOS Stream \$releasever - ResilientStorage - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/ResilientStorage/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[resilientstorage-source]
name=CentOS Stream \$releasever - ResilientStorage - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/ResilientStorage/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[extras-common]
name=CentOS Stream \$releasever - Extras packages
baseurl=http://mirrors.aliyun.com/centos-stream/SIGs/\$stream/extras/\$basearch/extras-common/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1
[extras-common-source]
name=CentOS Stream \$releasever - Extras packages - Source
baseurl=http://mirrors.aliyun.com/centos-stream/SIGs/\$stream/extras/source/extras-common/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
EOF
可以通过yum方式在线安装,也可以通过源码编译方式安装
这里,采用源码编译方式安装:
第一步:找到对应的安装包资源,使用wget命令下载,这里安装的7.4.0版本
安装包资源地址:https://download.redis.io/releases/
第二步:上传或者下载Redis到Linux系统中
wget https://download.redis.io/releases/redis-7.4.0.tar.gz
第三步:配置=>编译=>安装
tar -zxvf redis-7.4.0.tar.gz
cd redis-7.4.0
yum install epel-release -y
yum install make gcc jemalloc jemalloc-devel -y
make
make install PREFIX=/usr/local/redis
第四步:配置环境变量
echo 'PATH=$PATH:/usr/local/redis/bin/' >> /etc/profile && source /etc/profile
redis-cli -v
安装成功后,Redis 的可执行文件将被安装到 /usr/local/redis
2. 修改配置
mkdir -p /usr/local/redis/conf
cp /root/redis-7.4.0/redis.conf /usr/local/redis/conf/
# 修改配置
vim /usr/local/redis/conf/redis.conf
88: bind 127.0.0.1 -::1 --> bind 0.0.0.0
310: daemonize no --> daemonize yes
#过量使用内存设置为1
vm.overcommit_memory 的 3 种模式
0(默认)内核根据启发式算法决定是否允许超分配“看情况给,不一定准”
1允许内存超分配,不做任何限制,想分就分,不管你有没有这么多内存
2严格限制,不允许超分配非常安全,但可能导致程序申请内存失败
echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf
配置好后执行以下命令让配置生效
sysctl -p
3. 启动Redis
手工实现服务验证
#查看版本
redis-cli -v
#启动
redis-server /usr/local/redis/conf/redis.conf
#查看服务进程
ps aux | grep redis
ps -ef | grep redis
netstat -pantul|grep redis
netstat -pantul|grep 6379
ss -pantul|grep redis
ss -pantul|grep 6379
#登录
redis-cli
127.0.0.1:6379> info
配置redis.service
cat >/etc/systemd/system/redis.service<<EOF
[Unit]
Description=redis-server
After=network.target
[Service]
Type=forking
ExecStart=/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis.conf
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
启动服务
pkill redis-server
systemctl daemon-reload
systemctl start redis
systemctl enable redis
systemctl status redis --no-pager
4. Redis命令行客户端简单使用
redis属于c/s架构软件,telnet可以连接redis,没有本身redis-cli更加好用
① 简单的数据操作
string类型:字符串类型、文本类型,用于保存文本信息
# redis-cli
127.0.0.1:6379 > set post-name devops
OK
127.0.0.1:6379 > get post-name
"devops"
② 查看操作语法帮助
127.0.0.1:6379 > help
127.0.0.1:6379 > help set
③ 系统状态信息
127.0.0.1:6379 > info
127.0.0.1:6379> info
# Server
redis_version:7.4.0
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:b9206d9f7fbfa22a
redis_mode:standalone
os:Linux 5.14.0-511.el9.x86_64 x86_64
arch_bits:64
monotonic_clock:POSIX clock_gettime
multiplexing_api:epoll
atomicvar_api:c11-builtin
gcc_version:11.5.0
process_id:61047
process_supervised:no
run_id:ba3a3c88f38135718b012f77ac1eb8fba01810dd
tcp_port:6379
server_time_usec:1764558428231770
uptime_in_seconds:2622
uptime_in_days:0
hz:10
configured_hz:10
lru_clock:2950748
executable:/usr/local/redis/bin/redis-server
config_file:/usr/local/redis/conf/redis.conf
io_threads_active:0
listener0:name=tcp,bind=0.0.0.0,port=6379
# Clients
connected_clients:1
cluster_connections:0
maxclients:10000
client_recent_max_input_buffer:8
client_recent_max_output_buffer:0
blocked_clients:0
tracking_clients:0
pubsub_clients:0
watching_clients:0
clients_in_timeout_table:0
total_watched_keys:0
total_blocking_keys:0
total_blocking_keys_on_nokey:0
# Memory
used_memory:1095248
used_memory_human:1.04M
used_memory_rss:12165120
used_memory_rss_human:11.60M
used_memory_peak:1239632
used_memory_peak_human:1.18M
used_memory_peak_perc:88.35%
used_memory_overhead:948936
used_memory_startup:946208
used_memory_dataset:146312
used_memory_dataset_perc:98.17%
allocator_allocated:2616032
allocator_active:2842624
allocator_resident:5689344
allocator_muzzy:0
total_system_memory:1826394112
total_system_memory_human:1.70G
used_memory_lua:31744
used_memory_vm_eval:31744
used_memory_lua_human:31.00K
used_memory_scripts_eval:0
number_of_cached_scripts:0
number_of_functions:0
number_of_libraries:0
used_memory_vm_functions:32768
used_memory_vm_total:64512
used_memory_vm_total_human:63.00K
used_memory_functions:192
used_memory_scripts:192
used_memory_scripts_human:192B
maxmemory:0
maxmemory_human:0B
maxmemory_policy:noeviction
allocator_frag_ratio:1.07
allocator_frag_bytes:150560
allocator_rss_ratio:2.00
allocator_rss_bytes:2846720
rss_overhead_ratio:2.14
rss_overhead_bytes:6475776
mem_fragmentation_ratio:11.34
mem_fragmentation_bytes:11092168
mem_not_counted_for_evict:0
mem_replication_backlog:0
mem_total_replication_buffers:0
mem_clients_slaves:0
mem_clients_normal:1928
mem_cluster_links:0
mem_aof_buffer:0
mem_allocator:jemalloc-5.3.0
mem_overhead_db_hashtable_rehashing:0
active_defrag_running:0
lazyfree_pending_objects:0
lazyfreed_objects:0
# Persistence
loading:0
async_loading:0
current_cow_peak:0
current_cow_size:0
current_cow_size_age:0
current_fork_perc:0.00
current_save_keys_processed:0
current_save_keys_total:0
rdb_changes_since_last_save:2
rdb_bgsave_in_progress:0
rdb_last_save_time:1764555806
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:-1
rdb_current_bgsave_time_sec:-1
rdb_saves:0
rdb_last_cow_size:0
rdb_last_load_keys_expired:0
rdb_last_load_keys_loaded:0
aof_enabled:0
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_rewrites:0
aof_rewrites_consecutive_failures:0
aof_last_write_status:ok
aof_last_cow_size:0
module_fork_in_progress:0
module_fork_last_cow_size:0
# Stats
total_connections_received:2
total_commands_processed:8
instantaneous_ops_per_sec:0
total_net_input_bytes:218
total_net_output_bytes:432800
total_net_repl_input_bytes:0
total_net_repl_output_bytes:0
instantaneous_input_kbps:0.00
instantaneous_output_kbps:0.00
instantaneous_input_repl_kbps:0.00
instantaneous_output_repl_kbps:0.00
rejected_connections:0
sync_full:0
sync_partial_ok:0
sync_partial_err:0
expired_subkeys:0
expired_keys:0
expired_stale_perc:0.00
expired_time_cap_reached_count:0
expire_cycle_cpu_milliseconds:96
evicted_keys:0
evicted_clients:0
evicted_scripts:0
total_eviction_exceeded_time:0
current_eviction_exceeded_time:0
keyspace_hits:2
keyspace_misses:0
pubsub_channels:0
pubsub_patterns:0
pubsubshard_channels:0
latest_fork_usec:0
total_forks:0
migrate_cached_sockets:0
slave_expires_tracked_keys:0
active_defrag_hits:0
active_defrag_misses:0
active_defrag_key_hits:0
active_defrag_key_misses:0
total_active_defrag_time:0
current_active_defrag_time:0
tracking_total_keys:0
tracking_total_items:0
tracking_total_prefixes:0
unexpected_error_replies:0
total_error_replies:0
dump_payload_sanitizations:0
total_reads_processed:10
total_writes_processed:12
io_threaded_reads_processed:0
io_threaded_writes_processed:0
client_query_buffer_limit_disconnections:0
client_output_buffer_limit_disconnections:0
reply_buffer_shrinks:3
reply_buffer_expands:1
eventloop_cycles:25987
eventloop_duration_sum:10997368
eventloop_duration_cmd_sum:2580
instantaneous_eventloop_cycles_per_sec:9
instantaneous_eventloop_duration_usec:372
acl_access_denied_auth:0
acl_access_denied_cmd:0
acl_access_denied_key:0
acl_access_denied_channel:0
# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:11b588e942329b3f07bc77bc486c5c60be1a7919
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
# CPU
used_cpu_sys:1.296887
used_cpu_user:10.129402
used_cpu_sys_children:0.000000
used_cpu_user_children:0.000000
used_cpu_sys_main_thread:1.297919
used_cpu_user_main_thread:10.128088
# Modules
# Errorstats
# Cluster
cluster_enabled:0
# Keyspace
db0:keys=2,expires=0,avg_ttl=0,subexpiry=0
127.0.0.1:6379>
四、Redis 的 Key-Value
1. 16个逻辑库
默认在redis配置文件redis.conf中,提供了16个库,查看配置文件:
redis-cli
127.0.0.1:6379> config get databases
1) "databases"
2) "16"
127.0.0.1:6379>
数据库的编号都是从0开始,最大值为16-1=15
grep 16 /usr/local/redis/conf/redis.conf
[root@server2 ~]# redis-cli
127.0.0.1:6379> config get databases
1) "databases"
2) "16"
127.0.0.1:6379>
[root@server2 ~]# grep 16 /usr/local/redis/conf/redis.conf
# bind 192.168.1.100 10.0.0.1 # listens on two specific IPv4 addresses
databases 16
# -3: max size: 16 Kb <-- probably not recommended
# 16 bytes header. When a HyperLogLog using the sparse representation crosses
# A value greater than 16000 is totally useless, since at that point the
# 16 megabytes / 10 seconds, the client will get disconnected immediately
# disconnected if the client reaches 16 megabytes and continuously overcomes
[root@server2 ~]#
Redis 默认配置文件 redis.conf 中设置了 16 个逻辑数据库(编号 0 至 15)。
它们是 Redis 服务端在单个实例内提供的 数据隔离空间,类似于“命名空间”。通过 SELECT 命令(如 SELECT 1)可在客户端切换当前操作的数据库,默认连接的是 第 0 号库。
不同库之间的 Key 相互独立,但共用同一实例的资源(如内存、CPU、端口),适用于简单场景下的数据分类存储。
[root@server2 ~]# redis-cli
127.0.0.1:6379> select 0
OK
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> select 2
OK
127.0.0.1:6379[2]> select 3
OK
127.0.0.1:6379[3]>
2. Key 操作
NoSQL数据库,存储形式,键值对,键类似身份证号(不能重复,必须唯一)
key的命名规则不同于一般语言,键盘上除了空格、\n换行符外其他的大部分字符都可以使用。
但是像"my key"和"mykey\n"这样包含空格和换行的key是不允许的。
我们在使用的时候可以自己定义一个key的格式,但是要特别注意:
key不要太长,占内存,查询慢。
key不要太短,像u:1000:pwd:123456 就不如 user:1000:password:123456可读性好

2.1. ☆ 显示所有键 keys
# keys *
127.0.0.1:6379> set name ithaung
OK
127.0.0.1:6379> set age 25
OK
127.0.0.1:6379> keys *
1) "age"
2) "name"
127.0.0.1:6379>
2.2. ☆ 判断键是否存在 exists
# exists key 键名
存在1,不存在0
127.0.0.1:6379> exists key name
(integer) 1
127.0.0.1:6379> exists key age
(integer) 1
127.0.0.1:6379> exists key address
(integer) 0
127.0.0.1:6379>
2.3. ☆ 删除键 del
# del 键名
存在1,不存在0
127.0.0.1:6379> set name666 xiaoming
OK
127.0.0.1:6379> set name123 xiaohong
OK
127.0.0.1:6379> keys *
1) "name123"
2) "age"
3) "name666"
4) "name"
127.0.0.1:6379> del name123
(integer) 1
127.0.0.1:6379> del name666
(integer) 1
127.0.0.1:6379> keys *
1) "age"
2) "name"
127.0.0.1:6379>
2.4. ☆ 获取键类型 type
# type 键名
127.0.0.1:6379> keys *
1) "age"
2) "name"
127.0.0.1:6379> type key
none
127.0.0.1:6379> type name
string
127.0.0.1:6379> type age
string
127.0.0.1:6379>
2.5. ☆ 设置过期时间(单位s)expire
# set name test
# expire name 25
2.6. ☆ 查看剩余时间 ttl
# ttl name
127.0.0.1:6379> set name test
OK
127.0.0.1:6379> expire name 25
(integer) 1
127.0.0.1:6379> ttl name
(integer) 18
127.0.0.1:6379> ttl name
(integer) 14
127.0.0.1:6379> ttl name
(integer) 11
127.0.0.1:6379> ttl name
(integer) 9
127.0.0.1:6379> ttl name
(integer) 8
127.0.0.1:6379> ttl name
(integer) 7
127.0.0.1:6379> ttl name
(integer) -2
127.0.0.1:6379> ttl name
(integer) -2
127.0.0.1:6379>
| 返回值(整数) | 含义 |
|---|---|
| 正整数(如 3600) | 键存在,并且设置了过期时间,返回的是 剩余的秒数(例如 3600 表示还有 1 小时过期)。 |
| -1 | 键存在,但没有设置过期时间(永久有效)。 |
| -2 | 键不存在(可能从未设置过,或已过期并被自动删除)。 |
TTL是什么含义?
TTL(Time To Live),在计算机中,指数据(如数据包、缓存、键值对等)在系统或网络中允许存在的 “最大存活时长”。
除此之外,还有 EOL(End of Life,生命周期结束),指软件或硬件产品的 “官方支持的终止时间”,厂商不再提供更新、维护或技术支持。
3. 库操作
3.1. ☆ 查看当前库key数量 dbsize
# dbsize
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> dbsize
(integer) 0
127.0.0.1:6379> set name ithuang
OK
127.0.0.1:6379> dbsize
(integer) 1
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> set age 25
OK
127.0.0.1:6379> keys *
1) "age"
2) "name"
127.0.0.1:6379> dbsize
(integer) 2
127.0.0.1:6379>
3.2. ☆ 切换数据库 select
Redis 共16个库,index = number - 1
# select 0到15 # 下标从0到15
127.0.0.1:6379> client info
id=4 addr=127.0.0.1:42570 laddr=127.0.0.1:6379 fd=12 name= age=679 idle=0 flags=N db=0 sub=0 psub=0 ssub=0 multi=-1 watch=0 qbuf=26 qbuf-free=20448 argv-mem=10 multi-mem=0 rbs=1024 rbp=5 obl=0 oll=0 omem=0 tot-mem=22426 events=r cmd=client|info user=default redir=-1 resp=2 lib-name= lib-ver=
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> client info
id=4 addr=127.0.0.1:42570 laddr=127.0.0.1:6379 fd=12 name= age=683 idle=0 flags=N db=1 sub=0 psub=0 ssub=0 multi=-1 watch=0 qbuf=26 qbuf-free=20448 argv-mem=10 multi-mem=0 rbs=1024 rbp=5 obl=0 oll=0 omem=0 tot-mem=22426 events=r cmd=client|info user=default redir=-1 resp=2 lib-name= lib-ver=
127.0.0.1:6379[1]> select 2
OK
127.0.0.1:6379[2]> client info
id=4 addr=127.0.0.1:42570 laddr=127.0.0.1:6379 fd=12 name= age=687 idle=0 flags=N db=2 sub=0 psub=0 ssub=0 multi=-1 watch=0 qbuf=26 qbuf-free=20448 argv-mem=10 multi-mem=0 rbs=1024 rbp=5 obl=0 oll=0 omem=0 tot-mem=22426 events=r cmd=client|info user=default redir=-1 resp=2 lib-name= lib-ver=
127.0.0.1:6379[2]>
3.3. ☆ 清空当前库 flushdb
# flushdb
127.0.0.1:6379[2]> select 0
OK
127.0.0.1:6379> dbsize
(integer) 2
127.0.0.1:6379> keys *
1) "age"
2) "name"
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379>
3.4. ☆ 清空所有库 flushall
127.0.0.1:6379> flushall
OK
[root@redis ~]# redis-cli
127.0.0.1:6379> select 6
OK
127.0.0.1:6379[6]> keys *
1) "redis1"
127.0.0.1:6379[6]> select 7
OK
127.0.0.1:6379[7]> keys *
1) "test2"
2) "test"
127.0.0.1:6379[7]> select 0
OK
127.0.0.1:6379> flushall
OK
127.0.0.1:6379> select 6
OK
127.0.0.1:6379[6]> keys *
(empty array)
127.0.0.1:6379[6]> select 7
OK
127.0.0.1:6379[7]> keys *
(empty array)
127.0.0.1:6379[7]>
五、Redis 五大核心数据结构
1. string
string是redis最基本的类型
redis的string可以包含任何数据,包括jpg图片、base64编码或者序列化的对象
单个value值最大上限是512MB
如果只用string类型,redis就可以被看作加上持久化特性的memcached

☆ 设置与批量设置 set|mset
127.0.0.1:6379> set name itheima
OK
127.0.0.1:6379> get name
"itheima"
127.0.0.1:6379> mset name redis age 25 address canton
OK
127.0.0.1:6379> get name
"redis"
127.0.0.1:6379> keys *
1) "age"
2) "name"
3) "address"
127.0.0.1:6379> get age
"25"
127.0.0.1:6379> get address
"canton"
127.0.0.1:6379>
☆ 获取与批量获取 get|mget
127.0.0.1:6379> get name
"redis"
127.0.0.1:6379> mget name age address
1) "redis"
2) "25"
3) "canton"
☆ 增加与减少 incr|decr
# incr age 增加1
# decr age 减少1
# incrby age 2 增加2
# decrby age 3 减少3
127.0.0.1:6379> get age
"25"
127.0.0.1:6379> incr age
(integer) 26
127.0.0.1:6379> incr age
(integer) 27
127.0.0.1:6379> decr age
(integer) 26
127.0.0.1:6379> decr age
(integer) 25
127.0.0.1:6379> incrby age 2
(integer) 27
127.0.0.1:6379> decrby age 3
(integer) 24
127.0.0.1:6379> get age
"24"
127.0.0.1:6379>
☆ 追加 append
127.0.0.1:6379> append name 666
(integer) 8
127.0.0.1:6379> get name
"redis666"
☆ 截取 substr
# substr name start end
start:从哪里开始截取,默认从0,第一个字符开始
end:到哪里截取结束,必须要添加结束字符的索引号
127.0.0.1:6379> get name
"redis666"
127.0.0.1:6379> substr name 0 4
"redis"
127.0.0.1:6379> substr name 0 5
"redis6"
127.0.0.1:6379> substr name 5 7
"666"
127.0.0.1:6379>
小结
String 是 Redis 最基础、最常用的数据类型,本质是一个 binary-safe 的字节序列,可存储文本、数字或任何二进制数据。**单个字符串最大允许 512MB。**该类型性能极高,常用于缓存热点数据、分布式锁、计数器、限流器等高频场景,是 Redis 业务中使用最广泛的结构。
2. list
Redis 的 List 类型本质是一个双向链表,支持通过 LPUSH/RPUSH(头部/尾部插入)和 LPOP/RPOP(头部/尾部删除)操作灵活管理元素。
- 栈功能:若仅从同一端进出(如都从头部操作:LPUSH+ LPOP),则遵循 后进先出(LIFO) 原则,类似栈结构。
- 队列功能:若从一端进(如尾部 RPUSH)、另一端出(如头部 LPOP),则符合 先进先出(FIFO) 原则,类似队列(堆通常指优先级队列,此处更准确说是队列)。
这种双向操作特性使 List 既能当栈又能当队列,适用于消息队列、最新动态列表等场景。

首部(左 left) 尾部(右right) head tail
需求:显示最后登录的几个用户
设计实现:
① 登录一个用户,把用户名称或者id存储在list中
② 从左侧取第一个元素
特点:同一端进,同一端出(大部分以左为主)
用户:xiaohua xiaoming xiaobai
key名称:lastlogin
案例1:获取最后登录的用户
# 1. 首先清空测试环境(可选)
127.0.0.1:6379> DEL lastlogin
(integer) 1
# 2. 模拟用户登录 - 使用 LPUSH 从左侧添加
# 这样最新登录的用户总是在最前面
127.0.0.1:6379> LPUSH lastlogin xiaohua
(integer) 1
127.0.0.1:6379> LPUSH lastlogin xiaoming
(integer) 2
127.0.0.1:6379> LPUSH lastlogin xiaobai
(integer) 3
# 3. 查看当前列表中的所有用户
# 语法:LRANGE key start stop
# 0表示第一个元素,-1表示最后一个元素
127.0.0.1:6379> LRANGE lastlogin 0 -1
1) "xiaobai" # 最新登录的(最后push的)
2) "xiaoming" # 中间登录的
3) "xiaohua" # 最早登录的(最先push的)
# 4. 获取最后登录的2个用户
127.0.0.1:6379> LRANGE lastlogin 0 1
1) "xiaobai"
2) "xiaoming"
# 5. 再模拟一个新用户登录
127.0.0.1:6379> LPUSH lastlogin xiaohong
(integer) 4
# 6. 再次查看最新登录的2个用户
127.0.0.1:6379> LRANGE lastlogin 0 1
1) "xiaohong" # 最新登录的
2) "xiaobai" # 之前最新登录的
3. set(sadd)
Redis 的 set 是 无序且唯一的字符串集合(元素不重复,最大支持 2³²-1 个元素)。
除基础增删操作外,核心功能是通过 交集(intersection)、并集(union)、差集(difference) 快速处理多集合关系。set 是“数据结构”,而 sadd 是“操作 set 的命令”。
这些操作能高效实现 SNS 好友推荐(如求共同好友、交叉关注推荐),例如通过 SINTER找共同好友,SUNION合并好友圈,SDIFF分析差异好友。
案例1:朋友圈
设计:
key value
xiaomingFR xiaohong xiaoqiang xiaogang xiaobai xiaohei
xiaohongFR xiaoming xiaolv xiaolan xiaobai xiaohei
第一步:使用sadd添加xiaomingFR与xiaohongFR
127.0.0.1:6379> sadd xiaomingFR xiaohong xiaoqiang xiaogang xiaobai xiaohei
(integer) 5
127.0.0.1:6379> sadd xiaohongFR xiaoming xiaolv xiaolan xiaobai xiaohei
(integer) 5
127.0.0.1:6379> SMEMBERS xiaomingFR
1) "xiaohong"
2) "xiaoqiang"
3) "xiaogang"
4) "xiaobai"
5) "xiaohei"
127.0.0.1:6379> SMEMBERS xiaohongFR
1) "xiaoming"
2) "xiaolv"
3) "xiaolan"
4) "xiaobai"
5) "xiaohei"
第二步:求交集(共同好友)
127.0.0.1:6379> sinter xiaomingFR xiaohongFR
1) "xiaobai"
2) "xiaohei"
127.0.0.1:6379>
第三步:求并集(所有好友)
127.0.0.1:6379> sunion xiaomingFR xiaohongFR
1) "xiaohong"
2) "xiaoqiang"
3) "xiaogang"
4) "xiaobai"
5) "xiaohei"
6) "xiaoming"
7) "xiaolv"
8) "xiaolan"
127.0.0.1:6379>
第四步:求差集(互相推荐好友)
127.0.0.1:6379> sdiff xiaomingFR xiaohongFR
1) "xiaohong"
2) "xiaoqiang"
3) "xiaogang"
127.0.0.1:6379> sdiff xiaohongFR xiaomingFR
1) "xiaoming"
2) "xiaolv"
3) "xiaolan"
127.0.0.1:6379>
案例2:IP列表
# 向集合(ips)中添加多个IP地址成员(自动去重,重复IP不会重复存储)
# 命令:sadd 集合名 成员1 成员2 ...
sadd ips 10.1.1.11 10.1.1.12 # 将IP 10.1.1.11和10.1.1.12加入集合ips
# 检查指定IP是否为集合(ips)的成员(返回1表示存在,0表示不存在)
# 命令:sismember 集合名 成员
sismember ips 10.1.1.11 # 检查IP 10.1.1.11是否在集合ips中(预期返回1,存在)
# 检查另一个IP是否为集合(ips)的成员
sismember ips 10.1.1.100 # 检查IP 10.1.1.100是否在集合ips中(预期返回0,不存在)
127.0.0.1:6379> sadd ips 10.1.1.11 10.1.1.12
(integer) 2
127.0.0.1:6379> sismember ips 10.1.1.11
(integer) 1
127.0.0.1:6379> sismember ips 10.1.1.100
(integer) 0
127.0.0.1:6379> smembers ips
1) "10.1.1.11"
2) "10.1.1.12"
小结
set:无序,且天生去重
核心:求交集、并集、差集
4. zset(zadd)
Redis 的 Sorted Set(简称 ZSet)是一种 可排序的集合类型。 与普通 Set 一样,它保证 成员唯一性;与列表不同,它通过为每个成员关联一个 Score(浮点数权重) 来实现排序功能。 ZSet 内部使用 哈希表 + 跳表 组合结构,因此可以高效支持按 Score 排序、按范围查询、按排名称查询等操作。
核心特点:
- **元素唯一性:**与 Set 相同,ZSet 中的每个 元素(成员/Value)必须唯一(例如不能同时存在两个相同的用户ID)。
- **权重排序:**每个元素会关联一个 浮点数权值(Score),Redis 根据 Score 自动对所有元素排序(默认升序,也可降序查询)。
- **灵活排序:**支持按 Score 范围、排名称范围查询,满足“有序且去重”的复杂需求。
ZSet 与 Set 的区别:
Set:仅存储唯一元素,无排序功能(如标签集合)。
ZSet:存储唯一元素 + 权重 Score,元素按 Score 自动排序(如排行榜)。
Score(分数/权重) 是 ZSet(有序集合)中用于排序的数值,它决定了元素在集合中的位置顺序。
案例1:实现手机APP市场的软件排名
key : hotTop
id score name
1 2 qq
2 3 wechat
3 5 alipay
4 7 taobao
5 10 mi
6 8 jd
第一步:插入数据
# zadd hotTop 2 qq 3 wechat 5 alipay 7 taobao 10 mi 8 jd
第二步:排序,从小到大,qq -> wechat -> alipay -> taobao -> jd -> mi
# zrange hotTop 0 5
第三步:排序,从大到小,mi -> jd -> taobao -> alipay -> wecaht -> qq
# zrevrange hotTop 0 5
扩展:获取某个软件的score值
# zscore hotTop jd
# zscore hotTop taobao
扩展:更新某个软件的score值
# zincrby hotTop -2 jd #分数减2
# 从新打印前 5 名
# zrange hotTop 0 5
127.0.0.1:6379> zadd hotTop 2 qq 3 wechat 5 alipay 7 taobao 10 mi 8 jd
(integer) 6
127.0.0.1:6379> zrange hotTop 0 5
1) "qq"
2) "wechat"
3) "alipay"
4) "taobao"
5) "jd"
6) "mi"
127.0.0.1:6379> zrevrange hotTop 0 5
1) "mi"
2) "jd"
3) "taobao"
4) "alipay"
5) "wechat"
6) "qq"
127.0.0.1:6379> zscore hotTop jd
"8"
127.0.0.1:6379> zscore hotTop taobao
"7"
127.0.0.1:6379> zscore hotTop wechat
"3"
127.0.0.1:6379> zincrby hotTop -2 jd
"6"
127.0.0.1:6379> zscore hotTop jd
"6"
127.0.0.1:6379> zrange hotTop 0 5
1) "qq"
2) "wechat"
3) "alipay"
4) "jd"
5) "taobao"
6) "mi"
127.0.0.1:6379>
小结
和set一样,zset也是集合的一种;不同点在于zset是有序集合,set是无序集合;共同点是元素唯一。
5. hash(哈希)
作用:使用Redis做缓存,除了可以使用string,还可以使用hash结构,比string压缩效率和使用效率更高。
hash存储数据和关系型数据库(mysql)存储的一条数据的结构极为相似
key:value(field:value)
insert into table(id,name,sex,address) values (1,'王维','男',18,'北京市昌平区')
id:1
name:'王维'
sex:'男'
age:18
address:'北京市昌平区'
☆ 设置hash数据
127.0.0.1:6379> hmset devops username redis age 18 email redis@itcast.cn
HMSET:一次性设置多个字段-值对
结构:
键:devops
字段:username → 值:redis
字段:age → 值:18
字段:email → 值:redis@itcast.cn
127.0.0.1:6379> hgetall devops # 查看多个值
127.0.0.1:6379> hmset devops username redis age 18 email redis@itcast.cn
OK
127.0.0.1:6379> hgetall devops
1) "username"
2) "redis"
3) "age"
4) "18"
5) "email"
6) "redis@itcast.cn"
☆ 获取的指定的field字段信息
127.0.0.1:6379> hget devops username
127.0.0.1:6379> hmget devops username age email
127.0.0.1:6379> hget devops username
"redis"
127.0.0.1:6379> hmget devops username age email
1) "redis"
2) "18"
3) "redis@itcast.cn"
☆ 更新devops的age字段信息
127.0.0.1:6379> hincrby devops age 1
127.0.0.1:6379> hmget devops username age
1) "redis"
2) "18"
127.0.0.1:6379> hincrby devops age 1
(integer) 19
127.0.0.1:6379> hget devops age
"19"
☆ 获取某个key的所有field信息
127.0.0.1:6379> hkeys devops
127.0.0.1:6379> hkeys devops
1) "username"
2) "age"
3) "email"
☆ 获取某个key的所有field的所有value信息
127.0.0.1:6379> hvals devops
127.0.0.1:6379> hkeys devops
1) "username"
2) "age"
3) "email"
127.0.0.1:6379> hvals devops
1) "redis"
2) "19"
3) "redis@itcast.cn"
☆ 删除指定的field字段
127.0.0.1:6379> hdel devops age
127.0.0.1:6379> hget devops age
"19"
127.0.0.1:6379> hdel devops age
(integer) 1
127.0.0.1:6379> hget devops age
(nil)
☆ 获取devops的key数量
127.0.0.1:6379> hlen devops
127.0.0.1:6379> hlen devops
(integer) 2
127.0.0.1:6379> hkeys devops
1) "username"
2) "email"
☆ 查询指定field是否存在
127.0.0.1:6379> hexists devops name
127.0.0.1:6379> hexists devops username
127.0.0.1:6379> hkeys devops
1) "username"
2) "email"
127.0.0.1:6379> hexists devops name
(integer) 0
127.0.0.1:6379> hexists devops username
(integer) 1
小结
Redis既可以作为存储也可以作为NoSQL数据库使用
存储数据时,如果数据与数据之间关联度不太大 => string
存储数据时,如果数据与数据之间关联度还比较大=> hash
相对而言,hash拥有更高的压缩比
总结
Redis 常说的 5 大数据类型:String、List、Set、ZSet、Hash 加上 3 个高级类型:Bitmap、HyperLogLog、Stream 总计:8 种常用数据结构
Redis 基础 5 大数据类型
| 类型 | 说明 | 常用场景 |
|---|---|---|
| String | 字符串(包括数字、文本、二进制),最大 512MB | 缓存、计数器、分布式锁 |
| Hash | 键值对集合,类似小型对象 | 用户信息、商品信息 |
| List | 双向链表 | 队列、栈、消息流 |
| Set | 无序集合、元素唯一 | 去重、共同好友、标签 |
| ZSet(Sorted Set) | 带分数的有序集合,按 score 排序 | 排行榜、延时队列 |
Redis 扩展 3 大高级数据类型
| 类型 | 说明 | 常用场景 |
|---|---|---|
| Bitmap | 位图,基于 String 的位操作 | 签到、用户活跃统计 |
| HyperLogLog | 基于概率的基数统计结构 | UV 统计(去重人数) |
| Stream | 消息流(类似 Kafka) | 消息队列、事件系统(Redis 5.0+) |
六、Redis数据持久化操作(重点)
1. 基本概念
数据持久化(数据在服务或者软件重启之后不丢失)
如果数据只存在内存中,肯定会丢失,实现持久化,就需要把数据存储到磁盘中

2. RDB 持久化 - Snappshoting 快照
RDB(Redis DataBase)是 Redis 默认开启的持久化方式,通过 定时生成内存数据的二进制快照(snapshot) 将当前数据保存到磁盘文件(默认 dump.rdb),重启时直接加载快照恢复数据。
其特点是 恢复速度快、文件体积小,但可能存在最后一次快照之后的数据有丢失风险。
默认Snappshoting是开启的,而且有一个"拍照"的频率。
自动备份机制
触发条件:只有满足触发条件(指定时间内至少发生指定次数的增删改操作),才会自动备份!
优化Redis配置文件
[root@redis ~]# mv /usr/local/redis/conf/redis.conf /usr/local/redis/conf/redis.conf.bak
[root@redis ~]# grep -Ev "^$|#" /usr/local/redis/conf/redis.conf.bak > /usr/local/redis/conf/redis.conf
[root@redis ~]# cat /usr/local/redis/conf/redis.conf
bind 0.0.0.0
protected-mode yes
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize yes
pidfile /var/run/redis_6379.pid
loglevel notice
logfile ""
databases 16
always-show-logo no
set-proc-title yes
proc-title-template "{title} {listen-addr} {server-mode}"
locale-collate ""
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
rdb-del-sync-files no
dir /usr/local/redis
replica-serve-stale-data yes
replica-read-only yes
repl-diskless-sync yes
repl-diskless-sync-delay 5
repl-diskless-sync-max-replicas 0
repl-diskless-load disabled
repl-disable-tcp-nodelay no
replica-priority 100
acllog-max-len 128
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
lazyfree-lazy-user-del no
lazyfree-lazy-user-flush no
oom-score-adj no
oom-score-adj-values 0 200 800
disable-thp yes
appendonly no
appendfilename "appendonly.aof"
appenddirname "appendonlydir"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
aof-timestamp-enabled no
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-listpack-entries 512
hash-max-listpack-value 64
list-max-listpack-size -2
list-compress-depth 0
set-max-intset-entries 512
set-max-listpack-entries 128
set-max-listpack-value 64
zset-max-listpack-entries 128
zset-max-listpack-value 64
hll-sparse-max-bytes 3000
stream-node-max-bytes 4096
stream-node-max-entries 100
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes
jemalloc-bg-thread yes
[root@redis ~]#
配置文件/usr/local/redis/conf/redis.conf save配置说明
save 900 1 # 15分钟内(900秒)至少有1个key被修改 → 触发快照
save 300 100 # 5分钟内(300秒)至少有100个key被修改 → 触发快照
save 60 10000 # 1分钟内(60秒)至少有10000个key被修改 → 触发快照
三个条件满足任意一个即可触发快照(“或”关系),例如若 1 分钟内修改了 10001 个 key,则立即生成快照。
触发后,计时会重置。
下面的
save 3600 1 300 100 60 10000
等价的分行写法
save 3600 1
save 300 100
save 60 10000
可以自定义配置
# 语法:save 秒数 redis事务型操作(增删改)次数
save 10 2 # 10秒内至少2个写操作触发快照(原配置可注释或删除)
[root@redis ~]# echo 'save 10 2' >> /usr/local/redis/conf/redis.conf
[root@redis ~]# systemctl restart redis
[root@redis ~]# systemctl status redis
快照文件:
[root@redis ~]# grep dump.rdb /usr/local/redis/conf/redis.conf
dbfilename dump.rdb
从Redis6版本开始,引入了一个dir参数 => 代表默认保存路径,之前版本默认安装路径 => /usr/local/redis
[root@redis ~]# redis-cli
127.0.0.1:6379> config get dir
1) "dir"
2) "/"
可以查看默认保存路径
建议直接更改配置518行,数据存放路径
[root@redis ~]# vim /usr/local/redis/conf/redis.conf
dir /usr/local/redis
配置完成后,一定要记得重启redis
[root@redis ~]# systemctl restart redis
[root@redis ~]# systemctl status redis
[root@redis ~]# redis-cli
127.0.0.1:6379> config get dir
1) "dir"
2) "/usr/local/redis"
127.0.0.1:6379>
测试备份频率
在10s内,进行两个key的改变,查看备份效果:
[root@redis ~]# redis-cli
127.0.0.1:6379> set num1 1
OK
127.0.0.1:6379> set num2 2
OK
127.0.0.1:6379>
测试结果:查看dump.rdb文件大小的变化
[root@redis ~]# ll /usr/local/redis/
total 4
drwxr-xr-x. 2 root root 134 Nov 28 20:56 bin
drwxr-xr-x. 2 root root 46 Nov 29 16:17 conf
-rw-r--r--. 1 root root 109 Nov 29 16:18 dump.rdb
如果 11s 内只有1个key改变,会触发条件吗?
不会触发,仍使用上一次的快照文件。
如果这时,第 11s 时 Redis 宕机,从上次快照到宕机前的数据会丢失吗?
会丢失,这是 RDB 的固有缺点 —— 依赖 “触发条件 + 时间窗口”,可能丢失两次快照之间的增量数据。
总结
RDB 因 “条件触发” 特性,在未满足快照条件时发生宕机,会丢失上次快照后的所有数据。
即使只有 1 个 key 变更也不例外。
手动快照备份
127.0.0.1:6379> save 或 bgsave
127.0.0.1:6379> save
OK
127.0.0.1:6379> bgsave
Background saving started
127.0.0.1:6379>
☆ save
使用 save 的时候,在主程序中执行会 阻塞 当前 Redis 服务器,直到持久化工作完成。执行 save 命令期间, Redis 不能处理其他命令,所以生产上禁止使用!
☆ bgsave(Background Save)
Redis 会在后台(Background)异步对所有数据进行快照操作, 不阻塞快照同时还可以响应客户端请求。
该触发方式会 fork 一个子进程,由子进程复制持久化过程。
这个操作是子进程在后台完成的,这就允许父进程同时还可以修改数据。
☆ 总结
| 命令 | 行为 | 是否阻塞 | 适用场景 |
|---|---|---|---|
| save | 在主线程中同步执行快照,期间 Redis 完全阻塞(无法处理其他请求) | ✅ 阻塞 | 禁止线上使用(仅测试或紧急情况) |
| bgsave | 在后台异步执行快照(fork 子进程处理),主线程 继续响应客户端请求 | ❌ 不阻塞 | 生产环境推荐(安全且高效) |
lastsave
lastsave
可以通过lastsave命令获取最后一次成功的执行快照时间。
运行效果:
[root@redis ~]# redis-cli
127.0.0.1:6379> set num1 1
OK
127.0.0.1:6379> set num2 2
OK
127.0.0.1:6379> save
OK
127.0.0.1:6379> bgsave
Background saving started
127.0.0.1:6379> lastsave
(integer) 1764404398
获取一个看不懂的时间戳,需要转换一下
date -d @[redis内获取的时间戳]
比如
date -d @1764404398
[root@redis ~]# redis-cli
127.0.0.1:6379> set num1 1
OK
127.0.0.1:6379> set num2 2
OK
127.0.0.1:6379> save
OK
127.0.0.1:6379> bgsave
Background saving started
127.0.0.1:6379> lastsave
(integer) 1764404398
127.0.0.1:6379>
[root@redis ~]# date -d @1764404398
Sat Nov 29 04:19:58 PM CST 2025
[root@redis ~]# date -R
Sat, 29 Nov 2025 16:21:22 +0800
[root@redis ~]#
CST,China Standard Time 中国标准时间。
数据还原
[root@redis ~]# rm -rf * # 这个操作可选
[root@redis ~]# ll /usr/local/redis/
total 4
drwxr-xr-x. 2 root root 134 Nov 28 20:56 bin
drwxr-xr-x. 2 root root 46 Nov 29 16:17 conf
-rw-r--r--. 1 root root 109 Nov 29 16:39 dump.rdb
[root@redis ~]# redis-cli
127.0.0.1:6379> set test1 2025
OK
127.0.0.1:6379> set test2 2026
OK
127.0.0.1:6379> exit
触发自动备份机制
[root@redis ~]# ll /usr/local/redis/
total 4
drwxr-xr-x. 2 root root 134 Nov 28 20:56 bin
drwxr-xr-x. 2 root root 46 Nov 29 16:17 conf
-rw-r--r--. 1 root root 129 Nov 29 16:40 dump.rdb
[root@redis ~]# cp /usr/local/redis/dump.rdb ./
[root@redis ~]# ll
total 4
-rw-r--r--. 1 root root 129 Nov 29 16:40 dump.rdb
[root@redis ~]# redis-cli
127.0.0.1:6379> get test1
"2025"
127.0.0.1:6379> get test2
"2026"
127.0.0.1:6379> del test1 test2
(integer) 2
127.0.0.1:6379> get test1
(nil)
127.0.0.1:6379> get test2
(nil)
127.0.0.1:6379> exit
[root@redis ~]# ll /usr/local/redis/
total 4
drwxr-xr-x. 2 root root 134 Nov 28 20:56 bin
drwxr-xr-x. 2 root root 46 Nov 29 16:17 conf
-rw-r--r--. 1 root root 109 Nov 29 16:41 dump.rdb
[root@redis ~]# systemctl stop redis
[root@redis ~]# cp dump.rdb /usr/local/redis/
cp: overwrite '/usr/local/redis/dump.rdb'? y
[root@redis ~]# systemctl start redis
[root@redis ~]# redis-cli
127.0.0.1:6379> get test1
"2025"
127.0.0.1:6379> get test2
"2026"
127.0.0.1:6379>
RDB高级配置
☆ 关键配置参数 (redis.conf)
a) stop-writes-on-bgsave-error
默认:yes 如果配置成 no,表示不停止写,也就是允许在后台快照写入失败时,Redis 仍接受新写请求,不阻断服务。
b) rdbcompression
默认:yes
对于存储到磁盘中的快照,可以进行压缩存储。
如果是的话,redis会采用LZF算法进行压缩。
如果你不想消耗CPU来进行压缩的话,可以设置为关闭此功能。
c) rdbchecksum
默认:yes
在存储快照后,还可以让redis使用CRC64算法来进行数据校验。
但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。
d) rdb-del-sync-files
默认:no
默认情况下,保留那些没持久化的 RDB 文件,以防后面需要用。
☆ RDB快照触发场景 (了解)
除配置的 save 规则外,以下操作也会触发 RDB 快照:
- 手动执行 save/bgsave 命令;
- 执行 flushall 清空数据库并持久化(生成空 RDB 文件,无实际意义);
- 主从复制时,主节点自动触发快照发送给从节点;
- 执行 shutdown 且未开启 AOF 持久化时,自动保存最后一次快照。
☆ 禁用RDB快照
若需完全关闭 RDB,可通过以下方式:
# 方式1:命令行临时禁用(重启后恢复原配置)
127.0.0.1:6379> config set save ""
# 方式2:修改配置文件永久禁用
vim /usr/local/redis/conf/redis.conf
# 添加或修改:save "" # 空引号表示禁用所有自动快照规则
127.0.0.1:6379> config get save
1) "save"
2) "10 2"
127.0.0.1:6379> config set save ""
OK
127.0.0.1:6379> config get save
1) "save"
2) ""
或者
总结
| 优点 | 缺点 |
|---|---|
| 1. 恢复速度快:单文件加载比 AOF 日志重放更快(适合大规模数据恢复)。 | 1. 可能丢数据:若 Redis 宕机发生在两次快照之间,会丢失最后一次快照后的所有变更(如 10 秒内 1 个 key 变更未触发快照)。 |
| 2. 文件紧凑:二进制格式存储,适合备份和传输(可按业务定时归档不同版本的 RDB)。 | 2. 全量同步压力:大数据量时 fork 子进程可能导致瞬时 I/O 和 CPU 飙升(如 1 天修改 1000 次,同步数据量大)。 |
| 3. 适合容灾备份:可按小时/天备份多份 RDB 文件,支持恢复到不同时间点。 | 3. fork 耗时风险:数据集极大时,fork 子进程可能阻塞主线程几毫秒至秒级(影响服务响应)。 |
3. AOF持久化(日志追加)
AOF(Append Only File) 是 Redis 的另一种持久化方式。
它不记录数据快照,而是记录所有写操作命令(读操作不记录),就像数据库的“操作日志”。
Redis 重启时,通过重新执行这些命令恢复数据。
类似 MySQL 的 BinLog 重放
核心特点:
- 只追加不修改:AOF 文件仅允许在末尾追加新命令(增删改内容),不允许直接编辑或删除已有内容。
- 数据恢复可靠:通过重放日志,能精确还原到崩溃前的状态(丢失数据量可控)。
- 文件可读性强:命令以 Redis 协议格式存储,人类可读(如 SET key value)。
工作流程 (从命令到恢复)
| 步骤 | 详解 |
|---|---|
| ①命令接收 | 客户端发送的写操作(如 SET name "redis")先到达 Redis 服务端。 |
| ②缓存写入 | 命令不会直接写入磁盘,而是先存入 AOF 缓存区(内存区域),避免频繁磁盘 I/O。 |
| ③策略同步 | AOF缓存会根据AOF缓存区 同步文件的三种写回策略 将命令写入磁盘上的AOF文件。 |
| ④文件优化 | 随着 AOF 文件变大,Redis 会根据规则进行命令的合并( 又称AOF重写 ),从而起到AOF文件压缩的目的。 |
| ⑤重启恢复 | Redis 重启时,读取 AOF 文件 并 按顺序执行所有写命令,重建原始数据集。 |
Redis 当中,只要备份做的好,重启能解决 90% 以上的问题;
核心配置
☆ 开启 AOF
默认情况下,Redis 未开启 AOF,需手动修改配置文件(redis.conf):
vim /usr/local/redis/conf/redis.conf
appendonly yes # 开启 AOF(原默认值为 no)
☆ 三种写回策略
三种写回策略小结:
☆ 文件位置与命名
Redis 6或之前版本: AOF 保存文件的位置和 RDB 保存文件的位置一样,都是通过 redis.conf 配置文件中的 dir 配置的。
Redis 7: redis.conf 配置文件中除了要设置dir以外,还新增加了一个属性appenddirname 。
AOF保存文件的位置:dir + appenddirname
[root@redis ~]# vim /usr/local/redis/conf/redis.conf
...
515 # The Append Only File will also be created inside this directory.
516 #
517 # Note that you must specify a directory here, not a file name.
518 dir /usr/local/redis
...
1416 # Append-only file names are created by Redis following a specific pattern.
1417 # The file name's prefix is based on the 'appendfilename' configuration
1418 # parameter, followed by additional information about the sequence and type.
1419 #
1420 # For example, if appendfilename is set to appendonly.aof, the following file
1421 # names could be derived:
1422 #
1423 # - appendonly.aof.1.base.rdb as a base file.
1424 # - appendonly.aof.1.incr.aof, appendonly.aof.2.incr.aof as incremental files.
1425 # - appendonly.aof.manifest as a manifest file.
1426
1427 appendfilename "appendonly.aof"
1428
1429 # For convenience, Redis stores all persistent append-only files in a dedicated
1430 # directory. The name of the directory is determined by the appenddirname
1431 # configuration parameter.
1432
1433 appenddirname "appendonlydir"
# 记得重启redis
[root@redis ~]# systemctl restart redis
[root@redis ~]# systemctl status redis
# 查看目录
[root@redis ~]# ll /usr/local/redis/appendonlydir
[root@redis ~]# ll /usr/local/redis/
total 4
drwxr-xr-x. 2 root root 134 Nov 28 20:56 bin
drwxr-xr-x. 2 root root 46 Nov 29 16:52 conf
-rw-r--r--. 1 root root 129 Nov 29 16:39 dump.rdb
[root@redis ~]# systemctl restart redis
[root@redis ~]# systemctl status redis
● redis.service - redis-server
Loaded: loaded (/etc/systemd/system/redis.service; enabled; preset: disabl>
Active: active (running) since Fri 2026-03-13 09:48:51 CST; 5s ago
Process: 2029 ExecStart=/usr/local/redis/bin/redis-server /usr/local/redis/>
Main PID: 2030 (redis-server)
Tasks: 6 (limit: 22927)
Memory: 7.3M
CPU: 57ms
CGroup: /system.slice/redis.service
└─2030 "/usr/local/redis/bin/redis-server 0.0.0.0:6379"
Mar 13 09:48:51 redis systemd[1]: Starting redis-server...
Mar 13 09:48:51 redis systemd[1]: Started redis-server.
[root@redis ~]# ll /usr/local/redis/
total 4
drwxr-xr-x. 2 root root 103 Nov 29 16:52 appendonlydir
drwxr-xr-x. 2 root root 134 Nov 28 20:56 bin
drwxr-xr-x. 2 root root 46 Nov 29 16:52 conf
-rw-r--r--. 1 root root 129 Nov 29 16:39 dump.rdb
验证测试
[root@redis ~]# ll /usr/local/redis/
total 4
drwxr-xr-x. 2 root root 103 Nov 29 16:52 appendonlydir
drwxr-xr-x. 2 root root 134 Nov 28 20:56 bin
drwxr-xr-x. 2 root root 46 Nov 29 16:52 conf
-rw-r--r--. 1 root root 129 Nov 29 16:39 dump.rdb
[root@redis ~]# ll /usr/local/redis/appendonlydir/
total 8
-rw-r--r--. 1 root root 88 Nov 29 16:52 appendonly.aof.1.base.rdb
-rw-r--r--. 1 root root 0 Nov 29 16:52 appendonly.aof.1.incr.aof
-rw-r--r--. 1 root root 88 Nov 29 16:52 appendonly.aof.manifest
添加一些数据
redis-cli
127.0.0.1:6379 > set name devops
127.0.0.1:6379 > set age 25
127.0.0.1:6379 > set address canton
查看AOF文件
[root@redis ~]# ll /usr/local/redis/appendonlydir/
total 8
-rw-r--r--. 1 root root 88 Nov 29 16:52 appendonly.aof.1.base.rdb
-rw-r--r--. 1 root root 0 Nov 29 16:52 appendonly.aof.1.incr.aof
-rw-r--r--. 1 root root 88 Nov 29 16:52 appendonly.aof.manifest
[root@redis ~]# redis-cli
127.0.0.1:6379> set name devops
OK
127.0.0.1:6379> set age 25
OK
127.0.0.1:6379> set address canton
OK
127.0.0.1:6379> keys *
1) "address"
2) "age"
3) "name"
127.0.0.1:6379> exit
[root@redis ~]# ll /usr/local/redis/appendonlydir/
total 12
-rw-r--r--. 1 root root 88 Nov 29 16:52 appendonly.aof.1.base.rdb
-rw-r--r--. 1 root root 126 Nov 29 16:54 appendonly.aof.1.incr.aof
-rw-r--r--. 1 root root 88 Nov 29 16:52 appendonly.aof.manifest
[root@redis ~]#
数据恢复
[root@redis ~]# redis-cli
127.0.0.1:6379> set name devops
OK
127.0.0.1:6379> set age 25
OK
127.0.0.1:6379> set address canton
OK
127.0.0.1:6379> exit
[root@redis ~]# ll /usr/local/redis/appendonlydir/
total 12
-rw-r--r--. 1 root root 88 Nov 29 16:52 appendonly.aof.1.base.rdb
-rw-r--r--. 1 root root 126 Nov 29 16:54 appendonly.aof.1.incr.aof
-rw-r--r--. 1 root root 88 Nov 29 16:52 appendonly.aof.manifest
[root@redis ~]# cp /usr/local/redis/appendonlydir/appendonly.aof.1.incr.aof ./
[root@redis ~]# systemctl restart redis
[root@redis ~]# redis-cli
127.0.0.1:6379> get name
"devops"
127.0.0.1:6379> get age
"25"
127.0.0.1:6379> get address
"canton"
127.0.0.1:6379> del name age address
(integer) 3
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> get age
(nil)
127.0.0.1:6379> get address
(nil)
127.0.0.1:6379> exit
[root@redis ~]# systemctl stop redis
[root@redis ~]# ls
appendonly.aof.1.incr.aof dump.rdb
[root@redis ~]# ll /usr/local/redis/appendonlydir/
total 12
-rw-r--r--. 1 root root 88 Nov 29 16:52 appendonly.aof.1.base.rdb
-rw-r--r--. 1 root root 194 Nov 29 16:58 appendonly.aof.1.incr.aof
-rw-r--r--. 1 root root 88 Nov 29 16:52 appendonly.aof.manifest
[root@redis ~]# cp appendonly.aof.1.incr.aof /usr/local/redis/appendonlydir/
cp: overwrite '/usr/local/redis/appendonlydir/appendonly.aof.1.incr.aof'? y
[root@redis ~]# systemctl start redis
[root@redis ~]# redis-cli
127.0.0.1:6379> keys *
1) "address"
2) "age"
3) "name"
127.0.0.1:6379> get name
"devops"
127.0.0.1:6379> get age
"25"
127.0.0.1:6379> get address
"canton"
127.0.0.1:6379> exit
[root@redis ~]#
appendonlydir目录下三个文件的作用对比
appendonly.aof.1.base.rdbRDB(二进制)基础数据快照包含某个时间点的完整数据镜像
appendonly.aof.1.incr.aofAOF(文本)增量操作日志记录 BASE 文件之后的写命令
appendonly.aof.manifestJSON(文本)文件清单和版本管理管理文件序列和加载顺序
总结
4. RDB vs AOF
| 特性 | RDB(快照) | AOF(Append Only File) |
|---|---|---|
| 数据形式 | 内存数据的二进制快照(时间点备份) | 记录所有写操作命令(日志) |
| 恢复方式 | 直接加载快照文件 | 重启时重放命令 |
| 数据安全性 | 可能丢失最后一次快照后的所有数据 | 可控丢失(默认每秒同步,最多丢 1 秒数据) |
| 文件大小 | 更紧凑(仅存数据状态) | 通常比 RDB 大(记录详细命令) |
| 性能影响 | 全量同步可能阻塞主线程(fork 压力) | 写操作需同步到磁盘(依赖策略,默认每秒同步性能较好) |
| 适用场景 | 对恢复速度要求高(如大数据量备份) | 对数据安全性要求高(如金融业务) |
生产建议:AOF + RDB 混合使用(Redis 4.0+ 支持),兼顾数据安全与恢复效率!
5. RDB + AOF 混合模式
**RDB + AOF 混合模式,**指在同一 Redis 实例中既开启 RDB 快照,又开启 AOF 日志,结合两者优势:
- RDB:提供 快速恢复(单文件加载效率高)和 全量数据备份(时间点快照)。
- AOF:提供 数据高可靠性(记录所有写操作,丢失数据量更小)。
核心价值:
通过混合模式,既保留 RDB 的快速加载能力,又弥补 AOF 文件体积大、恢复慢的缺点,实现 “又快又安全” 的数据持久化。
☆ 共存优先级:AOF 优先于 RDB
翻译如下:
AOF 和 RDB 持久化可以同时启用,不会有问题。
如果启动时启用了 AOF,Redis 将加载 AOF ,即文件具有更好的持久性保证。则 AOF 的优先级高于 RDB。
☆ 数据恢复顺序及加载流程
同时开启 RDB 和 AOF 时, Redis 默认先优加载 AOF ,则不去加载 RDB (可以说和 RDB 毫无关系)。
如果 AOF 文件不存在,会刷新一个空的 AOF 配置,而忽略 RDB 文件。
☆ 开启 RDB 和 AOF 混合模式
结合了 RDB 和 AOF 的优点,既能快速加载又能避免丢失过多的数据。江湖人称“ 鸳鸯锅 ”
配置文件中 aof-use-rdb-preamble 的默认值为 yes 。 yes 表示开启,设置为 no 表示禁用。
用 RDB 快照做 “基础数据”,用 AOF 日志补 “最新操作”,既解决了纯 RDB 丢数据的问题,又解决了纯 AOF 恢复慢、文件大的问题,是现在 Redis 推荐的持久化搭配(默认开启)。
RDB+AOF 的混合方式
- RDB 镜像做全量持久化,AOF 做增量持久化。
- 先使用 RDB 进行快照存储,然后使用 AOF 持久化记录所有的写操作。
- 当重写策略满足或手动触发重写的时候,将最新的数据存储为新的 RDB 记录。
这样的话,重启服务的时候会从 RDB 和 AOF 两部分恢复数据,既保证了数据完整性,又提高了恢复数据的性能。
简单来说:
混合持久化方式产生的文件一部分是 RDB 格式,一部分是 AOF 格式。即 AOF 包括了 RDB 头部 + AOF 混写。
时间点恢复(了解)
https://www.percona.com/blog/perform-point-in-time-recovery-pitr-in-valkey-redis/
总结
掌握:学会开启与恢复 RDB、学会开启与恢复 AOF 即可!
- RDB 适用于一般的数据持久化使用,效率高,数据迁移方便
- AOF 适合于增量备份、数据实时性备份要求更高的情况
RDB 和 AOF 同时开启,Redis听谁的?
① 听 AOF 的,RDB 与 AOF 同时开启默认加载 AOF 的配置文件
② 相同数据集,AOF 文件要远大于 RDB 文件,恢复速度慢于 RDB
③ AOF 运行效率慢于 RDB,但是同步策略效率好,异步效率和 RDB 相同
概括:
生产环境都是混合模式居多,RDB 负责全量备份,AOF 适合增量备份,RDB 恢复数据快。
如果只能选一个:一般场景用 RDB,实时要求高场景用 AOF。
七、Redis 企业实战
1. Redis 主从复制
Redis 主从复制原理
1)第一次同步时,从库会把主库的数据整体拉取一份(全量同步)
主库会生成一个数据快照,并把这份快照发给从库,从库加载后与主库保持一致。
2)全量同步完成后,主库会把这期间发生的写操作再补发给从库
这样从库不会漏掉主库在同步过程中产生的新数据。
3)进入正常工作后,主库的每一条写操作都会实时推送给从库(增量同步)
从库按顺序执行这些写命令,从而与主库持续保持数据一致。
4)如果从库短暂断线,重新连接后会尽量只同步缺失的部分命令(部分同步)
避免每次都全量同步,提高效率。
5)主从之间维持长连接,通过心跳与偏移量确保同步状态正常
这样主库可以知道从库是否在线、是否落后。
注意:
主从复制使用的是“快照 + 写命令流”的方式,与 RDB/AOF 是否开启持久化无关,即使持久化关闭也不影响主从复制正常工作。
主从环境
| 主机名 | IP | Redis版本 | 角色 |
|---|---|---|---|
| redis01 | 192.168.88.101 | redis-7.4.0 | master |
| redis02 | 192.168.88.102 | redis-7.4.0 | slave |
优化Linux环境
sed -i -r 's/SELINUX=[ep].*/SELINUX=disabled/g' /etc/selinux/config
setenforce 0
systemctl stop firewalld &> /dev/null
systemctl disable firewalld &> /dev/null
iptables -F
改主机名
hostnamectl set-hostname redis01 && bash
hostnamectl set-hostname redis02 && bash
[root@redis01 ~]# redis-cli --version
redis-cli 7.4.0
准备redis02,需要提前安装Redis
第一步:找到对应的安装包资源,使用wget命令下载,这里安装的7.4.0版本。
安装包资源地址:https://download.redis.io/releases/
第二步:上传或者下载Redis到Linux系统中
wget https://download.redis.io/releases/redis-7.4.0.tar.gz
第三步:配置=>编译=>安装
tar -zxvf redis-7.4.0.tar.gz
cd redis-7.4.0
yum install epel-release -y
yum install make gcc jemalloc jemalloc-devel -y
make
make PREFIX=/usr/local/redis install
第四步:配置环境变量
echo 'PATH=$PATH:/usr/local/redis/bin/' >> /etc/profile && source /etc/profile
优化配置文件
mkdir /usr/local/redis/conf -p
cp redis.conf /usr/local/redis/conf
修改配置文件redis.conf
bind 0.0.0.0 # 允许所有IP连接
daemonize yes # 允许后台运行
创建 redis.service
cat >/etc/systemd/system/redis.service<<EOF
[Unit]
Description=redis-server
After=network.target
[Service]
Type=forking
ExecStart=/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis.conf
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
过量使用内存设置为1
echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf
sysctl -p
systemctl daemon-reload
systemctl start redis
systemctl enable redis
systemctl status redis --no-pager
[root@redis02 ~]# redis-cli --version
redis-cli 7.4.0
建议清理一下数据,redis01和redis02都要执行flushall
redis-cli
flushall
操作之前,可以把redis01和redis02拍摄一个快照
第一步:配置 master 192.168.88.101
vim /usr/local/redis/conf/redis.conf
开启监听,在网络中与其他服务器进行网络交互的网卡
bind的ip指的是其他的主机需要和这个主机通讯的ip
bind 0.0.0.0 # 允许所有IP连接
protected-mode no # 关闭redis安全保护机制,允许主从、哨兵、集群中各节点之间的相互访问,没有安全限制
logfile "/usr/local/redis/redis.log" #日志文件存放路径
replica-read-only no
删除注释行和空行(可选)
[root@web01 conf]# vim redis.conf
:g/#/d 删除注释行
:g/^$/d 删除空行
[root@redis01 ~]# vim /usr/local/redis/conf/redis.conf
[root@redis01 ~]# cat /usr/local/redis/conf/redis.conf
bind 0.0.0.0
protected-mode no
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize yes
pidfile /var/run/redis_6379.pid
loglevel notice
logfile "/usr/local/redis/redis.log"
databases 16
always-show-logo no
set-proc-title yes
proc-title-template "{title} {listen-addr} {server-mode}"
locale-collate ""
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
rdb-del-sync-files no
dir /usr/local/redis
replica-serve-stale-data yes
replica-read-only no
repl-diskless-sync yes
repl-diskless-sync-delay 5
repl-diskless-sync-max-replicas 0
repl-diskless-load disabled
repl-disable-tcp-nodelay no
replica-priority 100
acllog-max-len 128
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
lazyfree-lazy-user-del no
lazyfree-lazy-user-flush no
oom-score-adj no
oom-score-adj-values 0 200 800
disable-thp yes
appendonly yes
appendfilename "appendonly.aof"
appenddirname "appendonlydir"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
aof-timestamp-enabled no
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-listpack-entries 512
hash-max-listpack-value 64
list-max-listpack-size -2
list-compress-depth 0
set-max-intset-entries 512
set-max-listpack-entries 128
set-max-listpack-value 64
zset-max-listpack-entries 128
zset-max-listpack-value 64
hll-sparse-max-bytes 3000
stream-node-max-bytes 4096
stream-node-max-entries 100
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes
jemalloc-bg-thread yes
save 10 2
[root@redis01 ~]# systemctl restart redis
[root@redis01 ~]# systemctl status redis --no-pager
● redis.service - redis-server
Loaded: loaded (/etc/systemd/system/redis.service; enabled; preset: disabled)
Active: active (running) since Sat 2025-11-29 17:52:57 CST; 17s ago
Process: 3387 ExecStart=/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis.conf (code=exited, status=0/SUCCESS)
Main PID: 3388 (redis-server)
Tasks: 6 (limit: 22927)
Memory: 7.3M
CPU: 91ms
CGroup: /system.slice/redis.service
└─3388 "/usr/local/redis/bin/redis-server 0.0.0.0:6379"
Nov 29 17:52:57 redis01 systemd[1]: Starting redis-server...
Nov 29 17:52:57 redis01 systemd[1]: Started redis-server.
[root@redis01 ~]#
第二步:配置 slave 192.168.88.102
vim /usr/local/redis/conf/redis.conf
主从配置:设置master redis信息
bind 0.0.0.0
protected-mode no
logfile "/usr/local/redis/redis.log"
replicaof 192.168.88.101 6379 # redis5/6/7 版本
[root@redis02 ~]# vim /usr/local/redis/conf/redis.conf
[root@redis02 ~]# cat /usr/local/redis/conf/redis.conf
bind 0.0.0.0
protected-mode no
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize yes
pidfile /var/run/redis_6379.pid
loglevel notice
logfile "/usr/local/redis/redis.log"
databases 16
always-show-logo no
set-proc-title yes
proc-title-template "{title} {listen-addr} {server-mode}"
locale-collate ""
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
rdb-del-sync-files no
dir ./
replica-serve-stale-data yes
replica-read-only yes
repl-diskless-sync yes
repl-diskless-sync-delay 5
repl-diskless-sync-max-replicas 0
repl-diskless-load disabled
repl-disable-tcp-nodelay no
replica-priority 100
replicaof 192.168.88.101 6379
acllog-max-len 128
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
lazyfree-lazy-user-del no
lazyfree-lazy-user-flush no
oom-score-adj no
oom-score-adj-values 0 200 800
disable-thp yes
appendonly no
appendfilename "appendonly.aof"
appenddirname "appendonlydir"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
aof-timestamp-enabled no
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-listpack-entries 512
hash-max-listpack-value 64
list-max-listpack-size -2
list-compress-depth 0
set-max-intset-entries 512
set-max-listpack-entries 128
set-max-listpack-value 64
zset-max-listpack-entries 128
zset-max-listpack-value 64
hll-sparse-max-bytes 3000
stream-node-max-bytes 4096
stream-node-max-entries 100
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes
jemalloc-bg-thread yes
[root@redis02 ~]# systemctl restart redis
[root@redis02 ~]# systemctl status redis --no-pager
● redis.service - redis-server
Loaded: loaded (/etc/systemd/system/redis.service; enabled; preset: disab>
Active: active (running) since Sat 2025-11-29 17:57:13 CST; 5s ago
Process: 2591 ExecStart=/usr/local/redis/bin/redis-server /usr/local/redis>
Main PID: 2593 (redis-server)
Tasks: 6 (limit: 22927)
Memory: 7.4M
CPU: 48ms
CGroup: /system.slice/redis.service
└─2593 "/usr/local/redis/bin/redis-server 0.0.0.0:6379"
Nov 29 17:57:13 redis02 systemd[1]: Starting redis-server...
Nov 29 17:57:13 redis02 systemd[1]: Started redis-server.
第三步:重启Redis服务器,查看是否成功
redis-cli
127.0.0.1:6379> info replication
[root@redis01 ~]# redis-cli
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.88.102,port=6379,state=online,offset=28,lag=1
master_failover_state:no-failover
master_replid:455f2585d7338f0828b40e38c9405ef57061d64a
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:28
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:28
127.0.0.1:6379>
[root@redis02 ~]# redis-cli
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:192.168.88.101
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_read_repl_offset:84
slave_repl_offset:84
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:455f2585d7338f0828b40e38c9405ef57061d64a
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:84
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:84
127.0.0.1:6379>
第四步:测试Redis主从,主写从读
[root@redis01 ~]# redis-cli
127.0.0.1:6379> set title itheima
OK
127.0.0.1:6379> keys *
1) "title"
127.0.0.1:6379> get title
"itheima"
127.0.0.1:6379>
[root@redis02 ~]# redis-cli
127.0.0.1:6379> keys *
1) "title"
127.0.0.1:6379> get title
"itheima"
127.0.0.1:6379>
注:slave不允许写操作,因为从服务器Redis配置文件里进行了replica-read-only设置,也是符合业务的使用需求
replica-read-only yes
2. 安全限制
目前redis已经完成相关配置,缺少安全配置,如IP限制,密码限制。
==IP限制登录==
① master打开配置IP限制
注意如果有防火墙,先关闭防火墙或者开启端口放行。
bind ip 监听绑定网卡的IP
# vim /usr/local/redis/conf/redis.conf
bind 127.0.0.1 本机的网卡IP地址
bind 192.168.88.101 具体某个IP
bind 0.0.0.0 适合公网环境,没有限制,任意主机均可访问
重启Redis服务
② slave服务器进行远程连接测试
# redis-cli -h 远程IP地址
如果设置了密码也可以通过-a指定密码,密码会保留终端
[root@redis02 ~]# redis-cli -h 192.168.88.101
192.168.88.101:6379> info
# Server
redis_version:7.4.0
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:1f85b0fd6901cd00
redis_mode:standalone
os:Linux 5.14.0-511.el9.x86_64 x86_64
arch_bits:64
monotonic_clock:POSIX clock_gettime
multiplexing_api:epoll
atomicvar_api:c11-builtin
gcc_version:11.5.0
process_id:8979
process_supervised:no
run_id:02bc1933766a3a0338274eb04b0a03f4530eab08
tcp_port:6379
server_time_usec:1764411380991945
uptime_in_seconds:37
uptime_in_days:0
hz:10
configured_hz:10
lru_clock:2803700
executable:/usr/local/redis/bin/redis-server
config_file:/usr/local/redis/conf/redis.conf
io_threads_active:0
listener0:name=tcp,bind=0.0.0.0,port=6379
...省略剩余输出信息...
③ master进行密码限制
1051行 # requirepass 密码
[root@redis01 ~]# vim /usr/local/redis/conf/redis.conf
[root@redis01 ~]# cat /usr/local/redis/conf/redis.conf
bind 0.0.0.0
protected-mode no
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize yes
pidfile /var/run/redis_6379.pid
loglevel notice
logfile "/usr/local/redis/redis.log"
databases 16
always-show-logo no
set-proc-title yes
proc-title-template "{title} {listen-addr} {server-mode}"
locale-collate ""
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
rdb-del-sync-files no
dir /usr/local/redis
replica-serve-stale-data yes
replica-read-only no
repl-diskless-sync yes
repl-diskless-sync-delay 5
repl-diskless-sync-max-replicas 0
repl-diskless-load disabled
repl-disable-tcp-nodelay no
replica-priority 100
acllog-max-len 128
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
lazyfree-lazy-user-del no
lazyfree-lazy-user-flush no
oom-score-adj no
oom-score-adj-values 0 200 800
disable-thp yes
appendonly yes
appendfilename "appendonly.aof"
appenddirname "appendonlydir"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
aof-timestamp-enabled no
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-listpack-entries 512
hash-max-listpack-value 64
list-max-listpack-size -2
list-compress-depth 0
set-max-intset-entries 512
set-max-listpack-entries 128
set-max-listpack-value 64
zset-max-listpack-entries 128
zset-max-listpack-value 64
hll-sparse-max-bytes 3000
stream-node-max-bytes 4096
stream-node-max-entries 100
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes
jemalloc-bg-thread yes
save 10 2
requirepass redis666
[root@redis01 ~]# systemctl restart redis
[root@redis01 ~]# systemctl status redis
● redis.service - redis-server
Loaded: loaded (/etc/systemd/system/redis.service; enabled; preset: disab>
Active: active (running) since Sat 2025-11-29 18:19:11 CST; 4s ago
Process: 9567 ExecStart=/usr/local/redis/bin/redis-server /usr/local/redis>
Main PID: 9569 (redis-server)
Tasks: 6 (limit: 22927)
Memory: 7.3M
CPU: 870ms
CGroup: /system.slice/redis.service
└─9569 "/usr/local/redis/bin/redis-server 0.0.0.0:6379"
Nov 29 18:19:11 redis01 systemd[1]: Starting redis-server...
Nov 29 18:19:11 redis01 systemd[1]: Started redis-server.
[root@redis01 ~]#
重启redis服务,在slave服务器测试密码是否可用
[root@redis02 ~]# redis-cli -h 192.168.88.101
192.168.88.101:6379> info
NOAUTH Authentication required.
192.168.88.101:6379> auth redis666
OK
或者
[root@redis02 ~]# redis-cli -h 192.168.88.101 -a redis666
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
192.168.88.101:6379> info
# Server
redis_version:7.4.0
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:1f85b0fd6901cd00
redis_mode:standalone
os:Linux 5.14.0-511.el9.x86_64 x86_64
arch_bits:64
...省略部分输出信息...
[root@redis02 ~]# redis-cli -h 192.168.88.101
192.168.88.101:6379> info
NOAUTH Authentication required.
192.168.88.101:6379> auth redis666
OK
192.168.88.101:6379> info
# Server
redis_version:7.4.0
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:1f85b0fd6901cd00
redis_mode:standalone
os:Linux 5.14.0-511.el9.x86_64 x86_64
arch_bits:64
monotonic_clock:POSIX clock_gettime
multiplexing_api:epoll
atomicvar_api:c11-builtin
gcc_version:11.5.0
process_id:9569
process_supervised:no
run_id:35ba011debf3d9676b3497239481e5d199c1da06
tcp_port:6379
server_time_usec:1764411590255650
uptime_in_seconds:39
uptime_in_days:0
hz:10
configured_hz:10
lru_clock:2803910
executable:/usr/local/redis/bin/redis-server
config_file:/usr/local/redis/conf/redis.conf
io_threads_active:0
listener0:name=tcp,bind=0.0.0.0,port=6379
...省略剩余输出信息...
[root@redis02 ~]# redis-cli -h 192.168.88.101 -a redis666
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
192.168.88.101:6379> info
# Server
redis_version:7.4.0
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:1f85b0fd6901cd00
redis_mode:standalone
os:Linux 5.14.0-511.el9.x86_64 x86_64
arch_bits:64
monotonic_clock:POSIX clock_gettime
multiplexing_api:epoll
atomicvar_api:c11-builtin
gcc_version:11.5.0
process_id:9569
process_supervised:no
run_id:35ba011debf3d9676b3497239481e5d199c1da06
tcp_port:6379
server_time_usec:1764411651816602
uptime_in_seconds:100
uptime_in_days:0
hz:10
configured_hz:10
lru_clock:2803971
executable:/usr/local/redis/bin/redis-server
config_file:/usr/local/redis/conf/redis.conf
io_threads_active:0
listener0:name=tcp,bind=0.0.0.0,port=6379
...省略剩余输出信息...
注意:如果开启了密码限制,搭建主从需要在slave配置中填写master密码
# vim /usr/local/redis/conf/redis.conf
547行:masterauth 密码
[root@redis02 ~]# vim /usr/local/redis/conf/redis.conf
[root@redis02 ~]# cat /usr/local/redis/conf/redis.conf
bind 0.0.0.0
protected-mode no
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize yes
pidfile /var/run/redis_6379.pid
loglevel notice
logfile ""
databases 16
always-show-logo no
set-proc-title yes
proc-title-template "{title} {listen-addr} {server-mode}"
locale-collate ""
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
rdb-del-sync-files no
dir ./
replica-serve-stale-data yes
replica-read-only yes
repl-diskless-sync yes
repl-diskless-sync-delay 5
repl-diskless-sync-max-replicas 0
repl-diskless-load disabled
repl-disable-tcp-nodelay no
replica-priority 100
replicaof 192.168.88.101 6379
acllog-max-len 128
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
lazyfree-lazy-user-del no
lazyfree-lazy-user-flush no
oom-score-adj no
oom-score-adj-values 0 200 800
disable-thp yes
appendonly no
appendfilename "appendonly.aof"
appenddirname "appendonlydir"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
aof-timestamp-enabled no
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-listpack-entries 512
hash-max-listpack-value 64
list-max-listpack-size -2
list-compress-depth 0
set-max-intset-entries 512
set-max-listpack-entries 128
set-max-listpack-value 64
zset-max-listpack-entries 128
zset-max-listpack-value 64
hll-sparse-max-bytes 3000
stream-node-max-bytes 4096
stream-node-max-entries 100
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes
jemalloc-bg-thread yes
masterauth redis666
[root@redis02 ~]# systemctl restart redis
[root@redis02 ~]# systemctl status redis
● redis.service - redis-server
Loaded: loaded (/etc/systemd/system/redis.service; enabled; preset: disab>
Active: active (running) since Sat 2025-11-29 18:21:59 CST; 4s ago
Process: 6672 ExecStart=/usr/local/redis/bin/redis-server /usr/local/redis>
Main PID: 6674 (redis-server)
Tasks: 6 (limit: 22927)
Memory: 7.4M
CPU: 37ms
CGroup: /system.slice/redis.service
└─6674 "/usr/local/redis/bin/redis-server 0.0.0.0:6379"
Nov 29 18:21:59 redis02 systemd[1]: Starting redis-server...
Nov 29 18:21:59 redis02 systemd[1]: Started redis-server.
[root@redis02 ~]#
3. PHP Redis(拓展)
项目:LNMP(PHP) => .so扩展文件 => Redis
源码安装LNMP,要参考下面的代码,手工编译安装redis.so扩展
第一步:安装redis.so扩展
https://pecl.php.net/package/redis
[root@server3 ~]# wget https://pecl.php.net/get/redis-5.3.3.tgz
--2025-11-29 18:29:29-- https://pecl.php.net/get/redis-5.3.3.tgz
Resolving pecl.php.net (pecl.php.net)... 185.85.0.29, 2a02:cb40:200::1ad
Connecting to pecl.php.net (pecl.php.net)|185.85.0.29|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 266990 (261K) [application/octet-stream]
Saving to: ‘redis-5.3.3.tgz’
redis-5.3.3.tgz 100%[==================>] 260.73K 337KB/s in 0.8s
2025-11-29 18:29:31 (337 KB/s) - ‘redis-5.3.3.tgz’ saved [266990/266990]
[root@server3 ~]# ls -hl
total 268K
-rw-------. 1 root root 984 Jul 18 15:57 anaconda-ks.cfg
-rw-r--r--. 1 root root 261K Feb 2 2021 redis-5.3.3.tgz
[root@server3 ~]# tar xf redis-5.3.3.tgz
[root@server3 ~]# ls
anaconda-ks.cfg package.xml redis-5.3.3 redis-5.3.3.tgz
[root@server3 ~]# cd redis-5.3.3/
[root@server3 redis-5.3.3]# ls
arrays.markdown CREDITS redis_array_impl.c redis_session.c
cluster_library.c INSTALL.markdown redis_array_impl.h redis_session.h
cluster_library.h liblzf redis.c sentinel_library.c
cluster.markdown library.c redis_cluster.c sentinel_library.h
common.h library.h redis_cluster.h sentinel.markdown
config.m4 php_redis.h redis_commands.c tests
config.w32 README.markdown redis_commands.h
COPYING redis_array.c redis_sentinel.c
crc16.h redis_array.h redis_sentinel.h
[root@server3 redis-5.3.3]# yum install -y gcc make autoconf php-devel php-pear php-fpm
[root@server3 redis-5.3.3]# which phpize
/usr/bin/phpize
[root@server3 redis-5.3.3]# /usr/bin/phpize
Configuring for:
PHP Api Version: 20200930
Zend Module Api No: 20200930
Zend Extension Api No: 420200930
[root@server3 redis-5.3.3]# ./configure --with-php-config=/usr/bin/php-config --enable-fpm
[root@server3 redis-5.3.3]# make
...省略部分输出信息...
If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the '-LLIBDIR'
flag during linking and do at least one of the following:
- add LIBDIR to the 'LD_LIBRARY_PATH' environment variable
during execution
- add LIBDIR to the 'LD_RUN_PATH' environment variable
during linking
- use the '-Wl,-rpath -Wl,LIBDIR' linker flag
- have your system administrator add LIBDIR to '/etc/ld.so.conf'
See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
----------------------------------------------------------------------
Build complete.
Don't forget to run 'make test'.
[root@server3 redis-5.3.3]# make install
Installing shared extensions: /usr/lib64/php/modules/
[root@server3 redis-5.3.3]# php -v
PHP 8.0.30 (cli) (built: Oct 3 2025 08:25:46) ( NTS gcc x86_64 )
Copyright (c) The PHP Group
Zend Engine v4.0.30, Copyright (c) Zend Technologies
[root@server3 redis-5.3.3]# systemctl start php-fpm
[root@server3 redis-5.3.3]# systemctl status php-fpm
● php-fpm.service - The PHP FastCGI Process Manager
Loaded: loaded (/usr/lib/systemd/system/php-fpm.service; disabled; preset>
Active: active (running) since Sat 2025-11-29 19:11:24 CST; 1s ago
Main PID: 38930 (php-fpm)
Status: "Ready to handle connections"
Tasks: 6 (limit: 22927)
Memory: 9.2M
CPU: 57ms
CGroup: /system.slice/php-fpm.service
├─38930 "php-fpm: master process (/etc/php-fpm.conf)"
├─38931 "php-fpm: pool www"
├─38932 "php-fpm: pool www"
├─38933 "php-fpm: pool www"
├─38934 "php-fpm: pool www"
└─38935 "php-fpm: pool www"
Nov 29 19:11:24 server3 systemd[1]: Starting The PHP FastCGI Process Manager...
Nov 29 19:11:24 server3 systemd[1]: Started The PHP FastCGI Process Manager.
[root@server3 redis-5.3.3]# php -m|grep redis
[root@server3 redis-5.3.3]#
第二步:配置php.ini
在最后一行添加如下内容
vim /etc/php.ini
extension = redis.so
[root@server3 redis-5.3.3]# vim /etc/php.ini
[root@server3 redis-5.3.3]# tail -n 1 /etc/php.ini
extension = redis.so
[root@server3 redis-5.3.3]#
优化php.ini配置文件
[root@server3 redis-5.3.3]# cp /etc/php.ini /etc/php.ini.bak
[root@server3 redis-5.3.3]# sed -i '/^\s*;/d; /^$/d' /etc/php.ini
[root@server3 redis-5.3.3]# cat /etc/php.ini
[PHP]
engine = On
short_open_tag = Off
precision = 14
output_buffering = 4096
zlib.output_compression = Off
implicit_flush = Off
unserialize_callback_func =
serialize_precision = -1
disable_functions =
disable_classes =
zend.enable_gc = On
zend.exception_ignore_args = On
zend.exception_string_param_max_len = 0
expose_php = On
max_execution_time = 30
max_input_time = 60
memory_limit = 128M
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
display_errors = Off
display_startup_errors = Off
log_errors = On
log_errors_max_len = 1024
ignore_repeated_errors = Off
ignore_repeated_source = Off
report_memleaks = On
variables_order = "GPCS"
request_order = "GP"
register_argc_argv = Off
auto_globals_jit = On
post_max_size = 8M
auto_prepend_file =
auto_append_file =
default_mimetype = "text/html"
default_charset = "UTF-8"
doc_root =
user_dir =
enable_dl = Off
file_uploads = On
upload_max_filesize = 2M
max_file_uploads = 20
allow_url_fopen = On
allow_url_include = Off
default_socket_timeout = 60
[CLI Server]
cli_server.color = On
[Date]
[filter]
[iconv]
[imap]
[intl]
[sqlite3]
[Pcre]
pcre.jit=0
[Pdo]
[Pdo_mysql]
pdo_mysql.default_socket=
[Phar]
[mail function]
sendmail_path = /usr/sbin/sendmail -t -i
mail.add_x_header = Off
[ODBC]
odbc.allow_persistent = On
odbc.check_persistent = On
odbc.max_persistent = -1
odbc.max_links = -1
odbc.defaultlrl = 4096
odbc.defaultbinmode = 1
[MySQLi]
mysqli.max_persistent = -1
mysqli.allow_persistent = On
mysqli.max_links = -1
mysqli.default_port = 3306
mysqli.default_socket =
mysqli.default_host =
mysqli.default_user =
mysqli.default_pw =
mysqli.reconnect = Off
[mysqlnd]
mysqlnd.collect_statistics = On
mysqlnd.collect_memory_statistics = Off
[PostgreSQL]
pgsql.allow_persistent = On
pgsql.auto_reset_persistent = Off
pgsql.max_persistent = -1
pgsql.max_links = -1
pgsql.ignore_notice = 0
pgsql.log_notice = 0
[bcmath]
bcmath.scale = 0
[browscap]
[Session]
session.save_handler = files
session.use_strict_mode = 0
session.use_cookies = 1
session.use_only_cookies = 1
session.name = PHPSESSID
session.auto_start = 0
session.cookie_lifetime = 0
session.cookie_path = /
session.cookie_domain =
session.cookie_httponly =
session.cookie_samesite =
session.serialize_handler = php
session.gc_probability = 1
session.gc_divisor = 1000
session.gc_maxlifetime = 1440
session.referer_check =
session.cache_limiter = nocache
session.cache_expire = 180
session.use_trans_sid = 0
session.sid_length = 26
session.trans_sid_tags = "a=href,area=href,frame=src,form="
session.sid_bits_per_character = 5
[Assertion]
zend.assertions = -1
[mbstring]
[gd]
[exif]
[Tidy]
tidy.clean_output = Off
[soap]
soap.wsdl_cache_enabled=1
soap.wsdl_cache_dir="/tmp"
soap.wsdl_cache_ttl=86400
soap.wsdl_cache_limit = 5
[sysvshm]
[ldap]
ldap.max_links = -1
[dba]
[opcache]
[curl]
[openssl]
[ffi]
extension = redis.so
[root@server3 redis-5.3.3]#
sed -i '/^\s*;/d; /^$/d' /etc/php.ini 命令解析
-
sed -i:-i选项表示 "in-place"(原地修改),直接对/etc/php.ini文件进行修改。 -
/^\s*;/d: -
^: 匹配行首。\s*: 匹配零个或多个空格或制表符(处理行首有空格的注释)。;: 匹配分号。d: 删除匹配到的行。- 作用: 删除所有以分号开头的注释行,包括前面有空格的注释。
-
/^$/d: -
^$: 匹配空行(行首紧跟行尾)。d: 删除匹配到的行。- 作用: 删除所有空行。
第三步:重启php-fpm
# systemctl restart php-fpm
# php -m #使用命令查看是否有对应的redis模块
第四步:测试php redis是否安装成功
[root@server3 redis-5.3.3]# systemctl restart php-fpm
[root@server3 redis-5.3.3]# php -m|grep redis
redis
4. Redis 应用场景:缓存与 Session 存入 Redis(了解)
缓存设计:减少Web对MySQL的访问,减轻数据库压力
与之前session存储到file文件的方式不同,将session存储到redis中,可以实现session的共享以及单点登录(sso)的操作。
pan.baidu.com
image.baidu.com
music.baidu.com
① 更改缓存保存方式
vim /data/CRMEB/crmeb/config/cache.php
return [
// 默认缓存驱动
'default' => Env::get('cache.driver', 'redis'), //修改这里
// 缓存连接方式配置
'stores' => [
'file' => [
// 驱动方式
'type' => 'File',
// 缓存保存目录
'path' => app()->getRuntimePath() . 'cache' . DIRECTORY_SEPARATOR,
// 缓存前缀
'prefix' => '',
// 缓存有效期 0表示永久缓存
'expire' => 0,
// 缓存标签前缀
'tag_prefix' => 'tag:',
// 序列化机制 例如 ['serialize', 'unserialize']
'serialize' => [],
],
// 更多的缓存连接
// redis缓存
'redis' => [
// 驱动方式
'type' => 'redis',
// 服务器地址
'host' => Env::get('redis.redis_hostname', '192.168.88.132'), //缓存服务器地址
// 端口
'port' => Env::get('redis.port', '6379'), //缓存服务器地址端口
// 密码
'password' => Env::get('redis.redis_password', '123456'), //缓存服务器密码
// 缓存有效期 0表示永久缓存
'expire' => 0 ,
// 缓存前缀
'prefix' => Env::get('cache.cache_prefix', 'c:'),
// 缓存标签前缀
'tag_prefix' => Env::get('cache.cache_tag_prefix', 'CRMEB:'),
// 数据库 0号数据库
'select' => intval(Env::get('redis.select', 0)),
// 序列化机制 例如 ['serialize', 'unserialize']
'serialize' => [],
// 服务端主动关闭
'timeout' => 0
],
],
];
② 更改Session存储位置
https://doc.thinkphp.cn/v6_1/Session.html
vim /data/CRMEB/crmeb/config/session.php
web01 session文件
web02 session文件
web01/web02 => session => redis
<?php
// +----------------------------------------------------------------------
// | 会话设置
// +----------------------------------------------------------------------
return [
// session name
'name' => 'PHPSESSID',
// SESSION_ID的提交变量,解决flash上传跨域
'var_session_id' => '',
// 驱动方式 支持file cache
'type' => 'cache', // 修改这里
// 存储连接标识 当type使用cache的时候有效
// 过期时间
'expire' => 1440*1000,
// 前缀
'prefix' => 'think', // 修改这里
];
5. Nginx+Lua+Redis 实现访问攻击黑名单 WAF(了解)
WAF:(Web Application Firewalld),根据nginx访问流量判断是否为恶意攻击,如果1s内超过200个请求,就认为这是恶意攻击。
① redis01,安装openresty 和之前安装一致
#!/bin/bash
dnf -y install pcre-devel zlib-devel openssl-devel
tar -zxf openresty-1.25.3.2.tar.gz
cd openresty-1.25.3.2
./configure && make && make install
② 编写lua脚本
# mkdir -p /usr/local/lua
# vim /usr/local/lua/access_limit.lua
-- access_by_lua_file '/usr/local/lua/access_limit.lua'
local function close_redis(red)
if not red then
return
end
--释放连接(连接池实现)
local pool_max_idle_time = 10000 --毫秒
local pool_size = 100 --连接池大小
local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)
if not ok then
ngx_log(ngx_ERR, "set redis keepalive error : ", err)
end
end
local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000)
local ip = "192.168.88.132" -- redis ip
local port = 6379 -- redis port
local ok, err = red:connect(ip,port)
red:auth("123456") -- redis auth password
if not ok then
return close_redis(red)
end
local clientIP = ngx.req.get_headers()["X-Real-IP"]
if clientIP == nil then
clientIP = ngx.req.get_headers()["x_forwarded_for"]
end
if clientIP == nil then
clientIP = ngx.var.remote_addr
end
local incrKey = "user:"..clientIP..":freq"
local blockKey = "user:"..clientIP..":block"
local is_block,err = red:get(blockKey) -- check if ip is blocked
if tonumber(is_block) == 1 then
ngx.exit(ngx.HTTP_FORBIDDEN) -- return 403
return close_redis(red)
end
res, err = red:incr(incrKey)
if res == 1 then
res, err = red:expire(incrKey,1)
end
if res > 5 then -- block 频率,测试环境可以考虑设置为3或5
res, err = red:set(blockKey,1)
res, err = red:expire(blockKey,600)
end
close_redis(red)
在Nginx中添加Lua脚本:
# vim /usr/local/openresty/nginx/conf/nginx.conf
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
root html;
location / {
index index.html index.htm;
access_by_lua_file /usr/local/lua/access_limit.lua;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}
# 启动openresty
cd /usr/local/openresty
bin/openresty
启动openresty,在lb01上面可以先停旧的nginx(如何存在了nginx),然后再启动,也可以通过修改/usr/local/openresty/nginx/conf里面nginx.conf监听端口号
停掉旧版本nginx再启动
[root@node1 conf]# pkill nginx
[root@node1 conf]# cd /usr/local/openresty
[root@node1 conf]# bin/openresty
或者修改/usr/local/openresty/nginx/conf/nginx.conf端口
[root@node1 conf] vim /usr/local/openresty/nginx/conf/nginx.conf
server {
listen 8080; //修改端口号
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
access_by_lua_file /usr/local/lua/access_limit.lua;
}
}
启动服务
[root@node1 conf]# /usr/local/openresty/bin/openresty
通过浏览器进行访问
③ 测试验证黑名单效果
6. 实现商城前端恶意攻击IP加入黑名单(了解)
停掉旧版nginx 服务器并禁止开机自启动
复制配置文件
[root@lb01 conf]# systemc disable nginx --now
[root@lb01 conf]# cp -a /etc/nginx/conf.d /usr/local/openresty/nginx/conf/
修改配置文件,
[root@lb01 conf]# cd /usr/local/openresty/nginx/conf/conf.d
[root@lb01 conf]# vim my_web_service.conf
upstream my_web_service {
#ip_hash;
server 192.168.88.130:80;
server 192.168.88.131:80;
}
server {
listen 80;
#################### 配置开始 ######################
server_name www.itheimashop.com; # 替换为实际域名或 IP
location / {
proxy_pass http://my_web_service; # 将请求转发到负载均衡组
proxy_set_header HOST $host;
proxy_set_header X-Real-IP $remote_addr; # 添加这两行
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
access_by_lua_file /usr/local/lua/access_limit.lua;
}
#################### 配置结束 ######################
}
修改lua脚本访问频率
[root@lb01 lua]# vim /usr/local/lua/access_limit.lua
-- access_by_lua_file '/usr/local/lua/access_limit.lua'
local function close_redis(red)
if not red then
return
end
--释放连接(连接池实现)
local pool_max_idle_time = 10000 --毫秒
local pool_size = 100 --连接池大小
local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)
if not ok then
ngx_log(ngx_ERR, "set redis keepalive error : ", err)
end
end
local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000)
local ip = "192.168.88.132" -- redis ip
local port = 6379 -- redis port
local ok, err = red:connect(ip,port)
red:auth("123456") -- redis auth password
if not ok then
return close_redis(red)
end
local clientIP = ngx.req.get_headers()["X-Real-IP"]
if clientIP == nil then
clientIP = ngx.req.get_headers()["x_forwarded_for"]
end
if clientIP == nil then
clientIP = ngx.var.remote_addr
end
local incrKey = "user:"..clientIP..":freq"
local blockKey = "user:"..clientIP..":block"
local is_block,err = red:get(blockKey) -- check if ip is blocked
if tonumber(is_block) == 1 then
ngx.exit(ngx.HTTP_FORBIDDEN) -- return 403
return close_redis(red)
end
res, err = red:incr(incrKey)
if res == 1 then
res, err = red:expire(incrKey,1)
end
if res > 100 then -- block 频率,网站前端改成100
res, err = red:set(blockKey,1)
res, err = red:expire(blockKey,600)
end
close_redis(red)
启动服务
[root@lb01 lua]# /usr/local/openresty/bin/openresty
浏览器http://www.itheimashop.com访问
总结
一、Redis 核心价值与应用场景
业务背景匹配
-
用户规模:6万用户,日活跃2万,PV 20-30万
-
适用场景:
-
- 活跃用户统计:使用 Set 集合统计日活用户
- Session 共享:存储用户会话,支持分布式架构
- 安全防护:配合 OpenResty+Lua 实现 WAF 防火墙
Redis 五大核心优势
- 内存级性能:读写速度极快,适合高并发场景
- 丰富数据结构:5种基础+3种高级类型,满足复杂业务需求
- 持久化保障:RDB+AOF 保证数据安全不丢失
- 高可用方案:主从复制、哨兵、集群多种选择
- 分布式支持:支持水平扩展,满足大数据量需求
二、Redis 核心数据结构与业务映射
| 数据类型 | 典型业务场景 | 关键操作 |
|---|---|---|
| String | 计数器、验证码、简单缓存 | SET/GET/INCR/EXPIRE |
| List | 消息队列、最新动态、登录历史 | LPUSH/RPOP/LRANGE |
| Set | 去重统计、共同好友、黑白名单 | SADD/SMEMBERS/SINTER |
| ZSet | 排行榜、热度排序、优先级队列 | ZADD/ZRANGE/ZSCORE |
| Hash | 用户信息、商品详情、对象缓存 | HSET/HGET/HGETALL |
三、持久化策略选择指南
RDB 快照模式
# 触发条件配置
save 900 1 # 15分钟至少1个键改变
save 300 10 # 5分钟至少10个键改变
save 60 10000 # 1分钟至少10000个键改变
- 优点:恢复速度快,文件小,适合备份
- 缺点:可能丢失最后一次快照后的数据
- 适用:对数据完整性要求不苛刻,追求快速恢复的场景
AOF 日志模式
# 写回策略
appendfsync always # 每个命令都同步,最安全
appendfsync everysec # 每秒同步,推荐使用
appendfsync no # 由系统决定,性能最好但风险最大
- 优点:数据丢失少,可读性强
- 缺点:文件大,恢复速度慢
- 适用:对数据安全要求极高的场景
混合模式(生产推荐)
aof-use-rdb-preamble yes # Redis 4.0+ 默认开启
效果:RDB 做基础快照 + AOF 记录增量操作,兼顾速度与安全
四、高可用架构对比
| 特性 | 主从复制 | 哨兵模式 | 集群模式 |
|---|---|---|---|
| 架构 | 1主多从 | 主从+哨兵监控 | 多主多从分片 |
| 故障转移 | 手动 | 自动(10-30秒) | 自动(秒级) |
| 扩展性 | 垂直扩展 | 读写分离 | 水平扩展 |
| 数据量 | 单机容量 | 单机容量 | 海量数据 |
| 适用场景 | 简单备份 | 中小规模高可用 | 大规模高并发 |
五、企业实战应用总结
1. 主从复制配置要点
# Master 配置
bind 0.0.0.0
protected-mode no
requirepass redis666
# Slave 配置
replicaof 192.168.88.101 6379
masterauth redis666
replica-read-only yes
2. 安全加固措施
- 密码认证:所有节点配置
requirepass - 访问控制:结合防火墙限制访问IP
- 权限分离:主节点读写,从节点只读
- 网络隔离:生产环境使用内网通信
3. 性能优化建议
- 内存优化:设置
vm.overcommit_memory = 1 - 连接池:客户端使用连接池减少连接开销
- 键值设计:避免大Key、热Key,合理使用数据结构
- 持久化权衡:根据业务容忍度选择合适策略
六、典型解决方案
方案一:会话共享
// PHP 配置 session 存储到 Redis
session.save_handler = redis
session.save_path = "tcp://192.168.88.101:6379?auth=redis666"
优势:多台Web服务器共享Session,支持负载均衡
方案二:访问频率控制
-- OpenResty + Lua 实现 IP 黑名单
local incrKey = "user:"..clientIP..":freq"
if res > 100 then -- 1秒内超过100次请求
red:set(blockKey, 1)
red:expire(blockKey, 600) -- 封禁10分钟
end
方案三:排行榜实现
# 使用 ZSet 实现热门软件排行
ZADD hotTop 2 qq 3 wechat 5 alipay
ZREVRANGE hotTop 0 10 WITHSCORES # 获取前10名
七、运维最佳实践
监控指标
- 内存使用率:避免超过物理内存
- 连接数:监控
connected_clients - 命中率:关注
keyspace_hits/keyspace_misses - 持久化状态:定期检查 RDB/AOF 文件状态
- 主从延迟:监控
master_repl_offset
故障处理
- 数据恢复:优先使用AOF,其次RDB
- 主从中断:检查网络、密码配置、复制状态
- 内存溢出:分析内存使用,优化数据结构
- 性能下降:排查慢查询、连接数激增
备份策略
- 定期备份:RDB快照 + AOF日志双重备份
- 异地备份:重要数据跨机房备份
- 恢复演练:定期测试备份文件可恢复性
八、技术选型建议
选型决策树
是否需要数据分片?
├── 否 → 数据量是否超过单机内存?
│ ├── 否 → 是否需要自动故障转移?
│ │ ├── 否 → 主从复制
│ │ └── 是 → 哨兵模式
│ └── 是 → 集群模式
└── 是 → 集群模式
容量规划
- 内存需求:预估数据量 × 1.5(预留增长空间)
- CPU需求:4核起步,高并发场景8核以上
- 网络需求:千兆网络,集群节点间低延迟
九、核心要点
- 核心定位:Redis是企业级高性能缓存和数据结构存储解决方案
- 数据结构:5大基础类型应对90%业务场景,合理选择是关键
- 持久化:生产环境推荐RDB+AOF混合模式,平衡性能与安全
- 高可用:根据业务规模和重要性选择主从、哨兵或集群
- 安全运维:密码、防火墙、监控、备份四维一体保障稳定运行
- 扩展性:设计之初考虑分片策略,为业务增长预留空间
Redis在企业应用中不仅是缓存工具,更是支撑高并发、高性能业务的核心组件。正确选型、合理配置、有效监控是保障Redis稳定运行的关键。