5.5.5.3 Использование маркеров версии
Перед использованием маркеров версии, установите их согласно инструкциям в разделе 5.5.5.2, «Установка или удаление маркеров версии».
Ситуация, в которой маркеры версии могут быть полезны, — это система, которая обращается к набору серверов MySQL, но нуждается в управлении ими для балансировки нагрузки, отслеживая их и корректируя назначения серверов в соответствии с изменениями нагрузки. Такая система состоит из следующих элементов:
Набор серверов MySQL, подлежащих управлению.
Административное или управляющее приложение, которое взаимодействует с серверами и организует их в группы высокой доступности. Группы служат различным целям, и серверы в каждой группе могут иметь разные назначения. Назначение сервера в определённой группе может измениться в любой момент.
Приложения-клиенты, которые обращаются к серверам для получения и обновления данных, выбирая серверы в соответствии с назначенными им целями. Например, клиент не должен отправлять обновление на сервер, ограниченный только чтением.
Маркеры версии позволяют управлять доступом к серверу в соответствии с назначением, без необходимости, чтобы клиенты многократно запрашивали информацию о назначении серверов:
-
Управляющее приложение выполняет назначения серверов и устанавливает маркеры версии на каждом сервере, чтобы отразить его назначение. Приложение кеширует эту информацию для предоставления центральной точки доступа к ней.
Если в какой-то момент управляющее приложение нужно изменить назначение сервера (например, изменить его с разрешения записи на только чтение), оно изменяет список маркеров версии сервера и обновляет свой кэш.
Для повышения производительности приложения-клиенты получают информацию из кэша управляющего приложения, позволяя избежать необходимости извлечения информации о назначениях серверов для каждой инструкции. Основываясь на типе выполняемых инструкций (например, чтение или запись), клиент выбирает соответствующий сервер и подключается к нему.
-
Кроме того, клиент отправляет на сервер свои собственные маркеры версии, относящиеся к клиенту, чтобы указать требуемое назначение сервера. Для каждой инструкции, отправленной клиентом на сервер, сервер сравнивает свой собственный список маркеров со списком маркеров клиента. Если список маркеров сервера содержит все маркеры, присутствующие в списке маркеров клиента с одинаковыми значениями, возникает совпадение, и сервер выполняет инструкцию.
С другой стороны, возможно, управляющее приложение изменило назначение сервера и его список маркеров версии. В этом случае новое назначение сервера может теперь быть несовместимо с требованиями клиента. Происходит несовпадение маркеров между списками маркеров сервера и клиента, и сервер возвращает ошибку в ответ на инструкцию. Это указание клиенту обновить информацию о маркерах версии из кэша управляющего приложения и выбрать новый сервер для связи.
Логика клиентской стороны для обнаружения ошибок маркеров версии и выбора нового сервера может быть реализована различными способами:
Клиент может сам обрабатывать регистрацию всех маркеров версии, обнаружение несовпадений и переключение соединений.
Логика этих действий может быть реализована в соединителе, который управляет соединениями между клиентами и серверами MySQL. Такой соединитель может сам обрабатывать обнаружение ошибок несовпадения и повторную отправку инструкции, или он может передать ошибку приложению и оставить повторную отправку инструкции приложению.
Следующий пример иллюстрирует обсуждаемые моменты более конкретно.
Когда маркеры версии инициализируются на определённом сервере, список маркеров версии сервера пуст. Ведение списка маркеров выполняется путём вызова функций. Для вызова любой из функций маркеров версии требуется привилегия SUPER, поэтому ожидается, что изменение списка маркеров будет выполняться управляющим или административным приложением, имеющим это разрешение.
Предположим, что управляющее приложение взаимодействует с набором серверов, которые запрашиваются клиентами для доступа к базам данных сотрудников и продуктов (называемым emp и prod соответственно). Все серверы разрешено обрабатывать запросы на получение данных, но только некоторые из них разрешено выполнять обновления базы данных. Для обработки этого на базе данных, управляющее приложение устанавливает список маркеров версии на каждом сервере. В списке маркеров для данного сервера имена маркеров представляют имена баз данных, а значения маркеров — read или write в зависимости от того, должна ли база данных использоваться только для чтения или может принимать как чтения, так и записи.
Клиентские приложения регистрируют список маркеров версии, которые они требуют, чтобы сервер сопоставил, установив системную переменную. Установка переменной происходит на основе каждого клиента, поэтому разные клиенты могут регистрировать разные требования. По умолчанию список маркеров клиента пуст, что соответствует любому списку маркеров сервера. Когда клиент устанавливает свой список маркеров в ненулевое значение, соответствие может быть успешным или неудачным, в зависимости от списка маркеров версии сервера.
Чтобы определить список маркеров версии для сервера, управляющее приложение вызывает функцию 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. |
+-------------------------------------------+
В каждом случае список маркеров указывается в виде списка пар , разделённых точкой с запятой. Результирующие значения списков маркеров приводят к таким назначениям серверов: name=value
Любой сервер принимает запросы на чтение для любой базы данных.
Только сервер 2 принимает обновления для базы данных
emp.Только сервер 3 принимает обновления для базы данных
prod.
В дополнение к назначению каждого сервера списка маркеров версии, управляющее приложение также поддерживает кэш, который отражает назначения серверов.
Перед взаимодействием с серверами приложение-клиент связывается с управляющим приложением и извлекает информацию о назначениях серверов. Затем клиент выбирает сервер на основе этих назначений. Предположим, что клиент хочет выполнить как чтения, так и записи в базе данных 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)
Расхождения между списками маркеров версии сервера и клиента могут произойти двумя способами:
Имя маркера в значении
version_tokens_sessionотсутствует в списке маркеров сервера. В этом случае возникает ошибка.Значение маркера в значении
version_tokens_sessionотличается от значения соответствующего маркера в списке маркеров сервера. В этом случае возникает ошибка.
Пока назначение сервера 2 не изменится, клиент продолжает использовать его для чтения и записи. Но предположим, что управляющее приложение хочет изменить назначения серверов так, чтобы записи для базы данных emp должны быть отправлены на сервер 1 вместо сервера 2. Для этого оно использует version_tokens_edit() для изменения значения маркера 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)Выполнить сравнение между списками маркеров сервера и клиента
Выполнить инструкцию или сгенерировать ошибку в зависимости от результата сравнения
Освободить блокировки
Сервер использует общие блокировки, чтобы сравнения для нескольких сессий могли происходить без блокировки, одновременно предотвращая изменения маркеров для любой сессии, которая пытается получить эксклюзивную блокировку, прежде чем она манипулирует маркерами с одинаковыми именами в списке маркеров сервера.
В предыдущем примере использовались только некоторые из функций, включённых в библиотеку плагина маркеров версии, но есть и другие. Одна группа функций позволяет манипулировать и инспектировать список маркеров версии сервера. Другая группа функций позволяет блокировать и разблокировать маркеры версии.
Эти функции позволяют создавать, изменять, удалять и просматривать список маркеров версии сервера:
version_tokens_set()полностью заменяет текущий список и присваивает новый. Аргументом является список пар, разделённых точкой с запятой.name=valueversion_tokens_edit()позволяет выполнять частичные изменения в текущем списке. Она может добавлять новые маркеры или изменять значения существующих. Аргументом является список пар, разделённых точкой с запятой.name=valueversion_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=valueversion_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() приводит к списку маркеров с двумя маркерами: 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; |
+--------------------------+
Если список маркеров содержит два маркера, почему version_tokens_set() вернул значение 3 version tokens set? Это произошло потому, что исходный список маркеров содержал два определения для tok1, и второе определение заменило первое.
Функции управления маркерами версии Version Tokens накладывают следующие ограничения на имена и значения маркеров:
Имена маркеров не могут содержать
=или;символов и имеют максимальную длину 64 символа.Значения маркеров не могут содержать
;символов. Длина значений ограничена значением системной переменнойmax_allowed_packet.Version Tokens рассматривает имена и значения маркеров как двоичные строки, поэтому сравнения регистрозависимы.
Version Tokens также включает набор функций, позволяющих блокировать и разблокировать маркеры:
version_tokens_lock_exclusive()приобретает эксклюзивные блокировки маркеров версии. Она принимает список одного или нескольких имён блокировок и значение таймаута.version_tokens_lock_shared()приобретает общие блокировки маркеров версии. Она принимает список одного или нескольких имён блокировок и значение таймаута.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)'.
Блокировка с помощью функций блокировки Version Tokens является рекомендательной; приложения должны договариваться о сотрудничестве.
Возможна блокировка несуществующих имён маркеров. Это не создаёт маркеры.
Функции блокировки Version Tokens основаны на службе блокировки, описанной в разделе 5.5.6.1, “The Locking Service”, и поэтому имеют одинаковые семантику для общих и эксклюзивных блокировок. (Version Tokens использует встроенные в сервер процедуры службы блокировки, а не интерфейс функции службы блокировки, поэтому эти функции устанавливать не нужно, чтобы использовать Version Tokens.) Блокировки, полученные Version Tokens, используют пространство имён службы блокировки version_token_locks. Блокировки службы блокировки можно отслеживать с помощью Performance Schema, поэтому это также верно для блокировок Version Tokens. Подробнее см. Monitoring Locking Service.
Для функций блокировки Version Tokens имена маркеров в аргументах используются точно так, как указано. Окружающие пробелы не игнорируются, и = и ; символы допускаются. Это потому, что Version Tokens просто передаёт имена маркеров для блокировки как есть в службу блокировки.
© 2025 Oracle
Licensed under the GPLv2 License.