由于Windows服務(wù)之間有很強(qiáng)的相互依存關(guān)系,當(dāng)RPC服務(wù)被禁用后,很多依賴于RPC服務(wù)的系統(tǒng)服務(wù)也不能正常運(yùn)行(見圖),如Messenger服務(wù)、Windows Installer服務(wù)等;另外,還可能導(dǎo)致某些應(yīng)用程序運(yùn)行失敗和系統(tǒng)異常。下面筆者就介紹三種啟動(dòng)該服務(wù)的方法。
目前創(chuàng)新互聯(lián)已為上千家的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)絡(luò)空間、網(wǎng)站托管、服務(wù)器托管、企業(yè)網(wǎng)站設(shè)計(jì)、索縣網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。
方法一:修改注冊(cè)表法
點(diǎn)擊"開始→運(yùn)行",鍵入"Regedit"打開"注冊(cè)表編輯器",展開分支"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\RpcSs",將Start項(xiàng)的值修改為"00000002",重新啟動(dòng)系統(tǒng)即可。
方法二:使用sc.exe命令
點(diǎn)擊"開始→運(yùn)行",鍵入"cmd"進(jìn)入"命令提示符"窗口,鍵入"sc config RpcSs start= auto"命令,系統(tǒng)會(huì)顯示"?SC? ChangeServiceConfig SUCCESS",這樣就可以成功啟動(dòng)RPC服務(wù)。
注意:要想使用"sc"命令必須安裝Windows 2000/2003 Resource Kit(資源工具包),否則使用該命令無效。
方法三:使用故障恢復(fù)控制臺(tái)
以Windows XP系統(tǒng)為例,在光驅(qū)中放入安裝光盤,并且在BIOS參數(shù)中設(shè)置為從CD-ROM啟動(dòng);啟動(dòng)電腦后,系統(tǒng)進(jìn)入到Windows XP安裝界面,按下"R"鍵登錄到故障恢復(fù)控制臺(tái)。在故障恢復(fù)控制臺(tái)下,鍵入"enable RpcSs service_auto_start"命令,然后再鍵入"exit"命令,重新啟動(dòng)系統(tǒng),以正常模式登錄,即可成功啟動(dòng)RPC服務(wù)。
注意:"Enable"是故障恢復(fù)控制臺(tái)提供的一個(gè)用來啟動(dòng)系統(tǒng)服務(wù)和設(shè)備驅(qū)動(dòng)程序的命令,只能在故障恢復(fù)控制臺(tái)下使用。
=============================
使用上面的幾種方法都不成功的話,看來只有自己動(dòng)手解決了。我想注冊(cè)表中的某些鍵值一定要變,這樣才能啟用。
把禁用前的備份注冊(cè)表恢復(fù)到被禁用后的注冊(cè)表中,提示無法導(dǎo)入,不成功。無法啟用。
把禁用前和禁用后的兩個(gè)注冊(cè)表(只取HKEY_LOCAL_MACHINE\SYSTEM分支)內(nèi)容轉(zhuǎn)化成Word文檔,再使用Word中的“比較并合并文檔”功能,就能自動(dòng)找到兩個(gè)注冊(cè)表的不同之處。我通過比較分析,發(fā)現(xiàn)禁用后的注冊(cè)表中有以下分支:
1. HKEY_LOCAL_MACHINE\SYSTEM\Curr-
entControlSet\HardwareProfiles\0001\System\CurrentControlSet\Enum\ROOT\LEGACY_RPCSS
2.HKEY_LOCAL_MACHINE\SYSTEM\Curr-entControlSet\HardwareProfiles\Current\System\CurrentControlSet\Enum\ROOT\LEGACY_RPCSS
禁用前的注冊(cè)表中沒有以上兩個(gè)分支。通過進(jìn)一步操作,發(fā)現(xiàn)只要?jiǎng)h除第1個(gè)分支即可重新起用RPC服務(wù)。
原來上面三種方法,只能應(yīng)用于把RPC服務(wù)啟動(dòng)類型改為禁止后的情況。筆者關(guān)閉RPC服務(wù)不是改變啟動(dòng)類型,而是禁止與之相關(guān)聯(lián)的硬件配置文件服務(wù),“Start”項(xiàng)的值仍是“2”,沒有變。所以先要將硬件配置文件服務(wù)啟用,才能啟用RPC服務(wù)。
智能合約調(diào)用是實(shí)現(xiàn)一個(gè) DApp 的關(guān)鍵,一個(gè)完整的 DApp 包括前端、后端、智能合約及區(qū)塊 鏈系統(tǒng),智能合約的調(diào)用是連接區(qū)塊鏈與前后端的關(guān)鍵。
我們先來了解一下智能合約調(diào)用的基礎(chǔ)原理。智能合約運(yùn)行在以太坊節(jié)點(diǎn)的 EVM 中。因此要 想調(diào)用合約必須要訪問某個(gè)節(jié)點(diǎn)。
以后端程序?yàn)槔?,后端服?wù)若想連接節(jié)點(diǎn)有兩種可能,一種是雙 方在同一主機(jī),此時(shí)后端連接節(jié)點(diǎn)可以采用 本地 IPC(Inter-Process Communication,進(jìn) 程間通信)機(jī)制,也可以采用 RPC(Remote Procedure Call,遠(yuǎn)程過程調(diào)用)機(jī)制;另 一種情況是雙方不在同一臺(tái)主機(jī),此時(shí)只能采用 RPC 機(jī)制進(jìn)行通信。
提到 RPC, 讀者應(yīng)該對(duì) Geth 啟動(dòng)參數(shù)有點(diǎn)印象,Geth 啟動(dòng)時(shí)可以選擇開啟 RPC 服務(wù),對(duì)應(yīng)的 默認(rèn)服務(wù)端口是 8545。。
接著,我們來了解一下智能合約運(yùn)行的過程。
智能合約的運(yùn)行過程是后端服務(wù)連接某節(jié)點(diǎn),將 智能合約的調(diào)用(交易)發(fā)送給節(jié)點(diǎn),節(jié)點(diǎn)在驗(yàn)證了交易的合法性后進(jìn)行全網(wǎng)廣播,被礦工打包到 區(qū)塊中代表此交易得到確認(rèn),至此交易才算完成。
就像數(shù)據(jù)庫一樣,每個(gè)區(qū)塊鏈平臺(tái)都會(huì)提供主流 開發(fā)語言的 SDK(Software Development Kit,軟件開發(fā)工具包),由于 Geth 本身就是用 Go 語言 編寫的,因此若想使用 Go 語言連接節(jié)點(diǎn)、發(fā)交易,直接在工程內(nèi)導(dǎo)入 go-ethereum(Geth 源碼) 包就可以了,剩下的問題就是流程和 API 的事情了。
總結(jié)一下,智能合約被調(diào)用的兩個(gè)關(guān)鍵點(diǎn)是節(jié)點(diǎn)和 SDK。
由于 IPC 要求后端與節(jié)點(diǎn)必須在同一主機(jī),所以很多時(shí)候開發(fā)者都會(huì)采用 RPC 模式。除了 RPC,以太坊也為開發(fā)者提供了 json- rpc 接口,本文就不展開討論了。
接下來介紹如何使用 Go 語言,借助 go-ethereum 源碼庫來實(shí)現(xiàn)智能合約的調(diào)用。這是有固定 步驟的,我們先來說一下總體步驟,以下面的合約為例。
步驟 01:編譯合約,獲取合約 ABI(Application Binary Interface,應(yīng)用二進(jìn)制接口)。 單擊【ABI】按鈕拷貝合約 ABI 信息,將其粘貼到文件 calldemo.abi 中(可使用 Go 語言IDE 創(chuàng)建該文件,文件名可自定義,后綴最好使用 abi)。
最好能將 calldemo.abi 單獨(dú)保存在一個(gè)目錄下,輸入“l(fā)s”命令只能看到 calldemo.abi 文件,參 考效果如下:
步驟 02:獲得合約地址。注意要將合約部署到 Geth 節(jié)點(diǎn)。因此 Environment 選擇為 Web3 Provider。
在【Environment】選項(xiàng)框中選擇“Web3 Provider”,然后單擊【Deploy】按鈕。
部署后,獲得合約地址為:0xa09209c28AEf59a4653b905792a9a910E78E7407。
步驟 03:利用 abigen 工具(Geth 工具包內(nèi)的可執(zhí)行程序)編譯智能合約為 Go 代碼。abigen 工具的作用是將 abi 文件轉(zhuǎn)換為 Go 代碼,命令如下:
其中各參數(shù)的含義如下。 (1)abi:是指定傳入的 abi 文件。 (2)type:是指定輸出文件中的基本結(jié)構(gòu)類型。 (3)pkg:指定輸出文件 package 名稱。 (4)out:指定輸出文件名。 執(zhí)行后,將在代碼目錄下看到 funcdemo.go 文件,讀者可以打開該文件欣賞一下,注意不要修改它。
步驟 04:創(chuàng)建 main.go,填入如下代碼。 注意代碼中 HexToAddress 函數(shù)內(nèi)要傳入該合約部署后的地址,此地址在步驟 01 中獲得。
步驟 04:設(shè)置 go mod,以便工程自動(dòng)識(shí)別。
前面有所提及,若要使用 Go 語言調(diào)用智能合約,需要下載 go-ethereum 工程,可以使用下面 的指令:
該指令會(huì)自動(dòng)將 go-ethereum 下載到“$GOPATH/src/github.com/ethereum/go-ethereum”,這樣還算 不錯(cuò)。不過,Go 語言自 1.11 版本后,增加了 module 管理工程的模式。只要設(shè)置好了 go mod,下載 依賴工程的事情就不必關(guān)心了。
接下來設(shè)置 module 生效和 GOPROXY,命令如下:
在項(xiàng)目工程內(nèi),執(zhí)行初始化,calldemo 可以自定義名稱。
步驟 05:運(yùn)行代碼。執(zhí)行代碼,將看到下面的效果,以及最終輸出的 2020。
上述輸出信息中,可以看到 Go 語言會(huì)自動(dòng)下載依賴文件,這就是 go mod 的神奇之處??吹?2020,相信讀者也知道運(yùn)行結(jié)果是正確的了。
作者 | Python編程時(shí)光
責(zé)編 | 胡巍巍
什么是RPC呢?百度百科給出的解釋是這樣的:“RPC(Remote Procedure Call Protocol)——遠(yuǎn)程過程調(diào)用協(xié)議,它是一種通過網(wǎng)絡(luò)從遠(yuǎn)程計(jì)算機(jī)程序上請(qǐng)求服務(wù),而不需要了解底層網(wǎng)絡(luò)技術(shù)的協(xié)議”。
這個(gè)概念聽起來還是比較抽象,沒關(guān)系,繼續(xù)往后看,后面概念性的東西,我會(huì)講得足夠清楚,讓你完全掌握 RPC 的基礎(chǔ)內(nèi)容。
在 OpenStack 里的進(jìn)程間通信方式主要有兩種,一種是基于HTTP協(xié)議的RESTFul API方式,另一種則是RPC調(diào)用。
那么這兩種方式在應(yīng)用場景上有何區(qū)別呢?
有使用經(jīng)驗(yàn)的人,就會(huì)知道:
首先,給你提兩個(gè)問題,帶著這兩個(gè)問題再往下看:
1、RPC 和 REST 區(qū)別是什么?2、為什么要采用RPC呢?
首先,第一個(gè)問題:RPC 和 REST 區(qū)別是什么?
你一定會(huì)覺得這個(gè)問題很奇怪,是的,包括我,但是你在網(wǎng)絡(luò)上一搜,會(huì)發(fā)現(xiàn)類似對(duì)比的文章比比皆是,我在想可能很多初學(xué)者由于基礎(chǔ)不牢固,才會(huì)將不相干的二者拿出來對(duì)比吧。既然是這樣,那為了讓你更加了解陌生的RPC,就從你熟悉得不能再熟悉的 REST 入手吧。
01、所屬類別不同
REST,是Representational State Transfer 的簡寫,中文描述表述性狀態(tài)傳遞(是指某個(gè)瞬間狀態(tài)的資源數(shù)據(jù)的快照,包括資源數(shù)據(jù)的內(nèi)容、表述格式(XML、JSON)等信息。)
REST 是一種軟件架構(gòu)風(fēng)格。這種風(fēng)格的典型應(yīng)用,就是HTTP。其因?yàn)楹唵?、擴(kuò)展性強(qiáng)的特點(diǎn)而廣受開發(fā)者的青睞。
而RPC 呢,是 Remote Procedure Call Protocol 的簡寫,中文描述是遠(yuǎn)程過程調(diào)用,它可以實(shí)現(xiàn)客戶端像調(diào)用本地服務(wù)(方法)一樣調(diào)用服務(wù)器的服務(wù)(方法)。
而 RPC 可以基于 TCP/UDP,也可以基于 HTTP 協(xié)議進(jìn)行傳輸?shù)?,按理說它和REST不是一個(gè)層面意義上的東西,不應(yīng)該放在一起討論,但是誰讓REST這么流行呢,它是目前最流行的一套互聯(lián)網(wǎng)應(yīng)用程序的API設(shè)計(jì)標(biāo)準(zhǔn),某種意義下,我們說 REST 可以其實(shí)就是指代 HTTP 協(xié)議。
02、使用方式不同
03、面向?qū)ο蟛煌?/p>
從設(shè)計(jì)上來看,RPC,所謂的遠(yuǎn)程過程調(diào)用 ,是面向方法的 ,REST:所謂的 Representational state transfer ,是面向資源的,除此之外,還有一種叫做 SOA,所謂的面向服務(wù)的架構(gòu),它是面向消息的,這個(gè)接觸不多,就不多說了。
04、序列化協(xié)議不同
接口調(diào)用通常包含兩個(gè)部分,序列化和通信協(xié)議。
通信協(xié)議,上面已經(jīng)提及了,REST 是 基于 HTTP 協(xié)議,而 RPC 可以基于 TCP/UDP,也可以基于 HTTP 協(xié)議進(jìn)行傳輸?shù)摹?/p>
常見的序列化協(xié)議,有:json、xml、hession、protobuf、thrift、text、bytes等,REST 通常使用的是 JSON或者XML,而 RPC 使用的是 JSON-RPC,或者 XML-RPC。
通過以上幾點(diǎn),我們知道了 REST 和 RPC 之間有很明顯的差異。
然后第二個(gè)問題:為什么要采用RPC呢?
那到底為何要使用 RPC,單純的依靠RESTful API不可以嗎?為什么要搞這么多復(fù)雜的協(xié)議,渣渣表示真的學(xué)不過來了。
關(guān)于這一點(diǎn),以下幾點(diǎn)僅是我的個(gè)人猜想,僅供交流哈:
說了這么多,我們?cè)撊绾芜x擇這兩者呢?我總結(jié)了如下兩點(diǎn),供你參考:
“遠(yuǎn)程調(diào)用”意思就是:被調(diào)用方法的具體實(shí)現(xiàn)不在程序運(yùn)行本地,而是在別的某個(gè)地方(分布到各個(gè)服務(wù)器),調(diào)用者只想要函數(shù)運(yùn)算的結(jié)果,卻不需要實(shí)現(xiàn)函數(shù)的具體細(xì)節(jié)。
光說不練嘴把式,接下來,我將分別用三種不同的方式全面地讓你搞明白 rpc 遠(yuǎn)程調(diào)用是如何實(shí)現(xiàn)的。
01、基于 xml-rpc
Python實(shí)現(xiàn) rpc,可以使用標(biāo)準(zhǔn)庫里的 SimpleXMLRPCServer,它是基于XML-RPC 協(xié)議的。
有了這個(gè)模塊,開啟一個(gè) rpc server,就變得相當(dāng)簡單了。執(zhí)行以下代碼:
有了 rpc server,接下來就是 rpc client,由于我們上面使用的是 XML-RPC,所以 rpc clinet 需要使用xmlrpclib 這個(gè)庫。
然后,我們通過 server_proxy 對(duì)象就可以遠(yuǎn)程調(diào)用之前的rpc server的函數(shù)了。
SimpleXMLRPCServer是一個(gè)單線程的服務(wù)器。這意味著,如果幾個(gè)客戶端同時(shí)發(fā)出多個(gè)請(qǐng)求,其它的請(qǐng)求就必須等待第一個(gè)請(qǐng)求完成以后才能繼續(xù)。
若非要使用 SimpleXMLRPCServer 實(shí)現(xiàn)多線程并發(fā),其實(shí)也不難。只要將代碼改成如下即可。
02、基于json-rpc
SimpleXMLRPCServer 是基于 xml-rpc 實(shí)現(xiàn)的遠(yuǎn)程調(diào)用,上面我們也提到 除了 xml-rpc 之外,還有 json-rpc 協(xié)議。
那 python 如何實(shí)現(xiàn)基于 json-rpc 協(xié)議呢?
答案是很多,很多web框架其自身都自己實(shí)現(xiàn)了json-rpc,但我們要獨(dú)立這些框架之外,要尋求一種較為干凈的解決方案,我查找到的選擇有兩種
第一種是 jsonrpclib
第二種是 python-jsonrpc
先來看第一種 jsonrpclib
它與 Python 標(biāo)準(zhǔn)庫的 SimpleXMLRPCServer 很類似(因?yàn)樗念惷徒凶?SimpleJSONRPCServer ,不明真相的人真以為它們是親兄弟)?;蛟S可以說,jsonrpclib 就是仿照 SimpleXMLRPCServer 標(biāo)準(zhǔn)庫來進(jìn)行編寫的。
它的導(dǎo)入與 SimpleXMLRPCServer 略有不同,因?yàn)镾impleJSONRPCServer分布在jsonrpclib庫中。
服務(wù)端
客戶端
再來看第二種python-jsonrpc,寫起來貌似有些復(fù)雜。
服務(wù)端
客戶端
調(diào)用過程如下
還記得上面我提到過的 zabbix API,因?yàn)槲矣薪佑|過,所以也拎出來講講。zabbix API 也是基于 json-rpc 2.0協(xié)議實(shí)現(xiàn)的。
因?yàn)閮?nèi)容較多,這里只帶大家打個(gè),zabbix 是如何調(diào)用的:直接指明要調(diào)用 zabbix server 的哪個(gè)方法,要傳給這個(gè)方法的參數(shù)有哪些。
03、基于 zerorpc
以上介紹的兩種rpc遠(yuǎn)程調(diào)用方式,如果你足夠細(xì)心,可以發(fā)現(xiàn)他們都是http+rpc 兩種協(xié)議結(jié)合實(shí)現(xiàn)的。
接下來,我們要介紹的這種(zerorpc),就不再使用走 http 了。
zerorpc 這個(gè)第三方庫,它是基于TCP協(xié)議、 ZeroMQ 和 MessagePack的,速度相對(duì)快,響應(yīng)時(shí)間短,并發(fā)高。zerorpc 和 pyjsonrpc 一樣,需要額外安裝,雖然SimpleXMLRPCServer不需要額外安裝,但是SimpleXMLRPCServer性能相對(duì)差一些。
調(diào)用過程如下
客戶端除了可以使用zerorpc框架實(shí)現(xiàn)代碼調(diào)用之外,它還支持使用“命令行”的方式調(diào)用。
客戶端可以使用命令行,那服務(wù)端是不是也可以呢?
是的,通過 Github 上的文檔幾個(gè) demo 可以體驗(yàn)到這個(gè)第三方庫做真的是優(yōu)秀。
比如我們可以用下面這個(gè)命令,創(chuàng)建一個(gè)rpc server,后面這個(gè) time Python 標(biāo)準(zhǔn)庫中的 time 模塊,zerorpc 會(huì)將 time 注冊(cè)綁定以供client調(diào)用。
經(jīng)過了上面的學(xué)習(xí),我們已經(jīng)學(xué)會(huì)了如何使用多種方式實(shí)現(xiàn)rpc遠(yuǎn)程調(diào)用。
通過對(duì)比,zerorpc 可以說是脫穎而出,一支獨(dú)秀。
為此,我也做了一番思考:
OpenStack 組件繁多,在一個(gè)較大的集群內(nèi)部每個(gè)組件內(nèi)部通過rpc通信頻繁,如果都采用rpc直連調(diào)用的方式,連接數(shù)會(huì)非常地多,開銷大,若有些 server 是單線程的模式,超時(shí)會(huì)非常的嚴(yán)重。
OpenStack 是復(fù)雜的分布式集群架構(gòu),會(huì)有多個(gè) rpc server 同時(shí)工作,假設(shè)有 server01,server02,server03 三個(gè)server,當(dāng) rpc client 要發(fā)出rpc請(qǐng)求時(shí),發(fā)給哪個(gè)好呢?這是問題一。
你可能會(huì)說輪循或者隨機(jī),這樣對(duì)大家都公平。這樣的話還會(huì)引出另一個(gè)問題,倘若請(qǐng)求剛好發(fā)到server01,而server01剛好不湊巧,可能由于機(jī)器或者其他因?yàn)閷?dǎo)致服務(wù)沒在工作,那這個(gè)rpc消息可就直接失敗了呀。要知道做為一個(gè)集群,高可用是基本要求,如果出現(xiàn)剛剛那樣的情況其實(shí)是很尷尬的。這是問題二。
集群有可能根據(jù)實(shí)際需要擴(kuò)充節(jié)點(diǎn)數(shù)量,如果使用直接調(diào)用,耦合度太高,不利于部署和生產(chǎn)。這是問題三。
引入消息中間件,可以很好的解決這些問題。
解決問題一:消息只有一份,接收者由AMQP的負(fù)載算法決定,默認(rèn)為在所有Receiver中均勻發(fā)送(round robin)。
解決問題二:有了消息中間件做緩沖站,client 可以任性隨意的發(fā),server 都掛掉了?沒有關(guān)系,等 server 正常工作后,自己來消息中間件取就行了。
解決問題三:無論有多少節(jié)點(diǎn),它們只要認(rèn)識(shí)消息中間件這一個(gè)中介就足夠了。
既然講到了消息隊(duì)列,如果你之前沒有接觸過這塊內(nèi)容,最好花幾分鐘的時(shí)間跟我好好過下關(guān)于消息隊(duì)列的幾個(gè)基礎(chǔ)概念。
首先,RPC只是定義了一個(gè)通信接口,其底層的實(shí)現(xiàn)可以各不相同,可以是 socket,也可以是今天要講的 AMQP。
AMQP(Advanced Message Queuing Protocol)是一種基于隊(duì)列的可靠消息服務(wù)協(xié)議,作為一種通信協(xié)議,AMQP同樣存在多個(gè)實(shí)現(xiàn),如Apache Qpid,RabbitMQ等。
以下是 AMQP 中的幾個(gè)必知的概念:
Publisher:消息發(fā)布者
Queue:用來保存消息的存儲(chǔ)空間,消息沒有被receiver前,保存在隊(duì)列中。
Exchange:用來接收Publisher發(fā)出的消息,根據(jù)Routing key 轉(zhuǎn)發(fā)消息到對(duì)應(yīng)的Message Queue中,至于轉(zhuǎn)到哪個(gè)隊(duì)列里,這個(gè)路由算法又由exchange type決定的。
Exchange type:主要四種描述exchange的類型。
direct:消息路由到滿足此條件的隊(duì)列中(queue,可以有多個(gè)):routing key = binding key
topic:消息路由到滿足此條件的隊(duì)列中(queue,可以有多個(gè)):routing key 匹配 binding pattern. binding pattern是類似正則表達(dá)式的字符串,可以滿足復(fù)雜的路由條件。
fanout:消息路由到多有綁定到該exchange的隊(duì)列中。
binding :binding是用來描述exchange和queue之間的關(guān)系的概念,一個(gè)exchang可以綁定多個(gè)隊(duì)列,這些關(guān)系由binding建立。前面說的binding key /binding pattern也是在binding中給出。
為了讓你明白這幾者的關(guān)系,我畫了一張模型圖。
關(guān)于AMQP,有幾下幾點(diǎn)值得注意:
前面鋪墊了那么久,終于到了講真實(shí)應(yīng)用的場景。在生產(chǎn)中RPC是如何應(yīng)用的呢?
其他模型我不太清楚,在 OpenStack 中的應(yīng)用模型是這樣的
至于為什么要如此設(shè)計(jì),前面我已經(jīng)給出了自己的觀點(diǎn)。
接下來,就是源碼解讀 OpenStack ,看看其是如何通過rpc進(jìn)行遠(yuǎn)程調(diào)用的。如若你對(duì)此沒有興趣(我知道很多人對(duì)此都沒有興趣,所以不浪費(fèi)大家時(shí)間),可以直接跳過這一節(jié),進(jìn)入下一節(jié)。
目前Openstack中有兩種RPC實(shí)現(xiàn),一種是在oslo messaging,一種是在openstack.common.rpc。
openstack.common.rpc是舊的實(shí)現(xiàn),oslo messaging是對(duì)openstack.common.rpc的重構(gòu)。openstack.common.rpc在每個(gè)項(xiàng)目中都存在一份拷貝,oslo messaging即將這些公共代碼抽取出來,形成一個(gè)新的項(xiàng)目。oslo messaging也對(duì)RPC API 進(jìn)行了重新設(shè)計(jì),對(duì)多種 transport 做了進(jìn)一步封裝,底層也是用到了kombu這個(gè)AMQP庫。(注:Kombu 是Python中的messaging庫。Kombu旨在通過為AMQ協(xié)議提供慣用的高級(jí)接口,使Python中的消息傳遞盡可能簡單,并為常見的消息傳遞問題提供經(jīng)過驗(yàn)證和測試的解決方案。)
關(guān)于oslo_messaging庫,主要提供了兩種獨(dú)立的API:
因?yàn)?notify 實(shí)現(xiàn)是太簡單了,所以這里我就不多說了,如果有人想要看這方面內(nèi)容,可以收藏我的博客() ,我會(huì)更新補(bǔ)充 notify 的內(nèi)容。
OpenStack RPC 模塊提供了 rpc.call,rpc.cast, rpc.fanout_cast 三種 RPC 調(diào)用方法,發(fā)送和接收 RPC 請(qǐng)求。
rpc.call 和 .rpc.cast 從實(shí)現(xiàn)代碼上看,他們的區(qū)別很小,就是call調(diào)用時(shí)候會(huì)帶有wait_for_reply=True參數(shù),而cast不帶。
要了解 rpc 的調(diào)用機(jī)制呢,首先要知道 oslo_messaging 的幾個(gè)概念主要方法有四個(gè):
transport:RPC功能的底層實(shí)現(xiàn)方法,這里是rabbitmq的消息隊(duì)列的訪問路徑
transport 就是定義你如何訪連接消息中間件,比如你使用的是 Rabbitmq,那在 nova.conf中應(yīng)該有一行transport_url的配置,可以很清楚地看出指定了 rabbitmq 為消息中間件,并配置了連接rabbitmq的user,passwd,主機(jī),端口。
target用來表述 RPC 服務(wù)器監(jiān)聽topic,server名稱和server監(jiān)聽的exchange,是否廣播fanout。
rpc server 要獲取消息,需要定義target,就像一個(gè)門牌號(hào)一樣。
rpc client 要發(fā)送消息,也需要有target,說明消息要發(fā)到哪去。
endpoints:是可供別人遠(yuǎn)程調(diào)用的對(duì)象
RPC服務(wù)器暴露出endpoint,每個(gè) endpoint 包涵一系列的可被遠(yuǎn)程客戶端通過 transport 調(diào)用的方法。直觀理解,可以參考nova-conductor創(chuàng)建rpc server的代碼,這邊的endpoints就是 nova/manager.py:ConductorManager
dispatcher:分發(fā)器,這是 rpc server 才有的概念
只有通過它 server 端才知道接收到的rpc請(qǐng)求,要交給誰處理,怎么處理?
在client端,是這樣指定要調(diào)用哪個(gè)方法的。
而在server端,是如何知道要執(zhí)行這個(gè)方法的呢?這就是dispatcher 要干的事,它從 endpoint 里找到這個(gè)方法,然后執(zhí)行,最后返回。
Serializer:在 python 對(duì)象和message(notification) 之間數(shù)據(jù)做序列化或是反序列化的基類。
主要方法有四個(gè):
每個(gè)notification listener都和一個(gè)executor綁定,來控制收到的notification如何分配。默認(rèn)情況下,使用的是blocking executor(具體特性參加executor一節(jié))
模仿是一種很高效的學(xué)習(xí)方法,我這里根據(jù) OpenStack 的調(diào)用方式,抽取出核心內(nèi)容,寫成一個(gè)簡單的 demo,有對(duì) OpenStack 感興趣的可以了解一下,大部分人也可以直接跳過這章節(jié)。
注意以下代碼不能直接運(yùn)行,你還需要配置 rabbitmq 的連接方式,你可以寫在配置文件中,通過 get_transport 從cfg.CONF 中讀取,也可以直接將其寫成url的格式做成參數(shù),傳給 get_transport 。而且還要nova或者其他openstack組件的環(huán)境中運(yùn)行(因?yàn)樾枰衏txt這個(gè)環(huán)境變量)
簡單的 rpc client
簡單的 rpc server
【End】
熱 文 推 薦
?Facebook 發(fā)幣 Libra;谷歌十億美金為窮人造房;第四代樹莓派 Raspberry Pi 4 發(fā)布 | 開發(fā)者周刊
?WebRTC 將一統(tǒng)實(shí)時(shí)音視頻天下?
?小米崔寶秋:小米 AIoT 深度擁抱開源
?華為在美研發(fā)機(jī)構(gòu) Futurewei 意欲分家?
?老司機(jī)教你如何寫出沒人敢維護(hù)的代碼!
?Python有哪些技術(shù)上的優(yōu)點(diǎn)?比其他語言好在哪兒?
?上不了北大“圖靈”、清華“姚班”,AI專業(yè)還能去哪上?
?公鏈?zhǔn)酚?| 從鴻蒙初辟到萬物生長的十年激蕩……
?邊緣計(jì)算容器化是否有必要?
?馬云曾經(jīng)偶像,終于把阿里留下的1400億敗光了!
你點(diǎn)的每個(gè)“在看”,我都認(rèn)真當(dāng)成了喜歡
近幾年誕生了很多微服務(wù)框架,比如JAVA的Spring Cloud、Dubbo;Golang的GoKit和GoMicro以及NodeJs的Seneca。幾乎每種主流語言都有其對(duì)應(yīng)的微服務(wù)框架。
Go在微服務(wù)框架中有其獨(dú)特的優(yōu)勢,至于優(yōu)勢在哪,自行g(shù)oogle。
1、GoKit框架
這是一個(gè)工具包的集合,可以幫助攻城獅構(gòu)建強(qiáng)大、可靠和可維護(hù)的微服務(wù)。提供了用于實(shí)現(xiàn)系統(tǒng)監(jiān)控和彈性模式組件的庫,例如日志、跟蹤、限流、熔斷等。
基于這個(gè)框架的應(yīng)用程序架構(gòu)由三個(gè)主要的部分組成:
傳輸層:用于網(wǎng)絡(luò)通信,服務(wù)通常使用HTTP或者gRPC等網(wǎng)絡(luò)傳輸協(xié)議,或者使用NATS等發(fā)布訂閱系統(tǒng)相互通信。
接口層:是服務(wù)器和客戶端的基本構(gòu)建塊。每個(gè)對(duì)外提供的接口方法都會(huì)定義為一個(gè)Endpoint,一遍在服務(wù)器和客戶端之間進(jìn)行網(wǎng)絡(luò)通信,每個(gè)端點(diǎn)使用傳輸層通過HTTP或gRPC等具體通信模式對(duì)外提供服務(wù)
服務(wù)成:具體的業(yè)務(wù)邏輯實(shí)現(xiàn)
2、GoMicro框架
這是一個(gè)基于Go語言實(shí)現(xiàn)的插件化RPC微服務(wù)框架。提供了服務(wù)發(fā)現(xiàn)、負(fù)載均衡、同步傳輸、異步通信以及事件驅(qū)動(dòng)等機(jī)制,嘗試簡化分布式系統(tǒng)之間的通信,讓開發(fā)者更專注于自身業(yè)務(wù)邏輯的開發(fā)。
GoMicro的設(shè)計(jì)哲學(xué)是可插拔的架構(gòu)理念,提供了可快速構(gòu)建系統(tǒng)的組件,并且可以根據(jù)自身的需求對(duì)GoMicro提供的默認(rèn)實(shí)現(xiàn)進(jìn)行定制。所有插件都可在倉庫github.com/micro/go-plugins 中找到。
Remote Procedure Calls
遠(yuǎn)程過程調(diào)用 (RPC) 是一種協(xié)議,程序可使用這種協(xié)議向網(wǎng)絡(luò)中的另一臺(tái)計(jì)算機(jī)上的程序請(qǐng)求服務(wù)。由于使用 RPC 的程序不必了解支持通信的網(wǎng)絡(luò)協(xié)議的情況,因此 RPC 提高了程序的互操作性。在 RPC 中,發(fā)出請(qǐng)求的程序是客戶程序,而提供服務(wù)的程序是服務(wù)器。
RPC是指遠(yuǎn)程過程調(diào)用,也就是說兩臺(tái)服務(wù)器A,B,一個(gè)應(yīng)用部署在A服務(wù)器上,想要調(diào)用B服務(wù)器上應(yīng)用提供的函數(shù)/方法,由于不在一個(gè)內(nèi)存空間,不能直接調(diào)用,需要通過網(wǎng)絡(luò)來表達(dá)調(diào)用的語義和傳達(dá)調(diào)用的數(shù)據(jù)。
為什么要用RPC呢?就是無法在一個(gè)進(jìn)程內(nèi),甚至一個(gè)計(jì)算機(jī)內(nèi)通過本地調(diào)用的方式完成的需求,比如不同的系統(tǒng)間的通訊,甚至不同的組織間的通訊,由于計(jì)算能力需要橫向擴(kuò)展,需要在多臺(tái)機(jī)器組成的集群上部署應(yīng)用。
RPC就是要像調(diào)用本地的函數(shù)一樣去調(diào)遠(yuǎn)程函數(shù)。在研究RPC前,我們先看看本地調(diào)用是怎么調(diào)的。假設(shè)我們要調(diào)用函數(shù)Multiply來計(jì)算lvalue * rvalue的結(jié)果:
1 int Multiply(int l, int r) {
2 int y = l * r;
3 return y;
4 }
5
6 int lvalue = 10;
7 int rvalue = 20;
8 int l_times_r = Multiply(lvalue, rvalue);
那么在第8行時(shí),我們實(shí)際上執(zhí)行了以下操作:
將 lvalue 和 rvalue 的值壓棧
進(jìn)入Multiply函數(shù),取出棧中的值10 和 20,將其賦予 l 和 r
執(zhí)行第2行代碼,計(jì)算 l * r ,并將結(jié)果存在 y
將 y 的值壓棧,然后從Multiply返回
第8行,從棧中取出返回值 200 ,并賦值給 l_times_r
以上5步就是執(zhí)行本地調(diào)用的過程。
在遠(yuǎn)程調(diào)用時(shí),我們需要執(zhí)行的函數(shù)體是在遠(yuǎn)程的機(jī)器上的,也就是說,Multiply是在另一個(gè)進(jìn)程中執(zhí)行的。這就帶來了幾個(gè)新問題:
Call ID映射。我們?cè)趺锤嬖V遠(yuǎn)程機(jī)器我們要調(diào)用Multiply,而不是Add或者FooBar呢?在本地調(diào)用中,函數(shù)體是直接通過函數(shù)指針來指定的,我們調(diào)用Multiply,編譯器就自動(dòng)幫我們調(diào)用它相應(yīng)的函數(shù)指針。但是在遠(yuǎn)程調(diào)用中,函數(shù)指針是不行的,因?yàn)閮蓚€(gè)進(jìn)程的地址空間是完全不一樣的。所以,在RPC中,所有的函數(shù)都必須有自己的一個(gè)ID。這個(gè)ID在所有進(jìn)程中都是唯一確定的??蛻舳嗽谧鲞h(yuǎn)程過程調(diào)用時(shí),必須附上這個(gè)ID。然后我們還需要在客戶端和服務(wù)端分別維護(hù)一個(gè) {函數(shù) -- Call ID} 的對(duì)應(yīng)表。兩者的表不一定需要完全相同,但相同的函數(shù)對(duì)應(yīng)的Call ID必須相同。當(dāng)客戶端需要進(jìn)行遠(yuǎn)程調(diào)用時(shí),它就查一下這個(gè)表,找出相應(yīng)的Call ID,然后把它傳給服務(wù)端,服務(wù)端也通過查表,來確定客戶端需要調(diào)用的函數(shù),然后執(zhí)行相應(yīng)函數(shù)的代碼。序列化和反序列化??蛻舳嗽趺窗褏?shù)值傳給遠(yuǎn)程的函數(shù)呢?在本地調(diào)用中,我們只需要把參數(shù)壓到棧里,然后讓函數(shù)自己去棧里讀就行。但是在遠(yuǎn)程過程調(diào)用時(shí),客戶端跟服務(wù)端是不同的進(jìn)程,不能通過內(nèi)存來傳遞參數(shù)。甚至有時(shí)候客戶端和服務(wù)端使用的都不是同一種語言(比如服務(wù)端用C++,客戶端用Java或者Python)。這時(shí)候就需要客戶端把參數(shù)先轉(zhuǎn)成一個(gè)字節(jié)流,傳給服務(wù)端后,再把字節(jié)流轉(zhuǎn)成自己能讀取的格式。這個(gè)過程叫序列化和反序列化。同理,從服務(wù)端返回的值也需要序列化反序列化的過程。網(wǎng)絡(luò)傳輸。遠(yuǎn)程調(diào)用往往用在網(wǎng)絡(luò)上,客戶端和服務(wù)端是通過網(wǎng)絡(luò)連接的。所有的數(shù)據(jù)都需要通過網(wǎng)絡(luò)傳輸,因此就需要有一個(gè)網(wǎng)絡(luò)傳輸層。網(wǎng)絡(luò)傳輸層需要把Call ID和序列化后的參數(shù)字節(jié)流傳給服務(wù)端,然后再把序列化后的調(diào)用結(jié)果傳回客戶端。只要能完成這兩者的,都可以作為傳輸層使用。因此,它所使用的協(xié)議其實(shí)是不限的,能完成傳輸就行。盡管大部分RPC框架都使用TCP協(xié)議,但其實(shí)UDP也可以,而gRPC干脆就用了HTTP2。Java的Netty也屬于這層的東西。
所以,要實(shí)現(xiàn)一個(gè)RPC框架,其實(shí)只需要把以上三點(diǎn)實(shí)現(xiàn)了就基本完成了。Call ID映射可以直接使用函數(shù)字符串,也可以使用整數(shù)ID。映射表一般就是一個(gè)哈希表。序列化反序列化可以自己寫,也可以使用Protobuf或者FlatBuffers之類的。網(wǎng)絡(luò)傳輸庫可以自己寫socket,或者用asio,ZeroMQ,Netty之類。
分享題目:go語言rpc怎么用,go語言grpc
文章位置:http://sd-ha.com/article12/hsesdc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供企業(yè)建站、關(guān)鍵詞優(yōu)化、自適應(yīng)網(wǎng)站、網(wǎng)站建設(shè)、定制網(wǎng)站、網(wǎng)站排名
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)