Название ключа для кеша

Awilum

Новичок
Доброе времени суток!

Проводя оптимизацию кода по рекомендациям blackfire.io дошел до пункта "YAML parsing should be cached in production" и вот я решил значит в своей обвёртке над YAML::decode добавить кеширование для всего что обрабатывается Yaml парсером, а в качестве названия ключа использую хеш контента.

Код:
public function decode(string $input)
{
    $key = md5($input);

    if ($this->flextype['cache']->contains($key)) {
        return $this->flextype['cache']->fetch($key);
    } else {
        $res = YamlParser::decode($input);
        $this->flextype['cache']->save($key, $res);
        return $res;
    }
}
Тестирую уже который день подряд и не вижу проблем с текущими данными и с новыми тоже, вроде бы все работает отлично. Одинаковый контент хранится под одним ключом, а если разный или новый, то хранится он под новым ключем.

Я не совсем уверен в том что можно ли использовать хеш контента в качестве названия ключа и не вылезет ли это проблемой в будущем ? или все же стоит использовать более осмысленное именование ключей - передавая их название отдельным параметром в метод public function decode ?
 

флоппик

promotor fidei
Команда форума
Партнер клуба
Я не совсем уверен в том что можно ли использовать хеш контента в качестве названия ключа и не вылезет ли это проблемой в будущем ? или все же стоит использовать более осмысленное именование ключей - передавая их название отдельным параметром в метод public function decode ?
Ключ по хешу - самое хорошее решение, потому что просто из своего дизайна очень хорошо отражает логику изменения ключа при изменении контента. Выгоды от "осмысленного" ключа тут нет. Другое дело, что кешировать парсинг это хорошо, но можно кешировать в том числе и чтение этих данных из файловой системы. Ну и нужно убедится, что сериализация в твое решении для кеша не медленнее, чем парсинг.
 

Awilum

Новичок
Вот так я делал раньше:
1. Загружаю контент YAML файла (название то мне известно его) в строковую переменную file_get_contents
2. Передаю переменную с YAML контентом в decode() который переводит YAML в массив
3. Отображаю контент массив который мне вернул decode()

Сейчас так:
1. Загружаю контент YAML файла (название то мне известно его) в строковую переменную file_get_contents
2. Передаю переменную с YAML контентом в decode()
2.1. Получаю ключ на основе контента, который был передан вот так $key = md5($input);
2.2. Если ключ есть в Кеше, тогда берем уже сохранённый массив в Кеше иначе парнем YAML контент, сохраняем его с ключом $key = md5($input); и возвращаем массив.
3. Отображаю контент массив который мне вернул decode()

PHP:
public function decode(string $input) {
    $key = md5($input);
 
    if ($this->flextype['cache']->contains($key)) {
        return $this->flextype['cache']->fetch($key);
    } else {
        $res = YamlParser::decode($input);
        $this->flextype['cache']->save($key, $res);
        return $res;
    }
}
если не кешировать по ключу, который основан на контенте, тогда надо передавать осмысленное название ключа и собственно к Кешу тогда наверное обращаться на более высшем уровне по всему коду, там где вызывается decode()

но вроде как операций с файловой системой во втором варианте больше выходит...
но backfire показывает, что благодаря тому что не приходится каждый раз прогонять данные через YAML парсер, то производительность вырастает в разы. Вот файл с кодом в проекте https://github.com/flextype/flextype/blob/dev/flextype/parsers/Parser.php
 

fixxxer

К.О.
Партнер клуба
PHP:
    if ($this->flextype['cache']->contains($key)) {
        return $this->flextype['cache']->fetch($key);
Вот этот кусок мне не нравится. contains - это лишнее обращение к кэшу, плюс между contains() и fetch() может произойти что угодно.

Лучше так:
PHP:
$res = $this->flextype['cache']->fetch($key);
if ($res !== null) { // или !== false, или поймать исключение - я не знаю, какой контракт fetch() там
    return $res;
}
...
 

Awilum

Новичок
PHP:
    if ($this->flextype['cache']->contains($key)) {
        return $this->flextype['cache']->fetch($key);
Вот этот кусок мне не нравится. contains - это лишнее обращение к кэшу, плюс между contains() и fetch() может произойти что угодно.

Лучше так:
PHP:
$res = $this->flextype['cache']->fetch($key);
if ($res !== null) { // или !== false, или поймать исключение - я не знаю, какой контракт fetch() там
    return $res;
}
...
возвращает false либо контент
если я вас правильно понял, то можно не проверять наличие файла если дальше по коду будет его чтение(и вероятнее всего с проверкой) и отображение его контента
 

fixxxer

К.О.
Партнер клуба
Судя по API, это Doctrine Cache, так что там сегодня файл, а завтра - когда серверов станет больше одного - какой-нибудь Redis. :)

Да, правильно. Почему? Во-первых, между contains и fetch запись из кэша может исчезнуть по любой причине. Во-вторых, лишний вызов.
Потому просто fetch, а если вернуло false, значит, нету там ничего, надо парсить.

Если операция парсинга сильно долгая (относительно частоты поступающих запросов), еще имеет смысл сделать лок, чтобы не получилось, что как только из кэша запись исчезла, 100 процессов начинают параллельно парсить один и тот же yaml. Но, наверное, в вашем случае этим можно пренебречь.

Еще вопрос насколько там объемные yaml-ы, может так получиться, что на достаточно длинной строке md5() считается не особо быстро и этим все сводится на нет. Хотя это вряд ли.
 
Последнее редактирование:

AnrDaemon

Продвинутый новичок
1. Загружаю контент YAML файла (название то мне известно его) в строковую переменную file_get_contents
2. Передаю переменную с YAML контентом в decode() который переводит YAML в массив
Почему не сразу декодировать из файла?…
 
Сверху