智能BI(后端)-- 系统优化(安全性,数据存储,限流)

文章目录

安全性

问题引入:如果用户上传一个超大的文件怎么办?比如1000G?

预防:
只要涉及到用户自主上传的操作,一定要校验文件(图像)

校验什么?

  • 文件的大小
  • 文件的后缀
  • 文件的内容(成本高一点)
  • 文件的合规性,比如敏感内容(建议用第三方审核功能),todo 接入腾讯云的图片万象数据审核(COS对象存储的审核功能)

代码校验实现:

java 复制代码
        //校验文件大小
        long ONE_MB = 1024 * 1024l;
        long size = multipartFile.getSize();
        ThrowUtils.throwIf(size > ONE_MB,ErrorCode.PARAMS_ERROR,"文件过大");
        //校验后缀名
        String originalFilename = multipartFile.getOriginalFilename();
        String suffix = FileUtil.getSuffix(originalFilename);
        List<String> validSuffix = Arrays.asList("png","jpg","svg","webp","jpeg");
        ThrowUtils.throwIf(!validSuffix.contains(suffix),ErrorCode.PARAMS_ERROR,"文件后缀非法");

todo 数据存储

现状:我们把每个图表的原始数据全部放在了同一个数据表(chart表)的字段里

问题:

  1. 如果用户上传的原始数据量很大,图表数日益增多,查询chart表就会很慢
  2. 对于BI平台,用户是有查看原始数据,对原始数据进行简单查询的需求的,现在如果把所有数据放在一个字段(列)中,查询时,只能取出这个列的所有内容

**解决方案:分库分表:

**把每个图表对应的原始数据单独保存为一个新的数据表,而不是都存在一个字段里

优点:

  1. 存储时,能够分开存储,互不影响(也能增加安全性)
  2. 查询时,可以使用各种sql语句灵活取出需要的字段,查询性能更快

todo 实现:动态sql,这里鱼皮也实现了,不过没有应用,只是测试,等等复习下知识再说

限流

现在的问题 :使用系统是需要消耗成本的,用户有可能疯狂刷量,让你破产
解决问题:

  1. 控制成本 -> 限制用户调用总次数
  2. 用户在短时间内疯狂使用,导致服务器资源被占满,其他用户无法使用->限流

思考:限流阈值多大合适?参考正常用户的使用,比如限制单个用户在每秒只能使用一次

限流的几种算法

  1. 固定窗口限流
  2. 滑动窗口限流
  3. 漏桶限流
  4. 领令牌桶限流

限流粒度

  1. 针对某个方法限流
  2. 针对某个用户限流
  3. 针对用户调用某个方法限流

限流的实现

本地限流(单机限流)

每个服务器单独限流,一般适用于单体项目,你的项目只有一个服务器

Guava RateLimiter

java 复制代码
import com.google.common.util.concurrent.RateLimiter;

public static void main(String[] args) {
    // 每秒限流5个请求
    RateLimiter limiter = RateLimiter.create(5.0);
    while (true) {
        if (limiter.tryAcquire()) {
            // 处理请求
        } else {
            // 超过流量限制,需要做何处理
        }
    }
}

Redisson实现分布式限流(多机限流)

[官方项目仓库和文档](https://github.com/redisson/redisson)

  1. 引入依赖
java 复制代码
<dependency>
   <groupId>org.redisson</groupId>
   <artifactId>redisson</artifactId>
   <version>3.28.0</version>
</dependency>  
  1. 创建Redisson配置类
java 复制代码
package com.yupi.springbootinit.config;

import io.lettuce.core.RedisClient;
import io.swagger.models.auth.In;
import lombok.Data;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@ConfigurationProperties("spring.redis")
@Data
public class RedissonConfig {

    private Integer database;

    private String host;

    private Integer port;

    // spring启动时,会自动创建一个RedissonClient对象
    @Bean
    public RedissonClient getRedissonClient() {
        // 1.创建配置对象
        Config config = new Config();
        // 2. 添加单机Redisson配置
        config.useSingleServer()
        // 设置数据库
                .setDatabase(1)
        //设置redis的地址
                .setAddress("redis://" + host + ":" + port);
        //3..创建Redisson实例
        RedissonClient redissonClient = Redisson.create(config);
        return redissonClient;
    }

}
  1. 创建通用限流管理类RedisLimiterManager

(专门提供 RedisLimiter 限流基础服务),manager包存放通用模版,没有业务逻辑,可以放在任何一个项目里

java 复制代码
package com.yupi.springbootinit.manager;

import com.yupi.springbootinit.common.ErrorCode;
import com.yupi.springbootinit.exception.BusinessException;
import org.redisson.api.RRateLimiter;
import org.redisson.api.RateIntervalUnit;
import org.redisson.api.RateType;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class RedisLimiterManager {
    @Resource
    private RedissonClient redissonClient;

    public void doRateLimit(String key){
        // 创建一个名称为rateLimiter的限流器
        RRateLimiter rateLimiter = redissonClient.getRateLimiter(key);
        // 限流器的统计规则(每秒2个请求;连续的请求,最多只能有1个请求被允许通过)
        // RateType.OVERALL表示速率限制作用于整个令牌桶,即限制所有请求的速率
        rateLimiter.trySetRate(RateType.OVERALL,2,1, RateIntervalUnit.SECONDS);
        // 每当一个操作来了后,请求一个令牌
        boolean canop = rateLimiter.tryAcquire(1);
        // 如果没有令牌,还想执行操作,就抛出异常
        if(!canop){
            throw new BusinessException(ErrorCode.TOO_MANY_REQUEST);
        }

    }
}
  1. 测试后整合进项目(一行代码解决)
java 复制代码
 //限流判断,每个用户一个限流器
redisLimiterManager.doRateLimit("genChartByAi_" + loginUser.getId());
相关推荐
非优秀程序员5 小时前
第04章 邮箱大战,163 与 QQ 的暗战|《互联网产品恩仇录》
java·vue.js·架构
知已难寻5 小时前
Docker 入门:容器技术与 Docker 基础
java·运维·服务器·docker·云原生·容器
文丑颜不良啊7 小时前
LeetCode2481~2500题目解析
java·leetcode
Flynn Liang8 小时前
同一需求三套写法:用 Spring AI、LangChain4j、AgentScope Java 各实现一个带工具调用的 RAG 助手(实战对比)
java·人工智能·大模型·架构设计·spring ai·langchain4j·agentscope
聪明的笨猪猪9 小时前
实际工程问题:AI 生成 Spring Cache(@Cacheable / @CachePut / @CacheEvict)缓存注解踩坑
java·经验分享·面试·ai编程
愿有所息9 小时前
记一次 ARM64 + JDK8 上 fastjson2 的诡异数据错乱
java
秋饼10 小时前
MCP 2026-07-28 无状态协议大改版:Spring AI 2.1 多轮往返请求与网关路由落地
java·ai·技术分享·后端开发
flyingonpine11 小时前
PowerShell脚本数字签名实战:自签名证书、代码签名与信任链验证
windows·信任链
SL_staff11 小时前
JVS-BI 实战:业务人员如何用零代码 ELT + 可视化配置构建实时经营分析闭环
java·spring·全栈
SL_staff11 小时前
企业AI落地难?JVS-AI渐进式实践:安全可控、小切口验证、标准化沉淀与规模化复制
java·开源·aigc