假如我是一個函數
這兩天有人問我RPC相關的問題,這其實是個非常“古老”的概念了,沒有經歷過DCOM和RMI開發時代的同學可能對RPC的來龍去脈沒有直觀的認識,之前我寫過一篇文章做過講述,今天再發一次,希望能解決一部分人的疑惑吧!
我是一個函數, 生活在內存當中,我的家--用你們的“黑話”來說--就是進程的地址空間, 我的鄰居也是一個函數,其中有一段很有趣的代碼。
我經常去拜訪他,去的時候當然不能空著手,我會攜帶四個數字作為禮物送給他計算, 耐心等待他在CPU中忙活半天,最后,作為回贈的禮物,他告訴我一個地址,讓我去那里取結果。
拜訪的次數多了,我慢慢地琢磨出了我這個鄰居做的事情:房貸計算。
我給他發的四個參數分別是房貸總額,利率,貸款年限,還款方式(等額本息是1, 等額本金是2) 他告訴我的是一個地址,其實就是一個列表,存放著每個月應還的月供、本金和利息。
用你們的“黑話”來說就是這樣:
List calculateHouseLoan(float total, float intrestRate, int years ,int loanType)
所有的調用都發生在本機內的一個進程中, 大家把這種方式稱為本地過程調用。
這種調用方式速度飛快,眨眼間就可完成。
有時候,房貸計算鄰居會驚呼道:我賽,你給我發了一個多大的數啊, 800萬的貸款總額!
我就知道,帝都的房價又漲了!
日子過了一天又一天, 房價也漲了一天又一天。
一天早上, 我睡了一覺醒來感覺不太對勁,頭暈暈的,一般情況下這就表示昨天夜里系統重啟了。
還沒等我清醒過來, 我就接到上司(調用我的函數)的命令,又要計算房貸了,我忍著頭暈趕緊去找鄰居,可是這一次卻換成了陌生人, 他笑瞇瞇的說:“是不是要找你的鄰居房貸計算啊”
“是啊”
“他已經搬走了!”
“啊?他搬到哪兒去了?我怎么計算房貸?”
“ 他搬到另外一臺機器去住了,具體位置我也不清楚,不過從IP看應該是在同一個機房吧”
說實話這個消息讓我吃驚不小,我聽人說過,想和網絡上的機器通信,那可比本機的同一進程內的通信麻煩太多了。
之前我們生活在同一個進程中,每個函數的住處(地址)對大家來說都是可見的,想要調用了,直接去函數的住處去執行代碼即可。
現在這個函數都搬走了,新的地址我也不知道,就是知道了,跨域網絡的調用,據說得使用什么socket,建立連接,在連接上按雙方商量好格式、次序來發送數據, 接收數據,聽著就頭大, 打死我也搞不定。
(碼農翻身老劉注:socket的故事參見《張大胖和socket》)
陌生人看出了我的擔心, 笑著說:“放心吧, 我是他的客戶端代理,你盡管把那四個參數交給我,我來幫你搞定。”
這家伙自稱為客戶端代理的家伙竟然知道那個四個參數!也許能行,對我來說反正調用方式沒什么變化, 于是我將信將疑地像以前把4個參數傳遞過去, 他馬上就忙活起來,建立連接,發送數據,接收數據,過了很久(我感覺比平時要慢了100倍)他才說房貸已經計算好了,數據在地址XXXX處, 你去拿吧。
我去那個地方一查,和往常一樣,每月的還款結果已經整整齊齊的擺在那里了。
“你這個房貸計算的客戶端代理還真不含糊啊, 既然你是客戶端代理, 難道還有服務器端代理人? ”
“沒錯, 我還有個好基友,在服務器端忙活, 我和他約定好了消息的格式, 你交給我的數據其實我都通過socket發給他了,由他來調用真正的房貸計算, 然后再把結果發回來。”
“難道這就是傳說中的遠程過程調用(RPC) ?” 我問道
“是的, 我們這兩個代理人把臟活累活都幫著你們做了,把那些復雜的網絡細節都給隱藏起來了, 在你們看來和本地調用一樣。對了,有人會把我稱為Stub, 把我的好基友稱為 Skeleton, 我和他之間的交互是通過socket進行的, 有些RPC的代理人可能不用這么底層的東西,直接用HTTP, 不過沒關系,只要兩端的代理人約定好就行了, 關鍵是要給你們提供一個舒適的體驗。”
“我想到一個問題, 如果我傳遞給你的不是簡單的float, int型的參數, 而是內存中的對象, 怎么處理?”
“當然要做序列化了, 要不然怎么通過網絡發送啊, 其實float,int也得做序列化, 把內存中的值和對象變成二進制流,這樣才能發送出去。到了我的好基友那邊,他還得做反序列化,把而二進制流再轉化為對象, 然后才能調用真正的函數, 唉,這工作實在是麻煩啊。”
我對他表示了深切的同情和敬意, 為了我們能做透明的遠程調用,這些代理們真不容易。
“我聽說還能用XML和JSON?” 我問道
“你知道的不少嘛 !有些人在使用HTTP作為通信協議的時候, 喜歡把對象變成文本,例如XML/JSON,可讀性比較好,但是你要知道,雖然應用層的HTTP中看起來時文本, 但是到了底層通道例如TCP發送出去的時候,那還得變成二進制流, 到了目的地再把他們轉化成文本。”
(碼農翻身老劉注:參加《序列化:一個老家伙的咸魚翻身》)
聊了半天,我們越來越熟, 我無意間談起了他的身世, 他說 :“我們這些代理人啊,出生的方式主要有兩種, 一種就是程序員們一行行代碼的把我們給敲出來、費心而費力, 另外一種就是自動生成。”
“自動生成,具體怎么做?”
“拿Java來舉個例子, 你可以先定義一個接口(interface), 讓這個接口擴展自java.rmi.Remote, 然后寫個實現類, 最后用一個工具rmic就可以自動生成客戶端和服務器端的代理人了 , 是不是很簡單? ”
(碼農翻身老劉注:從JDK5.0開始, 連這個rmic這一步都可以省略, 完全由JVM自動生成,運行時可以把客戶端代理人下載到客戶端。)
網絡的世界遠比單機精彩, 不知不覺我已經和這個代理人聊了將近800毫秒, 我的上司已經等不及了,他抱怨地說:“這次怎么這么慢?難道人類在調試,在你這里加了斷點?”
我說 :“沒有調試, 原來是本地過程調用,現在變成遠程過程調用了!”
【本文為51CTO專欄作者“劉欣”的原創稿件,轉載請通過作者微信公眾號coderising獲取授權】