二、Redis基础原理

Redis基础原理

一、Redis基础与高级数据结构
二、Redis基础原理
三、Redis拓展知识

一、 Redis为什么快

  • 内存操作;
  • IO多路复用 select、epull、kqueue算法;
  • 指令序列化简单,解析性能好。

二、持久化

1.AOF

  • AOF:连续的增量备份,Redis服务器执行的顺序指令序列,只记录修改操作的指令记录,一般应用于从节点;
  • AOF日志的记录过程:指令的执行内容先写到内核为文件操作符分配的内存缓存,然后系统异步的刷到磁盘(fsync),通常1s执行一次刷盘(可配置),如果执行太频繁会导致执行速度慢,但太久不刷盘会有宕机损失数据的风险;
  • AOF文件过大后可以使用bgrewriteaof指令进行重写(瘦身)。

2.RDB(快照)

  • 快照:全量的备份,采用二进制序列化的形式;
  • 快照备份原理:开启fork子进程,利用多进程COW(Copy On Write)进行持久化,子进程持久化,不会修改现有内存数据结构,父进程持续处理客户端请求,父进程对数据段中的数据页进行修改时,会复制出来一份进行分离(最多页就是原内存的2倍),然后再对复制的页面进行修改,而不会影响持久化使用的数据页。

3.混合模式:RDB全量+RDB以后的AOF增量

三、事务

  • 原理:所有的指令在exec之前都缓存在服务器中的一个事务队列中,遇到exec后开始执行,来确保“原子性”;
  • 非原子性:事务不是严格的“原子性”,如果中间的指令发生了错误,后面的指令依旧执行,因为redis考虑到指令的错误发生的概率会比较小
  • :对于一个并发问题(如先查看一个key的值,再进行key值的操作),可以使用分布式锁(悲观锁)处理,也可以使用watch指令(乐观锁)处理,watch指令(能在事务执行之前执行)会在修改时与watch执行时当时的值进行比较,如果值不一样会返回NULL,客户端可以进行重试处理;
  • 高可用锁:悲观锁的这种情况在主从或者集群的环境下可能会因为主节点不可用时候造成多个现成获得锁,可以使用开源库Redlock算法,它连接的redis所有实例都相互独立,采用大多数的机制进行申请和释放锁,因为与多个实例交互,所以性能有所降低。

四、内存回收

  • 内存回收机制:删除大量的key内存不会立刻的变小,因为操作系统以页为单位来回收内存,只要页上有key就不会进行回收,但如果执行flushdb会强行回收;
  • 内存算法:内存回收算法不由redis自身提供,依赖于第三方厂商库,如facebook的jemalloc和google的tcmalloc,默认是性能会好一些的tcmalloc。

五、主从

1.背景:从CAP(一致性、可用性、分区容忍性)结合网络分区(断开)的角度进行分析,发生网络分区时,一致性与可用性不能两全,Redis满足可用性,尽量保持最终一致性。

2.主从(从从)同步

  • 增量同步原理:redis同步的是指令流,主节点修改的记录都记录在本地内存buffer,然后以异步的方式同步到从节点,从节点反馈同步的偏移量,如果由于网络原因buffer满了会造成指令的覆盖,可以采用快照再进行同步;
  • 快照同步原理:主节点执行bgsave,然后将文件传送到从节点,从节点清空数据进行数据同步,同步完成后继续进行增量同步,如果在快照同步的过程中buffer又满了,同样还会产生覆盖指令;
  • 无盘复制:主机点进行主从同步时,比较消耗IO,在非SSD硬盘会产生较大的负载,如果此时还在进行aof备份,刷盘fsync会推迟,从而影响主节点效率。redis2.8.18后支持无盘复制,直接通过套接字将快照内容发送到从节点,从节点处理流程与之前一致,先存磁盘文件再一次性加载;
  • 增加从节点:必须需要做一个快照同步然后再进行增量同步。

六、哨兵

1.原理:sentinel集群类似于zookeeper集群,主节点挂掉选择一个最优的作为新的主节点,客户端连接集群首先连接sentinel,通过sentinel来查询主节点的地址,然后再连接主节点,当一个主节点故障会选举新的主节点,然后持续监控故障的结点,等待他恢复。

2.消息丢失:主节点有问题时可能有未同步的消息发送到从节点,可以通过两个参数尽可能的减少消息的丢失。

  • min-slaves-to-write=-1 主节点至少有一个从节点可以正常,否则停止对外写
  • min-slaves-max-lat=10 10s内没收到从节点的反馈就算主从同步不正常

3.客户端处理

  • 如果sentinel进行主从切换时,客户端会在建立时都会从sentinel中获取主节点信息,如果获取的与内存中的不一致就进行修正,断开所有连接,重新连接。如果是主节点挂掉,所有正在使用的连接都会被关闭,然后进行重新连接。
  • 如果说运维主动进行了服务端sentinel的主从切换(节点没有故障),客户端可以捕获一个特殊的ReadOnlyError异常,然后将所有旧的连接关闭。

七、集群

1.condis集群方案:

  • 原理:国产豌豆荚中间件,开发一个高可用的代理中间件集群,用于进行redis集群环境key的分片,默认分配1024个槽,槽位与redis实例的映射关系可以保存在内存、zookeeper、etcd(key-value数据库)中;
  • 扩容:扩容时遇到请求,直接处理,先迁移然后再将指令转发到新的实例中
  • 优点:可以自动均衡处理key的不均衡问题,使用简单,有直观的前台管理页面
  • 缺点:有的跨槽的指令不支持,如事务、rename、大key查询卡顿,不是亲儿子更新依赖于redis的更新速度

2.cluster集群方案:

  • 原理:划分16384个槽,与condis不同去中心化,槽位信息保存在每个节点中,客户端连接集群时候可以获取到集群槽位配置信息,并缓存起来,不一致时进行纠正(访问错误节点会返回MOVE指令),可以使用{tag}强制key挂在同一个槽位,cluster集群不支持事务,mget方法比单体redis要慢,rename不是原子性操作。

  • 槽迁移

    A.原理
    ①标识源节点状态为migrating,目标节点状态为importing
    ②获取源节点的key采用dump、restore的方式进行迁移
    ③迁移的过程为同步,迁移完成后删除源节点中的key

    B.客户端:槽迁移的过程中,客户端先访问旧节点,如果旧节点中存在就进行处理,如果不存在该key就认为在新节点或根本不存在,然后返回客户端ASK指令,客户端会先发送一个空的ASKING指令到新节点,告知新节点我后面发送的指令你要当成自己的节点来处理,不要在返回MOVE指令,引发重定向循环问题。

  • 容错:
    A.机制:如果一个主出现故障,集群会进行主从的切换,参数cluster-node-timeout表示持续多久失联认定为故障需要进行主从切换,cluster-salve-validity-factor表示超时的容错紧急程度(松弛系数);
    B.原理:一个节点认为另一个节点故障,会采用Gossip协议向整个集群广播失联的信息,如果失联节点反馈的数量达到了集群的大多数,则会标识为确定下线(Fail),然后再进行广播进行主从切换。
    C.客户端:
    ①节点挂了会抛出ConnectionError异常,客户端会会随便挑选一个节点重试来获取move指令中的新地址;
    ②运维手动修改集群,将主切换到其他节点,客户端会收到ClusterDown的错误,表示当前的节点被孤立,客户端会关闭所有连接,清空槽位信息表,向上抛异常等重新初始化连接。

你可能感兴趣的:(二、Redis基础原理)