Jump to content

Волчьи заметки

Sign in to follow this  
  • entries
    57
  • comments
    9
  • views
    64442

Подводные камни кэширования данных

Belkir

515 views

Кэширование данных в наше время является неотъемлемой частью оптимизации процессов. Плохое и неуместное, оно легко может потопить систему и добавить багов, в то время как правильно реализованное в нужном месте кэширование способно дать системе новые "силы" для обслуживания запросов и внутренних процессов.
Практически недавно мне пришлось решать проблему кэширования данных на базе 3х механизмов языка Php: APCu, Файлы и Внутренние массивы данных. Каждый из подходов имеет свои преимущества и недостатки. Вкратце расскажу о каждом:

 

1) APCu - механизм кэширования данных (наследник APC), реализованный на базе ядра Php. Сюда же можно отнести и MemCache. Хранит данные в виде "ключ=>значение" в оперативной памяти сервера, за счет чего имеет немалые показатели в скорости чтения/записи.

 

Преимущества:

  • Высокая скорость чтения/записи
  • Доступность данных между запущенными процессами php
  • Может хранить несериализованные данные (толкайте объекты, массивы, бинарные данные - он всё проглотит)


Недостатки:

  • Сбрасывается через таймаут сервера, перезагрузки сервера (как следствие - энергозависим)
  • При неправильном именовании ключей легко затирается "соседними" процессами
  • При достижении лимита, установленного в настройках сервера, обнуляется целиком вместо того, чтобы удалять самые старые данные

 


2) Файлы - стандартный и порядком бородатый механизм кэширования данных. Хранит данные в простых файлах вашего сайта в любом символьном виде.

 

Преимущества:

  • Доступность данных между запущенными процессами php
  • Гибкость реализации (разработчик сам реализует механизм обработки кэша)
  • Независим от настроек Php
  • Энергонезависим


Недостатки

  • Относительно медленная скорость чтения/записи (в отличии от оперативной памяти)
  • При неправильном именовании ключей легко затирается "соседними" процессами
  • Не имеет встроенного лимита и без контроля легко разрастается и набирает вес в файловой системе
  • Не может хранить данные в несериализованном виде (привет-привет json_encode, serialize, pack и т.п.), в следствии чего не все данные могут быть приведены к начальному виду (как пример - экземпляры классов)

 


3) Внутренние массивы - самый простой вариант кэширования данных. Реализуется хранением данных в массиве текущего потока.

 

Преимущества:

  • Практически вне конкуренции по скорости чтения/записи
  • Гибкость реализации (разработчик сам реализует механизм обработки кэша)
  • Защищен от затирания "соседними" процессами
  • Может хранить несериализованные данные


Недостатки:

  • Сбрасывается при перезагрузке сервера (как следствие - энергозависим)
  • Сбрасывается при умирании процесса (уместен только в рамках одного процесса)
  • При достижении лимита, установленного в настройках сервера, вызывает всеми "любимую" memory overflow и посылает запущенный поток в fatal
  • Недоступен другим потокам

 


Как видно, каждый из вариантов хорош по-своему. Стоит так же учесть, что, кроме этих подходов, существует еще целое множество других, а если их начать комбинировать, то можно реализовать и что-то гибридное.

 

Так или иначе, совсем недавно мне пришлось решать проблемы, связанные с различными подходами кэширования в моей системе. Очень часто в единственный механизм кэширования системы натолкано несколько вариантов его реализации, и администратор, устанавливая в настройках тот или иной вариант, даже не подозревает, что обработка данных (да и вообще всё поведение) той или иной реализации кэширования могут существенно различаться. Программисты же, реализующие эти варианты, чаще всего даже не удосуживаются сравнить их логику с уже существующими в системе, удовлетворяя свой результат только лишь тем, что проверяют наличие факта кэширования данных своей новой реализации.

 

Приведу пример:

 

Вы воспользуетесь реализацией кэширования через APCu и отправите в кэш экземпляр какого-то класса, потом вернете его обратно из кэша, при этом получив в точности то, что отправили туда ранее. Но если вы воспользуетесь реализацией с помощью Файлов, то, после возвращения таких данных из кэша, вы можете удивиться тому, что ваш экземпляр класса попросту потеряет бОльшую часть данных. Это будет связано с тем, что файловый кэш отсылает и получает данные через механизм сериализации данных, который позволяет записывать их в файл в виде строк или бинарных данных. При этом, не каждый экземпляр может быть сериализован без потери данных.

 

Так как система чаще всего использует множественное API реализации (это значит, что у N реализаций механизма имеется X<=N вариантов внешнего API), то получается очень грубое нарушение логики - в зависимости от выбранной в настройках реализации, поведение системы меняется. А этого быть не должно.

 

Идеальный вариант выглядит как возможность смены реализации механизма без потерь в алгоритмах сериализации/десериализации данных. Вкратце говоря, не важно, как и в каком виде кэшируются ваши данные, важно, чтобы они удовлетворяли следующему постулату:

x = данные до сериализацииy = сериализованные данные в кэшеz = данные после десериализацииx -> y -> zгде x === z


Это показывает нам необходимость того, чтобы реализация сериализации/десериализации данных для любых реализаций механизма кэширования была единой и одинаковой. Т.е.: не важно, как и в каком виде кэшируются ваши данные, важно, чтобы они были совершенно идентичны до и после процедуры кэширования.

 


В наше время этому не уделяется особого внимания, и большинство разработчиков не удосуживаются проверять соответствие формата данных вне процедур кэширования. Что приводит к их несоответствию между различными реализациями механизмов кэшиования и, как следствие, нарушению структур данных во время работы системы.

 

Не важно, сколько у вас реализовано механизмов кэширования, важно, чтобы перед их API был реализован единый уровень сериализации/десериализации данных. Стоит также заметить, что общий механизм сериализации данных приведет к некоторым потерям в структурах данных (к примеру, урезание данных при сериализации объектов), но это то, чем необходимо пожертвовать для идентичности данных при любых реализациях механизма кэширования - уж если данные и будут урезаться, то пусть это будет одинаково при любой реализации.



0 Comments


Recommended Comments

There are no comments to display.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×