天天看點

SpringCloud(四)Ribbon——負載均衡1 ribbon介紹2 實戰

在上一篇文章中,我們建立了一個服務注冊(或服務發現)服務,一個可樂服務,一個使用者服務,并且後兩個服務都注冊到了服務注冊服務上。

在真實環境中我們的微服務架構通常要承載幾十萬,幾百萬,幾千萬甚至更進階别的流量考驗,面對這種高并發場景,服務往往都是分布式部署。那麼問題來了,我們如何讓伺服器叢集的每個節點處理的請求數量相當呢,不至于一台伺服器快要撐爆了,一台伺服器無人問津,如何讓每台伺服器負載均衡呢?

在單體架構中,我們一般會到nginx來做負載均衡,正向代理,反向代理等等。那麼在Spring Cloud微服務架構中如何實作均衡負載呢?接下來我們有請ribbon登場。ningx是伺服器端的負載均衡元件,ribbon是用戶端的負載均衡元件。

源碼托管位址:https://github.com/cddofficial/SpringCloudRepo

目錄

1 ribbon介紹

1.1 簡介

1.2 原理

1.2.1 Eureka使用Ribbon時的架構

1.2.2 工作流程

2 實戰

2.1 RestTemplate應用執行個體

2.1.1 測試使用者微服務

2.1.2. 修改可樂微服務

2.1.3 測試

2.2 Ribbon應用

2.2.1 複制得到eureka-client-coke-ribbon微服務

2.2.2 啟動使用者服務eureka-client-user多個節點

2.2.3 處理eureka-client-coke-ribbon微服務

2.2.4 測試

1 ribbon介紹

1.1 簡介

ribbon也是Netflix公司的,英文直譯為絲帶,準确的是指 蝴蝶結。大家立馬能夠想到蝴蝶結兩邊是對稱的,這不正好有點均衡負載的意思在裡面嗎,是以把ribbon翻譯為蝴蝶結更好些。

Ribbon是Netflix釋出的雲中間層服務開源項目,其主要功能是提供用戶端側負載均衡算法。Ribbon用戶端元件提供一系列完善的配置項如連接配接逾時,重試等。簡單的說,Ribbon是一個用戶端負載均衡器,我們可以在配置檔案中列出Load Balancer後面所有的機器,Ribbon會自動的幫助你基于某種規則(如簡單輪詢,随機連接配接等)去連接配接這些機器,我們也很容易使用Ribbon實作自定義的負載均衡算法。

1.2 原理

1.2.1 Eureka使用Ribbon時的架構

架構圖如下:

SpringCloud(四)Ribbon——負載均衡1 ribbon介紹2 實戰

在上圖中,假如:服務提供者是我們的使用者服務,有多個節點。服務的消費者是我們的可樂服務。

有3個使用者服務節點,1個可樂服務節點注冊到服務注冊服務;有一個請求過來時,可樂服務要向使用者服務發送請求。

可樂服務先從服務注冊服務擷取到可以請求的使用者服務節點,再根據負載均衡規則命中到其中一個使用者服務節點。

這時候請求處理了,3個使用者服務節點處理的請求數也差不多達到均衡。

1.2.2 工作流程

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

第二步再根據使用者指定的政策,在從Server取到的服務注冊清單中選擇一個位址。其中Ribbon提供了多種政策,例如輪詢round robin、随機Random、根據響應時間權重等。

預設政策為輪詢方式。

2 實戰

下面的實戰在上一篇文章所編寫代碼的基礎上進行,如有問題可檢視上篇文章eureka實戰。

2.1 RestTemplate應用執行個體

在學習用ribbon負載均衡前,我們先要會微服務間的通信,即,可樂微服務向使用者微服務發送請求。在這裡可樂微服務就是服務消費者,使用者服務就是服務提供者。、

那麼如何實作微服務間的通信呢?我們可以采用HttpClient等一些其他技術,但是太過複雜。在這裡我們使用RestTemplate,是Spring提供的用于通路Rest服務的用戶端,RestTemplate提供了多種便捷通路遠端Http服務的方法,能夠大大提高用戶端的編寫效率。

2.1.1 測試使用者微服務

啟動服務eureka-client-user,啟動成功。在浏覽器中輸入:http://localhost:9002/user/2,響應頁面如下:

SpringCloud(四)Ribbon——負載均衡1 ribbon介紹2 實戰

說明使用者微服務正常,如果有問題,一定要先解決。

2.1.2. 修改可樂微服務

修改eureka-client-coke微服務的代碼。

1. 在啟動類裡注冊RestTemplate的bean

代碼如下:

package com.cdd.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableEurekaClient  //eureka client 注解
public class EurekaClientCokeApplication {

	public static void main(String[] args) {
		SpringApplication.run(EurekaClientCokeApplication.class, args);
	}
	
	// 向spring容器中中注冊RestTemplate
	@Bean
	public RestTemplate restTemplate() {
		return new RestTemplate();
	}
}
           

2 建立User類

在啟動類所在包下建立entity包,entity包下建立一個User類,屬性和使用者微服務中的User類相同,代碼如下:

package com.cdd.demo.entity;

public class User {

	private Long id;
	
	private String name;
	
	private Short age;

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Short getAge() {
		return age;
	}

	public void setAge(Short age) {
		this.age = age;
	}
	
}
           

3.建立CokeController類

在啟動類所在包下建立controller包,controller包下建立一個CokeController類,代碼如下:

package com.cdd.demo.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import com.cdd.demo.entity.User;

@RestController
public class CokeController {

	// 注入RestTemplate
	@Autowired
	private RestTemplate restTemplate;

	// 通過RestTemplate向使用者微服務發送請求
	@GetMapping("/coke/{id}")
	public User findById(@PathVariable Long id) {
		return this.restTemplate.getForObject("http://localhost:9002/user/" + id, User.class);
	}
}
           

4. 啟動可樂微服務eureka-client-coke(确定使用者微服務eureka-client-user也要在啟動狀态),啟動成功。

2.1.3 測試

在浏覽器中輸入:http://localhost:9001/coke/2,響應頁面如下:

SpringCloud(四)Ribbon——負載均衡1 ribbon介紹2 實戰

說明我們通過RestTemplate進行微服務間的通信成功了。

2.2 Ribbon應用

上面的示例,是确定要通路那個使用者服務節點,可以看到CokeController類中restTemplate.getForObject方法的請求位址(主機+端口)是寫死的。那麼現在如果這種請求特别多呢,有多個使用者微服務節點,那麼我們怎麼用ribbon來實作負載均衡呢?請往下看。

從這裡開始,每學習一個新技術點,都要在一個新微服務上去實作。保證對應的微服務例子對應的技術點,這些代碼我會上傳的github上。到時候可以随時下載下傳下拉看。

2.2.1 複制得到eureka-client-coke-ribbon微服務

複制eureka-client-coke服務重命名為eureka-client-coke-ribbon,導入到工作IDE工具STS中(至于如何複制這裡不再贅述,請看eureka——實戰中的 “2.4.1 建立可樂微服務” 的 “複制得到eureka-client-coke“)。導入到STS中後,如下圖:

SpringCloud(四)Ribbon——負載均衡1 ribbon介紹2 實戰

大家這裡有問題的話一定嘗試解決或者要問我,很簡單的,不能被這個步驟擋住了前進了腳步。

2.2.2 啟動使用者服務eureka-client-user多個節點

這個時候其他微服務全部關閉,先啟動服務注冊服務eureka-server-service-discover。

1. 修改eureka-client-user微服務的執行個體化id

在application.yml中,如下:

SpringCloud(四)Ribbon——負載均衡1 ribbon介紹2 實戰

2.修改eureka-client-user微服務的啟動端口為8001

修改檔案為application.yml,修改後代碼如下:

server:
  port: 8001  #修改端口為8001

spring:
  application:
    name: eureka-client-user   #應用程式名稱
  jpa:
    generate-ddl: false
    show-sql: true
    hibernate:
      ddl-auto: none
  datasource:
    platform: h2
    schema: classpath:schema.sql   #一般是建立表結構的sql
    data: classpath:data.sql   #一般是處理表資料的sql
    
logging:
  level:
    root: INFO
    org.hibernate: INFO
    com.cdd: DEBUG

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true
    instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}}  #執行個體id 
           

修改完成之後,啟動eureka-client-user微服務。從控制台我們可以看到這個8001端口的使用者服務節點啟動時間為:下午5:50:57

SpringCloud(四)Ribbon——負載均衡1 ribbon介紹2 實戰

3. 再次修改eureka-client-user微服務的啟動端口為8002

修改檔案為application.yml,修改後代碼如下:

server:
  port: 8002  #修改端口為8002

spring:
  application:
    name: eureka-client-user   #應用程式名稱
  jpa:
    generate-ddl: false
    show-sql: true
    hibernate:
      ddl-auto: none
  datasource:
    platform: h2
    schema: classpath:schema.sql   #一般是建立表結構的sql
    data: classpath:data.sql   #一般是處理表資料的sql
    
logging:
  level:
    root: INFO
    org.hibernate: INFO
    com.cdd: DEBUG

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true
    instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}}  #執行個體id 
           

修改完成之後,再啟動一次eureka-client-user微服務。從控制台我們可以看到這個8002端口的使用者服務節點啟動時間為:下午5:52:50

SpringCloud(四)Ribbon——負載均衡1 ribbon介紹2 實戰

4. 檢視服務注冊清單

在浏覽器中輸入:http://localhost:8761/ 響應頁面如下:

SpringCloud(四)Ribbon——負載均衡1 ribbon介紹2 實戰

此時我們的使用者微服務eureka-client-user已經有2個節點注冊打服務注冊服務了。

2.2.3 處理eureka-client-coke-ribbon微服務

1.添加ribbon依賴

eureka-client-coke-ribbon項目中需要ribbon依賴,首先我們先搜尋下已有的依賴中是否包含ribbon依賴,

(1)如果有我們就不用添加了,如下圖:

SpringCloud(四)Ribbon——負載均衡1 ribbon介紹2 實戰

(2)如果沒有這個依賴,就要我們自己手動添加了,如下:

SpringCloud(四)Ribbon——負載均衡1 ribbon介紹2 實戰

我們這裡是不用再手動添加ribbon依賴的,在spring-cloud-starter-netflix-eureka-client依賴中包含着。

2.修改啟動類

啟動類名稱改為:EurekaClientCokeRibbonApplication,并且給啟動類的restTemplate方法添加@LoadBalanced注解,

修改後代碼如下:

package com.cdd.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableEurekaClient  //eureka client 注解
public class EurekaClientCokeRibbonApplication {

	public static void main(String[] args) {
		SpringApplication.run(EurekaClientCokeRibbonApplication.class, args);
	}
	
	
	@Bean   // 向spring容器中中注冊RestTemplate
	@LoadBalanced  // 負載均衡注解
	public RestTemplate restTemplate() {
		return new RestTemplate();
	}
}
           

3.修改CokeController類,修改後代碼如下:

package com.cdd.demo.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import com.cdd.demo.entity.User;

@RestController
public class CokeController {

	// 注入RestTemplate
	@Autowired
	private RestTemplate restTemplate;

	// 通過RestTemplate向使用者微服務發送請求
	@GetMapping("/coke/{id}")
	public User findById(@PathVariable Long id) {
		// 方法getForObject目前請求路徑參數已經換成了使用者微服務的 serviceId,
		return this.restTemplate.getForObject("http://eureka-client-user/user/" + id, User.class);
	}
}
           

補充:使用者微服務serviceId的來源

來自服務注冊清單(localhost:8761/頁面),如下圖:

SpringCloud(四)Ribbon——負載均衡1 ribbon介紹2 實戰

4. 啟動微服務eureka-client-coke-ribbon,啟動成功後,檢視服務注冊清單,如下圖:

SpringCloud(四)Ribbon——負載均衡1 ribbon介紹2 實戰

說明該微服務已經注冊上來了。

2.2.4 測試

清空控制台是以微服務的日志。

在浏覽器中輸入:http://localhost:9001/coke/2,去請求可樂微服務,可樂微服務又回去請求使用者微服務,不過使用者微服務有兩個節點,端口分别為8001和8002,響應頁面如下:

SpringCloud(四)Ribbon——負載均衡1 ribbon介紹2 實戰

再次清空所有執行個體的控制台日志,連續點選重新整理http://localhost:9001/coke/2頁面4次,接下來看控制台日志。

啟動時間為下午5:50:57啟動的端口為8001的使用者微服務執行個體,執行了2次(看列印sql條數),

SpringCloud(四)Ribbon——負載均衡1 ribbon介紹2 實戰

啟動時間為下午5:52:50啟動的端口為8002的使用者微服務執行個體,也執行了2次,

SpringCloud(四)Ribbon——負載均衡1 ribbon介紹2 實戰

從上面日志可以看出,可樂服務發送了4次請求,使用者微服務的2個執行個體分别執行處理了2次,說明已經實作負載均衡了。

繼續閱讀