Skip to content

Commit

Permalink
- 实现服务限流功能
Browse files Browse the repository at this point in the history
- 支持自定义限流
- 支持限流自定义模板
  • Loading branch information
239573049 committed Apr 11, 2024
1 parent 7303862 commit e0d2ae5
Show file tree
Hide file tree
Showing 21 changed files with 1,084 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public sealed class StatisticsBackgroundService(IServiceProvider serviceProvider
Channel.CreateUnbounded<StatisticRequestCountDto>();

private static readonly ConcurrentDictionary<string, StatisticRequestCountDto> RequestCountDic = new(-1, 5);
private static readonly ConcurrentDictionary<string, StatisticIpDto> IpDic = new();
private static readonly ConcurrentDictionary<string, StatisticIpDto> IpDic = new(-1,5);

private static readonly Channel<StatisticIpDto> StatisticIpChannel = Channel.CreateUnbounded<StatisticIpDto>();

Expand Down
3 changes: 2 additions & 1 deletion src/FastGateway/Domain/Location.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
/// 服务节点管理
/// </summary>
[Table(Name = "location")]
[Index("location_serviceid", "ServiceId")]
public class Location
{
public string Id { get; set; }
Expand Down Expand Up @@ -35,7 +36,7 @@ public sealed class LocationService
/// </summary>
[Column(MapType = typeof(string), StringLength = -1)]
public Dictionary<string, string> AddHeader { get; set; } = new();

/// <summary>
/// 静态文件或目录
/// </summary>
Expand Down
85 changes: 57 additions & 28 deletions src/FastGateway/Domain/RateLimit.cs
Original file line number Diff line number Diff line change
@@ -1,62 +1,91 @@
using System.Threading.RateLimiting;

namespace FastGateway.Domain;
namespace FastGateway.Domain;

public sealed class RateLimit
{
public RateLimitType Type { get; set; }

#region 固定窗口限制器
/// <summary>
/// 限流策略名称
/// </summary>
[Column(IsIdentity = true)]
public string Name { get; set; }

public int? PermitLimit { get; set; }
/// <summary>
/// 是否启用
/// </summary>
public bool Enable { get; set; }

/// <summary>
/// 限流时间窗口
/// 通用规则列表
/// </summary>
public TimeSpan? Window { get; set; }
[Column(MapType = typeof(string), StringLength = -1)]
public List<GeneralRules> GeneralRules { get; set; }

/// <summary>
/// QueueProcessingOrder
/// 端点白名单
/// </summary>
public QueueProcessingOrder? QueueProcessingOrder { get; set; }
[Column(MapType = typeof(string), StringLength = -1)]
public List<string> EndpointWhitelist { get; set; }

/// <summary>
/// QueueLimit
/// 客户端ID头部
/// </summary>
public int? QueueLimit { get; set; }
public string ClientIdHeader { get; set; } = "X-ClientId";

#endregion
/// <summary>
/// 客户端白名单
/// </summary>
[Column(MapType = typeof(string), StringLength = -1)]
public List<string> ClientWhitelist { get; set; }

#region 滑动窗口限制器
/// <summary>
/// 真实IP头部
/// </summary>
public string RealIpHeader { get; set; } = "X-Real-IP";

/// <summary>
/// SegmentsPerWindow
/// IP白名单
/// </summary>
public int? SegmentsPerWindow { get; set; }
[Column(MapType = typeof(string), StringLength = -1)]
public List<string> IpWhitelist { get; set; }

#endregion
/// <summary>
/// HTTP状态码
/// </summary>
public int HttpStatusCode { get; set; } = 429;

#region 令牌桶限制器
/// <summary>
/// 超出配额消息
/// </summary>
public string QuotaExceededMessage { get; set; }

/// <summary>
/// TokenLimit
/// 错误内容类型
/// </summary>
public int? TokenLimit { get; set; }
public string RateLimitContentType { get; set; } = "text/html";

/// <summary>
/// TokensPerPeriod
/// 速率限制计数器前缀
/// </summary>
public int? TokensPerPeriod { get; set; }
public string RateLimitCounterPrefix { get; set; } = "crlc";

/// <summary>
/// AutoReplenishment
/// 启用端点速率限制
/// </summary>
public bool? AutoReplenishment { get; set; }
public bool EnableEndpointRateLimiting { get; set; }

#endregion
/// <summary>
/// 禁用速率限制头部
/// </summary>
public bool DisableRateLimitHeaders { get; set; }

/// <summary>
/// 拒绝响应状态码
/// 启用正则规则匹配
/// </summary>
public int RejectionStatusCode { get; set; }
public bool EnableRegexRuleMatching { get; set; }
}

public class GeneralRules
{
public string Endpoint { get; set; }
public string Period { get; set; }
public int Limit { get; set; }
}
8 changes: 7 additions & 1 deletion src/FastGateway/Domain/Service.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using FreeSql.DataAnnotations;
using System.ComponentModel.DataAnnotations;
using FreeSql.DataAnnotations;

namespace FastGateway.Domain;

Expand Down Expand Up @@ -56,4 +57,9 @@ public class Service
/// </summary>
[Navigate(nameof(Location.ServiceId))]
public virtual List<Location> Locations { get; set; }

public string? RateLimitName { get; set; }

[Column(IsIgnore = true)]
public virtual RateLimit? RateLimit { get; set; }
}
3 changes: 3 additions & 0 deletions src/FastGateway/Domain/StatisticIp.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
namespace FastGateway.Domain;

[Table(Name = "statistic_ip")]
[Index("statistic_ip_year", "Year")]
[Index("statistic_ip_month", "Month")]
[Index("statistic_ip_day", "Day")]
public sealed class StatisticIp
{
[Column(IsIdentity = true)]
Expand Down
3 changes: 3 additions & 0 deletions src/FastGateway/Domain/StatisticRequestCount.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
namespace FastGateway.Domain;

[Table(Name = "statistic_request_count")]
[Index("statistic_request_count_year", "Year")]
[Index("statistic_request_count_month", "Month")]
[Index("statistic_request_count_day", "Day")]
public sealed class StatisticRequestCount
{
[Column(IsIdentity = true)]
Expand Down
2 changes: 2 additions & 0 deletions src/FastGateway/Dto/ServiceInput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ public class ServiceInput
/// </summary>
public bool EnableTunnel { get; set; }

public string RateLimitName { get; set; }

/// <summary>
/// 服务配置
/// </summary>
Expand Down
1 change: 1 addition & 0 deletions src/FastGateway/FastGateway.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
<PackageReference Include="Certes" Version="3.0.4" />
<PackageReference Include="FreeSql.Provider.Sqlite" Version="3.2.820" />
<PackageReference Include="IP2Region.Net" Version="2.0.2" />
Expand Down
36 changes: 32 additions & 4 deletions src/FastGateway/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@
}
var freeSql = new FreeSqlBuilder()
.UseConnectionString(DataType.Sqlite, @default)
.UseConnectionString(DataType.Sqlite, @default)
#if DEBUG
.UseMonitorCommand(cmd => Console.WriteLine($"Sql:{cmd.CommandText}"))
.UseMonitorCommand(cmd => Console.WriteLine($"Sql:{cmd.CommandText}"))
#endif
.UseAutoSyncStructure(true)
.Build();
.UseAutoSyncStructure(true)
.Build();
return freeSql;
});
Expand Down Expand Up @@ -92,6 +92,9 @@
Utils.TypeHandlers.TryAdd(typeof(List<LocationService>),
new LocationServiceHandler());

Utils.TypeHandlers.TryAdd(typeof(List<GeneralRules>)
, new StringJsonHandler<List<GeneralRules>>());

#endregion

freeSql.CodeFirst.SyncStructure<Service>();
Expand All @@ -100,6 +103,7 @@
freeSql.CodeFirst.SyncStructure<StatisticRequestCount>();
freeSql.CodeFirst.SyncStructure<StatisticIp>();
freeSql.CodeFirst.SyncStructure<Location>();
freeSql.CodeFirst.SyncStructure<RateLimit>();

await ProtectionService.LoadBlacklistAndWhitelistAsync(freeSql);

Expand Down Expand Up @@ -264,6 +268,30 @@

#endregion


#region RateLimit

var rateLimitService = app.MapGroup("/api/v1/RateLimit")
.RequireAuthorization()
.AddEndpointFilter<ExceptionFilter>();

rateLimitService.MapPost(string.Empty,
RateLimitService.CreateAsync);

rateLimitService.MapPut("{name}",
RateLimitService.UpdateAsync);

rateLimitService.MapDelete("{name}",
RateLimitService.DeleteAsync);

rateLimitService.MapGet("/List",
RateLimitService.GetListAsync);

rateLimitService.MapGet("/Names",
RateLimitService.GetNamesAsync);

#endregion

FastContext.SetQpsService(app.Services.GetRequiredService<IQpsService>(),
app.Services.GetRequiredService<IMemoryCache>());

Expand Down
Loading

0 comments on commit e0d2ae5

Please sign in to comment.