课程名称:海量数据高并发场景,构建Go+ES8企业级搜索微服务
课程章节:5-6
课程讲师:少林码僧
课程内容:
什么是限流
限流就是在一段时间内,可以处理或者接收规定数量的请求,超出该阈值,则不进行处理或者拒接接受。相对于限流,普通情况下是不限制的,理论上是无限制。
限流的目的
应对突发流量
防止某个用户将系统资源耗尽而影响到其他用户的正常使用,比如mysql集群,机器里的内存
控制成本,在有限的资源下能够稳定提供正常的服务。至少要保证一部分流量是正常工作了,不至于在大流量下崩溃掉
应用在哪些地方需要限流
请求入口处。比如nginx,比如独立的网关服务
业务服务入口处,业务服务应该提前预估QPS,告诉下游依赖
公共基础服务入口。此服务级别很高,如果崩溃,影响面巨大,所以要对其进行压测,确定流量阈值
分布式限流
不需要实时上报,可以对服务做一个缓存区,按时间段向redis进行上报,比如每10次上报一次,这样可以避免峰值流量对redis的压力
令牌桶和漏桶算法只能针对单个节点,不能对分布式整体进行限流
针对每个用户的限流控制是十分有必要的,避免出现单用户恶意大流量访问,比如爬虫,ddos攻击
分布式限流控制是整个应用全局的流量
分布式可以使用redis来实现。
如何确定流量的阈值
普通压测
全链路压测:通过TCPCopy来复制真实流量,使用一些消息中间件储存请求数据,然后在压测平台进行“流量回放”
使用开源的全链路压测工具,比如Takin
全链路压测注意点
只对核心流程有影响的部分进行压测,全链路压测成本高,影响大,涉及面广,如果压测时间过长会影响业务
可以选择适当的隔离方式,独立环境或者影子库
缩小服务依赖
固定的限流值有什么问题呢
业务代码不断的变更,执行所消耗的资源不是一成不变的,当次压测数据与下次压测的数据很可能不一样,阈值会发生改变
不同操作对数据库造成的压力或者数据体量不一样,吞吐性能不是已成不变的
基于成本考虑,很多情况下没有跟线上完全一样的环境,导致压测数据失真
不同的API或者微服务需要设置不同的限流阈值,服务多了很难统一管理
微服务所使用的的资源大多数是可以伸缩的,扩容和缩容是很正常的操作,需要根据伸缩动作动态调整阈值
基于响应时间的动态限流
首先我们记录每次调用后端请求的响应时间
然后在一个时间区间内(比如5秒内)计算这段时间的P90或者P99(P90->90%)
如果这个P90或者P99大于我们设定的阈值,我们就开启自动限流
对P99或者P90的计算也是很消耗cpu资源
流量控制我们可以像TCP控制cwnd(拥塞窗口)一样,使用退避算法,按照阶段性递减,控制qps
基于系统资源的动态限流
通过系统资源的使用率来动态限流
统计一段时间的系统资源(CPU,内存)等消耗达到某个百分比就限流
限流设计需要注意什么
限流需要有开关控制,可以随时禁用
限流发生后触发监控警告,让管理员即时介入
限流发生后应该让调用方知道,避免调用方继续重试,可以在header里增加标识位,约定code或者其他标识来通知到调用方
课程收获: