前面说到基于nacos的注册发现有可以扩展实现我们自己的负载均衡算法(Nacos数据模型),来实现同集群调用,是基于spring.cloud.nacos.discovery.cluster-name参数。另外基于spring.cloud.nacos.discovery.metadata参数也可以实现金丝雀发布调用。这里就使用ribbon来实现这两种负载均衡算法。
直接使用feign调用,因为feign里面就是用的ribbon,引入feign依赖也就引入了ribbon
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
1.继承com.netflix.loadbalancer.AbstractLoadBalancerRule 实现自己的负载均衡算法,从NacosDiscoveryProperties中获取实例信息,然后筛选出来cluster-name和metadata中version相同的实例,进行调用。
package com.nijunyang.order.ribbon.rule; import com.alibaba.cloud.nacos.NacosDiscoveryProperties; import com.alibaba.cloud.nacos.ribbon.NacosServer; import com.alibaba.nacos.api.naming.NamingService; import com.alibaba.nacos.api.naming.pojo.Instance; import com.netflix.client.config.IClientConfig; import com.netflix.loadbalancer.AbstractLoadBalancerRule; import com.netflix.loadbalancer.BaseLoadBalancer; import com.netflix.loadbalancer.Server; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import java.security.SecureRandom; import java.util.ArrayList; import java.util.List; /** * Description: 集群和版本规则 * Created by nijunyang on 2020/12/14 21:36 */ @Slf4j public class ClusterWithVersionRule extends AbstractLoadBalancerRule { @Autowired private NacosDiscoveryProperties nacosDiscoveryProperties; /** * 重写choose方法 * @param key * @return */ @SneakyThrows @Override public Server choose(Object key) { //获取服务配置的集群名 String clusterName = nacosDiscoveryProperties.getClusterName(); //当前的版本号 配置文件配置的metadata信息 String currentVersion = nacosDiscoveryProperties.getMetadata().get("version"); //获取负载均衡器 BaseLoadBalancer baseLoadBalancer = (BaseLoadBalancer) getLoadBalancer(); //调用服务的名字 String invokedServerName = baseLoadBalancer.getName(); //获取namingServer(包含nacos注册发现相关api) NamingService namingService = nacosDiscoveryProperties.namingServiceInstance(); //获取被调用的服务的所有实例 List<Instance> invokedAllInstanceList = namingService.getAllInstances(invokedServerName); //同集群同版本 List<Instance> theSameClusterAndVersionList = new ArrayList<>(); //跨集群同版本 List<Instance> theSameVersionList = new ArrayList<>(); for (Instance instance : invokedAllInstanceList) { if (clusterName.equalsIgnoreCase(instance.getClusterName()) && currentVersion.equalsIgnoreCase(instance.getMetadata().get("version"))) { theSameClusterAndVersionList.add(instance); } else if (currentVersion.equalsIgnoreCase(instance.getMetadata().get("version"))) { theSameVersionList.add(instance); } } Instance invokedInstance; if (theSameClusterAndVersionList.isEmpty()) { //跨集群同版本调用, 随机选一个 if (theSameVersionList.isEmpty()) { throw new RuntimeException("无对应版本服务"); } SecureRandom random = new SecureRandom(); int i = random.nextInt(theSameVersionList.size()); invokedInstance = theSameVersionList.get(i); } else { //同集群同版本调用 随机选一个 SecureRandom random = new SecureRandom(); int i = random.nextInt(theSameClusterAndVersionList.size()); invokedInstance = theSameClusterAndVersionList.get(i); } return new NacosServer(invokedInstance); } @Override public void initWithNiwsConfig(IClientConfig iClientConfig) { } }
2.配置自定义的负载均衡算法
spring:
application:
name: order
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 #不用写协议
# namespace: 688bf906-8b48-4ee2-a433-828f042ec860 #test id
# group: pay
cluster-name: CD
metadata:
version: v2
ribbon:
NFLoadBalancerRuleClassName: com.nijunyang.order.ribbon.rule.ClusterWithVersionRule #指定全局的负载均衡算法
eager-load:
enabled: true #饥饿加载(ribbon客户端不是在服务启动的时候加载的,所以可能第一次调用会很慢,甚至超时)
clients: stock #指定哪些服务使用饥饿加载
#按服务指定负载均衡算法
stock:
ribbon:
NFLoadBalancerRuleClassName: com.nijunyang.order.ribbon.rule.ClusterWithVersionRule
eager-load:
enabled: true
当需要指定某一服务使用某一负载均衡算法的时候,不要让spring容器扫描到该规则。在配置文件中如上配置即可。
完整代码:https://github.com/bluedarkni/study/tree/master/cloud-alibaba