参考资料

https://blog.csdn.net/luanlouis/article/details/83060310
https://www.iocoder.cn/Spring-Cloud-Netflix/Ribbon/
https://www.cnblogs.com/trust-freedom/p/11216280.html
https://blog.51cto.com/u_8958931/2817488
https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-ribbon.html

概念

容器

  • 创建客户端、负载均衡器和客户端配置实例的工厂。 它为每个客户端名称创建一个 Spring ApplicationContext,并从那里提取它需要的 bean。
  • org.springframework.cloud.netflix.ribbon.SpringClientFactory ```java public class SpringClientFactory extends NamedContextFactory {

    static final String NAMESPACE = “ribbon”;

    public SpringClientFactory() {

    1. super(RibbonClientConfiguration.class, NAMESPACE, "ribbon.client.name");

    }

    // 获取当前客户端关联的 Reset 客户端。 public > C getClient(String name, Class clientClass) {

      return getInstance(name, clientClass);
    

    }

    // 获取当前客户端关联的 负载均衡器 public ILoadBalancer getLoadBalancer(String name) {

      return getInstance(name, ILoadBalancer.class);
    

    }

    // 获取当前客户端关联的 客户端配置 public IClientConfig getClientConfig(String name) {

      return getInstance(name, IClientConfig.class);
    

    }

    // 获取当前客户端关联的 负载均衡器上下文 public RibbonLoadBalancerContext getLoadBalancerContext(String serviceId) {

      return getInstance(serviceId, RibbonLoadBalancerContext.class);
    

    }

    @Override protected AnnotationConfigApplicationContext getContext(String name) {

      return super.getContext(name);
    

    }

}

<a name="W2vmX"></a>
## 组件
![Ribbon-DefaultClientConfigImpl.png](https://cdn.nlark.com/yuque/0/2022/png/106112/1641455710573-504368d2-685f-4d8b-8fee-0449da0e9463.png#clientId=u26bde30d-d62e-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=251&id=uac7b5047&margin=%5Bobject%20Object%5D&name=Ribbon-DefaultClientConfigImpl.png&originHeight=251&originWidth=487&originalType=binary&ratio=1&rotation=0&showTitle=false&size=7585&status=done&style=none&taskId=ub64cb3cf-a2f6-49d9-ae6b-da3e0c7986f&title=&width=487)<br />初始化 Ribbon 客户端和负载均衡器的配置的方法,配置Ribbon的相关设置
```java
@Import({ HttpClientConfiguration.class, OkHttpRibbonConfiguration.class,
        RestClientRibbonConfiguration.class, HttpClientRibbonConfiguration.class })
public class RibbonClientConfiguration {

    /**
     * Ribbon client default connect timeout.
     */
    public static final int DEFAULT_CONNECT_TIMEOUT = 1000;

    /**
     * Ribbon client default read timeout.
     */
    public static final int DEFAULT_READ_TIMEOUT = 1000;

    /**
     * Ribbon client default Gzip Payload flag.
     */
    public static final boolean DEFAULT_GZIP_PAYLOAD = true;

    @RibbonClientName
    private String name = "client";

    // TODO: maybe re-instate autowired load balancers: identified by name they could be
    // associated with ribbon clients

    @Autowired
    private PropertiesFactory propertiesFactory;

    @Bean
    @ConditionalOnMissingBean
    public IClientConfig ribbonClientConfig() {
        DefaultClientConfigImpl config = new DefaultClientConfigImpl();
        config.loadProperties(this.name);
        config.set(CommonClientConfigKey.ConnectTimeout, DEFAULT_CONNECT_TIMEOUT);
        config.set(CommonClientConfigKey.ReadTimeout, DEFAULT_READ_TIMEOUT);
        config.set(CommonClientConfigKey.GZipPayload, DEFAULT_GZIP_PAYLOAD);
        return config;
    }

    @Bean
    @ConditionalOnMissingBean
    public IRule ribbonRule(IClientConfig config) {
        if (this.propertiesFactory.isSet(IRule.class, name)) {
            return this.propertiesFactory.get(IRule.class, config, name);
        }
        ZoneAvoidanceRule rule = new ZoneAvoidanceRule();
        rule.initWithNiwsConfig(config);
        return rule;
    }

    @Bean
    @ConditionalOnMissingBean
    public IPing ribbonPing(IClientConfig config) {
        if (this.propertiesFactory.isSet(IPing.class, name)) {
            return this.propertiesFactory.get(IPing.class, config, name);
        }
        return new DummyPing();
    }

    @Bean
    @ConditionalOnMissingBean
    @SuppressWarnings("unchecked")
    public ServerList<Server> ribbonServerList(IClientConfig config) {
        if (this.propertiesFactory.isSet(ServerList.class, name)) {
            return this.propertiesFactory.get(ServerList.class, config, name);
        }
        ConfigurationBasedServerList serverList = new ConfigurationBasedServerList();
        serverList.initWithNiwsConfig(config);
        return serverList;
    }

    @Bean
    @ConditionalOnMissingBean
    public ServerListUpdater ribbonServerListUpdater(IClientConfig config) {
        return new PollingServerListUpdater(config);
    }

    @Bean
    @ConditionalOnMissingBean
    public ILoadBalancer ribbonLoadBalancer(IClientConfig config,
            ServerList<Server> serverList, ServerListFilter<Server> serverListFilter,
            IRule rule, IPing ping, ServerListUpdater serverListUpdater) {
        if (this.propertiesFactory.isSet(ILoadBalancer.class, name)) {
            return this.propertiesFactory.get(ILoadBalancer.class, config, name);
        }
        return new ZoneAwareLoadBalancer<>(config, rule, ping, serverList,
                serverListFilter, serverListUpdater);
    }

    @Bean
    @ConditionalOnMissingBean
    @SuppressWarnings("unchecked")
    public ServerListFilter<Server> ribbonServerListFilter(IClientConfig config) {
        if (this.propertiesFactory.isSet(ServerListFilter.class, name)) {
            return this.propertiesFactory.get(ServerListFilter.class, config, name);
        }
        ZonePreferenceServerListFilter filter = new ZonePreferenceServerListFilter();
        filter.initWithNiwsConfig(config);
        return filter;
    }

    @Bean
    @ConditionalOnMissingBean
    public RibbonLoadBalancerContext ribbonLoadBalancerContext(ILoadBalancer loadBalancer,
            IClientConfig config, RetryHandler retryHandler) {
        return new RibbonLoadBalancerContext(loadBalancer, config, retryHandler);
    }

    @Bean
    @ConditionalOnMissingBean
    public RetryHandler retryHandler(IClientConfig config) {
        return new DefaultLoadBalancerRetryHandler(config);
    }

    @Bean
    @ConditionalOnMissingBean
    public ServerIntrospector serverIntrospector() {
        return new DefaultServerIntrospector();
    }

    @PostConstruct
    public void preprocess() {
        setRibbonProperty(name, DeploymentContextBasedVipAddresses.key(), name);
    }

    static class OverrideRestClient extends RestClient {

        private IClientConfig config;

        private ServerIntrospector serverIntrospector;

        protected OverrideRestClient(IClientConfig config,
                ServerIntrospector serverIntrospector) {
            super();
            this.config = config;
            this.serverIntrospector = serverIntrospector;
            initWithNiwsConfig(this.config);
        }

        @Override
        public URI reconstructURIWithServer(Server server, URI original) {
            URI uri = updateToSecureConnectionIfNeeded(original, this.config,
                    this.serverIntrospector, server);
            return super.reconstructURIWithServer(server, uri);
        }

        @Override
        protected Client apacheHttpClientSpecificInitialization() {
            ApacheHttpClient4 apache = (ApacheHttpClient4) super.apacheHttpClientSpecificInitialization();
            apache.getClientHandler().getHttpClient().getParams().setParameter(
                    ClientPNames.COOKIE_POLICY, CookiePolicy.IGNORE_COOKIES);
            return apache;
        }

    }

}

Ribbon-IPing.png
主动 ping 服务实例的方法,判断其是否存活
Robin-IRule.png
负载均衡规则接口,定义了从服务中选择一个实例的方法
Ribbon-ServerList.png
获得服务实例列表的方法
静态和动态的。如果是动态的,会有后台定时任务定时重新获取最新的服务实例列表

  • com.netflix.loadbalancer.ConfigurationBasedServerList 从配置文件获取
  • org.springframework.cloud.netflix.ribbon.StaticServerList 静态的实例列表
  • com.alibaba.cloud.nacos.ribbon.NacosServerList Nacos实现客户端动态刷新的服务列表

Ribbon-ServerList.png

Ribbon-ServerListFilter.png

过滤不符合条件的服务实例的方法

Ribbon-ServerListUpdater.png

启动一个定时任务,定时重新获取最新的服务实例列表

Ribbon-ILoadBalancer.png