MaxScaleでのデータベースの高可用性と回復性

ミッションクリティカルなアプリケーションは高可用性を必要とします。高可用性の目標は、ユーザーにサービスやリソースへの一貫したアクセスを提供し、中断の可能性を最小限に抑えることです。自動フェイルオーバーは、高可用性を達成するために使用される特定のメカニズムです。これは、システムコンポーネント(サーバー、ネットワーク、データベースなど)の障害を自動的に検出し、人間の介入なしで直ちにスタンバイコンポーネントに操作を切り替えることを含みます。これにより、回復力が高まります。

MariaDB MaxScaleは、高可用性の機能を含むデータベースプロキシです。この記事では、JavaとSvelteで実装されたオンラインストアシミュレータアプリケーションでそれを試す方法を紹介します。

アーキテクチャ

以下の図は、デモアプリケーションのアーキテクチャを示しています。


A web application developed with JavaScript and the Svelte framework makes HTTP requests to a Java backend. The backend answers with server-sent events that the frontend uses to update the user interface on the browser.

バックエンドはSpring Bootで実装され、MariaDBデータベースクラスタにR2DBC(リアクティブ)を使用して接続されています。バックエンドのロジックは、要するに、オンラインストアデータベースへの読み取りと書き込みのシミュレーションです。シミュレーションはパラメータ化され、ユーザーは以下を調整できます。

  • 1分あたりの商品閲覧数: 1分あたりのデータベースへの読み取り回数。
  • 1分あたりの注文数: 1分あたりのデータベースへの書き込み回数。
  • 注文あたりの商品数: 書き込みアンプリファイア。
  • タイムアウト(ミリ秒単位): データベースへのリクエストが失敗と見なされるまでの秒数。

データベースクラスタは、Javaバックエンドに単一の論理データベースのように見せるデータベースプロキシであるMaxScaleによってフロントエンド化されています。このプロキシは、読み取り/書き込み分割(書き込みをプライマリMariaDBサーバーに、読み取りをレプリカに送信)を実行し、レプリカサーバー間で読み取りの負荷分散を設定可能なアルゴリズムを使用して行います。データは自動的にレプリケートされ、プライマリからレプリカデータベースサーバーにコピーされます。

Dockerイメージのソースからのビルド

I have prepared custom Docker images for every component in the simulator. You can either build the images from the source (optional) or use the already built and published images from Docker Hub. If you decide to build the images yourself, you can find the source code on GitHub:

  • MariaDBのデプロイメント: MaxScaleを使用したレプリケートされたMariaDBトポロジーの簡単なデプロイのためのカスタムイメージ。本番環境では使用しないでください!これらのイメージはデモアプリケーションのみに適しています。公式のMariaDB Dockerイメージを本番環境のデプロイに使用してください。
  • バックエンドアプリケーション: データベースクラスタに接続するバックエンドアプリケーション。
  • フロントエンドアプリケーション: バックエンドにシミュレーション設定のリクエストを行い、シミュレーション結果を表示するためのイベントを受け取るフロントエンドアプリケーション。

各リポジトリには独自のDockerイメージを作成するために使用できるDockerfileが含まれています。例えば、バックエンドアプリケーションのイメージを作成するには、以下を実行します:

Shell

 

docker build --tag alejandrodu/online-store-simulator-java-backend .

シミュレーションの実行

すべてのサービスは以下のDocker Composeファイル(docker-compose.yml)を使用して起動できます:

YAML

 

version: "3.9"
services:
  server-1:
    container_name: server-1
    image: alejandrodu/mariadb
    ports:
      - "3306:3306"
    environment:
      - MARIADB_CREATE_DATABASE=demo
      - MARIADB_CREATE_USER=user:Password123!
      - MARIADB_CREATE_REPLICATION_USER=replication_user:ReplicationPassword123!
      - MARIADB_CREATE_MAXSCALE_USER=maxscale_user:MaxScalePassword123!

  server-2:
    container_name: server-2
    image: alejandrodu/mariadb
    ports:
      - "3307:3306"
    environment:
      - MARIADB_REPLICATE_FROM=replication_user:ReplicationPassword123!@server-1:3306

  server-3:
    container_name: server-3
    image: alejandrodu/mariadb
    ports:
      - "3308:3306"
    environment:
      - MARIADB_REPLICATE_FROM=replication_user:ReplicationPassword123!@server-1:3306

  maxscale:
    container_name: maxscale
    image: alejandrodu/mariadb-maxscale
    command: --admin_host 0.0.0.0 --admin_secure_gui false
    ports:
      - "4000:4000"
      - "8989:8989"
      - "27017:27017"
    environment:
      - MAXSCALE_USER=maxscale_user:MaxScalePassword123!
      - MARIADB_HOST_1=server-1 3306
      - MARIADB_HOST_2=server-2 3306
      - MARIADB_HOST_3=server-3 3306
    healthcheck:
      test: ["CMD", "maxctrl", "list", "servers"]
      interval: 5s
      timeout: 10s
      retries: 5

  java-backend:
    container_name: java-backend
    image: alejandrodu/online-store-simulator-java-backend
    ports:
      - "8080:8080"
    environment:
    - spring.r2dbc.url=r2dbc:mariadb://maxscale:4000/demo
    - spring.r2dbc.username=user
    - spring.r2dbc.password=Password123!
    - spring.liquibase.url=jdbc:mariadb://maxscale:4000/demo
    - spring.liquibase.user=user
    - spring.liquibase.password=Password123!
    depends_on:
      maxscale:
        condition: service_healthy

  svelte-frontend:
    container_name: svelte-fronted
    image: alejandrodu/online-store-simulator-svelte-frontend
    ports:
      - "5173:80"
    environment:
      - BACKEND_URL=http://java-backend:8080

Docker Composeファイルがあるディレクトリに移動し、以下のようにデタッチモードでサービスを開始します:

Shell

 

docker compose up -d

MaxScaleの設定

シミュレーションを開始する前に、トランザクションリプレイのためにMaxScaleを設定します。また、タイムアウトを調整してシミュレーションをより面白くします。

http://localhost:8989/ に移動し、UIにログインしてください。

  • ユーザー名:admin
  • パスワード:mariadb

ダッシュボードが表示され、MariaDBクラスタの状態が確認できます。


プライマリサーバー(server-1)と2つのレプリカサーバー(server-2およびserver-3)があります。レプリケーションはserver-1(プライマリ)からserver-2およびserver-3(レプリカ)に既に設定されており、すべてのサーバーが稼働しているはずです。

mdb_monitorをクリックし、鉛筆アイコンを選択してパラメータの編集を有効にしてください。以下のパラメータを設定してください:

  • auto_failover(true): これにより自動フェイルオーバーが有効になります。MariaDBサーバーが停止した場合、MaxScaleはレプリカサーバーを選択し、新しいプライマリとして再構成して書き込みを継続できるようにします。
  • auto_rejoin(true): これにより復旧したサーバーの自動再参加が有効になります。障害が発生したサーバーが再び稼働すると、MaxScaleはそれを検出し、利用可能なレプリカサーバーとして構成します。
  • failcount(1): サーバーがダウンしてフェイルオーバー処理を活性化するために必要なモニタ(サーバーステータスをチェックするMaxScaleのコンポーネント)の反復回数を設定します。このデモでは、障害が発生した直後にフェイルオーバーが開始されるように1の値を設定します。
  • backend_connect_timeout(1000): モニタ接続のタイムアウトを設定します。このデモでは、フェイルオーバーを迅速に活性化するために低い値(1秒)を設定します。
  • backend_read_timeout (1000): 監視接続のリードタイムアウト。
  • backend_write_timeout (1000): 監視接続のライトタイムアウト。
  • master_failure_timeout (1000): プライマリ失敗タイムアウト。
  • monitor_interval (1000): サーバーの監視頻度。

警告: これらの値はこのデモに適していますが、本番環境にはおそらく最適ではありません!

パラメータが設定されたら、編集完了をクリックし、確認をクリックしてください。

トランザクションリプレイを有効にする必要もあります。これは、SQLステートメントがルーティングされた直後にダウンしたサーバーで失敗したインフライトトランザクションを自動的に再実行する機能です。これは、失敗ケースとトランザクションリトライのコーディングが不要になるため、ソフトウェア開発者にとって便利です。

メインメニューでダッシュボードをクリックし、サーバーのリストのいずれかのクエリルーターサービスリンクをクリックします。以下のようにパラメータを編集してください:

  • transaction_replay (true): 失敗したトランザクションの自動リトライを有効にします。
  • transaction_replay_retry_on_deadlock (true): 前述の通り、デッドロックが発生した場合。
  • transaction_replay_retry_on_mismatch (true): 前述の通り、チェックサム不一致が発生した場合。

パラメータが設定されたら、編集完了をクリックし、確認をクリックしてください。

シミュレーションの開始

設定が完了したら、シミュレーションを開始できます。http://localhost:5173/ にアクセスし、以下のパラメータを設定してください(名前は、説明不要だと思いますが):

  • 1分間あたりの商品訪問数:6000
  • 1分間あたりの注文数:60
  • タイムアウト(ミリ秒単位):8000

ただし、シミュレーションを開始する前に、オンラインストアの商品を作成する必要があります。データ | 商品を作成…をクリックしてください。デフォルト値のままにして、作成をクリックしてください。商品がデータベースに作成されると、UIが更新されるはずです。

それでは、開始をクリックして、シミュレーションを実行してみましょう。


サーバー障害のシミュレーション

現時点では、プライマリサーバーが書き込み(注文)を処理しています。そのサーバーを停止するとどうなるでしょうか?コマンドラインで実行してください:

Shell

 

docker stop server-1

複数の要因によって、シミュレータで「がっかりした訪問者」や「逃したチャンス」が発生することもあります。また、何も発生しない場合もあります!商品訪問(読み取り)と注文(書き込み)はMaxScaleのおかげで継続します。自動フェイルオーバーがない場合、手動で再設定する必要があり、オフライン時間が長くなり、多くのがっかりした訪問者や逃したチャンスが発生します!

障害が発生したサーバーを再起動してください:

Shell

 

docker start server-1

MaxScaleのダッシュボード(http://localhost:8989/)にアクセスし、server-1が正常なレプリカになっていることを確認してください。

手動で切り替えを行って、server-1を再びプライマリサーバーにすることができます。mdb_monitorをクリックし、MASTERセクションにマウスオーバーしてください。鉛筆アイコンをクリックし、server-1を選択してください。スワップをクリックし、ダッシュボードで新しいプライマリサーバーがserver-1であることを再確認してください。

結論

自動フェイルオーバーは、高可用性システムの構成要素の一つに過ぎません。MaxScaleのようなデータベースプロキシを使用して自動フェイルオーバーを設定することができますが、負荷分散、クエリルーティング、トランザクション再試行、トポロジーの分離など、他の様々なコンポーネントも利用可能です。詳細はこちらのドキュメントをご覧ください。

Source:
https://dzone.com/articles/high-availability-and-resiliency-in-databases