【Redis】浅谈数据结构和内部编码和单线程架构

🐼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

  1. hash这种数据类型,第一种内部编码是hashtable,这种实现方式就是最基本的实现方式,Redis内部也是用这种最基本的方式来实现的,虽然这里的实现方式和前面的不太一样,但是也大体思维差不多
  2. 而对于一些元素比较少的时候,如果还使用哈希表其实是没有意义的,因此就会把对应的编码方式更换为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在执行这些命令时,是串行执行的。(现实生活打饭的例子~)

相关推荐
山峰哥1 小时前
现代 C++ 的炼金术:铸就高性能与高可维护性的工程实践
java·开发语言·前端·数据结构·c++
工藤学编程1 小时前
零基础学AI大模型之新版LangChain向量数据库VectorStore设计全解析
数据库·人工智能·langchain
+VX:Fegn08952 小时前
计算机毕业设计|基于springboot + vue服装商城系统(源码+数据库+文档)
数据库·vue.js·spring boot
SoleMotive.2 小时前
Mysql底层的数据结构,为什么用B+树,如果在内存中,B树和B+树查询效率怎么样
数据结构·b树·mysql
JIngJaneIL2 小时前
基于Java在线考试管理系统(源码+数据库+文档)
java·开发语言·数据库·vue.js·spring boot
煎蛋学姐2 小时前
SSM水务办公管理网emxyu(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·ssm 框架·水务办公管理·抄表管理系统
JIngJaneIL2 小时前
基于Java音乐管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot
数据皮皮侠2 小时前
中国气候政策不确定性数据(2000-2022)
大数据·数据库·人工智能·信息可视化·微信开放平台
代码雕刻家2 小时前
1.10.课设实验-数据结构-查找-机票查询
c语言·数据结构·算法