Как сократить время отклика и повысить производительность с помощью кэширования Redis
4 мая 2023 г.Мы живем в эпоху сиюминутности, когда время уже стоит больше, чем деньги. И эта эпоха в сочетании с динамизмом Интернета делает нашу аудиторию все более требовательной с каждым днем.
Содержание вашего веб-сайта может быть превосходным, но если скорость загрузки не очень хорошая, будут ли люди ждать, чтобы увидеть его?
Согласно нескольким исследованиям, половина пользователей не ждет больше трех секунд. Это проблема для веб-сайтов, таких как интернет-магазины, где пользователи могут покинуть страницу, если она не загружается почти сразу, и потерять потенциальные продажи.
Кэширование данных вашего веб-приложения может иметь решающее значение для решения этой проблемы и обеспечения высокой производительности при масштабировании.
В последние годы Redis стала самой популярной базой данных кэширования, поскольку она позволяет веб-сайту значительно повысить производительность и работать более плавно, получая доступ к данным за миллисекунды.
Что такое Redis?
Удаленный сервер словарей (Redis) – это высокопроизводительная база данных NoSQL с открытым исходным кодом, которая в основном используется в качестве решения для кэширования для различных типов приложений.
Redis основан на структуре хеш-таблицы, в которой каждый ключ имеет связанное значение. По сравнению с другими базами данных типа "ключ-значение" Redis позволяет использовать более сложные и гибкие структуры, которые открывают несколько возможностей для различных потребностей бизнес-приложений.
Использование Redis настоятельно рекомендуется, когда скорость доступа и время отклика имеют решающее значение для бизнес-решения. Его использование также показано при работе с приложениями реального времени, которым требуется быстрый доступ к данным для сокращения времени отклика. Среди наиболее распространенных вариантов использования мы можем найти:
* Системы чата и обмена сообщениями * Список самых последних предметов * Счетчики в реальном времени и использование статистики * Управление и администрирование корзины онлайн-покупок * Хранение пользовательских сессий в приложении * Поддержка кэширования веб-страниц
Что такое кэширование?
Кэширование – это процесс хранения копий данных в памяти, позволяющий приложениям быстрее получать доступ к данным и извлекать их.
Цель кэширования — ускорить операции доступа к данным лучше, чем это может позволить база данных или удаленный сервер. Особенно это касается дорогостоящих (по времени) операций.
Например, если наши запросы требуют нескольких операций, таких как получение данных из базы данных, выполнение вычислений, получение дополнительных данных из других служб и т. д., мы можем использовать кэширование.
При этом мы обрабатываем данные только один раз, сохраняем их в кеше, а затем извлекаем непосредственно из кеша, не выполняя всех этих дорогостоящих операций. Затем мы будем периодически обновлять кеш, чтобы пользователи могли видеть обновленную информацию.
Кэширование с помощью Node.js и Redis
Теперь мы начнем с разработки нашего приложения. В этом руководстве мы хотим добиться выполнения запросов к внешнему API и измерения времени отклика.
После этого мы внедрим Redis в наше приложение, сохраняя результат наших запросов в кеше. Благодаря этому мы сможем сравнить время отклика до Redis и после Redis.
Настройка Redis
Первое, что нужно сделать в этом руководстве, это установить Redis в нашей локальной среде. Для этого мы будем следовать этим руководствам по установке для каждой платформы.
Установить в Ubuntu< /а>сильный>
Настройка Node.js
Мы начинаем наш проект Node.js с команды для создания package.json
.
npm init
Для нашего приложения Node.js нам необходимо установить следующие зависимости с помощью следующих команд:
npm install express redis axios
* Express для создания сервера. * Redis для подключения нашего приложения к Redis и выполнения запросов. * axios для выполнения запросов REST
npm install nodemon response-time -D
* nodemon для автоматического пробуждения нашего приложения после каждого изменения * время ответа, чтобы узнать, сколько времени занимает каждый запрос
В нашем файле package.json
мы создадим внутри ключа «scripts» новый скрипт, который мы будем использовать для запуска нашего приложения.
"dev": "nodemon src/app.js"
Создание приложения Node.js
Настройте исходный шаблон для приложения Node.js следующим образом. Мы создаем файл app.js
и добавляем в него следующие строки:
const express = require('express')
const responseTime = require('response-time')
const redis = require('redis')
const axios = require('axios')const app = express()app.listen(process.env.PORT || 3000, () => {
console.log("Node server started")
})
Теперь у нас есть созданный сервер Express, если мы выполним команду.
npm run dev
Мы увидим в консоли сообщение "Сервер Node запущен"
Получение данных из внешнего API
В нашем руководстве мы будем использовать REST-версию The Rick and Morty API, которая предлагает нам следующие конечные точки:
{
"characters": "https://rickandmortyapi.com/api/character",
"locations": "https://rickandmortyapi.com/api/location",
"episodes": "https://rickandmortyapi.com/api/episode"
}
Теперь мы сделаем запрос с помощью axios к конечной точке /character
.
const express = require('express')
const responseTime = require('response-time')
const redis = require('redis')
const axios = require('axios')
const app = express()
app.use(responseTime())app.get("/character", async (req, res) => {
try {
const response = await axios.get('https://rickandmortyapi.com/api/character')
await client.set('characters', JSON.stringify(response.data))
return res.status(200).json(response.data)
} catch (err) {
return res.status(err.response.status).json({ mmessage: err.mmessage })
}
});
app.listen(process.env.PORT || 3000, () => { console.log("Node server started")})
С этим запросом, который мы сделали, API возвращает нам объект со всеми символами, и нас интересует время ответа
, которое занял этот запрос.
Используя время отклика, которое мы добавили в качестве промежуточного программного обеспечения, мы сможем увидеть в заголовках запроса новый заголовок с именем X-Response-Time
, который будет указывать время в большем количестве. р>
Этот запрос занял 238,831 мс:
Внедрение кэша Redis для нашей конечной точки
Теперь давайте посмотрим, как мы можем повысить производительность приложения с помощью кэширования.
Во-первых, нам нужно подключиться к серверу Redis через наше приложение. Для этой задачи мы используем установленный пакет Redis.
По умолчанию redis.createClient()
будет использовать 127.0.0.1
и 6379
в качестве имени хоста и порта соответственно. Если у вас другой хост/порт, вы можете указать их следующим образом:
const client = redis.createClient(port, host)
const runApp = async () => {
const client = redis.createClient()
client.on('error', (err) => console.log('Redis Client Error', err))
await client.connect()
console.log('Redis connected!')
}
runApp()
Теперь мы сделаем тот же запрос к API и кэшируем ответ методом set()
клиента Redis, который получает в качестве первого параметра имя ключа, который мы хотим сохранить. В качестве второго параметра значение этого ключа, которое мы должны сохранить в виде строки, поэтому мы должны преобразовать JSON в строку.
const runApp = async () => {
app.get('/character', async (req, res) => {
try {
const response = await axios.get('https://rickandmortyapi.com/api/character')
await client.set('characters', JSON.stringify(response.data))
return res.status(200).json(response.data)
} catch (err) {
return res.status(err.response.status).json({ mmessage: err.mmessage })
}
})
}
runApp()
Как только мы перезагрузим наше приложение и получим результат запроса, мы уже кэшируем ответ.
Чтобы проверить это, мы будем использовать Redis-commander. Redis-commander позволяет нам просматривать через веб-интерфейс нашу базу данных Redis. Мы устанавливаем его с помощью следующей команды:
npm install -g redis-commander
Этот пакет предоставит нам команду redis-commander
, которая при выполнении запустит веб-интерфейс базы данных на порту 127.0.0.1:8081
.
И когда мы войдем в redis-commander, мы увидим, что ответ на наш /character
запрос уже сохранен с именем, которое мы ему присвоили.
Процесс кэширования с Redis довольно прост. Когда мы получаем запрос от пользователя, мы сначала проверяем, закэшированы ли запрошенные данные. Если это так, мы можем быстро получить данные из Redis и отправить ответ.
Однако, если данные не кэшируются, что мы называем промахом кеша, мы должны сначала получить данные из базы данных или внешнего API и отправить их клиенту. Мы также сохраняем извлеченные данные в кеше, чтобы в следующий раз, когда будет получен тот же запрос, мы могли просто быстрее отправить кешированные данные пользователю.
const runApp = async () => {
app.get('/character', async (req, res) => {
try {
const cacheCharacters = await client.get('characters')
if (cacheCharacters) {
return res.json(JSON.parse(cacheCharacters))
}
const response = await axios.get('https://rickandmortyapi.com/api/character')
await client.set('characters', JSON.stringify(response.data))
return res.status(200).json(response.data)
} catch (err) {
return res.status(err.response.status)
.json({ mmessage: err.mmessage })
}
})
}
runApp()
n Теперь, когда мы извлекаем информацию из кеша, время отклика значительно сократилось до 4 230 мс.
Важно отметить, что в этом руководстве мы коснулись только поверхности, и Redis может предложить гораздо больше. Я настоятельно рекомендую ознакомиться с официальной документацией.
Вот полный скрипт с еще одним примером с получением параметров конечной точкой:
const express = require('express')
const responseTime = require('response-time')
const redis = require('redis')
const axios = require('axios')
const runApp = async () => {
// connect to redis
const client = redis.createClient()
client.on('error', (err) => console.log('Redis Client Error', err));
await client.connect();
console.log('Redis connected!')
const app = express()
// add response-time to requests
app.use(responseTime())
app.get('/character', async (req, res) => {
try {
// check if the request is already stored in the cache, if so, return the response
const cacheCharacters = await client.get('characters')
if (cacheCharacters) {
return res.json(JSON.parse(cacheCharacters))
}
// makes the request to the API
const response = await axios.get('https://rickandmortyapi.com/api/character')
/* Another way to save the data is to save it with the name of the requets url, with the property
req.originalUrl which would be the same as '/character'
await client.set(req.originalUrl, JSON.stringify(response.data))
*/
// save the response in the cache
await client.set('characters', JSON.stringify(response.data))
return res.status(200).json(response.data)
} catch (err) {
return res.status(err.response.status).json({ mmessage: err.mmessage })
}
})
app.get('/characters/:id', async (req, res) => {
try {
const cacheCharacter = await client.get('cacheCharacter' + req.params.id)
if (cacheCharacter) {
return res.json(JSON.parse(cacheCharacter))
}
const response = await axios.get('https://rickandmortyapi.com/api/character/' + req.params.id)
await client.set('cacheCharacter' + req.params.id, JSON.stringify(response.data))
return res.json(response.data)
} catch (err) {
return res.status(err.response.status)
.json({ message: err.message })
}
})
app.listen(process.env.PORT || 3000, () => {
console.log(`server on port 3000`)
})
}
runApp()
Заключение
В этом руководстве мы рассмотрели краткое введение в Redis и создали с его помощью простой кеш для приложения Node.js.
Теперь вы можете использовать Redis для кэширования часто запрашиваемых данных в своем приложении для значительного повышения производительности, особенно в проектах, которые обрабатывают много запросов в секунду, где производительность, обеспечиваемая Redis, становится очень важной.
Хотите подключиться? Люблю общаться с друзьями по всему миру в Twitter.
:::информация Также опубликовано здесь.
:::
Оригинал