MySQL 8.0 リファレンスマニュアル


5.6.6.3 バージョントークンの使用

バージョントークンを使用する前に、セクション5.6.6.2「バージョントークンのインストールまたはアンインストール」 に記載されている手順に従ってインストールします。

バージョントークンが役立つシナリオは、MySQL サーバーのコレクションにアクセスするシステムですが、ロードバランシングの目的でそれらを監視し、負荷の変更に応じてサーバー割当てを調整することで管理する必要があります。 このようなシステムは、次の要素で構成されます:

  • 管理対象の MySQL サーバーのコレクション。

  • サーバーと通信し、それらを高可用性グループに編成する管理アプリケーションまたは管理アプリケーション。 グループは異なる目的で使用され、各グループ内のサーバーには異なる割当てがある場合があります。 特定のグループ内のサーバーの割当ては、いつでも変更できます。

  • サーバーにアクセスしてデータを取得および更新し、割り当てられた目的に応じてサーバーを選択するクライアントアプリケーション。 たとえば、クライアントは読み取り専用サーバーに更新を送信しないでください。

バージョントークンを使用すると、クライアントが割当てについてサーバーに繰り返しクエリーすることなく、割当てに従ってサーバーアクセスを管理できます:

  • 管理アプリケーションはサーバー割当てを実行し、その割当てを反映するために各サーバーにバージョントークンを確立します。 アプリケーションはこの情報をキャッシュして、集中アクセスポイントを提供します。

    ある時点で、管理アプリケーションがサーバー割当てを変更する必要がある場合 (たとえば、書込みを許可から読取り専用に変更する場合)、サーバーバージョントークンリストを変更し、そのキャッシュを更新します。

  • パフォーマンスを向上させるために、クライアントアプリケーションは管理アプリケーションからキャッシュ情報を取得するため、各ステートメントのサーバー割当てに関する情報を取得する必要がなくなります。 クライアントは、発行するステートメントのタイプ (読み取りと書き込みなど) に基づいて、適切なサーバーを選択して接続します。

  • さらに、クライアントはサーバーにクライアント固有のバージョントークンを送信して、サーバーに必要な割当てを登録します。 クライアントからサーバーに送信されたステートメントごとに、サーバーは独自のトークンリストをクライアントトークンリストと比較します。 サーバートークンリストに同じ値を持つクライアントトークンリストに存在するすべてのトークンが含まれている場合、一致があり、サーバーはステートメントを実行します。

    一方、管理アプリケーションによってサーバー割当てとそのバージョントークンリストが変更された可能性があります。 この場合、新しいサーバー割当てがクライアント要件と互換性がなくなる可能性があります。 サーバーとクライアントトークンリストの間でトークンの不一致が発生し、サーバーはステートメントへの応答としてエラーを返します。 これは、管理アプリケーションキャッシュからバージョントークン情報をリフレッシュし、通信する新しいサーバーを選択するようクライアントに指示します。

バージョントークンエラーを検出して新しいサーバーを選択するためのクライアント側ロジックは、様々な方法で実装できます:

  • クライアントは、すべてのバージョントークン登録、不一致検出および接続切替え自体を処理できます。

  • これらのアクションのロジックは、クライアントと MySQL サーバー間の接続を管理するコネクタに実装できます。 このようなコネクタは、不一致エラー検出およびステートメントの再送信自体を処理したり、アプリケーションにエラーを渡してアプリケーションに残し、ステートメントを再送信したりする場合があります。

次の例は、より具体的な形式で前述の説明を示しています。

特定のサーバーでバージョントークンが初期化されると、サーバーバージョントークンリストは空になります。 トークンリストのメンテナンスは、ユーザー定義関数 (UDF) をコールすることで実行されます。 任意のバージョントークン UDF をコールするには、VERSION_TOKEN_ADMIN 権限 (または非推奨の SUPER 権限) が必要であるため、トークンリストの変更は、その権限を持つ管理アプリケーションまたは管理アプリケーションによって実行される必要があります。

管理アプリケーションが、従業員および製品データベース (それぞれ emp および prod という名前) にアクセスするためにクライアントによってクエリーされる一連のサーバーと通信するとします。 すべてのサーバーでデータ取得ステートメントの処理が許可されていますが、一部のサーバーでのみデータベースの更新が許可されています。 これをデータベース固有のベースで処理するために、管理アプリケーションは各サーバーにバージョントークンのリストを確立します。 特定のサーバーのトークンリストでは、トークン名はデータベース名を表し、トークン値は、データベースを読取り専用で使用する必要があるかどうか、または読取りおよび書込みが可能かどうかに応じて read または write です。

クライアントアプリケーションは、システム変数を設定して、サーバーが一致する必要があるバージョントークンのリストを登録します。 変数の設定はクライアント固有のベースで行われるため、クライアントごとに異なる要件を登録できます。 デフォルトでは、クライアントトークンリストは空で、任意のサーバートークンリストに一致します。 クライアントがトークンリストを空でない値に設定すると、サーバーバージョンのトークンリストに応じて、照合が成功または失敗する場合があります。

サーバーのバージョントークンリストを定義するために、管理アプリケーションは version_tokens_set() UDF を呼び出します。 (後で説明するように、トークンリストを変更および表示するための UDF もあります。) たとえば、アプリケーションは次のステートメントを 3 つのサーバーのグループに送信します:

サーバー 1:

mysql> SELECT version_tokens_set('emp=read;prod=read');
+------------------------------------------+
| version_tokens_set('emp=read;prod=read') |
+------------------------------------------+
| 2 version tokens set.                    |
+------------------------------------------+

サーバー 2:

mysql> SELECT version_tokens_set('emp=write;prod=read');
+-------------------------------------------+
| version_tokens_set('emp=write;prod=read') |
+-------------------------------------------+
| 2 version tokens set.                     |
+-------------------------------------------+

サーバー 3:

mysql> SELECT version_tokens_set('emp=read;prod=write');
+-------------------------------------------+
| version_tokens_set('emp=read;prod=write') |
+-------------------------------------------+
| 2 version tokens set.                     |
+-------------------------------------------+

いずれの場合も、トークンリストはセミコロンで区切られた name=value ペアのリストとして指定されます。 生成されるトークンリストの値は、次のサーバー割当てになります:

  • いずれかのサーバーがいずれかのデータベースの読取りを受け入れます。

  • サーバー 2 のみが emp データベースの更新を受け入れます。

  • prod データベースの更新を受け入れるのはサーバー 3 のみです。

管理アプリケーションは、各サーバーにバージョントークンリストを割り当てるだけでなく、サーバー割当てを反映するキャッシュも保持します。

サーバーと通信する前に、クライアントアプリケーションは管理アプリケーションに接続し、サーバー割当てに関する情報を取得します。 次に、クライアントはそれらの割り当てに基づいてサーバーを選択します。 クライアントが emp データベースで読取りと書込みの両方を実行するとします。 前述の割当てに基づいて、サーバー 2 のみが修飾されます。 クライアントはサーバー 2 に接続し、その version_tokens_session システム変数を設定してサーバー要件を登録します:

mysql> SET @@SESSION.version_tokens_session = 'emp=write';

クライアントからサーバー 2 に送信される後続のステートメントの場合、サーバーは独自のバージョントークンリストをクライアントリストと比較して、それらが一致するかどうかを確認します。 その場合、ステートメントは正常に実行されます:

mysql> UPDATE emp.employee SET salary = salary * 1.1 WHERE id = 4981;
Query OK, 1 row affected (0.07 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> SELECT last_name, first_name FROM emp.employee WHERE id = 4981;
+-----------+------------+
| last_name | first_name |
+-----------+------------+
| Smith     | Abe        |
+-----------+------------+
1 row in set (0.01 sec)

サーバとクライアントのバージョントークンリストの不一致は、次の 2 つの方法で発生します:

  • version_tokens_session 値のトークン名がサーバートークンリストに存在しません。 この場合、ER_VTOKEN_PLUGIN_TOKEN_NOT_FOUND エラーが発生します。

  • version_tokens_session 値のトークン値は、サーバートークンリストの対応するトークンの値とは異なります。 この場合、ER_VTOKEN_PLUGIN_TOKEN_MISMATCH エラーが発生します。

サーバー 2 の割り当てが変更されないかぎり、クライアントはそれを読み取りおよび書き込みに引き続き使用します。 ただし、管理アプリケーションがサーバー割当てを変更して、emp データベースの書込みをサーバー 2 ではなくサーバー 1 に送信する必要があるとします。 これを行うには、version_tokens_edit() を使用して、2 つのサーバーの emp トークン値を変更します (また、サーバー割当てのキャッシュを更新します):

サーバー 1:

mysql> SELECT version_tokens_edit('emp=write');
+----------------------------------+
| version_tokens_edit('emp=write') |
+----------------------------------+
| 1 version tokens updated.        |
+----------------------------------+

サーバー 2:

mysql> SELECT version_tokens_edit('emp=read');
+---------------------------------+
| version_tokens_edit('emp=read') |
+---------------------------------+
| 1 version tokens updated.       |
+---------------------------------+

version_tokens_edit() では、サーバートークンリスト内の名前付きトークンが変更され、他のトークンは変更されません。

クライアントが次回サーバー 2 にステートメントを送信するときに、独自のトークンリストがサーバーのトークンリストと一致しなくなり、エラーが発生します:

mysql> UPDATE emp.employee SET salary = salary * 1.1 WHERE id = 4982;
ERROR 3136 (42000): Version token mismatch for emp. Correct value read

この場合、クライアントは管理アプリケーションに連絡して、サーバー割当てに関する更新情報を取得し、新しいサーバーを選択して、失敗したステートメントを新しいサーバーに送信する必要があります。

注記

各クライアントは、特定のサーバーに登録されているトークンリストに従ってステートメントのみを送信することで、バージョントークンと連携する必要があります。 たとえば、クライアントが'emp=read'のトークンリストを登録した場合、クライアントが emp データベースの更新を送信できないようにするためのものがバージョントークンにありません。 クライアント自体がそのような処理を再試行する必要があります。

クライアントから受信したステートメントごとに、サーバーは次のように暗黙的にロックを使用します:

  • クライアントトークンリストで指定されたトークン (version_tokens_session 値) ごとに共有ロックを取得

  • サーバーとクライアントトークンリストの比較を実行

  • ステートメントを実行するか、比較結果に応じてエラーを生成

  • ロックの解除

サーバーは共有ロックを使用するため、ブロックせずに複数のセッションの比較を行うことができますが、サーバートークンリスト内の同じ名前のトークンを操作する前に排他ロックを取得しようとするセッションのトークンに対する変更を防止します。

前述の例では、バージョントークンプラグインライブラリに含まれているユーザー定義の一部のみを使用していますが、他にもあります。 UDF のセットでは、バージョントークンのサーバーリストを操作および検査できます。 UDF の別のセットでは、バージョントークンをロックおよびロック解除できます。

次の UDF を使用すると、バージョントークンのサーバーリストを作成、変更、削除および検査できます:

  • version_tokens_set() では、現在のリストが完全に置換され、新しいリストが割り当てられます。 引数は、セミコロンで区切られた name=value ペアのリストです。

  • version_tokens_edit() では、現在のリストを部分的に変更できます。 新しいトークンを追加したり、既存のトークンの値を変更できます。 引数は、セミコロンで区切られた name=value ペアのリストです。

  • version_tokens_delete() は、現在のリストからトークンを削除します。 引数は、セミコロンで区切られたトークン名のリストです。

  • version_tokens_show() に現在のトークンリストが表示されます。 引数は取りません。

これらの各関数は、成功した場合、発生したアクションを示すバイナリ文字列を返します。 次の例では、サーバートークンリストを確立し、新しいトークンを追加して変更し、一部のトークンを削除して、結果のトークンリストを表示します:

mysql> SELECT version_tokens_set('tok1=a;tok2=b');
+-------------------------------------+
| version_tokens_set('tok1=a;tok2=b') |
+-------------------------------------+
| 2 version tokens set.               |
+-------------------------------------+
mysql> SELECT version_tokens_edit('tok3=c');
+-------------------------------+
| version_tokens_edit('tok3=c') |
+-------------------------------+
| 1 version tokens updated.     |
+-------------------------------+
mysql> SELECT version_tokens_delete('tok2;tok1');
+------------------------------------+
| version_tokens_delete('tok2;tok1') |
+------------------------------------+
| 2 version tokens deleted.          |
+------------------------------------+
mysql> SELECT version_tokens_show();
+-----------------------+
| version_tokens_show() |
+-----------------------+
| tok3=c;               |
+-----------------------+

トークンリストの形式が正しくない場合、警告が発生します:

mysql> SELECT version_tokens_set('tok1=a; =c');
+----------------------------------+
| version_tokens_set('tok1=a; =c') |
+----------------------------------+
| 1 version tokens set.            |
+----------------------------------+
1 row in set, 1 warning (0.00 sec)

mysql> SHOW WARNINGS\G
*************************** 1. row ***************************
  Level: Warning
   Code: 42000
Message: Invalid version token pair encountered. The list provided
         is only partially updated.
1 row in set (0.00 sec)

前述のように、バージョントークンは、セミコロンで区切られた name=value ペアのリストを使用して定義されます。 version_tokens_set() の次の呼出しについて考えてみます:

mysql> SELECT version_tokens_set('tok1=b;;; tok2= a = b ; tok1 = 1\'2 3"4')
+---------------------------------------------------------------+
| version_tokens_set('tok1=b;;; tok2= a = b ; tok1 = 1\'2 3"4') |
+---------------------------------------------------------------+
| 3 version tokens set.                                         |
+---------------------------------------------------------------+

バージョントークンは、引数を次のように解釈します:

  • 名前と値の前後の空白は無視されます。 名前と値の中に空白を含めることができます。 (値のない名前のリストを取る version_tokens_delete() の場合、名前の前後の空白は無視されます。)

  • 引用メカニズムはありません。

  • トークンの順序は重要ではありませんが、トークンリストに特定のトークン名の複数のインスタンスが含まれている場合は、最後の値が以前の値より優先されます。

これらのルールを考慮すると、前述の version_tokens_set() コールの結果、2 つのトークンを含むトークンリストが生成されます: tok1 の値は 1'2 3"4 で、tok2 の値は a = b です。 これを確認するには、version_tokens_show() をコールします:

mysql> SELECT version_tokens_show();
+--------------------------+
| version_tokens_show()    |
+--------------------------+
| tok2=a = b;tok1=1'2 3"4; |
+--------------------------+

トークンリストに 2 つのトークンが含まれている場合、version_tokens_set() が値 3 version tokens set を返したのはなぜですか。 これは、元のトークンリストに tok1 の 2 つの定義が含まれ、2 つ目の定義が最初の定義に置き換わったために発生しました。

バージョントークンのトークン操作 UDF は、トークン名と値に次の制約を設定します:

  • トークン名に = または;文字を含めることはできず、最大長は 64 文字です。

  • トークン値に;文字を含めることはできません。 値の長さは、max_allowed_packet システム変数の値によって制約されます。

  • バージョントークンはトークン名と値をバイナリ文字列として扱うため、比較では大文字と小文字が区別されます。

バージョントークンには、トークンをロックおよびロック解除できる UDF のセットも含まれています:

  • version_tokens_lock_exclusive() は排他的バージョントークンロックを取得します。 1 つ以上のロック名とタイムアウト値のリストを取ります。

  • version_tokens_lock_shared() は、共有バージョンのトークンロックを取得します。 1 つ以上のロック名とタイムアウト値のリストを取ります。

  • version_tokens_unlock() は、バージョントークンロック (排他的および共有) を解放します。 引数は取りません。

各ロック関数は、成功した場合はゼロ以外を返します。 それ以外の場合は、次のエラーが発生します:

mysql> SELECT version_tokens_lock_shared('lock1', 'lock2', 0);
+-------------------------------------------------+
| version_tokens_lock_shared('lock1', 'lock2', 0) |
+-------------------------------------------------+
|                                               1 |
+-------------------------------------------------+

mysql> SELECT version_tokens_lock_shared(NULL, 0);
ERROR 3131 (42000): Incorrect locking service lock name '(null)'.

バージョントークンロック機能を使用したロックは勧告です。アプリケーションは協調する必要があります。

存在しないトークン名をロックできます。 トークンは作成されません。

注記

バージョントークンロック関数は、セクション5.6.8.1「ロックサービス」 で説明されているロックサービスに基づいているため、共有ロックと排他ロックのセマンティクスは同じです。 (バージョントークンは、ロックサービス UDF インタフェースではなく、サーバーに組み込まれたロックサービスルーチンを使用するため、バージョントークンを使用するためにこれらの UDF をインストールする必要はありません。) バージョントークンによって取得されたロックは、version_token_locks のロックサービスネームスペースを使用します。 ロックサービスのロックはパフォーマンススキーマを使用してモニターできるため、これはバージョントークンロックにも当てはまります。 詳細は、ロックサービスの監視を参照してください。

バージョントークンロック関数の場合、トークン名引数は指定したとおりに正確に使用されます。 前後の空白は無視されず、= および;文字は許可されます。 これは、バージョントークンが単にロック対象のトークン名をロックサービスにそのまま渡すためです。


関連キーワード:  サーバー, version, tokens, バージョン, リスト, ロック, アプリケーション, 管理, emp, 変更