# Shopify ย้ายการจองสินค้าคงคลังไปที่ MySQL

Published: 2026-10-10

Shopify ย้ายระบบการจองสินค้าคงคลังจาก Redis ไปยังฐานข้อมูล MySQL ซึ่งเป็นที่จัดเก็บข้อมูลบัญชีสินค้าคงคลังอยู่แล้ว กลุ่มแถวของหน่วยที่สามารถล็อกได้ทีละรายการในขอบเขตที่กำหนดช่วยให้การชำระเงินที่เกิดขึ้นพร้อมกันสามารถใช้ SKIP LOCKED เพื่อเลือกหน่วยที่เหมาะสมที่แตกต่างกันได้ การออกแบบนี้ยังขึ้นอยู่กับขอบเขตของธุรกรรม, โครงสร้างคีย์หลัก, กฎการเติมสินค้า และการสังเกตระยะเวลาการถือครองการเชื่อมต่อตลอดกระบวนการชำระเงิน

Canonical: https://thedailydiff.dev/th/video/shopify-reservation-locks/

## วิดีโอนี้ครอบคลุมอะไรบ้าง

- โมเดลตัวนับปริมาณของ Redis เดิมสามารถจัดการกับการทำงานพร้อมกันได้ แต่การล้างการจองและการอัปเดตบัญชี MySQL ไม่สามารถแชร์ธุรกรรมอะตอมมิคในเครื่องเดียวกันได้
- การเปลี่ยนมาใช้หนึ่งแถวต่อหนึ่งหน่วยที่พร้อมใช้งานในกลุ่มที่จำกัดสูงสุด 1,000 แถวต่อชุดค่าผสมของสินค้า/สถานที่ การที่กลุ่มว่างเปล่าสามารถกระตุ้นการเติมสินค้าแบบอินไลน์ได้ โดยคำขอที่เกิดขึ้นพร้อมกันจะรออยู่เบื้องหลังการล็อกการเติมสินค้า
- คีย์หลักแบบคอมโพสิตคือ (shop\_id, inventory\_item\_id, inventory\_group\_id, id) Shopify ลดโอเวอร์เฮดของการล็อกในโปรโตไทป์และใช้ READ COMMITTED เพื่อหลีกเลี่ยง gap locks ที่บล็อกการเติมสินค้า
- การจองจะลบแถวในกลุ่มก่อนที่จะแทรกบันทึกการจอง การคอมมิตจะปล่อยการล็อกฐานข้อมูลในขณะที่การถือครองที่เก็บไว้ยังคงอยู่หลังจากการชำระเงิน การชำระเงินที่สำเร็จจะอ้างสิทธิ์ในบัญชีและลบการจองในธุรกรรมอะตอมมิคในภายหลัง
- MySQL ระบุว่า SKIP LOCKED เป็นมุมมองที่ไม่สอดคล้องกันที่ละเว้นแถวที่ถูกล็อก ไม่ได้สร้างการนับสต็อกที่สมบูรณ์หรือการหมุนเวียนที่เป็นธรรม ใช้ได้กับการล็อกระดับแถวเท่านั้นและไม่ปลอดภัยสำหรับการจำลองแบบตามคำสั่ง
- ตัวอย่างต้นฉบับมี expires\_at แต่ Shopify ไม่ได้ระบุอัลกอริทึมการล้างข้อมูลหมดอายุของ MySQL สาขาการปล่อย/หมดอายุของวิดีโอเป็นข้อกำหนดวงจรชีวิตเพื่อการอธิบาย
- ระยะเวลาการถือครองการเชื่อมต่อในโค้ดการชำระเงินอื่น ๆ เป็นคอขวดสุดท้ายของปริมาณงาน Shopify ทำการเขียนเงา (shadow-wrote) ทั้งสองระบบ เปรียบเทียบผลลัพธ์และเปลี่ยนผ่านอย่างค่อยเป็นค่อยไปด้วยสวิตช์ปิด Redis

## บท

- 0:00 ทำไมต้องย้ายการจองไปที่ MySQL?
- 0:29 ทำไมร้านค้าสองแห่งถึงมีความเสี่ยง?
- 0:52 หน่วยที่ล็อกได้กลายเป็นอะไร?
- 1:15 จะเกิดอะไรขึ้นเมื่อกลุ่มว่างเปล่า?
- 2:14 SKIP LOCKED ละเว้นอะไรไปบ้าง?
- 2:26 ขีดจำกัดที่แท้จริงอยู่ที่ไหน?
- 2:38 ทำไมฉันถึงจะส่งมอบการออกแบบนี้?

## บทถอดเสียงที่แปลแล้ว

แปลจากการบรรยายภาษาอังกฤษต้นฉบับ เสียงและคำบรรยายที่มีให้จะควบคุมโดย YouTube

### ทำไมต้องย้ายการจองไปที่ MySQL?

0:00 การชำระเงินต้องการให้ Redis รวดเร็วอยู่เสมอ Shopify ย้ายการจองสินค้าคงคลังไปที่ MySQL โดยใช้หนึ่งแถวต่อหนึ่งหน่วยใน กลุ่มที่จำกัด ทำไมถึงเลือก MySQL? คุณจะข้ามการล็อกได้อย่างปลอดภัยได้อย่างไร? นี่คือ The Daily Diff, เบื้องหลัง แล้วทำไมคำสั่งค้นหาที่รวดเร็วยังคงชนเพดาน? Shopify เป็นแพลตฟอร์มอีคอมเมิร์ซสำหรับการขายออนไลน์และหน้าร้าน Redis เป็นฐานข้อมูลในหน่วยความจำ

0:21 MySQL เป็นฐานข้อมูลเชิงสัมพันธ์ และ Shopify ได้เก็บข้อมูลบัญชีสินค้าคงคลังไว้ ที่นั่นอยู่แล้ว การจองจะกักตุนสินค้าไว้ชั่วคราวขณะที่ผู้ซื้อชำระเงิน

### ทำไมร้านค้าสองแห่งถึงมีความเสี่ยง?

0:29 โมเดล Redis ของพวกเขาจะลดจำนวนตัวนับสินค้า การเรียกร้องคำสั่งซื้อที่ชำระเงินแล้วหมายถึงการอัปเดตบัญชี MySQL และการล้าง Redis การเขียนที่แยกกันเหล่านั้นอาจทำให้สินค้าถูกขายซ้ำสองครั้งหรือไม่พร้อมใช้งานทั้งที่ควรจะ ขายได้ โมเดลเก่าขาดความเข้าใจเรื่องสถานที่ตั้งด้วย การเปลี่ยนมาใช้ใหม่จะต้องเลือกสต็อกจากที่ไหนสักแห่งที่สามารถจัดส่งคำสั่งซื้อได้ คลังสินค้าที่อยู่ผิดทวีปทำให้รายการฐานข้อมูลยอดเยี่ยมและ คำสัญญาในการจัดส่งที่แย่มาก ความพยายามในการใช้ MySQL ก่อนหน้านี้ใช้แถวปริมาณ ดังนั้นการชำระเงินที่แข่งขันกันจึงเข้าคิวที่

### หน่วยที่ล็อกได้กลายเป็นอะไร?

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

### จะเกิดอะไรขึ้นเมื่อกลุ่มว่างเปล่า?

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

1:35 การย้อนกลับจะยกเลิกการเปลี่ยนแปลง การจองจะยังคงอยู่หลังจากการประมวลผลการชำระเงินในสถานะที่จัดเก็บไว้ การชำระเงินที่สำเร็จจะอ้างสิทธิ์ในบัญชีและลบการจองแบบอะตอมมิค การล็อกฐานข้อมูลไม่จำเป็นต้องดูแลแบบฟอร์มการชำระเงิน คีย์หลักแบบคอมโพสิตของพวกเขาเริ่มต้นด้วยร้านค้า, สินค้า กลุ่ม, แล้วตามด้วยรหัสหน่วย การจับคู่การค้นหาช่วยลดการล็อกดัชนีในโปรโตไทป์ของพวกเขา พวกเขายังใช้ read committed เพื่อหลีกเลี่ยง gap locks ที่บล็อกการเติมสินค้าในกลุ่ม

1:57 และลำดับตารางที่สอดคล้องกันเพื่อป้องกันการรอคอยแบบวงกลม ตัวอย่างที่เผยแพร่บันทึกเวลาหมดอายุ การชำระเงินที่ถูกละทิ้งจำเป็นต้องมีการปล่อยสต็อกในที่สุด มิฉะนั้นตะกร้าสินค้าจะกลายเป็น เจ้าของที่ดิน โพสต์ของ Shopify ไม่ได้ระบุอัลกอริทึมการล้างข้อมูลนั้น ดังนั้นแผนภาพนี้แสดงข้อกำหนดของวงจรชีวิต นี่คือปัญหา

### SKIP LOCKED ละเว้นอะไรไปบ้าง?

2:14 Skip locked ไม่รวมแถวที่ถูกล็อก ดังนั้นคู่มือจึงเรียกผลลัพธ์ว่าเป็นมุมมองที่ไม่สอดคล้องกัน มันไม่ได้ให้การนับสต็อกที่สมบูรณ์หรือการหมุนเวียนที่เป็นธรรม เก็บการตัดสินใจเรื่องความพร้อมใช้งานและกฎการเติมสินค้าไว้รอบๆ

### ขีดจำกัดที่แท้จริงอยู่ที่ไหน?

2:26 แล้วเพดานนั้นล่ะ? โค้ดการชำระเงินอื่นกำลังถือการเชื่อมต่อฐานข้อมูลนานเกินไป Shopify ติดแท็กผู้เรียกและวัดระยะเวลาการถือครองการเชื่อมต่อ จากนั้นจึงทำความสะอาดเส้นทางการชำระเงินและตรวจสอบการทำงานพร้อมกันของเธรดอีกครั้ง การค้นหาที่รวดเร็วยังสามารถเข้าคิวนอกการค้นหาได้

### ทำไมฉันถึงจะส่งมอบการออกแบบนี้?

2:38 พวกเขาเขียนเงาทั้งสองระบบโดยให้ Redis เป็นผู้มีอำนาจ เปรียบเทียบผลลัพธ์ แล้วสลับไปทีละน้อยด้วยสวิตช์ปิด คำตัดสินของฉันคือ SHIP IT ฉันจะจัดส่งขอบเขตธุรกรรมที่ใช้ร่วมกันและการเปิดตัวที่สามารถย้อนกลับได้นั้น โดยมีเส้นทางการชำระเงินทั้งหมดที่ได้รับการตรวจสอบ มีคำถามเกี่ยวกับเรื่องนี้หรือไม่? ใส่ไว้ในความคิดเห็น และนั่นคือความแตกต่างสำหรับวันนี้

2:54 ฉันชื่อ Niko จาก Axrisi รวมอย่างรับผิดชอบ

## แหล่งที่มา

- [We replaced Redis with MySQL for inventory reservations—and it scaled](https://shopify.engineering/scaling-inventory-reservations) — Shopify Engineering — Emilie Noel
- [Simplified reservation SQL embedded in Shopify's article](https://gist.github.com/CourtneySymons/cb5ecbe86331047aae166d5b1f1d555c) — Shopify Engineering / CourtneySymons on GitHub Gist
- [MySQL 8.0 — Locking Reads](https://dev.mysql.com/doc/refman/8.0/en/innodb-locking-reads.html) — Oracle / MySQL Reference Manual
- [MySQL 8.0 — Transaction Isolation Levels](https://dev.mysql.com/doc/refman/8.0/en/innodb-transaction-isolation-levels.html) — Oracle / MySQL Reference Manual
- [What Is Shopify and How Does It Work?](https://www.shopify.com/blog/what-is-shopify) — Shopify
- [Redis quick starts](https://redis.io/docs/latest/develop/get-started/) — Redis documentation
- [What is MySQL?](https://dev.mysql.com/doc/refman/8.0/en/what-is-mysql.html) — Oracle / MySQL Reference Manual
