您好,登錄后才能下訂單哦!
自從成為架構師()之后,李大胖的學習動力似乎少了一些,尤其是今年(當然也有一些客觀因素)。
臨近歲末,內心著實有些慚愧,決定學習一把大數據。跟隨一下業界前沿(其實已經不是前沿了),夢想著有一天能夠擁有擁有夢想的權力。
操練起來
啟動裝有CentOS的虛擬機(IP是172.18.232.181),按照官方文檔內容選擇hadoop-2.8.5和hbase-2.0.2,還有zookeeper-3.4.11進行下載、解壓。
以下是官方文檔的步驟,熟悉的同學可以直接跳到“噩夢開始”()。
HDFS
進入hadoop的解壓目錄,進入etc/hadoop/hadoop-env.sh中設置Java目錄,如圖
執行./sbin/start-dfs.sh腳本,如圖
jps一下,發現啟動好了,如圖
執行./bin/hdfs dfs -ls /命令,進到hdfs里看看,如圖
注:初次進來是空的,沒有這個hbase目錄的。
Zookeeper
進入zookeeper解壓目錄,進入conf/zoo.cfg中設置下數據目錄,如圖
執行./bin/zkServer.sh start命令啟動,如圖
jps一下,發現啟動好了,如圖
Hbase
進入hbase的解壓目錄,進入conf/hbase-env.sh中設置Java目錄,如圖
進入conf/hbase-site.xml中修改內容,如圖
注:指定好hdfs,zookeeper和集群模式。
執行./bin/start-hbase.sh腳本啟動,如圖
jps一下,啟動好了,如圖
執行./bin/hbase shell命令,進入shell交互,如圖
可以進行建表,插入數據,刪除數據等(這里不再演示了)。
最后進入hdfs看一下,發現hbase已經在里面存了數據,如圖
李大胖發現按照官方文檔一路走下來,非常順暢,心里不由得成就感倍增(是不是略有膚淺)。
噩夢開始
作為一個寫了近十年Java的老碼農,不用Java連一下Hbase,那怎么能讓李大胖死心呢(噩夢的種子就在此刻埋進了土里)。
開始整起來,先弄個springboot,再引入相關依賴、獲取連接等等(具體細節等明年會推文,明年?沒毛病啊),按照官方文檔方法搞好了。
激動的心,顫抖的手,點了運行按鈕。咦,竟然沒報錯,正常啟動了()。
李大胖心想,見證奇跡的時刻到了。就點了頁面上的調用按鈕,仿佛整個世界都在靜靜的等待看到結果的喜悅()。1秒,2秒,3秒過去了,沒反應,不好,估計出問題了,趕緊看下Eclipse的控制臺,果然報錯了(噩夢的種子已經發芽了)。錯誤如下:
Caused by: org.apache.hadoop.hbase.MasterNotRunningException: java.net.ConnectException: Call to localhost/127.0.0.1:16000 failed on connection exception: org.apache.hbase.thirdparty.io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: localhost/127.0.0.1:16000
錯誤是說Master沒有運行,原因是訪問localhost/127.0.0.1:16000被拒絕。
得虧學了一點Hbase,知道16000是master(節點)的默認端口(老版本中master的默認端口是60000),只是這個IP為啥是本機啊,李大胖心中有些疑惑,Hbase明明是在虛擬機里運行的呀。
“狄仁杰”辦案
這就像狄仁杰遇到了大案,而且是離奇的案子。此時狄閣老總是說,在大案面前一定要穩住,不能自亂方寸。特別是案件前期撲朔迷離,陷入僵局,你甚至都不知道對手是誰的時候,一定是你在辦案過程中忽略了某些細節,此時你需要從頭仔細回憶一遍,看能不能想起一些蛛絲馬跡(是不是有點入戲太深了)。
好吧,那就跟著李大胖復盤一下吧()。Hbase在啟動的時候會把一些信息注冊到zookeeper中,我們在Java程序中只配置了zookeeper的地址,所以程序是從zookeeper中讀出了master的地址,然后才去訪問的。
既然最后訪問的是localhost/127.0.0.1:16000,說明master注冊的就是它。想到Dubbo在往zookeeper里注冊url時使用的就是IP,所以李大胖認為master往zookeeper里注冊的也是IP,即127.0.0.1:16000。
為了驗證自己的想法,就進到zookeeper里去看,發現有master節點,但是并沒有它的地址信息。既然驗證不了,那就解決問題吧,目前看起來只需要master采用所在機器的實際IP注冊就行了。
于是使用中文關鍵詞進行了搜索,發現可以在hbase-site.xml配置文件中設置一個hbase.master的參數,趕緊加進去試試,如圖:
重啟Hbase后發現不行()。
“元芳”的猜想
李大胖繼續想,這是搭建的偽集群,官方文檔明確說明,偽集群的意思是雖然有多個進程,但是還都是在一個機器上的。會不會是Hbase在啟動時檢測到了自己是偽集群,所以總是用127.0.0.1去注冊啊(請允許李大胖自顧自的胡思亂想)。
俗話說的好,是騾子是馬拉出來遛遛()。首先把zookeeper移到另一臺虛擬機上,重啟Hbase,發現還不行()。莫非還要把HDFS也移到第三臺虛擬機上?仔細想想,不對吧,Hbase應該不會自己去檢測安裝方式,單節點/偽集群/真集群,它不會這么無聊的()。于是放棄了后續的驗證。
李大胖接著想,既然在Hbase的配置文件中可以指定hbase.master配置項,那我直接把這個配置項放到Java程序里試試(),興許管用。但前提是在本機可以訪問虛擬機里的master。
于是進入cmd窗口,執行telnet 172.18.232.181 16000,我去,竟然不通()。趕緊跑到虛擬機里執行telnet 172.18.232.181 16000,我嘞個去,竟然還不通()。既然已經在虛擬機里了,就試試telnet 127.0.0.1 16000,擦,竟然它是通的()。于是忽然想起之前看master日志時,總是發現綁定到127.0.0.1,只不過當時沒有引起重視。如圖
雪上加霜
得,老的問題還沒解決,新的問題又出現了。那就解決新問題吧,再次使用中文關鍵詞一通搜索,沒有很好的答案。
突然想到,要不使用英文關鍵詞試試,哈哈,一下子就被我get到了。發現這是一個2010年()的提問。八年后被我趕上了,在此非常感謝這個問題的提出者和回答者(https://grokbase.com/t/hbase/user/103pq6p14k/master-binds-only-to-loopback)。
回答中指出,Hbase master綁定的一般算法是這樣的,分三步(和把大象裝進冰箱里一樣):
1、獲取host name(在posix系統上一般使用hostname命令獲取)
2、在這個hostname上執行DNS查找
3、使用找到的IP作為綁定的IP
忽然想起幾年前看視頻學習時,提到過Java程序部署到Linux后,很多網絡問題有時都和hostname有關。
趕緊執行hostname命令,發現結果是localhost,根據localhost得到的IP就是127.0.0.1,所以master最后綁定到了127.0.0.1:16000上。
于是修改了hostname為host1,同時在/etc/hosts文件中將host1映射為本機實際IP,如圖:
重啟Hbase,看master日志,終于綁定的IP變了,如圖:
我開心地認為是不是所有問題都解決了,趕緊使用Java再調一下,發現還是一開始的錯誤。因為我每次重啟Hbase時都會把logs目錄清空,當我修改完hostname后重啟時,我發現zookeeper的日志文件名稱發生了變化,原來是以localhost結尾,現在變成以新的hostname結尾了,如圖:
但是發現master的日志文件還是以localhost結尾,心想是不是因為修改完hostname沒有reboot呀(我既在文件中修改了,又用hostname命令修改了,就是懶得重啟了),算了,還是重啟下吧()。重啟完Linux后,再啟動Hbase,果然master的日志文件名稱變了,也以host1結尾了,如圖:
又興奮起來了,趕緊再用Java調一下試試,可惜,還是原來的配方,原來的味道()。
痛定思痛
再總結下目前的情況,master在啟動時,已經綁定到正確的IP和端口,即172.18.232.181:16000。但是Java調用時依然是原來的錯誤,即訪問127.0.0.10:16000被拒絕。說明master雖然啟動時server
socket綁定對了,但是往zookeeper里注冊時錯了,依然使用的是127.0.0.1:16000()。
此時李大胖更加納悶,既然綁定都對了,沒有理由往zookeeper里注冊時不對啊。為什么非要注冊127.0.0.1,而不是實際的IP呢。這個問題之前已經使用中文關鍵詞搜索了很多次,沒有得到解決。
狄公曾經說過,有些案子,表面上看去是什么樣子,實際就是什么樣子。有些案子卻恰恰相反,因為有人在故意蒙蔽你的雙眼(也有可能是自我蒙蔽了雙眼)。
那這個問題該如何解決呢?或者更準確的說,現在的問題根本還沒有被定位出來,我們看到的錯誤只是一個結果(或者說現象)。
愛因斯坦
愛因斯坦曾經說過,“提出一個問題比解決一個問題更重要”。他還說過,“想象力比知識更重要”。(他的名言翻譯成中國話,怎么感覺像“沒有做不到的,只有想不到的”。)
正在李大胖一籌莫展時,一道靈光乍現()。等等,既然server socket綁定時是根據hostname找到IP的,而且修改了hostname后連日志文件名的后面部分都變了,說明和hostname有莫大的關系,且又回憶起master日志文件中在master注冊時打印的日志,忽然就想明白了,先看下日志吧,如圖:
可以看到首先注冊一個備份master,然后刪除了這個備份master,因為把它注冊為一個活動的master了。而且注冊時使用的是localhost而不是IP。我們的Java程序拿到的是localhost而不是一開始想到的127.0.0.1。
那為什么最后又變成了127.0.0.1了呢,因為Windows系統的hosts文件同樣把localhost映射為127.0.0.1,這就造成了最后向127.0.0.1:16000發起連接請求而被拒絕,也就是一開始看到的錯誤現象。到此真相已大白()。
之所以一直認為master向zookeeper注冊時使用的是IP,就是受到Dubbo的影響了(當然這里不能怪Dubbo,只能怪自己)。
柳暗花明
問題已經找到,這次直接使用英文關鍵詞搜索,又是一下子就get到答案了。解決方案很簡單,就是往hbase-site.xml中加一個hbase.master.hostname的配置項(https://stackoverflow.com/questions/9615707/hbase-how-to-specify-hostname-for-hbase-master),如圖:
老外給的答案一般還是值得相信的。重啟Hbase。
按照李大胖的推斷,此時使用Java調用時,應該報的錯是host1無法被解析,因為Windows并不知道host1是什么鬼。那就調一下試試吧,哈哈,果然是這樣的,如圖:
那么就修改下Windows的hosts文件,把host1加進去,映射為虛擬機的IP即可,如圖:
再調一次,已經調通了。
最后再看一眼maser的日志文件,驗證下master往zookeeper注冊時的內容,如圖:
可以看到已經變為host1了。至此,所有問題都已解決。
PS:雖然說理論+實踐才能出效果,但是千萬別還沒看幾眼就著急實踐,這樣會被一些弱智的問題絆倒。事后發現明明很容易,自己卻在此耗費好多時間。而且也容易使自己的自信心受到嚴重打擊,甚至懷疑人生()。
相關文章
五分鐘輕松了解Hbase列式存儲
(完)
編程新說
用獨特的視角說技術
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。