Redisを.NET 8 Web APIのプライマリデータストアとして活用する方法
はじめに
本記事では、Redisについて解説し、データを保存するプライマリデータベース(主データストア)としてRedisを活用するユースケースをご紹介します。
- Redisの概要
- Redisのデータ型
- Redisをデータベースとして使うメリットとデメリット
- コンテナへのRedisセットアップ
- .NET 8 Web APIでプライマリデータベースとしてRedisを使用する方法
前提条件
- Visual Studio Code
- .NET 8 SDK
- Redis Desktop Manager(https://redis.io/resources/tools/ からダウンロード可能)
- Docker Desktop
- NuGetパッケージ
- Microsoft.Extensions.Caching.StackExchangeRedis
- StackExchange.Redis
Redisとは
Redisはインメモリ型のキーバリューストアであり、主にキャッシュ層として利用されています。データをメモリ上に保持するため、非常に高速な読み書きが可能で、低レイテンシでのデータアクセスに最適です。
ここで「Redisはメモリ上にデータを保存するため、システム再起動時にデータが失われるのでは?」という疑問が生じるかもしれません。
このデータ永続化の課題に対して、Redisはスナップショット(RDB)やAOF(Append Only File)といった仕組みを提供しています。これらの仕組みにより、データをディスクに永続化でき、システム再起動後もデータを復元できます。Redisの永続化について詳しくは、公式ドキュメントをご参照ください。
Redisはキャッシュ層として使われることがほとんどですが、複雑なデータベースシステムへのアクセス回数を減らす目的で、データベースとして利用することもできます。Redisはドキュメント型データベースモデルを採用しており、主にJSON形式でデータをドキュメントとして保存します。
Redisのデータ型
Redisは、キャッシュ、キューイング、イベント処理などの課題を解決できる豊富なデータ型を提供しています。
- Strings(文字列): バイト列を表現する最も基本的な型
- Lists(リスト): 文字列のコレクション
- Sets(セット): 重複のない文字列の順序なしコレクション
- Hashes(ハッシュ): フィールドと値のペアのコレクションとしてモデル化されたレコード型
各データ型の詳細については、公式ドキュメントをご確認ください。
Redisをデータベースとして使うメリット
- 高いパフォーマンス
- 柔軟なデータ構造
- 低レイテンシ
- スケーラビリティ
Redisをデータベースとして使うデメリット
- データ耐久性の課題
- 限定的なクエリ機能
- メモリ容量の制約
DockerコンテナへのRedisセットアップ
Docker Desktopが起動していることを確認し、Visual Studio 2022を開きます。
「新しいプロジェクトの作成」を選択し、「ASP.NET Core Web API」をクリックして「次へ」を押します。
構成ページでプロジェクト名を入力し、「次へ」をクリックします。

追加情報ページでは、スクリーンショットに従って情報を選択し、「作成」をクリックします。

次に、Redisの構成を保持するための「docker-compose.yaml」ファイルを作成し、以下のコードを貼り付けます。
version: '3.8'
services:
redis:
image: redis:alpine
container_name: redisStudentAPI
ports:
- 6379:6379
その後、ツール → コマンドライン → 開発者PowerShellから開発者PowerShellを開きます。
プロジェクトフォルダに移動し、YAMLファイルを実行するコマンド「docker compose up -d」を入力します。
Docker Desktopを開いてコンテナ一覧に移動すると、YAMLファイルから作成されたコンテナを確認できます。また、「docker ps」コマンドでも稼働中のコンテナを確認できます。

Redisサーバーと対話するには、コンテナIDを指定して以下のコマンドを実行します。
docker exec -it <container_id> /bin/sh
以上でDockerの基本セットアップは完了し、コマンドラインからRedisと対話できるようになりました。
続いて、キーと値のペアを文字列として保存するため、String型について詳しく見ていきましょう。
Strings(文字列型)
String型は、キーに関連付けることができる最もシンプルな値の型で、キーと値が1対1でマッピングされます。
SET <key> <value> コマンドで値を設定し、GET <key> で取得できます。
また、DEL <key> コマンドでキーを削除することもできます。
次に、NuGetパッケージマネージャーから必要なパッケージをインストールしてください。

Program.csへの構成の追加
Program.cs
builder.Services.AddSingleton<IConnectionMultiplexer>(options =>
ConnectionMultiplexer.Connect(("127.0.0.1:6379")));
builder.Services.AddScoped<IStudentRepository, StudentRepository>();
Modelsフォルダを作成し、モデル用のファイル「Student.cs」を作成して、以下のコードを貼り付けます。
Student.cs
namespace StudentAPIWithRedisDB.Models
{
public class Student
{
public string Id { get; set; } = $"student:{Guid.NewGuid().ToString()}";
public required string StudentName { get; set; } = string.Empty;
}
}
続いて、リポジトリファイルに以下のコードをコピー&ペーストします。
IStudentRepository.cs
using StudentAPIWithRedisDB.Models;
namespace StudentAPIWithRedisDB.Data
{
public interface IStudentRepository
{
IEnumerable<Student> GetAllStudents();
Student? GetStudentById(string id);
void AddStudent(Student student);
Student? UpdateStudent(Student student);
Student? DeleteStudent(string id);
}
}
StudentRepository.csは、IStudentRepositoryインターフェースとそのすべてのメソッドの実装クラスです。
using StackExchange.Redis;
using StudentAPIWithRedisDB.Models;
using System.Text.Json;
namespace StudentAPIWithRedisDB.Data
{
public class StudentRepository : IStudentRepository
{
private readonly IConnectionMultiplexer _redis;
public StudentRepository(IConnectionMultiplexer redis)
{
_redis = redis;
}
public void AddStudent(Student student)
{
if(student == null)
{
throw new ArgumentOutOfRangeException(nameof(student));
}
var db = _redis.GetDatabase();
var serializedStudent = JsonSerializer.Serialize(student);
db.StringSet(student.Id, serializedStudent);
}
public Student? DeleteStudent(string id)
{
var db = _redis.GetDatabase();
var student = db.StringGet(id);
if (student.IsNullOrEmpty)
{
return null;
}
db.KeyDelete(id);
return JsonSerializer.Deserialize<Student>(student);
}
public IEnumerable<Student> GetAllStudents()
{
var db = _redis.GetDatabase();
var studentKeys = db.Multiplexer.GetServer(_redis.GetEndPoints().First()).Keys(pattern: "student:*");
var students = new List<Student>();
foreach (var key in studentKeys)
{
var studentJson = db.StringGet(key);
if (!studentJson.IsNullOrEmpty)
{
var student = JsonSerializer.Deserialize<Student>(studentJson);
students.Add(student);
}
}
return students;
}
public Student? GetStudentById(string id)
{
var db = _redis.GetDatabase();
var student = db.StringGet(id);
if(student.IsNullOrEmpty)
{
return null;
}
return JsonSerializer.Deserialize<Student>(student);
}
public Student UpdateStudent(Student student)
{
var db = _redis.GetDatabase();
var id = student.Id;
if (db.KeyExists(id))
{
var updatedStudentJson = JsonSerializer.Serialize(student);
db.StringSet(id, updatedStudentJson);
return student;
}
else
{
return null;
}
}
}
}
StudentsController.cs
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using StudentAPIWithRedisDB.Data;
using StudentAPIWithRedisDB.Models;
namespace StudentAPIWithRedisDB.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class StudentsController : ControllerBase
{
private readonly IStudentRepository _studentRepository;
public StudentsController(IStudentRepository studentRepository)
{
_studentRepository = studentRepository;
}
[HttpGet("{Id}", Name = "GetStudentById")]
public ActionResult<Student> GetStudentById(string Id)
{
var student = _studentRepository.GetStudentById(Id);
if(student == null)
{
return NotFound();
}
return Ok(student);
}
[HttpPost]
public ActionResult<Student> AddStudent(Student student)
{
_studentRepository.AddStudent(student);
return CreatedAtRoute(nameof(GetStudentById), new { Id = student.Id }, student);
}
[HttpGet(Name = "GetAllStudents")]
public ActionResult<Student> GetAllStudents()
{
var students = _studentRepository.GetAllStudents();
return Ok(students);
}
[HttpDelete("{id}")]
public ActionResult<Student> DeleteStudent(string id)
{
var student = _studentRepository.DeleteStudent(id);
if(student == null)
{
return NotFound();
}
return Ok(student);
}
[HttpPatch]
public ActionResult<Student> UpdateStudent(Student student)
{
var studentToUpdate = _studentRepository.GetStudentById(student.Id);
if(studentToUpdate == null)
{
return NotFound();
}
_studentRepository.UpdateStudent(student);
return NoContent();
}
}
}
アプリケーションを実行すると、Swaggerを使ってブラウザ上にエンドポイントが表示されているのが確認できます。

また、Redis Desktop Managerを開くとデータを確認できます。初期状態では、データが何もない16個のデータベースが表示されます。
作成用エンドポイントを叩くと、DB0に自動的にレコードが作成されます。
CREATE(作成)
テストを簡単に行えるよう、Postmanを使ってエンドポイントを検証しました。
学生名だけを渡すと、学生名と新しく生成されたGUIDを接尾辞としたIDが自動的に作成されます。
そして、ドキュメントがDB0上に作成されます。
GetStudentById(ID指定取得)
この操作では、ドキュメントからIDをコピーし、それをリクエストURLに渡します。
すると、IDに基づいた値が返却されます。
GetAllStudents(全件取得)
データベース内のすべてのドキュメントが返却されます。
Update(更新)
IDと更新後の値を渡します。そうすることで、IDに基づいてデータが更新されます。
マネージャーを更新すると、更新された値を確認できます。
Delete(削除)
ユーザーを削除するには、IDを渡してください。そうすると、Student DBから該当ドキュメントが削除されます。
そして、ドキュメントがファイルから削除されます。
以前はStudentテーブルに2つのドキュメントがありましたが、最初の1つが削除されました。
以上が、アプリケーションでRedisをデータベースとして使用するシンプルな例でした。ここではキャッシュを介さず、データを直接Redisに保存し、取得・変更を行いました。同様の手法をあなたのアプリケーションにも適用することができます。
-
Upstash KafkaとMongoDBコネクタで実現する低レイテンシセグメンテーションプラットフォームの構築
はじめに セグメンテーションプラットフォームは、顧客や製品といった関連データを理解し、分類するうえで重要な役割を担います。 セグメンテーションとは、一定の基準に基づいて大きなグループを、より均質性の高い小さなサブグループへ分割することです。たとえばECサイトにおける顧客セグメンテーションでは、パーソナライズされたマーケティング施策の立案、ターゲットを絞ったプロモーションの実施、きめ細かなショッピング体験の提供などが可能になります。 目次 要件の把握 基本アーキテクチャ アーキテクチャ構成要素 設計上の課題 提案ソリューション まとめ 1. 要件の把握 EC向けの顧客セグメントを対象とし
-
Redisキーの基本と管理コマンド一覧|DEL・EXPIRE・TTLなどの使い方を解説
Redisにおけるキー(Key)は、データベースに格納された値を識別・保存・取得するための一意な識別子として機能します。キーはredis-cliから各種Redisコマンドを実行することで自由に管理でき、値の追加・削除だけでなく、有効期限の設定や名前の変更なども行えます。 本記事では、Redisのキー操作に使われる代表的なコマンドを一覧形式で解説します。日々の開発や運用でキーを扱う際のリファレンスとしてご活用ください。 基本構文 Redisのキーコマンドは、以下の形式で記述します。 redis host:port> <コマンド名> <キー名> 実行例 Redisキ