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