负载均衡Ribbon 网络请求框架RestTemplate
RestTemplate是Spring Resources中一个访问第三方RESTful API接口的网络请求框架。 RestTeamplate是用来消费REST服务的,所以RestTeamplate也有HEAD、GET、POST、PUT、DELETE、OPTIONS等方法。注意:head对应的方法为headForHeaders(),其它都为xxxForObject()
示例:
1 2 3 4 5 6 7 8 @RestControllrt public class RestController { @GetMapping("/testRest") public String testRest () { RestTemplate restTemplate = new RestTemplate (); return restTemplate.getForObject("htpps://www.baidu.com/" ,String.class); } }
在上面例子中,RestTemplate用Get方法获取百度网页的html字符串。RestTemplate支持XML、JSON数据格式,默认实现了序列化,可以自动将JSON字符串转换为实体,如下:User user = restTemplate.getForObject("https://www.xxx.xxx/",User.class);
Ribbon简介 负载均衡是指负载分摊到多个执行单元上,常见的有以下两种:
通过负载均衡策略,将请求转发到不同的执行单元上,如Nginx
将负载均衡逻辑以代码的形式封装到服务消费者的客户端上,并且服务消费者客户端维护了一份服务提供者的信息列表。有了信息列表,通过负载均衡策略将请求分摊给多个服务提供者,从而达到负载均衡目的。Ribbon属于这一种。
目前 Netflix 公司用于生产环境的Ribbon子模块如下:
ribbon-loadbalancer:可以独立使用或与其它模块一起使用的负载均衡器API
ribbon-eureka:Ribbon结合Eureka客户端的API,为负载均衡器提供动态服务注册列表信息
ribbon-core:Ribbon的核心API
RestTemplate结合Ribbon消费服务 本案例直接从上一个案例中编写 首先启动服务注册中心eureka-server,端口为8761。然后启动两个Eureka-client,端口分别为8762、8763.(点击Edit Configurations,然后关闭右上角的Single instance only即可重复启动Springboot) 在上一个案例的基础上再创建一个Module工程,取名为eureka-ribbon-client,用它作为服务消费者,通过RestTemplate来远程调用eureka-client服务API接口的”/hi”. eureka-ribbon-client的pom文件如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 <?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 > top.code666</groupId > <artifactId > ribbon</artifactId > <version > 0.0.1-SNAPSHOT</version > <packaging > jar</packaging > <name > eureka-ribbon-client</name > <description > Demo project for Spring Boot</description > <parent > <groupId > com.eureka</groupId > <artifactId > eureka_study</artifactId > <version > 1.0-SNAPSHOT</version > </parent > <properties > <project.build.sourceEncoding > UTF-8</project.build.sourceEncoding > <project.reporting.outputEncoding > UTF-8</project.reporting.outputEncoding > <java.version > 1.8</java.version > </properties > <dependencies > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-eureka</artifactId > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-ribbon</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-test</artifactId > <scope > test</scope > </dependency > </dependencies > <build > <plugins > <plugin > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-maven-plugin</artifactId > </plugin > </plugins > </build > </project >
在工程的配置文件application.yml做程序相关配置,包括制定程序名为eureka-ribbon-client,程序的端口,服务的地址,代码如下
1 2 3 4 5 6 7 8 9 spring: application: name: eureka-ribbon-client server: port: 8764 eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/
作为Eureka-client需要在程序入口类加上注解@EnableEurekaClient开启Eureka Client功能。(这里代码就不列出来了) 再写一个RESTful-api接口,在该接口内部调用另外两个eureka-client的API接口”/hi”,既服务消费。在调用eureka-client的API接口”/hi”时希望做到轮流访问这两个实例时,就需要将RestTemplate和Ribbon相结合,进行负载均衡。只需要在程序的IOC容器找那个注入一个restTemplate的Bean,并在这个Bean上加上@LoadBalanced注解,此时RestTemplate就结合Ribbon开启了负载均衡功能,如下:
1 2 3 4 5 6 7 8 @Configuration public class RibbonConfig { @Bean @LoadBalanced RestTemplate restTemplate () { return new RestTemplate (); } }
写一个Service类,在该类中用restTemplate调用rureka-client的API接口,此时Uri上不需要使用硬编码(IP地址)只需要写服务名即可,如下:
1 2 3 4 5 6 7 8 @Service public class RibbonService { @Autowired RestTemplate restTemplate; public String hi (String name) { return restTemplate.getForObject("http://eureka-client/hi?name=" +name,String.class); } }
再写一个Controller类,代码如下:
1 2 3 4 5 6 7 8 9 @RestController public class RibbonController { @Autowired RibbonService ribbonService; @GetMapping("/hi") public String hi (@RequestParam(required = false,defaultValue = "wangsiyuan") String name) { return ribbonService.hi(name); } }
启动eureka-ribbon-client工程,在浏览器上访问localhost:8761,会显示有两个服务被注册,其中eureka-client有两个实例,端口为8762和8763,而eureka-ribbon-client的端口为8764. 然后在浏览器多次访问localhost:8764/hi?name=wsy的API接口时,会发现浏览器轮流显示不同的内容。此时负载均衡已经起了作用,它会轮流的请求eureka-client的两个实例中的”/hi”API接口。
LoadBalancerClient简介 负载均衡器的核心类为LoadBalancerClient,它可以获取负载均衡的服务提供者的实例信息。为了演示,在RibbonController重写一个接口”/testRibbon”,通过LoadBalancerClient去选择一个eureka-client的服务实例信息,并将该信息返回,代码如下:
1 2 3 4 5 6 7 8 ... @Autowired private LoadBalancerClient loadBalancerClient; @GetMapping("testRibbon") public String testRibbon () { ServiceInstance instance = loadBalancerClient.choose("stores" ); return instance.getHost()+":" +instance.getPort(); }
修改application.yml
1 2 3 4 5 6 7 8 9 stores: ribbon: listOfServers: example.com,code666.top,google.com ribbon: eureka: enabled: false server: port: 8769
启动工程,在浏览器上多次访问localhost:8769/testRibbon,浏览器会交替出现以下内容:
example.com:80 code666.top:80 google.com:80
由此可知,在Ribbon中的负载均衡客户端LoadBalancerClient。在Spring Cloud项目中,负载均衡器Ribbon会默认从Eureka Client的服务注册列表中获取服务的信息,并缓存一份。根据缓存的服务注册列表信息,可以通过LoadBalancerClient来选择不同的服务实例,从而实现负载均衡。如果禁止Ribbon从Eureka获取注册列表信息,则需要自己去维护一份服务注册列表信息。根据自己维护服务注册列表的信息,Ribbon 也可以实现负载均衡。
源码解析 TODO