Aiforthai

บันทึกการเดินทางอันแสนยาว

มันเหมือนการเดินทางราวๆ 9 เดือนของผม ตอนต้นปีได้รับคำสั่งมาว่า วันที่ 99 เราจะมีเปิดตัว service ใหญ่นะให้ออกแบบระบบไว้ด้วย service นี้จะเป็นการรวมเอา API ต่างๆที่มีมาปล่อยให้คนทั่วไปใช้กัน จากวันนั้นก็เริ่มรับ requirement ของระบบมาซึ่งได้มาประมาณนี้

Requirement ระบบ

  • สำคัญสุดห้ามล่ม
  • มี resource ให้ 3 เครื่อง วางไว้ที่ network ข้างนอก
  • ภายหลังมีี support VM จากทาง Inet และ CAT เพิ่มมาอีก

เลือก Stack

หลังจากได้ requirement มาแล้วสิ่งที่กลัวที่สุดคือ “ห้ามล่ม” เพราะตัว API แต่ละตัวที่ต้องเอามาขึ้นนั้นบอกได้คำเดีียวว่า “สะมะปิ”มาก เพราะ API ไม่ได้เขียนขึ้นมาโดย software engineer แต่ถูกเขียนขึ้นโดยนักวิจัย โดยธรรมชาติแล้วนักวิจัยจะเขียน code ให้ได้ผล โดยไม่คำนึงถึง response time ไม่คิดว่าจะ scale แต่ละ service ถ้าไม่ได้เข้าไปคลุกคลี ตั้งแต่เริ่มปั้นแรกๆจะทำให้มัน scale ได้ยากมากๆ แถม response time ข้าอีกฉะนั้นสิ่งที่ผมจะต้องทำก่อนเลือก stack คือ

  • เจ้าไป join กับ project ต่างๆให้เยอะที่สุดเพื่อจะได้แนะนำนักวิจัยให้ desigin ระบบได้ตั้งแต่ต้น
  • แนะนำ framework tool ต่างๆที่เหมาะจะทำให้ service ของนักวิจัยเป็น API ได้

จุดนี้ พยายามทำเยอะที่สุดเท่าที่จะเยอะได้ เพื่อลดภาระของตัวเองตอน service ขึ้นซึ่งพอปลายทางผลของเรื่องนี้เป็นตามที่หวังจริงๆช่วยลดงานได้เยอะจริงๆ แต่สำหรับบางคนที่ไม่ได้คุยด้วยหรือไม่ได้ design ช่วยก็ปล่อยๆเค้าไป ทำ req/s ได้ต่ำก็ช่างเค้างานเค้าเราทำดีที่สุดละ

มาพูดถึงเลือก stack ต่อ

ตอนแรกที่ได้เครื่องมา กะว่าจะใช้ K8S ทั้งลงเรียน udamy ทั้งติดตั้งระบบได้เสร็จสรรพ แต่แล้ว ก่อนจะ production 2-3 เดือน flannel network พังแล้วแก้คืนไม่ได้ สรุปคือ “เราเอามันไม่อยู่” ถอยกรูดกลับไปใช้ docker ธรรมดาก่อนแล้วกันเดี๋ยวงานจะเสร็จไม่ทัน

สรูปไม้แรกของเราคือ Docker docker

ต่อไปเลือก storage จะไปท่าไหนดี เคยใช้ gluster ไม่ค่อยประทับใจ performance เลยไปเลือกใช้ ceph กว่าจะทำให้ใช้ได้ร่วมกับ docker ก็แทบแย่เหมือนกันเพราะลอง driver หลายตัวมากใช้กับ rbd ไม่ได้และหาเจอตัวหนึ่งที่ใช้ได้คือ

rexray/rbd
https://hub.docker.com/r/rexray/rbd

พอทำ production แล้วกลับเจอว่า performance ไม่ได้ตามที่ต้องการ ลองเอา mount มาใส่กับ Docker volume แล้วก็ performance ตกฮวบ เลยตัดสินใจว่า เอาเป็นทีี่เก็บพวก static file ที่นักวิจัยเก็บไว้ใช้งานทีหลังดีกว่าพวก access บ่อยๆใช้จาก host ไปเลย ข้อจำกัดนี้เกิดจากตอนซื้อ เครื่องซื้อ Harddisk เป็นแบบจานหมุนทั้งระบบ performance เลยไม่ได้

สรุปไม้ที่ 2 คือ Volume on Host & CEPH RBD for static fileceph

ตัวถัดไปที่จะต้องเลือกคือระบบเก็บ log คงไม่ feed ลง file แล้ว docker logs ดูระบบเก็บ log เลือก

filebeat -> logstash -> Elasticsearch + Kibana

elk

เมื่อ design infra + base system แล้วก็ถึงจังหวะที่จะต้องมาเลือก ระบบภายในว่าจะใช้อะไร ก่อนจะเข้าถึง API แต่ละตัว จะต้องทำ reverse proxy คั่นก่อน ไม่คิดมากเลย เลือก openresty ตัวเดียว ไม่พูดเยอะเจ็บคอสำหรับ openresty เพราะ config มันเขียนเป็น program ได้ แถม มี plugin สำหรั บprometheus อีก ทำให้ monitor เชิงลึกได้อีกต่างหาก openresty

เมื่อหลุดจาก reverse proxy เข้ามาแล้ว ต่อไปก็เป็น API management ก็มีตัวเดียวใจดวงใจเหมือนกันน KONG ไม่มีอะไรดีกว่านี้แล้วสำหรับชั่วโมงนี้ โดย kong จะเข้ามาทำหน้าที่คอยจัดการ kong

  • user auth by API-KEY
  • Rate limit
  • Request size limit

api gateway มี issue อยู่นิดหน่อยเพราะโจทย์คือ บอกว่า ห้ามล่ม ฉะนั้นการทำ limit มันจะไม่ใช่แค่ limit ชั้นเดียว จะต้อง limit 2 ชั้นพื่อป้องกันระบบ overload โดยมีขั้นตอนการพิจารณาดัังนี้

  • loadtest หา req/s ที่เหมาะสมสำหรับแต่ละ API ว่า req/s เท่านี้แล้วได้ responsetime ตามที่ควรจะเป็น (บางอันเยอะบางอันน้อยตามแต่ ธรรมขาติของ แต่ละ API)
  • set req/s ของ consumer ให้ = max req/s ที่เราหามาได้ เพื่อเป็นการ limit ของระบบ
  • set req/s(min) ของ apikey แยกต่างหาก ให้น้อยกว่า max ของระบบที่รับได้เป็นการ limit รายบุคคล

แต่ปัญหาคือ kong ทำตามเงื่อนไขที่ต้องการไม่ได้เพราะ rate limit plugin ใช้ memory ตัวเดียวกันในการ count (cunsumer & credential) ฉะนั้น วิธีการแก้ปัญหานี้คือ เราจะต้องสร้าง rate limit plugin ขึ้นมาใหมม่เอามาทำ ratelimit เฉพาะ consumer แยกจาก credential อีกอัน เรื่องนี้ติดอยู่เป็นอาทิตย์เหมือนนกันกว่าจะแก้ได้ ต้องขอบคุณ นเรศ เลยเรื่องนี้ที่เข้ามาช่วย

kong

ขั้นต่อไปเป็นการ monitor ระบบรวมไปถึง API ทั้ง 2 อย่างก็เลือก Prometheus + Grafana เพราะอยู่ด้วยกันมาหลายงานแล้วถือว่าเอาอยู่ระดับหนึ่งเลยและตอบโจทย์ทุกความต้องการที่อยากได้

prometheus grafana

Dploy API ขึ้นระบบ

ง่ายเลยเพราะเข้าไปคลุกคลีตีโมงกับนักวิจัยแต่ละงานอยู่แล้วว่าจะทำให้ scale ยัังไง อันไหนที่ไม่ได้คุยกันตั้งแต่แรกก็ scale ยากหน่อยแต่ก็เข็นจน scale ได้ทุก service พอเอาขึ้นได้ก็ limit resource ที่ใช้แล้วค่อย ยิง loadtest เรียงตัวเลย ตัว loadtest ใช้อยู่ 2 ตัวแล้วแต่งานเลยคือ wrk กับ jmeter jmeter

  • wrk ใช้ ยิงสำหรับ API ที่รับโหลดได้เยอะ ยิง สาด เข้าไปเลยจะได้ req/s แบบเร็วๆเลย
  • jmeter ใช้สำหรับ API ที่รับโหลดได้น้อย ยิง สาด แบบ wrk ไม่ได้ ต้องค่อยๆยิงทีละ 5req/s 10req/s ไล่ไปเรื่อยๆหาจุดที่ API รับได้

partii

ระหว่างทางก่อนจะถึง 99 ก็มีอุปสรรคบ้างแต่ก็ฟันฝ่ามันมาได้จนถึงวันที่จะเปิดตัว

ก่อนเปิดตัว 2 วัน

partii

ทุกคนในทีมเร่งมือกันทั้ง front end และ Ops(+back end) เจอว่าทำไมเว็บมันน load ช้าจัง วันก่อนๆยัังเร็วอยู่เลย โหลดยังไงก็ได้ราวๆ 10s ไล่อยู่นานมาก ผมไล่จากล่างขึ้นบนคือ

  • sysctl
  • filesystem
  • network
  • nginx

หายังไงก็หาไม่เจอแล้วไป inspect เว็บดูแล้วตั้งสติดูดีดี เจอว่า ที่มันช้าเพราะ รูปที่มันโหลดมันถูกโหลดจาก js ตัวหนนึ่ง ไปไล่ดุใน code เจอว่า js ตัวนี้อยุ่ท้าย file ลองเอาไปไว้ ต้น file เว็บกลับมาโหลดเสร็จภายใน 1.5s

partii

วันที่ 9 เดือน 9

และแล้วก็มาถึงวันเปิดตัวของระบบ ระบบเปิดตัวบนเวทีตอน 10:00 มีโหลดเข้ามาถือว่าน้อยมากๆ cc หน้าเว็บอยู่ที่ 100 cc ส่วน API ไม่ต้องพูดถึงเพราะการจะ call API ได้จะต้องมีการ code ในหน้า ทดสอบ API บนหน้าแรกเรา cache ไว้หมดแล้วทำให้ไม่กระทบระบบ โหลดมาน้อยตามที่คาดไว้ไม่ล่มแน่นอน วางใจไปกินข้าว ลั้นลาสักบ่ายๆเปิดมาดูระบบ ถึงกับช๊อก เพราะเครื่อง Master IO ไม่เคยเต็มวันนี้มันดันเต็ม เข้าไปทำอะไรแทบไม่ได้ พยายามหาสาเหตุให้เร็วที่สุด เจอว่า process ของ partii ชุดหนึ่งค้างอยู่ประมาณ 800% cpu เลยจัดการ restart service แล้วอาการก็หายไป โชคดีที่ไม่เจอปัญหาต่อเนื่องจนระบบล่มไปเจอก่อน ตอนแรกไม่ได้ ตั้ง alert io เพราะสัก ตี3-4 ระบบจะมีการทำ log จน IO พุ่งเลยไม่ได้ตั้งไว้ วางใจไปหน่อย สุดท้ายก็ต้อง set alert IO ทิ้งไว้กันเจอปัญหา

partii

สรุปแล้วก็มีเรื่องตื่นเต้นนิดหน่อยพอให้กระชุ่มกระชวยกัน แต่มันคือการเริ่มต้นเพราะหลังจากนี้จะมี load ที่แท้จริงเข้ามาคนจะ call API หลังจากนี้ต้องรอ monitor กันต่อไป