1つは、ZooKeeperの概要です
1.1 Zookeeperとは何ですか?****
Zookeeperは、分散システムの調整および管理サービスを提供するオープンソースの分散型オープンソースソフトウェアです。
1. CAPの原則
CAPの原則には、一貫性、可用性、およびパーティションのフォールトトレランスが含まれます。
1)一貫性:強力な一貫性(銀行の引き出しの成功または失敗など)、最終的な一貫性。
2)可用性:合理的な結果を妥当な時間で得ることができます。
3)パーティションのフォールトトレランス:各エリアは、外部の可用性と一貫したサービスを提供できます。
図1分散システムの例
上の図は、AとBがアクセスノードである分散システムを示しています。CDEは上海エリアの外界にサービスを提供するノードであり、FGは深センエリアの外界にサービスを提供するノードです。
図1CAPの原則は次のように反映されます
。1)一貫性:BはポイントCでパスワードを変更し、Fは新しいパスワードを使用して正常にログインします。
2)AがCに接続され、CがダウンしているAが分散システムに再度接続されると、接続可能(G)になります。つまり、ノードのダウンタイムはシステムの通常の機能に影響を与えません。
3)パーティションのフォールトトレランス:上海のコンピュータールームと深センのコンピュータールームはネットワークから切断されており、ABは引き続き一貫性とフォールトトレランスを提供できます。
CAPの原則:2つを保持し、1つを破棄します。通常、パーティションのフォールトトレランスは保持されます。他の2つのうちの1つを選択してください。
1)Redisの場合、APを満たすために解決する必要のある主な問題は、単一障害点、高可用性です。
2)飼育係の場合、CPを満たします。
2.基本
的な考え方:分散システムで強い一貫性を実現できない場合でも、適切な方法を使用して、分散システムに究極の一貫性を実現させます。
ベース:基本的に利用可能(ba)、弱い状態(s)、結果整合性(e)。
1)基本的に利用可能:応答時間と機能。
2)弱い状態:同期の遅延を許可します。
3)結果整合性:データは結果整合性があります。
1.2なぜZookeeperが必要なのですか?
分散システムには、外の世界にサービスを提供するために協力する多数のマイクロサービスがあります。現時点では、これらのマイクロサービスを管理および調整するために、安定した安全な調整管理ツールが必要です。
2.ZooKeeperの動作メカニズム
2.1データストレージ+モニタリング通知
ZooKeeperの動作メカニズムは、データストレージ+監視通知メカニズムです。
その中で、データストレージは同様のUnixファイルシステム形式とKV方式のストレージを採用しています。監視通知メカニズムとは、zookeeperがキーデータを保存および管理し、分散システム内のノードを受け入れてキーデータの変更を登録およびリッスンすることを意味します。キーデータが変更されると、 Zookeeperは、データの変更を登録したノードに通知します。
図2Zookeeperのデータストレージ構造
図3zookeeperクラスターの
図図3監視メカニズムの例:
node1が起動したら、値gate1を使用してzkクラスターにノード/ node / node1を作成します。node2
が起動したら、zkクラスターにnode / node / node2を作成します。値gate2。Node3
はノードを監視します。node2がダウンしてオフラインであると仮定すると、node3はnode2がダウンしているというデータを受信できます。
2.2ノードタイプ
zookeeperのノードのタイプには、永続ノード、永続シーケンシャルノード、一時ノード、および一時シーケンシャルノードが含まれます。
1.永続ノード
データノードが作成された後、削除操作がアクティブにノードをクリアするまで、データノードは常にzookeeperに存在します。
2.永続シーケンスノード。
各親ノードは、第1レベルの子ノードのシーケンスを維持します。これは、各子ノードの作成シーケンスを記録するために使用されます(指定されたノード名に最大の数値サフィックスを追加します。値は整数の最大値です)。
3.
一時ノード一時ノードのライフサイクルはクライアントのセッションにバインドされます。クライアントのセッションに障害が発生すると、このノードは自動的にクリアされます。一時ノードは子ノードを作成できず、リーフノードとしてのみ使用できます。
4.
一時ノード一時ノードに基づいてシーケンス機能を追加します。
2.3ノードのstat属性
- ノードが作成されたときのczxidトランザクションID
- 最後に更新されたときのmzxidノードのトランザクションID
- ctimeノードが作成された時刻
- mtimeノードが最後に更新された時刻
- versionノードのバージョン番号
- 子ノードのcversionバージョン番号
- 嫌悪ノードACLバージョン番号
- ephemeralOwnerは、一時ノードのセッションIDを作成します。永続ノードの場合、値は0です。
- dataLengthデータコンテンツの長さ
- numChildren現在のノードの子の数
- pzxidノードのサブノードリストが最後に変更されたときのトランザクションID。子ノードリストが変更された場合にのみ値が変更され、子ノードの内容が変更された場合に値は変更されません。
3、ZooKeeperの原則
3.1役割の紹介
1.
クラスタートランザクション処理のシーケンスを保証するリーダートランザクション要求の唯一のスケジューラーおよびプロセッサー。
クラスター内の各ノードのスケジューラー。
2.フォロワー
はクライアントの非トランザクション要求を処理し、トランザクション要求をリーダーサーバーに転送します。
パラメータトランザクション要求提案(提案)投票。
リーダー選出投票に参加します。
3.オブザーバー
は非トランザクションサービスのみを提供し、通常、クラスターのトランザクション処理機能に影響を与えることなく、クラスターの非トランザクション処理機能を改善するために使用されます。
3.2データストレージ
データストレージには、メモリデータストレージとディスクデータストレージが含まれ、ディスクデータにはトランザクションログとスナップショットデータが含まれます。
3.3同期プロセスの更新
- 分散システムのノードは、トランザクション要求を開始します。
- a。リーダーの場合は、トランザクションリクエストをトランザクションプロポーザルに変換し、プロポーザルごとにグローバルzxidを生成します
。b。ラーナーの場合は、最初にトランザクションリクエストをリーダーに転送し、次にリーダーがトランザクションを変換します。トランザクションプロポーザルへのリクエストと同時に、各プロポーザルはグローバルzxidを生成します。 - リーダーは、ブロードキャストする必要のあるプロポーザルを順番にFIFOキューに入れ、順番に送信します。
- フォロワーはプロポーザルを受信すると、トランザクションログの形式でローカルディスクに書き込まれます。書き込みが成功すると、リーダーにack応答パケットが送信されます。
- リーダーは、フォロワーの半数以上からack応答を受信した後、送信が成功したと見なし、コミットメッセージを送信できます。
- リーダーはすべてのフォロワーにコミットメッセージをブロードキャストすると同時に、トランザクションの送信を完了します。フォロワーがコミットを受信した後、トランザクション操作を実行します。
3.4同期プロセスを初期化します
初期同期には、リーダーの選出の開始とリーダーのクラッシュという2つの状況が含まれます。
1.リーダーを選出するために投票し、2つの要因に従ってリーダー<sid、zxid>を決定します。zxidが大きい場合は誰がリーダーになりますか。zxidが等しい場合はsidが大きくなり、勝者になります。選出されます。
2.データ同期を実行します。2つの状況があります:
a。トランザクションがリーダーで送信され、フォロワーの半数以上がackに応答しましたが、コミットメッセージが送信される前に電話を切りました;
b。トランザクションが生成された後にリーダーが電話を切りましたリーダー。
次のことを確認する必要
があります
。a。新しく選出されたリーダーに未提出の提案を含めることはできません。b。新しく選出されたリーダーに最大のzxidが含まれます。
質問動物園飼育係のクラスターは奇数のノードを使用しますか、それとも偶数のノードを使用しますか?どうして?
奇数のノードが使用されます。Zookeeperは半分以上の選挙戦略(n / 2 + 1)を使用しているためです。
偶数4を使用する場合は、4/2 + 1 = 3を満たす必要があるため、分散システムの4-3 = 1ノードのみが問題を抱えることができます。
奇数の5を使用する場合は、5/2 + 1 = 3を満たす必要があります。これにより、分散システムの5-3 = 2ノードで問題が発生する可能性があります。
質問なぜ大きいzxidがリーダーとして選ばれるのですか?
zxidが大きいほど最新のデータであり、運用中の基本データとして最新のデータを使用する必要があります。
3.5データ同期の原則
Zookeeperデータ同期の原則には、差分同期、ロールバック、次に差分同期、ロールバック同期、完全同期などが含まれます。
実際のアプリケーションは、必要に応じて同期タイプを選択できます。
3.6クライアントの原則
1. 2つのスレッドを作成します。ioスレッドはネットワークイベントの読み取りと書き込みを担当し、完了スレッドは非同期コールバック関数とウォッチャー呼び出しを処理します。
2. ioスレッドはデータをシリアル化し、ネットワークを介してzkノードに送信します。
3. zkノードによって返されたデータは、ioスレッドを介して逆シリアル化され、パイプを介して処理するために完了スレッドに非同期的に送信されます。
4、ZooKeeperの実際の戦闘例
Zookeeperのアプリケーションは、統合されたネーミングサービス、統合された構成管理、分散ロック、分散キュー、負荷分散などで実現できます。
4.1zookeeperのインストール
1. JDKをインストールし、環境変数を構成します
2. zookeeperの
Webサイトをダウンロードします:https://www.apache.org/dyn/closer.lua/zookeeper/zookeeper-3.6.2/apache-zookeeper-3.6.2.tar.gz
3.
1)centosをインストールします
yum install cppunit
yum install python-setuptools
yum install openssl openssl-devel
yum install cyrus-sasl-md5 cyrus-sasl-gssapi cyrus-sasl-devel
2)ubuntu
apt-get install libcppunit-dev
apt-get install python-setuptools python2.7-dev
apt-get install openssl libssl-dev
apt-get install libsasl2-modules-gssapi-mit libsasl2-modules libsasl2-dev
4.ソースコードフォルダを入力します
mvn clean install -DskipTests
5.cドライバーをコンパイルします
mvn clean -pfull-build
mvn install -pfull-build -DskipTests
4.2Zookeeperの構成
構成ファイル:./ conf / zoo_sample.cfg
#心跳包间隔,在这里每2秒发送一次
tickTime=2000
#初始化同步时,最大允许10次延时,也就是2*10秒内同步成功就认为成功
initLimit=10
#更新同步时,最大允许5次延时,也就是2*5秒内同步成功就认为成功
syncLimit=5
#快照或持久化数据存储路径
dataDir=/tmp/zookeeper
#zk监听端口
clientPort=2181
4.3サンプルソースコード
主要なサンプルソースコード:zookeeperの初期化、ノードの作成、ノードの切断の監視、ビジネスロジック、zookeeperのシャットダウンなどが含まれます。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "include/zookeeper.h"
#include "include/zookeeper_log.h"
typedef struct zk_mutex_s {
int seq_me; // 序号
int seq_watch; // 监听的序号
char watch[64]; // 监听的节点名
} zk_mutex_t;
static zk_mutex_t zmt = {
0};
static int quit = 0;
void zk_create_lock_res1_es(int rc, const char *value, const void *data) {
printf("zk_create_lock_res1_es rc = %d\n", rc);
if (rc == 0) {
zhandle_t* zk_hdl = (zhandle_t*)data;
int seq;
sscanf(value, "/lock/res1/%d", &seq);
printf("\tname = %s seq = %d\n", value, seq);
zmt.seq_me = seq;
if (seq > 0) {
//业务逻辑操作
return;
}
printf("%s 获取锁, 获取执行权, 释放锁\n", value);
zoo_adelete(zk_hdl, value, -1, zk_delete_lock_res1_children, "");
}
}
//只要节点断开,都会回调此函数
void zk_watcher_disconnect(zhandle_t *zh, int type, int state, const char *path, void *ctx) {
if (0 == strcmp(zmt.watch, path)) {
int ret = zoo_aget_children(zh, "/lock/res1", 0, zk_get_children_lock_res1, zh);
if (ret) {
printf("error: zk_watcher_disconnect:zoo_aget_children\n");
exit(EXIT_FAILURE);
}
}
}
int main(int argc, const char *argv[])
{
/* 初始化 zk ,zk_watcher_disconnect为回调函数*/
zhandle_t* zk_hdl = zookeeper_init("127.0.0.1:2181",zk_watcher_disconnect,
30000, 0, "zookeeper for distribute mutex.", 0);
if (!zk_hdl)
{
printf("error: connecting to zookeeper server...\n");
exit(EXIT_FAILURE);
}
int ret;
/* 创建 /lock/res1/ 短暂顺序节点*/
ret = zoo_acreate(zk_hdl, "/lock/res1/", "mark", 5, &ZOO_OPEN_ACL_UNSAFE,
ZOO_EPHEMERAL_SEQUENTIAL, zk_create_lock_res1_es, zk_hdl);
if (ret)
{
printf("error: create /lock/res1 EPHEMERAL SEQUENTIAL\n");
exit(EXIT_FAILURE);
}
ret = 0;
for (;;)
{
if (quit) break;
usleep(2500);
}
zookeeper_close(zk_hdl);
return 0;
}