Nacos、Sentinel、Gateway、Feign学习相关记录
上一篇笔记在2019年06月23日,,,
Nacos+Gateway实现灰度控制
在Gateway增加配置类,如果Header中存在Version(或者自己定义的其他玩意),从符合的服务进行调用,否则走默认的轮询
/**
* 灰度控制
*
* 需要在Header中增加version
* 如果没有默认走轮询
*
* @author Krasus1966
* @date 2021/5/4 22:52
**/
// 这个注解放在 init 类上了,理论上可以加在能扫描的包上面
public class VersionControlSupplier extends DiscoveryClientServiceInstanceListSupplier {
public VersionControlSupplier(DiscoveryClient delegate, Environment environment) {
super(delegate, environment);
}
public VersionControlSupplier(ReactiveDiscoveryClient delegate, Environment environment) {
super(delegate, environment);
}
public Flux<List<ServiceInstance>> get(Request request) {
final String requestVersion = ((RequestDataContext) request.getContext()).getClientRequest().getHeaders().getFirst("version");
if (requestVersion != null) {
return super.get(request).map(list -> {
List<ServiceInstance> tmpList = list.stream()
.filter(instance -> requestVersion.equals(instance.getMetadata().get("version")))
.collect(Collectors.toList());
return tmpList.isEmpty() ? list : tmpList;
});
}
return super.get(request);
}
// VersionControlSupplierConfiguration 注册的 bean
VersionControlSupplier serviceInstanceListSupplier(ConfigurableApplicationContext context) {
ReactiveDiscoveryClient reactiveDiscoveryClient = context.getBean(ReactiveDiscoveryClient.class);
return new VersionControlSupplier(reactiveDiscoveryClient, context.getEnvironment());
}
}
在需要版本控制的服务中增加版本的元数据
spring:
cloud:
nacos:
discovery:
# 元数据中增加版本号
metadata:
version: v1.0
Sentinel推送限流规则到Nacos进行持久化
需要下载Sentinel源码,首次运行前,需要将除DashBoard以外的模块打包进本地Maven仓库,完成后能成功运行DashBoard,就可以将DashBoard模块迁移到需要的项目中。
增加Nacos依赖和配置,能在Nacos控制台看到DashBoard服务。在 test->rule->nacos 目录中有写好的Nacos推送规则相关代码,移动到主目录的rule中。其中的NacosConfig需要增加bean,如果需要拓展其他规则的推送,也可以仿照源代码中内容进行补充。
// 源代码中的限流规则配置,需要拓展其他规则就仿写这里的,对应规则实体在com.alibaba.csp.sentinel.dashboard.datasource.entity.rule 下
public Converter<List<FlowRuleEntity>, String> flowRuleEntityEncoder() {
return JSON::toJSONString;
}
public Converter<String, List<FlowRuleEntity>> flowRuleEntityDecoder() {
return s -> JSON.parseArray(s, FlowRuleEntity.class);
}
// 需要补充Nacos连接配置,不配置的话默认Nacos控制台地址为localhost:8848,命名空间为public,不受bootstrap.yml配置文件管理
public ConfigService nacosConfigService() throws Exception {
Properties properties = new Properties();
// Nacos 控制台地址
properties.put(PropertyKeyConst.SERVER_ADDR,serverAddr);
// 命名空间
properties.put(PropertyKeyConst.NAMESPACE,namespace);
return ConfigFactory.createConfigService(properties);
}
在对应的Controller中,将SentinelApiClient用源码中的ruleProvider和rulePublisher替换
public class FlowControllerV2 {
private final Logger logger = LoggerFactory.getLogger(FlowControllerV2.class);
private InMemoryRuleRepositoryAdapter<FlowRuleEntity> repository;
private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
public Result<List<FlowRuleEntity>> apiQueryMachineRules( String app) {
if (StringUtil.isEmpty(app)) {
return Result.ofFail(-1, "app can't be null or empty");
}
try {
// 此处的获得规则列表用ruleProvider.getRules(appName)获得,其他方法基本相同
List<FlowRuleEntity> rules = ruleProvider.getRules(app);
if (rules != null && !rules.isEmpty()) {
for (FlowRuleEntity entity : rules) {
entity.setApp(app);
if (entity.getClusterConfig() != null && entity.getClusterConfig().getFlowId() != null) {
entity.setId(entity.getClusterConfig().getFlowId());
}
}
}
rules = repository.saveAll(rules);
return Result.ofSuccess(rules);
} catch (Throwable throwable) {
logger.error("Error when querying flow rules", throwable);
return Result.ofThrowable(-1, throwable);
}
}
// 需要将方法修改成以下内容
private void publishRules(/*@NonNull*/ String app) throws Exception {
List<FlowRuleEntity> rules = repository.findAllByApp(app);
rulePublisher.publish(app, rules);
}
}
<li ui-sref-active="active" ng-if="!entry.isGateway">
<!-- 这个a标签中的内容就是js中调用的Controller,其他规则仿写就行 -->
<a ui-sref="dashboard.flow({app: entry.app})">
<i class="glyphicon glyphicon-filter"></i> 流控规则</a>
</li>
需要注意此处的angular项目需要使用node.js版本10.x(使用n对node.js进行版本管理),修改后使用gulp build进行打包。运行DashBoard后页面报错优先清理缓存。
Nacos内显示如下
Sentinel DashBoard + Gateway
Sentinel可以整合Gateway,Gateway服务中增加以下依赖,并像其他服务一样写Sentinel配置文件。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
在Gateway的启动类中增加以下代码
// 不增加此代码,或者启动时不在启动参数中写此内容,
// Sentinel会把Gateway服务当成普通服务,显示url地址,
// 加了会显示链路、API分组等内容
System.setProperty("csp.sentinel.app.type", "1");
Feign相关说明
Feign传递Header
public class FeignInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// jwt
template.header(AuthInfoConstant.USER_TOKEN, request.getHeader(AuthInfoConstant.USER_TOKEN));
// 网关
template.header(AuthInfoConstant.GATEWAY_AUTH, request.getHeader(AuthInfoConstant.GATEWAY_AUTH));
}
}
Feign的继承
Feign的接口可以被Controller继承,Controller中不用再写@RequestMapping和@RequestParam等注解,官网不推荐使用继承特性。
需要注意Feign默认使用Post方式请求,使用@SpringQueryMap替换@RequestParam注解可以实现GET接收数据。
GET下@SpringQueryMap可以接收param和form-data,POST下可以接收x-www-form-urlencoded,JSON格式接不到