一、redis是什么
Redis(Remote Dictionary Server) 是一个使用 C 语言编写的,开源的(BSD许可)高性能非关系型(NoSQL)的键值对数据库。有五大数据类型,包括String,List,Set,Sortedset,Hash。redis是NoSQL数据库。
NoSQL的特点
- 不遵循SQL标准
- 不支持ACID(原子性,一致性,持久性,隔离性)
- 远超于SQL的性能。
为什么要用 Redis /为什么要用缓存
主要从“高性能”和“高并发”这两点来看待这个问题。
高性能:
用户第一次访问数据库中的某些数据。这个过程会比较慢,因为是从硬盘上读取的。将该用户访问的数据存在缓存中,这样下一次再访问这些数据的时候就可以直接从缓存中获取了。如果数据库中的对应数据改变的之后,同步改变缓存中相应的数据即可!
高并发:
直接操作缓存能够承受的请求是远远大于直接访问数据库的,所以我们可以考虑把数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接到缓存这里而不用经过数据库。
二、持久化机制
1.RDB
是什么?
将指定的时间间隔内将内存中的数据集快照写入磁盘,这个过程就是RDB
他恢复时是将快照文件直接读到内存中
备份是如何执行的?
有三种触发方式
save bgsave 自动化
bgsave
单独建一个子进程(fork)进行持久化,这个进程他是怎么工作的
先将数据写入到一个临时文件中,待持久化过程结束了,再将这个临时文件替换上次持久化的文件。有个缺点就是最后一次持久化的数据可能会丢失。
这个工程用到一个技术“写时复制技术”。具体来说,数据要进行持久化,要生成一个文件,文件默认名为dump.rdb,fork进程创建临时文件同步redis数据,再把临时区域的内容覆盖到dump.rdb文件中
save
立即停止RedisServer对外的服务,开始将内存中的数据保存到硬盘指定的位置
默认保存在:命令执行所在的文件目录
自动化
Redis根据配置文件每过一定时间间隔保存一个rdb文件
为什么要同步到临时文件
假如说我们是直接同步到dump.rdb文件中,我们要上传一个10T的文件,当上传到8T的文件时,但是这个时候服务器突然挂掉,上传了一部分,使得这个数据不完整了
所以我们先把数据同步到临时文件,等同步完成后,再替换rdb文件,保证了数据的一致性和完整性,也是为了数据的安全考虑。
适用于
适合大规模的数据恢复
对数据完整性和一致性要求不高更适合使用
2.AOF (默认不开启)
当两种方式同时开启时,数据恢复Redis会优先选择AOF恢复。
是什么
以日志的形式来记录每个写操作(增量保存),将redis执行过的所有写指令都下来(读操作不记录),只许追加文件但不可以改写文件。redis启动时读取文件重构数据
AOF的时机
开机如何进行工作(AOF配合RBD共同完成)
怎样一个流程呢
在redis实例重启时,会使⽤RDB持久化⽂件重新构建内存,再使⽤AOF重放近期的操作指令来实现完整恢复重启之前的状态。
这⾥很好理解,把RDB理解为⼀整个表全量的数据,AOF理解为每次操作的⽇志就好了,服务器重启的时候先把表的数据全部搞进去,但是他可能不完整,你再回放⼀下⽇志,数据不就完整了嘛。不过Redis本身的机制是 AOF持久化开启且存在AOF⽂件时,优先加载AOF⽂件;AOF关闭或者AOF⽂件不存在时,加载RDB⽂件;加载AOF/RDB⽂件后,Redis启动成功; AOF/RDB⽂件存在错误时,Redis启动失败并打印错误信息
同步
全量同步
1.从服务器连接主服务器
2.1主服务器接收到请求开始BGSave保存数据。保存成一个RDB文件
2.2主服务器可以继续接受客户端的请求,但是会将写命令单独存放起来
3.主服务器将RDB发送给从服务器,从服务器开始史新数据
4.主服务器特备份期间接受的写命令在发送给从服务器
5.从服务器继续更新数据,更新完成后可以接受客户端的请求
增量同步
从服务器正常运行之后
当主服务接受请求之后,主服务器会把写命令发送给从服务器
从服务器执行写命令
三、主从复用与主备切换
主从服用
读写分离
主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,master以写为主,slaver以读为主
应用会访问到主服务器,在master中进行一个写操作,写完数据后,把数据复制到从服务器上
主服务器做写操作,从服务器做读操作,分担服务器的压力
容灾快速恢复(故障转移)
- 从服务器挂掉,再读读不到,可以根据一定的策略让他去别的从服务器去读这个数据(不能只有一台从服务器,所以都是一主多从)
- 主服务挂掉,主服务器只能配置一台,配置一个集群,配置多个主从
主备切换
- 哨兵机制,配置哨兵一直去ping这个主服务器,如果在一定时间内没有ping到,认为主服务器挂掉,一半以上的哨兵都认为主服务器挂掉,主服务器就挂掉,之后就会进行一个选举,一半以上的哨兵认为某人从服务器可以选举成为主服务器,那这个从服务器可以变为主服务器,而刚刚挂掉的主服务器重新恢复会变更为从服务器。
四、缓存异常(击穿、穿透、雪崩、数据一致性)
- 缓存击穿
高并发请求的情况下,某些热门的key突然过期,导致不能从redis中获取缓存数据,进而大量的请求直接访问数据库,给数据库造成极大的压力
解决方法:
- 设置热门key永不过期
- 定期检测将要过期的key,然后在将要过期的时重新从数据库中把数据刷新到缓存中,但这样的话增加了系统的复杂度,实现比较复杂
- 利用互斥锁,在缓存中没有数据去数据库中查询时加上锁,让一个线程去查询数据库以及更新缓存,其他线程等待,这样减小数据库压力
- 缓存穿透
缓存穿透是指查询缓存和DB中都不存在的数据。先查询缓存为空,再查询数据库依然为空,向请求返回空,如果大量请求同时访问这些不存在key那么这些请求依然会造成压垮数据库的现象,这种通常是恶意查询和被攻击几率较大
解决方案:
- 布隆过滤器;把一定不存在的key过滤掉,从而避免这些恶意攻击对数据库造成的压力
- 如果查询的结果为空,不管是数据不存在还是系统故障,仍然把这个空结果进行缓存,但给它设置一个很短的过期时间,最长不超过5分钟
- 缓存雪崩
缓存中如果大量缓存在一段时间内集中过期了,这时候会发生大量的缓存击穿现象,所有的请求都落在了DB上,由于查询数据量巨大,引起DB压力过大甚至导致DB宕机。
解决方案
- 给缓存的失效时间加一个随机值,不让他们在同一时刻过期;如果集群部署,让他们分布到不同的redis库也能避免全部失效的问题
- 使用互斥锁,但吞吐量明显下降
- 设置热点数据永不过期
- 设置双缓存,a缓存设置失效时间,b缓存不设失效时间;如果a缓存中有数据则直接返回,如果没有就从b缓存中去找,直接返回,并异步启动一个更新线程,同步更新a缓存和b缓存
- 数据的一致性
缓存的一致性问题:缓存和实际数据不一致
解决方案:
- 建立缓存的时候应该以不常发生的数据为主
- 当数据库的数据 发生变化的时候优先清除缓存中对应的数据
布隆过滤器
它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。
布隆过滤器的优点:
- 时间复杂度低,增加和查询元素的时间复杂为O(N),(N为哈希函数的个数,通常情况比较小)
- 保密性强,布隆过滤器不存储元素本身
- 存储空间小,如果允许存在一定的误判,布隆过滤器是非常节省空间的(相比其他数据结构如Set集合)
布隆过滤器的缺点:
- 有点一定的误判率,但是可以通过调整参数来降低
- 无法获取元素本身
- 很难删除元素
五、一致性Hash
Redis的Slot槽
一致性Hash的升级版,集群使用公式CRC16(key)%16384来计算键key于哪个槽