Documentation Home

5.5.5.3 使用版本令牌

在使用版本令牌之前,请按照 第 5.5.5.2 节“安装或卸载版本令牌”中提供的说明进行安装。

Version Tokens 可以发挥作用的一个场景是访问一组 MySQL 服务器但需要通过监视它们并根据负载变化调整服务器分配来管理它们以达到负载平衡目的的系统。这样的系统包括以下元素:

  • 要管理的 MySQL 服务器的集合。

  • 与服务器通信并将它们组织成高可用性组的管理或管理应用程序。组服务于不同的目的,每个组中的服务器可能有不同的分配。某个组内服务器的分配可以随时更改。

  • 访问服务器以检索和更新数据的客户端应用程序,根据分配给它们的目的选择服务器。例如,客户端不应向只读服务器发送更新。

版本令牌允许根据分配管理服务器访问,而无需客户端重复查询服务器有关其分配的信息:

  • 管理应用程序执行服务器分配并在每个服务器上建立版本令牌以反映其分配。应用程序缓存此信息以提供对其的中央访问点。

    如果在某个时候管理应用程序需要更改服务器分配(例如,将其从允许写入更改为只读),它会更改服务器的版本令牌列表并更新其缓存。

  • 为了提高性能,客户端应用程序从管理应用程序获取缓存信息,使它们能够避免为每个语句检索有关服务器分配的信息。根据它发出的语句类型(例如,读取与写入),客户端选择合适的服务器并连接到它。

  • 此外,客户端向服务器发送它自己的特定于客户端的版本令牌,以注册它需要的服务器分配。对于客户端发送给服务器的每个语句,服务器都会将自己的令牌列表与客户端令牌列表进行比较。如果服务器令牌列表包含客户端令牌列表中存在的所有具有相同值的令牌,则存在匹配并且服务器执行该语句。

    另一方面,管理应用程序可能更改了服务器分配及其版本令牌列表。在这种情况下,新的服务器分配现在可能与客户端要求不兼容。服务器和客户端令牌列表之间发生令牌不匹配,并且服务器在回复语句时返回错误。这指示客户端从管理应用程序缓存中刷新其版本令牌信息,并选择一个新的服务器进行通信。

可以通过不同的方式实现用于检测版本令牌错误和选择新服务器的客户端逻辑:

  • 客户端可以自行处理所有版本令牌注册、不匹配检测和连接切换。

  • 这些操作的逻辑可以在管理客户端和 MySQL 服务器之间连接的连接器中实现。这样的连接器可能会处理不匹配错误检测并自行重新发送语句,或者它可能会将错误传递给应用程序并让应用程序重新发送语句。

以下示例以更具体的形式说明了前面的讨论。

当版本令牌在给定服务器上初始化时,服务器的版本令牌列表为空。令牌列表维护是通过调用函数来执行的。SUPER 调用任何 Version Token 函数都需要权限,因此令牌列表修改应由具有该权限的管理或管理应用程序完成 。

假设管理应用程序与一组服务器通信,客户端查询这些服务器以访问员工和产品数据库(分别命名为empprod)。所有服务器都被允许处理数据检索语句,但只有其中一些服务器被允许进行数据库更新。为了在特定于数据库的基础上处理这个问题,管理应用程序在每个服务器上建立一个版本令牌列表。在给定服务器的令牌列表中,令牌名称代表数据库名称,令牌值是readwrite 取决于数据库是否必须以只读方式使用或是否可以读取和写入。

客户端应用程序通过设置系统变量注册它们需要服务器匹配的版本令牌列表。变量设置发生在特定于客户的基础上,因此不同的客户可以注册不同的要求。默认情况下,客户端令牌列表为空,与任何服务器令牌列表匹配。当客户端将其令牌列表设置为非空值时,匹配可能成功或失败,具体取决于服务器版本令牌列表。

要为服务器定义版本令牌列表,管理应用程序调用该 version_tokens_set()函数。(还有用于修改和显示令牌列表的函数,稍后描述。)例如,应用程序可能将这些语句发送到一组三个服务器:

服务器 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.                     |
+-------------------------------------------+

每种情况下的令牌列表都指定为以分号分隔的 成对列表。生成的令牌列表值导致这些服务器 assingments: name=value

  • 任何服务器都接受对任一数据库的读取。

  • 只有服务器 2 接受emp 数据库更新。

  • 只有服务器 3 接受 prod数据库更新。

除了为每个服务器分配一个版本令牌列表之外,管理应用程序还维护一个反映服务器分配的缓存。

Before communicating with the servers, a client application contacts the management application and retrieves information about server assignments. Then the client selects a server based on those assignments. Suppose that a client wants to perform both reads and writes on the emp database. Based on the preceding assignments, only server 2 qualifies. The client connects to server 2 and registers its server requirements there by setting its version_tokens_session system variable:

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

For subsequent statements sent by the client to server 2, the server compares its own version token list to the client list to check whether they match. If so, statements execute normally:

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)

Discrepancies between the server and client version token lists can occur two ways:

As long as the assignment of server 2 does not change, the client continues to use it for reads and writes. But suppose that the management application wants to change server assignments so that writes for the emp database must be sent to server 1 instead of server 2. To do this, it uses version_tokens_edit() to modify the emp token value on the two servers (and updates its cache of server assignments):

Server 1:

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

Server 2:

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

version_tokens_edit() modifies the named tokens in the server token list and leaves other tokens unchanged.

The next time the client sends a statement to server 2, its own token list no longer matches the server token list and an error occurs:

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

In this case, the client should contact the management application to obtain updated information about server assignments, select a new server, and send the failed statement to the new server.

Note

Each client must cooperate with Version Tokens by sending only statements in accordance with the token list that it registers with a given server. For example, if a client registers a token list of 'emp=read', there is nothing in Version Tokens to prevent the client from sending updates for the emp database. The client itself must refrain from doing so.

For each statement received from a client, the server implicitly uses locking, as follows:

  • Take a shared lock for each token named in the client token list (that is, in the version_tokens_session value)

  • Perform the comparison between the server and client token lists

  • Execute the statement or produce an error depending on the comparison result

  • Release the locks

The server uses shared locks so that comparisons for multiple sessions can occur without blocking, while preventing changes to the tokens for any session that attempts to acquire an exclusive lock before it manipulates tokens of the same names in the server token list.

The preceding example uses only a few of the functions included in the Version Tokens plugin library, but there are others. One set of functions permits the server's list of version tokens to be manipulated and inspected. Another set of functions permits version tokens to be locked and unlocked.

These functions permit the server's list of version tokens to be created, changed, removed, and inspected:

  • version_tokens_set() completely replaces the current list and assigns a new list. The argument is a semicolon-separated list of name=value pairs.

  • version_tokens_edit() enables partial modifications to the current list. It can add new tokens or change the values of existing tokens. The argument is a semicolon-separated list of name=value pairs.

  • version_tokens_delete() deletes tokens from the current list. The argument is a semicolon-separated list of token names.

  • version_tokens_show() displays the current token list. It takes no argument.

Each of those functions, if successful, returns a binary string indicating what action occurred. The following example establishes the server token list, modifies it by adding a new token, deletes some tokens, and displays the resulting token list:

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;               |
+-----------------------+

Warnings occur if a token list is malformed:

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)

As mentioned previously, version tokens are defined using a semicolon-separated list of name=value pairs. Consider this invocation of 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 interprets the argument as follows:

  • Whitespace around names and values is ignored. Whitespace within names and values is permitted. (For version_tokens_delete(), which takes a list of names without values, whitespace around names is ignored.)

  • There is no quoting mechanism.

  • Order of tokens is not significant except that if a token list contains multiple instances of a given token name, the last value takes precedence over earlier values.

Given those rules, the preceding version_tokens_set() call results in a token list with two tokens: tok1 has the value 1'2 3"4, and tok2 has the value a = b. To verify this, call version_tokens_show():

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

If the token list contains two tokens, why did version_tokens_set() return the value 3 version tokens set? That occurred because the original token list contained two definitions for tok1, and the second definition replaced the first.

The Version Tokens token-manipulation functions place these constraints on token names and values:

  • Token names cannot contain = or ; characters and have a maximum length of 64 characters.

  • Token values cannot contain ; characters. Length of values is constrained by the value of the max_allowed_packet system variable.

  • Version Tokens treats token names and values as binary strings, so comparisons are case-sensitive.

Version Tokens also includes a set of functions enabling tokens to be locked and unlocked:

Each locking function returns nonzero for success. Otherwise, an error occurs:

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)'.

Locking using Version Tokens locking functions is advisory; applications must agree to cooperate.

It is possible to lock nonexisting token names. This does not create the tokens.

Note

Version Tokens locking functions are based on the locking service described at Section 5.5.6.1, “The Locking Service”, and thus have the same semantics for shared and exclusive locks. (Version Tokens uses the locking service routines built into the server, not the locking service function interface, so those functions need not be installed to use Version Tokens.) Locks acquired by Version Tokens use a locking service namespace of version_token_locks. Locking service locks can be monitored using the Performance Schema, so this is also true for Version Tokens locks. For details, see Locking Service Monitoring.

对于 Version Tokens 锁定函数,完全按照指定使用令牌名称参数。周围的空格不会被忽略,=并且; 允许使用字符。这是因为 Version Tokens 只是将要锁定的令牌名称按原样传递给锁定服务。