Spring cloud - 負(fù)載均衡/服務(wù)調(diào)用

Ribbon
是一個(gè)客戶端負(fù)載均衡器。
LB 負(fù)載均衡,平攤用戶請(qǐng)求到多個(gè)服務(wù)上,以達(dá)到系統(tǒng)的高可用。

  • 集中式: F5、Nginx,獨(dú)立于消費(fèi)方和提供方。
  • 進(jìn)程式:Ribbon,將負(fù)載均衡邏輯集成到消費(fèi)方,從注冊(cè)中心獲取可用的服務(wù),然后自己選擇一個(gè)進(jìn)行訪問(wèn)。

Spring Cloud Netflix默認(rèn)情況下為 (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

可以自定義修改相關(guān)配置:

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

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

這里指定了 ping 規(guī)則和負(fù)載均衡規(guī)則。

  • ZoneAvoidanceRule 默認(rèn)規(guī)則,復(fù)合判斷 server 所在區(qū)域的性能和可用性選擇。
  • RandomRule 隨機(jī)
  • RoundRobinRule 輪詢
  • WeightedResponseTimeRule 計(jì)算平均響應(yīng)時(shí)間去設(shè)置權(quán)重。剛開(kāi)始啟動(dòng)收集的數(shù)據(jù)少,就使用輪詢規(guī)則。

接下來(lái)自定義一個(gè)負(fù)載均衡規(guī)則:
官網(wǎng)例子:

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

注意:

FooConfiguration必須是@Configuration,但請(qǐng)注意,它不在主應(yīng)用程序上下文的@ComponentScan中,否則將由所有@RibbonClients共享。如果您使用@ComponentScan(或@SpringBootApplication),則需要采取措施避免包含(例如將其放在一個(gè)單獨(dú)的,不重疊的包中,或者指定要在@ComponentScan)。

public class TimesRule extends AbstractLoadBalancerRule {
    private int times = 5;
    private int total = 0; // 總共被調(diào)用的次數(shù)
    private int currentIndex = 0; // 當(dāng)前提供服務(wù)的機(jī)器號(hào)
    
    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) {

    }
}

Ribbon + RestTemplate 就是其中一種服務(wù)調(diào)用的方式。


Feign

Feign是一個(gè)聲明式的Web服務(wù)客戶端。使用它就又可以回歸面向接口開(kāi)發(fā),脫離面向 restTemplate 開(kāi)發(fā)。
定義一個(gè)接口,加上注解,@FeignClient 綁定服務(wù),@RequestMapping 聲明調(diào)用的 api 接口,在配置中開(kāi)啟 @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,實(shí)現(xiàn)了負(fù)載均衡,集成了 Hystrix,實(shí)現(xiàn)了服務(wù)降級(jí)。
與 Ribbon + RestTemplate 不同的是,通過(guò) Feign只需要定義服務(wù)綁定接口且以聲明的方式控制層調(diào)用接口,優(yōu)雅而簡(jiǎn)單的實(shí)現(xiàn)了服務(wù)調(diào)用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容