12シリーズ] Redisのクラスタ方式1-センチネル

オリジナル: 12 [シリーズ] Redisのクラスタ・スキームの1-センチネル

現在、私たちはRedisのマスター・スレーブ方式で、結果整合性について話しています。読者は、プライマリノード場合の対処方法ダウン午前3時バーストを熟考することができますか?等の運用・保守、ベッドから座って、その後、手動でプライマリからの切り替え、その後、バックラインに再びそれをプログラムアドレスのすべてのすべての変更を通知?間違いなく、次元の効率が低すぎるような人の労働運動、事故がHuanguoライに発生したときに、少なくとも1時間であることを推定しました。それは大企業、ニュース、十分にそのような事故の場合。

我々は、ノード障害に抵抗する高可用性ソリューションを持っている必要があり、障害が発生したときに自動的にプライマリから切り替えることができるので、プログラムは何事もなかったかのように操作とメンテナンスが、スリープ状態に続けることができ、再起動することはできません。Redisのセンチネル(センチネル) - Redisの関係者は、このようなA方式を提供します。

image.png

我々クラスタとしてRedisのセンチネルのZooKeeperクラスタをすることができ、それは心の高可用性クラスタである、それは一般的にも正常に動作することができますので、クラスタ内の個々のノードにリンクされ、3〜5つのノードで構成されています。

プライマリノードが自動的にハングアップマスターノードから最適なスイッチングノードを選択した場合には、マスタノードからの健康の継続的な監視を担当しています。クライアントは、マスターノードアドレスを照会することにより、クラスタ、最初の接続センチネル、センチネルに接続し、メインのノードがデータを交換接続するために行くとき。プライマリノードに障害が発生した場合、クライアントは、センチネルノードがクライアントに最新のメジャーアドレスになり、センチネル再アドレスになるでしょう。だから、自動的にスイッチ・ノードにアプリケーションを再起動する必要はありません。上の図ハングのマスターノードの後、等、クラスタは自動的に図1に示す構造に調節することができます。

image.png

この図から、我々は、メインのノードがハング見ることができ、また、オリジナルのマスターからコピーは、クライアントを切断し、損傷の主ノードも切断されます。ノードから新しい主ノード、最初に昇格し、他の新しいマスター・ノードのレプリケーション関係がノードから確立されています。クライアントは、新しいプライマリノードを介して相互作用し続けています。Sentinelは、それが回復するまで、クラスタは以下の映像に調整します、マスターノードがハングアップされた監視を続けます。

image.png

このとき、元のマスターノードは、現在スレーブノードになってハングアップ、マスターノードのレプリケーション関係が新しいからが確立されています。

消息丢失
Redis 主从采用异步复制,意味着当主节点挂掉时,从节点可能没有收到全部的同步消息,这部分未同步的消息就丢失了。如果主从延迟特别大,那么丢失的数据就可能会特别多。Sentinel 无法保证消息完全不丢失,但是也尽可能保证消息少丢失。它有两个选项可以限制主从延迟过大。

min-slaves-to-write 1
min-slaves-max-lag 10
第一个参数表示主节点必须至少有一个从节点在进行正常复制,否则就停止对外写服务,丧失可用性。

何为正常复制,何为异常复制?这个就是由第二个参数控制的,它的单位是秒,表示如果 10s 没有收到从节点的反馈,就意味着从节点同步不正常,要么网络断开了,要么一直没有给反馈。

Sentinel 基本使用
接下来我们看看客户端如何使用 sentinel,标准的流程应该是客户端可以通过 sentinel 发现主从节点的地址,然后在通过这些地址建立相应的连接来进行数据存取操作。我们来看看 Python 客户端是如何做的。

>>> from redis.sentinel import Sentinel
>>>sentinel = Sentinel([('localhost', 26379)], socket_timeout=0.1)
>>>sentinel.discover_master('mymaster')
('127.0.0.1', 6379)
>>> sentinel.discover_slaves('mymaster')
[('127.0.0.1', 6380)]

sentinel 的默认端口是 26379,不同于 Redis 的默认端口 6379,通过 sentinel 对象的 discover_xxx 方法可以发现主从地址,主地址只有一个,从地址可以有多个。

>>> master = sentinel.master_for('mymaster', socket_timeout=0.1)
>>> slave = sentinel.slave_for('mymaster', socket_timeout=0.1)
>>> master.set('foo', 'bar')
>>> slave.get('foo')
'bar'

通过 xxx_for 方法可以从连接池中拿出一个连接来使用,因为从地址有多个,redis 客户端对从地址采用轮询方案,也就是 RoundRobin 轮着来。

有个问题是,但 sentinel 进行主从切换时,客户端如何知道地址变更了 ? 通过分析源码,我发现 redis-py 在建立连接的时候进行了主库地址变更判断。

连接池建立新连接时,会去查询主库地址,然后跟内存中的主库地址进行比对,如果变更了,就断开所有连接,重新使用新地址建立新连接。如果是旧的主库挂掉了,那么所有正在使用的连接都会被关闭,然后在重连时就会用上新地址。

但是这样还不够,如果是 sentinel 主动进行主从切换,主库并没有挂掉,而之前的主库连接已经建立了在使用了,没有新连接需要建立,那这个连接是不是一致切换不了?

继续深入研究源码,我发现 redis-py 在另外一个点也做了控制。那就是在处理命令的时候捕获了一个特殊的异常ReadOnlyError,在这个异常里将所有的旧连接全部关闭了,后续指令就会进行重连。

主从切换后,之前的主库被降级到从库,所有的修改性的指令都会抛出ReadonlyError。如果没有修改性指令,虽然连接不会得到切换,但是数据不会被破坏,所以即使不切换也没关系。

おすすめ

転載: www.cnblogs.com/lonelyxmas/p/12515054.html