当前位置: 首页 > news >正文

java八股-流量封控系统

文章目录

  • 请求后台管理的频率-流量限制
    • 流量限制的业务代码
      • UserFlowRiskControlFilter
  • 短链接中台的流量限制
        • CustomBlockHandler
    • 对指定接口限流
      • UserFlowRiskControlConfiguration
      • SentinelRuleConfig

请求后台管理的频率-流量限制

根据登录用户做出控制,比如 x 秒请求后管系统的频率最多 x 次。
实现原理也比较简单,通过 Redis increment 命令对一个数据进行递增,如果超过 x 次就会返回失败。这里有个细节就是我们的这个周期是 x 秒,需要对 Redis 的 Key 设置 x 秒有效期。
但是 Redis 中对于 increment 命令是没有提供过期命令的,这就需要两步操作,进而出现原子性问题。

lua脚本步骤:

  1. 递增key对应的访问次数
  2. 給该key设置过期时间TTL,TTL是限制时间内的秒数,
  3. 最后返回TTL内的访问次数

使用lua脚本保证原子性,这里主要的作用是记录在timeWindow秒限制内的访问次数AccessCnt。
其中timeWindow是多少多少秒,lua脚本返回值(是在timeWindow秒内)被访问了AccessCnt次,

-- 设置用户访问频率限制的参数
local username = KEYS[1]
local timeWindow = tonumber(ARGV[1]) -- 时间窗口,单位:秒-- 构造 Redis 中存储用户访问次数的键名
local accessKey = "short-link:user-flow-risk-control:" .. username-- 原子递增访问次数,并获取递增后的值
local currentAccessCount = redis.call("INCR", accessKey)-- 设置键的过期时间
redis.call("EXPIRE", accessKey, timeWindow)-- 返回当前访问次数
return currentAccessCount

流量限制的业务代码

UserFlowRiskControlFilter


package com.nageoffer.shortlink.admin.common.biz.user;import com.alibaba.fastjson2.JSON;
import com.google.common.collect.Lists;
import com.nageoffer.shortlink.admin.common.convention.exception.ClientException;
import com.nageoffer.shortlink.admin.common.convention.result.Results;
import com.nageoffer.shortlink.admin.config.UserFlowRiskControlConfiguration;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;import java.io.IOException;
import java.io.PrintWriter;
import java.util.Optional;import static com.nageoffer.shortlink.admin.common.convention.errorcode.BaseErrorCode.FLOW_LIMIT_ERROR;@Slf4j
@RequiredArgsConstructor
//用户流量封控过滤器
public class UserFlowRiskControlFilter implements Filter {private final StringRedisTemplate stringRedisTemplate;//用户流量封控配置器//这里这个UserFlowRiskControlConfiguration 在下面会有介绍的,反正这里的MaxAccessCount和time-window都是从Application.yaml里面读取到的private final UserFlowRiskControlConfiguration userFlowRiskControlConfiguration;private static final String USER_FLOW_RISK_CONTROL_LUA_SCRIPT_PATH = "lua/user_flow_risk_control.lua";@SneakyThrows@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();//设置加载到lua脚本对象redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource(USER_FLOW_RISK_CONTROL_LUA_SCRIPT_PATH)));//设置lua脚本返回值类型是LongredisScript.setResultType(Long.class);String username = Optional.ofNullable(UserContext.getUsername()).orElse("other");Long result;try {result = stringRedisTemplate.execute(redisScript, Lists.newArrayList(username), userFlowRiskControlConfiguration.getTimeWindow());} catch (Throwable ex) {//设置为Throwable,防止捕获不到log.error("执行用户请求流量限制LUA脚本出错", ex);returnJson((HttpServletResponse) response, JSON.toJSONString(Results.failure(new ClientException(FLOW_LIMIT_ERROR))));return;}//如果访问次数Result>最大限制访问次数getMaxAccessCount,则返回流量限制异常if (result == null || result > userFlowRiskControlConfiguration.getMaxAccessCount()) {returnJson((HttpServletResponse) response, JSON.toJSONString(Results.failure(new ClientException(FLOW_LIMIT_ERROR))));return;}filterChain.doFilter(request, response);}private void returnJson(HttpServletResponse response, String json) throws Exception {response.setCharacterEncoding("UTF-8");response.setContentType("text/html; charset=utf-8");try (PrintWriter writer = response.getWriter()) {writer.print(json);}}
}

短链接中台的流量限制

使用sentinel来做中台的流量限制,首先引入依赖

<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-annotation-aspectj</artifactId>
</dependency>
CustomBlockHandler
package com.nageoffer.shortlink.project.handler;import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.nageoffer.shortlink.project.common.convention.result.Result;
import com.nageoffer.shortlink.project.dto.req.ShortLinkCreateReqDTO;
import com.nageoffer.shortlink.project.dto.resp.ShortLinkCreateRespDTO;public class CustomBlockHandler {public static Result<ShortLinkCreateRespDTO> createShortLinkBlockHandlerMethod(ShortLinkCreateReqDTO requestParam, BlockException exception) {return new Result<ShortLinkCreateRespDTO>().setCode("B100000").setMessage("当前访问网站人数过多,请稍后再试...");}
}

sentinel技术对接口限流,超过指定的QPS之后会接口限流,Block住
下面的@SentinelResource里面的value是对保护资源的名称的指定,Blockhandler是保护资源用到的方法,BlockHandlerClass是保护资源用到的类Class
在这里插入图片描述

对指定接口限流

这里对接口限流,指定他的资源名称为create-short-link,以后带着这个名称,在SentinelRuleConfig(文章下面会介绍到位,也可以在目录里面快速定位到相关内容)里面会加入对这个资源的保护
在这里插入图片描述

UserFlowRiskControlConfiguration

Application.yaml和UserFlowRiskControlConfiguration

@Data
@Component
@ConfigurationProperties(prefix = "short-link.flow-limit") //从Application.yaml配置文件里面读取相应的数据信息
public class UserFlowRiskControlConfiguration {/*** 是否开启用户流量风控验证*/private Boolean enable;/*** 流量风控时间窗口,单位:秒*/private String timeWindow;/*** 流量风控时间窗口内可访问次数*/private Long maxAccessCount;
}

SentinelRuleConfig

定义接口规则

package com.nageoffer.shortlink.project.config;import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;import java.util.ArrayList;
import java.util.List;//解释一下,实现InitializingBean 接口并重写afterPropertiesSet是为了在Bean初始化完成之后,
//执行FlowRuleManager.loadRules(rules)把这个流量限制规则加入到位!!!!
@Component
public class SentinelRuleConfig implements InitializingBean { //@Overridepublic void afterPropertiesSet() throws Exception {List<FlowRule> rules = new ArrayList<>();FlowRule createOrderRule = new FlowRule();//通过对指定资源名称进行保护限流createOrderRule.setResource("create_short-link");//通过QPS限制createOrderRule.setGrade(RuleConstant.FLOW_GRADE_QPS);//QPS超过1就限流createOrderRule.setCount(1);rules.add(createOrderRule);FlowRuleManager.loadRules(rules);}
}

InitializingBean 接口,实现该接口的类需要提供一个 afterPropertiesSet 方法,该方法会在所有依赖注入完成后被调用

package org.springframework.beans.factory;public interface InitializingBean {void afterPropertiesSet() throws Exception;
}

在这里插入图片描述

在这里插入图片描述

相关文章:

java八股-流量封控系统

文章目录 请求后台管理的频率-流量限制流量限制的业务代码UserFlowRiskControlFilter 短链接中台的流量限制CustomBlockHandler 对指定接口限流UserFlowRiskControlConfigurationSentinelRuleConfig 请求后台管理的频率-流量限制 根据登录用户做出控制&#xff0c;比如 x 秒请…...

【WebRTC】Android SDK使用教学

文章目录 前言PeerConnectionFactoryPeerConnection 前言 最近在学习WebRTC的时候&#xff0c;发现只有JavaScript的API文档&#xff0c;找了很久没有找到Android相关的API文档&#xff0c;所以通过此片文章记录下在Android应用层如何使用WebRTC 本篇文章结合&#xff1a;【W…...

基于单片机的智能晾衣控制系统的设计与实现

摘要:本文是以 AT89C52 单片机为核心来实现智能晾衣控制系统。在这个系统中,雨水检测传感器是用来检测出雨的,而控制器将检测信号的变换,根据变换后的信号自动驱动直流电机将被风干 的棒收回,以便随时控制直流电机来实现晾衣;在光敏模块中检测昼夜的环境,自动控制晾衣杆…...

多人聊天室 NIO模型实现

NIO编程模型 Selector监听客户端不同的zhuangtai不同客户端触发不同的状态后&#xff0c;交由相应的handles处理Selector和对应的处理handles都是在同一线程上实现的 I/O多路复用 在Java中&#xff0c;I/O多路复用是一种技术&#xff0c;它允许单个线程处理多个输入/输出&…...

三、使用 Maven:命令行环境

文章目录 1. 第一节 实验一&#xff1a;根据坐标创建 Maven 工程1.1 Maven 核心概念&#xff1a;坐标1.2 实验操作1.3 Maven核心概念&#xff1a;POM1.4 Maven核心概念&#xff1a;约定的目录结构 2. 实验二&#xff1a;在 Maven 工程中编写代码2.1 主体程序2.2 测试程序 3. 执…...

Blender导入下载好的fbx模型像的骨骼像针戳/像刺猬

为什么我下载下来的骨骼模型和我自己绑定的模型骨骼朝向完全不一样 左边是下载的模型 右边是我自己绑定的模型 左边的模型刚刚感觉都是像针一样往外戳的&#xff0c;像刺猬一样那种。 解决方法勾选自动骨骼坐标系...

如何高效搭建智能BI数据分析系统

作为当今信息化时代&#xff0c;数据资产已经成为企业最为核心倚重的&#xff0c;自然企业也就面临来自于对内部这些数据的处理和分析。如何在大批量的数据当中提取有用信息&#xff0c;帮助企业做出智慧决策&#xff0c;是不少企业面临的问题。作为国内知名的BI数据分析系统服…...

第 6 章 Java 并发包中锁原理剖析Part one

目录 6.1 LockSupport 工具类 6.2 独占锁 ReentrantLock 的原理 获取锁 1&#xff0e;void lock() 方法 2&#xff0e;void lockInterruptibly() 方法 3&#xff0e;boolean tryLock() 方法 4&#xff0e;boolean tryLock(long timeout, TimeUnit unit) 方法 释放锁 6.1 Lo…...

使用 Canvas 绘制一个镂空的圆形区域

如果要实现一个类似人脸识别的界面&#xff0c;要求使用 canvas 进行绘制&#xff0c;中间镂空透明区域&#xff0c;背景是白色的画布。 技术方案&#xff1a; 首先&#xff0c;使用 canvas 绘制一个白色画布其次&#xff0c;使用 context.globalCompositeOperation 合成属性进…...

【Notepad++】---设置背景为护眼色(豆沙绿)最新最详细

在编程的艺术世界里&#xff0c;代码和灵感需要寻找到最佳的交融点&#xff0c;才能打造出令人为之惊叹的作品。而在这座秋知叶i博客的殿堂里&#xff0c;我们将共同追寻这种完美结合&#xff0c;为未来的世界留下属于我们的独特印记。 【Notepad】---设置背景为护眼色&#xf…...

2024 数学建模国一经验分享

2024 数学建模国一经验分享 背景&#xff1a;武汉某211&#xff0c;专业&#xff1a;计算机科学 心血来潮&#xff0c;就从学习和组队两个方面指点下后来者&#xff0c;帮新人避坑吧 2024年我在数学建模比赛中获得了国一&#xff08;教练说论文的分数是湖北省B组第一&#xff0…...

安全见闻2

安全见闻&#xff0c;犹如一座庞大而深邃的知识宝库&#xff0c;其中涵盖了形形色色的网络安全知识与错综复杂的网络技术体系。在当今数字化时代&#xff0c;这些领域的重要性不言而喻&#xff0c;它们不仅关乎个人信息的保护与隐私安全&#xff0c;更是支撑着整个互联网世界以…...

Web游戏开发指南:在 Phaser.js 中读取和管理游戏手柄输入

前言 Phaser.js 是一个广受欢迎的 HTML5 游戏框架&#xff0c;为开发者提供了创建跨平台 2D 游戏的强大工具。在现代游戏开发中&#xff0c;支持游戏手柄已成为提升玩家体验的重要方面。本文将详细介绍如何在 Phaser.js 中监听和处理游戏手柄的输入&#xff0c;帮助开发者为他…...

代码随想录32 动态规划理论基础,509. 斐波那契数,70. 爬楼梯,746. 使用最小花费爬楼梯。

1.动态规划理论基础 动态规划刷题大纲 什么是动态规划 动态规划&#xff0c;英文&#xff1a;Dynamic Programming&#xff0c;简称DP&#xff0c;如果某一问题有很多重叠子问题&#xff0c;使用动态规划是最有效的。 所以动态规划中每一个状态一定是由上一个状态推导出来的…...

记录一个Flutter 3.24单元测试点击事件bug

哈喽&#xff0c;我是老刘 这两天发现一个Flutter 3.24版本的单元测试的一个小bug&#xff0c;提醒大家注意一下。 老刘自己写代码十多年了&#xff0c;写Flutter也6年多了&#xff0c;没想到前两天在一个小小的BottomNavigationBar 组件上翻了车。 给大家分享一下事件的经过。…...

使用Python将 word文档转pdf文档

第一步&#xff1a;我们需要导入支持包 >pip install pywin32 如果下载速度比较慢的话&#xff0c;可以考虑使用国内镜像源。 第二步&#xff1a;我们需要导入文件&#xff0c;这里采用 input,用户填入路径后&#xff0c;直接获取路径下的word文档&#xff0c;实现批量转换…...

基于C#+SQLite开发数据库应用的示例

SQLite数据库&#xff0c;小巧但功能强大&#xff1b;并且是基于文件型的数据库&#xff0c;驱动库就是一个dll文件&#xff0c;有些开发工具 甚至不需要带这个dll&#xff0c;比如用Delphi开发&#xff0c;用一些三方组件&#xff1b;数据库也是一个文件&#xff0c;虽然是个文…...

Vue基本语法

Options API 选项式/配置式api 需要在script中的export default一个对象对象中可以包含data、method、components等keydata是数据&#xff0c;数据必须是一个方法&#xff08;如果是对象&#xff0c;会导致多组件的时候&#xff0c;数据互相影响&#xff0c;因为对象赋值后&…...

芯片发展史

芯片的发展史可分为几个重要的阶段&#xff0c;从早期的真空管到现代的集成电路&#xff0c;反映了技术进步和创新的历程&#xff1a; 1. 真空管时代 (1904 - 1950年代) 真空管是20世纪初的电子元件&#xff0c;用于放大信号和开关&#xff0c;广泛应用在早期的收音机、电视机…...

我的知识图谱和Neo4j数据库的使用

知识图谱概述 知识图谱的含义 RDF与RDFS RDF&#xff08;Resource Description Framework&#xff0c;资源描述框架&#xff09;和RDFS&#xff08;RDF Schema&#xff0c;RDF模式&#xff09;是构建知识图谱的基础技术之一。它们提供了一种标准的方式来表示信息&#xff0c;…...

KubeSphere 容器平台高可用:环境搭建与可视化操作指南

Linux_k8s篇 欢迎来到Linux的世界&#xff0c;看笔记好好学多敲多打&#xff0c;每个人都是大神&#xff01; 题目&#xff1a;KubeSphere 容器平台高可用&#xff1a;环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

【力扣数据库知识手册笔记】索引

索引 索引的优缺点 优点1. 通过创建唯一性索引&#xff0c;可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度&#xff08;创建索引的主要原因&#xff09;。3. 可以加速表和表之间的连接&#xff0c;实现数据的参考完整性。4. 可以在查询过程中&#xff0c;…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

Qt Widget类解析与代码注释

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码&#xff0c;写上注释 当然可以&#xff01;这段代码是 Qt …...

CMake 从 GitHub 下载第三方库并使用

有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

技术栈RabbitMq的介绍和使用

目录 1. 什么是消息队列&#xff1f;2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...