SpringCloud筆記(三)使用DiscoveryClient手動實現客戶端負載均衡
1、什麼是客戶端負載均衡(Ribbon)?
Ribbon是從eureka註冊中心伺服器端上獲取服務註冊資訊列表,快取到本地,然後在本地實現輪訓負載均衡策略。既在客戶端實現負載均衡。
2、什麼是服務端負載均衡(Nginx)?
Nginx是客戶端所有請求統一交給Nginx,由Nginx進行實現負載均衡請求轉發,屬於伺服器端負載均衡。 即請求由Nginx伺服器端進行轉發。
3、兩者的應用場景?
Nginx適合於伺服器端實現負載均衡 比如Tomcat ,Ribbon適合在微服務中RPC遠端呼叫實現本地服務負載均衡,比如Dubbo、SpringCloud中都是採用本地負載均衡。
4、SpringCloud中如何使用客戶端負載均衡?
在springcloud中使用客戶端的負載均衡非常簡單,在之前的部落格中已經提到過(SpringCloud筆記(一)服務註冊與發現),只需要在服務呼叫方配置如下
@Bean @LoadBalanced //就能讓這個RestTemplate在請求時擁有客戶端負載均衡的能力 public RestTemplate restTemplate() { return new RestTemplate(); } @RestController public class OrderController { @Autowired private RestTemplate restTemplate; @RequestMapping("/getorder") public String getOrder() { // order 使用rpc 遠端呼叫技術 呼叫 會員服務restTemplate String memberUrl = "http://app-producer/getMember"; String result = restTemplate.getForObject(memberUrl, String.class); System.out.println("會員服務呼叫訂單服務,result:" + result); return result; } }
由於restTemplate開啟了@LoadBalance註解,因此就開啟了本地負載均衡策略。
當服務呼叫方拿著服務別名呼叫其他服務時,會首先在註冊中心根據別名查詢對應的服務地址列表,查詢到後首先會快取在本地JVM中,預設會每隔30s重新整理一次。之後在服務地址列表中根據負載均衡策略選取一個地址,在底層通過HttpClient進行遠端呼叫。
4、如何使用DiscoveryClient手動實現客戶端負載均衡?
我們可以根據DiscoveryClient獲取註冊中心的服務列表,因此可以使用DiscoveryClient手動實現本地負載均衡。
@Autowired private DiscoveryClient discoveryClient;
使用DiscoveryClient的前提是
a、關閉restTemplate的@LoadBalance註解,負載均衡邏輯由我們手動控制。
b、關閉自我保護機制:保證不可用的服務能夠被及時踢出
自我保護機制的工作機制是如果在15分鐘內超過85%的客戶端節點都沒有正常的心跳,那麼Eureka就認為客戶端與註冊中心出現了網路故障,Eureka Server自動進入自我保護機制,此時會出現以下幾種情況:
(1)Eureka Server不再從註冊列表中移除因為長時間沒收到心跳而應該過期的服務。
(2)Eureka Server仍然能夠接受新服務的註冊和查詢請求,但是不會被同步到其它節點上,保證當前節點依然可用。
(3)當網路穩定時,當前Eureka Server新的註冊資訊會被同步到其它節點中。
下來改造SpringCloud筆記(一)服務註冊與發現中的專案:
首先在eureka-sever的application,yml中關閉自我保護
#埠號
server:
port: 8100
eureka:
instance:
#註冊到本地地址
hostname: 127.0.0.1
client:
serviceUrl:
#客戶端訪問的路徑
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
#自己就是註冊中心,不需要註冊自己
register-with-eureka: false
#自己就是註冊中心,不需要檢索自己
fetch-registry: false
server:
# 測試時關閉自我保護機制,保證不可用服務及時踢出
enable-self-preservation: false
eviction-interval-timer-in-ms: 2000
對應的在springcloud-producer的application.yml中配置如下:
spring:
application:
name: app-producer
server:
port: 8005
eureka:
client:
service-url:
defaultZone: http://localhost:8100/eureka/
register-with-eureka: true
fetch-registry: true
instance:
#Eureka服務端在收到最後一次心跳之後等待的時間上限,單位為秒,超過則剔除(客戶端告訴服務端按照此規則等待自己)
lease-expiration-duration-in-seconds: 2
##Eureka客戶端向服務端傳送心跳的時間間隔,單位為秒(客戶端告訴服務端自己會按照該規則)
lease-renewal-interval-in-seconds: 1
對應的在springcloud-consumer的application.yml中配置如下
spring:
application:
name: app-consumer
server:
port: 8001
eureka:
client:
service-url:
defaultZone: http://localhost:8100/eureka/ #註冊中心地址
register-with-eureka: true
fetch-registry: true
instance:
#Eureka服務端在收到最後一次心跳之後等待的時間上限,單位為秒,超過則剔除(客戶端告訴服務端按照此規則等待自己)
lease-expiration-duration-in-seconds: 2
##Eureka客戶端向服務端傳送心跳的時間間隔,單位為秒(客戶端告訴服務端自己會按照該規則)
lease-renewal-interval-in-seconds: 1
之後在springcloud-consumer中自定義負載均衡邏輯:
/**
* 自定義實現客戶端負載均衡
*/
@RestController
public class ExtRibbonController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
//初始化請求數
private AtomicInteger requestCnt = new AtomicInteger(1);
@RequestMapping("/ribbon")
public String ribbon() {
//1、選取一個服務地址
String serviceUrl = getServiceUrl() + "/getMember";
//2、遠端呼叫
return restTemplate.getForObject(serviceUrl, String.class);
}
//本地負載均衡核心程式碼
private String getServiceUrl() {
//在註冊中心獲取app-producer對應的服務列表
List<ServiceInstance> list = discoveryClient.getInstances("app-producer");
if(list == null && list.size() == 0) {
return null;
}
//獲取服務列表的數量
int serviceSize = list.size();
//請求數 % 服務列表數量 得到下標
int index = requestCnt.get() % serviceSize;
//將請求數增加1
requestCnt.incrementAndGet();
//根據計算的下標選取一個服務地址返回
return list.get(index).getUri().toString();
}
}
啟動類:關閉掉自動負載均衡策略
@SpringBootApplication
@EnableEurekaClient
public class SpringcloudConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringcloudConsumerApplication.class, args);
}
@Bean
//@LoadBalanced 在編寫自定義負載均衡時,關閉此註解
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
啟動eureka-sever
啟動springcloud-producer 更改埠後,再啟動一個例項
啟動springcloud-consumer
此時註冊中心的服務列表如下:
現在訪問APP-CONSUMER中我們自己實現的負載均衡邏輯:http://localhost:8001/ribbon
第一次訪問:
第二次訪問:
可以看到自己實現的負載均衡策略發揮處理本地負載均衡的策略!