org.springframework.boot
spring-boot-starter-actuator
org.springframework.cloud
spring-cloud-starter-netflix-hystrix
2.2.3 配置HostName的规则限流
目前只对user-center用户中心进行限流
spring:
cloud:
gateway:
discovery:
locator:
lowerCaseServiceId: true
enabled: true
routes:
=====================================
- id: api-eureka
uri: lb://eureka-server
order: 8000
predicates:
- Path=/api-eureka/**
filters:
-
StripPrefix=1
-
name: Hystrix
args:
name : default
fallbackUri: ‘forward:/defaultfallback’
- id: api-user
uri: lb://user-center
order: 8001
predicates:
- Path=/api-user/**
filters:
-
GwSwaggerHeaderFilter
-
StripPrefix=1
-
name: Hystrix
args:
name : default
fallbackUri: ‘forward:/defaultfallback’
- name: RequestRateLimiter #对应 RequestRateLimiterGatewayFilterFactory
args:
redis-rate-limiter.replenishRate: 1 # 令牌桶的容积 放入令牌桶的容积每次一个
redis-rate-limiter.burstCapacity: 3 # 流速 每秒
key-resolver: “#{@ipAddressKeyResolver}” # SPEL表达式去的对应的bean
2.2.4 新增配置类RequestRateLimiterConfig
配置类新建在com.open.capacity.client.config路径下
package com.open.capacity.client.config;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.core.publisher.Mono;
/**
-
定义spring cloud gateway中的 key-resolver: “#{@ipAddressKeyResolver}” #SPEL表达式去的对应的bean
-
ipAddressKeyResolver 要取bean的名字
*/
@Configuration
public class RequestRateLimiterConfig {
/**
-
根据 HostName 进行限流
-
@return
*/
@Bean(“ipAddressKeyResolver”)
public KeyResolver ipAddressKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}
/**
-
根据api接口来限流
-
@return
*/
@Bean(name=“apiKeyResolver”)
public KeyResolver apiKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getPath().value());
}
/**
-
用户限流
-
使用这种方式限流,请求路径中必须携带userId参数。
-
提供第三种方式
-
@return
*/
@Bean(“userKeyResolver”)
KeyResolver userKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst(“userId”));
}
}
2.2.5 压力测试
接下来配置东西弄完之后 我们开始进行压力测试,压力测试之前,由于new-api-gateway有全局拦截器 AccessFilter 的存在,如果不想进行登录就进行测试的。先把
“/api-auth/**” 的判断中的注释掉。接下来我们开用postman进行测试
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// TODO Auto-generated method stub
String accessToken = extractToken(exchange.getRequest());
if(pathMatcher.match(“//v2/api-docs/”,exchange.getRequest().getPath().value())){
return chain.filter(exchange);
}
if(!pathMatcher.match(“/api-auth/**”,exchange.getRequest().getPath().value())){
// if (accessToken == null) {
// exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
// return exchange.getResponse().setComplete();
// }else{
// try {
// Map<String, Object> params = (Map<String, Object>) redisTemplate.opsForValue().get(“token:” + accessToken) ;
// if(params.isEmpty()){
// exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
// return exchange.getResponse().setComplete();
// }
// } catch (Exception e) {
// exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
// return exchange.getResponse().setComplete();
// }
// }
}
return chain.filter(exchange);
}
- 1.打开postman 选择Collections 点击新建按钮
- 2.点击新建的Collection 新建一个request
-
- 输入地址:127.0.0.1:9200/api-user/users-anon/login?username=admin
- 4.切换成Tests的tab下,选择右边Status code is 200选项,这里可以选择其他的方法,根据自己的api定义。
- 5.这里需要注意:操作完刚刚的数据,必须点击save进行保存,否则无法生效;
请求配置
-
- 点击 Run,就可以查看结果,有五次成功,五次失败;限流成功返回429
在前一章,我们已经做了简单spring cloud gateway 介绍 和 限流,接下来,spring cloud gateway最重要的,也是最为关键的 动态路由,首先,API网关负责服务请求路由、组合及协议转换,客户端的所有请求都首先经过API网关,然后由它将匹配的请求路由到合适的微服务,是系统流量的入口,在实际生产环境中为了保证高可靠和高可用,尽量避免重启,如果有新的服务要上线时,可以通过动态路由配置功能上线。
首先,springcloudgateway配置路由有2种方式:
-
yml配置文件
-
面向对象配置(代码方式配置)
3.1 yml配置
3.2 代码方式配置
3.3 路由初始化
srping cloud gateway网关启动时,路由信息默认会加载内存中,路由信息被封装到RouteDefinition对象中,
org.springframework.cloud.gateway.route.RouteDefinition
该类有的属性为 :
@NotEmpty
private String id = UUID.randomUUID().toString();
//路由断言定义
@NotEmpty
@Valid
private List predicates = new ArrayList<>();
//路由过滤定义
@Valid
private List filters = new ArrayList<>();
//对应的URI
@NotNull
private URI uri;
private int order = 0;
一个RouteDefinition有个唯一的ID,如果不指定,就默认是UUID,多个RouteDefinition组成了gateway的路由系统,所有路由信息在系统启动时就被加载装配好了,并存到了内存里。
3.4 网关的自动配置
org.springframework.cloud.gateway.config.GatewayAutoConfiguration
//RouteLocatorBuilder 采用代码的方式注入路由
@Bean
public RouteLocatorBuilder routeLocatorBuilder(ConfigurableApplicationContext context) {
return new RouteLocatorBuilder(context);
}
//PropertiesRouteDefinitionLocator 配置文件路由定义
@Bean
@ConditionalOnMissingBean
public PropertiesRouteDefinitionLocator propertiesRouteDefinitionLocator(GatewayProperties properties) {
return new PropertiesRouteDefinitionLocator(properties);
}
//InMemoryRouteDefinitionRepository 内存路由定义
@Bean
@ConditionalOnMissingBean(RouteDefinitionRepository.class)
public InMemoryRouteDefinitionRepository inMemoryRouteDefinitionRepository() {
return new InMemoryRouteDefinitionRepository();
}
//CompositeRouteDefinitionLocator 组合多种模式,为RouteDefinition统一入口
@Bean
@Primary
public RouteDefinitionLocator routeDefinitionLocator(List routeDefinitionLocators) {
return new CompositeRouteDefinitionLocator(Flux.fromIterable(routeDefinitionLocators));
}
@Bean
public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties,
List GatewayFilters,
List predicates,
RouteDefinitionLocator routeDefinitionLocator) {
return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates, GatewayFilters, properties);
}
//CachingRouteLocator 为RouteDefinition提供缓存功能
@Bean
@Primary
//TODO: property to disable composite?
public RouteLocator cachedCompositeRouteLocator(List routeLocators) {
return new CachingRouteLocator(new CompositeRouteLocator(Flux.fromIterable(routeLocators)));
}
装配yml文件的,它返回的是PropertiesRouteDefinitionLocator,该类继承了RouteDefinitionLocator,RouteDefinitionLocator就是路由的装载器,里面只有一个方法,就是获取路由信息的。
org.springframework.cloud.gateway.route.RouteDefinitionLocator
RouteDefinitionLocator 类图如下:
子类功能描述:
-
CachingRouteDefinitionLocator:RouteDefinitionLocator包装类, 缓存目标RouteDefinitionLocator 为routeDefinitions提供缓存功能
-
CompositeRouteDefinitionLocator -RouteDefinitionLocator包装类,组合多种 RouteDefinitionLocator 的实现,为 routeDefinitions提供统一入口
-
PropertiesRouteDefinitionLocator-从配置文件(GatewayProperties 例如,YML / Properties 等 ) 读取RouteDefinition
-
RouteDefinitionRepository-从存储器( 例如,内存 / Redis / MySQL 等 )读取RouteDefinition
-
DiscoveryClientRouteDefinitionLocator-从注册中心( 例如,Eureka / Consul / Zookeeper / Etcd 等
推荐参考文章:https://www.jianshu.com/p/b02c7495eb5e
3.5 编写动态路由
新建数据脚本,在 sql目录下 02.oauth-center.sql
Structure for table “sys_gateway_routes”
DROP TABLE IF EXISTS sys_gateway_routes;
CREATE TABLE sys_gateway_routes
(
id
char(32) NOT NULL COMMENT ‘id’,
uri
VARCHAR(100) NOT NULL COMMENT ‘uri路径’,
predicates
VARCHAR(1000) COMMENT ‘判定器’,
filters
VARCHAR(1000) COMMENT ‘过滤器’,
order
INT COMMENT ‘排序’,
description
VARCHAR(500) COMMENT ‘描述’,
delFlag
int(11) DEFAULT ‘0’ COMMENT ‘删除标志 0 不删除 1 删除’,
createTime
datetime NOT NULL,
updateTime
datetime NOT NULL,
PRIMARY KEY (id
)
) ENGINE=InnoDB AUTO_INCREMENT=38 DEFAULT CHARSET=utf8mb4 COMMENT ‘服务网关路由表’;
/**
- 路由实体类
*/
public class GatewayRoutes {
private String id;
private String uri;
private String predicates;
private String filters;
private Integer order;
private String description;
private Integer delFlag;
private Date createTime;
private Date updateTime;
//省略getter,setter
}
/**
- 路由的Service类
*/
@Service
public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware, IDynamicRouteService {
/**
-
新增路由
-
@param gatewayRouteDefinition
-
@return
*/
@Override
public String add(GatewayRouteDefinition gatewayRouteDefinition) {
GatewayRoutes gatewayRoutes = transformToGatewayRoutes(gatewayRouteDefinition);
gatewayRoutes.setDelFlag(0);
gatewayRoutes.setCreateTime(new Date());
gatewayRoutes.setUpdateTime(new Date());
gatewayRoutesMapper.insertSelective(gatewayRoutes);
gatewayRouteDefinition.setId(gatewayRoutes.getId());
redisTemplate.opsForValue().set(GATEWAY_ROUTES_PREFIX + gatewayRouteDefinition.getId(), JSONObject.toJSONString(gatewayRouteDefinition));
return gatewayRoutes.getId();
}
/**
-
修改路由
-
@param gatewayRouteDefinition
-
@return
*/
@Override
public String update(GatewayRouteDefinition gatewayRouteDefinition) {
GatewayRoutes gatewayRoutes = transformToGatewayRoutes(gatewayRouteDefinition);
gatewayRoutes.setCreateTime(new Date());
gatewayRoutes.setUpdateTime(new Date());
gatewayRoutesMapper.updateByPrimaryKeySelective(gatewayRoutes);
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
最后
手绘了下图所示的kafka知识大纲流程图(xmind文件不能上传,导出图片展现),但都可提供源文件给每位爱学习的朋友
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。[外链图片转存中…(img-C10AVIFG-1712657722510)]
[外链图片转存中…(img-6dhjUxmO-1712657722511)]
[外链图片转存中…(img-ylf6cNtP-1712657722511)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
最后
手绘了下图所示的kafka知识大纲流程图(xmind文件不能上传,导出图片展现),但都可提供源文件给每位爱学习的朋友
[外链图片转存中…(img-jSQMJS4G-1712657722511)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!