Насколько масштабируем этот файловый подход БД?

У меня есть простой скрипт PHP, который вычисляет некоторые вещи о заданном вводе строки. Он кэширует результаты в базе данных, и мы время от времени удаляем записи, которые старше определенного количества дней.

Наши программисты реализовали эту базу данных как:

function cachedCalculateThing($input) {
$cacheFile = 'cache/' . sha1($input) . '.dat';
if (file_exists($cacheFile) {
return json_decode(file_get_contents($cacheFile));
}
$retval = ...
file_put_contents(json_encode($retval));
}
function cleanCache() {
$stale = time() - 7*24*3600;
foreach (new DirectoryIterator('cache/') as $fileInfo) {
if ($fileInfo->isFile() && $fileInfo->getCTime() < $stale) {
unlink($fileInfo->getRealPath());
}
}

Мы используем Ubuntu LAMP и ext3. При каком количестве записей поиск в кэше становится непостоянным или нарушает жесткий лимит?

0

Решение

Хотя этот конкретный код не очень «масштабируемый» *, существует ряд вещей, которые могут его улучшить:

  1. sha1 берет строку. Таким образом, переменная $ input должна быть сериализована или сначала json_encoded, прежде чем вычислять хеш. Просто измените порядок, чтобы защитить от неожиданных входов.
  2. Используйте crc32 вместо sha1, это быстрее (Самый быстрый хеш для не криптографического использования?)
  3. каталог ‘cache /’ относится к текущему каталогу, поэтому, по мере изменения рабочего каталога dir, также и каталог кеша. Там будет искусственно большое количество кешей.
  4. Каждый раз, когда вы сохраняете файл в cachedCalculateThing (), сохраняйте имя файла в индексе в / dev / shm / indexedofcaches (или что-то в этом роде). Проверьте индекс перед вызовом file_exists. ext3 медленный, и кэши вместе с индексом ядра ext3 будут выгружены. Это означает, что сканирование каталога будет выполняться каждый раз, когда вы спрашиваете, существует ли file_exist. Для небольших кэшей это достаточно быстро, но для больших вы увидите замедление.
  5. Операции write будут блокироваться, поэтому ограничение нагрузки на сервер будет достигнуто, когда кеш пуст, и возникнут коллизии с именем файла кеша, когда два или более пишущих php приходят одновременно, пытаясь записать ранее несуществующий кеш-файл. Поэтому вы можете попытаться перехватить эти ошибки и / или выполнить тестирование файла блокировки.
  6. Мы рассматриваем этот код в несколько девственной среде. Правда в том, что записи также будут блокировать неопределенное количество времени в зависимости от текущего использования диска. Если ваш диск вращающийся или более старый ssd, вы можете увидеть очень медленные записи. проверять iostat -x 4 и посмотрите текущее использование диска. Если оно уже выше, чем, скажем, 25%, включение кэширования диска увеличит его до 100% в случайное время и замедлит работу всех веб-служб. (Поскольку запросы к диску должны быть поставлены в очередь и обслуживаться (обычно) по порядку (не всегда, но не рассчитывайте на это)).
  7. В зависимости от размера файлов кеша, возможно, напрямую сохраните их в / dev / shm / my_cache_files /. Если они все хорошо вписываются в память, вы получаете выгоду от полного отказа диска от сервисной цепочки. Затем вам нужно поставить задачу cron, чтобы проверить общий размер кэша и убедиться, что он не поглотит всю вашу память. Недостаток = непостоянный. Вы можете также сделать резервное копирование на нем.
  8. Не вызывайте cleanCache () в коде времени выполнения / службы. Эта итерационная проверка каталогов будет очень медленной и блокированной.

* Для масштабируемости это обычно определяется в терминах скорости линейного запроса или ресурсов параллельного сервера. Этот код:

  1. (-) В зависимости от того, когда и где выполняется эта функция cleanCache (), она эффективно блокирует индексацию каталога, пока не будут проверены все элементы в каталоге кэша. Так что это должно пойти на работу cron. Если в задании cron / shell есть гораздо более быстрые способы удаления устаревших кешей. Например: find ./cache -type f -mtime +7 -exec rm -f "{}" \;
  2. (-) Вы правы упомянуть ext3 — индексирование и скорость выполнения ext3 для небольших файлов и очень большого содержимого каталога относительно невелики. Google noatime для индекса, и если вы можете переместить каталог кэша на отдельный том, вы можете отключить журнал, избегая двойной записи, или использовать отдельный тип файловой системы. Или посмотрите, есть ли у вас dir_index в качестве опции монтирования. Вот эталонная ссылка: http://fsi-viewer.blogspot.com/2011/10/filesystem-benchmarks-part-i.html
  3. (+) Записи кэша каталогов гораздо проще распространять на другие серверы с помощью rsync, чем, скажем, репликация базы данных.
  4. (+/-) На самом деле это зависит от того, сколько разных элементов кэша вы будете хранить и как часто к ним обращаетесь. Для небольшого количества файлов, скажем, 10-100, менее 100 Кб, частых обращений, тогда ядро ​​будет хранить файлы кэша в памяти, и вы не увидите никакого серьезного замедления вообще (если оно правильно реализовано).

Основной вывод заключается в том, что для достижения реальной масштабируемости и хорошей производительности системы кэширования необходимо уделить немного больше внимания, чем показано в коротком блоке кода. Может быть больше ограничений, чем те, которые я перечислил, но даже они зависят от таких переменных, как размер, количество записей, количество запросов / сек, текущая загрузка диска, тип файловой системы и т. Д. — внешние вещи к коду. Что и следовало ожидать, потому что кеш сохраняется вне кода. Приведенный код может работать для небольшого набора кэширования с небольшим количеством запросов, но не для больших размеров, для которых требуется кэширование.

Кроме того, вы используете Apache в режиме потока или prefork? Это повлияет на то, как php блокирует чтение и запись.

— Хм, наверное, мне следовало добавить, что вы хотите отслеживать свой объект и ключ / хэш. Если $ input уже является строкой, она находится в своей базовой форме / уже вычислена, извлечена, сериализована и т. Д. Если $ input является ключом, то file_put_contents () должен поместить что-то еще (фактическую переменную / содержимое). Если $ input — это объект для поиска (который может быть похож на длинную строку или даже короткую), тогда ему нужен ключ поиска, в противном случае никакие вычисления не будут пропущены / сохранены.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]