ITPub博客

首页 > 数据库 > 数据库开发技术 > 重新认识redis(十一)

重新认识redis(十一)

原创 数据库开发技术 作者:DBA修行之路 时间:2021-11-28 16:16:29 0 删除 编辑

文字表述

文字表述

文字表述

左右滑动查看更多




点击上方“蓝字”,发现更多精彩。





重新认识redis(十一)

爱恨情仇

凡事都有利有弊,正如药能医人,也能杀人一样,redis中的主从同步机制带给我们很多好处,通过主从设置主从同步,我们可以实现高可用,在主库异常的时候实现自动切换到备库,为业务提供高可靠服务。同时,还可以开启读写分离,让读库承担更多的读请求,从而减轻主库的压力。但是主从同步实际在使用时,因为某些原因也会坑你没商量。每每这时候,是不是对redis又爱又恨呢。  

不说了,看下下面的图吧:          

主从同步异常

对于主从同步异常,可以从原因,现象,解决方法三个方面来进行学习:

原因:redis主从同步异常的根本原因可以追溯到主从同步的实现,我们知道,redis主从同步是异步的,主库收到命令会发送给从库,但不会等到从库执行完命令再返回结果给客户端,而是在本地执行完就会向客户端返回结果。因此,如果网络有传输延迟,会导致从库无法及时收到主库发送的命令。另外,redis命令是顺序执行的,在读写分离的场景下,如果从库因处理复杂命令而阻塞从而无法及时执行接收到的来自主库的命令,这也会导致主从同步异常。

现象:从库读取到的数据值和主库的最新值不一致。

解决方案:可以从多方面来解决这个问题:一方面,可以从硬件着手,尽可能保证主从库间的网络连接良好。例如可以将主从库部署在相同的机房,但是从容灾来说,这个会有隐患,或者避免将redis服务器与网络通信密集的应用服务器部署在一起。另一方面,可以从软件着手,可以通过监控程序来监控redis主从库的主从复制进度,可以通过INFO replication命令查看主从同步的进度信息,使用master_repl_offset值减去slave_repl_offset值,即可得到从库和主库间的复制进度差,如果大于设定的阈值,则设置该从库不可用。



过期数据

读取过期数据指的是某条记录在主库已经过期被删除了但是客户端还是能在从库中读取到。思考两个问题,1.为什么会读取到过期数据?2.如何避免读到过期数据?带着这两个问题来看接下来的内容。


1.为什么会读取到过期数据?

redis读取到过期数据与redis的删除策略,过期时间设置以及版本都有关系。先看redis的删除策略吧,redis中同时使用惰性删除策略和定期删除策略,定期删除策略很好理解,即redis定期(默认100ms)会选出一些过期数据进行删除。惰性删除策略指的是即使数据过期时间到了,redis并不会立即删除数据,而是当下次有请求来读写这个数据时再进行删除。如果过期数据较多,且一直未被访问,则就会一直留在redis中,如果此时客户端在从库访问这些过期数据,就有可能返回过期数据。这里的可能与redis版本有关,redis3.2之前,在从库执行读请求时,从库不会判断数据是否过期,会直接返回数据,而在redis3.2后,从库会进行数据是否已过期判断,如果过期,则返回空值。然后还有一个就是过期时间设置的命令了,redis中提供了四个设置数据过期时间的命令,expire,pexpire,expireat,pexpireat,具体的后面补充,一般来说expire受主从同步的影响较大,容易读到过期数据。


2.那么如何避免读到过期数据问题呢?

解决问题的最好方法就是从原因入手,对于前面提到的几点原因,可以有的放矢。第一,我们可以尽可能地使用redis3.2及其后的版本,第二,设置过期时间时,使用expireat或者pexpireat而不是expire或者pexpire,但是需要注意,主从节点服务器需要保持时钟一致。



脑裂现象

知道啥叫脑裂嘛,不清楚的话想象一下你的大脑中有两个小人,左边的小人说我要吃苹果,右边的小人说我要吃橘子,这时候你到底是听谁的呢,是不是头大呢,哈哈,开个玩笑。redis中的脑裂指的是在主从集群中同时有两个主节点都能接收写请求,导致客户端不知道往哪个主节点写入数据。下面,从脑裂的原因,影响以及规避方法三个方面来了解脑裂吧。

脑裂的原因:

脑裂的原因根本原因是原来的主库发生了假故障,我们知道,哨兵和从库是通过心跳机制来判断主库是否正常的,因此,如果主库某个时刻无法正常响应心跳,可能就会被误判为故障,具体原因可能有网络问题,主库服务器资源被占用,主库发生阻塞。

脑裂的影响:

redis脑裂是发生在主从切换的过程中,此时因为redis还没有完成主从切换,因为某种原因被误判为故障的原主库恢复正常,客户端连接原主库进行读写请求,而等到主从切换后,从库升级为新主库,哨兵会让原主库执行slave of命令与新主库重新进行全量同步,并清空本地的数据,因此,原主库在主从切换期间写入的数据就会丢失。

脑裂的规避方法:

脑裂丢失的数据是在主从切换期间写入的数据,如果限制原主库在该阶段接收请求,是不是就能避免呢。redis提供了两个配置项来限制主库的请求处理。min-slaves-to-write和min-slaves-max-lag,其中min-slaves-to-write表示主库能进行数据同步的最少从库数量,min-slaves-max-lag表示主从库进行数据复制时从库给主库发送ACK消息的最大延迟(单位为秒)。仅以设置min-slaves-to-write值为从库个数/2+1,min-slaves-max-lag设置为十几秒,此时,至少要有一半的从库和主库进行数据复制时的ACK消息延迟不能超过min-slaves-max-lag设置的值,否则就禁止原主库接收客户端的请求。


透心凉

在进行主从切换时,如果配置不合理,可能会导致无法切换或者集群服务挂掉,因此需要关注一些配置,如下:

protected-mode选项:该配置项的作用是限制哨兵实例是否能被其他服务器访问,当设置为yes时候,哨兵实例只能在部署的服务器本地访问,如果其他哨兵实例部署在其他服务器,则哨兵实例间无法通信以致与当主库故障时无法进行切换从而最终redis服务不可用。可以设置为no,同时设置bind配置项为其他哨兵实例的ip地址,既保证了集群实例间正常通信,又保证了哨兵的安全性,是不是一举两得呢。

cluster-node-timeout选项:在一主一从集群模式中,如果主实例异常,会触发主从切换,如果切换时间较长,超出cluster-node-timeout设置的值,就会导致实例心跳超时,被集群判定为异常。如果半数以上的实例心跳超时,就会导致整个集群挂掉。因此在实际生产环境中,建议将cluster-node-timeout值调整为十几秒左右。



自问自答

Q:
expire,pexpire,expireat,pexpireat?

expire,pexpire,expireat,pexpireat这四个命令可以分为两类。第一类,expire/pexpire,其中,expire将key的存活时间设置为ttl秒,命令为expire $key $ttl, pexpire将key的存活时间设置为ttl毫秒,命令为pexpire $key   $ttl。第二类,expireat/pexpireat,其中,expireat将key的存活时间设置为timestamp指定的秒数时间点,命令为expireat $key $timestamp。pexpireat将key的存活时间设置为timestamp指定的毫秒数时间点,命令为pexpireat $key $timestamp。

Q:
设置双min-slaves参数后,还会脑裂吗?

前面说过设置min-slaves-to-write和min-slaves-max-lag可以规避脑裂,但是能完全避免脑裂吗,实际答案是不能。如果在min-slaves-max-lag的时间内,原主库恢复正常,而此时主从切换还没完成,此时原主库不会被禁止接收请求,则客户端可以发送请求给原主库,当新主库上线后,主从切换期间写入原主库的数据便会丢失。

Q:
是否能在从库设置slave-read-only为no?

如果设置从库slave-read-only为no,会产生双写风险。例如客户端在主库设置了某个key的过期时间,然后在从库又对该key进行了过期时间设置,则会导致主从数据不一致。


结尾小结

本篇学习的内容是redis的主从同步中出现的一些容易踩到的坑及解决的方法,当然实际生产中遇到的问题可能远比书上学的要复杂的多,绝知此事要躬行。




END



扫码关注我
每天进步一点点,未来才可期,我们共同的目标是星辰大海。

赞一下你最美!







原文作者:DBA修行之路;如有侵权,请联系管理员删除。

下一篇: 重新认识redis(十)
请登录后发表评论 登录
全部评论

注册时间:2021-05-25

  • 博文量
    64
  • 访问量
    23943