下咽顿除烟火气,入齿便作冰雪声。 文天祥 西瓜吟

场景 : 618抢购。 很多系统宕机,很多服务500(404)。

发生这个场景的问题所在:

1: 独立api频繁被调用

2:电商网站某个模块入口被瞬间挤爆

3: 调用第三方网站api,我方请求过多,第三方网站无法及时响应,服务器排队太多宕机。

针对不同的场景,使用不同的限流算法来避免网站不可用。

高并发系统的三把利剑

1:缓存

1.1 缓存目的 : 提升系统访问速度和增大系统能处理的容量。提升性能,缓解数据库压力

1.2 缓存的方式: redis , memcached

1.3 缓存带来的问题

【1】、缓存穿透:缓存穿透是说收到一个请求,但是该请求缓存中不存在,只能去数据库中查询,然后放进缓存。
【2】、缓存击穿:上面提到的某个数据没有,然后好多请求查询数据库,可以归为缓存击穿的范畴:对于热点数据,当缓存失效的一瞬间,所有的请求都被下放到数据库去请求更新缓存,数据库被压垮。
【3】、缓存雪崩:缓存雪崩是指当我们给所有的缓存设置了同样的过期时间,当某一时刻,整个缓存的数据全部过期了,然后瞬间所有的请求都被抛向了数据库,数据库就崩掉了。
【4】、缓存刷新:既清空缓存 ,一般在insert、update、delete操作后就需要刷新缓存,如果不执行就会出现脏数据。但当缓存请求的系统蹦掉后,返回给缓存的值为null。   

2:降级 Spring Cloud Hystrix

2.1 人工降级

修改配置中心的配置,代码里面根据相关配置开关去执行不同的代码逻辑块。

2.2 自动降级

熔断策略

熔断本质上是一个过载保护机制

举例:

微服务A -》微服务B -》微服务C,如果微服务A需要发布新版本,会对B,C产生影响。

房子的排污管道从上至下,如果你家楼下的管道堵住了,污水会灌到你们家。这时候你先避免自己

家收到影响,然后通知楼下去疏通。

 熔断系统性能

3:限流

海底捞高峰时间,如果采取熔断,关门10分钟,会导致用户体验不好。

画图看看现有项目部署下的多层面限流实现

限流策略

3.1 api限流(黑白名单等皆可)

3.1.1 计数器(固定窗口) : 若干定长时间内,ip地址/用户/流量等访问次数.

String remoteAddr = request.getRemoteAddr();Integer count = map.get(remoteAddr);
​//统计ip访问次数,或者总共的访问次数if(null == count){map.put(remoteAddr,1);}else{map.put(remoteAddr,count+1);}
​//可以记录该ip的访问时间,限制其 1s 内只能访问一次等long timeMillis = System.currentTimeMillis();
​if(count > 5){return ; //不继续处理请求}
​System.out.println(remoteAddr +" : "+ map.get(remoteAddr));

问题: 流量请求不是一个 **固定周期内的恒定值**,可能会所有请求在固定周期内最后一秒,或者第一秒涌入,这样固定周期内其他时间空闲了下来导致资源无法高效利用,或者固定周期内一些请求无法处理。滑动窗口可以解决这个问题。

滑动窗口

https://media.pearsoncmg.com/aw/ecs_kurose_compnetwork_7/cw/content/interactiveanimations/selective-repeat-protocol/index.html

3.1.2 漏桶算法

通过一个缓冲区将不平滑的流量“整形”成平滑的,也就是说将高于平均值的流量补充到低于平均值的流量,以此最大化计算处理资源的利用率。

应用场景: 如果你的系统需要调用第三方发短信,支付等接口。对方接口gps为2000,但是你的系统同一时间接收到5000个请求,这样可以设置漏桶,系统恒定输出2000,流量入口可以暂存。

3.1.3 令牌桶 。 不会误削峰

以恒定的速度 (Rate:令牌生成速率 / 每秒)往桶里面放入令牌,如果这时候有请求需要处理,则需要先从桶里面获取一个令牌,如果这时候桶里面的令牌被消耗完毕,则返回其他结果(停止服务等)。

应用场景:应对秒杀的场景,秒杀1000个商品,在1s之内,永远只接受10个请求去处理。

Semaphore : 限制现成个数(控制并发数量)

控制速率(处理突发流量): Burst 令牌桶大小 /

Ratelimiter实现令牌桶:

实现上并不是有个定时器在那里放令牌,然后消耗令牌,而是将空闲时间利用令牌的思想进行建模,实质上是计算并保留下次可执行请求的时间,并根据这个时间与请求到来的时间作比较,然后决定是否执行

3.2 应用级限流tomcat   网上拷贝的

配置tomcat中的自定义线程池,配置最大连接数,请求处理队列等参数来限流。

conf/server.xml文件中,在Connector之前配置一个Executor (线程池)


<Executor name="tomcatPool"namePrefix="tomcatPool-"maxThreads="500"maxIdleTime="300000"minSpareThreads="100"/>
<!--
name:共享线程池的名字。该名字必须唯一。默认值:None;
namePrefix:在JVM上,每个运行线程都可以有一个name 字符串。
maxThreads:该线程池可以容纳的最大线程数。默认值:200;
maxIdleTime:在Tomcat关闭一个空闲线程之前,允许空闲线程持续的时间(以毫秒为单位)。只有当前活跃的线程数大于minSpareThread的值,才会关闭空闲线程。默认值:60000(一分钟)。
minSpareThreads:Tomcat应该始终打开的最小不活跃线程数。默认值:25。
-->
配置Connector<Connector executor="tomcatThreadPool"port="8080" protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443"minProcessors="5"maxProcessors="75"acceptCount="1000"/><!--executor:表示使用该参数值对应的线程池;minProcessors:服务器启动时创建的处理请求的线程数;maxProcessors:最大可以创建的处理请求的线程数;acceptCount:指定当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个                 数的请求将不予处理。-->

3.2.3 分布式限流(流量入口)

限制接口: 获取令牌的方式,采用redis。RedissonClient getRateLimiter()。

//结合redis,实现分布式的qpi接口限流public static void test() throws InterruptedException, ExecutionException {
​Config config = new Config();
//        config.useClusterServers()
//                .setScanInterval(2000)
//                .addNodeAddress("127.0.0.1:7000", "127.0.0.1:7001")
//                .addNodeAddress("127.0.0.1:7002");config.useSingleServer().setAddress("redis://192.168.8.154:6379").setConnectionMinimumIdleSize(10);
​
​RedissonClient redisson = Redisson.create(config);
​/*** 基于Redis的分布式限流器可以用来在分布式环境下现在请求方的调用频率。* 既适用于不同Redisson实例下的多线程限流,也适用于相同Redisson实例下的多线程限流。* 该算法不保证公平性。*/RRateLimiter myLimiter = redisson.getRateLimiter("my");
​
​/*** Total rate for all RateLimiter instances* 作用在所有的RRateLimiter实例* OVERALL** Total rate for all RateLimiter instances working with the same Redisson instance* 作用在同一个Redisson实例创建的 RRateLimiter上面。* PER_CLIENT** return : 设置是否成功。 对同一个redis服务端,只需要设置一次。如果redis重启需要重新设置*/boolean bl = myLimiter.trySetRate(RateType.OVERALL,5,5, RateIntervalUnit.SECONDS);
​
​System.out.println(bl);
​for(int i = 0 ; i < 200 ; i++){System.out.println(myLimiter.tryAcquire());Thread.sleep(100);}}

前置化限流: nginx+lua (Openresty)  网上拷贝的:

location /buy {access_by_lua_block {local limit_req = require "resty.limit.req"-- 这里设置rate=2/s,漏桶桶容量设置为0,(也就是来多少水就留多少水) -- 因为resty.limit.req代码中控制粒度为毫秒级别,所以可以做到毫秒级别的平滑处理local lim, err = limit_req.new("my_limit_req_store", 2, 60)if not lim thenngx.log(ngx.ERR, "failed to instantiate a resty.limit.req object: ", err)return ngx.exit(500)end
​local key = ngx.var.binary_remote_addrlocal delay, err = lim:incoming(key, true)if not delay thenif err == "rejected" thenreturn ngx.exit(503)endngx.log(ngx.ERR, "failed to limit req: ", err)return ngx.exit(500)end-- 此方法返回,当前请求需要delay秒后才会被处理,和他前面对请求数-- 所以此处对桶中请求进行延时处理,让其排队等待,就是应用了漏桶算法-- 此处也是与令牌桶的主要区别既if delay >= 0.001 thenngx.sleep(delay)end}
​proxy_pass http://192.168.10.111:6666;proxy_set_header Host $host;proxy_redirect off;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_connect_timeout 60;proxy_read_timeout 600;proxy_send_timeout 600;
}

分布式api限流实现代码:   链接: https://pan.baidu.com/s/1-1vY7KgIooQ8cOVS67UOWQ 提取码: wrqh

高并发系统的三把利剑(缓存,降级,限流)相关推荐

  1. 开发高并发系统的三把利器

    在开发高并发系统时有三把利器用来保护系统:缓存.降级和限流.缓存的目的是提升系统访问速度和增大系统能处理的容量,可谓是抗高并发流量的银弹:而降级是当服务出问题或者影响到核心流程的性能则需要暂时屏蔽掉, ...

  2. 高并发系统 3 大利器之缓存

    引言 随着互联网的高速发展,市面上也出现了越来越多的网站和app.我们判断一个软件是否好用,用户体验就是一个重要的衡量标准.比如说我们经常用的微信,打开一个页面要十几秒,发个语音要几分钟对方才能收到. ...

  3. 高并发的场景下,不能不说的限流算法

    来自:会点代码的大叔 先举个例子,说明为什么要做"限流". 旅游景点通常都会有最大的接待量,不可能无限制的放游客进入,比如故宫每天只卖八万张票,超过八万的游客,无法买票进入,因为如 ...

  4. 【高并发】高并发五个利器(缓存、限流、降级、熔断、隔离)

    文章目录 文章目录 一.前言 二.缓存 2.1 缓存本质 + 缓存分类 + 缓存三大特征 + 三种淘汰算法 + 根据业务场景设计过期时间 2.2 本地缓存(进程内缓存) 2.3 分布式缓存 2.4 缓 ...

  5. 谈谈高并发系统的限流

    开涛大神在博客中说过:在开发高并发系统时有三把利器用来保护系统:缓存.降级和限流.本文结合作者的一些经验介绍限流的相关概念.算法和常规的实现方式. 缓存 缓存比较好理解,在大型高并发系统中,如果没有缓 ...

  6. 高并发系统之限流特技

    转载至:http://blog.csdn.net/g_hongjin/article/details/51649246 在开发高并发系统时有三把利器用来保护系统:缓存.降级和限流.缓存的目的是提升系统 ...

  7. 慌了,居然被问到怎么做高并发系统的限流

    点击上方"朱小厮的博客",选择"设为星标" 后台回复"加群"加入公众号专属技术群 来源:uee.me/cDuRD 在开发高并发系统时有三把利 ...

  8. 高并发系统之降级特技

    2019独角兽企业重金招聘Python工程师标准>>> 高并发系统之降级特技 博客分类: 架构 在开发高并发系统时有三把利器用来保护系统:缓存.降级和限流.之前已经有一些文章介绍过缓 ...

  9. 面试官 | 讲一下如何给高并发系统做限流?

    作者 | nick hao 来源 | uee.me/cDuRD 在开发高并发系统时有三把利器用来保护系统:缓存.降级和限流.本文结合作者的一些经验介绍限流的相关概念.算法和常规的实现方式. 缓存 缓存 ...

最新文章

  1. 人要懂得放下已经发生,却又无法改变的事情
  2. rdd与mysql表 join_6、JdbcRDD读取mysql的数据
  3. idea clone 华为云仓库
  4. 【算法系列 二】Stack
  5. 定义指令时“控制器”,“链接”和“编译”函数之间的区别
  6. [YTU]_2878( 结构体--学生信息排序)
  7. php 字符串 中文,php实现中文字符串截取无乱码
  8. 学计算机的快毕业要学论文吗,学计算机的好写毕业论文吗?
  9. [转载]DB2数据库移植罕见成绩片面理睬(4)
  10. api-gateway实践(03)新服务网关 - 网关请求拦截检查
  11. 点击页面元素,这个Vite插件竟然帮我打开了Vue组件文件!超级好用!
  12. java 不加锁_在java中,在高并发的时候,不加锁的时候。
  13. 互联网时代的了解和未来的预期_互联网时代品牌农业该如何营销 后园带你了解这五点...
  14. 三层交换机关于VLAN的划分以及ACL的使用
  15. mysql批量替换 语法
  16. 以太坊 node data write error_那个坚持写了四年《每周以太坊》的劳模分享关于以太坊的最新看法...
  17. HiveSQL和普通SQL的区别
  18. 个推科普漫画,解读《女心理师》中的智能语音识别系统
  19. 渐进记号 Asymptotic Notations-------geeksforgeeks 翻译
  20. Eclipse 安装 yml 编辑器插件

热门文章

  1. 189Echarts - 日历坐标系(Custom Calendar Icon)
  2. ubuntu 16.04上ns2+nam+GT-ITM安装笔记
  3. 镇海三日游——ZJOI2019游记
  4. vue 中使用element-ui的menu选中项高亮的问题
  5. 想学习,无方法,十年老码农告诉你方法
  6. springboot没有报任何错反而都标红了如何解决
  7. iView——表单校验是否为空填坑
  8. js小程序连接websocket开发者工具可以,真机不行;
  9. 智能语音机器人市场对手如此多,微服网络如何更胜一筹
  10. java最主要的3个就业方向你知道吗