第三篇:Redis 为什么只有五种数据类型,却能支撑几乎所有业务?

第三篇:Redis 为什么只有五种数据类型,却能支撑几乎所有业务? Redis 为什么只有五种数据类型却能支撑几乎所有业务上一篇我们聊了《Redis 为什么选择单线程性能为什么还能这么高》知道了 Redis 为什么敢让所有命令都串行执行。很多同学又会产生新的疑问。Redis 官方不是一直说只有五种数据类型吗StringListHashSetZSet可是现实项目里无论是缓存、排行榜、点赞、签到、消息队列、购物车几乎都能用 Redis 实现。五种数据类型为什么能够支撑这么多业务答案其实只有一句话你看到的是数据类型Redis 内部真正使用的是数据结构。今天我们就把 Redis 最重要的设计思想讲明白。很多人理解错了数据类型先来看一个例子。我们执行下面这条命令SET name pxp很多人会认为Redis 创建了一个 String实际上并不是。Redis 内部真正保存的是RedisObject │ ▼ Type │ ▼ Encoding │ ▼ 真正的数据结构也就是说。Redis 对外暴露的是五种数据类型对内却可以有很多种实现方式。这也是 Redis 灵活和高性能的关键。RedisObject 才是真正的入口Redis 里面所有数据都会被包装成一个对象。可以简单理解成RedisObject ├── type ├── encoding ├── ptr例如type String encoding INT ptr - 100或者type String encoding EMBSTR ptr - hello再或者type String encoding RAW ptr - SDS注意。它们三个都是String。但是底层实现完全不同这就是 Redis 最经典的一层抽象。什么是 Encoding很多同学第一次看源码时都会看到一个字段encoding一脸懵为什么还有 Encoding原因很简单。同一种数据类型在不同场景下最优的数据结构并不一样。例如 String。如果保存的是100Redis 根本不会申请字符串直接保存整数。如果保存的是helloRedis 会采用一种针对短字符串优化的结构。如果保存的是一个几 KB 的长字符串……又会切换成另一种实现。对外都是 String对内已经完全不同整个过程对开发者完全透明。Hash 也是一样很多人觉得 Hash 就是一张哈希表。其实不是假设保存一个用户。HSET user:1 name Tom age 18如果字段很少Redis 会采用一种连续内存结构。优点就是更省内存CPU Cache 命中率高但是如果字段越来越多Redis 会自动切换成真正的哈希表整个切换过程开发者完全感觉不到。你仍然执行的是HGET并不会因为底层发生变化而修改代码。List 真的是链表吗很多人学 Redis 时都会看到一句话List 底层是链表。实际上。这句话早就过时了。Redis 为了性能List 的实现经历了多次演进。大致经历了LinkedList │ ▼ ZipList │ ▼ QuickList │ ▼ QuickList ListPack为什么一直改因为开发者发现不同的数据结构各有优缺点链表插入快。但是占内存CPU Cache 不友好连续内存访问快。但是插入效率下降于是 Redis 不断优化最终形成今天的 QuickList。下一篇我们就专门讲它为什么不用传统链表。ZSet 为什么既排序又查找很快排行榜就是最经典的场景。例如张三 100 李四 98 王五 95既要查张三分数又要查排行榜前十如果只用哈希表排名很慢。如果只用链表查找又很慢于是 Redis 直接组合了两种数据结构。最终既能O(1) 查找又能O(logN) 排序至于为什么不是红黑树而是跳表。我们后面会单独讲。Redis 为什么不直接让开发者选择底层数据结构很多数据库都会让开发者自己决定BTreeHashBitmap但是 Redis 没有。因为 Redis 希望做到同一种数据类型根据数据规模自动选择最佳实现。例如今天只有三个字段使用省内存方案明天数据变成三万个字段自动升级成高性能方案整个过程业务代码一行都不用改。这就是 Redis 的设计哲学让复杂留给自己让简单留给开发者。Redis 为什么只有五种数据类型现在我们回到最开始的问题。为什么只有五种数据类型却能支撑几乎所有业务原因就在于五种只是对外暴露的接口。真正工作的是后面各种不同的数据结构可以简单理解成String │ ├── INT ├── EMBSTR └── RAW Hash │ ├── ListPack └── Hashtable List │ └── QuickList Set │ ├── IntSet └── Hashtable ZSet │ ├── SkipList └── Hashtable也就是说 Redis 真正厉害的地方不是只有五种数据类型。而是一种数据类型可以根据不同场景自动切换最合适的数据结构。这才是 Redis 能兼顾性能和易用性的真正原因。总结很多人学习 Redis只记住了五种数据类型。其实这只是 Redis 暴露给开发者的一层抽象。真正支撑 Redis 高性能的是隐藏在背后的各种数据结构以及自动切换 Encoding 的设计思想。所以我们真正应该记住的是一句话Redis 对外提供的是数据类型对内维护的是数据结构。正因为有了这层抽象Redis 才能在不同的数据规模、不同的业务场景下始终选择更合适的实现方式。这也是 Redis 设计最巧妙的地方之一。上一篇《Redis 为什么选择单线程性能为什么还能这么高》下一篇《Redis String 为什么不是 StringSDS 到底解决了什么问题》如果这篇文章让你第一次理解了 RedisType 和 Encoding的关系欢迎点赞、收藏。下一篇我们正式进入 Redis 最经典的数据结构——SDS看看 Redis 为什么宁愿自己重新发明字符串也不用 C 语言原生的char*。