redis高级-day6——python操作哨兵python操作集群缓存优化

Posted zhihuanzzh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了redis高级-day6——python操作哨兵python操作集群缓存优化相关的知识,希望对你有一定的参考价值。


一 、python操作哨兵

# 高可用架构后---》不能直接连某一个主库了---》主库可能会挂掉,后来它就不是主库了
# 之前学的连接redis的操作,就用不了了
import redis
conn=redis.Redis(host=\'\',port=6379)
conn.set()
conn.close()

# 新的连接哨兵的操作
# 连接哨兵服务器(主机名也可以用域名)
# 10.0.0.101:26379
import redis
from redis.sentinel import Sentinel
# 哨兵的地址和端口
sentinel = Sentinel([(\'10.0.0.101\', 26379),
                     (\'10.0.0.101\', 26378),
                     (\'10.0.0.101\', 26377)
         ],socket_timeout=5)

print(sentinel)
# 获取主服务器地址
master = sentinel.discover_master(\'mymaster\')
print(master)

# 获取从服务器地址
slave = sentinel.discover_slaves(\'mymaster\')
print(slave)



##### 读写分离
# 获取主服务器进行写入
# master = sentinel.master_for(\'mymaster\', socket_timeout=0.5)
# w_ret = master.set(\'foo\', \'bar\')

# slave = sentinel.slave_for(\'mymaster\', socket_timeout=0.5)
# r_ret = slave.get(\'foo\')
# print(r_ret)




###注意:要写机器的ip地址,不要写127.0.0.1,想在公网用,就写公网ip,python要是在内网中使用,要写内网ip

二、python操作集群

# 一旦搭建了集群,python操作也变了
# rediscluster
# pip3 install redis-py-cluster
from rediscluster import RedisCluster
startup_nodes = ["host":"127.0.0.1", "port": "7000","host":"127.0.0.1", "port": "7001","host":"127.0.0.1", "port": "7002"]
# rc = RedisCluster(startup_nodes=startup_nodes,decode_responses=True)
rc = RedisCluster(startup_nodes=startup_nodes)
rc.set("foo", "bar")
print(rc.get("foo"))

三、缓存优化

3.1 redis缓存更新策略

# redis本身,内存存储,会出现内存不够用,放数据放不进去,有些策略,删除一部分数据,再放新的

# LRU/LFU/FIFO算法剔除:例如maxmemory-policy(到了最大内存,对应的应对策略)

LRU -Least Recently Used,没有被使用时间最长的
LFU -Least Frequenty Used,一定时间段内使用次数最少的
FIFO -First In First Out  先进先出

3.2 缓存击穿,雪崩,穿透

###  缓存穿透
#描述:
缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。
#解决方案:
1 接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
2 从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击
3 通过布隆过滤器实现


### 缓存击穿
#描述:
缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力
#解决方案:
设置热点数据永远不过期。

 
### 缓存雪崩
#描述:
缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。和缓存击穿不同的是,        缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
# 解决方案:
1 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
2 如果缓存数据库是分布式部署,将热点数据均匀分布在不同搞得缓存数据库中。
3 设置热点数据永远不过期。


Day734.哨兵集群:哨兵挂了,主从库还能切换吗?-Redis 核心技术与实战

哨兵集群:哨兵挂了,主从库还能切换吗?

Hi,我是阿昌,今天学习记录的是关于哨兵集群:哨兵挂了,主从库还能切换吗?

哨兵机制,它可以实现主从库的自动切换。

通过部署多个实例,就形成了一个哨兵集群。哨兵集群中的多个实例共同判断,可以降低对主库下线的误判率

但是,还是要考虑一个问题:

如果有哨兵实例在运行时发生了故障,主从库还能正常切换吗?

实际上,一旦多个实例组成了哨兵集群,即使有哨兵实例出现故障挂掉了,其他哨兵还能继续协作完成主从库切换的工作,包括判定主库是不是处于下线状态,选择新主库,以及通知从库和客户端。

如果你部署过哨兵集群的话就会知道,在配置哨兵的信息时,只需要用到下面的这个配置项,设置主库的 IP 和端口,并没有配置其他哨兵的连接信息。

sentinel monitor <master-name> <ip> <redis-port> <quorum> 

这些哨兵实例既然都不知道彼此的地址,又是怎么组成集群的呢?

一、基于 pub/sub 机制的哨兵集群组成

哨兵实例之间可以相互发现,要归功于 Redis 提供的 pub/sub 机制,也就是发布 / 订阅机制

哨兵只要和主库建立起了连接,就可以在主库上发布消息了,比如说发布它自己的连接信息(IP 和端口)。

同时,它也可以从主库上订阅消息,获得其他哨兵发布的连接信息。

当多个哨兵实例都在主库上做了发布和订阅操作后,它们之间就能知道彼此的 IP 地址和端口。除了哨兵实例,我们自己编写的应用程序也可以通过 Redis 进行消息的发布和订阅。

所以,为了区分不同应用的消息,Redis 会以频道的形式,对这些消息进行分门别类的管理。

所谓的频道,实际上就是消息的类别。当消息类别相同时,它们就属于同一个频道。

反之,就属于不同的频道。

只有订阅了同一个频道的应用,才能通过发布的消息进行信息交换。

在主从集群中,主库上有一个名为“_ sentinel _:hello”的频道,不同哨兵就是通过它来相互发现,实现互相通信的。

举个例子,具体说明一下:

在下图中,哨兵 1 把自己的 IP(172.16.19.3)和端口(26579)发布到“_ sentinel _:hello”频道上,哨兵 2 和 3 订阅了该频道。

那么此时,哨兵 2 和 3 就可以从这个频道直接获取哨兵 1 的 IP 地址和端口号。

然后,哨兵 2、3 可以和哨兵 1 建立网络连接。通过这个方式,哨兵 2 和 3 也可以建立网络连接,这样一来,哨兵集群就形成了。

它们相互间可以通过网络连接进行通信,比如说对主库有没有下线这件事儿进行判断和协商。

哨兵除了彼此之间建立起连接形成集群外,还需要和从库建立连接。

这是因为,在哨兵的监控任务中,它需要对主从库都进行心跳判断,而且在主从库切换完成后,它还需要通知从库,让它们和新主库进行同步。

那么,哨兵是如何知道从库的 IP 地址和端口的呢?这是由哨兵向主库发送 INFO 命令来完成的。

就像下图所示,哨兵 2 给主库发送 INFO 命令,主库接受到这个命令后,就会把从库列表返回给哨兵。

接着,哨兵就可以根据从库列表中的连接信息,和每个从库建立连接,并在这个连接上持续地对从库进行监控。

哨兵 1 和 3 可以通过相同的方法和从库建立连接。

通过 pub/sub 机制哨兵之间可以组成集群,同时,哨兵又通过 INFO 命令,获得了从库连接信息,也能和从库建立连接,并进行监控了。

但是,哨兵不能只和主、从库连接。

因为,主从库切换后,客户端也需要知道新主库的连接信息,才能向新主库发送请求操作。

所以,哨兵还需要完成把新主库的信息告诉客户端这个任务

而且,在实际使用哨兵时,有时会遇到这样的问题:

如何在客户端通过监控了解哨兵进行主从切换的过程呢?

比如说,主从切换进行到哪一步了?

这其实就是要求,客户端能够获取到哨兵集群在监控、选主、切换这个过程中发生的各种事件。

此时,仍然可以依赖 pub/sub 机制,来帮完成哨兵和客户端间的信息同步

二、基于 pub/sub 机制的客户端事件通知

从本质上说,哨兵就是一个运行在特定模式下的 Redis 实例,只不过它并不服务请求操作,只是完成监控、选主和通知的任务。

所以,每个哨兵实例也提供 pub/sub 机制,客户端可以从哨兵订阅消息。

哨兵提供的消息订阅频道有很多,不同频道包含了主从库切换过程中的不同关键事件。

频道有这么多,一下子全部学习容易丢失重点。

把重要的频道汇总在了一起,涉及几个关键事件,包括主库下线判断、新主库选定、从库重新配置。

知道了这些频道之后,就可以让客户端从哨兵这里订阅消息了。

具体的操作步骤是,客户端读取哨兵的配置文件后,可以获得哨兵的地址和端口,和哨兵建立网络连接。

然后,可以在客户端执行订阅命令,来获取不同的事件消息。

举个例子,可以执行如下命令,来订阅“所有实例进入客观下线状态的事件”:

SUBSCRIBE +odown

当然,也可以执行如下命令,订阅所有的事件:

PSUBSCRIBE  *

当哨兵把新主库选择出来后,客户端就会看到下面的 switch-master 事件。

这个事件表示主库已经切换了,新主库的 IP 地址和端口信息已经有了。

这个时候,客户端就可以用这里面的新主库地址和端口进行通信了。

switch-master <master name> <oldip> <oldport> <newip> <newport>

有了这些事件通知,客户端不仅可以在主从切换后得到新主库的连接信息,还可以监控到主从库切换过程中发生的各个重要事件。

这样,客户端就可以知道主从切换进行到哪一步了,有助于了解切换进度。

好了,有了 pub/sub 机制,哨兵和哨兵之间、哨兵和从库之间、哨兵和客户端之间就都能建立起连接了,再加上介绍主库下线判断和选主依据,哨兵集群的监控、选主和通知三个任务就基本可以正常工作了。

不过,还需要考虑一个问题:主库故障以后,哨兵集群有多个实例,那怎么确定由哪个哨兵来进行实际的主从切换呢?

三、由哪个哨兵执行主从切换?

确定由哪个哨兵执行主从切换的过程,和主库“客观下线”的判断过程类似,也是一个“投票仲裁”的过程。

在具体了解这个过程前,我们再来看下,判断“客观下线”的仲裁过程。哨兵集群要判定主库“客观下线”,需要有一定数量的实例都认为该主库已经“主观下线”了。

在判断“客观下线”的原则,任何一个实例只要自身判断主库“主观下线”后,就会给其他实例发送is-master-down-by-addr命令。

接着,其他实例会根据自己和主库的连接情况,做出 Y 或 N 的响应,Y 相当于赞成票,N 相当于反对票。


一个哨兵获得了仲裁所需的赞成票数后,就可以标记主库为“客观下线”。

这个所需的赞成票数是通过哨兵配置文件中的 quorum 配置项设定的。例如,现在有 5 个哨兵,quorum 配置的是 3,那么,一个哨兵需要 3 张赞成票,就可以标记主库为“客观下线”了。

这 3 张赞成票包括哨兵自己的一张赞成票和另外两个哨兵的赞成票。此时,这个哨兵就可以再给其他哨兵发送命令,表明希望由自己来执行主从切换,并让所有其他哨兵进行投票。这个投票过程称为“Leader 选举”。

因为最终执行主从切换的哨兵称为 Leader,投票过程就是确定 Leader。

在投票过程中,任何一个想成为 Leader 的哨兵,要满足两个条件:

  • 第一,拿到半数以上的赞成票
  • 第二,拿到的票数同时还需要大于等于哨兵配置文件中的 quorum 值

以 3 个哨兵为例,假设此时的 quorum 设置为 2,那么,任何一个想成为 Leader 的哨兵只要拿到 2 张赞成票,就可以了。

一张图片,展示一下 3 个哨兵、quorum 为 2 的选举过程。

T1 时刻,S1 判断主库为“客观下线”,它想成为 Leader,就先给自己投一张赞成票,然后分别向 S2 和 S3 发送命令,表示要成为 Leader。

T2 时刻,S3 判断主库为“客观下线”,它也想成为 Leader,所以也先给自己投一张赞成票,再分别向 S1 和 S2 发送命令,表示要成为 Leader。

T3 时刻,S1 收到了 S3 的 Leader 投票请求。因为 S1 已经给自己投了一票 Y,所以它不能再给其他哨兵投赞成票了,所以 S1 回复 N 表示不同意。

同时,S2 收到了 T2 时 S3 发送的 Leader 投票请求。

因为 S2 之前没有投过票,它会给第一个向它发送投票请求的哨兵回复 Y,给后续再发送投票请求的哨兵回复 N,所以,在 T3 时,S2 回复 S3,同意 S3 成为 Leader。

T4 时刻,S2 才收到 T1 时 S1 发送的投票命令。

因为 S2 已经在 T3 时同意了 S3 的投票请求,此时,S2 给 S1 回复 N,表示不同意 S1 成为 Leader。

发生这种情况,是因为 S3 和 S2 之间的网络传输正常,而 S1 和 S2 之间的网络传输可能正好拥塞了,导致投票请求传输慢了。

T5 时刻,S1 得到的票数是来自它自己的一票 Y 和来自 S2 的一票 N。而 S3 除了自己的赞成票 Y 以外,还收到了来自 S2 的一票 Y。

此时,S3 不仅获得了半数以上的 Leader 赞成票,也达到预设的 quorum 值(quorum 为 2),所以它最终成为了 Leader。

接着,S3 会开始执行选主操作,而且在选定新主库后,会给其他从库和客户端通知新主库的信息。

如果 S3 没有拿到 2 票 Y,那么这轮投票就不会产生 Leader。

哨兵集群会等待一段时间(也就是哨兵故障转移超时时间的 2 倍),再重新选举。这是因为,哨兵集群能够进行成功投票,很大程度上依赖于选举命令的正常网络传播。如果网络压力较大或有短时堵塞,就可能导致没有一个哨兵能拿到半数以上的赞成票。所以,等到网络拥塞好转之后,再进行投票选举,成功的概率就会增加。需要注意的是,如果哨兵集群只有 2 个实例,此时,一个哨兵要想成为 Leader,必须获得 2 票,而不是 1 票。所以,如果有个哨兵挂掉了,那么,此时的集群是无法进行主从库切换的。因此,通常我们至少会配置 3 个哨兵实例。这一点很重要,你在实际应用时可不能忽略了。

四、总结

通常,在解决一个系统问题的时候,会引入一个新机制,或者设计一层新功能,为了实现主从切换,引入了哨兵;为了避免单个哨兵故障后无法进行主从切换,以及为了减少误判率,又引入了哨兵集群;

哨兵集群又需要有一些机制来支撑它的正常运行。

支持哨兵集群的这些关键机制,包括:

  • 基于 pub/sub 机制的哨兵集群组成过程;
  • 基于 INFO 命令的从库列表,这可以帮助哨兵和从库建立连接;
  • 基于哨兵自身的 pub/sub 功能,这实现了客户端和哨兵之间的事件通知

对于主从切换,当然不是哪个哨兵想执行就可以执行的,否则就乱套了。

所以,这就需要哨兵集群在判断了主库“客观下线”后,经过投票仲裁选举一个 Leader 出来,由它负责实际的主从切换,即由它来完成新主库的选择以及通知从库与客户端。

分享一个经验:要保证所有哨兵实例的配置是一致的,尤其是主观下线的判断值 down-after-milliseconds

一个“坑”。当时,在项目中,因为这个值在不同的哨兵实例上配置不一致,导致哨兵集群一直没有对有故障的主库形成共识,也就没有及时切换主库,最终的结果就是集群服务不稳定


Redis 1主4从,5个哨兵,哨兵配置quorum为2,如果3个哨兵故障,当主库宕机时,哨兵能否判断主库“客观下线”?能否自动切换?

1、哨兵集群可以判定主库“主观下线”。由于quorum=2,所以当一个哨兵判断主库“主观下线”后,询问另外一个哨兵后也会得到同样的结果,2个哨兵都判定“主观下线”,达到了quorum的值,因此,哨兵集群可以判定主库为“客观下线”
2、但哨兵不能完成主从切换。哨兵标记主库“客观下线后”,在选举“哨兵领导者”时,一个哨兵必须拿到超过多数的选票(5/2+1=3票)。但目前只有2个哨兵活着,无论怎么投票,一个哨兵最多只能拿到2票,永远无法达到多数选票的结果。
但是投票选举过程的细节并不是大家认为的:每个哨兵各自1票,这个情况是不一定的。
下面具体说一下:
场景a:哨兵A先判定主库“主观下线”,然后马上询问哨兵B(注意,此时哨兵B只是被动接受询问,并没有去询问哨兵A,也就是它还没有进入判定“客观下线”的流程),哨兵B回复主库已“主观下线”,达到quorum=2后哨兵A此时可以判定主库“客观下线”。此时,哨兵A马上可以向其他哨兵发起成为“哨兵领导者”的投票,哨兵B收到投票请求后,由于自己还没有询问哨兵A进入判定“客观下线”的流程,所以哨兵B是可以给哨兵A投票确认的,这样哨兵A就已经拿到2票了。等稍后哨兵B也判定“主观下线”后想成为领导者时,因为它已经给别人投过票了,所以这一轮自己就不能再成为领导者了。
场景b:哨兵A和哨兵B同时判定主库“主观下线”,然后同时询问对方后都得到可以“客观下线”的结论,此时它们各自给自己投上1票后,然后向其他哨兵发起投票请求,但是因为各自都给自己投过票了,因此各自都拒绝了对方的投票请求,这样2个哨兵各自持有1票。
场景a是1个哨兵拿到2票,场景b是2个哨兵各自有1票,这2种情况都不满足大多数选票(3票)的结果,因此无法完成主从切换。
经过测试发现,场景b发生的概率非常小,只有2个哨兵同时进入判定“主观下线”的流程时才可以发生。我测试几次后发现,都是复现的场景a。
哨兵实例是不是越多越好?
并不是,我们也看到了,哨兵在判定“主观下线”和选举“哨兵领导者”时,都需要和其他节点进行通信,交换信息,哨兵实例越多,通信的次数也就越多,而且部署多个哨兵时,会分布在不同机器上,节点越多带来的机器故障风险也会越大,这些问题都会影响到哨兵的通信和选举,出问题时也就意味着选举时间会变长,切换主从的时间变久。
调大down-after-milliseconds值,对减少误判是不是有好处?
是有好处的,适当调大down-after-milliseconds值,当哨兵与主库之间网络存在短时波动时,可以降低误判的概率。但是调大down-after-milliseconds值也意味着主从切换的时间会变长,对业务的影响时间越久,需要根据实际场景进行权衡,设置合理的阈值。


以上是关于redis高级-day6——python操作哨兵python操作集群缓存优化的主要内容,如果未能解决你的问题,请参考以下文章

Redis高级(持久化--redis主从架构--redis哨兵模式--redis分片集群)

高级开发运维从简单学:Redis哨兵和集群小贴士

高级开发运维从简单学:Redis哨兵和集群小贴士

redis--高级命令主从复制安全性哨兵

day6-Python学习笔记(十三)redis数据库

分布式缓存技术redis学习系列——redis高级应用(集群搭建集群分区原理集群操作)