2017 © Pedro Peláez
 

library shm-cache

Shared Memory ReadOnly Cache

image

text-media/shm-cache

Shared Memory ReadOnly Cache

  • Tuesday, May 8, 2018
  • by text-media
  • Repository
  • 0 Watchers
  • 0 Stars
  • 355 Installations
  • 0 Dependents
  • 0 Suggesters
  • 0 Forks
  • 0 Open issues
  • 2 Versions
  • 105 % Grown

The README.md

Shared Memory ReadOnly Cache

Packagist Packagist, (*1)

Кэш типа "ключ -> значение" на основе разделяемой памяти., (*2)

Предназначен для работы большого количества одновременно запущенных скриптов с большим блоком статичных неизменяемых данных:, (*3)

  • один скрипт по расписанию или какому-то событию "прогревает" кэш, т.е. читает откуда-то данные, приводит их к нужному виду и сохраняет в памяти;
  • множество других скриптов читают данные из памяти, т.е. не тратят ни ресурсы процессора на чтение и приведение к нужному виду, ни память на хранение одних и тех же общих для всех них данных.

Настройка

Для настройки кэша необходимо создать класс-потомок абстракции \TextMedia\ShmCache\Behavior. В нем необходимо обязательно переопределить следующие константы:, (*4)

Константа Описание
PROJECT_ID Идентификатор проекта. Это должен быть один символ (см. http://php.net/manual/ru/function.ftok.php).
CACHE_SIZE Размер блока разделяемой памяти. Может быть задан целым числом байт или строкой типа: 1m, 100k и т.п. Должен быть не менее 1 Кб.
VALUE_SIZE Определяет, сколько нужно байт для хранения длины упакованных данных. Может меняться в пределах от 1 до 4.

VALUE_SIZE должен подбираться из расчета длины хранимых значений. Если это просто число или небольшой текст (не более 255 ASCII-символов) - достаточно указать 1 байт., (*5)

CACHE_SIZE следует выбирать исходя из суммы следующих значений:, (*6)

  • число записей в кэше, умноженное на 1 - столько байт потребуется для хранения длин ключей;
  • суммарная длина строковых представлений всех ключей;
  • число записей, умноженное на VALUE_SIZE - столько нужно для хранения длин значений;
  • суммарная длина строковых представлений всех значений.

Строковые представления значений не должны быть представлены в виде результата выполнения var_export и т.п., т.к. такие данные имеют избыточную информацию, в частности - имена ключей., (*7)

Например, при сохранении массива вида ['x' => число1, 'y' => число2] достаточно сохранить только числа в бинарном виде, а при чтении из памяти приводить их к нужному типу и формировать массив нужного вида. Для этого в классе необходимо переопределить следующие методы:, (*8)

Метод Описание
string packData(string $key, $data) Упаковка элемента данных в строку для записи.
mixed unpackData(string $key, string $packed) Распаковка прочитанных из памяти данных в исходную структуру.

Значение $key передается в оба метода, т.к. оно может повлиять на алгоритм упаковки/распаковки., (*9)

Например, если хранимые данные имеют вид массива со следующими полями:, (*10)

  • user_id: число, на запись которого нужно не более 2 байт;
  • name: строка, длиной не более 255 символов;
  • desc: строка.
use TextMedia\ShmCache\Behavior;

class MyCacheBehavior extends Behavior
{
    public function packData(string $key, $data): string
    {
        return (self::packNumber($data['user_id'], 2)
            . self::packNumber(strlen($data['name'], 1))
            . $data['name']
            . $data['desc']);
    }

    public function unpackData(string $key, string $packed)
    {
        $nameLength = self::unpackNumber(substr($packed, 2, 1));
        return [
            'user_id' => self::unpackNumber(substr($packed, 0, 2)),
            'name'    => substr($packed, 3, $nameLength),
            'desc'    => substr($packed, 3 + $nameLength),
        ];
    }
}

Если метод packData() должен прости привести к строке, лучше использовать parent::packData(), т.к. он проверяет, можно ли значение привести к строки, и выбрасывает исключение, если нельзя. Это позволит избежать фатальных ошибок., (*11)

Метод unpackData() при распаковке данных может проверятьо их валидность, соответствие каким-то своим шаблонам, и в случае ошибки - выбрасывать исключение типа \TextMedia\ShmCache\Exception (см. раздел "Ошибки"), которое будет перехвачено основным объектом, в следствии чего будут выполнены следующие действия:, (*12)

  • кэшу будет выставлен статус "поврежден";
  • вызовется метод onCorrupt - по умолчанию он ничего не делает, его можно переопределить;
  • исключение будет проброшено выше, т.е. работа скрипта будет прекращена.

Так же этот класс обязательно должен определять метод getData(), необходимый для "прогрева" кэша. Этот метод должен возвращать ArrayObject для сохранения в кэше в виде "ключ-значение". Например:, (*13)

use ArrayObject;
use TextMedia\ShmCache\Behavior;

class MyCacheBehavior extends Behavior
{
    public function getData(): ArrayObject
    {
        return new ArrayObject($this->database->getQueryResult('SELECT user_id, name, desc FROM users', 'user_id'));
    }
}

Класс \TextMedia\ShmCache\Behavior содержит следующие статичные методы, которые можно использовать для упаковки/распаковки данных:, (*14)

Метод Описание
string packNumber(int $number, int $size) Упаковка числа в последовательность символов ($size - число байт).
int unpackNumber(string $string) Распаковка последовательности символов в число.

Обработчики событий

Класс-потомок \TextMedia\ShmCache\Behavior может переопределять поведение при возникновении некоторых событий (все три метода необязательны для переопределения и по умолчанию ничего не делают):, (*15)

Метод Событие
onCorrupt В процессе обработки данных, прочитанных из кэша, произошла ошибка.
onEmpty При попытке чтения данных из кэша выяснилось, что он (кэш) пуст.
onWarmed Завершен "прогрев" кэша.
onIndexed Завершено формирование таблицы индексов (смещений).

Первым аргументом для каждого метода является объект-кэш класса \TextMedia\ShmCache\Cache, при работе с которым произошло данное событие., (*16)

Для обработчика onCorrupt дополнительными аргументами являются:, (*17)

Аргумент Тип Описание
$key string Ключ, данные по которому не удалось обработать.
$value string Данные, прочитанные из памяти.

Обработчики onWarmed и onIndexed имеет дополнительно два аргумента $onStart и $onReady; оба - являются обычными объектами со следующими полями:, (*18)

Поле Тип Описание
time float Когда был запущен/завершен процесс (microtime(true)).
memory integer Используемая память на момент запуска/завершения (memory_get_peak_usage(true)).
records integer Число записанных/прочитанных записей (на момент старта = 0).
size integer Сколько байт было записано/прочитано (на момент старта = 0); без учета размера заголовка кэша.

Обработчик onEmpty дополнительных аргументов не имеет и по умолчанию вызывается обработчиком onCorrupt (если он не переопределен никак иначе), т.к. очевидно, что итоговое поведение в обоих случаях должно быть одно - исправить содержимое кэша, "прогреть" его заново., (*19)

Использование

Для работы с кэшем необходимо создать экземпляр класса \TextMedia\ShmCache\Cache, передав в его конструктор объект-наследник \TextMedia\ShmCache\Behavior., (*20)

Для "прогрева" кэша используется метод warmup(), имеющий один необязательный параметр, указывающий на то, нужно ли сперва полностью вычистить все данные из памяти, т.е. забить их 0-ми. По умолчанию этот параметр имеет значение TRUE., (*21)

Для чтение данных из разделяемой памяти доступны следующие методы:, (*22)

Метод Описание
mixed getItem(string $key) Чтение по одному ключу ключу.
array getItems(array $keys) Чтение по множеству ключей. На выходе массив вида "ключ --> значение".

Вторым аргументом в метод getItems() можно передать bool $ignoreMissing (по умолчанию = TRUE), который указывает, нужно ли игнорировать отсутствующие в таблице индексов ключи или все же выбрасывать исключения. Если этот аргумент равен TRUE и было выброшено исключение с кодом FAILED_SEARCH_KEY (см. раздел "Ошибки"), то значение не попадет в результирующий массив; в остальных случаях - исключение будет проброшено вверх., (*23)

Ошибки

Все вышеперечисленные классы в случае ошибок выбрасывают исключения типа \TextMedia\ShmCache\Exception. Каждому типу ошибок назначен свой код - константа данного класса:, (*24)

Константа Значение Описание ошибки
INVALID_PROJECT_ID 1 Неправильное значение идентификатора проекта.
FAILED_GET_SHM_ID 2 Не удалось определить идентификатор блока разделяемой памяти.
INVALID_CACHE_SIZE 3 Неправильное значение размера блока разделяемой памяти.
INVALID_VALUE_SIZE 4 Неправильное значение размера длины строкового представления данных.
FAILED_OPEN_SHMOP 5 Не удалось открыть блок разделяемой памяти.
FAILED_DELETE_SHMOP 6 Не удалось удалить блок разделяемой памяти.
INVALID_STATUS_VALUE 7 Неправильное значение статуса.
FAILED_READ_SHMOP 8 Ошибка чтения из разделяемой памяти.
FAILED_WRITE_SHMOP 9 Ошибка записи в разделяемую память.
FAILED_SEARCH_KEY 10 Указанный ключ отсутствует в таблице.
CACHE_NOT_READY 11 Кэш не готов к чтению.
FAILED_PACK_VALUE 12 Не удалось привести значение к строке.
FAILED_UNPACK_VALUE 13 Не удалось распаковать значение из строки.

Отладка

Для включения режима отладки необходимо вызвать метод Cache::setDebugMode() с аргументом TRUE; для отключения - его же, но с аргументом FALSE., (*25)

Режим отладки включает сохранение данных о времени выполнения операций и используемой для этого памяти. Отслеживаются следующие операции:, (*26)

Название Описание
CACHE CLEAN Очистка кэша.
CACHE WARMUP "Прогрев" кэша.
TABLE CREATION Формирование таблицы индексов.
OFFSET SEARCH Поиск по таблице индексов.

Данные отладки могут быть получены методом Cache::getDebugData(), который возврашает массив, список которого являются массивы со следующими полями:, (*27)

Поле Описание
action Выполненное действие (см. таблицу выше).
time Затраченное время (секунды, до 8 знаков после запятой).
memory Сколько в итоге было максимально использовано памяти (в байтах).

Тесты

cd /path/to/package
vendor/bin/phpunit

Кроме проверки записи/чтения в разделяюмую память, тесты включают в себя сравнение производительности по сравнению с Memcached:, (*28)

  • запускается отдельный скрипт, который:
    • очищает и разделяемую память, и memcached;
    • запускает 300 процессов (поровну для всех типов кэша); запущенные процессу "висят" в памяти, ожидая "прогрева" кэша;
    • выполняет "прогрев" - все типы кэшей заполняются 200 одинаковыми элементами;
  • запущенные скрипты выполняют 10000 запросов к кэшу к рандомным элемнтам;
  • по завершении работы всех скриптов выводится:
    • среднеее время работы отдельного процесса;
    • максимальное;
    • минимальное;
    • время "прогрева" кэша.

Тест производительности активен по умолчанию, но может быть отключен следующим образом:, (*29)

export PHP_UNIT='--no-performance' && vendor/bin/phpunit

Если тест производительности не был отключен и либо "завис", либо прерван, перед запуском следующего теста необоходимо "убить" запущенные ранее процессы:, (*30)

pkill -f "TestPerformance.php"

The Versions

08/05 2018

dev-master

9999999-dev https://bitbucket.org/text-media/shm-cache

Shared Memory ReadOnly Cache

  Sources   Download

MIT

The Requires

  • php >=7.0

 

The Development Requires

by Andrey Ivanov

08/05 2018

v1.2.0

1.2.0.0 https://bitbucket.org/text-media/shm-cache

Shared Memory ReadOnly Cache

  Sources   Download

MIT

The Requires

  • php >=7.0

 

The Development Requires

by Andrey Ivanov