dubbo及zookeeper結(jié)合springboot學(xué)習(xí)

傳統(tǒng)互聯(lián)網(wǎng)架構(gòu)到分布式架構(gòu)的架構(gòu)演變

命令記憶:
netstat -tlun  :查看當(dāng)前啟動的應(yīng)用占用的端口
systemctl status firewalld:查看防火墻狀態(tài)
  • 互聯(lián)網(wǎng)時(shí)代演變過程

pc時(shí)代-->移動互聯(lián)網(wǎng)時(shí)代-->物聯(lián)網(wǎng)時(shí)代

  • 互聯(lián)網(wǎng)架構(gòu)演變過程

傳統(tǒng)單體應(yīng)用

  • 缺點(diǎn):系統(tǒng)耦合度高? 開發(fā)效率隨著時(shí)間的增長而降低? 啟動應(yīng)用的時(shí)間長? 依賴龐大? 等等
  • 適用場景:初創(chuàng)公司队丝、業(yè)務(wù)場景簡單靡馁、功能單一、研發(fā)人員較少
  • 微服務(wù)

優(yōu)點(diǎn):易開發(fā)机久、理解臭墨、維護(hù)獨(dú)立部署和啟動

不足:

需要管理多個(gè)服務(wù)、在架構(gòu)的層面變得復(fù)雜

服務(wù)切分之后吞加、服務(wù)之間的調(diào)用可能需要去解決分布式事務(wù)的問題


傳統(tǒng)單體架構(gòu).jpg

傳統(tǒng)單體架構(gòu)的擴(kuò)展.jpg

單體架構(gòu)解耦.jpg

異步架構(gòu).jpg

soa架構(gòu).jpg

soa架構(gòu)和微服務(wù)最大不同就是,微服務(wù)沒有企業(yè)服務(wù)總線尽狠,微服務(wù)是再soa基礎(chǔ)上演進(jìn)出來的


微服務(wù)架構(gòu).jpg

微服務(wù)核心基礎(chǔ)知識講解

講解微服務(wù)核心模塊 :網(wǎng)關(guān)衔憨、服務(wù)發(fā)現(xiàn)注冊、配置中心袄膏、鏈路追蹤践图、負(fù)載均衡器、熔斷

  • 網(wǎng)關(guān):路由轉(zhuǎn)發(fā) + 過濾器

    • /api/v1/pruduct/ 商品服務(wù)?
    • /api/v1/order/ 訂單服務(wù)?
    • /api/v1/user/ 用戶服務(wù)
  • 服務(wù)注冊發(fā)現(xiàn):調(diào)用和被調(diào)用方的信息維護(hù)

  • 配置中心:管理配置沉馆,動態(tài)更新 application.properties

  • 鏈路追蹤:分析調(diào)用鏈路耗時(shí)

例子:下單-》查詢商品服務(wù)獲取商品價(jià)格-》查詢用戶信息-》保存數(shù)據(jù)庫

  • 負(fù)載均衡器:分發(fā)負(fù)載

  • 熔斷:保護(hù)自己和被調(diào)用方

dubbo的發(fā)展歷程

  • 簡介:介紹dubbo的相關(guān)歷史码党,對dubbo形成初步認(rèn)知
  • 2011年由阿里開源dubbo首個(gè)版本 --dubbo-2.0.7
  • 隨后更新維護(hù)頻繁
  • 直到2014年發(fā)布 dubbo-2.4.11之后,在之后的幾年里斥黑,幾乎沒見到更新
  • 同期springboot揖盘、springcloud出現(xiàn)
  • 消沉了很長一段時(shí)間后,dubbo于2017年锌奴,浴火重生,捐獻(xiàn)給Apache

dubbo與spring-cloud比較

簡介:對目前主流微服務(wù)框架進(jìn)行對比兽狭,給技術(shù)選型提供相應(yīng)的參考

dubbo: zookeeper + dubbo + springmvc/springboot

官方地址:http://dubbo.apache.org/#!/?lang=zh-cn?

  • 通信方式:rpc 性能高?
  • 注冊中心:zookeper/redis?
  • 配置中心:diamond(企業(yè)很少用)

springcloud: 全家桶+輕松嵌入第三方組件(Netflix 奈飛)

官網(wǎng):http://projects.spring.io/spring-cloud/?

  • 通信方式:http restful?
  • 注冊中心:eruka/consul?
  • 配置中心:config?
  • 斷路器:hystrix?
  • 網(wǎng)關(guān):zuul?
  • 分布式追蹤系統(tǒng):sleuth+zipkin

補(bǔ)充:環(huán)境搭建參考VMWare設(shè)置靜態(tài)IP以及CentOS7 JDK環(huán)境配置

zookeeper講解

什么是微服務(wù)的注冊中心

  • 理解注冊中心:服務(wù)管理,核心是有個(gè)服務(wù)注冊表,心跳機(jī)制動態(tài)維護(hù)
  • 服務(wù)提供者provider: 啟動的時(shí)候向注冊中心上報(bào)自己的網(wǎng)絡(luò)信息
  • 服務(wù)消費(fèi)者consumer: 啟動的時(shí)候向注冊中心上報(bào)自己的網(wǎng)絡(luò)信息鹿蜀,拉取provider的相關(guān)網(wǎng)絡(luò)信息

為什么要用

微服務(wù)應(yīng)用和機(jī)器越來越多箕慧,調(diào)用方需要知道接口的網(wǎng)絡(luò)地址,如果靠配置文件的方式去控制網(wǎng)絡(luò)地址茴恰,對于動態(tài)新增機(jī)器颠焦,維護(hù)帶來很大問題

主流的注冊中心:zookeeper、Eureka往枣、consul伐庭、etcd 等

CAP理論知識

指的是在一個(gè)分布式系統(tǒng)中粉渠,Consistency(一致性)、 Availability(可用性)似忧、Partition tolerance(分區(qū)容錯(cuò)性)渣叛,三者不可同時(shí)獲得。

  • 一致性(C):在分布式系統(tǒng)中的所有數(shù)據(jù)備份盯捌,在同一時(shí)刻是否同樣的值淳衙。(所有節(jié)點(diǎn)在同一時(shí)間的數(shù)據(jù)完全一致,越多節(jié)點(diǎn)饺著,數(shù)據(jù)同步越耗時(shí))

    • 強(qiáng)一致性(strong consistency):任何時(shí)刻箫攀,任何用戶都能讀取到最近一次成功更新的數(shù)據(jù)。?
    • 單調(diào)一致性(monotonic consistency):任何時(shí)刻幼衰,任何用戶一旦讀到某個(gè)數(shù)據(jù)在某次更新后的值靴跛,那么就不會再讀到比這個(gè)值更舊的值。也 就是說渡嚣,可獲取的數(shù)據(jù)順序必是單調(diào)遞增的梢睛。
    • 會話一致性(session consistency):任何用戶在某次會話中,一旦讀到某個(gè)數(shù)據(jù)在某次更新后的值识椰,那么在本次會話中就不會再讀到比這值更舊的值會話一致性是在單調(diào)一致性的基礎(chǔ)上進(jìn)一步放松約束绝葡,只保證單個(gè)用戶單個(gè)會話內(nèi)的單調(diào)性,在不同用戶或同一用戶不同會話間則沒有保障腹鹉。
    • 最終一致性(eventual consistency):用戶只能讀到某次更新后的值藏畅,但系統(tǒng)保證數(shù)據(jù)將最終達(dá)到完全一致的狀態(tài),只是所需時(shí)間不能保障功咒。
    • 弱一致性(weak consistency):用戶無法在確定時(shí)間內(nèi)讀到最新更新的值愉阎。
  • 可用性(A):負(fù)載過大后,集群整體是否還能響應(yīng)客戶端的讀寫請求力奋。(服務(wù)一直可用榜旦,而且是正常響應(yīng)時(shí)間)

  • 分區(qū)容錯(cuò)性(P):分區(qū)容錯(cuò)性,就是高可用性景殷,一個(gè)節(jié)點(diǎn)崩了章办,并不影響其它的節(jié)點(diǎn)(100個(gè)節(jié)點(diǎn),掛了幾個(gè)滨彻,不影響服務(wù)藕届,越多機(jī)器越好)

CAP理論就是說在分布式存儲系統(tǒng)中,最多只能實(shí)現(xiàn)上面的兩點(diǎn)亭饵。而由于當(dāng)前的網(wǎng)絡(luò)硬件肯定會出現(xiàn)延遲丟包等問題休偶,所以分區(qū)容錯(cuò)性是我們必須需要實(shí)現(xiàn)的,所以我們只能在一致性可用性之間進(jìn)行權(quán)衡辜羊。

cap.jpg

win踏兜、linux雙環(huán)境安裝zookeeper

  • 下載zookeeper https://zookeeper.apache.org/
  • 解壓下載好的zk
  • 重命名conf目錄下的zoo_sample.cfg 文件為zoo.cfg 并修改里面的內(nèi)容
# 心跳時(shí)間
tickTime=2000
# 1o指的是tickTime*10词顾,也就是20s,F(xiàn)ollower和Leader之間初始化能容忍的最長時(shí)間
initLimit=10
# Follower和Leader之間能容忍的最大失敗數(shù)碱妆,此時(shí)是5次
syncLimit=5
# 如果linux則是linux對應(yīng)的地址
# dataDir=/usr/local/zookeeper-3.4.12/data
dataDir=D:\Soft\zookeeper-3.4.12\data
clientPort=2181
  • 直接運(yùn)行bin目錄下的zkServer肉盹,單一實(shí)例便啟動了
./zkServer.sh start
  • 配置文件主要配置項(xiàng)
    • tickTime? 心跳基本時(shí)間單位,毫秒級疹尾,ZK基本上所有的時(shí)間都是這個(gè)時(shí)間的整數(shù)倍上忍。
    • initLimit? 集群中的follower服務(wù)器(F)與leader服務(wù)器(L)之間初始連接時(shí)能容忍的最多心跳數(shù)
    • syncLimit? 集群中的follower服務(wù)器與leader服務(wù)器之間請求和應(yīng)答之間能容忍的最多心跳數(shù)
    • dataDir? 內(nèi)存數(shù)據(jù)庫快照存放地址,如果沒有指定事務(wù)日志存放地址(dataLogDir)纳本,默認(rèn)也是存放在這個(gè) 路徑下窍蓝,建議兩個(gè)地址分開存放到不同的設(shè)備上。

centos下安裝zk

  • tar -zxvf zookeeper-3.4.12.tar.gz -C /usr/local/
  • cd /usr/local/zookeeper-3.4.12/conf
  • mv zoo_sample.cfg zoo.cfg
  • vim zoo.cfg
  • 修改dataDir /usr/local/zookeeper-3.4.12/data
  • 新增一個(gè)用戶名為zookeeper : useradd zookeeper
  • 將整個(gè)文件夾所屬權(quán)賦予zookeeper用戶

chown -R zookeeper:zookeeper /usr/local/zookeeper-3.4.12

  • 切換到zookeeper用戶 : su zookeeper
  • cd /usr/local/zookeeper-3.4.12/bin 找到對應(yīng)的zkServer.sh啟動
./zkServer.sh start

ZooKeeper數(shù)據(jù)模型

  • zookeeper的數(shù)據(jù)模型類似于linux下的文件目錄
  • /usr/local /usr/local/tomcat
  • 每一個(gè)節(jié)點(diǎn)都叫做zNode繁成,可以有子節(jié)點(diǎn)吓笙,也可以有數(shù)據(jù)
  • 每個(gè)節(jié)點(diǎn)都能設(shè)置相應(yīng)的權(quán)限控制用戶的訪問
  • 每個(gè)節(jié)點(diǎn)存儲的數(shù)據(jù)不宜過大
  • 每個(gè)節(jié)點(diǎn)都帶有一個(gè)版本號,數(shù)據(jù)變更時(shí)巾腕,版本號變更(樂觀鎖)
  • 節(jié)點(diǎn)分永久節(jié)點(diǎn)跟臨時(shí)節(jié)點(diǎn)


    zookeeper數(shù)據(jù)模型.png

常用命令之zkCli

  • zkCli.sh/cmd :不填后面的參數(shù)面睛,默認(rèn)連接的就是localhost:2181
  • win下面運(yùn)行的是.cmd結(jié)尾的文件,linux下運(yùn)行的是.sh結(jié)尾的文件
  • 連接遠(yuǎn)程服務(wù)器
zkCli.sh -timeout 0 -r -server ip:port

.\zkCli.cmd -timeout 5000 -server 192.168.40.100:2181

//驗(yàn)證是否開啟成功
stat /
  • 幫助信息 : ./zkCli.sh h
ZooKeeper -server host:port cmd args? 
stat path [watch]? 
set path data [version]? 
ls path [watch]? 
delquota [-n|-b] 
path? ls2 path [watch]? 
setAcl path 
acl? setquota -n|-b val path? history? redo cmdno? printwatches on|off? 
delete path [version]? 
sync path? listquota path? 
rmr path? get path [watch]?
create [-s] [-e] path data 
acl? addauth scheme auth? quit? 
getAcl path? close? connect host:port
  • zookeeper節(jié)點(diǎn)

創(chuàng)建節(jié)點(diǎn) create [-s] [-e] path data acl -s表示創(chuàng)建順序節(jié)點(diǎn) -e表示創(chuàng)建臨時(shí)節(jié)點(diǎn) data表示創(chuàng)建的節(jié)點(diǎn)的數(shù)據(jù)內(nèi)容

  • 獲取節(jié)點(diǎn)的子節(jié)點(diǎn) ls path
  • 獲取節(jié)點(diǎn)的數(shù)據(jù) get path
  • 查看節(jié)點(diǎn)狀態(tài) stat path
cZxid = 0x3 --事務(wù)id? 
ctime = Tue Dec 04 10:37:58 EST 2018 --節(jié)點(diǎn)創(chuàng)建的時(shí)候的時(shí)間? mZxid = 0x3 --最后一次更新時(shí)的事務(wù)id? 
mtime = Tue Dec 04 10:37:58 EST 2018 最后一次更新的時(shí)間? 
pZxid = 0x3 該節(jié)點(diǎn)的子節(jié)點(diǎn)列表最后一次被修改的事務(wù)id? 
cversion = 0 子節(jié)點(diǎn)列表的版本? 
# 例如更新數(shù)據(jù):加版本信息的話尊搬,必須dataVersion`相等`才能更新數(shù)據(jù),不加版本信息則自動變化
dataVersion = 0 數(shù)據(jù)內(nèi)容的版本? 
aclVersion = 0 acl版本? 
ephemeralOwner = 0x0 用于臨時(shí)節(jié)點(diǎn)叁鉴,表示創(chuàng)建該臨時(shí)節(jié)點(diǎn)的事務(wù)id,如果當(dāng)前的節(jié)點(diǎn)不是臨時(shí)節(jié)點(diǎn)毁嗦,該字段值為0? 
dataLength = 8 數(shù)據(jù)內(nèi)容的長度? 
numChildren = 0 子節(jié)點(diǎn)的數(shù)量
  • 獲取節(jié)點(diǎn)的子節(jié)點(diǎn)以及當(dāng)前節(jié)點(diǎn)的狀態(tài) ls2 path
  • 修改節(jié)點(diǎn)的數(shù)據(jù) set path data [version]
  • 刪除節(jié)點(diǎn)數(shù)據(jù)

delete path [version] 刪除節(jié)點(diǎn)亲茅,如果此時(shí)該節(jié)點(diǎn)有子節(jié)點(diǎn)回铛,則不允許刪除

  • rmr path 遞歸刪除整個(gè)節(jié)點(diǎn)

zookeeper session機(jī)制

  • 用于客戶端與服務(wù)端之間的連接狗准,可設(shè)置超時(shí)時(shí)間,通過心跳包的機(jī)制(客戶端向服務(wù)端ping包請求)檢查心跳結(jié)束,session就過期
  • session過期的時(shí)候茵肃,該session創(chuàng)建的所有臨時(shí)節(jié)點(diǎn)都會被拋棄


    zookeeper session機(jī)制.png

zookeeper watcher機(jī)制

  • 節(jié)點(diǎn)的watcher操作 get stat

針對每一個(gè)節(jié)點(diǎn)的操作腔长,都可以有一個(gè)監(jiān)控者,當(dāng)節(jié)點(diǎn)發(fā)生變化验残,會觸發(fā)watcher事件 zk中watcher是一次性的捞附,觸發(fā)后立即銷毀 所有有監(jiān)控者的節(jié)點(diǎn)的變更操作都能觸發(fā)watcher事件;watcher的一次性,只是針對zookeeper原生指令您没,不針對代碼級別

  • 子節(jié)點(diǎn)的watcher操作(監(jiān)控父節(jié)點(diǎn),當(dāng)父節(jié)點(diǎn)對應(yīng)的子節(jié)點(diǎn)發(fā)生變更的時(shí)候,父節(jié)點(diǎn)上的watcher事件會被觸發(fā)) ls ls2(ls /ls2后面更上watcher) 增刪會觸發(fā)鹰贵、修改不會辰妙,如果子節(jié)點(diǎn)再去新增子節(jié)點(diǎn),不會觸發(fā)(也就是說仆抵,觸發(fā)watcher事件一定是直系子節(jié)點(diǎn))
    watcher機(jī)制.png

zookeeper的acl(access control lists)權(quán)限控制

  • 針對節(jié)點(diǎn)可以設(shè)置相關(guān)的讀寫等權(quán)限跟继,目的是為了保證數(shù)據(jù)的安全性
  • 權(quán)限permissions可以指定不同的權(quán)限范圍及角色

常用的命令

  • getAcl 獲取節(jié)點(diǎn)權(quán)限
  • setAcl 設(shè)置節(jié)點(diǎn)權(quán)限
  • addauth 輸入認(rèn)證授權(quán)信息种冬,注冊時(shí)輸入明文密碼,但是在zk里舔糖,以加密的形式保存
//`設(shè)置或者獲取權(quán)限`直接設(shè)置和獲取如果提示不行娱两,需要先輸入下面一行,然后再設(shè)置和獲取權(quán)限
addauth digest xdclass:xdclass
setAcl /xdclass auth:xdclass:xdclass:cdrwa

acl的組成 [scheme??permissions]

scheme 授權(quán)機(jī)制

  • world下只有一個(gè)id金吗,也就是anyone十兢,表示所有人 world:anyone:permissions
  • auth 代表認(rèn)證登錄,需要注冊用戶有權(quán)限才可以 auth:user:password:permissions
  • digest 需要密碼加密才能訪問 digest:username:BASE64(SHA1(password)):permissions(跟auth區(qū)別在于辽聊,auth明文纪挎,digest為密文)
  • ip ip:localhost:psermissions
  • super 代表超管,擁有所有的權(quán)限跟匆;
    打開zk目錄下的/bin/zkServer.sh服務(wù)器腳本文件异袄,找到如下一行:
nohup $JAVA "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" "-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}"
加上 "-Dzookeeper.DigestAuthenticationProvider.superDigest=super:xQJmxLMiHGwaqBvst5y6rkB6HQs="
此處后面的密文為密碼加密后的
  • id:允許訪問的用戶
  • permissions:權(quán)限組合字符串
cdrwa
c create 創(chuàng)建子節(jié)點(diǎn)
d delete 刪除子節(jié)點(diǎn)
r read 讀取節(jié)點(diǎn)的數(shù)據(jù)
w write 寫入數(shù)據(jù)
a admin 可管理的權(quán)限
cdrwa cdr cdw 
  • 栗子
設(shè)置訪問控制:

方式一:(推薦)
1)增加一個(gè)認(rèn)證用戶
addauth digest 用戶名:密碼明文
eg. addauth digest user1:password1
2)設(shè)置權(quán)限
setAcl /path auth:用戶名:密碼明文:權(quán)限
eg. setAcl /test auth:user1:password1:cdrwa
3)查看Acl設(shè)置
getAcl /path

方式二:
setAcl /path digest:用戶名:密碼密文:權(quán)限

注:這里的加密規(guī)則是SHA1加密,然后base64編碼玛臂。
  • acl的使用場景
    • 開發(fā)環(huán)境跟測試環(huán)境烤蜕,使用acl就可以進(jìn)行分離,開發(fā)者無權(quán)去操作測試的節(jié)點(diǎn)
    • 生產(chǎn)環(huán)境上控制指定ip的服務(wù)可以訪問相關(guān)的節(jié)點(diǎn)

一致性協(xié)議之 ZAB

Zookeeper 設(shè)計(jì)的分布式一致性協(xié)議

  1. ZAB 協(xié)議全稱:Zookeeper Atomic Broadcast(Zookeeper 原子廣播協(xié)議)迹冤。
  2. Zookeeper 是一個(gè)為分布式應(yīng)用提供高效且可靠的分布式協(xié)調(diào)服務(wù)讽营。在解決分布式一致性方面,Zookeeper 并沒有使用 Paxos 泡徙,而是采用了 ZAB 協(xié)議橱鹏。
  3. ZAB 協(xié)議定義:ZAB 協(xié)議是為分布式協(xié)調(diào)服務(wù) Zookeeper 專門設(shè)計(jì)的一種支持崩潰恢復(fù)原子廣播協(xié)議。
  4. 基于該協(xié)議堪藐,Zookeeper 實(shí)現(xiàn)了一種主備模式的系統(tǒng)架構(gòu)來保持集群中各個(gè)副本之間數(shù)據(jù)一致性莉兰。
    1.jpg
  • 上圖顯示了 Zookeeper 如何處理集群中的數(shù)據(jù)。所有客戶端寫入數(shù)據(jù)都是寫入到 主進(jìn)程(稱為 Leader)中礁竞,然后糖荒,由 Leader 復(fù)制到備份進(jìn)程(稱為 Follower)中。從而保證數(shù)據(jù)一致性模捂。從設(shè)計(jì)上看捶朵,和 Raft 類似。

  • 那么復(fù)制過程又是如何的呢狂男?復(fù)制過程類似 2PC综看,ZAB 只需要 Follower 有一半以上返回 Ack 信息就可以執(zhí)行提交,大大減小了同步阻塞岖食。也提高了可用性红碑。

  • 簡單介紹完,開始重點(diǎn)介紹 消息廣播 和 崩潰恢復(fù)县耽。整個(gè) Zookeeper 就是在這兩個(gè)模式之間切換句喷。 簡而言之,當(dāng) Leader 服務(wù)可以正常使用镣典,就進(jìn)入消息廣播模式,當(dāng) Leader 不可用時(shí)唾琼,則進(jìn)入崩潰恢復(fù)模式兄春。

消息廣播

ZAB 協(xié)議的消息廣播過程使用的是一個(gè)原子廣播協(xié)議,類似一個(gè) 二階段提交過程锡溯。對于客戶端發(fā)送的寫請求赶舆,全部由 Leader 接收,Leader 將請求封裝成一個(gè)事務(wù) Proposal祭饭,將其發(fā)送給所有 Follwer 芜茵,然后,根據(jù)所有 Follwer 的反饋倡蝙,如果超過半數(shù)成功響應(yīng)九串,則執(zhí)行 commit 操作(先提交自己,再發(fā)送 commit 給所有 Follwer)寺鸥。

  • 基本上猪钮,整個(gè)廣播流程分為 3 步驟:

    • 將數(shù)據(jù)都復(fù)制到 Follwer 中


      2.jpg
    • 等待 Follwer 回應(yīng) Ack,最低超過半數(shù)即成功


      3.jpg
    • 當(dāng)超過半數(shù)成功回應(yīng)胆建,則執(zhí)行 commit 烤低,同時(shí)提交自己


      4.jpg

通過以上 3 個(gè)步驟,就能夠保持集群之間數(shù)據(jù)的一致性笆载。實(shí)際上扑馁,在 Leader 和 Follwer 之間還有一個(gè)消息隊(duì)列,用來解耦他們之間的耦合凉驻,避免同步腻要,實(shí)現(xiàn)異步解耦。

  • 還有一些細(xì)節(jié):
  1. Leader 在收到客戶端請求之后沿侈,會將這個(gè)請求封裝成一個(gè)事務(wù)闯第,并給這個(gè)事務(wù)分配一個(gè)全局遞增的唯一 ID市栗,稱為事務(wù)ID(ZXID)缀拭,ZAB 兮協(xié)議需要保證事務(wù)的順序,因此必須將每一個(gè)事務(wù)按照 ZXID 進(jìn)行先后排序然后處理填帽。
  2. 在 Leader 和 Follwer 之間還有一個(gè)消息隊(duì)列蛛淋,用來解耦他們之間的耦合,解除同步阻塞篡腌。
  3. zookeeper集群中為保證任何所有進(jìn)程能夠有序的順序執(zhí)行褐荷,只能是 Leader 服務(wù)器接受寫請求,即使是 Follower 服務(wù)器接受到客戶端的請求嘹悼,也會轉(zhuǎn)發(fā)到 Leader 服務(wù)器進(jìn)行處理叛甫。
  4. 實(shí)際上层宫,這是一種簡化版本的 2PC,不能解決單點(diǎn)問題其监。等會我們會講述 ZAB 如何解決單點(diǎn)問題(即 Leader 崩潰問題)萌腿。

崩潰恢復(fù)

剛剛我們說消息廣播過程中,Leader 崩潰怎么辦抖苦?還能保證數(shù)據(jù)一致嗎毁菱?如果 Leader 先本地提交了,然后 commit 請求沒有發(fā)送出去锌历,怎么辦贮庞?

實(shí)際上,當(dāng) Leader 崩潰究西,即進(jìn)入我們開頭所說的崩潰恢復(fù)模式(崩潰即:Leader 失去與過半 Follwer 的聯(lián)系)窗慎。下面來詳細(xì)講述。

假設(shè)1:Leader 在復(fù)制數(shù)據(jù)給所有 Follwer 之后崩潰卤材,怎么辦捉邢?
假設(shè)2:Leader 在收到 Ack 并提交了自己,同時(shí)發(fā)送了部分 commit 出去之后崩潰怎么辦商膊?

  • 針對這些問題伏伐,ZAB 定義了 2 個(gè)原則:
    1. ZAB 協(xié)議確保那些已經(jīng)在 Leader 提交的事務(wù)最終會被所有服務(wù)器提交。
    2. ZAB 協(xié)議確保丟棄那些只在 Leader 提出/復(fù)制晕拆,但沒有提交的事務(wù)藐翎。

所以,ZAB 設(shè)計(jì)了下面這樣一個(gè)選舉算法:能夠確保提交已經(jīng)被 Leader 提交的事務(wù)实幕,同時(shí)丟棄已經(jīng)被跳過的事務(wù)

針對這個(gè)要求吝镣,如果讓 Leader 選舉算法能夠保證新選舉出來的 Leader 服務(wù)器擁有集群總所有機(jī)器編號(即 ZXID 最大)的事務(wù),那么就能夠保證這個(gè)新選舉出來的 Leader 一定具有所有已經(jīng)提交的提案昆庇。
而且這么做有一個(gè)好處是:可以省去 Leader 服務(wù)器檢查事務(wù)的提交和丟棄工作的這一步操作末贾。


5.jpg

這樣,我們剛剛假設(shè)的兩個(gè)問題便能夠解決整吆。假設(shè) 1 最終會丟棄調(diào)用沒有提交的數(shù)據(jù)拱撵,假設(shè) 2 最終會同步所有服務(wù)器的數(shù)據(jù)。這個(gè)時(shí)候表蝙,就引出了一個(gè)問題拴测,如何同步?

數(shù)據(jù)同步

當(dāng)崩潰恢復(fù)之后府蛇,需要在正式工作之前(接收客戶端請求)集索,Leader 服務(wù)器首先確認(rèn)事務(wù)是否都已經(jīng)被過半的 Follwer 提交了,即是否完成了數(shù)據(jù)同步。目的是為了保持?jǐn)?shù)據(jù)一致务荆。

當(dāng)所有的 Follwer 服務(wù)器都成功同步之后妆距,Leader 會將這些服務(wù)器加入到可用服務(wù)器列表中。

實(shí)際上函匕,Leader 服務(wù)器處理或丟棄事務(wù)都是依賴著 ZXID 的毅厚,那么這個(gè) ZXID 如何生成呢?

答:在 ZAB 協(xié)議的事務(wù)編號 ZXID 設(shè)計(jì)中浦箱,ZXID 是一個(gè) 64 位的數(shù)字吸耿,其中低 32 位可以看作是一個(gè)簡單的遞增的計(jì)數(shù)器,針對客戶端的每一個(gè)事務(wù)請求酷窥,Leader 都會產(chǎn)生一個(gè)新的事務(wù) Proposal 并對該計(jì)數(shù)器進(jìn)行 + 1 操作咽安。

而高 32 位則代表了 Leader 服務(wù)器上取出本地日志中最大事務(wù) Proposal 的 ZXID,并從該 ZXID 中解析出對應(yīng)的 epoch 值蓬推,然后再對這個(gè)值加一妆棒。

6.jpg

高 32 位代表了每代 Leader 的唯一性,低 32 代表了每代 Leader 中事務(wù)的唯一性沸伏。同時(shí)糕珊,也能讓 Follwer 通過高 32 位識別不同的 Leader。簡化了數(shù)據(jù)恢復(fù)流程毅糟。

基于這樣的策略:當(dāng) Follower 鏈接上 Leader 之后红选,Leader 服務(wù)器會根據(jù)自己服務(wù)器上最后被提交的 ZXID 和 Follower 上的 ZXID 進(jìn)行比對,比對結(jié)果要么回滾姆另,要么和 Leader 同步喇肋。

zookeeper選舉機(jī)制

zookeeper集群中的三種角色以及其各自的作用

  • leader:作為整個(gè)zk集群寫請求的唯一處理者,并負(fù)責(zé)進(jìn)行投票的發(fā)起和決議迹辐,更新系統(tǒng)的狀態(tài)蝶防。
  • follower:接收客戶端請求,處理讀請求明吩,并向客戶端返回結(jié)果间学;將寫請求轉(zhuǎn)給 Leader;在選舉 Leader過程中參與投票印荔。
  • observer:可以理解為無選舉投票權(quán)的 Flollower低葫,其主要是為了協(xié)助 Follower 處理更多的讀請求。如果 Zookeeper 集群的讀請求負(fù)載很高躏鱼,或者客戶端非常非常多氮采,多到跨機(jī)房殷绍,則可以設(shè)置一些 Observer 服務(wù)器染苛,以提高讀取的吞吐量。


    zk集群角色.png
observer作用.png

zk集群選舉核心概念及選舉時(shí)狀態(tài)

  • myid

zk 集群中服務(wù)器的唯一標(biāo)識,稱為 myid茶行。例如躯概,有三個(gè)zk服務(wù)器,那么編號分別是 1,2,3。

  • zxid
?
高位              低位
0000000000000000  0000000000000000
?
                    epoch                                 xid
00000000000000000000000000000000   00000000000000000000000000000000
zxid 為 Long 類型畔师,其中高 32 位表示 epoch娶靡,低 32 位表示 xid。即 zxid 由兩部分構(gòu)成:epoch 與 xid看锉。 
每個(gè) Leader 都會具有一個(gè)不同的 epoch 值姿锭,表示一個(gè)時(shí)期、時(shí)代;在選舉還沒成功的時(shí)候伯铣,所有節(jié)點(diǎn)zxid是相同的呻此。新的 Leader 產(chǎn)生,則會更新所有 zkServer 的 zxid 中的 epoch腔寡。 而 xid 則為 zk 的事務(wù) id焚鲜,每一個(gè)寫操作都是一個(gè)事務(wù),都會有一個(gè) xid放前。每一個(gè)寫操作都需要由 Leader 發(fā)起一個(gè)提議忿磅,由所有 Follower 表決是否同意本次寫操作。
  • 邏輯時(shí)鐘

邏輯時(shí)鐘凭语,Logicalclock葱她,是一個(gè)整型數(shù),該概念在選舉時(shí)稱為 logicalclock似扔,而在 zxid 中則為 epoch 的值览效。即 epoch 與 logicalclock 是同一個(gè)值,在不同情況下的不同名稱虫几。

  • zk的選舉狀態(tài)
  • LOOKING锤灿,選舉狀態(tài)(查找 Leader 的狀態(tài))。
  • LEADING辆脸,領(lǐng)導(dǎo)者狀態(tài)但校。處于該狀態(tài)的服務(wù)器稱為 Leader。
  • FOLLOWING啡氢,隨從狀態(tài)状囱,同步 leader 狀態(tài)。處于該狀態(tài)的服務(wù)器稱為 Follower倘是。
  • OBSERVING亭枷,觀察狀態(tài),同步 leader 狀態(tài)搀崭。處于該狀態(tài)的服務(wù)器稱為 Observer叨粘。

zk集群選舉發(fā)生的時(shí)機(jī)及選舉算法

  • 發(fā)生時(shí)機(jī):整個(gè)集群群龍無首的時(shí)候(1.服務(wù)啟動 2.leader宕機(jī)之后)
  • 選舉機(jī)制:集群中猾编,半數(shù)zkServer同意,則產(chǎn)生新的leader(搭建集群時(shí)升敲,一般都是奇數(shù)個(gè))例如:三臺服務(wù)器答倡,最多允許一臺宕機(jī),四臺服務(wù)器驴党,也是最多允許一臺宕機(jī)
  • 選舉算法:
    對比(myid瘪撇,zxid),先對比zxid港庄,zxid大者(大表示數(shù)據(jù)越新)勝出倔既,成為leader,如果zxid一致鹏氧,則myid大者成為leader


    三種模式.png
選舉發(fā)生的時(shí)機(jī)及其選舉算法.png

zk集群搭建

  • 端口的作用
    • 2181 對client端提供服務(wù)
    • 2888 集群內(nèi)及其通訊使用的端口
    • 3888 集群選舉leader
# 心跳時(shí)間
tickTime=2000
# 1o指的是tickTime*10叉存,也就是20s,F(xiàn)ollower和Leader之間初始化能容忍的最長時(shí)間
initLimit=10
# Follower和Leader之間能容忍的最大失敗數(shù)度帮,此時(shí)是5次
syncLimit=5
dataDir=D:\Soft\zookeeper-3.4.12\data
clientPort=2181
server.1=192.168.40.100:2888:3888 
server.2=192.168.40.101:2888:3888 
server.3=192.168.40.102:2888:3888
  • 在zk的根目錄下歼捏,新建一個(gè)data目錄,并在data目錄下新增一個(gè)myid的文件(myid中內(nèi)容是1,2,3這種)
  • 三臺服務(wù)器笨篷,分別新增一個(gè)叫做zookeeper的用戶 useradd zookeeper
  • 將修改好配置的zk瞳秽,分別放到三臺服務(wù)器的/usr/local/,并將目錄權(quán)限改為zookeeper用戶
  • chown -R zookeeper:zookeeper zookeeper-3.4.12/
  • 注意:三臺服務(wù)器,均修改/usr/local/zookeeper-3.4.12/data/目錄里的myid文件,文件內(nèi)容是一個(gè)數(shù)字率翅,對應(yīng)server.1=192.168.40.100:2888:3888 里的1
  • 關(guān)閉防火墻

systemctl stop firewalld.service

  • 如果不關(guān)閉防火墻可以通過以下方式
添加防火墻策略练俐,允許2181端口可用,吧幾個(gè)所需端口都添加進(jìn)策略即可
firewall-cmd --zone=public --add-port=2181/tcp --permanent
防火墻重新加載
firewall-cmd --reload
  • 依次啟動 ./zkServer.sh start
  • 三臺機(jī)子均啟動完成之后,可以使用zkServer.sh status去查看狀態(tài)

查看是leader還是follower

分布式鎖

  • 為什么要有分布式鎖

分布式服務(wù)中冕臭,如果各個(gè)服務(wù)節(jié)點(diǎn)需要去競爭資源腺晾,沒辦法使用單機(jī)多線程中JDK自帶的鎖,故此時(shí)需要分布式鎖來協(xié)調(diào)

  • 企業(yè)中有哪些常見的手段來實(shí)現(xiàn)分布式鎖

zookeeper辜贵、redis悯蝉、memcache

  • 分布式鎖的原理
    • zookeeper:去創(chuàng)建相應(yīng)的節(jié)點(diǎn),創(chuàng)建成功托慨,則表示獲取到相應(yīng)的鎖鼻由,創(chuàng)建失敗(如果已經(jīng)存在則創(chuàng)建失敗),則表示獲取鎖失敗
    • redis厚棵、memcache:對應(yīng)的去設(shè)置一個(gè)值做為鎖的一標(biāo)志蕉世,每次獲取鎖的時(shí)候,判斷對應(yīng)的值是否存在婆硬,存在則無法獲取狠轻,不存在,則設(shè)置相應(yīng)的值彬犯,表示獲取到鎖向楼。(redis 使用setnx查吊,memcache使用add)
  • 創(chuàng)建鎖時(shí)候,一定要?jiǎng)?chuàng)建臨時(shí)節(jié)點(diǎn),避免應(yīng)用獲取到鎖后蜜自,宕機(jī)菩貌,導(dǎo)致鎖一直被持有
  • 如果是單一應(yīng)用卢佣,盡量不要使用分布式鎖重荠,畢竟jdk本身鎖性能更高
  • zk原生api不支持遞歸創(chuàng)建節(jié)點(diǎn)


    基于zk實(shí)現(xiàn)分布式鎖的多種方式.png

案例代碼

<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.4.13</version>
</dependency>
package com.wiggin.lock;

import org.apache.zookeeper.*;

import java.io.IOException;
import java.util.concurrent.CountDownLatch;

import static org.apache.zookeeper.CreateMode.EPHEMERAL;
import static org.apache.zookeeper.ZooDefs.Ids.OPEN_ACL_UNSAFE;

/**
 * 基于zk實(shí)現(xiàn)自定義分布式鎖
 */
public class ZkLock {

    private ZooKeeper zooKeeper;

    private static CountDownLatch countDownLatch = new CountDownLatch(1);

    private ZkLock() {
        try {
            zooKeeper = new ZooKeeper("192.1.1.101:2181,192.1.1.102:2181,192.1.1.103:2181", 5000, new ZkWatcher());
            System.out.println(zooKeeper.getState());
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("與zk建立連接=====>"+zooKeeper.getState());

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static ZkLock getInstance() {
        return Singleton.getInstance();
    }

    private class ZkWatcher implements Watcher {
        @Override
        public void process(WatchedEvent event) {
            //當(dāng)連接zk成功會觸發(fā)這個(gè)回調(diào),再判斷下狀態(tài)(因?yàn)槠渌O(jiān)聽也可能觸發(fā)),調(diào)用countDown
            //則上面的countDownLatch.await(); 就會放行
            System.out.println("接收到監(jiān)聽事件=====》"+event);
            if (Event.KeeperState.SyncConnected == event.getState()) {
                countDownLatch.countDown();
            }
        }
    }


    public void lock(Integer id) {
        //注釋地方是遞歸節(jié)點(diǎn)虚茶,但是zk原生api不支持遞歸創(chuàng)建戈鲁,所以如果使用會拋出異常,通過catch內(nèi)部打印可知
        // String path = "/xdclass/product/lock/" + id;
        String path = "/xdclass-product-lock-" + id;
        //創(chuàng)建臨時(shí)節(jié)點(diǎn),如果創(chuàng)建成功的話嘹叫,就表示獲取鎖婆殿,如果失敗,則不斷嘗試
        try {
            //路徑罩扇,內(nèi)容婆芦,代表不設(shè)置acl權(quán)限,零時(shí)節(jié)點(diǎn)
            zooKeeper.create(path,"".getBytes(),ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
            System.out.println("成功獲取到鎖");
        } catch (Exception e) {
            while (true) {
                try {
                    Thread.sleep(500L);
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
                try {
                    zooKeeper.create(path,"".getBytes(),ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
                } catch (Exception e1) {
                    continue;
                }
                break;
            }
        }
    }

    /**
     * 釋放鎖喂饥,直接刪除zk節(jié)點(diǎn)
     * @param id
     */
    public void unLock(Integer id) {
        String path = "/xdclass-product-lock-" + id;
        try {
            zooKeeper.delete(path,-1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        }
    }


    private static class Singleton {

        private static ZkLock instance;
        static {
            instance = new ZkLock();
        }

        private static ZkLock getInstance() {
            return instance;
        }

    }
}
package com.wiggin.lock;


import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 線程不安全操作代碼實(shí)例
 */
public class UnSafeThread {

    private static int num = 0;

    private static CountDownLatch countDownLatch = new CountDownLatch(10);
    private static ZkLock lock = ZkLock.getInstance();

    /**y
     * 每次調(diào)用對num進(jìn)行++操作
     */
    public static void inCreate() {
        lock.lock(1);
        num++;
        System.out.println(num);
        lock.unLock(1);
    }

    public static void test() {
        System.out.println(Thread.currentThread().getName());
    }


    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                for (int j = 0; j < 100; j++) {
                    inCreate();
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //每個(gè)線程執(zhí)行完成之后消约,調(diào)用countdownLatch
                countDownLatch.countDown();
            }).start();
        }

        while (true) {
            if (countDownLatch.getCount() == 0) {
                System.out.println(num);
                break;
            }
        }
    }
}

dubbo核心架構(gòu)及流程

1.jpg
節(jié)點(diǎn) 角色說明
Provider 暴露服務(wù)的服務(wù)提供方
Consumer 調(diào)用遠(yuǎn)程服務(wù)的服務(wù)消費(fèi)方
Registry 服務(wù)注冊與發(fā)現(xiàn)的注冊中心
Monitor 統(tǒng)計(jì)服務(wù)的調(diào)用次數(shù)和調(diào)用時(shí)間的監(jiān)控中心
Container 服務(wù)運(yùn)行容器

調(diào)用關(guān)系說明

  • 服務(wù)容器負(fù)責(zé)啟動,加載员帮,運(yùn)行服務(wù)提供者或粮。
  • 服務(wù)提供者在啟動時(shí),向注冊中心注冊自己提供的服務(wù)捞高。
  • 服務(wù)消費(fèi)者在啟動時(shí)氯材,向注冊中心訂閱自己所需的服務(wù)。
  • 注冊中心返回服務(wù)提供者地址列表給消費(fèi)者硝岗,如果有變更氢哮,注冊中心將基于長連接推送變更數(shù)據(jù)給消費(fèi)者。
  • 服務(wù)消費(fèi)者型檀,從提供者地址列表中命浴,基于軟負(fù)載均衡算法,選一臺提供者進(jìn)行調(diào)用贱除,如果調(diào)用失敗生闲,再選另一臺調(diào)用。
  • 服務(wù)消費(fèi)者和提供者月幌,在內(nèi)存中累計(jì)調(diào)用次數(shù)和調(diào)用時(shí)間碍讯,定時(shí)每分鐘發(fā)送一次統(tǒng)計(jì)數(shù)據(jù)到監(jiān)控中心。

dubbo常見的多種開發(fā)方式

  • 通過注解的方式(多用于與springboot整合)
  • 通過xml配置
  • 通過api的方式----日常開發(fā)中比較少見

配置相關(guān)

雖然整合springboot時(shí)候可以通過注解方式扯躺,不過因?yàn)闅v史原因以及注解支持力度不足捉兴,所以一般還是通過配置文件xml形式開發(fā)蝎困。注意:dubbo可以單獨(dú)使用,不整合spring等倍啥,只是配置較為復(fù)雜而已禾乘。

創(chuàng)建多模塊項(xiàng)目

  • 首先正常創(chuàng)建maven項(xiàng)目
  • 刪除src文件夾
  • 在該項(xiàng)目下面創(chuàng)建module
  • 分別創(chuàng)建user-api(都是interface,然后本身作為其他項(xiàng)目的依賴),
  • user-service(服務(wù)提供者),user-web(服務(wù)消費(fèi)者)三個(gè)module
user-service的pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>dubbo</artifactId>
        <groupId>com.tjsmc</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>user-service</artifactId>

    <properties>
        <spring-boot.version>2.1.1.RELEASE</spring-boot.version>
        <dubbo.version>2.7.0</dubbo.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!-- Spring Boot -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!-- Aapche Dubbo  -->
            <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo-dependencies-bom</artifactId>
                <version>${dubbo.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo</artifactId>
                <version>${dubbo.version}</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>javax.servlet</groupId>
                        <artifactId>servlet-api</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>log4j</groupId>
                        <artifactId>log4j</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>com.tjsmc</groupId>
            <artifactId>user-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <!-- Dubbo Spring Boot Starter -->
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>2.7.0</version>
        </dependency>

        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo</artifactId>
        </dependency>

        <!-- Zookeeper -->
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
        </dependency>
    </dependencies>
user-web的pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>dubbo</artifactId>
        <groupId>com.tjsmc</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>user-web</artifactId>

    <properties>
        <spring-boot.version>2.1.1.RELEASE</spring-boot.version>
        <dubbo.version>2.7.0</dubbo.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!-- Spring Boot -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!-- Aapche Dubbo  -->
            <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo-dependencies-bom</artifactId>
                <version>${dubbo.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo</artifactId>
                <version>${dubbo.version}</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>javax.servlet</groupId>
                        <artifactId>servlet-api</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>log4j</groupId>
                        <artifactId>log4j</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>

        <dependency>
            <groupId>com.tjsmc</groupId>
            <artifactId>user-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <!-- Dubbo Spring Boot Starter -->
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>2.7.0</version>
        </dependency>

        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- Zookeeper -->
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
        </dependency>
    </dependencies>
</project>
項(xiàng)目的pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.tjsmc</groupId>
    <artifactId>dubbo</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>user-api</module>
        <module>user-service</module>
        <module>user-web</module>
    </modules>

    <build>
        <!--為了解決默認(rèn)使用jdk1.5當(dāng)作版本的提示錯(cuò)誤信息-->
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

基于注解的案例

user-api
UserService.java

package com.xdclass.user.service;
public interface UserService {
    String sayHello();
}
user-service
ServiceApplication.java


package com.xdclass.user.service;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;

@EnableAutoConfiguration
public class ServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServiceApplication.class);
    }
}
user-service
UserService.java


package com.xdclass.user.service.impl;

import com.xdclass.user.service.UserService;
import org.apache.dubbo.config.annotation.Service;

@Service(version = "1.0.0")
public class UserServiceImpl implements UserService {
    public String sayHello() {
        return "hello";
    }
}

user-service
application.yml

spring:
  application:
    name: dubbo-auto-configuration-provider-demo

dubbo:
  scan:
    base-packages: com.xdclass.user.service.impl
  protocol:
    name: dubbo
    port: 12345
  registry:
    address: N/A
user-web
WebApplication.java

package com.xdclass.user;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class WebApplication {
    public static void main(String[] args) {
        SpringApplication.run(WebApplication.class);
    }
}
user-web
UserController.java

package com.xdclass.user.controller;

import com.xdclass.user.service.UserService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {
    @Reference(version = "1.0.0", url = "dubbo://127.0.0.1:12345")
    private UserService userService;

    @RequestMapping("/sayHello")
    public String sayHello() {
        return userService.sayHello();
    }
}
user-web
application.yml

spring:
  application:
    name: dubbo-auto-configure-consumer-sample

之后的項(xiàng)目都使用xml文件形式配置

dubbo服務(wù)注冊中心

  • simple 注冊中心 ----不支持集群虽缕,不適用于生產(chǎn)環(huán)境
  • Multicast 注冊中心 ----開發(fā)階段使用
  • zookeeper 注冊中心 ----目前企業(yè)中最常用始藕,也是官方推薦
  • redis 注冊中心 ----雖然支持,但是較少使用
  • nacos 注冊中心 ----后起之秀

參考(https://nacos.io/zh-cn/docs/use-nacos-with-dubbo.html)

整合zk

Zookeeper 是 Apacahe Hadoop 的子項(xiàng)目氮趋,是一個(gè)樹型的目錄服務(wù)伍派,支持變更推送,適合作為 Dubbo 服務(wù)的注冊中心剩胁,工業(yè)強(qiáng)度較高诉植,可用于生產(chǎn)環(huán)境,并推薦使用


3.jpg

流程說明:

  • 服務(wù)提供者啟動時(shí): 向 /dubbo/com.foo.BarService/providers 目錄下寫入自己的 URL 地址
  • 服務(wù)消費(fèi)者啟動時(shí): 訂閱 /dubbo/com.foo.BarService/providers 目錄下的提供者 URL * 地址昵观。并向 /dubbo/com.foo.BarService/consumers 目錄下寫入自己的 URL 地址
  • 監(jiān)控中心啟動時(shí): 訂閱 /dubbo/com.foo.BarService 目錄下的所有提供者和消費(fèi)者 URL 地址晾腔。

支持以下功能:

  • 當(dāng)提供者出現(xiàn)斷電等異常停機(jī)時(shí),注冊中心能自動刪除提供者信息
  • 當(dāng)注冊中心重啟時(shí)啊犬,能自動恢復(fù)注冊數(shù)據(jù)灼擂,以及訂閱請求
  • 當(dāng)會話過期時(shí),能自動恢復(fù)注冊數(shù)據(jù)椒惨,以及訂閱請求
  • 當(dāng)設(shè)置 <dubbo:registry check="false" /> 時(shí)缤至,記錄失敗注冊和訂閱請求,后臺定時(shí)重試
  • 可通過 <dubbo:registry username="admin" password="1234" /> 設(shè)置 zookeeper 登錄信息
  • 可通過 <dubbo:registry group="dubbo" /> 設(shè)置 zookeeper 的根節(jié)點(diǎn)康谆,不配置將使用默認(rèn)的根節(jié)點(diǎn)领斥。
  • 支持 * 號通配符 <dubbo:reference group="" version="" />,可訂閱服務(wù)的所有分組和所有版本的提供者

官方文檔

user-service:服務(wù)提供者

spring:
  application:
    name: dubbo-auto-configuration-provider-demo


dubbo:
  scan:
    base-packages: com.xdclass.user.service.impl
  protocol:
    name: dubbo
    port: 12345
  registry:
    address: zookeeper://127.0.0.1:2181
user-web:服務(wù)消費(fèi)者
spring:
  application:
    name: dubbo-auto-configure-consumer-sample-terst
dubbo:
  registry:
    address: zookeeper://127.0.0.1:2181

配置如上則沃暗,@Reference(version = "1.0.0", url = "dubbo://127.0.0.1:12345")可以只留下@Reference(version = "1.0.0")

另外月洛,不論服務(wù)消費(fèi)還是提供者,都需要有個(gè)name代表項(xiàng)目唯一標(biāo)記孽锥,例如上面的spring的name嚼黔,也就是說如果springname沒有則必須添加dubbo的name否則啟動報(bào)錯(cuò)失敗

dubbo使用xml的配置方式

  • 在服務(wù)提供方,新增provider.xml(resources目錄下)惜辑,在里面配置服務(wù)提供方相應(yīng)的信息
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
    <dubbo:protocol name="dubbo" port="12345"/>
    <bean id="userService" class="com.xdclass.user.service.impl.UserServiceImpl"/>
    <dubbo:service interface="com.xdclass.user.service.UserService" ref="userService"/>
</beans>
  • 去掉具體服務(wù)實(shí)現(xiàn)類中@Service注解
  • 在啟動類中新增@ImportResource("provider.xml")
  • 在服務(wù)消費(fèi)方唬涧,新增consumer.xml的配置文件
  • 在啟動類中新增@ImportResource("consumer.xml")
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
    <dubbo:reference id="userService" check="false" interface="com.xdclass.user.service.UserService"/>
</beans>
  • 使用spring的@autowire注解替代@Reference

啟動依賴檢查

  • Dubbo 缺省會在啟動時(shí)檢查依賴的服務(wù)是否可用,不可用時(shí)會拋出異常盛撑,阻止 Spring 初始化完成碎节,以便上線時(shí),能及早發(fā)現(xiàn)問題,默認(rèn) check="true";例如消費(fèi)者先啟動根资,但是提供者還沒啟動,如果true則消費(fèi)者啟動報(bào)錯(cuò)秉犹,如果設(shè)置false殖氏,則

  • 可以通過 check="false"關(guān)閉檢查晚树,比如,測試時(shí)雅采,有些服務(wù)不關(guān)心爵憎,或者出現(xiàn)了循環(huán)依賴,必須有一方先啟動总滩。另外纲堵,如果你的 Spring 容器是懶加載的巡雨,或者通過 API 編程延遲引用服務(wù)闰渔,請關(guān)閉 check,否則服務(wù)臨時(shí)不可用時(shí)铐望,會拋出異常冈涧,拿到 null 引用,如果 check="false"正蛙,總是會返回引用督弓,當(dāng)服務(wù)恢復(fù)時(shí),能自動連上乒验。

  • 具體配置的方式

    • 針對特定某一服務(wù)去設(shè)置 @Reference(version = "1.0.0",check = false)
    • 在配置文件中進(jìn)行配置(實(shí)際開發(fā)中愚隧,比較建議使用配置文件的配置方式)
    • 啟動使用 -D 參數(shù)
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<!--    <dubbo:registry group="aaa" address="zookeeper://127.0.0.1:2181"/>-->
    <dubbo:reference id="userService" timeout="3000" check="false" interface="com.tjsmc.user.service.UserService">
<!--        方法級別的優(yōu)先級高于整個(gè)服務(wù)的優(yōu)先級-->
        <dubbo:method name="sayHello" timeout="5000" retries="4"></dubbo:method>
    </dubbo:reference>
    <dubbo:reference id="fileService" timeout="3000" check="false" interface="com.tjsmc.user.service.FileService"/>
</beans>
  • 各種配置對比
    • dubbo.reference.check=false,強(qiáng)制改變所有 reference 的 check 值锻全,就算配置中有聲明狂塘,也會被覆蓋。
    • dubbo.consumer.check=false鳄厌,是設(shè)置 check 的缺省值荞胡,如果配置中有顯式的聲明,如:<dubbo:reference check="true"/>了嚎,不會受影響泪漂。
    • dubbo.registry.check=false,前面兩個(gè)都是指訂閱成功歪泳,但提供者列表是否為空是否報(bào)錯(cuò)萝勤,如果注冊訂閱失敗時(shí),也允許啟動呐伞,需使用此選項(xiàng)敌卓,將在后臺定時(shí)重試。

dubbo配置加載流程

配置來源

  • JVM System Properties荸哟,-D參數(shù)

-D dubbo.reference.com.xdclass.user.service.UserService.check=true

  • Externalized Configuration假哎,外部化配置(2.7版本),基于dubbo-ops
  • ServiceConfig瞬捕、ReferenceConfig等編程接口采集的配置
  • 本地配置文件dubbo.properties
  • 配置的優(yōu)先級: 配置優(yōu)先級是從上往下一次遞減

dubbo超時(shí)機(jī)制及集群容錯(cuò)機(jī)制

  • 超時(shí)機(jī)制
    • 服務(wù)提供方進(jìn)行配置
    • 服務(wù)消費(fèi)方進(jìn)行配置
      • 方法級別
      • 服務(wù)級別
  • 如果方法跟整個(gè)服務(wù)同時(shí)設(shè)置了超時(shí)時(shí)間,這個(gè)時(shí)候以方法設(shè)置的超時(shí)時(shí)間為準(zhǔn)
  • 如果服務(wù)提供方跟服務(wù)消費(fèi)方同時(shí)設(shè)置了超時(shí)時(shí)間舵抹,則以服務(wù)消費(fèi)方為準(zhǔn)

集群容錯(cuò)機(jī)制

當(dāng)服務(wù)調(diào)用失敗的時(shí)候肪虎,默認(rèn)情況下,dubbo會進(jìn)行重試惧蛹,默認(rèn)重試次數(shù)為2(不包含第一次)扇救,所以可見被調(diào)用三次;通過retries="4" 設(shè)置重試次數(shù)

注意:集群容錯(cuò)如果設(shè)置,則會優(yōu)先,而重試次數(shù)反而不會執(zhí)行。集群容錯(cuò)類型

<dubbo:service interface="com.tjsmc.user.service.UserService" ref="userService" cluster="failsafe"/>

cluster="failsafe"就是集群容錯(cuò)的一種方式

容錯(cuò)簡介

在集群調(diào)用失敗時(shí)香嗓,Dubbo 提供了多種容錯(cuò)方案迅腔,缺省為 failover 重試


2.jpg

各節(jié)點(diǎn)關(guān)系:

  • 這里的 Invoker 是 Provider 的一個(gè)可調(diào)用 Service 的抽象,Invoker 封裝了 Provider 地址及 Service 接口信息
  • Directory 代表多個(gè) Invoker靠娱,可以把它看成 List<Invoker> 沧烈,但與 List 不同的是,它的值可能是動態(tài)變化的像云,比如注冊中心推送變更
  • Cluster 將 Directory 中的多個(gè) Invoker 偽裝成一個(gè) Invoker锌雀,對上層透明,偽裝過程包含了容錯(cuò)邏輯迅诬,調(diào)用失敗后腋逆,重試另一個(gè)
  • Router 負(fù)責(zé)從多個(gè) Invoker 中按路由規(guī)則選出子集,比如讀寫分離侈贷,應(yīng)用隔離等
  • LoadBalance 負(fù)責(zé)從多個(gè) Invoker中選出具體的一個(gè)用于本次調(diào)用惩歉,選的過程包含了負(fù)載均衡算法,調(diào)用失敗后俏蛮,需要重選

集群容錯(cuò)模式

  • Failover Cluster

失敗自動切換撑蚌,當(dāng)出現(xiàn)失敗,重試其它服務(wù)器 [1]嫁蛇。通常用于讀操作锨并,但重試會帶來更長延遲〔桥铮可通過 retries="2" 來設(shè)置重試次數(shù)(不含第一次)第煮。

重試次數(shù)配置如下(服務(wù)級別和方法級別):

<dubbo:service retries="2" />

<dubbo:reference>
    <dubbo:method name="findFoo" retries="2" />
</dubbo:reference>
  • Failfast Cluster

快速失敗,只發(fā)起一次調(diào)用抑党,失敗立即報(bào)錯(cuò)包警。通常用于非冪等性的寫操作,比如新增記錄底靠。

  • Failsafe Cluster

失敗安全害晦,出現(xiàn)異常時(shí),直接忽略。通常用于寫入審計(jì)日志等操作壹瘟。

  • Failback Cluster

失敗自動恢復(fù)鲫剿,后臺記錄失敗請求,定時(shí)重發(fā)稻轨。通常用于消息通知操作灵莲。

  • Forking Cluster

并行調(diào)用多個(gè)服務(wù)器,只要一個(gè)成功即返回殴俱。通常用于實(shí)時(shí)性要求較高的讀操作政冻,但需要浪費(fèi)更多服務(wù)資源∠哂可通過 forks="2" 來設(shè)置最大并行數(shù)明场。

  • Broadcast Cluster

廣播調(diào)用所有提供者,逐個(gè)調(diào)用李丰,任意一臺報(bào)錯(cuò)則報(bào)錯(cuò)苦锨。通常用于通知所有提供者更新緩存或日志等本地資源信息。

集群模式配置

按照以下示例在服務(wù)提供方和消費(fèi)方配置集群模式

<dubbo:service cluster="failsafe" />

<dubbo:reference cluster="failsafe" />

dubbo各協(xié)議及多協(xié)議配置

  • 依賴
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-util</artifactId>
</dependency>
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
</dependency>
<dependency>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-server</artifactId>
</dependency>
<dependency>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-servlet</artifactId>
</dependency>
  • 配置多協(xié)議

provider.xml文件中新增想要的協(xié)議

<dubbo:protocol name="http" port="8888"/>

暴露服務(wù)時(shí)使用 protocol="http" 讓其使用特性的協(xié)議暴露

基本實(shí)例:
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
    <dubbo:registry id="local" address="zookeeper://127.0.0.1:2181"/>
    <dubbo:protocol name="dubbo" port="12345"/>
<!--    地處聲明新協(xié)議-->
    <dubbo:protocol name="http" port="8888"/>
    <bean id="userService" class="com.tjsmc.user.service.impl.UserServiceImpl"/>
    <bean id="fileService" class="com.tjsmc.user.service.impl.FileServiceImpl"/>
<!--    暴漏給多個(gè)注冊中心則用逗號隔開id即可-->
    <dubbo:service interface="com.tjsmc.user.service.UserService" ref="userService" cluster="failsafe" registry="local"/>
<!--    此處使用指定協(xié)議,不指定默認(rèn)dubbo-->
    <dubbo:service interface="com.tjsmc.user.service.FileService" ref="fileService" protocol="http"/>
</beans>
  • 修改啟動類的方式為非web

new SpringApplicationBuilder(ServiceApplication.class).web(WebApplicationType.NONE).run();

多注冊中心及其配置

Dubbo 支持同一服務(wù)向多注冊中心同時(shí)注冊逆屡,或者不同服務(wù)分別注冊到不同的注冊中心上去圾旨,甚至可以同時(shí)引用注冊在不同注冊中心上的同名服務(wù)踱讨。另外,注冊中心是支持自定義擴(kuò)展的

  • 新增<dubbo:registry address="zookeeper://192.1.1.101:2181"/>
  • 多個(gè)注冊中心使用id屬性進(jìn)行區(qū)分 id="remote"砍的,服務(wù)暴露時(shí)痹筛,多個(gè)注冊中心使用逗號分隔

多注冊中心注冊

比如:中文站有些服務(wù)來不及在青島部署,只在杭州部署廓鞠,而青島的其它應(yīng)用需要引用此服務(wù)帚稠,就可以將服務(wù)同時(shí)注冊到兩個(gè)注冊中心。

<?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://dubbo.apache.org/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
    <dubbo:application name="world"  />
    <!-- 多注冊中心配置 -->
    <dubbo:registry id="hangzhouRegistry" address="10.20.141.150:9090" />
    <dubbo:registry id="qingdaoRegistry" address="10.20.141.151:9010" default="false" />
    <!-- 向多個(gè)注冊中心注冊 -->
    <dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" registry="hangzhouRegistry,qingdaoRegistry" />
</beans>

不同服務(wù)使用不同注冊中心

比如:CRM 有些服務(wù)是專門為國際站設(shè)計(jì)的床佳,有些服務(wù)是專門為中文站設(shè)計(jì)的滋早。

<?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://dubbo.apache.org/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
    <dubbo:application name="world"  />
    <!-- 多注冊中心配置 -->
    <dubbo:registry id="chinaRegistry" address="10.20.141.150:9090" />
    <dubbo:registry id="intlRegistry" address="10.20.154.177:9010" default="false" />
    <!-- 向中文站注冊中心注冊 -->
    <dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" registry="chinaRegistry" />
    <!-- 向國際站注冊中心注冊 -->
    <dubbo:service interface="com.alibaba.hello.api.DemoService" version="1.0.0" ref="demoService" registry="intlRegistry" />
</beans>

多注冊中心引用

比如:CRM 需同時(shí)調(diào)用中文站和國際站的 PC2 服務(wù),PC2 在中文站和國際站均有部署砌们,接口及版本號都一樣杆麸,但連的數(shù)據(jù)庫不一樣。

<?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://dubbo.apache.org/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
    <dubbo:application name="world"  />
    <!-- 多注冊中心配置 -->
    <dubbo:registry id="chinaRegistry" address="10.20.141.150:9090" />
    <dubbo:registry id="intlRegistry" address="10.20.154.177:9010" default="false" />
    <!-- 引用中文站服務(wù) -->
    <dubbo:reference id="chinaHelloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" registry="chinaRegistry" />
    <!-- 引用國際站站服務(wù) -->
    <dubbo:reference id="intlHelloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" registry="intlRegistry" />
</beans>

如果只是測試環(huán)境臨時(shí)需要連接兩個(gè)不同注冊中心浪感,使用豎號分隔多個(gè)不同注冊中心地址:

<?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://dubbo.apache.org/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
    <dubbo:application name="world"  />
    <!-- 多注冊中心配置昔头,豎號分隔表示同時(shí)連接多個(gè)不同注冊中心,同一注冊中心的多個(gè)集群地址用逗號分隔 -->
    <dubbo:registry address="10.20.141.150:9090|10.20.154.177:9010" />
    <!-- 引用服務(wù) -->
    <dubbo:reference id="helloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" />
</beans>

Dubbo服務(wù)分組及其配置

當(dāng)一個(gè)接口有多種實(shí)現(xiàn)時(shí)影兽,可以用 group 區(qū)分;服務(wù)提供者揭斧,在標(biāo)簽里加多個(gè)group進(jìn)行區(qū)分

<dubbo:service group="user1" interface="com.xdclass.user.service.UserService" ref="userService" /> 
<dubbo:service group="user2" interface="com.xdclass.user.service.UserService" ref="userService2" />

服務(wù)消費(fèi)者在引用的時(shí)候,也在標(biāo)簽里加group

<dubbo:reference group="user2" id="userService" check="false" interface="com.xdclass.user.service.UserService"/>

任意組

<dubbo:reference id="barService" interface="com.foo.BarService" group="*" />

Dubbo服務(wù)多版本化及其配置

當(dāng)一個(gè)接口實(shí)現(xiàn)峻堰,出現(xiàn)不兼容升級時(shí)讹开,可以用版本號過渡盅视,版本號不同的服務(wù)相互間不引用。

可以按照以下的步驟進(jìn)行版本遷移:

  • 在低壓力時(shí)間段旦万,先升級一半提供者為新版本
  • 再將所有消費(fèi)者升級為新版本
  • 然后將剩下的一半提供者升級為新版本

老版本服務(wù)提供者配置:

<dubbo:service interface="com.foo.BarService" version="1.0.0" />

新版本服務(wù)提供者配置:

<dubbo:service interface="com.foo.BarService" version="2.0.0" />

老版本服務(wù)消費(fèi)者配置:

<dubbo:reference id="barService" interface="com.foo.BarService" version="1.0.0" />

新版本服務(wù)消費(fèi)者配置:

<dubbo:reference id="barService" interface="com.foo.BarService" version="2.0.0" />

如果不需要區(qū)分版本左冬,可以按照以下的方式配置:

<dubbo:reference id="barService" interface="com.foo.BarService" version="*" />

新版管控臺dubbo-ops的編譯安裝

舊版:dubbo-admin 新版 dubbo-ops

新版管理控制臺主要的作用

  • 服務(wù)查詢,服務(wù)治理(包括Dubbo2.7中新增的治理規(guī)則)以及服務(wù)測試纸型、配置管理

  • 步驟

克隆項(xiàng)目到本地拇砰,并編譯安裝和啟動

git clone https://github.com/apache/incubator-dubbo-ops.git

cd incubator-dubbo-ops

mvn clean package

修改配置文件 dubbo-admin-server/src/main/resources/application-production.properties中的注冊中心的地址

cd dubbo-distribution/target

java -jar dubbo-admin-0.1.jar

啟動完成后,直接訪問http://localhost:8080

動態(tài)配置中心及配置外部化

  • 動態(tài)配置中心的責(zé)職

外部化配置,啟動配置的集中式存儲,簡單理解為dubbo.properties的外部化存儲, 服務(wù)治理,服務(wù)治理規(guī)則的存儲與通知狰腌。

  • 如何使用?
在dubbo-ops 進(jìn)行配置信息配置
在項(xiàng)目里使用<dubbo:config-center address="zookeeper://127.0.0.1:2181"/>
配置中心中的配置的作用域

如果全局配置跟應(yīng)用級別均配置了相同的信息除破,這個(gè)時(shí)候以應(yīng)用級別的為準(zhǔn)

元數(shù)據(jù)中心及服務(wù)測試

  • dubbo provider中的服務(wù)配置項(xiàng)有接近30個(gè)配置項(xiàng)。 排除注冊中心服務(wù)治理需要之外琼腔,很大一部分配置項(xiàng)是provider自己使用瑰枫,不需要透傳給消費(fèi)者。這部分?jǐn)?shù)據(jù)不需要進(jìn)入注冊中心丹莲,而只需要以key-value形式持久化存儲光坝。 dubbo consumer中的配置項(xiàng)也有20+個(gè)配置項(xiàng)。在注冊中心之中甥材,服務(wù)消費(fèi)者列表中只需要關(guān)注application盯另,version,group洲赵,ip鸳惯,dubbo版本等少量配置,其他配置也可以以key-value形式持久化存儲叠萍。 這些數(shù)據(jù)是以服務(wù)為維度注冊進(jìn)入注冊中心芝发,導(dǎo)致了數(shù)據(jù)量的膨脹,進(jìn)而引發(fā)注冊中心(如zookeeper)的網(wǎng)絡(luò)開銷增大苛谷,性能降低辅鲸。
  • 除了上述配置項(xiàng)的存儲之外,dubbo服務(wù)元數(shù)據(jù)信息也需要被存儲下來腹殿。元數(shù)據(jù)信息包括服務(wù)接口独悴,及接口的方法信息。這些信息將被用于服務(wù)mock赫蛇,服務(wù)測試绵患。
  • 官方文檔
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市悟耘,隨后出現(xiàn)的幾起案子落蝙,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件筏勒,死亡現(xiàn)場離奇詭異移迫,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)管行,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進(jìn)店門厨埋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人捐顷,你說我怎么就攤上這事荡陷。” “怎么了迅涮?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵废赞,是天一觀的道長。 經(jīng)常有香客問我叮姑,道長唉地,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任传透,我火速辦了婚禮耘沼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘朱盐。我一直安慰自己群嗤,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布托享。 她就那樣靜靜地躺著骚烧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪闰围。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天既峡,我揣著相機(jī)與錄音羡榴,去河邊找鬼。 笑死运敢,一個(gè)胖子當(dāng)著我的面吹牛校仑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播传惠,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼迄沫,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了卦方?” 一聲冷哼從身側(cè)響起羊瘩,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后尘吗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體逝她,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年睬捶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了黔宛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,643評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡擒贸,死狀恐怖臀晃,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情介劫,我是刑警寧澤积仗,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站蜕猫,受9級特大地震影響寂曹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜回右,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一隆圆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧翔烁,春花似錦渺氧、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至慨默,卻和暖如春贩耐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背厦取。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工潮太, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人虾攻。 一個(gè)月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓铡买,卻偏偏與公主長得像,于是被迫代替她去往敵國和親霎箍。 傳聞我的和親對象是個(gè)殘疾皇子奇钞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,509評論 2 348