本文目錄一覽:
- 1、如何通過IP訪問並運行服務器上的python文件
- 2、python怎麼經過protobuf完成rpc
- 3、Electron 框架中調用 Python 構建桌面應用
- 4、微服務跨語言調用(摘選)
- 5、從 0 到 1:全面理解 RPC 遠程調用
如何通過IP訪問並運行服務器上的python文件
很多種方法,例如:
rpc遠程調用.通過ip地址,遠程指定python文件,直接調用
寫一個簡單的socket,進行通信,發送命令,根據命令啟動python文件
通過http協議,建立簡單的web服務,通過http請求調用
通過消息隊列,例如zmq,rabbitmq,amq,發送消息或者命令,由消費者調用python文件.
python怎麼經過protobuf完成rpc
客戶方像挪用當地辦法同樣去挪用長途接口辦法,RPC 結構供給接口的署理完成,理論的挪用將拜託給署理RpcProxy
。署理封裝挪用資訊並將挪用轉交給RpcInvoker 去理論履行。在客戶真箇RpcInvoker 經過銜接器RpcConnector
去保持與效勞端的通道RpcChannel,並運用RpcProtocol
履行協定編碼(encode)並將編碼後的懇求音訊經過通道發送給效勞方。RPC 效勞端接納器 RpcAcceptor
接納客戶真箇挪用懇求,一樣運用RpcProtocol 履行協定解碼(decode)。解碼後的挪用資訊傳送給RpcProcessor
去掌握處置挪用進程,末了再拜託挪用給RpcInvoker 去理論履行並前往挪用後果。
protobuf
rpc在下面組件中首要表演RpcProtocol的人物,使得咱們省去了協定的描繪,而且protobuf協定在編碼和時間效力都是上十分高效的,這也是許多公司選用protobuf作為數值序列化和通訊協議的起因。一起protobuf
rpc界說了一個籠統的rpc結構,以下圖所示:
RpcServiceStub和RpcService類是protobuf編譯器依據proto界說天生的類,RpcService界說了效勞端表露給客戶真箇函數接口,詳細完成需求用戶本人擔當這個類來完成。RpcServiceStub界說了效勞端表露函數的描繪,並將客戶端對RpcServiceStub中函數的挪用同一轉換到挪用RpcChannel中的CallMethod辦法,CallMethod經過RpcServiceStub傳過去的函數描繪符和函數參數對該次rpc挪用停止encode,最後經過RpcConnecor發送給效勞方。自己以客戶端相反的進程最後挪用RpcSerivice中界說的函數。現實上,protobuf
rpc的結構僅僅RpcChannel中界說了空的CallMethod,以是詳細怎麼樣停止encode和挪用RpcConnector都要本人完成。RpcConnector在protobuf中沒有界說,以是這個完結由用戶本人完成,它的效果那是收發rpc音訊包。在效勞端,RpcChannel經過挪用RpcService中的CallMethod來詳細挪用RpcService中表露給客戶真箇函數。
引見了這麼多,關於怎樣用protobuf rpc來完成一個rpc確定仍是一頭霧水吧,下面就用protobuf rpc來完成一個簡略的python版rpc demo吧。
下面間接給出demo描繪PRC的proto文件,至於proto文件的編寫規定能夠參考protobuf官網。
common.proto文件:
package game;
message RequestMessage
{
required string message = 1;
}
message ResponseMessage
{
required string message = 1;
}
game_service.proto文件:
package game;
import “common.proto”;
option py_generic_services = true;
service GameService
{
rpc connect_server(RequestMessage) returns(RequestMessage);
}
common.proto文件描繪了RPC中收發的音訊;game_service.proto描繪了效勞器導出的connect_server函數,該函數承受RequestMessage目標作為參數,並前往RequestMessage目標。在運用PRC協定時,必需加之option
py_generic_services =
true;可選項,要否則編譯器不會天生蘊含connect_server函數的GameService描繪。
運用編譯器protoc編譯proto文件,詳細號令為:
protoc.exe –python_out=. game_service.proto
編譯後天生的文件為game_service_pb2.py,該文件首要是完成了GameService和GameService_Stub類。GameService_Stub類用於客戶端挪用者來挪用GameService的效勞。
後面曾經說了,在客戶端,RpcChannel只完成了一個空的CallMethod,以是需求擔當RpcChannel從新這個函數來encode音訊和發送音訊。在效勞端RpcChannel需求挪用CallMethod來挪用Service中的函數。詳細完成以下:
class MyRpcChannel(service.RpcChannel):
def __init__(self, rpc_service, conn):
super(MyRpcChannel, self).__init__()
self.logger = LogManager.get_logger(“MyRpcChannel”)
def CallMethod(self, method_descriptor, rpc_controller, request, response_class, done):
“”””protol buffer rpc 需求的函數,用來發送rpc挪用”””
self.logger.info(‘CallMethod’)
cmd_index = method_descriptor.index
assert(cmd_index 65535)
data = request.SerializeToString()
total_len = len(data) + 2
self.conn.send_data(”.join([pack(‘I’, total_len), pack(‘H’, cmd_index), data]))
def from_request(self):
“”””從收集剖析出一個完好的懇求以後調的函數”””
index_data = self.rpc_request.data[0:2]
cmd_index = unpack(‘H’, index_data)[0]
rpc_service = self.rpc_service
s_descriptor = rpc_service.GetDescriptor()
method = s_descriptor.methods[cmd_index]
try:
request = rpc_service.GetRequestClass(method)()
serialized = self.rpc_request.data[2:]
request.ParseFromString(serialized)
rpc_service.CallMethod(method, self.controller, request, None)
except:
self.logger.error(“Call rpc method failed!”)
self.logger.log_last_except()
return True
末了那是擔當GameService,並完成connect_server函數了。
class GameService(game_service_pb2.GameService):
def __init__(self):
self.logger = LogManager.get_logger(“GameService”)
def connect_server(self, rpc_controller, request, callback):
self.logger.info(‘%s’, request.message)
至於用於收集收發音訊的RpcConnector,可使用python的asyncore庫完成,詳細完成在這就不評論了。
從下面的完成來看,protobuf rpc的完成首要囊括編寫proto文件並編譯天生對應的service_pb2文件,擔當RpcChannel並完成CallMethod和挪用Service的CallMethod,擔當Service來完成表露給客戶真箇函數。
Electron 框架中調用 Python 構建桌面應用
不同的語言、框架都有自己擅長的領域:Electron 基於 Chromium 和 Node.js 能以 Web 開發的模式打造桌面應用,開發用戶界面又快捷又簡單;Python 則在數據分析、自動化腳本等領域有非常多的應用。兩者的社區生態都十分強大,由兩者共同構建應用,在界面開發、功能、性能上能夠強強聯合;
為了簡單驗證技術可行性,我們來編寫一個 Demo:
目的:驗證 Electron 打造的桌面應用能夠調用 Python,思路是使用 RPC 或 HTTP 或 WebSocket 進行通信
Demo 功能:輸入 x、y 坐標,程序會移動鼠標到屏幕的 x,y 位置(通過 python 庫 pyautogui 實現)
Demo 運行環境:MacOS、pyInstaller: 版本 4.5.1、python: 版本 3.9.7
源碼:——– 項目源碼 ——–
注意:移動鼠標需要授予應用控制權限,在 MacOS 下設置 偏好設置 – 隱私 – 輔助功能 – 允許對應的應用。
技術棧:NodeJS、Electron、Python、aiohttp(HTTP、WebSocket)、pyautogui(控制鼠標)
為了使 NodeJS 和 Python 能夠通信,Python 需要啟動一個本地通信服務,Demo 中 py/api.py 能夠啟動一個本地 HTTP 服務:
然後我們需要執行 Python 代碼以啟動服務,為了使 NodeJS 可以執行 Python,我們使用 pyinstaller 將 Python 打包成可執行文件:
Python 啟動了本地 HTTP 服務後,Chromium 和 Node.js 就可以通過請求的方式,與 python 連接通信了:
簡單來說三個步驟:
本項目只是一個驗證思路的 Demo,真的需要在項目上實踐,還需要考慮以下幾個點:
應該使用 RPC 通信而不是 HTTP 或者 WebSocket,Demo 使用 HTTP 只是搭建方便。實踐中在建立連接、保持連接、異常重連都需要編寫更多的邏輯來處理。為什麼 Demo 沒有使用 zerorpc? 這個庫已經 4 年沒有維護了,不兼容新版 NodeJS。
項目通過 pyinstaller 打包成可執行文件來調用 python。實際上其他能編譯為可執行文件的語言也一樣。還可以使用 WebAssembly 將其他語言編譯成 .wasm,在 NodeJS 中引入執行。
微服務跨語言調用(摘選)
微服務架構已成為目前互聯網架構的趨勢,關於微服務的討論,幾乎佔據了各種技術大會的絕大多數版面。國內使用最多的服務治理框架非阿里開源的 dubbo 莫屬,千米網也選擇了 dubbo 作為微服務治理框架。另一方面,和大多數互聯網公司一樣,千米的開發語言是多樣的,大多數後端業務由 java 支撐,而每個業務線有各自開發語言的選擇權,便出現了 nodejs,python,go 多語言調用的問題。
跨語言調用是一個很大的話題,也是一個很有挑戰的技術活,目前業界經常被提及的解決方案有如下幾種,不妨拿出來老生常談一番:
當我們再聊跨語言調用時我們在聊什麼?縱觀上述幾個較為通用,成熟的解決方案,可以得出結論:解決跨語言調用的思路無非是兩種:
如果一個新型的團隊面臨技術選型,我認為上述的方案都可以納入參考,可考慮到遺留系統的兼容性問題
舊系統的遷移成本
這也關鍵的選型因素。我們做出的第一個嘗試,便是在 RPC 協議上下功夫。
通用協議的跨語言支持
springmvc的美好時代
springmvc
springmvc
在沒有實現真正的跨語言調用之前,想要實現“跨語言”大多數方案是使用 http 協議做一層轉換,最常見的手段莫過於藉助 springmvc 提供的 controller/restController,間接調用 dubbo provider。這種方案的優勢和劣勢顯而易見
通用協議的支持
事實上,大多數服務治理框架都支持多種協議,dubbo 框架除默認的 dubbo 協議之外,還有噹噹網擴展的 rest協議和千米網擴展的 json-rpc 協議可供選擇。這兩者都是通用的跨語言協議。
rest 協議為滿足 JAX-RS 2.0 標準規範,在開發過程中引入了 @Path,@POST,@GET 等註解,習慣於編寫傳統 rpc 接口的人可能不太習慣 rest 風格的 rpc 接口。一方面這樣會影響開發體驗,另一方面,獨樹一幟的接口風格使得它與其他協議不太兼容,舊接口的共生和遷移都無法實現。如果沒有遺留系統,rest 協議無疑是跨語言方案最簡易的實現,絕大多數語言支持 rest 協議。
和 rest 協議類似,json-rpc 的實現也是文本序列化http 協議。dubbox 在 restful 接口上已經做出了嘗試,但是 rest 架構和 dubbo 原有的 rpc 架構是有區別的,rest 架構需要對資源(Resources)進行定義, 需要用到 http 協議的基本操作 GET、POST、PUT、DELETE。在我們看來,restful 更合適互聯網系統之間的調用,而 rpc 更適合一個系統內的調用。使用 json-rpc 協議使得舊接口得以兼顧,開發習慣仍舊保留,同時獲得了跨語言的能力。
千米網在早期實踐中採用了 json-rpc 作為 dubbo 的跨語言協議實現,並開源了基於 json-rpc 協議下的 python 客戶端 dubbo-client-py 和 node 客戶端 dubbo-node-client,使用 python 和 nodejs 的小夥伴可以藉助於它們直接調用 dubbo-provider-java 提供的 rpc 服務。系統中大多數 java 服務之間的互相調用還是以 dubbo 協議為主,考慮到新舊協議的適配,在不影響原有服務的基礎上,我們配置了雙協議。
dubbo 協議主要支持 java 間的相互調用,適配老接口;json-rpc 協議主要支持異構語言的調用。
定製協議的跨語言支持
微服務框架所謂的協議(protocol)可以簡單理解為:報文格式和序列化方案。服務治理框架一般都提供了眾多的協議配置項供使用者選擇,除去上述兩種通用協議,還存在一些定製化的協議,如 dubbo 框架的默認協議:dubbo 協議以及 motan 框架提供的跨語言協議:motan2。
motan2協議的跨語言支持
motan2
motan2
motan2 協議被設計用來滿足跨語言的需求主要體現在兩個細節中—MetaData 和 motan-go。在最初的 motan 協議中,協議報文僅由 Header+Body 組成,這樣導致 path,param,group 等存儲在 Body 中的數據需要反序列得到,這對異構語言來說是很不友好的,所以在 motan2 中修改了協議的組成;weibo 開源了 motan-go ,motan-php ,motan-openresty ,並藉助於 motan-go 充當了 agent 這一翻譯官的角色,使用 simple 序列化方案來序列化協議報文的 Body 部分(simple 序列化是一種較弱的序列化方案)。
agent
agent
仔細揣摩下可以發現這麼做和雙協議的配置區別並不是大,只不過這裡的 agent 是隱式存在的,與主服務共生。明顯的區別在於 agent 方案中異構語言並不直接交互。
dubbo協議的跨語言支持
dubbo 協議設計之初只考慮到了常規的 rpc 調用場景,它並不是為跨語言而設計,但跨語言支持從來不是只有支持、不支持兩種選擇,而是要按難易程度來劃分。是的,dubbo 協議的跨語言調用可能並不好做,但並非無法實現。千米網便實現了這一點,nodejs 構建的前端業務是異構語言的主戰場,最終實現了 dubbo2.js,打通了 nodejs 和原生 dubbo 協議。作為本文第二部分的核心內容,重點介紹下我們使用 dubbo2.js 幹了什麼事。
Dubbo協議報文格式
dubbo協議
dubbo協議
dubbo協議報文消息頭詳解:
magic:類似java字節碼文件里的魔數,用來判斷是不是 dubbo 協議的數據包。魔數是常量 0xdabb
flag:標誌位, 一共8個地址位。低四位用來表示消息體數據用的序列化工具的類型(默認 hessian),高四位中,第一位為 1 表示是 request 請求,第二位為 1 表示雙向傳輸(即有返回 response),第三位為 1 表示是心跳 ping 事件。
status:狀態位, 設置請求響應狀態,dubbo 定義了一些響應的類型。具體類型見com.alibaba.dubbo.remoting.exchange.Response
invoke id:消息 id, long 類型。每一個請求的唯一識別 id(由於採用異步通訊的方式,用來把請求 request 和返回的 response 對應上)
body length:消息體 body 長度, int 類型,即記錄 Body Content 有多少個字節
body content:請求參數,響應參數的抽象序列化之後存儲於此。
協議報文最終都會變成字節,使用 tcp 傳輸,任何語言只要支持網絡模塊,有類似 Socket 之類的封裝,那麼通信就不成問題。那,跨語言難在哪兒?以其他語言調用 java 來說,主要有兩個難點:
ps:dubbo 協議通訊demo( )
從 0 到 1:全面理解 RPC 遠程調用
作者 | Python編程時光
責編 | 胡巍巍
什麼是RPC呢?百度百科給出的解釋是這樣的:“RPC(Remote Procedure Call Protocol)——遠程過程調用協議,它是一種通過網絡從遠程計算機程序上請求服務,而不需要了解底層網絡技術的協議”。
這個概念聽起來還是比較抽象,沒關係,繼續往後看,後面概念性的東西,我會講得足夠清楚,讓你完全掌握 RPC 的基礎內容。
在 OpenStack 里的進程間通信方式主要有兩種,一種是基於HTTP協議的RESTFul API方式,另一種則是RPC調用。
那麼這兩種方式在應用場景上有何區別呢?
有使用經驗的人,就會知道:
首先,給你提兩個問題,帶着這兩個問題再往下看:
1、RPC 和 REST 區別是什麼?2、為什麼要採用RPC呢?
首先,第一個問題:RPC 和 REST 區別是什麼?
你一定會覺得這個問題很奇怪,是的,包括我,但是你在網絡上一搜,會發現類似對比的文章比比皆是,我在想可能很多初學者由於基礎不牢固,才會將不相干的二者拿出來對比吧。既然是這樣,那為了讓你更加了解陌生的RPC,就從你熟悉得不能再熟悉的 REST 入手吧。
01、所屬類別不同
REST,是Representational State Transfer 的簡寫,中文描述表述性狀態傳遞(是指某個瞬間狀態的資源數據的快照,包括資源數據的內容、表述格式(XML、JSON)等信息。)
REST 是一種軟件架構風格。這種風格的典型應用,就是HTTP。其因為簡單、擴展性強的特點而廣受開發者的青睞。
而RPC 呢,是 Remote Procedure Call Protocol 的簡寫,中文描述是遠程過程調用,它可以實現客戶端像調用本地服務(方法)一樣調用服務器的服務(方法)。
而 RPC 可以基於 TCP/UDP,也可以基於 HTTP 協議進行傳輸的,按理說它和REST不是一個層面意義上的東西,不應該放在一起討論,但是誰讓REST這麼流行呢,它是目前最流行的一套互聯網應用程序的API設計標準,某種意義下,我們說 REST 可以其實就是指代 HTTP 協議。
02、使用方式不同
03、面向對象不同
從設計上來看,RPC,所謂的遠程過程調用 ,是面向方法的 ,REST:所謂的 Representational state transfer ,是面向資源的,除此之外,還有一種叫做 SOA,所謂的面向服務的架構,它是面向消息的,這個接觸不多,就不多說了。
04、序列化協議不同
接口調用通常包含兩個部分,序列化和通信協議。
通信協議,上面已經提及了,REST 是 基於 HTTP 協議,而 RPC 可以基於 TCP/UDP,也可以基於 HTTP 協議進行傳輸的。
常見的序列化協議,有:json、xml、hession、protobuf、thrift、text、bytes等,REST 通常使用的是 JSON或者XML,而 RPC 使用的是 JSON-RPC,或者 XML-RPC。
通過以上幾點,我們知道了 REST 和 RPC 之間有很明顯的差異。
然後第二個問題:為什麼要採用RPC呢?
那到底為何要使用 RPC,單純的依靠RESTful API不可以嗎?為什麼要搞這麼多複雜的協議,渣渣表示真的學不過來了。
關於這一點,以下幾點僅是我的個人猜想,僅供交流哈:
說了這麼多,我們該如何選擇這兩者呢?我總結了如下兩點,供你參考:
“遠程調用”意思就是:被調用方法的具體實現不在程序運行本地,而是在別的某個地方(分布到各個服務器),調用者只想要函數運算的結果,卻不需要實現函數的具體細節。
光說不練嘴把式,接下來,我將分別用三種不同的方式全面地讓你搞明白 rpc 遠程調用是如何實現的。
01、基於 xml-rpc
Python實現 rpc,可以使用標準庫里的 SimpleXMLRPCServer,它是基於XML-RPC 協議的。
有了這個模塊,開啟一個 rpc server,就變得相當簡單了。執行以下代碼:
有了 rpc server,接下來就是 rpc client,由於我們上面使用的是 XML-RPC,所以 rpc clinet 需要使用xmlrpclib 這個庫。
然後,我們通過 server_proxy 對象就可以遠程調用之前的rpc server的函數了。
SimpleXMLRPCServer是一個單線程的服務器。這意味着,如果幾個客戶端同時發出多個請求,其它的請求就必須等待第一個請求完成以後才能繼續。
若非要使用 SimpleXMLRPCServer 實現多線程並發,其實也不難。只要將代碼改成如下即可。
02、基於json-rpc
SimpleXMLRPCServer 是基於 xml-rpc 實現的遠程調用,上面我們也提到 除了 xml-rpc 之外,還有 json-rpc 協議。
那 python 如何實現基於 json-rpc 協議呢?
答案是很多,很多web框架其自身都自己實現了json-rpc,但我們要獨立這些框架之外,要尋求一種較為乾淨的解決方案,我查找到的選擇有兩種
第一種是 jsonrpclib
第二種是 python-jsonrpc
先來看第一種 jsonrpclib
它與 Python 標準庫的 SimpleXMLRPCServer 很類似(因為它的類名就叫做 SimpleJSONRPCServer ,不明真相的人真以為它們是親兄弟)。或許可以說,jsonrpclib 就是仿照 SimpleXMLRPCServer 標準庫來進行編寫的。
它的導入與 SimpleXMLRPCServer 略有不同,因為SimpleJSONRPCServer分布在jsonrpclib庫中。
服務端
客戶端
再來看第二種python-jsonrpc,寫起來貌似有些複雜。
服務端
客戶端
調用過程如下
還記得上面我提到過的 zabbix API,因為我有接觸過,所以也拎出來講講。zabbix API 也是基於 json-rpc 2.0協議實現的。
因為內容較多,這裡只帶大家打個,zabbix 是如何調用的:直接指明要調用 zabbix server 的哪個方法,要傳給這個方法的參數有哪些。
03、基於 zerorpc
以上介紹的兩種rpc遠程調用方式,如果你足夠細心,可以發現他們都是http+rpc 兩種協議結合實現的。
接下來,我們要介紹的這種(zerorpc),就不再使用走 http 了。
zerorpc 這個第三方庫,它是基於TCP協議、 ZeroMQ 和 MessagePack的,速度相對快,響應時間短,並發高。zerorpc 和 pyjsonrpc 一樣,需要額外安裝,雖然SimpleXMLRPCServer不需要額外安裝,但是SimpleXMLRPCServer性能相對差一些。
調用過程如下
客戶端除了可以使用zerorpc框架實現代碼調用之外,它還支持使用“命令行”的方式調用。
客戶端可以使用命令行,那服務端是不是也可以呢?
是的,通過 Github 上的文檔幾個 demo 可以體驗到這個第三方庫做真的是優秀。
比如我們可以用下面這個命令,創建一個rpc server,後面這個 time Python 標準庫中的 time 模塊,zerorpc 會將 time 註冊綁定以供client調用。
經過了上面的學習,我們已經學會了如何使用多種方式實現rpc遠程調用。
通過對比,zerorpc 可以說是脫穎而出,一支獨秀。
為此,我也做了一番思考:
OpenStack 組件繁多,在一個較大的集群內部每個組件內部通過rpc通信頻繁,如果都採用rpc直連調用的方式,連接數會非常地多,開銷大,若有些 server 是單線程的模式,超時會非常的嚴重。
OpenStack 是複雜的分布式集群架構,會有多個 rpc server 同時工作,假設有 server01,server02,server03 三個server,當 rpc client 要發出rpc請求時,發給哪個好呢?這是問題一。
你可能會說輪循或者隨機,這樣對大家都公平。這樣的話還會引出另一個問題,倘若請求剛好發到server01,而server01剛好不湊巧,可能由於機器或者其他因為導致服務沒在工作,那這個rpc消息可就直接失敗了呀。要知道做為一個集群,高可用是基本要求,如果出現剛剛那樣的情況其實是很尷尬的。這是問題二。
集群有可能根據實際需要擴充節點數量,如果使用直接調用,耦合度太高,不利於部署和生產。這是問題三。
引入消息中間件,可以很好的解決這些問題。
解決問題一:消息只有一份,接收者由AMQP的負載算法決定,默認為在所有Receiver中均勻發送(round robin)。
解決問題二:有了消息中間件做緩衝站,client 可以任性隨意的發,server 都掛掉了?沒有關係,等 server 正常工作後,自己來消息中間件取就行了。
解決問題三:無論有多少節點,它們只要認識消息中間件這一個中介就足夠了。
既然講到了消息隊列,如果你之前沒有接觸過這塊內容,最好花幾分鐘的時間跟我好好過下關於消息隊列的幾個基礎概念。
首先,RPC只是定義了一個通信接口,其底層的實現可以各不相同,可以是 socket,也可以是今天要講的 AMQP。
AMQP(Advanced Message Queuing Protocol)是一種基於隊列的可靠消息服務協議,作為一種通信協議,AMQP同樣存在多個實現,如Apache Qpid,RabbitMQ等。
以下是 AMQP 中的幾個必知的概念:
Publisher:消息發布者
Queue:用來保存消息的存儲空間,消息沒有被receiver前,保存在隊列中。
Exchange:用來接收Publisher發出的消息,根據Routing key 轉發消息到對應的Message Queue中,至於轉到哪個隊列里,這個路由算法又由exchange type決定的。
Exchange type:主要四種描述exchange的類型。
direct:消息路由到滿足此條件的隊列中(queue,可以有多個):routing key = binding key
topic:消息路由到滿足此條件的隊列中(queue,可以有多個):routing key 匹配 binding pattern. binding pattern是類似正則表達式的字符串,可以滿足複雜的路由條件。
fanout:消息路由到多有綁定到該exchange的隊列中。
binding :binding是用來描述exchange和queue之間的關係的概念,一個exchang可以綁定多個隊列,這些關係由binding建立。前面說的binding key /binding pattern也是在binding中給出。
為了讓你明白這幾者的關係,我畫了一張模型圖。
關於AMQP,有幾下幾點值得注意:
前面鋪墊了那麼久,終於到了講真實應用的場景。在生產中RPC是如何應用的呢?
其他模型我不太清楚,在 OpenStack 中的應用模型是這樣的
至於為什麼要如此設計,前面我已經給出了自己的觀點。
接下來,就是源碼解讀 OpenStack ,看看其是如何通過rpc進行遠程調用的。如若你對此沒有興趣(我知道很多人對此都沒有興趣,所以不浪費大家時間),可以直接跳過這一節,進入下一節。
目前Openstack中有兩種RPC實現,一種是在oslo messaging,一種是在openstack.common.rpc。
openstack.common.rpc是舊的實現,oslo messaging是對openstack.common.rpc的重構。openstack.common.rpc在每個項目中都存在一份拷貝,oslo messaging即將這些公共代碼抽取出來,形成一個新的項目。oslo messaging也對RPC API 進行了重新設計,對多種 transport 做了進一步封裝,底層也是用到了kombu這個AMQP庫。(註:Kombu 是Python中的messaging庫。Kombu旨在通過為AMQ協議提供慣用的高級接口,使Python中的消息傳遞儘可能簡單,並為常見的消息傳遞問題提供經過驗證和測試的解決方案。)
關於oslo_messaging庫,主要提供了兩種獨立的API:
因為 notify 實現是太簡單了,所以這裡我就不多說了,如果有人想要看這方面內容,可以收藏我的博客() ,我會更新補充 notify 的內容。
OpenStack RPC 模塊提供了 rpc.call,rpc.cast, rpc.fanout_cast 三種 RPC 調用方法,發送和接收 RPC 請求。
rpc.call 和 .rpc.cast 從實現代碼上看,他們的區別很小,就是call調用時候會帶有wait_for_reply=True參數,而cast不帶。
要了解 rpc 的調用機制呢,首先要知道 oslo_messaging 的幾個概念主要方法有四個:
transport:RPC功能的底層實現方法,這裡是rabbitmq的消息隊列的訪問路徑
transport 就是定義你如何訪連接消息中間件,比如你使用的是 Rabbitmq,那在 nova.conf中應該有一行transport_url的配置,可以很清楚地看出指定了 rabbitmq 為消息中間件,並配置了連接rabbitmq的user,passwd,主機,端口。
target用來表述 RPC 服務器監聽topic,server名稱和server監聽的exchange,是否廣播fanout。
rpc server 要獲取消息,需要定義target,就像一個門牌號一樣。
rpc client 要發送消息,也需要有target,說明消息要發到哪去。
endpoints:是可供別人遠程調用的對象
RPC服務器暴露出endpoint,每個 endpoint 包涵一系列的可被遠程客戶端通過 transport 調用的方法。直觀理解,可以參考nova-conductor創建rpc server的代碼,這邊的endpoints就是 nova/manager.py:ConductorManager
dispatcher:分發器,這是 rpc server 才有的概念
只有通過它 server 端才知道接收到的rpc請求,要交給誰處理,怎麼處理?
在client端,是這樣指定要調用哪個方法的。
而在server端,是如何知道要執行這個方法的呢?這就是dispatcher 要乾的事,它從 endpoint 里找到這個方法,然後執行,最後返回。
Serializer:在 python 對象和message(notification) 之間數據做序列化或是反序列化的基類。
主要方法有四個:
每個notification listener都和一個executor綁定,來控制收到的notification如何分配。默認情況下,使用的是blocking executor(具體特性參加executor一節)
模仿是一種很高效的學習方法,我這裡根據 OpenStack 的調用方式,抽取出核心內容,寫成一個簡單的 demo,有對 OpenStack 感興趣的可以了解一下,大部分人也可以直接跳過這章節。
注意以下代碼不能直接運行,你還需要配置 rabbitmq 的連接方式,你可以寫在配置文件中,通過 get_transport 從cfg.CONF 中讀取,也可以直接將其寫成url的格式做成參數,傳給 get_transport 。而且還要nova或者其他openstack組件的環境中運行(因為需要有ctxt這個環境變量)
簡單的 rpc client
簡單的 rpc server
【End】
熱 文 推 薦
☞Facebook 發幣 Libra;谷歌十億美金為窮人造房;第四代樹莓派 Raspberry Pi 4 發布 | 開發者周刊
☞WebRTC 將一統實時音視頻天下?
☞小米崔寶秋:小米 AIoT 深度擁抱開源
☞華為在美研發機構 Futurewei 意欲分家?
☞老司機教你如何寫出沒人敢維護的代碼!
☞Python有哪些技術上的優點?比其他語言好在哪兒?
☞上不了北大“圖靈”、清華“姚班”,AI專業還能去哪上?
☞公鏈史記 | 從鴻蒙初辟到萬物生長的十年激蕩……
☞邊緣計算容器化是否有必要?
☞馬雲曾經偶像,終於把阿里留下的1400億敗光了!
你點的每個“在看”,我都認真當成了喜歡
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/304950.html