在一般的互联网应用中限流是一个比较常见的场景,也有很多常见的方式可以实现对应用的限流比如通过令牌桶通过滑动窗口等等方式都可以实现,也可以在整个请求流程中进行限流比如客户端限流就是在客户端通过随机数直接返回成功失败来决定是否发起请求。也可以在网关层直接根据一定策略丢弃一部分流量达到限流的目的,亦可请求到业务端后由业务端判断是否进行限流。而一般的service mesh框架会在代理的sidecar部分完成限流的工作。今天就讲讲dapr是如何通过简易的配置来实现一个限流的。
目录:
一、通过Dapr实现一个简单的基于.net的微服务电商系统
二、通过Dapr实现一个简单的基于.net的微服务电商系统(二)——通讯框架讲解
三、通过Dapr实现一个简单的基于.net的微服务电商系统(三)——一步一步教你如何撸Dapr
四、通过Dapr实现一个简单的基于.net的微服务电商系统(四)——一步一步教你如何撸Dapr之订阅发布
通过Dapr实现一个简单的基于.net的微服务电商系统(五)——一步一步教你如何撸Dapr之状态管理
通过Dapr实现一个简单的基于.net的微服务电商系统(六)——一步一步教你如何撸Dapr之Actor服务
附录:(如果你觉得对你有用,请给个star)
一、电商Demo地址:https://github.com/sd797994/Oxygen-Dapr.EshopSample
二、通讯框架地址:https://github.com/sd797994/Oxygen-Dapr
Dapr限流包含两种模式,一种是客户端限流,一种是服务端限流。
客户端限流简单来讲就是对下游服务的一种限流保护,举个例子比如我的网关要保护后面的所有服务,我可以配置一个ratelimit的component下游限流注入到网关的sidecar中,Dapr会为流经该网关实例的流量的下游服务根据远程IP和路径进行限流,确保单位时间内最大请求数被限制在规定范围之内。
下面我们就来模拟这种限流模式,首先我们创建一个类型为middleware.http.ratelimit的Component,其metadata可以设置一个maxRequestsPerSecond参数,代表每秒流经该sidecar的请求最大能通过多少前往下游服务。如果超出这个请求,则sidecar会直接返回一个429响应码提示客户端请求过多
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:name: ratelimit
spec:type: middleware.http.ratelimitversion: v1metadata:- name: maxRequestsPerSecondvalue: 1
接着我们配置一个Configuration并注入到clientsample的deployment中(注意红字部分)
apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:name: appconfig
spec:httpPipeline:handlers:- name: ratelimittype: middleware.http.ratelimit
apiVersion: apps/v1
kind: Deployment
metadata:name: clientsamplelabels:app: clientsample
spec: replicas: 1selector:matchLabels:app: clientsampletemplate: metadata:labels: app: clientsampleannotations:dapr.io/enabled: "true"dapr.io/app-id: "clientsample"dapr.io/app-port: "80"dapr.io/config: "appconfig"spec:containers:- name: webimage: clientsample:releaseimagePullPolicy: Neverports:- containerPort: 80
现在我们在代码中,让clientsample通过多现成同时发起10个下游请求
public async Task<dynamic> Call(){var result1 = new OutDto();var remoteService = serviceProxyFactory.CreateProxy<IHelloService>();var tasks = new Task<OutDto>[10];for (int i = 0; i < 10; i++){tasks[i] = remoteService.HelloWorldByName(new InputDto() { Name = "xiaoming" });}await Task.WhenAll(tasks);foreach (var item in tasks){Console.WriteLine($"result is :{(item.GetAwaiter().GetResult().Word ?? "noresult")}");}return "操作完成";}
可以看到并发访问10条task,只有1条返回了result,其余的请求发送到自己的sidecar后就直接返回429然后被通讯框架捕获429后抛到日志中。
接下来我们看看服务端模式,服务端模式顾名思义就是保护自己,确保所有流向自己的请求会以一个限定频率被处理,有点类似于C#的semaphore,通过信号量来阻塞线程并发访问数。注意该模式并不是通过限制每秒流量来实现的,而是指同时只能有多个请求被处理。
接着我们看看yaml需要调整的部分,通过dapr.io/app-max-concurrency参数即可实现并发数控制
apiVersion: apps/v1
kind: Deployment
metadata:name: servicesamplelabels:app: servicesample
spec: replicas: 1selector:matchLabels:app: servicesampletemplate: metadata:labels: app: servicesampleannotations:dapr.io/enabled: "true"dapr.io/app-id: "servicesample"dapr.io/app-port: "80"dapr.io/app-max-concurrency: "1"spec:containers:- name: webimage: servicesample:releaseimagePullPolicy: Neverports:- containerPort: 80
clientsample不用修改,我们在servicesample的方法中增加以下模拟耗时操作
重新生成后(注意需要删除之前配置在clientsample上的dapr.io/config),我们通过postman模拟发起请求:
可以看到请求全部都执行成功并获取回调了,但是整个请求耗时是10秒,恰好就是一次处理1个请求,单个请求耗时1秒得到的结果,我们可以再次验证一下将app-max-concurrency设置为2,应该会5秒请求完毕:
可以看到信号量每次放入了两个线程同步处理,我们的请求确实被压缩到了5秒处理完毕。
整个限流其实分为下游限流+并发控制两种方式,其实都是为了保护自己/下游服务。另外大家注意一下如果你的请求并不是通过sidecar进入到服务的比如直接暴露服务端口到network或通过ingress+service的方式访问应用也就是说流量不走sidecar,则无法通过dapr进行限流!关于限流今天就到这,下次分享一下如何做链路监控~
相关文章:
Dapr能否引领云原生中间件的未来?
云原生 | 阿里巴巴的Dapr实践与探索
Dapr | 云原生的抽象与实现
Dapr 可视化指南
Dapr 知多少 | 分布式应用运行时
Dapr 正式发布 1.0
Dapr 交通流量控制示例
Dapr是如何简化微服务的开发和部署
微软开源微服务运行时Dapr,赋能云原生应用开发
YARP实现Dapr服务调用的反向代理
Dapr微服务应用开发系列0:概述
Dapr微服务应用开发系列1:环境配置
Dapr微服务应用开发系列2:Hello World与SDK初接触
Dapr微服务应用开发系列3:服务调用构件块
Dapr微服务应用开发系列4:状态管理构件块
Dapr微服务应用开发系列5:发布订阅构建块
Windows环境下Dapr入门
云原生 | .NET 5 with Dapr 初体验
通过Dapr实现一个简单的基于.net的微服务电商系统
通过Dapr实现一个简单的基于.net的微服务电商系统(二)——通讯框架讲解
通过Dapr实现一个简单的基于.net的微服务电商系统(三)——一步一步教你如何撸Dapr
通过Dapr实现一个简单的基于.net的微服务电商系统(四)——一步一步教你如何撸Dapr之订阅发布
通过Dapr实现一个简单的基于.net的微服务电商系统(五)——一步一步教你如何撸Dapr之状态管理