GTID - global transaction identifier
Цитата:
When using GTIDs, each transaction can be identified and tracked as it is committed on the originating server and applied by any slaves; this means that it is not necessary when using GTIDs to refer to log files or positions within those files when starting a new slave or failing over to a new master, which greatly simplifies these tasks. Because GTID-based replication is completely transaction-based, it is simple to determine whether masters and slaves are consistent; as long as all transactions committed on a master are also committed on a slave, consistency between the two is guaranteed
(с)
https://dev.mysql.com/doc/refman/5.7/en ... gtids.htmlGTID - идентификатор транзакции. При их использовании сильно упрощается процедура репликации и восстановления: просто сверяются ID закоммиченных транзакций на серверах.
Или вот наш пример: есть 2 сервера Master-Master, хотим прикрутить третий как слейв и снимать с него бэкап. Но без GTID он будет получать коммиты только непосредственно выполненные на том сервере, к которому он прикручен. Т.е. если sql3 прицеплен к sql0, а коммит делается на sql1, то sql3 не получит это коммит в связке (sql3 <- sql0 <-> sql1), если использовать репликацию по логу транзакций.
Использование GTID на сервере включается просто установкой соответствующей переменной. Но имеет ряд ограничений на запросы, в результате код биллинга начинает кидать SQLException и не выполнять запросы, небезопасные с точки зрения логики GTID:
Код:
ava.sql.SQLException: When @@GLOBAL.ENFORCE_GTID_CONSISTENCY = 1, the statements CREATE TEMPORARY TABLE and DROP TEMPORARY TABLE can be executed in a non-transactional context only, and require that AUTOCOMMIT = 1.
Ограничения два:
- Нельзя использовать CREATE TABLE ... SELECT.
- Нельзя использовать временные таблицы ( CREATE TEMPORARY TABLE и DROP TEMPORARY TABLE ) внутри транзакций. Можно только с autocommit=true
(с)
https://dev.mysql.com/doc/refman/5.7/en ... tions.htmlЧто интересно, конструкция CREATE TEMPORARY TABLE ... SELECT прекрасно работает (с автокоммитом). Видимо потому что не порождает 2 транзакции в логике мускуля. Мы специально потестили даже.
Есть предложение к разработчикам сделать в биллинге поддержку GTID, т.е. избавиться в коде от слабых мест.
1. CREATE TABLE ... SELECT
Это вроде несложно поправить: просто разбить на 2 запроса.
Декомпилером нашли в 7.0 в следующих местах:
Код:
1. bitel.billing.server.gorod.bean.RegisterItemManager в gorod.jar:
query = "CREATE TABLE contract_status_balance_dump( UNIQUE(cid) ) SELECT cid, MAX(yy*12+(mm-1))%12 + 1 AS mm,FLOOR(MAX(yy*12+(mm-1)) / 12) AS yy FROM contract_balance WHERE ((yy*12) + mm)<=((?*12) + ?) GROUP BY cid";
2. ru.bitel.bgbilling.kernel.contract.status.server.bean.ContractStatusMonitorDao в kernel.jar:
query = "CREATE TABLE contract_status_balance_dump( UNIQUE(cid) ) SELECT cid, MAX(yy*12+(mm-1))%12 + 1 AS mm,FLOOR(MAX(yy*12+(mm-1)) / 12) AS yy FROM contract_balance WHERE ((yy*12) + mm)<=((?*12) + ?) GROUP BY cid";
3. bitel.billing.server.reports.dialup.Report_Shturman_1 в reports.jar:
query = "CREATE TABLE " + tmpTrafficSums + " (UNIQUE(cid, sid)) SELECT detail.cid, detail.sid, service.title, SUM(detail.amount) AS amount FROM " + sessionDetailTable + " AS detail INNER JOIN contract ON detail.cid=contract.id " + contractGroupFilter + "LEFT JOIN service ON detail.sid=service.id ";
…
query = "CREATE TABLE " + tmpAccountSums + " (UNIQUE(cid, sid)) SELECT account.cid, account.sid, service.title, ROUND(SUM(account.summa),2) AS summa FROM contract_account AS account INNER JOIN contract ON account.cid=contract.id " + contractGroupFilter + "LEFT JOIN service ON account.sid=service.id WHERE account.yy=? AND account.mm=? GROUP BY account.cid, account.sid";
2. Тут будет посложнее, т.к., со слов Амира, в основном везде стоит autocommit=false.
Можем найти все CREATE TEMPORARY - как с ними быть? Мб. ставить для них autocommit=true, а потом вновь убирать?