分布式系统面试准备
一、基本說明
我有一些同學,主要是做傳統行業,外包項目,技術一直都搞的比較簡單。共同的一個問題,就是都沒怎么搞過分布式系統,現在互聯網公司,一般都是做分布式的系統。當然了,大家都不是做底層的分布式系統,比如分布式存儲系統,hadoop hdfs,分布式計算系統,hadoop mapreduce,spark,分布式流式計算系統,storm。
分布式業務系統,把原來用java開發的一個大塊系統,給拆分成多個子系統,多個子系統之間互相調用,形成一個大系統的整體。假設原來你做了一個OA系統,里面包含了權限模塊、員工模塊、請假模塊、財務模塊,一個工程,里面包含了一堆模塊,模塊與模塊之間會互相去調用,1臺機器部署。
現在如果你把他這個系統給拆開,權限系統,員工系統,請假系統,財務系統,4個系統,4個工程,分別在4臺機器上部署。
一個請求過來,完成這個請求,這個員工系統,調用權限系統,調用請假系統,調用財務系統,4個系統分別完成了一部分的事情,最后4個系統都干完了以后,才認為是這個請求已經完成了。
事情就是這么個事,那么面試中常見的問題有哪些呢?
| (1)為什么要進行系統拆分? (2)說一下rpc框架的工作原理?注冊中心掛了可以繼續通信嗎? (3)dubbo支持哪些序列化協議?說一下hessian的數據結構?PB知道嗎?為什么PB的效率是最高的? (4)負載均衡策略和高可用策略都有哪些?動態代理策略呢? (5)dubbo的spi思想是什么? (6)如何進行服務治理、服務降級、失敗重試以及超時重試? (7)分布式服務接口的冪等性如何設計(比如不能重復扣款)? (8)分布式服務接口請求的順序性如何保證? (9)如何自己設計一個類似dubbo的rpc框架? (9)dubbo和spring cloud的區別是什么? |
下面主要以dubbo為主講一下分布式系統的相關內容,為什么選擇dubbo而不是spring cloud,原因很簡單,因為dubbo相對來說要麻煩的多(dubbo更具有技術含量)。當然了,要是工作使用肯定選擇spring cloud要好的多,但是這是面試。不過也無所謂,dubbo面試的問題會了,spring cloud的也不成問題了,也就那回事。
二、分布式系統的意義
1、面試題
為什么要進行系統拆分?如何進行系統拆分?拆分后不用rpc可以嗎?
2、面試官心里分析
從這個問題開始就進行分布式系統環節了,現在出去分布式成標配了,沒有哪個公司不問問你分布式的事兒。你要是不會分布式的東西,簡直這簡歷沒法看,你的面試機會會很少。
3、面試題剖析
1.為什么要將系統進行拆分?
網上查查,答案極度零散和復雜,很瑣碎,原因一大坨。一句話總結,如果是那種代碼量多達幾十萬行的中大型項目,團隊里有幾十個人,那么如果不拆分系統,開發效率極其低下,問題很多。但是拆分系統之后,每個人就負責自己的一小部分就好了,可以隨便玩兒隨便弄。分布式系統拆分之后,可以大幅度提升復雜系統大型團隊的開發效率。
但是同時,也要提醒的一點是,系統拆分成分布式系統之后,大量的分布式系統面臨的問題也是接踵而來,所以后面的問題都是在圍繞分布式系統帶來的復雜技術挑戰在說。
2.如何進行系統拆分?
這個問題說大可以很大,可以扯到領域驅動模型設計上去,說小了也很小,大部分的系統,是要進行多輪拆分的,第一次拆分,可能就是將以前的多個模塊該拆分開來了,比如說將電商系統拆分成訂單系統、商品系統、采購系統、倉儲系統、用戶系統,等等吧。
但是后面可能每個系統又變得越來越復雜了,比如說采購系統里面又分成了供應商管理系統、采購單管理系統,訂單系統又拆分成了購物車系統、價格系統、訂單管理系統。
扯深了實在很深,所以這里給大家舉個例子,你自己感受一下,核心意思就是根據情況,先拆分一輪,后面如果系統更復雜了,可以繼續分拆。你根據自己負責系統的例子,來考慮一下就好了。一個服務的代碼不要太多,1萬行左右,兩三萬撐死了吧。
3.拆分后不用rpc框架可以嗎?
當然可以了,大不了最次,就是各個系統之間,直接基于spring mvc,就純http接口互相通信唄,還能咋樣。但是這個肯定是有問題的,因為http接口通信維護起來成本很高,你要考慮超時重試、負載均衡等等各種亂七八糟的問題,比如說你的訂單系統調用商品系統,商品系統部署了5臺機器,你怎么把請求均勻地甩給那5臺機器?這不就是負載均衡?你要是都自己搞那是可以的,但是確實很痛苦。
我們通常用的rpc框架,就是本地進行接口調用,現有的注冊組件會代理這個調用請求,跟遠程機器網絡通信,給你處理掉負載均衡了、服務實例上下線自動感知了、超時重試了,等等亂七八糟的問題,那你就不用自己做了。
三、rpc的工作原理
1、面試題
說一下的rpc的工作原理?注冊中心掛了可以繼續通信嗎?說說一次rpc請求的流程?
2、面試官心里分析
那既然開始聊分布式系統了,那肯定是先從RPC的原理開始聊了,我們知道,現在比較常見RPC框架就是dubbo和spring cloud。
前幾年大部分公司的分布式系統的rpc框架標準是dubbo,基于dubbo也可以構建一整套的微服務架構,但是需要自己大量開發。現在大量的公司開始轉向spring cloud了,spring cloud人家畢竟是微服務架構的全家桶式的這么一個東西。
3、面試題剖析
1.dubbo的工作原理
因為很多公司還在用dubbo,所以dubbo肯定還是會問的,何況人家dubbo現在重啟開源社區維護了,未來應該也還是有一定市場和地位的。要搞清楚dubbo的工作原理,我們先來了解一下dubbo組件的幾個層級:
| 層級 | 說明 | 備注 |
| service層 | 接口層 | 給服務提供者和消費者來實現的 |
| config層 | 配置層 | 主要是對dubbo進行各種配置的 |
| proxy層 | 服務代理層 | 透明生成客戶端的stub和服務單的skeleton |
| registry層 | 服務注冊層 | 負責服務的注冊與發現 |
| cluster層 | 集群層 | 封裝多個服務提供者的路由以及負載均衡,將多個實例組合成一個服務 |
| monitor層 | 監控層 | 對rpc接口的調用次數和調用時間進行監控 |
| protocol層 | 遠程調用層 | 封裝rpc調用 |
| exchange層 | 信息交換層 | 封裝請求響應模式,同步轉異步 |
| transport層 | 網絡傳輸層 | 抽象mina和netty為統一接口 |
| serialize層 | 數據序列化層 | 數據序列化處理 |
知道上面的概念后,dubbo的工作原理就好理解了,首先就是provider向注冊中心去注冊,然后consumer從注冊中心訂閱服務,注冊中心會通知consumer注冊好的服務,consumer調用provider。此外,consumer和provider都異步的通知監控中心。
那么,注冊中心掛了可以繼續通信嗎?
答案是可以的,因為剛開始初始化的時候,消費者會將提供者的地址等信息拉取到本地緩存,所以注冊中心掛了可以繼續通信。
2.spring cloud工作原理
spring cloud 為開發人員提供了快速構建分布式系統的一些工具,包括配置管理、服務發現、斷路器、路由、微代理、事件總線、全局鎖、決策競選、分布式會話等等。其中最核心的組件就是注冊中心——Eureka組件了。
Eureka 是 Netflix 出品的用于實現服務注冊和發現的工具,Spring Cloud 封裝了 Netflix 公司開發的 Eureka 模塊來實現服務注冊和發現。Eureka采用C-S的設計架構,包含Eureka Server(服務提供者) 和Eureka Client(服務消費者)兩個組件。
服務啟動后向Eureka注冊,Eureka Server會將注冊信息向其他Eureka Server進行同步,當服務消費者要調用服務提供者,則向服務注冊中心獲取服務提供者地址,然后會將服務提供者地址緩存在本地,下次再調用時,則直接從本地緩存中取,完成一次調用。
在默認配置中EurekaServer服務在一定時間(默認為90秒)沒接受到某個服務的心跳連接后,EurekaServer會注銷該服務。但是會存在當網絡分區發生故障,導致該時間內沒有心跳連接,但該服務本身還是健康運行的情況。Eureka通過“自我保護模式”來解決這個問題。在自我保護模式中,Eureka Server會保護服務注冊表中的信息,不再注銷任何服務實例。
3、Eureka與Zookeeper的區別
CAP理論指出,一個分布式系統不可能同時滿足C(一致性)、A(可用性)和P(分區容錯性)。由于分區容錯性P在是分布式系統中必須要保證的,因此我們只能在A和C之間進行權衡。
Zookeeper保證CP
Zookeeper(dubbo注冊中心底層) 為主從結構,有leader節點和follow節點。當leader節點down掉之后,剩余節點會重新進行選舉。選舉過程中會導致服務不可用,丟掉了可用行。
Eureka保證AP
Eureka各個節點都是平等的,幾個節點掛掉不會影響正常節點的工作,剩余的節點依然可以提供注冊和查詢服務。而Eureka的客戶端在向某個Eureka注冊或時如果發現連接失敗,則會自動切換至其它節點,只要有一臺Eureka還在,就能保證注冊服務可用(保證可用性),只不過查到的信息可能不是最新的(不保證強一致性)。
四、dubbo的通信協議以及序列化協議
1、面試題
dubbo支持哪些通信協議?支持哪些序列化協議?
2、面試官心里分析
上一個問題,說說dubbo的基本工作原理,那是你必須知道的,至少知道dubbo分成哪些層,然后平時怎么發起rpc請求的,注冊、發現、調用,這些是基本的。
接著就可以針對底層進行深入的問問了,比如第一步就可以先問問序列化協議這塊,就是平時rpc的時候怎么走的?
3、面試題剖析
1.dubbo支持的通信協議
dubbo協議
默認就是走dubbo協議(dubbo://192.168.0.1:20188)的,單一長連接,NIO異步通信,基于hessian作為序列化協議。
適用的場景就是,傳輸數據量很小(每次請求在100kb以內),但是并發量很高。
為了要支持高并發場景,一般是服務提供者就幾臺機器,但是服務消費者有上百臺,可能每天調用量達到上億次!此時用長連接是最合適的,就是跟每個服務消費者維持一個長連接就可以,可能總共就100個連接。然后后面直接基于長連接NIO異步通信,可以支撐高并發請求。否則如果上億次請求每次都是短連接的話,服務提供者會扛不住。
而且因為走的是單一長連接,所以傳輸數據量太大的話,會導致并發能力降低。所以一般建議是傳輸數據量很小,支撐高并發訪問。
rmi協議
走java二進制序列化,多個短連接,適合消費者和提供者數量差不多,適用于文件的傳輸,一般較少用。
hessian協議
走hessian序列化協議,多個短連接,適用于提供者數量比消費者數量還多,適用于文件的傳輸,一般較少用。
http協議
走json序列化。
webservice
走SOAP文本序列化。
2.dubbo支持的序列化協議
dubbo實際基于不同的通信協議,支持hessian、java二進制序列化、json、SOAP文本序列化多種序列化協議。但是hessian是其默認的序列化協議。
五、服務的高可用
1、面試題
服務的負載均衡策略和集群容錯策略都有哪些?動態代理策略呢?
2、面試官心里分析
繼續深問吧,這些都是用微服務必須知道的一些東西,你得知道基本原理,知道序列化是什么協議,還得知道具體用某個rpc框架的時候,如何負載均衡,如何高可用,如何動態代理。
3、面試題剖析
1.負載均衡策略
- dubbo負載均衡策略
random loadbalance
默認情況下,dubbo是random load balance隨機調用實現負載均衡,可以對provider不同實例設置不同的權重,會按照權重來負載均衡,權重越大分配流量越高,一般就用這個默認的就可以了。
roundrobin loadbalance
還有roundrobin loadbalance,這個的話默認就是均勻地將流量打到各個機器上去,但是如果各個機器的性能不一樣,容易導致性能差的機器負載過高。所以此時需要調整權重,讓性能差的機器承載權重小一些,流量少一些。
leastactive loadbalance
這個就是自動感知一下,如果某個機器性能越差,那么接收的請求越少,越不活躍,此時就會給不活躍的性能差的機器更少的請求。
consistanthash loadbalance
一致性Hash算法,相同參數的請求一定分發到一個provider上去,provider掛掉的時候,會基于虛擬節點均勻分配剩余的流量,抖動不會太大。如果你需要的不是隨機負載均衡,是要一類請求都到一個節點,那就走這個一致性hash策略。
- spring cloud負載均衡策略
RoundRobinRule
輪詢策略,輪詢是最簡單的一種負載均衡算法,它的原理是將用戶的請求輪流分配給內部的服務器,并且輪詢算法并不需要記錄當前所有連接的狀態,所以它是一種無狀態的調度。
RandomRule
隨機,也沒什么好解釋的。
AvailabilityFilteringRule
會先過濾掉由于多次訪問故障而處于斷路器跳閘狀態的服務,還有并發的連接數超過閾值的服務,然后對剩余的服務列表進行輪詢。
WeightedResponseTimeRule
權重,根據平均響應時間計算所有服務的權重,響應時間越快服務權重越大被選中的概率越高。剛啟動時,如果統計信息不足,則使用輪詢策略,等信息足夠,切換到 WeightedResponseTimeRule。
RetryRule
重試,先按照輪詢策略獲取服務,如果獲取失敗則在指定時間內重試,獲取可用服務
BestAvailableRule 選過濾掉多次訪問故障而處于斷路器跳閘狀態的服務,然后選擇一個并發量最小的服務。
ZoneAvoidanceRule
符合判斷server所在區域的性能和server的可用性選擇服務。
2.dubbo集群容錯策略
failover cluster模式
失敗自動切換,自動重試其他機器,默認就是這個,常見于讀操作。
failfast cluster模式
一次調用失敗就立即失敗,常見于寫操作。
failsafe cluster模式
出現異常時忽略掉,常用于不重要的接口調用,比如記錄日志。
failbackc cluster模式
失敗了后臺自動記錄請求,然后定時重發,比較適合于寫消息隊列這種。
forking cluster
并行調用多個provider,只要一個成功就立即返回。
broadcacst cluster
逐個調用所有的provider。
spring cloud關于集群容錯的話,一般就使用Hystrix組件就好了。
3.dubbo動態代理策略
默認使用javassist動態字節碼生成,創建代理類。但是可以通過spi擴展機制配置自己的動態代理策略。
六、dubbo的SPI機制
1、面試題
dubbo的spi思想是什么?
2、面試官心里分析
繼續深入問唄,前面一些基礎性的東西問完了,確定你應該都ok了解dubbo的一些基本東西,那么問個稍微難一點點的問題,就是spi,先問問你spi是啥?然后問問你dubbo的spi是怎么實現的?
3、面試題剖析
spi,簡單來說,就是service provider interface,說白了是什么意思呢,比如你有個接口,現在這個接口有3個實現類,那么在系統運行的時候對這個接口到底選擇哪個實現類呢?這就需要spi了,需要根據指定的配置或者是默認的配置,去找到對應的實現類加載進來,然后用這個實現類的實例對象。
比如說你要通過jar包的方式給某個接口提供實現,然后你就在自己jar包的META-INF/services/目錄下放一個跟接口同名的文件,里面指定接口的實現里是自己這個jar包里的某個類。ok了,別人用了一個接口,然后用了你的jar包,就會在運行的時候通過你的jar包的那個文件找到這個接口該用哪個實現類。
比如說你有個工程A,有個接口A,接口A在工程A里是沒有實現類的 -> 系統在運行的時候,怎么給接口A選擇一個實現類呢?
你就可以自己搞一個jar包,META-INF/services/,放上一個文件,文件名就是接口名,接口A,接口A的實現類=com.zhss.service.實現類A2。讓工程A來依賴你的這個jar包,然后呢在系統運行的時候,工程A跑起來,對接口A,就會掃描自己依賴的所有的jar包,在每個jar里找找,有沒有META-INF/services文件夾,如果有,在里面找找,有沒有接口A這個名字的文件,如果有在里面找一下你指定的接口A的實現是你的jar包里的哪個類?
SPI機制,一般來說用在哪兒?插件擴展的場景,比如說你開發的是一個給別人使用的開源框架,如果你想讓別人自己寫個插件,插到你的開源框架里面來,擴展某個功能。
經典的思想體現,大家平時都在用,比如說jdbc。java定義了一套jdbc的接口,但是java是沒有提供jdbc的實現類。但是實際上項目跑的時候,要使用jdbc接口的哪些實現類呢?一般來說,我們要根據自己使用的數據庫,比如msyql,你就將mysql-jdbc-connector.jar,引入進來;oracle,你就將oracle-jdbc-connector.jar,引入進來。
在系統跑的時候,碰到你使用jdbc的接口,他會在底層使用你引入的那個jar中提供的實現類。但是dubbo也用了spi思想,不過沒有用jdk的spi機制,是自己實現的一套spi機制。
Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();Protocol接口,dubbo要判斷一下,在系統運行的時候,應該選用這個Protocol接口的哪個實現類來實例化對象來使用呢?
他會去找一個你配置的Protocol,他就會將你配置的Protocol實現類,加載到jvm中來,然后實例化對象,就用你的那個Protocol實現類就可以了。Protocol負責rpc調用的東西,你可以實現自己的rpc調用組件,實現Protocol接口,給自己的一個實現類即可。
這行代碼就是dubbo里大量使用的,就是對很多組件,都是保留一個接口和多個實現,然后在系統運行的時候動態根據配置去找到對應的實現類。如果你沒配置,那就走默認的實現好了,沒問題。
@SPI("dubbo") public interface Protocol { int getDefaultPort(); @Adaptive <T> Exporter<T> export(Invoker<T> invoker) throws RpcException; @Adaptive <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException; void destroy(); }在dubbo自己的jar里,在/META_INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol文件中:
dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol http=com.alibaba.dubbo.rpc.protocol.http.HttpProtocol hessian=com.alibaba.dubbo.rpc.protocol.hessian.HessianProtocol所以說,這就看到了dubbo的spi機制默認是怎么玩兒的了,其實就是Protocol接口,@SPI(“dubbo”)說的是,通過SPI機制來提供實現類,實現類是通過dubbo作為默認key去配置文件里找到的,配置文件名稱與接口全限定名一樣的,通過dubbo作為key可以找到默認的實現了就是com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol。
dubbo的默認網絡通信協議,就是dubbo協議,用的DubboProtocol。如果想要動態替換掉默認的實現類,需要使用@Adaptive接口,Protocol接口中,有兩個方法加了@Adaptive注解,就是說那倆接口會被代理實現。
啥意思呢?
比如這個Protocol接口搞了倆@Adaptive注解標注了方法,在運行的時候會針對Protocol生成代理類,這個代理類的那倆方法里面會有代理代碼,代理代碼會在運行的時候動態根據url中的protocol來獲取那個key,默認是dubbo,你也可以自己指定,你如果指定了別的key,那么就會獲取別的實現類的實例了。
通過這個url中的參數不通,就可以控制動態使用不同的組件實現類。好吧,那下面來說說怎么來自己擴展dubbo中的組件。
自己寫個工程,要是那種可以打成jar包的,里面的src/main/resources目錄下,搞一個META-INF/services,里面放個文件叫:com.alibaba.dubbo.rpc.Protocol,文件里搞一個my=com.zhss.MyProtocol。自己把jar弄到nexus私服里去。
然后自己搞一個dubbo provider工程,在這個工程里面依賴你自己搞的那個jar,然后在spring配置文件里給個配置:
<dubbo:protocol name=”my” port=”20000” />這個時候provider啟動的時候,就會加載到我們jar包里的my=com.zhss.MyProtocol這行配置里,接著會根據你的配置使用你定義好的MyProtocol了,這個就是簡單說明一下,你通過上述方式,可以替換掉大量的dubbo內部的組件,就是扔個你自己的jar包,然后配置一下即可。
dubbo里面提供了大量的類似上面的擴展點,就是說,你如果要擴展一個東西,只要自己寫個jar,讓你的consumer或者是provider工程,依賴你的那個jar,在你的jar里指定目錄下配置好接口名稱對應的文件,里面通過key=實現類。
然后對對應的組件,用類似<dubbo:protocol>用你的哪個key對應的實現類來實現某個接口,你可以自己去擴展dubbo的各種功能,提供你自己的實現。
七、基于dubbo實現服務治理
1、面試題
如何基于dubbo進行服務治理、服務降級、失敗重試以及超時重試?
2、面試官心里分析
服務治理,這個問題如果問你,其實就是看看你有沒有服務治理的思想,因為這個是做過復雜微服務的人肯定會遇到的一個問題。
服務降級,這個是涉及到復雜分布式系統中必備的一個話題,因為分布式系統互相來回調用,任何一個系統故障了,你不降級,直接就全盤崩潰?那就太坑爹了吧。
失敗重試,分布式系統中網絡請求如此頻繁,要是因為網絡問題不小心失敗了一次,是不是要重試?
超時重試,同上,如果不小心網絡慢一點,超時了,如何重試?
3、面試題剖析
1.服務治理
調用鏈路自動生成
一個大型的分布式系統,或者說是用現在流行的微服務架構來說吧,分布式系統由大量的服務組成。那么這些服務之間互相是如何調用的?調用鏈路是啥?說實話,幾乎到后面沒人搞的清楚了,因為服務實在太多了,可能幾百個甚至幾千個服務。
那就需要基于dubbo做的分布式系統中,對各個服務之間的調用自動記錄下來,然后自動將各個服務之間的依賴關系和調用鏈路生成出來,做成一張圖,顯示出來,大家才可以看到對吧。
服務訪問壓力以及時長統計
需要自動統計各個接口和服務之間的調用次數以及訪問延時,而且要分成兩個級別。一個級別是接口粒度,就是每個服務的每個接口每天被調用多少次,TP50,TP90,TP99,三個檔次的請求延時分別是多少;第二個級別是從源頭入口開始,一個完整的請求鏈路經過幾十個服務之后,完成一次請求,每天全鏈路走多少次,全鏈路請求延時的TP50,TP90,TP99,分別是多少。
這些東西都搞定了之后,后面才可以來看當前系統的壓力主要在哪里,如何來擴容和優化啊。此外,還有其他的內容,調用鏈路失敗監控和報警,服務鑒權,每個服務的可用性的監控(接口調用成功率?幾個9?,99.99%,99.9%,99%)
2.服務降級
比如說服務A調用服務B,結果服務B掛掉了,服務A重試幾次調用服務B,還是不行,直接降級,走一個備用的邏輯,給用戶返回響應
public interface HelloService {void sayHello();}public class HelloServiceImpl implements HelloService {public void sayHello() {System.out.println("hello world......");}}然后配置中,
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"><dubbo:application name="dubbo-provider" /><dubbo:registry address="zookeeper://127.0.0.1:2181" /><dubbo:protocol name="dubbo" port="20880" /><dubbo:service interface="com.zhss.service.HelloService" ref="helloServiceImpl" timeout="10000" /><bean id="helloServiceImpl" class="com.zhss.service.HelloServiceImpl" /></beans><?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"><dubbo:application name="dubbo-consumer" /><dubbo:registry address="zookeeper://127.0.0.1:2181" /><dubbo:reference id="fooService" interface="com.test.service.FooService" timeout="10000" check="false" mock="return null"></dubbo:reference></beans>現在就是mock,如果調用失敗統一返回null。但是可以將mock修改為true,然后在跟接口同一個路徑下實現一個Mock類,命名規則是接口名稱加Mock后綴。然后在Mock類里實現自己的降級邏輯。
public class HelloServiceMock implements HelloService {public void sayHello() {// 降級邏輯} }3.失敗重試和超時重試
所謂失敗重試,就是consumer調用provider要是失敗了,比如拋異常了,此時應該是可以重試的,或者調用超時了也可以重試。
<dubbo:reference id="xxxx" interface="xx" check="true" async="false" retries="3" timeout="2000"/>某個服務的接口,要耗費5s,你這邊不能干等著,你這邊配置了timeout之后,我等待2s,還沒返回,我直接就撤了,不能干等你。
如果是超時了,timeout就會設置超時時間;如果是調用失敗了自動就會重試指定的次數。你就結合你們公司的具體的場景來說說你是怎么設置這些參數的,timeout,一般設置為200ms,我們認為不能超過200ms還沒返回。
retries,3次,設置retries,還一般是在讀請求的時候,比如你要查詢個數據,你可以設置個retries,如果第一次沒讀到,報錯,重試指定的次數,嘗試再次讀取2次。
八、分布式系統中的冪等性
1、面試題
分布式服務接口的冪等性如何設計(比如不能重復扣款)?
2、面試官心里分析
從這個問題開始,面試官就已經進入了實際的生產問題的面試了。
一個分布式系統中的某個接口,要保證冪等性,該如何保證?這個事兒其實是你做分布式系統的時候必須要考慮的一個生產環境的技術問題。啥意思呢?
你看,假如你有個服務提供一個接口,結果這服務部署在了5臺機器上,接著有個接口就是付款接口。然后人家用戶在前端上操作的時候,不知道為啥,總之就是一個訂單不小心發起了兩次支付請求,然后這倆請求分散在了這個服務部署的不同的機器上,好了,結果一個訂單扣款扣兩次?尷尬了。
或者是訂單系統調用支付系統進行支付,結果不小心因為網絡超時了,然后訂單系統走了前面我們看到的那個重試機制,咔嚓給你重試了一把,好,支付系統收到一個支付請求兩次,而且因為負載均衡算法落在了不同的機器上,尷尬了。
所以你肯定得知道這事兒,否則你做出來的分布式系統恐怕容易埋坑。
網絡問題很常見,100次請求,都ok;1萬次,可能1次是超時會重試;10萬,10次;100萬,100次;如果有100個請求重復了,你沒處理,導致訂單扣款2次,100個訂單都扣錯了;每天被100個用戶投訴;一個月被3000個用戶投訴。。。
3、面試題剖析
這個不是技術問題,這個沒有通用的一個方法,這個是結合業務來看應該如何保證冪等性的,你的經驗。
所謂冪等性,就是說一個接口,多次發起同一個請求,你這個接口得保證結果是準確的,比如不能多扣款,不能多插入一條數據,不能將統計值多加了1,這就是冪等性。
不給大家來學術性詞語了。其實保證冪等性主要是三點:
- 對于每個請求必須有一個唯一的標識,舉個例子:訂單支付請求,肯定得包含訂單id,一個訂單id最多支付一次,對吧。
- 每次處理完請求之后,必須有一個記錄標識這個請求處理過了,比如說常見的方案是在mysql中記錄個狀態啥的,比如支付之前記錄一條這個訂單的支付流水,而且支付流水采。
- 每次接收請求需要進行判斷之前是否處理過的邏輯處理,比如說,如果有一個訂單已經支付了,就已經有了一條支付流水,那么如果重復發送這個請求,則此時先插入支付流水,orderId已經存在了,唯一鍵約束生效,報錯插入不進去的。然后你就不用再扣款了。
- 上面只是給大家舉個例子,實際運作過程中,你要結合自己的業務來,比如說用redis用orderId作為唯一鍵。只有成功插入這個支付流水,才可以執行實際的支付扣款。
要求是支付一個訂單,必須插入一條支付流水,order_id建一個唯一鍵,unique key。所以你在支付一個訂單之前,先插入一條支付流水,order_id就已經進去了。你就可以寫一個標識到redis里面去,set order_id payed,下一次重復請求過來了,先查redis的order_id對應的value,如果是payed就說明已經支付過了,你就別重復支付了。
然后呢,你再重復支付這個訂單的時候,你寫嘗試插入一條支付流水,數據庫給你報錯了,說unique key沖突了,整個事務回滾就可以了。來保存一個是否處理過的標識也可以,服務的不同實例可以一起操作redis。
九、分布式系統接口調用的順序性
1、面試題
分布式服務接口請求的順序性如何保證?
2、面試官心里分析
其實分布式系統接口的調用順序,也是個問題,一般來說是不用保證順序的。但是有的時候可能確實是需要嚴格的順序保證。給大家舉個例子,你服務A調用服務B,先插入再刪除。好,結果倆請求過去了,落在不同機器上,可能插入請求因為某些原因執行慢了一些,導致刪除請求先執行了,此時因為沒數據所以啥效果也沒有;結果這個時候插入請求過來了,好,數據插入進去了,那就尷尬了。
本來應該是先插入,再刪除,這條數據應該沒了,結果現在先刪除,再插入,數據還存在,最后你死都想不明白是怎么回事。所以這都是分布式系統一些很常見的問題。
3、面試題剖析
首先,一般來說,建議是,你們從業務邏輯上最好設計的這個系統不需要這種順序性的保證,因為一旦引入順序性保障,會導致系統復雜度上升,而且會帶來效率低下,熱點數據壓力過大,等問題。
下面我給個我們用過的方案吧,簡單來說,首先你得用dubbo的一致性hash負載均衡策略,將比如某一個訂單id對應的請求都給分發到某個機器上去,接著就是在那個機器上因為可能還是多線程并發執行的,你可能得立即將某個訂單id對應的請求扔一個內存隊列里去,強制排隊,這樣來確保他們的順序性。
但是這樣引發的后續問題就很多,比如說要是某個訂單對應的請求特別多,造成某臺機器成熱點怎么辦?解決這些問題又要開啟后續一連串的復雜技術方案。
最好是比如說剛才那種,一個訂單的插入和刪除操作,能不能合并成一個操作,就是一個刪除,或者是什么,避免這種問題的產生。
十、如何設計一個類似dubbo的rpc框架
1、面試題
如何自己設計一個類似dubbo的rpc框架?
2、面試官心里分析
說實話,就這問題,其實就跟問你,如何自己設計一個MQ,一樣的道理,就考兩個:
- 你有沒有對某個rpc框架原理有非常深入的理解
- 你能不能從整體上來思考一下,如何設計一個rpc框架,考考你的系統設計能力
3、面試題剖析
其實一般問到這問題,起碼不能認慫,自己說說參照dubbo的原理,舉個例子,dubbo不是有那么多分層么?而且每個分層是干啥的,你大概是不是知道?那就按照這個思路大致說一下吧。舉個例子:
- 上來你的服務就得去注冊中心注冊吧,你是不是得有個注冊中心,保留各個服務的信心,可以用zookeeper來做,對吧
- 然后你的消費者需要去注冊中心拿對應的服務信息吧,對吧,而且每個服務可能會存在于多臺機器上
- 接著你就該發起一次請求了,咋發起?蒙圈了是吧。當然是基于動態代理了,你面向接口獲取到一個動態代理,這個動態代理就是接口在本地的一個代理,然后這個代理會找到服務對應的機器地址
- 然后找哪個機器發送請求?那肯定得有個負載均衡算法了,比如最簡單的可以隨機輪詢是不是
- 接著找到一臺機器,就可以跟他發送請求了,第一個問題咋發送?你可以說用netty了,nio方式;第二個問題發送啥格式數據?你可以說用hessian序列化協議了,或者是別的,對吧。然后請求過去了。。
- 服務器那邊一樣的,需要針對你自己的服務生成一個動態代理,監聽某個網絡端口了,然后代理你本地的服務代碼。接收到請求的時候,就調用對應的服務代碼,對吧。
這就是一個最最基本的rpc框架的思路,先不說你有多牛逼的技術功底,哪怕這個最簡單的思路你先給出來行不行?
十一、spring cloud和dubbo的對比
| 特性 | spring cloud | dubbo |
| 傳輸協議 | http協議傳輸,帶寬會比較多,同時使用http協議一般會使用JSON報文,消耗會更大 | 二進制的傳輸,占用帶寬會更少 |
| 開發難度 | springcloud的接口協議約定比較自由且松散,需要有強有力的行政措施來限制接口無序升級 | dubbo的開發難度較大,原因是dubbo的jar包依賴問題很多大型工程無法解決 |
| 注冊中心 | springcloud的注冊中心只能用eureka或者自研 | dubbo的注冊中心可以選擇zk,redis等多種 |
| 系統結構簡易度 | springcloud的系統結構更簡單,“注冊+springmvc=springcloud” | dubbo各種復雜的Url,protocol,register,invocation,dubbofilter,dubboSPI,dubbo序列化...炫技的成分更多一些 |
| 網絡性能消耗 | 大 | 小 |
| 后續改進 | springcloud自己帶了很多監控、限流措施,但是功能可能和歐美習慣相同,國內需要進行適當改造,但更簡單,就是ServletFilter而已,但是總歸比dubbo多一些東西是好的 | dubbo的改進是通過dubbofilter,很多東西沒有,需要自己繼承,如監控,如日志,如限流,如追蹤 |
| 功能完備性 | Spring Cloud由眾多子項目組成,如Spring Cloud Config、Spring Cloud Netflix、Spring Cloud Consul 等,提供了搭建分布式系統及微服務常用的工具,如配置管理、服務發現、斷路器、智能路由、微代理、控制總線、一次性token、全局鎖、選主、分布式會話和集群狀態等,滿足了構建微服務所需的所有解決方案。比如使用Spring Cloud Config 可以實現統一配置中心,對配置進行統一管理;使用Spring Cloud Netflix 可以實現Netflix 組件的功能 - 服務發現(Eureka)、智能路由(Zuul)、客戶端負載均衡(Ribbon)。 | Dubbo具有調度、發現、監控、治理等功能,支持相當豐富的服務治理能力。Dubbo架構下,注冊中心對等集群,并會緩存服務列表已被數據庫失效時繼續提供發現功能,本身的服務發現結構有很強的可用性與健壯性,足夠支持高訪問量的網站。 |
簡而言之,Dubbo確實類似于Spring Cloud的一個子集,Dubbo功能和文檔完善,在國內有很多的成熟用戶,然而鑒于Dubbo的社區現狀(曾經長期停止維護),使用起來還是有一定的門檻。dubbo曾經確實很牛逼,但是Spring Cloud是站在近些年技術發展之上進行開發,因此更具技術代表性。
雖然Dubbo 支持短連接大數據量的服務提供模式,但絕大多數情況下都是使用長連接小數據量的模式提供服務使用的。所以,對于類似于電商等同步調用場景多并且能支撐搭建Dubbo 這套比較復雜環境的成本的產品而言,Dubbo 確實是一個可以考慮的選擇。但如果產品業務中由于后臺業務邏輯復雜、時間長而導致異步邏輯比較多的話,可能Dubbo 并不合適。同時,對于人手不足的初創產品而言,這么重的架構維護起來也不是很方便。
總結
- 上一篇: android短信uri,Android
- 下一篇: java信息管理系统总结_java实现科