javascript
负载均衡Ribbon和Feign---SpringCloud
負載均衡Ribbon和Feign
Ribbon負載均衡(基于客戶端)
6.1 負載均衡以及Ribbon
Ribbon是什么?
- Spring Cloud Ribbon 是基于Netflix Ribbon 實現的一套客戶端負載均衡的工具。
- 簡單的說,Ribbon 是 Netflix 發布的開源項目,主要功能是提供客戶端的軟件負載均衡算法,將 Netflix 的中間層服務連接在一起。Ribbon 的客戶端組件提供一系列完整的配置項,如:連接超時、重試等。簡單的說,就是在配置文件中列出 LoadBalancer (簡稱LB:負載均衡) 后面所有的及其,Ribbon 會自動的幫助你基于某種規則 (如簡單輪詢,隨機連接等等) 去連接這些機器。我們也容易使用 Ribbon 實現自定義的負載均衡算法!
Ribbon能干嘛?
- LB,即負載均衡 (LoadBalancer) ,在微服務或分布式集群中經常用的一種應用。
- 負載均衡簡單的說就是將用戶的請求平攤的分配到多個服務上,從而達到系統的HA (高用)。
- 常見的負載均衡軟件有 Nginx、Lvs 等等。
- Dubbo、SpringCloud 中均給我們提供了負載均衡,SpringCloud 的負載均衡算法可以自定義。
負載均衡簡單分類
- 集中式LB
- 即在服務的提供方和消費方之間使用獨立的LB設施,如Nginx(反向代理服務器),由該設施負責把訪問請求通過某種策略轉發至服務的提供方!
- 進程式 LB
- 將LB邏輯集成到消費方,消費方從服務注冊中心獲知有哪些地址可用,然后自己再從這些地址中選出一個合適的服務器。
- Ribbon 就屬于進程內LB,它只是一個類庫,集成于消費方進程,消費方通過它來獲取到服務提供方的地址!
集成Ribbon
springcloud-consumer-dept-80向pom.xml中添加Ribbon和Eureka依賴
<!--Ribbon--> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-ribbon</artifactId><version>1.4.6.RELEASE</version> </dependency> <!--Eureka: Ribbon需要從Eureka服務中心獲取要拿什么--> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-eureka</artifactId><version>1.4.6.RELEASE</version> </dependency>在application.yml文件中配置Eureka
# Eureka配置 eureka:client:register-with-eureka: false # 不向 Eureka注冊自己service-url: # 從三個注冊中心中隨機取一個去訪問defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/主啟動類加上@EnableEurekaClient注解,開啟Eureka
//Ribbon 和 Eureka 整合以后,客戶端可以直接調用,不用關心IP地址和端口號 @SpringBootApplication @EnableEurekaClient //開啟Eureka 客戶端 public class DeptConsumer_80 {public static void main(String[] args) {SpringApplication.run(DeptConsumer_80.class, args);} }自定義Spring配置類:ConfigBean.java 配置負載均衡實現RestTemplate
@Configuration public class ConfigBean {//@Configuration -- spring applicationContext.xml@LoadBalanced //配置負載均衡實現RestTemplate@Beanpublic RestTemplate getRestTemplate() {return new RestTemplate();} }修改conroller:DeptConsumerController.java
//Ribbon:我們這里的地址,應該是一個變量,通過服務名來訪問 //private static final String REST_URL_PREFIX = "http://localhost:8001"; private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";數據庫導出
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-9eSa5VMs-1610696634599)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210115135531598.png)]
使用Ribbon實現負載均衡
流程圖:
1.新建兩個服務提供者Moudle:springcloud-provider-dept-8003、springcloud-provider-dept-8002
2.參照springcloud-provider-dept-8001 依次為另外兩個Moudle添加pom.xml依賴 、resourece下的mybatis和application.yml配置,Java代碼
3.啟動所有服務測試(根據自身電腦配置決定啟動服務的個數),訪問http://eureka7001.com:7002/查看結果
測試訪問http://localhost/consumer/dept/list 這時候隨機訪問的是服務提供者8003
再次訪問http://localhost/consumer/dept/list這時候隨機的是服務提供者8001
以上這種每次訪問http://localhost/consumer/dept/list隨機訪問集群中某個服務提供者,這種情況叫做輪詢,輪詢算法在SpringCloud中可以自定義。
自定義負載均衡
在springcloud-provider-dept-80模塊下的ConfigBean中進行配置,切換使用不同的規則
@Configuration public class ConfigBean {//@Configuration -- spring applicationContext.xml/*** IRule:* RoundRobinRule 輪詢策略* RandomRule 隨機策略* AvailabilityFilteringRule : 會先過濾掉,跳閘,訪問故障的服務~,對剩下的進行輪詢~* RetryRule : 會先按照輪詢獲取服務~,如果服務獲取失敗,則會在指定的時間內進行,重試*/@Beanpublic IRule myRule() {return new RandomRule();//使用隨機策略//return new RoundRobinRule();//使用輪詢策略//return new AvailabilityFilteringRule();//使用輪詢策略//return new RetryRule();//使用輪詢策略} }也可以自定義規則,在myRule包下自定義一個配置類MyRule.java,注意:該包不要和主啟動類所在的包同級,要跟啟動類所在包同級:
MyRule.java
/*** @Auther: csp1999* @Date: 2020/05/19/11:58* @Description: 自定義規則*/ @Configuration public class MyRule {@Beanpublic IRule myRule(){return new MyRandomRule();//默認是輪詢RandomRule,現在自定義為自己的} }主啟動類開啟負載均衡并指定自定義的MyRule配置類
//Ribbon 和 Eureka 整合以后,客戶端可以直接調用,不用關心IP地址和端口號 @SpringBootApplication @EnableEurekaClient //在微服務啟動的時候就能加載自定義的Ribbon類(自定義的規則會覆蓋原有默認的規則) @RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = MyRule.class)//開啟負載均衡,并指定自定義的規則 public class DeptConsumer_80 {public static void main(String[] args) {SpringApplication.run(DeptConsumer_80.class, args);} }自定義的規則(這里我們參考Ribbon中默認的規則代碼自己稍微改動):MyRandomRule.java
public class MyRandomRule extends AbstractLoadBalancerRule {/*** 每個服務訪問5次則換下一個服務(總共3個服務)* <p>* total=0,默認=0,如果=5,指向下一個服務節點* index=0,默認=0,如果total=5,index+1*/private int total = 0;//被調用的次數private int currentIndex = 0;//當前是誰在提供服務//@edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE")public Server choose(ILoadBalancer lb, Object key) {if (lb == null) {return null;}Server server = null;while (server == null) {if (Thread.interrupted()) {return null;}List<Server> upList = lb.getReachableServers();//獲得當前活著的服務List<Server> allList = lb.getAllServers();//獲取所有的服務int serverCount = allList.size();if (serverCount == 0) {/** No servers. End regardless of pass, because subsequent passes* only get more restrictive.*/return null;}//int index = chooseRandomInt(serverCount);//生成區間隨機數//server = upList.get(index);//從或活著的服務中,隨機獲取一個//=====================自定義代碼=========================if (total < 5) {server = upList.get(currentIndex);total++;} else {total = 0;currentIndex++;if (currentIndex > =upList.size()) {currentIndex = 0;}server = upList.get(currentIndex);//從活著的服務中,獲取指定的服務來進行操作}//======================================================if (server == null) {/** The only time this should happen is if the server list were* somehow trimmed. This is a transient condition. Retry after* yielding.*/Thread.yield();continue;}if (server.isAlive()) {return (server);}// Shouldn't actually happen.. but must be transient or a bug.server = null;Thread.yield();}return server;}protected int chooseRandomInt(int serverCount) {return ThreadLocalRandom.current().nextInt(serverCount);}@Overridepublic Server choose(Object key) {return choose(getLoadBalancer(), key);}@Overridepublic void initWithNiwsConfig(IClientConfig clientConfig) {// TODO Auto-generated method stub} }Feign負載均衡(基于服務端)
7.1 Feign簡介
Feign是聲明式Web Service客戶端,它讓微服務之間的調用變得更簡單,類似controller調用service。SpringCloud集成了Ribbon和Eureka,可以使用Feigin提供負載均衡的http客戶端
只需要創建一個接口,然后添加注解即可~
Feign,主要是社區版,大家都習慣面向接口編程。這個是很多開發人員的規范。調用微服務訪問兩種方法
Feign能干什么?
- Feign旨在使編寫Java Http客戶端變得更容易
- 前面在使用Ribbon + RestTemplate時,利用RestTemplate對Http請求的封裝處理,形成了一套模板化的調用方法。但是在實際開發中,由于對服務依賴的調用可能不止一處,往往一個接口會被多處調用,所以通常都會針對每個微服務自行封裝一個客戶端類來包裝這些依賴服務的調用。所以,Feign在此基礎上做了進一步的封裝,由他來幫助我們定義和實現依賴服務接口的定義,在Feign的實現下,我們只需要創建一個接口并使用注解的方式來配置它 (類似以前Dao接口上標注Mapper注解,現在是一個微服務接口上面標注一個Feign注解),即可完成對服務提供方的接口綁定,簡化了使用Spring Cloud Ribbon 時,自動封裝服務調用客戶端的開發量。
Feign默認集成了Ribbon
- 利用Ribbon維護了MicroServiceCloud-Dept的服務列表信息,并且通過輪詢實現了客戶端的負載均衡,而與Ribbon不同的是,通過Feign只需要定義服務綁定接口且以聲明式的方法,優雅而簡單的實現了服務調用。
Feign的使用
創建springcloud-consumer-fdept-feign模塊
拷貝springcloud-consumer-dept-80模塊下的pom.xml,resource,以及java代碼到springcloud-consumer-feign模塊,并添加feign依賴。
<!--Feign的依賴--> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-feign</artifactId><version>1.4.6.RELEASE</version> </dependency>通過Ribbon實現:—原來的controller:DeptConsumerController.java
/*** @Auther: csp1999* @Date: 2020/05/17/22:44* @Description:*/ @RestController public class DeptConsumerController {/*** 理解:消費者,不應該有service層~* RestTemplate .... 供我們直接調用就可以了! 注冊到Spring中* (地址:url, 實體:Map ,Class<T> responseType)* <p>* 提供多種便捷訪問遠程http服務的方法,簡單的Restful服務模板~*/@Autowiredprivate RestTemplate restTemplate;/*** 服務提供方地址前綴* <p>* Ribbon:我們這里的地址,應該是一個變量,通過服務名來訪問*/ // private static final String REST_URL_PREFIX = "http://localhost:8001";private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";/*** 消費方添加部門信息* @param dept* @return*/@RequestMapping("/consumer/dept/add")public boolean add(Dept dept) {// postForObject(服務提供方地址(接口),參數實體,返回類型.class)return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class);}/*** 消費方根據id查詢部門信息* @param id* @return*/@RequestMapping("/consumer/dept/get/{id}")public Dept get(@PathVariable("id") Long id) {// getForObject(服務提供方地址(接口),返回類型.class)return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id, Dept.class);}/*** 消費方查詢部門信息列表* @return*/@RequestMapping("/consumer/dept/list")public List<Dept> list() {return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class);} }通過Feign實現:—改造后controller:DeptConsumerController.java
/*** @Auther: csp1999* @Date: 2020/05/17/22:44* @Description:*/ @RestController public class DeptConsumerController {@Autowiredprivate DeptClientService deptClientService;/*** 消費方添加部門信息* @param dept* @return*/@RequestMapping("/consumer/dept/add")public boolean add(Dept dept) {return deptClientService.addDept(dept);}/*** 消費方根據id查詢部門信息* @param id* @return*/@RequestMapping("/consumer/dept/get/{id}")public Dept get(@PathVariable("id") Long id) {return deptClientService.queryById(id);}/*** 消費方查詢部門信息列表* @return*/@RequestMapping("/consumer/dept/list")public List<Dept> list() {return deptClientService.queryAll();} }Feign和Ribbon二者對比,前者顯現出面向接口編程特點,代碼看起來更清爽,而且Feign調用方式更符合我們之前在做SSM或者SprngBoot項目時,Controller層調用Service層的編程習慣!
主配置類:
/*** @Auther: csp1999* @Date: 2020/05/17/22:47* @Description:*/ @SpringBootApplication @EnableEurekaClient // feign客戶端注解,并指定要掃描的包以及配置接口DeptClientService @EnableFeignClients(basePackages = {"com.haust.springcloud"}) // 切記不要加這個注解,不然會出現404訪問不到 //@ComponentScan("com.haust.springcloud") public class FeignDeptConsumer_80 {public static void main(String[] args) {SpringApplication.run(FeignDeptConsumer_80.class, args);} }改造springcloud-api模塊
pom.xml添加feign依賴
<!--Feign的依賴--> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-feign</artifactId><version>1.4.6.RELEASE</version> </dependency>新建service包,并新建DeptClientService.java接口,
package com.kuang.springcloud.controller;import com.kuang.springcloud.pojo.Dept; import com.kuang.springcloud.service.DeptClientService; 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.RestController;import java.util.List;/*** @Auther: csp1999* @Date: 2020/05/17/22:44* @Description:*/ @RestController public class DeptConsumerController {@Autowiredprivate DeptClientService deptClientService=null;/*** 消費方添加部門信息* @param dept* @return*/@RequestMapping("/consumer/dept/add")public boolean add(Dept dept) {return deptClientService.addDept(dept);}/*** 消費方根據id查詢部門信息* @param id* @return*/@RequestMapping("/consumer/dept/get/{id}")public Dept get(@PathVariable("id") Long id) {return deptClientService.queryById(id);}/*** 消費方查詢部門信息列表* @return*/@RequestMapping("/consumer/dept/list")public List<Dept> list() {return deptClientService.queryAll();} }Feign VS Ribbon
根據個人習慣而定,如果喜歡REST風格使用Ribbon;如果喜歡社區版的面向接口風格使用Feign.
Feign 本質上也是實現了 Ribbon,只不過后者是在調用方式上,為了滿足一些開發者習慣的接口調用習慣!
下面我們關閉springcloud-consumer-dept-80 這個服務消費方,換用springcloud-consumer-dept-feign(端口還是80) 來代替:(依然可以正常訪問,就是調用方式相比于Ribbon變化了)
總結
以上是生活随笔為你收集整理的负载均衡Ribbon和Feign---SpringCloud的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 苹果led灯怎么设置(苹果led灯怎么设
- 下一篇: Hystrix---SpringClou