springBoot整合Dubbo的使用
Zookeeper
ZooKeeper是一種為分散式應用所設計的高可用、高效能且一致的開源協調服務,它提供了一項基本服務:分散式鎖服務。由於ZooKeeper的開源特性,後來我們的開發者在分散式鎖的基礎上,摸索了出了其他的使用方法:配置維護、組服務、分散式訊息佇列、分散式通知/協調等。
建議使用zookeeper3.4.5及以上版本註冊中心。
Zookeeper是Apache Hadoop的子專案,強度相對較好,建議生產環境使用該註冊中心。
Dubbo未對Zookeeper伺服器端做任何侵入修改,只需安裝原生的Zookeeper伺服器即可,所有註冊中心邏輯適配都在呼叫Zookeeper客戶端時完成。
Zookeeper配置
1、下載zookeeper
2、然後修conf/zoo.cfg
dataDir=D:\zookeeper-3.3.6\\data
dataLogDir=D:\zookeeper-3.3.6\\log
3、執行zkServer.cmd,啟動Zookeeper
監控中心
監控中心的主要使用就是檢視dubbo提供者和消費者的資訊,以及他們的呼叫情況。
監控中心配置
1、下載dubbo-monitor
2、然後修conf/dubbo.properties
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.jetty.port=28080
3、執行start.bat,啟動監控中心
監控中心介面
在瀏覽器輸入 http://localhost:8080,就可以進入監控中心
構建API模組
專案結構:
springbootdubboapi
springbootdubboclient
springbootdubboservice
api模組中就一個介面,然後將api模組打包(maven→Lifecycle→install)雙擊install
public interface TestServiceApi { String sayHello(String name); }
Dubbo服務提供者
Pom.xml新增dubbo依賴
<!--spring web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 整合dubbo--> <dependency> <groupId>com.alibaba.spring.boot</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>2.0.0</version> </dependency> <!-- zookeeper客戶端--> <dependency> <groupId>com.101tec</groupId> <artifactId>zkclient</artifactId> <version>0.11</version> </dependency> <!-- 打包的api路徑 --> <dependency> <groupId>com.test</groupId> <artifactId>springbootdubbo_api</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
application.yml配置dubbo註冊中心
server: port: 8081 # 埠號 spring: dubbo: # Dubbo服務提供者配置 application: name: provider # 服務名稱 registry: address: zookeeper://127.0.0.1:2181 # 註冊中心地址 protocol: name: dubbo # dubbo協議 port: 28081 # dubbo協議埠
提供服務
@Service //注意是com.alibaba.dubbo.config.annotation.Service包的service @Component public class ITestService implements TestServiceApi { @Override public String sayHello(String s) { return "Hello" + s; } }
啟動服務
注意加上@EnableDubboConfiguration註解
@SpringBootApplication @ComponentScan(basePackages = "com.Test.*") @EnableDubboConfiguration public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
監控中心可檢視到釋出的服務
Dubbo服務消費者
Pom.xml新增dubbo依賴
<!-- spring web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 整合dubbo--> <dependency> <groupId>com.alibaba.spring.boot</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>2.0.0</version> </dependency> <!-- zookeeper客戶端--> <dependency> <groupId>com.101tec</groupId> <artifactId>zkclient</artifactId> <version>0.11</version> </dependency> <!-- 打包的api路徑 --> <dependency> <groupId>com.test</groupId> <artifactId>springbootdubbo_api</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
application.yml配置dubbo註冊中心
server: port: 8082 # 埠號 spring: dubbo: # Dubbo服務提供者配置 application: name: provider # 服務名稱 registry: address: zookeeper://127.0.0.1:2181 # 註冊中心地址 protocol: name: dubbo # dubbo協議 port: 28082 # dubbo協議埠
消費者呼叫服務
@RestController @RequestMapping(value = "/test") public class DepController { @Reference //注意是com.alibaba.dubbo.config.annotation.Reference包的 private TestServiceApi testServiceApi; @RequestMapping(value = "/sayHello") public String sayHello() { return testServiceApi.sayHello("張三消費者"); } }
啟動消費者
注意加上@EnableDubboConfiguration註解
@SpringBootApplication @ComponentScan(basePackages = "com.test.*") @EnableDubboConfiguration public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
監控中心可檢視到釋出的consumer服務
輸入網址就能顯示內容了
http://localhost:8082/test/sayHello
超時時間,重試次數配置
timeout:可以設定duboo呼叫的超時時間(毫秒為單位)
retries :可以設定重試次數
@Service(timeout = 1000, retries = 3, group = "group1")
@Component
服務分組
可以用group屬性
示例:
@Service(timeout = 1000, retries = 3, group = "group1") @Component public class IEmpService implements EmpServiceApi { @Override public String sayHello(String s) { return "hello" + s; } } @Service(timeout = 1000, retries = 3, group = "group2") @Component public class IEmpService implements EmpServiceApi { @Override public String sayHello(String s) { return "hello" + s; } } @RestController @RequestMapping(value = "/test") public class EmpController { @Reference(group = "group1", loadbalance = "roundrobin") private TestServiceApi testServiceApi1; @Reference(group = "group2", loadbalance = "roundrobin") private TestServiceApi testServiceApi2; @RequestMapping(value = "/sayHello1") public String sayHello() { return empServiceApi1.sayHello("消費者1"); } @RequestMapping(value = "/sayHello2") public String sayHello() { return empServiceApi2.sayHello("消費者2"); } }
負載均衡演算法
random 隨機
leastactive 最小活躍值
consistenthash 一致雜湊
roundrobin 輪詢
配置:
random:權重隨機演算法,根據權重值進行隨機負載。它的演算法思想很簡單。
假設我們有一組伺服器 servers = [A, B, C],他們對應的權重為 weights = [5, 3, 2],權重總和為 10。
現在把這些權重值平鋪在一維座標值上,[0, 5) 區 間屬於伺服器 A,[5, 8) 區間屬於伺服器 B,[8, 10) 區間屬於伺服器 C。
接下來通過 隨機數生成器生成一個範圍在 [0, 10) 之間的隨機數,然後計算這個隨機數會落到哪個 區間上。
比如數字 3 會落到伺服器 A 對應的區間上,此時返回伺服器 A 即可。
權重 越大的機器,在座標軸上對應的區間範圍就越大,因此隨機數生成器生成的數字就會 有更大的概率落到此區間內。
只要隨機數生成器產生的隨機數分佈性很好,在經過多 次選擇後,每個伺服器被選中的次數比例接近其權重比例。
leastactive:最少活躍呼叫數演算法,活躍呼叫數越小,表明該服務提供者效率越高,單位時間內可處理更多的請求這個是比較科學的負載均衡演算法。
每個服務提供者對應一個活躍數 active。初始情況下,所有服務提供者活躍數均為 0。 每收到一個請求,活躍數加 1,完成請求後則將活躍數減 1。
在服務執行一段時間後, 效能好的服務提供者處理請求的速度更快,因此活躍數下降的也越快,此時這樣的服 務提供者能夠優先獲取到新的服務請求。
consistenthash:hash 一致性演算法,相同引數的請求總是發到同一提供者 當某一臺提供者掛時,原本發往該提供者的請求,基於虛擬節點,平攤到其它提供者, 不會引起劇烈變動。
roundrobin:加權輪詢演算法是指將請求輪流分配給每臺伺服器。
舉個例子,我們有三臺伺服器 A、B、C。 我們將第一個請求分配給伺服器 A,第二個請求分配給伺服器 B,第三個請求分配給 伺服器 C,第四個請求再次分配給伺服器 A。
這個過程就叫做輪詢。輪詢是一種無狀 態負載均衡演算法,實現簡單,適用於每臺伺服器效能相近的場景下。
但現實情況下, 我們並不能保證每臺伺服器效能均相近。
如果我們將等量的請求分配給效能較差的服 務器,這顯然是不合理的。
因此,這個時候我們需要對輪詢過程進行加權,以調控每 臺伺服器的負載。經過加權後,每臺伺服器能夠得到的請求數比例,接近或等於他們 的權重比。
比如伺服器 A、B、C 權重比為 5:2:1。那麼在 8 次請求中,伺服器 A 將 收到其中的 5 次請求,伺服器 B 會收到其中的 2 次請求,伺服器 C 則收到其中的 1次請求。
叢集容錯
在分散式網路通訊中,容錯能力是必須要具備的,什麼叫容錯呢? 從字面意思來看: 容:是容忍, 錯:是錯誤。 就是容忍錯誤的能力。
我們知道網路通訊會有很多不確定因素,比如網路延遲、網路中斷、服務異常等,會造成當前這次請求出現失敗。當服務通訊出現這個問題時,需要採取一定的措施應對。
而 dubbo 中提供了容錯機制來優雅處理這種錯誤,在叢集呼叫失敗時,Dubbo 提供了多種容錯方案,預設為 failover 重試。
failover:失敗自動切換,當出現失敗,重試其它伺服器。(預設) 通常用於讀操作,但重試會帶來更長延遲。 可通過 retries=“2” 來設定重試次數(不含第一次)。
failfast:快速失敗,只發起一次呼叫,失敗立即報錯。 通常用於非冪等性的寫操作,比如新增記錄。
failsafe:失敗安全,出現異常時,直接忽略。 通常用於寫入審計日誌等操作。
failback:失敗自動恢復,後臺記錄失敗請求,定時重發。 通常用於訊息通知操作。
forking:並行呼叫多個伺服器,只要一個成功即返回。 通常用於實時性要求較高的讀操作,但需要浪費更多服務資源。 可通過 forks=“2” 來設定最大並行數。
broadcast:廣播呼叫所有提供者,逐個呼叫,任意一臺報錯則報錯。(2.1.0 開始支援) 通常用於通知所有提供者更新快取或日誌等本地資源資訊。
在實際應用中查詢語句容錯策略建議使用預設 failover ,而增刪改建議使用 failfast 或者使用 failover (retries=”0”) 策略,防止出現數據重複、新增等等其它問題!
建議在設計介面時候把查詢介面方法單獨做一個介面提供查詢。
服務降級
當某個非關鍵服務出現錯誤時,可以通過降級功能來臨時遮蔽這個服務。降級可以有幾個層面的分類: 自動降級和人工降級; 按照功能可以分為:讀服務降級和寫服務降級;
1. 對一些非核心服務進行人工降級,在大促之前通過降級開關關閉哪些推薦內容、評 價等對主流程沒有影響的功能。
2. 故障降級,比如呼叫的遠端服務掛了,網路故障、或者 RPC 服務返回異常。
那麼 可以直接降級,降級的方案比如設定預設值、採用兜底資料(系統推薦的行為廣告 掛了,可以提前準備靜態頁面做返回)等等 。
3. 限流降級,在秒殺這種流量比較集中並且流量特別大的情況下,因為突發訪問量特 別大可能會導致系統支撐不了。
這個時候可以採用限流來限制訪問量。當達到閥值 時,後續的請求被降級,比如進入排隊頁面,比如跳轉到錯誤頁(活動太火爆,稍 後重試等)
Dubbo中如何實現服務降級?
Dubbo中提供了一個mock的配置,可以通過 mock來實現當服務提供方出現網路異常或者掛掉以後,客戶端不丟擲異常,而是通過 Mock資料返回自定義的資料 。
客服端呼叫服務配置引數,增加mock配置,以及修改timeout=500, 表示本次呼叫的超時時間是0.5秒,
這樣可以模擬出失敗的場景 需要配置cluster=failfast,否則因為預設是failover導致客戶端會發起3次重試,等待的時間比較長。
服務端程式碼,只需要加一個休眠時間讓客戶端呼叫超時即可。
啟動時檢查
Dubbo 預設會在啟動時檢查依賴的服務是否可用,不可用時會丟擲異常,阻止 Spring 初始化完成,以便上線時,能及早發現問題,預設 check="true"。
可以通過 check="false" 關閉檢查,比如,測試時,有些服務不關心,或者出現了迴圈依賴,必須有一方先啟動。