Основы базы данных Redis – как работает интерфейс командной строки Redis, общие команды и примеры проектов

  • Михаил
  • 12 мин. на прочтение
  • 156
  • 27 Jun 2022
  • 21 Nov 2022

Redis - это популярная база данных в памяти, используемая для различных проектов, таких как кэширование и ограничение скорости.

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

Что такое база данных в памяти?

Традиционные базы данных хранят часть базы данных (обычно "горячие" или часто используемые индексы) в памяти для более быстрого доступа, а остальную часть базы данных на диске.

С другой стороны, Redis уделяет большое внимание задержкам и быстрому извлечению и хранению данных. Таким образом, он работает полностью на памяти (RAM) вместо устройств хранения (SSD / HDD). Скорость важна!

Redis - это база данных ключ-значение. Но не позволяйте этому обмануть вас, думая, что это простая база данных. У вас есть много способов хранить и извлекать эти ключи и значения.

Зачем вам нужен Redis?

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

  1. Вы создаете приложение, в котором хотите сделать уровень кода без состояния. Почему? - Потому что, если ваш код не имеет состояния, он масштабируется по горизонтали. Таким образом, вы можете использовать Redis в качестве центральной системы хранения и позволить вашему коду обрабатывать только логику.
  2. Вы создаете приложение, в котором нескольким приложениям может потребоваться совместное использование данных. Например, что, если кто-то пытается применить грубое насилие к вашему сайтуpayments.codedamn.com, и как только вы это обнаружите, вы также захотите заблокировать ихlogin.codedamn.com? Redis позволяет нескольким отключенным / слабо подключенным службам совместно использовать общее пространство памяти.

Основы Redis

Redis относительно прост в освоении, поскольку вам нужно знать всего несколько команд. В следующих двух разделах мы рассмотрим несколько основных концепций Redis и некоторые полезные общие команды.

Интерфейс командной строки Redis

ezgif.com-gif-maker

У Redis есть интерфейс командной строки, который является версией командной строки REPL. Все, что вы напишете, будет оценено.

На приведенном выше рисунке показано, как выполнить простой PINGили приветственный мир в Redis в одном из упражнений моего курса codedamn Redis (ссылка на курс приведена в конце, если вы хотите его проверить).

Этот Redis REPL очень полезен, когда вы работаете с базой данных в приложении и вам нужно быстро просмотреть несколько ключей или состояние Redis.

Common Redis commands

ezgif.com-gif-maker--1-

Trying out common commands on Redis CLI in codedamn course

Here are a few very commonly used commands in Redis to help you learn more about how it works:

SET

SET allows you to set a key to a value in Redis.

Here's an example of how it works:

SET mehul "developer from india"

This sets the key mehul to the value developer from india.

GET

GET allows you to get the keys you've set.

Here's the syntax:

GET mehul

This will return the string "developer from india" as we set above.

SETNX

This key will set a value only if the key does not exist. This command has a number of use cases, including not accidentally overwriting the value of a key which might already be present.

Here's how it works:

SET key1 value1
SETNX key1 value2
SETNX key2 value2

После запуска этого примера у вас key1будет значение value1и key2as value2. Это связано с тем, что вторая команда не будет иметь никакого эффекта, поскольку key1она уже присутствовала.

MSET

MSET похож на SET, но вы можете установить несколько ключей вместе в одной команде. Вот как это работает:

MSET key1 "value1" key2 "value2" key3 "value3"

Прямо сейчас мы используем keyand valueв качестве префикса для ключей и значений. Но на самом деле, когда вы пишете такой код, легко потерять представление о том, что является ключом, а что значением в такой длинной команде.

Итак, одна вещь, которую вы можете сделать, это всегда заключать свое значение в двойные кавычки и оставлять свои ключи без кавычек (если они являются допустимыми именами ключей без кавычек).

MGET

MGET похож на GET, но он может возвращать несколько значений одновременно, например:

MGET key1 key2 key3 key4

Это вернет четыре значения в виде массива: value1, value2, value3и null. Мы получили key4значение null, потому что мы никогда его не устанавливали.

DEL

Эта команда удаляет ключ – достаточно просто, не так ли?

Вот пример:

SET key value
GET key # gives you "value"
DEL key 
GET key # null

INCR и DECR

Вы можете использовать эти две команды для увеличения или уменьшения ключа, который является числом. Они очень полезны, и вы будете часто их использовать, потому что Redis может выполнять две операции одновременно – ПОЛУЧИТЬ ключ и УСТАНОВИТЬ ключ в key + 1.

Это позволяет избежать повторных переходов к вашему родительскому приложению и делает операцию также безопасной для выполнения без использования транзакций (подробнее об этом позже)

Вот как они работают:

SET favNum 10
INCR favNum # 11
INCR favNum # 12
DECR favNum # 11

СРОК ДЕЙСТВИЯ ИСТЕКАЕТ

Команда EXPIRE используется для установки таймера истечения срока действия на ключ. Технически это не таймер, а временная метка завершения, после которой ключ всегда будет возвращать значение null, если он не будет установлен снова.

SET bitcoin 100
EXPIRE bitcoin 10

GET bitcoin # 100
# after 10 seconds
GET bitcoin # null

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

TTL

С помощью этой команды можно узнать, сколько времени должен жить ключ.

Пример:

SET bitcoin 100
TTL bitcoin # -1
TTL somethingelse # -2

EXPIRE bitcoin 5
# wait 2 seconds
TTL bitcoin # returns 3
# after 1 second
GET bitcoin # null
TTL bitcoin # -2

Итак, чему мы можем научиться из этого кода?

  1. TTL будет возвращен-1, если ключ существует, но срок его действия не истек
  2. TTL вернет-2, если ключ не существует
  3. TTL вернет время жизни в секундах, если ключ существует и истекает

SETEX

Вы можете выполнять SET и EXPIRE вместе с SETEX.

Вот так:

SETEX key 10 value

Здесь ключ - "ключ", значение - "значение", а время жизни (TTL) равно 10. Этот ключ будет сброшен через 10 секунд.

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

Проект 1 – Создание системы кэширования API с помощью Redis

Скриншот-2021-04-13- в-4.20.13-УТРА

Предварительный просмотр лаборатории построения системы кэширования API на codedamn

Этот проект включает в себя настройку системы кэширования API с помощью Redis, где вы кэшируете результаты с стороннего сервера и используете его в течение некоторого времени.

This is useful so that you are not rate limited by that third party. Also, caching improves your site's speed, so if you implement it correctly it's a win-win for everyone.

You can build this project interactively on codedamn inside the browser using Node.js. If you're interested, you can try the API caching lab for free.

If you're only interested in the solution (and not building it yourself) here's how the core logic will work in Node.js:

app.post('/data', async (req, res) => {
	const repo = req.body.repo

	const value = await redis.get(repo)

	if (value) {
		// means we got a cache hit
		res.json({
			status: 'ok',
			stars: value
		})

		return
	}

	const response = await fetch(`https://api.github.com/repos/${repo}`).then((t) => t.json())

	if (response.stargazers_count != undefined) {
		await redis.setex(repo, 60, response.stargazers_count)
	}

	res.json({
		status: 'ok',
		stars: response.stargazers_count
	})
})

Let's see what's happening here:

  • We try to get the repo (which is the passed repo format - facebook/react) from our Redis cache. If present, great! We return the star count from our redis cache, saving us a roundtrip to GitHub's servers.
  • Если мы не находим его в кэше, мы делаем запрос к серверам GitHub и получаем количество звезд. Мы проверяем, не определено ли количество звездочек (в случае, если репозиторий не существует / является частным). Если у него есть значение, мы setexвводим значение с таймаутом 60 секунд.
  • Мы устанавливаем тайм-аут, потому что не хотим со временем обслуживать устаревшие значения. Это помогает нам обновлять количество звездочек не реже одного раза в минуту.

Вот полный исходный код:

codedamn-классы / redis-nodejs-classroom

Проект 2 - API с ограничением скорости с Redis

Скриншот-2021-04-13- в-4.21.31-УТРА

Предварительный просмотр API ограничения скорости с Redis

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

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

В этой лаборатории мы выполняем ограничение скорости по IP-адресу. Если вы хотите попробовать эту кодовую лабораторию, вы можете попробовать ее бесплатно на codedamn.

Если вас интересует только решение (а не создание его самостоятельно), вот как основная логика будет работать в Node.js:

app.post('/api/route', async (req, res) => {
	// add data here
	const ip = req.headers['x-forwarded-for'] || req.ip

	const reqs = await redis.incr(ip)
	await redis.expire(ip, 2)

	if (reqs > 15) {
		return res.json({
			status: 'rate-limited'
		})
	} else if (reqs > 10) {
		return res.json({
			status: 'about-to-rate-limit'
		})
	} else {
		res.json({
			status: 'ok'
		})
	}
})

Давайте разберемся с этим блоком кода:

  • Мы пытаемся извлечь IP-адрес из x-forwarded-forзаголовка (или вы можете использоватьreq.ip, как мы используем express)
  • Мы INCRвводим поле IP-адреса. Если бы наш ключ в Redis никогда не существовал, INCR автоматически установил бы его в 0 и увеличил, то есть окончательно установил бы его в 1.
  • Мы устанавливаем срок действия ключа через 2 секунды. В идеале вам нужно большее значение - но это то, что указано выше в задаче codedamn, так что у нас это есть.
  • Наконец, мы проверяем количество запросов, если они превышают определенный порог, мы блокируем доступ запроса к основному телу функции.

Вот полное решение:

codedamn-классы / redis-nodejs-classroom

Подробнее о Redis

Redis - это гораздо больше, чем то, что мы узнали до сих пор. Но хорошо то, что мы узнали достаточно, чтобы уже начать работать с ним!

В этом разделе давайте рассмотрим еще несколько основ Redis.

Redis является однопоточным

Redis выполняется как однопоточный процесс даже в многоядерной системе, поддерживающей многопоточность. Это не кошмар производительности, а мера безопасности против непоследовательного чтения / записи в многопоточной среде.

Если бы Redis был многопоточным, чтобы обеспечить потокобезопасность при доступе к одному ключу, вы бы в конечном итоге решили использовать какой-то механизм блокировки, который, вероятно, в любом случае работал бы хуже, чем однопоточный / последовательный доступ.

Транзакции Redis

Конечно, вы не можете сделать все в Redis одной командой. Но вы, конечно, можете попросить его выполнить блок команд за один раз (то есть никто другой не разговаривает с Redis, пока он выполняет этот блок). Вы можете сделать это с помощью MULTIкоманды.

Вот как это работает:

MULTI
SET hello world
SET yo lo
SET number 1
INCR number
EXPIRE hello 10
EXPIRE yo 5
EXEC

Это выполнит все эти операции за один раз, то есть после этого он вообще ничего не MULTIбудет запускать и запустит все сразу, как только увидит EXECключевое слово.

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