Atomixの紹介

Atomixの概要

1. 概要

ほとんどの分散アプリケーションでは、一貫性がありフォールトトレラントなステートフルコンポーネントが必要です。 Atomix is an embeddable library helping in achieving fault-tolerance and consistency for distributed resources.

コレクション、グループ、同時実行用ツールなどのリソースを管理するための豊富なAPIセットを提供します。

開始するには、pomに次のMaven依存関係を追加する必要があります。


    io.atomix
    atomix-all
    1.0.8

この依存関係は、ノードが相互に通信するために必要なNettyベースのトランスポートを提供します。

2. クラスターのブートストラップ

Atomixを開始するには、最初にクラスターをブートストラップする必要があります。

Atomixは、ステートフルな分散リソースの作成に使用される一連のレプリカで構成されています。 Each replica maintains a copy of the state of each resource existing in the cluster.

レプリカは、クラスター内の2つのタイプ、アクティブとパッシブです。

分散リソースの状態変更はアクティブレプリカを介して伝播されますが、パッシブレプリカはフォールトトレランスを維持するために同期が保たれます。

2.1. 組み込みクラスターのブートストラップ

単一ノードクラスターをブートストラップするには、最初にAtomixReplicaのインスタンスを作成する必要があります。

AtomixReplica replica = AtomixReplica.builder(
  new Address("localhost", 8700))
   .withStorage(storage)
   .withTransport(new NettyTransport())
   .build();

ここで、レプリカはStorageTransportで構成されています。 ストレージを宣言するコードスニペット:

Storage storage = Storage.builder()
  .withDirectory(new File("logs"))
  .withStorageLevel(StorageLevel.DISK)
  .build();

レプリカが宣言され、ストレージとトランスポートで構成されたら、bootstrap()を呼び出すだけでブートストラップできます。これにより、関連するブロッキング%(を呼び出してサーバーがブートストラップされるまで、ブロックに使用できるCompletableFutureが返されます。 t2)sメソッド:

CompletableFuture future = replica.bootstrap();
future.join();

これまで、単一ノードクラスターを構築してきました。 これで、ノードをさらに追加できます。

これを行うには、他のレプリカを作成し、それらを既存のクラスターに結合する必要があります。 join(Address)メソッドを呼び出すために新しいスレッドを生成する必要があります。

AtomixReplica replica2 = AtomixReplica.builder(
  new Address("localhost", 8701))
    .withStorage(storage)
    .withTransport(new NettyTransport())
    .build();

replica2
  .join(new Address("localhost", 8700))
  .join();

AtomixReplica replica3 = AtomixReplica.builder(
  new Address("localhost", 8702))
    .withStorage(storage)
    .withTransport(new NettyTransport())
    .build();

replica3.join(
  new Address("localhost", 8700),
  new Address("localhost", 8701))
  .join();

これで、3ノードのクラスターがブートストラップされました。 または、bootstrap(List<Address>)メソッドでListのアドレスを渡すことにより、クラスターをブートストラップすることもできます。

List
cluster = Arrays.asList( new Address("localhost", 8700), new Address("localhost", 8701), new Address("localhsot", 8702)); AtomixReplica replica1 = AtomixReplica .builder(cluster.get(0)) .build(); replica1.bootstrap(cluster).join(); AtomixReplica replica2 = AtomixReplica .builder(cluster.get(1)) .build(); replica2.bootstrap(cluster).join(); AtomixReplica replica3 = AtomixReplica .builder(cluster.get(2)) .build(); replica3.bootstrap(cluster).join();

レプリカごとに新しいスレッドを作成する必要があります。

2.2. スタンドアロンクラスターのブートストラップ

Atomixサーバーは、Maven Centralからダウンロードできるスタンドアロンサーバーとして実行できます。 簡単に言えば、これはJavaアーカイブであり、提供することでターミナル経由で実行できます。

簡単に言えば、これはJavaアーカイブであり、アドレスフラグにhost: portパラメータを指定し、-bootstrapフラグを使用することで端末を介して実行できます。

クラスタをブートストラップするコマンドは次のとおりです。

java -jar atomix-standalone-server.jar
  -address 127.0.0.1:8700 -bootstrap -config atomix.properties

ここで、atomix.propertiesは、ストレージとトランスポートを構成するための構成ファイルです。 マルチノードクラスターを作成するには、-joinフラグを使用して既存のクラスターにノードを追加します。

その形式は次のとおりです。

java -jar atomix-standalone-server.jar
  -address 127.0.0.1:8701 -join 127.0.0.1:8700

3. クライアントとの連携

Atomixは、AtomixClient APIを介して、クラスターにリモートアクセスできるクライアントの作成をサポートしています。

クライアントはステートフルである必要がないため、AtomixClientにはストレージがありません。 トランスポートはクラスターとの通信に使用されるため、クライアントの作成中にトランスポートを構成するだけです。

トランスポートを使用してクライアントを作成しましょう。

AtomixClient client = AtomixClient.builder()
  .withTransport(new NettyTransport())
  .build();

ここで、クライアントをクラスターに接続する必要があります。

AddressListを宣言し、Listを引数としてクライアントのconnect()メソッドに渡すことができます。

client.connect(cluster)
  .thenRun(() -> {
      System.out.println("Client is connected to the cluster!");
  });

4. リソースの取り扱い

Atomixの真の力は、分散リソースを作成および管理するための強力なAPIセットにあります。 Resources are replicated and persisted in a cluster and are bolstered by a replicated state machine – Raft ConsensusProtocolの基盤となる実装によって管理されます。

分散リソースは、そのget()メソッドの1つによって作成および管理できます。 AtomixReplicaから分散リソースインスタンスを作成できます。

replicaAtomixReplicaのインスタンスであると考えると、分散マップリソースを作成し、それに値を設定するためのコードスニペットは次のとおりです。

replica.getMap("map")
  .thenCompose(m -> m.put("bar", "Hello world!"))
  .thenRun(() -> System.out.println("Value is set in Distributed Map"))
  .join();

ここで、join()メソッドは、リソースが作成されて値が設定されるまでプログラムをブロックします。 AtomixClientを使用して同じオブジェクトを取得し、get(“bar”)メソッドを使用して値を取得できます。

最後にget()メソッドを使用して、結果を待つことができます。

String value = client.getMap("map"))
  .thenCompose(m -> m.get("bar"))
  .thenApply(a -> (String) a)
  .get();

5. 一貫性とフォールトトレランス

Atomixは、可用性よりも一貫性がはるかに重要なミッションクリティカルな小規模データセットに利用されます。

It provides strong configurable consistency through linearizability for both reads and writes。 線形化可能性では、書き込みがコミットされると、すべてのクライアントが結果の状態を認識することが保証されます。

Atomixのクラスターの一貫性は、選出されたリーダーが以前に成功したすべての書き込みを持つ、基盤となるRaftコンセンサスアルゴリズムによって保証されます。

すべての新しい書き込みはクラスターリーダーを経由し、完了前にサーバーの大部分に同期的に複製されます。

フォールトトレランスを維持するには、majority server of the cluster needs to be alive。 少数のノードに障害が発生すると、ノードは非アクティブとしてマークされ、パッシブノードまたはスタンバイノードに置き換えられます。

リーダーに障害が発生した場合、クラスター内の残りのサーバーは新しいリーダーの選択を開始します。 その間、クラスターは使用できなくなります。

パーティションの場合、リーダーがパーティションの非クォーラム側にある場合、そのリーダーは辞任し、新しいリーダーがクォーラムのある側で選出されます。

そして、リーダーが過半数の側にいる場合、それは変更なしで続行されます。 パーティションが解決されると、非クォーラム側のノードはクォーラムに参加し、それに応じてログを更新します。

6. 結論

ZooKeeperと同様に、Atomixは分散コンピューティングの問題に対処するための堅牢なライブラリセットを提供します。

そして、いつものように、このタスクの完全なソースコードはover on GitHubで利用できます。