🐼Redis 的 5 种数据类型
type 命令实际返回的就是当前键的数据结构类型,它们分别是:string(字符串)、list(列表)、hash(哈希)、set(集合)、zset(有序集合),但这些只是 Redis 对外的数据结构,当然Redis可不只这5种数据结构,大概有10种。我们介绍最常用的,如图所示:

实际上 Redis 针对每种数据结构都有自已的底层内部编码实现,而且是多种实现,这样 Redis 会
在合适的场景选择合适的内部编码,目的就是为了达到节省时间/空间的效果!举个例子:对于哈希表来说,Reids给我们承诺:进行增加,删除,查找,保证时间复杂度为O(1)。但是在这个背后,在特定场景下,使用别的数据结构来实现,不保证是真的用哈希表实现的,但是仍要保持时间复杂度为O(1)的承诺!
所以数据结构/类型是Redis承诺给我们的,但是其底层的实现,也就是内部编码方式,Redis对于不同的类型会采取不同的内部编码,会自适应,我们用户感知不到,对于我们用户是透明的
不过要想查看内部编码方式可以使用OBJECT encoding key来查看
下面我们来一一看看Redis的数据结构和数据编码方式,数据结构可以看做为数据类型,数据编码方式,就是内部的底层实现:如图:
✅string
类比于std::string.其编码方式
- 如果采用的是raw,表示的是最基本的字符串,它的底层就是一个char的数组
- 而如果采用的是int的编码方式,则对应的场景可能是要使用一些类似于计数的功能,那么此时作为Value值,其实使用传统意义的字符是没有意义的,直接使用整数int来保存是一个更好的解决方案
- 如果采用的是embstr,则表示的是针对于短字符串进行的特殊优化
✅hash
- hash这种数据类型,第一种内部编码是hashtable,这种实现方式就是最基本的实现方式,Redis内部也是用这种最基本的方式来实现的,虽然这里的实现方式和前面的不太一样,但是也大体思维差不多
- 而对于一些元素比较少的时候,如果还使用哈希表其实是没有意义的,因此就会把对应的编码方式更换为ziplist,它的主要目的可以进行列表的压缩,这样可以节省空间
可是为什么要压缩?
redis中可能会有很多key,key的value也可能对应很多hash,如果key特别多,hash也特别多,但是每个hash又不是很大,Redis就会自适应,内部编码就为ziplist,帮助我们去压缩,压缩后整体的空间就会变小了很多。
✅list
linklist可以看做链表,ziplist就是压缩链表,不过现在有了quicklist,兼顾了linklist和ziplist的优点
✅set
类比于我们学的集合
✅zset
有序集合,其中skiplist是根据跳表实现的
为啥redis要这么设计嘞?
可以改进内部编码,⽽对外的数据结构和命令没有任何影响,这样⼀旦开发出更优秀的内部编码,⽆需改动外部数据结构和命令,例如 Redis 3.2 提供了 quicklist,结合了 ziplist 和 linkedlist 两者的优势,为列表类型提供了⼀种更为优秀的内部编码实现,而对用户来说基本⽆感知
多种内部编码实现可以在不同场景下发挥各⾃的优势,例如 ziplist ⽐较节省内存,但是在列表元素⽐较多的情况下,性能会下降,这时候 Redis 会根据配置选项将列表类型的内部实现转换为 linkedlist,整个过程用户同样无感知
最后总结一下,redis会根据实际情况来选择内部的编码方式,我们只需要理解编码方式的思想即可
redis只有一个线程,来处理所有的命令请求!不是说redis服务器内部只有一个线程,还是有多个线程去处理网络IO
🐼redis单线程还能这么快?
难不成这个线程有魔法?其实不是这样的。redis快,是比MySQL要快。为什么redis能够使用单线程处理任务?
✅redis能够使用单线程的原因,是因为它是在内存的,并且任务仅仅就是处理kv键值对,这样的简单操作,短平快的操作。Redis 将所有数据放在内存中,内存的响应时⻓⼤约为 100 纳秒,这是 Redis 达到每秒万级别访问的重要基础。
✅redis的核心业务逻辑,不太消耗CPU和内存,都是很简单的
✅没有了多线程,就不会进行线程间切换,并且避免了锁带来的竞争
✅redis采用多用复用的非阻塞IO,使⽤ epoll 作为 I/O 多路复⽤技术的实现,再加上 Redis ⾃⾝的事件处理模型将 epoll 中的连接、读写、关闭都转换为事件,不在⽹络 I/O 上浪费过多的时间
不过这样单线程带来的缺点就是redis特别怕哪个线程发来一个请求特别长,最阻塞其他命令的执行。
我们这里再来思考一个问题,如果多个并发的客户端同时请求redis服务器,修改一个变量,会导致线程安全问题吗?不会!多个请求会在redis事件处理队列中排队,所以这些命令即使在发起时是并发的,但是到达redis,就变的有序了,需要排队,redis在执行这些命令时,是串行执行的。(现实生活打饭的例子~)