Предположим, over 128 запущенных на машине процессов, обслуживающих REST-запросы, практически одновременно, независимо друг от друга, получили запросы на сборку дорогостоящего JSON'а. Они все поняли, что та версия, которая ныне лежит в кеше, устарела, и начали вытаскивать данные. Считаем, что процессы никак не взаимодействуют, поскольку это именно процессы, а не потоки - им затруднительно узнать что-то вроде «данные находятся на пересчёте, обождите и приходите в кеш снова, когда данные посчитаются».
Теперь все эти процессы через некоторое время получаю огромный такой текстовый блоб -и хотят его засунуть в кеш обратно. И вот все 128 процессов идут в кеш и засовывают туда этот свой JSON. Вот только... wait, oh shi... да они ведь одно и то же засовывают в один и тот же кеш! Т.е. буквально: все 128 процессов бомбардируют кеш тем, что надо было бы записать всего один раз.
Мне кажется, что второй ситуации можно было бы избежать, если бы каждый процесс поговорил с кешем по душам вот о чём:
а) Дорогой Кеш, вот у меня есть данные для ключа «ААА», которые я собрал в (метка времени). Можно ли мне их тебе засунуть или твои данные новее?
б) Конец, если Кеш говорит: нельзя. Если Кеш ответил «можно», то спросить: а вот у меня есть данные для ключа «ААА», и md5-сумма этих данных такая-то - могу ли я их тебе, дорогой Кеш, передать или у тебя там точно такие же данные уже есть?
в) Конец, если то, что мы пытаемся передать, точно совпадает с тем, что уже есть. Если данные всё же нужно записать, говорим: «Дорогой Кеш, вот тебе данные, актуальные на момент времени X, прими эти данные, если у тебя там запись для ключа ААА древнее моей».
Таким образом, с высокой долей вероятности на этапах а и б процессы, пытающиеся записать ненужное - будут отсеяны. На этапе «в» отсев произойдёт в ситуации гонки, когда между «а» и «в» вклинился ещё один процесс, успевший записать данные раньше нашего.
Теперь внимание вопрос: а есть ли кеш-движки, которые умеют всё-таки не только хранить гигабайты в спуле, но умеют быть достаточно «ленивыми» для того, чтобы не принимать лишнее? Я вот написал подобную обвязку с протоколом обмена для Redis на Perl'е, но хотелось бы конечно, чтобы подобные вещи были встроенными.
Объясняется это очень просто: производительность кеша, который сам по себе является критичной компонентой системы, не должна бы «проваливаться» в случае подобного рода «лавинных» записей. Каждый процесс моет внутри себя творить всё, что угодно: в конце-концов у него всё равно отберут его квант времени и передадут управление другим процессам, а вот напрягать без веских на то оснований разделяемые ресурсы типа кешей - это нездорово, потому что мы никогда не знаем, насколько сейчас тому же Redis'у и без нас хреново.
В общем, бывают ли умные кеш-движки, умеющие что-то проверять прежде, чем писать?