定制IRule
使前后端开发可定制匹配, 学习并配置了网关的负载策略,zuul 底层使用的是 ribbon 的负载组件, ribbon 可以从 eureka 获取服务列表, 所以想要自定义负载, 得从 ribbon 入手, 查看并搜索 loadBalance 相关的类, 可以看到 AbstractLoadBalancerRule 这个类, 查看类树, 可以看到顶级接口为 IRule
1 2 3 4 5 6 7 8 9 10 11 12
|
public Server choose(Object key);
public void setLoadBalancer(ILoadBalancer lb);
public ILoadBalancer getLoadBalancer();
|
debug 分析, 得知 ribbon 默认的负载策略为: ZoneAvoidanceRule, 这个类继承自 AbstractLoadBalancerRule, AbstractLoadBalancerRule中存在 ILoadBalancer 属性, 可以获取负载器, 负载器中又可以获取服务列表等信息
所以我们只需要继承ZoneAvoidanceRule, 重写 choose 方法即可
ribbon 默认的负载器为: DynamicServerListLoadBalancer, 其中包括节点健康状态服务支持, 节点状态的更新(ServerListUpdater), 负载策略, 可用区域的分析, 可以从此类详细了解 ribbon 的运行机制
解决
自定义路由策略, 继承ZoneAvoidanceRule, 当有特定标记的请求过来时, 走定义的服务, 如果没有, 则还是走默认的路由策略,自定义路由策略, 继承ZoneAvoidanceRule, 当有特定标记的请求过来时, 走定义的服务, 如果没有, 则还是走默认的路由策略。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| import com.gomyck.util.ResponseWriter; import com.gomyck.util.StringJudge; import com.gomyck.util.TokenTake; import com.netflix.loadbalancer.ILoadBalancer; import com.netflix.loadbalancer.Server; import com.netflix.loadbalancer.ZoneAvoidanceRule; import org.slf4j.Logger; import org.slf4j.LoggerFactory;
import java.util.List;
public class CkLoadBalanceRule extends ZoneAvoidanceRule {
Logger log = LoggerFactory.getLogger(CkLoadBalanceRule.class);
@Override public Server choose(Object key) { ILoadBalancer loadBalancer = getLoadBalancer(); List<Server> allServers = loadBalancer.getReachableServers(); String ckDev = TokenTake.getToken(ResponseWriter.getRequest(), "CkDev"); try { if (StringJudge.notNull(ckDev)) { log.info("CkLoadBalanceRule will route server name is: " + ckDev); final String _ckDev = ckDev.split("-")[0]; Server server = allServers.stream().filter(e -> { String instanceId = e.getMetaInfo().getInstanceId().split("-")[0]; return _ckDev.equals(instanceId); }).findFirst().get(); if (server.isAlive() && (server.isReadyToServe())) { return (server); } else { log.error("server :" + server.getMetaInfo().getAppName() + " is not available!"); } } } catch (Exception e) { } return super.choose(key); } }
|
- 在 zuul 服务的 yml 文件中配置需要使用该负载策略的服务 ID, 格式为:
1 2 3
| server-name: ribbon: NFLoadBalancerRuleClassName: com.gomyck.gateway.config.CkLoadBalanceRule
|
疑惑解答
在最开始, 我把自定义负载策略注册成 bean, 发现所有的路由都失效了, debug 发现, 策略 bean 拿到的服务, 缺失, 注释掉 bean, 查看之前的运行逻辑, 发现每个服务都对应一个路由策略实例, 也就是每个服务对应各自的 IRule 实例