0Pricing
Cloud & IT Cert Prep · บทเรียน

การจัดเก็บเซสชันและรูปแบบกระดานผู้นำ

ใช้ ElastiCache เพื่อลดภาระสถานะเซสชัน HTTP จากเซิร์ฟเวอร์แอปพลิเคชัน และสร้างกระดานผู้นำแบบเรียลไทม์ด้วยชุดข้อมูลเรียงลำดับของ Redis

การจัดเก็บเซสชันและรูปแบบกระดานผู้นำ เป็นบทเรียน Cloud & IT Cert Prep ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Cloud & IT Cert Prep และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Cloud & IT Cert Prep มีบทเรียนทั้งหมด 4 บทเรียน

ปัญหาของเซสชันฝั่งเซิร์ฟเวอร์

แอปพลิเคชันเว็บแบบดั้งเดิมเก็บข้อมูลเซสชันไว้ในหน่วยความจำของเซิร์ฟเวอร์ วิธีนี้ใช้ได้กับเซิร์ฟเวอร์เครื่องเดียว แต่จะมีปัญหาเมื่อปรับขนาดในแนวนอน — หากคำขอถัดไปของผู้ใช้ถูกส่งไปยังอินสแตนซ์ EC2 อื่น อินสแตนซ์นั้นจะไม่รู้จักเซสชันของผู้ใช้ ทำให้ผู้ใช้ถูกออกจากระบบ เซสชันแบบยึดติด (การกำหนดความสัมพันธ์ของเซสชันในตัวกระจายโหลด) ช่วยแก้ปัญหาได้บางส่วน แต่ลดประสิทธิภาพของการกระจายโหลด วิธีแก้ปัญหาที่ปรับขนาดได้คือย้ายสถานะเซสชันไปยังพื้นที่จัดเก็บที่ใช้ร่วมกันและมีความหน่วงต่ำ ซึ่งทุกอินสแตนซ์เข้าถึงได้ — และนี่คือสิ่งที่ ElastiCache Redis มอบให้

Redis สำหรับการจัดเก็บเซสชัน

การจัดเก็บเซสชันใน Redis ให้ความสามารถดังนี้: อ่านเซสชันข้ามเซิร์ฟเวอร์แอปพลิเคชันทั้งหมดได้ในระดับต่ำกว่ามิลลิวินาที มี TTL ในตัวสำหรับทำให้เซสชันหมดอายุโดยอัตโนมัติ อัปเดตเซสชันแบบอะตอมิกเพื่อป้องกันเงื่อนไขการแข่งขัน และทำให้เซสชันใช้ไม่ได้ทันทีด้วยการลบคีย์ แอปพลิเคชันจะเก็บรหัสเซสชันไว้ในคุกกี้ และในแต่ละคำขอจะค้นหารหัสเซสชันใน Redis เพื่อดึงข้อมูลเซสชัน เซิร์ฟเวอร์แอปพลิเคชันทั้งหมดใช้ Redis เดียวกัน ดังนั้นเซิร์ฟเวอร์ใด ๆ ก็สามารถจัดการคำขอของผู้ใช้คนใดก็ได้

# Session storage with Redis (Python Flask example)
import redis, json, uuid
from datetime import timedelta

redis_client = redis.Redis(host='prod-redis-primary', port=6379)
SESSION_TTL = int(timedelta(hours=8).total_seconds())

def create_session(user_id):
    session_id = str(uuid.uuid4())
    session_data = {'user_id': user_id, 'logged_in': True}
    redis_client.setex(f'session:{session_id}', SESSION_TTL, json.dumps(session_data))
    return session_id

def get_session(session_id):
    data = redis_client.get(f'session:{session_id}')
    return json.loads(data) if data else None

TTL ของเซสชันและการหมดอายุแบบเลื่อน

TTL แบบคงที่หมายความว่าเซสชันจะหมดอายุหลังจากสร้างเป็นเวลา N วินาที โดยไม่คำนึงถึงกิจกรรม TTL แบบเลื่อน (ขยายเวลาหมดอายุเมื่อมีการเข้าถึงแต่ละครั้ง) เป็นมิตรต่อผู้ใช้มากกว่า — เซสชันจะหมดอายุหลังจากการเข้าถึงครั้งล่าสุดเป็นเวลา N วินาที ใน Redis ให้ใช้งาน TTL แบบเลื่อนโดยเรียกใช้ EXPIRE (หรือ EXPIREAT) กับคีย์เซสชันทุกครั้งที่อ่านเซสชันสำเร็จ เพื่อเริ่มนับเวลาหมดอายุใหม่ วิธีนี้ช่วยให้ผู้ใช้ที่กำลังใช้งานไม่ถูกออกจากระบบโดยไม่คาดคิด ขณะที่เซสชันที่ไม่มีการใช้งานจะหมดอายุโดยอัตโนมัติและคืนหน่วยความจำ

# Sliding TTL session implementation
def get_session_with_sliding_ttl(session_id, redis_client, ttl_seconds=1800):
    session_key = f'session:{session_id}'

    # Pipeline: GET + EXPIRE in one round trip
    pipe = redis_client.pipeline()
    pipe.get(session_key)
    pipe.expire(session_key, ttl_seconds)  # Reset TTL on access
    results = pipe.execute()

    data = results[0]
    if data:
        return json.loads(data)
    return None   # Session expired or not found

ตะกร้าสินค้าใน Redis

ตะกร้าสินค้าของอีคอมเมิร์ซเหมาะกับ Redis โดยธรรมชาติ ตะกร้าแต่ละใบจะจัดเก็บเป็นแฮชของ Redis โดยฟิลด์คือ SKU ของผลิตภัณฑ์ และค่าคือจำนวนสินค้า การดำเนินการกับแฮช เช่น HINCRBY และ HDEL ช่วยให้อัปเดตแบบอะตอมิกได้โดยไม่ต้องดึงข้อมูลและเขียนตะกร้าทั้งใบใหม่ เมื่อใช้ร่วมกับ TTL (เพื่อทำให้ตะกร้าที่ถูกละทิ้งหมดอายุหลัง 24 ชั่วโมง) Redis จะมอบพื้นที่จัดเก็บตะกร้าที่รวดเร็วและคงอยู่ได้ โดยไม่ต้องใช้ฐานข้อมูลเชิงสัมพันธ์รองรับทุกเหตุการณ์การเพิ่มสินค้าลงตะกร้า

# Shopping cart operations using Redis Hash
cart_key = f'cart:{user_id}'

# Add item (or increase quantity)
# HINCRBY cart:user42 SKU-001 2
redis_client.hincrby(cart_key, 'SKU-001', 2)

# Remove item
# HDEL cart:user42 SKU-001
redis_client.hdel(cart_key, 'SKU-001')

# Get all items in cart
# HGETALL cart:user42
cart = redis_client.hgetall(cart_key)  # {b'SKU-001': b'2', b'SKU-002': b'1'}

# Set TTL for cart abandonment (24 hours)
redis_client.expire(cart_key, 86400)

สถาปัตยกรรมกระดานผู้นำ

กระดานผู้นำแบบเรียลไทม์ เป็นกรณีการใช้งาน Redis แบบคลาสสิกที่ทำงานด้วย Sorted Sets (ZSETs) รายการของผู้เล่นแต่ละรายมีคะแนน และชุดข้อมูลแบบเรียงลำดับจะรักษาสมาชิกให้อยู่ในลำดับคะแนนจากน้อยไปมากตลอดเวลา การค้นหาข้อมูลบนกระดานผู้นำ เช่น ผู้เล่น N อันดับแรก อันดับของผู้เล่น และผู้เล่นในช่วงคะแนนที่กำหนด ใช้เวลา O(log n) หรือ O(log n + m) ซึ่งรวดเร็วมากแม้มีผู้เล่นหลายล้านคน Sorted sets ของ Redis เป็นรากฐานของฟีเจอร์จัดอันดับในเกม ฟิตเนส และโซเชียลจำนวนมาก โดยไม่ต้องใช้คำค้นฐานข้อมูลที่ซับซ้อนหรือคำนวณอันดับใหม่ทุกครั้งที่เปิดหน้า

# Real-time leaderboard with Redis Sorted Set

# Add or update a player's score
# ZADD game:weekly:leaderboard 15750 'player:alice'
redis_client.zadd('game:weekly:leaderboard', {'player:alice': 15750})

# Increment score (atomic)
# ZINCRBY game:weekly:leaderboard 500 'player:alice'
redis_client.zincrby('game:weekly:leaderboard', 500, 'player:alice')

# Get top 10 players (highest scores first)
# ZREVRANGE game:weekly:leaderboard 0 9 WITHSCORES
top_10 = redis_client.zrevrange('game:weekly:leaderboard', 0, 9, withscores=True)

อันดับผู้เล่นและผู้เล่นใกล้เคียง

ฟีเจอร์กระดานผู้นำทั่วไปสองอย่างที่นอกเหนือจาก “แสดง 10 อันดับแรก” คือ แสดงอันดับของผู้เล่น และ แสดงผู้เล่นที่อยู่ใกล้ผู้เล่นที่กำหนด ทั้งสองอย่างทำได้ง่ายด้วย sorted sets ของ Redis ZREVRANK จะคืนค่าอันดับแบบเริ่มนับจาก 0 ของผู้เล่น โดยเรียงคะแนนจากมากไปน้อย หากต้องการแสดงผู้เล่นที่อยู่เหนือและต่ำกว่าผู้เล่นหนึ่งรายอย่างละ 5 คน ให้ดึงอันดับของผู้เล่นก่อน แล้วใช้ ZREVRANGE ตั้งแต่อันดับ-5 ถึงอันดับ+5 วิธีนี้จะแสดงมุมมองกระดานผู้นำเฉพาะบุคคลด้วยคำสั่ง Redis เพียงสองคำสั่ง โดยไม่ต้องใช้ฟังก์ชันหน้าต่างของ SQL ที่ซับซ้อน

# Get Alice's rank (0-indexed, so add 1 for display)
# ZREVRANK game:weekly:leaderboard 'player:alice'
rank = redis_client.zrevrank('game:weekly:leaderboard', 'player:alice')
print(f'Alice is rank #{rank + 1}')

# Get 5 players above and below Alice
start = max(0, rank - 5)
end = rank + 5
nearby = redis_client.zrevrange(
    'game:weekly:leaderboard', start, end, withscores=True
)
print('Players near Alice:', nearby)

การจำกัดอัตราด้วย Redis

การจำกัดอัตรา (การจำกัดจำนวนคำขอที่ไคลเอ็นต์ส่งได้ภายในช่วงเวลาใดช่วงเวลาหนึ่ง) เป็นอีกกรณีการใช้งาน Redis ที่มีคุณค่าสูง อัลกอริทึมหน้าต่างเลื่อนใช้ sorted set โดยสมาชิกแต่ละรายการคือเวลาประทับของคำขอ ในทุกคำขอ ให้ดำเนินการดังนี้: ลบสมาชิกที่เก่ากว่าหน้าต่างเวลา นับสมาชิกที่เหลือ ปฏิเสธคำขอหากจำนวนเกินขีดจำกัด และเพิ่มเวลาประทับใหม่ วิธีนี้ทำให้จำกัดอัตราแบบหน้าต่างเลื่อนได้อย่างแม่นยำในระดับมิลลิวินาที ซึ่งแม่นยำกว่าตัวนับแบบหน้าต่างคงที่มาก และไม่เพิ่มภาระให้ฐานข้อมูล

# Sliding window rate limiter (100 requests per 60 seconds)
import time

def is_rate_limited(user_id, redis_client, limit=100, window_seconds=60):
    key = f'ratelimit:{user_id}'
    now = time.time()
    window_start = now - window_seconds

    pipe = redis_client.pipeline()
    pipe.zremrangebyscore(key, '-inf', window_start)  # Remove old
    pipe.zcard(key)                                    # Count current
    pipe.zadd(key, {str(now): now})                   # Add this request
    pipe.expire(key, window_seconds)
    results = pipe.execute()

    request_count = results[1]
    return request_count >= limit  # True = rate limited

การทำล็อกแบบกระจายด้วย Redis

ล็อกแบบกระจายใช้ประสานการเข้าถึงทรัพยากรที่ใช้ร่วมกันแบบผูกขาดระหว่างเซิร์ฟเวอร์แอปพลิเคชันหลายเครื่อง คำสั่ง SET key value NX EX ttl ของ Redis ช่วยให้การยึดล็อกเป็นอะตอม โดยจะตั้งค่าคีย์ก็ต่อเมื่อคีย์นั้นยังไม่มีอยู่ (NX = Not eXists) และตั้งค่า TTL เพื่อป้องกันการล็อกค้างหากผู้ถือครองหยุดทำงาน เมื่อการดำเนินการเสร็จสิ้น ผู้ถือครองจะลบคีย์นั้น อัลกอริทึม Redlock (ใช้โหนด Redis หลายโหนดเพื่อให้ได้องค์ประชุม) ให้ล็อกแบบกระจายที่แข็งแกร่งกว่า แต่ก็เพิ่มความซับซ้อน สำหรับกรณีการใช้งานส่วนใหญ่ ล็อกบนโหนด Redis เดียวก็เพียงพอ

# Distributed lock with Redis SET NX EX
import uuid

def acquire_lock(redis_client, resource, ttl_seconds=30):
    lock_id = str(uuid.uuid4())  # Unique ID to identify this lock holder
    key = f'lock:{resource}'
    acquired = redis_client.set(key, lock_id, nx=True, ex=ttl_seconds)
    return lock_id if acquired else None

def release_lock(redis_client, resource, lock_id):
    key = f'lock:{resource}'
    # Only delete if we still own the lock (Lua script for atomicity)
    lua = 'if redis.call("get",KEYS[1])==ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end'
    redis_client.eval(lua, 1, key, lock_id)

การจัดเก็บเซสชัน: ElastiCache เทียบกับ DynamoDB

ทั้ง ElastiCache Redis และ DynamoDB สามารถจัดเก็บข้อมูลเซสชันได้ แต่มีข้อแลกเปลี่ยนแตกต่างกัน ElastiCache Redis: เวลาแฝงระดับไมโครวินาที จัดเก็บในหน่วยความจำ (ข้อมูลอาจสูญหายหากไม่เปิดใช้การคงอยู่) รูปแบบข้อมูลเรียบง่ายกว่า และต้องใช้ VPC DynamoDB: เวลาแฝงระดับมิลลิวินาทีหลักหน่วย (DAX ทำให้ใกล้เคียง Redis ได้) เป็นบริการที่จัดการให้ทั้งหมดโดยไม่ต้องดูแลคลัสเตอร์ มีความทนทานเป็นค่าเริ่มต้น เข้าถึงได้ทั่วโลกด้วย Global Tables และเป็นแบบไร้เซิร์ฟเวอร์เมื่อใช้ความจุตามการใช้งาน สำหรับการสอบ SAA-C03 หากโจทย์เน้น เวลาแฝงระดับไมโครวินาที หรือ การดำเนินการในหน่วยความจำที่ซับซ้อน ให้เลือก Redis หากเน้น ความทนทานของข้อมูล แบบไร้เซิร์ฟเวอร์ หรือ การรองรับระดับโลก ให้พิจารณา DynamoDB

การทำดัชนีเชิงภูมิสารสนเทศด้วย Redis

Redis มี ชนิดข้อมูลเชิงภูมิสารสนเทศในตัว (คำสั่ง GEO) ซึ่งจัดเก็บพิกัดละติจูด/ลองจิจูดและรองรับการค้นหาตามระยะใกล้ไกล ด้วย GEOADD GEODIST และ GEORADIUS (ปัจจุบันใช้ GEOSEARCH ใน Redis 6.2) คุณสามารถค้นหาตำแหน่งทั้งหมดภายในรัศมีที่กำหนดจากจุดหนึ่งได้ในเวลา O(n + log n) กรณีการใช้งาน ได้แก่ ค้นหาคนขับรถใกล้เคียง (บริการร่วมเดินทาง) ค้นหาร้านอาหารภายในระยะ 5 กม. และเรียงผลการค้นหาตามระยะทาง วิธีนี้ไม่ต้องใช้ฐานข้อมูลเชิงภูมิสารสนเทศแยกต่างหาก และยังคงให้การค้นหาตำแหน่งทำงานด้วยความเร็วระดับหน่วยความจำ

# Store driver locations
# GEOADD drivers 13.361389 38.115556 'driver:001'
# GEOADD drivers 15.087269 37.502669 'driver:002'

# Find all drivers within 10 km of a point
# GEOSEARCH drivers FROMLONLAT 13.5 38.1 BYRADIUS 10 km ASC COUNT 5 WITHCOORD

# Result: sorted list of driver IDs within 10 km with coordinates

HyperLogLog สำหรับนับผู้เข้าชมที่ไม่ซ้ำกัน

HyperLogLog คือโครงสร้างข้อมูลเชิงความน่าจะเป็นที่ใช้ประมาณการ จำนวนองค์ประกอบที่ไม่ซ้ำกันในชุดข้อมูล โดยใช้หน่วยความจำคงที่ (12 KB ใน Redis) ไม่ว่าจำนวนรายการที่ไม่ซ้ำกันซึ่งเพิ่มเข้ามาจะมีมากเพียงใด ค่าความคลาดเคลื่อนมาตรฐานอยู่ที่ประมาณ 0.81% ใช้ PFADD เพื่อเพิ่มองค์ประกอบ และใช้ PFCOUNT เพื่อรับค่าประมาณ วิธีนี้เหมาะอย่างยิ่งสำหรับนับผู้ใช้ที่ใช้งานรายวันแบบไม่ซ้ำกัน การเปิดดูหน้าเว็บที่ไม่ซ้ำกัน หรือที่อยู่ IP ที่ไม่ซ้ำกัน เมื่อไม่จำเป็นต้องได้จำนวนที่แม่นยำและให้ความสำคัญกับการใช้หน่วยความจำอย่างมีประสิทธิภาพ หากจัดเก็บ ID ผู้ใช้ที่ไม่ซ้ำกันหลายล้านรายการเป็น Redis Set จะใช้พื้นที่หลาย GB แต่ HyperLogLog ใช้เพียง 12 KB

# Count unique daily visitors using HyperLogLog
date = '2024-01-15'
hll_key = f'unique_visitors:{date}'

# Track a visitor (PFADD is idempotent for the same user)
# PFADD unique_visitors:2024-01-15 'user:12345'
redis_client.pfadd(hll_key, 'user:12345')
redis_client.pfadd(hll_key, 'user:67890')
redis_client.pfadd(hll_key, 'user:12345')  # Duplicate — not counted again

# Get estimated unique visitor count
# PFCOUNT unique_visitors:2024-01-15
count = redis_client.pfcount(hll_key)
print(f'Unique visitors today (estimate): {count}')

ตรวจสอบความเข้าใจ

ทดสอบความเข้าใจแนวคิด AWS Solutions Architect (SAA-C03) จากบทเรียนนี้

ทบทวนบทเรียน

ในบทเรียนนี้ คุณได้เรียนรู้ว่า การจัดเก็บเซสชันด้วย Redisช่วยให้ขยายระบบในแนวนอนได้โดยไม่ต้องเก็บสถานะ ด้วยการทำให้ทุกอินสแตนซ์เข้าถึงสถานะเซสชันร่วมกันได้ด้วยเวลาแฝงต่ำกว่าหนึ่งมิลลิวินาที Redis sorted setsช่วยขับเคลื่อนกระดานผู้นำแบบเรียลไทม์ด้วยการค้นหาอันดับในเวลา O(log n) และ ชนิดข้อมูล Redis เฉพาะทาง (HyperLogLog สำหรับนับรายการที่ไม่ซ้ำกัน GEO สำหรับค้นหาตามระยะใกล้ไกล และล็อกแบบกระจาย) ช่วยแก้ปัญหาสถาปัตยกรรมทั่วไปได้อย่างมีประสิทธิภาพ เนื้อหานี้เป็นบทสุดท้ายของหลักสูตรการแคชด้วย ElastiCache — บทถัดไปเราจะสำรวจสถาปัตยกรรมแบบพร้อมใช้งานสูงและทนทานต่อข้อผิดพลาด

คำถามที่พบบ่อย

บทเรียน “การจัดเก็บเซสชันและรูปแบบกระดานผู้นำ” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การจัดเก็บเซสชันและรูปแบบกระดานผู้นำ” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Cloud & IT Cert Prep ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Cloud & IT Cert Prep มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การจัดเก็บเซสชันและรูปแบบกระดานผู้นำ”

ใช้ ElastiCache เพื่อลดภาระสถานะเซสชัน HTTP จากเซิร์ฟเวอร์แอปพลิเคชัน และสร้างกระดานผู้นำแบบเรียลไทม์ด้วยชุดข้อมูลเรียงลำดับของ Redis คุณปฏิบัติ Cloud & IT Cert Prep ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Cloud & IT Cert Prep หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Cloud & IT Cert Prep บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “การจัดเก็บเซสชันและรูปแบบกระดานผู้นำ” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Cloud & IT Cert Prep นี้ได้ไหม

ได้ บทเรียน Cloud & IT Cert Prep ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. Redis เทียบกับ Memcached: การเลือกกลไกที่เหมาะสม
  2. กลุ่มการจำลองข้อมูล Redis ของ ElastiCache และโหมดคลัสเตอร์
  3. กลยุทธ์การแคช: การโหลดแบบขี้เกียจและการเขียนผ่าน
  4. การจัดเก็บเซสชันและรูปแบบกระดานผู้นำ
← กลับไปที่ Cloud & IT Cert Prep