Кэш, который живёт в оперативной памяти
Почти пятая часть изображений счётчика, которые рисует эта служба, ничего уже не меняет. Скрипт слежения за мышью из прошлого поколения перезагружает картинку при каждом движении, и с тех пор как эти запросы перестали что-либо увеличивать, два подряд дают одну и ту же картинку, байт в байт.
Очевидный кандидат на кэш. Интересными были решения, куда его положить и на чём строить ключ.
Не на диск
Это работает на Raspberry Pi, и диск здесь — карта SD. Класть туда нарисованные картинки означало бы около 70 МБ записи в день в обмен на измеренную экономию в 1,6 минуты процессорного времени в день.
Это плохой обмен. Карты SD умирают от записи, а покупается погрешность округления на машине, которая процессором не ограничена. Поэтому кэш живёт в /dev/shm, то есть в tmpfs, то есть в оперативной памяти. Измерено там: 0,027 мс на чтение, 0,036 мс на запись, 1,9 ГБ свободно.
После перезагрузки всё исчезает. Для кэша это не потеря, а нормальное положение дел.
На том же Pi работает Redis. Его не взяли по причине, никак не связанной с техникой: он принадлежит другому приложению и защищён для него паролем. Общий экземпляр связал бы две несвязанные службы так, что плохой день одной становился бы плохим днём другой.
Ключ содержит числа
Обычный ключ кэша — это тождество плюс срок годности, а срок годности — это пари: за последние пять минут ничего важного не изменилось. У счётчика то, что меняется, ровно и есть то, что показано.
Поэтому показанные значения уходят внутрь ключа. Изменится число — это другой ключ, и картинка рисуется заново. Пари исчезает вместо того, чтобы заключаться осторожно. Каждое засчитанное посещение увеличивает по меньшей мере общий итог, значит ни одно засчитанное посещение не может получить устаревшую картинку. Оставшийся срок годности — лишь верхняя граница для значений, которых в ключе нет: недельных, месячных и годовых.
Что пришлось проверить заранее
Кэш безопасен только тогда, когда хранимое есть функция его ключа. Это утверждение о каждом оформлении, и оно было проверено, а не принято на веру:
- ни одно оформление не использует
rand(),mt_rand(),shuffle()илиuniqid() - ни одно оформление не читает часы точнее, чем по часам
- параметры слежения старого скрипта не читаются нигде в дереве
Последний пункт дал самый красивый провал всего упражнения. Пока эти параметры входили в ключ, каждый запрос нёс чуть иные координаты мыши, значит каждый ключ был неповторим. Кэш проработал целый день и записал 13 попаданий. Он работал безупречно и не делал ничего, а это самый труднозаметный вид поломки.
И если здесь что-то откажет — нечитаемый каталог, полный диск, испорченная запись — картинка рисуется обычным образом. Кэш никогда не должен быть причиной того, что счётчик не появился.