Google App Engine MemcacheService.delete (key, millisNoReAdd) не всегда выдерживает одновременные установки - PullRequest
0 голосов
/ 30 апреля 2020

В моем приложении GAE (java 8 стандартное окружение) мы широко используем MemcacheService. Создавая некоторые механизмы управления параллелизмом, я обнаружил, что использование MemcacheService.delete (Object key, long millisNoReAdd) не всегда удерживает одновременных пользователей кэша от помещения этого же ключа в millisNoReAdd. задержка.

Я использую 1000ms в качестве millisNoReAdd, и во время регистрации я часто вижу, как ключ повторно добавляется в memcache в течение этих 1000 мс. Иногда это только 10 миллис после удаления, иногда 100. Я не уверен, существует ли необоснованный нижний предел для ожидания того, что Google сможет обрабатывать параллельные операции в memcache из-за вызовов rp c или нет, но документация кажется довольно простой, что использование delete с помощью millisNoReAdd должно препятствовать добавлению того же самого ключ для этой продолжительности, период. Мы используем обычный MemcacheService, а не AsyncMemcacheService fyi.

Наша общая стратегия кэширования заключается в том, что чтение из хранилища данных будет кэшировать объекты для последующего чтения, а запись в хранилище данных удалит объекты из кэша. Это довольно базовый c, но, похоже, самый надежный подход для GAE. Мы также пробовали кэшировать записи при записи, но затем столкнулись с слишком большим количеством состязаний, что привело к устареванию данных кэша. Таким образом, удаление сущностей при записи кажется самым чистым подходом, несмотря на то, что первый читатель после этого заплатил штраф за повторное кэширование сущности.

При попытке нескольких вещей разобраться с этой проблемой millisNoReAdd (или обойти ее) Я остановился на этом для удаления из memcache (псевдокод):

MemcacheService.putAll(keyValuesMap, expiration, SetPolicy.SET_ALWAYS);
MemcacheService.deleteAll(keyValuesMap.keySet(), 1000);

У меня есть putAll (), потому что в документации не ясно, что будет делать deleteAll (), если ключ не найдено ... он все еще блокирует этот ключ для millisNoReAdd или ничего не происходит вообще? Помещение метода putAll () обеспечивает удаление ключа, поэтому мне не нужно беспокоиться об этом вопросе. Не мой любимый взлом, но, похоже, он уменьшил количество проблем в течение периода действия millisNoReadd. 1000 мсек дают время фактической записи в хранилище данных rp c, чтобы к моменту истечения задержки millisNoReAdd все читатели должны были получать самые свежие данные непосредственно из хранилища данных перед его кэшированием. Любые читатели в течение этого периода могут получить устаревшие данные непосредственно из хранилища данных, но вы можете сделать только очень много.

Параллельные паттеры, которые следует удерживать, но не всегда, используют SetPolicy.ADD_ONLY_IF_NOT_PRESENT, который должен быть предметом millisNoReAdd (в отличие от SetPolicy.SET_ALWAYS, который ему не подчиняется).

...