开发访问量比较大的系统是,爬虫的目的就是解决访问量大的问题;缓存穿透是为了保护后端数据库查询服务;计数服务解决了接近真实访问量以及数据库服务的压力。

架构图

限流

就拿十万博客来说,如果存在热点文章,可能会有数十万级别的并发用户参与阅读。如果想让这些用户正常访问,无非就是加机器横向扩展各种服务,但凡事都有一个利益平衡点,有时候只需要少量的机器保证大部分用户在大部分时间可以正常访问即可。

亦或是,如果存在大量爬虫或者恶意攻击,我们必须采取一定的措施来保证服务的正常运行。这时候我们就要考虑限流来保证服务的可用性,以防止非预期的请求对系统压力过大而引起的系统瘫痪。通常的策略就是拒绝多余的访问,或者让多余的访问排队等待服务。

限流算法

任何限流都不是漫无目的的,也不是一个开关就可以解决的问题,常用的限流算法有:令牌桶,漏桶。

令牌桶

令牌桶算法是网络流量整形(Traffic Shaping)和速率限制(Rate Limiting)中最常使用的一种算法。典型情况下,令牌桶算法用来控制发送到网络上的数据的数目,并允许突发数据的发送(百科)。

用户的请求速率是不固定的,这里我们假定为10r/s,令牌按照5个每秒的速率放入令牌桶,桶中最多存放20个令牌。仔细想想,是不是总有那么一部分请求被丢弃。

漏桶

漏桶算法的主要目的是控制数据注入到网络的速率,平滑网络上的突发流量。漏桶算法提供了一种机制,通过它,突发流量可以被整形以便为网络提供一个稳定的流量(百科)。

令牌桶是无论你流入速率多大,我都按照既定的速率去处理,如果桶满则拒绝服务。

应用限流

Tomcat

在Tomcat容器中,我们可以通过自定义线程池,配置最大连接数,请求处理队列等参数来达到限流的目的。

Tomcat默认使用自带的连接池,这里我们也可以自定义实现,打开/conf/server.xml文件,在Connector之前配置一个线程池:

  • name:共享线程池的名字。这是Connector为了共享线程池要引用的名字,该名字必须唯一。默认值:None;

  • namePrefix:在JVM上,每个运行线程都可以有一个name 字符串。这一属性为线程池中每个线程的name字符串设置了一个前缀,Tomcat将把线程号追加到这一前缀的后面。默认值:tomcat-exec-;

  • maxThreads:该线程池可以容纳的最大线程数。默认值:200;

  • maxIdleTime:在Tomcat关闭一个空闲线程之前,允许空闲线程持续的时间(以毫秒为单位)。只有当前活跃的线程数大于minSpareThread的值,才会关闭空闲线程。默认值:60000(一分钟)。

  • minSpareThreads:Tomcat应该始终打开的最小不活跃线程数。默认值:25。

配置Connector

  • executor:表示使用该参数值对应的线程池;

  • minProcessors:服务器启动时创建的处理请求的线程数;

  • maxProcessors:最大可以创建的处理请求的线程数;

  • acceptCount:指定当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理。

API限流

这里我们采用开源工具包guava提供的限流工具类RateLimiter进行API限流,该类基于"令牌桶算法",开箱即用。

自定义定义注解

自定义切面

业务实现:

分布式限流

Nginx

如何使用Nginx实现基本的限流,比如单个IP限制每秒访问50次。通过Nginx限流模块,我们可以设置一旦并发连接数超过我们的设置,将返回503错误给客户端。

配置nginx.conf

配置说明

imitconnzone

是针对每个IP定义一个存储session状态的容器。这个示例中定义了一个100m的容器,按照32bytes/session,可以处理3200000个session。

limit_rate 300k;

对每个连接限速300k. 注意,这里是对连接限速,而不是对IP限速。如果一个IP允许两个并发连接,那么这个IP就是限速limit_rate×2。

burst=5;

这相当于桶的大小,如果某个请求超过了系统处理速度,会被放入桶中,等待被处理。如果桶满了,那么抱歉,请求直接返回503,客户端得到一个服务器忙的响应。如果系统处理请求的速度比较慢,桶里的请求也不能一直待在里面,如果超过一定时间,也是会被直接退回,返回服务器忙的响应。

OpenResty

这里我们使用 OpenResty 开源的限流方案,测试案例使用OpenResty1.15.8.1最新版本,自带lua-resty-limit-traffic模块以及案例 ,实现起来更为方便。

限制接口总并发数/请求数

热点博文,由于突发流量暴增,有可能会影响整个系统的稳定性从而造成崩溃,这时候我们就要限制热点博文的总并发数/请求数。

这里我们采用 lua-resty-limit-traffic中的resty.limit.count模块实现:

限制接口时间窗请求数

现在网络爬虫泛滥,有时候并不是人为的去点击,亦或是存在恶意攻击的情况。此时我们就要对客户端单位时间内的请求数进行限制,以至于黑客不是那么猖獗。当然了道高一尺魔高一丈,攻击者总是会有办法绕开你的防线,从另一方面讲也促进了技术的进步。

这里我们采用 lua-resty-limit-traffic中的resty.limit.conn模块实现:

平滑限制接口请求数

之前的限流方式允许突发流量,也就是说瞬时流量都会被允许。突然流量如果不加以限制会影响整个系统的稳定性,因此在秒杀场景中需要对请求整形为平均速率处理,即20r/s。

这里我们采用 lua-resty-limit-traffic 中的resty.limit.req 模块实现漏桶限流和令牌桶限流。

其实漏桶和令牌桶根本的区别就是,如何处理超过请求速率的请求。漏桶会把请求放入队列中去等待均速处理,队列满则拒绝服务;令牌桶在桶容量允许的情况下直接处理这些突发请求。

漏桶

桶容量大于零,并且是延迟模式。如果桶没满,则进入请求队列以固定速率等待处理,否则请求被拒绝。

令牌桶

桶容量大于零,并且是非延迟模式。如果桶中存在令牌,则允许突发流量,否则请求被拒绝。

压测

为了测试以上配置效果,我们采用AB压测,Linux下执行以下命令即可:

测试命令:

测试结果:

总结

以上限流方案,只是针对此次大访问量项目做一个简单的小结,大家也不要刻意区分那种方案的好坏,只要适合业务场景就是最好的。

SpringBoot项目的限流的更多相关文章

  1. SpringBoot 如何进行限流?老鸟们都这么玩的!

    大家好,我是飘渺.SpringBoot老鸟系列的文章已经写了四篇,每篇的阅读反响都还不错,那今天继续给大家带来老鸟系列的第五篇,来聊聊在SpringBoot项目中如何对接口进行限流,有哪些常见的限流算 ...

  2. springboot + aop + Lua分布式限流的最佳实践

    整理了一些Java方面的架构.面试资料(微服务.集群.分布式.中间件等),有需要的小伙伴可以关注公众号[程序员内点事],无套路自行领取 一.什么是限流?为什么要限流? 不知道大家有没有做过帝都的地铁, ...

  3. 【Distributed】限流技巧

    一.概述 1.1 高并发服务限流特技 1.2 为什么要互联网项目要限流 1.3 高并发限流解决方案 二.限流算法 2.1 计数器 2.2 滑动窗口计数 2.3 令牌桶算法 使用RateLimiter实 ...

  4. SpringBoot 整合 RabbitMQ(包含三种消息确认机制以及消费端限流)

    目录 说明 生产端 消费端 说明 本文 SpringBoot 与 RabbitMQ 进行整合的时候,包含了三种消息的确认模式,如果查询详细的确认模式设置,请阅读:RabbitMQ的三种消息确认模式 同 ...

  5. SpringBoot 2.0 + 阿里巴巴 Sentinel 动态限流实战

    前言 在从0到1构建分布式秒杀系统和打造十万博文系统中,限流是不可缺少的一个环节,在系统能承受的范围内既能减少资源开销又能防御恶意攻击. 在前面的文章中,我们使用了开源工具包 Guava 提供的限流工 ...

  6. SpringCloud(六)之 网关概念、Zuul项目搭建-(利用Zuul 实现鉴权和限流实战)

    一.网关概念 1.什么是路由网关 网关是系统的唯一对外的入口,介于客户端和服务器端之间的中间层,处理非业务功能 提供路由请求.鉴权.监控.缓存.限流等功能.它将"1对N"问题转换成 ...

  7. SpringBoot进阶教程(六十八)Sentinel实现限流降级

    前面两篇文章nginx限流配置和SpringBoot进阶教程(六十七)RateLimiter限流,我们介绍了如何使用nginx和RateLimiter限流,这篇文章介绍另外一种限流方式---Senti ...

  8. springBoot整合Sentinel实现降级限流熔断

    由于hystrix的停止更新,以及阿里Sentinel在历年双十一的贡献.项目中使用了Sentinel,今天我们来讲讲Sentinel的入门教程,本文使用1.6.3版本进行讲解 本文通过Sentine ...

  9. WCF 项目应用连载[8] - 绑定、服务、行为 大数据传输与限流 - 下 (ServiceThrottlingAttribute)

    因为ORM的原因,对Attribute编程有一种情节..所以这节的出现,完全是因为在WCF对自定义Attribute的一种应用. WCF 项目应用连载[7] - 绑定.服务.行为 大数据传输与限流 - ...

随机推荐

  1. 【C++】插值函数代码分析学习

    插值函数代码分析学习,用的CImage类load图像. // Imagejoint.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #inc ...

  2. ylbtech-SQL-W3School-高级:SQL NOT NULL 约束

    ylbtech-SQL-W3School-高级:SQL NOT NULL 约束 1.返回顶部 1. SQL NOT NULL 约束 NOT NULL 约束强制列不接受 NULL 值. NOT NULL ...

  3. JAVA WEB开放中的编码问题

    1.getParamter获取GET方式传来的中文参数乱码 场景:A B 两端都为JAVA 所有编码都为UTF-8.GET得到的参数是乱码 原因,getParamter会将中文参数先URLDECODE ...

  4. 简单实现react中虚拟DOM渲染

    /** * @method createElement * @param type {string} * @param props {Object} * @param children {string ...

  5. X-Forwarded-For注入漏洞实战

    准备工具 Burp suite Sqlmap 实训目标 1.掌握SQL注入的基本原理:2.了解服务器获取客户端IP的方式:3.了解SQL注入的工具使用: 解题方向 对登录表单的各参数进行测试,找到SQ ...

  6. AbstractQueuedSynchronizer 源码解读(转载)

    转载文章,拜读了一下原文感觉很不错,转载一下,侵删 链接地址:http://objcoding.com/2019/05/05/aqs-exclusive-lock/ Java并发之AQS源码分析(一) ...

  7. mysql 全表扫描场景

    全表扫描是数据库搜寻表的每一条记录的过程,直到所有符合给定条件的记录返回为止.通常在数据库中,对无索引的表进行查询一般称为全表扫描:然而有时候我们即便添加了索引,但当我们的SQL语句写的不合理的时候也 ...

  8. There are no packages available

    { "bootstrapped": true, "channels": [ "https://raw.githubusercontent.com/Ja ...

  9. poj2406(求字符串的周期,kmp算法next数组的应用)

    题目链接:https://vjudge.net/problem/POJ-2406 题意:求出给定字符串的周期,和poj1961类似. 思路:直接利用next数组的定义即可,当没有周期时,周期即为1. ...

  10. hdoj4276(树形dp+分组背包)

    题目链接:https://vjudge.net/problem/HDU-4276 题意:给出一棵树,起点为1,时间为V,终点为n,每个点有一个价值a[u],每条边有一个时间花费w,求在时间V内到达终点 ...