Подписка

Кеширование файлов в память

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

Основным требованием к системе кеширования файлов является изолированость, а также интеграция без изменения архитектуры и кода приложения, чтобы иметь возможность использовать ее в популярных CMS, таких как Wordpress, Drupal и др.

Рассмотрим метод кеширования файлов при помощи MFS и проверим есть ли прирост производительнсти на примере Drupal блога.

Memory file system (или tmpfs) - файловая система Unix, использующая оперативную память как временное хранилище данных. После перезагрузки компьютера и очистки памяти все данные конечно же будут утеряны. Создается стандартным для Unix путем - монтированием диска с указанием типа файловой системы и размера хранилища:

sudo mount -osize=100m tmpfs /mnt/tmpfs -t tmpfs
После выполнения этого кода, данные находящиеся в папке /mnt/tmpfs будут скопированы на виртуальный диск и все последующие операции ввода\вывода будут работать с оперативной памятью. При перезагрузке виртуальный диск будет удален, без выполнения каких-либо операций синхронизации с папкой на жестком диске.

Вернемся к нашей задаче: перенести файлы Drupal в ОЗУ, для ускорения загрузки. Так как все данные Drupal хранит в базе данных, единственной проблемой являются загружаемые через интерфейс файлы (картинки, документы), которые нужно синхронизировать с папкой на жестком диске.

Для синхронизации напрашиваются два решение - использование утилиты rsync или подсистемы ядра inotify.

Первое решение хорошо простотой - запускать с некоторым интервалом rsync с указанием папок для синхронизации, а остальное утилита сделает сама. Но конечно же хромает производительность: во-первых актуальность данных привязана к частоте синхронизации, а при перезагрузке без синхронизации, данные будут утеряны; во-вторых rsync перелопачивает все файлы в поисках изменений.

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

Процедура настройки rsync намного проще, поэтому на ней и остановимся. Если интересен вариант с inotify, пишите в комментариях, оформлю в виде отдельного поста.

Добавим немного автоматизации

Итак, попробуем написать скрипт, который будет инициализировать хранилище в памяти и запускать процедуру синхронизации.

1. Создадим виртуальный диск

Для этого создадим папку и выполним описанную выше процедуру монтирования:
mkdir /var/www/memdrive
sudo mount -osize=100m tmpfs /var/www/memdrive -t tmpfs

2. Скопируем файлы блога

Допустим, что блог лежит в папке /var/www/drupal, тогда выполним:
cp -r /var/www/drupal/* /var/www/memdrive

3. Запланируем синхронизацию раз в минуту

Для выполнения синхронизации rsync'у нужно только указать папки для синхронизации:
rsync -r /var/www/memdrive/* /var/www/drupal/
После выполнения команды, измененные файлы из папки memdrive будут скопированы в папку drupal, что нам и нужно. Добавим команду в cron для регулярного выполнения раз в минуту:
crontab -l | grep 'rsync -r /var/www/memdrive' || crontab -l | { cat; echo "* * * * * rsync -r /var/www/memdrive/* /var/www/drupal/"; } | crontab -

Вот и все, ниже весь скрипт целиком:

#!/bin/bash
mkdir /var/www/memdrive
sudo mount -osize=100m tmpfs /var/www/memdrive -t tmpfs
cp -r /var/www/drupal/* /var/www/memdrive
crontab -l | grep 'rsync -r /var/www/memdrive' || crontab -l | { cat; echo "* * * * * rsync -r /var/www/memdrive/* /var/www/drupal/"; } | crontab -

Измерим производительность

Теперь измерим время генерации страниц и сравним с сайтом работающим с жесткого диска.

Сайт на жестком диске:

ab -c 10 -n 100 http://drupal/

Requests per second:    4.64 [#/sec] (mean)
Time per request:       2155.171 [ms] (mean)
Time per request:       215.517 [ms] (mean, across all concurrent requests)
Transfer rate:          64.41 [Kbytes/sec] received

Сайт на mfs диске:

ab -c 10 -n 100 http://memdrive/

Requests per second:    4.62 [#/sec] (mean)
Time per request:       2164.804 [ms] (mean)
Time per request:       216.480 [ms] (mean, across all concurrent requests)
Transfer rate:          63.99 [Kbytes/sec] received

Оказалось, что кеширования файлов никак не повлияло на скорость работы Drupal. Похоже, что время потраченое на чтение файлов слишком мало по сравнению с выполеннием кода и работы с базой.

Проведем еще один эксперемент - измерим скорость скачивания статического файла.

Сайт на жестком диске:

ab -c 100 -n 100 http://drupal/sites/default/files/styles/medium/public/field/image/3.gif

Requests per second:    2034.42 [#/sec] (mean)
Time per request:       49.154 [ms] (mean)
Time per request:       0.492 [ms] (mean, across all concurrent requests)
Transfer rate:          33246.12 [Kbytes/sec] received

Сайт на msf диске:

ab -c 100 -n 100 http://memdrive/sites/default/files/styles/medium/public/field/image/3.gif

Requests per second:    3852.67 [#/sec] (mean)
Time per request:       25.956 [ms] (mean)
Time per request:       0.260 [ms] (mean, across all concurrent requests)
Transfer rate:          62959.61 [Kbytes/sec] received

Это уже интересней - файл с mfs диска, отдается почти в два раза быстрей файла с жесткого, благодаря огромной скорости передачи данных оперативной памяти.

Напрашивается вывод

Судя по полученным результатам - MFS хранилище отлично подходит для раздачи статических ресурсов, которые не нуждаются в риалтайм синхронизации, например, картинок, джаваскрипт файлов. А выигрыш за счет кеширования в память php файлов практически не заметен.

Если пост понравился - нажмите на гугловский +1 - мне будет больше мотивации писать ещё.

@kkooler

@kkooler

Занимаюсь разработкой высоконагруженных проектов и распределенных систем на PHP.
В свободное время разрабатываю нано-проекты:

Следить за блогом

RSS канал Twitter