Viper 是.NET平臺下的Anno微服務框架的一個示例項目。入門簡單、安全、穩定、高可用、全平臺可監控。底層通信能夠隨意切換thrift
grpc
。 自帶服務發現、調用鏈追蹤、Cron 調度、限流、事件總線、CQRS 、DDD、相似MVC的開發體驗,插件化開發html
一個不可監控
的微服務平臺是可怕的
,出了問題 難以準肯定位問題的根源, Anno則提供了一套完整的監控體系,包括鏈路追蹤
、服務佔用的系統資源
、系統自身 CPU、內存、硬盤使用率
實時可監控等等。git
今天要說的是.netcore 微服務Viper的限流,防止惡意攻擊,作一個打不死的小強。github
若是對Viper不瞭解的能夠看上篇文章瞭解 net core 微服務 快速開發框架 Viper 初體驗算法
github:
https://github.com/duyanming/Viper
文檔地址:
https://duyanming.github.io/express
體驗地址:(體驗用戶爲anno 密碼123456 同一時間一個用戶只能在一個終端登陸用戶多的時候可能發生強制退出的狀況,稍後登陸體驗)
http://140.143.207.244/緩存
限流用到兩個庫 Anno.RateLimit、IPAddressRange。Anno.RateLimit爲限流組件,IPAddressRange爲IP匹配組件。安全
IPAddressRange地址:https://github.com/jsakamoto/ipaddressrange框架
using NetTools; ... // rangeA.Begin is "192.168.0.0", and rangeA.End is "192.168.0.255". var rangeA = IPAddressRange.Parse("192.168.0.0/255.255.255.0"); rangeA.Contains(IPAddress.Parse("192.168.0.34")); // is True. rangeA.Contains(IPAddress.Parse("192.168.10.1")); // is False. rangeA.ToCidrString(); // is 192.168.0.0/24 // rangeB.Begin is "192.168.0.10", and rangeB.End is "192.168.10.20". var rangeB1 = IPAddressRange.Parse("192.168.0.10 - 192.168.10.20"); rangeB1.Contains(IPAddress.Parse("192.168.3.45")); // is True. rangeB1.Contains(IPAddress.Parse("192.168.0.9")); // is False. // Support shortcut range description. // ("192.168.10.10-20" means range of begin:192.168.10.10 to end:192.168.10.20.) var rangeB2 = IPAddressRange.Parse("192.168.10.10-20"); // Support CIDR expression and IPv6. var rangeC = IPAddressRange.Parse("fe80::/10"); rangeC.Contains(IPAddress.Parse("fe80::d503:4ee:3882:c586%3")); // is True. rangeC.Contains(IPAddress.Parse("::1")); // is False. // "Contains()" method also support IPAddressRange argument. var rangeD1 = IPAddressRange.Parse("192.168.0.0/16"); var rangeD2 = IPAddressRange.Parse("192.168.10.0/24"); rangeD1.Contains(rangeD2); // is True. // IEnumerable<IPAddress> support, it's lazy evaluation. foreach (var ip in IPAddressRange.Parse("192.168.0.1/23")) { Console.WriteLine(ip); } // You can use LINQ via "AsEnumerable()" method. var longValues = IPAddressRange.Parse("192.168.0.1/23") .AsEnumerable() .Select(ip => BitConvert.ToInt32(ip.GetAddressBytes(), 0)) .Select(adr => adr.ToString("X8")); Console.WriteLine(string.Join(",", longValues); // Constructors from IPAddress objects. var ipBegin = IPAddress.Parse("192.168.0.1"); var ipEnd = IPAddress.Parse("192.168.0.128"); var ipSubnet = IPAddress.Parse("255.255.255.0"); var rangeE = new IPAddressRange(); // This means "0.0.0.0/0". var rangeF = new IPAddressRange(ipBegin, ipEnd); var rangeG = new IPAddressRange(ipBegin, maskLength: 24); var rangeH = new IPAddressRange(ipBegin, IPAddressRange.SubnetMaskLength(ipSubnet)); // Calculates Cidr subnets var rangeI = IPAddressRange.Parse("192.168.0.0-192.168.0.254"); rangeI.ToCidrString(); // is 192.168.0.0/24
Anno.RateLimit限流組件的使用微服務
Anno.RateLimit支持令牌桶和漏桶兩種算法post
using System; using System.Collections.Generic; using System.Text; using System.Threading; using System.Threading.Tasks; using Anno.RateLimit; namespace ConsoleTest { /// <summary> /// 限流測試 /// </summary> public class RateLimitTest { /// <summary> /// 限流測試 /// </summary> public void Handle() { var service = LimitingFactory.Build(TimeSpan.FromSeconds(1),LimitingType.TokenBucket, 20, 5); Console.Write("請輸入線程數:"); long.TryParse(Console.ReadLine(), out long th); for (int i = 0; i < th; i++) { var t = Task.Factory.StartNew(() => { while (true) { var result = service.Request(); //若是返回true,說明能夠進行業務處理,不然須要繼續等待 if (result) { Console.WriteLine($"{DateTime.Now}--{Task.CurrentId}---ok"); //業務處理...... } else Thread.Sleep(100); } }, TaskCreationOptions.LongRunning); } } } }
下圖是用Jmeter測試線上http://140.143.207.244/ 的截圖,下圖紅色部分爲限流直接返回失敗的記錄,調用方爲 NewApi目標服務爲NewApi能夠看到返回的信息爲Trigger current limiting,
經過限流保證Viper成爲一個打不死的小強
配置Viper的限流
{ "Target": { "AppName": "ApiGateway", "IpAddress": "127.0.0.1", "Port": 7010, "TraceOnOff": true }, "Limit": { "Enable": true, "TagLimits": [ { "channel": "*", "router": "*", "timeSpan": "1",//限流週期單位秒 "rps": 100,//週期內經過的請求個數 "limitSize": 100//令牌桶,漏桶池子大小 } ], "IpLimit": {//ip限流 "timeSpan": 1,//限流週期單位秒 "rps": 100,//週期內經過的請求個數 "limitSize": 100//池子大小 }, "White": [//白名單 用法能夠參考IPAddressRange "0.0.0.1", "192.168.1.2", "192.168.2.18" ], "Black": [//黑名單 "0.0.0.2", "192.168.3.18" ] } }
Limit.Enable:是否啓用限流
Limit.TagLimits:根據Tag限流
channel: Anno.Plugs.Logic//請求tag 必須參數 router: Platform //模塊名稱(沒有Module) 必須參數 method: GetFunc //模塊方法 必須參數 profile: fSFhFv5d4ZlC/JTz1EvoBDNWTr+sNtAhKWTuykqfZHU2oB8/W7aUayqsXmFJXPlR uname: yrm
Limit.IpLimit:根據客戶端Ip限流
Limit.White:白名單
Limit.IpLimit:黑名單
關於更多的Viper限流細節可參考github:https://github.com/duyanming/Viper/blob/master/Viper/Extensions/Middleware/DymWebHostBuilderExtensions.cs
以上分享了,Viper網關的限流。後面分享每一個微服務如何經過註解方式限流、以及請求緩存、ViperService的 全局過濾器、模塊過濾器、方法過濾器。
過濾器類型有,受權過濾器、異常過濾器、Action過濾器。 Anno.EngineData.Filters
兩種經常使用算法
令牌桶(Token Bucket)和漏桶(leaky bucket)是 最經常使用的兩種限流的算法。
令牌桶主要是控制注入的速度,漏桶則是控制出的速度。
漏桶算法
令牌桶算法
關於更多限流只是可參考:
張善友博客:http://www.javashuo.com/article/p-gdjhqapi-ch.html
凌晨三點半:http://www.javashuo.com/article/p-vcvchlyt-bn.html
Viper
github:
https://github.com/duyanming/Viper
文檔地址:
https://duyanming.github.io/
體驗地址:(體驗用戶爲anno 密碼123456 同一時間一個用戶只能在一個終端登陸用戶多的時候可能發生強制退出的狀況,稍後登陸體驗)
http://140.143.207.244/
關於Viper的更多內容,隨後更新。敬請關注。開源不易,感謝Star。