2019年7月14日 星期日

Ribbon ( SpringCloud 2.x 三)

Ribbon 為客戶端的負載均衡,所以會改 consumer

@Configuration
public class ConfigRestTemplate {
    @Bean
    // @LoadBalanced
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}


※新增一個類別,因為要使用到 @LoadBananced 這個註解,只好放棄使用 @Import,但在使用前先註解,確保之前的程式是可以跑的


// @Import(RestTemplate.class)
public class consumerController {
    // private static final String PROVIDER_URI = "http://localhost:9001";
    private static final String PROVIDER_URI = "http://"+ "provider1".toUpperCase();
    // ...
}


※確保之前的程式能跑後,使用 ribbon 要三步
1.打開 @LoadBananced
2.訪問路徑改成 provider 的 spring.application.name 名稱,大小寫都可以,但 eureka 是大寫,最好都用一樣的

※以上缺一都會報錯

※不需要 ribbon 的 jar 包,eureka-client 已經有依賴了,這個 eureka-client 在第一篇已經加過了

※遇到的問題:

如果出現 Request URI does not contain a valid hostname 的錯,表示 spring.application.name 的名字找不到,不要忘了要加 http://
另外一個是 name 名稱不能有「_」,都會報這樣的錯

這個專案在隔天 run 時,居然出現找不到 PROVIDER1 的錯,結果 mvn clean install 就解決了



※測試 ribbon 預設的模式

新增兩個專案:
1.複製 pom.xml
2.複製 啟動類別和 controller,為了測試區別,/xxx 的內容三支都修改 ab.setName("xxx9002"); // 9001-9003
3.instance.instance-id 修改不同的名稱,但 spring.application.name 一樣
4.http://localhost/xxx 每重整一次會發現是有順序性的,如第一次循環是 132,就會一直按 132 的方式循環

畫面如下:
可看見 PROVIDER1 有三個實例



※改變預設模式


@Configuration
public class ConfigRestTemplate {
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
    
    @Bean
    public IRule myRibbonRule() {
    // return new RoundRobinRule();
    // return new RandomRule();
        return new RetryRule();
    }
}

※在自訂的 ConfigRestTemplate 增加 IRule 的回傳 Bean,RoundRobinRule 是預設的、
RandomRule 是隨機的、RetryRule 和預設的很像,差在如果其中有 provider 掛了就不一樣了,假設是 132 一直循環,然後 2 掛了,那就會是 13掛、13掛、經過幾次之後,就只會有13而已,可以將三個 provider 啟好後,關閉其中一個測試

※也可以寫個 class,然後回傳 IRule



※自定義規則



@Configuration
public class MyCustomRibbonRule {
    @Bean
    public IRule myRibbonRule() {
        // return new RandomRule();
        return new CalcRibbonRule();
    }
}


※改變預設模式的 @Bean 要註解或改名,不然會有 2 個 IRule


public class CalcRibbonRule extends AbstractLoadBalancerRule {
    private int currentIndex = 1; //  PROVIDER1 的機器號碼
    
    private 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) {
                return null;
            }
    
            // 主要邏輯在這
            if (upList.size() % 2 == 1) {
                server = upList.get(currentIndex);
                currentIndex++;
                System.out.println("size==>" + upList.size());
                System.out.println("currentIndex==>" + currentIndex);
                if (currentIndex >= serverCount) {
                    currentIndex = 1;
                }
            }
    
            if (server == null) {
                Thread.yield();
                continue;
            }
    
            if (server.isAlive()) {
                return (server);
            }
            server = null;
            Thread.yield();
        }
        return server;
    }
    
    @Override
    public Server choose(Object key) {
        return choose(getLoadBalancer(), key);
    }
    
    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {}
}


※我想不到什麼好規則,所以就是奇數的機器才去訪問,但並不是 9051 和 9053 這兩台機器的意思,機器的順序不是我們決定的,假設是 132,那就是 1 和 2

※本來是將 CalcRibbonRule 寫在 MyCustomRibbonRule 裡面,成為內部類別,但訪問的時候報錯了,NoSuchMethodException: controller.MyCustomRibbonRule$CalcRibbonRule.

※最後 consumer 的 main 方法要加上 @RibbonClient(value = "PROVIDER1", configuration = MyCustomRibbonRule.class) 即可

沒有留言:

張貼留言