Redis常用数据库及单线程模式
数据结构和内部编码
type命令实际放回是当前键数据结构类型,有string,list,hash,set,zest。
redis底层实现上述数据,在源码层面会有优化,就可以节省空间和时间上的消耗,编码方式会有不同。
redis针对每种数据结构都有自己底层内部编码实现,有多种的形式,如hash表,进行查询,插入,删除操作都是O(1),但是背后的实现不一定是hash,但能保证时间复杂度是不变的。就像你买可乐,但是给你雪碧,虽然不一样,但是都有汽包。
示例
127.0.0.1:6379> set hello world
OK
127.0.0.1:6379> lpush mylist a b c
(integer) 3
127.0.0.1:6379> object encoding hello
"embstr"
127.0.0.1:6379> object encoding mylist
"quicklist"
“编码”(encoding) 指的是 Redis 在底层存储数据时采用的具体实现方式或数据结构。
设计意义
可以进行内部编码,对外部数据结构没有任何影响,一旦开发出更优势的内部编码,就不需要改动外部数据结构和命令。
多种内部编码实现,就可以在不同场景下发挥各自优势,有的可以节省空间,有的可以提高效率,具体使用哪一个是看环境的,阈值不是不变的。
redis内部编码
raw:底层就是持有一个char数组。
int:Redis 通常也可以用来实现“计数”的功能 --- 点赞计数,当value就是一个整数的时候, Redis就会直接使用 int 来保存。
embstr:针对短字符串进行的特殊优化,这样占据的空间会比较小,大了就转成raw。
hashtable:这就是最基本的哈希表。
ziplist:压缩列表,针对特殊的场景下,就是在哈希表里面元素比较少的时候,可能就优化成了 ziplist 了,可以节省空间。遍历的过程因为量少也是O(1)的。
linkedlist:就是普通的链表。Redis 3.2 开始引入了 quicklist 来代替了 list 的上面这两种内部编码。
intset:集合中存放的都是整数,就会优化成intset
skiplist:跳表,每个节点上有多个指针域,巧妙的搭配这些指针域的指向,就可以做到从跳表上查询元素的时间复杂度是 O(logN)。
跳表 = 电梯 + 楼梯
第 1 层(L1):每层都有楼梯(所有节点相连,相当于原始链表)。
第 2 层(L2):每隔 2 层有一个电梯(比如 1→3→5→7→9),可以直接跳过中间楼层。
第 3 层(L3):每隔 4 层有一个高速电梯(比如 1→5→9),跳过的楼层更多。
查找过程(查询 Nike 在 7 楼):
先坐 L3 高速电梯:1→5(因为 9 超过了 7,不下)。
换乘 L2 电梯:5→7(找到目标!)。
总共只检查了 1→5→7 三个节点,而不是 1→2→...→7 的 7 次。
单线程架构
redis只是用一个线程,处理所有的命令请求,redis内部并不是只有一个线程,有多个线程,但是其它线程都是处理网络IO请求,这些线程会把数据都交给一个核心线程处理。
多个线程数据发送过去,但是因为单线程,所以是串行执行,所有请求的处理都是出一个进一个。
Redis单线程高效原因
通常来讲,单线程处理能力要比多线程差,例如有 10000 公斤货物,每辆车的运载能力是每次 200 公斤,那么要 50 次才能完成;但是如果有 50 辆车,只要安排合理,只需要依次就可以完成任务。那么为什么 Redis 使用单线程模型会达到每秒万级别的处理能力呢?
1.内存访问
redis的所有数据都在内存中,而内存响应时间短。
2.非阻塞IO
redis使用epoll作为IO多路复用技术实现,redis中事件处理模型将连接,读写,关闭都变为事件,就在网络IO上减少了时间,在业务逻辑不复杂情况下,这样就可以高效处理请求了,要是业务逻辑复杂,就会在处理业务上等待时间,就会阻塞住。