redis学习总结
一:redis过期键删除策越
1:惰性删除:每次get的时候才判断key是否过期,如果过期才会执行删除,这样会导致大量的过期key占用内存。
2:定期删除:通过设置删除频率和时长(需要根据实际情况,可以压数据,看某个时间范围内过期的key有多少,占用多少内存,大概需要多久才能删除完),在某个时候执行删除操作,并只执行设置的时长时间,这样既降低了CPU消耗时间(不会长时间占用cpu去执行删除过期key的操作),同时也避免了一定的内存浪费(删除一定时长,即使还存在未删除的key,也可以下次删除)
3: 过期键不会对RDB和AOF有影响(执行save(阻塞主进程),bgsave(直接fork出一个进程处理,主进程继续处理client请求),bgrewriteaof),在主从复制时,如果是从服务器收到get key命令,而key已经过期,那么会返回value(这个地方有可能返回过期的数据,可以设置Key的有效时间),只有当主redis收到get key时,发现Key过期了,会给所有的从redis发送del命令,删除过期key,可以看到,这完全由主redis控制,保证主从的数据一致性。
二:RDB持久化
2.1 rdb文件用于保存和还原redis服务器数据库中所有的键值对数据
2.2 save命令强制由主进程写rdb,阻塞client请求
2.3 bgsave命令fork(克隆内存中个数据)出一个子进程执行写rdb,主进程继续处理请求,但是如果数据很大,fork也会很耗时,可能会导致某个时刻服务不处理请求
2.4 最后一次持久化的数据可能丢失
三:AOF持久化
3.1 Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发
3.2 RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件。那要不要只使用AOF呢?建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份),快速重启,而且不会有AOF可能潜在的bug,留着作为一个万一的手段。
性能建议:
因为RDB文件只用作后备用途,建议只在Slave上持久化RDB文件,而且只要15分钟备份一次就够了,只保留save 900 1这条规则。
如果Enalbe AOF,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了。代价一是带来了持续的IO,二是AOF rewrite的最后将rewrite过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上。默认超过原大小100%大小时重写可以改到适当的数值。
如果不Enable AOF ,仅靠Master-Slave Replication 实现高可用性也可以。能省掉一大笔IO也减少了rewrite时带来的系统波动。代价是如果Master/Slave同时倒掉,会丢失十几分钟的数据,启动脚本也要比较两个Master/Slave中的RDB文件,载入较新的那个。新浪微博就选用了这种架构.
四:redis服务器处理请求流程
Client发送请求给server--->server读取命令请求,并分析命令参数--->命令执行器根据参数查找对应命令的实现函数--->实现函数执行命令--->server将命令执行回复返给client
五 主从复制
从服务器slaveof master ip 即可连上主服务器开始同步,同步分为完全同步和部分重同步,三者根据server运行的run id,复制偏移量,复制积压缓冲区来实现,主从server都会维护一个复制偏移量记录当前服务器数据的偏移位置,复制积压缓冲区是由主server维护的一个FIFO的队列,每次主server像从server发送同步命令的同时会将写命令入队到复制积压缓冲区,server运行的Id在每次重启后都会改变,因为它是存在内存中的一个随机生成的字符串,当slave server收到了master server发送的同步命令时,开始执行同步,如果中途网络掉线,重连的时间内主server还有数据写入,当slave server重连上master后,会将当前slave server记录的偏移量一并发送给master server,如果主从是第一次复制,将开始一次全量同步,如果不是第一次,master在判断slave发送的run id 是否是自己的id后,检查复制缓存区里是否pos+1后还有数据,如果有,表明断线后主server继续处理了写请求,这个时候master就会将pos+1后面的数据部分发送给slave执行数据同步。在主server发送命令给slave的过程中如果出现了网络故障导致一部分命令或者全部命令丢失,从server像主server发送repliy ack的时候,带过去的参数pos,主server检测到pos和自己当前的pos不一样,又会再次在复制积压缓冲区里面找到slave缺失的数据,再次发送给slave,直到master/slave数据完全同步为止。
六 sentinel哨兵线程
sentinel主要是保证redis的高可用,在master选举的过程中发挥监听和故障转移的作用,
主观下线:sentinel会像其监听的master,slave,其他的sentinel发送ping命令,如果在设置的时间范围内未收到有效回复,那么监听的该sentinel就会将被监听的server在其属性中打开SRI_S_DOWN标识表示主观下线,此后该sentinel询问其它的sentinel是否也认为该server已经下线了,如果收到了半数以上的回复,那么就会将其列为客观下线,准备开始故障转移.
领头sentinel选举: 当master被标识为客观下线后,监视这个master的各个sentinel会协调选举出一个领头的sentinel执行故障转移,主要规则是先到先得,半数同意。
每个sentinel都有机会成为领头的,当某一个sentinel(目标)收到来自其它sentinel(源)的请求要将源设置为领头时遵循先到先得,即谁先像目的sentinel发送了要将其自己设置为局部领头的sentinel时,最新收到请求的将成为目标sentinel的领头sentinel,其它的都拒绝,当整个sentinel中超过半数的sentinel都将某个sentinel选举为局部领头的sentinel,那么这个sentinel就会成为最终的领头sentinel(如果在一定时间内,没有选举出领头sentinel,会隔一段时间再进行选举)
七 故障转移
1:从以下线的master的所有slave里面找一个slave执行salveof no one 将其变为master
领头的sentinel将会在所有的slave里面选择一个slave为新的master,首先要删除slave里面不是正常在线的(ping,通讯不正常等),然后根据配置的优先级(优先级越高就是master,如果一样,看后面的条件),各个salve维护的自身偏移量(偏移量越大,说明数据越完整,如果一样看后面的条件),如果还没选举出,则根据运行的id排序后选择出最小的为新的master
2:将其它slave的的master设置为新的master ip
执行slaveof masterip masterport
3:将以下线的master设置为新的master的salve
执行slaveof masterip masterport
八:集群
节点通过握手来讲其它节点添加到自己的集群中,集群中的16384个槽分别指派给集群中各个主节点,当有新节点加入时,可以执行重新分片(重新分片不会对集群产生任何的影响),将某个节点所有槽对应的键值对从一个节点移动到另一个节点,当客户端发送了get key给某个server,server需要首先检查这个get命令所处理的键所在的槽是否是自己负责的,如果是,直接返回,如果不是,需要重新定向到负责这个槽的节点。如果在发生分片的过程中,如A-B,如果A收到了请求,如果key对应的槽还由A负责,则A直接返回,如果不由A处理了,节点A会返回一个ASK错误指引client去B处获取。