Статьи

Повысьте производительность своего приложения с помощью Memcached

Один из самых простых способов повысить производительность вашего приложения — поместить решение для кэширования перед вашей базой данных. В этом уроке я покажу вам, как использовать Memcached с Rails, Django или Drupal.

Memcached — отличный выбор для этой проблемы, учитывая ее солидную историю, простую установку и активное сообщество. Он используется компаниями, большими и малыми, и включает в себя такие гиганты, как Facebook, YouTube и Twitter. Сайт Memcached сам по себе хорошо описывает Memcached как «бесплатную и открытую высокопроизводительную систему кэширования объектов с распределенной памятью, универсальную по своей природе, но предназначенную для ускорения динамических веб-приложений за счет снижения нагрузки на базу данных. «

Как правило, вызовы базы данных медленные.

Как правило, вызовы базы данных выполняются медленно, поскольку запрос обрабатывает ресурсы ЦП, а данные (обычно) извлекаются с диска. С другой стороны, кэш в памяти, такой как Memcached, занимает очень мало ресурсов ЦП, и данные извлекаются из памяти, а не с диска. Облегченный процессор является следствием дизайна Memcached; это не для запросов, как база данных SQL. Вместо этого он использует пары ключ-значение для извлечения всех данных, и вы не можете извлечь данные из Memcached, предварительно не узнав его ключ.

Memcached хранит пары ключ-значение полностью в памяти. Это делает поиск чрезвычайно быстрым, но при этом делает данные эфемерными. В случае сбоя или перезагрузки память очищается, и все пары ключ-значение необходимо перестраивать. В Memcached нет встроенных систем высокой доступности и / или аварийного переключения. Однако это распределенная система, поэтому данные хранятся на нескольких узлах. Если один узел потерян, остальные узлы продолжают обслуживать запросы и заполнять отсутствующий узел.

Установка Memcached — довольно простой процесс. Это можно сделать через менеджер пакетов или скомпилировав его из исходного кода. В зависимости от вашего дистрибутива вы можете компилировать из исходного кода, поскольку пакеты имеют тенденцию немного отставать.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
# Install on Debian and Ubuntu
apt-get install memcached
 
# Install on Redhat and Fedora
yum install memcached
 
# Install on Mac OS X (with Homebrew)
brew install memcached
 
# Install from Source
get http://memcached.org/latest
tar -zxvf memcached-1.xxtar.gz
cd memcached-1.xx
./configure
make && make test
sudo make install

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

1
memcached -m 512 -c 1024 -p 11211 -d

На этом этапе вы должны работать с Memcached. Далее мы рассмотрим, как использовать его с Rails, Django и Drupal. Следует отметить, что Memcached не ограничивается использованием в рамках. Вы можете использовать Memcached со многими языками программирования через один из множества доступных клиентов .

Rails 3 абстрагировал систему кеширования, так что вы можете изменить клиента по своему желанию. В Ruby предпочтительным клиентом Memcached является Dalli.

1
2
3
4
5
6
# Add Dalli to your Gemfile
gem ‘dalli’
 
# Enable Dalli in config/environments/production.rb:
config.perform_caching = true
config.cache_store = :dalli_store, ‘localhost:11211’

В режиме разработки вы обычно не запускаете Memcached, поэтому либо запустите Rails в рабочем режиме с rails server -e production , либо добавьте приведенные выше строки в ваш config/environments/development.rb .

Простейшее использование кэша — использование методов write / read для извлечения данных:

1
2
Rails.cache.write ‘hello’, ‘world’ #=> true
Rails.cache.read ‘hello’ #=> «world»

Самым распространенным шаблоном для кэширования Rails является использование fetch . Он попытается получить ключ (в данном случае, expensive-query ) и вернуть значение. Если ключ не существует, он выполнит переданный блок и сохранит результат в ключе.

1
2
3
4
5
6
7
Rails.cache.fetch ‘expensive-query’ do
  results = Transaction.
    joins(:payment_profile).
    joins(:order).
    where(‘:created > orders.created_at’, :created => Time.now)
end
# … more code working with results

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

1
2
3
4
5
6
users = User.active
users.each do |u|
  Rails.cache.fetch «profile/#{u.id}/#{u.updated_at.to_i}» do
    u.profile
  end
end

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

1
2
3
class Profile < ActiveRecord::Base
  belongs_to :user, touch: true
end

Теперь у вас есть самодействующие профили, и вам не нужно беспокоиться о получении старых данных при обновлении пользователя. Это почти как волшебство!

После установки Memcached доступ к Django становится довольно простым. Сначала вам нужно установить клиентскую библиотеку. Мы будем использовать pylibmc .

01
02
03
04
05
06
07
08
09
10
# Install the pylibmc library
pip install pylibmc
 
# Configure cache servers and binding settings.py
CACHES = {
    ‘default’: {
        ‘BACKEND’: ‘django.core.cache.backends.memcached.PyLibMCCache’,
        ‘LOCATION’: ‘127.0.0.1:11211’,
    }
}

Ваше приложение должно быть запущено с Memcached прямо сейчас. Как и другие библиотеки, вы получите базовые методы getter и setter для доступа к кешу:

1
2
cache.set(‘hello’, ‘world’)
cache.get(‘hello’) #=> ‘world’

Вы можете условно установить ключ, если он еще не существует с add . Если ключ уже существует, новое значение будет игнорироваться.

1
2
3
cache.set(‘hello’, ‘world’)
cache.add(‘hello’, ‘mundus’)
cache.get(‘hello’) #=> ‘world’

Из библиотеки Python Decorator вы можете создать созданный memoized декоратор для кэширования результатов вызова метода.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import collections
import functools
 
class memoized(object):
    »’Decorator.
    If called later with the same arguments, the cached value is returned
    (not reevaluated).
    »’
    def __init__(self, func):
        self.func = func
        self.cache = {}
    def __call__(self, *args):
        if not isinstance(args, collections.Hashable):
            # uncacheable.
            # better to not cache than blow up.
            return self.func(*args)
        if args in self.cache:
            return self.cache[args]
        else:
            value = self.func(*args)
            self.cache[args] = value
            return value
    def __repr__(self):
        »’Return the function’s docstring.»’
        return self.func.__doc__
    def __get__(self, obj, objtype):
        »’Support instance methods.»’
        return functools.partial(self.__call__, obj)
 
@memoized
def fibonacci(n):
    «Return the nth fibonacci number.»
    if n in (0, 1):
        return n
    return fibonacci(n-1) + fibonacci(n-2)
 
print fibonacci(12)

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

Начало работы с Memcached в Drupal начинается с установки расширения PHP для Memcached.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
# Install the Memcached extension
pecl install memcache
 
<?php
    // Configure Memcached in php.ini
    [memcache]
    memcache.hash_strategy = consistent
    memcache.default_port = 11211
?>
 
<?php
    // Tell Drupal about Memcached in settings.php
    $conf[‘cache_backends’][] = ‘sites/all/modules/contrib/memcache/memcache.inc’;
    $conf[‘cache_default_class’] = ‘MemCacheDrupal’;
    $conf[‘memcache_key_prefix’] = ‘app_name’;
    $conf[‘memcache_servers’] = array(
        ‘10.1.1.1:11211’ => ‘default’,
        ‘10.1.1.2:11212’ => ‘default’
    );
?>

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

Как и ожидалось, вы получите стандартные методы getter и setter с модулем Memcached. Одно предупреждение: cache_get возвращает строку кеша, поэтому вам нужно получить доступ к сериализованным данным внутри нее.

1
2
3
4
5
<?php
    cache_set(‘hello’, ‘world’);
    $cache = cache_get(‘hello’);
    $value = $cache->data;
?>

И просто так, у вас есть кеширование в Drupal. Вы можете создавать собственные функции для репликации таких функций, как cache.fetch в Rails. При небольшом планировании вы можете получить надежное решение для кэширования, которое выведет отзывчивость вашего приложения на новый уровень.

В то время как хорошая стратегия кэширования требует времени для улучшения, она не должна мешать вам начать работу.

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

Как и в любой сложной системе, мониторинг имеет решающее значение. Понимание того, как используется ваш кэш и где находятся «горячие точки» в ваших данных, поможет вам повысить производительность вашего кэша. Memcached имеет систему статистики качества, которая поможет вам контролировать кластер кеша. Вам также следует использовать такой инструмент, как New Relic, чтобы следить за балансом между временем кеша и базой данных. В качестве дополнительного бонуса вы можете получить бесплатную футболку Data Nerd при регистрации и развертывании.