본문으로 건너뛰기

เนื้อหาภาษาไทย / 태국어 콘텐츠

시스템 가이드 검수 완료된 콘텐츠

การใช้ Caching Strategies: Cache Invalidation

บทความนี้กล่าวถึงความสำคัญของ Cache Invalidation ใน Caching Strategies เพื่อให้มั่นใจว่าข้อมูลใน Cache เป็นปัจจุบันและถูกต้อง โดยอธิบายกลยุทธ์ต่างๆ เช่น TTL, Ca...

การใช้ Caching Strategies: Cache Invalidation

ในบทที่แล้ว เราได้เรียนรู้เกี่ยวกับการใช้ Queues เพื่อจัดการงานที่ใช้เวลานานใน Background ซึ่งช่วยให้เว็บแอปพลิเคชันของเราตอบสนองต่อผู้ใช้ได้รวดเร็วขึ้น ในบทนี้ เราจะมาเจาะลึกเรื่อง Caching Strategies โดยเฉพาะอย่างยิ่งเรื่อง Cache Invalidation ซึ่งเป็นสิ่งสำคัญเพื่อให้แน่ใจว่าข้อมูลที่เรา Cache นั้นถูกต้องและเป็นปัจจุบันเสมอ

Cache Invalidation คือกระบวนการในการลบหรืออัปเดตข้อมูลที่อยู่ใน Cache เมื่อข้อมูลต้นฉบับมีการเปลี่ยนแปลง หากเราไม่จัดการ Cache Invalidation อย่างถูกต้อง ข้อมูลใน Cache อาจเก่าและไม่ถูกต้อง ซึ่งจะทำให้ผู้ใช้ได้รับข้อมูลที่ไม่ถูกต้องและส่งผลเสียต่อประสบการณ์การใช้งาน

Time-to-Live (TTL)

TTL เป็นหนึ่งในกลยุทธ์ Cache Invalidation ที่ง่ายที่สุดและถูกใช้กันอย่างแพร่หลาย TTL คือระยะเวลาที่ข้อมูลใน Cache จะถือว่ายังคงถูกต้อง หลังจากระยะเวลา TTL หมดลง ข้อมูลนั้นจะถูกลบออกจาก Cache หรือถูกทำเครื่องหมายว่าหมดอายุ และเมื่อมีการร้องขอข้อมูลนั้นอีกครั้ง ระบบจะต้องดึงข้อมูลใหม่จากแหล่งข้อมูลต้นฉบับและ Cache ข้อมูลนั้นอีกครั้ง

ข้อดีของ TTL:

  • ใช้งานง่ายและเข้าใจได้ง่าย
  • เหมาะสำหรับข้อมูลที่มีการเปลี่ยนแปลงไม่บ่อยนัก

ข้อเสียของ TTL:

  • อาจทำให้ข้อมูลใน Cache หมดอายุเร็วกว่าที่ควรจะเป็น ทำให้ระบบต้องดึงข้อมูลใหม่บ่อยครั้ง
  • อาจทำให้ข้อมูลใน Cache เก่ากว่าที่ควรจะเป็น หากข้อมูลต้นฉบับมีการเปลี่ยนแปลงก่อนที่ TTL จะหมดอายุ

ตัวอย่างการใช้ TTL ใน PHP กับ Redis:

<?php

// เชื่อมต่อกับ Redis
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

// กำหนด Key และ Value ที่จะ Cache
$key = 'product:123';
$product = [
    'id' => 123,
    'name' => 'Awesome Product',
    'price' => 99.99,
];

// กำหนด TTL เป็น 3600 วินาที (1 ชั่วโมง)
$ttl = 3600;

// Cache ข้อมูลพร้อม TTL
$redis->set($key, json_encode($product), $ttl);

// ดึงข้อมูลจาก Cache
$cachedProduct = $redis->get($key);

if ($cachedProduct) {
    // ข้อมูลอยู่ใน Cache
    $product = json_decode($cachedProduct, true);
    echo "Product from Cache: " . $product['name'];
} else {
    // ข้อมูลไม่อยู่ใน Cache ต้องดึงจาก Database
    // (สมมติว่ามีการดึงข้อมูลจาก Database)
    $product = [
        'id' => 123,
        'name' => 'Awesome Product',
        'price' => 99.99,
    ];
    echo "Product from Database: " . $product['name'];

    // Cache ข้อมูลพร้อม TTL
    $redis->set($key, json_encode($product), $ttl);
}

$redis->close();

?>

ในตัวอย่างนี้ เราทำการ Cache ข้อมูล Product ด้วย Key `product:123` และกำหนด TTL เป็น 3600 วินาที (1 ชั่วโมง) เมื่อมีการร้องขอข้อมูล Product นี้ครั้งแรก ระบบจะดึงข้อมูลจาก Database และ Cache ข้อมูลนั้นไว้ เมื่อมีการร้องขอข้อมูล Product นี้อีกครั้งภายใน 1 ชั่วโมง ระบบจะดึงข้อมูลจาก Cache แทนการดึงจาก Database

Cache-Aside Pattern

Cache-Aside Pattern เป็นกลยุทธ์ Cache Invalidation ที่นิยมใช้อีกรูปแบบหนึ่ง ในรูปแบบนี้ แอปพลิเคชันจะตรวจสอบ Cache ก่อนเสมอ หากข้อมูลอยู่ใน Cache จะส่งคืนข้อมูลนั้นทันที หากข้อมูลไม่อยู่ใน Cache แอปพลิเคชันจะดึงข้อมูลจากแหล่งข้อมูลต้นฉบับ (เช่น Database) แล้ว Cache ข้อมูลนั้นไว้ก่อนที่จะส่งคืนให้ผู้ใช้

เมื่อข้อมูลต้นฉบับมีการเปลี่ยนแปลง แอปพลิเคชันจะต้องทำการ Invalidate Cache โดยการลบข้อมูลออกจาก Cache หรืออัปเดตข้อมูลใน Cache ให้เป็นปัจจุบัน

ข้อดีของ Cache-Aside Pattern:

  • ช่วยลดภาระของแหล่งข้อมูลต้นฉบับ
  • ช่วยให้มั่นใจว่าข้อมูลใน Cache เป็นปัจจุบัน

ข้อเสียของ Cache-Aside Pattern:

  • มีความซับซ้อนในการ Implement มากกว่า TTL
  • อาจเกิด "Cache Stampede" ได้ หากข้อมูลใน Cache หมดอายุพร้อมกัน

ตัวอย่างการใช้ Cache-Aside Pattern ใน PHP กับ Redis:

<?php

// เชื่อมต่อกับ Redis
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

function getProduct(int $productId): array
{
    $key = 'product:' . $productId;

    // ดึงข้อมูลจาก Cache
    $cachedProduct = $redis->get($key);

    if ($cachedProduct) {
        // ข้อมูลอยู่ใน Cache
        return json_decode($cachedProduct, true);
    } else {
        // ข้อมูลไม่อยู่ใน Cache ต้องดึงจาก Database
        // (สมมติว่ามีการดึงข้อมูลจาก Database)
        $product = getProductFromDatabase($productId); // เรียกฟังก์ชันที่ดึงข้อมูลจาก Database

        // Cache ข้อมูล
        $redis->set($key, json_encode($product));

        return $product;
    }
}

function updateProduct(int $productId, array $productData): void
{
    // อัปเดตข้อมูลใน Database
    updateProductInDatabase($productId, $productData); // เรียกฟังก์ชันที่อัปเดตข้อมูลใน Database

    // Invalidate Cache โดยการลบข้อมูลออกจาก Cache
    $key = 'product:' . $productId;
    $redis->del($key);
}

// ตัวอย่างการใช้งาน
$productId = 123;
$product = getProduct($productId);
echo "Product Name: " . $product['name'] . "<br>";

// อัปเดต Product
$newProductData = ['name' => 'Updated Awesome Product'];
updateProduct($productId, $newProductData);

// ดึง Product อีกครั้ง (จะดึงจาก Database และ Cache ใหม่)
$product = getProduct($productId);
echo "Product Name (After Update): " . $product['name'];

$redis->close();

// ฟังก์ชันจำลองการดึงข้อมูลจาก Database
function getProductFromDatabase(int $productId): array {
    // ในความเป็นจริง จะมีการเชื่อมต่อ Database และดึงข้อมูล
    return [
        'id' => $productId,
        'name' => 'Awesome Product',
        'price' => 99.99,
    ];
}

// ฟังก์ชันจำลองการอัปเดตข้อมูลใน Database
function updateProductInDatabase(int $productId, array $productData): void {
    // ในความเป็นจริง จะมีการเชื่อมต่อ Database และอัปเดตข้อมูล
    echo "Product {$productId} updated in database.<br>";
}

?>

ในตัวอย่างนี้ ฟังก์ชัน `getProduct` จะตรวจสอบ Cache ก่อนเสมอ หากข้อมูลอยู่ใน Cache จะส่งคืนข้อมูลนั้นทันที หากข้อมูลไม่อยู่ใน Cache จะดึงข้อมูลจาก Database และ Cache ข้อมูลนั้นไว้ก่อนที่จะส่งคืนให้ผู้ใช้ ฟังก์ชัน `updateProduct` จะทำการอัปเดตข้อมูลใน Database และ Invalidate Cache โดยการลบข้อมูลออกจาก Cache

Write-Through Cache

Write-Through Cache เป็นกลยุทธ์ Cache Invalidation ที่เมื่อมีการเขียนข้อมูลลงในระบบ ข้อมูลนั้นจะถูกเขียนลงในทั้ง Cache และแหล่งข้อมูลต้นฉบับพร้อมกัน

ข้อดีของ Write-Through Cache:

  • ข้อมูลใน Cache จะเป็นปัจจุบันเสมอ

ข้อเสียของ Write-Through Cache:

  • ประสิทธิภาพในการเขียนข้อมูลอาจลดลง เนื่องจากต้องเขียนข้อมูลลงในทั้ง Cache และแหล่งข้อมูลต้นฉบับ

Write-Through Cache มักถูกใช้ในสถานการณ์ที่ความสอดคล้องของข้อมูลมีความสำคัญอย่างยิ่ง และความเร็วในการเขียนข้อมูลไม่ใช่ข้อจำกัดหลัก

เหตุผลเชิงออกแบบ Trade-offs และแนวปฏิบัติที่ดี:

  • TTL: เลือก TTL ที่เหมาะสมกับความถี่ในการเปลี่ยนแปลงข้อมูล หากข้อมูลมีการเปลี่ยนแปลงบ่อย ควรใช้ TTL ที่สั้นลง
  • Cache-Aside: ใช้เมื่อต้องการลดภาระของ Database และมั่นใจว่าข้อมูลใน Cache เป็นปัจจุบัน ใช้ร่วมกับ TTL เพื่อป้องกัน Cache Stampede
  • Write-Through: ใช้เมื่อความสอดคล้องของข้อมูลเป็นสิ่งสำคัญที่สุด แม้ว่าประสิทธิภาพในการเขียนอาจลดลง
  • Event-Driven Invalidation: เมื่อข้อมูลเปลี่ยนแปลง ให้ใช้ Event Bus หรือ Message Queue เพื่อแจ้งให้ Service อื่นๆ ที่ใช้ Cache นั้นทราบและทำการ Invalidate Cache
  • Cache Versioning: เมื่อโครงสร้างข้อมูลเปลี่ยนแปลง ให้ใช้ Cache Versioning เพื่อหลีกเลี่ยงปัญหาความเข้ากันไม่ได้

การเลือกใช้ Caching Strategies ที่เหมาะสมขึ้นอยู่กับความต้องการของแต่ละโปรเจกต์ การทำความเข้าใจข้อดีข้อเสียของแต่ละกลยุทธ์จะช่วยให้เราสามารถออกแบบระบบ Cache ที่มีประสิทธิภาพและเชื่อถือได้

ในบทถัดไป เราจะพูดถึง Load Balancing เพื่อกระจาย Traffic และทำให้เว็บแอปพลิเคชันของเราสามารถรองรับผู้ใช้งานจำนวนมากได้

Office.in.th Custom Service

이 구조를 바탕으로 시스템을 개발하거나 맞춤 변경하고 싶으신가요?

Office.in.th는 엔터프라이즈 웹 애플리케이션, API 연동, 공공/민간 업무 관리 시스템을 설계·개발하며 장기 지원을 제공합니다.

소프트웨어 개발 서비스 보기