Spring cloud - 负载均衡

Ribbon
是一个客户端负载均衡器
LB 负载均衡,平摊用户请求到多个服务上,以达到系统的高可用。

  • 集中式: F5、Nginx,独立于消费方和提供方。
  • 进程式:Ribbon,将负载均衡逻辑集成到消费方,从注册中心获取可用的服务,然后自己选择一个进行访问。

Spring Cloud Netflix默认情况下为Ribbon(BeanType beanName:ClassName)提供以下bean:

  • IClientConfig ribbonClientConfig:DefaultClientConfigImpl

  • IRule ribbonRule:ZoneAvoidanceRule

  • IPing ribbonPing:NoOpPing

  • ServerList<Server> ribbonServerList:ConfigurationBasedServerList

  • ServerListFilter<Server> ribbonServerListFilter:ZonePreferenceServerListFilter

  • ILoadBalancer ribbonLoadBalancer:ZoneAwareLoadBalancer

  • ServerListUpdater ribbonServerListUpdater:PollingServerListUpdater

可以自定义修改相关配置:

@Configuration
public class FooConfiguration {
    @Bean
    public IPing ribbonPing(IClientConfig config) {
        return new PingUrl();
    }

    @Bean
    public IRule ribbonRule() {
        return new RetryRule();
    }
}

这里指定了 ping 规则和负载均衡规则。

  • ZoneAvoidanceRule 默认规则,复合判断 server 所在区域的性能和可用性选择。
  • RandomRule 随机
  • RoundRobinRule 轮询
  • WeightedResponseTimeRule 计算平均响应时间去设置权重。刚开始启动收集的数据少,就使用轮询规则。

接下来自定义一个负载均衡规则:
官网例子:

@Configuration
@RibbonClient(name = "foo", configuration = FooConfiguration.class)
public class TestConfiguration {
}

注意:

FooConfiguration必须是@Configuration,但请注意,它不在主应用程序上下文的@ComponentScan中,否则将由所有@RibbonClients共享。如果您使用@ComponentScan(或@SpringBootApplication),则需要采取措施避免包含(例如将其放在一个单独的,不重叠的包中,或者指定要在@ComponentScan)。

public class TimesRule extends AbstractLoadBalancerRule {
    private int times = 5;
    private int total = 0; // 总共被调用的次数
    private int currentIndex = 0; // 当前提供服务的机器号
    
    public TimesRule() {
        super();
    }

    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        }
        Server server = null;

        while (server == null) {
            if (Thread.interrupted()) {
                return null;
            }
            List<Server> upList = lb.getReachableServers();
            List<Server> allList = lb.getAllServers();

            int serverCount = allList.size();
            if (serverCount == 0) {
                /*
                 * No servers. End regardless of pass, because subsequent passes only get more
                 * restrictive.
                 */
                return null;
            }

            if (total < times) {
                server = upList.get(currentIndex);
                total++;
            } else {
                total = 0;
                currentIndex++;
                if (currentIndex >= upList.size()) {
                    currentIndex = 0;
                }
            }

            if (server == null) {
                /*
                 * The only time this should happen is if the server list were somehow trimmed.
                 * This is a transient condition. Retry after yielding.
                 */
                Thread.yield();
                continue;
            }

            if (server.isAlive()) {
                return (server);
            }

            // Shouldn't actually happen.. but must be transient or a bug.
            server = null;
            Thread.yield();
        }

        return server;

    }

    @Override
    public Server choose(Object key) {
        return choose(getLoadBalancer(), key);
    }

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {

    }
}

Feign

Feign是一个声明式的Web服务客户端。使用它就又可以回归面向接口开发,脱离面向 restTemplate 开发。
定义一个接口,加上注解,@FeignClient 绑定服务,@RequestMapping 声明调用的 api 接口,在配置中开启 @EnableFeignClients。

@FeignClient("stores")
public interface StoreClient {
    @RequestMapping(method = RequestMethod.GET, value = "/stores")
    List<Store> getStores();

    @RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json")
    Store update(@PathVariable("storeId") Long storeId, Store store);
}

Feign 集成了 Ribbon,与 Ribbon 不同的是,通过 Feign只需要定义服务绑定接口且以声明的方式,控制层调用接口,优雅而简单的实现了服务调用。

转载于:https://www.jianshu.com/p/f4f2ec6ad81d

猜你喜欢

转载自blog.csdn.net/weixin_33847182/article/details/91273179