1、为什么要使用Redis呢,对Redis的一些个人理解
官方解释:Redis是一个可基于内存亦可持久化的日志型、Key-Value数据库。
论持久化,我们平时使用的MySQL就足够了,那为什么还需要引入Redis呢?无非就是 :性能 。
Redis的性能表现在哪方面呢——快 和 并发。
为什么快?
1)基于内存
2)单线程,避免上下文切换
3)非阻塞I/O多路复用机制
4)数据结构用的好。使用hash结构、压缩表、跳表等。
并发:
在高并发的情况下,比如说秒杀,当大量的请求都直接访问数据库,数据库会出现压力,如果使用Redis,就可以把MySQL的数据更新同步的到Redis,请求过来就可以先查Redis,没有再差数据库,减少压力。
2、I/O多路复用机制
多路 指的是多个网络连接,复用 指的是复用同一个线程。
例子 作者:柴小喵 链接:https://www.zhihu.com/question/28594409/answer/52835876
模拟一个tcp服务器处理30个客户socket。 假设你是一个老师,让30个学生解答一道题目,然后检查学生做的是否正确,你有下面几个选择:
- 第一种选择:按顺序逐个检查,先检查A,然后是B,之后是C、D。。。这中间如果有一个学生卡主,全班都会被耽误。 这种模式就好比,你用循环挨个处理socket,根本不具有并发能力。
- 第二种选择:你创建30个分身,每个分身检查一个学生的答案是否正确。 这种类似于为每一个用户创建一个进程或者线程处理连接。
- 第三种选择,你站在讲台上等,谁解答完谁举手。这时C、D举手,表示他们解答问题完毕,你下去依次检查C、D的答案,然后继续回到讲台上等。此时E、A又举手,然后去处理E和A。。。 这种就是IO复用模型,Linux下的select、poll和epoll就是干这个的。将用户socket对应的fd注册进epoll,然后epoll帮你监听哪些socket上有消息到达,这样就避免了大量的无用操作。此时的socket应该采用非阻塞模式。 这样,整个过程只在调用select、poll、epoll这些调用的时候才会阻塞,收发客户消息是不会阻塞的,整个进程或者线程就被充分利用起来,这就是事件驱动,所谓的reactor模式。
注意区分:select、poll跟epoll是不一样的。select/poll只会告诉你有人举手,不会告诉你是哪个同学举的手。
2.1、什么是 IO 多路复用
IO多路复用(Input/Output Multiplexing)是一种在单个线程中管理多个输入/输出通道的技术。
它允许一个线程同时监听多个输入流(例如网络套接字、文件描述符等),并在有数据可读或可写时进行相应的处理,而不需要为每个通道创建一个独立的线程。
常见的IO多路复用机制包括select、poll和epoll。这些机制通过将多个IO通道注册到一个事件管理器中,然后通过阻塞方式等待事件的发生。
一旦有事件发生(如有数据可读或可写),线程就会被唤醒,然后可以针对具体的事件进行处理。
IO多路复用的优点是可以有效地管理大量的IO通道,减少线程的创建和销毁开销,提高系统的并发性能。它在网络编程中特别有用,可以用于实现高性能的服务器和客户端应用程序。
3、Redis的数据类型和用法
String 字符串 可以为整形、浮点型和字符串,统称为元素:点赞、计数、粉丝数
Hash 一个 string 类型的 field(字段) 和 value(值) 的映射表:特别适合用于存储对象、用户信息
List 有序串列表:粉丝列表、消息队列。
Set 无序集合,集合成员是唯一的,这就意味着集合中不能出现重复的数据:共同关注、喜好、好友,标签。
ZSet 有序集合,集合成员是唯一的:排行榜。
4、过期策略
4.1、定时删除
在设置key的过期时间的同时,为该key创建一个定时器,让定时器在key的过期时间来临时,对key进行删除
优点: 保证内存被尽快释放
缺点:
1)若过期key很多,删除这些key会占用很多的CPU时间,在CPU时间紧张的情况下,CPU不能把所有的时间用来做要紧的事儿,还需要去花时间删除这些key。
2)定时器的创建耗时,若为每一个设置过期时间的key创建一个定时器(将会有大量的定时器产生),性能影响严重
4.2、惰性删除
key过期的时候不删除,每次从数据库获取key的时候去检查是否过期,若过期,则删除,返回null。
优点: 删除操作只发生在从数据库取出key的时候发生,而且只删除当前key,
所以对CPU时间的占用是比较少的,而且此时的删除是已经到了非做不可的地步.
缺点:
若大量的key在超出超时时间后,很久一段时间内,都没有被获取过,那么可能发生内存泄露(无用的垃圾占用了大量的内存)
4.3、定期删除
每隔一段时间随机从数据库中取出一定数量的key进行检查,并删除其中的过期key。
优点:
1)通过限制删除操作的时长和频率,来减少删除操作对CPU时间的占用–处理”定时删除”的缺点
2)定期删除过期key–处理”惰性删除”的缺点
缺点:
1)在内存友好方面,不如”定时删除”
2)在CPU时间友好方面,不如”惰性删除”
Redis采用的策略:定期删除+惰性删除
| 删除策略 | 描述 | 优点 | 缺点 |
|---|---|---|---|
| 定时删除 | 在设置key过期时间时,同时创建一个定时事件。当时间到达时,由事件处理器自动执行key的删除操作。 | 对内存友好。可以保证过期key会被尽快删除,去释放内存。 | 对CPU不友好。在过期key较多的情况下,会占用相当一部分CPU时间,这会对服务器的响应时间和吞吐量造成影响。 |
| 惰性删除 | 不主动删除过期键,每次从数据库访问key时,都检测key是否过期,过期则删除该key。 | 对CPU友好。只有每次访问时,才检查key,所以只会使用很少的系统资源。 | 对内存不友好。如果一个key已经过期,但是我们一直没有去访问,它占用的内存空间就一直得不到释放。 |
| 定期删除 | 每隔一段时间随机从数据库中取出一定数量的key进行检查,并删除其中的过期key。 | 限制删除操作的执行时长和频率,减少对CPU的影响,也能删除过期数据减少对内存的无效占用。 | 1.内存清理方面没有定时删除好也没有惰性删除使用的系统资源少。2.难以确定删除操作执行的时长和频率。 |
5、内存淘汰机制
Redis有过期策略,假如你的Redis只能存1G的数据,你一个请求写入2G,而你也没有及时请求key,那么惰性删除就不生效了,Redis占用内存就会越来越高。
Redis可以设置内存大小:
1 | # maxmemory <bytes> |
超过了这个内存大小,就会触发内存淘汰机制
Redis有一个默认配置,这个是Redis的默认内存淘汰机制(直接报错):
1 | # maxmemory-policy noeviction |
maxmemory-policy一共有8个值,当内存不足时:
1)noeviction: 不删除,直接返回报错信息。
2)allkeys-lru:移除最久未使用(使用频率最少)使用的key。推荐使用这种。
3)volatile-lru:在设置了过期时间的key中,移除最久未使用的key。
4)allkeys-random:随机移除某个key。
5)volatile-random:在设置了过期时间的key中,随机移除某个key。
6)volatile-ttl: 在设置了过期时间的key中,移除准备过期的key。
7)allkeys-lfu:移除最近最少使用的key。
8)volatile-lfu:在设置了过期时间的key中,移除最近最少使用的key。
报错、随机、最久、最近最少、即将过期
LRU和LFU的区别:
LRU是最久未使用页面置换算法(Least Recently Used),也就是首先淘汰最长时间未被使用的页面!
LFU是最近最不常用页面置换算法(Least Frequently Used),也就是淘汰一定时期内被访问次数最少的页!
引申:
假如我的key没有设置expire,即没有设置过期时间。
那么 volatile-lru、volatile-random、volatile-ttl 就无法执行了,和 noeviction 就一样了。
6、持久化机制
持久化到硬盘、当Redis重启的时候就把硬盘的数据加载到内存。
Redis支持两种持久化机制,一种是RDB,另一种是AOF,可以单独使用其中一种或将二者结合使用。
6.1、RDB持久化
RDB持久化是将当前进程中的数据生成快照保存到硬盘(因此也称作快照持久化),
保存的文件后缀是.rdb;当Redis重新启动时,可以读取快照文件恢复数据。
RDB做持久化操作的时候,主线程需要调用系统的 fork() 函数,构建出一个子进程去操作;但是在子线程执行期间,父进程是阻塞的,无法响应其他请求。
所以这种RDB方式很影响Redis的性能。
6.2、AOF持久化
AOF是将Redis执行的每次写命令记录到单独的日志文件中。
(缓冲器) 随着日志文件的越来越大,Redis也是需要fork()函数去缩小日志文件大小的。 AOF还有另外一个方法,就是刷盘策略fsync,Redis默认每隔一秒进行一次fsync调用,将缓冲器的数据写入到磁盘。 如果磁盘不稳定,fsync也是会耗时的,也会影响性能。
AOF有三种刷盘模式:
always:把每个写命令都立即同步到aof,很慢,但是很安全
everysec:每秒同步一次,是折中方案
no:redis不处理,交给OS来处理,非常快,但是也最不安全
一般采用everysec策略。
6.3、Redis重启如何恢复数据呢?
Redis启动前会先检查AOF文件,不存在才会去加载RDB文件,因为AOF的数据完整性高,最多也就损失1秒的数据。
6.4、两者区别:
1、都是调用了**fork()**函数,期间主线程会阻塞,然后子线程执行不阻塞。
2、AOF恢复比较慢;RDB文件小,恢复快。
3、RDB是数据快照文件,AOF是命令操作的日志文件,追加写。