Hazelcast IMap.tryLock с tryTimeout 100 мельниц застревает более чем на 1 минуту - PullRequest
0 голосов
/ 15 мая 2018

Мы используем Hazelcast 3.9.2

Работает кластер с двумя узлами: Windows Server 2012 R2 Standard с Oracle JAVA_VERSION = "1.8.0_144"

, на котором работает от 2 до 20 клиентовотдельные виртуальные машины: 3.10.0-327.28.3.el7.x86_64 # 1 SMP пт 12 августа 13:21:05 EDT 2016 x86_64 x86_64 x86_64 GNU / Linux с IBM JAVA_VERSION = "1.7.1_64"

hazelcast.xml snippet:

<map name="lock*">
    <in-memory-format>BINARY</in-memory-format>
    <statistics-enabled>true</statistics-enabled>
    <backup-count>1</backup-count>
    <eviction-policy>NONE</eviction-policy>
</map>

Это наш hazelcast-client.xml

<hazelcast-client xmlns="http://www.hazelcast.com/schema/client-config" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.hazelcast.com/schema/client-config file:///C:/caching/hazelcast-client-config-3.9.xsd">
<group>
    <name>OUR_GROUP_NAME</name>
</group>
<properties>
    <property name="hazelcast.client.shuffle.member.list">true</property>
    <property name="hazelcast.client.heartbeat.timeout">60000</property>
    <property name="hazelcast.client.heartbeat.interval">5000</property>
    <property name="hazelcast.client.event.thread.count">10</property>
    <property name="hazelcast.client.event.queue.capacity">1000000</property>
    <property name="hazelcast.client.invocation.timeout.seconds">35</property>
    <property name="hazelcast.client.statistics.enabled">true</property>
</properties>
<network>
    <cluster-members>
        <address>tvlcacheqa1.blqa.qa:5709</address>
        <address>tvlcacheqa2.blqa.qa:5709</address>
    </cluster-members>
    <smart-routing>true</smart-routing>
    <redo-operation>true</redo-operation>
    <connection-attempt-period>15000</connection-attempt-period>
    <connection-attempt-limit>1048576</connection-attempt-limit>
<socket-options>
        <tcp-no-delay>false</tcp-no-delay>
        <keep-alive>true</keep-alive>
        <reuse-address>true</reuse-address>
        <linger-seconds>5</linger-seconds>
        <timeout>-1</timeout>
        <buffer-size>64</buffer-size>
    </socket-options>
</network>

<near-cache name="cache*">
    <in-memory-format>OBJECT</in-memory-format>
    <invalidate-on-change>true</invalidate-on-change>
    <time-to-live-seconds>1800</time-to-live-seconds>
    <max-idle-seconds>1800</max-idle-seconds>
    <eviction eviction-policy="LRU" max-size-policy="ENTRY_COUNT" size="10000"/>
</near-cache>   

Все предпочтения, которые не упомянуты выше, относятся к DEFAULT, и мы не делаемизменения предпочтений в коде.

При пакетной обработке мы запускаем этот код на каждом клиенте одновременно:

synchronizer.startSyncSection(key, 100);
try {
     doSomeCriticalStuff();
} finally {
     synchronizer.endSyncSection(key);
}

Это наша реализация Synchronizer, основанная на функциях Hazelcast IMap:

@Override
public void startSynchedSection(MultiKey<?> key, long tryLockTimeoutInMs, long releaseLockTimeoutInMs) {
    keyNullCheck(key);
    tryLockTimeoutInMs = Math.max(tryLockTimeoutInMs, minimumObtainLockTimeoutInMs);
    if (isClusterReady()) {
        boolean locked = false;
        try {
            locked = this.locks.tryLock(key, tryLockTimeoutInMs, TimeUnit.MILLISECONDS, releaseLockTimeoutInMs, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            throw new TechnicalException(e);
        }
        if (!locked) {
            throw new SyncTimeoutException(FAILED_TO_OBTAIN_EXCEPTION + key);
        }
        int lockCounter = incrementLockCounter(key);
    } else {
        throw new SyncTimeoutException(CLUSTER_NOT_READY_EXCEPTION);
    }
}
/** Note This should be called in a FINALLY section!!! */
@Override
public void endSynchedSection(MultiKey<?> key) {
    keyNullCheck(key);
    int lockCounterBefore = getThreadLocalCounter(key.toString()).get();
    if (lockCounterBefore == 0) {
        return;
    }
    try {
        int lockCounterAfter = decrementLockCounter(key);
        if (this.locks.isLocked(key)) {
            this.locks.unlock(key);
        }
    } catch (OperationTimeoutException e) {
        this.logger.warn("endSynchedSection - Lock-> {} was not released properly in Hazelcast because of exception:\n{}\n in Thread={}", key, e
            .getMessage(), Thread.currentThread().getName());
    }
}

Иногда (очень часто, когда мы запускаем наши пакеты) поток застревает в этом вызове IMap:

locked = this.locks.tryLock(key, tryLockTimeoutInMs, TimeUnit.MILLISECONDS, releaseLockTimeoutInMs, TimeUnit.MILLISECONDS);

, где this.locks равно private IMap<String, String> locks;

Хотя мы установили tryLockTimeoutInMs = 100ms поток может зависнуть на 2 минуты!

К сожалению, мы не можем воспроизвести эту ситуациюв тестовой среде, но мы используем инструмент Dynatrace, где мы видим такой отчет в производстве: https://user -images.githubusercontent.com / 12655866 / 39863775-74a3da5a-53fc-11e8-96b4-d55bea1f5e06.PNG

Я просмотрел журналы каждого участника кластера и клиентов и не нашел ничего особенного.Любые предупреждения или потери соединения в это время.

Есть некоторые из моих предположений:

  1. Я звоню на IMap.tryLock(key, tryTime, TimeUnit.MILLISECONDS, leaseTime, TimeUnit.MILLISECONDS); с leaseTime = 30 минут в соответствии с моими деловыми требованиями, т.е.сделать так, чтобы разблокировать себя так: if (this.locks.isLocked(key)) this.locks.unlock(key); Так, может быть, очень частые звонки на IMap.isLocked(key) и / или IMap.unlock(key) одновременно с IMap.tryLock это причина?
  2. Разные JRE для моего участника и клиента-боковая сторона.И особенно сервер приложений Websphere 8.5.5.12 и Java 1.7.1_64 от IBM на стороне client .Может быть, из-за того, что метод Unsafe.park(boolean, long) использует специфичный для архитектуры код (следовательно, причина, по которой он «небезопасен»), и мы видим зависания во время этого метода.
  3. Это может быть некоторые ошибки в моих настройках hazelcast.xml, причинамы только начинаем использовать Hazelcast в нашем проекте.

Есть предложения?

...