Мы используем 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
Я просмотрел журналы каждого участника кластера и клиентов и не нашел ничего особенного.Любые предупреждения или потери соединения в это время.
Есть некоторые из моих предположений:
- Я звоню на
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
это причина? - Разные JRE для моего участника и клиента-боковая сторона.И особенно сервер приложений Websphere 8.5.5.12 и Java 1.7.1_64 от IBM на стороне client .Может быть, из-за того, что метод
Unsafe.park(boolean, long)
использует специфичный для архитектуры код (следовательно, причина, по которой он «небезопасен»), и мы видим зависания во время этого метода. - Это может быть некоторые ошибки в моих настройках hazelcast.xml, причинамы только начинаем использовать Hazelcast в нашем проекте.
Есть предложения?