智能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());
相关推荐
好奇的菜鸟1 小时前
如何在IntelliJ IDEA中设置数据库连接全局共享
java·数据库·intellij-idea
程序视点1 小时前
Window 10文件拷贝总是卡很久?快来试试这款小工具,榨干硬盘速度!
windows
wuk9982 小时前
基于MATLAB编制的锂离子电池伪二维模型
linux·windows·github
DuelCode2 小时前
Windows VMWare Centos Docker部署Springboot 应用实现文件上传返回文件http链接
java·spring boot·mysql·nginx·docker·centos·mybatis
优创学社22 小时前
基于springboot的社区生鲜团购系统
java·spring boot·后端
幽络源小助理2 小时前
SpringBoot基于Mysql的商业辅助决策系统设计与实现
java·vue.js·spring boot·后端·mysql·spring
猴哥源码2 小时前
基于Java+springboot 的车险理赔信息管理系统
java·spring boot
lzb_kkk3 小时前
【C++】C++四种类型转换操作符详解
开发语言·c++·windows·1024程序员节
YuTaoShao3 小时前
【LeetCode 热题 100】48. 旋转图像——转置+水平翻转
java·算法·leetcode·职场和发展
Dcs3 小时前
超强推理不止“大”——手把手教你部署 Mistral Small 3.2 24B 大模型
java