SpringCloud Netfilx Ribbon負載均衡工具使用方法介紹
一、介紹
Spring Cloud Ribbon是一個基于HTTP和TCP的客戶端負載均衡工具,它基于Netflix Ribbon實現(xiàn)。通過Spring Cloud的封裝,可以讓我們輕松地將面向服務(wù)的REST模版請求自動轉(zhuǎn)換成客戶端負載均衡的服務(wù)調(diào)用。Spring Cloud Ribbon雖然只是一個工具類框架,它不像服務(wù)注冊中心、配置中心、API網(wǎng)關(guān)那樣需要獨立部署,但是它幾乎存在于每一個Spring Cloud構(gòu)建的微服務(wù)和基礎(chǔ)設(shè)施中。因為微服務(wù)間的調(diào)用,API網(wǎng)關(guān)的請求轉(zhuǎn)發(fā)等內(nèi)容,實際上都是通過Ribbon來實現(xiàn)的,包括后續(xù)我們將要學(xué)習(xí)的OpenFeign,它也是基于Ribbon實現(xiàn)負載均衡的遠程服務(wù)調(diào)用工具。所以,對Spring Cloud Ribbon的理解和使用,對于我們使用Spring Cloud來構(gòu)建微服務(wù)非常重要.
二、使用
@Service public class ApplicationClientServiceImpl implements ApplicationClientService { /** * Ribbon提供的負載均衡器 */ @Autowired private LoadBalancerClient loadBalancerClient; @Override public String client() { ServiceInstance si = loadBalancerClient.choose("application-service"); // 獲取Application Service IP。 System.out.println(si.getHost()); // 獲取Ip及端口。 System.out.println(si.getInstanceId()); // 端口 System.out.println(si.getPort()); // 應(yīng)用程序名 application-service System.out.println(si.getServiceId()); // URI http://Application Service IP:端口 System.out.println(si.getUri().toString()); return null; } }
三、SpringWeb之RestTemplate基于Http協(xié)議的遠程訪問
要想使用RestRemplate必須自己配置
package com.bjsxt.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; @Configuration public class MyConfig { @Bean public RestTemplate restTemplate(){ return new RestTemplate(); } }
(1)控制器
@RestController public class ServerController { @Value("${server.port}") private int port; /** * 返回類型為集合,泛型為自定類型。 */ @RequestMapping("/returnUsers") public List<User> returnUsers(int nums){ List<User> result = new ArrayList<>(); for(int i = 0; i < nums; i++){ result.add(new User(100 + i, "姓名-" + i, 20+i)); } return result; } /** * 任意請求方式, 返回值類型是集合。相對復(fù)雜的Java類型。 * @return */ @RequestMapping("/returnList") public List<String> returnList(int nums){ List<String> result = new ArrayList<>(); for(int i = 0; i < nums; i++){ result.add("返回結(jié)果 - " + i); } return result; } /** * 任意請求,傳遞路徑地址參數(shù) * @param name * @param age * @return */ @RequestMapping("/restfulParams/{name}/{age}") public String restfulParams(@PathVariable("name") String name, @PathVariable int age){ System.out.println("端口號: " + port + ", 任意請求方式,restful參數(shù), name = " + name + " ; age = " + age); return "restful參數(shù), name = " + name + " ; age = " + age; } /** * post請求,請求體傳遞參數(shù)。參數(shù)使用@RequestBody處理。 */ @PostMapping("/postBodyParams") public String postBodyParams(@RequestBody Map<String, String> params){ System.out.println("端口號: " + port + " , post請求,有請求體參數(shù), params = " + params); return "post請求,請求體參數(shù), params = " + params; } /** * post請求,有參數(shù) */ @PostMapping("/postWithParams") public String postWithParams(String name, int age){ System.out.println("端口號: " + port + " , post請求,有參數(shù), name = " + name + " ; age = " + age); return "post請求有參數(shù) : name = " + name + " ; age = " + age; } /** * post請求,沒有參數(shù) */ @PostMapping("/postNoParams") public String postNoParams(){ System.out.println("端口號: " + port + " , post請求,沒有參數(shù)"); return "post請求,沒有參數(shù)"; } /** * get請求,包含參數(shù) */ @GetMapping("/getWithParams") public String getWithParams(String name, int age){ System.out.println("端口號: " + port + " 。 get請求,有參數(shù), name = " + name + " ; age = " + age); return "get請求,包含參數(shù) : name = " + name + " ; age = " + age; } /** * get請求,沒有參數(shù) * @return */ @GetMapping("/getNoParams") public String getNoParams(){ System.out.println("端口號:" + port + "。 get請求,無參數(shù)。"); return "get請求,無參數(shù)。"; } }
(2)無參數(shù)GET請求-getForObject
/** * 發(fā)get請求。 * 沒有請求參數(shù) * * <T> T getForObject(String url, Class<T> returnValueType, Object... params) * url - 要訪問的具體地址 * returnValueType - 服務(wù)器返回的響應(yīng)體數(shù)據(jù)類型 * params - 可選的請求參數(shù) * return - 響應(yīng)體中的具體內(nèi)容。 */ @Test public void testGetNoParams(){ // 定義要訪問的地址是什么 String url = baseUrl + "/getNoParams"; // 發(fā)get請求。沒有參數(shù) String result = restTemplate.getForObject(url, String.class); System.out.println("服務(wù)器返回:" + result); }
(3)有參數(shù)GET請求-getForObject
/** * get請求,有參數(shù) * <T> T getForObject(String url, Class<T> returnValueType, Object... params) * <T> T getForObject(String url, Class<T> returnValueType, Map params) * 傳遞參數(shù),就是處理請求地址url,并傳遞需要的參數(shù)。 * 要傳遞參數(shù),則處理請求地址url。使用{名字}作為占位變量。傳遞參數(shù)的時候, * 可以根據(jù)占位變量從左至右的順序,使用可變長數(shù)組依次傳遞。 * 也可以根據(jù)占位變量名稱,做指定傳遞,使用map集合傳遞,map的key就是占位變量名, * map的value,是要傳遞的請求參數(shù)。 */ @Test public void testGetWithParams(){ String url = baseUrl + "/getWithParams?name={x}&age={y}"; String result1 = restTemplate.getForObject(url, String.class, "張三", "20"); System.out.println("可變長數(shù)組傳遞參數(shù),服務(wù)器返回:" + result1); System.out.println("=========================================="); Map<String, Object> params = new HashMap<>(); params.put("x", "李四"); params.put("y", 25); String result2 = restTemplate.getForObject(url, String.class, params); System.out.println("Map集合傳遞參數(shù),服務(wù)器返回:" + result2); }
(4)GET請求-getForEntity
/** * 在RestTemplate中。除方法getForObject以外,還有g(shù)etForEntity。 * 方法除返回值類型,其他一致。 * <T> ResponseEntity<T> getForEntity(String url, Class<T> returnValueType, * Object... params) * ResponseEntity - 包含響應(yīng)頭和響應(yīng)體。 * 如果需要對響應(yīng)頭做特殊處理,使用getForEntity方法。 */ @Test public void testGetForEntity(){ String url = baseUrl + "/getNoParams"; ResponseEntity<String> entity = restTemplate.getForEntity(url, String.class); HttpHeaders headers = entity.getHeaders(); for(String headerName : headers.keySet()){ System.out.println("響應(yīng)頭: " + headerName + " = " + headers.get(headerName)); } System.out.println("響應(yīng)狀態(tài)碼: " + entity.getStatusCodeValue()); System.out.println("響應(yīng)體數(shù)據(jù): " + entity.getBody()); }
(5)無參數(shù)POST請求
/** * post請求,沒有參數(shù) * <T> T postForObject(String url, Object body, Class<T> returnBodyType, * Object... params); * <T> T postForObject(String url, Object body, Class<T> returnBodyType, * Map params); * body參數(shù) - 使用post請求方式發(fā)請求的時候,請求體是什么? * 建議傳遞的對象類型是HttpEntity。 * 如果對請求體沒有要求,可以傳遞null。 */ @Test public void testPostNoParams(){ String url = baseUrl + "/postNoParams"; String result = restTemplate.postForObject(url, null, String.class); System.out.println("post請求,無參數(shù),服務(wù)器返回:" + result); }
(6)post請求路徑地址傳遞參數(shù)
/** * post請求,有參數(shù) * 1. 請求地址傳遞參數(shù)。 請求頭傳參。 傳參方式和get一樣。 * 2. 請求體表單參數(shù)。 請求體傳參。 需要提供請求體數(shù)據(jù) */ @Test public void testPostWithParamsPath(){ String url = baseUrl + "/postWithParams?name={1}&age={2}"; String result = restTemplate.postForObject(url, null, String.class, "王五", 30); System.out.println(result); }
(7)post請求表單傳遞參數(shù)
/** * spring web在處理請求頭和請求體的時候, * 需要HttpMessageConverter提供數(shù)據(jù)轉(zhuǎn)換處理。 * HttpMessageConverter是接口,由Spring WEB定義。 * 具體實現(xiàn),需要依賴不同的具體技術(shù)實現(xiàn)。 * 一般都使用jackson做實現(xiàn)。請求頭和體數(shù)據(jù),都是基于JSON轉(zhuǎn)換的。 */ @Test public void testPostWithParamsForm(){ String url = baseUrl + "/postWithParams"; // 創(chuàng)建請求體信息。 // 請求頭, 表單請求。 application/x-www-form-urlencoded HttpHeaders headers = new HttpHeaders(); headers.add("content-type", "application/x-www-form-urlencoded"); // 表單 MultiValueMap<String, Object> form = new LinkedMultiValueMap<>(); // add 提供一個 請求參數(shù) 名 = 值。 form.add("name", "尼古拉斯.趙四"); form.add("age", 40); // put 提供 鍵值對 //form.put("name", Arrays.asList("尼古拉斯.趙四")); //List<Object> ages = new ArrayList<>(); //ages.add(40); //form.put("age", ages); HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(form, headers); String result = restTemplate.postForObject(url, entity, String.class); System.out.println(result); }
(8)post請求請求體傳遞參數(shù)
/** * post請求,有參數(shù) * 使用請求體傳遞參數(shù)。@RequestBody處理請求參數(shù)。 * 1. 請求參數(shù)只能在請求體中,以字符串描述,且是一個完整的請求參數(shù)。此參數(shù)沒有名稱。如:JSON * 2. 請求頭 content-type的設(shè)置,和具體的參數(shù)值的格式相關(guān),如: JSON對應(yīng)的content-type是application/json * 如:xml字符串對應(yīng)的content-type是application/xml * 3. 請求體傳遞的參數(shù),只能由唯一的一個完整參數(shù)。可以同時攜帶表單參數(shù)和地址欄參數(shù)。 */ @Test public void testPostBodyParams(){ String url = baseUrl + "/postBodyParams"; // 創(chuàng)建請求參數(shù), 使用JSON格式的字符串,描述一個Map集合。 String params = "{\"key1\":\"value1\", \"key2\":\"value2\"}"; // 創(chuàng)建請求時,使用的請求體描述 HttpHeaders headers = new HttpHeaders(); headers.add("content-type", "application/json;charset=utf-8"); HttpEntity<String> entity = new HttpEntity<>(params, headers); String result = restTemplate.postForObject(url, entity, String.class); System.out.println("返回結(jié)果:" + result); } @Test public void testPostBodyParams2(){ // 可以使用簡單的處理方案,實現(xiàn)請求體傳遞JSON格式的數(shù)據(jù) // 使用postForObject(),第二個參數(shù),直接傳遞一個Java對象,作為請求體中傳遞的參數(shù)。 // 參數(shù)沒有名字,由RestTemplate做數(shù)據(jù)轉(zhuǎn)換,默認使用JSON格式字符串做轉(zhuǎn)換結(jié)果。 String url = baseUrl + "/postBodyParams"; // 創(chuàng)建Map類型的參數(shù)對象 Map<String, String> params = new HashMap<>(); params.put("name", "測試"); params.put("gender", "男"); // 請求服務(wù)器。 直接傳遞java對象,默認請求頭content-type=application/json;charset=utf-8 String result = restTemplate.postForObject(url, params, String.class); System.out.println("返回結(jié)果:" + result); }
(9)RestFUL傳遞參數(shù)
/** * 使用get請求方式,傳遞restful參數(shù) */ @Test public void testRestfulParams(){ String url = baseUrl + "/restfulParams/{name}/{age}"; // 訪問 String result = restTemplate.getForObject(url, String.class, "restful", "15"); System.out.println(result); }
(10)Exchange通用處理方案(處理相對復(fù)雜的結(jié)果類型例如自定義類型數(shù)組)
/** * RestTemplate類型中的通用方法,exchange??梢蕴峤蝗我夥绞降恼埱?。 * 且可以定義相對復(fù)雜的返回類型。如:帶有泛型要求的集合。 * * <T> ResponseEntity<T> exchange(String url, HttpMethod requestMethod, HttpEntity http, * Class<T> returnType, Object... params) * <T> ResponseEntity<T> exchange(String url, HttpMethod requestMethod, HttpEntity http, * Class<T> returnType, Map params) * <T> ResponseEntity<T> exchange(String url, HttpMethod requestMethod, HttpEntity http, * ParameterizedTypeReference<T> returnType, Object... params) * <T> ResponseEntity<T> exchange(String url, HttpMethod requestMethod, HttpEntity http, * ParameterizedTypeReference<T> returnType, Map... params) */ @Test public void testExchangeMethod(){ String url = baseUrl + "/returnList?nums={1}"; // 相對復(fù)雜的返回結(jié)果類型描述對象 url = baseUrl + "/returnUsers?nums={1}"; ParameterizedTypeReference<List<User>> type = new ParameterizedTypeReference<List<User>>() {}; // 訪問遠程 ResponseEntity<List<User>> entity = restTemplate.exchange(url, HttpMethod.GET, null, type, 3); List<User> body = entity.getBody(); System.out.println(body); }
四、調(diào)用Application Service集群
基于RestTemplate和Ribbon實現(xiàn)Application Client調(diào)用Application Service集群
(1)編寫配置類
@Configuration public class AppClientConfiguration { /** * 創(chuàng)建RestTemplate對象的方法,增加注解 * LoadBalanced - 把Spring Cloud封裝的LoadBalancerClient于RestTemplate整合。 * 讓RestTemplate自帶負載均衡能力。僅在當前的Ribbon環(huán)境中生效。 * 邏輯是: * 請求 http://服務(wù)名稱/具體地址. RestTemplate解析請求地址。 * 把服務(wù)名稱解析出,作為參數(shù),調(diào)用LoadBalancerClient中的choose方法。 * 把返回的ServiceInstance.getUri().toASCIIString()作為服務(wù)器地址,拼接上 * 請求的具體地址。訪問遠程。 * @return */ @Bean @LoadBalanced public RestTemplate restTemplate(){ return new RestTemplate(); } }
(2)發(fā)起遠程調(diào)用
@Service public class ApplicationClientServiceImpl implements ApplicationClientService { @Autowired private RestTemplate restTemplate; //http://服務(wù)名 private final String baseUrl = "http://eureka-client-app-service"; @Override public String getNoParams() { String url = baseUrl + "/getNoParams"; // 訪問 String result = restTemplate.getForObject(url, String.class); System.out.println(result); return result; } }
五、Ribbon負載均衡算法
Ribbon的負載均衡策略是通過不同的類型來實現(xiàn)的(都是IRule接口的實現(xiàn)),下表詳細介紹一些常用負載均衡策略及對應(yīng)的Ribbon策略類。
編號 | 策略名稱 | 策略對應(yīng)的類名 | 實現(xiàn)原理 |
---|---|---|---|
1 | 輪詢策略(默認) | RoundRobinRule | 輪詢策略表示每次都按照順序取下一個application service,比如一共有5個application service,第1次取第1個,第2次取第2個,第3次取第3個,以此類推 |
2 | 權(quán)重輪詢策略(常用,中小型項目使用) | WeightedResponseTimeRule | 1.根據(jù)每個application service的響應(yīng)時間分配一個權(quán)重,響應(yīng)時間越長,權(quán)重越小,被選中的可能性越低。 2.原理:一開始為輪詢策略,并開啟一個計時器,每30秒收集一次每個application service的平均響應(yīng)時間,當信息足夠時,給每個application service附上一個權(quán)重,并按權(quán)重隨機選擇application service,權(quán)重越高的application service會被高概率選中。 |
3 | 隨機策略(不推薦,測試使用,開發(fā)使用) | RandomRule | 從application service列表中隨機選擇一個 |
4 | 最少并發(fā)數(shù)策略(應(yīng)用在硬件軟件環(huán)境一致的情況下,中小型項目使用) | BestAvailableRule | 選擇正在請求中的并發(fā)數(shù)最小的application service,除非這個application service在熔斷中。 |
5 | 重試策略。在“選定的負載均衡策略”基礎(chǔ)上進行重試機制 | RetryRule | 1.“選定的負載均衡策略”這個策略是輪詢策略RoundRobinRule 2.該重試策略先設(shè)定一個閾值時間段,如果在這個閾值時間段內(nèi)當選擇application service不成功,則一直嘗試采用“選定的負載均衡策略:輪詢策略”最后選擇一個可用的application service |
6 | 可用性敏感策略(一般在同區(qū)域內(nèi)服務(wù)集群環(huán)境中使用) | AvailabilityFilteringRule | 過濾性能差的application service,有2種: 第一種:過濾掉在eureka中處于一直連接失敗application service 第二種:過濾掉高并發(fā)的application service |
7 | 區(qū)域敏感性策略(應(yīng)用在大型的,物理隔離分布式環(huán)境中) | ZoneAvoidanceRule | 1.以一個區(qū)域為單位考察可用性,對于不可用的區(qū)域整個丟棄,從剩下區(qū)域中選可用的application service 2.如果這個ip區(qū)域內(nèi)有一個或多個實例不可達或響應(yīng)變慢,都會降低該ip區(qū)域內(nèi)其他ip被選中的權(quán)重。 |
指定負載均衡策略,新增Bean對象管理方法
@Bean public IRule iRule(){ return new RandomRule(); }
到此這篇關(guān)于SpringCloud Netfilx Ribbon負載均衡工具使用方法介紹的文章就介紹到這了,更多相關(guān)SpringCloud Netfilx Ribbon內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
spring boot項目打包成war在tomcat運行的全步驟
這篇文章主要給大家介紹了關(guān)于spring boot項目打包成war在tomcat運行的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用spring boot具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04JAVA中JSONObject對象和Map對象之間的相互轉(zhuǎn)換
這篇文章主要介紹了JAVA中JSONObject對象和Map對象之間的相互轉(zhuǎn)換,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01Java解析zip文件,并識別壓縮包里面的文件轉(zhuǎn)換成可操作的IO流方式
這篇文章主要介紹了Java解析zip文件,并識別壓縮包里面的文件轉(zhuǎn)換成可操作的IO流方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-08-08