КЕШУВАННЯ ДАНИХ НА КЛІЄНТІ

“There are only two hard things in Computer Science:
cache invalidation and naming things.”
Phil Karlton

Всім Привіт!
Мене звати Антон, я працюю Senior .Net Developer в AllStars-IT Ukraine. В цій статті хочу трішки описати таку тему, як кешування даних на клієнті.
Почнемо…
Якщо Ви розробляєте додаток-клієнт який використовує дані з сервера, то як правило з часом виникає завдання поліпшити його завантаження. Зазвичай першим що спадає на думку – оптимізувати шар (layer), який отримує дані шляхом часткового їх кешування.
На практиці непоодинокі випадки коли неправильна робота кеша призводить до креша додатку або до важковловимих багів, на виправлення яких можна витратити чимало часу.

Наприклад в минулому, працюючи в аутсорсинговій компанії, на одному з проектів, мені довелось зіткнутися з такою проблемою. Як виявилось, додаток зберігав дані в кеші, який представляв собою зашифрований і стислий xml файл. При завантаженні додатку файл розпаковувався, декриптовувався та скормлювався XmlDocument, для подальшої десеріалізації в масив об’єктів певного типу. При цьому ситуація погіршувалася тим, що використовували декілька кешів. Як наслідок в LargeObjectHeap створювалося багато об’єктів, він швидко кластиризувався і додаток злетів з OutOfMemory exception при спробі виділити місце для нового об’єкта.

Тому при організації кешування варто продумати деякі деталі:

• Розташування кеша та організація даних в кеші: кеш може бути розташований в оперативній пам’яті або на диску в локальній БД або в бінарному файлі в форматі черзі, асоціативного масиву або дерева. У випадку з пам’яттю – дані будуть очищені при виході з програми. У випадку з локальною БД або диском потрібно також враховувати шифрування даних .

• Інвалідація даних в кеші – подія після якої збережені дані стають не актуальними. Іншими словами ми повинні розуміти в який момент потрібно оновити інформацію. Нотифікація при цьому може бути реалізована просто по таймаут, за запитом користувача (by demand) або шляхом відправки повідомлення з сервера. При цьому для кожного елемента потрібно зберігати додатково інформацію: унікальний ключ, час коли дані були додані або expired date.

Давайте розглянемо як це може бути реалізовано, наприклад для простого випадку, коли потрібно зберігати дані в кеші якийсь час і мати можливість отримати дані по ключу.

В .NET для реалізації шару доступу до даних дуже зручно використовувати generic типи.
Спочатку нам потрібно створити враппер для даних, який буде зберігати додаткову інформацію – в нашому випадку про час додавання об’єкта в кеш.

 


Тоді клас для роботи з кешем може бути представлений в наступному вигляді:

В цьому класі конструктор приймає аргумент типу TimeSpan на підставі якого в методі GetItemByKey приймається рішення про те чи потрібно оновити дані. Якщо потрібно – тоді отримуємо дані за допомогою переданої callback функції, інакше повертаємо їх у викликаючий код (вьюмодель або контролер).

Використовувати цей шар можна наступним чином:

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

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


Антон Пушкін
Senior .Net Developer в AllStars-IT Ukraine

Our News