Создание масштабируемого сокращателя URL-адресов с помощью Redis
В этом руководстве мы создадим масштабируемый сервис сокращения URL-адресов с помощью Node.js и Redis. Этот сервис будет использовать распределенное кэширование для эффективной обработки большого трафика, сокращения задержек и плавного масштабирования. Мы рассмотрим ключевые концепции, такие как согласованное хэширование, стратегии аннулирования кэша и сегментирование, чтобы гарантировать, что система остается быстрой и надежной.
К концу этого руководства у вас будет полнофункциональный сервис для сокращения URL-адресов, использующий распределенное кэширование для оптимизации производительности. Мы также создадим интерактивную демонстрацию, в которой пользователи смогут вводить URL-адреса и видеть показатели в реальном времени, такие как количество попаданий в кэш и пропущенных запросов.
Перед началом работы убедитесь, что у вас установлено следующее:
- Node.js (версия 14 или выше)
- Redis
- Docker
Обзор проекта
Мы создадим сервис для сокращения URL-адресов, в котором:
- Пользователи могут сокращать длинные URL-адреса и извлекать исходные URL-адреса. Служба использует кэширование Redis для сохранения сопоставлений между сокращенными URL-адресами и исходными URL-адресами. Кэш распределяется по нескольким экземплярам Redis для обработки большого трафика. Система будет демонстрировать попадания в кэш и промахи в режиме реального времени.
Системная архитектура
Чтобы обеспечить масштабируемость и производительность, мы разделим наш сервис на следующие компоненты:
- Сервер API: Обрабатывает запросы на сокращение и получение URL-адресов. Уровень кэширования Redis: Использует несколько экземпляров Redis для распределенного кэширования. Docker: Имитирует распределенную среду с несколькими контейнерами Redis.
Шаг 1: Настройка проекта
Давайте создадим наш проект, инициализация приложения Node.js :
mkdir scalable-url-shortener
cd scalable-url-shortener
npm init -y
Теперь установите необходимые зависимости:
npm install express redis shortid dotenv
- express - это облегченная платформа для веб-сервера. redis - Для обработки кэширования. shortid - Для создания коротких уникальных идентификаторов. dotenv - Для управления переменными среды.
Создайте env-файл в корневом каталоге вашего проекта:
PORT=3000
REDIS_HOST_1=localhost
REDIS_PORT_1=6379
REDIS_HOST_2=localhost
REDIS_PORT_2=6380
REDIS_HOST_3=localhost
REDIS_PORT_3=6381
Эти переменные определяют хосты и порты Redis, которые мы будем использовать.
Шаг 2: Настройка экземпляров Redis
Мы будем использовать Docker для моделирования распределенной среды с несколькими экземплярами Redis.
Выполните следующие команды, чтобы запустить три контейнера Redis:
docker run -p 6379:6379 --name redis1 -d redis
docker run -p 6380:6379 --name redis2 -d redis
docker run -p 6381:6379 --name redis3 -d redis
Это позволит настроить три экземпляра Redis, работающих на разных портах. Мы будем использовать эти экземпляры для реализации согласованного хэширования и сегментирования.
Шаг 3: Внедрение службы сокращения URL-адресов
Давайте создадим наш основной файл приложения, index.js:
require('dotenv').config();
const express = require('express');
const redis = require('redis');
const shortid = require('shortid');
const app = express();
app.use(express.json());
const redisClients = [
redis.createClient({ host: process.env.REDIS_HOST_1, port: process.env.REDIS_PORT_1 }),
redis.createClient({ host: process.env.REDIS_HOST_2, port: process.env.REDIS_PORT_2 }),
redis.createClient({ host: process.env.REDIS_HOST_3, port: process.env.REDIS_PORT_3 })
];
// Hash function to distribute keys among Redis clients
function getRedisClient(key) {
const hash = key.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0);
return redisClients[hash % redisClients.length];
}
// Endpoint to shorten a URL
app.post('/shorten', async (req, res) => {
const { url } = req.body;
if (!url) return res.status(400).send('URL is required');
const shortId = shortid.generate();
const redisClient = getRedisClient(shortId);
await redisClient.set(shortId, url);
res.json({ shortUrl: `http://localhost:${process.env.PORT}/${shortId}` });
});
// Endpoint to retrieve the original URL
app.get('/:shortId', async (req, res) => {
const { shortId } = req.params;
const redisClient = getRedisClient(shortId);
redisClient.get(shortId, (err, url) => {
if (err || !url) {
return res.status(404).send('URL not found');
}
res.redirect(url);
});
});
app.listen(process.env.PORT, () => {
console.log(`Server running on port ${process.env.PORT}`);
});
Как вы можете видеть в этом коде, у нас есть:
- Последовательное хэширование: Мы распределяем ключи (сокращенные URL-адреса) между несколькими клиентами Redis с помощью простой хэш-функции. Хэш-функция обеспечивает равномерное распределение URL-адресов по экземплярам Redis. Сокращение URL-адресов: Конечная точка /shorten принимает длинный URL и генерирует короткий идентификатор, используя библиотеку shortid. Сокращенный URL сохраняется в одном из экземпляров Redis с помощью нашей хэш-функции. Перенаправление URL: Конечная точка /:shortId извлекает исходный URL-адрес из кэша и перенаправляет пользователя. Если URL-адрес не найден в кэше, возвращается ответ 404.
Шаг 4: Реализация аннулирования кэша
В реальном приложении срок действия URL-адресов может истечь или они могут изменяться с течением времени. Чтобы справиться с этим, нам нужно реализовать аннулирование кэша.
Добавление срока действия к кэшированным URL-адресам
Давайте изменим наш файл index.js, чтобы установить время истечения срока действия для каждой кэшированной записи:
// Endpoint to shorten a URL with expiration
app.post('/shorten', async (req, res) => {
const { url, ttl } = req.body; // ttl (time-to-live) is optionalif (!url) return res.status(400).send('URL is required');
const shortId = shortid.generate();
const redisClient = getRedisClient(shortId);
await redisClient.set(shortId, url, 'EX', ttl || 3600); // Default TTL of 1 hour
res.json({ shortUrl: `http://localhost:${process.env.PORT}/${shortId}` });
});
- Срок действия (Time-To-Live): По умолчанию мы устанавливаем срок действия в 1 час для каждого сокращенного URL-адреса. При необходимости вы можете настроить срок действия для каждого URL-адреса. Аннулирование кэша: По истечении срока действия запись автоматически удаляется из кэша.
Шаг 5: Мониторинг показателей кэша
Чтобы отслеживать попадания и промахи в кэш, мы добавим некоторые протоколы в наши конечные точки в index.js:
app.get('/:shortId', async (req, res) => {
const { shortId } = req.params;
const redisClient = getRedisClient(shortId);
redisClient.get(shortId, (err, url) => {
if (err || !url) {
console.log(`Cache miss for key: ${shortId}`);
return res.status(404).send('URL not found');
}
console.log(`Cache hit for key: ${shortId}`);
res.redirect(url);
});
});
Вот что происходит в этом коде:
- Попадание в кэш: Если URL-адрес найден в кэше, это означает попадание в кэш. Пропуски в кэше: Если URL-адрес не найден, это означает, что он не найден в кэше. Это ведение журнала поможет вам отслеживать производительность вашего распределенного кэша.
Шаг 6: Тестирование приложения
- Запустите свои экземпляры Redis:
docker start redis1 redis2 redis3
- Запустите Node.js сервер:
node index.js
- Протестируйте конечные точки с помощью curl или Postman: Сократить URL-адрес: СООБЩЕНИЕ http://localhost:3000/shorten Тело: { "url": "https://example.com " } Получите доступ к сокращенному URL-адресу: ПОЛУЧИТЬ http://localhost:3000 /{Короткий идентификатор}
Заключение: Чему вы научились
Поздравляю! Вы успешно создали масштабируемый сервис сокращения URL-адресов с распределенным кэшированием, используя Node.js и Redis. В этом руководстве вы узнали, как:
- Реализуйте согласованное хэширование для распределения записей кэша по нескольким экземплярам Redis. Оптимизируйте свое приложение с помощью стратегий аннулирования кэша, чтобы поддерживать актуальность данных. Используйте Docker для моделирования распределенной среды с несколькими узлами Redis. Отслеживайте попадания и промахи в кэш для оптимизации производительности.
следующие шаги:
- Добавьте базу данных: Сохраняйте URL-адреса в базе данных для сохранения за пределами кэша.
- Внедрите аналитику: Отслеживайте количество кликов и анализируйте сокращенные URL-адреса.
- Развертывание в облаке: Разверните свое приложение с помощью Kubernetes для автоматического масштабирования и повышения устойчивости.
Счастливого кодирования!