服务发现的领域模型(命名空间、组、集群、实例)

领域模型是用来对注册到nacos上面的微服务进行隔离以及逻辑划分。
服务发现,Ribbon - 图1
配置如下:

  1. cloud:
  2. nacos:
  3. discovery:
  4. server-addr: localhost:8848
  5. #命名空间,值是nacos服务创建的唯一key
  6. namespace: 541a64ac-65af-41e9-8a66-115dda2285a1
  7. #组
  8. group: 1
  9. #集群
  10. cluster-name: SH

NacosDiscoveryProperties

该对象是一个nacos的信息对象,在ioc容器里面,可以直接注入使用,通过该对象可以获取到当前服务的所有信息,包括领域模型里面的数据。

@Autowired
private NacosDiscoveryProperties nacosDiscoveryProperties;

NacosServiceManager

在高版本的nacos里面(比如1.8)一部分关于服务注册查询等管理对象的获取使用从NacosDiscoveryProperties对象里面抽取了出来形成了NacosServiceManager对象,我们对服务的一些操作或则服务注册核心对象的获取都可以通过该对象来得到。

@Autowired
private NacosServiceManager nacosServiceManager;

NamingService

这是nacos的服务注册与发现对象,可以通过它来进行服务的注册以及服务查询,查询提供了一些负载均衡算法,比如通过权重进行服务发现。该对象针对版本不一样可以通过NacosDiscoveryProperties或则NacosServiceManager对象来进行获取。

RestTemplate

RestTemplate是一个http客户端,通过它能够在java端发起http请求。可以用它来进行服务间的调用。

  1. 获取RestTemplate对象,可以new也可以放入容器

    @Configuration
    public class BaseConfig {
     @Bean
     public RestTemplate getRestTemplate() {
         RestTemplate rs = new RestTemplate();
         return rs;
     }
    }
    
  2. 访问服务:

    @Autowired
    RestTemplate rt;
    String value = rt.getForObject("http://ip:port/user/findUser", String.class);
    

    Ribbon

    Ribbon是什么

    Ribbon是Netflix发布的云中间层服务开源项目,主要功能是提供客户端(消费者方)负载均衡算法。Ribbon客户端组件提供一系列完善的配置项,如,连接超时,重试等。简单的说,Ribbon是一个客户端负载均衡器,我们可以在配置文件中列出loadBalancer后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器,我们也很容易使用Ribbon实现自定义的负载均衡算法。
    服务发现,Ribbon - 图2

    RestTemplate在访问服务的时候加入负载均衡

    @Bean
    @LoadBalanced //加上该注解就会集成负载均衡
    public RestTemplate rt() {
     return new RestTemplate();
    }
    
    //负载均衡访问:
    String value = rt.getForObject("http://注册到nacos的服务名/user/findUser", String.class);
    

    Ribbon内置的负载均衡策略

    | 规则名称 | 特点 | | :—- | :—- | | AvailabilityFilteringRule | 过滤掉一直连接失败的被标记为circuit tripped的后端Server,并过滤掉那些高并发的后端Server或则使用一个AvailabilityPredicate来包含过滤Server的逻辑,其实就是检查status里面记录的各个Server的运行状态 | | BestAvailableRule | 选择一个最小的并发请求的Server,逐个考察Server,如果Server被tripped了,则跳过 | | RandomRule | 随机选择一个Server | | RetryRule | 对选定的负载均衡策略机上重试机制,在一个配置时间段内当选择Server不成功,则一直尝试使用subRule的方式选择一个可用的Server | | RoundRobinRule | 轮询选择,轮询index,选择index对应位置的Server | | WeightedResponseTimeRule | 根据响应时间加权,响应时间越长,权重越小,被选中的可能性越低 | | ZoneAvoidanceRule | 符合判断Server所Zone的性能和Server的可用性选择Server,在没有Zone的环境下,类似于轮询(RoundRobinRule) |

Ribbon的配置接口(了解)

接口 配置 默认值
IClientConfig 读取配置 DefaultClientConfigImpl
IRule 负载均衡规则,选择实例 ZoneAvoidanceRule
IPing 筛选掉ping不通的实例 DummyPing
ServerList 交给Ribbon的实例列表 Ribbon:ConfigurationBasedServerList
Spring Cloud Alibaba:NacosServerList
ServerListFilter 过滤掉不符合条件的实例 ZonePreferenceServerListFilter
ILoadBalancer Ribbon的入口 ZoneAwareLoadBalancer
ServerListUpdater 更新交给Ribbon的List的策略 PollingServerListUpdater

Ribbon基础配置

Ribbon有两种配置方式,一是java代码配置,一种是属性配置。
代码配置如下:

@Configuration
public class RibbonConfig {
  //添加负载均衡策略对象
  @Bean
  public IRule createIRule() {
    return new WeightRule();
  }
}

把上面的配置类用到主配置上面:

@Configuration
//全局配置
@RibbonClients(defaultConfiguration = RibbonConfig.class)
//局部配置
//@RibbonClient(value = "服务名",configuration = RibbonConfig.class)
public class BaseConfig {
}

属性配置如下:

<clientName>.ribbon: 
  NFLoadBalancerClassName: ILoadBalancer实现类
  NFLoadBalancerRuleClassName: IRule实现类
  NFLoadBalancerPingClassName: IPing实现类
  NIWSServerListClassName: ServerList实现类
  NIWSServerListFilterClassName: ServerListFilter实现类

自定义Ribbon的负载均衡规则

自定义类实现IRule接口或则继承AbstractLoadBalancerRule

public class WeightRule extends AbstractLoadBalancerRule {
        //自身信息对象
        @Autowired
        private NacosDiscoveryProperties nacosDiscoveryProperties;
        //nacos服务管理对象
        @Autowired
        private NacosServiceManager nsm;
        @Override
        public Server choose(Object key) {
            //获取需要访问的服务名
            BaseLoadBalancer ilb = (BaseLoadBalancer)this.getLoadBalancer();
            String name = ilb.getName();
            //获取自身的clusterName
            String clusterName = nacosDiscoveryProperties.getClusterName();
            //获取nacos服务发现对象
            NamingService ns = nsm.getNamingService(nacosDiscoveryProperties.getNacosProperties());
            try {
                //获取所有的需要访问的服务节点
                List<Instance> insts =  ns.getAllInstances(name);
                //过滤出相同集群的节点
                List<Instance> clusterInstances = insts.stream().filter(x -> {
                    if(StringUtils.isNotEmpty(clusterName) && StringUtils.isNotEmpty(x.getClusterName())) {
                        if(clusterName.equals(x.getClusterName())) return true;
                    }
                    return false;
                }).collect(Collectors.toList());
                insts = clusterInstances != null && clusterInstances.size() > 0 ? clusterInstances:insts;
                //通过权重算法获取该服务的一个实例
                Instance instance = MyBalancer.getHostByRandomWeight(insts);
                return new NacosServer(instance);
            } catch (NacosException e) {
                e.printStackTrace();
                return null;
            }
        }
        @Override
        public void initWithNiwsConfig(IClientConfig clientConfig) {
        }
        //拉取权重调用算法
        static class MyBalancer extends Balancer {
          public static Instance getHostByRandomWeight(List<Instance> hosts) {
                 return Balancer.getHostByRandomWeight(hosts);
          }
        }
}