Транзакции и тонкие клиенты#

В DataGrid реализован механизм приостановки пользовательских транзакций. Транзакция приостанавливается в двух случаях:

  1. По явному запросу пользователя в результате вызова метода tx.suspend() на объекте ClientTransaction.

  2. При запуске транзакции с помощью тонкого клиента. В этом случае сразу после создания транзакция переводится в статус SUSPENDED и выходит из него при получении последующих запросов от клиента.

В обоих случаях в момент приостановки транзакция переводится в статус SUSPENDED.

Данный механизм позволяет более оптимально использовать ресурсы серверного узла: при остановке транзакции поток, который отвечает за клиентские подключения, не будет ждать следующего сообщения от клиента, а сможет переключиться на другую задачу. Такой сценарий позволяет исключить ситуации, в которых потоки на сервере долго ждут ответа медленного клиента (например, в случае проблем с сетевым подключением), а остальные задачи простаивают.

Пример запуска транзакции из тонкого клиента

Java#
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();
}
// Прикладная логика.

Последовательность операций:

  1. При запуске транзакции тонкий клиент отправляет на сервер запрос ClientTxStartRequest. Сразу после создания транзакция находится в статусе ACTIVE, но переводится в статус SUSPENDED. После этого приостановленная транзакция сохраняется в транзакционный контекст клиента на сервере.

  2. Клиент выполняет cache.put(), и на кластер отправляется ClientCachePutRequest. На сервере вызывается метод GridNearTxLocal#resume, и транзакция переводится обратно в статус ACTIVE. После выполнения cache.put() транзакционный контекст отпускается и транзакция снова переводится в статус SUSPENDED.

  3. Клиент выполняет cache.get(), и транзакция снова переводится в статус ACTIVE. Триггером является ClientCacheGetRequest. После выполнения cache.get() транзакционный контекст отпускается и транзакция переводится обратно в статус SUSPENDED.

  4. После вызова 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]]]] 

Решение: явно задайте тайм-аут при запуске транзакции в прикладном коде:

Java#
try (ClientTransaction tx = client.transactions().txStart(PESSIMISTIC,
REPEATABLE_READ, 1000)) 

При повторных возникновениях LRT в статусе SUSPENDED используйте метки (labels) для транзакций. Метка будет отображаться в логах при выводе списка LRT. Это позволит определить, как именно запускаются проблемные транзакции и что они делают:

Java#
try (ClientTransaction tx = client.transactions().withLabel("LABEL").txStart(PESSIMISTIC, REPEATABLE_READ, 1000)) 

Подробнее о возможных причинах возникновения LRT в статусе SUSPENDED написано в документе «Часто встречающиеся проблемы и пути их устранения».