redis
一.什么是redis
高性能的key-value数据库 , 支持的数据结构类型包括:字符串(String)、链表(list)、哈希表(hash)、集合(set)、有序集合(Zset)等。为了保证读取的效率,redis把数据对象都存储在内存当中,它可以支持周期性的把更新的数据写入磁盘文件中。
二.redis集群
文章:https://www.jianshu.com/p/84dbb25cc8dc
视频: https://www.bilibili.com/video/av73287780?from=search&seid=17109570147136350701
三.redis逐出算法
MySQL里有1000w数据,redis中只存10w的数据,如何保证redis中的数据都是热点数据
1.voltile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
2.volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
3.volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
4.allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
5.allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
6.no-enviction(驱逐):禁止驱逐数据
四.redis删除策略
redis采用的方式:定期删除+惰性删除
定时删除
创建一个定时器,当key设置有过期时间,且过期时间到达时,由定时器任务立即执行对键的删除操作
优点:节约内存,到时就删除,快速释放掉不必要的内存占用
缺点:CPU压力很大,无论CPU此时负载量多高,均占用CPU,会影响redis服务器响应时间和指令吞吐量
总结:用处理器性能换取存储空间 (拿时间换空间)
惰性删除
数据到达过期时间,不做处理。等下次访问该数据时执行,如果未过期,返回数据,发现已过期,删除,返回不存在。
优点:节约CPU性能,发现必须删除的时候才删除
缺点:内存压力很大,出现长期占用内存的数据
总结:用存储空间换取处理器性能(拿空间换时间)
定期删除
redis 会将每个设置了过期时间的 key 放入到一个独立的字典中,以后会定期遍历这个字典来删除到期的 key。
Redis 默认会每秒进行十次过期扫描(100ms一次),过期扫描不会遍历过期字典中所有的 key,而是采用了一种简单的贪心策略。从过期字典中随机 20 个 key;删除这 20 个 key 中已经过期的 key;如果过期的 key 比率超过 1/4,那就重复步骤 1;
五.redis事务
https://blog.csdn.net/azurelaker/article/details/85045220 (深入理解Redis事务)
六.redis持久化
1.AOF:以追加的方式记录Redis的写操作,并在Redis重启时进行重放(与MySQL的binlog日志的原理是一样的)。当AOF日志过大时,redis支持日志重写。【在Redis中是先执行命令再记录日志到AOF,这也是Redis事务不支持回滚的原因:即使发生异常,没有可以用来执行回滚操作的日志。而传统的数据库例如MySQL都是先做日志然后再做操作,所以能够支持回滚】
AOF的原理:操作系统将写操作首先记录到内存缓冲区中,然后使用fsync函数将数据刷新到磁盘中。
AOF优点:如果不考虑性能,AOF可以最大限度保证数据完整性,可以设置每发生一次写操作就调用一次fsync函数;更加灵活,可以使用不同的fsync策略,完全不使用fsync,每秒使用fsync(默认),以及每次查询时使用fsync;
缺点:与下面的RDB方式相比,相同数据集大小AOF占用空间更大;若调用fsync的频率过快,性能会变差;
AOF文件损坏?AOF文件中可能有一条命令是不完整的,比如发生正在写入的时候断电的这种情况,redis支持重放这样的AOF文件,他会在启动日志中记录错误命令的行数,并在重放时对该行进行忽略。
2.RDB:也称快照方式,配置每隔一段时间执行一次全量备份,Redis将数据集快照保存在磁盘上,保存在一个名为dump.rdb的二进制文件中,也可以手动调用SAVE或BGSAVE命令。
RDB的原理:主进程调用fork函数生成一个子进程,子进程进行磁盘I/O操作,操作完成后替换旧的RDB文件
RDB优点:非常适合做备份与回滚到指定的时间点,例如我们可以每天晚上2点执行定时计划全量备份一次Redis中的数据,以后我们进行恢复的时候可以将Redis恢复到指定的时间点的版本;与AOF相比使用RDB方式性能较高;与AOF相比Redis重启的速度较快;当AOF文件变的过大时可以自动进行重写(2.4版本以上,2.4以下版本需要手动调用)
RDB的缺点:相比AOF丢失的数据可能会更多,比如设置5分钟备份一次快照,那么最多会损失5分钟的数据。
3.混合方式:RDB与AOF混合使用。将 RDB文件的内容和增量的 AOF 日志文件存在一起。这里的 AOF 日志不再是全量的日志,而是自持久化开始到持久化结束的这段时间发生的增量 AOF 日志。
七.redis常见问题
缓存穿透
一般是黑客故意去请求缓存中不存在的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量请求而崩掉。
解决方案
1.布隆过滤器:将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。将数据通过哈希函数以0,1的方式存在bit数组(位数组)里。影响布隆过滤器效率的是:数组size,哈希函数个数;(缺点:布隆过滤器里数据无法进行删除操作)
有很多种方法可以有效地解决缓存穿透问题,最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。另外
2.缓存空对象:一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。(缺点:空值的键值对会占用大量内存)
缓存雪崩
指在我们设置缓存时采用了相同的过期时间,缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。
解决方案
事前:尽量保证整个 redis 集群的高可用性,发现机器宕机尽快补上。选择合适的内存淘汰策略。或在原有的失效时间基础上增加一个随机值,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。
事中:本地ehcache缓存 + hystrix限流&降级,避免MySQL崩掉
事后:利用 redis 持久化机制保存的数据尽快恢复缓存
缓存击穿(热点key)
对于一些设置了过期时间的key,如果这些key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据。这个时候,需要考虑一个问题:缓存被“击穿”的问题,这个和缓存雪崩的区别在于这里针对某一key缓存,前者则是很多key。缓存在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。
解决方案
1.使用互斥锁(mutex key)
业界比较常用的做法,是使用mutex。简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操作返回成功时,再进行load db的操作并回设缓存;否则,就重试整个get缓存的方法。
SETNX,是「SET if Not eXists」的缩写,也就是只有不存在的时候才设置,可以利用它来实现锁的效果。
"提前"使用互斥锁(mutex key)
2.永不过期
(1) 从redis上看,确实没有设置过期时间,这就保证了,不会出现热点key过期问题,也就是“物理”不过期。
(2) 从功能上看,如果不过期,那不就成静态的了吗?所以我们把过期时间存在key对应的value里,如果发现要过期了,通过一个后台的异步线程进行缓存的构建,也就是“逻辑”过期
3.维护过期时间
在value内部设置1个超时值(timeout1), timeout1比实际的memcache timeout(timeout2)小。当从cache读取到timeout1发现它已经过期时候,马上延长timeout1并重新设置到cache。然后再从数据库加载数据并设置到cache中。
八.redis常见性能问题和解决方案
(1) Master最好不要做任何持久化工作,如RDB内存快照和AOF日志文件
(2) 如果数据比较重要,某个Slave开启AOF备份数据,策略设置为每秒同步一次
(3) 为了主从复制的速度和连接的稳定性,Master和Slave最好在同一个局域网内
(4) 尽量避免在压力很大的主库上增加从库
(5) 主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <- Slave3…
这样的结构方便解决单点故障问题,实现Slave对Master的替换。如果Master挂了,可以立刻启用Slave1做Master,其他不变。
九.redis相比memcached的优势
(1) memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型
(2) redis的速度比memcached快很多 , 速度快:使用标准C写,所有数据都在内存中完成,读写速度分别达到10万/20万 . Memcached是多线程,分为监听线程、worker线程,引入锁,带来了性能损耗。Redis使用单线程的IO复用模型(redis单线程,避免了线程切换、加锁等资源消耗,redis内存处理比较快。多路io复用,多个socket链接复用, 使用同一个线程处理使用epoll策略,实现哪些socket有通讯,处理那些socket、 高效),将速度优势发挥到最大,也提供了较简单的计算功能。
(3) redis可以持久化其数据