Зміст

Підсистема кешування

Являє собою штатний рівень абстракції для задач, котрі вимагають кешування даних на певний час. Присутній у складі, починаючи з Ubilling 0.6.8. Усе брутально і прямолінійно як завжди. Реалізовано у вигляді класу UbillingCache і керується такими опціями alter.ini:

; Встановлює тип сховища системного кешу, можливі значення:
; files - у файлах, використовується за замовчуванням, не потребує конфігурації
; memcached - використовує Memcached для кешування даних в оперативній пам'яті на основі хеш-таблиць
; redis - використовує Redis як мережеве журнальоване сховище даних типу "ключ - значення"
; fake - фейковий кеш - вважається, що він завжди порожній
UBCACHE_STORAGE=files
; Необов'язкові опції, що встановлюють, якщо потрібно, альтернативні параметри memcached і redis
;MEMCACHED_SERVER=localhost
;MEMCACHED_PORT=11211
;REDIS_SERVER=localhost
;REDIS_PORT=6379
;Вмикає запис логування роботи кешу в exports/cache.log. Воно дуже вбиває швидкодію і використовується тільки для налагодження.
;UBCACHE_DEBUG=1

Приклад використання

Вся робота з класом намотана навколо методу getCallback:

$cache = new UbillingCache(); // створюємо об'єкт
$cacheTime=60; // час кешування в секундах
$someData = $cache->getCallback('EXAMPLE_KEY', function () {
    return (web_AnalyticsPaymentsMonthGraph('2015'));
}, $cacheTime);
 
//відображаємо результат
show_window(__('Example data from cache'), $someData);

Варто зауважити, що ви можете не перейматися серіалізацією своїх даних під час засовування в кеш. На виході ви отримаєте той самий тип даних, який передбачався спочатку.

ООП або використання у своєму класі

Для протягування властивостей вашого об'єкта всередину анонімної функції коллбека вам доведеться використовувати невеликий хак.

     public function sampleFunction() {
        $result = '';
        $this->initCache(); // тут ми ініціалізуємо загальний для об'єкта екземпляр кешу
                            // а саме створюємо $this->cache і $this->timeout
        $obj = $this; // а ось власне і хак
        $result = $this->cache->getCallback('SAMPLE_FUNCT_CACHE', function() use ($obj) {
            return ($obj->getLargeData()); // на жаль getLargeData може бути тільки публічним методом
        }, $this->timeout);
        return ($result);
    }

Очищення

Хоча дані з кеша самостійно видаляються після закінчення часу $expiration, що вказується в секундах, можливо, вам буде потрібно очистити дані кеша “ось прямо зараз”. Для примусового очищення конкретного ключа кеша, ми можемо використовувати публічний метод delete якось так:

$cache->delete('EXAMPLE_KEY');

А якщо без наркоманії?

Ви можете використовувати це все просто на рівні set/get, вказуючи час зберігання даних ключа в кеші. Так, у цьому разі нам доведеться самим вирішувати, коли і як засовувати дані в кеш, у разі його старіння/інвалідації.

Якось так:

$cache=new UbillingCache();
$cacheTime=60;
$dataToPush='sample data';
 
 
//намагаємося отримати дані з кешу
$dataInCache=$cache->get('CACHE_TEST_KEY', $cacheTime);
if (!empty($dataInCache)) {
    //якщо щось отримано і воно не порожнє - показуємо це у віконці
    show_window(__('Data from cache'),$dataInCache);
} else {
    //запихаємо дані в кеш на скільки нам потрібно часу
    $cache->set('CACHE_TEST_KEY', $dataToPush, $cacheTime);
    show_warning(__('No data in received, cache expired'));
}

Слід також пам'ятати, що при прямій роботі за допомогою set/get рекомендується вказувати таймаут кешування в обох функціях. Оскільки для стораджів типу memcached або redis на таймаут зберігання даних впливає безпосередньо set, який реалізовано засобами самого сховища, а для сховища files з цілком зрозумілих причин актуальність даних, що містяться в ньому, перевіряється під час здійснення get (файли на ФС не вміють самі по собі видалятися, дивно, чи не так?).

Memcached

Цілком зрозуміло, що для UBCACHE_STORAGE=memcached потрібен увімкнений і працюючий сам memcached.

/etc/rc.conf

rc.conf
memcached_enable="YES"
memcached_flags="-l 127.0.0.1 -m 128 -I 10M"
 # /usr/local/etc/rc.d/memcached restart

Redis

Вмикаємо в /etc/rc.conf

rc.conf
redis_enable="YES"

з подальшим запуском

# service redis restart

Хочу особливе сховище

Припустимо, з якоїсь причини, вам хочеться в якомусь вашому, конкретному модулі використовувати сховище кешу, що відрізняється від зазначеного в опції UBCACHE_STORAGE. Припустимо, вам потрібно багато швидкого читання memcached, а для решти системи ви використовуєте redis, який у цьому конкретному випадку може виявитись менш продуктивним, виходячи з бенчмарків. Або ви використовуєте memcached з маленькими ключами, але вам різко потрібно покласти в кеш якийсь більший обсяг даних, що вміщується в files або redis, до якого ви не очікуєте дуже частих звернень. У такому разі, починаючи з релізу 1.1.5 ви можете використовувати перевизначення типу сховища прямо в конструкторі класу, наприклад так:

$this->cacheFiles = new UbillingCache('files'); // тут я хочу файловий кеш, "тому-що".
$this->cacheRedis = new UbillingCache('redis'); // а для цього екземпляра - редис. 
// а в конфігурації для всієї іншої системи в нас буде взагалі memcached і все це тільки тому, що наркотики - зло.