If God Built Netflix

ผมพยายามเขียนบล็อคนึงมาหลายปีแต่ก็ไม่เคยตกผลึกเขียนจบสักที

section ใหญ่ๆ ในบล็อคนั้นคือ ถ้าพระเจ้าสร้าง Netflix มันจะ design ระบบมายังไงกันนะ

เพราะในช่วงนั้น Microservice กำลังอยู่ในช่วงบูม gut feeling ผมบอกว่า microservice มันไม่ถูก แต่ไม่รู้ว่าที่ถูกต้องทำยังไงเลยไปนั่งคิดอยู่ว่าถ้าออกแบบระบบโดยมีเวลาไม่จำกัด มีเงินไม่จำกัด และทีมพัฒนาเทพมากไม่ต้องกังวลว่าจะเกิด feature creep มันจะออกมาหน้าตายังไง


ช่วงนี้ได้กลับไปดูคนอื่นแก้ module ที่เคยถือก่อนหน้านี้

module นี้ผมก็อยู่ในทีมก่อตั้งเลย แต่ตอนนั้นดูฝั่ง client side เลยไม่ค่อยรู้เรื่องว่ามัน design มายังไง จนตอนหลังมาปะติดปะต่อภาพแล้วเข้าใจว่าไอเดียของมันคือจะมี API กลางตัวนึงซึ่งมันแทบจะเป็น REST API ให้ database เลยแหละ แล้วก็ handle authn/authz ต่างๆ และ API นี้จะไม่รู้จัก module ที่เป็น UI เลยจะรู้จักแต่ module ที่ provide service เพื่อ implement feature ของมันเท่านั้น

ในฝั่ง UI ด้านนอกก็จะทำหน้าที่แทบจะเป็น API Gateway แค่นั้นไม่ได้มี logic อะไรเพิ่มนอกจาก map field ต่างๆ

ปัญหาก็คือบางครั้ง UI อยากจะทำ push notification เมื่อ object change ซึ่งเนื่องจาก API กลางจะไม่รู้จักกับ UI module เลยจะ push ไป trigger ไม่ได้ ก็ต้องส่ง message เข้าไปใน message queue ว่ามีการ change แล้ว แล้วใครอยากได้ก็อ่านไป ใน message เองก็จะไม่ได้ระบุว่า change อะไรบ้างส่งมาแต่ snapshot ของ object ที่เวลานั้นๆ

Design นี้ถ้าเคยศึกษา Kubernetes ก็น่าจะพอ map ได้เลยว่า API กลางเหมือน kube-apiserver แล้ว UI ก็คือพวก controller/operator ต่างๆ ซึ่งก็ถือว่าทันสมัยมากเพราะในตอนนั้น Kubernetes ยังเป็นของใหม่มากๆ และคิดว่าทีมก็ยังไม่ได้ศึกษา design ของ Kubernetes มาก่อน แต่มันก็เป็นไปตามหลัก microservice design

ที่จะแตกต่างกันคือ Kubernetes จะมีส่วนเก็บ status ของ object ที่ให้ controller สามารถเขียน state กลับไปได้ ทำให้ controller ทุกตัวเป็น stateless ได้หมด แต่โปรแกรมนี้ไม่ได้คิดไปถึงตรงนั้น

ฟีเจอร์แรกๆ ที่ต้องยิง callback ผมจำได้ว่าใช้วิธีเปิด Redis ของ UI module ตัวนั้นมาเก็บ state ส่วนตัว พอมาฟีเจอร์ที่สองบนอีก UI module หนึ่ง คนที่ออกแบบก็เลือกจะเอา API กลางยิงออกไป 3rd party แทนแล้ว ผมก็ยังไม่แน่ใจว่าทำไมเลือกใช้ design แบบนี้ในตอนนั้น

หลังจากนั้นแล้วผมก็ทิ้งหายจาก module นี้ไปนาน ทีมที่เขียนก็แยกย้ายกันไป บางคนก็ยังอยู่ในบริษัทแต่ทำหน้าที่อื่นๆ แล้ว จนกระทั่งผมได้กลับไปดู UI module ตัวนึงซึ่งทีมปัจจุบันไม่มีคนดู ปัญหาใหญ่ๆ ที่ผมเห็นคือมัน scale ไม่ได้และห้าม restart ด้วยเพราะมันเก็บ state ใน memory ตอนนั้นถึงเข้าใจว่า design ของระบบจริงๆ เค้าคิดอะไรอยู่

หนึ่งปีให้หลัง ทีมปัจจุบันเข้ามาแก้เพิ่มฟีเจอร์ใน UI module นั้น ผมรีวิวแล้วก็เพิ่งรู้ตัวว่า design ของระบบนี้มันเปลี่ยนไปเยอะมากเพราะทีมใหม่คุ้นชินกับการที่ทำฟีเจอร์ใหม่เป็น explicit เกือบหมด อยากได้อะไรก็ยิงไปบอกคนนั้นว่าให้ทำแบบนี้ ซึ่งมันเขียนง่ายขึ้นเยอะแต่ service ก็จะพันกันหมด


ถามว่าถ้าตอนนั้นไปลอก design แบบ Kubernetes มาคือแก้ให้ API กลางช่วย module อื่นเก็บ state ได้มันจะแก้ปัญหานี้มั้ย?

ผมก็ยังคิดว่าปัญหามันยังไม่จบนะ ถ้าดูจาก Kubernetes เองก็จะเห็นว่า API บางอย่างมันจำเป็นต้องมี flow explicit action จริงๆ เช่นขอดู log ที่ถ้าทำเป็น implicit แล้ว kubelet ต้อง stream log ไปที่ API server ตลอดเวลา หรือ API server ต้องมี Kubelet log URL เพื่อให้ client ไปยิงเป็น explicit กันเอง ก็เป็นปัญหา network security อีก และอย่างคำสั่ง exec นี่คงจะไม่มีทางเลี่ยง ยังไงก็ต้องเปิด channel ตรงๆ

นอกจากนี้ Kubernetes design ยังทำให้เกิด traffic ในการ polling เยอะ ก็จะเห็นว่า Kubernetes เริ่มติด scaling limit ระดับหลายพัน node ที่ API Server กินทรัพยากรจำนวนมาก

สำหรับ project ที่เล่าไปนี้ design ปัจจุบันที่ยิง action ตรงๆ ผมว่ามันเป็นอะไรที่ตรงไปตรงมา น่าเบื่อ แต่มันก็เหมือนจะเป็น system design ที่ผ่านการพิสูจน์มานานแล้ว ถ้าไม่กังวลปัญหาใหม่ๆ อย่าง microservice design ก็ดูเหมือนจะเป็น solution ที่น่าสนใจ


ผมเล่าเรื่องถ้าพระเจ้าสร้าง Netflix ลงใน Facebook อาจารย์ผมมาอ่านแล้ว comment ว่า

“ถ้าจะแก้ทีนึงก็ต้องสวดชุมนุมเทวดาก่อน”

ผมขำอยู่ปีนึงถึงจะเข้าใจความหมายที่อาจารย์จะสื่อ

Forum

เหมือนว่า Facebook เราจะกลายเป็น Blog ไปแล้ว (แต่อันไหนมีสาระมากๆ ก็จะพยายามไปใส่ใน [Google+](https://plus.google.com/108003073552145737788/posts) ด้วย)

ช่วงปิดเทอมนี้กำลังจะพยายามเขียนเว็บบอร์ดใน [menome](http://menome.sunburn.in.th) อยู่ มันเป็นความคิดชั่ววูบว่าน่าจะเขียนบอร์ดเองและใส่แนวคิดแปลกใหม่ลงไปบ้าง

ผมเองเห็นบอร์ดที่ไอเดียดีมากๆ มาจาก Pantip3G เป็นตัวแรก ตอนนี้มันยังไม่ออก แต่ผมชอบไอเดียของเขาที่ว่ากระทู้ไม่ได้มีแค่กระทู้ไล่ลงมา แต่มันมีกระทู้รายงานสด กระทู้โพสต์รูป ฯลฯ อีก แต่ละแบบการแสดงผลหัวข้อ และโพสต์คำตอบมันต่างกันออกไป

ตอนผมทำ bd2.in.th ก็เคยได้โจทย์นี้ อยากทำ gallery ผมว่ามันเกะกะเลยไม่ทำแล้วทำเป็น gallery tag ไปในบอร์ดแทน ซึ่งจะมีการแสดงที่สวยกว่าเอา img tag เรียงๆ กันทั่วไป แต่นั่นคือสิ่งที่เราทำได้ในเว็บบอร์ดแบบทั่วๆ ไป (traditional forum software)

ต่อมาผมเปลี่ยน bd2.in.th ไปใช้ Vanilla Forum ซึ่งผมเห็นไอ้นี่มานานแล้ว แต่ตอนได้ลองเอง มันเป็นบอร์ดที่ความคิดสดใหม่มาก คือมันเหมือนเฟสบุ๊คในรูปแบบของบอร์ด

– หน้ารวมกระทู้ อันนี้บอร์ดทั่วไปไม่ค่อยมี คือแสดงทุกหมวดรวมกัน
– Profile มี Wall
– ระบบ Messaging มันสุดยอด! เวลา PM มันจะจัดกลุ่มเป็น thread แล้ว thread นึงมีมากกว่า 2 คนได้ สามารถลากคนเพิ่มเข้าไปได้ด้วย
– Notification มันก็เด็ด เหมือนเฟสบุ๊ค เวลามีอะไรมันจะเด้งด้านล่าง หรือจะกดไปดูย้อนหลังก็ได้ สามารถตั้งได้ว่าเด้งแค่ไหน เช่นกระทู้นี้มีคนตอบให้เด้ง อันนี้ผมเอาไปต่อยอดใน bd2.in.th ทำ site wide notification ([บล็อคเก่า](/node/876))
– ระบบ user ยืดหยุ่นมาก LDAP ก็ได้ แต่ที่เจ๋งคือ Facebook/Twitter ก็ได้ แล้วก็ยังมีแบบ Connect plugin ให้ระบบอื่นเป็น auth source เลยก็ได้ (เราใช้กับ WordPress)
– Wall ของเว็บ มีคนเปลี่ยน avatar มีกระทู้ก็จะขึ้น หรือจะไปเขียนเองก็ได้
– Wall comment เป็นแบบเฟส คือ threaded ชั้นเดียว

ผมว่าไอ้นี่อะมันคือชุมชนขนาดย่อมได้เลย โดยเฉพาะ wall ที่ทำให้ชุมชนมันใกล้ขึ้น แต่เสียงส่วนมากจากผุ้ใช้ที่ผมได้ยินคือมันใช้ยาก อันนี้ผมเถียงตายเลย มันไม่ใช่บอร์ดที่คุณชินในฟอร์แมตที่คุณเคยใช้ แต่ผมว่ามันใช้ง่ายกว่าเยอะมาก

ทีนี้มาถึง menome ผมนึกไปถีง Google Wave แล้วว่าเออ ไอ้นี่มันเจ๋ง เหมาะมาทำบอร์ด แต่จะทำแบบนั้นก็ยากไป ผมก็ไม่ไหว (Wave ใช้เวลาเขียนสองปีนะครับ และมันคือเวลาอิสระ 40% ของ Full-time engineer ส่วนผมตอนทำงานชอบคิดว่ามีเวลาแบบนั้นทั้งๆ ที่ไม่มี) ก็เมื่อกี้ผมก็เลยไปสำรวจบอร์ดอนิเมะที่ดังๆ อย่าง tirkx แล้วผมเห็นดังนี้

– หัวกระทู้มักจะยาวและมีสาระ (แต่จากประสบการณ์บางกระทู้หัวกระทู้มีแค่คำว่า “เหมือนหัวข้อ”)
– comment 60% จะเข้ามาโฮกกกกกกแล้วก็จากไป หรือเป็น comment ที่แบบว่าไม่อ่านก็ได้
– comment ที่เหลือจะไม่ค่อยมีสาระเท่าหัวข้อกระทู้
– “คิดว่า” การตอบกระทู้ใช้แค่ @mention พอแล้ว ไม่ต้องขนาด quote
– คนจะตอบกระทู้กันประมาณ 2-4 บรรทัด แต่จริงๆ แล้วคิดว่าเอามารวมกันก็อ่านได้ เพียงแต่ที่เขาเหลือเยอะ เลยกดให้มันอ่านง่าย
– category ที่มีสาระกว่าอนิเมะหน่อยอย่างห้องไอทีจะต่างจากนี้สิ้นเชิง comment น้อยแต่สาระเยอะ

ปัญหาที่ผมเห็นชัดๆ คือทำไมเข้ามาโฮกกกกกซายากะะะะะแค่นี้ทำไมต้องแสดงโพสต์ขนาด 400px ทั้งๆ ที่ใช้เวลาอ่านประมาณ 500ms ฉะนั้น ผมเลยได้ spec บอร์ดตัวเองแบบนี้

– หัวกระทู้เป็นแบบ traditional (แบบชาวบ้านเขาใช้กัน)
– comment ผมใช้ระบบ quick reply ถ้าใช้ quick ตอบต้องจบใน 1 บรรทัด ความยาวอาจจะสัก 500 ตัว และจะแสดงเป็น comment เล็กๆ แบบใน stackoverflow
– upvote comment ได้ และต่อไปอาจจะมีการตั้ง threshold
– comment มีโหมดพิมพ์ยาว 10k ตัว comment ที่เขียนในโหมดนี้จะแสดงผลแบบปกติ คือมีชื่อคนโพสต์ avatar และใช้ที่แสดงผลมากกว่า

ทีนี้เลยคิดว่าอีกจุดขายนึงของ Wave คือ realtime ฉะนั้นผมกำลังชอบ ก็เลยจัด socket.io server มาตัวแล้วทำให้ comment รับส่งกันแบบ realtime ไปเลย! ระบบ quick reply ก็จะกลายเป็น chat ไปในตัว ช่วยให้การสนทนาน่าสนใจไปอีก

พอมาเป็น chat ปัญหาที่จะเกิดคือ

– message มันจะเก็บไว้ถาวร เพราะมันคือ comment ในกระทู้ ไม่ใช่ห้องแชทที่เขียนแล้วหายไป ฉะนั้นมันจะรกมาก อันนี้กำลังคิดว่าจะดูจาก upvote ถ้าไม่ถึงก็ hide แต่ comment ในสตรีมให้มันไหลไปเลยไม่มี filter
– message ใหม่มันมาข้างล่าง ซึ่งมันคือหน้าสุดท้าย แต่ถ้าจะอ่านหน้าแรกของกระทู้สิบหน้าต้องกด load more เก้าครั้ง อันนี้คงไม่ใช่ วิธีที่คิดออกตอนนี้คือ unread อยู่ไหนก็โหลดจากหน้านั้นไป ถ้าไม่ถึงหน้าล่าสุดสตรีมจะยังไม่โหลด
– reply แบบเต็มอาจจะไม่ซ่อน
– flooding อันนี้คิดว่า rate limit อาจจะคิดตามความยาวของ post เพราะแน่นอนว่าโพสต์ยาวก็ต้องใช้เวลาพิมพ์มาก ถ้าคุณจะ copy paste ยาวๆ มาฟลัดมันจะติดลิมิตแต่คนทั่วไปถ้าไม่พิมพ์เร็วมากก็ไม่ควรติด
– เมื่อกี้ทดสอบแชทมา พบว่าพอเป็น realtime สิ่งต่อมาที่ต้องมีคือ “user online”

ไม่รู้จะจบโพสต์นี้ยังไงดี เอาเป็นว่าจบห้วนๆ แบบนี้แล้วกัน เพราะบอร์ดเองก็ยังไม่เสร็จ ไว้เขียนแล้วเจออะไรจะเก็บมาเล่าอีกแล้วกันนะครับ

ปล. unread ยังคิดไม่ออกเลยว่าเก็บยังไงดี คือเก็บอะได้ แต่ยังไงให้ efficient