Redis-数据结构与命令

63 阅读11分钟

Redis-数据结构与命令

一、SQL VS NoSQL

维度SQL(关系型数据库,如 MySQL/PostgreSQL)NoSQL(非关系型数据库,以 Redis 为代表)
数据模型结构化数据,严格遵循表结构、字段类型、约束(主键 / 外键)非结构化 / 半结构化,支持键值、文档、列族、图形等灵活模型(Redis 为键值型)
存储方式磁盘存储为主,依赖磁盘 IO内存存储为主(Redis 可持久化到磁盘),内存 IO 性能远高于磁盘
事务特性支持 ACID 完整事务(原子性、一致性、隔离性、持久性)部分支持(Redis 仅单命令原子性,集群下弱事务),优先性能
扩展性垂直扩展为主(升级硬件),水平扩展复杂(分库分表)天然支持水平扩展(Redis Cluster 分片),扩容简单
查询能力支持复杂 SQL 查询(联表、聚合、子查询),查询灵活仅支持简单键查询 / 特定数据结构命令,复杂查询需客户端处理
数据一致性强一致性,符合 ACID最终一致性(分布式场景),Redis 单机强一致、集群弱一致
适用场景数据关系复杂、需事务保障、复杂查询(如订单系统、财务系统)高性能读写、缓存、临时数据、非关系型数据(如计数器、排行榜、会话存储)
示例MySQL、Oracle、PostgreSQLRedis、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. 基础数据类型(核心命令 + 应用场景)

数据类型核心命令应用场景
StringSET、GET、INCR、DECR、MSET、 MGET计数器、缓存简单值、会话存储、验证码存储
HashHSET(本身可批量)、HGET、HGETALL、HDEL、HKEYS、HVALS存储 对象(如用户信息、商品详情)
ListLPUSH、RPUSH(咱俩都可批量)、LPOP、RPOP、LRANGE消息队列、最新列表、评论分页
SetSADD、SISMEMBER、SDIFF、SUNION、SREM数据去重、好友交集 / 并集、抽奖活动
Sorted Set(ZSet)ZADD、ZRANGE、ZREVRANK、ZSCORE、ZREM排行榜、带权重的队列、延迟任务

2. 特殊数据类型(核心命令 + 应用场景)

数据类型核心命令应用场景
GEOGEOADD、GEOPOS、GEODIST、GEORADIUS、GEOHASH地理位置计算(附近的人、门店距离、同城服务)
BitMapSETBIT、GETBIT、BITCOUNT、BITOP、BITPOS海量用户二值状态统计(签到、在线状态、打卡)
HyperLogLogPFADD、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. 缓存三大问题解决方案

问题现象解决方案
缓存穿透查询不存在的数据,绕过缓存打 DB1. 缓存空值(设置短期过期);2. 布隆过滤器拦截
缓存击穿热点 Key 过期,大量请求瞬间打 DB1. 互斥锁(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. 正面示例(按业务场景分类)

业务场景数据类型键名示例说明
用户基本信息Hashuser:info:1000存储用户 1000 的昵称、手机号、头像等
用户月度签到BitMapuser:sign:1000:202501存储用户 1000 2025 年 1 月每日签到状态
商品库存Stringgoods:stock:8888存储商品 8888 的实时库存数量
订单支付状态Stringorder:status:99999存储订单 99999 的支付状态(0 = 未支付 / 1 = 已支付)
热门商品排行榜ZSetgoods:rank:hot存储热门商品的销量排行榜(分数 = 销量)
购物车商品列表Setcart:goods:1000存储用户 1000 购物车中的商品 ID 集合
测试环境用户 TokenStringtest: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 *FLUSHDBFLUSHALL,改用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 为正常)