The Art of Embracing Failures: ออกแบบ Serverless Architecture ให้พร้อมรับมือความล้มเหลว (AWS Summit Bangkok 2026)

The Art of Embracing Failures: ออกแบบ Serverless Architecture ให้พร้อมรับมือความล้มเหลว (AWS Summit Bangkok 2026)

สรุป session 'The Art of Embracing Failures in Serverless Architectures' จาก AWS Summit Bangkok 2026 ว่าด้วยการทำความเข้าใจ Retry, Timeout และ Service Limit เพื่อสร้างระบบ Serverless ที่ resilient พร้อมกรณีศึกษา Voice AI Agent จาก Amity ที่รันบน AWS
2026.06.19

สไลด์เปิด session "The Art of Embracing Failures in Serverless Architectures" พร้อมชื่อสปีกเกอร์จาก AWS และ Amity

บทนำ (Introduction)

ในช่วงท้ายของ Track 4 ที่งาน AWS Summit Bangkok 2026 มี session ที่ชื่อว่า "The Art of Embracing Failures in Serverless Architectures" บรรยายโดยคุณภัทร ปิยะพันธ์ Solutions Architect จาก Amazon Web Services ร่วมกับคุณวัชรมิตร หมวดเครือ Director of AI Research and Application Center จาก Amity

แนวคิดหลักของ session นี้สรุปได้ด้วยประโยคคลาสสิกของ Werner Vogels (CTO ของ Amazon) ที่ว่า "Everything fails all the time" — ทุกอย่างพังได้เสมอ คำถามจึงไม่ใช่ว่าระบบของเรา "จะพังไหม" แต่เป็นว่าเรา "เตรียมพร้อมรับมือกับความล้มเหลวดีแค่ไหน" บทความนี้จะสรุปหลักการสำคัญสามเรื่องที่ช่วยให้ระบบ Serverless ของเรา resilient ขึ้น พร้อมกรณีศึกษาจริงจากทีม Amity

เนื้อหาหลัก (Main Content)

Serverless ที่ดูสมบูรณ์ใน Dev แต่ Fail ใน Production

Distributed architecture diagram: Amazon Kinesis Data Streams → AWS Lambda → Amazon DynamoDB

หลายท่านคงเคยออกแบบ Serverless architecture โดยเลือกหลาย service มาประกอบกัน เช่น use case แบบ streaming data ที่ใช้ Amazon Kinesis Data Streams รับข้อมูล ใช้ AWS Lambda ประมวลผล และเก็บข้อมูลลง Amazon DynamoDB ทุกอย่างทำงานเข้ากันได้อย่างราบรื่นใน development environment และดูพร้อม deploy ขึ้น production

แต่เมื่อระบบรันไปเรื่อย ๆ เรามักจะเจอเคสที่ service ตัวใดตัวหนึ่ง fail, เกิด data inconsistency, หรือ timeout ขึ้นมา คำถามคือ "ปัญหาที่แท้จริงเกิดจากอะไร?" สปีกเกอร์ชี้ว่าบ่อยครั้งมันไม่ได้เกิดจาก AWS (เพราะ service ออกแบบมาให้ highly available อยู่แล้ว) และไม่ได้เกิดจากเราที่เขียนโค้ดตาม best practice เสมอไป — ความจริงคือ failure เป็นเรื่องปกติของ distributed system และจะมาในจังหวะที่เราคาดไม่ถึง

📎 Amazon Kinesis Data Streams — Developer Guide · Using AWS Lambda with Amazon Kinesis · Amazon DynamoDB — Developer Guide

หัวข้อที่ 1: Retry — ลองใหม่อย่างถูกวิธี

เมื่อเกิด failure สิ่งแรกที่เรานึกถึงคือการ retry แต่ session แนะนำ best practice 3 ข้อที่ควรพิจารณา:

  1. Retry เฉพาะเคสที่ retry แล้วมีโอกาสสำเร็จ เช่น throttling error หรือ HTTP 5xx เท่านั้น ส่วนเคสอย่าง 4xx หรือ validation error นั้น retry ไปกี่ครั้งก็ fail เหมือนเดิม
  2. กำหนดจำนวน retry สูงสุด (max retries) เช่น 3 หรือ 10 ครั้ง ไม่ปล่อยให้ retry ไม่จำกัด
  3. ใช้ exponential backoff ร่วมกับ jitter — backoff ทำให้ระยะห่างระหว่างแต่ละครั้งของการ retry เพิ่มขึ้นเรื่อย ๆ ส่วน jitter (ค่าสุ่ม) ทำให้ client หลายตัวไม่ retry พร้อมกันจนไป "ถล่ม" service ปลายทางซ้ำ

ข้อควรระวังที่สปีกเกอร์ย้ำคือ หลายคนคิดว่า retry ทำให้ระบบแข็งแรงขึ้น แต่จริง ๆ แล้วถ้าทำผิดวิธี (ไม่มี backoff ไม่มี jitter หรือ retry ทั้งที่ service กำลังช้าอยู่) มันจะกลายเป็น retry storm ที่ทำให้ระบบล่มหนักกว่าเดิม

📎 Timeouts, retries, and backoff with jitter — Amazon Builders' Library

หัวข้อที่ 2: Timeout — ตัดการรอที่ไม่มีวันสิ้นสุด

การสื่อสารระหว่าง distributed system มีโอกาส fail ได้หลายจุด ทั้ง request หายระหว่างทาง, service ปลายทางล่ม หรือ response หายไป กรณีเหล่านี้ทำให้แอปของเรา "ค้าง" รอ response ที่ไม่มีวันกลับมา วิธีแก้คือการตั้งค่า timeout เพื่อบอกว่าเราจะรอ response นานแค่ไหน

ตัวอย่าง configuration ของ HTTP client (เช่นการตั้ง retry strategy และ timeout):

import boto3
from botocore.config import Config

config = Config(
    retries={
        "max_attempts": 10,      # retry สูงสุด 10 ครั้ง
        "mode": "standard",      # ใช้ exponential backoff + jitter
    },
    connect_timeout=2,           # timeout การเชื่อมต่อ (วินาที)
    read_timeout=5,              # timeout การอ่าน response (วินาที)
)

client = boto3.client("kinesis", region_name="ap-southeast-7", config=config)

สิ่งที่ต้องระวังเรื่อง timeout คือ ถ้าตั้งนานเกินไป แอปจะไม่ effective (รอนานเกินจำเป็น) แต่ถ้าตั้งสั้นเกินไป request ที่ปกติดีอาจถูกตัดทิ้งก่อนได้ response กลับมา จึงต้องเลือกให้สมดุลกับ use case

จุดที่สปีกเกอร์เน้นเป็นพิเศษคือเรื่อง default value ของ AWS SDK: AWS SDK for Java v2 มี default timeout ที่ราว 2 นาที แต่ AWS SDK for JavaScript v3 ไม่มี default timeout ให้ เพราะแนวคิดต่างกัน — v2 ออกแบบให้ใช้งานได้ทันที ส่วน v3 มองว่า developer รู้ behavior ของแอปตัวเองดีที่สุด (เช่น การ upload ไฟล์ใหญ่ขึ้น S3 อาจใช้เวลาเป็นนาที แต่การอ่านข้อมูลจาก DynamoDB ควรเร็วระดับ millisecond) บทเรียนสำคัญคือ "อย่าใช้ค่า default" — ให้เข้าใจ behavior ของระบบเราเองแล้วตั้งค่าให้เหมาะสม

📎 Retry behavior — AWS SDKs and Tools Reference Guide

หัวข้อที่ 3: Service Limit — Serverless ไม่ได้ไร้ขีดจำกัด

หลายคนพอได้ยินคำว่า Serverless แล้วมักคิดว่ามัน scale ได้ไม่จำกัด แต่ความจริงคือ ไม่มี resource ใดที่ scale ได้แบบ infinite เพราะบน cloud เราแชร์ infrastructure ร่วมกับผู้ใช้รายอื่นจำนวนมาก สปีกเกอร์เปรียบเทียบกับทางด่วน — ถ้าไม่จำกัดจำนวนรถ ทุกคนขึ้นพร้อมกันก็รถติดหมด

Service limit จึงเป็น failure ที่ AWS ตั้งใจออกแบบให้เกิด เพื่อเป็นเพดานป้องกันไม่ให้ผู้ใช้รายใดรายหนึ่งใช้ทรัพยากรจนกระทบคนอื่น (ปัญหา noisy neighbor) เช่น เมื่อเรายิง request เร็วเกินไปจะได้รับ HTTP 429 (Too Many Requests / throttling) กลับมา ทั้งนี้ limit ส่วนใหญ่สามารถขอเพิ่มได้ผ่าน AWS Service Quotas ให้เหมาะกับ use case ของเรา

📎 AWS service quotas — AWS General Reference

เจาะลึก Kinesis + Lambda: เมื่อ Service Limit เจอกับ Streaming

Kinesis Data Streams: Shard เป็น unit of parallelism รองรับ 1 MB/sec หรือ 1,000 records/sec และ records are ordered

กลับมาที่ตัวอย่าง streaming pipeline เดิม — Amazon Kinesis Data Streams มีหน่วยของ parallelism คือ shard โดยแต่ละ shard รองรับ input ได้ 1 MB/sec หรือ 1,000 records/sec และรับประกันว่า record ถูกประมวลผลตามลำดับ (ordered) หากเราส่งข้อมูลเข้ามามากกว่านั้นจะเจอ ProvisionedThroughputExceededException ซึ่งแก้ได้ด้วยการ scale shard เพิ่มหรือทำ exponential backoff ฝั่ง producer

จุดที่ต้องระวังคือ เมื่อใช้ PutRecords ส่งข้อมูลแบบ batch แม้ API จะตอบกลับว่าสำเร็จ แต่ บาง record ใน batch อาจ fail ได้ เราจึงต้องเช็คเองว่ามี record ไหน fail (ดูจากจำนวน FailedRecordCount) แล้ว retry เฉพาะ record ที่ fail เท่านั้น — Kinesis จะไม่ retry ให้อัตโนมัติ

Lambda: 1 shard == 1 concurrent Lambda invocation และเพิ่มได้สูงสุด 10 ด้วย Parallelization Factor

ฝั่ง consumer นั้น Lambda ดึงข้อมูลจาก Kinesis ผ่าน Event Source Mapping (ESM) ซึ่งเป็นตัวกลางที่ poll record จาก stream มาเป็น batch แล้วส่งให้ Lambda function โดยปกติ 1 shard จะ map กับ 1 concurrent Lambda invocation แต่ถ้าประมวลผลไม่ทันก็สามารถใช้ Parallelization Factor เพิ่มได้สูงสุด 10 invocation ต่อ 1 shard

ข้อควรระวังคือ ยิ่งมี shard เยอะและตั้ง Parallelization Factor สูง (เช่น shard เยอะ × 10) ก็ยิ่งมีโอกาสไปชน account-level concurrency limit ของ Lambda จึงต้องพิจารณาให้ดี

📎 Using Lambda to process records from Amazon Kinesis Data Streams

"Poison Pill": เมื่อ record เดียวทำให้ทั้ง shard ค้าง

Lambda Failures: เมื่อ record fail Lambda จะ retry ทั้ง batch จน success หรือ data expiration และ batch อื่นใน shard จะถูก block เกิดปัญหา "Poison pill"

เมื่อ Lambda ได้รับ batch ที่มี record fail อยู่ พฤติกรรม default คือ Lambda จะ retry ทั้ง batch ซ้ำ จนกว่าจะสำเร็จ หรือจนกว่า record จะ expire (data retention ของ Kinesis ตั้งได้ตั้งแต่ 24 ชั่วโมง, 7 วัน ไปจนถึง 365 วัน) และเนื่องจาก Kinesis ต้องประมวลผลตามลำดับ batch อื่น ๆ ใน shard เดียวกันจะถูก block รอไปด้วย

ปรากฏการณ์นี้เรียกว่า "Poison pill" — record เสียเพียงตัวเดียวเปรียบเหมือนยาพิษเม็ดเดียวที่ทำให้ทั้ง shard หยุดชะงัก

Lambda Failures: วิธีรับมือ — Maximum retry attempts, Maximum record age, Report failed record, Bisect batch on failure, On-failure destination (SQS/SNS/S3)

วิธีรับมือ poison pill มีหลายทางที่ตั้งค่าได้ที่ Event Source Mapping:

  • Maximum Retry Attempts — จำกัดจำนวนครั้งที่ retry batch
  • Maximum Record Age — กำหนดอายุสูงสุดของ record ถ้าเกินก็ทิ้ง
  • Report Batch Item Failures — รายงานเฉพาะ record ที่ fail กลับมา เพื่อให้ retry เฉพาะตัวที่เหลือ (partial batch response)
  • Bisect Batch on Function Error — แบ่ง batch ที่ fail ออกเป็นสองส่วนแล้ว retry เพื่อค้นหา record เสียให้เจอ (การแบ่ง batch ไม่กิน retry quota)
  • On-failure Destination — ส่ง record ที่ fail ไปยัง Amazon SQS / SNS / S3 แต่ต้องระวังว่าจะได้แค่ metadata ส่วน record จริงยังคง expire ตามเดิม

สไลด์เน้นย้ำ "Not the defaults!" สำหรับการตั้งค่า Lambda failure handling

ข้อความสำคัญบนสไลด์ตอกย้ำอีกครั้งว่า "Not the defaults!" — ค่าเริ่มต้นของ failure handling เหล่านี้ (เช่น Maximum Retry Attempts และ Maximum Record Age ที่ default เป็น -1 คือ infinite) มักไม่เหมาะกับ production เราจึงต้องตั้งค่าให้สอดคล้องกับระบบของเราเอง

📎 Configuring partial batch response with Kinesis and Lambda · Retain discarded batch records (on-failure destination)

กรณีศึกษา: Voice AI Agent ของ Amity บน AWS

สไลด์ About Us ของ Amity: ก่อตั้งปี 2012, ทำ AI/GenAI solutions, มี Amity AI Research and Application Center (ARAC)

ช่วงท้าย session คุณวัชรมิตรจาก Amity มาแชร์ use case จริง Amity ก่อตั้งปี 2012 ทำ AI solution ให้ enterprise และปัจจุบันโฟกัสเรื่อง Specialized AI — โมเดลที่เก่งกว่า frontier model ในงานเฉพาะทาง โดย use case ที่นำมาแชร์คือ Voice AI Agent สำหรับงาน debt collection (การติดตามทวงหนี้) ที่โทรหาลูกค้าด้วยเสียงเหมือน AI ของ call center ทั่วไป

งานนี้มีข้อกำหนดสำคัญ 3 ข้อ: (1) Data residency — ข้อมูลต้องประมวลผลในประเทศไทยเท่านั้นตาม PDPA, (2) Legal compliance — การทวงหนี้มีกฎหมายเฉพาะที่แม้แต่มนุษย์ก็ห้ามคุกคามลูกค้า AI agent จึงต้อง comply 100%, และ (3) User experience — เป็น conversation-based ที่ latency ในการตอบกลับไม่ควรเกิน ~1 วินาที

สถาปัตยกรรม Voice AI ของพวกเขาประกอบด้วย 4 component หลัก: Voice Activity Detector (ตรวจว่าผู้พูดพูดจบหรือยัง) → Speech-to-Textโมเดลเฉพาะทางที่เทรนเองสำหรับงานทวงหนี้Text-to-Speech ทีม Amity เลือกทำ full-custom stack แทนการใช้ real-time voice API สำเร็จรูป เพราะลองแล้วพบว่า capacity ของ real-time API ถูกแชร์ทั่วโลกและ GPU compute ไม่ได้อยู่ในไทย ทำให้ latency spike บ่อย (จาก ~500ms พุ่งเป็น 2-3 วินาที) อีกทั้ง data store ก็ไม่ compliant การคุมทุกอย่างเองทำให้ optimize ได้เต็มที่

ในแง่ deployment ระบบแบ่งเป็น 2 layer: Orchestration layer (data processing, managed gateway ต่าง ๆ) รันแบบ Serverless บน AWS เพื่อให้ได้ auto-scaling และ auto-recovery โดยสปีกเกอร์ระบุว่า AWS เป็น cloud provider ที่รองรับ Serverless ใน Thailand Region ส่วน Compute layer ที่เป็น GPU compute ของโมเดลยัง host on-premises เพราะยังไม่มี cloud provider รองรับ GPU compute ใน Thailand Region

บทเรียนที่ Amity ได้จากการทำงานร่วมกับ AWS สรุปเป็น 3 ข้อ: (1) เริ่มจาก customer case point ไม่ใช่เริ่มจากเทคโนโลยีแล้วค่อยหาทางขาย, (2) ต้องมีการวัดผล before & after อย่างเข้มข้น, และ (3) service/solution ที่เลือกต้องรองรับ auto-recovery เมื่อ scale

สรุป (Conclusion)

หัวใจของ session นี้คือการเข้าใจพื้นฐานสามเรื่อง — Retry, Timeout และ Service Limit เมื่อเข้าใจแล้วเราสามารถนำไป apply กับ service อะไรก็ได้ ไม่จำกัดเฉพาะ Serverless อย่าใช้ค่า default โดยไม่คิด, retry อย่างมีหลักการด้วย backoff + jitter, ตั้ง timeout ให้เหมาะกับ behavior ของระบบ และเข้าใจว่า service limit มีไว้ปกป้องทุกคน

ดังคำกล่าวของ Amazon ที่ว่า "Everything fails all the time" — ความล้มเหลวเป็นสิ่งที่หลีกเลี่ยงไม่ได้ แต่ถ้าเราเตรียมพร้อม เราก็รับมือกับมันได้ และกรณีศึกษาของ Amity ก็สะท้อนว่าการเลือก architecture ที่รองรับ auto-recovery ตั้งแต่ต้น คือกุญแจสำคัญของระบบที่ resilient ในโลกจริง

อ้างอิง (References)

  1. Amazon Kinesis Data Streams — Developer Guide
  2. Using AWS Lambda with Amazon Kinesis Data Streams
  3. Amazon DynamoDB — Developer Guide
  4. Timeouts, retries, and backoff with jitter — Amazon Builders' Library
  5. Retry behavior — AWS SDKs and Tools Reference Guide
  6. AWS service quotas — AWS General Reference
  7. Configuring partial batch response with Kinesis Data Streams and Lambda
  8. Retain discarded batch records for a Kinesis event source in Lambda

この記事をシェアする

AWSのお困り事はクラスメソッドへ

関連記事