服务端代码上一篇已经写过了,这篇主要配置gateway
服务端代码:https://codechina.csdn.net/wwwzhouzy/rediswatch
gateway代码:https://codechina.csdn.net/wwwzhouzy/limitgateway
1、pom.xml引入
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.6.RELEASE</version>
<relativePath/>
</parent>
<groupId>com.zhouzy.gateway</groupId>
<artifactId>zzy-gateway</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>zzy-gateway</name>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!--spring cloud gateway依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--基于 reactive stream 的redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
2、配置application.yml
server:
port: 8082
spring:
cloud:
gateway:
routes:
- id: neo_route
uri: http://127.0.0.1:8081/api/miaosha
predicates:
- Path=/api/**
filters:
- name: RequestRateLimiter
args:
key-resolver: '#{@remoteUserResolver}'
redis-rate-limiter.replenishRate: 1
redis-rate-limiter.burstCapacity: 3
redis:
host: localhost
port: 6379
database: 0
key-resolver: '#{@remoteUserResolver}' ##用于限流的键的解析器的 Bean 对象的名字。它使用 SpEL 表达式根据#{@beanName}从 Spring 容器中获取 Bean 对象。
redis-rate-limiter.replenishRate: 1 ## 令牌桶每秒填充平均速率。
redis-rate-limiter.burstCapacity: 3 ##令牌桶总容量
3、定义remoteUserResolver对象
package com.zhouzy.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import reactor.core.publisher.Mono;
@EnableAutoConfiguration
@SpringBootApplication
class WebApplication{
public static void main(String[] args) {
SpringApplication.run(WebApplication.class, args);
}
/**
* 自定义限流标志的key,多个维度可以从这里入手
* exchange对象中获取服务ID、请求信息,用户信息等
*/
@Bean
KeyResolver remoteAddrKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}
/**
* 自定义限流标志的key,多个维度可以从这里入手
* exchange对象中获取服务ID、请求信息,用户信息等
*/
@Bean
KeyResolver remoteUserResolver() {
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));
}
}
4、测试验证
package com.zhouzy.boot.zhouzyBoot;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.junit.Test;
public class MiaoshaTest {
//JUC工具类 栅栏,实现满一定数量线程后往下执行,跟countdownlatch不同的是,这个可以重复使用
private static CyclicBarrier cyclicBarrier = new CyclicBarrier(100);
@Test
public void test() {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i=0;i<200;i++){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
final int num = i%5;//这样是为了让一批线程里有两个相同的用户去竞争,主要是为了测试并发
executorService.execute(()->{
try {
play("userId"+num,"name"+num);
} catch (BrokenBarrierException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
}
public static void play(String userId,String name) throws BrokenBarrierException, InterruptedException {
System.out.println(Thread.currentThread().getName() + " 已准备");
cyclicBarrier.await();
Map<String,String> map = new HashMap();
map.put("userId", userId);
map.put("name", name);
HttpClientUtil.doPost("http://127.0.0.1:8082/api/miaosha?userId="+userId, map, "UTF-8");
System.out.println(Thread.currentThread().getName() + " 开始执行");
}
}
转发结果:
转发过去22条,总共执行200条,过滤了178条,说明限流起到效果了
因为只有5个不同用户,所以只减去5个库存,说明redis watch功能有效果