響應(yīng)式網(wǎng)站設(shè)計(jì)稿百度知道下載
一.由來
1.在傳統(tǒng)的架構(gòu)里面,我們是通過使用RestTemplate來訪問其他的服務(wù),但是這種方式就存在了一個(gè)很大的缺陷,也就是被調(diào)用方如果發(fā)生了服務(wù)的遷移(IP和端口發(fā)生了變化),那么調(diào)用方也需要同步的在代碼里面進(jìn)行修改,然后重啟服務(wù);
2.這種方法在微服務(wù)新起以后,它的弊端就被無線放大,因此這個(gè)方式就逐漸的演變,然后形成了注冊(cè)中心和配置中心,雖然我們使用注冊(cè)中心解決服務(wù)發(fā)送遷移等等其他的一系列問題,但是最根本的服務(wù)之間的Http訪問問題還是沒有解決;
3.在兩個(gè)服務(wù)之間,需要發(fā)生調(diào)用,它首先需要來到注冊(cè)中心,在注冊(cè)中心拿到相應(yīng)的服務(wù)以后,再在本地進(jìn)行負(fù)載,負(fù)載之后再發(fā)起遠(yuǎn)程調(diào)用,但是在微服務(wù)里面,服務(wù)的調(diào)用是非常的頻繁,比如在一個(gè)方法里面可能出現(xiàn)多個(gè)服務(wù)的調(diào)用,那么同一個(gè)服務(wù)之間的調(diào)用就出現(xiàn)了代碼的冗余。(我們以為最簡(jiǎn)單的為例:比如我們通過一個(gè)代碼來都注冊(cè)中心里面,拉取這個(gè)注冊(cè)配置,然后再本地進(jìn)行負(fù)載,負(fù)載之后再通過RestTemplate進(jìn)行訪問,也就是說一次簡(jiǎn)單的調(diào)用就需要寫三行代碼,如果是多個(gè)服務(wù),就要編寫更多的代碼,這樣就出現(xiàn)了代碼的冗余)
因此,基于這種場(chǎng)景就引入了Fegin。
二.基本概念
1.Fegin是一個(gè)聲明式的Web服務(wù)客戶端,它簡(jiǎn)化了使用基于HTTP的遠(yuǎn)程服務(wù)開發(fā);(相當(dāng)于把我們上面說的三行代碼進(jìn)行了一個(gè)封裝,當(dāng)我們使用遠(yuǎn)程調(diào)用的時(shí)候,直接使用Fegin,然后Fegin的底層來幫我們實(shí)現(xiàn)這個(gè)調(diào)用的過程)
2.Fegin是在RestTemplate和Ribbon的基礎(chǔ)上進(jìn)一步封裝,使用RestTemplate實(shí)現(xiàn)Http調(diào)用,使用Ribbon實(shí)現(xiàn)負(fù)載均衡,關(guān)系如圖所示:
Feign的主要特點(diǎn)和功能包括:
1.聲明式API:Feign允許開發(fā)者使用簡(jiǎn)單的注解來定義和描述對(duì)遠(yuǎn)程服務(wù)的訪問,通過使用注解,開發(fā)者可以輕松地指定URL、HTTP方法、請(qǐng)求參數(shù)、請(qǐng)求頭等信息,使得遠(yuǎn)程調(diào)用變得非常直觀和易于理解。
@FeignClient(name = "example", url = "https://api.example.com")public interface ExampleService {@GetMapping("/endpoint")String getEndpointData();}
2.集成負(fù)載均衡:Feign集成了Ribbon負(fù)載均衡器,可以自動(dòng)實(shí)現(xiàn)客戶端的負(fù)載均衡,它可以根據(jù)服務(wù)名和可用實(shí)例進(jìn)行動(dòng)態(tài)路由,并分發(fā)請(qǐng)求到不同的服務(wù)實(shí)例上,提高系統(tǒng)的可用性和可伸縮性;(我們不需要來處理負(fù)載均衡了,由Fegin來幫我們集成了)
3.容錯(cuò)機(jī)制:Feign支持集成Hystrix容錯(cuò)框架,可以在調(diào)用遠(yuǎn)程服務(wù)時(shí)提供容錯(cuò)和斷路器功能(防止雪崩),當(dāng)遠(yuǎn)程服務(wù)不可用或響應(yīng)時(shí)間過長(zhǎng)時(shí),Feign可以快速失敗并返回預(yù)設(shè)的響應(yīng)結(jié)果,避免對(duì)整個(gè)系統(tǒng)造成級(jí)聯(lián)故障。
3.自定義錯(cuò)誤處理:允許你配置自定義的錯(cuò)誤處理策略,當(dāng)遠(yuǎn)程服務(wù)返回錯(cuò)誤時(shí),能夠進(jìn)行定制化的處理:
@FeignClient(name = "user-service", configuration = CustomFeignConfiguration.class)
public interface UserClient {// 方法定義
}@Configuration
public class CustomFeignConfiguration {@Beanpublic ErrorDecoder errorDecoder() {return new MyCustomErrorDecoder(); // 自定義錯(cuò)誤解碼器}
}
注意:
在2019年,Netflix宣布停止對(duì)Feign的維護(hù),為了替代 Feign ,Spring Cloud 社區(qū)推出了 OpenFeign,它繼承了Feign的所有功能,并增加了對(duì)Spring MVC注解的支持?,OpenFeign目前仍在維護(hù)中,特別是在Spring Cloud Finchley及以上版本中廣泛使用?。
其實(shí),OpenFeign 和 Feign 在使用方式上非常相似,因?yàn)?OpenFeign 是 Feign 的社區(qū)版,并且在設(shè)計(jì)上保持了與 Feign 一致的 API 和功能,換句話說,OpenFeign 基本上是對(duì) Feign 的延續(xù)和改進(jìn),尤其是在與 Spring Cloud 集成方面,所以,二者的使用方式差異并不大。
三.為什么Fegin第一次調(diào)用耗時(shí)很長(zhǎng)?
主要原因是由于Ribbon的懶加載機(jī)制,當(dāng)第一次調(diào)用發(fā)生時(shí),Fegin會(huì)觸發(fā)Ribbon的加載過程,包括從服務(wù)注冊(cè)中心獲取服務(wù)列表、建立連接池等操作,這個(gè)加載過程會(huì)增加首次調(diào)用的耗時(shí)。
解決方案:
ribbon:eager-load:enabled: true // 開啟饑餓加載clients: service-1 // 服務(wù)名,多個(gè)以逗號(hào)隔開
可以在應(yīng)用啟動(dòng)時(shí)預(yù)熱Fegin客戶端,自動(dòng)觸發(fā)一次無關(guān)緊要的調(diào)用,來提前加載Ribbon和其他相關(guān)組件,這個(gè),就相當(dāng)于提前進(jìn)行了一次調(diào)用。
四.Fegin是怎么做負(fù)載均衡?
在Feign中,負(fù)載均衡是通過集成Ribbon來實(shí)現(xiàn)的。
Ribbon是Netfix開源的一個(gè)客戶端負(fù)載均衡器,可以與Feign無縫集成,為Feign提供負(fù)載均衡的能力。
Ribbon在發(fā)起請(qǐng)求前,會(huì)從“服務(wù)中心”獲取服務(wù)列表(清單),然后按照一定的負(fù)載均衡策略去發(fā)起請(qǐng)求,從而實(shí)現(xiàn)客戶端的負(fù)載均衡。
Ribbon本身也維護(hù)著“服務(wù)提供者”清單的有效性,相當(dāng)于是緩存了服務(wù)清單,只有當(dāng)它發(fā)現(xiàn)“服務(wù)提供者”不可用,才會(huì)重新從“服務(wù)中心”獲取有效的“服務(wù)提供者”清單來及時(shí)更新,并不是每一次調(diào)用都會(huì)進(jìn)行拉取,這種方式也提高了整個(gè)系統(tǒng)的性能。
五.Fegin怎么實(shí)現(xiàn)認(rèn)證傳遞?
首先先我們需要知道,為什么Fegin需要實(shí)現(xiàn)認(rèn)證傳遞?先了解一下微服務(wù)的完調(diào)用鏈路:
1.通常用戶在前端進(jìn)行請(qǐng)求,請(qǐng)求就就會(huì)到達(dá)Nginx,然后Nginx就會(huì)進(jìn)行轉(zhuǎn)發(fā),到達(dá)我們的Api網(wǎng)關(guān)層,在Api網(wǎng)關(guān)層就會(huì)通過一個(gè)過濾器來實(shí)現(xiàn)一個(gè)認(rèn)證服務(wù),然后校驗(yàn)通過的請(qǐng)求就會(huì)將相應(yīng)的認(rèn)證信息或者是用戶信息存到請(qǐng)求頭里面;
2.網(wǎng)關(guān)完成認(rèn)證之后,就會(huì)將請(qǐng)求轉(zhuǎn)發(fā)到一個(gè)具體的微服務(wù),微服務(wù)中使用HandlenInterceptor攔截器來獲取Api層傳遞過來的認(rèn)證信息,使用過濾器和攔截器就打通了Api層和微服務(wù)層的一個(gè)認(rèn)證信息的傳遞;
3.但是,其實(shí)大量的請(qǐng)求并不是直接通過網(wǎng)關(guān)層到達(dá)服務(wù)層,而是直接由微服務(wù)之間的調(diào)用產(chǎn)生,微服務(wù)都是通過了HandlenInterceptor攔截器來獲取請(qǐng)求頭里面的信息,而微服務(wù)之間的調(diào)用是通過了openFegin來進(jìn)行處理的,而使用openFegin時(shí)并沒有在請(qǐng)求頭中添加相應(yīng)的一個(gè)請(qǐng)求信息,所以被調(diào)用的微服務(wù)就沒有辦法直接使用攔截器獲取到一個(gè)相應(yīng)的認(rèn)證信息,所以為了解決這個(gè)問題,就需要在openfegin調(diào)用的時(shí)候?qū)⑾鄳?yīng)的用戶信息或認(rèn)證信息存儲(chǔ)到請(qǐng)求頭里面,這樣才能完成微服務(wù)之間的一個(gè)認(rèn)證問題。
解決方案:
比較常見的一種做法就是使用攔截器傳遞認(rèn)證信息,可以通過實(shí)現(xiàn)RequestInterceptor接口來定義攔截器,在攔截器里,把認(rèn)證信息添加到請(qǐng)求頭中,然后將其注冊(cè)到Fegin的配置中。
@Configuration
public class FeignclientConfig {@Beanpublic RequestInterceptor requestInterceptor() {return new RequestInterceptor() {@Overridepublic void apply(RequestTemplate template) {// 添加認(rèn)證信息到請(qǐng)求頭中template.header("Authorization", "Bearer " + getToken());}};}private String getToken() {return "token";}
}