目录
Redis
1.1 Redis是什么?
redis是C语言开发的一个开源的(遵从BSD协议)高性能非关系型(NoSQL)的(key-value)键值对数据库。可以用作数据库,缓存,消息中间件等。
redis过期时间介绍:
有时候我们并不希望redis的key一直存在。例如缓存,验证码等数据,我们希望它们能在一定时间内自动的被销毁。redis提供了一些命令,能够让我们对key设置过期时间,并且让key过期之后被自动删除。
1.2 Redis的存储结构有哪些?
String 字符串,是redis的最基本的类型,一个key对应一个value。是二进制安全的,最大存储512MB
适用场景:存储Json类型对象, 计数器,用户点赞,粉丝数等
Hash 散列,是一个键值对集合,string类型的field和value的映射表,特别适合用于存储对象,每个 hash可以存储232-1键值对
适用场景:key_value对的一种集合,非常适合纯粹对象的信息,比如用户名,用户性别,用户年龄等
List 列表, 是最简单的字符串列表,按照插入顺序,可以添加一个元素到列边或者尾部(右边)。最多可以存储232-1元素。
适用场景:可以使用redis的list模拟队列,堆栈, 朋友圈点赞
Set 集合 是string类型的无序集合,最大的成员数为232-1
适用场景:当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择, 并且set提供了判断某个成员是否在一个set集合内的重要接口
Sorted set 有序集合,和set一样也是string类型元素,且不允许重复的成员,不同的是每个元素都会关联一个double 类型的分数,redis 正是通过分数来为集合中的成员进行从小到大的排序。zset的成员是唯一的,但分数却可以重复。
适用场景:已排序的字符串集合 文章阅读量排名,一般用作排名场景
1.3 Redis的优点:
- 因为是纯内存操作,Redis的性能非常出色,每秒可以处理超过10万次读写操作,是已知性能最快的Key-Value数据库,支持事务化,持久化
- 单线程操作,避免了频繁的上下文切换
- 采用了非阻尼塞I/O多路多路复用机制。I/O多路复用就是只有单个线程,通过跟踪每个i/Oliu的状态,来管理多个I/O流。
1.4 为什么要用redis
- 高性能
假如用户第一次访问数据库中的某些数据,这个过程会比较慢,因为是从硬盘上读取的。讲该用户访问的数据存在缓存中,这样下一次再访问这些数据的时候就可以直接从缓存中获取了,操作缓存就是操作内存,所以速度相当快。如果数据库中的数据更新以后,同步改变缓存中相应的数据即可。
- 高并发
直接操作缓存能够承受的请求是远远大于直接访问数据库的,所以我们可以考虑把数据库中的部分数据转移到缓存中去,这样一部分用户请求就会直接到缓存这里而不用经过数据库。
1.5 Redis 的持久化
redis提供了两种持久化方式,分别是RDB(redis database)和 AOF(append only file)。
- RDB 就是在不同的时间点,将redis存储的数据生成快照并存储到磁盘等介质上。
- AOF 则是换了一个角度来实现持久化,就是将redis执行过的所有指令记录下来,在下次redis重新启动的时候,只要把这些指令从前往后再重复执行一遍,就可以实现数据恢复了。
RDB 和 AOF 可以同时使用,再这种情况下,如果redis重启的话,则会优先采用AOF方式,进行数据恢复,因为AOF的数据恢复完整度高。
1.6 Redis 的缺点:
- 缓存和数据库双写一致性问题
请求先是从redis中查询,如果redis中存在数据就不会走数据库,如果不能保证缓存跟数据库的一致性就会导致请求获取的数据不是最新数据
解决方案:
- 编写删除缓存的接口,在更新数据库的同时,调用删除缓存的接口,删除缓存中的数据。 注意:这样做会有耦合高以及调用接口失败的情况。
-
使用延迟双删策略,在写库前后都进行redis的删除操作,并且第二次删除通过延迟的方式进行。实现逻辑: 第一步:先删除缓存,第二步:写入数据库,第三步:休眠xxx毫秒,第四步:再次删除缓存
(为什么进行双删: 因为第一次删除的是还没更新前的数据第二次删除是因为读取的并发性导致的缓存,重新写入数据出现的垃圾数据)
- 缓存的并发竞争问题
并发竞争指有多个子系统去set同一个key值
解决方案:
-
准备一个分布式锁,让请求都去抢锁,抢到锁就去做set操作
- 缓存雪崩问题
即缓存在同一时间大面积失效,这个时候又来了一大波请求,请求都到数据库上,导致数据库连接异常。
解决方案:
- 给缓存失效的时间加上一个随机值,避免集体失效。
- 使用互斥锁,但是这样会导致吞吐量明显下降。
- 搭建redis集群
(互斥锁: 对共享数据进行锁定,保证同一时刻只能有一个线程去操作)
- 缓存击穿问题
即黑客故意去请求缓存中不存在的数据,导致所有的请求都到数据库上,导致数据库连接异常
解决方案:
- 使用互斥锁,缓存失效的时候,先去获得锁,得到锁以后再请求数据库,没得到锁就休眠一段时间重试
- 采用异步更新策略,无论key是否取到值,都直接返回,value值中维护一个缓存失效时间,缓存如果过期,异步起一个线程去读数据库,更新缓存。
1.7 Redis 集群
- 主从复制(读写分离)
优点:
- 一个Master可以同步多个Slaves
- Slave同样可以接受其它Slaves的连接和同步请求,这样可以有效的分载Master的同步压力。因此我们可以将Redis的Replication架构视为图结构
- Master Server是以非阻塞的方式为Slaves提供服务。所以在Master-Slave同步期间,客户端仍然可以提交查询或修改请求
- Slave Server同样是以非阻塞的方式完成数据同步。在同步期间,如果有客户端提交查询请求,Redis则返回同步之前的数据
- 为了分载Master的读操作压力,Slave服务器可以为客户端提供只读操作的服务,写服务仍然必须由Master来完成。即便如此,系统的伸缩性还是得到了很大的提高
- Master可以将数据保存操作交给Slaves完成,从而避免了在Master中要有独立的进程来完成此操作
- 支持主从复制,主机会自动将数据同步到从机,可以进行读写分离
缺点:
- Redis不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复
- 主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性
- Redis的主从复制采用全量复制,复制过程中主机会fork出一个子进程对内存做一份快照,并将子进程的内存快照保存为文件发送给从机,这一过程需要确保主机有足够多的空余内存。若快照文件较大,对集群的服务能力会产生较大的影响,而且复制过程是在从机新加入集群或者从机和主机网络断开重连时都会进行,也就是网络波动都会造成主机和从机间的一次全量的数据复制,这对实际的系统运营造成了不小的麻烦
- Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。为避免这一问题,运维人员在系统上线时必须确保有足够的空间,这对资源造成了很大的浪费
- 哨兵模式
哨兵的作用就是监视Redis系统的运营状况,它的功能主要有:
- 哨兵(sentinel) 是一个分布式系统,用于对主从结构中的每台服务器进行监控,当出现故障时通过投票机制选择新的 master并将所有slave连接到新的master。
优点:哨兵模式是基于主从模式的,所有主从的优点,哨兵模式都有。主从可以自动切换,系统更健壮,可用性更高。
缺点:Redis较难支持在线扩容,在集群容量达到上限时在线扩容就会变得很复杂。