redis学习

1.redis的基本数据结构

一、Redis支持的数据类型

(1)String:

​ 数据结构:简单动态字符串

(2)List:

数据结构:双向链表,压缩链表

(3)Hash:

数据结构:哈希表 压缩列表

(4)Set:

数据结构:哈希表 整数数组

(5)Sorted Set:

数据结构:跳表 压缩列表

二、Redis数据类型的数据结构

(1.)为什么集合类型都包含有整数数组,和压缩列表

1.能够提升内存利用率:整数数组和压缩列表都是非常紧凑的数据结构,比链表要占用更少的内存,Redis是内存数据库所以尽可能调高内存利用率。

2.数组对CPU的高速缓存支持更友好,所以Redis在设计时,在集合元素较少的情况下默认采用内存紧凑的方式进行存储,高速缓存不会降低访问速度,当元素超过阈值后避免复杂度太高转为哈希和跳表结构存储,保存效率值。

三、Redis是怎么样存储数据的

1.全局Hash:

Redis才用全局Hash的方式存储数据,Hash中的每一个数据都是一个HASH桶,Hash桶中保存了键值对和数据。哈希桶中的元素保存的并不是值本身而是指向具体值的指针,不管是String,还是集合类型哈希桶中的元素都是指向他们的指针。时间复杂度为O(1)

2.哈希冲突和Reshash

1.如果插入大量数据,会造成Hash桶的数量少于数据的量,会造成hash值相同,即多个数据在一个哈希桶中,这种情况Redis采用链式哈希来解决,在一个哈希桶中,采用链表的结构,一个数据保存一个指针,指向下一条数据。但是当链式的长度过长时,会影响Redis的效率,这对于要求快速的Redis是不能接受的。解决方法就是ReHash

2.Redis的ReHash 是全局维护两个Hash表,表一,表二,表二先不分配内存空间,当表一达到一定的阈值后为表二创建内存空间大小为表一的两倍,然后把表一的数据复制到表二中,释放哈希表1的空间。但是Redis是单线程,直接复制可能会造成线程阻塞,所以在Redis采用了渐进式哈希,执行一次操作时,把表一中第一条数据复制到表二中,这样就不会影响到Redis的运行效率。

四、数据结构的时间复杂度

1.哈希表 O(1)

2.跳表 O(logn) 建立一级索引和二级索引,来降低命中的访问次数

3.压缩列表 O(n) 在表头有三个字段,zlbytes,zltail,zlen分别表示列表长度,列表尾的偏移量和列表中的entry的个数,在列表为还有一个zlend表示列表结束。

4.双向链表 O(n)

5.整数数组 O(n)

五、不同操作的复杂度

1.口诀:

单元素操作是基础,范围操作非常耗时,统计操作通常高效,例外情况只有几个

list类型的底层数据结构是双向链表和压缩链表,所以操作的复杂度都比较高,但是LPOP,LPUSH,RPOP,RPUSH,的时间复杂度为O(1)因为维护了头信息和尾信息,适合FIFO队列场景,而不是一个可以随机读写的集合。

可以采用SCAN命令来 范围查询,避免全集合遍历的操作。

2.redis 为什么能够那么快

一.为什么redis单线程还会快

  1. 首先,我们需要厘清一个事实,我们通常说,Redis 是单线程,主要是指 Redis 的网络 IO 和键值对读写是由一个线程来完成的,这也是 Redis 对外提供键值存储服务的主要流程。但 Redis 的其他功能,比如持久化、异步删除、集群数据同步等,其实是由额外的线程执行的。 所以,严格来说,Redis 并不是单线程,但是我们一般把 Redis 称为单线程高性能,这样显得“酷”些。
  2. “ 为什么用单线程?为什么单线程能这么快?”要弄明白这个问题,我们就要深入地学习下 Redis 的单线程设计机制以及多路复用机制。

二.redis为什么使用单线程

1.多线程的开销

1.我们经常会听到一种说法:“使用多线程,可以增加系统吞吐率,或是可以增加系统扩展性。”的确,对于一个多线程的系统来说,在有合理的资源分配的情况下,可以增加系统中处理请求操作的资源实体,进而提升系统能够同时处理的请求数,即吞吐率。但是,请注意,通常情况下,在我们采用多线程后,如果没有良好的系统设计,实际得到的结果,其实是不符合我们的期待的。我们刚开始增加线程数时,系统吞吐率会增加,但是,再进一步增加线程时,系统吞吐率就增长迟缓了,有时甚至还会出现下降的情况。
2. 为什么会出现这种情况呢?一个关键的瓶颈在于,系统中通常会存在被多线程同时访问的共享资源,比如一个共享的数据结构。当有多个线程要修改这个共享资源时,为了保证共享资源的正确性,就需要有额外的机制进行保证,而这个额外的机制,就会带来额外的开销。拿 Redis 来说,,Redis 有 List 的数据类型,并提供出队(LPOP)和入队(LPUSH)操作。假设 Redis 采用多线程设计,如下图所示,现在有两个线程 A 和 B,线程 A 对一个 List 做 LPUSH 操作,并对队列长度加 1。同时,线程 B 对该 List 执行 LPOP 操作,并对队列长度减 1。为了保证队列长度的正确性,Redis 需要让线程 A 和 B 的 LPUSH 和 LPOP 串行执行,这样一来,Redis 可以无误地记录它们对 List 长度的修改。否则,我们可能就会得到错误的长度结果。这就是多线程编程模式面临的共享资源的并发访问控制问题。

在这里插入图片描述
1.并发访问控制一直是多线程开发中的一个难点问题,如果没有精细的设计,比如说,只是简单地采用一个粗粒度互斥锁,就会出现不理想的结果:即使增加了线程,大部分线程也在等待获取访问共享资源的互斥锁,并行变串行,系统吞吐率并没有随着线程的增加而增加。而且,采用多线程开发一般会引入同步原语来保护共享资源的并发访问,这也会降低系统代码的易调试性和可维护性。为了避免这些问题,Redis 直接采用了单线程模式

2.单线程的快

1.通常来说,单线程的处理能力要比多线程差很多,但是 Redis 却能使用单线程模型达到每秒数十万级别的处理能力,这是为什么呢?其实,这是 Redis 多方面设计选择的一个综合结果。一方面,Redis 的大部分操作在内存上完成,再加上它采用了高效的数据结构,例如哈希表和跳表,这是它实现高性能的一个重要原因。另一方面,就是 Redis 采用了多路复用机制,使其在网络 IO 操作中能并发处理大量的客户端请求,实现高吞吐率。

3.基于多路复用的高性能 I/O 模型

1.Linux 中的 IO 多路复用机制是指一个线程处理多个 IO 流,就是我们经常听到的 select/epoll 机制。简单来说,在 Redis 只运行单线程的情况下,该机制允许内核中,同时存在多个监听套接字和已连接套接字。内核会一直监听这些套接字上的连接请求或数据请求。一旦有请求到达,就会交给 Redis 线程处理,这就实现了一个 Redis 线程处理多个 IO 流的效果。下图就是基于多路复用的 Redis IO 模型。图中的多个 FD 就是刚才所说的多个套接字。Redis 网络框架调用 epoll 机制,让内核监听这些套接字。此时,Redis 线程不会阻塞在某一个特定的监听或已连接套接字上,也就是说,不会阻塞在某一个特定的客户端请求处理上。正因为此,Redis 可以同时和多个客户端连接并处理请求,从而提升并发性。
在这里插入图片描述

2.基于多路复用的Redis高性能IO模型为了在请求到达时能通知到 Redis 线程,select/epoll 提供了基于事件的回调机制,即针对不同事件的发生,调用相应的处理函数。那么,回调机制是怎么工作的呢?其实,select/epoll 一旦监测到 FD 上有请求到达时,就会触发相应的事件。这些事件会被放进一个事件队列,Redis 单线程对该事件队列不断进行处理。这样一来,Redis 无需一直轮询是否有请求实际发生,这就可以避免造成 CPU 资源浪费。同时,Redis 在对事件队列中的事件进行处理时,会调用相应的处理函数,这就实现了基于事件的回调。因为 Redis 一直在对事件队列进行处理,所以能及时响应客户端请求,提升 Redis 的响应性能。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值