Ribbon幾乎存在於每一個Spring cloud構建的微服務和基礎設施中,因爲微服務之間的調用,API網關的請求轉發等內容實際上都是通過Ribbon來實現的,是一個客戶端負載均衡的工具類框架。
通過Spring Cloud Ribbon的封裝,在微服務架構中使用客戶端負載均衡調用很簡單,只需要兩個步驟:
1、服務提供者只需要啓動多個服務實例並註冊到註冊中心
2、服務消費者直接通過調用被@LoadBalanced註解修飾過的RestTemplate來實現面向服務的接口調用
在《Spring cloud Eureka服務治理 (1)》中使用了RestTemplate實現了最簡單的服務訪問,下面介紹一下RestTemplate針對幾種不同請求類型和參數類型的服務調用實現;
GET請求
在 RestTemplate 中, 對 GET 請求可以通過如下兩個方法進行調用實現。
(1)getForEntity
該方法返回的是 ResponseEntity, 該對象是 Spring 對 HTTP 請求響應的封裝, 其中主要存儲了 HTTP 的幾個重要元素, 比如 HTTP 請求狀態 碼的枚舉對象 HttpStatus (也就是我們常說的 404、 500 這些錯誤碼)、 在它的父類 httpEntity 中還存儲着 HTTP 請求的頭信息對象 HttpHeaders 以及泛型類型的請求體 對象。 比如下面的例子, 就是訪問 USER-SERVER 服務的/user 請求, 同時最後一個參數 didi 會替換 url 中的{ 1} 佔位符, 而返回的 ResponseEntity 對象中的 body 內容類型 會根據第二個參數轉換爲 String 類型
Res七Template restTemplate = new RestTemplate();
ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://USER SERVICE/user?name= {1}", String.class, "didi");
String body = responseEntity. getBody();
還有三種不同的重載方法:
getForEntity(String url, Class responseType, Object... urlVariables):
getForEntity(String url, Class responseType, Map urlVariables): map中以鍵值對的方法存放參數
getForEntity(URI url, Class responseType)
(2)getForObject
getForObject (String url, Class responseType, Object... urlVariables):
getForObject(String url, Class responseType, Map urlVariables)
getForObject(URI url, Class responseType)
RestTemplale restTemplate = new RestTemplate();
String result = restTemplate.getForObject(uri, String.class);
POST請求:
RestTemplate restTemplate = new RestTemplate();
User user = new User("didi", 30);
ResponseEntity<String> responseEntity =
restTemplate.postForEntity("http://USER-SERVICE/user", user, String.class);
String body = responseEntity.getBody();
postForEntity函數也實現了三種不同的重載方法:
postForEntity(String url, Object request, Class responseType, Object... uriVariables)
postForEntity(String url, Object request, Class responseType, Map uriVariables)
postForEntity(URI url, Object request, Class responseType)
postForObject 函數。 該方法也跟getForObject 的類型類似, 它的作 用是簡化postForEntity的後續處理
RestTemplate restTemplate = new RestTemplate();
User user = new User("didi", 20);
String postResult = restTempla七e.postForObject("http://USER-SERVICE/user", user,
String.class);
postForObjec七函數也實現了三種 不同的重載方法:
• postForObject(String url, Object request, Class responseType, Object... uriVariables)
• postForObject(String url, Object request, Class responseType, Map uriVariables)
• postForObject(URI url, Object request, Class responseType)
User user = new User("didi", 40);
URI responseURI = restTemplate.postForLocation("http://USER-SERVICE/user", user);
postForLocation函數也實現了三種不同的重載方法:
postForLocation(Stringurl, Object request, Object...urlVariables)
postForLocation(String url, Object request, Map urlVariables)
postForLocation(URI url, Object request)
PUT請求:
RestTemplate restTemplate = new RestTemplate ();
Long id = 100011;
User user = new User("didi", 40);
restTemplate.put("http://USER-SERVICE/user/{l}", user, id);
put函數也實現 了三種不同的重載方法:
• put(String url, Object request, Object... urlVariables)
• put(String url, Object request, Map urlVariables)
• put(URI url, Object request)
DELETE請求:
RestTemplate restTemplate = new RestTemplate();
Long id= 10001L;
restTemplate.delete("http://USER-SERVICE/user/{1)", id);
delete函數也實現了三種不同的重載方法:
• delete(String url, Object ... urlVariables)
• delete(String url, Map urlVariables)
• delete(URI url)
Spring cloud Ribbon自動化配置:
IclientConfig:Ribbon的客戶端配置
IRule:Ribbon的負載均衡策略
IPing:Ribbon的實例檢查策略
ServiceList<Server>:服務實例清單的維護機制
ServerListFilter<Server>:服務實例清單過濾機制
ILoadBalancer:負載均衡器
自定義負載均衡策略:
兩種方式,
第一,代碼方式:
新建一個類,加上@Configration註解,並且包含一個返回IRule的Bean:
@Configuration
public class RibbonRuleConfiguration {
@Bean
public IRule ruleStyle(){
// return new BestAvailableRule(); //選擇一個最小的併發請求的server
// return new WeightedResponseTimeRule(); //根據相應時間分配一個weight,相應時間越長,weight越小,被選中的可能性越低。
// return new RetryRule(); //對選定的負載均衡策略機上重試機制。
// return new RoundRobinRule(); //roundRobin方式輪詢選擇server
// return new RandomRule(); //隨機選擇一個server
// return new ZoneAvoidanceRule(); //複合判斷server所在區域的性能和server的可用性選擇server
return new RandomRule();
}
}
上面是使用了隨機策略,
然後再application上加註解@RibbonClients,表示對調用的所有服務使用這個策略。
@EnableDiscoveryClient
@SpringBootApplication
@RibbonClients(defaultConfiguration = RibbonRuleConfiguration.class)
public class RibbonApplication {
@Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(RibbonApplication.class, args);
}
}
如果想要指定單個服務的策略:
@RibbonClient(name="server-hi",configuration = RibbonRuleConfiguation.class)
上面就是隻對server-hi使用了此策略。
但是使用上訴的方式,如果調用的服務太多,那麼就會有很多configuration類,application中也很臃腫,所以還有一種配置文件方式:
helloservice-1.ribbon.NFLoadBalancerRuleClassNam=com.netflix.loadbalancer.RandomRule
helloservice-1 是服務名,等號後面就是負載均衡策略。
重試機制:
Eureka爲了更高的服務可用性,犧牲了一定的一致性,在極端情況下,寧願接受故障實例,也不要丟掉實例,當服務註冊中心的網絡發生故障斷開時, 由於所有 的服務實例無法維持續約心跳, 在強調AP的服務治理中將會把所有服務實例都剔除掉, 而Eureka則會因爲超過85%的實例丟失心跳而會觸發保護機制,註冊中心將會保留此時的 所有節點, 以實現服務間依然可以進行互相調用。
以之前的服務helloservice-1爲例,可以在配置文件中增加以下內容:
helloservice-1.ribbon.ConnectTimeOut=250
#請求連接的超時時間
helloservice-1.ribbon.ReadTimeOut=1000
#請求處理的超時時間
helloservice-1.ribbon.OkToRetryOnAllOperations=true
#對所有服務都進行重試
helloservice-1.ribbon.MaxAutoRetriesNextServer=2
#切換實例重試的次數
helloservice-1.ribbon.MaxAutoRetries=1
#單個實例重試的次數