Redis的数据结构与单线程架构

"飞吧,去寻觅红色的流星"


Redis中的五种数据结构和编码

Redis是一种通过键值对关系存储数据的软件,在前一篇中,我们可以使用type命令实际返回当前键所对应的数据结构类型,例如: String\list\hash\set等等。

但这些所有的数据结构都是对外表现的,也就是底层可能不是真正的列表,不是真正所谓的所谓的哈希!实际上Redis针对每种数据结构都有⾃⼰的底层内部编码实现,而且是每个类型都有多种实现方式,这样Redis能够在不同的场景下,选择使用合适的内部编码。

数据结构: redis承诺给你的,也可以理解为数据类型

编码方式: redis数据类型的底层实现

|--------|-----------|
| 数据结构 | 内部编码 |
| string | raw |
| string | int |
| string | emstr |
| hash | hashtable |
| hash | ziplist |
| list | linklist |
| list | ziplist |
| set | hashtable |
| set | intset |
| zset | skiplist |
| zset | ziplist |

● string:

raw表示最基本的字符串,底层是持有char类型的数组(C++),或者byte数组(Java)。

int在redis中通常会用来实现一些计数功能。

embstr 针对短字符串的优化。

● hash:

hashtable 最基本的哈希表,由redis内部哈希实现。

ziplist 当哈希表中的元素较少时,可能优化为ziplist了,压缩列表节省空间。

● list:

linkedlist 普通链表,ziplist压缩列表。在redis3.2之后引入了新的实现方式,它兼顾了linkedlist和ziplist的方式------quicklist。quicklist就是一个链表,每一个元素是ziplist,把空间和效率都兼顾到。这个quicklist可以类似C++中的deque。

● set:

inset集合中存储的是整数。

● zset:

skiplist跳表,这是一个用来查找的比较复杂链式结构。它能够做到将查找效率优化到O(logN)。

为什么需要压缩?

redis中有很多key,某些key中的value类型是一个哈希结构,如果key特别多可是value中的哈希不多时,就会尽量去压缩空间,让其整体占用空间变小。


Redis的单线程架构

现如今,我们已经学习了redis中的基本命令以及常用的五种数据结构和它们自身内部的编码方式,对redis本身也算有了一定了解。可是你是否有和我一样有一定的疑问,就是redis为什么是一个单线程进程?换句话说,为什么redis只用一个线程来处理、执行命令呢?

假设有多个客户端同时操作redis服务器:

所以,单线程模型的好处就在于,执行命令的串行化,能够保障线程安全。另外,redis使用单线程模型的另外的原因在于,redis的核心业务逻辑都是短平快的!不太会占用大量的CPU资源和过多核。

当然单线程模型的坏处就在于,比如之前提及到的 "keys *" ,单个操作如果占用太长的时间,会导致其他请求无法得到快速地处理。

redis虽然是一个单线程模型,为啥效率这么高呢?

这伙同redis为什么快是差不多的。这里的效率高、快都是相对于关系型数据库Mysql、oracle、SQL server等。

● redis访问的内存,而数据库访问的是硬盘。

● redis的核心功能更为简单,比起数据库而言。

比如数据库需要提供数据插入、删除的各种约束,提供更加复杂的功能支持,这样势必会花费更多开销。

● 单线程模型,避免了线程切换和竞态产⽣的消耗。加之redis处理的场景都是些短平快的业务,不占用太多cpu,就算改成多线程提升也不明显。

● ⾮阻塞IO。Redis使⽤epoll作为I/O多路复⽤技术的实现,再加上Redis⾃⾝的事件处理模型将epoll中的连接、读写、关闭都转换为事件,不在⽹络I/O上浪费过多的时间。

如何理解多路I/O复用技术?

所谓的多路I/O复用机制,就是指的是一个线程可以管理监测多个socket。针对Tcp而言,每一次连接都需要服务端为客户端安排一个socket。最开始的时候,是为每一个socket分配一个线程, 但一旦客户端持续增多,连接数持续增多,线程也就开的越多,系统开销越大。

可是,一个服务器上那么多个socket,它们并非时时刻刻都会向客户端传输数据,所以,大多数情况下,tcp上的IO是处于阻塞当中,在等待客户端发送数据过来。所以,同一时刻只有少数的socket是活跃的状态,需要服务端提供服务。

Linux中提供了三套多路复用的AIP:

select、poll、epoll,其中属epoll使用频率最高,因为它使用起来简单,并且效率是最高的(LT\ET模式) 。

Epoll底层机制:


本篇到此结束,感谢你的阅读。

祝你好于,向阳而生~

相关推荐
吃海鲜的骆驼1 小时前
使用Spring Data Redis操作Redis
java·redis·spring
hzj61 小时前
极简Redis速成学习
数据库·redis·学习
图图图图爱睡觉2 小时前
用大白话解释缓存Redis +MongoDB是什么有什么用怎么用
数据库·redis·mongodb
笨手笨脚の3 小时前
Redis 源码分析-内部数据结构 robj
数据结构·数据库·redis·raw·redisobject·44字节·embstr
ccc_9wy14 小时前
玄机-第二章 redis应急响应的测试报告
redis·网络安全·ssh·主从复制·ida pro·玄机靶场·redis应急响应
程序猿小白菜15 小时前
Redis缓存一致性难题:如何让数据库和缓存不“打架”?
数据库·redis·缓存
m0_7482400215 小时前
macOS安装Redis
数据库·redis·macos
m0_7482513517 小时前
redis批量删除namespace下的数据
数据库·redis·缓存
别致的影分身18 小时前
Redis 分布式锁
数据库·redis·分布式
八月五18 小时前
Redis 底层数据结构 —— SDS(简单动态字符串)
redis