SpringCloud客戶端負載均衡——Ribbon
Ribbon——A ribbon is a long, narrow piece of cloth that you use for tying things together or as a decoration.
Ribbon是一個工具類框架,不需要獨立部署。
負載均衡裝置/負載均衡軟體模組都會維護一個可用的服務清單,透過心跳檢測來剔除故障節點,保證清單中都是可用節點。
客戶端負載均衡,由客戶端節點維護要訪問的服務清單,服務清單來自於註冊中心。
如前所示,使用客戶端負載均衡呼叫分兩步:
1. 服務提供者註冊到服務中心。
2. 服務消費者透過標有@LoadBalanced註解的RestTemplate進行服務呼叫。
在service-consumer服務中,透過呼叫RestTemplate的getForEntity方法,GET呼叫hello-service的/hello介面。
RestTemplate
GET
RestTemplate有兩類GET實現:getForEntity和getForObject。
getForEntity()有三個過載實現,均返回ResponseEntity,
// url為請求地址,responseType為響應體body的型別,uriVariables為url引數
// uriVariables配合url中的佔位符進行動態傳參,如:
// entity = getForEntity("{1}", String.class, "John");,將John傳給引數name
public ResponseEntity getForEntity(String url, Class responseType, Object... uriVariables) throws RestClientException {
RequestCallback requestCallback = acceptHeaderRequestCallback(responseType); // new AcceptHeaderRequestCallback(responseType)
ResponseExtractor> responseExtractor = responseEntityExtractor(responseType); // new ResponseEntityResponseExtractor<>(responseType)
return nonNull(execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables));
}
// uriVariables為Map型別,key需要與url中的佔位符對應,如:
// params.put("myname", "John");
// entity = getForEntity("{myname}", String.class, params); 將key為myname對應的value——John傳給name
public ResponseEntity getForEntity(String url, Class responseType, Map uriVariables);
// 使用URI物件代替url和uriVariables
public ResponseEntity getForEntity(URI url, Class responseType);
// 使用:
ResponseEntity entity = restTemplate.getForEntity(url, String.class, "John");
String body = entity.getBody();
ResponseEntity entity = restTemplate.getForEntity(url, User.class, "John");
User body = entity.getBody();
getForObject()也有三個過載實現,傳入execute方法的不是ResponseExtractor,而是HttpMessageConverterExtractor,返回的則是物件型別,三個過載和getForEntity的三個過載關係類似:
public T getForObject(String url, Class responseType, Object... uriVariables) throws RestClientException {
RequestCallback requestCallback = acceptHeaderRequestCallback(responseType); // new AcceptHeaderRequestCallback(responseType)
HttpMessageConverterExtractor responseExtractor = new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);
}
public T getForObject(String url, Class responseType, Map uriVariables);
public T getForObject(URI url, Class responseType);
// 使用:
String result = restTemplate.getForObject(url, String.class, "John");
User user = restTempleate.getForObject(url, User.class, "John");
// 使用getForObject可以省略從response中獲取body的步驟
POST
RestTemplate有三類POST實現:postForEntity和postForObject,postForLocation。
postForEntity()有三個過載實現,均返回ResponseEntity,
// 相較於getForEntity,新增引數Object request,reqeust如果是HttpEntity物件,RestTemplate將其當作完整的http請求物件處理,request中包含了header和body的內容。如果request是普通物件,RestTemplate將其轉換為HttpEntity來處理,request作為body。
// if (request instanceof HttpEntity){this.requestEntity = (HttpEntity) request; }
// else if (requestBody != null) { this.requestEntity = new HttpEntity<>(request); }
// else { this.requestEntity = HttpEntity.EMPTY; }
// 使用:
// User user = new User("didi", 30);
// entity = postForEntity(" user, String.class, "John");,將John傳給引數name
public ResponseEntity postForEntity(String url, Object request, Class responseType, Object... uriVariables) throws RestClientException {
RequestCallback requestCallback = httpEntityCallback(request, responseType); // new HttpEntityRequestCallback(requestBody, responseType)
ResponseExtractor> responseExtractor = responseEntityExtractor(responseType); // new ResponseEntityResonseExtracor<>(responseType)
return nonNull(execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables));
}
public ResponseEntity postForEntity(String url, Object request, Class responseType, Map uriVariables);
public ResponseEntity postForEntity(URI url, Object request, Class responseType);
postForObject()也有三個過載實現,傳入execute方法的不是ResponseExtractor,而是HttpMessageConverterExtractor,返回的則是物件型別,三個過載和postForEntity的三個過載關係類似:
public T postForObject(String url, Object request, Class responseType, Object... uriVariables) throws RestClientException {
RequestCallback requestCallback = httpEntityCallback(request, responseType);
HttpMessageConverterExtractor responseExtractor = new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
}
public T postForObject(String url, Object request, Class responseType, Map uriVariables);
public T postForObject(URI url, Object request, Class responseType);
postForLocation()用於傳送post請求,返回新資源的URI,有三個過載實現,均返回URI物件,
public URI postForLocation(String url, Object request, Object... uriVariables) throws RestClientException {
RequestCallback requestCallback = httpEntityCallback(request); // new HttpEntityRequestCallback(request, null)
HttpHeaders headers = execute(url, HttpMethod.POST, requestCallback, headersExtractor(), uriVariables); // new HeadersExtractor()
return (headers != null ? headers.getLocation() : null);
}
public URI postForLocation(String url, Object request, Map uriVariables);
public URI postForLocation(URI url, Object ruquest);
execute
RestTemplate中,不同的請求方式,最終會呼叫到execute的三個過載實現上來
// ------------------------------------
public T execute(String url, HttpMethod method, RequestCallback requestCallback, ResponseExtractor responseExtractor, Object... uriVariables) {
URI expanded = getUriTemplateHandler().expand(url, uriVariables);
return doExecute(expanded, method, requestCallback, responseExtractor);
}
public T execute(String url, HttpMethod method, RequestCallback requestCallback, ResponseExtractor responseExtractor, Map uriVariables);
public T execute(URI url, HttpMethod method, RequestCallback requestCallback, ResponseExtractor responseExtractor);
execute()的三個過載實現,都會呼叫doExecute()方法,去執行請求
protected T doExecute(URI url, HttpMethod method, RequestCallback requestCallback, ResponseExtractor responseExtractor) throws RestClientException {
ClientHttpResponse response = null;
ClientHttpRequest request = createRequest(url, method);
if (requestCallback != null) { requestCallback.doWithRequest(request); }
response = request.execute();// 此處執行前會被攔截
handleResponse(url, method, response);
return (responseExtractor != null ? responseExtractor.extractData(response) : null);
}
doExecute()方法接收的引數中,有RequestCallback和ResponseExtractor。
RequestCallback
AcceptHeaderRequestCallback implements RequestCallback // AcceptHeaderRequestCallback用於GET請求
HttpEntityRequestCallback extends AcceptHeaderRequestCallback // HttpEntityRequestCallback 用於POST、PUT等請求
ResponseEntity
// ResponseEntity擴充套件自HttpEntity,增加了http的status(http請求狀態碼)
package org.springframework.http;
public class ResponseEntity extends HttpEntity {
private final Object status; // status為int或HttpStatus型別
// getter/setter...
}
// HttpEntity表示http的request或response的entity,包含headers(http請求的頭資訊)和body(http請求的請求體)
package org.springframework.http;
public class HttpEntity {
private final HttpHeaders headers;
private final T body;
// getter/setter...
}
@LoadBalanced
在服務消費者中,給RestTemplate新增了@LoadBalanced註解,根據註釋,該註解用於標記RestTemplate使用LoadBalancerClient來配置,即客戶端負載均衡器。
// Annotation to mark a RestTemplate bean to be configured to use a LoadBalancerClient.
public @interface LoadBalanced {}
LoadBalancerClient
客戶端負載均衡器,具有如下能力:
// Represents a client-side load balancer. 即客戶端負載均衡器
interface LoadBalancerClient extends ServiceInstanceChooser {
// 使用serviceId服務執行request請求
T execute(String serviceId, LoadBalancerRequest request) throws IOException;
T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest request) throws IOException;
// 將邏輯服務名 替換為host:port的形式
URI reconstructURI(ServiceInstance instance, URI original);
}
// 選擇一個server用來傳送請求的實現介面
interface ServiceInstanceChooser {
// 根據serviceId,從負載均衡器選擇一個服務例項ServiceInstance
ServiceInstance choose(String serviceId);
}
LoadBalancerClient有一個實現類RibbonLoadBalancerClient。
在RestTemplate的doExecute()方法中,呼叫request.execute()之前,會被LoadBalancerInterceptor攔截。該攔截器中有一個LoadBalancerClient例項,此外該攔截器在LoadBalancerAutoConfiguration中被建立。而LoadBalancerAutoConfiguration有兩個特殊的註解@ConditionalOnClass(RestTemplate.class)和@ConditionalOnBean(LoadBalancerClient.class),且註釋明確說明LoadBalancerAutoConfiguration為Ribbon的自動化配置類。
spring-cloud-commons的loadbalancer包中的配置類,以2.1.2為例
LoadBalancerAutoConfiguration:建立LoadBalancerInterceptor、建立RestTemplateCustomizer(匿名內部類)、建立LoadBalancerRequestFactory、建立SmartInitializingSingleton(匿名內部類)
AsyncLoadBalancerAutoConfiguration:針對AsyncRestTemplate做的類似配置
spring-cloud-netflix-ribbon中的幾個配置類,以2.1.2為例
RibbonClientConfiguration:建立IClientConfig、建立IRule,建立IPing,建立ServerList,建立ServerListUpdater,建立ILoadBalancer(使用ZoneAwareLoadBalancer實現),建立ServerListFilter、建立RibbonLoadBalancerContext,建立RetryHandler,建立ServerIntrospector
RibbonAutoConfiguration:建立HasFeatures,建立SpringClientFactory,建立LoadBalancerClient(使用RibbonLoadBalancerClient實現),建立LoadBalancedRetryFactory(使用RibbonLoadBalancedRetryFactory實現),建立PropertiesFactory,建立RibbonApplicationContextInitializer,建立RestTemplateCustomizer(使用匿名內部類),建立RibbonClientHttpRequestFactory
RestCilentRibbonConfiguration:建立RestClient
LoadBalancerAutoConfiguration
Ribbon的自動化配置類:
@Configuration
@ConditionalOnClass(RestTemplate.class) // 需要RestTemplate類在classpath中
@ConditionalOnBean(LoadBalancerClient.class) // 需要LoadBalancerClient的實現Bean在BeanFactory中
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
class LoadBalancerAutoConfiguration {
@LoadBalanced
@Autowired(required = false)
// 工程中註冊的RestTemplate的Bean會在此被載入
private List restTemplates = Collections.emptyList();
@Autowired(required = false)
private List transformers = Collections.emptyList();
// 建立SmartInitializingSingleton的Bean,負責用每個Customizer去修飾每個RestTemplate
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
ObjectProvider> restTemplateCustomizers) {
return () -> restTemplateCustomizers.ifAvailable(customizers -> {
for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
for (RestTemplateCustomizer customizer : customizers) {
customizer.customize(restTemplate);
}
}
});
}
@Configuration
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
static class LoadBalancerInterceptorConfig {
// 建立攔截器Bean,入參為客戶端負載均衡器
@Bean
public LoadBalancerInterceptor ribbonInterceptor(LoadBalancerClient loadBalancerClient, LoadBalancerRequestFactory requestFactory) {
return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}
// 建立一個RestTemplateCustomizer的Bean,負責將負載均衡攔截器加到入參RestTemplate的攔截器列表中,新增方式為get、add、set
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(final LoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List list = new ArrayList<>(restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
}
}
}
}
LoadBalancerInterceptor
負載均衡攔截器,用於在請求最終執行前進行攔截,在攔截器的intercept()方法中,首先從request中獲取服務名稱serviceName,然後呼叫request工廠的createRequest()方法,建立一個負載均衡的request——LoadBalancerRequest例項,最後將其連同serviceName一起作為LoadBalancerClient的execute()方法的入參。
class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
LoadBalancerClient loadBalancer;
LoadBalancerRequestFactory requestFactory;
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) {
// 此處呼叫request的getURI方法,
final URI originalUri = request.getURI();
String serviceName = originalUri.getHost();
return this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));
}
}
LoadBalancerRequestFactory——建立LoadBalancerRequest的工廠
public LoadBalancerRequest createRequest(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) {
// 返回LoadBalancerRequest的匿名內部類
return instance -> {
// 該LoadBalancerRequest的匿名內部類實現,先建立一個ServiceRequestWrapper的request,然後呼叫execution的execute方法執行請求
HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance, this.loadBalancer);
return execution.execute(serviceRequest, body);
};
}
LoadBalancerRequest
LoadBalancerRequest使用該介面的apply()的方法,為request新增處理動作
interface LoadBalancerRequest {
T apply(ServiceInstance instance);
}
ServiceRequestWrapper
ServiceRequestWrapper繼承自HttpRequestWrapper,HttpRequestWrapper對外提供了獲取一個request的method、URI、headers、methodValue等資訊的方法。
ServiceRequestWrapper改寫了預設的getURI()方法,使用客戶端負載均衡器LoadBalancerClient的重構URI的方法,將入參request的URI進行重構,其具體實現在LoadBalancerClient的實現類RibbonLoadBalancerClient中。
class ServiceRequestWrapper extends HttpRequestWrapper {
private final ServiceInstance instance;
private final LoadBalancerClient loadBalancer;
public ServiceRequestWrapper(HttpRequest request, ServiceInstance instance, LoadBalancerClient loadBalancer) {}
@Override
public URI getURI() {
// 呼叫loadBalancer的reconstructURI方法,進行URI重構,改寫成host:port的形式,具體實現在RibbonLoadBalancerClient中
return this.loadBalancer.reconstructURI(this.instance, getRequest().getURI());
}
}
RibbonLoadBalancerClient
RibbonLoadBalancerClient實現了LoadBalancerClient和ServiceInstanceChooser中的execute、reconstructURI、choose方法,完成了請求執行、URI重構和選擇服務例項的任務,execute
class RibbonLoadBalancerClient implements LoadBalancerClient {
SpringClientFactory clientFactory;
@Override
public URI reconstructURI(ServiceInstance instance, URI original) {
String serviceId = instance.getServiceId();
RibbonLoadBalancerContext context = this.clientFactory.getLoadBalancerContext(serviceId);
URI uri; Server server;
if (instance instanceof RibbonServer) {
server = ((RibbonServer) instance).getServer();
uri = updateToSecureConnectionIfNeeded(original, ribbonServer);
} else {
server = new Server(instance.getScheme(), instance.getHost(), instance.getPort());
IClientConfig clientConfig = clientFactory.getClientConfig(serviceId);
ServerIntrospector serverIntrospector = serverIntrospector(serviceId);
uri = updateToSecureConnectionIfNeeded(original, clientConfig, serverIntrospector, server);
}
// 用server中的host、port等替換原始uri
return context.reconstructURIWithServer(server, uri);
}
public ServiceInstance choose(String serviceId, Object hint) {
// 先呼叫getLoadBalancer方法,根據serviceId,獲取一個ILoadBalancer
// 然後呼叫getServer(ILoadBalancer loadBalancer, Object hint),使用loadBalancer選擇一個Server,hint預設為"default"
Server server = getServer(getLoadBalancer(serviceId), hint);
if (server == null) { return null; }
// 用入參serviceId、選擇的Server,構造一個RibbonServer
return new RibbonServer(serviceId, server, isSecure(server, serviceId), serverIntrospector(serviceId).getMetadata(server));
}
public T execute(String serviceId, LoadBalancerRequest request, Object hint) {
// 首先選擇一個RibbonServer,該部分流程與choose相同
Server server = getServer(getLoadBalancer(serviceId), hint);
RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(server, serviceId), serverIntrospector(serviceId).getMetadata(server));
// 呼叫execute的過載實現,執行請求
return execute(serviceId, ribbonServer, request);
}
public T execute(String serviceId, ServiceInstance serviceIntance, LoadBalancerRequest request) {
Server server = null;
if (serviceInstance instanceof RibbonServer) {
server = ((RibbonServer) serviceInstance).getServer();
}
RibbonLoadBalancerContext context = this.clientFactory.getLoadBalancerContext(serviceId);
RibbonStatsRecorder statsRecorder = new RibbonStatsRecorder(context, server);
try { 無錫做人流手術多少錢
// 呼叫apply,向服務例項發起請求
T returnVal = request.apply(serviceInstance);
statsRecorder.recordStats(returnVal);
return returnVal;
} catch (IOException ex) {
statsRecorder.recordStats(ex); throw ex;
} catch (Exception ex) {
statsRecorder.recordStats(ex); throw ex;
}
return null;
}
// Ribbon 實現了ServiceInstance介面,即服務例項介面
public static class RibbonServer implements ServiceInstance {
private final String serviceId;
private final Server server;
private final boolean secure;
private Map metadata;
// @Override方法
}
}
ILoadBalancer
在RibbonLoadBalancerClient的choose()和execute()方法中,都是透過呼叫ILoadBalancer的chooseServer()方法,來選擇一個服務例項Server的,該ILoadBalancer介面是由Ribbon定義的。
在ILoadBalancer介面中,定義了軟體負載均衡器的操作:一個服務例項的集合、標記一個服務停止、選擇服務
package com.netflix.loadbalancer;
interface ILoadBalancer {
void addServers(List newServers); // 初始化、後續新增服務列表
Server chooseServer(Object key); // 從負載均衡器選擇一個服務例項
void markServerDown(Server server); // 標記並通知某個服務例項已經停止
List getReachableServers(); // up/reachable狀態的服務例項,可以提供正常服務
List getAllServers(); // 所有已知的服務例項,reachable/unreachable都包括
}
其中的Server,代表一個服務端節點,包含了一個服務的基本資訊:host、port、scheme、id、zone、後設資料等等。
在RibbonLoadBalancerClient的choose()和execute()方法中,透過getLoadBalancer()方法,來根據serviceId獲取ILoadBalancer的例項,然後將其包裝成RibbonServer。
配置類RibbonClientConfiguration建立ILoadBalancer時如果配置檔案裡有配置,則使用配置的實現,否則預設使用ZoneAwareLoadBalancer實現。
ClientHttpRequestExecution
RibbonLoadBalancerClient的execute()方法中,呼叫了入參LoadBalancerRequest的apply方法,execute()方法在LoadBlancerInterceptor的intercept方法中呼叫,並傳入LoadBalancerRequestFactory.createRequest建立的LoadBalancerRequest實現,其實現中最終使用ClientHttpRequestExecution的execute方法執行請求。
總結
使用時,註冊一個使用@LoadBalanced註解修飾的RestTemplate,在需要發起請求的地方呼叫RestTemplate的相應的請求方法,最終呼叫到其doExecute方法。
@LoadBalanced註解關聯了LoadBalancerClient。
配置類LoadBalancerAutoConfiguration註冊瞭如下Bean:
SmartInitializingSingleton:遍歷restTemplates、遍歷customizers,並customizer.customize(restTemplate)
LoadBalancerRequestFactory:使用LoadBalancerClient構造
LoadBalancerInterceptor:使用LoadBalancerClient和LoadBalancerRequestFactory建立
RestTemplateCustomizer:使用LoadBalancerInterceptor構造一個匿名類,將註冊的LoadBalancerInterceptor新增進restTemplate的interceptors列表中
攔截器LoadBalancerInterceptor的intercept方法從原始請求中獲取URI,然後使用LoadBalancerClient的execute方法執行請求,接收兩個引數:serviceName即host和請求工廠建立的request
請求工廠LoadBalancerRequestFactory的createRequest方法,由原始請求建立一個LoadBalancerRequest的匿名實現
負載均衡請求LoadBalancerRequest介面只有apply方法,其匿名實現建立HttpRequest的實現類ServcieRequestWrapper的例項,然後由ClientHttpRequestExecution的execute方法執行請求,返回響應ClientHttpResponse
ServiceRequestWrapper重寫了父類HttpRequestWrapper的getURI方法,返回LoadBalancerClient的reconstructURI方法重構的URI
ClientHttpRequestExecution的實現類是InterceptingClientHttpRequest的內部類IntercpetingRequestExecution,其execute方法遍歷interceptors,如果有攔截器,就執行攔截方法,如果沒有了,就執行請求。
在4中,LoadBalancerClient的execute方法執行請求,其實現類是RibbonLoadBalancerClient。execute 先透過serviceId獲取ILoadBalancer,然後呼叫ILoadBalancer的chooseServer方法,選擇一個Server,並將之轉換成RibbonServer,RibbonServer是ServiceInstance的子類,最後呼叫LoadBalancerRequest的apply方法,執行請求,返回響應。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69945560/viewspace-2656283/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- SpringCloud 客戶端負載均衡:RibbonSpringGCCloud客戶端負載
- SpringCloud系列之客戶端負載均衡Netflix RibbonSpringGCCloud客戶端負載
- ③SpringCloud 實戰:使用 Ribbon 客戶端負載均衡SpringGCCloud客戶端負載
- Spring Cloud Ribbon 客戶端負載均衡SpringCloud客戶端負載
- 【SpringCloud】之Ribbon負載均衡SpringGCCloud負載
- gRPC負載均衡(客戶端負載均衡)RPC負載客戶端
- Spring Cloud入門教程-Ribbon實現客戶端負載均衡SpringCloud客戶端負載
- SpringCloud入門(四)Ribbon負載均衡SpringGCCloud負載
- spring cloud 上雲的情況下,Ribbon 客戶端負載均衡 與 ALB 服務端負載均衡的選擇SpringCloud客戶端負載服務端
- SpringCloud Fegin結合Ribbon實現負載均衡SpringGCCloud負載
- SpringCloud 服務負載均衡和呼叫 Ribbon、OpenFeignSpringGCCloud負載
- SpringCloud學習筆記:負載均衡Ribbon(3)SpringGCCloud筆記負載
- (20)SpringCloud-Ribbon自定義負載均衡策略SpringGCCloud負載
- 負載均衡---ribbon負載
- 客服端負載均衡:Spring Cloud Ribbon負載SpringCloud
- Spring Cloud Netflix—客戶端負載平衡器:RibbonSpringCloud客戶端負載
- Ribbon實現負載均衡負載
- Spring Cloud Ribbon負載均衡SpringCloud負載
- Ribbon負載均衡 (原始碼分析)負載原始碼
- 微服務架構如何實現客戶端負載均衡微服務架構客戶端負載
- openGauss JDBC客戶端負載均衡與讀寫分離JDBC客戶端負載
- Spring cloud(3)-負載均衡(Feign,Ribbon)SpringCloud負載
- 微服務負載均衡器 Ribbon微服務負載
- (4)什麼是Ribbon負載均衡負載
- 【SpringCloud】Ribbon如何自定義客戶端配置和全域性配置SpringGCCloud客戶端
- SpringCloud微服務中使用RestTemplate+Ribbon實現負載均衡(實現方法+實現原理+替換負載均衡策略)SpringGCCloud微服務REST負載
- (23)go-micro微服務客戶端開發(使用負載均衡)Go微服務客戶端負載
- RocketMQ 客戶端負載均衡機制詳解及最佳實踐MQ客戶端負載
- Spring Cloud:自定義 Ribbon 負載均衡策略SpringCloud負載
- Ribbon負載均衡策略與自定義配置負載
- Ribbon - 幾種自定義負載均衡策略負載
- Ribbon 支援的9大負載均衡策略負載
- 四. SpringCloud負載均衡與呼叫SpringGCCloud負載
- mysqlslap 負載模擬客戶端MySql負載客戶端
- SpringCloud學習系列之二 ----- 服務消費者(Feign)和負載均衡(Ribbon)SpringGCCloud負載
- Spring Cloud之負載均衡元件Ribbon原理分析SpringCloud負載元件
- Ribbon提供的負載均衡演算法IRule(四)負載演算法
- SpringCloud(二):服務呼叫與負載均衡SpringGCCloud負載