ribbon是負責負載均衡的,屬於進程內負載均衡。請求發送到ribbon然后由ribbon發送到各個服務.
服務端負載均衡:Nginx與F5集中式負載均衡指位於因特網與服務提供者之間,並負責把網絡請求轉發到各個提供單位.
進程內負載均衡是指從一個實例庫選取一個實例進行流量導入,在微服務的范疇內,實例庫一般是存儲在Eureka、Consul、Zookeeper、etcd這樣的注冊中心,而此時的負載均衡器就是類似Ribbon的IPC(Inter-Process Communication,進程間通信)組件,因此,進程內負載均衡也叫作客戶端負載均衡
Ribbon負載均衡策略
可以在java配置文件中配置自己需要的負載均衡策略如:
也可以在yml文件中配置負載均衡的實現類:(注意:yml的配置高於java配置文件,若同時配置了Java和yml則會選擇yml的配置)
bootstrap.yml中配置ribbon的其他配置:
ribbon默認是懶加載,所以第一次請求會慢很多(它需要從注冊中心拿取服務實例列表,在進行自身策略的調整),為了避免這個問題使懶加載變為餓加載讓其在項目啟動時就加載,我們采用如下配置:
ribbon1.2.0之后的版本支持了yml配置ribbon的行為,也就是說通過配置文件能決定讓ribbon使用哪些實現類來完成負載均衡:
ribbon各個功能的接口:這些接口在用到的時候可查有哪些實現類,若有興趣也可自己實現具體實現類來配置。
自定義配置實現類的列表:
配置具體功能的實現類如:
由於ribbon因為是以eureka client的身份去連接eureka server,從而拿到各個服務實例的列表去做負載均衡,所以當eureka server是一個社區型的公共注冊中心時,可能下面的實例有的是你不需要的。這時候就沒必要從eureka server來拿服務實例了,可自行配置需要的服務實例如下配置:
1.先關掉從eureka那服務實例列表的開關:
2.在配置需要做負載均衡的實例:
代碼:
啟動類:負載均衡依靠@LoadBalanced注解修飾過的RestTemplate來實現。具體原理可通過源碼@loadBalanced注解內部注釋或網上介紹查看。
package cn.springcloud.book; 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.cloud.netflix.ribbon.RibbonClient; import org.springframework.cloud.netflix.ribbon.RibbonClients; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.FilterType; import org.springframework.web.client.RestTemplate; import cn.springcloud.book.config.AvoidScan; import cn.springcloud.book.config.TestConfiguration; @SpringBootApplication @EnableDiscoveryClient @RibbonClient(name = "client-a", configuration = TestConfiguration.class) //@RibbonClients(value = { // @RibbonClient(name = "client-a", configuration = TestConfiguration.class), // @RibbonClient(name = "client-b", configuration = TestConfiguration.class) //}) @ComponentScan(excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = {AvoidScan.class})}) public class RibbonLoadbalancerApplication { public static void main(String[] args) { SpringApplication.run(RibbonLoadbalancerApplication.class, args); } @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } }
自定義注解:該注解是個空注解,主要是為了讓啟動類中的掃描注解過濾掉改擁有該注解的類。
package cn.springcloud.book.config; public @interface AvoidScan { }
配置類:
package cn.springcloud.book.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 @AvoidScan public class TestConfiguration { @Autowired IClientConfig config; @Bean public IRule ribbonRule(IClientConfig config) { return new RandomRule(); } }
controller類:該類是接收外部請求,拿到請求后先確定是哪個服務,之后在負載均衡到該服務下的某個服務實例上。
package cn.springcloud.book.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.RestController; import org.springframework.web.client.RestTemplate; @RestController public class TestController { @Autowired private RestTemplate restTemplate; @Autowired private LoadBalancerClient lbClient; @GetMapping("/add") public String adda(Integer a, Integer b) { String result = restTemplate .getForObject("http://CLIENT-A/add?a=" + a + "&b=" + b, String.class); System.out.println(result); return result; } @GetMapping("/add1") public void add1(Integer a, Integer b) { ServiceInstance instance = this.lbClient.choose("client-a"); System.out.println(instance.getHost()+":"+instance.getPort()); } @GetMapping("/add2") public void add2(Integer a, Integer b) { ServiceInstance instance = this.lbClient.choose("client-b"); System.out.println(instance.getHost()+":"+instance.getPort()); } }
bootstrap.yml
spring:
application:
name: ribbon-loadbalancer
server:
port: 7777
eureka:
client:
serviceUrl:
defaultZone: http://${eureka.host:127.0.0.1}:${eureka.port:8888}/eureka/
instance:
prefer-ip-address: true
#client-a:
# ribbon:
# ConnectTimeout: 3000
# ReadTimeout: 60000
# MaxAutoRetries: 1 #對第一次請求的服務的重試次數
# MaxAutoRetriesNextServer: 1 #要重試的下一個服務的最大數量(不包括第一個服務)
# OkToRetryOnAllOperations: true
# NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule#
#ribbon:
# eager-load:
# enabled: true
# clients: client-a, client-b, client-c
pom.xml
<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> <parent> <groupId>cn.springcloud.book</groupId> 父類為spring boot 2.0.0 <artifactId>ch5-2</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <artifactId>ch5-2-ribbon-loadbalancer</artifactId> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>