Redis設計と実装:プライマリ・スレーブ・レプリケーション

10825 ワード

目次:


1.マスターコピーとは何ですか.どんな用途がありますか.2.主従レプリケーションの環境はどのように構築されますか?3.主従レプリケーションの機能はどのように実現しますか?4.完全なプライマリ・スレーブ・レプリケーション・プロセス?

参考内容:


「Reis設計と実装」第3部第15章Redis公式ドキュメントをコピーする:https://redis.io/topics/replication

1.マスターコピーとは何ですか。どんな用途がありますか。


コンセプト:


プライマリ・スレーブ・レプリケーションとは、Redisで構成することによって、あるサーバに別のサーバのデータをレプリケーションさせ、両者に同じデータ内容を保存させ、「データベースの状態が一致する」という効果を達成することです.

用途:


(1)主従レプリケーションにより、1つの主ノードに複数の従ノードがあり、主ノードは書き込み可能で読み取り可能であり、ノードから読み取り可能であり、読み取り操作をノードから転送し、主ノードのアクセス負荷を低減することができる.(2)プライマリノードが意図的にオフになっている場合(ハードウェア障害によってデータが復旧できない場合など)、ノードからのデータバックアップはデータ損失を回避することができる.

欠点:


自動フェイルオーバはサポートされていないため、高可用性を提供できません.プライマリノードが停止すると、サーバは書き込みサービスを外部に提供することができず、実際の生産環境ではサービスは一刻も停止できないため、一般的な生産環境ではプライマリ・スレーブ・モードだけでなく、その上に1層の哨兵モードまたはクラスタ・モード(high availability features provided as an additional layer by Redis Cluster or Redis Sentine)をカプセル化することはできない.

2.主従レプリケーションの環境はどのように構築されますか?


2つの方法:

方法1:プロファイルを変更してスレーブを起動する

redis.confプロファイルの変更:
redis.conf ---> slaveof 127.0.0.1:8001

次にサーバを起動します.
127.0.0.1:8002>./redis-server redis.conf

127.0.0.1:8002を127.0.1:8001のスレーブにする.

方法2:運転中のスレーブにslabeofコマンドを入力する

127.0.0.1:8002> SLAVEOF 127.0.0.1:8001
// SLAVEOF :
SLAVEOFコマンドを入力すると、スレーブ上のデータは上書きされます(元のデータはクリアされ、データはホストと同期します).

主従関係の表示:


接続サーバのクライアントにINFOコマンドを入力します.
ホスト:
127.0.0.1:8001> INFO REPLICATION
#Replication
role:master
connected slaves:1
slave0:ip=127.0.0.1,port=8002,state=online, offset=224,lag=1

スレーブ:
127.0.0.1:8002> INFO REPLICATION
#Replication
role:slave
master _host:127.0.0.1
naster_ port:8001
master_link_status:up
master_last_io_seconds_ ago:2
slave_priority:100
slave_read_only:1
connected slaves:0

主従関係を切断する方法:


スレーブにコマンドを入力します.
127.0.0.1:8002> SLAVEOF NO ONE

3.主従レプリケーションの機能はどのように実現しますか?


Redisのプライマリ・スレーブ・レプリケーション機能は、同期(sync)とコマンド伝播(command propagate)の2つの操作によって実現されます.
(1)プライマリスレーブノードが初めて接続を確立した場合、または接続が切断された後に再接続された場合、「同期」の操作によってプライマリスレーブレプリケーションを完了する.
(2)マスタスレーブノード間が正常に接続されている場合、「コマンド伝播」の操作によりマスタスレーブレプリケーションが完了する.
注意:
       “  " "    "   epoll  ET LT  :
	“  "   “    ”:          ,        ,             ;
	“    "   “     ”:          ,               ,                  。

3.1「同期」:


サーバからプライマリサーバにPSYNCコマンドを送信して同期操作を実行します.

PSYNCコマンドの実装:


①サーバから送信されるPSYNCコマンドには、2つの形式があります。


1つ目:
PSYNC ? -1

サーバから以前にサーバがコピーされていない場合、またはSLAVEOF no oneコマンドが実行されている場合は、この時点で部分的な再同期は実行できないことを示します.PSYNC呼び出しのフォーマットは上記の通りです(完全な再同期を要求します).
2つ目:
PSYNC  

サーバから以前にマスターサーバがコピーされていた場合、新しいコピーが開始されたときのPSYNC呼び出しフォーマットは、上述の通りであり、は、前回コピーされたマスターサーバの「実行ID」、は、サーバからの現在の「コピーオフセット量」を示す.

②プライマリ・サーバの戻り値は、次の3つの形式があります。


1つ目:
+FULLRESYNC

プライマリ・サーバがスレーブ・サーバと完全な再同期を実行することを示します.
2つ目:
+CONTINUE

プライマリ・サーバがスレーブ・サーバの実行部分と再同期することを示します.
3つ目:
-ERR

プライマリ・サーバのバージョンがRedis 2.8より低く、PSYNCコマンドを認識できないことを示し、サーバからFULLRESYNCコマンドを送信し、完全な再同期を実行します.

完全再同期(full resynchronization)の実装:


① PSYNC:
クライアントはサーバからSLAVEOFコマンドを送信し、サーバからソケット接続を確立し、PINGコマンド、認証を実行した後、メインサーバにPSYNCコマンドを送信する.
② BGSAVE:
メインサーバはPSYNCを受け取った後、完全な再同期を実行する必要があると判断し、BGSAVEコマンドを実行し、バックグラウンドでRDBファイルを生成し、バッファを使用して今から実行するすべての書き込みコマンドを記録する.
③ RDB:
メインサーバBGSAVEの実行が完了すると、生成したRDBファイルをスレーブサーバに送信し、サーバから受信して書き込む.
④バッファ:
プライマリ・サーバは、バッファに記録された書き込みをサーバに送信し、サーバから受信した書き込みコマンドを実行します.

部分再同期(partial resynchronization)の実装:


部分再同期機能は、1主、サーバからの「コピーオフセット量」(replication offset);②メインサーバのレプリケーション「蓄積バッファ」(replication backlog);③サーバの「運転ID」(runID)です.
プロセス:
a.             “     ”,       N           +N,       N           +N,                      。
           ,       PSYNC  ,             ;

b.        “       "      【           】,               【   】,               ;

c.             PSYNC    ,                       (  offset+1      )               :
   ,       “+CONTINUE”      ,     “     ”          ,
    ,        。

d.                40         “  ID”,                    ID。          ,         ID       ,    ID  ,                ,  ,                ,        。

添付:「コピー・バックログ・バッファ」のサイズを設定します。


Redisレプリケーション蓄積バッファのデフォルトサイズは1 MBであり、PSYNCコマンドの一部の再レプリケーション機能が正常に機能するように、実際の状況に応じてバッファのサイズを設計する必要があります.レプリケーション・バッファのサイズは、次の式に基づいて推定されます.
second * write_size_per_second

このうち、secondは、サーバから断線再接続するのに要する平均時間であり、write_size_per_secondは、プライマリサーバの平均1秒当たりの書き込みコマンドデータ量である.

3.2「コマンド伝播」:


「同期」操作の実行が完了すると、プライマリ・スレーブ・サーバはデータベースの状態が一致し、プライマリ・サーバで書き込み操作が発生すると、プライマリ・サーバのデータが書き換えられ、プライマリ・サーバはコマンド伝播方式でこの書き込みコマンドをセカンダリ・サーバに送信し、サーバから受信した後にこの書き込み命令を実行します.

心拍数検出:


コマンド伝播フェーズでは、デフォルトでは、サーバから の頻度でプライマリ・サーバにコマンドが送信されます.
REPLCONF ACK 

ここで、replication_offsetは、サーバからの現在のレプリケーションオフセット量である.

心拍数検出には3つの役割があります。


(1)マスタスレーブサーバーのネットワーク接続状態を検出する:
プライマリ・サーバは、通常1秒おきにサーバからハートビート・パケットが受信されることを知っています.長時間受信されていない場合は、プライマリ・サーバはプライマリ・スレーブ間の接続に問題があることを知ることができます.プライマリ・サーバ上のINFO replicationでは、サーバから最後のハートビート・パケットが受信された時間を表示できます.(通常は0~1秒でジャンプします)
127.0.0.1:8001> INFO replication
#Replication
role:master
connected slaves:3
slave0:ip=127.0.0.1,port=8002,state=online,offset=252,lag=1    <===
slave1:ip=127.0.0.1,port=8003, state=online,offset=252,lag=1   <===
slave2:ip=127.0.0.1,port=8004,state=online,offset=252,lag=0    <===
master_replid:9b9ea7eef504c05da56067b53f64 59827283c46
master_replid2:0000000000000000000000000000000000000000

このうちlagフィールドは、このslaveがサーバから最後に受信した心拍数検出時間を表し、正常値は0または1です.
(2)補助実装min-slave構成オプション:(プライマリサーバが安全でない場合の書き込みを防止)
Redisは、プライマリ・サーバが安全でない場合に書き込みコマンドを実行しないように、2つの構成オプションを提供します.
min-slaves-to-wite  	3
min-slaves-max-lag 		10

プライマリ・サーバは、スレーブ・サーバの数が3未満、または最大スレーブ・サーバの3つの遅延(lag)が10秒以上ある場合、書き込みコマンドを実行しません.
(3)検出コマンドの紛失:
心拍数検出にはreplication_offsetフィールドがあり、プライマリサーバは前回のコマンド伝播が失われたかどうかを判断することができ、失われた場合、蓄積バッファ内のデータをコピーすることによってタイムリーに再送することができる.

4.完全なマスターコピープロセス:

127.0.0.1:8001127.0.0.1:8002の2つのRedisサーバがあると仮定し、8002を8001のスレーブにします.プロセス全体は以下の通りです.

手順1:サーバから:プライマリ・サーバのアドレスとポートを設定する:(redisServer)


サーバ(8002)から接続されたクライアントにSLAVEOFコマンドを入力します.
127.0.0.1:8002> SLAVEOF 127.0.0.1:8001
OK

サーバからコマンドを受け取ったら、接続するプライマリサーバのIPアドレスとポート番号を保存します.
struct redisServer {
	char	*masterhost; 	//     IP  
	int 	masterport; 	//        
};

注意SLAVEOFは、 であり、サーバからSLAVEOFのコマンドを受信すると、OKに直接戻ってクライアントにコマンドが受信されたことを示し、masterhostおよびmasterportのプロパティの設定を開始します.(同期コマンドの場合、実装手順はどうなりますか?サーバからSLAVEOFコマンドを受信すると、クライアントブロック待ちコマンドが返され、サーバ実行完了後にOKがクライアントに返され、クライアントは下向きに実行されます.)

手順2:サーバから:プライマリサーバへのソケット接続を確立する:(connect)


サーバからステップ1で保存したプライマリサーバIPとポート番号に従って、プライマリサーバへのソケット接続を作成します.すなわち、ノードからconnectを呼び出し、プライマリノードからacceptを呼び出して接続を受け入れます.
接続が正常に確立されると、サーバからプライマリ・セカンダリ・レプリケーション・ジョブを処理するためのIOイベント・プロセッサ(epollに傍受fdを追加)が作成され、後続のレプリケーション・ジョブ(例えば、RDBファイルの受信、プライマリ・サーバから伝播された書き込みコマンドの受信など)は、このIOイベント・プロセッサによって完了します.

ステップ3:サーバから:PINGコマンドを送信:(PING)


ステップ2でマスタサーバからsocketソケット接続が確立されたが、双方はまだこのソケットを使用して通信していないため、PING命令を先に実行して双方の読み書き処理が正常であるかどうかを確認する必要がある(ステップ2はTCP 3回の握手を完了したことに相当し、マスタは双方のconnect、acceptから正常に呼び出され、ステップ3はマスタは双方のread、writeから正常に呼び出されたかどうかを検出する).
(1)       PING            PONG  ,         ,       ;
(2)       PING              ,                 (TIMEOUT),         。

ステップ4:認証:(AUTH)


(1)認証の構成項目について:

redis.confプロファイルには、プライマリ・スレーブ・レプリケーションの認証に関する2つの構成項目があります.

①サーバーからマスターサーバーのパスワードを設定する:(デフォルトは設定されていません)

#  masterauth 

例:
masterauth 10086

②マスターサーバに自身のパスワードを設定する:(デフォルトは設定されていません)

# requirepass foobared

例:
requirepass 10086

(2)認証プロセス:


(1)サーバからmasterauthオプションが設定されている場合、サーバから認証が開始され、コマンドのパラメータがAUTHオプションの値であるmasterauthコマンドがサーバからプライマリサーバに送信される.
AUTH 10086

この場合:
          `requirepass`          ,     ,    ;
       ,     ,                   .

(2)サーバからmasterauthオプションが設定されていない場合、サーバから認証は開始されません.
          requirepass  ,     ;
         requirepass  ,     ,                   。

ステップ5:ポート情報の送信:(listening-port)


サーバからプライマリサーバに自分のリスニングポート番号を送信し、プライマリサーバが受信した後、対応するセカンダリサーバのredisClient構造に保存してサーバからコマンドを呼び出す.
REPLCONF listening-port 8002

プライマリ・サーバの保存:
typedef struct redisClient
	int slave_listening_port;  //          
} redisClient;
slave_listening_portプロパティの唯一の役割は、プライマリ・サーバがINFO replicationコマンドを実行するときに、サーバからのポート番号を印刷することです.

手順6:同期化:


サーバからプライマリサーバにPSYNCコマンドを送信し、同期操作を実行し、自分のデータベースをプライマリサーバと一致するように更新します.
注意:
       ,               ;
       ,                。

       "     "  "     ",                (RDB        ),                  ,       。

ステップ7:コマンド伝播:


同期操作が完了すると、プライマリ・サーバはコマンド伝播段階に入ります.この場合、プライマリ・サーバは、自分が実行したライト・コマンドをサーバから送信し、サーバから伝播したライト・コマンドを実行するだけで、プライマリ・データベースの状態を一致させることができます.
また、コマンド伝播フェーズでは、サーバから一定の頻度(デフォルトでは1秒に1回)でハートビート検出コマンドがプライマリサーバに送信されます.
これまでに接触したredisServer構造のメンバー:
struct redisServer{
	redisDb 	*db;
	int 		dbnum; 				//   
	
	long long 	dirty;
	time_t 		lastchange;
	struct saveparam *saveparams;	//RDB   
	
	sds 		aof_buf;			//AOF   
	
	char 		*masterhost;
	int 		masterport;			//    ,         ,    IP    
};
redisClient :
typedef struct redisClient {
	redisDb  *db; 					//               
	int 	 slare_listening_port;  //                   ,              
} redisClient;