聊聊DataStream API 應(yīng)用實(shí)例
本文轉(zhuǎn)載自微信公眾號(hào)「數(shù)倉寶貝庫」,作者張利兵 。轉(zhuǎn)載本文請(qǐng)聯(lián)系數(shù)倉寶貝庫公眾號(hào)。
不想看字的同學(xué)可直接劃到底部查看思維導(dǎo)圖
問題分析
使用過Dubbo的朋友很多都碰到過如下報(bào)錯(cuò):
No provider available for the service org.newboo.basic.api.MyDemoService from registry 127.0.0.1:2181 on the consumer 127.0.0.1 using the dubbo version 2.7.6. Please check if the providers have been started and registered.
從源碼來看這個(gè)報(bào)錯(cuò)位于
org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker#checkInvokers
- protected void checkInvokers(List<Invoker<T>> invokers, Invocation invocation) {
- if (CollectionUtils.isEmpty(invokers)) {
- throw new RpcException(RpcException.NO_INVOKER_AVAILABLE_AFTER_FILTER, "Failed to invoke the method "
- + invocation.getMethodName() + " in the service " + getInterface().getName()
- + ". No provider available for the service " + getDirectory().getConsumerUrl().getServiceKey()
- + " from registry " + getDirectory().getUrl().getAddress()
- + " on the consumer " + NetUtils.getLocalHost()
- + " using the dubbo version " + Version.getVersion()
- + ". Please check if the providers have been started and registered.");
- }
- }
當(dāng)配置reference的check=false時(shí)調(diào)用它的代碼位于
org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker#doInvoke
(為true時(shí)在啟動(dòng)時(shí)校驗(yàn))
從代碼能看出導(dǎo)致這個(gè)報(bào)錯(cuò)的直接原因是:invokers為空
此處invoker對(duì)應(yīng)一個(gè)provider URL,當(dāng)沒有provider可用時(shí),invokers為空
排查思路
這個(gè)問題看似簡(jiǎn)單,但實(shí)際情況異常復(fù)雜,碰到后無從下手,本文提供一種可行的排查思路。
排查大致分為兩條線,provider端和consumer端。
provider端
出問題第一時(shí)間排查provider,因?yàn)閜rovider的情況比較少,可以簡(jiǎn)單地排除一部分情況。
provider出問題只有一種情況:未注冊(cè)到注冊(cè)中心
所以對(duì)應(yīng)的排查思路是去看provider有沒有注冊(cè)成功:
- 如果有dubbo控制臺(tái)或者注冊(cè)中心查詢頁面,直接查詢一下即可
- 如果沒有可視化界面,比如zk、etcd可通過相應(yīng)的客戶端連上去查看是否注冊(cè)成功
以zk為例,可通過 ls /dubbo/${service}/providers 查看注冊(cè)上的provider
如果provider未注冊(cè)成功,那么就需要排查,可能的原因有:
- provider未啟動(dòng)成功,啟動(dòng)一下即可
- provider雖然啟動(dòng)了,但注冊(cè)失敗了,查看一下錯(cuò)誤日志,對(duì)癥解決
- 注冊(cè)中心地址是否寫錯(cuò)?環(huán)境是否一致?
如果provider已經(jīng)注冊(cè),說明provider沒問題,再看consumer。
consumer端
consumer端排查還需再細(xì)分,以是否訂閱(拉取)到對(duì)應(yīng)provider信息為界
如何查看consumer的訂閱信息
consumer訂閱信息可從緩存文件中查看,緩存文件默認(rèn)按如下規(guī)則生成:
- tring defaultFilename = System.getProperty("user.home") + "/.dubbo/dubbo-registry-" + url.getApplication() + "-" + url.getAddress().replaceAll(":", "-") + ".cache";
例如:
~/.dubbo/dubbo-registry-ddog-my-demo-c0-127.0.0.1-2181.cache
有多個(gè)注冊(cè)中心,將有多個(gè)緩存文件,文件內(nèi)容如下:
- #Dubbo Registry Cache
- #Wed Aug 11 20:26:15 CST 2021
- org.newboo.basic.api.MyDemoService=empty\://127.0.0.1/org.newboo.basic.api.MyDemoService?application\=ddog-my-demo-c0&category\=routers&check\=false&dubbo\=2.0.2&init\=false&interface\=org.newboo.basic.api.MyDemoService&loadbalance\=xxx&methods\=call&owner\=roshilikang&pid\=3084&qos.enable\=true&qos.port\=33333&release\=2.7.6&side\=consumer&sticky\=false×tamp\=1628684774590 empty\://127.0.0.1/org.newboo.basic.api.MyDemoService?application\=ddog-my-demo-c0&category\=configurators&check\=false&dubbo\=2.0.2&init\=false&interface\=org.newboo.basic.api.MyDemoService&loadbalance\=xxx&methods\=call&owner\=roshilikang&pid\=3084&qos.enable\=true&qos.port\=33333&release\=2.7.6&side\=consumer&sticky\=false×tamp\=1628684774590 dubbo\://127.0.0.1\:20880/org.newboo.basic.api.MyDemoService?anyhost\=true&application\=ddog-my-demo-p0&deprecated\=false&dubbo\=2.0.2&dynamic\=true&generic\=false&interface\=org.newboo.basic.api.MyDemoService&methods\=call&owner\=roshilikang&pid\=2058&release\=2.7.6&side\=provider&threads\=500×tamp\=1628684412247
搜索文件中是否有對(duì)應(yīng)服務(wù)的provider
未成功訂閱
如果沒拿到信息(搜索不到對(duì)應(yīng)的provider),說明訂閱存在問題,檢查consumer日志是否有報(bào)錯(cuò),注冊(cè)中心地址,環(huán)境等配置是否有問題。
成功訂閱
比如這個(gè)文件,存在
- dubbo\://127.0.0.1\:20880/org.newboo.basic.api.MyDemoService?anyhost\=true&application\=ddog-my-demo-p0&deprecated\=false&dubbo\=2.0.2&dynamic\=true&generic\=false&interface\=org.newboo.basic.api.MyDemoService&methods\=call&owner\=roshilikang&pid\=2058&release\=2.7.6&side\=provider&threads\=500×tamp\=1628684412247
說明consumer已經(jīng)拿到了provider信息
當(dāng)consumer拿到provider,也不一定就能保證調(diào)用不會(huì)報(bào)No provider,有這么幾種情況需要排查
- 檢查consumer的group、version是否和provider完全匹配,不匹配會(huì)報(bào)No provider
- 是否被禁用,搜索緩存文件中是否有該服務(wù)對(duì)應(yīng)的override URL,且disabled=true
- consumer是否配置了路由規(guī)則,如tag路由,條件路由等,路由規(guī)則可能導(dǎo)致No provider
group、version是否匹配,有一個(gè)不看代碼就知道consumer的version、group配置的小技巧,如果consumer指定了version或group,報(bào)錯(cuò)信息如下(group=read,version=1.0):
No provider available from registry 127.0.0.1:2181 for service read/org.newboo.basic.api.MyDemoService:1.0 on consumer 127.0.0.1 use dubbo version 2.7.6
service前包含group,用斜線分隔,service后有version用冒號(hào)分隔。
以上可覆蓋95%的場(chǎng)景,還有一種比較少見:consumer生成invoker失敗導(dǎo)致invokers為空;
此種情況請(qǐng)仔細(xì)檢查錯(cuò)誤日志,不明的報(bào)錯(cuò)需要關(guān)注。此處列舉一些碰到過的case
- Dubbo 2.6.x中transport實(shí)現(xiàn)了netty和netty4,而在2.6.10版本中,netty transport擴(kuò)展名字被改為了netty3;如果provider使用dubbo 2.6.10且指定了transport為netty3,低版本的dubbo調(diào)用時(shí)因?yàn)闆]有實(shí)現(xiàn)netty3的擴(kuò)展而導(dǎo)致invoker生成失敗;此時(shí)consumer端看起來是拿到了provider的URL,但也會(huì)報(bào)No provider錯(cuò)誤
- 與1類似,當(dāng)自定義某些擴(kuò)展只在provider使用時(shí),provider的一些參數(shù)會(huì)傳遞給consumer,讓consumer也使用相同擴(kuò)展,但consumer不一定實(shí)現(xiàn)了該擴(kuò)展,導(dǎo)致invoker生成失敗;比如自定義的dispatcher擴(kuò)展。
注:可能你會(huì)問為什么provider的參數(shù)會(huì)傳遞給consumer?這合理嗎?舉個(gè)例子,如果provider指定序列化協(xié)議為json,那consumer是否也要按照provider的序列化協(xié)議json來傳輸數(shù)據(jù)呢?只能說沒有萬全的設(shè)計(jì)
總結(jié)
跟很多問題排查思路一樣,根據(jù)已有現(xiàn)象一步步縮小排查范圍,最終鎖定根本原因。用一副思維導(dǎo)圖來總結(jié):