单机Redis的问题:
机器故障:可能丢数据。
容量瓶颈:存不下,硬件有瓶颈。
结论:多台服务器互相复制,实现冗余。
需要解决的问题:如何数据同步。
由主服务器往从服务器复制数据,就叫主从同步。
主服务器 | | --------------|-------------- | | | | | | slave1 slave2 slave3master:
只写不读。写操作后数据自动同步到slave。slave:
只读不写好处:
读写分离。提高读写能力。负载均衡。故障恢复。数据冗余。实现数据的热备份,是AOF和RDB之外的一个手段。高可用的基石。slave到master的连接。
slaveof ip port
如果连通,master会回复masterhost和masterport。slave将信息保存下来。建立socket。
根据保存的信息连接master的socket。slave通过定时任务发送ping命令。
master回复pong,证明连接没断。身份验证。
auth password
Redis不对外提供服务,基本上不需要密码。发送slave端口信息。
replcof listening-port <port-number>
slave将自己的端口号发给master,master保存下来。连接方式:
方式一:客户端发送命令
slaveof masterIP masterPort
方式二: 启动服务器时加上参数
redis-server --slaveof masterIP masterPort
方式三: 配置文件中配置master节点信息
slaveof masterIP masterPort
断开方式:
从客户端发送命令
slaveof no one
授权访问:
master:
master配置文件设置密码
requirepass 密码
master客户端发送命令设置密码
config set requirepass 密码 设置密码config get requirepass 获取密码slave:
slave 客户端发送命令设置密码
auto 密码
slave配置文件设置密码
masterauth 密码
启动客户端时输入密码(访问自己服务端的密码)
redis-cli -a 密码
请求同步数据
刚建立连接时,slave请求把master的所有数据都复制到本机。psync2
master创建rdb同步数据
master执行 bgsave。master创建了一个复制缓冲区,将新来的数据放进缓冲区。slave恢复RDB同步数据(全量复制)
slave接收rdb文件,并清空自己的数据,执行rdb恢复过程。slave发送命令告诉master恢复完成。请求并恢复部分同步数据(增量复制)
master复制缓冲区信息。slave接收信息,执行bgrewriteaof,恢复数据。数据同步注意事项
如果master数据量过大,数据同步阶段应该避开流量高峰期。
如果复制缓冲区大小设置的不合理,就会导致数据溢出。如果部分复制发生溢出,那么必须进行第二次全量复制。
repl-backlog-size 1mb 缓冲区默认是1M。
master单机内存占用主机内存的比例不应过大,建议50%-70%,剩下的内存用于执行bgsave和创建复制换冲区。
为避免slave进行复制时服务器阻塞,建议关闭此时的对外服务。
slave-serve-stale-data yes|no
多个slave同时请求数据同步,会占用大量带宽,注意错峰。
树状节点时,数据一致性比较差,应该谨慎选择。
命令传播阶段会部分复制
如果出现了长时间断网:全量复制短时间网络中断:部分中断服务器运行ID: 识别每一次服务运行时的身份识别码,40位的16进制字符。用来在服务器间发送命令时校验身份。
复制缓冲区: 每次传播命令,master都会将传播的命令记录下来,存储在缓冲区。
复制缓冲区是用字符来存储的,拆成AOF那种形式。仅保存影响数据变更的指令,比如set、select等。偏移量offset: 使用偏移量来确认发送到了哪一个字节。
master和slave都会记录offset,用来对比复制差异。master会保存多个offset,每个slave对应一个。slave只保存自己的。在命令传播阶段,master与slave间需要进行信息交换,使用心跳机制保持双方在线。
master心跳:
指令:PING周期: 由repl-ping-slave-period决定,默认是10秒。作用:判断slave是否在线。查询:INFO replication 获取slave最后一次连接时间间隔。slave心跳:
指令 REPLCONF ACK offset周期 一秒向master汇报自己的复制偏移量,并且判断master是否在线。注意:
当slave多次掉线或者延迟过高,就会被master踢了。
min-slaves-to-write 2
最少只剩下2个slave了,就停止写了。
min-slaves-max-lag 8
延迟过高,也不写了。
slave数量和延迟由slave发送REPLCONF ACK命令来确认。
一旦master重启,runid发生变化,会导致slave全部全量复制。
Redis内部优化方案:
会生成一个repl-id和offset。在master关闭时进行RDB持久化,将repl-id和offset保存进RDB文件。重启后将这两个东西恢复回来,使slave以为还是原来的master。 断网后slave的offset 越界,触发全量复制。 最优的复制缓冲区空间测算master到slave的重连平均时长
空间 = 2*second*master每秒钟产生写命令数据总量
slave收到了慢查询,比如keys *这种命令,导致slave无法响应master,master不停地尝试连接slave,占用了大量资源。
合理地设置超时时间,将slave断开。repl-timeout 60默认60秒master的ping频率低,超时时间短,ping万一丢包了,master就会踢掉slave。
repl-ping-slave-period超时时间至少是ping频率的5-10倍。多个slave数据不同步,网络信息不同步,数据发送有延迟。
优化主从机器的网络环境,尽量放在同一个机房。如果延迟非常大,建议暂时关闭slave的对外服务。slave-serve-stale-data yes|no打开后slave仅响应info,slaveof等少数命令。慎用。如果master宕机,需要下线master,再选出来一个slave当做master,再通知所有slave。
哨兵是一个分布式系统,用于对主从结构的每台服务器进行监控,当出现问题时通过投票机制来选取新的master。
作用:
监控通知自动故障转移哨兵一般是奇数,3个起。
哨兵也是Redis服务器,只不过不提供数据服务。
配置文件
sentinel.conf
port 26379sentinel monitor mymaster 127.0.0.1 6379 2 mymaster是给master起的名字。2的意思是如果有两个哨兵觉得master宕机,那就真的宕机了。一般是所有哨兵的一半+1。 sentinel down-after-milliseconds mymaster 30000 主机多少秒没联系就认为宕机 sentinel parallel-syncs mymaster 1 挂了之后一次有多少台机器来和新master同步。 sentinel failover-timeout mymaster 180000 同步时多久同步完成是有效的。默认180秒同步超时。启动哨兵
redis-sentinel sentinel_port.conf
启动顺序
启动master。启动slave。启动sentinel。注意:
哨兵启动后,配置文件内会被追加一些自己id和其他哨兵ID和slave的信息。每个哨兵启动后都能互相被其他已经启动的哨兵识别到。用于同步各个节点的状态信息。
获取各个sentinel的信息。获取master的信息。 master属性: runidrole 各个slave的信息 获取所有的slave状态。 slave属性 runidroleportoffset等等。如果一个哨兵发现master联不通,就会将其标记为sdown。
其他哨兵收到第一个哨兵的通知后,也会去访问master,如果超过配置文件中那个数量的哨兵都确认master宕机,就会将其标记为odown。
哨兵们会选举出来一个带头人,内部会有一个投票机制,选定一个哨兵去处理故障转移。
选master原则:
slave在线。响应慢的淘汰。与master断开时间久的踢掉。优先级。 优先级偏移量(偏移量小的说明同步的快)runid(选id小的)现在就选到了新的master。向新的slave发送slaveof no one。
向其他的slave发送slaveof masterIP masterPort。
如果原来的master恢复上线后,作为slave连接。
将若干台机器连接在一起,统一对外服务。
数据存储设计
先对Key进行计算CRC16(key),再对16384取余,得到一个数字,然后存到对应的机器。这个数字,官方叫做槽。增删节点,就是移动槽的位置。
集群内部通讯设计
内部节点会互相通讯,了解每个节点有哪些槽。一次命中,直接返回。不命中就查表。所以最多两次就能找到槽。
配置文件里添加cluster相关配置。
cluster-enabled yes|oncluster-config-file nodes-端口.confcluster-node-timeout 超时下线时间src文件夹有个命令 redis-trib.rb ,是个ruby脚本。
redis-trib.rb create --replicas 1 master1IP:Port master2IP:Port.....
- 1代表一个master拖一个slave。 - 后面的ip和端口,前面是master,后面是slave。redis-cli -c 这是集群专用的客户端。一定要加上-c命令。
slave对应的master会将slave标记为下线。同时将slave下线的消息发送给集群其他的节点。
slave再次上线后,会与master建立同步,集群其他节点会清除slave的下线状态。
slave会重连10次,一秒连接一次。
slave会经历一串转变升级为master。
master再次上线后,就会变成slave,去找刚才升级为master的slave同步信息。