使用多個實例調整 SignalR 服務
SignalR Service SDK 支援 SignalR 服務實例的多個端點。 您可以使用此功能來調整並行連線,或使用此功能進行跨區域傳訊。
針對 ASP.NET Core
從組態新增多個端點
使用金鑰Azure:SignalR:ConnectionString
或 Azure:SignalR:ConnectionString:
SignalR Service 連接字串 進行設定。
如果機碼開頭 Azure:SignalR:ConnectionString:
為 ,則其格式 Azure:SignalR:ConnectionString:{Name}:{EndpointType}
應該是 ,其中 Name
和 EndpointType
是對象的屬性 ServiceEndpoint
,而且可從程式代碼存取。
您可以使用下列dotnet
命令來新增多個實體 連接字串:
dotnet user-secrets set Azure:SignalR:ConnectionString:east-region-a <ConnectionString1>
dotnet user-secrets set Azure:SignalR:ConnectionString:east-region-b:primary <ConnectionString2>
dotnet user-secrets set Azure:SignalR:ConnectionString:backup:secondary <ConnectionString3>
從程式代碼新增多個端點
類別 ServiceEndpoint
描述 Azure SignalR 服務端點的屬性。
使用 Azure SignalR Service SDK 時,您可以透過下列方式設定多個實例端點:
services.AddSignalR()
.AddAzureSignalR(options =>
{
options.Endpoints = new ServiceEndpoint[]
{
// Note: this is just a demonstration of how to set options.Endpoints
// Having ConnectionStrings explicitly set inside the code is not encouraged
// You can fetch it from a safe place such as Azure KeyVault
new ServiceEndpoint("<ConnectionString0>"),
new ServiceEndpoint("<ConnectionString1>", type: EndpointType.Primary, name: "east-region-a"),
new ServiceEndpoint("<ConnectionString2>", type: EndpointType.Primary, name: "east-region-b"),
new ServiceEndpoint("<ConnectionString3>", type: EndpointType.Secondary, name: "backup"),
};
});
自訂端點路由器
根據預設,SDK 會使用 DefaultEndpointRouter 來挑選端點。
預設行為
用戶端要求路由:
使用應用程式伺服器的用戶端
/negotiate
時。 根據預設,SDK 會隨機從一組可用的服務端點中選取 一個端點。伺服器訊息路由:
將訊息傳送至特定 連線 ,並將目標連線路由傳送至目前伺服器時,訊息會直接傳送至該連線的端點。 否則,訊息會廣播至每個 Azure SignalR 端點。
自定義路由演算法
當您有特殊知識可識別訊息應前往的端點時,您可以建立自己的路由器。
下列範例會定義自定義路由器,以從 開頭 east-
的群組將訊息路由傳送至名為 east
的端點:
private class CustomRouter : EndpointRouterDecorator
{
public override IEnumerable<ServiceEndpoint> GetEndpointsForGroup(string groupName, IEnumerable<ServiceEndpoint> endpoints)
{
// Override the group broadcast behavior, if the group name starts with "east-", only send messages to endpoints inside east
if (groupName.StartsWith("east-"))
{
return endpoints.Where(e => e.Name.StartsWith("east-"));
}
return base.GetEndpointsForGroup(groupName, endpoints);
}
}
下列範例會覆寫預設交涉行為,並根據應用程式伺服器的位置選取端點。
private class CustomRouter : EndpointRouterDecorator
{ public override ServiceEndpoint GetNegotiateEndpoint(HttpContext context, IEnumerable<ServiceEndpoint> endpoints)
{
// Override the negotiate behavior to get the endpoint from query string
var endpointName = context.Request.Query["endpoint"];
if (endpointName.Count == 0)
{
context.Response.StatusCode = 400;
var response = Encoding.UTF8.GetBytes("Invalid request");
context.Response.Body.Write(response, 0, response.Length);
return null;
}
return endpoints.FirstOrDefault(s => s.Name == endpointName && s.Online) // Get the endpoint with name matching the incoming request
?? base.GetNegotiateEndpoint(context, endpoints); // Or fallback to the default behavior to randomly select one from primary endpoints, or fallback to secondary when no primary ones are online
}
}
別忘了使用下列專案向 DI 容器註冊路由器:
services.AddSingleton(typeof(IEndpointRouter), typeof(CustomRouter));
services.AddSignalR()
.AddAzureSignalR(
options =>
{
options.Endpoints = new ServiceEndpoint[]
{
new ServiceEndpoint(name: "east", connectionString: "<connectionString1>"),
new ServiceEndpoint(name: "west", connectionString: "<connectionString2>"),
new ServiceEndpoint("<connectionString3>")
};
});
針對 ASP.NET
從組態新增多個端點
使用金鑰Azure:SignalR:ConnectionString
或 Azure:SignalR:ConnectionString:
SignalR Service 連接字串 進行設定。
如果機碼以 開頭 Azure:SignalR:ConnectionString:
,它的格式應該是 Azure:SignalR:ConnectionString:{Name}:{EndpointType}
,其中 Name
和 EndpointType
是對象的屬性 ServiceEndpoint
,而且可從程式代碼存取。
您可以將多個實體 連接字串 新增至 web.config
:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings>
<add name="Azure:SignalR:ConnectionString" connectionString="<ConnectionString1>"/>
<add name="Azure:SignalR:ConnectionString:en-us" connectionString="<ConnectionString2>"/>
<add name="Azure:SignalR:ConnectionString:zh-cn:secondary" connectionString="<ConnectionString3>"/>
<add name="Azure:SignalR:ConnectionString:Backup:secondary" connectionString="<ConnectionString4>"/>
</connectionStrings>
...
</configuration>
從程式代碼新增多個端點
類別 ServiceEndpoint
描述 Azure SignalR 服務端點的屬性。
使用 Azure SignalR Service SDK 時,您可以透過下列方式設定多個實例端點:
app.MapAzureSignalR(
this.GetType().FullName,
options => {
options.Endpoints = new ServiceEndpoint[]
{
// Note: this is just a demonstration of how to set options. Endpoints
// Having ConnectionStrings explicitly set inside the code is not encouraged.
// You can fetch it from a safe place such as Azure KeyVault
new ServiceEndpoint("<ConnectionString1>"),
new ServiceEndpoint("<ConnectionString2>"),
new ServiceEndpoint("<ConnectionString3>"),
}
});
自定義路由器
ASP.NET SignalR 與 ASP.NET Core SignalR 之間的唯一差異是 的 GetNegotiateEndpoint
http 內容類型。 針對 ASP.NET SignalR,其為 IOwinContext 類型。
下列程式代碼是 ASP.NET SignalR 的自定義交涉範例:
private class CustomRouter : EndpointRouterDecorator
{
public override ServiceEndpoint GetNegotiateEndpoint(IOwinContext context, IEnumerable<ServiceEndpoint> endpoints)
{
// Override the negotiate behavior to get the endpoint from query string
var endpointName = context.Request.Query["endpoint"];
if (string.IsNullOrEmpty(endpointName))
{
context.Response.StatusCode = 400;
context.Response.Write("Invalid request.");
return null;
}
return endpoints.FirstOrDefault(s => s.Name == endpointName && s.Online) // Get the endpoint with name matching the incoming request
?? base.GetNegotiateEndpoint(context, endpoints); // Or fallback to the default behavior to randomly select one from primary endpoints, or fallback to secondary when no primary ones are online
}
}
別忘了使用下列專案向 DI 容器註冊路由器:
var hub = new HubConfiguration();
var router = new CustomRouter();
hub.Resolver.Register(typeof(IEndpointRouter), () => router);
app.MapAzureSignalR(GetType().FullName, hub, options => {
options.Endpoints = new ServiceEndpoint[]
{
new ServiceEndpoint(name: "east", connectionString: "<connectionString1>"),
new ServiceEndpoint(name: "west", connectionString: "<connectionString2>"),
new ServiceEndpoint("<connectionString3>")
};
});
服務端點計量
為了啟用進階路由器,SignalR 伺服器 SDK 提供多個計量,以協助伺服器做出明智的決策。 屬性位於 底下 ServiceEndpoint.EndpointMetrics
。
標準名稱 | 描述 |
---|---|
ClientConnectionCount |
服務端點所有中樞上的並行用戶端連線總數 |
ServerConnectionCount |
服務端點所有中樞上的並行伺服器連線總數 |
ConnectionCapacity |
服務端點的連線配額總計,包括客戶端和伺服器連線 |
下列程式代碼是根據 ClientConnectionCount
自定義路由器的範例。
private class CustomRouter : EndpointRouterDecorator
{
public override ServiceEndpoint GetNegotiateEndpoint(HttpContext context, IEnumerable<ServiceEndpoint> endpoints)
{
return endpoints.OrderBy(x => x.EndpointMetrics.ClientConnectionCount).FirstOrDefault(x => x.Online) // Get the available endpoint with minimal clients load
?? base.GetNegotiateEndpoint(context, endpoints); // Or fallback to the default behavior to randomly select one from primary endpoints, or fallback to secondary when no primary ones are online
}
}
動態調整 ServiceEndpoints
從 SDK 1.5.0 版開始,我們會先啟用 ASP.NET Core 版本的動態調整 ServiceEndpoints。 因此,當您需要新增/移除 ServiceEndpoint 時,不需要重新啟動應用程式伺服器。 由於 ASP.NET Core 支援使用 reloadOnChange: true
的預設appsettings.json
組態,因此您不需要變更程式碼,而且本質上也支援它。 如果您想要新增一些自定義組態並使用熱重載,請參閱 ASP.NET Core 中的設定。
注意
考慮到伺服器/服務和用戶端/服務之間的連線設定時間可能不同,為了確保在調整程序期間不會遺失訊息,我們有暫存期間,等待伺服器連線準備好,再將新的 ServiceEndpoint 開啟給用戶端。 通常需要幾秒鐘的時間才能完成,而且您將能夠看到記錄訊息,例如,表示 Succeed in adding endpoint: '{endpoint}'
進程完成。
在某些情況下,例如不同應用程式伺服器上的跨區域網路問題或設定不一致,暫存期間可能無法正確完成。 在這些情況下,建議您在發現調整程式無法正常運作時重新啟動應用程式伺服器。
調整的預設逾時期間為5分鐘,而且可以藉由變更中的 ServiceOptions.ServiceScaleTimeout
值來自定義。 如果您有許多應用程式伺服器,建議您再擴充一點值。
跨區域案例中的設定
物件 ServiceEndpoint
具有 EndpointType
值為 primary
或 secondary
的屬性。
主要端點是接收用戶端流量的慣用端點,因為它們具有更可靠的網路連線。 次要端點的網路連線較不可靠,而且僅用於伺服器對用戶端流量。 例如,次要端點用於廣播訊息,而不是客戶端到伺服器流量。
在跨區域的情況下,網路可能不穩定。 對於位於美國東部的應用程式伺服器,位於相同美國東部區域的SignalR服務端點是 primary
,而其他區域中的端點則標示為 secondary
。 在此設定中,其他區域中的服務端點可以 接收 來自美國 東部 應用程式伺服器的訊息,但不會 將跨區域 用戶端路由傳送至此應用程式伺服器。 下圖顯示架構:
當客戶端嘗試/negotiate
使用具有預設路由器的應用程式伺服器時,SDK 會隨機從一組可用的primary
端點中選取一個端點。 當主要端點無法使用時,SDK 會 隨機 選取所有可用的 secondary
端點。 當伺服器與服務端點之間的連線運作時,端點會標示為 可用 。
在跨區域案例中,當用戶端嘗試/negotiate
使用裝載在美國東部的應用程式伺服器時,預設一律會primary
傳回位於相同區域的端點。 當所有 美國 東部端點都無法使用時,路由器會將用戶端重新導向至其他區域中的端點。 下列 故障轉移 區段將詳細說明案例。
容錯移轉
當沒有 primary
可用的端點時,用戶端會 /negotiate
從可用的 secondary
端點中挑選。 此故障轉移機制需要每個端點作為至少一個 primary
應用程式伺服器的端點。
下一步
您可以在高可用性和災害復原案例中使用多個端點。
意見反映
https://aka.ms/ContentUserFeedback。
即將推出:我們會在 2024 年淘汰 GitHub 問題,並以全新的意見反應系統取代並作為內容意見反應的渠道。 如需更多資訊,請參閱:提交及檢視以下的意見反映: