赞
踩
- Kong
- Zuul
- Traefik
- Spring Cloud Gateway
- Nginx+lua
简单配置一下,
Zuul是Netflix开源的微服务网关,他可以和Eureka,Ribbon,Hystrix等组件配合使用。Zuul组件的核心是一系列的过滤器,这些过滤器可以完成以下功能:
- 身份认证和安全:识别每一个资源的验证要求,并拒绝那些不符的请求
- 审查与监控:在服务边界追踪并统计数据,提供精确的生产视图
- 动态路由:动态将请求路由到不同后端集群
- 压力测试:逐渐增加指向集群的流量,以了解性能
- 负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求
- 静态响应处理:边缘位置进行响应,避免转发到内部集群
- 多区域弹性:跨域AWS Region进行请求路由,旨在实现ELB(ElasticLoad Balancing)使用多样化
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
<version>2.0.7.RELEASE</version>
</dependency>
//开启zuul网关功能
@EnableZuulProxy
server:
port: 8080
spring:
application:
name: api_zuul_server
zuul:
prefix: /yyong
ignored-services: "*"
routes:
mydept: #路由id,随便写
serviceId: mydept-service #指定Eureka注册中心中的服务id
path: /mydept/**#映射路径
- 添加eureka的依赖
- 开启服务发现
- 相当于大门
/** * 自定义的zuul过滤器 * 继承抽象父类 */ @Component public class LoginFilter extends ZuulFilter { /** * 定义过滤器类型 * pre:转发到微服务之前执行的过滤器 * routing:在路由请求是执行的过滤器 * post:执行微服务获取返回值之后执行的过滤器 * error:在整个阶段抛出异常的时候执行的过滤器 * @return */ @Override public String filterType() { return "pre"; } /** * 指定过滤器的执行顺序 * 返回值越少,执行顺寻越高 * @return */ @Override public int filterOrder() { return 1; } /** * 当前过滤器是否生效 * true:使用此过滤器 * flase:不使用此过滤器 * @return */ @Override public boolean shouldFilter() { return true; } /** * 指定过滤器中的业务逻辑 * @return * @throws ZuulException */ @Override public Object run() throws ZuulException { System.out.println("执行了过滤器"); return null; } }
小小的案例
/** * 指定过滤器中的业务逻辑 * 身份认证: * 1.所有的请求需要携带一个参数:access-token * 2.获取request请求 * 3.通过request获取参数access-token * 4.判断token是否为空 * 4.1 token==null:身份验证失败 * 4.2 token!==null:执行后续操作 * 在zuul网关中,通过RequestContext的上下文对象,可以获取对象request对象 * @return * @throws ZuulException */ @Override public Object run() throws ZuulException { System.out.println("执行了过滤器"); //1.获取zuul提供的上下文对象RequestContext RequestContext ctx = RequestContext.getCurrentContext(); //2.从RequestContext中获取request HttpServletRequest request = ctx.getRequest(); //3.获取请求参数access-token String token = request.getParameter("access-token"); //4.判断 if (token == null){ //4.1 token==null:身份验证失败 ctx.setSendZuulResponse(false);//拦截请求 ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value()); } //4.2 token!==null:执行后续操作 return null; }
在实际使用中我们会发现直接使用Zuul会存在诸多问题,包括:
- 性能问题
- 不支持任何长连接,如websocket
Zuul网关的替换方案
- zuul2.x
- Spring Cloud Gateway
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
#配置SpringCloudGateway的路由
spring:
cloud:
gateway:
routes:
#配置路由:路由id,路由到微服务的uri,断言(判断条件)
- id: xxxx-dept #保持唯一
uri: http://127.0.0.1 #目标微服务请求地址
predicates:
- Path=/product/** #路由匹配条件
断言条件
2)动态路由(面向服务的路由):
#配置SpringCloudGateway的路由 spring: cloud: gateway: routes: #配置路由:路由id,路由到微服务的uri,断言(判断条件) - id: xxxx-dept #保持唯一 # uri: http://127.0.0.1 #目标微服务请求地址 uri: lb://service-product #lb:// 根据微服务名称从注册中心中拉取服务请求路径 predicates: - Path=/product-service/** #路由匹配条件 filters: #配置路由过滤器,http://127.0.0.1:8080/product-service/product/1 ---> http://127.0.0.1:9001/product/1 - RewritePath=/product-service/(?<segment>.*),/$\{segment} #路径重写的过滤器 #配置自动的根据微服务名称进行路由转发 discovery: locator: enabled: true #开启根据服务名称自动转发 lower-case-service-id: true #微服务名称已小写形式呈现
1)过滤器的生命周期
2)过滤器类型
/** * 自定义一个全局过滤器 * 实现 globalfilter,ordered */ public class LoginGlobalFilter implements GlobalFilter, Ordered { /** * 执行过滤器的业务逻辑 * @param exchange * @param chain * @return */ @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { System.out.println("执行了自定义的全局过滤器"); return chain.filter(exchange);//继续向下执行 } /** * 指定过滤器的执行顺序,返回值越小,执行优先级越高 * @return */ @Override public int getOrder() { return 1; } }
/** * 执行过滤器的业务逻辑 * 对请求参数中的access-token进行判断 * 如果存在此参数:代表已经认证成功 * 如果不存在此参数:认证失败 * ServerWebExchange:相当于请求和响应的上下文(zuul中的RequestContext) * @param exchange * @param chain * @return */ @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { System.out.println("执行了自定义的全局过滤器"); //1.获取请求参数 String first = exchange.getRequest().getQueryParams().getFirst("access-token"); //2.判断是否存在: if(first == null){ //3.如果不存在:认证失败 System.out.println("没有登录"); exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); return exchange.getResponse().setComplete(); } //4.如果存在:继续执行 return chain.filter(exchange);//继续向下执行 }
1)常见的限流算法
(1)计数器:不平滑
(2)漏桶算法
(3)令牌桶算法
2)基于 Filter 的限流
(1)准备工作
redis
在工程中引入redis相应的依赖
<!--actuator监控信息完善-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- redis依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
(2)修改网关中的application.yml配置
spring: application: api-server #服务名称 redis: host: 127.0.0.1 pool: 6379 database: 0 cloud: #配置SpringCloudGateway的路由 gateway: routes: - id: payment-router uri: lb://payment-service predicates: - Path=/pay/** filters: # RequestRateLimiter:使用限流过滤器,是springcloud gateway提供的 # 参数 replenishRate:向令牌桶中填充的速率 # burstCapacity :令牌桶的容量 - name: RequestRateLimiter args: # 令牌桶每秒填充平均速率 redis-rate-limiter.replenishRate: 1 # 令牌桶的上限 redis-rate-limiter.burstCapacity: 5 # 使用SpEL从容器中获取对象 key-resolver: '#{@pathKeyResolver}'
(3)配置redis中解析器keySesolver
@Configuration public class KeyResolverConfiguration { /** * 编写基于请求路径的限流规则 * //abc * //基于请求ip 127.0.0.1 * //基于参数 * @return */ @Bean public KeyResolver pathKeyResolver(){ //自定义的KeyResolver return new KeyResolver(){ /** * ServerWebExchange: * 上下文参数 * @param exchange * @return */ @Override public Mono<String> resolve(ServerWebExchange exchange) { return Mono.just(exchange.getRequest().getPath().toString()); } }; } /** * 基于请求参数的限流 * 请求 abc ? userId=1 * @return */ @Bean public KeyResolver userKeyResolver(){ return new KeyResolver(){ @Override public Mono<String> resolve(ServerWebExchange exchange) { return Mono.just(exchange.getRequest().getQueryParams().getFirst("userId")); } }; } /** * 基于请求ip的限流 * 请求 abc ? userId=1 * @return */ @Bean public KeyResolver userKeyResolver(){ return new KeyResolver(){ @Override public Mono<String> resolve(ServerWebExchange exchange) { return Mono.just(exchange.getRequest().getHeaders().getFirst("X-Forwarded-For")); } }; } }
3)基于 Sentinel 的限流
<!--sentinel限流-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
<version>1.6.3</version>
</dependency>
配置类
@Configuration public class GatewayConfiguration { private final List<ViewResolver> viewResolvers; private final ServerCodecConfigurer serverCodecConfigurer; public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,ServerCodecConfigurer serverCodecConfigurer){ this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList); this.serverCodecConfigurer = serverCodecConfigurer; } /** * 配置限流的异常处理器:SentinelGatewayBlockExceptionHandler * @return */ @Bean @Order(Ordered.HIGHEST_PRECEDENCE) public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler(){ return new SentinelGatewayBlockExceptionHandler(viewResolvers,serverCodecConfigurer); } /** * 配置限流过滤器 * @return */ @Bean @Order(Ordered.HIGHEST_PRECEDENCE) public GlobalFilter sentinelGlobalFilter() { return new SentinelGatewayFilter(); } /** * 配置初始化的限流参数 * 用户指定资源的限流的规则 * 1.资源名称(路由id) * 2.配置统计时间 * 3.配置限流阈值 */ @PostConstruct public void initGatewayRules(){ Set<GatewayFlowRule> rules = new HashSet<>(); /* rules.add( new GatewayFlowRule("order-service")//资源名称 .setCount(1)//限流阈值 .setIntervalSec(1)//统计事件窗口,单位秒,默认是一秒 ); rules.add( new GatewayFlowRule("order-service")//资源名称 .setCount(1)//限流阈值 .setIntervalSec(1)//统计事件窗口,单位秒,默认是一秒 .setParamItem(new GatewayParamFlowItem() .setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_URL_PARAM).setFieldName("id")) );*/ rules.add( new GatewayFlowRule("product_api") .setCount(1) .setIntervalSec(1) ); rules.add( new GatewayFlowRule("order_api") .setCount(1) .setIntervalSec(1) ); GatewayRuleManager.loadRules(rules); } /* @PostConstruct public void initBlockhandlers(){ BlockRequestHandler blockRequestHandler = new BlockRequestHandler(){ @Override public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) { Map map = new HashMap<>(); map.put("code",001); map.put("message","对不起,接口限流了"); return ServerResponse.status(HttpStatus.OK) .contentType(MediaType.APPLICATION_JSON_UTF8) .body(BodyInserters.fromObject(map)); } }; GatewayCallbackManager.setBlockHandler(blockRequestHandler); } @PostConstruct public void initCustomizedApis(){ Set<ApiDefinition> definitions = new HashSet<>(); ApiDefinition api1 = new ApiDefinition("product_api") .setPredicateItems(new HashSet<ApiPredicateItem>(){{ add(new ApiPathPredicateItem().setPattern("/product-service/product/**") .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX)); }}); ApiDefinition api2 = new ApiDefinition("order_api") .setPredicateItems(new HashSet<ApiPredicateItem>(){{ add(new ApiPathPredicateItem().setPattern("/order-service/order")); }}); definitions.add(api1); definitions.add(api2); GatewayApiDefinitionManager.loadApiDefinitions(definitions); }*/ }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。