Extract microservices ด้วยวิธี reuse บน kubernetes เพื่อ resource efficiency

Nutchalum Kitpongsai
3 min readOct 19, 2018

--

เพราะทรัพยากรเรามีอยู่จำกัด ทำให้เราต้องกังวลถึงขนาดของ container นั่นเอง และจะยิ่งกังวลมากขึ้นหากเราใช้ cloud service เพราะการใช้ทรัพยากรณ์มากขึ้นย่อมหมายถึงใช้เงินที่มากขึ้นเช่นกัน

Example system

สมมติระบบ karaoke เรามี service อยู่ 2 ตัวอย่างง่าย คือ music service (backend) และ jukebox service (frontend) โดยทุกอย่างที่ jukebox จะเอามาแสดงผล ใช้ข้อมูลมาจาก music service

karaoke system overview

Music service

และ music service นั้น expose REST API อย่างง่าย อยู่ 3 อย่างคือ
/musics, /music/{id} และ /search

music service API

Memory usage per request

ทุกๆ request ที่เกิดขึ้น service ของเราจะมีการใช้ memory อยู่บ้างซึ่งไม่ใช่เรื่องแปลกอะไร

average memory usage per route-request

ทว่าด้วยเหตุผลบางประการ /search ของเราดันใช้ memory สูงกว่าคนอื่นอยู่มาก
ทำให้เราต้องขยายขนาดของ container ขึ้นเพื่อให้รองรับ /search

music service container specification

note:
สาเหตุที่ไม่ใช้วิธี set upper bound > lower bound (burstable) ของ memory นั้นเพราะมองว่าหากเกิด out-of-memory event ที่ระดับ node จะทำให้ chain of failure หรือ domino effect มากกว่า ถึงแม้ QoS ของ pod จะเป็น burstable อยู่ดีก็ตาม (ในรูป cpu burst ได้ ทำให้ class เป็น burstable)

see more: Quality Of Service
see more: Node OOM Behaviour

Wasted memory scaling

เมื่อ pod/container มีขนาดใหญ่ การขยายตัวออกก็ทำให้ใช้ทรัพยากรณ์เยอะตามไปด้วย

3 pods with 1.5 gb usage

จะกังวลขนาดของ container ไปทำไม? คำตอบก็ง่ายแสนง่าย เพราะทรัพยากรณ์เรามีอยู่จำกัดนั่นเอง

note:
ถ้าโชคดีที่ทุกๆ api มีอัตราการถูกเรียกใช้งานเท่าๆกัน การ scale out แบบนี้ถือว่าโอเค แต่ถ้าในความเป็นจริงมีคนเรียกใช้ /search แค่ 10% ละ? (หรืออีกนัยหนึ่งก็คือแค่ pod/container เดียวก็เพียงพอจะทำงานได้)

Extracting by Reusing

ด้วยความสามารถของ Kubernetes ทำให้เราสามารถที่จะสร้าง virtual service ขึ้นมาอีกตัวได้อย่างง่ายดาย เราจึงทำการ extract /search ออกมาเป็น search service โดยการ reuse image ของ music service ได้อย่างง่าย

จากรูปจะเห็นว่าเราใช้วิธี resuse image music:1.0.0 ตรงๆ แต่ทำให้เราได้ search service ขึ้นมา (ถึงแม้ข้างในจะเป็น music service เหมือนเดิมนั่นแหละ)

แล้วเราได้ประโยชน์อะไรจากการทำแบบนี้? คำตอบก็คือช่วยให้ประหยัด resource ในตอน scale out นั่นเอง

/musics กับ /music/{id} ใน music service จะยังคงมี 3 pods/containers เท่าเดิมเพราะต้องรองรับ load 90% ในขณะที่ /search ใน search service มี load แค่ 10% แค่ pod/container เดียวก็เพียงพอแล้ว

reduce from 1500mb to 650 mb

จะเห็นว่าประหยัดพื้นที่ได้อีกเกือบ 60% เลยทีเดียว หลังจากนั้นก็ปรับแก้ไข code นิดหน่อยให้ไปเรียกใช้งาน search service ที่สร้างขึ้นมาใหม่

เพิ่ม env ที่ frontend และแก้ไข code บางส่วน

Adaptive

วิธีนี้ยังสามารถนำไปประยุกต์กับการ extract microservices from monolith ได้อีกด้วย เริ่มจาก wrap monolith ให้เป็น containerized application

สร้าง service และแก้ไข code ให้ใช้ service ที่สร้างขึ้นมาใหม่ ด้วยวิธีการ reuse image แล้วค่อยๆ implement microservices จริงๆมา replace ทีละ service

Backward compatible

หากเข้าใจ concept จะพบว่าเราสามารถใช้วิธีได้ตั้งแต่ที่ระดับของ docker หรือ container orchestration ตัวอื่นๆได้อีกด้วย ไม่จำเป็นต้องใช้ kubernetes เพียงอย่างเดียว

--

--