負載均衡組件Robbin

1.負載均衡Robbin

Eureka中已經幫我們集成了負載均衡組件:Ribbon,簡單修改代碼即可使用。

什麼是Ribbon:
在這裏插入圖片描述

接下來,我們就來使用Ribbon實現負載均衡。

1.1.啓動兩個服務實例

首先我們啓動兩個user-service實例,一個8081,一個8082。

在這裏插入圖片描述

Eureka監控面板:

在這裏插入圖片描述

1.2.開啓負載均衡

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

在RestTemplate的配置方法上添加@LoadBalanced註解:

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

修改調用方式,不再手動獲取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;
    }
}

訪問頁面,查看結果:

在這裏插入圖片描述

完美!

1.3.源碼跟蹤

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

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

我們進行源碼跟蹤:

在這裏插入圖片描述

繼續跟入execute方法:發現獲取了8082端口的服務

在這裏插入圖片描述

再跟下一次,發現獲取的是8081:

在這裏插入圖片描述

1.4.負載均衡策略

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的實現類。

再次測試,發現結果變成了隨機:

在這裏插入圖片描述

1.5.重試機制

Eureka的服務治理強調了CAP原則中的AP,即可用性和可靠性。它與Zookeeper這一類強調CP(一致性,可靠性)的服務治理框架最大的區別在於:Eureka爲了實現更高的服務可用性,犧牲了一定的一致性,極端情況下它寧願接收故障實例也不願丟掉健康實例,正如我們上面所說的自我保護機制。

但是,此時如果我們調用了這些不正常的服務,調用就會失敗,從而導致其它服務不能正常工作!這顯然不是我們願意看到的。

我們現在關閉一個user-service實例:

在這裏插入圖片描述

因爲服務剔除的延遲,consumer並不會立即得到最新的服務列表,此時再次訪問你會得到錯誤提示:

在這裏插入圖片描述

但是此時,8081服務其實是正常的。

因此Spring Cloud 整合了Spring Retry 來增強RestTemplate的重試能力,當一次服務調用失敗後,不會立即拋出一次,而是再次重試另一個服務。

只需要簡單配置即可實現Ribbon的重試:

spring:
  cloud:
    loadbalancer:
      retry:
        enabled: true # 開啓Spring Cloud的重試功能
user-service:
  ribbon:
    ConnectTimeout: 250 # Ribbon的連接超時時間
    ReadTimeout: 1000 # Ribbon的數據讀取超時時間
    OkToRetryOnAllOperations: true # 是否對所有操作都進行重試
    MaxAutoRetriesNextServer: 1 # 切換實例的重試次數
    MaxAutoRetries: 1 # 對當前實例的重試次數

根據如上配置,當訪問到某個服務超時後,它會再次嘗試訪問下一個服務實例,如果不行就再換一個實例,如果不行,則返回失敗。切換次數取決於MaxAutoRetriesNextServer參數的值

引入spring-retry依賴

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>

我們重啓user-consumer-demo,測試,發現即使user-service2宕機,也能通過另一臺服務實例獲取到結果!

在這裏插入圖片描述

發佈了48 篇原創文章 · 獲贊 11 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章