Russian (Pусский) translation by Masha Kolesnikova (you can also view the original English article)
Одним из способов уменьшить нагрузку на сервер является кеширование данных. Это делается путем кэширования данных после их обработки и последующего получения из кэша при следующем запросе. В этом учебнике дается подробное обсуждение Redis, объясняя, как установить Redis и как кэшировать данные в приложениях Python.
Введение в Redis и кэширование
Кэширование относится к сохранению ответа сервера на самом клиенте, так что клиенту не нужно снова и снова запрашивать сервер для одного и того же ресурса. Ответ сервера должен содержать информацию о том, как сделать кеширование, чтобы клиент кэшировал ответ на определенный период времени или вообще никогда не кэшировал ответ сервера.
Кэш, с другой стороны, является аппаратным или программным компонентом, который используется для хранения данных, поэтому будущие запросы на одни и те же данные могут быть отправлены быстрее.
В наше время, когда пользователи ожидают результаты в течение секунды, целесообразно обслуживать запросы, читая данные из кеша, что в конечном счете будет быстрее, чем чтение из более медленного хранилища данных; таким образом, производительность системы зависит от количества запросов, которые могут быть получены из кеша.
Redis - хранилище данных в памяти с открытым исходным, используемое в качестве базы данных, кеша и брокера сообщений. Он работает, сохраняя данные в кеше и предоставляя их при следующем запросе, а не каждый раз запрашивая базу данных.
Установка Redis
Первый шаг - получить Redis и запустить локально на вашем компьютере. Самый простой способ установить Redis через диспетчер пакетов операционной системы:
1 |
sudo apt-get install redis-server |
Вы также можете следовать инструкциям официального сайта Redis.
Загрузите и извлеките Redis 4.0.6 tar следующим образом:
1 |
$ wget https://download.redis.io/releases/redis-4.0.6.tar.gz
|
2 |
$ tar xzf redis-4.0.6.tar.gz |
3 |
$ cd redis-4.0.6 $ make |
Бинарные файлы, которые теперь компилируются, доступны в каталоге src. Запустите Redis с помощью:
1 |
$ src/redis-server
|
Вы можете взаимодействовать с Redis с помощью встроенного клиента:
1 |
$ src/redis-cli
|
2 |
redis set foo bar OK redis
|
3 |
get foo "bar"
|
Чтобы проверить, запущен ли сервер redis, выполните в терминале следующую команду:
1 |
$ sudo redis-server |
2 |
* Ready to accept connections
|
Пример API Django
Давайте создадим наш проект Django. Наш проект сможет кэшировать все продукты в магазине, что позволяет легко и быстро извлекать данные при последующих запросах.
Чтобы использовать Redis в нашем приложении, нам нужно сделать следующее:
- Проверить, существуют ли результаты для текущего запроса в кеше.
- Если результаты есть в кеше, извлеките их.
- Если результатов не существует, извлеките их, сохраните их в кеше и затем пересылайте их запрашивающему объекту.
Требования
- Django
- django-redis
- Redis
- loadtest
Создаем свой проект
Прежде чем приступить к работе, создайте каталог и установите виртуальное окружение. Виртуальное окружение позволит вам устанавливать версии библиотек, требуемые вашим приложением.
1 |
mkdir myprojects
|
2 |
|
3 |
cd myprojects
|
Затем активируйте виртуальное окружение и установите требования к проекту.
1 |
source venv/bin/activate
|
2 |
|
3 |
pip install django==1.9 |
4 |
|
5 |
pip install django-redis
|
6 |
|
7 |
pip install djangorestframework
|
Создание проекта Django
1 |
django-admin startproject django_cache |
Создайте новое приложение под названием store, которое будет обрабатывать управление продуктами в нашем магазине.
1 |
cd django_cache
|
2 |
|
3 |
python manage.py startapp store |
Добавьте приложение store и rest_framework в список установленных приложений в файле settings.py
.
1 |
# settings.py
|
2 |
INSTALLED_APPS = [ |
3 |
'django.contrib.admin', |
4 |
'django.contrib.auth', |
5 |
'django.contrib.contenttypes', |
6 |
'django.contrib.sessions', |
7 |
'django.contrib.messages', |
8 |
'django.contrib.staticfiles', |
9 |
'store', # add here |
10 |
'rest_framework', # add here too |
11 |
]
|
Создание моделей
В store/models.py
мы начинаем с создания модели продукта для хранения сведений о продукте следующим образом:
1 |
from __future__ import unicode_literals |
2 |
from django.db import models |
3 |
import datetime |
4 |
|
5 |
# Create your models here.
|
6 |
|
7 |
|
8 |
class Product(models.Model): |
9 |
|
10 |
name = models.CharField(max_length=255) |
11 |
description = models.TextField(null=True, blank=True) |
12 |
price = models.IntegerField(null=True, blank=True) |
13 |
date_created = models.DateTimeField(auto_now_add=True, blank=True) |
14 |
date_modified = models.DateTimeField(auto_now=True, blank=True) |
15 |
|
16 |
def __unicode__(self): |
17 |
return self.name |
18 |
|
19 |
def to_json(self): |
20 |
return { |
21 |
'id': self.id, |
22 |
'name': self.name, |
23 |
'desc': self.description, |
24 |
'price': self.price, |
25 |
'date_created': self.date_created, |
26 |
'date_modified': self.date_modified |
27 |
}
|
Миграции
Создайте первоначальную миграцию для нашей модели продуктов и выполните синхронизацию базы данных.
1 |
python manage.py makemigration store |
2 |
|
3 |
python manage.py migrate |
Создание суперпользователя
Создайте суперпользователя, войдите в панель администратора и заполните базу данных примерами данных, которые мы будем использовать для проведения наших тестов.
1 |
python manage.py createsuperuser |
Настройка Redis в приложениях Python
Чтобы использовать Redis с приложением Django, нам нужно настроить Redis для хранения данных кэша приложения. Добавьте следующее в файл settings.py
:
1 |
CACHES = { |
2 |
'default': { |
3 |
'BACKEND': 'django_redis.cache.RedisCache', |
4 |
'LOCATION': 'redis://127.0.0.1:6379/', |
5 |
'OPTIONS': { |
6 |
'CLIENT_CLASS': 'django_redis.client.DefaultClient', |
7 |
}
|
8 |
}
|
9 |
}
|
Затем мы создадим ендпоинт, который достает все продукты из нашей базы данных. Сначала мы проверим производительность приложения с точки зрения того, сколько времени потребуется для извлечения данных из базы данных без кэширования. Затем мы реализуем другой ендпоинт, который извлекает данные из кеша и сравним производительность.
В файле store/views.py
добавьте следующий код, который извлекает все продукты, существующие в базе данных.
1 |
from django.shortcuts import render |
2 |
from rest_framework.decorators import api_view |
3 |
from rest_framework.response import Response |
4 |
from rest_framework import status |
5 |
|
6 |
# Create your views here.
|
7 |
|
8 |
|
9 |
|
10 |
@api_view(['GET']) |
11 |
def view_books(request): |
12 |
|
13 |
products = Product.objects.all() |
14 |
results = [product.to_json() for product in products] |
15 |
return Response(results, status=status.HTTP_201_CREATED) |
Настройка URL-адресов
Создайте файл store/urls.py
и добавьте в него следующий код.
1 |
# store/urls.py
|
2 |
from django.conf.urls import url |
3 |
from .views import view_books |
4 |
|
5 |
|
6 |
urlpatterns = [ |
7 |
url(r'^$', view_books), |
8 |
]
|
Нам также необходимо импортировать URL-адреса из приложения users в основной файл django_cache/urls.py
.
1 |
# django_cache/urls.py
|
2 |
|
3 |
from django.conf.urls import url, include |
4 |
from django.contrib import admin |
5 |
|
6 |
urlpatterns = [ |
7 |
url(r'^admin/', admin.site.urls), |
8 |
url(r'^store/', include('store.urls')) |
9 |
]
|
Давайте проведем тест и посмотрим, как у нас все получилось. Мы будем использовать loadtest. Если вы не знакомы с loadtest, то это инструмент для тестирования производительности.
Установка loadtest как root довольна простая:
1 |
sudo npm install -g loadtest |
1 |
$ loadtest -n 100 -k http://localhost:8000/store/ |
2 |
|
3 |
# result
|
4 |
INFO Requests per second: 55 |
5 |
Как видно из вышеизложенного, 55 запросов обрабатываются за секунду.
Давайте создадим еще один ендпоинт для извлечения данных после кэширования с помощью Redis. Измените файл users/views.py
, чтобы в нем был следующий код:
1 |
from rest_framework.decorators import api_view |
2 |
from rest_framework import status |
3 |
from rest_framework.response import Response |
4 |
from django.core.cache import cache |
5 |
from django.conf import settings |
6 |
from django.core.cache.backends.base import DEFAULT_TIMEOUT |
7 |
|
8 |
CACHE_TTL = getattr(settings, 'CACHE_TTL', DEFAULT_TIMEOUT) |
9 |
from .models import Product |
10 |
|
11 |
|
12 |
# Create your views here.
|
13 |
|
14 |
|
15 |
@api_view(['GET']) |
16 |
def view_books(request): |
17 |
# rest of the code
|
18 |
|
19 |
|
20 |
@api_view(['GET']) |
21 |
def view_cached_books(request): |
22 |
if 'product' in cache: |
23 |
# get results from cache
|
24 |
products = cache.get('product') |
25 |
return Response(products, status=status.HTTP_201_CREATED) |
26 |
|
27 |
else: |
28 |
products = Product.objects.all() |
29 |
results = [product.to_json() for product in products] |
30 |
# store data in cache
|
31 |
cache.set(product, results, timeout=CACHE_TTL) |
32 |
return Response(results, status=status.HTTP_201_CREATED) |
33 |
В приведенном выше коде будет проверяться, присутствует ли нужный продукт в кеше, и если он найден, соответствующие данные будут возвращены в браузер. В случае отсутствия данных в кеше мы сначала извлекаем данные из базы данных, сохраняем их в кеше и затем возвращаем в браузер.
Обновите store/urls.py
следующим образом.
1 |
from django.conf.urls import url |
2 |
from .views import view_books, view_cached_books |
3 |
|
4 |
|
5 |
urlpatterns = [ |
6 |
url(r'^$', view_books), |
7 |
url(r'^cache/', view_cached_books), |
8 |
|
9 |
]
|
Давайте проведем тесты.
1 |
$ loadtest -n 100 -k http://localhost:8000/store/cache/ |
2 |
|
3 |
# results
|
4 |
INFO Requests per second: 233 |
5 |
|
6 |
В первый раз, когда вы запросите ендпоинт localhost:8000/store/cache, приложение будет запрашивать данные из базы данных и возвращать их, но последующие вызовы на этот URL будут обходить базу данных и делать запрос в кеш, поскольку данные уже доступны будут доступны в нем ,
Заключение
В этом уроке мы использовали Redis, чтобы придать иллюзию скорости нашему приложению. Мы использовали Redis для хранения результатов запросов, а затем при последующих запросах возвращали эти результаты из кеша.
Существуют и другие инструменты кеширования, такие как Memcached, похожие на Redis. Однако Redis более популярен, чем Memcached, потому что для настройки и работы в приложениях требуется всего пара минут. Redis имеет более сложные механизмы, поскольку он был описан как «хранилище структур данных», что делает его более мощным и гибким. Redis также имеет большее преимущество, потому что вы можете хранить данные в любой форме.
Надеюсь, этот учебник показал вам, как легко добавить кэш-слой в ваше приложение, и, следовательно, повысить его производительность. Кэширование должно быть тем, что нужно учитывать, когда вам нужно сократить время загрузки и затраты на сервер.