Archive for the ‘case study’ category

Starbucks ไม่ใช้ 2-phase-commit

August 25th, 2010

แปลมาจาก 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! ”

Richardson Maturity Model: 3 สามขั้นสู่สุดยอด REST

April 1st, 2010

แปลมาจาก Richardson Maturity Model: 3 steps toward the glory of REST

Contents
Level 0
Level 1 – Resources
Level 2 – HTTP Verbs
Level 3 – Hypermedia Controls
The Meaning of the Levels
ถ้าเราพิจรณาเนื้อหาของหนังสือ REST In Practice แล้วพบว่าใจความสำคัญของหนังสือเล่มนี้คือการอธิบายถึงความสามารถของ RESTFul Web Services ที่เข้ามาช่วยเราในการแก้ปัญหาเรื่องของการ Integration ขององค์กรระดับ Enterprise กำลังเผชิญอยู่ โดยที่ใจความหลักของหนังสือเล่มนี้ได้อธิบายว่า “เวบ” เป็นสิ่งที่แสดงให้เห็นถึงความสามารถในการ scale ระบบที่ใหญ่มากๆและมันก็ยังทำงานได้ดี ทำให้เราสามารถดึงเอาแนวคิดสำคัญๆจาก “เวบ” เพื่อนำมาประยุกต์เข้ากับระบบของเราได้ เพื่อทำให้ระบบของเรา scale ได้ง่ายและมีปนะสิทธิภาพเหมือนกับ “Web”
» Read more: Richardson Maturity Model: 3 สามขั้นสู่สุดยอด REST

Ajax Simplifications in Spring 3.0

February 17th, 2010

แปลและย่อมาจากจาก Ajax Simplifications in Spring 3.0
Spring and Ajax Overview
จุดประสงค์สำหรับ Entry นี้คือการสาธิตการทำงานแบบ Aynchronous ระหว่าง JavaScript (jQuery, Dojo) และ SpringMVC 3.0 เพื่อให้เห็นความสามารถใหม่ใน Spring3 เนื่องก่อนหน้านี้ Spring เองไม่มีฟีเจอร์ในเรื่องของ
การทำงาน Ajax Remoting ในตัวมันเองทำให้ต้องเลี่ยงไปใช้ไลบารี่เช่น DWR เข้ามาช่วยแต่ช่วงหลังๆการส่งข้อมูลแบบ RESTful-JSON เป็นที่นิยมมากขึ้นทำให้ Spring3 ได้เตรียมความพร้อมในเรืองนี้มาให้เลย โดย Spring3
สามารถทำการสร้าง response ที่เป็น JSON ได้นอกจากนี้ยังสามารถ Bind JSON Parameter กลับมาเป็น Java Object ได้ด้วยเลยซึ่งจะแสดงให้เห็นตัวอย่างในส่วนต่อไปของเนื้อหา

MVC Ajax Sample
ตัวอย่าง ที่จะใช้ใน Entry นี้นั้นสามารถ export ได้จาก https://src.springframework.org/svn/spring-samples/mvc-ajax/trunk/ โดยหลังจากได้ sourcecode มาแล้วเราสามารถลอง deploy และลองเล่นได้เลยครับโดยสามารถ pack
เป็น WAR แล้วค่อยนำไป deploy ได้เลยหรือจะใช้บริการ Embeded Jetty ก็สามารถทำได้ด้วยการเพิ่ม plugin เข้าไปใน pom.xml ดังนี้ครับ

    <build>
        <plugins>
            <plugin>
                <groupid>org.mortbay.jetty</groupid>
                <artifactid>maven-jetty-plugin</artifactid>
            </plugin>
	...
	...
	...
       </plugins>

หลังจากเพิ่ม pluging แลัวเราก็พิมพ์ mvn jetty:run ได้เลยครับ
» Read more: Ajax Simplifications in Spring 3.0

SpringMVC: ตอนหนทางของ Request กว่าจะมาเป็น Response

November 21st, 2009

ใครเคยเขียน SpringMVC มาบ้างคงพอจะผ่านๆตามาบ้างกับ 6 ส่วนประกอบนี้
ซึ่งเมื่อจับมาวาดเป็นแผนภาพ ก็จะทำให้เข้าใจได้มากขึ้น
Diagram1
เริ่มต้นกันเลยดีกว่า

  1. มีใครสักคนส่ง Request เข้ามา ด่านแรกที่ต้องเจอคือ DispatcherServlet ถูกคอนฟิกไว้ใน web.xml ถ้า Reqest ตรงกับ url-pattern ที่กำหนด DispatcherServlet นี้ก็ทำงานไป
    * เรื่องชื่อของ DispatcherServlet ที่กำหนดไว้ก็สำคัญจะกล่าวต่อไป(รอไปก่อน)
  2. Request ที่เข้ามาถูกส่งไปตีความที่ HandlerMapping ว่า Controller ไหนจะเป็นผู้รับกรรมดี
    HandlerMapping มีอยู่หลายตัวเลือก ถ้าไม่เลือกเลย SpringMVC เองมีค่าพื้นฐานอยู่แล้วคือ BeanNameUrlHandlerMapping คู่กับ DefaultAnnotationHandlerMapping (สำหรับ Java5+) เขียนไปเดี่ยวก็งงมาดูตัวอย่างการใช้ BeanNameUrlHandlerMapping กันหน่อย

    <bean name="/home" class="com.springmvc.test2.mvc.HomeController" />
    

    อ่านชื่อของ BeanNameUrlHandlerMapping ก็คงพอรู้ว่ามันแมพกับ Controller ยังไง นั่นก็คือใช้ชื่อของ bean นั่นเอง

  3. หลังจาก DispatcherServlet รู้แล้วว่าเป็น Controller ตัวใด DispatcherServlet จะรอช้าอยู่ใย Controller ตัวนั้นก็ถูกเรียกทำงาน ผลลัพธ์จากการทำงานที่ได้คือ ModelAndView
  4. ModelAndView ประกอบด้วยสองส่วนคือ ชื่อของ View ซึ่งจะไปหากันต่อไปว่าชื่อที่ระบุนี้ตรงกับ View ตัวไหน ส่วน Model คือแมพอ็อพเจคที่จะเอาไปแสดงผลบน View
  5. หลังจากได้ชื่อ View มาแล้ว จะนำชื่อไปตีความที่ ViewResolver ซึ่งทำหน้าที่คล้ายคลึงกับ BeanNameUrlHandlerMapping คือแมพชื่อ View เข้ากับ View
  6. ตัวอย่างการแมพชื่อเข้ากับ View

    <bean name="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    
    	<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
    
    	<property name="prefix" value="/WEB-INF/jsp/"/>
    
    	<property name="suffix" value=".jsp"/>
    
    </bean>
    

    Screenshot

  7. สั่งให้ View เรนเดอร์ผลลัพธ์เป็นอันจบ การเดินทางของ Request กว่าจะมาเป็น Response ได้เดินทางมาจนถึงจุดจบที่นี่เอง
  8. หมายเหตุ HandlerMapping และ ViewResolver สามารถเซ็ตการทำงานได้ในลักษณะของโช่(chain) คือมีได้หลายตัวสามารถเซ็ตลำดับผ่าน property order ไว้ต่อตอนหน้า
    หมายเหตุ2 ใครใช้ SpringMVC แบบ Annotation อาจไม่ได้เห็นภาพตรงตามนี้เนื่องจาก SpringMVC แบบ Annotation ช่วยลดข้อยุ่งยากในการคอนฟิก และที่เห็นชัดๆเลยคือการสร้าง Controller ตัดการ implements หรือ extends คลาสที่น่าสับสนออกไป ถ้าจำไม่ผิด Controller แบบเดิมมีตั้ง 7 ชนิด

Picture Credit: SpringInAction2