Транзакции и тонкие клиенты#
В DataGrid реализован механизм приостановки пользовательских транзакций. Транзакция приостанавливается в двух случаях:
По явному запросу пользователя в результате вызова метода
tx.suspend()на объектеClientTransaction.При запуске транзакции с помощью тонкого клиента. В этом случае сразу после создания транзакция переводится в статус
SUSPENDEDи выходит из него при получении последующих запросов от клиента.
В обоих случаях в момент приостановки транзакция переводится в статус SUSPENDED.
Данный механизм позволяет более оптимально использовать ресурсы серверного узла: при остановке транзакции поток, который отвечает за клиентские подключения, не будет ждать следующего сообщения от клиента, а сможет переключиться на другую задачу. Такой сценарий позволяет исключить ситуации, в которых потоки на сервере долго ждут ответа медленного клиента (например, в случае проблем с сетевым подключением), а остальные задачи простаивают.
Пример запуска транзакции из тонкого клиента
script
// 1.
try (ClientTransaction tx = client.transactions().txStart(PESSIMISTIC, REPEATABLE_READ)) {
// 2.
cache.put(1, 1);
// 3.
int init = cache.get(1);
// 4.
tx.commit();
}
// Прикладная логика.
Последовательность операций:
При запуске транзакции тонкий клиент отправляет на сервер запрос
ClientTxStartRequest. Сразу после создания транзакция находится в статусеACTIVE, но переводится в статусSUSPENDED. После этого приостановленная транзакция сохраняется в транзакционный контекст клиента на сервере.Клиент выполняет
cache.put(), и на кластер отправляетсяClientCachePutRequest. На сервере вызывается методGridNearTxLocal#resume, и транзакция переводится обратно в статусACTIVE. После выполненияcache.put()транзакционный контекст отпускается и транзакция снова переводится в статусSUSPENDED.Клиент выполняет
cache.get(), и транзакция снова переводится в статусACTIVE. Триггером являетсяClientCacheGetRequest. После выполненияcache.get()транзакционный контекст отпускается и транзакция переводится обратно в статусSUSPENDED.После вызова
tx.commit()транзакция выходит из статусаSUSPENDEDи происходит ее коммит.
Таким образом, за время своего жизненного цикла транзакция может переходить в статус SUSPENDED и выходить из него несколько раз.
Диагностика LRT в статусе SUSPENDED#
Проблема: на серверных узлах наблюдаются LRT (Long Running Transactions, длительные транзакции) в статусе SUSPENDED, но в прикладном приложении не используется вызов Transaction.suspend(). При этом в логах DataGrid появляются строки:
YYYY-MM-DD 15:37:15.566 [WARN ][sys-#292468][org.apache.ignite.internal.diagnostic]
>>> Transaction [startTime=15:17:13,809, curTime=15:37:15,563, systemTime=0, userTime=1201754, tx=GridNearTxLocal [mappings=IgniteTxMappingsImpl [], nearLocallyMapped=false, colocatedLocallyMapped=false, needCheckBackup=null,
hasRemoteLocks=false, trackTimeout=false, sysTime=0, sysStartTime=0, prepareStartTime=0, prepareTime=0, commitOrRollbackStartTime=0, commitOrRollbackTime=0, lb=null, thread=client-connector-#85,
mappings=IgniteTxMappingsImpl [], super=GridDhtTxLocalAdapter [nearOnOriginatingNode=false, nearNodes=KeySetView [], dhtNodes=KeySetView [], explicitLock=false, super=IgniteTxLocalAdapter [doneFlag=0, completedBase=null, commitErr=null, depEnabled=false, txState=IgniteTxStateImpl [activeCacheIds=[],
recovery=null, txMap=EmptySet []], syncMode=null, super=IgniteTxAdapter [xidVer=GridCacheVersion [topVer=385590803, order=1774141905756, nodeOrder=2, dataCenterId=0], writeVer=null, implicit=false, loc=true, threadId=133, startTime=1776341833809, startTimeNanos=-1,
nodeId=a8dd4427-907a-4515-a02d1113ac169683, needRetVal=false, isolation=REPEATABLE_READ, concurrency=PESSIMISTIC, timeout=0, sysInvalidate=false, internal=false, sys=false, plc=2, commitVer=null,
finalizing=NONE, invalidParts=null, state=SUSPENDED, timedOut=false, topVer=AffinityTopologyVersion [topVer=-1, minorTopVer=0], subjId=bcdcf208-46fa-385a9d3d-56f8bcec8209, taskNameHash=0, storeEnabled=true,
incSnpId=null, skipCompletedVers=false, parentTx=null, duration=1201754ms, onePhaseCommit=false], size=0]]]]
Решение: явно задайте тайм-аут при запуске транзакции в прикладном коде:
try (ClientTransaction tx = client.transactions().txStart(PESSIMISTIC,
REPEATABLE_READ, 1000))
При повторных возникновениях LRT в статусе SUSPENDED используйте метки (labels) для транзакций. Метка будет отображаться в логах при выводе списка LRT. Это позволит определить, как именно запускаются проблемные транзакции и что они делают:
try (ClientTransaction tx = client.transactions().withLabel("LABEL").txStart(PESSIMISTIC, REPEATABLE_READ, 1000))
Подробнее о возможных причинах возникновения LRT в статусе SUSPENDED написано в документе «Часто встречающиеся проблемы и пути их устранения».