数据库-Redis:常用语法 / Redis 核心知识技能梳理
Redis 是目前最流行的键值存储数据库因其高性能、丰富的数据结构和原子操作成为后端开发中不可或缺的组件。下面从基础到高级系统性地梳理 Redis 的核心知识与技能。一、Redis 是什么维度说明补充/细节全称Remote Dictionary Server远程字典服务器C 语言编写开源、内存中的数据结构存储系统定位内存中的数据结构存储系统可用作数据库、缓存和消息中间件核心定位高性能的缓存和数据结构服务器核心特点基于内存极快、单线程6.0之前 I/O多路复用、支持持久化、丰富数据结构原子性所有单命令操作都是原子性的丰富数据结构是其区别于 Memcached 的核心优势性能读写速度可达 10万 QPS性能瓶颈通常在网络 I/O而非 CPU单线程模型下适用场景缓存、会话管理、排行榜、消息队列、分布式锁、实时分析不适用场景需要复杂关系查询、海量数据存储成本高、强一致性事务非 ACID二、Redis 支持的数据结构54种含模块扩展类型底层实现常用命令使用场景复杂度平均StringSDS简单动态字符串SET/GET/INCR/DECR/SETNX/MSET缓存对象、计数器、分布式锁、SessionO(1)Hash压缩列表(ziplist) / 哈希表(hashtable)HSET/HGET/HGETALL/HINCRBY存储对象如用户信息、购物车O(1)List压缩列表(ziplist) / 双向链表(linkedlist)LPUSH/RPUSH/LPOP/RPOP/LRANGE消息队列、最新消息列表、文章评论O(1) (头尾), O(N) (中间)Set整数集合(intset) / 哈希表(hashtable)SADD/SREM/SMEMBERS/SINTER/SUNION标签系统、共同好友、抽奖、去重O(1) (增删查), O(N*M) (交集/并集)Sorted Set压缩列表(ziplist) / 跳表(skiplist)ZADD/ZRANGE/ZRANK/ZREVRANGE/ZSCORE排行榜、延迟队列、优先级队列、带权重的消息O(log N) (增删查)BitmapsString 的位操作SETBIT/GETBIT/BITCOUNT/BITOP签到统计、在线状态、用户行为分析、布隆过滤器O(1)HyperLogLog概率数据结构PFADD/PFCOUNT/PFMERGE独立访客数UV统计、基数估算O(1)GEOSorted Set 实现GEOADD/GEORADIUS/GEODIST/GEOHASH附近的人、位置距离计算、地理围栏O(log N)StreamRadix Tree ListpackXADD/XREAD/XGROUP/XACK专业消息队列、事件溯源、日志收集O(1) (追加)三、Redis 底层核心机制1. 内存管理与数据结构机制说明关键细节SDS (简单动态字符串)Redis 自定义的字符串实现二进制安全可存储图片等二进制数据O(1) 获取长度len字段直接记录杜绝缓冲区溢出free字段预分配空间API 会检查减少内存重分配空间预分配和惰性释放策略。跳表 (Skip List)ZSet 底层实现之一多层链表结构通过“快车道”实现快速查找实现简单相比红黑树实现和维护更简单范围查询高效ZRANGE操作性能优异空间换时间需要额外指针存储。压缩列表 (ziplist)小数据量时使用的连续内存块节省内存无指针开销数据紧凑读写性能新增/删除元素可能引发连锁更新cascade update导致性能下降配置阈值hash-max-ziplist-entries等配置决定何时转为哈希表。整数集合 (intset)Set 在元素为整数时使用有序、无重复元素按升序排列升级机制当插入新类型整数如从 int16 到 int64时会升级整个集合并重新分配内存此操作不可逆。对象系统 (RedisObject)所有数据类型的统一封装每个对象包含type,encoding,lru(LRU算法),refcount(引用计数) 等元数据是 Redis 实现多态和内存回收的基础。2. 单线程模型 vs 多线程模型 (6.0)特性Redis 6.0 (单线程)Redis 6.0 (多线程 I/O)命令执行单线程避免了锁竞争和上下文切换开销核心命令执行仍是单线程保证原子性I/O 处理单线程处理网络读写和命令执行多线程处理网络 I/O读取和写入响应主线程只负责命令执行性能瓶颈CPU 成为瓶颈时无法利用多核优势主要解决网络 I/O 瓶颈对于大数据量、高并发的网络场景性能提升显著线程安全天然线程安全无需考虑锁命令执行层仍是单线程核心逻辑保持简单配置io-threads-do-reads no(默认)io-threads 4(建议设置为CPU核心数)3. I/O 多路复用技术说明Redis 中的应用select早期的 I/O 多路复用模型有连接数限制1024Redis 已不再使用epollLinux 下的高效 I/O 模型无连接数限制基于事件回调Redis 在 Linux 上的默认实现性能极高kqueuemacOS/FreeBSD 下的高效 I/O 模型类似 epollRedis 在相应系统上的默认实现工作流程1.epoll_create创建实例2.epoll_ctl注册/修改 Socket 事件3.epoll_wait阻塞等待事件发生4. 事件返回后由 Redis 单线程逐个处理这是 Redis 单线程能处理大量并发连接的基石四、Redis 持久化机制深度对比RDB快照 vs AOF日志 vs 混合持久化对比维度RDB (快照)AOF (仅追加文件)混合持久化 (AOF rewrite)原理在指定时间间隔内将内存数据快照写入磁盘记录所有写命令到 AOF 文件重启时重放命令AOF 重写时将当前内存数据以 RDB 格式写入 AOF 文件开头之后的增量命令以 AOF 格式追加恢复速度快慢需重放所有命令快RDB 部分加载快AOF 部分增量小数据完整性可能丢失最后一次快照后的数据高可配置appendfsync always高同 AOF但恢复更快文件大小较小紧凑较大随时间增长较小RDB 部分紧凑AOF 部分增量性能影响fork子进程时有短暂性能影响内存拷贝持续影响写入性能取决于fsync策略重写时有短暂性能影响平时同 AOF适用场景备份、灾难恢复、对数据完整性要求不高生产环境首选追求数据高可靠Redis 4.0 推荐兼顾恢复速度和数据完整性配置示例save 900 1stop-writes-on-bgsave-error yesappendonly yesappendfsync everysecauto-aof-rewrite-percentage 100开启 AOF 后重写机制自动生效最佳实践生产环境强烈建议开启 AOF并使用appendfsync everysec策略。同时可以开启 RDB 用于定时备份。Redis 4.0 默认开启混合持久化是最佳选择。五、Redis 高可用与集群方案详解方案对比与选型方案工作原理优点缺点适用场景主从复制Master 写Slave 读单向数据同步读写分离提升读性能数据备份Master 单点故障手动故障转移麻烦读多写少对高可用要求不高的场景哨兵模式 (Sentinel)监控主从节点自动进行故障转移高可用自动故障转移监控节点健康检查通知故障通知配置相对复杂主从切换期间服务短暂不可用秒级不解决写能力瓶颈对高可用有要求但数据量和并发量不是特别巨大的场景Redis Cluster数据分片16384个槽多主多从去中心化高可用节点故障自动转移水平扩展轻松增加节点提升容量和性能客户端复杂需支持 Cluster 协议处理 MOVED/ASK 重定向不支持多键操作如MSET跨槽位事务仅支持单节点海量数据、高并发、需要水平扩展的场景主从复制核心流程与问题全量同步 (Full Sync)Slave 发送REPLCONF listening-port和PSYNC ? -1。Master 响应FULLRESYNC runid offset并 fork 子进程生成 RDB 文件。Master 将 RDB 文件发送给 SlaveSlave 清空旧数据并加载 RDB。Master 将生成 RDB 期间的写命令存入复制缓冲区 (replication buffer)并发送给 Slave。Slave 执行这些写命令达到数据一致。增量同步 (Partial Sync)断线重连后Slave 发送PSYNC runid offset。Master 检查runid是否匹配且offset是否在复制积压缓冲区 (repl_backlog_buffer) 内。如果都满足则只发送从offset开始的增量命令。否则退化为全量同步。常见问题主从数据不一致网络延迟、Slave 负载过高、maxmemory配置不当导致 key 淘汰策略不同。主从延迟Master 写压力大、Slave 单线程处理慢、网络带宽瓶颈。Redis Cluster 核心机制机制说明数据分片 (Sharding)16384 个槽位 (Slot)通过CRC16(key) % 16384计算 key 所属槽位。每个 Master 节点负责一部分槽位。节点通信节点间通过 Gossip 协议交换信息如槽位映射、节点状态实现去中心化。请求路由客户端请求到错误节点时节点会返回MOVED(永久) 或ASK(临时) 重定向指令客户端需更新槽位映射。高可用 (Failover)集群中每个 Master 都有对应的 Slave。当 Master 失效时其 Slave 会被选举为新的 Master通过 Raft 类似的共识算法并接管其负责的槽位。不支持的操作涉及多个 key 的操作如MSET key1 val1 key2 val2如果 key 不在同一个槽位会报错。需使用hash tag如{user}1001强制 key 分配到同一槽位。六、Redis 缓存三大问题与解决方案方案对比问题核心原因解决方案方案对比与选型缓存穿透查询一个不存在的数据请求绕过缓存直击数据库。1.缓存空对象将null也缓存设短过期时间。2.布隆过滤器在缓存前加一层过滤器拦截不存在的 key。缓存空对象简单但会占用少量内存且数据不一致时需主动删除。布隆过滤器高效内存占用小但有误判率可调且不支持删除。生产环境常组合使用。缓存击穿一个热点 Key在失效瞬间大量并发请求直击数据库。1.互斥锁 (Mutex)只允许一个线程去数据库加载数据其他线程等待。2.逻辑过期 (永不过期)Key 物理上不过期通过后台线程异步更新。互斥锁实现简单但高并发下线程等待会增加响应时间。逻辑过期响应快无等待但数据一致性较差可能读到旧数据实现复杂。推荐互斥锁方案。缓存雪崩1. 大量 Key同时失效。2. Redis服务宕机。1.过期时间加随机值打散失效时间。2.高可用架构哨兵或集群保证 Redis 不宕机。3.服务降级/限流数据库前加限流组件。4.多级缓存本地缓存 (Caffeine) Redis。过期时间加随机值是基础必须做。高可用架构是根本保障。多级缓存和限流是最后的防线用于应对极端情况。七、分布式锁深度剖析Redis 实现分布式锁的演进版本实现方式优点缺点SETNXSET key value NX简单原子性1. 无过期时间易死锁。2. 无法保证释放锁的是加锁的客户端误删。SET NX PXSET key value NX PX 300001. 原子性。2. 自动过期防死锁。仍有误删他人锁的风险业务未执行完锁已过期被其他客户端获取并删除。Lua 脚本if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end1. 原子性。2. 防死锁。3.安全释放通过value校验只删除自己加的锁。1. 业务执行时间超过锁过期时间仍会导致问题。2. 主从切换时锁可能丢失。Redlock在 N 个独立 Redis 实例上依次加锁成功超过半数即算成功1. 解决主从切换锁丢失问题。2. 容错性更高。1. 实现复杂性能开销大。2. 依赖系统时钟时钟漂移可能导致问题。3. 官方文档也建议仅在对强一致性要求极高的场景使用。Redisson基于 Redis 的 Java 客户端库封装了 Redlock 和可重入锁1.可重入同一线程可多次加锁。2.看门狗机制自动续期解决业务超时问题。3.公平/非公平锁、读写锁等多种实现。4. 封装完善开箱即用。增加了客户端依赖但极大地简化了开发。生产环境推荐简单场景使用SET NX PX Lua 脚本的方案并确保业务逻辑在锁过期时间内能完成。复杂/高要求场景直接使用成熟的客户端库如Redisson它内置了看门狗、可重入等高级特性是事实上的工业标准。八、Redis 事务与 Pipeline对比与选择特性事务 (Transaction)Pipeline (管道)目的原子性保证一组命令要么全执行要么全不执行。性能减少网络往返次数 (RTT)批量执行命令。原子性不保证命令在队列中时不保证EXEC后也不保证某条命令失败不影响其他。无回滚。无原子性只是批量发送不保证原子性。隔离性不保证执行期间其他客户端的命令可能穿插进来在EXEC前后。不保证同上。错误处理1.语法错误EXEC前发现整个事务失败。2.运行时错误EXEC后发现该命令失败其他命令继续执行。每个命令独立返回结果需客户端自行判断。主要命令MULTI,EXEC,DISCARD,WATCHpipeline()对象最后execute()适用场景需要将多个操作作为一个逻辑单元但对严格的数据库事务ACID要求不高。例如INCR一个计数器然后LPUSH一条日志。需要批量操作以提升性能且不关心原子性。例如一次性GET100 个 key 的值。选择建议需要保证一组操作的逻辑原子性即不希望被其他命令打断用事务。只是为了提升批量操作的性能用Pipeline。在很多场景下两者可以结合使用。九、Redis 常用性能优化速查表优化方向问题/现象排查/解决方案大 Key慢查询、内存分布不均、集群迁移困难1.发现使用redis-cli --bigkeys或memory doctor。2.拆分将一个大 Hash 拆成多个小 Hash-Key。3.避免不要用GETALL使用HSCAN游标遍历。热点 Key单点 QPS 过高成为性能瓶颈1.发现hotkeys命令需插件或监控平台。2.拆分将热点 Key 拆分为多个如hot_key_1,hot_key_2通过随机数读写。3.本地缓存在应用层加 Caffeine 等本地缓存。慢查询命令执行时间过长阻塞其他请求1.发现SLOWLOG GET 10查看慢查询日志。2.分析检查慢查询命令如KEYS,HGETALL大 Key。3.解决用SCAN替代KEYS拆分大 Key优化业务逻辑。内存溢出maxmemory限制触发淘汰策略1.监控INFO memory查看used_memory。2.分析memory stats分析内存分布。3.解决调整maxmemory-policy如allkeys-lru增加内存优化数据结构。连接数过高CLIENT LIST显示大量连接1.优化使用连接池JedisPool, Lettuce复用连接。2.排查检查是否有连接泄漏未正确关闭。CPU 100%单线程模型下 CPU 跑满1.排查INFO commandstats查看高频命令。2.原因通常是执行了复杂命令如SORT,ZUNIONSTORE或大量 Key 过期。持久化开销fork子进程时响应变慢1.配置repl-diskless-sync yes无盘复制适用于主从。2.硬件使用 SSD 硬盘。十、企业级最佳实践与场景速查业务场景推荐 Redis 数据结构/方案核心命令/实现关键点高并发缓存String 本地缓存 (Caffeine)SETEX,GET缓存穿透/击穿/雪崩防护热点 Key 预热数据一致性策略计数器/排行榜String (INCR) / Sorted SetINCR,ZINCRBY,ZREVRANGE原子性操作Sorted Set 可带成员信息实现复杂排行分布式 SessionString HashSETEX user:session_id json_str,HSET user:1 name AKey 需有统一前缀设置合理过期时间序列化用 JSON 或 Protobuf分布式锁Redisson (推荐) / SET LuaRLock.lock(),SET key val NX PX防死锁过期时间/看门狗安全释放Lua校验可重入消息队列Stream (专业) / List (轻量)XADD,XREADGROUP,LPUSH,BRPOPStream 支持消费组、消息确认 (ACK)、消息回溯功能完善List 简单但无ACK社交关系Set / Sorted SetSADD,SINTER,ZRANGE共同好友用SINTER关注列表用Set或List实时统计 (UV/PV)HyperLogLog / BitmapPFADD,PFCOUNT,SETBIT,BITCOUNTHyperLogLog 基数统计省内存Bitmap 用于精确签到、在线状态地理位置服务GEOGEOADD,GEORADIUS基于 Sorted Set 实现可用于“附近的人”、“打车”等场景标签/筛选Set / BitmapSADD,SISMEMBER,SETBIT标签用 Set 实现交集/并集筛选多维筛选可用 Bitmap 实现配置中心Hash / StringHSET config_key field val,GET config_key监听 Key 的过期或变更消息需客户端实现或结合 Pub/Sub本文通过多维度的对比表格、深入的机制剖析、方案选型建议以及企业级最佳实践力求构建一个更加立体和深入的 Redis 知识体系。欢迎交流指正。