縣城做信息網(wǎng)站賺不賺錢搜索關(guān)鍵詞
一、微服務(wù)演變
1、單體架構(gòu)(Monolithic Architecture)
是一種傳統(tǒng)的軟件架構(gòu)模式,應(yīng)用程序的所有功能和組件都集中在一個單一的應(yīng)用中。
在單體架構(gòu)中,應(yīng)用程序通常由一個大型的、單一的代碼庫組成,其中包含了所有的功能模塊和業(yè)務(wù)邏輯。這個應(yīng)用程序作為一個整體部署和運行在一個應(yīng)用服務(wù)器上,并共享相同的內(nèi)存和數(shù)據(jù)庫。
當(dāng)單體架構(gòu)項目的性能無法滿足需求時,但又希望繼續(xù)沿用單體架構(gòu)的話,你可以采取以下一些優(yōu)化手段來改善性能,如以下方法:
-
使用緩存:引入緩存機制,將經(jīng)常請求的數(shù)據(jù)緩存起來,減少對數(shù)據(jù)庫等后端系統(tǒng)的訪問,以提高性能。
-
數(shù)據(jù)庫優(yōu)化:進行數(shù)據(jù)庫性能調(diào)優(yōu),包括建立索引、優(yōu)化查詢語句、使用合適的數(shù)據(jù)庫引擎等,以提高數(shù)據(jù)庫的響應(yīng)速度。
-
使用消息隊列:引入消息隊列來解耦耗時操作,將其轉(zhuǎn)化為異步的處理任務(wù)。這樣可以提高并發(fā)處理能力和系統(tǒng)的響應(yīng)性能。
-
水平擴展:通過復(fù)制多個實例來處理更多的請求??梢允褂秘撦d均衡器將請求分發(fā)到不同的實例上,從而提高系統(tǒng)的整體性能和容量。
-
引入分布式架構(gòu):將應(yīng)用程序拆分為多個獨立的服務(wù),并通過網(wǎng)絡(luò)進行通信和協(xié)作。這樣可以將負載分散到多個節(jié)點上,提高整體性能和可伸縮性。
?接下來就說一下單體架構(gòu)優(yōu)化中的引入分布式架構(gòu)。
2、分布式架構(gòu)
將系統(tǒng)的各個組件部署在不同的計算機節(jié)點上,并通過網(wǎng)絡(luò)進行通信和協(xié)作的軟件架構(gòu)模式。在分布式架構(gòu)中,各個節(jié)點可以獨立運行和處理任務(wù),并通過消息傳遞、遠程過程調(diào)用或其他通信機制進行數(shù)據(jù)交換和協(xié)調(diào)。
?在使用分布式時,我們就會有一下的疑問:
- 服務(wù)拆分到什么程度?
- 服務(wù)集群地址如何維護?
- 服務(wù)之間如何實現(xiàn)遠程調(diào)用?
- 服務(wù)健康狀況如何感知?
?3、微服務(wù)
?微服務(wù)是一種經(jīng)過改良好的架構(gòu)設(shè)計的分布式架構(gòu)方案,微服務(wù)架構(gòu)特征:
- 單一職責(zé):微服務(wù)拆分力度更小,每個服務(wù)都對應(yīng)唯一的服務(wù)能力,做的單一職責(zé),避免重復(fù)開發(fā)
- 面向服務(wù):微服務(wù)對外暴露業(yè)務(wù)接口
- 自治:團隊獨立、技術(shù)獨立、數(shù)據(jù)獨立、部署獨立
- 隔離性強:服務(wù)調(diào)用做好隔離、容錯、降級,避免出現(xiàn)級聯(lián)問題
假如我們有一個電商系統(tǒng),其中有以下一些微服務(wù):
- 用戶服務(wù)(User Service)負責(zé)用戶的注冊、登錄、信息管理等功能。
- 商品服務(wù)(Product Service)負責(zé)商品的查詢、添加、更新等功能。
- 訂單服務(wù)(Order Service)負責(zé)訂單的創(chuàng)建、支付、取消等功能。
現(xiàn)在假設(shè)用戶服務(wù)依賴于商品服務(wù)來獲取商品信息,并且訂單服務(wù)依賴于用戶服務(wù)來獲取用戶信息。這里我們可以看到微服務(wù)的幾個特征是如何應(yīng)用的:
- 單一職責(zé):每個微服務(wù)都具有清晰的職責(zé)。例如,用戶服務(wù)只負責(zé)用戶相關(guān)的功能,而不涉及商品或訂單。
- 面向服務(wù):每個微服務(wù)都對外暴露業(yè)務(wù)接口,其他微服務(wù)可以通過調(diào)用這些接口來訪問所需的功能。例如,用戶服務(wù)可以提供獲取用戶信息的接口給訂單服務(wù)使用。
- 自治:每個微服務(wù)的團隊在技術(shù)和數(shù)據(jù)上都是獨立的。例如,用戶服務(wù)的團隊可以獨立開發(fā)、測試、部署和擴展該服務(wù),無需依賴其他團隊。
- 隔離性強:微服務(wù)之間的調(diào)用需要做好隔離、容錯和降級,以避免出現(xiàn)級聯(lián)問題。例如,當(dāng)商品服務(wù)不可用時,用戶服務(wù)可以使用緩存或默認數(shù)據(jù)來避免影響用戶操作。
這個例子中提供了不同的微服務(wù)來處理不同的功能,并且彼此解耦、獨立運行。每個微服務(wù)都具有單一職責(zé),對外提供明確定義的業(yè)務(wù)接口,團隊在技術(shù)和數(shù)據(jù)上具有自治能力,同時采取適當(dāng)?shù)母綦x措施來保證系統(tǒng)的彈性和穩(wěn)定性。這些特征有助于提高開發(fā)效率、靈活性和可維護性,使得微服務(wù)架構(gòu)在構(gòu)建大型、復(fù)雜系統(tǒng)時具有優(yōu)勢。
4、 總結(jié)
單體架構(gòu)特點:簡單方便,高度耦合,擴展性差,合適小型項目。如:學(xué)生管理系統(tǒng)。
分布式架構(gòu)特點:松耦合,擴展性好,但架構(gòu)復(fù)雜,難道大,適合大型互聯(lián)網(wǎng)項目。如:京東、淘寶
微服務(wù):一種良好的分布式架構(gòu)方案。
- 優(yōu)點:拆分粒度更小、服務(wù)更獨立、耦合更低
- 缺點:架構(gòu)非常復(fù)雜,運維、監(jiān)控、部署難道更高
5、微服務(wù)架構(gòu)
微服務(wù)這方案需要技術(shù)框架來落地實現(xiàn),全球的互聯(lián)網(wǎng)公司都在積極嘗試自己的微服務(wù)落地技術(shù)。在國內(nèi)最知名的就是SpringCloud和阿里巴巴的Dubbo。
5.1、 微服務(wù)技術(shù)對比
?Dubbo、Spring Cloud、Spring Cloud和Spring Cloud Alibaba都是用于構(gòu)建分布式系統(tǒng)的開源框架。盡管它們的目標(biāo)相同,但它們在實現(xiàn)方式和功能特點上有所不同。
-
Dubbo:Dubbo是一個高性能的分布式服務(wù)框架,由阿里巴巴開發(fā)。它基于傳統(tǒng)的服務(wù)治理理念,提供了服務(wù)注冊、發(fā)現(xiàn)、路由、負載均衡、容錯等功能。Dubbo的核心特點是高性能和低延遲的RPC調(diào)用,適用于大規(guī)模的微服務(wù)架構(gòu)。Dubbo提供了對多種協(xié)議(如Dubbo協(xié)議、REST協(xié)議)和注冊中心(如ZooKeeper、Consul)的支持。
-
Spring Cloud:Spring Cloud是一個由Pivotal開發(fā)的微服務(wù)框架,構(gòu)建在Spring Framework之上,使得構(gòu)建分布式系統(tǒng)更加便捷。它提供了一系列的組件和模塊,用于實現(xiàn)服務(wù)注冊與發(fā)現(xiàn)、負載均衡、斷路器、配置管理、消息總線等功能。Spring Cloud采用了Spring Boot作為底層的開發(fā)框架,提供了更簡潔、快速搭建分布式系統(tǒng)的解決方案。
-
Spring Cloud Alibaba:Spring Cloud Alibaba是Spring Cloud與Alibaba開放平臺合作的結(jié)果,提供了一些在云原生應(yīng)用開發(fā)中常用的解決方案。它主要基于Spring Cloud框架,結(jié)合了一些Alibaba技術(shù)棧,如Nacos(服務(wù)注冊與發(fā)現(xiàn))、Sentinel(流量控制和熔斷降級)、RocketMQ(消息驅(qū)動)等。Spring Cloud Alibaba旨在提供云原生應(yīng)用開發(fā)的全棧解決方案。
雖然Dubbo和Spring Cloud都是用于構(gòu)建分布式系統(tǒng)的框架,但Dubbo更加注重于高性能的RPC調(diào)用和服務(wù)治理,而Spring Cloud則提供了一整套更全面的微服務(wù)解決方案。而Spring Cloud Alibaba則是在Spring Cloud的基礎(chǔ)上,進一步整合了Alibaba的一些技術(shù),為云原生應(yīng)用提供更全面的開發(fā)支持。選擇適合的框架取決于具體的需求、技術(shù)棧和團隊偏好。
5.2、企業(yè)需求
-
Spring Cloud + Spring Cloud Alibaba:Spring Cloud提供了豐富的微服務(wù)組件和解決方案,包括服務(wù)注冊與發(fā)現(xiàn)、負載均衡、斷路器、配置管理等。Spring Cloud Alibaba擴展了Spring Cloud,整合了阿里巴巴技術(shù)棧,如Nacos(服務(wù)注冊與發(fā)現(xiàn))、Sentinel(流量控制和熔斷降級)、RocketMQ(消息驅(qū)動)等。組合使用這兩個框架可以獲得全面的云原生應(yīng)用開發(fā)解決方案,適用于構(gòu)建現(xiàn)代化的微服務(wù)架構(gòu)。
-
Dubbo原生模式 + Spring Cloud Alibaba:Dubbo是一個高性能的RPC框架,提供了服務(wù)治理、負載均衡、容錯等功能。Spring Cloud Alibaba擴展了Dubbo,為Dubbo提供了更多云原生的支持,如Nacos作為注冊中心、Sentinel用于流量控制和熔斷降級等。通過將Dubbo和Spring Cloud Alibaba集成,可以獲得高性能的RPC調(diào)用和全面的云原生的服務(wù)治理解決方案。
無論是使用Spring Cloud + Spring Cloud Alibaba還是Dubbo原生模式 + Spring Cloud Alibaba,都可以受益于Spring Cloud和Spring Cloud Alibaba提供的豐富的微服務(wù)功能和云原生支持。具體選擇哪種組合取決于企業(yè)需求、技術(shù)棧和團隊實際情況。需要評估技術(shù)要求、性能需求、開發(fā)復(fù)雜度等因素,選擇適合的框架組合來構(gòu)建穩(wěn)定、高效的分布式系統(tǒng)。
二、spring cloud
SpringCloud是目前國內(nèi)使用最廣泛的微服務(wù)框架。官網(wǎng)地址:
????????????????????????????????????????????????Spring Cloud
SpringCloud集成了各種微服務(wù)功能組件,并基于SpringBoot實現(xiàn)了這些組件的自動裝配,從而提供了良好的開箱即用體驗:
?springCloud與SpringBoot的版本兼容關(guān)系
?本文學(xué)習(xí)版本是Hoxton.SR10,因此對應(yīng)的springboot版本是2.3.x版本。
1、服務(wù)拆分及遠程調(diào)用
1.1、服務(wù)拆分
1.1.1、服務(wù)拆分注意事項
- 不同微服務(wù),不要重復(fù)開發(fā)相同業(yè)務(wù)
- 微服務(wù)數(shù)據(jù)獨立,不要訪問其他微服務(wù)的數(shù)據(jù)庫
- 微服務(wù)可以將自己的業(yè)務(wù)暴露為接口,供其它微服務(wù)調(diào)用
1.1.2、項目實戰(zhàn)
實戰(zhàn)代碼:阿里云下載
把數(shù)據(jù)庫文件那到數(shù)據(jù)庫管理工具里執(zhí)行和idea中導(dǎo)入cloud-demo項目
最終數(shù)據(jù)庫結(jié)構(gòu):
?對與cloud-demo這個項目主要看一下用戶和訂單如何進行項目拆分的,結(jié)合這單體架構(gòu)的結(jié)果對比一下有什么變化和不同。
1.1.3、總結(jié)
- 微服務(wù)需要根據(jù)業(yè)務(wù)模塊拆分,做到單一職責(zé),不要重復(fù)開發(fā)相同業(yè)務(wù)。
- 微服務(wù)可以將業(yè)務(wù)暴露為接口,供其他微服務(wù)使用。
- 不同微服務(wù)都應(yīng)該有自己獨立的數(shù)據(jù)庫。
1.2、遠程調(diào)用
?需求:根據(jù)訂單id查詢訂單的同時,把訂單所屬的用戶信息一起返回。
1.2.1、遠程調(diào)用方法
?在我們的controller類中使用@GetMapping("/user/{id}")向外暴露了一個接口來訪問,可以將user信息放回為json數(shù)據(jù)格式,我們可以想一下瀏覽器可以發(fā)一個Ajax請求來獲取數(shù)據(jù),我們的訂單服務(wù)可不可以發(fā)一個Ajax請求來獲取數(shù)據(jù)呢?
1.2.2、實現(xiàn)遠程調(diào)用步驟
1)注冊RestTemplate
Spring Cloud中也使用了RestTemplate類。RestTemplate是Spring框架中的一部分,它在Spring Cloud項目中被廣泛用于進行微服務(wù)之間的通信。在微服務(wù)架構(gòu)中,各個微服務(wù)之間通常通過RESTful API進行通信。為了簡化這個過程,Spring Cloud對RestTemplate進行了增強,以便更好地支持微服務(wù)架構(gòu)。在Spring Cloud中,RestTemplate被稱為"服務(wù)調(diào)用"的一部分。通過使用RestTemplate,開發(fā)人員可以方便地發(fā)起HTTP請求來調(diào)用其他微服務(wù)的API。Spring Cloud還提供了一些增強功能,例如服務(wù)發(fā)現(xiàn)和負載均衡。開發(fā)人員可以使用服務(wù)名代替具體的URL,Spring Cloud會自動根據(jù)服務(wù)名找到可用的實例并進行負載均衡,從而實現(xiàn)更靈活和高效的服務(wù)調(diào)用。需要注意的是,自Spring Cloud 2020.0.0版本(即Hoxton.SR9及之后的版本)開始,官方推薦使用WebClient替代RestTemplate作為HTTP客戶端,因為WebClient提供了更強大、更靈活的功能,并且更適用于非阻塞的響應(yīng)式編程模型。但是,為了向后兼容,RestTemplate仍然可以繼續(xù)使用并被支持。
在order-service的OrderApplication中注冊ResteTemplate,將ResteTemplate用@Bean注解注冊為spring管理的對象,以后不管在什么地方都可以使用到RestTemplate對象。
?完成調(diào)用主要是在service層中實現(xiàn),向被調(diào)用服務(wù)發(fā)起一個Rest請求,在需要調(diào)用其他服務(wù)的服務(wù)中使用,實現(xiàn)步驟:
1、在服務(wù)啟動類中注冊RestTemplate,如這里是在order的啟動類中
2、在要調(diào)用其他服務(wù)的服務(wù)中的service層中自動裝配RestTemplate對象
3、使用RestTemplate的api來實現(xiàn)即可,里面有很多api,這里我使用的是getForObject()方法
4、將遠程調(diào)用返回的數(shù)據(jù)封裝到要封裝的對象中即可,這里我使用的是將遠程調(diào)用獲取的user對象信息封裝到order對象中。
1.3、提供者與消費者
?服務(wù)提供者:一次業(yè)務(wù)中,被其他微服務(wù)調(diào)用的服務(wù)。(提供接口給其他服務(wù)調(diào)用)如:user服務(wù)
服務(wù)消費者:一次業(yè)務(wù)中,調(diào)用其他微服務(wù)的服務(wù)。(調(diào)用其他微服務(wù)提供的接口)如order服務(wù)
總結(jié):
1.服務(wù)調(diào)用關(guān)系
- ? ? ? ? ? ? ? ? ? ? ? ? ? ?服務(wù)提供者:暴露接口給其它微服務(wù)調(diào)用
- ? ? ? ? ? ? ? ? ? ? ? ? ? ?服務(wù)消費者:調(diào)用其它微服務(wù)提供的接口
- ? ? ? ? ? ? ? ? ? ? ? ? ? ?提供者與消費者角色其實是相對的
- ? ? ? ? ? ? ? ? ? ? ? ? ? ?一個服務(wù)可以同時是服務(wù)提供者和服務(wù)消費者
三、Eureka注冊中心
1、服務(wù)調(diào)用出現(xiàn)的問題
在前面我們使用RestTemplate來實現(xiàn)服務(wù)遠程調(diào)用,在寫url時使用的是硬編碼方式,就會產(chǎn)生以下的問題,這些問題是值得我們考慮一下的。
- 服務(wù)消費者該如何獲取服務(wù)提供者的地址信息?
- 如果有多個服務(wù)提供者,消費者該如何選擇?
- 消費者如何得知服務(wù)提供者的健康狀態(tài)?
2、 Eureka基本原理
Eureka是Netflix開源的服務(wù)治理框架,在Spring Cloud中廣泛應(yīng)用。它的基本原理是建立了一個分布式的服務(wù)注冊中心,用于管理和維護各個微服務(wù)實例的注冊和發(fā)現(xiàn)。
以下是Eureka的基本原理:
-
Eureka服務(wù)器:Eureka由一個或多個Eureka服務(wù)器組成,它們構(gòu)成了服務(wù)注冊中心。每個微服務(wù)實例都將自己的信息注冊到Eureka服務(wù)器,包括服務(wù)名、主機名、端口號等。
-
服務(wù)注冊:微服務(wù)啟動時,會向Eureka服務(wù)器發(fā)送注冊請求,將自己的信息注冊到注冊中心。注冊中心維護一個服務(wù)注冊表,記錄所有已注冊的微服務(wù)實例。
-
服務(wù)發(fā)現(xiàn):其他微服務(wù)需要調(diào)用某個服務(wù)時,首先向注冊中心發(fā)送查詢請求,獲得目標(biāo)服務(wù)的實例列表。注冊中心將會返回所有可用的服務(wù)實例信息,包括IP地址、端口號等。
-
服務(wù)監(jiān)控:Eureka服務(wù)器會定期向已注冊的微服務(wù)實例發(fā)送心跳請求,微服務(wù)實例返回響應(yīng)以證明自己的健康狀態(tài)。如果一個微服務(wù)長時間未發(fā)送心跳消息或返回異常狀態(tài),Eureka服務(wù)器將從注冊表中刪除該實例。
-
服務(wù)同步:Eureka服務(wù)器之間會相互復(fù)制注冊表信息,以保證數(shù)據(jù)的一致性。當(dāng)有新的微服務(wù)實例注冊或注銷時,注冊中心會通知其他服務(wù)器進行注冊表更新。
通過Eureka提供的服務(wù)注冊和發(fā)現(xiàn)機制,微服務(wù)之間可以動態(tài)地發(fā)現(xiàn)和調(diào)用其他微服務(wù),從而實現(xiàn)了服務(wù)之間的解耦和靈活性。Eureka還提供了負載均衡、故障恢復(fù)等一些附加功能,使得微服務(wù)架構(gòu)更加可靠和高效。
回顧之前我們的幾個問題:
消費者該如何獲取服務(wù)提供者具體信息?
- 服務(wù)提供者啟動時向eureka注冊自己的信息
- eureka保存這些信息
- 消費者根據(jù)服務(wù)名稱向eureka拉取提供者信息
如果有多個服務(wù)提供者,消費者該如何選擇?
- 服務(wù)消費者利用負載均衡算法,從服務(wù)列表中挑選一個
消費者如何感知服務(wù)提供者健康狀態(tài)?
- 服務(wù)提供者會每隔30秒向EurekaServer發(fā)送心跳請求,報告健康狀態(tài)
- eureka會更新記錄服務(wù)列表信息,心跳不正常會被剔除
- 消費者就可以拉取到最新的信息
?總結(jié)
在Eureka架構(gòu)中,微服務(wù)角色有兩類:
? ?1、EurekaServer:服務(wù)端,注冊中心
- 記錄服務(wù)信息
- 心跳監(jiān)控
? ?2、EurekaClient: 客戶端
? ? ? ? ?1)Provider:服務(wù)提供者,例如案例中的 user-service
- ? ? ? ? ? ? ? 注冊自己的信息到EurekaServer
- ? ? ? ? ? ? ? 每隔30秒向EurekaServer發(fā)送心跳
? ? ? ? ?2)consumer:服務(wù)消費者,例如案例中的 order-service
- ? ? ? ? ? ? ? ? ? ? 根據(jù)服務(wù)名稱從EurekaServer拉取服務(wù)列表
- ? ? ? ? ? ? ? ? ? ? 基于服務(wù)列表做負載均衡,選中一個微服務(wù)后發(fā)起遠程調(diào)用
3、手動實戰(zhàn)
3.1、搭建eureka服務(wù)注冊中心(服務(wù)名稱)
1、創(chuàng)建項目,引入spring-cloud-starter-netflix-eureka-server的依賴
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency>
?2、啟用Eureka服務(wù)器:創(chuàng)建一個啟動類,并使用@EnableEurekaServer
注解來啟用Eureka服務(wù)器功能。
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {public static void main(String[] args) {SpringApplication.run(EurekaApplication.class,args);}
}
3、配置Eureka服務(wù)器:在應(yīng)用程序的配置文件(如application.properties
或application.yml
)中配置Eureka服務(wù)器的相關(guān)信息,例如:
# 服務(wù)器配置
server:port: 10001 # Eureka服務(wù)器運行的端口號# Spring應(yīng)用程序配置
spring:application:name: eurekaserver # Eureka服務(wù)器應(yīng)用程序的名稱# Eureka客戶端配置
eureka:client:service-url:defaultZone: http://localhost:10001/eureka/# Eureka客戶端注冊自身的Eureka服務(wù)器的URL# 在本例中,將Eureka服務(wù)器的URL設(shè)置為運行在10001端口的本地服務(wù)器
3.2、注冊user-service
這個操作是在user-service項目下實現(xiàn)的,主要是將服務(wù)信息注冊到Eureka服務(wù)端,eureka將這些服務(wù)信息保存到注冊表中進行管理。
將user-service服務(wù)注冊到EurekaServer步驟:
1、在user-service項目中引入spring-cloud-starter-netflix-eureka-client的依賴
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency>
2、在application.yml位置文件中編寫配置
spring:application:name: userservice #配置服務(wù)名稱
eureka:client:service-url:defaultZone: http://localhost:10001/eureka/ #配置eureka服務(wù)地址信息
其實orderservice的注冊也是這兩個步驟,我就寫了。
做完之后,我我們可以瀏覽一下eureka的服務(wù)網(wǎng)站看一下:http://localhost:10001
這里的端口號是你在自己的eureka的配置文件application.yml配置的eureka端口號一致。
?總結(jié):
1.服務(wù)注冊
- 引入eureka-client依賴
- 在application.yml中配置eureka地址
2.無論是消費者還是提供者,引入eureka-client依賴
知道eureka(服務(wù)注冊中心)地址后,都可以完成服務(wù)注冊
3.3、在order-service完成服務(wù)拉取
服務(wù)拉取是基于服務(wù)名稱獲取服務(wù)列表,然后在對服務(wù)列表做負載均衡
1.修改OrderService的代碼,修改訪問的url路徑,用服務(wù)名代替ip、端口:
String url ="http://userservice/user/" + order.getUserId();
2.在order-service項目的啟動類OrderApplication中的RestTemplate添加負載均衡注解:
@Bean
@LoadBalanced #負載均衡
public RestTemplate restTemplate() {return new RestTemplate();
}
總結(jié)
1.搭建EurekaServer
- 引入eureka-server依賴
- 添加@EnableEurekaServer注解
- 在application.yml中配置eureka地址
2.服務(wù)注冊
- 引入eureka-client依賴
- 在application.yml中配置連接eureka服務(wù)注冊中心地址
3.服務(wù)發(fā)現(xiàn)
- 引入eureka-client依賴
- 在application.yml中配置eureka服務(wù)注冊中心地址
- 給RestTemplate添加@LoadBalanced注解
- 用服務(wù)提供者的服務(wù)名稱遠程調(diào)用
四、Ribbon負載均衡
Ribbon是一個負載均衡解決方案,主要用于在分布式系統(tǒng)中將負載均勻地分發(fā)給多個服務(wù)實例。它是Netflix開 源的一個組件,常用于微服務(wù)架構(gòu)中。
1、負載均衡流程
?Ribbon的負載均衡原理可以概括如下:
-
服務(wù)注冊:Ribbon首先需要與服務(wù)注冊中心(如Eureka、Consul等)進行交互,獲取可用的服務(wù)實例列表。
-
負載均衡策略:Ribbon支持多種負載均衡策略,如隨機策略、輪詢策略、權(quán)重策略等。根據(jù)選擇的策略,Ribbon會根據(jù)服務(wù)實例的狀態(tài)、性能等因素來選擇一個合適的服務(wù)實例。
-
服務(wù)調(diào)用:一旦選擇了一個服務(wù)實例,Ribbon會將請求發(fā)送給該實例。它會維護一個與服務(wù)實例的長連接,并在需要時將請求發(fā)送給該實例。
-
失敗處理:如果請求在與服務(wù)實例的通信中失敗,Ribbon會嘗試選擇另一個可用的服務(wù)實例進行重試,以增加系統(tǒng)的可用性。
Ribbon還可以與其他組件配合使用,例如Netflix的Hystrix熔斷器,用于實現(xiàn)服務(wù)的容錯和故障保護。
總之,Ribbon通過動態(tài)獲取服務(wù)實例列表并根據(jù)負載均衡策略選擇合適的實例來進行負載均衡,從而提高系統(tǒng)的性能、可用性和可擴展性。
源碼執(zhí)行流程:
?2、Ribbon負載均衡策略
Ribbon負載均衡規(guī)則是一個叫做IRule的接口來實現(xiàn)的,每個子接口都是一種規(guī)則:
2.1、 負載均衡策略
?2.2、調(diào)整負責(zé)均衡策略的規(guī)則
通過定義IRule實現(xiàn)可以修改負載均衡規(guī)則,有兩種方式:
方式一:代碼方式
如消費者服務(wù)order-service,只要在OrderApplication類中定義一個新的IRule:
@Bean
public IRule iRule(){return new RandomRule();
}
其實也不一定要在OrderApplication啟動類中配置,也可以自己創(chuàng)建一個配置類來配置,在有@configuration注解的類就可以。
這種配置方案是全局的配置,只要使用了這種配置方案,以后不管你調(diào)用的是user-service服務(wù)還是order-service服務(wù)都是使用這里的配置方案。
方式二:配置文件方式
在order-service的application.yml文件中,添加新的配置也可以修改規(guī)則:
userservice: #被調(diào)用微服務(wù)器的服務(wù)名稱ribbon:NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #負載均衡規(guī)則
這種配置方案是只針對某個微服務(wù)的,是局部配置。
3、Ribbon餓加載
Ribbon默認是采用懶加載,即第一次訪問才會創(chuàng)建LoadBalanceClient,請求時間會很長。
而餓加載則會在項目啟動時創(chuàng)建,降低每一次訪問的耗時
3.1、配置開啟配置饑餓加載
#當(dāng)服務(wù)饑餓加載
ribbon:eager-load:enabled: true #開啟饑餓加載clients: userservice #指定對userservice這個服務(wù)饑餓加載#當(dāng)有多個服務(wù)需要饑餓加載可以用下面的方式:
ribbon:eager-load:enabled: true #開啟饑餓加載clients: #指定對userservice這個服務(wù)饑餓加載- userservice - xxservice
總結(jié)
1.Ribbon負載均衡規(guī)則
- 規(guī)則接口是IRule
- 默認實現(xiàn)是ZoneAvoidanceRule,根據(jù)zone選擇服務(wù)列表,然后輪詢
2.負載均衡自定義方式
- 代碼方式:配置靈活,但修改時需要重新打包布
- 配置方式:直觀,方便,無需重新打包發(fā)布但是無法做全局配置
3.饑餓加載
- 開啟饑餓加載
- 指定饑餓加載的微服務(wù)名稱
五、Nacos注冊中心
微服務(wù)的注冊中心我們已經(jīng)學(xué)了eureka,大家肯定會有疑問,為啥還有學(xué)校nacos呢?
其實nacos不僅有服務(wù)注冊中心和服務(wù)發(fā)現(xiàn)功能,還有更加強大的功能。
1、nacos和eureka對比
Nacos和Eureka是兩個常用的服務(wù)發(fā)現(xiàn)和注冊工具,它們都具有類似的功能,但在一些方面存在一些差異。以下是Nacos和Eureka的一些對比:
-
開發(fā)者生態(tài)圈:Nacos是由Alibaba開發(fā)并開源,擁有龐大的Alibaba生態(tài)圈支持,而Eureka是由Netflix開發(fā)并開源,得到了Netflix和Spring Cloud社區(qū)的廣泛應(yīng)用。
-
功能和特性:Nacos提供了更多的功能和特性,除了服務(wù)注冊與發(fā)現(xiàn)外,還包括配置管理、動態(tài)DNS、動態(tài)路由和流量管理等功能。Eureka主要關(guān)注服務(wù)注冊與發(fā)現(xiàn)的功能。
-
容錯性:Nacos具有更強的容錯性,支持多數(shù)據(jù)中心的分布式部署,可以保證在網(wǎng)絡(luò)分區(qū)和節(jié)點故障情況下的高可用性。Eureka在這方面的容錯性相對較弱。
-
數(shù)據(jù)一致性:Nacos使用Raft算法來實現(xiàn)數(shù)據(jù)一致性和高可用性,而Eureka使用的是AP模型,即優(yōu)先保證可用性而不保證強一致性。
-
社區(qū)活躍度:Nacos的開源社區(qū)活躍度相對較高,有更多的貢獻者和更新的版本發(fā)布。Eureka的開源社區(qū)相對較少活躍,更新較為緩慢。
選擇使用Nacos還是Eureka可以根據(jù)具體需求和項目背景來決定。如果需要更多的功能和特性,以及較強的容錯性和高可用性,Nacos可能是更好的選擇。如果項目已經(jīng)依賴于Netflix和Spring Cloud生態(tài)圈,或者對于服務(wù)注冊和發(fā)現(xiàn)的簡單功能需求,Eureka可能是更適合的選項。
2、Nacos下載安裝服務(wù)注冊中心
2.1下載nacos
在Nacos的GitHub頁面,提供有下載鏈接,可以下載編譯好的Nacos服務(wù)端或者源代碼:
GitHub主頁:https://github.com/alibaba/nacos
GitHub的Release下載頁:https://github.com/alibaba/nacos/releases
這里我提供了阿里云盤下載:Nacos1.4.1
2.2、解壓Nacos
?我這里使用的是在Windows下安裝的。
直接解壓到一個沒有中文字符的路徑下。
?目錄說明:
- - bin:啟動腳本
- - conf:配置文件
2.2.1、配置端口
Nacos的默認端口是8848,如果你電腦上的其它進程占用了8848端口,請先嘗試關(guān)閉該進程。
**如果無法關(guān)閉占用8848端口的進程**,也可以進入nacos的conf目錄,修改配置文件中的端口:
修改其中的內(nèi)容修改為一個沒有被占用的端口號。
2.2.2.啟動nacos服務(wù)注冊中心
啟動非常簡單,進入bin目錄,進入cmd窗口執(zhí)行下面的命令
startup.cmd -m standalone#startup.cmd -m standalone 的含義是執(zhí)行Nacos服務(wù)器的啟動腳本,并使用獨立模式啟動Nacos服務(wù)器。
#這將在單個節(jié)點上運行Nacos,并使用默認的配置文件和端口。這個命令適用于簡單部署或測試,并非生產(chǎn)環(huán)境下常見的集群模式啟動命令。
執(zhí)行后的效果如圖:?
在瀏覽器輸入地址:http://127.0.0.1:8848/nacos即可:
用戶名和密碼都是:nacos
?網(wǎng)頁直接就是中文的,對于英語不太好的比eureka的友好。
3、將服務(wù)注冊到nacos服務(wù)注冊中心
1、在cloud-demo父工程中添加spring-cloud-alibaba的管理依賴:
<!--nacos版本管理--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>2.2.5.RELEASE</version><type>pom</type><scope>import</scope></dependency>
2、注釋掉order-service和user-service中原有的eureka依賴。
3、添加nacos的客戶端依賴:
<!-- nacos客戶端依賴包 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency>
4、修改user-service & order-service中的application.yml文件,注釋掉eureka的地址,添加nacos地址:
spring:cloud:nacos:server-addr: localhost:8848
啟動項目測試:
?其實eureka和nacos在spring-cloud中除了依賴和端口號配置不同外其他的使用都是一樣的,他們底層使用的接口都是一樣的,所以代碼其他地方根本不用做改變。
總結(jié):
1.Nacos服務(wù)搭建
- 下載安裝包
- 解壓
- 在bin目錄下運行指令:startup.cmd -mstandalone
2.Nacos服務(wù)注冊或發(fā)現(xiàn)
- 引入nacos.discovery依賴
- 配置nacos地址spring.cloudnacos.server-addr
4、Nacos服務(wù)分級存儲模型
之前我們在學(xué)中,我們的服務(wù)分層都是只有兩層的,第一層是服務(wù),第二層是實例(如user-service、order-service),在我們部署時,都是將這些服務(wù)我實例部署到一個機器上或者一個機房里,但是如果這個機房收到破壞(地震、火災(zāi))時,服務(wù)就無法訪問了。
? 而nacos服務(wù)分層存儲模型則引出了集群的概念,一個集群就好比是我們的一個機房,而我們的一個服務(wù)下面就可以部署很多個集群,每個集群就可以部署在全球各地(北京、上海、深圳等),因此服務(wù)的層次結(jié)構(gòu)就變成了三層(服務(wù)、集群、實例)。
4.1、服務(wù)跨集群調(diào)用問題
- ?服務(wù)調(diào)用盡可能選擇本地集群的服務(wù),跨集群調(diào)用延遲高
- 本地集群不可以訪問時,在去訪問其他集群
?4.2、服務(wù)集群實現(xiàn)
1、修改application.yml,添加如下內(nèi)容,配置服務(wù)集群名稱
spring:cloud:nacos:server-addr: localhost:8848 #nacos 服務(wù)端地址cluster-name: YN #配置集群名稱,也就是機房位置,例如:YN ,云南
2、在Nacos控制臺可以看到集群變化
?現(xiàn)在的集群變成了yn,在沒有配置集群名稱是default。
總結(jié)
1.Nacos服務(wù)分級存儲模型
- 一級是服務(wù),例如userservice
- 二級是集群,例如杭州或上海
- 三級是實例,例如杭州機房的某臺部署了userservice的服務(wù)器
2.如何設(shè)置實例的集群屬性
- 修改application.yml文件,添加spring.cloud.nacos.discovery.cluster-name屬性即可
4.3、Nacos集群負載均衡
Nacos集群負載均衡的規(guī)則其實是優(yōu)先選擇本集群內(nèi)的服務(wù),如果本服務(wù)掛了,才會去選擇其他集群的服務(wù)來訪問。
配置
1、修改order-service中的application.yml,設(shè)置集群為HZ:
spring:cloud:nacos:server-addr: Localhost:8848 # nacos 服務(wù)端地加discovery:cLuster-name: HZdiscovery:cluster-name: bj #配集群名稱,也就是機房位置
2、然后在order-service中設(shè)置負載均衡的IRule為NacosRule,這個規(guī)則優(yōu)先會尋找與自己同集群的服務(wù):
userservice: #服務(wù)名稱ribbon:NFLoadBalancerRulecassName: com.alibaba.cloud.nacos.ribbon.NacosRule #負載均衡規(guī)則
3、注意將user-service的權(quán)重都設(shè)置為1
總結(jié):
1.NacosRule負載均衡策略
- 優(yōu)先選擇同集群服務(wù)實例列表
- 本地集群找不到提供者,才去其它集群尋找,并且會報警告
- 確定了可用實例列表后,再采用隨機負載均衡挑選實例
4.4、根據(jù)權(quán)重負載均衡
假設(shè)有一個微服務(wù)架構(gòu)的電子商務(wù)網(wǎng)站,其中包括以下幾個服務(wù):商品服務(wù)
、訂單服務(wù)
和用戶服務(wù)
。這些服務(wù)都注冊到了Nacos中進行服務(wù)發(fā)現(xiàn),并且它們有不同的實例數(shù)和性能配置。在這種情況下,可以通過基于權(quán)重的負載均衡來實現(xiàn)對這些服務(wù)實例的合理請求分配。以下是一些示例場景:
-
不同實例性能差異較大:
假設(shè)
商品服務(wù)
有3個實例,其中實例A和實例B配置較高,實例C配置較低。此時,可以設(shè)置實例A和實例B的權(quán)重為2,實例C的權(quán)重為1。這樣,每次有請求到來時,有較高性能的實例A和實例B將會處理更多的請求,而較低性能的實例C將會處理較少的請求,從而實現(xiàn)了性能調(diào)控。 -
服務(wù)實例容量不均衡:
假設(shè)
訂單服務(wù)
有5個實例,其中實例A、B和C的容量比實例D和E大??梢詾閷嵗鼳、B和C設(shè)置較高的權(quán)重值,如3,而為實例D和E設(shè)置較低的權(quán)重值,如1。這樣,請求將均衡分配到實例A、B和C之間,并保持實例D和E的請求數(shù)較少。 -
降低故障實例的負載:
假設(shè)
用戶服務(wù)
有4個實例,其中實例A由于某種原因,出現(xiàn)了故障或不穩(wěn)定情況。為了減少對實例A的請求分配,可以為其設(shè)置較低的權(quán)重值,如0,而將其他正常的實例設(shè)置為較高的權(quán)重值,如3。這樣,請求將主要被分配給其他正常的實例,降低了對故障實例A的負載。
通過在Nacos中設(shè)置服務(wù)實例的權(quán)重,可以根據(jù)實際情況動態(tài)調(diào)整請求的負載比例。這樣能夠充分利用資源、提高系統(tǒng)性能、保證服務(wù)穩(wěn)定性,并對不同實例進行合理分配。
Nacos提供了權(quán)重配置來控制訪問頻率,權(quán)重越大則訪問頻率越高。
配置
?
?4.5、環(huán)境隔離-namespace
1、認識環(huán)境隔離-namvespace
應(yīng)用場景:
假設(shè)有一個電商平臺,該平臺設(shè)計了一個基于Nacos的命名空間配置和服務(wù)注冊方案,以支持環(huán)境隔離和多租戶功能。
首先,假設(shè)該電商平臺有三個環(huán)境:開發(fā)環(huán)境、測試環(huán)境和生產(chǎn)環(huán)境。每個環(huán)境都有獨立的配置和服務(wù)需求。
-
環(huán)境隔離和配置管理:
-
使用Nacos的命名空間功能,平臺管理員可以創(chuàng)建三個命名空間:dev-namespace、test-namespace和prod-namespace。
-
在dev-namespace中,可以配置開發(fā)環(huán)境所需的各種參數(shù),如數(shù)據(jù)庫連接信息、調(diào)試模式等。
-
在test-namespace中,可以配置測試環(huán)境所需的參數(shù),如測試數(shù)據(jù)庫連接信息、測試數(shù)據(jù)源等。
-
在prod-namespace中,可以配置生產(chǎn)環(huán)境所需的參數(shù),如正式數(shù)據(jù)庫連接信息、生產(chǎn)級別的服務(wù)配置等。
-
每個命名空間下的配置項是相互隔離的,這樣就保證了不同環(huán)境配置的獨立性,并且可根據(jù)需求靈活管理和更新配置信息。
-
-
服務(wù)注冊和版本管理:
-
在每個命名空間中,可以注冊相應(yīng)環(huán)境需要的服務(wù)實例,如商品服務(wù)、訂單服務(wù)等。
-
平臺管理員可以使用命名空間功能來管理不同環(huán)境的服務(wù)注冊表,確保每個環(huán)境只能訪問屬于自己的服務(wù)實例。
-
每個命名空間可以獨立管理服務(wù)實例的版本,例如,在開發(fā)環(huán)境中可以注冊和測試新的服務(wù)版本,而在生產(chǎn)環(huán)境中則使用穩(wěn)定的服務(wù)版本。
-
通過這樣的命名空間配置和服務(wù)注冊方案,電商平臺能夠?qū)崿F(xiàn)對不同環(huán)境的配置和服務(wù)進行隔離,并支持多租戶功能。開發(fā)團隊可以獨立管理各自環(huán)境的配置和服務(wù),而不會相互干擾。此外,平臺還可以利用灰度發(fā)布和版本管理功能,在不同命名空間中進行服務(wù)版本控制,確保系統(tǒng)穩(wěn)定性和可用性。
2、配置命名空間
1)創(chuàng)建命名空間(在nacos服務(wù)頁面創(chuàng)建)
?2、將服務(wù)配置到指定的命名空間中(修改application.yml配置文件)
server:port: 8081
spring:datasource:url: jdbc:mysql://192.168.10.130:3306/cloud-user?useSSL=falseusername: rootpassword: rootdriver-class-name: com.mysql.jdbc.Driverapplication:name: userservice #配置服務(wù)名稱cloud:nacos:server-addr: localhost:8848discovery:cluster-name: yn #集群名稱,地址在云南namespace: 074da7cb-c3e3-4848-b893-3d15114e8729 #命令空間id
?此時,配置了namespace的服務(wù)已經(jīng)被配置到dev中了
?如果此時使用order-service去調(diào)用user-service就會報錯了
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalStateException: No instances available for userservice] with root causeservlet .service()的servlet [dispatcherServlet]在上下文與路徑[]拋出異常[請求處理失敗;嵌套異常是java.lang.IllegalStateException: No instances available for userservice],有根本原因
5、nacos注冊中介細節(jié)分析
?服務(wù)注冊:服務(wù)提供者啟動時,會向服務(wù)注冊中心發(fā)起注冊請求,包括服務(wù)名、IP 地址、端口等。注冊中心會將這些信息保存起來。
服務(wù)發(fā)現(xiàn):服務(wù)發(fā)現(xiàn)有兩種(pull和push相結(jié)合)
- pull:服務(wù)消費者會每隔30秒定時主動向服務(wù)注冊中心發(fā)起請求,來拉取服務(wù)信息,在服務(wù)消費者中有一個服務(wù)列表緩存,用于緩存從服務(wù)注冊中心拉取下的服務(wù)信息。
- push:當(dāng)有服務(wù)停掉后服務(wù)注冊中心會主動推送變更信息給消費者,消費者就會更新服務(wù)列表緩存。
心跳與健康檢查:也是有兩種(對臨時實力和非臨時實例)
- 臨時實例:采用心跳檢測,是臨時實例主動向注冊中心發(fā)送心跳檢測,如果一段時間注冊中心沒有收到臨時實例心跳檢測,就會剔除該臨時實例。
- 非臨時實例:采用nacos主動詢問,nacos主動詢問非臨時實例的健康狀態(tài),如果非臨時實例停止了,也不會剔除非臨時實例,只是修改非臨時實例的健康轉(zhuǎn)態(tài),會等待非臨時實例健康。
負載均衡:負載均衡和流量控制是由服務(wù)消費者一側(cè)的客戶端組件來實現(xiàn)的,而不是由注冊中心來處理。當(dāng)客戶端從Nacos注冊中心獲取到可用的服務(wù)實例列表后,負載均衡和流量控制的責(zé)任落在了客戶端的實現(xiàn)上。
5.1、臨時實例與非臨時實例
Nacos中的實例分為臨時實例和非臨時實例,它們在生命周期和用途上有所不同:
1、非臨時實例(Persistent Instance):
- 非臨時實例是指注冊到Nacos注冊中心的服務(wù)實例,其生命周期不會受到外部因素的影響,除非主動取消注冊或服務(wù)下線。
- 這種實例適用于通常情況下穩(wěn)定運行的服務(wù),它們的注冊信息會被持久化存儲在Nacos服務(wù)器中,提供持久性的服務(wù)發(fā)現(xiàn)和注冊功能。
2、臨時實例(Ephemeral Instance):
- 臨時實例是指服務(wù)實例在持有連接的客戶端斷開連接時,會自動從Nacos注冊中心上注銷的一種實例類型。
- 當(dāng)客戶端與Nacos注冊中心建立心跳連接后,臨時實例會周期性地向注冊中心進行連接進行檢測。如果一段時間注冊中心沒有收到臨時實例的心態(tài)檢測,注冊中心會將對應(yīng)的實例注銷。
- 臨時實例適用于動態(tài)擴縮容、臨時性訪問等場景,允許實例根據(jù)連接狀態(tài)進行動態(tài)管理。
臨時實例和非臨時實例在實踐中有不同的應(yīng)用場景:
-
對于穩(wěn)定運行的服務(wù),應(yīng)使用非臨時實例。這樣服務(wù)實例的注冊信息將持久存在于注冊中心中,即使服務(wù)發(fā)生故障或重啟,也能保證注冊信息的持久性,其他服務(wù)能夠繼續(xù)發(fā)現(xiàn)和使用該實例。
-
對于臨時性的任務(wù),如定時任務(wù)、臨時數(shù)據(jù)處理服務(wù)等,可以選擇使用臨時實例。這樣在任務(wù)完成后,實例會自動注銷,降低注冊中心中無用實例的數(shù)量,也能更好地適應(yīng)動態(tài)需求變化。
需要注意的是,臨時實例的自動注銷是基于與Nacos注冊中心之間的心跳連接,而非基于服務(wù)實例的具體運行狀態(tài)。因此,在使用臨時實例時,需要相應(yīng)地配置和管理心跳連接,以保證實例的不間斷注冊和注銷。
5.2、配置臨時實例與非臨時實例(默認是臨時實例)
服務(wù)注冊到nacos時,可以選擇注冊為臨時或非臨時實例,通過在application.yml文件中添加下面的配置來設(shè)置:
spring:cloud:nacos:discovery: #discovery:發(fā)現(xiàn),透露 ; ephemeral:短暫的ephemeral: false #設(shè)置為非臨時實例
?總結(jié)
1.Nacos與eureka的共同點
- 都支持服務(wù)注冊和服務(wù)拉取
- 都支持服務(wù)提供者心跳方式做健康檢測
2.Nacos與Eureka的區(qū)別
- Nacos支持服務(wù)端主動檢測提供者狀態(tài):臨時實例采用心跳模式,非臨時實例采用主動檢測模式
- 臨時實例心跳不正常會被剔除,非臨時實例則不會被剔除
- Nacos支持服務(wù)列表變更的消息推送模式,服務(wù)列表更新更及時
- Nacos集群默認采用AP方式,當(dāng)集群中存在非臨時實例時,采用CP模式;Eureka采用AP方式
6、Nacos配置管理
以下是幾個使用Nacos配置管理的實際業(yè)務(wù)場景的例子:
-
微服務(wù)配置管理:
假設(shè)你的公司采用了微服務(wù)架構(gòu),有多個微服務(wù)需要連接到不同的數(shù)據(jù)庫。通過使用Nacos配置管理,你可以將每個微服務(wù)的數(shù)據(jù)庫連接信息存儲在Nacos中,并動態(tài)地更新配置。例如,當(dāng)你需要更改數(shù)據(jù)庫的連接地址或密碼時,你可以直接在Nacos中修改配置,而無需重新部署微服務(wù),所有微服務(wù)將自動獲取最新的配置信息。 -
多環(huán)境配置管理:
假設(shè)你的應(yīng)用在開發(fā)、測試和生產(chǎn)環(huán)境中運行,并且每個環(huán)境都有不同的配置。使用Nacos配置管理,你可以為每個環(huán)境創(chuàng)建不同的配置文件,并通過Nacos的命名空間和配置組進行組織。開發(fā)人員可以通過選擇不同的命名空間和配置組,輕松地切換到不同的環(huán)境,而不必手動修改配置文件。 -
動態(tài)路由配置:
假設(shè)你的微服務(wù)架構(gòu)中使用了Spring Cloud Gateway作為API網(wǎng)關(guān),并且你希望能夠動態(tài)路由請求到不同的后端服務(wù)。通過使用Nacos配置管理,你可以將路由規(guī)則存儲在Nacos中,并通過Spring Cloud Gateway與Nacos集成。當(dāng)需要更新路由規(guī)則時,你可以直接在Nacos中修改配置,Spring Cloud Gateway將自動更新路由,并將請求動態(tài)地轉(zhuǎn)發(fā)到相應(yīng)的后端服務(wù)。 -
定時任務(wù)配置:
假設(shè)你的應(yīng)用需要執(zhí)行定時任務(wù),例如生成報表或清理數(shù)據(jù)。通過使用Nacos配置管理,你可以將定時任務(wù)的觸發(fā)時間、任務(wù)參數(shù)等信息存儲在Nacos中,并由任務(wù)調(diào)度器定期從Nacos獲取最新的配置。當(dāng)你需要調(diào)整定時任務(wù)的執(zhí)行時間或參數(shù)時,只需在Nacos中修改配置,任務(wù)調(diào)度器將自動根據(jù)最新的配置執(zhí)行任務(wù)。
這些例子只是Nacos配置管理功能的一部分,Nacos還提供了更多的特性,例如配置監(jiān)聽、配置推送等,可以根據(jù)具體的業(yè)務(wù)需求進行靈活使用。
6.1、統(tǒng)一配置管理
6.1.1、配置更改熱更新
?在Nacos中添加配置信息:
?在彈出表單中填寫配置信息:
?在nacos服務(wù)頁面中配置,讓服務(wù)找到nacos的配置:
1、引入nacos的配置管理客戶依賴:
<!--nacos配置管理依賴--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency>
2、在userservice中的resource目錄添加一個bootstrap.yml文件,這個文件是引導(dǎo)文件,優(yōu)先級高于application.yml:
spring:application:name: userservice #配置服務(wù)名稱cloud:nacos:server-addr: localhost:8848 #配置nacos服務(wù)地址config:file-extension: yaml #文件后綴profiles:active: dev #開發(fā)環(huán)境,這里是dev
可以在Usercontroller類中獲取一下nacos配置的信息來驗證一下:
@Value("${pattern.dateformat}")private String dateformat;@GetMapping("/now")public String now(){return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat));}
6.1.2、配置自動刷新
nacos中的配置文件變更后,微服務(wù)無需重新啟動就可以感知。不過需要通過下面兩種配置實現(xiàn):
方式一:在@Value注入的變量所在類上添加注解@RefreshScope
?方式二:使用@ConfigurationProperties注解
這種方式使用的是約束大于配置的配置方法。
@Data
@Component
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties {private String dateformat;
}
使用了Spring框架的注解(Data,Component,ConfigurationProperties)。這段代碼定義了一個名為PatternProperties的類。
@ConfigurationProperties注解是Spring框架中用于綁定配置屬性的注解。它的prefix屬性指定了配置文件中的屬性前綴為"pattern",這意味著在配置文件中,所有以"pattern"開頭的屬性會被綁定到PatternProperties類的對應(yīng)屬性上。
PatternProperties類中只有一個私有的String類型屬性dateformat,它對應(yīng)配置文件中的"pattern.dateformat"屬性。在配置文件中,你可以設(shè)置這個屬性的值,例如:
pattern:dateformat: yyyy-MM-dd HH:mm:ss
這樣,當(dāng)你運行程序時,Spring框架會自動將配置文件中的值綁定到PatternProperties類的dateformat屬性上,你可以通過獲取PatternProperties實例的方式來訪問并使用這個屬性的值。
在類中使用nacos中配置時可以通過以下方式獲取:
?總結(jié)
Nacos配置更改后,微服務(wù)可以實現(xiàn)熱更新,方式:
- 通過@Value注解注入,結(jié)合@RefreshScope來刷新
- 通過@ConfigurationProperties注入,自動刷新
注意事項:
- 不是所有的配置都適合放到配置中心,維護起來比較麻煩
- 建議將一些關(guān)鍵參數(shù),需要運行時調(diào)整的參數(shù)放到nacos配置中心,一般都是自定義配置
7、Nacos集群搭建
7.1、集群結(jié)構(gòu)圖
官方給出的Nacos集群圖:
其中包含3個nacos節(jié)點,然后一個負載均衡器代理3個Nacos。這里負載均衡器可以使用nginx。
DNS(Domain Name System)、SLB(Server Load Balancer)和Nacos可以一起使用來構(gòu)建一個完整的服務(wù)發(fā)現(xiàn)和負載均衡的系統(tǒng)。
DNS是用于將域名解析為對應(yīng)的IP地址的系統(tǒng)。在服務(wù)發(fā)現(xiàn)和負載均衡中,DNS可以被用來解析服務(wù)名稱為對應(yīng)的服務(wù)實例的IP地址。例如,假設(shè)有一個服務(wù)名為"my-service",通過將其注冊到DNS中,可以將"my-service"解析為具體的服務(wù)實例的IP地址。
SLB是一種負載均衡器,用于將流量分發(fā)到多個后端服務(wù)實例上,從而實現(xiàn)負載均衡和高可用性。SLB可以接收客戶端請求,并根據(jù)負載均衡算法將請求分發(fā)到多個服務(wù)實例上。例如,當(dāng)有多個服務(wù)實例提供相同的服務(wù)時,SLB可以根據(jù)負載情況,將請求分發(fā)到負載較低的實例上,以實現(xiàn)流量的均衡分布。
Nacos是一個用于服務(wù)發(fā)現(xiàn)、配置管理和服務(wù)治理的開源項目。在服務(wù)發(fā)現(xiàn)和負載均衡中,Nacos作為服務(wù)注冊中心和配置中心,可以用來管理各個服務(wù)實例的注冊和注銷,以及維護服務(wù)實例的元數(shù)據(jù)信息。Nacos可以提供給SLB和DNS所需的服務(wù)實例信息,從而實現(xiàn)服務(wù)發(fā)現(xiàn)和負載均衡的功能。
結(jié)合這三個組件,整體的架構(gòu)可以如下所示:
-
服務(wù)實例注冊:服務(wù)實例可以將自己的元數(shù)據(jù)信息注冊到Nacos中,包括服務(wù)名稱、IP地址、端口等信息。
-
Nacos服務(wù)注冊中心:Nacos注冊中心負責(zé)存儲和管理所有服務(wù)實例的元數(shù)據(jù)信息。
-
Nacos配置中心:Nacos配置中心負責(zé)存儲和管理應(yīng)用程序的配置信息。
-
DNS解析:客戶端可以通過DNS解析服務(wù)名稱為具體的服務(wù)實例的IP地址。
-
SLB負載均衡器:SLB可以接收客戶端請求,并根據(jù)負載均衡算法將請求分發(fā)到多個服務(wù)實例上。
通過這樣的結(jié)構(gòu),客戶端可以通過DNS解析獲取到服務(wù)實例的IP地址,并通過SLB將請求發(fā)送到可用的服務(wù)實例上,實現(xiàn)負載均衡。同時,Nacos作為服務(wù)注冊中心和配置中心,可以管理服務(wù)實例的注冊和配置信息,以確保服務(wù)的可用性和配置的一致性。這樣的架構(gòu)既提供了可靠的服務(wù)發(fā)現(xiàn)和負載均衡,也保證了配置的集中管理和動態(tài)更新能力。
我們計劃的集群結(jié)構(gòu):
?三個nacos節(jié)點的地址:
| 節(jié)點 ? | ip ? ? ? ? ? ?| port || nacos1 | 192.168.150.1 | 8845 || nacos2 | 192.168.150.1 | 8846 || nacos3 | 192.168.150.1 | 8847 |
7.2、集群搭建
搭建集群的基本步驟:
- 搭建數(shù)據(jù)庫,初始化數(shù)據(jù)庫表結(jié)構(gòu)- 下載nacos安裝包- 配置nacos- 啟動nacos集群- nginx反向代理
六、Feign遠程調(diào)用
RestTemplate方法調(diào)用存在的問題
先看一下我們以前利用RestTemplate發(fā)起遠程調(diào)用的代碼:
存在下面的問題:
- 代碼可讀性差,編程體驗不統(tǒng)一
- 參數(shù)復(fù)雜URL難維護
1、Feign的介紹
Feign 提供了一種簡單且優(yōu)雅的方式來定義和調(diào)用基于HTTP的遠程服務(wù)。通過使用Feign,您可以在客戶端代碼中定義接口,然后Feign會根據(jù)這些接口的定義自動生成實際的HTTP請求,并將其轉(zhuǎn)發(fā)到遠程服務(wù)。這樣,您可以像調(diào)用本地方法一樣調(diào)用遠程服務(wù)的方法,無需顯式地處理HTTP請求和響應(yīng)。
Feign 還支持對請求進行編碼和解碼、錯誤處理、請求和響應(yīng)攔截器等功能,使得在微服務(wù)架構(gòu)中處理遠程服務(wù)變得更加方便和高效。
使用Feign的一些優(yōu)點包括:
- 簡化了客戶端代碼,使其更易于維護和理解。
- 減少了手動處理HTTP請求和響應(yīng)的工作量。
- 支持多種編解碼器,可處理多種數(shù)據(jù)格式。
- 可與Spring Cloud等微服務(wù)框架無縫集成。
在使用Feign時,您需要定義一個Java接口,該接口包含與遠程服務(wù)相對應(yīng)的方法和參數(shù)。然后,通過在應(yīng)用程序的配置中啟用Feign并使用Spring的依賴注入功能,您可以將Feign客戶端注入到您的代碼中,從而實現(xiàn)對遠程服務(wù)的調(diào)用。
Feign作為一個聲明式的HTTP客戶端,在微服務(wù)架構(gòu)和分布式系統(tǒng)中有許多應(yīng)用場景。以下是一些常見的使用場景:
-
微服務(wù)間的通信:在微服務(wù)架構(gòu)中,各個服務(wù)之間需要頻繁地進行通信,Feign可以幫助簡化服務(wù)間的HTTP通信,使得調(diào)用遠程服務(wù)更加方便。
-
服務(wù)消費者:當(dāng)一個服務(wù)需要調(diào)用其他服務(wù)提供的API時,可以使用Feign來作為客戶端來消費這些服務(wù),而無需手動處理HTTP請求和響應(yīng)。
-
代理遠程API:Feign可以將遠程服務(wù)的API映射為本地接口,使得調(diào)用遠程服務(wù)的過程就像調(diào)用本地方法一樣簡單。
-
負載均衡:結(jié)合負載均衡的工具(如Ribbon),Feign可以實現(xiàn)在多個服務(wù)實例之間進行負載均衡,從而提高系統(tǒng)的可用性和性能。
-
聲明式的錯誤處理:Feign支持定義統(tǒng)一的錯誤處理邏輯,使得在發(fā)生錯誤時可以采取一致的處理方式,從而減少重復(fù)代碼。
-
數(shù)據(jù)格式處理:Feign支持多種編解碼器,可以處理不同的數(shù)據(jù)格式,例如JSON、XML等,使得數(shù)據(jù)的傳輸和解析更加靈活和便捷。
-
請求攔截與日志:Feign支持請求和響應(yīng)攔截器,可以在發(fā)送請求和接收響應(yīng)時進行攔截和處理,例如記錄日志、鑒權(quán)等。
總體而言,Feign適用于任何需要在微服務(wù)架構(gòu)中進行HTTP通信的場景,特別是當(dāng)您希望簡化遠程服務(wù)調(diào)用的代碼并增加可讀性和可維護性時,Feign是一個非常有用的工具。
2、定義和使用Feign客戶端
在之前我是在調(diào)用其他服務(wù)提供的接口是使用的是RestTempale,為什么還要學(xué)Feign呢?
Feign和RestTemplate都是在Spring框架中用于進行HTTP請求的工具,但它們在使用方式和特點上有一些區(qū)別。
-
聲明式 vs. 編程式:
- Feign是一個聲明式的HTTP客戶端,它允許您通過定義接口來描述對遠程服務(wù)的請求,并自動生成底層HTTP調(diào)用。Feign使用注解來配置請求的URL、HTTP方法、請求參數(shù)等信息,使得代碼更加簡潔和易讀。
- RestTemplate是一個編程式的HTTP客戶端,您需要在代碼中顯式地構(gòu)建HTTP請求,包括指定URL、HTTP方法、請求頭、請求體等信息。雖然可以通過RestTemplate靈活地控制請求細節(jié),但相比Feign,代碼可能會更冗長和復(fù)雜。
-
整合Spring Cloud vs. 單獨使用:
- Feign是Spring Cloud項目的一部分,它與Spring Cloud的其他組件(如Eureka、Ribbon、Hystrix等)緊密集成,使得在微服務(wù)架構(gòu)中使用Feign更加方便,并且提供了一些額外的特性,如負載均衡、服務(wù)發(fā)現(xiàn)等。
- RestTemplate是Spring Framework的一部分,它可以單獨使用,沒有與Spring Cloud的深度集成。如果您在非微服務(wù)環(huán)境中,或者不需要Spring Cloud提供的其他功能,RestTemplate是一個不錯的選擇。
-
自動化的負載均衡:
- Feign與Ribbon(Spring Cloud中的負載均衡組件)集成,可以自動進行負載均衡,使得在多個服務(wù)實例中選擇合適的目標(biāo)服務(wù)。
- RestTemplate在默認情況下不支持自動的負載均衡,您需要手動編寫代碼來實現(xiàn)負載均衡,或者結(jié)合Ribbon來實現(xiàn)自動化負載均衡。
-
請求攔截器和錯誤處理:
- Feign允許您定義請求和響應(yīng)攔截器,從而可以在發(fā)送請求和接收響應(yīng)時進行攔截和處理,例如記錄日志、鑒權(quán)等。它還提供了聲明式的錯誤處理機制,讓您可以統(tǒng)一處理請求錯誤。
- RestTemplate也支持請求和響應(yīng)攔截器,但是在處理錯誤時可能相對繁瑣,需要通過捕獲異常等方式來處理請求錯誤。
綜上所述,如果您在使用Spring Cloud和微服務(wù)架構(gòu),特別是在Feign與Ribbon、Eureka等組件進行集成時,Feign可能是更好的選擇,因為它提供了一種簡單且聲明式的方式來定義和調(diào)用遠程服務(wù)。然而,如果您在非微服務(wù)環(huán)境或不需要Spring Cloud提供的其他功能,RestTemplate仍然是一個可行的選擇,尤其是當(dāng)您需要更多的靈活性和對HTTP請求的直接控制時。
2.1、Feign實戰(zhàn)
定義和使用Feign客戶端需要以下步驟:
1、添加依賴:首先,您需要在項目中添加Feign的依賴。如果您是使用Spring Boot項目,可以在pom.xml中添加以下依賴:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2、啟用Feign客戶端:為了使Feign客戶端生效,您需要在Spring Boot應(yīng)用程序的主類上添加@EnableFeignClients
注解,這將啟用Feign客戶端的自動配置和發(fā)現(xiàn)。
@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
@EnableFeignClients
public class OrderApplication {public static void main(String[] args) {SpringApplication.run(OrderApplication.class, args);}}
3、創(chuàng)建Feign客戶端接口:接下來,您需要定義一個Java接口,該接口將包含與遠程服務(wù)相對應(yīng)的方法和參數(shù)。這些方法的定義類似于普通的Spring組件接口,但是您可以使用Spring的注解來定義遠程服務(wù)的URL、HTTP方法和其他相關(guān)信息。
package cn.itcast.order.clients;import cn.itcast.order.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;@FeignClient("userservice") //使用@FeignClient來指導(dǎo)這個接口所有接口方法要訪問的服務(wù)名稱
public interface UserClient {//定義調(diào)用接口@GetMapping("/user/{id}") User findUserById(@PathVariable("id") Long id);
}
?4、使用Feign客戶端:現(xiàn)在您可以在其他組件或服務(wù)中注入Feign客戶端,并使用它來調(diào)用遠程服務(wù)的方法。
package cn.itcast.order.service;import cn.itcast.order.clients.UserClient;
import cn.itcast.order.mapper.OrderMapper;
import cn.itcast.order.pojo.Order;
import cn.itcast.order.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class OrderService {@Autowiredprivate OrderMapper orderMapper;@Autowiredprivate UserClient userClient; //注入User的Feign客戶端public Order queryOrderById(Long id){Order order = orderMapper.findById(id);Long userId = order.getUserId();//使用Feign遠程調(diào)用User user = userClient.findUserById(userId);order.setUser(user);return order;}
}
總結(jié)
Feign的使用步驟
- 引入依賴
- 添加@EnableFeignClients注解
- 編寫FeignClient接口
- 使用FeignClient中定義的方法代替RestTemplate
3、自定義Feign的配置
Feign運行自定義配置來覆蓋默認配置,可以修改的配置如下:
?一般我們需要配置的就是日志級別。
日志級別
Feign支持四種不同的日志級別,您可以根據(jù)需要選擇適合的日志級別。這些日志級別用于控制Feign在發(fā)送請求和接收響應(yīng)時記錄的日志信息的詳細程度。
-
NONE:該日志級別最低,不記錄任何日志信息。如果您不想在控制臺輸出任何關(guān)于Feign請求和響應(yīng)的日志,可以選擇此級別。
-
BASIC:在BASIC級別下,Feign僅記錄請求方法、URL和響應(yīng)狀態(tài)碼的基本信息。這對于快速了解請求的基本情況很有幫助,但不會記錄請求和響應(yīng)的詳細內(nèi)容。
-
HEADERS:在HEADERS級別下,Feign將記錄請求和響應(yīng)的頭部信息,包括請求頭和響應(yīng)頭。這樣可以更詳細地查看請求和響應(yīng)的頭部信息,有助于調(diào)試和了解請求的上下文。
-
FULL:FULL級別是最詳細的日志級別,它會記錄請求和響應(yīng)的所有詳細信息,包括請求頭、請求體、響應(yīng)頭和響應(yīng)體。如果您需要完整的請求和響應(yīng)信息來進行詳細的調(diào)試和排查問題,FULL級別是最合適的選擇。
3.1自定義Feign的配置方式
方式一:配置文件方式
當(dāng)使用配置文件的方式來配置Feign的自定義配置時,您可以借助Spring Boot的屬性配置功能來實現(xiàn)。通過在配置文件(如application.properties或application.yml)中添加特定的屬性,您可以自定義Feign的行為。
首先,您需要在配置文件中添加Feign的相關(guān)屬性。以YAML格式的配置文件為例,假設(shè)您想要配置Feign的日志級別為FULL,可以這樣寫:
1、全局生效
# application.yml
feign:client:config:default: #這里用default就是全局配置,如果是寫服務(wù)器名稱,則是針對在某個微服務(wù)的配置loggerLevel: full #日志級別
2、局部生效
# application.yml
feign:client:config:orderservice: #這里用服務(wù)名稱,則只針對這個服務(wù)的配置loggerLevel: full #日志級別
方式二:java代碼方式,需要先聲明一個Bean:
在使用Feign時,您可以通過自定義配置來修改其行為和屬性。為了自定義Feign的配置,您需要創(chuàng)建一個配置類,并在其中添加相關(guān)的Bean定義。下面是一個簡單的示例來說明如何自定義Feign的配置:
package cn.itcast.order.config;import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class FeignConfig {@Beanpublic Logger.Level feignLogLevel(){return Logger.Level.BASIC;}
}
全局配置:
如果是全局配置,則把它放到@EnableFeignClients這個注解中:
@EnableFeignClients(defaultConfiguration = FeignConfig.class)
局部配置:
如果是局部配置,則把它放到@FeignClient這個注解中:
@FeignClient(value = "userservice",configuration = FeignConfig.class)
總結(jié)
Feign的日志配置
1.方式一是配置文件,feign.client.config.xxx.loggerLevel
- O如果xxx是default則代表全局
- 如果xxx是服務(wù)名稱,例如userservice則代表某服務(wù)
2.方式二是java代碼配置Logger.Level這個Bean
- 如果在@EnableFeignClients注解聲明則代表全局
- 如果在@FeignClient注解中聲明則代表某服務(wù)
4、Feign的性能優(yōu)化
Feign的底層客戶端實現(xiàn)是通過集成了其他HTTP客戶端庫來實現(xiàn)的。具體來說,Feign支持兩種主要的HTTP客戶端實現(xiàn):JDK的URLConnection和Apache HttpClient。
-
JDK的URLConnection:這是Java標(biāo)準庫中提供的用于HTTP通信的API。Feign可以直接使用JDK的URLConnection來發(fā)送HTTP請求。它是輕量級的,對于簡單的HTTP通信,可能足夠滿足需求。如果您在項目中沒有引入其他HTTP客戶端庫,Feign會默認使用JDK的URLConnection作為底層的客戶端實現(xiàn)。
-
Apache HttpClient:Apache HttpClient是Apache基金會提供的一個功能豐富、靈活的HTTP客戶端庫。它提供了許多高級功能,如連接池、重試機制、認證等。如果您在項目中引入了Apache HttpClient的依賴,Feign會自動選擇使用Apache HttpClient作為底層的客戶端實現(xiàn)。
-
OkHttp:OkHttp是Square公司開發(fā)的一款高效的HTTP客戶端庫。它支持HTTP/2、連接池、攔截器等現(xiàn)代特性。如果您在項目中引入了OkHttp的依賴,Feign會自動切換到OkHttp作為底層實現(xiàn)。
Feign的這種設(shè)計使得您可以根據(jù)需要靈活地選擇底層的HTTP客戶端。默認情況下,如果項目中沒有引入其他HTTP客戶端庫,Feign將使用JDK的URLConnection作為底層客戶端。如果您希望使用Apache HttpClient或OkHttp,只需在項目中添加相應(yīng)的依賴,Feign會自動檢測并使用它們作為底層實現(xiàn)。
通過這種方式,Feign可以同時滿足不同項目對HTTP客戶端的需求,并提供簡便的遠程服務(wù)調(diào)用方式。
因此優(yōu)化Feign的性能主要包括:
- 使用連接池代替默認的URLConnection
- 日志級別,做好使用basic或者none
4.1、 Feign性能優(yōu)化HttpClient的支持:
1、Feign添加HttpClient的支持:
引入依賴:
<dependency><groupId>io.github.openfeign</groupId><artifactId>feign-httpclient</artifactId></dependency>
配置連接池:
#feign自定義配置,配置日志級別
feign:client:config:default: #這里用default就是全局配置,如果是寫服務(wù)器名稱,則是針對在某個微服務(wù)的配置loggerLevel: basic #日志級別httpclient:enabled: true #開啟feign對HttpClient的支持max-connections: 200 #最大連接數(shù)量max-connections-per-route: 50 #每個路徑的最大連接數(shù)量
總結(jié)
Feign的優(yōu)化
1.日志級別盡量用basic
2.使用HttpClient或OKHttp代替URLConnection
- 引入feign-httpClient依賴
- 配置文件開啟httpClient功能,設(shè)置連接池參數(shù)
5、Feign的最佳實際
方式一(繼承):給消費者的FeignClient和提供者的controller系統(tǒng)定義一個父接口作為標(biāo)準。
這種實現(xiàn)方式雖然可以讓Controller和Feign Client共享同一個接口定義,但存在一些問題和注意事項:
-
潛在的耦合:共享同一個接口定義會讓Controller和Feign Client在代碼層面產(chǎn)生耦合,導(dǎo)致它們緊密地關(guān)聯(lián)在一起。一旦接口定義發(fā)生變化,兩者都需要進行相應(yīng)的修改,這可能影響到多個模塊。
-
不符合單一職責(zé)原則:Controller負責(zé)處理HTTP請求和返回響應(yīng),而Feign Client負責(zé)遠程服務(wù)調(diào)用。將它們共享同一個接口可能會讓代碼功能變得混亂,違反了單一職責(zé)原則。
-
難以做到完全解耦:盡管接口定義可以共享,但是在Feign Client的實現(xiàn)中,仍然需要涉及到遠程服務(wù)調(diào)用的邏輯。這會讓Feign Client的實現(xiàn)和Controller之間仍然有一定的耦合。
-
接口定義可能會變得復(fù)雜:為了適應(yīng)不同的調(diào)用場景,共享接口可能會變得復(fù)雜,可能需要添加各種參數(shù)和注解,從而導(dǎo)致接口的冗長和不易維護。
-
功能不一致問題:在Controller和Feign Client共享同一個接口的情況下,兩者的功能可能不完全一致。在Controller中可能需要做一些本地邏輯處理,而在Feign Client中可能需要進行額外的遠程服務(wù)調(diào)用。
綜上所述,雖然共享接口可以在一定程度上減少重復(fù)代碼,但也會引入潛在的問題和復(fù)雜性。在實際開發(fā)中,更常見的做法是將Controller和Feign Client分別定義獨立的接口,通過接口定義來規(guī)范各自的功能和職責(zé)。在需要共享方法定義的情況下,可以使用Java接口繼承來實現(xiàn)方法的復(fù)用,而避免在Feign Client中直接實現(xiàn)Controller的方法。這樣可以更好地保持代碼的清晰和可維護性,并符合單一職責(zé)原則。
方式二(抽取):將FeignClient抽取為獨立模塊,并且把接口有關(guān)的POJO、默認的Feign配置都放到這個模塊中,提供給所有消費者使用
以前實現(xiàn)?
假如:我們有order-service、pay-service和user-service兩個服務(wù),現(xiàn)在order-service和pay-service都要去調(diào)用user-service提供的接口,我們就得order-service和pay-service服務(wù)里都要實現(xiàn)UserClient,假如我們不止只有這兩個服務(wù)調(diào)用user-service呢,有10個、20個服務(wù)都要調(diào)用,那UserClient就得寫10遍、20遍,就會重復(fù)的開發(fā)代碼了。
現(xiàn)在
我們獨立創(chuàng)建一個項目,將哪些重復(fù)的代碼編寫的東西全部放到這個項目/模塊中(如UserClient、User實體類、DefaultConfig等),我們可以把這個項目的內(nèi)容打成jar包,假如以后服務(wù)需要的時候直接引用依賴就可以
?總結(jié)
Feign的最佳實踐
- 讓controller和FeignClient繼承同一接口
- 將FeignClient、poJo、Feign的默認配置都定義到一個項目中,供所有消費者使用
?抽取FeignClient
實現(xiàn)最佳實踐方式二的步驟如下:
1、創(chuàng)建一個module,命名為feign-api,然后引入feign的starter依賴
引入feign的starter依賴:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency>
2、將order-service中編寫的UserClient、User、DefaultFeignConfiguration都復(fù)制到feign-api項目中
?之前在order-service服務(wù)模塊中餓這些東西就可以刪除了。
?3、在order-service中引入feign-api的依賴
<!--引入feign的同一api--><dependency><groupId>cn.itcast.demo</groupId><artifactId>feign-api</artifactId><version>1.0</version></dependency>
這個依賴是我們項目中的feign-api模塊里的內(nèi)容。
4、修改order-service中的所有與上述三個組件有關(guān)的import部分,改成導(dǎo)入feign-api中的包
5、重啟測試
當(dāng)定義的FeignClient不在springApplication的包掃描范圍時,這些FeignClient無法使用問題
重啟order-service服務(wù)后我們會發(fā)現(xiàn)報錯了
Field userClient in cn.itcast.order.service.OrderService required a bean of type 'cn.itcast.feign.clients.UserClient' that could not be found.該錯誤信息表明在OrderService類中的userClient字段的類型為cn.itcast.feign.clients.UserClient,但是Spring容器中找不到該類型的Bean。
說明我們在自動裝配UserClient時是找不到這個對象的實例的,原因是我們現(xiàn)在在order-service模塊中使用的UserClient是通過添加了feign-api依賴而導(dǎo)進來的,在order-service模塊啟動時spring只會對啟動類所在目錄及這個目錄里所有類進行掃描注冊到spring容器中的,而UserClient所在的包就沒有被掃描到,所在在order-service這個模塊中的spring容器中就找不到了對于的對象實例了。
解決辦法方式一:指定FeignClient所在包
@EnableFeignClients(basePackages = "cn.itcast.feign.clients")
解決辦法方式二:指定FeignClient字節(jié)碼
@EnableFeignClients(clients = {UserClient.class})
總結(jié)
不同包的FeignClient的導(dǎo)入有兩種方式
- 在@EnableFeignClients注解中添加basePackages,指定FeignClient所在的包
- 在@EnableFeignClients注解中添加clients,指定具體FeignClient的字節(jié)碼
七、Gateway服務(wù)網(wǎng)關(guān)
網(wǎng)關(guān)(Gateway)服務(wù)在微服務(wù)架構(gòu)中起著重要的作用。它是位于客戶端和后端微服務(wù)之間的中間層,用于處理和轉(zhuǎn)發(fā)請求。為什么要使用網(wǎng)關(guān)服務(wù)呢?以下是一些主要的原因:
-
統(tǒng)一入口:網(wǎng)關(guān)服務(wù)提供了一個統(tǒng)一的入口,客戶端只需要向網(wǎng)關(guān)發(fā)送請求,而不需要直接調(diào)用各個微服務(wù)。這樣簡化了客戶端的調(diào)用邏輯,同時也方便地對請求進行統(tǒng)一管理和處理。
-
路由和負載均衡:網(wǎng)關(guān)服務(wù)可以根據(jù)請求的URL路徑或其他條件將請求路由到相應(yīng)的微服務(wù)實例。它還可以配合負載均衡算法,確保請求被均勻地分發(fā)給不同的服務(wù)實例,提高了系統(tǒng)的可用性和性能。
-
安全控制:通過網(wǎng)關(guān)服務(wù),可以實現(xiàn)對請求進行安全控制和認證。網(wǎng)關(guān)可以驗證請求的身份、權(quán)限以及合法性,確保只有授權(quán)的請求能夠訪問相應(yīng)的微服務(wù)。
-
聚合和分解請求:網(wǎng)關(guān)服務(wù)可以聚合多個微服務(wù)的請求,將它們合并為一個請求返回給客戶端,從而減少了客戶端與后端服務(wù)之間的請求次數(shù),降低了網(wǎng)絡(luò)開銷。
-
緩存:網(wǎng)關(guān)服務(wù)可以對請求的響應(yīng)進行緩存,從而減少重復(fù)請求對后端服務(wù)的壓力,提高了系統(tǒng)的性能和響應(yīng)速度。
-
降級和容錯:網(wǎng)關(guān)服務(wù)可以實現(xiàn)對后端服務(wù)的降級和容錯處理。當(dāng)某個微服務(wù)出現(xiàn)故障或不可用時,網(wǎng)關(guān)可以提供默認的響應(yīng)或調(diào)用備用服務(wù),避免了系統(tǒng)級的故障。
-
監(jiān)控和日志:通過網(wǎng)關(guān)服務(wù),可以實現(xiàn)對請求和響應(yīng)進行監(jiān)控和日志記錄。這有助于實時追蹤請求的流程和性能,發(fā)現(xiàn)問題并進行及時的處理。
綜上所述,網(wǎng)關(guān)服務(wù)在微服務(wù)架構(gòu)中扮演了一個重要的角色,它提供了統(tǒng)一入口、路由和負載均衡、安全控制、聚合和分解請求、緩存、降級和容錯、監(jiān)控和日志等功能,為整個系統(tǒng)提供了更高效、更安全、更穩(wěn)定的請求處理和管理能力。
1、網(wǎng)關(guān)技術(shù)
?在springcloud中網(wǎng)關(guān)的實現(xiàn)有兩種:gateway和zuul
Zuul和Spring Cloud Gateway都是常用的網(wǎng)關(guān)實現(xiàn),用于在微服務(wù)架構(gòu)中處理和轉(zhuǎn)發(fā)請求。它們都可以作為反向代理和請求路由器,但在設(shè)計和功能上有一些區(qū)別。
-
Zuul:
Zuul是Netflix提供的網(wǎng)關(guān)服務(wù),被稱為Netflix Zuul。它是一個基于Servlet的網(wǎng)關(guān)實現(xiàn),構(gòu)建在傳統(tǒng)的Spring Cloud項目上。Zuul 1.x版本采用阻塞式I/O模型,Zuul 2.x版本采用非阻塞式I/O模型,基于Netty。
特點:
- Zuul 1.x的阻塞式I/O模型限制了并發(fā)性能,雖然可以通過多實例部署來提高吞吐量,但對于高并發(fā)場景可能不夠高效。
- Zuul 2.x基于非阻塞式I/O模型,可以提供更好的性能和吞吐量。
- Zuul支持動態(tài)路由和過濾器等功能,可以實現(xiàn)請求的動態(tài)轉(zhuǎn)發(fā)和預(yù)處理。
- 配置方式較為靈活,可以使用Groovy或Java DSL配置路由和過濾器。
-
Spring Cloud Gateway:
Spring Cloud Gateway是Spring Cloud項目中的網(wǎng)關(guān)服務(wù),從Spring Cloud 2.x版本開始引入。它是基于Spring 5和Spring Boot 2構(gòu)建的,采用了WebFlux框架,支持響應(yīng)式編程。
特點:
- Spring Cloud Gateway采用基于異步非阻塞的WebFlux框架,提供了更好的性能和響應(yīng)能力,適用于高并發(fā)場景。
- 支持動態(tài)路由和過濾器等功能,可以實現(xiàn)請求的動態(tài)轉(zhuǎn)發(fā)和預(yù)處理。
- 提供了豐富的過濾器,支持全局和局部過濾器的定義和使用。
- 配置方式靈活,可以使用YAML或Java配置路由和過濾器。
綜合來說,Zuul和Spring Cloud Gateway都是成熟的網(wǎng)關(guān)實現(xiàn),各有優(yōu)勢。如果您在使用Spring Cloud項目,推薦使用Spring Cloud Gateway,特別是在需要高并發(fā)和響應(yīng)能力的場景下。而如果您在使用Netflix項目,可以選擇使用Netflix Zuul 2.x版本或更高的版本,或考慮遷移到Spring Cloud Gateway。選擇哪個網(wǎng)關(guān)取決于您的項目需求、技術(shù)棧和預(yù)期的性能要求。
總結(jié)
網(wǎng)關(guān)的作用:
- 對用戶請求做身份認證、權(quán)限校驗
- 將用戶請求路由到微服務(wù),并實現(xiàn)負載均衡
- 對用戶請求做限流
2、搭建網(wǎng)關(guān)服務(wù)
2.1、搭建網(wǎng)關(guān)服務(wù)的步驟:
-
創(chuàng)建Gateway項目:首先,創(chuàng)建一個新的Spring Boot項目作為Gateway服務(wù)網(wǎng)關(guān)。
-
添加依賴:在Gateway項目中,添加Spring Cloud Gateway和Nacos的依賴,以便使用Gateway和Nacos的功能。在
pom.xml
文件中添加以下依賴:
<dependencies><!-- Spring Cloud Gateway --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><!-- Spring Cloud Nacos 作為服務(wù)注冊和發(fā)現(xiàn)中心 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!-- 其他依賴 -->
</dependencies>
3、配置網(wǎng)關(guān)路由:在application.yml
中配置網(wǎng)關(guān)的路由規(guī)則,將請求路由到對應(yīng)的微服務(wù)。例如:
server:port: 10009 # 配置服務(wù)端口spring:application:name: gateway # 服務(wù)名稱cloud:nacos:server-addr: localhost:8848 # 配置Nacos注冊中心的地址和端口gateway:routes:- id: userservice_route # 路由規(guī)則的唯一標(biāo)識,用于識別該路由規(guī)則。自定義的標(biāo)識可以方便管理和維護。uri: lb://userservice # 指定目標(biāo)微服務(wù)的服務(wù)名。lb://前綴表示使用負載均衡器來選擇目標(biāo)微服務(wù)的實例。這里目標(biāo)微服務(wù)的服務(wù)名是userservice。predicates: # 斷言條件列表,用于匹配請求是否符合該路由規(guī)則。- Path=/user/** # 匹配的URL路徑,當(dāng)請求的URL路徑以/user/開頭時,該路由規(guī)則會匹配。**表示匹配任意后續(xù)路徑。- id: orderservice_route # 另一個路由規(guī)則的唯一標(biāo)識,用于識別該路由規(guī)則。uri: lb://orderservice # 指定目標(biāo)微服務(wù)的服務(wù)名。這里目標(biāo)微服務(wù)的服務(wù)名是orderservice。predicates: # 斷言條件列表,用于匹配請求是否符合該路由規(guī)則。- Path=/order/** # 匹配的URL路徑,當(dāng)請求的URL路徑以/order/開頭時,該路由規(guī)則會匹配。**表示匹配任意后續(xù)路徑。
4、啟動nacos服務(wù)
#Windows系統(tǒng)命令
startup.cmd -m standalone#Linux系統(tǒng)命令
sh startup.sh -m standalone
就可以直接使用gateway的ip+端口來訪問數(shù)據(jù)了,可以直接讓gateway來將這些訪問地址轉(zhuǎn)發(fā)到相應(yīng)的服務(wù)實例上,從而來訪問數(shù)據(jù)(如訪問地址:localhost:10009/order/101)
2.2、搭建網(wǎng)關(guān)服務(wù)流程圖
-
客戶端發(fā)起請求:客戶端(如Web應(yīng)用、移動端應(yīng)用、或其他服務(wù))發(fā)起HTTP請求。
-
請求到達Gateway:請求首先到達Gateway服務(wù)網(wǎng)關(guān)。
-
Gateway進行路由匹配:Gateway根據(jù)預(yù)先配置的路由規(guī)則,匹配請求的URL路徑、請求頭等信息,找到對應(yīng)的微服務(wù)實例。
-
服務(wù)發(fā)現(xiàn):Gateway需要通過服務(wù)注冊中心(如Nacos)來獲取微服務(wù)實例的信息。它向Nacos發(fā)送服務(wù)發(fā)現(xiàn)請求,Nacos會返回目標(biāo)微服務(wù)的實例列表。
-
負載均衡:Gateway使用負載均衡算法從目標(biāo)微服務(wù)實例列表中選擇一個實例,將請求轉(zhuǎn)發(fā)給該微服務(wù)實例。
-
微服務(wù)接收請求:目標(biāo)微服務(wù)實例接收到請求。
-
微服務(wù)處理請求:微服務(wù)實例處理請求,并根據(jù)業(yè)務(wù)邏輯執(zhí)行相應(yīng)的操作。
-
微服務(wù)返回響應(yīng):微服務(wù)實例生成響應(yīng)結(jié)果,并將響應(yīng)返回給Gateway。
-
Gateway接收響應(yīng):Gateway接收到微服務(wù)實例的響應(yīng)。
-
Gateway處理響應(yīng):Gateway可以對微服務(wù)實例的響應(yīng)進行處理,如添加響應(yīng)頭、日志記錄等。
-
響應(yīng)返回客戶端:Gateway將處理后的響應(yīng)返回給客戶端。
通過服務(wù)注冊中心(如Nacos)來進行服務(wù)發(fā)現(xiàn),Gateway能夠動態(tài)地獲取微服務(wù)的實例信息,從而實現(xiàn)請求的動態(tài)轉(zhuǎn)發(fā)和負載均衡。這樣,Gateway就能找到相應(yīng)的服務(wù)并將請求轉(zhuǎn)發(fā)給它們。感謝您的指正,希望這次的回答更加準確。
總結(jié)
網(wǎng)關(guān)搭建步驟
-
創(chuàng)建項目,引入nacos服務(wù)發(fā)現(xiàn)和gateway依賴
-
配置application.yml,包括服務(wù)基本信息、nacos地址、路由
路由配置包括
- 路由id:路由的唯一標(biāo)示
- 路由目標(biāo) (uri):路由的目標(biāo)地址,http代表固定地址,lb代表根據(jù)服務(wù)名負載均衡
- 路由斷言 (predicates): 判斷路由的規(guī)則
- 路由過濾器 (filters):對請求或響應(yīng)做處理
3、路由斷言工廠Route Predicate Factory
- 路由斷言工廠(Route Predicate Factory)是Spring Cloud Gateway中的一種配置方式,用于根據(jù)請求的條件來進行路由匹配。它可以根據(jù)請求的不同屬性(例如URL路徑、請求頭、請求方法等)來判斷請求是否匹配某個路由規(guī)則,如果匹配成功,則將請求轉(zhuǎn)發(fā)到相應(yīng)的目標(biāo)地址(服務(wù)實例)。
- 例如:Path=/order/**是按照路徑匹配,這個規(guī)則是由org.springframework.cloud.gateway.handler.predicata.PathRoutePredicateFactory類來處理
- 像這種短語工廠在SpringCloudGateway還有十幾個
3.1、spring提供了11種基本的Predicate工廠
?當(dāng)使用其他的Predicate工廠時,可到spring官網(wǎng)上看如何使用:spring route
?總結(jié)
- PredicateFactory的作用是什么?
????????讀取用戶定義的斷言條件,對請求做出判斷
- Path=/user/**是什么含義?
????????路徑是以/user開頭的就認為是符合的
4、路由過濾器(Route Filter)
路由過濾器(Route Filter)是Spring Cloud Gateway中的另一個重要組件,它用于在請求被路由到目標(biāo)服務(wù)之前或之后,對請求或響應(yīng)進行一系列的處理操作。通過路由過濾器,您可以對請求和響應(yīng)進行修改、增強或驗證,從而實現(xiàn)更加靈活和強大的網(wǎng)關(guān)功能。
?例如:
假設(shè)我們有一個微服務(wù)架構(gòu),包含多個服務(wù),其中一個是認證服務(wù)(Authentication Service),負責(zé)處理用戶的身份認證。其他服務(wù)(如用戶服務(wù)、訂單服務(wù)等)需要保護某些資源,只允許經(jīng)過認證的用戶訪問。
在這種情況下,我們可以使用Spring Cloud Gateway作為網(wǎng)關(guān),通過路由過濾器來實現(xiàn)請求認證和授權(quán):
-
全局過濾器(Global Filter):我們可以創(chuàng)建一個全局過濾器來攔截所有的請求,在這個過濾器中進行用戶身份認證的檢查。比如,我們可以檢查請求中是否包含有效的身份令牌(Token),以確定請求是否是經(jīng)過認證的用戶發(fā)起的。
-
局部過濾器(Route-Specific Filter):對于特定需要授權(quán)訪問的服務(wù),我們可以在路由配置中使用局部過濾器。在這個過濾器中,我們可以對請求進行權(quán)限驗證,檢查用戶是否有權(quán)限訪問該服務(wù)提供的資源。如果用戶沒有合法的權(quán)限,則可以拒絕請求或返回相應(yīng)的錯誤信息。
這樣,通過路由過濾器,我們可以實現(xiàn)全局的請求認證,并對需要授權(quán)訪問的服務(wù)進行權(quán)限控制。用戶在發(fā)起請求時,首先經(jīng)過全局過濾器進行認證,然后再經(jīng)過局部過濾器進行權(quán)限驗證。只有通過認證和授權(quán)的請求才能繼續(xù)訪問后端的微服務(wù)。
這種方式使得認證和授權(quán)邏輯從業(yè)務(wù)服務(wù)中剝離出來,統(tǒng)一交給網(wǎng)關(guān)進行處理,簡化了業(yè)務(wù)服務(wù)的實現(xiàn)和管理,同時提高了系統(tǒng)的安全性和可維護性。
4.1、過濾工廠 GratewayFilterFactory
在Spring Cloud Gateway中,過濾工廠(Filter Factory)是用于創(chuàng)建過濾器的工廠類,它用于生成過濾器實例并配置過濾器的行為。過濾工廠是一種更高級別的抽象,它將過濾器的創(chuàng)建和配置過程封裝在一起,使得配置網(wǎng)關(guān)過濾器更加簡單和靈活。
過濾工廠與過濾器的區(qū)別在于:
- 過濾器:是過濾器實際的執(zhí)行邏輯,它需要開發(fā)者自己實現(xiàn)并繼承特定的Filter接口(如GlobalFilter或GatewayFilter),完成請求和響應(yīng)的處理。
- 過濾工廠:是用于創(chuàng)建過濾器的工廠類,它將過濾器的創(chuàng)建和配置封裝起來,通過配置工廠的參數(shù),可以快速創(chuàng)建不同類型的過濾器,并指定過濾器的行為。
過濾工廠的優(yōu)勢在于,它提供了一些預(yù)定義的工廠,可以輕松地為常見的過濾器場景創(chuàng)建過濾器,而無需開發(fā)者自己編寫過濾器的實現(xiàn)。通過簡單的配置,開發(fā)者可以使用這些預(yù)定義的過濾工廠創(chuàng)建自定義的過濾器,從而實現(xiàn)特定的路由和請求處理邏輯。
spring提供了31種不同的路由過濾器工廠,一些常用的過濾工廠包括:
通過使用過濾工廠,您可以在網(wǎng)關(guān)中快速配置和管理過濾器,實現(xiàn)對請求和響應(yīng)的靈活處理。過濾工廠是Spring Cloud Gateway提供的一種高級配置方式,幫助開發(fā)者更加方便地定制和擴展網(wǎng)關(guān)的功能。
如果想使用其他的可以到過往進行學(xué)習(xí):spring GatewayFilterFactory
4.1.1、案例
?給所有進入userservice的請求添加一個請求頭
?默認過濾器
總結(jié)
- ?過濾器的作用是什么?
????????????????對路由的請求或響應(yīng)做加工處理,比如添加請求頭
????????????????配置在路由下的過濾器只對當(dāng)前路由的請求生效
- defaultFilters的作用是什么?
????????????????對所有路由都生效的過濾器
5、全局過濾器 GlobalFilter
全局過濾器(Global Filter):我們可以創(chuàng)建一個全局過濾器來攔截所有的請求,在這個過濾器中進行用戶身份認證的檢查。比如,我們可以檢查請求中是否包含有效的身份令牌(Token),以確定請求是否是經(jīng)過認證的用戶發(fā)起的。
全局過濾器的作用也是處理一切進入網(wǎng)關(guān)的請求和微服務(wù)響應(yīng),與GatewayFilter的作用一樣。區(qū)別在于GatewayFilter通過配置定義,處理邏輯是固定的。而GlobalFilter的邏輯需要自己寫代碼實現(xiàn)。定義方式是實現(xiàn)GlobalFilter接口。
5.1、實現(xiàn)步驟
自定義來,實現(xiàn)GlobalFilter接口,添加@Order注解
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;/*** 自定義全局過濾器:用于校驗請求中的authorization參數(shù)是否合法*/
@Component
@Order(-1)
public class AuthorizeFilter implements GlobalFilter {/*** 過濾器方法,用于校驗請求中的authorization參數(shù)是否合法* @param exchange 服務(wù)器WebExchange對象,包含請求和響應(yīng)信息* @param chain GatewayFilterChain對象,用于傳遞請求給下一個過濾器或路由處理器* @return Mono<Void>,表示請求的處理結(jié)果*/@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 獲取請求參數(shù)MultiValueMap<String, String> params = exchange.getRequest().getQueryParams();// 獲取authorization參數(shù)String authorization = params.getFirst("authorization");// 校驗authorization參數(shù)if ("ltc".equals(authorization)) {// 授權(quán)通過,請求繼續(xù)傳遞給下一個過濾器或路由處理器return chain.filter(exchange);} else {// 授權(quán)不通過,設(shè)置響應(yīng)狀態(tài)碼為403(禁止訪問),并結(jié)束處理,返回禁止訪問的響應(yīng)exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);return exchange.getResponse().setComplete();}}
}
總結(jié)
全局過濾器的作用是什么?
- 對所有路由都生效的過濾器,并且可以自定義處理邏輯
實現(xiàn)全局過濾器的步驟?
- 實現(xiàn)GlobalFilter接口
- 添加@Order注解或?qū)崿F(xiàn)Ordered接口
- 編寫處理邏輯
6、過濾器執(zhí)行順序
請求進入網(wǎng)關(guān)會碰到三類過濾器: 當(dāng)前路由的過濾器、DefaultFilter、GlobalFilter
請求路由后,會將當(dāng)前路由過濾器和DefaultFilter、GlobalFilter,合并到一個過濾器鏈(集合)中,排序后依次執(zhí)行每個過濾器。
這是我們就會想,這三個過濾器相同嗎?怎么就可以放在同一個集合中進行排序了,別著急。
?對于當(dāng)前路由過濾器和DefaultFilter的配置方法是非常相似的,區(qū)別就是當(dāng)前路由過濾器放在路由內(nèi),而DefaultFilter是放在默認的過濾器內(nèi)的。從java的底層來看他兩個本質(zhì)是一樣的,只是作用范圍不一樣而已。
?在配置文件中配置的當(dāng)前路由過濾器和DefaultFilter(默認過濾器)都是由AddRequestHeaderGatewayFilterFactory過濾器工廠來讀取,然后生成了GatewayFilter過濾器,所以這兩個過濾器本質(zhì)都是同一類,他們兩個都叫GatewayFilter過濾器。
但是GlobalFilter全局過濾器為什么又可以和GatewayFilter來進行配置執(zhí)行呢?
在網(wǎng)關(guān)中有一個適配器GatewayFilterAdapter,他就可以將GlobalFilter適配成GatewayFilter來用。
?GatewayFilterAdapter適配器這個類就實現(xiàn)了GatewayFilter接口,他內(nèi)部還接收了GlobalFilter全局過濾器,如果我們給他傳入一個GlobalFilter全局過濾器,他就會將GlobalFilter適配成GatewayFilter來用。所以在網(wǎng)關(guān)中所有的過濾器都會被適配成Gateway來使用,所以這些過濾器就可以放到一個集合中來進行排序了。
這時就會出現(xiàn)一個新的問題了,那放到了一個集合后,有怎么進行排序呢?
6.1、過濾器執(zhí)如何排序
- ?每個過濾器都必須指定一個int類型的order值,order值越小,優(yōu)先級越高,執(zhí)行順序越靠前。
- GlobalFilter通過實現(xiàn)Order接口,或者添加@Order注解來指定order值,由我們自己指定。
- 路由過濾器和defaultFilter的order由Spring指定,默認是按照聲明順序從1遞增。
?多余多個路由過濾器 和多個默認路由器:
- 如果有多個路由過濾器,那他們是按照聲明的順序來遞增order的值的,來排序他們的執(zhí)行順序。
- 多個默認路由也是如此的,也是按聲明的順序來遞增order的值,來排序他們的執(zhí)行順序。
但是當(dāng)默認過濾器、路由過濾器和GlobalFilter全局過濾器的order值相同呢,那又該怎么辦呢?
- 當(dāng)過濾器的order值一樣時,會按照defaultFilter > 路由過濾器 > GlobalFilter全局過濾器的順序執(zhí)行。
底層源碼中有兩個類是用來加載這三種過濾器的:
當(dāng)服務(wù)啟動后RouteDefinitionRouteLocator類的getFilter()方法會首先執(zhí)行,會先去配置文件中加載defaultFilters,然后才會去加載某個路由的route的filter,然后合并。?
當(dāng)getFilter()方法執(zhí)行完后,FilteringWebHandler類的handle()方法才會進行加載全局過濾器,加載后會與之前加載的過濾器合并后更具order排序,組織過過濾器鏈
總結(jié)
路由過濾器、defaultFilter、全局過濾器的執(zhí)行順序?
- order值越小,優(yōu)先級越高
- 當(dāng)order值一樣時,順序是defaultFilter最先,然后是局部的路由過濾器,最后是全局過濾器
7、跨域問題處理
7.1、跨越問題
跨域問題(Cross-Origin Issue)是由瀏覽器的同源策略引起的。同源策略是一種安全機制,限制了網(wǎng)頁文檔或腳本從一個源(協(xié)議、域名、端口號的組合)加載或操作另一個源的內(nèi)容。如果兩個網(wǎng)頁的協(xié)議、域名和端口號都相同,它們就是同源的,否則就被認為是跨域的。
跨域:域名不一致就是跨域,主要包括:
- 域名不同:www.taobao.com和 www.taobao.org 和 wwwjd.com 和 miaoshajd.com
- 域名相同,端口不同: localhost:8080和localhost8081
跨越問題:瀏覽器禁止請求的發(fā)起者和服務(wù)端發(fā)生跨域Ajax請求,請求被瀏覽器攔截的問題。
跨域問題的出現(xiàn)是為了防止惡意網(wǎng)站利用客戶端的漏洞進行攻擊,保護用戶的隱私和安全。瀏覽器會強制執(zhí)行同源策略,禁止網(wǎng)頁在不同源之間進行以下操作:
- 通過 XMLHttpRequest 或 Fetch API 發(fā)送跨域請求。
- 訪問其他源的 Cookie、LocalStorage 和 IndexedDB。
- 獲取其他源的 DOM 元素。
- 在其他源的窗口中執(zhí)行腳本。
舉個例子來說明跨域問題:假設(shè)網(wǎng)站A的域名是 https://www.example.com
,網(wǎng)站B的域名是 https://api.example.com
。如果網(wǎng)站A的網(wǎng)頁中使用 XMLHttpRequest 或 Fetch API 向網(wǎng)站B發(fā)送請求,那么由于它們不是同源的,瀏覽器會阻止這個請求,返回一個錯誤。這就是跨域問題。
7.2、跨越問題解決辦法 CORS
只需要在application.yml文件中添加下面的配置即可。
spring:cloud:gateway:globalcors:corsConfigurations:'[/**]': # 配置所有路徑的全局CORS設(shè)置allowedOrigins: "https://example.com" # 允許的跨域請求源,這里設(shè)置為https://example.comallowedMethods: "GET, POST, PUT, DELETE" # 允許的請求方法,這里設(shè)置為GET、POST、PUT、DELETEallowedHeaders: "*" # 允許的請求頭,這里設(shè)置為"*"表示允許任意請求頭allowCredentials: true # 是否允許發(fā)送憑證信息(如Cookie),這里設(shè)置為true表示允許發(fā)送憑證信息maxAge: 3600 # 預(yù)檢請求的緩存時間(單位:秒),這里設(shè)置為3600秒add-to-simple-url-handler-mapping: true #處理option請求被攔截問題
?配置詳細介紹:
-
corsConfigurations
: 這個屬性用于配置全局的CORS設(shè)置。[/**]
表示匹配所有路徑,也就是對所有請求生效的全局CORS配置。 -
allowedOrigins
: 允許的跨域請求源。這里設(shè)置為https://example.com
,表示只允許來自https://example.com
域名的請求進行跨域訪問。你可以根據(jù)實際需求設(shè)置允許的域名,也可以使用通配符*
表示允許所有域名的請求。 -
allowedMethods
: 允許的請求方法。這里設(shè)置為GET, POST, PUT, DELETE
,表示只允許這些HTTP方法的請求進行跨域訪問。你可以根據(jù)需要添加或刪除允許的方法。 -
allowedHeaders
: 允許的請求頭。這里設(shè)置為*
,表示允許任意請求頭。你也可以設(shè)置具體的請求頭名稱,比如"Content-Type, Authorization"
,只允許這些請求頭進行跨域訪問。 -
allowCredentials
: 是否允許發(fā)送憑證信息(如Cookie)。這里設(shè)置為true
,表示允許發(fā)送憑證信息。如果設(shè)置為false
,則不允許發(fā)送憑證信息。 -
maxAge
: 預(yù)檢請求的緩存時間(單位:秒)。預(yù)檢請求是指瀏覽器在發(fā)送跨域請求前先發(fā)送一個 OPTIONS 請求來檢查服務(wù)器是否允許跨域訪問。這里設(shè)置為3600
秒,表示預(yù)檢請求的結(jié)果在 3600 秒內(nèi)可以被緩存,減少預(yù)檢請求的次數(shù)。 -
add-to-simple-url-handler-mapping
: 這個屬性設(shè)置為true
,將CORS配置添加到簡單URL處理程序映射中。這是一個內(nèi)部屬性,通常不需要手動設(shè)置。
通過以上配置,Spring Cloud Gateway 將會在響應(yīng)中添加相應(yīng)的CORS響應(yīng)頭,允許來自 https://example.com
域名的跨域請求,允許的方法有 GET、POST、PUT、DELETE,允許任意請求頭,允許發(fā)送憑證信息(如 Cookie),并且預(yù)檢請求的緩存時間為 3600 秒。
總結(jié)
·CORS跨域要配置的參數(shù)包括哪幾個?
- 允許哪些域名跨域?
- 允許哪些請求頭?
- 允許哪些請求方式?
- 是否允許使用cookie?
- 有效期是多久?
?此篇是在學(xué)習(xí)黑馬課springcloud程是做的詳細的筆記,內(nèi)容是自己總結(jié)過后,易懂,但是就是篇幅有點多,需要大家多花時間去看。
---------------------
作者:m0_62498006
來源:CSDN
原文:https://blog.csdn.net/m0_62498006/article/details/131927338
版權(quán)聲明:本文為作者原創(chuàng)文章,轉(zhuǎn)載請附上博文鏈接!
內(nèi)容解析By:CSDN,CNBLOG博客文章一鍵轉(zhuǎn)載插件