クラスターとは何ですか? Redis でクラスターが必要な理由は何ですか?この記事では、Cluster クラスターについて詳しく説明し、Cluster クラスターがサポートできるデータの量について説明します。
この記事では、ノード、スロットの割り当て、コマンドの実行、再シャーディング、ステアリング、フェイルオーバー、メッセージなど、クラスターのさまざまな側面を詳しく分解します。 。 [関連する推奨事項: Redis ビデオ チュートリアル ]
目的は、クラスターとは何かをマスターすることです。クラスターのシャーディングの原則、クライアントの位置決めデータの原則、フェイルオーバー、マスターの選択、クラスターを使用するシナリオ、クラスターのデプロイ方法... [toc]
主に Redis RDB 永続化メカニズムが原因です。Redis は、RDB 永続化操作を完了するために子プロセスをフォークします。フォークの実行にかかる時間は、Redis データの量と正の関係があります。 Fork を実行するとメインスレッドがブロックされる データ量が多いため、メインスレッドが長時間ブロックされるため、Redis の応答が遅くなります。65 兄弟: マー兄弟、自動フェイルオーバーを実現するためにあなたが言及した Sentinel クラスターを使用したので、ついにこれが可能になりました。ガールフレンドと幸せに暮らしていますが、夜中に Redis がクラッシュする心配はありませんか?
しかし、最近厄介な問題に遭遇しました。Redis は 800 万のキーと値のペアを保存する必要があり、20 GB のメモリを占有します。 デプロイメントに 32G メモリ ホストを使用しましたが、Redis の応答が非常に遅い場合がありました。INFO コマンドを使用して、latest_fork_usec インジケーター (最新のフォークには時間がかかりました) を確認したところ、特に高いことがわかりました。
65 兄:事業規模の拡大に伴い、データ量はますます増大しています。マスター/スレーブアーキテクチャをアップグレードする場合、単一インスタンスのハードウェアを拡張することが難しく、大量のデータを保存すると応答が遅くなりますが、解決する方法はありますか?大量のデータを保存するには、大容量メモリ ホストの使用に加えて、スライス クラスターを使用することもできます。 「みんなで足したものは炎を明るくする」という言葉があるように、1 台のマシンではすべてのデータを保存することはできないため、複数のマシンでデータを共有する必要があります。
Redis Cluster クラスターを使用すると、主に大規模なデータ ストレージに起因するさまざまな速度低下の問題が解決され、水平方向の拡張も容易になります。
2 つのソリューションは、Redis データの増加に対する 2 つの拡張ソリューション、垂直拡張 (スケールアップ) と水平拡張 (スケールアウト) に対応します。
65 兄弟: これら 2 つのオプションの長所と短所は何ですか?
垂直拡張展開はシンプルですが、データ量が多く永続化のためにRDBを使用するとブロッキングやレスポンスの低下が発生します。さらに、ハードウェアとコストの制限により、1T メモリへの拡張など、メモリを拡張するコストが高すぎます。
3 つのノードは相互に接続されてピアツーピア クラスターを形成します。これらは Gossip
プロトコルを通じて相互にクラスター情報を交換します。最後に、各ノードは他のノードのスロット割り当てを保存します。
テクノロジーは万能ではないし、プログラマーが一番強いわけでもないことをしっかり理解し、「自分が世界一」などと考えないようにしましょう。この意識を持ってしまうと成長が遅れてしまう可能性があります。
テクノロジーは問題を解決するものであり、問題を解決できないテクノロジーには価値がありません。
自分のスキルを誇示しないと意味がありません。
クリック-> "Redis 6.X Cluster クラスターの構築"View
one Redis クラスターは通常、複数のノードで構成されます。最初は、各ノードは互いに独立しています。ノードは、自分自身だけを含むクラスター内にあります。真に機能するクラスターを構築するには、独立したノードが接続されて、複数のノードを含むクラスターを形成する必要があります。 。
各ノードの接続作業は、CLUSTER MEET
コマンド CLUSTER MEET <ip> <port></port></ip>
を使用して完了できます。
CLUSTER MEET
コマンドをノードnodeに送信して、ノードnodeがipおよびポートで指定されたノードとハンドシェイクできるようにします。ハンドシェイクが成功すると、ノードnodeはipを転送します。および ポートで指定されたノードは、そのノードが現在存在するクラスターに追加されます。
ノードノードが「IP = xx、ポート = xx の兄弟、「Code Byte」テクノロジー グループに参加しませんか? 参加してください。」と言っているようなものです。クラスターです。素晴らしい人間として成長する方法を見つけました。「Ma Ge Byte」公開アカウントをフォローして「グループに参加する」とリプライしてください。兄弟なら一緒に来てください! "
Redis Cluster クラスター構築の詳しい手順については、記事左下の「原文を読む」をクリックするか、-> をクリックしてください。 「Redis 6.X Cluster クラスターの構築を確認してください。。Redis クラスターの正式な詳細については、次を参照してください: redis.io/topics/clus…クラスターの実装原則
65 兄: データをスライスした後、データを別のインスタンスに分散する必要がありますが、データとインスタンスはどのように対応させるのですか?Redis 3.0 以降、データとインスタンスのルールを実装するスライシング クラスターを実装するための公式 Redis Cluster ソリューションが提供されます。 Redis Cluster ソリューションは、ハッシュ スロット (次では単にスロットと呼びます) を使用して、データとインスタンス間のマッピング関係を処理します。
「コード バイト」に従って、クラスター実装の原則を探求する旅に入ります...
データを複数のコピーに分割し、異なるインスタンスに保存します
キーとハッシュ スロット間のマッピング プロセスは、2 つの主要な手順に分けることができます。
ハッシュ スロットと Redis インスタンスのマッピング
65 兄弟: ハッシュ スロットは Redis インスタンスにどのようにマッピングされますか?cluster create を通じて作成された デプロイ クラスターの例 では、Redis は 16384 個のハッシュ スロットをクラスター インスタンス (N ノードなど) に自動的に均等に分散します。各ノードのハッシュ スロット = 16384 / N。
CLUSTER MEET コマンドを使用して、3 つのノード 7000、7001、および 7002 をクラスターに接続できます。ただし、3 つのインスタンスが No であるため、クラスターはまだオフラインです。ハッシュスロットが処理されます。
cluster addedslots コマンドを使用して、各インスタンスのハッシュ スロットの数を指定できます。
65 兄弟: なぜ手動で定式化する必要があるのですか?それができる人にとっては、さらに作業が必要です。クラスターに追加された Redis インスタンスの構成は異なります。同じ圧力に耐える場合、ガベージ マシンにとっては難しすぎます。強力なマシンはさらに多くのことをサポートします。 3 つのインスタンスからなるクラスターの場合、次の手順に従って各インスタンスにハッシュ スロットを割り当てます。
インスタンス 1 は 0 ~ 5460 のハッシュ スロットを担当し、
インスタンス 2 は5461 ~ 10922 のハッシュ スロットを担当し、
インスタンス 3 は 10923 ~ 16383 のハッシュ スロットを担当します。
redis-cli -h 172.16.19.1 –p 6379 cluster addslots 0,5460 redis-cli -h 172.16.19.2 –p 6379 cluster addslots 5461,10922 redis-cli -h 172.16.19.3 –p 6379 cluster addslots 10923,16383
すべての 16384 スロットが完全に割り当てられている場合、Redis クラスターは正常に動作できます。
レプリケーションとフェイルオーバー65 兄弟: Redis クラスターはどのようにして高可用性を実現するのですか?マスターとスレーブは読み書きで分離されたままですか?マスターはスロットの処理に使用され、スレーブ ノードは「
Redis マスター/スレーブ アーキテクチャ データ同期」メソッドを通じてマスター ノード データを同期します。
マスターがオフラインになっても、スレーブはマスター ノードに代わってリクエストを処理し続けます。マスター ノードとスレーブ ノードの間には読み取り/書き込みの分離はなく、スレーブはマスター障害の高可用性バックアップとしてのみ使用されます。 Redis クラスターは、マスター ノードごとに複数のスレーブ ノードをセットアップできます。単一のマスター ノードに障害が発生すると、クラスターはスレーブ ノードの 1 つをマスター ノードに自動的に昇格します。マスター ノードにスレーブ ノードがない場合、マスター ノードに障害が発生すると、クラスターは完全に使用できなくなります。 ただし、Redis には、部分的なノード障害を許可するパラメータ
cluster-require-full-coverage も用意されており、他のノードは外部アクセスを提供し続けることができます。 たとえば、マスターノード 7000 がダウンした場合、スレーブである 7003 がマスターノードとなり、サービスを提供し続けます。オフラインのノード 7000 がオンラインに戻ると、現在の 70003 のスレーブ ノードになります。
障害検出
65 兄: 「Redis 高可用性: Sentinel Cluster Principle」では、Sentinel がメイン データベースを自動的に切り替え、監視を通じて通知することを知っています。クライアントは自動フェイルオーバーを実装します。Cluster はどのように自動フェイルオーバーを実装しますか?
あるノードが接続されていないと考えているからといって、すべてのノードが接続されていないと考えているわけではありません。スロットの処理を担当するほとんどのノードがノードがオフラインであると判断した場合にのみ、クラスターはノードがマスター/スレーブ切り替えを実行する必要があるとみなします。
Redis クラスター ノードは、
Gossip プロトコルを使用して、自身のステータスとクラスター全体の知識の変更をブロードキャストします。たとえば、ノードが特定のノードの切断 (PFail) を検出すると、この情報がクラスター全体にブロードキャストされ、他のノードもこの切断された接続情報を受信できます。
プロトコルについては、Brother Wukong による記事を読むことができます:「ウイルス侵入、すべては配布に依存する
」If a Node特定のノードの切断数 (PFail Count) がクラスターの大部分に達した場合、そのノードはオフラインであることが確認されたもの (Fail) としてマークされ、クラスター全体にブロードキャストされ、他のノードにも強制的に受信させることができます。ノードのオフライン ステータスを確認し、失われたノードでマスター/スレーブの切り替えを直ちに実行します。
スレーブは、マスター ノードがオフライン状態に入ったことを検出すると、オフラインのマスター ノードへのフェイルオーバーを開始します。
オフライン マスター ノードおよびノード スレーブ ノード リストから新しいマスター ノードとなるノードを選択します。
新しいマスター ノードは、オフライン マスター ノードへのすべてのスロット割り当てを取り消し、これらのスロットを自分自身に割り当てます。
新しいマスター ノードは、クラスターに PONG メッセージをブロードキャストします。この PONG メッセージにより、クラスター内の他のノードは、このノードがスレーブ ノードからマスター ノードに変わったことをすぐに知ることができます。これにより、マスター ノードが、元々オフライン ノードによって処理されていたスロットを引き継ぎました。
新しいマスター ノードは、処理スロットに関連するコマンド リクエストの受信を開始し、フェイルオーバーが完了します。
65 兄弟: 新しいマスター ノードはどのように選出されるのですか?
クラスターの構成エポック 1 は、初期値が 0 のセルフタイマーカウンターであり、フェイルオーバーが実行されるたびに 1 に設定されます。
マスター ノードがオフラインであることを検出したスレーブ ノードは、CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST
メッセージをクラスターにブロードキャストし、このメッセージを受信し、投票権を持つすべてのマスター ノードに要求します。このスレーブ ノードは投票します。
このマスター ノードはまだ他のスレーブ ノードに投票していない場合、マスター ノードは投票を必要とするスレーブ ノードに CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK
メッセージを返します。マスターノードがスレーブノードをサポートし、新しいマスターノードになります。
選挙に参加しているすべてのスレーブ ノードは、CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK
メッセージを受け取ります。収集された投票が >= (N/2) 1 サポートの場合、スレーブ ノードは新しいマスターノードとして選択されます。
構成エポックで十分な支持票を収集できるスレーブ ノードがない場合、クラスターは新しい構成エポックに入り、新しいマスターが選出されるまでノードに対して選挙を再度実行します。
Sentinel と同様に、どちらも Raft アルゴリズムに基づいて実装されており、そのプロセスは図に示すとおりです。テーブル キーと値のペアとインスタンス間の関連付けを保存することは可能ですか?
65 兄弟、テストさせてください: 「Redis Cluster ソリューションは、ハッシュ スロットを通じてキーと値のペアをさまざまなインスタンスに割り当てます。このプロセスでは、キーと値のペアのキーに対する CRC 計算と、ハッシュ スロットの合計数のモジュロをインスタンスにマッピングする必要があります。テーブルを使用してキーと値のペアとインスタンスの間の対応関係を直接記録する場合 (たとえば、キーと値のペア 1 はインスタンス 2 にあります (キーと値のペア 2 はインスタンス 1 にあります)。そのため、キーとハッシュ スロットの対応関係を計算する必要はなく、テーブルを検索するだけです。 ?"
グローバル テーブル レコードが使用されている場合、キーと値のペアとインスタンスの関係が変化した場合 (再シャーディング、インスタンスの増減)、テーブルを変更する必要があります。シングルスレッド操作の場合、すべての操作をシリアル化する必要があり、パフォーマンスが非常に遅くなります。ハッシュ スロットの計算に関しては、ハッシュ スロットとインスタンス時間の関係を記録する必要がありますが、ハッシュ スロットの数ははるかに少なく、わずか 16384 であり、オーバーヘッドは非常に小さいです。 クライアントは、データが存在するインスタンスをどのように見つけますか?マルチスレッドではロックが必要になるため、また、キーと値のペアのデータ量が非常に多い場合、キーと値のペアとインスタンスの関係のテーブルデータを保存するために必要な記憶領域も必要になります。非常に大きい。
65 兄弟: クライアントは、アクセスされたデータがどのインスタンスに分散されているかをどのように判断しますか?
Redis インスタンスは、Gossip プロトコルを通じてクラスター内の他のインスタンスにハッシュ スロット情報を送信し、ハッシュ スロット割り当て情報の拡散を実現します。データをスライスするとき、キーは CRC16 を介して値として計算され、その後、対応するスロットを取得するために 16384 をモジュロします。この計算タスクは、リクエストの送信時にクライアントで実行できます。 ただし、スロットを見つけた後、そのスロットが配置されている Redis インスタンスをさらに見つける必要があります。 クライアントが任意のインスタンスに接続すると、インスタンスはハッシュ スロットとインスタンスの間のマッピング関係をクライアントに応答し、クライアントはハッシュ スロットとインスタンスのマッピング情報をローカルにキャッシュします。 クライアントがリクエストを行うと、キーに対応するハッシュ スロットが計算され、ローカル キャッシュ内のハッシュ スロット インスタンス マッピング情報を使用してデータが配置されているインスタンスが特定され、リクエストが行われます。対応するインスタンスに送信されます。このようにして、クラスター内の各インスタンスは、すべてのハッシュ スロットとインスタンスの間のマッピング関係情報を持ちます。
ハッシュ スロットの再配布
#65 兄弟: ハッシュ スロットとインスタンスの間のマッピング関係は、新しいインスタンスまたは負荷分散により再分散されます。 . 分布が変更された場合はどうすればよいですか?
集群中的实例通过 Gossip 协议互相传递消息获取最新的哈希槽分配信息,但是,客户端无法感知。
Redis Cluster 提供了重定向机制:客户端将请求发送到实例上,这个实例没有相应的数据,该 Redis 实例会告诉客户端将请求发送到其他的实例上。
65 哥:Redis 如何告知客户端重定向访问新实例呢?
分为两种情况:MOVED 错误、ASK 错误。
MOVED 错误(负载均衡,数据已经迁移到其他实例上):当客户端将一个键值对操作请求发送给某个实例,而这个键所在的槽并非由自己负责的时候,该实例会返回一个 MOVED 错误指引转向正在负责该槽的节点。
GET 公众号:码哥字节 (error) MOVED 16330 172.17.18.2:6379
该响应表示客户端请求的键值对所在的哈希槽 16330 迁移到了 172.17.18.2 这个实例上,端口是 6379。这样客户端就与 172.17.18.2:6379 建立连接,并发送 GET 请求。
同时,客户端还会更新本地缓存,将该 slot 与 Redis 实例对应关系更新正确。
65 哥:如果某个 slot 的数据比较多,部分迁移到新实例,还有一部分没有迁移咋办?
如果请求的 key 在当前节点找到就直接执行命令,否则时候就需要 ASK 错误响应了,槽部分迁移未完成的情况下,如果需要访问的 key 所在 Slot 正在从从 实例 1 迁移到 实例 2,实例 1 会返回客户端一条 ASK 报错信息:客户端请求的 key 所在的哈希槽正在迁移到实例 2 上,你先给实例 2 发送一个 ASKING 命令,接着发发送操作命令。
GET 公众号:码哥字节 (error) ASK 16330 172.17.18.2:6379
比如客户端请求定位到 key = 「公众号:码哥字节」的槽 16330 在实例 172.17.18.1 上,节点 1 如果找得到就直接执行命令,否则响应 ASK 错误信息,并指引客户端转向正在迁移的目标节点 172.17.18.2。
注意:ASK 错误指令并不会更新客户端缓存的哈希槽分配信息。
所以客户端再次请求 Slot 16330 的数据,还是会先给 172.17.18.1
实例发送请求,只不过节点会响应 ASK 命令让客户端给新实例发送一次请求。
MOVED
指令则更新客户端本地缓存,让后续指令都发往新实例。
65 哥:有了 Redis Cluster,再也不怕大数据量了,我可以无限水平拓展么?
答案是否定的,Redis 官方给的 Redis Cluster 的规模上线是 1000 个实例。
65 哥:到底是什么限制了集群规模呢?
关键在于实例间的通信开销,Cluster 集群中的每个实例都保存所有哈希槽与实例对应关系信息(Slot 映射到节点的表),以及自身的状态信息。
在集群之间每个实例通过 Gossip
协议传播节点的数据,Gossip
协议工作原理大概如下:
PING
消息发送给挑选出来的实例,用于检测实例状态以及交换彼此的信息。 PING
消息中封装了发送者自身的状态信息、部分其他实例的状态信息、Slot 与实例映射表信息。PING
消息后,响应 PONG
消息,消息包含的信息跟 PING
消息一样。集群之间通过 Gossip
协议可以在一段时间之后每个实例都能获取其他所有实例的状态信息。
所以在有新节点加入,节点故障,Slot 映射变更都可以通过 PING
,PONG
的消息传播完成集群状态在每个实例的传播同步。
发送的消息结构是 clusterMsgDataGossip
结构体组成:
typedef struct { char nodename[CLUSTER_NAMELEN]; //40字节 uint32_t ping_sent; //4字节 uint32_t pong_received; //4字节 char ip[NET_IP_STR_LEN]; //46字节 uint16_t port; //2字节 uint16_t cport; //2字节 uint16_t flags; //2字节 uint32_t notused1; //4字节 } clusterMsgDataGossip;
所以每个实例发送一个 Gossip
消息,就需要发送 104 字节。如果集群是 1000 个实例,那么每个实例发送一个 PING
消息则会占用 大约 10KB。
除此之外,实例间在传播 Slot 映射表的时候,每个消息还包含了 一个长度为 16384 bit 的 Bitmap
。
各ビットはスロットに対応します。値 = 1 の場合、このスロットは現在のインスタンスに属していることを意味します。このビットマップは 2KB を占有するため、PING
メッセージは約 12KB になります。
PONG
は PING
メッセージと同じで、送受信される 2 つのメッセージの合計は 24 KB です。クラスターのサイズが大きくなるにつれて、クラスターのネットワーク通信帯域幅を占有するハートビート メッセージが増え、クラスターのスループットが低下します。
65 兄: マー兄、PING メッセージの送信頻度もクラスターの帯域幅に影響しますよね。
Redis クラスター インスタンスが開始されると、デフォルトでローカル インスタンス リストから 5 つのインスタンスが毎秒ランダムに選択され、5 つのインスタンスのうち PING メッセージを受信していないインスタンスが 1 つ検出されます。インスタンスに PING メッセージを送信します。
65 兄弟: ランダムに 5 を選択しますが、選択されたインスタンスがクラスター全体で最も長い間 PING 通信を受信していないインスタンスであるという保証はありません。一部のインスタンスは、というメッセージが表示され、クラスターが維持されます。情報の有効期限がかなり前に切れています。どうすればよいですか?
これは良い質問です。Redis Cluster インスタンスは 100 ミリ秒ごとにローカル インスタンス リストをスキャンします。インスタンスが見つかると、最後に PONG
メッセージを受信した時間が表示されます。 クラスターノードタイムアウト/2
。その後、すぐに PING
メッセージをこのインスタンスに送信して、このノードのクラスター ステータス情報を更新します。
クラスターのサイズが増加すると、インスタンス間のネットワーク通信の遅延がさらに増加します。より多くの PING メッセージが頻繁に送信される可能性があります。
PING
メッセージを毎秒送信します。この頻度を減らすと、各インスタンスのステータス情報が失われる可能性があります。クラスターは時間内に拡散できません。 PONG
メッセージ受信が cluster-node-timeout / 2
を超えているかどうか、これが Redis インスタンスのデフォルトの定期検出タスク頻度です簡単に変更されることはありません。 したがって、変更できるのは cluster-node-timeout
の値のみです。インスタンスに障害があるかどうかを判断するためのクラスター内のハートビート時間です。デフォルトは 15 秒です。
したがって、クラスター帯域幅を占有するハートビート メッセージが多すぎるのを避けるために、cluster-node-timeout
を 20 秒または 30 秒に調整します。したがって、PONG
メッセージ受信タイムアウトの状況が緩和されます。
ただし、あまり大きく設定することはできません。そうしないと、インスタンスは失敗しますが、cluster-node-timeout
がこの失敗を検出するまで待つ必要があり、クラスターの通常のサービスに影響します。
プログラミング関連の知識について詳しくは、
プログラミング ビデオ以上がクラスターとは何ですか? Redis でクラスターが必要な理由は何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。