Как бороться с взаимоблокировками, используя ReentrantReadWriteLock в микросервисах - PullRequest
0 голосов
/ 30 апреля 2020

У нас возникла тупиковая ситуация, которая возникла из-за большой нагрузки на микросервис (например, A), вызвавшей несколько запросов от разных клиентских служб (B, C). Таким образом, эти вызовы из B и C приходят для одного и того же clientId (ключа) и обслуживаются разными экземплярами A, и они пытаются обновить одни и те же данные clientId в базе данных в одно и то же время, вызывая ошибку ниже.

CannotAcquireLockException is thrown,
(SQL Error: 60, SQLState: 61000..
ORA-00060: deadlock detected while waiting for resource

Мы решили реализовать разбиение на уровне балансировщика нагрузки (haproxy), которое будет гарантировать, что один и тот же экземпляр A всегда будет обслуживать запросы от B и C для определенного ключа c (clientId), поэтому у нас нет нескольких экземпляров обработка запроса на тот же ключ (clientId).

Теперь мы входим в режим всего в одном jvm, так как мы убедились, что запросы от B и C для определенного c clientId всегда приходят к одному и тому же экземпляру A.

При этом все еще возможно, что запросы от служб B и C приходят для одного и того же clientId с разницей во времени наносекунд. Любые несколько потоков будут снова пытаться обновить одни и те же данные clientId в базе данных одновременно, снова вызывая ту же ошибку.

Чтобы улучшить это, мы ищем возможные решения, и одним из решений является ReentrantReadWriteLock, который должен позаботиться об этом на основе по понятиям.

Мы используем данные весны jpa и выполняем сохранение, которое выглядит как

clientJpaRepository.save(ClientObject);

Теперь можно использовать что-то вроде ниже.

public void save(Client clientObject) {
   String clientId = clientObject.getClientId();
   try {
      boolean isLockAcquired = writeLock.tryLock(100, TimeUnit.MILLISECONDS);
      if (isLockAcquired) {
         clientJpaRepository.save(clientObject);
      }
   } catch (InterruptedException e) {
      log.error("exception occured trying to acquire lock for clientId={}", clientId);
   } finally {
      writeLock.unlock();
   }
}

Я не очень уверен, как это будет иметь дело с ключами. Как и в я не хочу, чтобы какие-либо потоки блокировать, если они хотят обновить для другого ключа (clientId 2). Кроме того, еще одна вещь, на которую следует обратить внимание, - это может быть чтение, как часть других вызовов API для этих данных из базы данных. Надеюсь, они не будут ждать слишком долго, и я надеюсь, что мне не нужно вносить какие-либо изменения для чтения. Извините за длинный вопрос, надеюсь, я скоро услышу от кого-то. Благодаря.

...