Workshop สำหรับเรียนรู้การเชื่อมต่อ Laravel กับ Redis Server โดยใช้ Docker Compose และทดลองใช้งาน Redis ในงาน Backend จริง

#1. Redis คืออะไร

Redis เป็น in-memory data store ที่จัดเก็บข้อมูลในหน่วยความจำ จึงเหมาะกับข้อมูลที่ต้องอ่าน/เขียนรวดเร็ว เช่น Cache, Session, Queue, Counter และ Rate Limiting

เมื่อใช้ร่วมกับ Laravel เราสามารถให้ฐานข้อมูลหลัก เช่น MySQL/PostgreSQL เก็บข้อมูลถาวร และให้ Redis รับผิดชอบข้อมูลที่ต้องเข้าถึงบ่อยหรือข้อมูลชั่วคราว

#2. Architecture

                         ┌─────────────────┐
                         │     Client      │
                         └────────┬────────┘
                                  │ HTTP
                                  ▼
                         ┌─────────────────┐
                         │     Laravel     │
                         │   Application   │
                         └───┬─────────┬───┘
                             │         │
                ┌────────────┘         └─────────────┐
                ▼                                    ▼
       ┌─────────────────┐                  ┌─────────────────┐
       │  Redis Server   │                  │ MySQL/PostgreSQL│
       ├─────────────────┤                  │ Persistent Data │
       │ Cache           │                  └─────────────────┘
       │ Session         │
       │ Queue           │
       │ Rate Limiting   │
       └─────────────────┘

#3. สิ่งที่ต้องมี

  • Docker และ Docker Compose
  • Laravel project
  • Composer
  • PHP Redis client: PhpRedis หรือ Predis

Laravel แนะนำ PhpRedis สำหรับงานที่ใช้ Redis หนัก แต่สามารถใช้ predis/predis ซึ่งเป็น PHP package ได้เช่นกัน

#4. สร้าง Laravel Project

composer create-project laravel/laravel laravel-redis
cd laravel-redis

หาก environment ยังไม่มี PhpRedis สามารถใช้ Predis ได้:

composer require predis/predis

จากนั้นกำหนด:

REDIS_CLIENT=predis

หาก container ของ PHP มี PhpRedis อยู่แล้ว:

REDIS_CLIENT=phpredis

#5. สร้าง Redis ด้วย Docker Compose

สร้าง compose.yaml

services:
  redis:
    image: redis:8-alpine
    container_name: laravel-redis
    restart: unless-stopped
    command: redis-server --appendonly yes
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data

volumes:
  redis_data:

เริ่ม Redis:

docker compose up -d
docker compose ps

ทดสอบ:

docker compose exec redis redis-cli ping

ผลลัพธ์:

PONG

การ map 6379:6379 เหมาะกับ workshop/local development หาก Laravel อยู่ใน Docker network เดียวกัน ไม่จำเป็นต้อง publish Redis port ออกสู่ host ใน production

#6. ตั้งค่า Laravel

กรณี Laravel ทำงานบนเครื่อง host:

REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=null

กรณี Laravel เป็น container และอยู่ใน Compose network เดียวกับ Redis:

REDIS_HOST=redis
REDIS_PORT=6379
REDIS_PASSWORD=null

หลังแก้ .env:

php artisan config:clear

#7. Workshop 1: Redis Command โดยตรง

เพิ่ม route ใน routes/web.php

use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Route;

Route::get('/redis-test', function () {
    Redis::set('course', 'Laravel with Redis');

    return [
        'status' => 'success',
        'value' => Redis::get('course'),
    ];
});

เปิด:

http://localhost:8000/redis-test

ตรวจข้อมูล:

docker compose exec redis redis-cli

แล้ว:

GET course

#8. Workshop 2: Redis Cache

กำหนด .env:

CACHE_STORE=redis

ตัวอย่าง:

use Illuminate\Support\Facades\Cache;

Route::get('/cache-test', function () {
    Cache::put('framework', 'Laravel', 600);

    return Cache::get('framework');
});

ตัวอย่างที่เหมาะกับระบบจริงกว่า คือ remember():

use App\Models\Product;
use Illuminate\Support\Facades\Cache;

Route::get('/products', function () {
    return Cache::remember('products.all', 300, function () {
        return Product::all();
    });
});

Flow:

Request
   │
   ▼
Redis Cache ── HIT ──► Response
   │
  MISS
   ▼
Database
   │
   ▼
Store in Redis
   │
   ▼
Response

เมื่อต้อง invalidate:

Cache::forget('products.all');

#9. Workshop 3: Session บน Redis

กำหนด:

SESSION_DRIVER=redis

จากนั้น:

php artisan config:clear

สร้าง route:

Route::get('/session-test', function () {
    $count = session()->get('visit_count', 0) + 1;
    session()->put('visit_count', $count);

    return [
        'visit_count' => $count,
    ];
});

Refresh browser หลายครั้ง ค่า visit_count จะเพิ่มขึ้น

ข้อดีของ Redis Session ชัดเจนเมื่อมี Laravel หลาย instance หลัง Load Balancer เพราะทุก instance สามารถใช้ session store ร่วมกันได้

#10. Workshop 4: Queue ด้วย Redis

กำหนด:

QUEUE_CONNECTION=redis

สร้าง Job:

php artisan make:job ProcessReport

ตัวอย่าง handle():

public function handle(): void
{
    logger()->info('Processing report with Redis Queue');
}

ส่งงานเข้า Queue:

ProcessReport::dispatch();

รัน Worker:

php artisan queue:work redis

Architecture:

HTTP Request
     │
     ▼
  Laravel
     │ dispatch()
     ▼
Redis Queue
     │
     ▼
Queue Worker
     │
     ▼
Background Job

แนวทางนี้เหมาะกับ email, report generation, image processing, import/export และงานที่ไม่ควร block HTTP request

#11. Workshop 5: Rate Limiting

Laravel สามารถใช้ cache backend ที่รวดเร็วเพื่อจัดการ counter สำหรับ rate limit

ตัวอย่าง route middleware:

Route::middleware('throttle:60,1')->get('/api/demo', function () {
    return response()->json([
        'message' => 'API OK',
    ]);
});

แนวคิด:

Client Request
      │
      ▼
Rate Limiter
      │
      ├── within limit ──► Controller
      │
      └── over limit ────► HTTP 429

#12. ตรวจสอบข้อมูล Redis

เข้า Redis CLI:

docker compose exec redis redis-cli

คำสั่งที่มีประโยชน์:

PING
DBSIZE
SCAN 0
TYPE some-key
TTL some-key
GET some-key
INFO memory
INFO stats

หลีกเลี่ยง KEYS * บน production ที่มี key จำนวนมาก เพราะอาจ block server; ใช้ SCAN สำหรับการไล่ดู key

#13. Persistence

ตัวอย่าง Workshop เปิด AOF:

command: redis-server --appendonly yes

และ mount:

volumes:
  - redis_data:/data

ดังนั้นการ restart container ไม่ได้หมายความว่าข้อมูลต้องหายทั้งหมด อย่างไรก็ตาม ควรออกแบบ persistence, backup และ recovery ให้เหมาะกับประเภทข้อมูลจริง

#14. Cache Invalidation

จุดสำคัญของ Cache ไม่ใช่แค่การเขียนข้อมูลลง Redis แต่คือการกำหนดว่า cache จะหมดอายุหรือถูกลบเมื่อใด

Cache::remember('product:10', 300, function () {
    return Product::findOrFail(10);
});

เมื่อแก้ไข Product:

$product->update($data);
Cache::forget("product:{$product->id}");

#15. Production Checklist

  • ไม่ควรเปิด Redis port 6379 สู่ public Internet โดยไม่จำเป็น
  • ใช้ private network / firewall
  • กำหนด authentication/ACL ตาม deployment model
  • ใช้ TLS เมื่อ Redis service/environment รองรับและ threat model ต้องการ
  • ตั้ง maxmemory และ eviction policy ให้เหมาะกับ workload
  • แยก key namespace ของแต่ละ application/environment
  • Monitor memory, hit ratio, latency และ evictions
  • วางแผน persistence และ backup หากข้อมูล Redis มีความสำคัญ
  • ใช้ Queue supervisor หรือ Laravel Horizon สำหรับระบบ Queue ที่จริงจัง
  • พิจารณา Sentinel/Cluster/managed Redis เมื่อระบบต้องการ high availability

#16. Redis เหมาะกับอะไร

Use case เหตุผล


Cache ลด query และ latency Session แชร์ session ระหว่าง application instances Queue ส่งงาน background ได้รวดเร็ว Rate Limit counter ที่เพิ่ม/หมดอายุได้รวดเร็ว Counter เหมาะกับ view/request counters Temporary Data รองรับ TTL Pub/Sub ส่ง message แบบ real-time ระหว่าง components

#17. Redis ไม่ใช่ตัวแทน Database ทุกกรณี

Redis ไม่ควรถูกนำมาแทน relational database โดยอัตโนมัติ ควรเลือก data store ตาม workload

MySQL/PostgreSQL
      │
      └── Source of Truth / Persistent Business Data

Redis
      │
      ├── Cache
      ├── Session
      ├── Queue
      └── Ephemeral / Fast-access Data

#18. แบบฝึกหัด

  1. Cache รายการ Product เป็นเวลา 5 นาที
  2. ลบ cache อัตโนมัติหลัง update Product
  3. เปลี่ยน Session Driver เป็น Redis
  4. สร้าง Queue Job สำหรับส่งอีเมลจำลอง
  5. จำกัด API ไม่เกิน 60 requests/minute
  6. ใช้ redis-cli ตรวจสอบ TTL และชนิดของ key
  7. Restart Redis container แล้วตรวจสอบผลของ AOF persistence

#สรุป

Laravel + Redis เป็นสถาปัตยกรรมที่เหมาะกับ Web/API ที่ต้องการลด latency และแยกงาน background ออกจาก request หลัก โดยเริ่มจาก Cache และ Session ได้ง่าย ก่อนต่อยอดไป Queue, Horizon, Rate Limiting, Pub/Sub และ Redis HA

หัวใจสำคัญคือไม่มอง Redis เพียงเป็น "ฐานข้อมูลที่เร็ว" แต่ควรกำหนดบทบาทให้ชัดว่า Redis กำลังทำหน้าที่ Cache, Session Store, Queue หรือ data structure server และออกแบบ TTL, persistence, security และ failure handling ให้สอดคล้องกับบทบาทนั้น

#อ้างอิง