การทำ Manual Scale ใน Azure App Service และการจัดการ Sesssion State ใน ASP.NET Core ให้ทำงานได้กับการ Scale แบบต่างๆ

Nakorn Rientrakrunchai
T. T. Software Solution
8 min readMay 8, 2022

บทนำ

บทความนี้ ค่อนข้างยาว ผมจะขอลำดับการทำความเข้าใจ และการนำเสนอ ดังนี้

  • การ Scaling คืออะไร
  • ตัวอย่างการทำ Manual Scale Up และ Scale Out ใน Azure App Service
  • Session State ใน ASP.NET Core
  • ตัวอย่าง source code ที่เก็บ session state ไว้ใน memory และ redis
  • ศึกษาการทำงานของ session ระหว่างการ scale ใน Azure App Service

คุณสามารถ ดาวโหลด source code ที่ใช้ในบทความนี้ ได้จาก ที่นี่

การสร้าง Azure App Service และอื่นๆ ที่แสดงเป็นตัวอย่างในบทความนี้ ถูกสร้างใน Central Us ทั้งหมด

การ Scaling คืออะไร

อธิบายโดยย่อ การ Scale คือการขยายโครงสร้างพื้นฐานต่างๆ เช่น CPU, Ram, Network ให้ใหญ่ขึ้น เพื่อรองรับปริมาณการใช้งานที่มากขึ้น

โดยทั่วไป รูปแบบของการ Scale จะแบ่งออกเป็น 2 แบบ คือ Scale Up กับ Scale Out

Scale Up คือการขยายขนาดของเครื่องเดิม ให้มีขนาดโครงสร้างพื้นฐานที่ใหญ่ขึ้น เช่น เพิ่มแรม เพิ่ม CPU เพิ่ม Network เข้าไปในเครื่องเดิม

Scale Out คือการขยายโครงสร้างเดิม ออกไปในทางขนาน คือหมายความว่า Duplicate เครื่องเดิม ออกมาเป็นหลายๆเครื่อง ให้ช่วยกันทำงาน นั่นเอง

โดยส่วนใหญ่ การ Scale up จะทำได้ง่าย, ถ้าไม่มีเงื่อนไขพิเศษ, Application เดิมจะ สามารถทำงานได้ใน Server เดิมที่ขยายขนาดขึ้นนั้น แต่ว่า มันมีข้อจำกัดคือ อาจต้องมี downtime และหากเรามีจำนวนเครื่องน้อย แล้วเครื่องนั้นดับ มันก็จะทำให้ระบบทั้งหมดทำงานไม่ได้

เพื่อลดข้อจำกัดดังกล่าว จึงมีวิธีการ Scale out เข้ามา โดยกลไกนี้ จะเพิ่มจำนวนเครื่องที่มาช่วยทำงานให้มากขึ้น เมื่อเครื่องใดดับ ก็มีเครื่องอื่นช่วยทำงานแทนอยู่ และหากเราปรับจังหวะการ scale out ให้เหมาะสม มันอาจไม่มี downtime เกิดขึ้น อย่างไรก็ตาม Application ที่ทำงานบนเครื่องหลายเครื่อง จำเป็นต้อง Implement ให้รองรับวิธีการทำงานดังกล่าวด้วย เช่น การเก็บ Session State เอาไว้ในตัวกลาง เช่น Redis เพื่อให้เวลา user เข้าใช้งานระบบ ไม่ว่าจะเข้าไปที่เครื่อง (instance) ไหนที่เพิ่มเข้ามาจากการ scale out ก็จะสามารถจดจำ ค่าการใช้งานเดิม ขณะกำลังใช้ระบบอยู่ได้

สำหรับวิธีการ Scale ใน Azure จะแบ่งเป็น 2 แบบคือ

  • Manual Scaling คือการกำหนดขนาดของทรัพยากร ด้วยตนเอง
  • Auto Scaling คือการกำหนดขนาดของทรัพยากร ตามเงื่อนไขที่ถูกกำหนดไว้ เช่น หาก CPU เกิน 80% ให้เพิ่มจำนวน instance ขึ้นอีก 1 เป็นต้น

ในบทความนี้ เราจะกล่าวถึง Manual Scaling เท่านั้น และเราจะ focus ไปที่ การกำหนดค่า Session ให้รองรับกับการ Scale out นะครับ

สำหรับการ Scaling ใน Azure ผมแนะนำให้ศึกษาจากบทความนี้นะครับ

ตัวอย่างการ Manual Scale up บน Azure App Service

ให้คุณเข้าไปที่เมนู Scale up จากนั้น ดูว่าปัจจุบัน เราอยู่ที่ plan ไหน มีคุณสมบัติอย่างไร ในรูป ผมจะใช้ F1 ซึ่งฟรี แต่ใช้ได้แค่ 60 นาทีต่อวัน

เมื่อลองเปลี่ยนเป็น D1 มันจะใช้งานได้มากขึ้นเป็น 240 นาที ต่อวัน โดยมี แรมเท่าเดิม และยังเป็น share infra อยู่, แต่มันก็จะไม่ฟรีแล้ว

เมื่อคุณลองเปลี่ยนระดับเป็น Production แล้วลองเลือก P1V2, คุณจะพบว่า มันจะไม่ได้ใช้ share infra แล้ว, มันจะมี compute ของตัวเอง อยู่ที่ 210 Acu แรม 3.5 GB พร้อมด้วยคุณสมบัติที่เพิ่มขึ้นมา ในกรอบแดงด้านล่าง อาทิเช่น Auto Scale, ด้วยคุณสมบัติต่างๆที่เพิ่มมา, จะตามมาด้วยราคาที่สูงขึ้นด้วย

เมื่อลองเลือกดูตามภาพข้างต้นแล้ว ถ้าคุณจะ scale up ไปเป็น plan ไหน ก็กด Apply ด้านล่าง ได้เลยครับ

ตัวอย่างการ Manual Scale out บน Azure App Service

การ scale out เป็นการเพิ่มจำนวน instance ที่รองรับการทำงานเข้ามา, ซึ่งจะมาพร้อมราคาที่สูงขึ้นตามจำนวน instance ด้วยนะครับ

ในการทำ Manual Scale ก่อนอื่น ให้เราเช็คให้เรียบร้อยก่อนว่า App Service Plan ที่เราใช้ support การ scale out หรือไม่ โดยกดดูที่ Scale up เพื่อเข้าไปดู plan ปัจจุบันของเรา

จากในรูปจะสังเกตุว่า ผมใช้ F1 ซึ่งเป็น plan แบบฟรี มันจะยังไม่ support scale out, ดังนั้น ผมจึงจำเป็นต้อง Scale up ให้มันอยู่ใน plan ที่ support scale out ก่อน ดังนี้

จากรูปด้านบน ผมได้เปลี่ยนมาใช้ B1 ซึ่งเมื่อลองดู จะพบว่า มัน support manual scale out อยู่ โดยสามารถกำหนดให้มีได้สูงสุด 3 instance โดยเท่าที่ผมเข้าใจ มันน่าจะเป็น plan ต่ำสุดที่สามารถ scale out ได้

หลังจากนั้น เรากดเข้ามาที่ Scale out มันจะสามารถ กำหนดค่า instance ได้ ให้เรากำหนดให้เป็น 3 สำหรับการทดลองในบทความนี้ แล้วกด Save

หลังจากนั้น ให้เราเข้ามาที่ Configuration แล้วเข้ามากำหนดค่า ARR affinity ให้เป็น Off เพื่อให้เวลาคนที่เข้าระบบของเรา เมื่อเข้ามาแล้ว มันจะกระจายการเข้าถึงไปยังทุกๆ instance ที่ถูกสร้างขึ้น

สำหรับท่านที่สงสัยว่า ARR affinity คืออะไร ผมมีอธิบาย ตอนท้าย ของบทความนะครับ

Session State คืออะไร

นิยามจาก Microsoft กล่าวไว้ดังนี้

Session state is an ASP.NET Core scenario for storage of user data while the user browses a web app. Session state uses a store maintained by the app to persist data across requests from a client. The session data is backed by a cache and considered ephemeral data. The site should continue to function without the session data. Critical application data should be stored in the user database and cached in session only as a performance optimization.

อธิบายโดยย่อ Session State คือกลไกการเก็บข้อมูลของ user ระหว่างการใช้งาน นั่นเองครับ

เริ่มใช้งาน ASP.NET Core Session State

ในการเริ่มต้นใช้งาน Session State ใน ASP.NET Core ผมอยากให้คุณทำความเข้าใจโดยตรงจากบทความของ Microsoft อันนี้ก่อน

หลังจากนั้น ลองมาดู source code ที่ผมทำเตรียมไว้ให้ ดังนี้ นะครับ ขออธิบาย code ตามกรอบแยกสีในรูปข้างล่าง ดังนี้

  • กรอบสีเขียว — เป็นการกำหนดค่าว่า จะให้เก็บ Session ไว้ที่ไหน โดยในโปรแกรมตัวอย่าง จะมีสองแบบใหเลือกคือ เก็บใน memory หรือ เก็บใน redis
  • กรอบสีแดง — กลไกการทำงานของ Session คือว่า มันจะสร้าง Session ID มาเก็บที่ Cookie, code ในกรอบแดง จะเป็นการกำหนดค่า ของ Cookie ว่ามีคุณสมบัติอย่างไรบ้าง ในกรอบแดง และกำหนดว่า Seesion มีอายุเท่าไร
  • กรอบสีฟ้า — เป็นการให้ application มีการใช้ Session

การเก็บ Session State ไว้ใน Redis

ให้เริ่มต้นจาก การ add package ตามรูปข้างล่างนี้ เข้ามาในโปรเจคก่อน

จากนั้น เขียน code ตามกรอบแดงลงไปนะคับ โดยในกรอบเขียว คือตำแหน่งที่โค๊ตจะไปอ่าน Connection String ที่จะใช้เชื่อมต่อไปที่ Redis

โดย Connection String ที่เชื่อมต่อกับ Redis สำหรับทดสอบระหว่าง development ในเครื่องจะเก็บอยู่ที่นี่

การ Start Redis ในเครื่อง Local เพื่อทำการทดสอบระหว่าง development ในเครื่อง local

ใน source code ในบทความนี้ จะมี docker compose ของ Redis 6 เอาไว้ให้อยู่

ให้ทำการ start Redis ในเครื่องขึ้นมา โดยรันคำสั่ง Docker compose ตามตัวอย่างนี้

หลังจากนั้น ให้เราแก้ไข Mode การทำงาน ให้เป็น Redis แล้วลองรันโปรแกรมดู

เมื่อรันโปรแกรมขึ้นมา ผมจะใช้ Swagger เป็น UI ในการทดสอบ, ในขั้นแรก เราจะทำการ สร้าง session ใหม่ กันขึ้นมาก่อน ให้ใส่ข้อมูลใน Swagger UI ตามขั้นตอนในรูป จะพบว่า มี Cookie ใหม่ โผล่ขึ้นมา มันคือ Cookie ของ ที่เก็บ Session ID นั้นเอง

จากนั้น ให้ลองทดสอบ Get Session ออกมา ตามตัวอย่างในรูปนี้ จะพบว่า มีค่า Session ที่เก็บไว้ชื่อ v1 โผล่ออกมา คือ 001, โดยสำหรับค่า InstanceId จะเป็นหมายเลขอ้างอิงของ Instance ที่รันอยู่ใน Azure, แต่ในการรันในเครื่องตัวเอง มันจะไม่มีค่า

ถ้าหากว่ารันโปรแกรม แล้วแสดงถูกต้องตามขั้นตอนข้างต้นนี้แล้ว แสดงว่า คุณรันโปรแกรมในเครื่องตัวเองได้เรียบร้อยแล้ว

อธิบายฟังชันก์การทำงานของ Code

ก่อนที่เราจะไปทดสอบการทำงานใน Azure มาทำความเข้าใจกันก่อนว่า โปรแกรมตัวอย่างในบทความนี้ มันทำอะไรบ้าง ให้เราเริ่มจาก เปิด Controller ขึ้นมาตามรูปนะคับ

เราจะมีเมธอดที่ทำงาน ดังนี้

  • GetInstanceId เป็นเมธอดสำหรับดึงค่า InstanceId ซึ่งคือหมายเลขอ้างอิงของ Instance ที่รันอยู่ใน Azure, แต่ในการรันในเครื่องตัวเอง มันจะไม่มีค่า
  • GetSession เป็นเมธอดที่ใช้ดึงค่า session ตาม key ที่ระบุเข้าไป โดยมันจะส่งกลับค่า session มาพร้อมกับว่า โปรแกรมกำลังรันอยู่ใน instance ไหน
  • UpdateSession เป็นเมธอดที่ใช้ Update ค่า session ตาม key ที่ระบุเข้าไป โดยมันจะส่งกลับค่า session มาพร้อมกับว่า โปรแกรมกำลังรันอยู่ใน instance ไหน
  • Logout เป็นเมธอด สำหรับการ logout ออกจากระบบ มันจะทำการล้าง session และ cookie ทั้งหมด ออกจาก browser

ในความเป็นจริง เราจะทำการ login ก่อน ถึงจะสร้าง session เพื่อเก็บค่าระหว่างการใช้งานของ user แต่ในตัวอย่าง code ข้างต้น จะขอข้ามส่วนดังกล่าวไปก่อน และแนะนำวิธี logout ไว้ให้ดูแทน

นอกจากนี้ การเปิดใช้ Swagger ไม่ใช่เรื่องเหมาะในการรันใน Cloud, แต่ในบทความนี้ มันคือการสาธิต และใช้ Swagger แทน UI เท่านั้น

การสร้าง Azure Cache for Redis

ขอให้คุณ ศึกษาวิธีการสร้าง Azure Cache for Redis และวิธีตรวจสอบค่าต่างๆ ระหว่างการทำงานกับ Redis จากบทความนี้

การ Deploy โปรแกรมในบทความ เพื่อไปทดสอบบน Azure

ก่อนอื่นให้คุณสร้าง app service ของคุณขึ้นมา โดย Scale Out ให้มี 3 Instance และกำหนดค่าให้ ARR affinity เป็น Off เพื่อจะดูผลว่า เวลา application ทำงานในหลายๆ instance มันจะเป็นอย่างไร, จากนั้นกำหนดค่า Configuration ตามกรอบแดง และฟ้านี้

  • กรอบแดง — คือ Mode การทำงาน ที่เราจะทดสอบ เบื้องต้น ให้กำหนดเป็น redis ไว้ก่อน
  • กรอบฟ้า — คือ Connection String ที่เชื่อมต่อไปยัง Azure Cache for Redis

เมื่อกำหนดค่าเสร็จแล้ว ให้คุณทำการ publish ตามขั้นตอน ในรูปนี้

หลังจากสำเร็จแล้ว ให้คุณลองเปิด swagger ขึ้นมา ถ้าเข้าได้ แปลว่า ok

ศึกษา การทำงานของ Session State บน Azure ขณะที่เก็บ session ด้วย Redis

ให้ทำการ เรียกเมธอด GetInstanceId เพื่อทดลองดู instance id จาก Azure จะพบว่า มันจะมีค่า สลับไปสลับมา โดยจะมี 3 ค่า วนๆกันไป ดังนี้

เลขต่างๆข้างต้น คือ instance id จำนวน 3 รายการ นั่นเอง ขั้นตอนต่อมา เราลองมากำหนดค่าให้ session ดังนี้

จากผลที่ออกมา จะพบว่า โปรแกรมทำงานที่ instance 960, ทีนี้ เราลองมาดึงค่าที่เก็บใน session มาดูกันครับ, เมื่อกดดูค่าวนๆ ไปเรื่อยๆ ค่าใน session จะเหมือนกันหมด ทุก instance id

จากผลข้างต้น จะพบว่า ค่าใน session ถูกดึงมาอย่างถูกต้อง แม้ว่าจะรันใน instance ไหน

อย่างไรก็ตาม ให้กดดู ภายใน 60 วินาที มิฉะนั้น ค่าใน session จะหายไป เพราะเรากำหนดอายุ session ใน code ไว้แค่ 60 วินาทีเท่านั้น จาก code ตรงนี้

ศึกษา การทำงานของ Session State บน Azure ขณะที่เก็บ session ด้วย Memory

ให้กำหนดค่า ให้โปรแกรมทำงาน โดยเก็บ session ไว้ใน memory ดังนี้

จากนั้น Restart App Service ดังนี้

ทำการกำหนด session ตามรูปดังนี้, หลังจากรัน จะพบว่า มันทำงานอยู่ใน instance 01f

เมื่อเราทำการ GetSession ออกมาดู จะพบดังนี้

จะพบว่า ค่าใน session ถูกเก็บไว้ที่ เครื่อง 01f เพียงอย่างเดียว ซึ่งไม่สามารถใช้งานได้ ในการกำหนดค่าการ Scale แบบ Scale Out

ศึกษาการทำงานของ Azure Scale ในแบบอื่นๆ

ให้คุณลองปรับแก้ไข ค่าต่างๆ แล้วทดลองดูผลการรันว่า Sesssion ทำงานอย่างไร อาทิเช่น

  • ทดลองกำหนด ARR affinity = ON
  • ทดลองเพิ่ม ลด Instance ของการ Scale
  • ทดลองใช้ Scale Up เพียงอย่างเดียว
  • ทดลอง Logout
  • ทดลอง restart app service ระหว่างที่ user กำลังใช้งาน
  • อื่นๆ เช่น Auto Scale

สรุปส่งท้าย

เมื่อ application มีการใช้งานที่มากขึ้น เราอาจจำเป็นต้องขยายโครงสร้างพื้นฐานของระบบให้รองรับการใช้งานดังกล่าว โดยในการ Scale out จำเป็นต้องปรับปรุงโปรแกรม ให้รองรับกับการทำงานในหลายๆ instance ด้วย

หวังว่าบทความนี้ จะมีประโยชน์บ้าง ไม่มากก็น้อย, หากมีความผิดพลาดอย่างไร ขออภัยมา ณ ที่นี้ ด้วยครับ

ARR affinity คืออะไร

อยากขอขยายความ เรื่อง ARR affinity เพิ่มสักหน่อยนะครับ, ตัวเลือกนี้ การกำหนดค่าแต่ละอย่างจะมีความหมายดังนี้

  • OFF = จะหมายความว่า สมมุติมี 900 request จากทุก user ที่เข้าใช้ระบบ เรียกเข้ามาที่โปรแกรมของเรา Azure จะกำหนดให้แต่ละ instace รับ Request พอๆกัน นั่นคือ ถ้ามี 3 instance ตามตัวอย่างในบทความนี้, แต่ละ instance จะรับ 300 request โดยประมาณ
  • ON = จะหมายความว่า เมื่อมี request ใดเข้ามา, azure จะสร้าง Affinity cookie ขึ้นมาที่ browser แล้วเมื่อมี request ถัดไปจาก browser ที่มี cookie นี้อยู่, azure ก็จะ ส่ง request ไปยัง instance เดิม เสมอ

ในรูปข้างล่างนี้ คือหน้าตาของ Affinity cookie ที่ Azure สร้างขึ้น นะครับ

--

--