一、Ribbon簡介:
Ribbon是一個為客戶端提供負載均衡功能的服務,它內部提供了一個叫做ILoadBalance的接口代表負載均衡器的操作,比如有添加服務器操作、選擇服務器操作、獲取所有的服務器列表、獲取可用的服務器列表等等。
需要解決的問題:
- ① 如何在配置Eureka Client注冊中心時不去硬編碼Eureka Server的地址?
- ② 在微服務不同模塊間進行通信時,如何不去硬編碼服務提供者的地址?
- ③ 當部署多個相同微服務時,如何實現請求時的負載均衡?
Ribbon是什么?

二、SpringCloud之Ribbon入門案例
<!-- eureka包含Ribbon依賴jar包 spring-cloud-netflix-ribbon--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
② 如何使用Ribbon
@Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); }
③ 如何解決硬編碼
使用添加@LoadBalanced注解后的RestTemplate調用服務提供者的接口時,可以使用虛擬IP替代真實IP地址。所謂的虛擬IP就是服務提供者在application.properties或yml文件中配置的spring.application.name屬性的值。示例如下:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import com.qxj.cloud.entity.User; @RestController public class MovieController { @Autowired private RestTemplate restTemplate; @RequestMapping(value="/movie/{id}",method = RequestMethod.GET,produces="application/json;charset=UTF-8") public User findById(@PathVariable Long id) {
//微服務的虛擬id http://provider-user User user = this.restTemplate.getForObject("http://provider-user:7900/simple/" + id, User.class); return user; } }
小總結:Ribbon和Eureka整合后Consumer可以直接調用服務而不用再關心ip地址和端口號
微服務(服務提供者)集群搭建:機器1
server:
port: 7900
spring:
application:
name: provider-user
#eureka客戶端連接配置
eureka:
client:
service-url:
#注冊中心地址
defaultZone: http://user:password123@localhost:8761/eureka
instance:
#將ip注冊到eureka上
prefer-ip-address: true
#微服務向eureka注冊實例名${spring.cloud.client.ip-address} 表示ip地址
instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${spring.application.instance_id:${server.port}}
機器2
server:
port: 7901
spring:
application:
name: provider-user
#eureka客戶端連接配置
eureka:
client:
service-url:
#注冊中心地址
defaultZone: http://user:password123@localhost:8761/eureka
instance:
#將ip注冊到eureka上
prefer-ip-address: true
#微服務向eureka注冊實例名${spring.cloud.client.ip-address} 表示ip地址
instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${spring.application.instance_id:${server.port}}
機器3
server:
port: 7902
spring:
application:
name: provider-user
#eureka客戶端連接配置
eureka:
client:
service-url:
#注冊中心地址
defaultZone: http://user:password123@localhost:8761/eureka
instance:
#將ip注冊到eureka上
prefer-ip-address: true
#微服務向eureka注冊實例名${spring.cloud.client.ip-address} 表示ip地址
instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${spring.application.instance_id:${server.port}}
其中{Spring.application.name}都是一樣的,不可以變。
三、Ribbon組件IRule
默認的是RoundBobinRule(輪詢)
四、自定義負載均衡算法:
所謂的自定義Ribbon Client的主要作用就是使用自定義配置替代Ribbon默認的負載均衡策略,注意:自定義的Ribbon Client是有針對性的,一般一個自定義的Ribbon Client是對一個服務提供者(包括服務名相同的一系列副本)而言的。自定義了一個Ribbon Client 它所設定的負載均衡策略只對某一特定服務名的服務提供者有效,但不能影響服務消費者與別的服務提供者通信所使用的策略。根據官方文檔的意思,推薦在 springboot 主程序掃描的包范圍之外進行自定義配置類。其實純代碼自定義RibbonClient的話有兩種方式:
方式一:在springboot主程序掃描的包外定義配置類,然后為springboot主程序添加 @RibbonClient 注解引入配置類。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.qxj.configuration.MySelfRule; @SpringBootApplication //該注解表明應用既作為eureka實例又為eureka client 可以發現注冊的服務 @EnableEurekaClient //在啟動該微服務的時候就能去加載我們的自定義Ribbon配置類,從而使配置生效 @RibbonClient(name = "provider-user",configuration = MySelfRule.class) public class ConsumerMovieRibbonApplication { @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(ConsumerMovieRibbonApplication.class, args); } }
Rule配置文件類,配置類不應該在SpringBoot的包路徑下,通過@RibbonClient 注解加載:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.netflix.loadbalancer.IRule; @Configuration public class MySelfRule { @Bean public IRule MyRule() { return new RandomRule_QXJ(); } }
自定義LoadBalance:
import java.util.List; import com.netflix.client.config.IClientConfig; import com.netflix.loadbalancer.AbstractLoadBalancerRule; import com.netflix.loadbalancer.ILoadBalancer; import com.netflix.loadbalancer.Server; public class RandomRule_QXJ extends AbstractLoadBalancerRule{ private int total = 0; // 總共被調用的次數,目前要求每台被調用5次 private int currentIndex = 0; // 當前提供服務的機器號 /** * 服務選擇算法,要求每台被調用5次 * @param lb * @param key * @return */ public Server choose(ILoadBalancer lb,Object key) { if(lb == null) { return null; } Server server = null; while(server == null) { //判斷當前線程是否中斷 //interrupted()是靜態方法:內部實現是調用的當前線程的isInterrupted(),並且會重置當前線程的中斷狀態 if(Thread.interrupted()) { return null; } //激活可用的服務 List<Server> upList = lb.getReachableServers(); //所有的服務 List<Server> allList = lb.getAllServers(); int serverCount = allList.size(); if(serverCount == 0) { return null; } if(total < 5) { server = upList.get(currentIndex); total++; }else { total=0; //使用下一台機器服務 currentIndex++; //若當前服務機器為upList集合里最后一台,重新使用第一台機器服務 if(currentIndex >= upList.size()) { currentIndex=0; } } System.out.println("currentIndex:" + currentIndex +"---total:"+total); //循環到第一台服務時,server==null,需要重新獲取server if(server == null) { Thread.yield(); continue; } if(server.isAlive()) { return server; } //該代碼實際上不會執行 server = null; Thread.yield(); } return server; } @Override public Server choose(Object key) { return choose(getLoadBalancer(),key); } @Override public void initWithNiwsConfig(IClientConfig clientConfig) { } }
方式二:application.yml文件配置方式
#@RibbonClient(name = "provider-user") 與name相同,表示針對該微服務使用自定義負載均衡規則
provider-user:
ribbon:
NFLoadBalancerRuleClassName: com.qxj.configuration.RandomRule_QXJ
配置的優先級
配置文件的優先級 > java代碼的配置方式 > netflix自定義的配置方式
版權聲明:本文為CSDN博主「安小岩說他很忙」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/JinXYan/java/article/details/90726707