Menskalakan SignalR Service dengan beberapa instans

SignalR Service SDK mendukung beberapa titik akhir untuk instans SignalR Service. Anda dapat menggunakan fitur ini untuk menskalakan koneksi serentak, atau menggunakannya untuk olahpesan lintas wilayah.

Untuk ASP.NET Core

Menambahkan beberapa titik akhir dari konfigurasi

Konfigurasikan dengan kunci Azure:SignalR:ConnectionString atau Azure:SignalR:ConnectionString: untuk string koneksi SignalR Service.

Jika kunci dimulai dengan Azure:SignalR:ConnectionString:, kunci harus dalam format Azure:SignalR:ConnectionString:{Name}:{EndpointType}, di mana Name dan EndpointType merupakan properti ServiceEndpoint objek, dan dapat diakses dari kode.

Anda dapat menambahkan beberapa string koneksi instans menggunakan perintah dotnet berikut:

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>

Menambahkan beberapa titik akhir dari kode

Kelas ServiceEndpoint menjelaskan properti titik akhir Azure SignalR Service. Anda dapat mengonfigurasi beberapa titik akhir instans saat menggunakan Azure SignalR Service SDK melalui:

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"),
            };
        });

Menyesuaikan perute titik akhir

Secara default, SDK menggunakan DefaultEndpointRouter untuk mengambil titik akhir.

Perilaku default

  1. Perutean permintaan klien:

    Ketika klien /negotiate dengan server aplikasi. Secara default, SDK memilih secara acak satu titik akhir dari kumpulan titik akhir layanan yang tersedia.

  2. Perutean pesan server:

    Saat mengirim pesan ke koneksi tertentu dan koneksi target dirutekan ke server saat ini, pesan langsung masuk ke titik akhir yang tersambung tersebut. Jika tidak, pesan disiarkan ke setiap titik akhir Azure SignalR.

Menyesuaikan algoritma perutean

Anda dapat membuat router Anda sendiri ketika Anda memiliki pengetahuan khusus untuk mengidentifikasi ke titik akhir mana pesan akan masuk.

Contoh berikut mendefinisikan router kustom yang merutekan pesan dengan grup yang dimulai dengan east- ke titik akhir bernama 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);
    }
}

Contoh berikut mengambil alih perilaku negosiasi default dan memilih titik akhir tergantung pada lokasi server aplikasi.

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
    }
}

Jangan lupa untuk mendaftarkan router ke kontainer DI menggunakan:

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>")
                };
            });

Untuk ASP.NET

Menambahkan beberapa titik akhir dari konfigurasi

Konfigurasi dengan kunci Azure:SignalR:ConnectionString atau Azure:SignalR:ConnectionString: untuk string koneksi SignalR Service.

Jika diawali dengan Azure:SignalR:ConnectionString:, kunci harus dalam format Azure:SignalR:ConnectionString:{Name}:{EndpointType}, di mana Name dan EndpointType adalah properti objek ServiceEndpoint, dan dapat diakses dari kode.

Anda dapat menambahkan beberapa string koneksi instans ke 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>

Menambahkan beberapa titik akhir dari kode

Kelas ServiceEndpoint menjelaskan properti titik akhir Azure SignalR Service. Anda dapat mengonfigurasi beberapa titik akhir instans saat menggunakan Azure SignalR Service SDK melalui:

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>"),
            }
        });

Menyesuaikan perute

Satu-satunya perbedaan antara ASP.NET SignalR dan ASP.NET Core SignalR adalah jenis konteks http untuk GetNegotiateEndpoint. Untuk ASP.NET SignalR, jenisnya adalah IOwinContext.

Kode berikut adalah contoh negosiasi kustom untuk 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
    }
}

Jangan lupa untuk mendaftarkan router ke kontainer DI menggunakan:

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>")
                };
});

Metrik Titik Akhir Layanan

Untuk mengaktifkan router tingkat lanjut, SignalR server SDK menyediakan beberapa metrik untuk membantu server membuat keputusan cerdas. Properti berada di bawah ServiceEndpoint.EndpointMetrics.

Nama Metrik Deskripsi
ClientConnectionCount Jumlah total koneksi klien bersamaan di semua hub untuk titik akhir layanan
ServerConnectionCount Jumlah total koneksi server bersamaan di semua hub untuk titik akhir layanan
ConnectionCapacity Total kuota koneksi untuk titik akhir layanan, termasuk koneksi klien dan server

Kode berikut adalah contoh penyesuaian router menurut 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
    }
}

Dynamic Scale ServiceEndpoints

Dari SDK versi 1.5.0, kami mengaktifkan ServiceEndpoints skala dinamis untuk versi ASP.NET Core terlebih dahulu. Jadi Anda tidak perlu menghidupkan ulang server aplikasi saat Anda perlu menambahkan/menghapus ServiceEndpoint. Karena ASP.NET Core mendukung konfigurasi default seperti appsettings.json , reloadOnChange: trueAnda tidak perlu mengubah kode, dan didukung oleh alam. Dan jika Anda ingin menambahkan beberapa konfigurasi yang disesuaikan dan bekerja dengan hot-reload, lihat Konfigurasi di ASP.NET Core.

Catatan

Mengingat waktu penyiapan koneksi antara server/layanan dan klien/layanan mungkin berbeda, untuk memastikan tidak ada kehilangan pesan selama proses skala, kami memiliki periode penahapan yang menunggu koneksi server siap sebelum membuka ServiceEndpoint baru kepada klien. Biasanya dibutuhkan beberapa detik untuk menyelesaikannya dan Anda akan dapat melihat pesan log seperti Succeed in adding endpoint: '{endpoint}' yang menunjukkan proses selesai.

Dalam beberapa situasi yang diharapkan, seperti masalah jaringan lintas wilayah atau inkonsistensi konfigurasi di server aplikasi yang berbeda, periode penahapan mungkin tidak selesai dengan benar. Dalam kasus ini, disarankan untuk memulai ulang server aplikasi saat Anda menemukan proses penskalaan tidak berfungsi dengan benar.

Periode batas waktu default untuk skala adalah 5 menit, dan dapat disesuaikan dengan mengubah nilai dalam ServiceOptions.ServiceScaleTimeout. Jika Anda memiliki banyak server aplikasi, disarankan untuk memperluas nilai sedikit lebih banyak.

Konfigurasi dalam skenario lintas wilayah

Objek ServiceEndpoint memiliki properti EndpointType dengan nilai primary atau secondary.

Titik akhir utama adalah titik akhir pilihan untuk menerima lalu lintas klien karena memiliki koneksi jaringan yang lebih andal. Titik akhir sekunder memiliki koneksi jaringan yang kurang andal dan hanya digunakan untuk lalu lintas server ke klien. Misalnya, titik akhir sekunder digunakan untuk menyiarkan pesan alih-alih lalu lintas klien ke server.

Dalam kasus lintas wilayah, jaringan dapat tidak stabil. Untuk server aplikasi yang terletak di US Timur, titik akhir SignalR Service yang terletak di wilayah US Timur yang sama adalah primary dan titik akhir di wilayah lain yang ditandai sebagai secondary. Dalam konfigurasi ini, titik akhir layanan di wilayah lain dapat menerima pesan dari server aplikasi US Timur ini, tetapi tidak ada klien lintas wilayah yang dirutekan ke server aplikasi ini. Diagram berikut menunjukkan arsitektur ini:

Infra Lintas Geografis

Saat klien mencoba /negotiate dengan server aplikasi dengan router default, SDK secara acak memilih satu titik akhir dari kumpulan titik akhir yang tersedia primary . Saat titik akhir utama tidak tersedia, SDK kemudian secara acak memilih dari semua titik akhir yang tersedia secondary . Titik akhir ditandai sebagai tersedia jika koneksi antara server dan titik akhir layanan masih aktif.

Dalam skenario lintas wilayah, ketika klien mencoba /negotiate dengan server aplikasi yang dihosting di US Timur, secara default selalu mengembalikan primary titik akhir yang terletak di wilayah yang sama. Ketika semua titik akhir US Timur tidak tersedia, router mengalihkan klien ke titik akhir di wilayah lain. Bagian failover berikut menjelaskan skenario secara rinci.

Negosiasi Normal

Failover

Ketika tidak ada primary titik akhir yang tersedia, klien /negotiate memilih dari titik akhir yang tersedia secondary . Mekanisme failover ini mengharuskan setiap titik akhir berfungsi sebagai primary titik akhir ke setidaknya satu server aplikasi.

Diagram memperlihatkan proses mekanisme Failover.

Langkah berikutnya

Anda dapat menggunakan beberapa titik akhir dalam skenario ketersediaan tinggi dan pemulihan bencana.