高并发系统下, 有三把利器 缓存 降级 限流.

  • 缓存: 将常用数据缓存起来, 减少数据库或者磁盘IO
  • 降级: 保护核心系统, 降低非核心业务请求响应
  • 限流: 在某一个时间窗口内对请求进行限速, 保护系统

本文主要介绍限流, 常见限流算法中又分为计数器算法, 漏桶算法, 令牌桶算法.

计数器算法

比较简单, 直接用一个map + counter即可实现. 请求来了, 以IP为key,

查询下之前响应次数, 如果调用次数超出MAX_COUT, 返回失败, 属于简单粗暴型选手.

漏桶算法

请求全部进入漏桶, 漏桶恒定速率输出反馈. 这样可以保证数据传输平滑,

但是无法预防突发大量请求, 一秒来了100个请求, 都要阻塞排队, 从小水管输出数据.

令牌桶算法

令牌桶是以固定速度往桶里存令牌, 例如一秒存1000个令牌, 业务请求来了, 直接从桶里获取令牌响应输出.

跟漏桶的差异在于, 他可以预存令牌, 如果一秒钟来了100个请求, 桶里有100个令牌,

那么可以立刻响应给客户端, 而不是排队输出.

令牌桶的实现

guava中提供了令牌桶的一个封装实现RateLimiter, 可以直接调用, 省的我们自己包装ConcurrentHashMap + Timer.

我们预设的场景是服务器端提供一个API供不同客户端查询, 要限流每个IP每秒只能调用两次该API.

首先要定义一个服务器端的缓存, 定期清理即可, 缓存 IP : 令牌桶

     // 根据IP分不同的令牌桶, 每天自动清理缓存
private static LoadingCache<String, RateLimiter> caches = CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterWrite(1, TimeUnit.DAYS)
.build(new CacheLoader<String, RateLimiter>() {
@Override
public RateLimiter load(String key) throws Exception {
// 新的IP初始化 (限流每秒两个令牌响应)
return RateLimiter.create(2);
}
});

然后在业务代码中进行限流调用

     private static void login(int i) throws ExecutionException {
// 模拟IP的key
String ip = String.valueOf(i).charAt(0) + "";
RateLimiter limiter = caches.get(ip); if (limiter.tryAcquire()) {
System.out.println(i + " success " + new SimpleDateFormat("HH:mm:ss.sss").format(new Date()));
} else {
System.out.println(i + " failed " + new SimpleDateFormat("HH:mm:ss.sss").format(new Date()));
}
}

模拟客户端调用

         for (int i = 0; i < 1000; i++) {
// 模拟实际业务请求
Thread.sleep(100);
login(i);
}

完整代码

 public class doLimit {

     // 根据IP分不同的令牌桶, 每天自动清理缓存
private static LoadingCache<String, RateLimiter> caches = CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterWrite(1, TimeUnit.DAYS)
.build(new CacheLoader<String, RateLimiter>() {
@Override
public RateLimiter load(String key) throws Exception {
// 新的IP初始化 (限流每秒两个令牌响应)
return RateLimiter.create(2);
}
}); public static void main(String[] args) throws InterruptedException, ExecutionException {
for (int i = 0; i < 1000; i++) {
// 模拟实际业务请求
Thread.sleep(100);
login(i);
}
} private static void login(int i) throws ExecutionException {
// 模拟IP的key
String ip = String.valueOf(i).charAt(0) + "";
RateLimiter limiter = caches.get(ip); if (limiter.tryAcquire()) {
System.out.println(i + " success " + new SimpleDateFormat("HH:mm:ss.sss").format(new Date()));
} else {
System.out.println(i + " failed " + new SimpleDateFormat("HH:mm:ss.sss").format(new Date()));
}
}
}

Java 对IP请求进行限流.的更多相关文章

  1. java 模拟http请求,通过流(stream)的方式,发送json数据和文件

    发送端: /** * 以流的方式 * 发送文件和json对象 * * @return */ public static String doPostFileStreamAndJsonObj(String ...

  2. 高可用服务设计之二:Rate limiting 限流与降级

    <高可用服务设计之二:Rate limiting 限流与降级> <nginx限制请求之一:(ngx_http_limit_conn_module)模块> <nginx限制 ...

  3. 限流降级神器,带你解读阿里巴巴开源 Sentinel 实现原理

    Sentinel 是阿里中间件团队开源的,面向分布式服务架构的轻量级高可用流量控制组件,主要以流量为切入点,从流量控制.熔断降级.系统负载保护等多个维度来帮助用户保护服务的稳定性. 大家可能会问:Se ...

  4. 【Distributed】限流技巧

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

  5. 限流10万QPS、跨域、过滤器、令牌桶算法-网关Gateway内容都在这儿

    一.微服务网关Spring Cloud Gateway 1.1 导引 文中内容包含:微服务网关限流10万QPS.跨域.过滤器.令牌桶算法. 在构建微服务系统中,必不可少的技术就是网关了,从早期的Zuu ...

  6. 微服务架构 | 5.2 基于 Sentinel 的服务限流及熔断

    目录 前言 1. Sentinel 基础知识 1.1 Sentinel 的特性 1.2 Sentinel 的组成 1.3 Sentinel 控制台上的 9 个功能 1.4 Sentinel 工作原理 ...

  7. 高并发之 API 接口,分布式,防刷限流,如何做?

    在开发分布式高并发系统时有三把利器用来保护系统:缓存.降级.限流 缓存 缓存的目的是提升系统访问速度和增大系统处理容量 降级 降级是当服务出现问题或者影响到核心流程时,需要暂时屏蔽掉,待高峰或者问题解 ...

  8. WebApiThrottle限流框架使用手册

    阅读目录: 介绍 基于IP全局限流 基于IP的端点限流 基于IP和客户端key的端点限流 IP和客户端key的白名单 IP和客户端key自定义限制频率 端点自定义限制频率 关于被拒请求的计数器 在we ...

  9. 前后端分离djangorestframework——限流频率组件

    频率限制 什么是频率限制 目前我们开发的都是API接口,且是开房的API接口.传给前端来处理的,也就是说,只要有人拿到这个接口,任何人都可以通过这个API接口获取数据,那么像网络爬虫的,请求速度又快, ...

随机推荐

  1. PPPoE拨号流程

    PPPoE(Point to Point Protocol over Ethernet,基于以太网的点对点协议)的工作流程包含发现(Discovery)和会话(Session)两个阶段,发现阶段是无状 ...

  2. java5 - 数组与排序算法

    数组是什么? 一.一维数组 1 声明与定义的区别 一般的情况下我们常常这样叙述, 把建立空间的声明称之为"定义", 而把不需要建立存储空间称之为"声明". 很明 ...

  3. 1.9 list 列表

    列表是什么? list是Python中的基本数据结构之一,属于可变序列,所以前文中讲的可变序列的通用操作都适用于list. 这一节讲列表的特性吧. 特性一: 列表是包含任意对象的有序集合,同一个列表中 ...

  4. Linux传统Huge Pages与Transparent Huge Pages再次学习总结

      Linux下的大页分为两种类型:标准大页(Huge Pages)和透明大页(Transparent Huge Pages).Huge Pages有时候也翻译成大页/标准大页/传统大页,它们都是Hu ...

  5. Pokémon Go呼应设计:让全世界玩家疯狂沉迷

    引言:什么样的呼应设计会让移动游戏玩家沉迷?那必须为玩家构建一个属于玩家本人或者被玩家认可的虚拟环境,或者说是被玩家认可的虚拟世界.在移动游戏时代,想要做到这一点并不容易.但Pokémon Go却做到 ...

  6. mongodb副本集中其中一个节点宕机无法重启的问题

    2-8日我还在家中的时候,被告知mongodb副本集中其中一个从节点因未知原因宕机,然后暂时负责代管的同事无论如何就是启动不起来. 当时mongodb的日志信息是这样的: 实际上这里这么长一串最重要的 ...

  7. mysql 查询表死锁 和结束死锁的表步骤

    1.查询是否锁表 show OPEN TABLES ; 2.查询进程 show processlist 查询到相对应的进程===然后 kill    id 3.查看正在锁的事务 SELECT * FR ...

  8. php出现Can't use function return value in write context

    <?php if(session('uid')){ }else{ } ?> 在用empty判断值为空的时候,报了这个Can't use function return value in w ...

  9. php5.3命名空间内使用 php内置类的时候

    在命名空间内使用内置类库的时候,需要使用 \ 比如 $zip =new \ZipArchive;

  10. Java获取当前的年月

    今天,我在尝试从数据库取数据的过程中,发现页面初始化时需要给时间控件赋初值.于是,我就写了一个获取当前年月的时间工具类. 1.具体源码如下: YearAndMonth.java: /** * @Tit ...