访问限流对于一个网关来说是个比较重要的功能,它可以根据不同服务的处理能力来控制相关的访问量,从而保障服务更可靠地运行。但是URL控制的路径比较多还加上可动态添加删除,大量的访问匹配会很容易引起性能上的问题,接下来讲解一下Beetlex的网关是如何实现,并得到一个更好的处理性能。
对于一个API服务来说它的接口非常多,当根据不同接口定义访问控制的时候每次请求都会匹配一下URL然后进行访问控制,当访问量比较大的时候这个字符匹配损耗是非常大的;解决这种问题可以对URL策略对象进行一个缓存,但缓存有一个延时性的问题,毕竟策略可以随意添加或删除,这时候当前URL的处理策略是否有效就存在一些延时问题了。接下介绍一下Beetlex的网关设计是怎样解决性能问题又能处理缓存的延时性问题。
Beetlex在设计的时候引入了策略代理和版本问题,当网关接收到请求会拿到当前URL策略代理的缓存,然后再对比一下当前代理的版本和配置策略的版本是否一致,当一致的情况下直接用策略代理计数并判断处理,否则重匹配策略生成代理写入到缓存中。看上去有些复杂,实际代码非常简单
private void OnRefreshTable()
{lock (this){var items = (from a in mLimitTable.Valuesorderby a.Url.Length descendingselect a).ToArray();if (items == null){items = new UrlLimitRecord[0];}mUrlTables = items;System.Threading.Interlocked.Increment(ref mVersion);}
}public void AddUrl(string url, int maxrps)
{mLimitTable[url] = new UrlLimitRecord { Url = url, MaxRPS = maxrps };OnRefreshTable();
}public void RemoveUrl(string url)
{mLimitTable.TryRemove(url, out UrlLimitRecord result);OnRefreshTable();
}
在策略容器中添加一个版本号,当有修改的情况重新刷新匹配表和修改版本号。接下来在获取策略的时候做一下判断即可:
internal UrlLimitAgent Match(string url)
{if (mCachedLimitTable.TryGetValue(url, out UrlLimitAgent result)){if (result.Version == Version)return result;}var items = mUrlTables;result = new UrlLimitAgent();foreach (var item in items){if (url.IndexOf(item.Url, StringComparison.CurrentCultureIgnoreCase) >= 0){result.RpsLimit = new RpsLimit(item.MaxRPS);result.Config = item;}}result.Version = System.Threading.Interlocked.Add(ref mVersion, 0);mCachedLimitTable[url] = result;return result;
}
从缓存表中获取代理,当获取成功后判断一下版本号,如果一致就返回否则重新匹配并更新到缓存中。
当看完以上代码是不是感觉非常简单,Beetlex网关的限流策略基本用这种方式进行设计和使用,以下是Beetlex网关的限流功能
if (!CheckIPTable(request, response))return;
if (!CheckDomains(request))
{if (string.IsNullOrEmpty(Options.InvalidDomainUrl)){response.InnerError("509", "Invalid domain name!");}else{Move302Result result = new Move302Result(Options.InvalidDomainUrl);response.Result(result);}return;
}
HttpToken token = (HttpToken)request.Session.Tag;
if (token.HttpRpsLimit.Check(this.Options.SessionMaxRps))
{response.InnerError("509", "session max rps limit!");return;
}
if (!mIPLimit.ValidateRPS(request))
{response.InnerError("509", $"{request.RemoteIPAddress} max rps limit!");return;
}
if (!CheckUrlLimit(request, response))return;
if (!CheckDomainsLimit(request, response))return;
if (RpsLimitHandlers.Count > 0)foreach (var handler in RpsLimitHandlers.Values){if (handler.Check(request, response)){response.InnerError("509", $"{handler.Name} max rps limit!");return;}}if (AllRpsLimit.Check(this.Options.MaxRps))
{response.InnerError("509", "server max rps limit!");return;
}
BeetleX
开源跨平台通讯框架(支持TLS)
提供高性能服务和大数据处理解决方案
https://beetlex-io.com