【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在执行这些命令时,是串行执行的。(现实生活打饭的例子~)

相关推荐
张彦峰ZYF2 分钟前
高并发场景下的缓存穿透问题探析与应对策略
redis·分布式
xiaolang_8616_wjl4 分钟前
c++题目_传桶(改编于atcoder(题目:Heavy Buckets))
数据结构·c++·算法
DB虚空行者14 分钟前
MySQL恢复之Binlog格式详解
android·数据库·mysql
lkbhua莱克瓦2418 分钟前
基础-SQL-DQL
java·开发语言·数据库·笔记·mysql·dql
lkbhua莱克瓦2422 分钟前
基础-SQL-DCL
开发语言·数据库·笔记·mysql·dcl
Rainly20001 小时前
工作日志之postgresql实现分布式锁
数据库·分布式·postgresql
爬山算法1 小时前
Hibernate(6) Hibernate支持哪些数据库?
java·数据库·hibernate
老华带你飞2 小时前
房屋租赁管理系统|基于java+ vue房屋租赁管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot·后端
张彦峰ZYF2 小时前
优化分布式系统性能:热key识别与实战解决方案
redis·分布式·性能优化
张彦峰ZYF2 小时前
高并发场景下的大 Key 问题及应对策略
redis·分布式·缓存