前言

最近发现有人恶意暴力注册我的网站Seaurl,导致我的网站发送邮件近万条数据,为了防止该事件,我决定在网站上面添加限流以及IP黑名单功能,本篇文章主要讲如何限流,后面再写一篇如何设置IP黑名单。

image.png

准备

最流行的限流技术有:Sentinel、Hystrix、Resilience4J,下面是他们的对比:

image.png

通过对比之后,我决定使用更加厉害的Sentinel,而且它是阿里出品的,又有双十一做过考验,接下来详解如何集成Sentinel

操作

1、引入Sentinel依赖包

<properties>
    <java.version>17</java.version>
    <spring-boot.version>3.0.2</spring-boot.version>
    <spring-cloud.version>2022.0.0</spring-cloud.version>
    <spring-cloud-alibaba.version>2022.0.0.0</spring-cloud-alibaba.version>
</properties>

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba.csp/sentinel-datasource-nacos -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
    <version>2.0.0-alpha</version>
</dependency>

2、在Nacos上面配置Sentinel数据源

spring:
  cloud:
    sentinel:
      transport:
        //这个是sentinel控制台,需要手动下载sentinel.jar安装启动即可
        dashboard: localhost:8080
      datasource:
        ds-flow:
          nacos:
            ## nacos的地址
            server-addr: ${server.nacos.addr}
            namespace:  ${server.nacos.ns}
            ## 配置ID
            data-id: sentinel-service
            ## 配置分组,默认是DEFAULT_GROUP
            group-id: DEFAULT_GROUP
            ##  默认提供两种内置的值,分别是 json 和 xml (不填默认是json)
            data-type: json
            ## rule-type设置对应得规则类型,总共七大类型,在com.alibaba.cloud.sentinel.datasource.RuleType这个枚举类中有体现
            rule-type: flow

    nacos:
      discovery:
        server-addr: ${server.nacos.addr}
        namespace: ${server.nacos.ns}
        service: ${server.name}
      config:
        server-addr: ${server.nacos.addr}
        namespace: ${server.nacos.ns}
        prefix: ${server.name}
        file-extension: yaml

注意:如果你的nacos有namespace那么Sentinel也必须设置namespace,否则不起作用

3、设置 Sentinel的Resource

下面的webRegister就是我们需要限流的resource名称

@PostMapping("/web/register")
@SentinelResource(value = "webRegister")
public ResponseEntity<?> register(@RequestBody RegisterRequest registerRequest, ServerHttpRequest request) {
    //省略
}

4、添加 CustomExceptionHandler

添加CustomExceptionHandler异常类的目的是当限流的时候返回指定错误消息,如下代码所示:

package com.seaurl.userservice.exception;

import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.seaurl.common.result.ResultInfo;
import com.seaurl.common.result.ResultStatus;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.HashMap;
import java.util.Map;

@RestControllerAdvice
public class CustomExceptionHandler {
    /**
     * 限流全局异常
     */
    @ExceptionHandler(FlowException.class)
    public ResultInfo handlerFlowException() {
        return new ResultInfo(ResultStatus.SERVER_Exception);
    }

    /**
     * 熔断全局异常
     */
    @ExceptionHandler(DegradeException.class)
    public ResultInfo handlerDegradeException() {
        return new ResultInfo(ResultStatus.SERVER_Degrade_Exception);
    }

    /**
     * 热点限流异常
     */
    @ExceptionHandler(ParamFlowException.class)
    public ResultInfo handlerparamFlowException() {
        return new ResultInfo(ResultStatus.SERVER_Exception);
    }

    /**
     * Sentinel 权限拦截全局异常
     */
//    @ExceptionHandler(AuthorityException.class)
//    @ResponseBody
//    public Map handlerAuthorityException() {
//        return new HashMap() {{
//            put("code", HttpStatus.UNAUTHORIZED.value());
//            put("msg", "暂无权限");
//        }};
//    }
}

5、在Nacos上面创建Sentinel数据源

下面就是创建好的配置文件,以及Sentinel配置的数据源:

image.png

下面说明一下上面的属性具体的作用:

  • resource :资源名,资源名是限流规则的作用对象,比如请求资源 getUser 。
  • grade :限流阈值类型,QPS 或线程数模式。0表示线程数,1表示QPS。默认为1,即 QPS 模式
  • count :限流阈值。比如值为2表示1秒超过2个请求就限流。
  • strategy :流控模式:直接、链路、关联,默认 直接 。0表示直接,1表示关联,2表示链路。
  • controlBehavior :流控效果(直接拒绝 / 排队等待 / 慢启动模式),0表示快速失败,1表示Warm Up,2表示排队等待。
  • limitApp :流控针对的调用来源。默认就是 default ,代表不区分调用来源.

5、下载Sentinel并启动

Github下载地址:https://github.com/alibaba/Sentinel

下载好后运行jar包即可:

java -jar sentinel-dashboard-1.8.1.jar

启动好之后,我们打开浏览器,输入:localhost:8080,出现如下界面:

image.png
这样就能清楚看到限流规则以及具体限流通过的QPS了,我们可以通过请求注册接口再查看sentinel控制台看看有没有显示成功!

image.png

SpringCloud Gateway+Redis限流

在网上也能看到其它的限流方式,如SpringCloud Gateway+Redis限流,下面简单介绍一下

1、引入依赖包

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

2、配置SpringCloud Gateway

- id: users-service
  uri: lb:http://users-service # lb://serviceId
  predicates:
  - Path=/v1/users/**
  filters:
  - StripPrefix=2
  - name: RequestRateLimiter
    args:
      key-resolver: "#{@ipAddressKeyResolver}"
      redis-rate-limiter.replenishRate: 1
      redis-rate-limiter.burstCapacity: 1

3、添加IpAddressKeyResolver实体类

@Component
public class IpAddressKeyResolver implements KeyResolver {

    @Override
    public Mono<String> resolve(ServerWebExchange exchange) {
        InetSocketAddress remoteAddress = (InetSocketAddress) exchange.getRequest().getRemoteAddress();
        return Mono.just(remoteAddress.getAddress().getHostAddress()); // 获取客户端 IP 地址
    }
}

这样就能完成限流,官网介绍

总结

1、上面限流的配置有点复杂,大家注意每个细节点
2、需要下载个sentineljar包才能显示控制台数据
3、后面有时间把熔断也加上

引用

Spring Cloud(七)Sentinel
基于Nacos限流规则持久化Demo
Spring Cloud Alibaba:将 Sentinel 熔断限流规则持久化到 Nacos 配置中心
用Nacos存储Sentinel的限流规则
Spring Boot 通用限流方案,还可以这样玩!
只需三步实现Gateway结合Sentinel实现无侵入网关限流,注意避坑!
Sentinel系列(8)-Sentinel使用 Nacos 配置规则
「SpringCloud」Sentinel+Nacos配置持久化
限流降级组件Sentinel、Hystrix、Resilience4j对比

Spring Cloud Gateway 本地内存 IP 限流
GateWay网关应用案例(跨域、限流、黑白名单)
分布式限流之 - Spring Cloud Gateway层限流实现
Spring Cloud Gateway 限流实战,终于有人写清楚了!
Spring Cloud Gateway自带RequestRateLimiter限流应用及扩展 | Spring Cloud 16


Awbeci
3.1k 声望213 粉丝

Awbeci