redis是个内存数据库,如果不将内存中的数据库状态保存到磁盘,那么一旦服务器进程退出,服务器中的数据库状态也会消失,所以redis提供了持久化功能!
Redis的持久化分两种,AOF和RDB
RDB
redis的默认持久化就是rdb。一般不需要修改这些配置。
rdb工作原理:指定时间间隔将内存中的数据集快照写入磁盘中,恢复时是直接将快照文件读到内存中。
Redis会单独创建一个子进程来进行持久化。会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次的持久化的文件。整个过程中主进程不进行任何io操作,这就确保了极高的性能。
如果需要进行大规模的数据的恢复,且队医数据恢复的完整性不是非常敏感,那么rdb方式比aof方式要更加的高效。但是rdb的缺点是最后一次持久化后的数据可能丢失(恰好没有替换的时候掉线了)。
rdb保存的文件默认是dump.rdb。
这里改下配置自己测试下这个快照功能:
上一篇文章提到了rdb的配置是sava xxx ttt(xxx是秒数。ttt是次数。即为在多少时间内动了多少次key就触发快照)
我这里改成了sava 60 5 (就是在60秒内触发5次会快照)如下代码:
其实这个时候我们关闭redis,并且再次启动,正常来讲应该是空的。因为redis被称作内存数据库,应该是关机即失的。但是我们重启redis会发现,之前的key1-key5都会存在。因为这些数据已经在rdb的文件中了。其实任何操作都是这样,如果你flushdb以后快速的关闭redis。那么下次启动你也会发现之前的key1-key5都还存在。因为这个删除操作还没同步到rdb文件中。
其实这块的操作老师只是简单的做了几个demo,如果你要是有什么想法或者不懂的可以自己慢慢尝试。比如正常来讲关闭redis然后重启,所有的key都会丢失。这个是最基本的一个,这也是内存数据库的一个很大的特点。
同样这个sava功能想要使用不能双击redis-server直接启动,要指定配置文件启动这个应该大家都知道。
而启动配置文件,设置了rdb的sava触发机制以后,我们虽然看不懂rdb文件存储了什么。但是关闭redis重启,keys * 就是rdb文件中存储的内容。
我刚刚试了一下,因为之前的key1-key5是写到了快照中了。剩下不管我重启几次,flushdb几次,每次重启完都有着五个默认的key。
另一个很有意思的事是:flushall这个命令会直接刷新rdb文件,大家可以注意一下这个rdb文件的修改时间:
flushall直接修改rdb文件
然后我关闭redis,重启后这五个key不见了。由此可以得出rdb文件更新的规则:
- 当sava语句的规则满足后,会触发rdb文件更新(这个是要等到了给定时间,再去判断打没达到给定的条件)
- 当执行了flushall命令后,会直接触发rdb文件更新
有些时候我们只是想要备份一下数据,而不是非要每次启动都执行rdb文件,那怎么办?
其实redis每次启动会在启动目录中检查dump.rdb文件(默认生成的dump.rdb文件就在redis的启动目录下)。如果我们不想rdb中的数据被恢复。只要把这个文件移除到别的位置就可以了。
正常来说,redis中rdb的默认配置就可以满足我们需求了。但是我们还要学会配置和原理,这样可以针对操作。rdb的优点和缺点:
优点:
- 适合大规模的数据恢复。
缺点
- 对数据的完整性要求不高。(比如我设置60秒判断一次,如果59秒关闭redis,那么最后一次的数据就没了)
- fork进程的时候,会占用一定的内存空间。
AOF(Append only file 追加文件)
本质上就是将所有命令都记录下来。恢复的时候就是把这个文件全部再执行一遍。
以日志的形式来记录每个写操作,将redis执行过的所有指令记录下来(读操作不记录),只许追加文件但不可以改写文件。redis启动之初会读取该文件重构数据。换言之就是根据日志内容将所有的除了读以外的指令从头到尾执行一遍以恢复数据。
aop默认是不开启的,需要再redis配置文件中手动开启:appendonly yes
生成的文件名字在配置文件也可以配置。一般保存默认就可以了。只要把是否开始从no改成yes就可以了。 (记得指定配置文件重启redis)
aof文件,大致是可以看出来是在记录的
另外有个比较有意思的测试,如果我们手动修改aof文件,那么这个redis是启动不了的:
修改aof文件后启动redis失败
如果aof文件有错,我们要修复aof文件,redis给我们提供了一个修复aof工具,而且也在启动失败报错的时候告诉我们修复的办法了:
image.png
修复aof文件办法
简单来说到了check-aof页面,然后--fix 文件名称。然后选择y就ok了。
修复成功后redis就可以起来了。但是你以为是修复是怎么修复的?找出问题解决问题?哈哈,怎么可能,这个修复的办法就是哪里报错删除哪里。解决不了问题,就解决出了问题的人,笑死我了。
而且aof文件是随着数据操作不断追加,越来越大的,可以在配置文件中配置,aof文件大于多少的时候,写在另一个文件里。(aof文件默认是无限追加,但是是不可能真的无限的。所以要大到一定程度就换一个文件。)
aof的优点和缺点:
优点:
- 每一次操作都同步,文件的完整性相比于rdb好的多。
- 每秒同步一次,可能会丢失一秒的数据。
缺点:
- 相对于数据文件来说,aof远远大于rdb,修复的速度也比rdb要慢
- aof的运行效率也比rdb慢。因为它是io操作。所以redis默认配置是rdb而不是aof。
关于aof和rdb的一些扩展:
aof的重写:
aof其实还有个重写功能。是redis对aof文件进行后台重写,使得aof文件的体积不会过大。
Redis服务器可以创建一个新的AOF文件来替代现有的AOF文件,新旧两个文件所保存的数据库状态是相同的,但是新的AOF文件不会包含任何浪费空间的冗余命令,通常体积会较旧AOF文件小很多。
这个重写其实就是对老aof文件进行的一个优化,比如老的aof中对list1这个key 不断增删修改几十次。 但是新的aof文件会记录现在list1这个key对应的值。然后直接一次记录。总结下aof的重写:
- AOF重写的目的是为了解决AOF文件体积膨胀的问题,使用更小的体积来保存数据库状态,整个重写过程基本上不影响Redis主进程处理命令请求;
- AOF重写其实是一个有歧义的名字,实际上重写工作是针对数据库的当前状态来进行的,重写过程中不会读写、也不适用原来的AOF文件;
- AOF可以由用户手动触发,也可以由服务器自动触发。
(ps:为了性能重写是发生在子进程。而且重写过程中发生读写等,所以还有个缓存区。)
一般我们会同时开启两种持久化方式。
在这种情况下会先读aof文件,因为aof的数据更完整。
但是要留着rdb备用,毕竟一来两者原理不同,aof可能有问题,但是rdb比较不容易出问题。做两手准备嘛。
性能建议
rdb一般我们只在从机上做后备用途。而且一般15分钟备份一次就行了(毕竟要考虑性能)。
aof最坏也不过丢失两秒的数据,所以比较保险。不过默认的64m重写太小了,建议改成5g以上(毕竟重写是很耗费性能的)。
其实aof很耗费性能。什么都不做仅仅依靠主从复制来实现高可用性也是可以的。代价就是如果主从同时down,那么就会丢掉十几分钟的数据。我们可以比价从机中rdb的时间,载入比较新的那个好一点。
Redis发布订阅
Redis发布订阅(pub/sub)是一种消息通信模式:发送者pub发送信息。订阅者sub接收信息。
消息发布订阅图
如图,发布订阅是有三个点:
- 消息发送者
- 消息订阅者
-
平台(redis中就是redis-server。如果是直播提醒的话,主播是发送者,观众是接收者,而直播的平台就是这个平台的角色)
redis中是有支持这些动作的命令的。
其实主要的就是六个命令(下面附上官网的截图)
pub/sub命令截图
- 订阅频道(订阅后就是监听。等待推送信息了。)
-
往频道发消息
发布订阅测试
原理:别的命令就不写了,感兴趣的自己去试试吧。总而言之redis是c语言写的。其底层就是redis-server维护了一个字典。字典的key是频道名称,值是个链表,存所有订阅的客户端的唯一标识。subcribe就是将所有的订阅了的客户端id加入到频道的链表中。
这个功能可以做群聊,实时聊天,或者微信朋友圈的指定人可见的朋友圈。或者直播提醒等。
Redis主从复制
redis的主从复制简单来说就是一个redis服务器对于项目压力太大了,而且如果这个redis意外宕机了这整个项目都会出问题。所以采用主机->从机的方式来减少redis压力和防止意外。
主从复制的主要作用:
- 数据冗余
- 故障恢复
- 负载均衡+读写分离,减压。
- 高可用(一般我们说高可用都是指集群)主从复制是哨兵和集群实现的基础。
主从复制
单机redis最大使用内存不应该超过20G
主从复制读写分离是指redis的主节点负责写,从节点负责读。因为百分之八十的情况都是读操作。这样可以减少服务器的压力。
一个主节点可以有多个从节点,但是一个从节点只能有一个主节点。
环境配置
每个redis都默认自己就是主库。所以只需要配置从库就可以了。
查看当前库的信息的命令:info
修改配置文件端口为了可以启动多个客户端
其实这里要改动的东西挺多的。比如我只改了端口,这个这是为了能够起来。但是本质上应该改动rdb,aof的输出路径。现在的话我这三个都写到一起了。不过其实实际上不一定会在一个服务器上启动,这个只是模拟的,我就偷个懒。
启动三个redis
接下来开始配置两台redis为从节点:
用控制台的话,可以slaveof host port来设置。返回ok说明成功了
配置为从节点
另外一台也是这么设置,但是我电脑死机了。。刚刚打开6个cmd。。就不一个个尝试了。
也可以在配置文件中配置:
slaveof ip port
配置文件中配置为从机
配置好后启动redis,在主机中可以看到从机
ps:如果主机有密码,建议从机也设置密码。
主机可以写,从机不可以写只能读(默认的)。主机中的所有内容都会被同步到从机中。默认情况下,主机宕机了,从机也只能是从机(哨兵模式就是主机宕机后可以选个从机推上主机)
如果是命令行配置的从机,那么重启后还是是主机。写到配置文件中的才会每次起来都是从机。并且只要变为从机,立刻就能获取到主机的所有值。
这个是主从复制的原理:
从机启动成功连接到主机后,就会发送一个sync同步命令。
当主机接到命令后回把所有的存盘进程发送给从机,这个叫做全量复制
当主从同步后,每次主写入会传给从机,这个叫做增量复制。
上面的slaveof ip port其实还有一种很有意思的写法:
slaveof no one
这个命令的意思就是想要自己当主节点.当主机断开以后可以用这个命令让自己变为主机。
上面说的不管是写在配置文件里还是写在控制台。如果有一台宕机了都是很麻烦的一件事。主宕机了所有从机不工作了。想要换个主,所有从机还要改。然后主再回来还要改回去。反正是麻烦的很,这些还都要手动操作!所以基于这些问题,出现了哨兵模式。
哨兵模式
主从切换技术的方法是:当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造成一段时间内服务不可用。这不是一种推荐的方式,更多时候,我们优先考虑哨兵模式。redis2.8以后正式提供了Sentinel(哨兵)架构来解决这个问题。
能够监控主机是否故障,如果故障了根据投票数自动将从库转成主库。
哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。
哨兵模式2
其实大概原理就是哨兵专门用来监控主机的。一般都是多个哨兵(因为一个哨兵容易出问题。不管是哨兵自己本身挂了,还是判断失误都算)。一个哨兵发现主机挂了,这个算是主观下线(毕竟也可能是哨兵自己出问题了),但是别的哨兵也发现主挂了,当数量到达一定比例就真的确定主死了,然后其实一个哨兵会发起投票。当从机票数多的那个就可以上位变成新的主机。各个从机也会连接到新主机上,这个就是客观下线。
下面是官方的说法(配合上面的图)
哨兵1先检测到这个结果,系统并不会马上进行failover过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象成为主观下线。当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线。这样对于客户端而言,一切都是透明的。
但是哨兵模式具体怎么用呢?下面来一一讲解
配置哨兵配置文件。
这个是要自己创建个文件的,sentinel.conf
# sentinel monitor 被监控的名称 host prot 1(这个1代表1个哨兵认为主机挂了就换主。 也可以换成2,3,4....)
sentinel monitor myredis 127.0.0.1 6379 1
其实到这里就是最基本的配置完成了,可以启动sentinel试试了,我反正是一次成功,如下图(注意一下命令,除了配置文件还要后面有 --sentinel):
sentinel启动成功
图上可以很明显的看出来,除了主机外还有一个从机(我只起了一个从机,笔记本真的性能不行)
其实现在如果主机宕机了(我会主动把主机关闭)如果这个时候那个从机变成了主机,就说明切换了的。
主从切换
上面的图片就是全流程,本来6379是主机,6378是从机。但是中间我手动把6379关闭了。然后哨兵自动把6378转成主机了。等我把6379再次起来以后,它已经自己变成从机了。这个就是哨兵模式的规则。
哨兵模式的优点:
- 哨兵集群,基于主从复制,所有的主从配置的优点它都有。
- 主从复制可以切换,故障可以转移,系统的可用性更好。
- 哨兵模式就是主从模式的升级版,手动到自动。
哨兵模式的缺点:
- redis不好在线扩容(哨兵启动时,主从要都在线。)集群容量一旦到达上线,在线扩容就十分麻烦。
- 实现哨兵模式的配置是很麻烦的。中间涉及到很多选择。(因为这个确实很多,所以我直接把官网网址贴过来,具体的看官网吧http://www.redis.cn/topics/sentinel.html)
关于哨兵模式就简单的讲一下啊,因为真正用到这种模式了。更多的是dba或者运营来配置,所以了解即可。真用到了再去查吧。下面说点实际的问题。
Redi缓存穿透和雪崩
记不记得之前说到mysql的发展史的时候,最开始是一次一查,后来发现读占百分之八十的访问量。所以进阶成可以再mysql和数据使用之间加了一层缓存。查询后的结果放入缓存中,在数据没有更改的前提下可以去缓存中直接获取(如果数据有更改不会缓存)。最开始没有nosql的时候,我们是用memcache.但是随着nosql 的出现,现在我们可以用redis当作缓存了。
而redis作为缓存,会出现的问题(其实这个我觉得不仅仅是redis,缓存都会存在这个问题):
缓存穿透:大量的请求去查询缓存中没有的数据,所以这个时候这些请求都砸到了数据库中。(可以理解为透过缓存直接落到数据库)
缓存击穿:一个热点数据请求量过大,当这个数据正好处于失效还没重新加入缓存的时候,所有的请求都落到数据库上。(这个可以想象是一个点被击穿。)
缓存雪崩:大批的key正好过期或者redis正好宕机(这个原因可以想象成是自然灾害,没有一条数据是无辜的。)
针对这三种情况有不同的解决办法,但是我觉得这些都是一些很笼统的东西。比如穿透的话,可以在缓存查询不到的时候直接设置成空值。但是都有利弊。
还有穿透的话可以设置只有一条线程会去数据库查询。
雪崩的话分批过期。
反正整体而言没有特别好的办法,都要酌情考虑和解决问题。
这一个redis知识点整理就到这里了,一共十多个小时的视频,一遍动手实践一遍记笔记,少说二十多个小时吧。这种学完后长舒一口气的满足感,大概等同于辛苦很久上个王者,荒野浪荡很久上个王牌差不多吧。学习是种乐趣,也希望和大家共勉!如果本篇笔记稍微帮到你了记得点个喜欢点个关注,也祝大家工作顺顺利利!另外java技术交流群130031711,欢迎各位小伙伴踊跃加入,一起学习!
网友评论