Redis-数据结构与命令
一、SQL VS NoSQL
| 维度 | SQL(关系型数据库,如 MySQL/PostgreSQL) | NoSQL(非关系型数据库,以 Redis 为代表) |
|---|---|---|
| 数据模型 | 结构化数据,严格遵循表结构、字段类型、约束(主键 / 外键) | 非结构化 / 半结构化,支持键值、文档、列族、图形等灵活模型(Redis 为键值型) |
| 存储方式 | 磁盘存储为主,依赖磁盘 IO | 内存存储为主(Redis 可持久化到磁盘),内存 IO 性能远高于磁盘 |
| 事务特性 | 支持 ACID 完整事务(原子性、一致性、隔离性、持久性) | 部分支持(Redis 仅单命令原子性,集群下弱事务),优先性能 |
| 扩展性 | 垂直扩展为主(升级硬件),水平扩展复杂(分库分表) | 天然支持水平扩展(Redis Cluster 分片),扩容简单 |
| 查询能力 | 支持复杂 SQL 查询(联表、聚合、子查询),查询灵活 | 仅支持简单键查询 / 特定数据结构命令,复杂查询需客户端处理 |
| 数据一致性 | 强一致性,符合 ACID | 最终一致性(分布式场景),Redis 单机强一致、集群弱一致 |
| 适用场景 | 数据关系复杂、需事务保障、复杂查询(如订单系统、财务系统) | 高性能读写、缓存、临时数据、非关系型数据(如计数器、排行榜、会话存储) |
| 示例 | MySQL、Oracle、PostgreSQL | Redis、MongoDB、Elasticsearch |
核心选型建议
-
需强事务、复杂关联查询:选 SQL(如核心业务数据存储)
-
需高性能读写、临时缓存、非结构化数据:选 NoSQL(如 Redis 做缓存层,MongoDB 存非结构化文档)
-
混合场景:SQL 存储核心业务数据 + Redis 做缓存提升读写性能
二、Redis 核心概念
1. 定义与定位
Redis(Remote Dictionary Server)是开源的基于内存的键值对存储系统,支持多种数据结构,兼具高性能、持久化、高可用等特性。核心应用场景包括缓存系统、会话存储、消息队列、实时统计。
2. 核心特性
-
高性能:内存操作 + IO 多路复用,单节点 QPS 可达 10 万 +
-
数据结构丰富:基础类型(String、Hash、List、Set、Sorted Set)+ 特殊类型(GEO、BitMap、HyperLogLog 等)
-
持久化:支持 RDB 和 AOF 两种机制,防止内存数据丢失
-
高可用:主从复制 + 哨兵模式,保障服务稳定性
-
跨平台:支持 Linux、Windows(官方有限支持)、Docker 部署
三、核心配置优化(redis.conf)
# 安全配置
bind 0.0.0.0 # 允许外部访问(生产需限制IP)
requirepass your_pwd # 设置密码
protected-mode yes # 保护模式(防止未授权访问)
# 性能优化
maxmemory 4gb # 限制最大内存(避免OOM)
maxmemory-policy allkeys-lru # 内存淘汰策略(推荐)
timeout 60 # 空闲连接超时时间(秒)
# 持久化配置
appendonly yes # 启用AOF持久化
appendfsync everysec # AOF同步策略(每秒一次,平衡性能与安全)
save 900 1 # RDB:900秒内1次修改触发备份
四、核心数据结构与命令
1. 基础数据类型(核心命令 + 应用场景)
| 数据类型 | 核心命令 | 应用场景 |
|---|---|---|
| String | SET、GET、INCR、DECR、MSET、 MGET | 计数器、缓存简单值、会话存储、验证码存储 |
| Hash | HSET(本身可批量)、HGET、HGETALL、HDEL、HKEYS、HVALS | 存储 对象(如用户信息、商品详情) |
| List | LPUSH、RPUSH(咱俩都可批量)、LPOP、RPOP、LRANGE | 消息队列、最新列表、评论分页 |
| Set | SADD、SISMEMBER、SDIFF、SUNION、SREM | 数据去重、好友交集 / 并集、抽奖活动 |
| Sorted Set(ZSet) | ZADD、ZRANGE、ZREVRANK、ZSCORE、ZREM | 排行榜、带权重的队列、延迟任务 |
2. 特殊数据类型(核心命令 + 应用场景)
| 数据类型 | 核心命令 | 应用场景 |
|---|---|---|
| GEO | GEOADD、GEOPOS、GEODIST、GEORADIUS、GEOHASH | 地理位置计算(附近的人、门店距离、同城服务) |
| BitMap | SETBIT、GETBIT、BITCOUNT、BITOP、BITPOS | 海量用户二值状态统计(签到、在线状态、打卡) |
| HyperLogLog | PFADD、PFCOUNT、PFMERGE | 基数统计(UV 统计、独立访客数,无需精确值) |
3. 特殊类型核心命令示例
GEO 操作
GEOADD city 116.403874 39.914885 "北京" 121.473701 31.230416 "上海" # 添加地理位置
GEODIST city 北京 上海 km # 计算两地距离(单位km)
GEORADIUS city 116.40 39.91 10 km WITHDIST WITHCOORD # 查找指定坐标10km内的地点(带距离/坐标)
BitMap 操作
SETBIT user:sign:1000 1 1 # 用户1000在1号签到(1=签到,0=未签到)
GETBIT user:sign:1000 1 # 查看用户1000 1号是否签到
BITCOUNT user:sign:1000 # 统计用户1000总签到天数
BITOP AND sign:result user:sign:1000 user:sign:1001 # 计算两个用户共同签到日期
HyperLogLog 操作
PFADD uv:20250101 "user1" "user2" "user3" "user1" # 统计1月1日UV(自动去重)
PFCOUNT uv:20250101 # 获取1月1日UV数(近似值)
PFMERGE uv:202501 uv:20250101 uv:20250102 # 合并1月1、2日UV数据
4. 特殊类型使用技巧
-
BitMap:1 亿用户 1 天的状态仅占约 12MB 内存,适合海量二值状态存储(签到、在线状态)
-
HyperLogLog:每个实例仅占 12KB 空间,误差率约 0.81%,适合非精确基数统计(UV、独立访问数)
-
GEO:基于 ZSet 实现,避免在业务层高频计算地理距离,推荐用
GEORADIUSBYMEMBER替代手动计算
5. 高频通用命令
连接与测试
redis-cli -h 127.0.0.1 -p 6379 -a your_pwd # 连接Redis
PING # 测试连接(返回PONG则正常)
键操作
KEYS pattern # 匹配键(生产环境慎用,阻塞线程)
SCAN 0 MATCH pattern COUNT 100 # 安全遍历键
EXPIRE key 3600 # 设置键过期时间(秒)
TTL key # 查看剩余过期时间(-1=永久,-2=已过期)
DEL key # 删除键
EXISTS key # 判断键是否存在
服务器信息
INFO memory # 查看内存使用情况
INFO replication # 查看主从复制状态
SLOWLOG GET 10 # 查看最近10条慢查询(默认>1ms)
五、持久化机制
1. RDB(Redis Database)
-
原理:定时将内存数据快照写入磁盘(.rdb 文件)
-
触发方式:配置触发(如
save 900 1)、手动触发(SAVE阻塞主线程、BGSAVE后台异步) -
优点:恢复速度快、文件体积小
-
缺点:可能丢失最近一次快照后的 data
2. AOF(Append Only File)
-
原理:记录所有写命令到日志文件(.aof 文件),恢复时重新执行命令
-
同步策略:
always(每写 1 次同步)、everysec(每秒同步,推荐)、no(操作系统决定) -
优点:数据丢失少(最多 1 秒)
-
缺点:文件体积大、恢复速度慢
3. 选择建议
-
高可靠性场景:AOF + RDB 结合(先加载 AOF,数据更完整)
-
高性能场景:仅 RDB(减少 IO 开销)
六、缓存核心机制
1. 内存淘汰策略(maxmemory-policy)
| 策略 | 说明 |
|---|---|
| allkeys-lru | 从所有键中淘汰最近最少使用的键(推荐) |
| volatile-lru | 仅淘汰设置过期时间的最近最少使用键 |
| allkeys-lfu | 从所有键中淘汰最不常使用的键 |
| volatile-ttl | 淘汰即将过期的键 |
| noeviction | 不淘汰,拒绝写操作(不推荐) |
2. 缓存三大问题解决方案
| 问题 | 现象 | 解决方案 |
|---|---|---|
| 缓存穿透 | 查询不存在的数据,绕过缓存打 DB | 1. 缓存空值(设置短期过期);2. 布隆过滤器拦截 |
| 缓存击穿 | 热点 Key 过期,大量请求瞬间打 DB | 1. 互斥锁(SETNX);2. 热点 Key 永不过期 + 逻辑更新 |
| 缓存雪崩 | 大量 Key 同时过期或 Redis 集群宕机 | 1. 过期时间加随机偏移(避免集中过期);2. 集群部署 + 熔断降级 |
七、常见问题排查与解决方案
1. 内存溢出(OOM)
-
现象:客户端报错
OOM command not allowed -
原因:内存达
maxmemory、淘汰策略未配置、大 Key 过多 -
解决方案:配置淘汰策略、拆分大 Key、定期用
redis-cli --bigkeys扫描清理
2. 响应延迟飙升
-
现象:请求响应时间 > 10ms,
redis-cli --latency检测到高延迟 -
原因:慢查询、持久化阻塞、网络问题
-
解决方案:用
SCAN替代KEYS、AOF 选everysec、主节点关闭持久化、监控慢查询
3. 主从复制失败
-
现象:
info replication显示master_link_status:down -
原因:网络不通、主节点内存不足、从节点写入数据
-
解决方案:检查网络连通性、主节点执行
BGSAVE后从节点重新关联、从节点配置replica-read-only yes
八、键设计规范
1. 核心设计原则
-
可读性优先:命名需见名知意,通过分层结构清晰体现业务含义
-
一致性:统一分隔符、前缀规则、命名格式,避免团队协作混乱
-
高效性:控制键长和分层数,减少内存占用和查询开销
-
可维护性:便于批量操作、环境隔离、数据迁移
2. 命名格式规范
(1)统一格式
[环境前缀:]业务域:数据分类[:唯一标识][:子属性]
(2)各部分说明
-
环境前缀(可选):区分测试 / 生产 / 预发,如
test:(测试环境)、prod:(生产环境),无环境区分可省略 -
业务域:2-4 个字符,明确数据所属业务,如
user(用户)、order(订单)、goods(商品)、cart(购物车) -
数据分类:说明数据用途 / 类型,如
info(基本信息)、sign(签到)、stock(库存)、rank(排行榜) -
唯一标识:业务主键(如用户 ID、商品 ID、订单号),确保键唯一性
-
子属性(可选):细分数据维度,如时间(
202501)、状态(status)
(3)格式约束
-
分隔符:仅用英文冒号
:,禁止使用下划线_、横线-等其他分隔符 -
字符限制:仅用小写字母、数字、冒号,禁用中文、空格、特殊符号(
!@#$%等) -
长度限制:总长度≤64 字符,分层数控制在 3-5 层(避免过度分层)
3. 正面示例(按业务场景分类)
| 业务场景 | 数据类型 | 键名示例 | 说明 |
|---|---|---|---|
| 用户基本信息 | Hash | user:info:1000 | 存储用户 1000 的昵称、手机号、头像等 |
| 用户月度签到 | BitMap | user:sign:1000:202501 | 存储用户 1000 2025 年 1 月每日签到状态 |
| 商品库存 | String | goods:stock:8888 | 存储商品 8888 的实时库存数量 |
| 订单支付状态 | String | order:status:99999 | 存储订单 99999 的支付状态(0 = 未支付 / 1 = 已支付) |
| 热门商品排行榜 | ZSet | goods:rank:hot | 存储热门商品的销量排行榜(分数 = 销量) |
| 购物车商品列表 | Set | cart:goods:1000 | 存储用户 1000 购物车中的商品 ID 集合 |
| 测试环境用户 Token | String | test:user:token:1000 | 测试环境下用户 1000 的登录 Token |
4. 反面示例(禁止使用)
-
无分隔符:
user1000info(可读性差,无法快速识别业务) -
分隔符混乱:
user_1000_info(混用下划线,与团队规范冲突) -
过长键名:
user_center:user_basic_info:mobile_phone:13812345678:202501(长度超 64,分层冗余) -
特殊字符:
用户:1000:信息(含中文)、order:status:9999#(含特殊符号) -
分层过度:
user:1000:2025:01:15:sign:morning(6 层,无必要细分) -
语义模糊:
data:1234(无业务域和分类,无法判断数据用途)
5. 进阶优化技巧
-
环境隔离:多环境共用 Redis 实例时,必须加环境前缀(如
test:、prod:),避免数据污染 -
过期键标识:带过期时间的临时数据(如 Token、验证码),可加
exp后缀便于识别,如user:verify:1000:exp(5 分钟过期) -
批量操作适配:同类型数据统一前缀,便于用
SCAN批量遍历(如SCAN 0 MATCH user:info:* COUNT 100) -
避免冗余字段:无需在键名中重复存储属性值,如无需写
user:info:1000:phone,可通过 Hash 的phone字段存储
九、其他最佳实践
1. 性能优化
-
使用连接池:客户端统一配置连接池(如 Java 的 JedisPool、Python 的 redis-py Pool),避免频繁创建 / 关闭连接
-
批量操作优先:用
MSET/MGET(String)、HMSET/HMGET(Hash)替代多次单条命令,减少网络往返 -
禁用阻塞命令:生产环境禁止使用
KEYS *、FLUSHDB、FLUSHALL,改用SCAN、分批删除
2. 高可用部署
-
生产环境:一主多从(1 主 2 从)+ 哨兵(3 节点),主节点故障自动切换
-
大规模场景:Redis Cluster 集群(至少 6 节点,3 主 3 从),分片存储提升容量
3. 监控重点
-
内存指标:
used_memory(已用内存)、mem_fragmentation_ratio(内存碎片率,<1.5 最佳) -
性能指标:
instantaneous_ops_per_sec(每秒操作数)、latency(平均响应延迟,<5ms 最佳) -
连接指标:
connected_clients(连接数,控制在 1000 以内)、blocked_clients(阻塞客户端数,0 为正常)