Redis

Redis

Posted by JYH on March 29, 2020

Redis

一.为什么用redis

使用redis主要考虑两个问题,性能和并发。

1.性能

在并发高的情况下,所有请求直接访问数据库,数据库会出现连接异常。用Redis做一个缓冲操作,让请求先访问Redis而不是数据库。

2.并发

二.redis优缺点

1.优点

①.性能优异

②.支持多种数据类型,操作方便。

③.支持数据持久化,支持AOF(append-only-file)和RDB快照(snapshotting)两种方式。

RDB:把当前内存中的数据集快照写入磁盘,恢复时将快照文件读到内存中。RDB分为自动触发和手动触发。

④.支持主从复制

2.缺点

①.不具备自动容错和恢复功能

②.存储的数据量和机器本身内存大小有关,需要提前预估和节约内存

③.单线程,单台服务器无法充分利用cpu

三.单线程redis为什么快

1.完全基于内存

redis的绝大部分请求都是基于内存的操作。

2.数据结构简单

redis的数据结构简单,对数据的操作也简单。

3.单线程

redis采用单线程,避免不必要的上下文切换和竞争条件,也不存在多进程或多线程导致的切换而消耗cpu,不需要去考虑各种锁的问题, 没有加锁、释放锁的操作,没有因为死锁而导致的性能消耗。

4.多路I/O复用模型,非阻塞IO

单个线程通过跟踪每个I/O流的状态,来管理多个I/O流。redis-client在操作的时候,会产生不同事件类型的socket。服务端有一段I/O多路复用程序,将socket放入队列中。 文件事件分派器,去队列中取然后转发到不同的事件处理器中。

5.底层模型不同

redis底层实现方式以及与客户端之间通信的应用协议不一样,redis自己构建了vm机制,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。

四.redis数据类型和使用场景

1.string

value可以是string也可以是数字

2.hash

是key-value的键值对集合,适合用于存储对象。

3.list

简单的字符串列表,按照插入顺序排序,可以添加元素到头或者尾

4.set

string类型的无序集合,通过哈希表实现,添加、删除、查找的时间复杂度都是O(1)

5.sorted set

比set多了一个权重参数score,集合中的元素能够按照score进行排列。

五.redis过期策略和内存淘汰机制

redis采用的是定期删除+惰性删除策略。

定期删除:redis默认每100ms将随机抽取key检查是否过期。如果存在过期的key则删除,因此只采用定期删除的策略会 导致一些key到了过期时间而没有被删除。

惰性删除:在获取key的时候,redis会检查是否过期,如果设置了过期时间并且过期了,就会删除。

定期删除+惰性删除存在的问题

如果定期删除没有删除key,也没有即使请求去获取key,惰性删除也没有生效,redis的内存会越来越高。那么就应该采用内存淘汰机制。

redis中有一行配置:

/# maxmemory-policy volatile-lru

这个就是配置内存淘汰策略的,当内存不足以容纳写入新数据时:

1.noeviction:新写入操作会报错。(不推荐)

2.allkeys-lru:移除最近最少使用的key。(推荐)

3.allkeys-random:随机移除key。(不推荐)

4.volatile-lru:在设置了过期时间的key空间中,移除最近最少使用的key。(这种一般是既当缓存,又做持久化存储的时候才使用)

5.volatile-random:在设置了过期时间的key空间中,随机移除key。(不推荐)

6.volatile-ttl:在设置了过期时间的key空间中,有更早过期时间的key优先移除。(不推荐)

没有设置过期时间的key,由于不满足先决条件,volatile-lru、volatile-random、volatile-ttl的策略行为和noeviction基本上一致。

六.redis和数据库双写一致性问题

一致性是分布式的常见问题,又可以分为强一致性和最终一致性。数据库和缓存双写,必然会存在不一致的问题。如果对数据有强一致性的要求, 就不能放入缓存中。

七.如何应对缓存击穿和缓存雪崩

缓存穿透

黑客故意去请求缓存中不存在的数据,导致所有请求都到数据上,使得数据库连接异常。

解决方案:

1.利用互斥锁,缓存失效的时候,先去获得锁,得到锁了,再去请求数据库。没得到锁则休眠一段时间再重试。

2.采用异步更新策略,无论key是否取到值,都直接返回。value中维护一个缓存失效时间,缓存如果过期,异步起一个线程去读数据库,更新缓存。 需要做缓存预热的操作。

3.提供一个能迅速判断请求是否有效的拦截机制,比如利用布隆过滤器, 内部维护一系列合法有效的key。迅速判断出请求的key是否合法有效。

缓存雪崩

缓存同一时间大面积失效,这时候又来了一波请求,结果请求都到了数据上,使得数据库异常。

解决方案:

1.给缓存的失效时间加上一个随机值,避免集中失效。

2.双缓存:缓存A和缓存B,A设置失效时间20min,B不设失效时间。

(1)从缓存A读数据,有则直接返回

(2)A没有数据,直接从B读数据,直接返回,异步启动一个更新线程。

(3)更新线程同时更新缓存A和缓存B

参考文章

https://blog.csdn.net/bjweimengshu/article/details/100911399 https://www.cnblogs.com/haha12/p/10470786.html