การปรับขนาดด้วย Redis Backplane
ปรับขนาด SignalR ข้ามเซิร์ฟเวอร์หลายเครื่องด้วย Redis backplane เพื่อซิงโครไนซ์ข้อความระหว่างอินสแตนซ์
การปรับขนาดด้วย Redis Backplane เป็นบทเรียน C# Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C# Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C# Academy มีบทเรียนทั้งหมด 4 บทเรียน
ปัญหาของหลายเซิร์ฟเวอร์
เมื่อ SignalR ทำงานบนเซิร์ฟเวอร์เดียว ไคลเอนต์กับเซิร์ฟเวอร์จะแชร์หน่วยความจำสำหรับการเชื่อมต่อและกลุ่ม แต่เมื่อขยายระบบเป็นเซิร์ฟเวอร์สองเครื่องขึ้นไป แต่ละเซิร์ฟเวอร์จะรู้จักเฉพาะการเชื่อมต่อ ของตนเอง เท่านั้น — ข้อความที่ส่งบนเซิร์ฟเวอร์ A จะไปไม่ถึงไคลเอนต์ที่เชื่อมต่อกับเซิร์ฟเวอร์ B
แบ็กเพลนคืออะไร
แบ็กเพลน คือบัสข้อความที่ใช้ร่วมกันระหว่างอินสแตนซ์เซิร์ฟเวอร์ SignalR เมื่อเซิร์ฟเวอร์หนึ่งต้องการส่งข้อความ เซิร์ฟเวอร์จะเผยแพร่ข้อความไปยังแบ็กเพลน จากนั้นเซิร์ฟเวอร์ทั้งหมดจะได้รับข้อความและส่งต่อไปยังการเชื่อมต่อภายในเครื่องของตน
การเพิ่มแบ็กเพลน Redis
ติดตั้งแพ็กเกจ Microsoft.AspNetCore.SignalR.StackExchangeRedis แล้วเรียกใช้ AddStackExchangeRedis() หลังจาก AddSignalR()
// dotnet add package Microsoft.AspNetCore.SignalR.StackExchangeRedis
builder.Services.AddSignalR()
.AddStackExchangeRedis("localhost:6379", options =>
{
options.Configuration.ChannelPrefix =
RedisChannel.Literal("myapp"); // namespace your channels
});
// Or from config:
// .AddStackExchangeRedis(builder.Configuration.GetConnectionString("Redis")!);การทำงานของระบบเผยแพร่/สมัครรับข้อความ Redis สำหรับ SignalR
เซิร์ฟเวอร์ SignalR แต่ละเครื่องจะสมัครรับช่องทาง Redis เมื่อเซิร์ฟเวอร์ A เผยแพร่ข้อความสำหรับกลุ่มหรือผู้ใช้ Redis จะส่งข้อความนั้นไปยังผู้สมัครรับทั้งหมด (เซิร์ฟเวอร์ B, C…) จากนั้นเซิร์ฟเวอร์เหล่านั้นจะส่งต่อข้อความไปยังการเชื่อมต่อภายในเครื่อง
// Server A: client sends message
// Hub on Server A calls:
await Clients.Group("room-42").ReceiveMessage(user, msg);
// Internally SignalR publishes to Redis:
// PUBLISH signalr/myapp/group/room-42 <serialized message>
// Redis delivers to Server B and C
// Both servers find connections in "room-42" and push to themตัวเลือกการกำหนดค่า
ปรับแต่งการเชื่อมต่อ Redis สำหรับระบบจริง: TLS รหัสผ่าน ความทนทานของการเชื่อมต่อ และคำนำหน้าช่องทางการเผยแพร่/สมัครรับข้อความ
builder.Services.AddSignalR()
.AddStackExchangeRedis(opts =>
{
opts.Configuration = ConfigurationOptions.Parse(
builder.Configuration["Redis:ConnectionString"]!);
opts.Configuration.Password = builder.Configuration["Redis:Password"];
opts.Configuration.Ssl = true;
opts.Configuration.AbortOnConnectFail = false;
opts.Configuration.ConnectRetry = 3;
});Azure SignalR Service
หากต้องการการขยายระบบที่มีการจัดการอย่างสมบูรณ์ ให้ใช้ Azure SignalR Service ซึ่งทำหน้าที่เป็นทั้งแบ็กเพลนและตัวจัดการการเชื่อมต่อ — เซิร์ฟเวอร์แอปพลิเคชันของคุณจะไม่เก็บสถานะ และไม่ต้องเก็บการเชื่อมต่อ WebSocket ไว้ด้วยตนเอง
// dotnet add package Microsoft.Azure.SignalR
builder.Services.AddSignalR()
.AddAzureSignalR(builder.Configuration["Azure:SignalR:ConnectionString"]!);
// That's it — Azure manages all connections and backplane
// Your server scales to zero when not neededเซสชันแบบยึดติด (ทางเลือกสำรองสำหรับการขนส่งที่ไม่ใช่ WebSocket)
เมื่อใช้เหตุการณ์ที่ส่งจากเซิร์ฟเวอร์หรือการสำรวจแบบยาว (ไม่ใช่ WebSockets) ไคลเอนต์เดิมจะต้องเชื่อมต่อกับเซิร์ฟเวอร์เดิมเสมอ ซึ่งเรียกว่า เซสชันแบบยึดติด ให้กำหนดค่านี้ในตัวกระจายโหลดหรือพร็อกซีแบบย้อนกลับ
# Nginx: sticky session config (IP hash)
upstream signalr_servers {
ip_hash; # ensures same client hits same server
server server1:5000;
server server2:5000;
server server3:5000;
}
# Or use cookie-based sticky sessions:
# sticky cookie srv_id expires=1h;
# WebSockets don't need sticky sessions —
# the connection is long-lived on one serverกลุ่มบนเซิร์ฟเวอร์หลายเครื่อง
แบ็กเพลนจะดูแลการเป็นสมาชิกกลุ่ม การเพิ่มการเชื่อมต่อเข้ากลุ่มบนเซิร์ฟเวอร์ A ทำให้เซิร์ฟเวอร์ B รับทราบผ่าน Redis — โดยโค้ดแอปพลิเคชันไม่ต้องจัดการเพิ่มเติม
// This works correctly across servers:
public async Task JoinRoom(string room)
{
// Adds to Redis-backed group
await Groups.AddToGroupAsync(Context.ConnectionId, room);
// Clients.Group sends via Redis to all servers
await Clients.Group(room).UserJoined(Context.User!.Identity!.Name!);
}
// No code changes needed — the Redis backplane handles distributionการตรวจสอบระบบเผยแพร่/สมัครรับข้อความของ Redis
ตรวจสอบช่องทาง Redis เพื่อยืนยันการรับส่งข้อมูลของ SignalR และวิเคราะห์ปัญหา ใช้ redis-cli SUBSCRIBE หรือ Redis Insights เพื่อดูการไหลของข้อความ
# redis-cli: monitor all SignalR channels
redis-cli PSUBSCRIBE "myapp*"
# Check active channel subscribers
redis-cli PUBSUB CHANNELS "myapp*"
# Check number of subscribers per channel
redis-cli PUBSUB NUMSUB "myapp/all"การจัดการความล้มเหลวของ Redis
หาก Redis ไม่พร้อมใช้งาน SignalR จะเปลี่ยนกลับไปใช้โหมดภายในเครื่องเท่านั้น — ข้อความจะไม่ข้ามไปยังเซิร์ฟเวอร์อื่น ให้กำหนดนโยบายการลองใหม่และระบบแจ้งเตือนสำหรับการเชื่อมต่อ Redis
builder.Services.AddSignalR()
.AddStackExchangeRedis(opts =>
{
opts.Configuration = ConfigurationOptions.Parse(redisConn);
opts.Configuration.AbortOnConnectFail = false; // don't crash app
opts.Configuration.ConnectRetry = 5;
opts.Configuration.ReconnectRetryPolicy =
new ExponentialRetry(5000, maxDeltaBackoffMilliseconds: 60000);
});การใช้งานจริง: สถาปัตยกรรมแชตแบบขยายระบบ
ในระบบจริง ให้เรียกใช้อินสแตนซ์เซิร์ฟเวอร์ SignalR อย่างน้อย 3 เครื่องอยู่หลังตัวกระจายโหลด โดยมี Redis (หรือ Azure SignalR Service) เป็นแบ็กเพลน สถานะทั้งหมดอยู่ใน Redis ส่วนเซิร์ฟเวอร์จะไม่เก็บสถานะและสามารถถอดออกได้
// Architecture:
// [Browser] -> [Load Balancer (any server, WebSocket)] ->
// [SignalR Server 1] -+
// [SignalR Server 2] -+-> [Redis Pub/Sub] -> all servers
// [SignalR Server 3] -+
// Server code is identical on all instances:
builder.Services.AddSignalR().AddStackExchangeRedis(redisConn);
app.MapHub<ChatHub>("/hubs/chat");
// Scale replicas: kubectl scale deployment chat --replicas=3ตรวจสอบความเข้าใจ
แบ็กเพลนของ SignalR แก้ปัญหาอะไร
ทบทวน: การขยายระบบด้วยแบ็กเพลน Redis
ประเด็นสำคัญ:
- หากไม่มีแบ็กเพลน ข้อความจากเซิร์ฟเวอร์หนึ่งจะไปไม่ถึงไคลเอนต์บนเซิร์ฟเวอร์อื่น
- AddStackExchangeRedis() เพิ่มแบ็กเพลน Redis สำหรับการเผยแพร่/สมัครรับข้อความโดยไม่ต้องตั้งค่าเพิ่มเติมในโค้ดแอปพลิเคชัน
- Azure SignalR Service เป็นทางเลือกแบ็กเพลนที่มีการจัดการอย่างสมบูรณ์และไม่ต้องจัดการเซิร์ฟเวอร์เอง
- การขนส่งที่ไม่ใช่ WebSocket (SSE, การสำรวจแบบยาว) จำเป็นต้องใช้เซสชันแบบยึดติด
- การเป็นสมาชิกกลุ่มจะซิงโครไนซ์ระหว่างเซิร์ฟเวอร์ผ่านแบ็กเพลน
- กำหนดค่า AbortOnConnectFail=false และนโยบายการลองใหม่เพื่อให้ Redis ทนทานต่อความขัดข้อง
คำถามที่พบบ่อย
บทเรียน “การปรับขนาดด้วย Redis Backplane” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การปรับขนาดด้วย Redis Backplane” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C# Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C# Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การปรับขนาดด้วย Redis Backplane”
ปรับขนาด SignalR ข้ามเซิร์ฟเวอร์หลายเครื่องด้วย Redis backplane เพื่อซิงโครไนซ์ข้อความระหว่างอินสแตนซ์ คุณปฏิบัติ C# Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C# Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน C# Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “การปรับขนาดด้วย Redis Backplane” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน C# Academy นี้ได้ไหม
ได้ บทเรียน C# Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- ฮับและการเชื่อมต่อ SignalR
- กลุ่ม ผู้ใช้ และการจัดการการเชื่อมต่อ
- ฮับแบบระบุชนิดอย่างเคร่งครัด
- การปรับขนาดด้วย Redis Backplane