天天看點

eureka+Ribbon實作負載均衡Ribbon簡述Ribbon核心元件IRule

Ribbon簡述

是什麼

spring cloud ribbon 是一套用戶端的負載均衡工具

主要用來:用戶端的軟體負載均衡算法和服務的調用

做什麼

負載均衡+RestTemplate調用

LB負載均衡:将使用者請求平攤到多個伺服器上,進而達到系統的HA(高可用)

ribbon是本地負載均衡:在調用微服務接口時,會在注冊中心中擷取注冊資訊服務清單之後緩存到jvm本地,進而在本地實作rpc的遠端調用;

nginx是伺服器負載均衡:用戶端所用請求交給nginx,然後由nginx實作轉發請求.即負載均衡是由服務端實作的。

Ribbon核心元件IRule

負載均衡方式

IRule接口實作類關系圖:

eureka+Ribbon實作負載均衡Ribbon簡述Ribbon核心元件IRule

RoundRobinRule:輪詢

RandomRule:随機

RetryRule:先按照RoundRobinRule的政策擷取服務,如果擷取服務失敗則在指定時間内進行重試,擷取可用的服務

WeightedResponseTimeRule:對RoundRobinRule的擴充,響應速度越快的執行個體選擇權重越多大,越容易被選擇

BestAvailableRule:會先過濾掉由于多次通路故障而處于斷路器跳閘狀态的服務,然後選擇一個并發量最小的服務

AvailabilityFilteringRule:先過濾掉故障執行個體,再選擇并發較小的執行個體

ZoneAvoidanceRule:預設規則,複合判斷server所在區域的性能和server的可用性選擇伺服器

切換負載均衡方式

已知,當我們搭建好的Eureka微服務(參考Eureka

搭建微服務架構),預設的負載均衡方式是輪詢,本案例要做的是将預設的輪詢方式切換為随機方式。

pom

由于eureka自帶了 Ribbon的依賴,故我們不需要額外的引入。

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
           
eureka+Ribbon實作負載均衡Ribbon簡述Ribbon核心元件IRule

如何替換算法,把輪詢改為随機

官網明确警告:這個自定義配置類不能放在@componentScan所掃描的目前包以及子包下。否則我們的自定義配置類會被所有的Ribbon用戶端所共享,達不到特殊化制定的目的。(負載均衡方式,一般配置在消費者端,是以我們隻需要對消費者端的代碼做一下修改即可)

已知,@SpringBootApplication已經将@componentScan的注解引入,故此,我們不能将我建立的配置類被該注解掃描到

eureka+Ribbon實作負載均衡Ribbon簡述Ribbon核心元件IRule
eureka+Ribbon實作負載均衡Ribbon簡述Ribbon核心元件IRule

從我的代碼結構,可以看到,我的配置類MySelfRule建立的位置與主啟動類不在同步一包下的,這就避免了MySelfRule被掃描進去。

MySelfRule:

@Configuration
public class MySelfRule {

    @Bean
    public IRule myRule() {
        // 定義為随機
        return new RoundRobinRule();
    }
}
           

主啟動類:

@SpringBootApplication
@EnableEurekaClient
//CLOUD-PAYMENT-SERVICE是服務注冊中心的服務名
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE", configuration = MySelfRule.class)
public class OraderMain80 {
    public static void main(String[] args) {
        SpringApplication.run(OraderMain80.class,args);
    }
}
           

在主啟動類添加@RibbonClient。

自定義負載均衡

在平時的工作中,往往現有的負載均衡政策無法滿足需求,是以我們有必要了解如何自定義負載均衡。

要寫一個自定義的負載均衡,我們需要先了解負載均衡的原理。下面将通過刨析RoundRobinRule輪詢方式來深入了解。

RoundRobinRule的工作原理

由上述的配置類可知,我們若想切換一個新的負載均衡政策,我們隻需要改變配置類注冊bean的類型即可。如下:

@Configuration
public class MySelfRule {
    @Bean
    public IRule myRule() {
        // 定義為随機
        return new RandomRule();
    }
}
           

是以,我們可以從這裡入手,要想自定義一個負載均衡政策,隻需要自行建立一個與RandomRule同性質的類并注入到容器中供即可。

什麼是同性質?

eureka+Ribbon實作負載均衡Ribbon簡述Ribbon核心元件IRule

我們參考上述截圖,可見AbstractLoadBalancerRule抽象類之下有幾個實作類,分别對應了上述類圖關系的其中已有的負載均衡政策,而且他們都實作了相關的三個方法。從這裡可以發現,我們若要自定義一個負載均衡,完完全全可以參考該類的實作,隻需要将核心的實作方法替換一下就可以了,這裡就是我們可以從源碼看到的資訊。

(友情提示:有時候看源碼,不能單純的看,還要懂得會套用)

我們繼續看RandomRule實作:

public class RandomRule extends AbstractLoadBalancerRule {

    /**
     * Randomly choose from all living servers
     */
    @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE")
    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;
            }

            int index = chooseRandomInt(serverCount);
            server = upList.get(index);

            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;

    }

    protected int chooseRandomInt(int serverCount) {
        return ThreadLocalRandom.current().nextInt(serverCount);
    }

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

	@Override
	public void initWithNiwsConfig(IClientConfig clientConfig) {
		// TODO Auto-generated method stub
		
	}
}
           

上面的源碼很簡單,也就是随機擷取一個服務int index = chooseRandomInt(serverCount);,getLoadBalancer()方法是父類的實作,是以我們隻需要看choose(ILoadBalancer lb, Object key)方法的實作即可。(我們也可以想到,我們自定義的負載均衡類,也隻重點實作該方法即可)

至此,沒什麼好說的,看到這我們已經知道要實作一個自定義的負載均衡政策,已經很明了了。好人做到底,随便貼一下輪詢方式的算法原理:

eureka+Ribbon實作負載均衡Ribbon簡述Ribbon核心元件IRule

自定義負載均衡實作

eureka+Ribbon實作負載均衡Ribbon簡述Ribbon核心元件IRule
eureka+Ribbon實作負載均衡Ribbon簡述Ribbon核心元件IRule

如上述截圖,具體隻需要參考實作抽象類的核心方法就可以了。

繼續閱讀