限流
限流 Traffic Shaping 又谓之流量整形,主要是针对突发流量的整形,实现网络流量的平滑,防止后端服务被突然的流量洪峰冲垮。限流是一旦流量达到阀值,就启动限流处理,主要有下面三种处理
1.拒绝服务 , 快速失败
2.排队等待,主要是秒杀,抢购的场景,针对稀缺资源。
3.应用降级 ,静态数据或者默认的本地行为。
常见的限流算法
1.计时器限流算法。使用计数器统计一算时间内的请求数量来限流。 适用于服务器端资源请求的限流,不适合用来控制用户请求的限流。
2.漏桶算法 Leaky Bucket 使用一个固定容量的桶,桶底部有一个洞,请求可以任意速率流入,但是只能固定速率处理,一旦超速桶就会溢出,新的请求会被丢弃。
3.令牌桶算法 和漏桶算法不同的是,使用有一个有固定容量令牌的桶,按照固定速率往桶内添加令牌,请求处理会先取令牌,没有申请到令牌则进入排队或直接拒绝。可以看出令牌桶,允许处理瞬间的大量突然请求。
限流方案主要分为下面几种,实际架构方案中,需要综合几种来共同处理,来实现更佳的限流效果
1.客户端限流
通过限制客户端发出请求来限制的。为避免单个客户端对服务的过度使用,可以在客户端进行限流,可以很好的控制全网的流量。但是由于客户端处理,应用会比较复杂,虽然可以通过统一的控制中心或配置中心做一些控制,但是算法升级会很麻烦。
这里可以采用Google开源的Guava类库中的RateLimiter来实现。 它提供一个基于令牌桶的限流方案。
API如下
Ratelimiter.cretae(速率) 0.5 表示每2秒放入一个令牌
Ratelimiter.cretae(速率,预热时间,时间单位) 通过预热时间,调节令牌的生成速率,实现令牌数量的自然平稳增长。
Ratelimiter.acquire();请求令牌
2.服务端限流
客户端限流可以控制单个客户端,但是不了解服务端全部状态,一个服务端可能同时服务多个客户端,因此还需要服务端限流。
服务端一般通过框架或者中间件来提供服务,如Tomcat,Dubbo等都提供了过载限流能力。
比如Tomcat的server.xml 的<Connector>项可以配置限流参数,MySQL,MongoDB,Redis等有类似能力
最后NetFlix提供的zuul组件也可以提供丰富的限流机制。
3.接入端限流
如图APP的接入端是流量的入口,一般会接负载均衡服务器。我们知道四层负载和七层负载的区别,所以四层的限流主要针对紧急情况的限流,比如后端服务会被峰值流量冲跨。通常更多是在七层负载均衡做限流,这里主要是使用Nginx,它提供了连接数限流和请求限流两个模块。
Ngx_http_limit_conn_module
Ngx_http_limit_req_module
这里的Ngx_http_limit_req_module采用的是基于漏桶算法进行的限流,具体配置
http{
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
Server{
location /{ limit_req zone=one burst=5 nodally
}
}
}
具体参数含义就不再这里详述了。
虽然Nginx内置了限流的标准话策略,但是无法满足业务应用的各种个性化需求,针对多个nginx的分布式限流策略,推荐可以使用openResty,它通过lua脚本可以非常方便让我们进行定制化策略开发。另外openResty本身是一个基于nginx+lua的高性能web平台,并内部集成饿大量扩展性强的web应用,服务和动态网关。
最后说说限流的维度和粒度。维度就是说限流的基准或者参考是什么,常用的有访问者IP,请求URL,用户令牌,用户组,设备信息等。这里要说下基于IP地址虽然简单有效,但是当网络中有nginx或者公司使用同一个IP出口防伪外网,此时就不灵了。这个有具体的方案,不知道的话,可以百度下。粒度就是限流的对象是集群还是服务,还是接口。集群粒度一般作为兜底手段,接口级别太小。所以面向服务的粒度最常见。当然对于接口,可以通过添加分组,然后基于分组做限流也是一种选择。
限流用于保证服务质量,限流的具体方案很多,一套健全的限流方案需要在各个部分都要考虑,综合上面三种,基本可以搭建出很难被流量压垮的系统。
熔断
熔断circuit breaker 类似股票市场的熔断机制或者电路的过载保险熔断,达到保护后端服务的有效手段,属于流量调控的范畴。熔断是完全禁止客户端访问。熔断的目的是为了防止单点超时阻塞,进而形成雪崩的有效方法。关于熔断的实现熔断器有三种状态
1.Closed(关闭) 熔断未开启,就是正常状态
2.Open(开启) 熔断开启,应用请求会立即返回错误或者失败,但是不会一直熔断,而是设置超时阀值,一旦到达法治,会进入半开启状态
3.Half-Open(半开启) 此时允许少量请求通过,如果请求符合预期,则会修复熔断,进入关闭;否则再次进入开启并重新计算超时。半开启模式能够有效探测服务状态,做到保护。
这块最知名的就是Netflix开源的Hystrix 它提供了熔断,隔离(分为默认进程隔离和信号量隔离),失效转移和监控功能等。
国内有阿里的Sentinel哨兵方案。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
Sentinel 的主要特性:
Sentinel 分为两个部分:
核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。
控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。