Logback MDC с ThreadPools или Spring Async

Я пытаюсь определить, насколько потокобезопасен MDC при использовании Cacheable ThreadPools или аннотации Spring Async.

У меня есть метод, который вызывает несколько CompletableFuture<> и выполняет их с использованием пулов потоков.

@Async
public CompletableFuture<List> someMethod(String request) {
    try {
        MDC.put("request", request)
        MDC.put("loggable1", "loggable1");
        MDC.put("loggable2", "loggable2");
        log.info("Log Event");
    } finally {
        MDC.clear();
    }
}

Соответствующие части из MDCAdapter от Logback

final ThreadLocal<Map<String, String>> copyOnThreadLocal = new ThreadLocal<Map<String, String>>();

public void put(String key, String val) throws IllegalArgumentException {
    if (key == null) {
        throw new IllegalArgumentException("key cannot be null");
    }

    Map<String, String> oldMap = copyOnThreadLocal.get();
    Integer lastOp = getAndSetLastOperation(WRITE_OPERATION);

    if (wasLastOpReadOrNull(lastOp) || oldMap == null) {
        Map<String, String> newMap = duplicateAndInsertNewMap(oldMap);
        newMap.put(key, val);
    } else {
        oldMap.put(key, val);
    }
}

public void clear() {
    lastOperation.set(WRITE_OPERATION);
    copyOnThreadLocal.remove();
}


public void remove(String key) {
    if (key == null) {
        return;
    }
    Map<String, String> oldMap = copyOnThreadLocal.get();
    if (oldMap == null)
        return;

    Integer lastOp = getAndSetLastOperation(WRITE_OPERATION);

    if (wasLastOpReadOrNull(lastOp)) {
        Map<String, String> newMap = duplicateAndInsertNewMap(oldMap);
        newMap.remove(key);
    } else {
        oldMap.remove(key);
    }
}

Поскольку ThreadPools повторно используют уже созданные потоки, а MDC использует карту контекста ThreadLocal. Возможно ли, что мы можем либо потерять, либо испортить значения, хранящиеся в MDC? Если да, то каковы потенциальные сценарии, в которых это может произойти?


person shinjw    schedule 07.10.2016    source источник


Ответы (1)


Я просто хотел сказать, что мы видим что-то подозрительно похожее на то, что вы описываете. У меня пока нет конкретных доказательств, но при просмотре кода кажется, что время, необходимое для сброса событий в приложения, может привести к чтению MDC после запуска нашей процедуры очистки пула потоков, особенно потому, что мы очищаем журналы. для Kafka (сетевой ввод-вывод обычно намного медленнее, чем что-либо в системе). Они используют локальный наследуемый поток копирования при записи для хранения самой карты MDC, но я не уверен, как это будет реагировать, например, на MDC.clear(). У нас есть много очень недолговечных задач, которые выполняются параллельно, поэтому с Kafka в смеси это, вероятно, вызовет состояние гонки.

Обратная сторона этого — сохранение копии карты с каждой записью — кажется, что она может не масштабироваться (может привести к взрыву памяти и перегрузке GC). Сейчас ищу золотую середину.

person jdcasey    schedule 07.05.2019
comment
вы нашли решение для этого? Я думаю, что мы могли бы столкнуться с той же проблемой... - person Java_Waldi; 02.01.2020