Spring Cloud 入门教程(五): Ribbon实现客户端的负载均衡
接上节,假如我们的Hello world服务的访问量剧增,用一个服务已经无法承载, 我们可以把Hello World服务做成一个集群。
很简单,我们只需要复制Hello world服务,同时将原来的端口8762修改为8763。然后启动这两个Spring Boot应用, 就可以得到两个Hello World服务。这两个Hello world都注册到了eureka服务中心。这时候再访问http://localhost:8761, 可以看到两个hello world服务已经注册。(服务与注册参见Spring Cloud 入门教程(一): 服务注册)。
1. 客户端的负载均衡
负载均衡可分为服务端负载均衡和客户端负载均衡,服务端负载均衡完全由服务器处理,客户端不需要做任何事情。而客户端负载均衡技术,客户端需要维护一组服务器引用,每次客户端向服务端发请求的时候,会根据算法主动选中一个服务节点。常用的负载均衡算法有: Round Robbin, Random,Hash,StaticWeighted等。
Spring 提供两辆种服务调度方式:Ribbon+restful和Feign。Ribbon就是一个基于客户端的负载均衡器, Ribbon提供了很多在HTTP和TCP客户端之上的控制.
Feign内部也已经使用了Ribbon, 所以只要使用了@FeignClient注解,那么这一章的内容也都是适用的。
下面就看看如何Spring Cloud如何用Ribbon来实现两个Hello World服务的负载均衡。以下是Spring cloud的ribbon客户端负载均衡架构图。
hello world服务和ribbon均注册到服务中心
service-hi工程跑了两个副本,端口分别为8762,8763,分别向服务注册中心注册, 当sercvice-ribbon通过restTemplate调用service-Hellowworld的接口时,利用用ribbon进行负载均衡,会轮流的调用处于两个不同端口的Hello world服务
2. 创建一个Ribbon服务
1) 创建一个maven工程,取名叫service-ribbon, pom.xml文件如下:
1 <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"> 2 <modelVersion>4.0.0</modelVersion> 3 <groupId>com.chry</groupId> 4 <artifactId>springcloud.helloworld.ribbon.service</artifactId> 5 <version>0.0.1-SNAPSHOT</version> 6 <packaging>jar</packaging> 7 <name>springcloud.helloworld.ribbon.service</name> 8 <description>Demo project for Spring Cloud Ribbon</description> 9 10 <parent> 11 <groupId>org.springframework.boot</groupId> 12 <artifactId>spring-boot-starter-parent</artifactId> 13 <version>1.5.3.RELEASE</version> 14 <relativePath/> <!-- lookup parent from repository --> 15 </parent> 16 17 <properties> 18 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 19 <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> 20 <java.version>1.8</java.version> 21 </properties> 22 23 <dependencies> 24 <dependency> 25 <groupId>org.springframework.cloud</groupId> 26 <artifactId>spring-cloud-starter-eureka</artifactId> 27 </dependency> 28 <dependency> 29 <groupId>org.springframework.cloud</groupId> 30 <artifactId>spring-cloud-starter-ribbon</artifactId> 31 </dependency> 32 <dependency> 33 <groupId>org.springframework.boot</groupId> 34 <artifactId>spring-boot-starter-web</artifactId> 35 </dependency> 36 37 <dependency> 38 <groupId>org.springframework.boot</groupId> 39 <artifactId>spring-boot-starter-test</artifactId> 40 <scope>test</scope> 41 </dependency> 42 </dependencies> 43 44 <dependencyManagement> 45 <dependencies> 46 <dependency> 47 <groupId>org.springframework.cloud</groupId> 48 <artifactId>spring-cloud-dependencies</artifactId> 49 <version>Dalston.RC1</version> 50 <type>pom</type> 51 <scope>import</scope> 52 </dependency> 53 </dependencies> 54 </dependencyManagement> 55 56 <build> 57 <plugins> 58 <plugin> 59 <groupId>org.springframework.boot</groupId> 60 <artifactId>spring-boot-maven-plugin</artifactId> 61 </plugin> 62 </plugins> 63 </build> 64 65 <repositories> 66 <repository> 67 <id>spring-milestones</id> 68 <name>Spring Milestones</name> 69 <url>https://repo.spring.io/milestone</url> 70 <snapshots> 71 <enabled>false</enabled> 72 </snapshots> 73 </repository> 74 </repositories> 75 </project>
2). 创建主类ServiceRibbonApplication
1 package springcloud.helloworld.ribbon.service; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 6 import org.springframework.cloud.client.loadbalancer.LoadBalanced; 7 import org.springframework.context.annotation.Bean; 8 import org.springframework.web.client.RestTemplate; 9 10 @SpringBootApplication 11 @EnableDiscoveryClient 12 public class ServiceRibbonApplication { 13 14 public static void main(String[] args) { 15 SpringApplication.run(ServiceRibbonApplication.class, args); 16 } 17 18 @Bean 19 @LoadBalanced 20 RestTemplate restTemplate() { 21 return new RestTemplate(); 22 } 23 }
@EnableDiscoveryClient向服务中心注册,并且注册了一个叫restTemplate的bean。
@ LoadBalanced注册表明,这个restRemplate是需要做负载均衡的。
3). 创建获取一个获取Hello内容的service类
1 package springcloud.helloworld.ribbon.client; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.stereotype.Service; 5 import org.springframework.web.client.RestTemplate; 6 7 @Service 8 public class HelloService { 9 @Autowired RestTemplate restTemplate; 10 11 public String getHelloContent() { 12 return restTemplate.getForObject("http://SERVICE-HELLOWORLD/",String.class); 13 } 14 }
这里关键代码就是, restTemplate.getForObject方法会通过ribbon负载均衡机制, 自动选择一个Hello word服务,
这里的URL是“http://SERVICE-HELLOWORLD/",其中的SERVICE-HELLOWORLD是Hello world服务的名字,而注册到服务中心的有两个SERVICE-HELLOWORLD。 所以,这个调用本质是ribbon-service作为客户端根据负载均衡算法自主选择了一个作为服务端的SERVICE-HELLOWORLD服务。然后再访问选中的SERVICE-HELLOWORLD来执行真正的Hello world调用。
3. 启动ribbon-service应用,我们就可以访问http://localhost:8901/, 然后每次刷新可以看到以下两种结果交替出现,表明实际调用的是在不同端口的不同的SERVICE-HELLOWORLD。
上一篇:Spring Cloud 入门教程(四): 分布式环境下自动发现配置服务
下一篇:Spring Cloud 入门教程(六): 用声明式REST客户端Feign调用远端HTTP服务
参考: http://blog.csdn.net/forezp/article/details/69788938