分布式消息隊(duì)列(MQ)
為什么使用 MQ巢株?
異步處理 - 相比于傳統(tǒng)的串行槐瑞、并行方式,提高了系統(tǒng)吞吐量阁苞。
應(yīng)用解耦 - 系統(tǒng)間通過(guò)消息通信随珠,不用關(guān)心其他系統(tǒng)的處理。
流量削鋒 - 可以通過(guò)消息隊(duì)列長(zhǎng)度控制請(qǐng)求量猬错;可以緩解短時(shí)間內(nèi)的高并發(fā)請(qǐng)求。
日志處理 - 解決大量日志傳輸茸歧。
消息通訊 - 消息隊(duì)列一般都內(nèi)置了高效的通信ji制倦炒,因此也可以用在純的消息通訊。比如實(shí)現(xiàn)點(diǎn)對(duì)點(diǎn)消息隊(duì)列软瞎,或者聊天室等逢唤。
如何保證 MQ 的高可用?
將所有 Broker 和待分配的 Partition 排序
將第 i 個(gè) Partition 分配到第(i mod n)個(gè) Broker 上
將第 i 個(gè) Partition 的第 j 個(gè) Replica 分配到第((i + j) mode n)個(gè) Broker 上
MQ 有哪些常見(jiàn)問(wèn)題涤浇?如何解決這些問(wèn)題鳖藕?
MQ 的常見(jiàn)問(wèn)題有:
消息的順序問(wèn)題
消息的重復(fù)問(wèn)題
消息的順序問(wèn)題
消息有序指的是可以按照消息的發(fā)送順序來(lái)消費(fèi)。
假如生產(chǎn)者產(chǎn)生了 2 條消息:M1只锭、M2著恩,假定 M1 發(fā)送到 S1,M2 發(fā)送到 S2蜻展,如果要保證 M1 先于 M2 被消費(fèi)喉誊,怎么做?
解決方案:
(1)保證生產(chǎn)者 - MQServer - 消費(fèi)者是一對(duì)一對(duì)一的關(guān)系
缺陷:
并行度就會(huì)成為消息系統(tǒng)的瓶頸(吞吐量不夠)
更多的異常處理纵顾,比如:只要消費(fèi)端出現(xiàn)問(wèn)題伍茄,就會(huì)導(dǎo)致整個(gè)處理流程阻塞,我們不得不花費(fèi)更多的精力來(lái)解決阻塞的問(wèn)題施逾。
(2)通過(guò)合理的設(shè)計(jì)或者將問(wèn)題分解來(lái)規(guī)避敷矫。不關(guān)注亂序的應(yīng)用實(shí)際大量存在
隊(duì)列無(wú)序并不意味著消息無(wú)序
所以從業(yè)務(wù)層面來(lái)保證消息的順序而不僅僅是依賴于消息系統(tǒng)例获,是一種更合理的方式。
消息的重復(fù)問(wèn)題
造成消息重復(fù)的根本原因是:網(wǎng)絡(luò)不可達(dá)曹仗。
所以解決這個(gè)問(wèn)題的辦法就是繞過(guò)這個(gè)問(wèn)題榨汤。那么問(wèn)題就變成了:如果消費(fèi)端收到兩條一樣的消息,應(yīng)該怎樣處理整葡?
消費(fèi)端處理消息的業(yè)務(wù)邏輯保持冪等性件余。只要保持冪等性,不管來(lái)多少條重復(fù)消息遭居,最后處理的結(jié)果都一樣啼器。保證每條消息都有唯一編號(hào)且保證消息處理成功與去重表的日志同時(shí)出現(xiàn)。利用一張日志表來(lái)記錄已經(jīng)處理成功的消息的 ID俱萍,如果新到的消息 ID 已經(jīng)在日志表中端壳,那么就不再處理這條消息。
Kafka, ActiveMQ, RabbitMQ, RocketMQ 各有什么優(yōu)缺點(diǎn)枪蘑?
分布式服務(wù)(RPC)
Dubbo 的實(shí)現(xiàn)過(guò)程损谦?
節(jié)點(diǎn)角色:
調(diào)用關(guān)系:
- 務(wù)容器負(fù)責(zé)啟動(dòng),加載岳颇,運(yùn)行服務(wù)提供者
- 服務(wù)提供者在啟動(dòng)時(shí)照捡,向注冊(cè)中心注冊(cè)自己提供的服務(wù)。
- 服務(wù)消費(fèi)者在啟動(dòng)時(shí)话侧,向注冊(cè)中心訂閱自己所需的服務(wù)栗精。
- 注冊(cè)中心返回服務(wù)提供者地址列表給消費(fèi)者,如果有變更瞻鹏,注冊(cè)中心將基于長(zhǎng)連接推送變更數(shù)據(jù)給消費(fèi)者悲立。
- 服務(wù)消費(fèi)者,從提供者地址列表中新博,基于軟負(fù)載均衡算法薪夕,選一臺(tái)提供者進(jìn)行調(diào)用,如果調(diào)用失敗赫悄,再選另一臺(tái)調(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ù)載均衡策略有哪些?
Random
- 隨機(jī)同诫,按權(quán)重設(shè)置隨機(jī)概率粤策。
- 在一個(gè)截面上碰撞的概率高,但調(diào)用量越大分布越均勻误窖,而且按概率使用權(quán)重后也比較均勻叮盘,有利于動(dòng)態(tài)調(diào)整提供者權(quán)重秩贰。
RoundRobin - 輪循,按公約后的權(quán)重設(shè)置輪循比率柔吼。
- 存在慢的提供者累積請(qǐng)求的問(wèn)題毒费,比如:第二臺(tái)機(jī)器很慢,但沒(méi)掛愈魏,當(dāng)請(qǐng)求調(diào)到第二臺(tái)時(shí)就卡在那觅玻,久而久之,所有請(qǐng)求都卡在調(diào)到第二臺(tái)上培漏。
LeastActive - 最少活躍調(diào)用數(shù)溪厘,相同活躍數(shù)的隨機(jī),活躍數(shù)指調(diào)用前后計(jì)數(shù)差牌柄。
- 使慢的提供者收到更少請(qǐng)求畸悬,因?yàn)樵铰奶峁┱叩恼{(diào)用前后計(jì)數(shù)差會(huì)越大。
ConsistentHash - 一致性 Hash珊佣,相同參數(shù)的請(qǐng)求總是發(fā)到同一提供者蹋宦。
- 當(dāng)某一臺(tái)提供者掛時(shí),原本發(fā)往該提供者的請(qǐng)求咒锻,基于虛擬節(jié)點(diǎn)冷冗,平攤到其它提供者,不會(huì)引起劇烈變動(dòng)惑艇。
- 缺省只對(duì)第一個(gè)參數(shù) Hash蒿辙,如果要修改,請(qǐng)配置 <dubbo:parameter key="hash.arguments" value="0,1" />
- 缺省用 160 份虛擬節(jié)點(diǎn)敦捧,如果要修改,請(qǐng)配置 <dubbo:parameter key="hash.nodes" value="320" />
Dubbo 集群容錯(cuò)策略 碰镜?
- Failover - 失敗自動(dòng)切換兢卵,當(dāng)出現(xiàn)失敗,重試其它服務(wù)器绪颖。通常用于讀操作秽荤,但重試會(huì)帶來(lái)更長(zhǎng)延遲∧幔可通過(guò) retries="2" 來(lái)設(shè)置重試次數(shù)(不含第一次)窃款。
- Failfast - 快速失敗,只發(fā)起一次調(diào)用牍氛,失敗立即報(bào)錯(cuò)晨继。通常用于非冪等性的寫操作,比如新增記錄搬俊。
- Failsafe - 失敗安全紊扬,出現(xiàn)異常時(shí)蜒茄,直接忽略。通常用于寫入審計(jì)日志等操作餐屎。
- Failback - 失敗自動(dòng)恢復(fù)檀葛,后臺(tái)記錄失敗請(qǐng)求,定時(shí)重發(fā)腹缩。通常用于消息通知操作屿聋。
- Forking - 并行調(diào)用多個(gè)服務(wù)器,只要一個(gè)成功即返回藏鹊。通常用于實(shí)時(shí)性要求較高的讀操作润讥,但需要浪費(fèi)更多服務(wù)資源』锱校可通過(guò) forks="2" 來(lái)設(shè)置最大并行數(shù)象对。
- Broadcast - 播調(diào)用所有提供者,逐個(gè)調(diào)用宴抚,任意一臺(tái)報(bào)錯(cuò)則報(bào)錯(cuò)勒魔。通常用于通知所有提供者更新緩存或日志等本地資源信息。
動(dòng)態(tài)代理策略菇曲?
Dubbo 作為 RPC 框架冠绢,首先要完成的就是跨系統(tǒng),跨網(wǎng)絡(luò)的服務(wù)調(diào)用常潮。消費(fèi)方與提供方遵循統(tǒng)一的接口定義弟胀,消費(fèi)方調(diào)用接口時(shí),Dubbo 將其轉(zhuǎn)換成統(tǒng)一格式的數(shù)據(jù)結(jié)構(gòu)喊式,通過(guò)網(wǎng)絡(luò)傳輸孵户,提供方根據(jù)規(guī)則找到接口實(shí)現(xiàn),通過(guò)反射完成調(diào)用岔留。也就是說(shuō)夏哭,消費(fèi)方獲取的是對(duì)遠(yuǎn)程服務(wù)的一個(gè)代理(Proxy),而提供方因?yàn)橐С植煌慕涌趯?shí)現(xiàn)献联,需要一個(gè)包裝層(Wrapper)竖配。調(diào)用的過(guò)程大概是這樣:
消費(fèi)方的 Proxy 和提供方的 Wrapper 得以讓 Dubbo 構(gòu)建出復(fù)雜秽五、統(tǒng)一的體系沛厨。而這種動(dòng)態(tài)代理與包裝也是通過(guò)基于 SPI 的插件方式實(shí)現(xiàn)的,它的接口就是ProxyFactory粉渠。
@SPI("javassist")
public interface ProxyFactory {
@Adaptive({Constants.PROXY_KEY})
<T> T getProxy(Invoker<T> invoker) throws RpcException;
@Adaptive({Constants.PROXY_KEY})
<T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;
}
ProxyFactory 有兩種實(shí)現(xiàn)方式原押,一種是基于 JDK 的代理實(shí)現(xiàn)胁镐,一種是基于 javassist 的實(shí)現(xiàn)。ProxyFactory 接口上定義了@SPI("javassist"),默認(rèn)為 javassist 的實(shí)現(xiàn)希停。
Dubbo 支持哪些序列化協(xié)議烁巫?Hessian?Hessian 的數(shù)據(jù)結(jié)構(gòu)宠能?
- dubbo 序列化亚隙,阿里尚不成熟的 java 序列化實(shí)現(xiàn)。
- hessian2 序列化:hessian 是一種跨語(yǔ)言的高效二進(jìn)制的序列化方式违崇,但這里實(shí)際不是原生的 hessian2 序列化阿弃,而是阿里修改過(guò)的 hessian lite,它是 dubbo RPC 默認(rèn)啟用的序列化方式羞延。
- json 序列化:目前有兩種實(shí)現(xiàn)渣淳,一種是采用的阿里的 fastjson 庫(kù),另一種是采用 dubbo 中自已實(shí)現(xiàn)的簡(jiǎn)單 json 庫(kù)伴箩,一般情況下入愧,json 這種文本序列化性能不如二進(jìn)制序列化。
- java 序列化:主要是采用 JDK 自帶的 java 序列化實(shí)現(xiàn)嗤谚,性能很不理想棺蛛。
- Kryo 和 FST:Kryo 和 FST 的性能依然普遍優(yōu)于 hessian 和 dubbo 序列化。
Hessian 序列化與 Java 默認(rèn)的序列化區(qū)別巩步?
Hessian 是一個(gè)輕量級(jí)的 remoting on http 工具旁赊,采用的是 Binary RPC 協(xié)議,所以它很適合于發(fā)送二進(jìn)制數(shù)據(jù)椅野,同時(shí)又具有防火墻穿透能力终畅。
- Hessian 支持跨語(yǔ)言串行
- 比 java 序列化具有更好的性能和易用性
- 支持的語(yǔ)言比較多
Protoco Buffer 是什么?
Protocol Buffer 是 Google 出品的一種輕量 & 高效的結(jié)構(gòu)化數(shù)據(jù)存儲(chǔ)格式竟闪,性能比 Json离福、XML 真的強(qiáng)!太炼蛤!多妖爷!
Protocol Buffer 的序列化 & 反序列化簡(jiǎn)單 & 速度快的原因是:
編碼 / 解碼 方式簡(jiǎn)單(只需要簡(jiǎn)單的數(shù)學(xué)運(yùn)算 = 位移等等)
采用 Protocol Buffer 自身的框架代碼 和 編譯器 共同完成
Protocol Buffer 的數(shù)據(jù)壓縮效果好(即序列化后的數(shù)據(jù)量體積小)的原因是:采用了獨(dú)特的編碼方式鲸湃,如 Varint赠涮、Zigzag 編碼方式等等
采用 T - L - V 的數(shù)據(jù)存儲(chǔ)方式:減少了分隔符的使用 & 數(shù)據(jù)存儲(chǔ)得緊湊
注冊(cè)中心掛了可以繼續(xù)通信嗎子寓?
可以暗挑。Dubbo 消費(fèi)者在應(yīng)用啟動(dòng)時(shí)會(huì)從注冊(cè)中心拉取已注冊(cè)的生產(chǎn)者的地址接口,并緩存在本地斜友。每次調(diào)用時(shí)炸裆,按照本地存儲(chǔ)的地址進(jìn)行調(diào)用。
ZooKeeper 原理是什么鲜屏?ZooKeeper 有什么用烹看?
ZooKeeper 是一個(gè)分布式應(yīng)用協(xié)調(diào)系統(tǒng)国拇,已經(jīng)用到了許多分布式項(xiàng)目中,用來(lái)完成統(tǒng)一命名服務(wù)惯殊、狀態(tài)同步服務(wù)酱吝、集群管理、分布式應(yīng)用配置項(xiàng)的管理等工作土思。
- 每個(gè) Server 在內(nèi)存中存儲(chǔ)了一份數(shù)據(jù)务热;
- Zookeeper 啟動(dòng)時(shí),將從實(shí)例中選舉一個(gè) leader(Paxos 協(xié)議)己儒;
- Leader 負(fù)責(zé)處理數(shù)據(jù)更新等操作(Zab 協(xié)議)崎岂;
- 一個(gè)更新操作成功,當(dāng)且僅當(dāng)大多數(shù) Server 在內(nèi)存中成功修改數(shù)據(jù)闪湾。
Netty 有什么用冲甘?NIO/BIO/AIO 有什么用?有什么區(qū)別途样?
Netty 是一個(gè)“網(wǎng)絡(luò)通訊框架”江醇。
Netty 進(jìn)行事件處理的流程。Channel是連接的通道娘纷,是 ChannelEvent 的產(chǎn)生者嫁审,而ChannelPipeline可以理解為 ChannelHandler 的集合。
IO 的方式通常分為幾種:
- 同步阻塞的 BIO
- 同步非阻塞的 NIO
- 異步非阻塞的 AIO
在使用同步 I/O 的網(wǎng)絡(luò)應(yīng)用中赖晶,如果要同時(shí)處理多個(gè)客戶端請(qǐng)求律适,或是在客戶端要同時(shí)和多個(gè)服務(wù)器進(jìn)行通訊,就必須使用多線程來(lái)處理遏插。
NIO 基于 Reactor捂贿,當(dāng) socket 有流可讀或可寫入 socket 時(shí),操作系統(tǒng)會(huì)相應(yīng)的通知引用程序進(jìn)行處理胳嘲,應(yīng)用再將流讀取到緩沖區(qū)或?qū)懭氩僮飨到y(tǒng)厂僧。也就是說(shuō),這個(gè)時(shí)候了牛,已經(jīng)不是一個(gè)連接就要對(duì)應(yīng)一個(gè)處理線程了颜屠,而是有效的請(qǐng)求,對(duì)應(yīng)一個(gè)線程鹰祸,當(dāng)連接沒(méi)有數(shù)據(jù)時(shí)甫窟,是沒(méi)有工作線程來(lái)處理的。
與 NIO 不同蛙婴,當(dāng)進(jìn)行讀寫操作時(shí)粗井,只須直接調(diào)用 API 的 read 或 write 方法即可。這兩種方法均為異步的,對(duì)于讀操作而言浇衬,當(dāng)有流可讀取時(shí)懒构,操作系統(tǒng)會(huì)將可讀的流傳入 read 方法的緩沖區(qū),并通知應(yīng)用程序耘擂;對(duì)于寫操作而言胆剧,當(dāng)操作系統(tǒng)將 write 方法傳遞的流寫入完畢時(shí),操作系統(tǒng)主動(dòng)通知應(yīng)用程序醉冤。即可以理解為赞赖,read/write 方法都是異步的,完成后會(huì)主動(dòng)調(diào)用回調(diào)函數(shù)冤灾。
為什么要進(jìn)行系統(tǒng)拆分前域?拆分不用 Dubbo 可以嗎?
系統(tǒng)拆分從資源角度分為:應(yīng)用拆分和數(shù)據(jù)庫(kù)拆分韵吨。
從采用的先后順序可分為:水平擴(kuò)展匿垄、垂直拆分、業(yè)務(wù)拆分归粉、水平拆分椿疗。
是否使用服務(wù)依據(jù)實(shí)際業(yè)務(wù)場(chǎng)景來(lái)決定。
當(dāng)垂直應(yīng)用越來(lái)越多糠悼,應(yīng)用之間交互不可避免届榄,將核心業(yè)務(wù)抽取出來(lái),作為獨(dú)立的服務(wù)倔喂,逐漸形成穩(wěn)定的服務(wù)中心铝条,使前端應(yīng)用能更快速的響應(yīng)多變的市場(chǎng)需求。此時(shí)席噩,用于提高業(yè)務(wù)復(fù)用及整合的分布式服務(wù)框架(RPC)是關(guān)鍵班缰。
當(dāng)服務(wù)越來(lái)越多,容量的評(píng)估悼枢,小服務(wù)資源的浪費(fèi)等問(wèn)題逐漸顯現(xiàn)埠忘,此時(shí)需增加一個(gè)調(diào)度中心基于訪問(wèn)壓力實(shí)時(shí)管理集群容量,提高集群利用率馒索。此時(shí)莹妒,用于提高機(jī)器利用率的資源調(diào)度和治理中心(SOA)是關(guān)鍵。
Dubbo 和 Thrift 有什么區(qū)別绰上?
- Thrift 是跨語(yǔ)言的 RPC 框架旨怠。
- Dubbo 支持服務(wù)治理,而 Thrift 不支持渔期。
更多精選面試題直達(dá)通道:https://shimo.im/docs/TC9Jq63Tp6HvTXdg/