Redis

📅 发布时间:2026/7/7 2:35:59 👁️ 浏览次数:
Redis
数据类型String用于用户会话管理、页面缓存和统计信息如访问计数。底层数据结构是 SDS (Simple Dynamic String)类似于 C 语言的动态字符串。hash适合存储用户资料、商品信息等复杂对象便于修改和访问。底层数据结构是 ziplist (压缩列表)当字段和值的数量较少且长度较小时使用hashtable (哈希表)当数据量大或长度较长时使用。List用于任务队列、消息队列或时间序列数据如聊天记录。底层数据结构是 ziplist (压缩列表)当列表元素较少或每个元素较小时使用linkedlist (双向链表)当列表较大时使用quicklist (快速列表)Redis 3.2 引入是 ziplist 和 linkedlist 的混合体用于减少内存消耗并提高操作效率。Set适合实现社交网络中的好友关系、标签系统处理去重。底层数据结构是 intset (整数集合)当集合中的元素全为整数且数量较少时使用hashtable (哈希表)当集合中的元素较多或类型复杂时使用。Sorted Set用于排行榜、延迟队列或事件时间戳管理能根据分数排序。底层数据结构是 ziplist (压缩列表)当元素数量较少且每个元素长度较短时使用skiplist (跳表) hashtable (哈希表)哈希表用来存储成员和分值之间的映射。跳表用于实现按分值排序。Bitmap实现布隆过滤器、统计活跃用户等。底层数据结构是字符串 (String)位图是以字符串为基础通过位操作实现。HyperLogLog统计基数例如估算不重复用户数。底层数据结构是基于稀疏矩阵的算法用较小的空间实现近似计数。Geo存储地理位置并计算距离或查找附近的点。底层数据结构是基于 Sorted Set使用 Geohash 编码将纬度和经度映射为分值。Stream日志、消息队列等实时数据流场景。底层数据结构是 Radix Tree (压缩字典树)存储数据Listpack (压缩列表)优化小范围数据的存储。Redis 读取数据速度快的原因将数据存储在内存中相比传统的磁盘存储内存访问速度更快响应时间低。使用单线程处理请求避免了多线程中的上下文切换和锁竞争简化了并发处理。提供了多种高效的数据结构并对这些数据结构进行了优化能够高效执行各种操作。使用自定义的协议RESP减少了网络通信的开销提高了数据传输速度。尽管主要运行在内存中Redis 还提供了快照和追加日志等持久化方式确保数据的安全性而不显著影响性能。Redis 允许客户端使用异步操作进一步提高了并发性能。并发 key 问题尽管 Redis 是单线程的但是它在高并发情况下依然会出现并发问题的单线程特性确实使得在执行请求时每个操作是顺序进行的但这并不能完全保证在高并发环境下客户端 A 和客户端 B 对同一键的操作会严格按照顺序执行。Redis 会依次处理客户端的请求。例如如果客户端 A 的请求先到达 Redis然后是客户端 B 的请求Redis 会先执行客户端 A 的操作。然而网络延迟和请求的到达顺序会影响执行的结果。在高并发情况下如果客户端 B 的请求在客户端 A 的读操作之前到达 Redis但由于客户端 A 的请求在处理时没有被打断Redis 仍然会按照收到请求的顺序执行。如果客户端 A 和 B 同时发送请求且客户端 A 依赖于读取的值进行后续写入可能会出现问题。比如客户端 A 读取值为 10。客户端 B 也读取值为 10。客户端 A 修改并写入 11。客户端 B 也基于读取的 10 修改并写入 15。在这种情况下最终的值会是 15而不是预期的 16。解决方案如下乐观锁使用 WATCH 命令监视特定键在事务 (MULTI 和 EXEC) 中执行时如果监视的键被修改则事务会失败可以重试。悲观锁使用 SETNX 命令实现分布式锁确保在处理关键数据时只允许一个线程或进程访问。原子操作Redis 的一些命令如 INCR、DECR 等是原子性的可以安全地在并发环境中使用。使用 Lua 脚本可以将多个命令打包在一个 Lua 脚本中执行保证脚本中的操作是原子性的避免中间状态被其他请求影响。请求合并对于频繁访问同一个 key 的请求可以考虑请求合并减少对数据库的压力。不要求顺序的话使用分布式锁抢到后进行更新要求顺序的话设定时间戳进行更新事务Redis 中的事务可以保证原子性但在特定的上下文中。MULTI 和 EXEC在事务中客户端通过 MULTI 命令开始一个事务然后可以排队多个命令。当执行 EXEC 命令时所有排队的命令会作为一个整体被执行确保它们在执行期间不被其他命令干扰。这种方式保证了排队命令的原子性。不支持回滚Redis 事务中的命令是原子的但一旦 EXEC 被执行所有命令都会执行即使其中某个命令失败。Redis 也不会回滚。WATCH 命令如果使用 WATCH 命令监视某些键在执行 EXEC 时如果监视的键在事务开始后被其他客户端修改事务将不会执行。这种机制可以避免在并发场景下出现数据不一致的情况。局限性事务中的所有命令都是依次执行的但如果某个命令的执行时间较长其他客户端的请求仍然会被阻塞可能会导致性能瓶颈。集群的最大槽数是16384 原因权衡性能和灵活性16384 是一个较小但足够分布均匀的数字Redis 的设计追求高效使用较小的槽数可以减少元数据开销同时加快槽位迁移和重平衡。16384 个槽能够较好地将数据分散到不同的节点上避免热点问题。内存开销每个槽都需要元数据记录其分配关系。16384 槽的元数据开销较小适合 Redis 的轻量化设计。如果槽数太大例如数百万不仅元数据管理变得复杂还可能导致性能下降。符合常见的分布式需求大多数 Redis 集群规模在 10 到 100 个节点之间16384 槽足以满足大部分业务需求。对于更大的集群数百个节点仍然可以通过增加每节点负责的槽数量来维持平衡。2 的次幂优化计算16384 是2142^{14}214是 2 的幂次方。这种设计在计算机科学中常用于优化计算使用位操作 运算可以快速计算哈希槽归属对硬件友好提升哈希计算效率。Redis 集群中槽数是固定的不能动态调整主要原因是固定槽数确保了 Redis 集群的哈希分布规则始终一致避免了因槽数调整导致的数据混乱或重分配问题固定槽数减少了复杂性避免了动态调整槽数时可能引入的额外逻辑动态槽数会导致元数据随集群规模而增长影响性能和内存使用。当 Redis 集群达到 16384 槽的限制时可以通过以下方式扩展部署多个独立的 Redis 集群每个集群管理自己的 16384 个槽。应用层可以通过逻辑分片如用户 ID 范围来路由到不同的集群。持久化RDBRedis 数据库备份通过定期快照将内存中的数据保存到磁盘上生成一个 RDB 文件通常为 dump.rdb。可以通过 SAVE 命令手动触发或通过 SAVE 和 CONFIG SET 指定时间间隔进行自动保存。启动速度快适合大数据量的快速恢复适合备份和迁移。但是数据在保存间隔内可能丢失即最后一次保存后到崩溃之间的数据。AOF追加文件将每次写操作记录到一个日志文件中通常为 appendonly.aof在重启时通过重放这些操作恢复数据。可以通过设置 appendfsync 选项指定写入策略如每次操作后、每秒或不进行同步。这样具有更高的数据安全性因所有写操作都被记录。可以在恢复时更细粒度地控制数据。但是启动速度较慢尤其是在大日志文件的情况下可能占用更多的磁盘空间。RDB 是默认方式持久化如果同时开启则选择 AOF。可以同时启用 RDB 和 AOF以结合两者的优点。Redis 允许根据需要配置这两种持久化机制从而实现数据的安全性和性能的平衡。