<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          SpringCloud:Ribbon與Feign

          共 10840字,需瀏覽 22分鐘

           ·

          2023-08-01 09:58

          走過路過不要錯過

          點擊藍字關(guān)注我們

          上一篇使用了Eureka與Ribbon組件做了最簡單的的服務(wù)注冊與發(fā)現(xiàn),我們知道Eureka是實現(xiàn)服務(wù)治理中心的組件,但是上一篇Eureka沒有實現(xiàn)集群,這樣沒有保證到Eureka Server的高可用。
          理論上來講,因為服務(wù)消費者本地緩存了服務(wù)提供者的地址,即使Eureka Server宕機,也不會影響服務(wù)之間的調(diào)用,但是一旦新服務(wù)上線,已經(jīng)在緩存在本地的服務(wù)提供者不可用了,服務(wù)消費者也無法知道,所以保證Eureka Server的高可用還是很有必要的。
          那我們先來搭建一個Eureka的集群
          一、Eureka集群配置
          要做集群,我們想到肯定是增加一臺服務(wù)器,那怎么讓服務(wù)器之間產(chǎn)生關(guān)系,先讓他們相互注冊,在修改之前,我們?yōu)榱藚^(qū)分服務(wù)器名稱,先修改下hosts文件,增加下面一段:
          127.0.0.1  eureka1.com127.0.0.1  eureka2.com
          然后修改下之前spring-cloud-learn-eureka 項目的配置文件,主要修改的是注冊的地址:
          spring:application:name: spring-cloud-learn-eureka
          server:port: 8761eureka:instance:hostname: eureka1.comclient: #表示是否將自己注冊到Eureka Server,默認為true。registerWithEureka: false #表示是否從Eureka Server獲取注冊信息,默認為true。fetchRegistry: falseserviceUrl:defaultZone: http://eureka2.com:8762/eureka/
          這個時候我們啟動此項目,并同時啟動服務(wù)提供者spring-cloud-learn-provider-dept,這里其實跟之前都沒什么區(qū)別,服務(wù)順利的注冊進去:
          這個時候我們修改spring-cloud-learn-eureka的配置,即再啟動一個eureka server :
          spring:application:name: spring-cloud-learn-eureka
          server:port: 8762eureka:instance:hostname: eureka2.comclient: #表示是否將自己注冊到Eureka Server,默認為true。registerWithEureka: false #表示是否從Eureka Server獲取注冊信息,默認為true。fetchRegistry: falseserviceUrl:defaultZone: http://eureka1.com:8761/eureka/

          這是啟動的第二臺服務(wù)器,注冊到了第一臺服務(wù)器中,啟動項目,這個時候我們訪問:http://eureka2.com:8762/
          這個時候我們發(fā)現(xiàn),第二臺服務(wù)也注冊進來了,是因為這兩個Eureka服務(wù)器互相同步信息,這樣就已經(jīng)完成集群了。
          接著實現(xiàn),這個時候我們停掉eureka1服務(wù),那eureka2中依然有服務(wù),這說明掛掉一臺服務(wù)器注冊服務(wù)仍然可用,那我們在想想,如果我們重啟服務(wù)提供者spring-cloud-learn-provider-dept會發(fā)生什么呢?
          啟動的時候,我們可以看到控制臺是會報錯誤的,因為在spring-cloud-learn-provider-dept我們只向eureka1進行了注冊,那此時eureka1停掉之后找不到注冊地址,就會報錯,但是只是刷新http://eureka2.com:8762/,我們發(fā)現(xiàn)此時服務(wù)提供者依然存在,這個是因為的自我保護機制。
          如果我們重啟eureka2服務(wù),那這個時候就會發(fā)現(xiàn)此時spring-cloud-learn-provider-dept 就沒有了,這個也很好理解,在啟動時兩個服務(wù)會互相同步消息,而這個時候服務(wù)提供者未注冊到eureka1,那eureka2啟動也是沒有效果的,為了解決這個問題,那就讓服務(wù)提供者分別向兩臺eureka服務(wù)器進行注冊:
          spring:application:name: spring-cloud-learn-provider-dept
          server:port: 8763
          eureka:client:serviceUrl:defaultZone: http://eureka1.com:8761/eureka/,http://eureka2.com:8762/eureka/
          二、Eureka與ZooKeeper的比較
          Eureka與ZooKeeper的主要區(qū)別在CAP原則的選擇上,CAP原則是指的是在一個分布式系統(tǒng)中,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分區(qū)容錯性),三者不可兼得(我們常說的魚和熊掌不可兼得)。CAP 原則也是 NoSQL 數(shù)據(jù)庫的基石。
          • 一致性(Consistency,C):在分布式系統(tǒng)中的所有數(shù)據(jù)備份,在同一時刻是否同樣的值。(等同于所有節(jié)點訪問同一份最新的數(shù)據(jù)副本)。
          • 可用性(Availability,A):在一個分布式系統(tǒng)的集群中一部分節(jié)點故障后,該集群是否還能夠正常響應客戶端的讀寫請求。(對數(shù)據(jù)更新具備高可用性)。
          • 分區(qū)容錯性(Partition tolerance,P):大多數(shù)的分布式系統(tǒng)都分布在多個子網(wǎng)絡(luò)中,而每個子網(wǎng)絡(luò)就叫做一個區(qū)(partition)。分區(qū)容錯的意思是,區(qū)間通信可能失敗。在一個分布式系統(tǒng)中一般分區(qū)容錯是無法避免的,因此可以認為 CAP 中的 P 總是成立的。CAP 理論告訴我們,在 C 和 A 之間是無法同時做到。
          這個時候Eureka選擇了 AP,在剛剛的集群配置中,Eureka Server 采用的是Peer to Peer 對等通信。這是一種去中心化的架構(gòu)(參看:微服務(wù)與微服務(wù)架構(gòu)思想與原則),無 master/slave 之分,每一個 Peer 都是對等的。
          在這種架構(gòu)風格中,節(jié)點通過彼此互相注冊來提高可用性,每個節(jié)點需要添加一個或多個有效的 serviceUrl 指向其他節(jié)點。每個節(jié)點都可被視為其他節(jié)點的副本。
          在集群環(huán)境中如果某臺 Eureka Server 宕機,Eureka Client 的請求會自動切換到新的 Eureka Server 節(jié)點上,當宕機的服務(wù)器重新恢復后,Eureka 會再次將其納入到服務(wù)器集群管理之中。
          當節(jié)點開始接受客戶端請求時,所有的操作都會在節(jié)點間進行復制(replicate To Peer)操作,將請求復制到該 Eureka Server 當前所知的其它所有節(jié)點中。
          當一個新的 Eureka Server 節(jié)點啟動后,會首先嘗試從鄰近節(jié)點獲取所有注冊列表信息,并完成初始化。Eureka Server 通過 getEurekaServiceUrls() 方法獲取所有的節(jié)點,并且會通過心跳契約的方式定期更新。
          默認情況下,如果 Eureka Server 在一定時間內(nèi)沒有接收到某個服務(wù)實例的心跳(默認周期為30秒),Eureka Server 將會注銷該實例(默認為90秒,如果某個 eureka.instance.lease-expiration-duration-in-seconds 進行自定義配置)。當 Eureka Server 節(jié)點在短時間內(nèi)丟失過多的心跳時,那么這個節(jié)點就會進入自我保護模式。
          與 Eureka 有所不同,Zookeeper 在設(shè)計時就緊遵CP原則,即任何時候?qū)?Zookeeper 的訪問請求能得到一致的數(shù)據(jù)結(jié)果,同時系統(tǒng)對網(wǎng)絡(luò)分割具備容錯性,但是 Zookeeper 不能保證每次服務(wù)請求都是可達的。
          從 Zookeeper 的實際應用情況來看,在使用 Zookeeper 獲取服務(wù)列表時,如果此時的 Zookeeper 集群中的 Leader 宕機了,該集群就要進行 Leader 的選舉,又或者 Zookeeper 集群中半數(shù)以上服務(wù)器節(jié)點不可用(例如有三個節(jié)點,如果節(jié)點一檢測到節(jié)點三掛了 ,節(jié)點二也檢測到節(jié)點三掛了,那這個節(jié)點才算是真的掛了),那么將無法處理該請求。所以說,Zookeeper 不能保證服務(wù)可用性。
          當然,在大多數(shù)分布式環(huán)境中,尤其是涉及到數(shù)據(jù)存儲的場景,數(shù)據(jù)一致性應該是首先被保證的,這也是 Zookeeper 設(shè)計緊遵CP原則的另一個原因。但是對于服務(wù)發(fā)現(xiàn)來說,情況就不太一樣了,針對同一個服務(wù),即使注冊中心的不同節(jié)點保存的服務(wù)提供者信息不盡相同,也并不會造成災難性的后果。
          因為對于服務(wù)消費者來說,能消費才是最重要的,消費者雖然拿到可能不正確的服務(wù)實例信息后嘗試消費一下,也要勝過因為無法獲取實例信息而不去消費,導致系統(tǒng)異常要好。
          三、Ribbon介紹
          Ribbon是負責客戶端負載均衡的工具,與Nginx的作用類似,負載均衡應該大部分開發(fā)都是知道的,不清楚的百度學習一波。

          簡單的說,Ribbon是Netflix發(fā)布的開源項目,主要功能是提供客戶端的軟件負載均衡算法,將Netflix的中間層服務(wù)連接在一起。Ribbon客戶端組件提供一系列完善的配置項如連接超時,重試等。簡單的說,就是在配置文件中列出Load Balancer(簡稱LB)后面所有的機器,Ribbon會自動的幫助你基于某種規(guī)則(如簡單輪詢,隨機連接等)去連接這些機器。我們也很容易使用Ribbon實現(xiàn)自定義的負載均衡算法。

          Ribbon的配置在上一篇中已經(jīng)給出,實現(xiàn)也是非常的簡單,主要看幾種負載均衡算法:

          策略名 策略描述 實現(xiàn)說明
          BestAvailableRule 選擇一個最小的并發(fā)請求的server 逐個考察Server,如果Server被tripped了,則忽略,在選擇其中ActiveRequestsCount最小的server
          AvailabilityFilteringRule 過濾掉那些因為一直連接失敗的被標記為circuit tripped的后端server,并過濾掉那些高并發(fā)的的后端server(active connections 超過配置的閾值) 使用一個AvailabilityPredicate來包含過濾server的邏輯,其實就就是檢查status里記錄的各個server的運行狀態(tài)
          WeightedResponseTimeRule 根據(jù)相應時間分配一個weight,相應時間越長,weight越小,被選中的可能性越低。 一個后臺線程定期的從status里面讀取評價響應時間,為每個server計算一個weight。Weight的計算也比較簡單responsetime 減去每個server自己平均的responsetime是server的權(quán)重。當剛開始運行,沒有形成statas時,使用roubine策略選擇server。
          RetryRule 對選定的負載均衡策略機上重試機制。 在一個配置時間段內(nèi)當選擇server不成功,則一直嘗試使用subRule的方式選擇一個可用的server
          RoundRobinRule roundRobin方式輪詢選擇server 輪詢index,選擇index對應位置的server
          RandomRule 隨機選擇一個server 在index上隨機,選擇index對應位置的server
          ZoneAvoidanceRule 復合判斷server所在區(qū)域的性能和server的可用性選擇server 使用ZoneAvoidancePredicate和AvailabilityPredicate來判斷是否選擇某個server,前一個判斷判定一個zone的運行性能是否可用,剔除不可用的zone(的所有server),AvailabilityPredicate用于過濾掉連接數(shù)過多的Server。

          當想要修改負載均衡的策略時,直接返回IRule實現(xiàn)即可,例:

          @Beanpublic IRule myRule(){return new RandomRule();}
          四、Feign
          Feign 是一個聲明式的偽 Http 客戶端,它使得寫 Http 客戶端變得更簡單。使用 Feign,只需要創(chuàng)建一個接口并注解。它具有可插拔的注解特性,可使用 Feign 注解和 JAX-RS 注解。Feign 支持可插拔的編碼器和解碼器。Feign 默認集成了 Ribbon,并和 Eureka 結(jié)合,默認實現(xiàn)了負載均衡的效果。
          Feign旨在使編寫Java Http客戶端變得更容易。前面在使用Ribbon+RestTemplate時,利用RestTemplate對http請求的封裝處理,形成了一套模版化的調(diào)用方法。但是在實際開發(fā)中,由于對服務(wù)依賴的調(diào)用可能不止一處,往往一個接口會被多處調(diào)用,所以通常都會針對每個微服務(wù)自行封裝一些客戶端類來包裝這些依賴服務(wù)的調(diào)用。
          所以,F(xiàn)eign在此基礎(chǔ)上做了進一步封裝,由他來幫助我們定義和實現(xiàn)依賴服務(wù)接口的定義。在Feign的實現(xiàn)下,我們只需創(chuàng)建一個接口并使用注解的方式來配置它(以前是Dao接口上面標注Mapper注解,現(xiàn)在是一個微服務(wù)接口上面標注一個Feign注解即可),即可完成對服務(wù)提供方的接口綁定,簡化了使用Spring cloud Ribbon時,自動封裝服務(wù)調(diào)用客戶端的開發(fā)量。
          來實踐感受下:跟之前一樣再創(chuàng)建一個項目spring-cloud-learn-consumer-dept-feign,并新建pom.xml文件,手動添加到maven中:
          <?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion>
          <parent><groupId>com.yuanqinnan</groupId><artifactId>spring-cloud-learn-parent</artifactId><version>1.0.0-SNAPSHOT</version></parent>
          <artifactId>spring-cloud-learn-consumer-dept-feign</artifactId><packaging>jar</packaging>
          <dependencies><!-- Spring Boot Begin --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- Spring Boot End -->
          <!-- Spring Cloud Begin --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!-- Spring Cloud End --></dependencies>
          </project>
          創(chuàng)建啟動類:
          @SpringBootApplication@EnableDiscoveryClient@EnableFeignClientspublic class ConsumerDeptFeignApplication {public static void main(String[] args) {        SpringApplication.run(ConsumerDeptFeignApplication.class, args);    }}
          application.yml:
          spring:application:name: spring-cloud-learn-consumer-dept-feign
          server:port: 8765
          eureka:client:serviceUrl:defaultZone: http://localhost:8761/eureka/
          現(xiàn)在就是調(diào)用服務(wù)的操作,添加一個部門服務(wù):
          @FeignClient(value = "spring-cloud-learn-provider-dept")public interface DeptService {
          @RequestMapping(value = "hi", method = RequestMethod.GET) String sayHi(@RequestParam(value = "message") String message);}
          這里添加的@FeignClient的注解里面的value屬性就是調(diào)用服務(wù)的名稱,而里面的方法的寫法與WebMVC的寫法很類似,相當于調(diào)用服務(wù)的方法
          然后再創(chuàng)建一個controller,,然后創(chuàng)建方法調(diào)用
          @RestControllerpublic class DeptController {@Autowiredprivate DeptService deptService;
          @RequestMapping(value = "hi", method = RequestMethod.GET)public String sayHi(@RequestParam String message) {return deptService.sayHi(message); }}
          這個時候編碼已經(jīng)完成,我們只需要啟動之前項目中的spring-cloud-learn-eureka與spring-cloud-learn-provider-dept,然后再啟動本項目,訪問地址:http://localhost:8765/hi?message=HelloFeign,這個時候服務(wù)就已經(jīng)生效了:
          這樣就已經(jīng)完成Feign組件的使用,非常的簡單, Feign通過接口的方法調(diào)用Rest服務(wù)(之前是Ribbon+RestTemplate),該請求發(fā)送給Eureka服務(wù)器,通過Feign直接找到服務(wù)接口,由于在進行服務(wù)調(diào)用的時候融合了Ribbon技術(shù),所以也支持負載均衡作用。


          想進大廠的小伙伴請注意,

          大廠面試的套路很神奇,

          早做準備對大家更有好處,

          埋頭刷題效率低,

          看面經(jīng)會更有效率!

          小編準備了一份大廠常問面經(jīng)匯總集

          剩下的就不會給大家一展出來了,以上資料按照一下操作即可獲得

          ——將文章進行轉(zhuǎn)發(fā)評論關(guān)注公眾號【Java烤豬皮】,關(guān)注后繼續(xù)后臺回復領(lǐng)取口令“ 666 ”即可免費領(lǐng)文章取中所提供的資料。




          往期精品推薦



          騰訊、阿里、滴滴后臺試題匯集總結(jié) — (含答案)

          面試:史上最全多線程序面試題!

          最新阿里內(nèi)推Java后端試題

          JVM難學?那是因為你沒有真正看完整這篇文章


          結(jié)束


          關(guān)注作者微信公眾號 — 《JAVA烤豬皮》


          了解了更多java后端架構(gòu)知識以及最新面試寶典



          看完本文記得給作者點贊+在看哦~~~大家的支持,是作者來源不斷出文的動力~

          瀏覽 57
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日本亚洲欧洲视频 | 免费高清在线观看黄色视频 | 欧美成人乱码视频 | 污污又黄又爽的网站免费 | 人人摸在线视频 |