结合选择器的后端页面,介绍下选择器是如何在请求的过程中起到作用的

soul(1)插件文档_权重

匹配方式条件

匹配方式的条件中有5个选项,分别是post、query、host、ip、header,其对应在请求时候的源码如下:

String buildRealData(final ConditionZkDTO condition, final ServerWebExchange exchange) {
String realData = "";
if (condition.getParamType().equals(ParamTypeEnum.QUERY.getName())) {
final MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
realData = queryParams.getFirst(condition.getParamName());
} else if (Objects.equals(ParamTypeEnum.HOST.getName(), condition.getParamType())) {
realData = Objects.requireNonNull(exchange.getRequest().getRemoteAddress()).getHostString();
} else if (Objects.equals(ParamTypeEnum.IP.getName(), condition.getParamType())) {
realData = Objects.requireNonNull(exchange.getRequest().getRemoteAddress()).getAddress().getHostAddress();
} else if (Objects.equals(ParamTypeEnum.HEADER.getName(), condition.getParamType())) {
final HttpHeaders headers = exchange.getRequest().getHeaders();
final List<String> list = headers.get(condition.getParamName());
if (CollectionUtils.isEmpty(list)) {
return realData;
}
realData = Objects.requireNonNull(headers.get(condition.getParamName())).stream().findFirst().orElse("");
} else if (condition.getParamType().equals(ParamTypeEnum.POST.getName())) {
final RequestDTO requestDTO = exchange.getAttribute(Constants.REQUESTDTO);
realData = (String) ReflectUtils.getFieldValue(requestDTO, condition.getParamName());
}
return realData;
}

divide

选择器

类型

  • 全流量:不匹配下面的条件,所有的请求都会走的插件
  • 自定义流量:匹配到下面的条件才会走的插件

匹配方式条件

匹配方式

具体含义

header

根据请求头的值匹配

post

根据requestDTO中的key对应的value匹配​​1​​

query

请求参数的值进行匹配(body中的请求参数无法匹配)

host

使用的是getRemoteAddress()).getHostString()方法,如果前面有nginx,获取到的是nginx的地址(=前面的输入框不需要填写,没用到)

ip

使用的是getRemoteAddress()).getAddress().getHostAddress()方法,获取的是远端请求的真实地址(=前面的输入框不需要填写,没用到)

是否继续后续选择器

这个参数在divideplugin中是没有起作用的
每个插件的选择器只能执行一个,根据顺序匹配的,执行到第一个后就无法再执行第二个选择器,代码如下

final SelectorZkDTO selectorZkDTO = selectors.stream()
.filter(selector -> selector.getEnabled() && filterSelector(selector, exchange))
.findFirst().orElse(null);

打印日志

是指在请求中选择了某个选择器后是否打印哪个插件选择了某个选择器的日志
代码如下:

if (selectorZkDTO.getLoged()) {
LogUtils.info(LOGGER, named()
+ " selector success selector name :{}", selectorZkDTO::getName);
}

http配置

http配置,放在了SelectorZkDTO的handle字段中,格式如下:

[{"upstreamHost":"localhost","protocol":"","upstreamUrl":"127.0.0.1:8088","weight":"100"},{"upstreamHost":"localhost","protocol":"","upstreamUrl":"127.0.0.1:8087","weight":"99"}]

http配置是可以配置多个的,在其中有三种负载均衡器,分别是RandomLoadBalance、HashLoadBalance、RoundRobinLoadBalance。。
http配置是可以配置多个的,

  • 如果在规则中配置的负载策略是random

    选择的规则是这样的,如果权重一样,随机选择一个http的配置,如果权重不一样,则根据权重的比例随机去取,比如第一个权重是100,第二个权重是50,则有三分之二的几率会路由到第一台机器,三分之一的记录路由到第二台机器
  • 如果配置的是hash,则是将配置的ip:port,根据一致性hash算法,看看ip落到哪个节点上,ip是获取的远端请求的真实ip。
  • 如果配置的是roundrobin,如果权重一样,就是轮询,如果权重不一样,则是根据权重轮询,举例如下:

如果服务器1配置的权重是2,服务器2配置的权重是3,第一次调用服务器1,第二次调用服务器2,第三次还是调用服务器2,第四次调用服务器1,第五次调用服务器2,第六次又调用了服务器2.

如果轮询配置权重的话,可以理解为,调用服务器的次数为weight-1次。

hostName

http://

ip:port

weight

可以当做http配置的名称

服务中未用到此字段

协议,如果不配置的话,默认是http

后端服务的ip,port

权重

执行顺序

每个插件只会选择一个选择器,按照执行顺序选择,顺序小的优先选择。

规则

Hystrix处理

如果是下游代码的问题,断路器是不负责的,这个成功或者失败表示的是netty调用服务的成功或失败状态

名称

作用

跳闸最小请求数

10s内要达到此数量才能让Hystrix

错误半分比阈值

错误的百分比达到此值则打开熔断器

最大并发数

这个值并非TPS、QPS、RPS等都是相对值,指的是1秒时间窗口内的事务/查询/请求

semaphore.maxConcurrentRequests是一个绝对值,无时间窗口,相当于亚毫秒级的,指任意时间点允许的并发数。当请求达到或超过该设置值后,其其余就会被拒绝。默认值是100。

跳闸休眠时间

熔断器打开后,在此时间后,有一个请求通过,如果此请求失败继续打开熔断器,如果成功,关闭熔断器

分组key(groupKey)

默认采用的是module的值,在同一个分组中的方法,用同一个线程池处理熔断逻辑

命令key(commandKey)

默认是采用method的值,上面的请求数的统计,都是根据commandKey来的

http负载

  • 负载策略:前面说过
  • 重试次数:重试次数的配置只有在dubbo插件起作用了,http和springcloud是不起作用的
  • 打印日志:如果选择打印,则会在选择到规则后打印相应的module,method,plugin,rule名称的日志。
  • 是否开启,如果开启就可以匹配到对应的rule,如果方法一个规则都没有匹配到,则会报错

执行顺序

顺序小的先匹配到,只会匹配一个规则,选择器也是。

rate_limiter

选择器(同divide插件)

规则

处理

限流是在速率内(秒),允许的容量(请求个数),举例:
如果速率是3,容量是100,则在3秒内只能有100个请求,超出的报错

write

选择器(同divide插件)

规则

处理

写上重写的路径,不要带ip端口号,如:test/findByUserId


  1. 比如requestDTO中有个参数名为appKey,则要配置appkey为某个值才能执行到这个选择器 ↩︎