กลยุทธ์การแคช: การโหลดแบบขี้เกียจและการเขียนผ่าน
ใช้การโหลดแบบขี้เกียจเพื่อเติมแคชเมื่อไม่พบข้อมูล และใช้การเขียนผ่านเพื่อให้แคชสอดคล้องกับทุกการเขียนลงฐานข้อมูล
กลยุทธ์การแคช: การโหลดแบบขี้เกียจและการเขียนผ่าน เป็นบทเรียน Cloud & IT Cert Prep ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Cloud & IT Cert Prep และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Cloud & IT Cert Prep มีบทเรียนทั้งหมด 4 บทเรียน
เหตุใดกลยุทธ์การแคชจึงสำคัญ
การแทรกแคชไว้ระหว่างแอปพลิเคชันกับฐานข้อมูลจำเป็นต้องมีกลยุทธ์การแคช ซึ่งเป็นชุดกฎที่กำหนดว่าจะนำข้อมูลเข้าแคชเมื่อใด จะอ่านข้อมูลจากแคชเมื่อใด และจะนำข้อมูลออกจากแคชเมื่อใด การเลือกกลยุทธ์ที่ไม่เหมาะสมอาจทำให้เกิดข้อมูลล้าสมัย (แคชส่งคืนค่าที่ไม่เป็นปัจจุบัน) แคชพลาดขณะว่างเปล่า (แคชไม่มีข้อมูลและทุกคำขอต้องเข้าถึงฐานข้อมูล) หรือการถล่มของแคช (คำขอพร้อมกันจำนวนมากสำหรับคีย์เดียวกันที่ไม่มีข้อมูล ต่างก็เข้าถึงฐานข้อมูลพร้อมกัน) กลยุทธ์พื้นฐานมีสองแบบ ได้แก่ การโหลดแบบขี้เกียจและการเขียนผ่าน
การโหลดแบบขี้เกียจ (แคชแบบแยกส่วน): วิธีการทำงาน
การโหลดแบบขี้เกียจ (เรียกอีกอย่างว่าแคชแบบแยกส่วน) เป็นรูปแบบการแคชที่ใช้กันมากที่สุด แอปพลิเคชันจะตรวจสอบแคชก่อน หากพบข้อมูลในแคช ข้อมูลจะถูกส่งคืนโดยตรงจากแคช ซึ่งเป็นเส้นทางที่รวดเร็ว หากไม่พบข้อมูลในแคช แอปพลิเคชันจะดึงข้อมูลจากฐานข้อมูล เขียนผลลัพธ์ลงในแคชพร้อมกำหนด TTL แล้วส่งคืนข้อมูลให้ผู้เรียก แคชจะเก็บเฉพาะข้อมูลที่มีการร้องขอจริงเท่านั้น จึงเรียกว่า “ขี้เกียจ” คำขอถัดไปสำหรับคีย์เดียวกันจะพบข้อมูลนั้นในแคช
# Lazy loading pattern (Python with redis-py)
def get_user(user_id, redis_client, db):
cache_key = f'user:{user_id}'
# 1. Check cache
cached = redis_client.get(cache_key)
if cached:
return json.loads(cached) # Cache HIT
# 2. Cache MISS: fetch from DB
user = db.query('SELECT * FROM users WHERE id = %s', user_id)
# 3. Populate cache with TTL of 300 seconds
redis_client.setex(cache_key, 300, json.dumps(user))
return userการโหลดแบบขี้เกียจ: ข้อดี
การโหลดแบบขี้เกียจมีข้อดีสำคัญสามประการ ได้แก่ แคชเฉพาะข้อมูลที่มีการร้องขอ — แคชจะไม่เต็มไปด้วยข้อมูลที่ไม่มีใครอ่าน จึงใช้หน่วยความจำได้อย่างมีประสิทธิภาพ แคชว่างเปล่าไม่ทำให้แอปพลิเคชันหยุดทำงาน — เมื่อไม่พบข้อมูลในแคช แอปพลิเคชันจะถอยกลับไปใช้ฐานข้อมูล ดังนั้นแม้ ElastiCache จะเริ่มต้นใหม่หรือโหนดล้มเหลว แอปพลิเคชันก็ยังทำงานต่อได้ แต่มีความหน่วงสูงขึ้น แคชจะมีความสอดคล้องในท้ายที่สุดกับฐานข้อมูลเสมอ เพราะข้อมูลเก่าจะหมดอายุผ่าน TTL แม้จะพลาดการอัปเดตก็ตาม
การโหลดแบบขี้เกียจ: ข้อเสีย
การโหลดแบบขี้เกียจมีข้อเสียสำคัญสามประการ ได้แก่ การไม่พบข้อมูลในแคชมีต้นทุนสูง — ต้องดำเนินการสามอย่าง (ตรวจสอบแคช อ่านฐานข้อมูล และเขียนแคช) เทียบกับการพบข้อมูลที่ใช้เพียงอย่างเดียว ทำให้คำขอขณะแคชว่างมีความหน่วงสูงขึ้น ข้อมูลล้าสมัย — หลังจากฐานข้อมูลได้รับการอัปเดต แคชยังคงส่งคืนค่าเดิมจนกว่า TTL จะหมดอายุหรือคีย์จะถูกทำให้ใช้ไม่ได้อย่างชัดเจน (ช่วงเวลาที่แคชไม่สอดคล้องกัน) การถล่มของแคช — หากคีย์ยอดนิยมหมดอายุ คำขอพร้อมกันจำนวนมากจะไม่พบข้อมูลในแคชและเข้าถึงฐานข้อมูลพร้อมกัน ซึ่งอาจทำให้ฐานข้อมูลรับภาระมากเกินไป
# Mitigating cache stampede with a probabilistic early expiration
# (Refresh the key before it expires to avoid simultaneous misses)
def get_with_stampede_protection(key, redis_client, db_fetch_fn, ttl=300):
value = redis_client.get(key)
ttl_remaining = redis_client.ttl(key)
# Probabilistically refresh before expiry
if value is None or (ttl_remaining < 30 and random.random() < 0.1):
value = db_fetch_fn()
redis_client.setex(key, ttl, json.dumps(value))
return json.loads(value)การเขียนผ่าน: วิธีการทำงาน
ในกลยุทธ์การเขียนผ่าน ทุกครั้งที่เขียนข้อมูลลงฐานข้อมูล จะเขียนข้อมูลลงแคชพร้อมกันด้วย แอปพลิเคชันจะเขียนทั้งแคชและฐานข้อมูลเป็นส่วนหนึ่งของการดำเนินการเดียวกัน (หรือให้ฐานข้อมูลเรียกใช้การอัปเดตแคช) ดังนั้นแคชจึงสอดคล้องกับฐานข้อมูลอยู่เสมอ และไม่มีช่วงเวลาที่ข้อมูลล้าสมัย การเขียนผ่านรับประกันว่าข้อมูลในแคชเป็นข้อมูลล่าสุดเสมอ ทำให้การอ่านครั้งถัดไปของข้อมูลที่เพิ่งเขียนเป็นการพบข้อมูลในแคชเสมอ
# Write-through pattern (Python)
def update_user(user_id, user_data, redis_client, db):
# 1. Write to database FIRST
db.execute('UPDATE users SET name=%s WHERE id=%s',
(user_data['name'], user_id))
# 2. Update cache immediately (write-through)
cache_key = f'user:{user_id}'
redis_client.setex(cache_key, 3600, json.dumps(user_data))
return user_data
# Every read is now a cache hit for recently updated dataการเขียนผ่าน: ข้อดี
ข้อดีของการเขียนผ่าน ได้แก่ ข้อมูลในแคชเป็นข้อมูลล่าสุดเสมอ — ไม่มีข้อมูลล้าสมัย เพราะแคชได้รับการอัปเดตทุกครั้งที่เขียน การอ่านทำได้รวดเร็วเสมอ — ข้อมูลยอดนิยมที่มีการเขียนบ่อยจะอยู่ในแคชเสมอ ไม่มีการถล่มของแคชขณะอ่าน — เนื่องจากข้อมูลถูกเติมไว้ล่วงหน้าก่อนอ่าน จึงไม่มีการไม่พบข้อมูลสำหรับข้อมูลที่เพิ่งเขียน กลยุทธ์นี้เหมาะอย่างยิ่งกับงานที่อ่านข้อมูลเป็นหลักและมีการอัปเดตบ่อย ซึ่งความใหม่ของข้อมูลมีความสำคัญ เช่น แค็ตตาล็อกผลิตภัณฑ์ ระบบราคา หรือแคชโปรไฟล์ผู้ใช้
การเขียนผ่าน: ข้อเสีย
ข้อเสียของการเขียนผ่าน ได้แก่ ต้นทุนของการเขียน — การเขียนทุกครั้งต้องดำเนินการสองอย่าง (ฐานข้อมูล + แคช) ทำให้การเขียนมีความหน่วงเพิ่มขึ้น ข้อมูลที่ไม่จำเป็นในแคช — ข้อมูลจะถูกเก็บในแคชแม้จะไม่มีการอ่านอีกเลย (เขียนครั้งเดียวและไม่เคยร้องขอ) ทำให้สิ้นเปลืองหน่วยความจำของแคช การเริ่มต้นแคชใหม่ทำให้แคชว่างเปล่า — หากคลัสเตอร์แคชเริ่มต้นใหม่ ข้อมูลที่เขียนไว้ล่วงหน้าทั้งหมดจะสูญหาย และต้องเติมข้อมูลลงแคชใหม่ผ่านการเขียนหรือกระบวนการอุ่นแคช ควรใช้การเขียนผ่านร่วมกับ TTL เพื่อป้องกันไม่ให้ข้อมูลที่ถูกอ่านน้อยเติบโตอย่างไม่จำกัด
การผสานการโหลดแบบขี้เกียจกับการเขียนผ่าน
ในทางปฏิบัติ ระบบที่ใช้งานจริงจำนวนมากผสานทั้งสองกลยุทธ์เข้าด้วยกัน ได้แก่ ใช้การเขียนผ่านกับข้อมูลที่อัปเดตบ่อยและอ่านบ่อย (เช่น เซสชันผู้ใช้หรือราคาปัจจุบัน) และใช้การโหลดแบบขี้เกียจกับข้อมูลที่อัปเดตน้อยแต่ถูกอ่านบ่อย (เช่น คำอธิบายผลิตภัณฑ์หรือเนื้อหาบทความ) กำหนด TTL ที่เหมาะสมให้กับทั้งสองแบบ โดยคีย์แบบเขียนผ่านจะมี TTL ยาว เนื่องจากข้อมูลเป็นข้อมูลล่าสุดเสมอ ส่วนคีย์ที่โหลดแบบขี้เกียจจะมี TTL สั้นกว่าเพื่อจำกัดช่วงเวลาที่ข้อมูลอาจล้าสมัย แนวทางแบบผสมนี้ช่วยเพิ่มอัตราการพบข้อมูลในแคชให้สูงสุด พร้อมลดความล้าสมัยของข้อมูล
# Hybrid: write-through for sessions, lazy loading for product data
# Write-through for session data (always fresh, critical)
def save_session(session_id, data, redis_client, db):
db.upsert('sessions', session_id, data)
redis_client.setex(f'session:{session_id}', 3600, json.dumps(data))
# Lazy loading for product catalog (infrequent updates OK)
def get_product(product_id, redis_client, db):
cached = redis_client.get(f'product:{product_id}')
if cached:
return json.loads(cached)
product = db.query('SELECT * FROM products WHERE id=%s', product_id)
redis_client.setex(f'product:{product_id}', 86400, json.dumps(product))
return productหลักการออกแบบ TTL
อายุการใช้งาน (TTL) ของข้อมูลที่แคชไว้จะควบคุมช่วงเวลาสูงสุดที่ข้อมูลอาจล้าสมัยและขนาดพื้นที่หน่วยความจำของแคช ควรออกแบบ TTL โดยพิจารณาจากความถี่ในการอัปเดตข้อมูล (ข้อมูลเซสชันเปลี่ยนแปลงบ่อย → TTL สั้น เนื้อหาแบบคงที่เปลี่ยนแปลงน้อย → TTL ยาว) ระดับการยอมรับข้อมูลล้าสมัย (ราคาทางการเงิน → สั้นมาก ข้อความในบล็อก → หลายชั่วโมงหรือหลายวัน) และความจุหน่วยความจำของแคช (หน่วยความจำเหลือน้อย → TTL สั้นลงเพื่อนำข้อมูลเก่าออกได้เร็วขึ้น) ควรกำหนด TTL เสมอ — อย่าเก็บข้อมูลในแคชโดยไม่มีวันหมดอายุ มิฉะนั้นแคชจะเต็มไปด้วยข้อมูลเก่าในที่สุด
# TTL examples by data type
# API rate limit counter: 60 seconds
redis_client.setex(f'ratelimit:{ip}', 60, count)
# User session: 30 minutes
redis_client.setex(f'session:{id}', 1800, json.dumps(session))
# Product catalog: 24 hours
redis_client.setex(f'product:{id}', 86400, json.dumps(product))
# Stock price: 10 seconds
redis_client.setex(f'price:{symbol}', 10, price)
# Static site content: 7 days
redis_client.setex(f'page:{slug}', 604800, html_content)การทำให้แคชใช้ไม่ได้เมื่อมีการอัปเดต
แทนที่จะพึ่งพาการหมดอายุของ TTL เพียงอย่างเดียว คุณสามารถทำให้คีย์ในแคชใช้ไม่ได้อย่างชัดเจน (ลบคีย์) เมื่อข้อมูลต้นทางมีการเปลี่ยนแปลง วิธีนี้จะกำจัดช่วงเวลาที่ข้อมูลล้าสมัยได้ทั้งหมด รูปแบบที่พบบ่อย ได้แก่ ลบเมื่อเขียน (ลบคีย์แคชหลังการอัปเดตฐานข้อมูลทุกครั้ง — การอ่านครั้งถัดไปจะเติมข้อมูลกลับผ่านการโหลดแบบขี้เกียจ) และการทำให้ใช้ไม่ได้ตามเหตุการณ์ (DynamoDB Streams หรือการเก็บการเปลี่ยนแปลงของ RDS เรียกใช้ Lambda เพื่อลบคีย์ที่ได้รับผลกระทบ) การทำให้แคชใช้ไม่ได้เป็นหนึ่งในปัญหาที่ยากที่สุดของระบบแบบกระจาย ยิ่งตรรกะการทำให้ใช้ไม่ได้เรียบง่ายเท่าใด แคชก็จะยิ่งน่าเชื่อถือมากขึ้นเท่านั้น
# Delete-on-write invalidation pattern
def update_product(product_id, new_data, redis_client, db):
# Update the database
db.execute('UPDATE products SET ... WHERE id=%s', (product_id,))
# Invalidate the cache key
redis_client.delete(f'product:{product_id}')
# Also invalidate any list/search caches that may include this product
redis_client.delete('products:list:page:1')
redis_client.delete(f'products:category:{new_data["category_id"]}')
# Next read will trigger lazy loading with fresh dataการแคชแบบเขียนภายหลัง (เขียนย้อนกลับ)
รูปแบบที่พบได้น้อยกว่าแต่มีประสิทธิภาพสูงคือการเขียนภายหลัง (เขียนย้อนกลับ) แอปพลิเคชันจะเขียนข้อมูลลงในแคชเท่านั้น จากนั้นแคชจะส่งข้อมูลไปยังฐานข้อมูลแบบไม่พร้อมกันในเบื้องหลัง วิธีนี้ให้การเขียนที่รวดเร็วมาก (เก็บไว้ในหน่วยความจำเท่านั้น) แต่ต้องแลกกับความเสี่ยงที่ข้อมูลจะสูญหาย หากแคชล้มเหลวก่อนส่งข้อมูลไปยังฐานข้อมูล การเขียนภายหลังเหมาะกับการเขียนที่มีความถี่และปริมาณสูง ซึ่งข้อมูลสามารถสร้างขึ้นใหม่ได้หรือยอมรับการสูญเสียเล็กน้อยได้ เช่น ตัวนับการพบข้อมูล เหตุการณ์การวิเคราะห์ หรือการอัปเดตคะแนนเกม ElastiCache ไม่รองรับการเขียนภายหลังโดยตรง จึงต้องนำไปใช้งานในชั้นแอปพลิเคชัน
# Write-behind pattern: write to cache, flush to DB asynchronously
# Application writes:
# redis_client.incr('post:42:views') # fast, in-memory only
# Background job (runs every 60 seconds):
def flush_view_counts(redis_client, db):
for key in redis_client.scan_iter('post:*:views'):
count = redis_client.getdel(key) # atomic get-and-delete
post_id = key.split(':')[1]
db.execute('UPDATE posts SET views = views + %s WHERE id = %s',
(int(count), post_id))ตรวจสอบความเข้าใจอย่างรวดเร็ว
ทดสอบความเข้าใจแนวคิดของ AWS Solutions Architect (SAA-C03) จากบทเรียนนี้
สรุปบทเรียน
ในบทเรียนนี้ คุณได้เรียนรู้ว่า การโหลดแบบขี้เกียจ จะเติมข้อมูลลงแคชเมื่ออ่านแล้วไม่พบข้อมูล และใช้หน่วยความจำอย่างมีประสิทธิภาพ แต่สามารถส่งคืนข้อมูลล้าสมัยจนกว่า TTL จะหมดอายุ การเขียนผ่าน จะอัปเดตแคชทุกครั้งที่เขียน ทำให้ไม่มีข้อมูลล้าสมัย แต่สิ้นเปลืองหน่วยความจำกับข้อมูลที่ไม่มีการอ่าน และการทำให้ใช้ไม่ได้อย่างชัดเจน จะลบคีย์แคชเมื่อฐานข้อมูลได้รับการอัปเดต เพื่อกำจัดช่วงเวลาที่ข้อมูลล้าสมัย บทถัดไปเราจะสำรวจรูปแบบการจัดเก็บเซสชันและกระดานจัดอันดับด้วย ElastiCache
เรียนรู้ Cloud & IT Cert Prep ด้วย AI tutor — ฟรี
เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป
- คอร์ส
- 150
- บทเรียน
- 600
คำถามที่พบบ่อย
บทเรียน “กลยุทธ์การแคช: การโหลดแบบขี้เกียจและการเขียนผ่าน” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “กลยุทธ์การแคช: การโหลดแบบขี้เกียจและการเขียนผ่าน” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Cloud & IT Cert Prep ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Cloud & IT Cert Prep มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “กลยุทธ์การแคช: การโหลดแบบขี้เกียจและการเขียนผ่าน”
ใช้การโหลดแบบขี้เกียจเพื่อเติมแคชเมื่อไม่พบข้อมูล และใช้การเขียนผ่านเพื่อให้แคชสอดคล้องกับทุกการเขียนลงฐานข้อมูล คุณปฏิบัติ Cloud & IT Cert Prep ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Cloud & IT Cert Prep หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Cloud & IT Cert Prep บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “กลยุทธ์การแคช: การโหลดแบบขี้เกียจและการเขียนผ่าน” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Cloud & IT Cert Prep นี้ได้ไหม
ได้ บทเรียน Cloud & IT Cert Prep ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- Redis เทียบกับ Memcached: การเลือกกลไกที่เหมาะสม
- กลุ่มการจำลองข้อมูล Redis ของ ElastiCache และโหมดคลัสเตอร์
- กลยุทธ์การแคช: การโหลดแบบขี้เกียจและการเขียนผ่าน
- การจัดเก็บเซสชันและรูปแบบกระดานผู้นำ