1. 程式人生 > >Spring Cloud 應用篇 之 Ribbon 的基本使用

Spring Cloud 應用篇 之 Ribbon 的基本使用

上一篇文章初步體驗了 Eureka 的基本使用,講了關於服務的註冊與發現。這一篇主要講解基於 Ribbon 實現的服務呼叫。

(一)簡介

Spring Cloud Ribbon 是一個基於 Http 和 TCP 的客服端負載均衡工具,它是基於 Netflix Ribbon 實現的。

客戶端負載均衡即是當瀏覽器向後臺發出請求的時候,客戶端會向 Eureka Server 讀取註冊到伺服器的可用服務資訊列表,然後根據設定的負載均衡策略(沒有設定即用預設的),抉擇出向哪臺伺服器傳送請求。

(二)搭建服務環境

1. 基於上一篇的工程,啟動 eureka-service,spring-demo-service

啟動完畢後,更改 spring-demo-service 的埠號,再啟動一個 spring-demo-service 的例項,訪問 http://localhost:8761,如下


spring-demo-service 在 eureka server 註冊了兩個例項。

2. 新建立一個 module(spring-demo-service-ribbon),建立過程參考上一篇

3. 新增 pom 依賴

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

4. 啟動類

@SpringBootApplication
@EnableEurekaClient
public class ServiceRibbonApplication {

	public static void main(String[] args) {
        SpringApplication.run(ServiceRibbonApplication.class, args);
	}

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

在啟動類中,通過 @EnableEurekaClient 向 eureka server 註冊,並向容器中注入 restTemplate,同時通過 @LoadBalanced 開啟 restTemplate 負載均衡功能。

5. 建立 SpringDemoRibbonService,通過 restTemplate 消費 spring-demo-service 服務的 port 介面

@Service
public class SpringDemoRibbonService {

    @Autowired
    RestTemplate restTemplate;

    public String port() {
        return restTemplate.getForObject("http://SPRING-DEMO-SERVICE/port", String.class);
    }

}

在這裡,restTemplate 呼叫服務介面的方法不是僅此一種,API 大致如下,具體怎麼選擇應用,可以檢視相關 API 文件,我們直接使用 getForObject 第一種,在這裡我們直接用的程式名替代了具體的 url 地址,在 Ribbon 中它會根據服務名來選擇具體的服務例項,根據服務例項在請求的時候會用具體的 url 替換掉服務名


6. 建立 SpringDemoRibbonController

@RestController
public class SpringDemoRibbonController {

    @Autowired
    SpringDemoRibbonService springDemoRibbonService;

    @RequestMapping("hello")
    public String port() {
        return springDemoRibbonService.port();
    }
}

7. 配置檔案 application.yaml

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
server:
  port: 8381
spring:
  application:
    name: spring-demo-service-ribbon

8. 啟動 spring-demo-service-ribbon,在瀏覽器中多次訪問 localhost:8381/hello,瀏覽器會輪流顯示如下



此時說明基本使用 Ribbon 實現了客戶端負載均衡的功能,當用 restTemplate 呼叫服務介面時,訪問了不同埠的服務例項。

(三)稍作延伸:負載均衡策略常見的還有使用 Nginx 作為反向代理伺服器,對服務的呼叫進行負載均衡,這種方式是伺服器端負載均衡。

Ribbon 實現的是客戶端負載均衡,它可以在客戶端經過一系列演算法來均衡呼叫服務。Ribbon 比 Nginx 更注重的是承擔併發而不是請求分發,Ribbon 工作時分兩步:

第一步:選擇 Eureka Server,它優先選擇在同一個 Zone 且負載較少的 Server。

第二步:根據使用者指定的策略,在從 Server 取到的服務註冊列表中選擇一個地址,其中 Ribbon 提供了多種策略,例如輪詢 RoundRobinRule、隨機 RandomRule等。

下面以隨機策略進行進一步的配置

配置檔案修改如下:

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
server:
  port: 8381
spring:
  application:
    name: spring-demo-service-ribbon

#新增配置策略
spring-demo-service:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
啟動類修改如下:
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class ServiceRibbonApplication {

	public static void main(String[] args) {
        SpringApplication.run(ServiceRibbonApplication.class, args);
	}

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

        //新增注入隨機策略 Bean
	@Bean
	public IRule ribbonRule() {
		return new RandomRule();	//這裡配置策略,和配置檔案對應
	}
}

SpringDemoRibbonService 修改如下

@Service
public class SpringDemoRibbonService {

    @Autowired
    RestTemplate restTemplate;

    @Autowired
    LoadBalancerClient loadBalancerClient;

    public String port() {
        this.loadBalancerClient.choose("spring-demo-service");  //隨機訪問策略
        return restTemplate.getForObject("http://SPRING-DEMO-SERVICE/port", String.class);
    }

}
修改完成後,修改 spring-demo-service 的埠號,再啟動一個服務例項,然後重啟 spring-demo-service-ribbon,在瀏覽器中多次訪問 localhost:8381/hello,此時會發現,對 spring-demo-service 的服務例項呼叫是隨機呼叫,而不再是之前輪流呼叫,說明負載策略配置成功。