Java面試被問到Dubbo,怎么回答可以得高分?
大家好,我是哪吒。
面試中被問到dubbo,我覺得可以從以下10點著手回答,堪稱完美!
Dubbo是一個高性能的Java RPC框架。RPC是遠程過程調用的縮寫,其基本思想是:客戶端像調用本地方法一樣,通過網絡請求調用遠程服務器上的服務。Dubbo可以幫助我們更方便地構建分布式應用程序,它具有高效的遠程調用、服務自動注冊和發現、負載均衡、容錯機制等眾多特性,是企業級應用中可靠的基礎架構。
一、介紹
1、Dubbo是什么
Dubbo是一種高性能、輕量級的分布式服務框架,它的設計目標是為大規模分布式應用提供支持。
Dubbo由阿里巴巴提供,最初由Alibaba Dubbo Team開發,目前已經成為Apache基金會的頂級項目。Dubbo在國內得到了廣泛的應用,像阿里巴巴、京東、美團等眾多互聯網企業都在使用該框架。
圖片
2、為什么需要Dubbo
在分布式系統中,服務之間相互依賴非常復雜,需要大量的通信和協調。Dubbo可以幫助我們更方便地構建分布式應用程序,它具有高效的遠程調用、服務自動注冊和發現、負載均衡、容錯機制等眾多特性。通過Dubbo,我們可以更方便地實現服務治理、服務調用鏈追蹤、服務降級、服務熔斷等重要功能。
3、Dubbo的特性
Dubbo最重要的特性包括:
- 高效的遠程調用,支持多種傳輸協議、序列化協議和集群容錯機制;
- 可擴展的服務自動發現,支持多種注冊中心;
- 豐富的負載均衡策略,支持輪詢、隨機、最少活躍調用等多種策略;
- 靈活的集群容錯機制,支持多種容錯策略;
- 多協議支持,Dubbo同時支持dubbo://、http://和hessian://等多種協議。
二、Dubbo的核心概念
1、暴露Export
Dubbo的暴露和引用是通過ProviderConfig和ConsumerConfig實現的。
ProviderConfig是服務提供者配置類,可以用于配置服務的接口、服務實現類、協議等,還可以設置暴露服務所用的協議、權重、端口號等信息。
ConsumerConfig是服務消費者配置類,可以用于配置服務消費者所接口、協議等信息,還可以設置引用服務所用的協議、集群等信息。
圖片
暴露:
- 暴露過程中,首先需要解析配置,根據配置中的協議創建相應的協議實現。
- 將協議綁定到指定的 IP 和端口上。
- 將服務地址信息注冊到注冊中心,以供其他調用者查詢。
- 通知訂閱者(監聽器)服務地址信息的變化。
- 調用者接收到訂閱者的通知,得知服務地址信息變化。
- 調用者通過網絡層向提供者發起調用請求。
- 提供者處理請求后,返回結果給調用者。
2、引用Refer
引用的過程類似,只是方向相反,具體如下:
圖片
引用
- 引用過程中,同樣需要解析配置,根據配置中的協議創建相應的協議實現。
- 連接到指定的服務地址。
- 查詢注冊中心,獲取對應服務地址信息。
- 返回服務地址信息給調用者。
- 提供者處理調用請求,返回結果給調用者。
- 調用者接收到結果,結束調用過程。
3、服務提供者和服務消費者
Dubbo的服務提供者是指提供服務的主體,通常會暴露自己的服務接口,并通過某種協議提供服務。而服務消費者是使用服務的主體,通常會引用提供者的服務接口,并通過某種協議調用服務。
圖片
- 服務提供者向 Zookeeper 注冊服務,服務消費者向 Zookeeper 訂閱服務。
- 服務消費者通過 Zookeeper 獲取服務提供者的地址信息,然后調用服務提供者的服務。
4、注冊中心
Dubbo最核心的概念就是注冊中心,它用于管理服務提供者的注冊與發現,使服務消費者能夠動態地發現和訪問服務提供者。Dubbo支持多種注冊中心,包括Zookeeper、Redis、Multicast等等,其中Zookeeper是Dubbo默認的注冊中心。
圖片
注冊中心
- 服務提供者將自己提供的服務注冊到注冊中心。
- 服務消費者從注冊中心訂閱所需的服務列表。
- 注冊中心返回可用的服務列表給服務提供者和服務消費者。
- 服務消費者調用服務提供者的服務。
- 服務提供者返回服務結果給服務消費者。
5、負載均衡
Dubbo 的負載均衡是指服務消費者在調用服務提供者的時候,如何從多個服務提供者中選擇一個進行調用。
Dubbo 默認提供了多種負載均衡策略,例如隨機、輪詢、最少活躍數等。服務消費者通過 Dubbo 的負載均衡模塊,將請求分發給多個服務提供者,然后由負載均衡模塊根據選定的負載均衡策略選擇一個服務提供者進行調用,從而達到分攤負載的效果。
圖片
負載均衡
在圖中,服務消費者 A 需要調用一個服務提供者,但是有多個服務提供者可供選擇,這時候負載均衡 B 就發揮作用了。B 會根據負載均衡策略,選擇一個服務提供者進行調用,例如選擇了服務提供者1 C。如果 C 發生故障或宕機,B 就會重新選擇一個可用的服務提供者,例如選擇了服務提供者2 D。這樣,服務消費者 A 就可以通過 Dubbo 的負載均衡模塊,動態地選擇服務提供者,從而實現負載均衡。
6、集群容錯
Dubbo的集群容錯是指當服務提供者發生故障時,Dubbo如何從備選節點中選擇一個可用的節點讓服務消費者訪問。Dubbo提供了多種集群容錯策略,包括快速失敗、失敗切換、失敗重試等等,可以根據需求選擇適合的策略。
圖片
集群容錯
- Consumer:服務的消費者,發起服務調用的一方。
- Invoker:Dubbo 中的調用器,將消費者的請求轉換成可執行的任務并執行。
- Cluster:Dubbo 中的集群容錯模塊,將多個 Invoker 封裝成一個集群。
- Failover:Dubbo 集群容錯模塊中的容錯策略之一,如果某次調用失敗,會自動切換到下一個 Invoker 進行調用,直到成功為止。
- Failfast:Dubbo 集群容錯模塊中的容錯策略之一,如果某次調用失敗,會立即拋出異常。
- Failsafe:Dubbo 集群容錯模塊中的容錯策略之一,如果某次調用失敗,會記錄下異常,但不會拋出異常。
- Failback:Dubbo 集群容錯模塊中的容錯策略之一,如果某次調用失敗,會在后臺異步重試。
- Forking:Dubbo 集群容錯模塊中的容錯策略之一,將請求并發調用多個 Invoker,只要有一個 Invoker 成功返回結果,就立即返回。
三、Dubbo的架構
1、服務提供者和服務消費者之間的通信流程
在Dubbo中,服務提供者和服務消費者之間的通信流程較為復雜,涉及到多個角色的交互。
下面簡要介紹Dubbo的通信流程:
- 服務消費者向注冊中心發起服務發現請求,獲取服務列表。
- 注冊中心返回服務列表給服務消費者。
- 服務消費者根據負載均衡策略選擇一個服務提供者。
- 服務提供者返回自身的 IP 地址和端口號給服務消費者。
- 服務消費者通過網絡向服務提供者發送請求消息。
- 服務提供者處理請求并返回響應消息給服務消費者。
圖片
dubbo的架構
整個通信流程中,Dubbo使用了類似RPC(Remote Procedure Call)的方式進行通信,即服務消費者發送請求給服務提供者,服務提供者返回結果給服務消費者。
Dubbo的主要區別在于,Dubbo支持多種協議和序列化機制,同時還提供了負載均衡、集群容錯等功能。
2、Dubbo的三層架構
Dubbo的三層架構包括:
(1)接口層
接口層是Dubbo的核心,它定義了服務提供者和服務消費者之間的通信接口。在Dubbo中,接口默認使用Java接口實現,具有很強的可擴展性。
(2)配置層
配置層的作用是通過配置文件或代碼來配置Dubbo的各種參數,包括連接參數、超時時間、重試次數等等。Dubbo支持多種配置方式,包括XML配置、注解配置和屬性配置。
(3)基礎設施層
基礎設施層是Dubbo的底層架構,包括了Dubbo的RPC框架、網絡通信、序列化和反序列化等實現細節。Dubbo的基礎設施層具有較高的性能和可定制性。
圖片
Dubbo的三層架構
3、Dubbo的擴展機制
Dubbo提供了較為完善的擴展機制,使得開發者可以輕松改變Dubbo的默認行為,實現個性化定制。
Dubbo的擴展機制主要有三種:
(1)SPI機制
Dubbo使用了SPI(Service Provider Interface)機制,開發者可以通過在class path下提供指定的接口實現類來替換Dubbo框架默認的實現。在Dubbo中,SPI機制通過Java的ServiceLoader實現。
(2)Adaptive機制
Dubbo的Adaptive機制是對SPI機制的一種補充,它可以根據不同的場景自動適配最合適的實現類。Adaptive機制通過動態生成的代理類來實現。
(3)Extension機制
Extension機制是Dubbo的核心擴展機制,它允許開發者自定義Dubbo的各種插件,包括Protocol、Transport和Serialization等。Extension機制通過@SPI和@Adaptive注解實現。開發者可以通過實現指定接口和在注解中指定拓展名,來實現自定義插件的加載和使用。
四、Dubbo的配置
1、XML配置
Dubbo的XML配置是最早的配置方式,在配置過程中需要編寫XML文件,指定Dubbo相關的標簽和屬性。其中,最基本的配置是服務提供者和服務消費者的相關配置,如下:
<!-- 服務提供者注冊到注冊中心 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<!-- 暴露服務 -->
<dubbo:service interface="com.xxx.xxxService" ref="xxxServiceImpl" timeout="3000" />
<!-- 引用服務 -->
<dubbo:reference interface="com.xxx.xxxService" id="xxxService" timeout="3000" />
在這段XML配置中,我們首先在標簽中指定了注冊中心的地址信息,然后在標簽中指定了服務提供者的接口和實現類,以及引用服務的接口和實現。timeout屬性用于設置超時時間。
除了服務提供者和服務消費者的相關配置外,還有其他相關的配置。比如,可以使用<dubbo:protocol>標簽指定Dubbo使用的協議類型和端口號,同時也可以在<dubbo:method>標簽中為方法單獨指定超時時間等參數。
2、注解配置
注解配置是一種比較簡便的配置方式,可以直接在Java代碼中使用注解指定Dubbo相關的配置信息。使用注解配置時,需要在配置類中添加@EnableDubbo注解開啟Dubbo相關功能,示例如下:
@Configuration
@EnableDubbo(scanBasePackages = "com.xxx.service.impl")
public class DubboConfig {
}
其中,scanBasePackages屬性指定了Dubbo掃描的包路徑。然后就可以在服務提供者和服務消費者的實現類中使用Dubbo提供的注解進行配置,示例如下:
@Service(timeout = 3000)
public class XxxServiceImpl implements XxxService {
@Override
public String hello(String name) {
return "Hello " + name;
}
}
對于服務消費者,則可以使用@DubboReference注解引用服務,示例如下:
@Service
public class XxxConsumer {
@DubboReference(timeout = 3000)
private XxxService xxxService;
public String hello(String name) {
return xxxService.hello(name);
}
}
在這個例子中,我們使用@DubboReference注解指定了服務的接口和超時時間,然后在XxxConsumer類中通過xxxService調用服務。
3、屬性配置
屬性配置是一種比較靈活的配置方式,它允許我們在配置文件中定義屬性,然后在代碼中讀取這些屬性并進行相關操作。使用屬性配置時,我們需要在代碼中創建一個DubboProperties對象,并將其中的屬性值通過@ConfigurationProperties注解注入到該對象中。示例如下:
@Component
@ConfigurationProperties(prefix = "dubbo")
public class DubboProperties {
private String registryAddress;
// get/set方法省略
}
然后,我們可以使用這個DubboProperties對象中定義的屬性配置Dubbo相關的參數,示例如下:
@Service(timeout = "#{dubboProperties.timeout}")
public class XxxServiceImpl implements XxxService {
@Autowired
private DubboProperties dubboProperties;
@Override
public String hello(String name) {
return "Hello " + name;
}
}
在這個例子中,我們使用了#{dubboProperties.timeout}的方式,讀取DubboProperties對象中的timeout屬性來指定服務超時時間。我們還可以在DubboProviders對象中定義其他屬性,在需要的地方使用${}的方式讀取這些屬性。
五、Dubbo的高可用與容錯
1、服務降級
服務降級指的是當系統出現故障或者異常情況時,系統可以通過關閉一些非核心的功能來保證其他核心功能的正常運行。Dubbo提供了服務降級的功能,通過這個功能,Dubbo可以在某些條件下提供替代方案,比如返回空結果、返回默認結果等等。
Dubbo的服務降級是通過Mock來實現的,Mock可以在接口定義的時候指定。Dubbo在正常情況下會使用服務提供者提供的服務,當服務提供者出現異常或者超時時,Dubbo會自動調用Mock中的方法返回預設的值。
2、服務熔斷
服務熔斷是指當系統中某個服務出現異常或者超時等情況時,Dubbo會在一定時間內暫停對該服務的調用,防止服務雪崩,提高系統的可用性。Dubbo支持配置熔斷的時間窗口和請求的最大失敗次數,當超過這個次數后,Dubbo將不再調用該服務,直到時間窗口結束。
Dubbo的服務熔斷是通過circuit breaker模式來實現的,Dubbo會根據服務的負載情況來判斷是否需要熔斷。
3、服務隔離
服務隔離指的是將不同的服務放在不同的進程或者容器中運行,防止某個服務出現故障影響到其他服務的正常運行。Dubbo支持將不同的服務放在不同的進程或者容器中運行,實現服務的隔離。
4、重試機制
重試機制指的是在服務調用失敗后,Dubbo會根據一定的規則進行重試,直到服務調用成功或達到最大重試次數。Dubbo可以配置重試次數、重試間隔時間等參數,實現重試機制。
Dubbo默認提供了重試機制,可以通過在配置文件中設置retries參數來啟用。如果服務調用失敗,則Dubbo會自動重新嘗試調用服務,直到達到最大重試次數或服務調用成功。重試過程中,Dubbo會等待一定的時間間隔,以避免對服務的過度壓力。
六、Dubbo的負載均衡策略
1、輪詢負載均衡
輪詢負載均衡算法是默認的算法,它會將服務提供者列表按照順序輪流選擇。如果其中一個服務提供者的性能較差,那么使用輪詢算法會導致它會被頻繁地請求,從而降低整體性能。因此,輪詢算法適用于所有服務提供者性能相同的情況下。
2、隨機負載均衡
隨機負載均衡算法可以隨機選擇一個服務提供者來處理請求。與輪詢算法相比,隨機算法并不考慮服務提供者之間的負載或性能,因此速度更快。但是,在某些情況下,服務提供者之間的負載差異太大,隨機算法可能會導致某些服務提供者接受過多的請求。因此,隨機算法適用于所有服務提供者性能相同的情況下,或服務提供者之間的性能差異較小的情況下。
3、最少活躍調用負載均衡
最少活躍調用(Least Active)是一種智能負載均衡算法。該算法會選擇活躍調用數最少的服務提供者來處理請求,也就是當前正忙碌程度最小的服務提供者。這種算法適合那些提供長時間服務的服務者,比如像查詢某種緩存服務,查詢開始不占用太多服務器資源,但是隨著查詢次數增加會占用 相當多的服務端資源,這時候使用Least Active算法可以選取負載最小的服務提供者,避免資源過度占用。
4、一致性哈希負載均衡
一致性哈希負載均衡是一種智能負載均衡算法,在分布式場景下,可以保證負載均衡和數據一致性。該算法會將所有服務提供者看作一個環,每個服務提供者對應一個獨特的哈希值。
對于一個請求,一致性哈希算法通過哈希值將其映射到服務提供者環中的一個位置,然后選擇服務提供者環上第一個順時針方向遇到的服務提供者來處理請求。
該算法優點在于,當新增或刪除一個服務提供者時,僅需重新映射部分請求到新的服務提供者,而不是全部請求,從而避免了大規模遷移,可以提高系統的穩定性和擴展性。
七、Dubbo的集群容錯機制
1、失敗自動切換
在調用服務時,Dubbo會選擇一個可用的服務提供者,如果該提供者未響應或發生異常,Dubbo會自動切換到下一個可用的服務提供者進行調用,這就是失敗自動切換機制。
2、失敗安全保護
在失敗自動切換的基礎上,Dubbo提供了另一種集群容錯機制:失敗安全保護。它的原理是當出現某個服務提供者不可用時,Dubbo會暫時禁用該服務提供者,一段時間后再次開啟,檢查其可用性。通過這種方式,Dubbo保證了系統的穩定性以及在出現異常情況時調用的可用性。
3、并行調用
Dubbo在集群容錯中提供了一種新的機制:并行調用。
當服務提供者在某個時間段內不能響應請求時,Dubbo會開啟多個服務提供者實例,將請求發送給這些實例進行并行處理,快速的獲取結果并返回給服務消費者。
4、快速失敗
快速失敗機制指當某個服務提供者出現異常時,Dubbo會快速的拋出異常給服務消費者,避免服務調用者長時間等待請求響應結果。同時,Dubbo也提供了一個超時時間,如果服務提供者在規定時間內未能響應請求,則Dubbo會快速的拋出異常給服務消費者,避免請求長時間等待沒有響應結果。
八、Dubbo的底層通信
1、Dubbo的網絡通信
Dubbo的底層通信是建立在Netty的通信框架上的,Netty是一個高性能的、異步的、事件驅動的網絡應用程序框架。在Dubbo中,Netty扮演著很重要的角色,其提供的通信能力能夠支持Dubbo不同節點之間的通信,并且通過高效的I/O操作完成請求響應的過程。Dubbo利用Netty的通信框架實現了從網絡層到協議層的完整封裝,使得Dubbo的通信效率得到很大的提升。
Dubbo的網絡通信過程是非常復雜的,在服務提供者和服務消費者之間建立連接,并進行請求響應的過程中,每一步都可能出現各種問題,例如網絡延遲、服務端宕機、序列化錯誤等等,因此Dubbo在網絡通信過程中加入了多種機制來提高網絡通信的效率和安全性。其中,比較重要的機制包括心跳機制、序列化與反序列化、長連接池等等。
2、序列化和反序列化
Dubbo利用Java自帶的ObjectInputStream和ObjectOutputStream類實現序列化和反序列化的過程,通過序列化和反序列化使得復雜的對象能夠在網絡中傳輸。
Dubbo支持多種序列化協議,包括Java原生的序列化協議(即Dubbo協議)、JSON、Hessian、Kryo等。Dubbo默認采用Java原生的序列化協議,雖然其具有很好的兼容性,但是其性能較差。因此,通常情況下建議使用其他的序列化協議,例如Hessian或Kryo,以提高序列化的效率。
九、Dubbo的擴展機制
1、自定義SPI擴展
Dubbo采用SPI(Service Provider Interface)的機制,用于擴展或替換框架中的某個實現。Dubbo對SPI機制的擴展可以通過Java的SPI機制實現,也可以通過Dubbo自己定義的SPI機制實現,Dubbo自己定義的SPI機制要完善一些。
Dubbo自定義的SPI機制定義了一個擴展點接口,每個擴展點接口對應了一組擴展實現類,而這些實現類都必須要使用SPI的配置文件進行配置。
Dubbo的擴展點接口中,我們可以定義類似于ExtensionLoader這樣的類,通過這些類,我們可以獲取到相關擴展實現類,從而進行自定義的擴展。
2、自定義過濾器
Dubbo的過濾器是一種攔截器,可以在請求到達消費者時、在提供者執行服務邏輯前后以及在調用方收到響應時對請求和響應進行處理。Dubbo提供了一些內置的過濾器,例如安全過濾器、異常過濾器、日志過濾器等。
不過,Dubbo也允許我們自定義過濾器來實現自己的特定需求,自定義的過濾器需要實現Filter接口,然后通過SPI機制進行擴展。
自定義的過濾器可以用于多種場景,例如監控、鑒權、統計和日志等。
3、自定義負載均衡策略
Dubbo框架內置了多種負載均衡策略,例如隨機負載均衡、輪詢負載均衡和最少活躍調用負載均衡等。但是,這些負載均衡策略并不一定適用于所有的場景,因此Dubbo也允許我們自定義負載均衡策略。
自定義負載均衡策略需要實現LoadBalance接口,然后通過SPI機制進行擴展。自定義負載均衡策略可以根據不同場景的需求,實現不同的算法和邏輯,從而更好地滿足業務需求。
十、總結
1、Dubbo的優缺點
Dubbo是阿里巴巴公司開發的一款高性能、高可用的分布式服務框架。在分布式架構中,Dubbo擔任著重要的角色,實現了服務的注冊、發現、負載均衡、容錯等功能,為分布式系統提供了更好的可擴展性和可維護性。
同時,Dubbo也存在一些優缺點。
首先,Dubbo具有較強的可定制化性,可以根據實際業務需求來選擇不同的配置和擴展機制。
其次,Dubbo的性能表現出色,適用于高并發、大規模的分布式系統。但是,Dubbo也存在一些問題,比如復雜的部署和配置流程,限制了其在小型項目中的應用。
2、Dubbo的未來發展趨勢
未來,Dubbo將會繼續發展和改進,市場對Dubbo的需求也將繼續增加。除了更新迭代,Dubbo還將更加注重安全、大數據等領域的拓展和應用。
總的來說,Dubbo在分布式架構中的地位和應用前景都非常廣闊。
本文轉載自微信公眾號「哪吒編程」,可以通過以下二維碼關注。轉載本文請聯系哪吒編程公眾號。