Ribbon实现客户端侧负载均衡
5.1. Ribbon简介
Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。
Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer
后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们也很容易
使用Ribbon实现自定义的负载均衡算法。简单地说,Ribbon是一个客户端负载均衡器。
Ribbon工作时分为两步:
第一步先选择 Eureka Server, 它优先选择在同一个Zone且负载较少的Server;
第二步再根据用户指定的策略,在从Server取到的服务注册列表中选择一个地址。其中Ribbon提供了多种策略,例如轮询、随机、根据响应时间加权等。
5.2. 为服务消费者整合Ribbon
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> <artifactId>microservice-consumer-movie-ribbon</artifactId> <packaging>jar</packaging> <parent> <groupId>com.itmuch.cloud</groupId> <artifactId>microservice-spring-cloud</artifactId> <version>0.0.1-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.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies> </project>
实体类
package com.itmuch.cloud.entity; import java.math.BigDecimal; public class User { private Long id; private String username; private String name; private Short age; private BigDecimal balance; public Long getId() { return this.id; } public void setId(Long id) { this.id = id; } public String getUsername() { return this.username; } public void setUsername(String username) { this.username = username; } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public Short getAge() { return this.age; } public void setAge(Short age) { this.age = age; } public BigDecimal getBalance() { return this.balance; } public void setBalance(BigDecimal balance) { this.balance = balance; } }
Controller类
package com.itmuch.cloud.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.itmuch.cloud.entity.User; @RestController public class MovieController { @Autowired private RestTemplate restTemplate; @GetMapping("/movie/{id}") public User findById(@PathVariable Long id) { return this.restTemplate.getForObject("http://microservice-provider-user/simple/" + id, User.class); } }
启动类
package com.itmuch.cloud; 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.cloud.netflix.ribbon.RibbonClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.FilterType; import org.springframework.web.client.RestTemplate; @SpringBootApplication @EnableEurekaClient public class RibbonApplication { @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(RibbonApplication.class, args); } }
配置文件
spring: application: name: microservice-consumer-movie-ribbon server: port: 8010 eureka: client: healthcheck: enabled: true serviceUrl: defaultZone: http://user:password123@localhost:8761/eureka instance: prefer-ip-address: true
访问路径:
5.3. 使用Java代码自定义Ribbon配置
Spring Cloud还允许通过使用@RibbonClient
声明其他配置(位于RibbonClientConfiguration
之上)来完全控制客户端。例:
启动类
package com.itmuch.cloud; 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.cloud.netflix.ribbon.RibbonClient; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; import com.itmuch.config.TestConfiguration; @SpringBootApplication @EnableEurekaClient @RibbonClient(name="microservice-provider-user",configuration=TestConfiguration.class) public class RibbonApplication { @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(RibbonApplication.class, args); } }
package com.itmuch.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.netflix.client.config.IClientConfig; import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.RandomRule; @Configuration public class TestConfiguration { @Autowired IClientConfig config; @Bean public IRule ribbonRule(IClientConfig config) { return new RandomRule(); } }
图文:
111--->172.20.10.4:7900:microservice-provider-user 222--->172.20.10.4:7801:microservice-provider-user2 111--->172.20.10.4:7901:microservice-provider-user 222--->172.20.10.4:7800:microservice-provider-user2 111--->172.20.10.4:7900:microservice-provider-user 222--->172.20.10.4:7801:microservice-provider-user2 111--->172.20.10.4:7900:microservice-provider-user 222--->172.20.10.4:7800:microservice-provider-user2 111--->172.20.10.4:7900:microservice-provider-user 222--->172.20.10.4:7801:microservice-provider-user2 111--->172.20.10.4:7900:microservice-provider-user 222--->172.20.10.4:7800:microservice-provider-user2 111--->172.20.10.4:7900:microservice-provider-user 222--->172.20.10.4:7801:microservice-provider-user2 111--->172.20.10.4:7901:microservice-provider-user 222--->172.20.10.4:7800:microservice-provider-user2 111--->172.20.10.4:7900:microservice-provider-user 222--->172.20.10.4:7801:microservice-provider-user2 111--->172.20.10.4:7900:microservice-provider-user 222--->172.20.10.4:7800:microservice-provider-user2 111--->172.20.10.4:7900:microservice-provider-user 222--->172.20.10.4:7801:microservice-provider-user2 111--->172.20.10.4:7900:microservice-provider-user 222--->172.20.10.4:7800:microservice-provider-user2 111--->172.20.10.4:7901:microservice-provider-user 222--->172.20.10.4:7801:microservice-provider-user2 111--->172.20.10.4:7900:microservice-provider-user 222--->172.20.10.4:7800:microservice-provider-user2 111--->172.20.10.4:7900:microservice-provider-user 222--->172.20.10.4:7801:microservice-provider-user2 111--->172.20.10.4:7900:microservice-provider-user 222--->172.20.10.4:7800:microservice-provider-user2 111--->172.20.10.4:7901:microservice-provider-user 222--->172.20.10.4:7801:microservice-provider-user2 111--->172.20.10.4:7901:microservice-provider-user 222--->172.20.10.4:7800:microservice-provider-user2
5.4. 使用属性自定义Ribbon配置
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> <artifactId>microservice-consumer-movie-ribbon-config</artifactId> <packaging>jar</packaging> <parent> <groupId>com.itmuch.cloud</groupId> <artifactId>microservice-spring-cloud</artifactId> <version>0.0.1-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.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies> </project>
配置文件
spring: application: name: microservice-consumer-movie-ribbon-config server: port: 8010 eureka: client: healthcheck: enabled: true serviceUrl: defaultZone: http://user:password123@localhost:8761/eureka instance: prefer-ip-address: true microservice-provider-user: ribbon: NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule
实体类
package com.itmuch.cloud.entity; import java.math.BigDecimal; public class User { private Long id; private String username; private String name; private Short age; private BigDecimal balance; public Long getId() { return this.id; } public void setId(Long id) { this.id = id; } public String getUsername() { return this.username; } public void setUsername(String username) { this.username = username; } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public Short getAge() { return this.age; } public void setAge(Short age) { this.age = age; } public BigDecimal getBalance() { return this.balance; } public void setBalance(BigDecimal balance) { this.balance = balance; } }
Controller类
package com.itmuch.cloud.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; 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.itmuch.cloud.entity.User; @RestController public class MovieController { @Autowired private RestTemplate restTemplate; @Autowired private LoadBalancerClient loadBalancerClient; @GetMapping("/movie/{id}") public User findById(@PathVariable Long id) { return this.restTemplate.getForObject("http://microservice-provider-user/simple/" + id, User.class); } @GetMapping("/test") public String test(){ ServiceInstance serviceInstance=this.loadBalancerClient.choose("microservice-provider-user"); System.out.println("cyj:--->"+serviceInstance.getHost()+":"+serviceInstance.getPort()+":"+serviceInstance.getServiceId()); ServiceInstance serviceInstance2=this.loadBalancerClient.choose("microservice-provider-user2"); System.out.println("lxq:--->"+serviceInstance2.getHost()+":"+serviceInstance2.getPort()+":"+serviceInstance2.getServiceId()); return "1"; } }
图文
5.5. 脱离Eureka使用Ribbon
Eureka是一种方便的方式来抽象远程服务器的发现,因此您不必在客户端中对其URL进行硬编码,
但如果您不想使用它,Ribbon和Feign仍然是适用的。假设您已经为“商店”申请了@RibbonClient
,
并且Eureka未被使用(甚至不在类路径上)。Ribbon客户端默认为已配置的服务器列表,
您可以提供这样的配置
stores: ribbon: listOfServers: example.com,google.com
在Ribbon中禁用Eureka使用
ribbon: eureka: enabled: false
设置属性ribbon.eureka.enabled = false
将明确禁用在Ribbon中使用Eureka。
spring: application: name: microservice-consumer-movie-ribbon-config server: port: 8010 eureka: client: healthcheck: enabled: true serviceUrl: defaultZone: http://user:password123@localhost:8761/eureka instance: prefer-ip-address: true ribbon: eureka: enabled: false microservice-provider-user: ribbon: listOfServers: localhost:7800