原文链接:https://blog.csdn.net/a745233700/article/details/85413179

一、Redis的过期策略以及内存淘汰策略:
1、过期策略:定期删除+惰性删除:

①定期删除:redis默认每隔100ms就随机抽取一些设置了过期时间的key,检查其是否过期,如果有过期就删除。注意这里是随机抽取的。为什么要随机呢?你想一想假如 redis 存了几十万个 key ,每隔100ms就遍历所有的设置过期时间的 key 的话,就会给 CPU 带来很大的负载。

②惰性删除:定期删除可能导致很多过期的key 到了时间并没有被删除掉。这时就要使用到惰性删除。在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间并且过期了,是的话就删除。

2、定期删除+惰性删除存在的问题:
如果定期删除没删除key,然后也没即时去请求key,也就是说惰性删除也没生效。这时,如果大量过期的key堆积在内存中,redis的内存会越来越高,导致redis的内存块耗尽。那么就应该采用内存淘汰机制。

3、为什么不用定时删除策略?
定时删除,用一个定时器来负责监视key,过期则自动删除。虽然内存及时释放,但是十分消耗CPU资源。在大并发请求下,CPU要将时间应用在处理请求,而不是删除key,因此没有采用这一策略。

4、redis内存数据淘汰策略:

问题:MySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据?redis内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。
①allkeys-lru:在所有的键空间中,移除最近最少使用的key。推荐使用,目前项目在用这种。

②volatile-lru:在设置了过期时间的键空间中,移除最近最少使用的key。这种情况一般是把redis既当缓存,又做持久化存储的时候才用。不推荐

③allkeys-random:在键空间中,随机移除某个key。应该也没人用吧,你不删最少使用Key,去随机删。

④volatile-random:在设置了过期时间的键空间中,随机移除某个key。依然不推荐。

⑤volatile-ttl:在设置了过期时间的键空间中,移除即将过期的key进行淘汰。不推荐。

⑥noeviction:不进行移除,新写入操作会报错。应该没人用吧。
ps:如果没有设置 expire 的key, 不满足先决条件(prerequisites); 那么 volatile-lru, volatile-random 和 volatile-ttl 策略的行为, 和 noeviction(不删除) 基本上一致。

 

二、Reids的持久化方式:RDB和AOF
第一种持久化方式:RDB
1、什么是RDB:

在指定的时间间隔内将内存中的数据集快照写入磁盘(dump.rdb文件),即Snapshot快照,它恢复时是将快照文件从磁盘直接读到内存里。

2、默认持久化设置:

save 900 1              #在900秒(15分钟)之后,如果至少有1个key发生变化,则dump内存快照。

save 300 10            #在300秒(5分钟)之后,如果至少有10个key发生变化,则dump内存快照。

save 60 10000        #在60秒(1分钟)之后,如果至少有10000个key发生变化,则dump内存快照。

是1分钟内改了1万次,或5分钟内改了10次,或15分钟内改了1次。

3、持久化原理:

        Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能。

        fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等)数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程。

 4、优势:

(1)如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。

(2)相比于AOF机制,如果数据集很大,RDB的启动效率会更高。

5、劣势:

(1)在一定间隔时间做一次备份,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改。

(2)fork的时候,内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑。

第二种持久化方式:AOF:
 1、什么是AOF:

以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。(appendonly.aof文件)

2、AOF文件的rewrite机制:

(1)因为AOF采用文件追加方式,文件会越来越大,为避免出现此种情况,新增了重写机制,当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集,可以使用命令bg rewriteaof,异步执行一个 AOF(AppendOnly File) 文件重写操作。

(2)重写原理:AOF文件持续增长而过大时,会fork出一条新进程来将文件重写(也是先写临时文件最后再rename),遍历新进程的内存中数据,每条记录有一条的Set语句。重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似。

在执行 BGREWRITEAOF 命令时,Redis 服务器会维护一个 AOF 重写缓冲区,该缓冲区会在子进程创建新AOF文件期
间,记录服务器执行的所有写命令。当子进程完成创建新AOF文件的工作之后,服务器会将重写缓冲区中的所有内容追加到新AOF文件的末尾,使得新旧两个AOF文件所保存的数据库状态一致。最后,服务器用新的AOF文件替换旧的AOF文件,以此来完成AOF文件重写操作。

(3)触发时机:Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发。

3、AOF持久化配置:

(1)每修改同步:appendfsync always   同步持久化,每次发生数据变更会被立即记录到磁盘,性能较差但数据完整性比较好。

(2)每秒同步:appendfsync everysec    异步操作,每秒记录,如果一秒内宕机,有数据丢失。

(3)不同步:appendfsync no   从不同步

4、劣势:

(1)相同数据集的数据而言aof文件要远大于rdb文件,恢复速度慢于rdb。

(2)aof运行效率要慢于rdb,每秒同步策略效率较好,不同步效率和rdb相同。

注:如果同时开启两种持久化方式,在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。

Redis4.0对于持久化机制的优化:

Redis4.0开始支持RDB和AOF的混合持久化(默认关闭,可以通过配置项 aof-use-rdb-preamble 开启)。

如果把混合持久化打开,AOF 重写的时候就直接把 RDB 的内容写到 AOF 文件开头。这样做的好处是可以结合 RDB和 AOF 的优点, 快速加载同时避免丢失过多的数据。当然缺点也是有的, AOF 里面的 RDB 部分是压缩格式不再是AOF 格式,可读性较差。

 

三、Redis事务:
可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,一次性地按顺序地串行化执行,并且在事务执行期间,服务器不会中断事务而改去执行其他客户端的命令请求,即不会被其它命令插入,不许加塞,它会将事务中的所有命令都执行完毕,然后才去处理其他客户端的命令请求。即一个队列中,一次性、顺序性、排他性的执行一系列命令。

1、常用命令:

(1)开启事务:MULTI。MULTI执行之后,客户端可以继续向服务器发送任意多条命令,这些命令不会立即被执行,而是被放到一个缓存队列中,当EXEC命令被调用时,所有队列中的命令才会被执行。

(2)执行事务:EXEC。

(3)放弃事务:DISCARD。开启事务之后,可以通过调用DISCARD,清空事务队列,并放弃执行事务。

(4)监视key:WATCH。作为WATCH命令的参数的键会受到Redis的监控,Redis能够检测到它们的变化。如果在事务执行之前这些key被其他命令所改动,那么整个事务将会被打断。WATCH命令可用于提供CAS(check-and-set)功能。

(5)取消监视:UNWATCH。

2、Redis事务的特性:

(1)非原子性,不支持回滚:执行EXEC命令的时候,Redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚。在 EXEC 命令只保证批量操作的一次性批量执行过程。

Redis 操作失败的原因只可能是语法错误或者错误的数据库类型操作,这些都是在开发层面能发现的问题不会进入到生产环境,因此不需要回滚。

Redis 内部设计推崇简单和高性能,因此不需要回滚能力。

并且,Redis 的应用场景明显不是为了数据存储的高可靠而设计的,而是为了数据访问的高性能而设计,设计者为了简单性和高性能而部分放弃了原子性。

②一致性:

③单独的隔离操作,事务中的所有命令都会被序列化,按顺序地执行。事务在执行的过程中,其他客户端发送来的命令请求不会插入到事务执行命令序列中。没有隔离级别的概念,事务队列中的命令没有提交之前都不会实际的被执行。

④持久性:如果Redis运行在某种特定的持久化模式下时,事务也具有持久性。当使用Append-Only模式时,Redis会通过调用系统函数write将该事务内的所有写操作在本次调用中全部写入磁盘。然而如果在写入的过程中出现系统崩溃,如电源故障导致的宕机,那么此时也许只有部分数据被写入到磁盘,而另外一部分数据却已经丢失。

 

四、Redis主从复制:
        Redis支持主从复制的模式。原则:主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,slave不会将数据同步到master,Master以写为主,Slave以读为主。这样可以有效减少单个机器的并发访问数量。

1、配置要点:

(1)配从库不配主。

(2)从库配置:slaveof 主库IP 主库端口:

(3)slave每次与master断开之后,都需要重新连接,除非你配置进redis.conf文件。

(4)查看redis的配置信息:info replication

2、主从复制原理:

(1)slave启动成功连接到master后会发送一个sync命令;

(2)Master接到slave的sync命令后,启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,以完成一次完全同步。

(3)全量复制:slave服务在接收到主机数据库文件数据后,将其存盘并加载到内存中。

(4)增量复制:Master继续将新的所有收集到的修改命令依次传给slave,完成同步。

(5)但是只要是重新连接master,一次完全同步(全量复制)将被自动执行。

 3、常用三招:

a、一主二从:一个Master两个Slave

(1)切入点问题?slave1、slave2是从头开始复制还是从切入点开始复制?比如从k4进来,那之前的123是否也可以复制。答:从头开始复制。

(2)从机是否可以写?是否可以使用set命令?答:不可以。

(3)主机shutdown后情况如何?从机是上位还是原地待命?答:如果没有配置哨兵模式,则是原地待命。

(4)主机又回来了后,主机新增记录,从机还能否顺利复制?答:能。

(5)其中一台从机down后情况如何?依照原有它能跟上大部队吗?答:需要重新连接。

b、薪火相传:

上一个Slave可以是下一个slave的Master,Slave同样可以接收其他slaves的连接和同步请求,那么该slave作为了链条中下一个的master,可以有效减轻master的写压力。但是,如果中途变更转向,则会清除之前的数据,重新建立拷贝最新的主机数据。

c、反客为主:SLAVEOF no one。原本的Master挂掉之后,执行此命令,会重新选择一台Master。

4、哨兵模式(sentinel):

反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库。 

如果之前的master重启回来,不会造成双master冲突,因为原本的master会变成slave。

配置步骤:

(1)在自定义的/myredis目录下新建sentinel.conf文件,名字绝不能错。

(2)配置哨兵,在配置文件中写: sentinel monitor 被监控数据库名字(自己起名字) 127.0.0.1 6379 1

上面最后一个数字1,表示主机挂掉后salve投票看让谁接替成为主机,得票数多少后成为主机。

(3)启动哨兵:redis-sentinel /myredis/sentinel.conf

5、主从复制的缺点:由于所有的写操作都是先在Master上操作,然后同步更新到Slave上,所以从Master同步到Slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重。