แปลมาจาก Starbucks Doesn’t use two phase commit
Hotto Cocoa o Kudasai
ผมเพิ่งกลับมาจากทริปญี่ปุ่นได้สองสัปดาห์ ระหว่างการเดินทางที่ญี่ปุ่นครั้งนี้มีสิ่งหนึ่งที่ผมคุ้นตามากมันคือสัญลักษณ์รูป ทรงกลมเขียวอันเป็นเอกลักษณ์ของ Starbucks นั่นเองโดยเฉพาะแถวๆเขต Shinjuku และ Roppongi และระหว่างที่ผม รอรับเครื่องดื่ม “Hotto Cocoa” ของผมผมก็สังเกตเห็นอะไรบางอย่างในกระบวนการจัดการ Order ของ Starbucks แนวคิดหลักของ Starbucks และธุรกิจอื่นๆคือการรับ Order ให้ได้มากที่สุดเท่าที่จะมากได้เพราะยิ่งรับ Order มากเท่าไหร่มันหมายถึงรายได้ที่เพิ่มขึ้นมาตามจำนวน นั่นเป็นสาเหตุให้ Starbucks เลือกใช้กระบวนการจัดการ Order แบบ Asynchornous ถ้าเราลองนึกภาพตามการสั่งกาแฟที่ Starbucks จะเริ่มจากเราสั่งกาแฟที่ cashier จากนั้น cashier จะจดรายการนั้นลงไปที่แก้วแล้ววางไว้ที่ Queue ระหว่างเครื่องชงซึ่ง Queue นี้เป็นปัจจัยหลักที่ทำให้ Cashier สามารถทำงานเป็นอิสระ (Decouple) จาก Barista ซึ่งจะทำให้ Cashier สามารถรับ Order ต่อไปได้เรื่อยๆโดยไม่ต้องสน ใจว่า Barista จะยุ่งขนาดไหนหรือเราสามารถมีจำนวน Barista ที่เพิ่มขึ้นได้ในกรณีที่ร้านยุ่งมากๆ
Correlation
อย่างไรก็ตามในเมื่อ Starbucks สามารถใช้ประโยชน์ของการจัดการ Order แบบ Asynchronus แล้ว Starbucks เองก็ยังต้องแก้ปัญหาที่มีมากับการทำงานแบบ Async เช่นเรื่องของ Correlation เนื่องจากกาแฟที่เราสั่งไปไม่สามารถทำ ให้เสร็จได้ที่ cashier เลยนั่นหมายความว่ามันต้องถูกส่งต่อไปให้ Barista เป็นคนทำ และในกรณีที่เรามี Barista หลายๆคนแต่ละคนก็อาจจะต้องทำงานกับเครื่องชงกาแฟหลายๆแบบผมที่ตามมาคือระยะเวลาในการทำจะไม่ท่ากันเช่นกาแฟที่ต้อง Blend ต้องใช้เวลานากว่ากาแฟสำเร็จ หรือ Barista อาจจะทำการรวบ Order หลายๆอันมาทำในครั้งเดียว กันเพื่อเพิ่มความเร็วในการทำงาน ผลคือปัญหาเรื่อง Correlation จะเกิดขึ้นเพราะการส่งกาแฟออกมาจะไม่ตรงตาม ลำดับของการสั่ง ซึ่ง Starbucks แก้ปัญหานี้ด้วยการใช้ pattern ที่อยู่ในกลุ่มของ messaging architecture นั่นคือ Correlation Identifier เราจะเห็นได้จากจังหวะการสั่งพนักงานที่ cashier จะจดชื่อของเราลงไปบนแก้วและจะเรียกชื่อเจ้า ของเมื่อ order เสร็จแต่ในบางประเทศอาจใช้ชื่อเครื่องดื่มแทน แต่ยังยังไม่พอยังมีอย่างอื่นอีกนั่นคือ Exception Handling
Exception Handling
การทำ Exception Handling ในมุมของ Async เป็นเรื่องยากระดับคลาสสิค ดังนั้นเพื่อให้เคสนี้ต่อเนื่องกันเราจะมาดูวิธี การจัดการกับ Exception ของ Starbucks กัน เร่ิมจากการยกตัวอย่าง พนักงานจะทำอย่างไรถ้าเราไม่สามารถจ่ายเงินได้ ? การแก้ปัญหาคือเททิ้งถ้ากาแฟแก้วนั้นทำเสร็จแล้ว หรือถ้ายังก็ทำแค่เพียงดึงแก้วออกจาก Queue แต่ถ้ากาแฟถูก ทำผิดไม่ตรงตามคำสั่งพนักงานก็ทำใหม่ แต่ถ้าเครื่องทำกาแฟพังก็ไม่ยาก “คืนเงิน” นี่เป็น Scenario มาตรฐานที่เกิดเสมอในร้านกาแฟแต่ถ้าเราจัดกลุ่มการทำงานเราจะพบว่าเราสามารถจำแนกได้ตามนี้
1.Write-off – นี่เป็นการจัดการกับปัญหาที่ตรงไปตรงมาและง่ายที่สุดคือ “ปล่อยมันไป” แนวทางนี้นิยมมากกับปัญหาที่ไม่ส่งผลกระทบกับรายได้มากนักและไม่คุ้มที่จะสร้างระบบที่ใช้จัดการ Exception ยกตัวอย่างเช่น ISP บางเจ้าจะไม่สนใจ Error ที่เกิดขึ้นในขั้นตอนของการทำ Billing/Provisioning ดังนั้นจึงมีความเป็นไปได้ที่ลูกค้าจะได้ใช้บริการโดยไม่ถูกเรียกเก็บเงิน เนื่องจากรายได้ที่เสียไปไม่กระทบกับภาพ รวมของระบบทั้งหมด อย่างไรก็ตามสุดท้ายจะมีการสร้าง report สำหรับการทำ reconciliation ตามเวลาที่กำหนดเพื่อปิดบริการฟรีเหล่านั้น
2.Retry – order ใหญ่เกิดขึ้นจากการประกอบของ order ย่อยๆ เรามีทางเลือกสองทางคือหนึ่งยกเลิกอันที่ทำไปแล้ว หรือพยายามทำอันที่ล้มเหลวจนสำเร็จ ทางแรกเป็นทางเลือกที่ดีในกรณีที่ความเป็นไปได้ในการทำใหม่ให้สำเร็จ สูงมาก ซึ่งเราสามารถนำเอาแนวคิดเรื่อง Idempotent Receiver เข้ามาใช้ได้คือไม่ว่าเราจะพยายามทำ order เก่าซ้ำกันกี่ครั้งก็ตาม เราจะไม่เจอปัญหาเรื่อง duplicate message เลย
3.Compensating Action – ทางเลือกสุดทายคือ undo งานที่ทำเสร็จแล้วเพื่อทำให้ ระบบย้อนกลับไปสู่สถานะเดิม ทางเลือกนี้เหมาะสมกับระบบที่รองรับการทำานในเรื่องของการทำ re-credit ได้
เราจะเห็นว่าการรับมือกับ Exception แบบนี้ต่างกับ two-phase commit เนื่องจาก asynchronous จะทำการแยก prepare และ excecute ออกจากกันถ้าดังนั้นถ้าเรามองกลับไปที่ Starbucks เราจะพบว่าเราจต้องรอที่ cashier พร้อมกับ reciept และเงินจนกว่ากาแฟจะชงเสร็จ ซึ่งจะเห็นได้ว่าในกรณีนี้ทั้ง cashier และลูกค้าจะไม่มีใครสามารถละจากตำแหน่ง ของตัวเองได้เลยจนกว่า Transaction นั้นจะสำเร็จ ซึ่งถ้า Starbucks เลือกใช้เทคนิคแบบ Two-Phase-Commit กับธุรกิจ ตัวเองมันอาจจะส่งผลให้เกิดการขาดทุนหรือล้มเหลวได้สูงมากเนื่องจากระบบจะไม่สามารถรองรับจำนวนลูกค้าได้เป็นปริมาณมากๆ นี่จึงเป็นอีกหนึ่งตัวอย่างที่เราจะเห็นได้ว่า Two-Phase-Commit ทำใหชีวิตเราง่ายขึ้นแต่มันก็ทำให้เราไม่ สามารถเป็นอิสระจากกระบวนการส่ง message ได้เนื่องจากเราต้องจัดการ state ของระบบไปตลอดเวลา
Conversations
ตัวอย่างของการมีปฎิสัมพันธ์กันในร้านกาแฟเป็นตัวอย่างที่เหมาะกับ Conversation Pattern มากๆซึ่งเราจะเห็นได้ว่าจริงๆแล้วการสื่อสารระหว่างคนสองกลุ่มนี้ประกอบไปด้วย Short Synchronous เช่นการทำ order และการจ่ายเงินและอีกส่วนคือ Long Asynchronous เช่น การทำกาแฟและการรับกาแฟ ซึ่งเราสามารถนำกระบวนการที่เกิดขึ้นนี้ไปประยุกติ์ใช้กับการทำธุรกรรมแบบอื่นๆอีกก็ได้เช่นกันเช่น การสร้าง order ใน amazon เราจะเห็น short synchronous เช่นการกำหนด Order Number ส่วนกระบวนการที่เหลือจะกลายเป็น Asynchronous ทั้งหมดไม่ว่าจะเป็น charging, packaging และ shipping หลังจากนั้นเราจะได้รับอีเมล์ยืนยันจาก amazon ทันทีเมื่อการทำ Transaction สำเร็จลง และในกรณีที่เกิดปัญหานั้น Amazon จะแจ้งเตือนเราผ่าน email (Async) หรือแม้กระทั่งกระบวนการ Refund ก็ทำในลักษณะเดียวกันไม่ว่าจะเป็นการจ่ายเงินคืนหรือการพยายามส่งสินค้าชิ้นใหม่แทนชิ้นเก่าที่ส่งไม่สำเร็จ
สรุปว่าในโลกแห่งความเป็นจริงเราจะเห็น Scenario ต่างๆที่เป็น Asynchronous มีมากมาย ในกระบวนทำงานต่างๆของเราไม่ว่าจะเป็นการอ่าน การตอบ email การซื้อกาแฟ ดังนั้น asynchronous messaging architecture จึงเป็นรูปแบบที่สามารถนำไปใช้งานได้อย่างเป็นธรรมชาติมากกว่า เราสามารถนำเอากระบวนการในชีวิตประจำวันของเรามาช่วยเพื่อให้เกิดความสำเร็จในการออกแบบเรื่องของ messaging ได้เป็นอย่างดี “Domo arigato gozaimasu! ”


