При розробці веб-додатків часто створюються декілька сторінок, і користувачі часто переходять між ними. Щоб покращити взаємодію з користувачем і зробити навігацію більш зручною та осмисленою, важливо зберігати певну інформацію та відображати її знову після входу користувача.
Ви, можливо, запитаєте: чому не зберігати цю інформацію в базі даних і не витягувати її, коли це необхідно? Хоча такий підхід працює, він має два основні недоліки:
- Структура даних: Інформація, яку потрібно зберігати, може сильно відрізнятися. В одному випадку це можуть бути продукти в кошику, в іншому — налаштування користувача або тимчасові переваги.
- Продуктивність: Запити до бази даних щоразу, коли потрібно отримати цю інформацію, можуть уповільнити роботу додатку та вплинути на загальну продуктивність, особливо при високому навантаженні.
- Збільшення витрат: Часті запити до бази даних, особливо для невеликих тимчасових даних, можуть збільшити використання ресурсів і витрати. Це особливо актуально для хмарних баз даних з оплатою за використання.
- Затримка: Доступ до бази даних, навіть для простих запитів, вводить затримку (latency). Це може уповільнити роботу додатка, особливо якщо користувачі виконують багато дій, що вимагають частих запитів до бази даних.
- Тимчасові дані: Не всі дані повинні зберігатися постійно. Такі речі, як переваги, специфічні для сесії (наприклад, чи віддає користувач перевагу темному режиму на час сесії), краще зберігати в тимчасовому сховищі, а не в постійній базі даних.
- Проблеми з конкурентністю: Якщо кілька користувачів одночасно звертаються до своїх даних і оновлюють їх, операції з базою даних можуть стати складнішими для керування. Тимчасове сховище сесій усуває цю проблему, оскільки воно ізольоване для кожного користувача.
Отже, In-Memory Storage — ось рішення! ... Хмм, не так швидко. У зберігання в пам'яті також є свої виклики:
- Обмеження пам'яті: Уявіть, що у вас є 1000 користувачів з активними сесіями, кожен з яких має 10–100 КБ даних. Це буде приблизно 50 МБ використаної пам'яті, що може призвести до перевантаження пам'яті в міру зростання навантаження.
- Вплив на продуктивність: Керування великою кількістю даних сесій у пам'яті може уповільнити роботу додатку, особливо коли пам'ять стає вузьким місцем.
- Втрати даних: Оскільки пам'ять є волатильним сховищем, будь-який перезапуск або збій додатку призведе до втрати даних сесії. Це суперечить меті зберігання стану, особливо для критичних даних сесії.
- Проблеми з масштабуванням: Під час масштабування додатку (додавання або видалення інстансів) зберігання в пам'яті стає непридатним. Кожен інстанс має свою ізольовану пам'ять, що призводить до втрати даних сесії, якщо не впровадити складну систему дублювання — що може бути як дорогим, так і схильним до помилок.
- Sticky Sessions: Sticky-сесії змушують користувачів завжди взаємодіяти з одним і тим самим інстансом сервера, що обмежує масштабованість і потенційно призводить до перевантаження окремих серверів.
- Проблеми безпеки: Чутливі дані сесії, збережені в пам'яті, можуть стати вразливими до атак, якщо сервер буде скомпрометований, оскільки атаки на пам'ять можуть призвести до витоку цих даних.
Тоді що ж робити, щоб мати чисте, швидке та надійне сховище сесій?
Redis — це відповідь!
Redis — це високопродуктивна NoSQL база даних, яка класифікується як сховище типу ключ/значення. Відомий своєю швидкістю, Redis працює, зберігаючи та обробляючи дані безпосередньо в пам'яті, а не на диску, що забезпечує надшвидку продуктивність. Він підтримує різноманітні типи даних, включаючи рядки, списки, множини, потоки та інші, з наданими командами для кожного типу для забезпечення ефективного зберігання та витягування даних.
Redis може виконувати кілька ролей, включаючи основну базу даних, кешуючий шар, брокер повідомлень або чергу.
Його універсальність робить Redis популярним вибором для реальних додатків у таких сферах, як ігрова індустрія, фінансові технології, охорона здоров’я та IoT. Завдяки надшвидким часам відгуку та репутації простоти і надійності, Redis є улюбленцем серед розробників, які шукають швидкість і масштабованість.
Але зачекайте — сховище в пам’яті? База даних? Хіба ми тільки що не погодились, що рішення в пам’яті мають обмеження?
Так, але Redis поєднує найкраще з обох світів! Це база даних, тому дані зберігаються поза додатком і можуть безперешкодно масштабуватися та підтримувати налаштування з кількома інстансами. При цьому він зберігає та витягує дані з пам’яті, що робить його неймовірно швидким. Redis поєднує ці сильні сторони і створює потужне, ефективне рішення.
Давайте побачимо, як це застосовувати в реальному світі
- Спочатку створимо Blazor Web App. Після того як він буде налаштований, давайте розглянемо вбудований компонент
Counter.razor
.
У цьому компоненті ви помітите, що значення лічильника ініціалізується заново кожного разу, коли сторінка відкривається. Це можна побачити в наступному фрагменті коду:
Наші користувачі не задоволені тим, що лічильник скидається щоразу, коли вони відкривають сторінку. Вони хочуть, щоб він запам’ятовував значення з останнього разу, коли вони його використовували! Давайте виправимо це, інтегрувавши Redis у наш додаток.
Крок 1: Запустіть Redis за допомогою Docker
Припускаючи, що ви вже встановили Docker Desktop, давайте запустимо Redis:
Завантажте Redis-образ:
docker pull redis
Запустіть контейнер Redis:
docker run -d -p 6379:6379 — name redis redis
Перевірте в Docker Desktop, чи працюють контейнери:
Ви повинні побачити, що Redis працює.
Чудово! Redis працює, тепер переходимо до нашого DotNet додатку.
Крок 2: Інтегруйте Redis у .NET додаток
- Встановіть NuGet пакет Redis:
dotnet add package NRedisStack
2. Додайте рядок підключення в appsettings.json
:
"ConnectionStrings": {
"Redis": "localhost:6379"
}
3. Впровадьте Redis у додаток через Dependency Injection (DI):
Додайте наступне в Program.cs
:
builder.Services.AddSingleton(_ =>
{
var configuration = builder.Configuration.GetConnectionString("Redis");
return ConnectionMultiplexer.Connect(configuration);
});
builder.Services.AddSingleton(sp =>
{
var multiplexer = sp.GetRequiredService();
return multiplexer.GetDatabase();
});
Крок 3: Оновіть компонент Counter.razor
- Додайте ці рядки на початку файлу:
@using StackExchange.Redis
@inject IDatabase redis
2. Змініть код, щоб отримати та зберігати значення лічильника в Redis:
@code {
private int currentCount = 0;
protected override async Task OnInitializedAsync()
{
currentCount= (int)(await redis.StringGetAsync("my_counter"));
}
private async Task IncrementCount()
{
currentCount++;
await redis.StringIncrementAsync("my_counter");
}
}
Спробуємо це:
І ми можемо навіть перевірити це в базі даних:
docker exec -it redis sh
redis-cli
get my_counter
Результат:
Чудово!
Наступні кроки: Управління складним сховищем сесій
Тепер, коли ми вирішили проблему з простим лічильником, час перейти до більш складного завдання. У Частині 2 ми розглянемо, як керувати складним сховищем сесій для кожного користувача.
Готуйтеся до вивчення того, як Redis може відкрити нові можливості для вашого додатку. Залишайтеся з нами для Частини 2!
Перекладено з: Dotnet Blazor Session Storage using Redis (part 1)