Published
- 2 min read
Transfer Money API — Engineering Notes
เมื่อเราพัฒนา API สำหรับการโอนเงิน (Transfer Money API) มีหลายเรื่องที่เราต้องคำนึงถึงเพื่อให้ระบบมีความน่าเชื่อถือและป้องกันปัญหาต่างๆที่อาจเกิดขึ้นได้ วันนี้ผมจะมาแชร์ 3 ข้อสำคัญที่ควรนำไปใช้กันครับ
1. ใช้ Distributed Lock
ให้ใช้ distributed lock ในกรณีที่ทำ saga pattern หรือ outbox pattern ไม่ได้
การใช้ distributed lock จะช่วยป้องกันไม่ให้มีการประมวลผล transaction เดียวกันพร้อมกันหลายครั้ง ซึ่งอาจทำให้เกิดปัญหาเงินโอนซ้ำหรือข้อมูลไม่สอดคล้องกันได้
การ implement ด้วย Redis
สำหรับ distributed lock เราสามารถใช้ Redis ได้ 2 แบบ:
1. Simple Redis Lock (Single Instance)
ใช้สำหรับระบบที่ไม่ซับซ้อนมาก โดยใช้คำสั่ง SET พร้อม options ดังนี้:
SET resource_name random_token NX PX 30000
NX- จะ set ก็ต่อเมื่อ key ยังไม่มีอยู่PX 30000- กำหนดเวลา expire 30,000 มิลลิวินาที (30 วินาที)random_token- ใช้ค่า random (เช่น UUID) เพื่อความปลอดภัยในการปลดล็อก
การปลดล็อกควรใช้ Lua script เพื่อเช็คว่า token ตรงกันก่อน delete เพื่อป้องกันการลบ lock ของคนอื่นโดยไม่ตั้งใจ
2. Redlock Algorithm
แนะนำสำหรับ production ที่ต้องการความน่าเชื่อถือสูง โดยจะกระจาย lock ไปยัง N Redis masters (โดยทั่วไปใช้ 5 instances)
ขั้นตอนการทำงาน:
- บันทึก timestamp ปัจจุบัน
- พยายาม acquire lock จาก N instances พร้อมกัน
- ตรวจสอบว่าได้ lock มาครบ majority หรือไม่ (≥N/2+1 instances)
- เช็คว่าเวลาที่ใช้ไปไม่เกินเวลา lock validity
- ถ้าล้มเหลว ให้ unlock ทุก instances ที่ได้มา
ข้อดีของ Redlock:
- Mutual exclusion - มีแค่ client เดียวถือ lock ได้ในเวลาเดียวกัน
- Deadlock-free - Lock จะ expire อัตโนมัติผ่าน TTL
- Fault-tolerant - ยังคงทำงานได้อย่างต่อเนื่องแม้ว่าจะมีโหนด (Node/Server) ใดโหนดหนึ่งล่ม เสียหาย หรือเกิดข้อผิดพลาดขึ้น
2. ให้ Client ส่ง Idempotency-ID
ให้ client ส่ง Idempotency-ID มาด้วยทุกครั้งที่เรียก API โดยมีรายละเอียดดังนี้:
- ส่วนใหญ่จะเป็นค่า UUID V4
- Cache TTL ควรอยู่ที่ 24 ชั่วโมงหรือน้อยกว่า
- ความยาวของ Idempotency-ID มากสุด 255 chars (string)
การมี Idempotency-ID จะช่วย:
- Support การทำ retry ของฝั่ง client ได้อย่างปลอดภัย
- ให้ฝั่ง payment provider ทำ circuit breaker ได้
3. เช็ค Transition State
ถ้ามีการแยก API เป็นหลาย step จนกว่าจะมีการยิง API มา confirm การโอนเงิน ให้ฝั่ง payment provider เช็ค transition state ด้วยว่า state1 เปลี่ยนไปเป็น state2 ได้มั้ย
หรือเรียกอีกอย่างว่า เช็ค step การยิง API ของ client
การทำแบบนี้จะช่วยป้องกันไม่ให้ client ข้าม step หรือเรียก API ในลำดับที่ไม่ถูกต้อง ซึ่งอาจทำให้เกิดปัญหากับ business logic ได้