SpringCloud之實現服務器端的負載均衡Ribbon(二)
一 Ribbon簡介
Ribbon是Netflix發布的負載均衡器,它有助於控制HTTP和TCP的客戶端的行為。為Ribbon配置服務提供者地址後,Ribbon就可基於某種負載均衡算法,自動地幫助服務消費者去請求。Ribbon默認為我們提供了很多負載均衡算法,例如輪詢、隨機等。當然,我們也可為Ribbon實現自定義的負載均衡算法。
在Spring Cloud中,當Ribbon與Eureka配合使用時,Ribbon可自動從Eureka Server獲取服務提供者地址列表,並基於負載均衡算法,請求其中一個服務提供者實例。展示了Ribbon與Eureka配合使用時的架構
搭建負載均衡Ribbon (ribbon-consumer)
接到上篇 http://www.cnblogs.com/grasp/p/9258811.html
繼續在springcloud工程中添加模塊ribbon-consumer,也是通過start.spring.io提供的模板創建
新的目錄
生成的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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.xuan</groupId> <artifactId>ribbon-consumer</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>ribbon-consumer</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <spring-cloud.version>Finchley.RELEASE</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-netflix-ribbon</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>
修改啟動文件RibbonConsumerApplication.java,註意增加RestTemplate 的bean註解。
package com.xuan.ribbonconsumer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @EnableDiscoveryClient @SpringBootApplication public class RibbonConsumerApplication { @Bean @LoadBalanced RestTemplate restTemplate () { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(RibbonConsumerApplication.class, args); } }
增加測試的消費接口ConsumerController.java
package com.xuan.ribbonconsumer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @RestController public class ConsumerController { @Autowired RestTemplate restTemplate; @RequestMapping(value = "/ribbon-consumer", method = RequestMethod.GET) public String helloConsumer() { return restTemplate.getForEntity("http://eureka-client/hello", String.class).getBody(); } }
註意要去實現提供者的“hello”接口,在後面在描述具體實現過程。
修改配置文件”application.properties“,讓消費者註冊中心註冊,並且通過註冊中心找到服務提供者。
spring.application.name=ribbon-consumer
server.port=9000
eureka.client.serviceUrl.defaultZone=http://localhost:8080/eureka/
為了觀察是否進行了負載均衡,在eureka-client模塊,增加一個服務提供者接口HelloController.java實現hello接口。
package com.xuan.eurekaclient; import com.netflix.appinfo.InstanceInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController public class HelloController { private static final Logger logger = LoggerFactory.getLogger(HelloController.class); @Autowired private DiscoveryClient client; @Value("${server.port}") String port; @RequestMapping(value = "hello", method = RequestMethod.GET) public String index() {
StringBuffer uriList = new StringBuffer("Hello World " + port + " 端口為您服務!<br>");
return uriList.toString();
}
}
如果需要打印服務端的詳細明細可以修改為:
package com.xuan.eurekaclient; import com.netflix.appinfo.InstanceInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController public class HelloController { private static final Logger logger = LoggerFactory.getLogger(HelloController.class); @Autowired private DiscoveryClient discoveryClient; @Value("${server.port}") String port; @RequestMapping(value = "hello", method = RequestMethod.GET) public String index() {
StringBuffer uriList = new StringBuffer("Hello World " + port + " 端口為您服務!<br>"); List<ServiceInstance> list = discoveryClient.getInstances("eureka-client"); uriList.append("<br>discoveryClient.getServices().size() = " + discoveryClient.getServices().size()); for( String s : discoveryClient.getServices()){ List<ServiceInstance> serviceInstances = discoveryClient.getInstances(s); for(ServiceInstance si : serviceInstances){ uriList.append("<br>services:" + s + ":getHost()=" + si.getHost()); uriList.append("<br>services:" + s + ":getPort()=" + si.getPort()); uriList.append("<br>services:" + s + ":getServiceId()=" + si.getServiceId()); uriList.append("<br>services:" + s + ":getUri()=" + si.getUri()); } } return uriList.toString(); } }
在eureka-client模塊再增加兩個配置文件,使用不同的端口,從而在一天電腦可以啟動多個服務提供者,方便測試
增加”application-peer1.properties“文件
spring.application.name=eureka-client
server.port=8091
eureka.client.serviceUrl.defaultZone=http://localhost:8080/eureka/
增加”application-peer1.properties“文件
spring.application.name=eureka-client
server.port=8092
eureka.client.serviceUrl.defaultZone=http://localhost:8080/eureka/
添加完成後eureka-client模塊的目錄結構為:
設置IDEA編輯器的Edit Configurations,增加兩個啟動配置,修改過完後的列表和註意的地方:
配置和環境都設置完成後:就可以分別啟動模塊了:
1.EurekaServerApplication
2.EurekaClientApplication,EurekaClientApplication1,EurekaClientApplication2
啟動後打開http://localhost:8080/顯示如圖:
最後啟動RibbonConsumerApplication模塊在打開http://localhost:8080/顯示如下
消費者RibbonConsumer也註冊成功了。
訪問消費者提供的接口http://localhost:9000/ribbon-consumer,查看是否進行了負載均衡,刷新一次,端口就變化了一次,說明訪問的是不同的服務提供者
源碼下載地址:https://gitee.com/xuantest/SpringCloud-Ribbon
SpringCloud之實現服務器端的負載均衡Ribbon(二)