[肥朝]從一次解決開發環境問題聊聊為什麼要看原始碼

肥朝發表於2019-04-08

前言

去年寫了Dubbo原始碼解析系列,但是因為一些不可抗拒的因素(加班),導致通訊、編解碼部分還沒寫.同時在和很多朋友交流過程中,其中反饋最多的一個問題是.看原始碼到底有什麼用?究竟是不是真的只是面試時裝裝逼,裝完繼續CRUD.

其實之所以有這樣的疑問,主要是因為平時遇到的問題都能通過搜尋引擎解決.然而,我近兩年的做的都是基礎平臺相關的工作,還是經常遇到一些必須要看原始碼才能解決的問題.所以我覺得光把自己看原始碼的經驗分享出來還不夠,更重要是講清楚,看原始碼,究竟解決了什麼實際問題.

本篇是為什麼要看原始碼系列的第三篇.先交代一下背景

由於公司做的是海外業務,為了方便海外同事辦公.我們把公司的開發伺服器(以下簡稱sit環境)遷移到了海外.但是這樣就產生了一個問題.由於伺服器在海外,運維部表示由於政策原因(具體細節不透露),那麼我們將無法訪問到sit環境.既然無法訪問,那麼這個sit環境對於我們就形同虛設了.經過協調.運維用Nginx做埠轉發.把我們常用的中介軟體(zookeeper,RocketMQ)、資料庫地址做對映.但是這樣依然存在一些問題,下面畫圖分析

類比學習,淺析常見中介軟體原理

其實我們常見的中介軟體的原理都大致相同,你瞭解一種後,通過類比學習.很容易掌握其他的.下面拿RocketMQ舉例.演示一下什麼叫類比學習法

RocketMQ的官方文件中物理部署結構圖如下:

[肥朝]從一次解決開發環境問題聊聊為什麼要看原始碼

NameSever你可能不知道是什麼.其實這個是RocketMQ3.X版本引入的,之前用的是zookeeper.就是說,3.X版本發現zookeeper功能很強大, 但是人家其實用不到zookeeper這麼多功能,基本上只用到了zookeeper的分散式協調,也就是註冊中心的功能,就弄了個更輕量的NameSever.

那麼Broker是什麼呢? 這個是資料儲存的核心,也是真正的MQ伺服器.我們所謂的訊息儲存,接收,拉取,推送操作都是在這個broker進行的.

簡單的說,我們平時在專案中配置的mq地址是NameSever.然後Broker把資訊註冊到NameSever.在框架的底層,我們訪問NameSever的時候,它通過註冊的資訊真正發起網路請求去訪問註冊的Broker.

類比fastDFS學習

那麼接下來我們就類比一下fastDFS

[肥朝]從一次解決開發環境問題聊聊為什麼要看原始碼

[肥朝]從一次解決開發環境問題聊聊為什麼要看原始碼

從上面兩個圖你就可以看出.在fastDFS中,Tracker Server就類似NameSever,Storage Server就類似Broker.原理基本是一樣的.同樣的,平時我們專案中配置的地址其實是Tracker Server的地址

類比Dubbo學習

Dubbo的原理我這裡就不想再多做解釋了,之前已經從原始碼角度各種剖析了.這裡給之前沒看過我Dubbo原始碼解析的朋友簡單科普一下(真的只是簡單講兩句)

兩個Dubbo服務之間的呼叫,絕大多數情況是網路呼叫(為什麼是絕大多數.因為這個涉及到本地暴露和遠端暴露的問題).那麼網路呼叫,至少要確定三個引數.就是

  • url地址
  • 請求引數
  • 響應引數

所以Dubbo最簡單的原理就是,生產者把本機的ip地址和暴露的介面資訊在zookeeper上建立節點.因為本機的ip地址就可以確定請求的url地址,介面資訊可以確定請求和響應的引數.然後消費者呼叫介面的時候,被動態代理攔截到,然後通過網路請求呼叫提供者.

同樣的,我們在專案中配置的地址是zookeeper的地址.原因同上兩個中介軟體原理一致

你會發現,中介軟體的簡單原理基本是一樣的.通過這個類比學習,你以後遇到其他的中介軟體,哪怕是自己公司自研的中介軟體,他們的原理你也能迅速上手.

遇到的問題

分析完原理之後,那我們遇到了什麼問題呢?比如RocketMQ,我們配置的是NameSever的地址,那麼這個地址我們可以通過Nginx對映出來.這樣我們就可以訪問到NameSever.但是Broker的地址,是Rocket自己註冊上去的.我們即使對映了192.168.X.XXX.但是Broker註冊地址的邏輯程式碼裡面還是會把192.168.Y.YYY註冊上去.那麼我們訪問的還是192.168.Y.YYY那麼我們對映的這個192.168.X.XXX就沒有作用.

那麼我們是不是裝個逼秀一波操作,改原始碼的邏輯,讓Broker註冊的地址按照我們對映的192.168.X.XXX註冊上去呢?

[肥朝]從一次解決開發環境問題聊聊為什麼要看原始碼

我只想說,年輕人,你這個思想很危險啊!

[肥朝]從一次解決開發環境問題聊聊為什麼要看原始碼

程式設計講究的是開閉原則,再說,你確定能駕馭得住的RocketMQ的原始碼改動嗎?我都說了,遇到問題,先不要著急看原始碼.先看官方文件,再通過搜尋引擎,如果都不能解決的.我們再看原始碼.我百度搜尋第一條就是答案的我還看個毛線原始碼!那麼我們來看下官方文件

[肥朝]從一次解決開發環境問題聊聊為什麼要看原始碼

人家這個說得就很清楚了,預設是註冊本地的ip地址上去,但是你可以設定.所以我們把自己的對映的ip地址配置上去就OK了.

Dubbo的問題

RocketMQ的問題我們通過官方文件解決了.但是Dubbo的問題文件沒有.搜尋了有類似答案,但是依然沒有把原理講清楚.那麼我們就直入原始碼一探究竟(好吧,讓我裝個逼)

如果你之前就關注肥朝,一直有看過我的dubbo原始碼解析系列,比如dubbo原始碼解析-zookeeper建立節點那麼你就能像我這種風一般的男子一樣迅速定位到原始碼中獲取ip地址的原始碼片段.如下

[肥朝]從一次解決開發環境問題聊聊為什麼要看原始碼

這部分的邏輯是,先呼叫InetAddress.getLocalHost().getHostAddress(),如果該方法返回一個合法地址,就直接認為這個地址是本地的ip地址.否則會遍歷本地的所有網路卡,並返回找到的第一個合法地址

//這部分是jdk的api
host = InetAddress.getLocalHost().getHostAddress();
複製程式碼

既然是jdk的api,那麼要弄懂原理就好搞很多了.我們直接看文件註釋

/**
 * Returns the address of the local host. This is achieved by retrieving
 * the name of the host from the system, then resolving that name into
 * an {@code InetAddress}.
 *
 * <P>Note: The resolved address may be cached for a short period of time.
 * </P>
 *
 * <p>If there is a security manager, its
 * {@code checkConnect} method is called
 * with the local host name and {@code -1}
 * as its arguments to see if the operation is allowed.
 * If the operation is not allowed, an InetAddress representing
 * the loopback address is returned.
 *
 * @return     the address of the local host.
 *
 * @exception  UnknownHostException  if the local host name could not
 *             be resolved into an address.
 *
 * @see SecurityManager#checkConnect
 * @see java.net.InetAddress#getByName(java.lang.String)
 */
複製程式碼

從文件的大概意思可以看出,他獲取的ip地址,和hostName有關.那麼這樣我們就有了突破口.

我們通過linux命令(uname -n)檢視機器的hostName,比如

[肥朝]從一次解決開發環境問題聊聊為什麼要看原始碼

然後編輯host檔案

vi /etc/hosts
複製程式碼

比如設定

192.168.1.102 testdemo
複製程式碼

[肥朝]從一次解決開發環境問題聊聊為什麼要看原始碼

那麼我們啟動dubbo服務

[肥朝]從一次解決開發環境問題聊聊為什麼要看原始碼

當然這樣我還是不放心,我們去zookeeper上看看節點

[肥朝]從一次解決開發環境問題聊聊為什麼要看原始碼

果然和我們看到的是一樣的.

[肥朝]從一次解決開發環境問題聊聊為什麼要看原始碼

寫在末尾

肥朝 是一個專注於 原理、原始碼、開發技巧的技術公眾號,號內原創專題式原始碼解析、真實場景原始碼原理實戰(重點)。掃描下面二維碼關注肥朝,讓本該造火箭的你,不再擰螺絲!

[肥朝]從一次解決開發環境問題聊聊為什麼要看原始碼

相關文章