Transactd 高可用運用 (THA)

概要

Transactd バージョン 3.5 から、Transactd 高可用運用 (Transactd High Availability : THA)が利用可能になりました。 複数サーバーによるTHA冗長構成を構築すると、単一のサーバーでの運用に比べて格段にダウンタイムの少ない高可用運用を行うことができます。 また、読み取りオペレーションをスレーブで行うなど負荷分散も簡単に行うことができます。

THAは以下の特徴と機能を持っています。

目次

THAの構成と仕組み

THAは、MySQLのGTIDレプリケーションを使用した、マスターと複数スレーブのサーバー構成からなります。 読取オペレーションをスレーブに分散するかどうかは自由です。 すべてのアクセスをマスターのみで行い、スレーブはフェイルオーバーのためだけにある構成でもかまいません。 スレーブは最低1台で、2台以上が望ましい構成です。

GTIDレプリケーションの使用が前提であるため、MySQL5.6以上/MariaDB 10.0以上の同一のサーバーバージョンで構成します。 GTIDレプリケーションを有効にしたレプリケーションサーバーを構築する方法は、MySQL/MariaDBのドキュメントを参照してください。

THAの仕組み

THAは以下の要素からなります。

ホスト名リゾルバー(THNR)

THAのための、クライアントに組み込まれたホスト名リゾルバーを、THNR(Transactd Host Name Resolver)と呼びます。

THNRは簡単にアプリケーションに組み込んで使用できるホスト名の名前解決ライブラリーです。 アプリケーションは、通常のホスト名に代えて仮想ホスト名でアクセスします。 THNRはtdclcライブラリのネットワークレイヤーに組み込まれており、仮想ホスト名から実ホスト名へ変換してアクセスします。 THNRにより、OS・ネットワーク機器・DNSなどの外部装置やソフトウェアに依存せずにマスターを切り替えることが可能です。

THNRは1つのプロセスにつき1つのインスタンスで、すべてのスレッドから共有されます。

サーバーロール

一般的に、サーバーのロール(役割)はマスターまたはスレーブのいずれかです。 レプリケーションの構成からどれがマスターかは概ね判断が付きますが、将来複雑な構成に対応することを踏まえて、THAではあえてサーバー変数にロールの明示を必要としています。

フェイルオーバー時には、フェイルオーバープログラムによって各サーバーのロールが正しく変更されます。

THNRを使用したアクセスでは、クライアントが要求したロールとサーバーのロールが一致しているかを検査することで、ロールの変更を検出すると同時に、誤ってスレーブに書き込みを行うなどのトラブル防止を実現しています。

クライアントの要求するロールは、アクセスに使用されたホスト名がマスター用の仮想ホスト名かスレーブ用の仮想ホスト名かで判断されます。

クライアントの再接続機能

クライアントには、ネットワークエラーが発生した際サーバーに再接続する機能が組み込まれています。

再接続できた場合、カレントレコードやロック状態などを回復させ、あたかもエラーが無かったかのように処理を継続できます。 ただし、beginTrn()beginSnapshot()でトランザクションが開始されていた場合は、再接続は行われません。 アプリケーションはトランザクションをAbortして、結果をユーザーに通知できます。その後のオペレーションにて再接続が行われます。

死活監視

THNRはマスターの死活監視とフェイルオーバープログラムの呼び出しも行います。 マスターがダウンしたことでクライアントにネットワークエラーが発生すると、エラー内容によって再接続がトライされます。 このとき、THNRに「再接続である」ことが通知されます。

再接続通知を受けると、THNRは現在のホスト名のキャッシュを破棄し、再度正しいホストの検出を行います。 この過程でマスターに正しくアクセスできない場合は、マスターがダウンしているとみなし、フェイルオーバープログラムを呼び出してマスターを切替え、新マスターの検出を行います。

この死活監視はクライアントアクセスのエラーをハンドリングすることで行います。これによって以下のような効果があります。

フェイルオーバープログラム(haMgr)

フェイルオーバープログラムhaMgrは独立したプロセスのプログラムです。(参考:haMgrリファレンス

haMgrがTHNRから呼び出し可能な(パス内に存在する)場合に限り、フェイルオーバーを実行します。 そうでない場合は、アプリケーションには単にネットワークエラーが返されます。

フェイルオーバープロセスは最初に開始したクライアントのみが行うことができます。 後から試みたクライアントはサーバーのHAオブジェクトをロックできずに失敗します。

失敗したクライアントはすぐにTHNRによって再度名前解決を開始します。 その際、フェイルオーバー中でないかを確認するため、HAオブジェクトのロックを最大60秒間試みます。 フェイルオーバーが完了しロックが開放されれば、新しい構成のホスト名が取得されます。

最小限のダウンタイム

以上の仕組みによって、マスターがダウンしても新しいマスターに自動でフェイルオーバーし、ダウンタイムなしに処理を継続することが可能です。 フェイルオーバーにかかる時間はスレーブの台数にもよりますが、検出に数秒、切替は1秒以下です。

また、実際のクライアントが直接死活監視を行うことで、検出とフェイルオーバープログラムの起動までの間にエラーを発生することがありません。 このため、マスターダウンで失敗するトランザクションは、ダウン時に既に開始されていたものだけになります。

THAは、意図的にマスターを切り替えるスイッチオーバーもサポートします。 スイッチオーバーの場合、現マスターでのトランザクションの終了を待って切替を行うので、何のデータも失うことはありません。

THAを構築する

THAを構築する手順を説明します。例では以下のサーバー構成と仮定します。

サーバーIPアドレス
マスター192.168.0.2
スレーブ1192.168.0.3
スレーブ2192.168.0.4
  1. MySQL5.6/MariaDB 10.0以上のサーバーを使い、単一マスターと複数スレーブでレプリケーションを構成します。 参考:MySQL/MariaDB GTID レプリケーション詳細

    このとき、Transactdアクセスのためのユーザー名・パスワード、レプリケーションのためのチャンネル・ユーザー名・パスワード・オプションなどはすべてのサーバーで同じものが使用できるようにします。

  2. すべてのサーバーのmy.cnfreport-host=192.168.0.xのように、自身のホスト名もしくはIPアドレスを明示します。 8610以外のポートを使用している場合はreport-host=192.168.0.x:8611のようにポート番号まで指定します。

    このホスト名は後述するstart関数やhealth_checkなどでも使用されます。

  3. マスターサーバーの起動オプションに–transactd-startup_ha=1を加えて、マスターとして起動し直します。

  4. Transactdクライアントアプリケーションから呼び出せる(パスの通った)ディレクトリにhaMgrを配置します。

  5. haMgr-c health_checkコマンドを使ってフェイルオーバー可能な状態かテストします。

    ./haMgr64 -c health_check -o 192.168.0.2 -s 192.168.0.3,192.168.0.4 -u root -p abcd
    2016-07-05T18:34:28 Starting health check...
      SLAVE_LIST=192.168.0.3,192.168.0.4
      192.168.0.2: Role = Master OK!
      192.168.0.2: HA lock OK!
      192.168.0.3: Role = Slave OK!
      192.168.0.3: Failover is disabled NG!
      192.168.0.3: HA lock OK!
      192.168.0.3: channel name=
      192.168.0.3: SQL thread running OK!
      192.168.0.3: IO thread running OK!
      192.168.0.3: SQL thread delay=0
      192.168.0.4: Role = Slave OK!
      192.168.0.4: Failover is disabled NG!
      192.168.0.4: HA lock OK!
      192.168.0.4: channel name=
      192.168.0.4: SQL thread running OK!
      192.168.0.4: IO thread running OK!
      192.168.0.4: SQL thread delay=0
          2 errors detected.
    2016-07-05T18:34:29 Done!

    2か所Failover is disabled NG!という問題を検出しますが、この時点ではそのままOKです。後で自動フェイルオーバーを有効にします。

  6. Transactdクライアントアプリケーションの先頭に、THNRのstart関数の呼び出しを追加します。

    haNameResolver::start("master_host", "slave_host", "192.168.0.2,192.168.0.3,192.168.0.4", 1, "root", "abcd");

    この関数の詳細はhaNameResolverを参照してください。

  7. クライアントアプリケーションの中で、実ホスト名を指定していた部分を仮想ホスト名に置換します。

    /* Access to the master */
    db->open("tdap://root@master_host/db/test?pwd=abcd");
    /* Access to the slave */
    db->open("tdap://root@slave_host/db/test?pwd=abcd");
  8. アプリケーションの動作チェックが済んで、正常に稼働することが確認できたら、haMgrを使って自動フェイルオーバーを有効にします。

    ./haMgr64 -c set_failover_enable -v 1 -o 192.168.0.2
    2016-07-06T10:21:04 Done!

transactd-startup_haオプションは、サーバー起動時のロールを設定します。

haMgrやAPI呼び出しを使用することで、サーバーを再起動せずにロールを指定することも可能です。

スイッチオーバーなどでマスターを切替えた後でサーバーを再起動すると、マスターは切替えられているにも関わらず、この起動オプションに従ったロールでサーバーが起動してしまいます。 起動時に前回終了時のロールを復元したい場合は、transactd-startup_haの値に4を足します。

ただし、障害でダウンしたマスターサーバーは、前回終了時のロールをマスターとして記憶しているため、修復後に起動するにはtransactd-startup_ha=0を指定し、スレーブとして明示する必要があります。

transactd-startup_haの値はdataフォルダのtransactd_srv_master.infoファイルに保存されます。 このファイルを削除すると復元は無効になります。

THAを使用するアプリケーションの注意点

同一スレッドの2つのdatabaseオブジェクトとトランザクション

同じサーバーに対する2つのdatabaseオブジェクトインスタンスDB_ADB_Bを使用しているとします。

まずDB_Aでトランザクションを開始し、そのトランザクション内でDB_Bを使用した際にエラーが発生したとします。 このときDB_ADB_Bが同じスレッドで使用された場合は、DB_Bでのエラーをトリガーとした再接続は行われません。 DB_Bで再接続するにはDB_Aのトランザクション終了を待つ必要がありますが、それらが同じスレッドだとそれ以上処理が進まず永久にトランザクションが終了しないためです。

THAの管理

健全性の維持

高可用運用を実現するには、異常時に正しくフェイルオーバーが行われるかどうか日ごろから確認しておく必要があります。 THAの管理プログラムhaMgrにはhealth_check機能があり、フェイルオーバーが問題なく行えるかどうかテストできます。 スケジューラ等で定期的にテストすることでTHAの健全性を維持するこができます。参照:ヘルスチェック

ヘルスチェックでは、repl_userusernameで示されるアカウントの有効性についてはチェックされません。 これらのアカウントが問題なくCHANGE MASTER TOなどのオペレーションを実行する権限を有するかどうか、別途テストを行ってください。

フェイルオーバーが行われたかどうかの確認

THNRによって自動フェイルオーバーが行われた場合、MySQLのerror.log(Windowsではイベントログ)にCHANGE MASTER TO ...とマスタ切替の内容が記録されます。この記録を監視することでフェイルオーバーが行われたかどうかを知ることができます。

フェイルオーバー処理の詳細なログ

THNRによる自動フェイルオーバーの詳細な記録は、クライアントのログに記録されます。(THNRによってhaMgrが実行された場合は、出力はエラーログにリダイレクトされます。haMgrを直接ユーザーが起動した場合はコンソールに出力されます。)

具体的には以下のように記録されます。参照:エラーログ

2016-07-07T09:29:33 Starting fail over...
  SLAVE_LIST=192.168.0.2,192.168.0.3,192.168.0.4
  HP6730B:8611: promote to master 
  HP6730B:8611: channel name=
  HP6730B:8611: set role=MASTER 
  HP6730B:8612: channel name=
  HP6730B:8612: stop slave all 
  HP6730B:8612: change master to new master, pos=slave_pos
  HP6730B:8612: start slave 
2016-07-07T09:29:33 Done!

Transactd ClientとSQLアクセスの両方を使用するアプリケーションでのTHA

THAは、Transactd APIのみを使用したアプリケーションでは、最高のHA性能を発揮します。 高可用運用が最大の課題であるならば、アプリケーションをそのように変更することをお勧めします。

THA構成は、SQLからのアクセスに弊害を与えることはありません。Transactd APIには親和的に、SQLアクセスには透過的に働きます。 両方のアクセスが必要な場合は、THAの構成要素のどれを組み合わせるかによって複数の選択肢があります。ここでは主な選択肢を説明します。

THAを主体に構成する

これまで説明したTHAをその通りに構成します。SQLからのアクセスの際、マスターホスト名を haNameResolver::master()、スレーブホスト名を haNameResolver::slave()を使って取得しアクセスを行うようにします。 これで通常の動作は何も問題ありません。

問題があるのは、マスターの障害発生後、最初にアクセスするのがSQLであった場合です。 Transactd APIであれば自動で障害検出とフェイルオーバーや再名前解決などが行われ、最小限のエラーで回復します。 しかし障害発生後の最初のアクセスがSQLであった場合は、それらが行われずそのままエラーになります。 次のTransactd APIアクセスがあるまで障害の回復が行われません。

この点に関しては、アプリケーションに「SQLでのアクセスエラーがあった際にTransactd APIでのアクセスを行う」処理を追加することで、回復を早めることが可能です。

自動フェイルオーバーを使わない場合は、この構成はベストな選択肢です。 マスターの障害発生後、手動でスイッチオーバーすればよいソリューションでは何の問題もなくこの構成で使用できます。 その場合は、自動フェイルオーバーを無効にしておきます。

./haMgr64 -c set_failover_enable -v 0 -o 192.168.0.2

障害発生後の最初のアクセスとは、クライアントのプロセス単位です。1つのクライアントプロセスはTHNRをすべてのスレッドで共有します。

従来よりあるMySQLのHA構成を使用する

従来のMySQLのHAは、以下のように構成されます。

  1. heartbeatなどによる障害検出
  2. mysqlfaileoverプログラムによるフェイルオーバー
  3. VirtualIPによるホストアドレスの変更
  4. ルータのARPキャッシュ更新

この構成の場合、アプリケーションでクライアントの再接続機能を有効にして、フェイルオーバー後新しいサーバーに再接続できるようにします。

/* アプリケーションの先頭で */
nsdatabase::setEnableAutoReconnect(true);

この構成の問題は、以下のようなものがあります。

従来よりあるMySQLのHA構成を主体にフェイルオーバーにhaMgrを使用する

フェイルオーバープログラムにhaMgrを使用すると、スイッチオーバーの際にTransactdによるトランザクションが実行されていた場合、その終了を待機するためエラーにならないメリットがあります。

haMgrリファレンス

haMgrはTHAをコントロールするためのプログラムです。以下の処理を行うことができます。

コマンドラインパラメータ

command line option:
  -c [ --command ]         command [switchover | failover | demote_to_slave | set_failover_enable | set_server_role | health_check]
  -o [ --cur_master ]      current master host name
  -n [ --new_master ]      new master host name
  -C [ --channel ]         new master channel name
  -P [ --repl_port ]       new master port
  -r [ --repl_user ]       new master repl user
  -d [ --repl_passwd ]     new master repl password
  -O [ --repl_option ]     option params for change master(ex:MASTER_CONNECT_RETRY=30)
  -s [ --slaves ]          slave list for failover
  -a [ --portmap ]         port map ex:3307:8611
  -v [ --value ]           value (For set_failover_enable or set_server_role)
  -u [ --username ]        transactd username
  -p [ --password ]        transactd password
  -R [ --readonly ]        0 | 1: When it is 1, the READONLY variable will be set ON to slaves and OFF to a master
  -D [ --disable_demote ]  0 | 1: disable old master demote

スイッチオーバー

マスターを切り替えます。

例:マスターを192.168.0.2から192.168.0.3に切り替える。

./haMgr64 -c switchover -o 192.168.0.2 -n 192.168.0.3 -R1 -r replication_user -d abcd -u root -p xxxx

スイッチオーバーは、マスターを切り替えると同時に、旧マスターをスレーブに降格させます。

フェイルオーバー

フェイルオーバーを手動で実行します。

例:現在のスレーブが192.168.0.3192.168.0.4の2台の状態でフェイルオーバーを実行する。

./haMgr64 -c failover -s 192.168.0.3,192.168.0.4 -u root -p xxxx

マスターの降格

例:ダウンした旧マスター192.168.0.2の修復が完了したので、192.168.0.3のスレーブに加える。

./haMgr64 -c demote_to_slave -o 192.168.0.2 -n 192.168.0.3 -r replication_user -d abcd -u root -p xxxx

フェイルオーバーの有効/無効切替

フェイルオーバーの有効/無効を切り替えます。値には、有効化は1、無効化は0を指定します。

例:現在のマスターサーバーは192.168.0.3で、フェイルオーバーを有効化する。

./haMgr64 -c set_failover_enable -v 1 -o 192.168.0.3 -u root -p xxxx

サーバーのロール変更

サーバーのロールを変更します。値には、マスターには1、スレーブには0を指定します。

例:192.168.0.3のロールをマスターにする。

./haMgr64 -c set_server_role -o 192.168.0.3 -v 1 -u root -p xxxx

構成のヘルスチェック

ヘルスチェックでは、マスターとマスターに接続しているすべてのスレーブのレプリケーションの状態・THAのためのサーバーロール・ロック可否・フェイルオーバーの有効/無効を確認して標準出力にレポートします。

プログラムの戻り値は、正常な場合は0、エラーがある場合は1が返されます。

例:マスターが192.168.0.2で、スレーブが192.168.0.3192.168.0.4の2台の状態で、ヘルスチェックを行う。

./haMgr64 -c health_check -o 192.168.0.2 -s 192.168.0.3,192.168.0.4 -u root -p xxxx
2016-07-05T18:34:28 Starting health check...
  SLAVE_LIST=192.168.0.3,192.168.0.4
  192.168.0.2: Role = Master OK!
  192.168.0.2: HA lock OK!
  192.168.0.3: Role = Slave OK!
  192.168.0.3: Failover is enabled OK!
  192.168.0.3: HA lock OK!
  192.168.0.3: channel name=
  192.168.0.3: SQL thread running OK!
  192.168.0.3: IO thread running OK!
  192.168.0.3: SQL thread delay=0
  192.168.0.4: Role = Slave OK!
  192.168.0.4: Failover is enabled OK!
  192.168.0.4: HA lock OK!
  192.168.0.4: channel name=
  192.168.0.4: SQL thread running OK!
  192.168.0.4: IO thread running OK!
  192.168.0.4: SQL thread delay=0
      No errors detected.
2016-07-05T18:34:29 Done!

ヘルスチェックでは、障害時に正しくフェイルオーバーできるかどうかを確認できます。 これを定期的に行うことで信頼性を高めることができます。

正しくヘルスチェックを行うには、パラメータの値に haNameResolver::start() と同じものを渡すことが重要です。