สรุป Talk: Managing Data in Microservices


       ถ้ามีเวลาซัก 1 ชม. แล้วขี้เกียจอ่านที่ผมเขียนไปฟังของจริงเลยครับที่ https://www.infoq.com/presentations/microservices-data-centric Talk นี้เป็น Talk ที่พูดถึงการจัดการข้อมูลใน Microservice ที่ดีมากๆ Talk นึงเลย Randy Shoup เป็น CTO อยู่ที่ Stichfix (เคยอยุ่ Google กับ Ebay) มาก่อน Talk นี้จริงๆ พูดถึงเรื่องเกี่ยวกับ Microservice หลายเรื่องมาก แต่หลักๆ คือพูดเรื่องการจัดการ Data (จริงๆ แค่ 20 นาทีสุดท้าย) ซึ่งแบ่งเทคนิคออกเป็น 3 เทคนิคใหญ่ๆ


Shared Data

       อันนี้เค้าเปรียบเทียบก็คือเรื่องการ shared table view ใน monolith มันง่ายมากๆ แต่พอเรา extract service ออกมาเป็น microservice เรื่องนี้ก็กลายเป็นเรื่องลำบากขึ้นมาทันที ทีนี้มันก็เกิดคำถามขึ้นว่า แล้ว shared data จะไปอยู่ตรงไหนในโลกของ microservice เค้าเลยไล่ไปถึง ทฤษฏี Single System of Record คือ 1 service จะเป็นเจ้าของ data หนึ่งๆ ที่ใช้โดย service อื่นๆ ทุก copy ของข้อมูลนี้จะอยู่ในโหมด read only หรือ cache เท่านั้น ซึ่งมันก็มีวิธีทำ Shared data อยุ่สองสามแบบคือ

  1. Synchronous lookup คือ service A เป็นเจ้าของ data แล้ว service B จะใช้ data นั้นจะต้องเรียก service A แบบ real time
  2. Async Event + Local cache อันนี้จะแก้ปัญหาข้อ 1 ถ้าการเรียก service A แบบ real time นั้นแพงไป (latency หรือ resource)  โดยจะทำการ store data ของ service A ไว้ใน service B  แล้วถ้าเกิดการอัพเดทใน service A ให้ service A ส่ง Event มาอัพเดท data ใน service B ด้วย ถ้ามองง่ายๆ ผมมองว่ามันคล้ายๆ Publish / Subscribe pattern เลย
  3. Shared metadata library วิธีนี้เหมาะกับ data ที่มันไม่ค่อยเปลี่ยนบ่อยๆ เช่น จังหวัด, ค่าสี, ขนาด schema อะไรก็ตามที่เป็น immutable data พวกนี้จะแชร์ผ่านทาง library เอาโดยไม่ต้องใช้วิธีที่ 1 หรือ 2 อันนี้พอดุแล้วรู้สึกเต็มๆ ว่าบางครั้งเรามอง microservice เป็นปัญหาที่ยาก ทั้งที่จริงๆ วิธีง่ายๆ แบบนี้ก็แก้ได้เหมือนกัน

Joins

       พูดถึงเรื่อง Join ถ้าเป็น monolith นี่มันง่ายมากๆ เพราะข้อมูลมันอยู่ที่เดียวกันหมด แต่พอแยก microservice ก็ลำบากอีก เหมือนข้อข้างบน แต่ก็มีวิธีแก้ปัญหาเรื่องนี้อยู่สองสามวิธี

  1. Join in Client Application วิธีคือ เราเรียก data จาก service A มาตัวนึง แล้ว query matching จาก data ของ service B วิธีนี้เหมาะกับการ Join แบบ Single A, multiple B หรือ 1:N Join ซึ่งระบบส่วนใหญ่ก็ทำแบบนี้ ผมก็ทำ
  2. Materialize the view วิธีนี้เกิดมาเพื่อแก้ปัญหาข้อ 1 ถ้าข้อหนึ่งมันแพงไป โดยจะใช้ Materialize View ที่รอ event จาก 2 service ที่ต้องการ join วิธีนี้เหมาะกับ high cardinality A and B หรือ M:N join ซึ่งส่วนตัวก็เคยทำเพราะมันเร็วกว่าจริงๆ พวก RDBMS, search engine, log ทำได้หมดแต่ก็มีข้อเสียคือ มัน Maintain ยากอยู่เพราะว่ามันอยู่นอกชั้น application

Workflows and Sagas

       อันนี้พูดถึงเรื่อง transaction ระหว่างหลายๆ entities ซึ่งแน่นอนใน monolith เราคุม atomic transaction ได้ง่ายมาก แต่พอเป็น microservice เอ่อ ผมต้องพูดเหมือนข้างบนมั้ย ทีนี้วิธีการจัดการเนี่ย เค้าเลยมองว่าตัว Transaction เนี่ยเป็น Saga หรือมอง transaction เนี่ยเป็น state machine ของ event เล็กๆ ที่ต่อเนื่องกัน (ผมก็ไม่ค่อยเข้าใจ Saga เท่าไร) โดยจะมองระบบว่าเป็น Workflow ที่ประกอบด้วย transaction แยกจากกันจากแบบ A -> B -> C -> D เวลาเกิดการ Rollback operation ก็จะ apply กลับด้าน workflow เป็น A <- B <- C <- D อะไรประมาณนี้ หลายๆ ระบบทำแบบนี้เช่น Payment processing แล้วเค้าพูดเลยไปถึงอีกว่าถ้าเป็น function as a service หรือ serverless เนี่ยมันทำ workflow แบบนี้ง่ายเพราะมันเล็กอยุ่แล้วในตัวและ stateless และก็ถูก trigger โดย event โดยธรรมชาติอยุ่แล้ว

       ช่วงถามตอบมีคำถามที่ดีมากเค้าถามว่า In Distributed system, How should we dealing with event come multiple time or out of order ?  ซึ่งก็จะมีวิธี Design แก้ปัญหานี้อยู่ 2 แบบคือ at least one delivery หรือ at most once delivery ซึ่งแบบหลังเค้าไม่ได้พูดถึง

       At least one delivery คือ receiver จะรับ event แค่ 0 หรือ 1 ครั้งเท่านั้น ถ้าเกิดอะไรที่ทำให้ส่งไม่ได้ขึ้น sender จะต้องทำการส่งอีกครั้ง วิธีนี้ก็จะเกิด 2 ปัญหาให้แก้อีกคือ
- ปัญหาแรกคือฝั่ง receiver ได้รับ event multiple time ซึ่งวิธีแก้พูดง่ายมาก แต่ก็ทำยากคือทำให้ Receiver มีคุณสมบัติของ Idempotency พูดง่ายๆ คือ ทำทุกครั้ง เหมือนเดิมทุกครั้ง
-  ปัญหาที่สองคือฝั่ง receiver ได้รับ event ไม่ถูก order เค้าแนะนำว่าถ้า care about order จริงๆ วิธีแก้คือต้อง maintain state ที่ฝั่ง consumer side ด้วย ยกตัวอย่างเช่น receiver ได้รับ delete event ก่อน create event วิธีนี้ไม่รู้ว่า data store ตัวอื่นมีวิธีแก้ปัญหามั้ยแต่ Cassandra มีคอนเซปที่เรียกว่า tombstones อยู่โดย มันจะ delay การ delete instance ไว้ซักพักก่อนที่จะทำจริงๆ อะไรประมาณนี้

       จริงๆ ใน Talk นี้มีเรื่องอื่นๆ ด้วยเกี่ยวกับ Software Development เช่น Small Team, TDD and CD และก็ DevOps รวมถึงการ Extract microservice ซึ่งเค้าก็พูดดีมาก แต่ผมโฟกัสตรง manage data in microservice มากกว่าเลยไม่ได้สรุปไว้ อ่อสุดท้าย link ของ Talk ถ้าลืมมองข้างบนไปก็ตามนี้เลยครับ


Comments