spring cloud 之 ribbon介紹
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>