一、Ribbon簡介
Ribbon是Netflix發佈的負載均衡器,它有助於控制HTTP和TCP客戶端行爲。爲Ribbon配置服務提供者地址列表後,Ribbon就可以基於某種負載均衡算法,自動地幫助服務消費者去提供請求。
在springcloud中,當Ribbon配合Eureka使用時,Ribbon可自動從Eureka Server獲取服務提供者的地址列表,並基於某種負載均衡算法,請求其中第一個服務提供者實例,常用的算法有隨機規則和輪詢,當沒有指定規則時,默認使用的算法爲輪詢。
下面來演示實怎麼用Ribbon結合Eureka實現負載均衡:
現準備一個eureka註冊中心,2個名爲expense的服務,均爲服務的提供者(provider),服務除了端口不一樣,其他都保持一致,1個payment服務,在案例中當消費者(consumer)。
各服務使用的springcloud版本爲:
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR4</spring-cloud.version>
</properties>
springboot版本爲:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.11.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
客戶端的依賴和配置文件如下:
payment服務:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.11.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example.hand</groupId>
<artifactId>payment</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>payment</name>
<description>project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR4</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
applicantion.properites配置文件:
server.port=9098
spring.application.name=payment
eureka.instance.prefer-ip-address=true
eureka.instance.instance-id=192.168.3.25:9098
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
eureka.instance.lease-renewal-interval-in-seconds =100
eureka.instance.lease-expiration-duration-in-seconds =50
spring.security.user.name=user
spring.security.user.password=user123
provider.name1=expense
另外一個擁有2個實例的expense服務的pom.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.11.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example.hand</groupId>
<artifactId>expense</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>expense</name>
<description>project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR4</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.example.hand.Expense1Application</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.properties文件 :
端口爲9096的:
server.port=9096
spring.application.name=expense
eureka.instance.prefer-ip-address=true
eureka.instance.instance-id=192.168.2.13:9096
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
eureka.instance.lease-renewal-interval-in-seconds =30
eureka.instance.lease-expiration-duration-in-seconds =30
端口爲9097的:
server.port=9097
spring.application.name=expense
eureka.instance.prefer-ip-address=true
eureka.instance.instance-id=192.168.2.13:9097
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
eureka.instance.lease-renewal-interval-in-seconds =30
eureka.instance.lease-expiration-duration-in-seconds =30
所需要的配置添加好以後,如果有遠程調用,需要在消費者端,啓動類添加如下代碼,將遠程調用RestTemplate類交給spring容器管理初始化,到後面我們要用的時候直接使用@Autowire註解就可以了,然後添加@LoadBanlanced註解,Ribbon客戶端請求服務端就有負載均衡的效果:
@Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
補充一點:介紹通過打jar包的形式,使用java命令來發布2個同名的實例。在expense服務下啓動兩個終端,分別使用不同端口號來啓動:
第一步,在pom文件中添加<packaging>jar</packaging>標籤,使用maven插件打jar包:
<groupId>com.example.hand</groupId>
<artifactId>expense</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>expense</name>
然後使用命令: mvn install
執行完成後,會在target目錄下生成一個後綴爲.jar的文件,和.jar.original文件:
然後分別使用9096端口和9097端口執行命令,如下默認使用的配置文件中的默認端口啓動:
java -jar expense-0.0.1-SNAPSHOT.jar
修改expense的實例id,在修改配置文件後,重新打jar包,修改實例的id和端口號後再啓動:
java -jar expense-0.0.1-SNAPSHOT.jar --server.port=9097
切換到指定的目錄下:
啓動後:
啓動各服務,效果如下:
然後在客戶端定義一個接口使用loadBalancerClient去調用主機名爲expense的服務,Ribbon客戶端會根據eureka裏面的服務器的地址列表來輪詢選擇一個實例進行請求!
Payment的java代碼如下:
@GetMapping("/get/instance")
public String getInstance(){
ServiceInstance instance=this.loadBalancerClient.choose("expense");
String str="實例的id爲:"+instance.getServiceId()+",實例的域名爲:"+instance.getHost()+",端口爲:"+instance.getPort();
LOGGER.info(str);
return str;
}
然後訪問如下Url:http://localhost:9098/api/wallet/get/instance
刷新頁面後,會發現返回的結果爲在9097和9096之間來回切換:
控制檯打印結果如下:
由上述結果發現,這樣就實現負載均衡了,默認的負載均衡規則爲輪詢,在2各節點之間來回切換!