【高性能网关soul学习】13. 插件之springcloud
本文目标:
- 介绍springcloud插件原理
SpringCloud 插件
springCloud 插件作为插件链的一环,处理springCloud 的请求
- 首先我们照惯例启动 soul-admin、soul-bootstrap(注意引入springcloud依赖 ),
- 然后启动 springCloud 的测试服务,使用了nacos 作为注册中心,配置如下
server:
port: 8884
address: 0.0.0.0
spring:
application:
name: springCloud-test
cloud:
nacos:
discovery:
server-addr: localhost:8848
springCloud-test:
ribbon.NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
# 指定了使用的负载均衡规则
soul:
springcloud:
admin-url: http://localhost:9095
context-path: /springcloud
下面我们直接分析 SpringCLoudPlugin
做了哪些事情,主要就是使用客户端负载均衡 选择了一个目标请求服务器,然后将参数设置进 exchange 中
@Override
protected Mono<Void> doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, final RuleData rule) {
// ... 获取对象
// 使用客户端负载均衡策略挑选一个合格的请求服务器
final ServiceInstance serviceInstance = loadBalancer.choose(selectorHandle.getServiceId());
if (Objects.isNull(serviceInstance)) {
// ... 异常处理
}
// 重新构建请求 uri
final URI uri = loadBalancer.reconstructURI(serviceInstance, URI.create(soulContext.getRealUrl()));
String realURL = buildRealURL(uri.toASCIIString(), soulContext.getHttpMethod(), exchange.getRequest().getURI().getQuery());
exchange.getAttributes().put(Constants.HTTP_URL, realURL);
//set time out.
exchange.getAttributes().put(Constants.HTTP_TIME_OUT, ruleHandle.getTimeout());
return chain.execute(exchange);
}
- loadBalancer 实际上为 RibbonLoadBalancerClient的实例对象,属于 LoadBalancerClient 客户端负载均衡的一种实现类
Ribbon是一个基于HTTP和TCP的客户端负载均衡器,当我们将Ribbon和注册中心一起使用时,Ribbon会从注册中心去获取服务端列表,然后进行轮询访问以到达负载均衡的作用,客户端负载均衡中也需要心跳机制去维护服务端清单的有效性,当然这个过程需要配合服务注册中心一起完成。
// RibbonLoadBalancerClient.java
public ServiceInstance choose(String serviceId, Object hint) {
Server server = getServer(getLoadBalancer(serviceId), hint);
if (server == null) {
return null;
}
return new RibbonServer(serviceId, server, isSecure(server, serviceId),
serverIntrospector(serviceId).getMetadata(server));
}
protected ILoadBalancer getLoadBalancer(String serviceId) {
return this.clientFactory.getLoadBalancer(serviceId);
}
protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
if (loadBalancer == null) {
return null;
}
// Use 'default' on a null hint, or just pass it on?
// 通过调用次数来轮询选择
return loadBalancer.chooseServer(hint != null ? hint : "default");
}
Server chooseServer(Object key) {
// 交由具体实例化的规则来挑选服务器
return rule.choose(key);
}
public Server choose(Object key) {
ILoadBalancer lb = getLoadBalancer();
// lb从注册中心获取到所有的服务器,然后挑选出一个合格的服务器进行返回
Optional<Server> server = getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
if (server.isPresent()) {
return server.get();
} else {
return null;
}
}
// 对服务器进行过滤之后,然后
public Optional<Server> chooseRoundRobinAfterFiltering(List<Server> servers, Object loadBalancerKey) {
List<Server> eligible = getEligibleServers(servers, loadBalancerKey);
if (eligible.size() == 0) {
return Optional.absent();
}
// 进行轮询计数和返回一个 Server
return Optional.of(eligible.get(incrementAndGetModulo(eligible.size())));
}
- IRule有非常多的实现类用来实现客户端的负载均衡策略(这里不再详述)
总结
- SpringCloudPlugin 主要集成了 Spring cloud 自带的
客户端负载均衡
来挑选一个请求的目标服务器,因此springCloudPlugin.doExecute()
方法自身实现的逻辑比较简单。