redis为了扩大并发访问量,支持多节点部署;虽然多节点部署,能够提高系统的性能和稳定;但是,由于各个节点都是相互独立的实例,各个实例之间数据相互独立,如此一来的话,多节点部署将会带来数据不一致的问题;
redis中,如何解决多个节点之间数据不一致的问题呢?接下来我们分享一下redis数据同步方式--主从数据拷贝
redis主从启动,对于master(主)节点来说,和配置普通的节点实例一样,不需要做任何修改;而slave(从)节点,则需要在配置文件中添加“slaveof ip port”配置项,ip和port为该从节点实例所对应的主节点实例监听的地址和端口。在配置完成之后,启动从节点实例,在定时器中,触发和主节点的连接,并完成握手鉴权环节;下图为握手环节从节点的状态机变化:
从上图可以看出,节点在启动之后,首先是none状态,如果配置了主节点信息,则说明该节点为从节点,状态会设置成connect状态,在定时器中,如果检测到复制状态为connect状态,则说明需要连接到主节点,此时创建理解句柄,并且连接到到主节点;此时,状态改为connecting状态,网络连接成功后,从节点会发送ping消息,与主节点进行通信,这个时候等待主节点的pong响应消息,在收到pong消息之后,将状态设置成send_auth状态,说明接下来需要进行鉴权认证,如果配置了主节点的鉴权信息则发送鉴权,否则将状态信息改为send_port状态,接下来发送子节点自己与主节点的通信端口,发送完成后,等待主节点的响应消息,此时状态为recv_port状态,在接收到响应消息之后,将状态码设置为send_ip状态,此时,同样需要判断是否设置了annouce_ip配置项,该配置项说明,岁外展示的ip是本级ip还是配置ip,如果配置annouce_ip配置项,则发送该配置项,否则直接将状态码设置成send_capa状态码,然后发送replconf消息,携带本节点的能力级,发送完成后将状态码改为recv_capa,然后等待主节点响应,响应完成之后将状态码改为send_psnyc发送本节点当前已经同步了主节点数据信息,等待主节点的响应,同时将状态码改为recv_psync状态,在主节点的响应中,会携带同步类型(增量同步还是全量同步);到此从节点的整个握手消息完成,在中间任何一个环节中出错,状态会设置成connect状态,在下一次定时器到达的时候,再次尝试与主节点连接。
上面描述的是从节点的握手过程,在握手过程中,主节点的工作是怎样的呢,是否也具有对应的状态机;redis主从复制模式下,任何连接到主节点的从节点,在主节点中都是将他当做一个客户端来进行处理,所以说,主从连接的整个握手过程,在主节点中,就是一个和客户端进行交互的过程,并没有特殊的状态机进行管理;
主从复制机制:
上图为master(主)节点收到slave(从)节点的psync消息后,首先解析出消息中携带的slave节点积压缓冲区的信息,并且与自身的积压缓冲区中的信息进行比对,用来判断接下来的数据同步是增量数据同步还是全量数据同步,如果是增量数据同步的话,返回增量同步标志,并将master节点积压缓冲区中的数据发送给slave;如果是全量同步的话,返回全量同步标志,然后检查是否需要开启子进程进行数据持久化,如果已经存在子进程正在进行持久化,则等到持久化完成,master(主)节点根据slave(从)节点是否需要全量同步数据,将数据信息发送给需要进行全量同步信息的slave(从)节点。
以上为slave(从)节点刚刚启动后第一次资源同步的过程,在后续运行过程中,master(主)节点会经常的收到数据修改的请求,接下来的数据修改的请求如何通知给slave(从)节点呢?master(主)节点在每次收到数据修改的情趣之后,操作自己实例中的数据,并将该请求分别写入aof持久化文件中(开启情况下)、本域的全局积压缓冲区中以及每一个slave实例的发送数据存储空间中;slave(从)节点会定时的发送replconf+ack消息,master(主)节点在收到ack消息之后,检查该slave实例中时候有数据可以发送,有的话,则将数据发送给slave(从)节点;slave(从)节点的ack消息为每一秒中发送一次;所有说主从redis中的数据有可能存在小于1秒钟的不一致情况;从上面的分析可知,redis的数据一致性为最终数据一致性策略;