1. 程式人生 > >微服務Springcloud超詳細教程+實戰(十一)

微服務Springcloud超詳細教程+實戰(十一)

本人正在找深圳Java實習工作,求大佬帶飛 QQ:1172796094
如在文件中遇到什麼問題請聯絡作者
——————————————————————————————————————

負載均衡Ribbon

在上章的案例中,我們啟動了一個user-service,然後通過DiscoveryClient來獲取服務例項資訊,然後獲取ip和埠來訪問。

但是實際環境中,我們往往會開啟很多個user-service的叢集。此時我們獲取的服務列表中就會有多個,到底該訪問哪一個呢?

一般這種情況下我們就需要編寫負載均衡演算法,在多個例項列表中進行選擇。

不過SpringCloud中已經幫我們集成了負載均衡元件:Ribbon,簡單修改程式碼即可使用。

什麼是Ribbon:
在這裡插入圖片描述
接下來,我們就來使用Ribbon實現負載均衡。

啟動兩個服務例項

首先我們啟動兩個user-service例項,一個8090,一個8092。
在這裡插入圖片描述
Eureka監控面板:
在這裡插入圖片描述

開啟負載均衡

因為Eureka中已經集成了Ribbon,所以我們無需引入新的依賴。直接修改程式碼:

在RestTemplate的配置方法上新增@LoadBalanced註解:

@Bean
@LoadBalanced
public RestTemplate restTemplate() {
    return new RestTemplate();
}

修改呼叫方式,不再手動獲取ip和埠,而是直接通過服務名稱呼叫:

@Service
public class UserService {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    public List<User> queryUserByIds(List<Long> ids) {
        List<User> users = new ArrayList<>();
        // 地址直接寫服務名稱即可
        String baseUrl = "http://user-service/user/";
        ids.forEach(id -> {
            // 我們測試多次查詢,
            users.add(this.restTemplate.getForObject(baseUrl + id, User.class));
            // 每次間隔500毫秒
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        return users;
    }
}

訪問頁面,檢視結果:
在這裡插入圖片描述
完美!

原始碼跟蹤

為什麼我們只輸入了service名稱就可以訪問了呢?之前還要獲取ip和埠。

顯然有人幫我們根據service名稱,獲取到了服務例項的ip和埠。它就是LoadBalancerInterceptor

我們進行原始碼跟蹤:(Debug執行user-consumer-demo專案)
在這裡插入圖片描述
繼續跟入execute方法:發現獲取了8082埠的服務
在這裡插入圖片描述
再跟下一次,發現獲取的是8081:
在這裡插入圖片描述

負載均衡策略

Ribbon預設的負載均衡策略是簡單的輪詢,我們可以測試一下:

編寫測試類,在剛才的原始碼中我們看到攔截中是使用RibbonLoadBalanceClient來進行負載均衡的,其中有一個choose方法,是這樣介紹的:
在這裡插入圖片描述
現在這個就是負載均衡獲取例項的方法。

我們對注入這個類的物件,然後對其測試:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = UserConsumerDemoApplication.class)
public class LoadBalanceTest {

    @Autowired
    RibbonLoadBalancerClient client;

    @Test
    public void test(){
        for (int i = 0; i < 100; i++) {
            ServiceInstance instance = this.client.choose("user-service");
            System.out.println(instance.getHost() + ":" + instance.getPort());
        }
    }
}

結果:
在這裡插入圖片描述
符合了我們的預期推測,確實是輪詢方式。

我們是否可以修改負載均衡的策略呢?

繼續跟蹤原始碼,發現這麼一段程式碼:
在這裡插入圖片描述
我們看看這個rule是誰:
在這裡插入圖片描述
這裡的rule預設值是一個RoundRobinRule,看類的介紹:
在這裡插入圖片描述
這不就是輪詢的意思嘛。

我們注意到,這個類其實是實現了介面IRule的,檢視一下:
在這裡插入圖片描述
定義負載均衡的規則介面。

它有以下實現:
在這裡插入圖片描述
SpringBoot也幫我們提供了修改負載均衡規則的配置入口:在這裡插入圖片描述

user-service:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

格式是:{服務名稱}.ribbon.NFLoadBalancerRuleClassName,值就是IRule的實現類。

再次測試,發現結果變成了隨機:
在這裡插入圖片描述