Sessions ใน Traditional Load Balancing Environments
โดยทั่วไป เราใช้ In-memory Sessions (Data เก็บใน RAM) ใน Web Applications ทั้งหมด มันทำงานได้ดีใน Traditional Hosting Environments ส่วนใหญ่ ที่เรา Host Application ใน Dedicated VM หรือ Shared Hosting Plans
อย่างไรก็ตาม เมื่อ Traffic โต เราวางแผน Load Balancing โดยสร้าง Multiple Web Servers และควบคุม Traffic ด้วย Load Balancers ใน Scenario นี้ Session ไม่ทำงาน เพราะ Requests (ที่เกี่ยวกับ Single Session เดียว) จะ Served โดย Multiple Servers (Same Server Serving Requests ของ Single Session ก็เป็นไปได้ แต่ไม่แนะนำ) Solution คือ ไปเก็บ Sessions ใน SQL Server ที่ Accessible ข้าม Web Servers ทั้งหมดใน Load Balancing Environment
Sessions ใน Azure Auto-scale Environment
แทน Theoretical Discussion เรามา Practical Discussion โดยพัฒนา Program เล็กที่ใช้ Sessions และดู Sessions ทำงานใน Azure ยังไง
สร้าง Website (MVC Application ก็ได้) กับ Web Pages ต่อไป และ Deploy ตามบทความก่อนหน้าของผม
- Azure App Service - Configure Existing Application From Visual Studio
Login.aspx
หน้านี้รับ Username และ Password กด "Login" สร้าง Session เก็บ Username ที่ Login และ Redirect ไป "Default.aspx"
โปรดสังเกต หน้านี้แสดง IP Address "10.202.116.91" ของ VM ที่ Host Website
Default.aspx
หน้านี้แสดง Messages ตามค่าใน Session
ถ้า Session มีค่า แสดง "Logged in user as admin. You are in 10.202.116.91" ตามภาพ
ถ้า Session ไม่มีค่า แสดง "Session is NULL. You are in 10.202.116.91" ตามภาพ
สังเกตว่า IP Address ของ Server ใน Login.aspx และ Default.aspx เหมือนกัน All Requests ถูก Redirect ไป Server เดียวกัน
และตามภาพ Session Maintained โดย Cookie ชื่อ "ASP.NET_SessionID" ควรคุ้นเคยกับส่วนใหญ่

สมมติ Traffic โต เราอยาก Scale เป็น 2 Instances เพิ่ม Instance Count เป็น 2
Note: โปรดสังเกต ไม่สามารถเพิ่ม Instance Count ใน Free และ Shared Tiers ได้ App Service ต้องอยู่ใน "Basic", "Standard" หรือ "Premium" Tiers

เข้าหน้า Login อีกครั้ง และ Refresh หลายครั้ง Refresh กี่ครั้งก็ตาม IP Address ไม่เปลี่ยน
สังเกตว่า Web Server เดียวกัน Serving Pages 雖然เรา Enable Scaling 2 Instances App Service ยัง Serve Requests จาก Server เดียว
นี่อาจเป็นปัญหาใน Real-world เพราะ Server เดียว Serve Requests แม้ Load Balancing Enabled และ Servers อื่นไม่ถูก Utilize ให้เต็มที่
เหตุผลคือ ARR Cookie ตามภาพด้านล่าง สำหรับ Info เพิ่มเติม ดูที่นี่

Simple Terms: Cookie นี้มี Server Info จาก Initial Request Served โดย Server ใด ทำให้ Subsequent Requests จาก Session เดียว Served โดย VM เดียวกัน
Disable ARR Cookie Feature โดยไปที่ App Service Application Settings

ปิด "ARR Affinity" ตามภาพ และ Save Restart App Service เพื่อ Clear Sessions
โปรดระมัดระวัง Paragraphs ถัดไป Confusing 一点
Important
ปิด ARR Affinity จะ Disable การสร้าง ARRAffinity Cookie ดังนั้นเมื่อ Cookie Disabled Requests อาจส่งไป Server ใดก็ได้ที่ Available ไม่มี Guarantee Sessions Maintained Properly Sessions ทำงาน ONLY เมื่อ Requests Served จาก Same Server ถ้า Request ใด Served โดย Another Server (แทน Server ที่ Session Stored) Session จะเป็น NULL
กลับไป Web App ไปหน้า Login สังเกต IP Address ใหม่ "10.202.174.84" (ใน Case ของคุณ อาจเห็น IP เดิม Refresh จะเปลี่ยน ใน Case ผม Refresh 2 ครั้ง ได้ IP ใหม่)

กด "Login" บนภาพข้างบน NOT Guarantee Post ไป 10.202.174.84 อาจ Post ไป Server อื่น "10.202.116.91" ใน Case ผม
ตอนกด "Login" บนภาพข้างบน มันพาไป Default Page ด้วยค่า:

- IP Address 10.202.174.84 (เหมือน Login Page)
- Session is NULL เหตุผล: กด Login Request อาจไป Instance อื่น ("10.202.116.91") ที่ Session เก็บไว้
- Refresh หน้าหลายครั้ง
โปรดสังเกต:
- Session มีค่า "admin"
- IPAddress 10.202.116.91
Conclusion: "Sessions" ไม่ทำงาน As Expected ใน Azure App Service เมื่อ Configure Load Balancer ด้วย Auto-scaling
นี่คือ Savior: Redis Cache Provider ตาม Definition จาก Azure Official Website
Azure Redis Cache Based on Popular Open-source Redis Cache ให้ Access to Secure, Dedicated Redis Cache, Managed by Microsoft Accessible จาก Application ใดๆ ใน Azure
Steps Required ทำ Sessions Work As Expected:
- Create Redis Cache จาก Azure Management Portal
- Configure Application ใช้ Azure Redis Cache
- Use Sessions
Create Redis Cache จาก Azure Management Portal
เริ่มสร้าง Redis Cache ด้วย Azure Management Portal
ใส่รายละเอียด Redis Cache
กด "Create" ใช้เวลาสองนาทีสร้าง Redis Cache
Configure Application ใช้ Azure Redis Cache
Configure Application ใช้ Redis Cache ที่เพิ่งสร้าง
ตามภาพ Package Manager Console พิมพ์ "Install-Package StackExchange.Redis" Enter
ตอนนี้ Install Required Packages เรียบร้อย (Note: .NET Framework ควร 4 หรือ Higher)
เพื่อใช้ Assemblies เราต้อง Add Namespace ต่อไปไปทั้ง Login.aspx และ Default.aspx
Using StackExchange.Redis;
เพิ่ม Class ใหม่ชื่อ "RedisConnection" ใน Project Refer Attached Project
เพื่อ Connect Redis Cache เราต้อง Pass Info ต่อไปให้ ConnectionMultiplexer.Connect Function Grab จาก Portal

- Redis Cache URL
- Keys
โปรดอย่า Save Keys ใน Code เพื่อ Simplicity ผมเก็บ Keys ใน Source Code โปรดดูหน้านี้สำหรับ Info ว่าเก็บ Credentials ยังไง
ตอนนี้ Ready Class สำหรับ Connect Redis Cache มาใช้สร้าง Session ใน Redis Cache
เปิด Login.aspx.cs แทนที่ Code:
Session["login"] = this.txtUsername.Text.Trim();
ด้วย:
IDatabase cache = RedisConnection.Connection.GetDatabase();
cache.StringSet("login", this.txtUsername.Text.Trim());
เปิด Default.aspx.cs แทนที่ Code:
protected void Page_Load(object sender, EventArgs e) {
if (Session["login"] == null) {
Response.Write("Session is NULL. You are in " + Request.ServerVariables["LOCAL_ADDR"]);
} else {
Response.Write("Logged in user is " + Session["login"] + ". You are in " + Request.ServerVariables["LOCAL_ADDR"]);
}
}
ด้วย:
protected void Page_Load(object sender, EventArgs e) {
IDatabase cache = RedisConnection.Connection.GetDatabase();
string strLoginValue = cache.StringGet("login");
if (strLoginValue == null) {
Response.Write("Session is NULL. You are in " + Request.ServerVariables["LOCAL_ADDR"]);
} else {
Response.Write("Logged in user is " + strLoginValue + ". You are in " + Request.ServerVariables["LOCAL_ADDR"]);
}
}
Deploy Code ไป Azure App Service Review Changes ไปหน้า Login
สังเกต IPAddress คือ 10.202.174.84 กด "Login" จะไป Default.aspx
สังเกตในภาพข้างบน 雖然 IPAddress ต่างกัน แต่ยังเห็น Username "admin" เพราะ SessionsStored ใน Distributed Location "Redis Cache" Accessible สำหรับ Both Instances
Refresh หลายครั้ง IP Addresses เปลี่ยน แต่ Username ไม่เปลี่ยน
That's it เราเรียนรู้ Store Sessions ใน Load Balancing Environment คุณสามารถ Store Data ใดๆ ใน Redis Cache
Hope you enjoyed reading the article Your Feedback Really Appreciated