1. 程式人生 > 其它 >多租戶系統中如何實現分別限流

多租戶系統中如何實現分別限流

限流是後端服務開發中經常要整合的一個功能,對於防範系統因壓力過大導致崩潰特別有用。在多租戶系統中,限流對於限制單個租戶使用的資源量也特別有用,這篇文章就來一探究竟。

限流是後端服務開發中經常要整合的一個功能,對於防範系統因壓力過大導致崩潰特別有用。在多租戶系統中,限流對於限制單個租戶使用的資源量也特別有用,這篇文章就來一探究竟。

問題

對於一個多租戶系統,某些租戶如果使用了過多的資源,很可能會對其它租戶造成影響。比如對於某個資源的查詢,系統的最高容量是300qps,假設正常情況下租戶的查詢水位都在10qps,此時可以同時為30個租戶服務;突然某個租戶的查詢水位上升到100qps,如果系統沒有限流,系統會變慢甚至可能崩潰,如果系統有限流,所有的租戶都可能受到限流的影響。

租戶的查詢水位突然暴漲可能是正常業務,也可能是惡意攻擊,不過無論哪種情況對其它租戶來說都是不公平的。這時候就可以對不同的租戶分別限流,下面就來看一下如何解決。

原理

下面這張圖演示了對多租戶系統進行限流的原理:

租戶A、B、C分別發起服務請求,服務中首先對使用者身份進行鑑別,身份驗證通過的進入限流檢查環節,對每個租戶分別進行限流檢查,如果未達到限流閾值,則可以通過進入下一步,如果達到了限流閾值,則終止處理並返回錯誤給租戶。

實現

如果你已經看懂了原理,相信你完全有能力寫出對應的限流控制邏輯。不過為了研發效率,還是應該儘可能重用現有的元件,這裡使用FireflySoft.RateLimit來實現這一邏輯,演示程式碼是以ASP.NET Core為基礎的,你也可以在任何其它.NET網路服務框架中使用,甚至自己手寫的專用處理程式。

安裝Nuget包

使用包管理器控制檯:

Install-Package FireflySoft.RateLimit.AspNetCore

或者使用 .NET CLI:

dotnet add package FireflySoft.RateLimit.AspNetCore

或者直接新增到專案檔案中:

<ItemGroup>
<PackageReference Include="FireflySoft.RateLimit.AspNetCore" Version="2.*" />
</ItemGroup>

使用中介軟體

在Startup.cs中註冊限流服務並使用限流中介軟體。

public void ConfigureServices(IServiceCollection services)
{
    ...

    services.AddRateLimit(new InProcessFixedWindowAlgorithm(
        new[] {
            new FixedWindowRule()
            {
                Id = "1",
                ExtractTarget = context =>
                {
                    // 這裡假設限流的目標是租戶的使用者Id,它是從HTTP Header中傳遞過來的
                    return (context as HttpContext).Request.GetTypedHeaders().Get<string>("userId");
                },
                CheckRuleMatching = context =>
                {
                    // 假設只對 /Weather/GetToday 這個介面請求進行限流
                    var path = (context as HttpContext).Request.Path.Value;
                    if(path == "/Weather/GetToday"){
                        return true;
                    }
                    return false;
                },
                Name="多租戶限流",
                LimitNumber=10, // 限流閾值
                StatWindow=TimeSpan.FromSeconds(1), //限流的時間視窗,這裡是1秒
                StartTimeType=StartTimeType.FromNaturalPeriodBeign
            }
        })
    );

    ...
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    ...

    app.UseRateLimit();

    ...
}

搞定這兩步,多租戶分別限流功能就可以正常運轉了。

這裡對所有租戶都使用了相同的限流閾值,如果租戶有特權租戶和普通租戶的區別,則可以在上邊的限流規則中分別為特權租戶和普通租戶定義不同的規則就可以了,具體可以參考這篇文章:ASP.NET Core中如何對不同型別的使用者進行區別限流

其它技術問題

注意這裡使用的限流演算法是程序內固定視窗限流,如果你需要在分散式環境下統一計數限流,則可以使用FireflySoft.RateLimit自帶的Redis固定視窗限流演算法,不過你需要先有一個Redis服務。

固定視窗演算法比較剛性,實際情況下,請求很可能是不均勻的,一會多一會少,剛性演算法很難設定一個合理的限流閾值。如果你想要允許一定的突發流量,則可以使用滑動視窗、漏桶、令牌桶等演算法,FireflySoft.RateLimit中已經集成了這些演算法,直接使用即可。

如果系統的服務能力增強了,現在允許一個租戶每秒發起20次請求,則需要調整規則,FireflySoft.RateLimit底層是支援動態調整規則的,具體可以看這篇文章:.NET6執行時動態更新限流


好了,以上就是本文的主要內容了。如有興趣,歡迎訪問開源倉庫:https://github.com/bosima/FireflySoft.RateLimit