在一般的互联网应用中限流是一个比较常见的场景,也有很多常见的方式可以实现对应用的限流比如通过令牌桶通过滑动窗口等等方式都可以实现,也可以在整个请求流程中进行限流比如客户端限流就是在客户端通过随机数直接返回成功失败来决定是否发起请求。也可以在网关层直接根据一定策略丢弃一部分流量达到限流的目的,亦可请求到业务端后由业务端判断是否进行限流。而一般的service mesh框架会在代理的sidecar部分完成限流的工作。今天就讲讲dapr是如何通过简易的配置来实现一个限流的。
目录:
一、通过Dapr实现一个简单的基于.net的微服务电商系统
二、通过Dapr实现一个简单的基于.net的微服务电商系统(二)——通讯框架讲解
三、通过Dapr实现一个简单的基于.net的微服务电商系统(三)——一步一步教你如何撸Dapr
四、通过Dapr实现一个简单的基于.net的微服务电商系统(四)——一步一步教你如何撸Dapr之订阅发布
五、通过Dapr实现一个简单的基于.net的微服务电商系统(五)——一步一步教你如何撸Dapr之状态管理
六、通过Dapr实现一个简单的基于.net的微服务电商系统(六)——一步一步教你如何撸Dapr之Actor服务
七、通过Dapr实现一个简单的基于.net的微服务电商系统(七)——一步一步教你如何撸Dapr之服务限流
八、通过Dapr实现一个简单的基于.net的微服务电商系统(八)——一步一步教你如何撸Dapr之链路追踪
九、通过Dapr实现一个简单的基于.net的微服务电商系统(九)——一步一步教你如何撸Dapr之OAuth2授权 && 百度版Oauth2
十、通过Dapr实现一个简单的基于.net的微服务电商系统(十)——一步一步教你如何撸Dapr之绑定
十一、通过Dapr实现一个简单的基于.net的微服务电商系统(十一)——一步一步教你如何撸Dapr之自动扩/缩容
十二、通过Dapr实现一个简单的基于.net的微服务电商系统(十二)——istio+dapr构建多运行时服务网格
十三、通过Dapr实现一个简单的基于.net的微服务电商系统(十三)——istio+dapr构建多运行时服务网格之生产环境部署
十四、通过Dapr实现一个简单的基于.net的微服务电商系统(十四)——开发环境容器调试小技巧
十五、通过Dapr实现一个简单的基于.net的微服务电商系统(十五)——集中式接口文档实现
十六、通过Dapr实现一个简单的基于.net的微服务电商系统(十六)——dapr+sentinel中间件实现服务保护
十七、通过Dapr实现一个简单的基于.net的微服务电商系统(十七)——服务保护之动态配置与热重载
十八、通过Dapr实现一个简单的基于.net的微服务电商系统(十八)——服务保护之多级缓存
十九、通过Dapr实现一个简单的基于.net的微服务电商系统(十九)——分布式事务之Saga模式
二十、通过Dapr实现一个简单的基于.net的微服务电商系统(二十)——Saga框架实现思路分享
附录:(如果你觉得对你有用,请给个star)
一、电商Demo地址
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.ratelimit version: v1 metadata: - name: maxRequestsPerSecond value: 1
接着我们配置一个Configuration并注入到clientsample的deployment中(注意红字部分)
apiVersion: dapr.io/v1alpha1 kind: Configuration metadata: name: appconfig spec: httpPipeline: handlers: - name: ratelimit type: middleware.http.ratelimit
apiVersion: apps/v1 kind: Deployment metadata: name: clientsample labels: app: clientsample spec: replicas: 1 selector: matchLabels: app: clientsample template: metadata: labels: app: clientsample annotations: dapr.io/enabled: "true" dapr.io/app-id: "clientsample" dapr.io/app-port: "80" dapr.io/config: "appconfig" spec: containers: - name: web image: clientsample:release imagePullPolicy: Never ports: - 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: servicesample labels: app: servicesample spec: replicas: 1 selector: matchLabels: app: servicesample template: metadata: labels: app: servicesample annotations: dapr.io/enabled: "true" dapr.io/app-id: "servicesample" dapr.io/app-port: "80" dapr.io/app-max-concurrency: "1" spec: containers: - name: web image: servicesample:release imagePullPolicy: Never ports: - containerPort: 80
clientsample不用修改,我们在servicesample的方法中增加以下模拟耗时操作
重新生成后(注意需要删除之前配置在clientsample上的dapr.io/config),我们通过postman模拟发起请求:
可以看到请求全部都执行成功并获取回调了,但是整个请求耗时是10秒,恰好就是一次处理1个请求,单个请求耗时1秒得到的结果,我们可以再次验证一下将app-max-concurrency设置为2,应该会5秒请求完毕:
可以看到信号量每次放入了两个线程同步处理,我们的请求确实被压缩到了5秒处理完毕。
整个限流其实分为下游限流+并发控制两种方式,其实都是为了保护自己/下游服务。另外大家注意一下如果你的请求并不是通过sidecar进入到服务的比如直接暴露服务端口到network或通过ingress+service的方式访问应用也就是说流量不走sidecar,则无法通过dapr进行限流!关于限流今天就到这,下次分享一下如何做链路监控~