บทนำ
ในบทความนี้ ผมจะพูดถึง Redis และกรณีการใช้งานในฐานะ Primary Database เพื่อเก็บข้อมูลของเรา
- บทนำ Redis
- ชนิดข้อมูล Redis (Redis Datatypes)
- ข้อดีและข้อเสียของการใช้ Redis เป็น Database
- การตั้งค่า Redis ใน Container
- การใช้ Redis เป็น Primary Database กับ .NET 8 Web API
ข้อกำหนดเบื้องต้น
- Visual Studio Code
- .NET 8 SDK
- Redis Desktop Manager (ดาวน์โหลดได้จาก https://redis.io/resources/tools/)
- Docker Desktop
- Packages:
- Microsoft.Extensions.Caching.StackExchangeRedis
- StackExchange.Redis
บทนำ Redis
Redis เป็น datastore แบบ in-memory และ key-value datastore ใช้ส่วนใหญ่สำหรับ caching layer เนื่องจาก Redis เก็บข้อมูลในหน่วยความจำ (memory) จึงทำให้การอ่านและเขียนข้อมูลเร็วมาก เหมาะสำหรับการเข้าถึงข้อมูลที่ต้องการ low-latency คุณอาจจะถามว่า Redis เก็บข้อมูลใน memory แต่เมื่อระบบรีบูต เราจะสูญเสียข้อมูลหรือไม่
เพื่อแก้ปัญหาการ persistence ของข้อมูล Redis มีกลไกต่างๆ เช่น snapshots (RDB) และ append-only files (AOF) กลไกเหล่านี้ช่วยให้คุณเก็บข้อมูลบนดิสก์อย่างถาวร ทำให้สามารถกู้คืนข้อมูลได้แม้หลังจากระบบรีบูต คุณสามารถเรียนรู้เพิ่มเติมเกี่ยวกับ Redis Persistence ได้จากเอกสารอย่างเป็นทางการ
Redis ใช้โมเดล Document database โดยเก็บข้อมูลในรูปแบบเอกสารส่วนใหญ่เป็น JSON format คุณสามารถอ่านเพิ่มเติมได้จากเอกสารอย่างเป็นทางการ
ชนิดข้อมูล Redis (Redis Datatypes)
Redis มีชนิดข้อมูลหลายแบบที่ช่วยให้เราแก้ปัญหาต่างๆ ได้ ตั้งแต่ caching, queuing, และ event processing
- Strings: แทนลำดับของไบต์ (bytes)
- Lists: รายการของ strings
- Sets: ชุดเก็บข้อมูล string แบบไม่มีลำดับและไม่ซ้ำกัน
- Hashes: ประเภท record ที่สร้างแบบ field-value pairs
คุณสามารถเรียนรู้เพิ่มเติมเกี่ยวกับชนิดข้อมูลได้จากเอกสารอย่างเป็นทางการ
ข้อดีของการใช้ Redis เป็น Database
- High Performance (ประสิทธิภาพสูง)
- Versatile DataStructure (โครงสร้างข้อมูลหลากหลาย)
- Low Latency (ความหน่วงต่ำ)
- Scalability (การขยายตัวได้)
ข้อเสียของการใช้ Redis เป็น Database
- Data Durability (ความทนทานของข้อมูล - ต้องตั้งค่า persistence ให้ถูกต้อง)
- Limited Query Capabilities (ความสามารถในการ query จำกัด - ไม่มี SQL หรือ complex queries)
- Memory Constraints (ข้อจำกัดหน่วยความจำ - ขึ้นกับ RAM ที่มีอยู่)
การตั้งค่า Redis ใน Container
ตรวจสอบว่า Docker Desktop กำลังทำงานอยู่ และเปิด Visual Studio 2022
เลือก "Create a New Project" → คลิก "ASP.NET Core Web API" แล้วคลิก "Next"

ในหน้า Configure ใส่ชื่อโปรเจกต์ แล้วกด "Next"

ในหน้า Additional information เลือกข้อมูลตามภาพ และกด "Create"
สร้างไฟล์ "docker-compose.yaml" เพื่อเก็บการกำหนดค่าสำหรับ Redis และวางโค้ดด้านล่าง
version: '3.8'
services:
redis:
image: redis:alpine
container_name: redisStudentAPI
ports:
- 6379:6379
หลังจากนั้น เปิด Developer Powershell prompt จาก Tools → Command line → Developer Powershell
นำทางไปในโฟลเดอร์โปรเจกต์ และรันคำสั่งเพื่อรันไฟล์ YAML: docker compose up -d

เปิด Docker Desktop ไปที่ containers คุณจะเห็น container ที่สร้างจาก YAML file สามารถรัน docker ps เพื่อดู containers ที่กำลังทำงานได้
เพื่อโต้ตอบกับ Redis Server ให้รันคำสั่งด้านล่างพร้อม container ID
docker exec -it <container_id> /bin/sh
การตั้งค่า Docker พื้นฐานเสร็จสิ้น เราสามารถโต้ตอบกับ Redis ผ่าน command line ได้แล้ว
ตอนนี้ เราจะดูเพิ่มเติมเกี่ยวกับชนิดข้อมูล Strings เนื่องจากเราจะเก็บ key-value pairs เป็น strings
Strings
เป็นชนิดค่าที่ง่ายที่สุดที่เชื่อมโยงกับ key และเป็นการแมป one-to-one ระหว่าง key และ value
เราสามารถตั้งค่าได้โดยใช้ SET <key> <value> และดึงค่าได้โดย GET <key>
สามารถลบ key ได้โดยใช้ DEL <key>
ตอนนี้ ติดตั้งแพ็กเกจที่จำเป็นจาก NuGet Package Manager

เพิ่มการกำหนดค่าในไฟล์ Program.cs
Program.cs
builder.Services.AddSingleton<IConnectionMultiplexer>(options =>
ConnectionMultiplexer.Connect(("127.0.0.1:6379")));
builder.Services.AddScoped<IStudentRepository, StudentRepository>();
สร้างโฟลเดอร์ Models และสร้างไฟล์ Model 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 - การนำ interface ไปใช้งาน
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();
}
}
}
ตอนนี้ รันแอปพลิเคชัน คุณจะเห็น endpoints บนเบราว์เซอร์ผ่าน Swagger

เปิด Redis Desktop Manager เพื่อดูข้อมูล เริ่มต้นจะมี 16 databases โดยไม่มีข้อมูล
เมื่อเรียก endpoint create จะสร้าง record ใน DB0 อัตโนมัติ
CREATE
เพื่อการทดสอบง่ายๆ ผมใช้ Postman ทดสอบ endpoints
ส่งแค่ชื่อ (name) ระบบจะสร้าง ID อัตโนมัติพร้อมชื่อนักเรียนและ suffix เป็น GUID ใหม่
เอกสารถูกสร้างใน DB0
GetStudentById
สำหรับนี้ ต้องคัดลอก ID จากเอกสาร แล้วส่งใน request URL
จะคืนค่าตาม ID
GetAllStudents
คืนค่าเอกสารทั้งหมดที่มีใน Database
Update
ต้องส่ง ID และค่าที่อัปเดต เพื่ออัปเดตตาม ID
รีเฟรช manager แล้วจะเห็นค่าที่อัปเดตแล้ว
Delete
สำหรับการลบผู้ใช้ ส่ง ID แล้วจะลบเอกสารออกจาก Student DB
เอกสารถูกลบจากไฟล์
ก่อนหน้านี้ มี 2 เอกสารในตาราง Students ตอนนี้ตัวแรกถูกลบแล้ว
นี่คือวิธีง่ายๆ ในการแสดงการใช้ Redis เป็น Database ในแอปพลิเคชันของเรา ที่นี่ เราลด Cache ลงและเก็บข้อมูลโดยตรงใน Redis และดึงข้อมูลแก้ไขได้เช่นกัน คุณสามารถนำไปประยุกต์ใช้กับแอปพลิเคชันของคุณได้เช่นกัน