阅读 202

spring cloud: 微服务环境搭建(alibaba)增强(限流、降级、熔断)

spring cloud: 微服务环境搭建(alibaba)进行限流、降级、熔断

官方文档:sentinelguard.io/zh-cn/

1. 错误信息配置化(3. 服务容错Sentinel)

目标:把限流返回信息变成可配置,并保存到nacos上

GatewayConfiguration.java

@Configuration
public class GatewayConfiguration {
	private final List<ViewResolver> viewResolvers;
	private final ServerCodecConfigurer serverCodecConfigurer;
        
	/**
	 * 限流配置
	 */
	@Value("${spring.cloud.sentinel.flow.status}")
	private String flowStatus;
	@Value("${spring.cloud.sentinel.flow.message}")
	private String 	flowMsg;
        @PostConstruct 
        public void initGatewayRules() {
            Set<GatewayFlowRule> rules = new HashSet<>(); 
            rules.add( new GatewayFlowRule("Item_route") //资源名称,对应路由id
                        .setCount(1) // 限流阈值
                         .setIntervalSec(1) // 统计时间窗口,单位是秒,默认是 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",flowStatus);
				map.put("message",flowMsg);

				return ServerResponse
						.status(HttpStatus.OK)
						.contentType(MediaType.APPLICATION_JSON)
						.body(BodyInserters.fromValue(map));
			}
		};
                GatewayCallbackManager.setBlockHandler(blockRequestHandler);
	}
	/**
	 * 增加这个函数的意义:可以从配置文件获取值(如果缺失,取不到)
	 * @return
	 */
	@Bean
	public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
		return new PropertySourcesPlaceholderConfigurer();
	}
复制代码

http://localhost:8848/nacos/ 增加如下配置

image.png

执行结果: 频繁访问后

image.png

2. Sentinel的限流、降级、熔断

具体参考:cloud.tencent.com/developer/a…

从上面代码可以看出来,initBlockHandlers按照异常类型分装就可

package com.temp.conf;

import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
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.alibaba.csp.sentinel.slots.system.SystemBlockException;
import lombok.Data;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.reactive.result.view.ViewResolver;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.util.Collections;
import java.util.List;

@Configuration
public class GatewayConfiguration {
	private final List<ViewResolver> viewResolvers;
	private final ServerCodecConfigurer serverCodecConfigurer;
	/**
	 * 限流
	 */
	@Value("${spring.cloud.sentinel.flow.status}")
	private Integer flowStatus;
	@Value("${spring.cloud.sentinel.flow.message}")
	private String flowMsg;
	/**
	 * 降级
	 */
	@Value("${spring.cloud.sentinel.degrade.status}")
	private Integer degradeStatus;
	@Value("${spring.cloud.sentinel.degrade.message}")
	private String degradeMsg;
	/**
	 * 热点参数限流
	 */
	@Value("${spring.cloud.sentinel.param.flow.status}")
	private Integer paramFlowStatus;
	@Value("${spring.cloud.sentinel.param.flow.message}")
	private String paramFlowMsg;
	/**
	 * 系统规则(负载/...不满足要求)
	 */
	@Value("${spring.cloud.sentinel.system.block.status}")
	private Integer systemBlockStatus;
	@Value("${spring.cloud.sentinel.system.block.message}")
	private String systemBlockMsg;

	@Value("${spring.cloud.sentinel.authority.status}")
	private Integer authorityStatus;
	@Value("${spring.cloud.sentinel.authority.message}")
	private String authorityMsg;

	public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
								ServerCodecConfigurer serverCodecConfigurer) {
		this.viewResolvers =
				viewResolversProvider.getIfAvailable(Collections::emptyList);
		this.serverCodecConfigurer = serverCodecConfigurer;

	}

	/**
	 * Initialize a current-limiting filter
	 */
	@Bean
	@Order(Ordered.HIGHEST_PRECEDENCE)
	public GlobalFilter sentinelGatewayFilter() {
		return new SentinelGatewayFilter();
	}

	/**
	 * Configure current limiting exception handler
	 *
	 * @return SentinelGatewayBlockExceptionHandler
	 */
	@Bean
	@Order(Ordered.HIGHEST_PRECEDENCE)
	public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
		return new SentinelGatewayBlockExceptionHandler(
				viewResolvers,
				serverCodecConfigurer
		);
	}

	@PostConstruct
	public void initBlockHandlers() {
		BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
			@Override
			public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable e) {

				SentinelErrorMsg sentinelErrorMsg = new SentinelErrorMsg();
					// 流控异常
				if (e instanceof FlowException) {
					sentinelErrorMsg.setMsg(flowMsg);
					sentinelErrorMsg.setStatus(flowStatus);
					// 降级异常
				} else if (e instanceof DegradeException) {
					sentinelErrorMsg.setMsg(degradeMsg);
					sentinelErrorMsg.setStatus(degradeStatus);
					// 参数流控异常
				} else if (e instanceof ParamFlowException) {
					sentinelErrorMsg.setMsg(paramFlowMsg);
					sentinelErrorMsg.setStatus(paramFlowStatus);
					// 系统堵塞异常
				} else if (e instanceof SystemBlockException) {
					sentinelErrorMsg.setMsg(systemBlockMsg);
					sentinelErrorMsg.setStatus(systemBlockStatus);
					// 权限异常
				} else if (e instanceof AuthorityException) {
					sentinelErrorMsg.setMsg(authorityMsg);
					sentinelErrorMsg.setStatus(authorityStatus);
				}

				return ServerResponse
						.status(HttpStatus.OK)
						.contentType(MediaType.APPLICATION_JSON)
						.body(BodyInserters.fromValue(sentinelErrorMsg));
			}
		};
		GatewayCallbackManager.setBlockHandler(blockRequestHandler);

	}

	/**
	 * 增加这个函数的意义:可以从配置文件获取值(如果缺失,取不到)
	 *
	 * @return
	 */
	@Bean
	public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
		return new PropertySourcesPlaceholderConfigurer();
	}

	/**
	 * Error message
	 */
	@Data
	static class SentinelErrorMsg {
		private Integer status;
		private String msg;
	}
}

复制代码

3. Sentinel 控制台 1.8.1控制

Sentinel上应该看到的工程没看到的话,请按照以下方法操作

执行参数:

-Dcsp.sentinel.app.type=1 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=alibaba-gateway

说明:-Dcsp.sentinel.app.type=1 网关限流设置。

如果还未出来,请清理浏览器缓存;因为是Sentinel是懒加载,需要执行具体api,再刷新就出来了。

3.1 流控

说明:这里做网关流控的话,谨记使用定义好的routId而不是对应的API地址

image.png

流控规则设定

image.png

在访问此routeID所辖链接时,就会有如下限流效果:

image.png

3.2 降级

image.png bug:bbs.huaweicloud.com/blogs/20606… 注意:1.8.0 版本的Sentinel dashboard降级页面有个bug,就是统计时长属性维护 丢失,有望再下一个版本中修复

需要切换到1.8.1版本,修复此bug了

3.2.1 修改之前的service:/item/{id}

@RestController
public class ItemController {
	@Autowired
	private ItemService itemService;

	@RequestMapping("/item/{id}")
	public Item query(@PathVariable Long id) {

		// 让此服务睡眠10秒钟
		try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return itemService.queryItemById(id);
	}

	@RequestMapping("/item/change/{id}/{order_id}")
	public Item saveOrderId(@PathVariable("id") Long id,@PathVariable("order_id") Long orderId) {
		return itemService.saveOrderId(id,orderId);
	}
}
复制代码

重启temp-item工程

3.2.2 降级配置

image.png

配置对话框

image.png

保存后,降级规则生效

image.png

3.2.3 测试

首次访问时,经过10s结果出来了

image.png

但是再次刷新后,服务就变成降级了

image.png

说明:10s后就能恢复访问

从这部分开始,对这部分配置进行持久化,稍微花的时间多了些。暂时另起一篇

文章分类
后端
文章标签