【Redis_Day4】内部编码和单线程模型
【Redis_Day4】内部编码和单线程模型
- 五大数据类型
- 内部编码
- object encoding key1:查询key1对应值的内部编码
- redis中的单线程模型
redis中的数据都是以键值对的方式存的,redis内部用哈希表组织这些键值对。
五大数据类型
站在用户角度,
在一个键值对内部,键的数据类型都是String,值的数据类型有很多选择,最常用的数据类型有五个,分别是字符串(String),哈希表(hash),列表(list),集合(set),有序集合(zset)。操作不同的数据结构需要使用不同的命令。
内部编码
站在redis角度,
Redis底层在实现用户使用的五大数据结构的时候,Redis针对每种数据结构的实现都有自己的底层内部编码,而且针对一种数据结构往往有多种实现,即一种数据结构对应多个内部编码。Redis内部会在合适的场景选择合适的内部编码存储管理数据。
每种数据结构都至少有两种以上的内部编码。
用户存储数据的时候,redis会自动选择具体用什么内部编码来保存数据,用户感知不到redis行为。比如用户存储字符串,redis中保存这个字符串的时候可能是通过raw,也可能是int,也可能是embstr。
-
raw,int,embstr都是String的内部编码。
- raw是最基本的字符串,一般保存较大字符串。
- 当value是一个整数的时候,redis可能就会直接用int保存value。一个int是64bit。
- embstr一般保存较短的字符串。
-
hashtable和ziplist都是哈希表的内部编码。
- hashtable实现了一个最基本的哈希表;
- ziplist是压缩列表,当哈希表中元素比较少的时候,redis就会把哈希表的内部实现转换成ziplist。ziplist可以节省空间,对于redis来说,如果key特别多,hash类型的value也特别多,但是每个hash类型的value又不大的情况下,通过压缩这些hash类型的value,就可以让整体键值对占用的内存更小。
-
redis3.2之前,linkedlist和ziplist都是列表的内部编码。
- 从redis3.2开始,引入quicklist取代了linkedlist和ziplist,quicklist同时兼顾了linkedlist和ziplist的优点,quicklist本身就是链表,每个元素又是一个ziplist。通过quicklist能节省空间和提高管理数据的效率。
-
hashtable和inset都是集合的内部编码。
- 如果集合中存的都是整数,集合就会被优化成inset。
-
skiplist和ziplist都是有序集合的内部编码
- skiplist也属于链表,但和普通链表相比,skiplist的每个结点上有多个指针域,通过巧妙搭配这些指针域的指向,可以做到在skiplist上查询元素的时间复杂度为O(logN)。
redis底层这样设计的好处:
-
可以改进内部编码,且对外的数据结构和命令没有任何影响,这样⼀旦开发出更优秀的内部编码,无需改动外部数据结构和命令,例如Redis3.2提供了quicklist,结合了ziplist和linkedlist两者的优势,为列表类型提供了⼀种更为优秀的内部编码实现,且对用户来说基本无感知。
-
多种内部编码实现可以在不同场景下发挥各自的优势。例如ziplist⽐较节省内存,但是在列表元素比较多的情况下,性能会下降,这时候Redis会根据配置选项将列表类型的内部实现转换为linkedlist,整个过程用户同样无感知。
object encoding key1:查询key1对应值的内部编码
redis中的单线程模型
redis单线程模型不是说一个redis服务器进程内部只有一个线程。
redis单线程模型指的是redis只使用一个线程处理所有的命令请求!!!
假设多个客户端同时操作一个redis服务器,此时服务器端并不会存在类似于线程不安全的问题。redis服务器实际上是单线程模型,当多个请求同时到达redis服务器,需要在队列中排队,等待redia服务器一个一个的取出里面的命令再执行,微观上说,redis服务器是串行执行/顺序执行多个命令的。
redis能使用单线程模型很好工作,原因主要在于redis的核心业务逻辑都是短平快的,不太消耗cpu资源,假设使用多线程模型处理业务,也提升不大。所以它的弊端也很明显,如果某个操作占用redis时间太长,就会阻塞redis执行其他命令。
和关系型数据库(mysql,oracle,sqlServer)相比,redis效率高速度快的原因:
- redis访问内存,关系型数据库访问硬盘。
- redis的核心功能,比关系型数据库的核心功能更简单。关系型数据库对于数据库的增删改查都有更复杂的功能支持,这样的功能势必要花费更多的开销。
- redis采用单线程模型,避免了一些不必要的线程竞争开销。
- redis处理网络IO的时候,使用了epoll这样的IO多路复用机制。C++可以直接使用Linux原生的epoll API,java可以使用NIO(NIO是java标准库提供的一组类,该类底层封装了epoll)。