- Redis для приложений на Python
- Почему Redis?
- Установка Redis
- Строка подключения к Redis
- Создание клиента Redis
- Пример использования Redis
- Типы данных в Redis
- Срок хранения данных
- Python guide
- redis-py
- Install
- Connect
- Connect to a Redis cluster
- Connect to your production Redis with TLS
- Example: Indexing and querying JSON documents
- Learn more
- On This Page
Redis для приложений на Python
База данных Redis появилась в 2009 году, но ей все еще предстоит пройти проверку временем и полезностью в реальном мире, хотя многие разработчики и признают, что уже активно используют ее в повседневной практике.
Почему Redis?
Обычно при упоминании Redis у многих возникают ассоциации с базами данных NoSQL, но это в корне неверно. У Redis нет с ними ничего общего: ни в плане своего позиционирования, ни в плане исполнения. MongoDB, например, хранит данные на диске.
Выделение места для записей подразумевает, что эти данные должны быть сохранены: аккаунты пользователей, записи в блог, разрешения и так далее. Большая часть данных любых приложений относится к этой категории.
Тем не менее есть и исключения. Было бы крайне неэффективно хранить, например, содержимое корзины пользователя или информацию о последней посещенной странице. В краткосрочной перспективе такая информация была бы полезной, но нагружать ею базы данных, основанные на транзакционных системах — не очень разумно. Благо, существует такое понятие как RAM (ОЗУ или оперативное запоминающее устройство).
Redis — это резидентная база данных (такая, которая хранит записи прямо в оперативной памяти) в виде пар ключ-значение. Чтение и запись в память происходит намного быстрее, чем в случае с дисками, поэтому такой подход отлично подходит для хранения второстепенных данных.
Это улучшает пользовательский опыт, но одновременно делает базы данных чистыми. Если же в будущем решается, что такие данные тоже нужно хранить, то их всегда можно записать на диск (например, в базу данных SQL).
В этом руководстве познакомимся с библиотекой Python для Redis под названием redis-py. В среде Python его называют просто redis. Официальная документация этой библиотеки — просто одна страница с перечислением всех методов в алфавитном порядке.
Если вы планируете использовать Redis с каким-либо из фреймворков, то рекомендуется выбирать конкретную библиотеку: например, Flask-Redis, а не redis-py. Однако все они преимущественно повторяют синтаксис redis-py и имеют несколько минимальных отличий.
Установка Redis
Что бы протестировать работу Redis рекомендую использовать облачное решение. Зарегистрируйтесь на Redis Labs, они дают бесплатный сервер для обучения и тестирования.
- Пройдите регистрацию.
- Подтвердите почту.
- Создайте подписку (сервер).
После активации приложения вам понадобятся хост(Endpoint) и пароль (Default User Password).
Строка подключения к Redis
Как и в случае с обычными базами данных подключить экземпляр Redis можно с помощью строки подключения. Вот как такая выглядит в Redis:
redis://:hostname.redislabs.com@mypassword:12345/0
[CONNECTION_METHOD]:[HOSTNAME]@[PASSWORD]:[PORT]/[DATABASE]
- CONNECTION_METHOD — это суффикс, который нужен во всех URI Redis. Он определяет способ подключения к приложению. redis:// — стандартное соединение, rediss:// — подключается по SSL, redis-socket:// — зарезервированный тип для сокетов Unix и redis-sentinel:// — тип подключения для кластеров Redis с высоким уровнем доступности.
- HOSTNAME — URL или IP приложения Redis. Если вы используете облачное решение, то, скорее всего, вам нужен адрес AWS EC2. (Такова особенность современного капитализма, где все весь мелкий бизнес — это реселлеры с заранее настроенным ПО).
- PASSWORD — у приложения Redis есть пароль, но нет пользователей. Скорее всего, это связано с тем, что в случае с резидентной базой данных сложно было хранить их имена.
- PORT — выбранный порт.
- DATABASE — если не уверены, что здесь указать, просто напишите 0.
Создание клиента Redis
URI есть. Теперь нужно подключиться к Redis, создав объект клиента:
import redis
r = redis.StrictRedis(
host='redis-17449.c55.eu-central-1-1.ec2.cloud.redislabs.com', # из Endpoint
port=17449, # из Endpoint
password='qwerty' # ваш пароль
)Но почему StrictRedis, вы можете спросить? Есть два вида создания клиентов Redis: redis.Redis() и redis.StrictRedis() . StrictRedis пытается правильно применять типы данных. Старые экземпляры так не умеют. redis.Redis() — обратно совместимая с устаревшими экземплярами Redis версия с любыми наборами данных, а redis.StrictRedis() — нет. Если сомневаетесь — используйте StrictRedis.
Есть множество других аргументов, которые можно (и нужно) передать в redis.StrictRedis() , чтобы упростить себе жизнь. Обязательно передайте decode_responses=True , ведь это избавит необходимости явно расшифровывать каждое значение из базы. Также не лишним будет указать кодировку:
import redis
r = redis.StrictRedis(
host='redis-17449.c55.eu-central-1-1.ec2.cloud.redislabs.com',
port=17449,
password='qwerty',
charset="utf-8",
decode_responses=True
)Пример использования Redis
Хранилище ключ-значение Redis очень напоминает словари Python, отсюда и расшифровка — Remote Dictionary Service (удаленный сервис словарей). Ключи — это всегда строки, но значениями могут быть разные типы данных. Заполним приложение Redis несколькими записями, чтобы лучше понять, как они работают:
import redis
import time
r = redis.StrictRedis(
host='redis-17449.c55.eu-central-1-1.ec2.cloud.redislabs.com',
port=17449,
password='qwerty',
charset="utf-8",
decode_responses=True
)
r.set('ip_address', '127.0.0.0')
r.set('timestamp', int(time.time()))
r.set('user_agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 11)')
r.set('last_page_visited', 'home')r.set([KEY], [VALUE]) — это основной синтаксис, чтобы задавать одиночные значения. Первый параметр — это ключ, а второй — присваиваемое ему значение.
По аналогии с обычными базами данных подключение к Redis осуществляется с помощью графического интерфейса, по типу TablePlus для проверки данных. Вот как выглядит тестовая база после выполнения кода выше:
KEY | VALUE | TYPE | TTL |
---|---|---|---|
user_agent | Mozilla/5.0 (Macintosh; Intel Mac OS X 11) | STRING | -1 |
last_page_visited | home | STRING | -1 |
ip_address | 127.0.0.0 | STRING | -1 |
timestamp | 1610803181 | STRING | -1 |
Кажется, операция прошла успешно. Узнать кое-что о Redis можно, просто взглянув на таблицу. Начнем с колонки type.
Типы данных в Redis
В Redis могут храниться данные 5 типов:
- STRING (строка) — любое значение, сохраняемое с помощью r.set() , хранится в виде строки. Вы также можете обратить внимание на то, что значение timestamp будет целым числом в Python, но здесь оно выступает строкой. Вы можете подумать, что это не очень удобно, но строки в Redis — это чуть больше, чем может показаться на первый взгляд. Во-первых, они являются бинарно-безопасными, что значит, что с их помощью можно хранить почти что угодно, вплоть до изображений и сериализованных объектов. У строк также есть несколько встроенных функций, которые позволяют управлять ими так, будто бы это целые числа (например INC для инкремента).
- LIST (список) — списки являются изменяемыми массивами строк в Redis, которые сортируются в порядке появления. После создания списка новые элементы могут добавляться в конец с помощью команды RPUSH или в начало с помощью LPUSH . Можно также ограничить максимальное количество элементов в списке с помощью команды LTRIM . Если вы знакомы с методом вытеснения из кэша LRU, например, то должны быть знакомы с этой командой.
- SET (множество) — несортированный набор строк. По аналогии с множествами в Python в Redis элементы не могут повторяться. У множеств также есть уникальные функции по объединению и пересечению, что позволяет эффективно и быстро объединять данные из разных наборов.
- ZSET — те же множества, но уже сортированные. Однако в них по-прежнему могут храниться только уникальные значения. После создания порядок в них можно менять, что удобно для ранжирования уникальных элементов, например. Структура ZSET похожа на сортированные словари в Python за исключением того, что у них есть ключ для каждого значения (что было бы ненужным, ведь все множества уникальны).
- HASH (хэши) — хэши в Redis являются парами ключ-значение. Эта структура позволяют присваивать ключам значение из ключа и значения. Однако вложенными хэши быть не могут.
Срок хранения данных
В базе данных Redis есть четвертая колонка под названием ttl . В нашем примере для всех записей в ней было значение -1 . Когда же там положительное значение, то оно указывает на количество секунд до истечения срока действия данных. Redis — отличное хранилище для временно полезных данных, однако не таких, которые нужны в долгосрочной перспективе. Вот когда полезно устанавливать срок действия — это позволяет не нагружать приложение информацией, которая быстро становится нерелевантной.
Вернемся к примеру, где хранится информация о сессии пользователя и зададим срок действия данных:
Python guide
Connect your Python application to a Redis database Install Redis and the Redis client, then connect your Python application to a Redis database.
redis-py
Get started with the redis-py client for Redis. redis-py requires a running Redis or Redis Stack server. See Getting started for Redis installation instructions.
Install
For faster performance, install Redis with hiredis support. This provides a compiled response parser, and for most cases requires zero code changes. By default, if hiredis >= 1.0 is available, redis-py attempts to use it for response parsing.
Connect
Connect to localhost on port 6379, set a value in Redis, and retrieve it. All responses are returned as bytes in Python. To receive decoded strings, set decode_responses=True . For more connection options, see these examples.
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
r.set('foo', 'bar') # True r.get('foo') # bar
r.hset('user-session:123', mapping= 'name': 'John', "surname": 'Smith', "company": 'Redis', "age": 29 >) # True r.hgetall('user-session:123') #
Connect to a Redis cluster
from redis.cluster import RedisCluster rc = RedisCluster(host='localhost', port=16379) print(rc.get_nodes()) # [[host=127.0.0.1,port=16379,name=127.0.0.1:16379,server_type=primary,redis_connection=Redis>>], . rc.set('foo', 'bar') # True rc.get('foo') # b'bar'
Connect to your production Redis with TLS
import redis r = redis.Redis( host="my-redis.cloud.redislabs.com", port=6379, username="default", # use your Redis user. More info https://redis.io/docs/management/security/acl/ password="secret", # use your Redis password ssl=True, ssl_certfile="./redis_user.crt", ssl_keyfile="./redis_user_private.key", ssl_ca_certs="./redis_ca.pem", ) r.set('foo', 'bar') # True r.get('foo') # b'bar'
Example: Indexing and querying JSON documents
import redis from redis.commands.json.path import Path import redis.commands.search.aggregation as aggregations import redis.commands.search.reducers as reducers from redis.commands.search.field import TextField, NumericField, TagField from redis.commands.search.indexDefinition import IndexDefinition, IndexType from redis.commands.search.query import NumericFilter, Query
r = redis.Redis(host='localhost', port=6379)
user1 = "name": "Paul John", "email": "paul.john@example.com", "age": 42, "city": "London" > user2 = "name": "Eden Zamir", "email": "eden.zamir@example.com", "age": 29, "city": "Tel Aviv" > user3 = "name": "Paul Zamir", "email": "paul.zamir@example.com", "age": 35, "city": "Tel Aviv" >
Define indexed fields and their data types using schema . Use JSON path expressions to map specific JSON elements to the schema fields.
schema = ( TextField("$.name", as_name="name"), TagField("$.city", as_name="city"), NumericField("$.age", as_name="age") )
Create an index. In this example, all JSON documents with the key prefix user: will be indexed. For more information, see Query syntax.
rs = r.ft("idx:users") rs.create_index( schema, definition=IndexDefinition( prefix=["user:"], index_type=IndexType.JSON ) ) # b'OK'
r.json().set("user:1", Path.root_path(), user1) r.json().set("user:2", Path.root_path(), user2) r.json().set("user:3", Path.root_path(), user3)
res = rs.search( Query("Paul @age:[30 40]") ) # Result'>]>
rs.search( Query("Paul").return_field("$.city", as_field="city") ).docs # [Document , Document ]
req = aggregations.AggregateRequest("*").group_by('@city', reducers.count().alias('count')) print(rs.aggregate(req).rows) # [[b'city', b'Tel Aviv', b'count', b'2'], [b'city', b'London', b'count', b'1']]
Learn more
On This Page
This is a community website sponsored by Redis Ltd. © 2023. Redis and the cube logo are registered trademarks of Redis Ltd. Terms of use & privacy policy.