问题
微服务和航显设备通过socket连接,微服务端管理socket的连接,用户从web发送指令到航显设备执行。
如果用户发送的指令到一台没有soket连接的微服务,那么控制指令将无法到达航显设备。
解决思路
用户发送的请求通过 spring cloud gateway负载,自定义负载均衡,发送请求的时候带航显设备连接的微服务ip,自定义负载根据ip去选择转发的服务器,这样请求就不会到达没有连接的微服务
自定义负载均衡全局过滤器 LoadBalancerClientFilter
根据自动配置规则,如果用户定义了LoadBalancerClientFilter ,就使用用户定义的
package com.cares.gateway.filter;
import com.cares.gateway.rules.FidsLoadBalanceRule;
import com.google.common.collect.Maps;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.gateway.config.LoadBalancerProperties;
import org.springframework.cloud.gateway.filter.LoadBalancerClientFilter;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import javax.annotation.Resource;
import java.net.URI;
import java.util.Map;
import static com.cares.gateway.consts.GatewayConstant.FIDS_CLIENT_KEY;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR;
/**
* @author wangcj
* @desc
* @date 2020/12/24 12:05
**/
@Component
public class CustomLoadBalancerClientFilter extends LoadBalancerClientFilter {
@Resource
FidsLoadBalanceRule fidsLoadBalanceRule;
public CustomLoadBalancerClientFilter(LoadBalancerClient loadBalancer, LoadBalancerProperties properties) {
super(loadBalancer, properties);
}
/**
* fids 模块向航显屏发送指令
* 1、航显屏必须在线
* 2、请求URL要带$FIDS_CLIENT=host 参数
* host是client当前连接到的主机ip,连接时记录到数据库
*
* @param exchange
* @return
*/
@Override
protected ServiceInstance choose(ServerWebExchange exchange) {
Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
String serviceId = ((URI) exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR)).getHost();
Object hint = null;
//这里使用userId做为选择服务实例的key
if (route.getId().equals("acdm-fids")) {
String host = exchange.getRequest().getQueryParams().getFirst(FIDS_CLIENT_KEY);
Map<String, Object> map = Maps.newHashMap();
map.put(FIDS_CLIENT_KEY, host);
hint=map;
}
return fidsLoadBalanceRule.choose(serviceId, hint);
}
}
自定义规则
package com.cares.gateway.rules;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient;
import org.springframework.cloud.netflix.ribbon.RibbonUtils;
import org.springframework.cloud.netflix.ribbon.ServerIntrospector;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import static com.cares.gateway.consts.GatewayConstant.FIDS_CLIENT_KEY;
/**
* @author wangcj
* @desc
* @date 2020/12/24 11:30
**/
@Component
public class FidsLoadBalanceRule extends AbstractLoadBalancerRule {
@Resource
SpringClientFactory springClientFactory;
private ILoadBalancer lb;
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
}
/**
* fids 模块向航显屏发送指令
* 1、航显屏必须在线
* 2、请求URL要带$FIDS_CLIENT=host 参数
* host是client当前连接到的主机ip,连接时记录到数据库
*
* @param o
* @return
*/
@Override
public Server choose(Object o) {
List<Server> servers = lb.getReachableServers();
if (CollectionUtils.isEmpty(servers)) {
return null;
}
if (null!=o && o instanceof Map) {
Map<String,Object> map = (Map<String, Object>) o;
String host = (String) map.get(FIDS_CLIENT_KEY);
Optional<Server> optional = servers.stream().filter(s -> s.getHost().equals(host)).findAny();
if (optional.isPresent()) {
return optional.get();
}
}
Random random = new Random(System.currentTimeMillis());
return servers.get(random.nextInt(servers.size()));
}
public ServiceInstance choose(String serviceId, Object hint) {
this.lb = springClientFactory.getLoadBalancer(serviceId);
Server server = choose(hint);
ServerIntrospector serverIntrospector = springClientFactory.getInstance(serviceId, ServerIntrospector.class);
Map map = serverIntrospector.getMetadata(server);
return new RibbonLoadBalancerClient.RibbonServer(serviceId, server, isSecure(server, serviceId), map);
}
private boolean isSecure(Server server, String serviceId) {
ServerIntrospector serverIntrospector = springClientFactory.getInstance(serviceId, ServerIntrospector.class);
IClientConfig config = springClientFactory.getClientConfig(serviceId);
return RibbonUtils.isSecure(config, serverIntrospector, server);
}
}
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!