遠程過程調用 (RPC) 是一種協(xié)議,程序可使用這種協(xié)議向網絡中的另一臺計算機上的程序請求服務。由于使用 RPC 的程序不必了解支持通信的網絡協(xié)議的情況,因此 RPC 提高了程序的互操作性。在 RPC 中,發(fā)出請求的程序是客戶程序,而提供服務的程序是服務器。 \x0d\x0aRPC 中處理 TCP/IP 上的消息交換的部分存在一個缺陷。錯誤地處理格式不正確的消息會導致出現錯誤。這種特定的錯誤會影響底層的 DCOM 接口,此接口偵聽 TCP/IP 端口 135。通過發(fā)送格式不正確的 RPC 消息,攻擊者可以使一臺計算機上的 RPC 服務出現問題,進而使任意代碼得以執(zhí)行。 \x0d\x0a遠程過程調用 (RPC) 是 Windows 操作系統(tǒng)使用的一個協(xié)議。RPC 提供了一種進程間通信機制,通過這一機制,在一臺計算機上運行的程序可以順暢地執(zhí)行某個遠程系統(tǒng)上的代碼。該協(xié)議本身是從 OSF(開放式軟件基礎)RPC 協(xié)議衍生出來的,只是增加了一些 Microsoft 特定的擴展。 \x0d\x0a\x0d\x0aRPC 中處理通過 TCP/IP 的消息交換的部分有一個漏洞。此問題是由錯誤地處理格式不正確的消息造成的。這種特定的漏洞影響分布式組件對象模型 (DCOM) 與 RPC 間的一個接口,此接口偵聽 TCP/IP 端口 135。此接口處理客戶端計算機向服務器發(fā)送的 DCOM 對象激活請求(例如通用命名約定 (UNC) 路徑)。 \x0d\x0a\x0d\x0a為利用此漏洞,攻擊者可能需要向遠程計算機上的 135 端口發(fā)送特殊格式的請求。 \x0d\x0a\x0d\x0a減輕影響的因素: \x0d\x0a\x0d\x0a為利用此漏洞,攻擊者可能需要擁有向遠程計算機上的 135 端口發(fā)送精心編造的請求的能力。對于 Intranet 環(huán)境,此端口通常是可以訪問的;但對于通過 Internet 相連的計算機,防火墻通常會封堵 135 端口。如果沒有封堵該端口,或者在 Intranet 環(huán)境中,攻擊者就不需要有任何其他特權。 \x0d\x0a\x0d\x0a最佳做法是封堵所有實際上未使用的 TCP/IP 端口。因此,大多數連接到 Internet 的計算機應當封堵 135 端口。RPC over TCP 不適合在 Internet 這樣存在著危險的環(huán)境中使用。像 RPC over HTTP 這樣更堅實的協(xié)議適用于有潛在危險的環(huán)境。 \x0d\x0a這是一個緩沖區(qū)溢出漏洞。成功利用此漏洞的攻擊者有可能獲得對遠程計算機的完全控制。這可能使攻擊者能夠對服務器隨意執(zhí)行操作,包括更改網頁、重新格式化硬盤或向本地管理員組添加新的用戶。 \x0d\x0a\x0d\x0a要發(fā)動此類攻擊,攻擊者需要能夠向 RPC 服務發(fā)送一條格式不正確的消息,從而造成目標計算機受制于人,攻擊者可以在它上面執(zhí)行任意代碼。 \x0d\x0a\x0d\x0a防范來自 Internet 的遠程 RPC 攻擊的最佳方法是:將防火墻配置為封堵 135 端口。RPC over TCP 不適合在 Internet 這樣存在著危險的環(huán)境中使用。 \x0d\x0a\x0d\x0a此漏洞是由于 Windows RPC 服務在某些情況下不能正確檢查消息輸入而造成的。如果攻擊者在 RPC 建立連接后發(fā)送某種類型的格式不正確的 RPC 消息,則會導致遠程計算機上與 RPC 之間的基礎分布式組件對象模型 (DCOM) 接口出現問題,進而使任意代碼得以執(zhí)行。
創(chuàng)新互聯公司從2013年開始,先為土默特右旗等服務建站,土默特右旗等地企業(yè),進行企業(yè)商務咨詢服務。為土默特右旗企業(yè)網站制作PC+手機+微官網三網同步一站式服務解決您的所有建站問題。
作者 | Python編程時光
責編 | 胡巍巍
什么是RPC呢?百度百科給出的解釋是這樣的:“RPC(Remote Procedure Call Protocol)——遠程過程調用協(xié)議,它是一種通過網絡從遠程計算機程序上請求服務,而不需要了解底層網絡技術的協(xié)議”。
這個概念聽起來還是比較抽象,沒關系,繼續(xù)往后看,后面概念性的東西,我會講得足夠清楚,讓你完全掌握 RPC 的基礎內容。
在 OpenStack 里的進程間通信方式主要有兩種,一種是基于HTTP協(xié)議的RESTFul API方式,另一種則是RPC調用。
那么這兩種方式在應用場景上有何區(qū)別呢?
有使用經驗的人,就會知道:
首先,給你提兩個問題,帶著這兩個問題再往下看:
1、RPC 和 REST 區(qū)別是什么?2、為什么要采用RPC呢?
首先,第一個問題:RPC 和 REST 區(qū)別是什么?
你一定會覺得這個問題很奇怪,是的,包括我,但是你在網絡上一搜,會發(fā)現類似對比的文章比比皆是,我在想可能很多初學者由于基礎不牢固,才會將不相干的二者拿出來對比吧。既然是這樣,那為了讓你更加了解陌生的RPC,就從你熟悉得不能再熟悉的 REST 入手吧。
01、所屬類別不同
REST,是Representational State Transfer 的簡寫,中文描述表述性狀態(tài)傳遞(是指某個瞬間狀態(tài)的資源數據的快照,包括資源數據的內容、表述格式(XML、JSON)等信息。)
REST 是一種軟件架構風格。這種風格的典型應用,就是HTTP。其因為簡單、擴展性強的特點而廣受開發(fā)者的青睞。
而RPC 呢,是 Remote Procedure Call Protocol 的簡寫,中文描述是遠程過程調用,它可以實現客戶端像調用本地服務(方法)一樣調用服務器的服務(方法)。
而 RPC 可以基于 TCP/UDP,也可以基于 HTTP 協(xié)議進行傳輸的,按理說它和REST不是一個層面意義上的東西,不應該放在一起討論,但是誰讓REST這么流行呢,它是目前最流行的一套互聯網應用程序的API設計標準,某種意義下,我們說 REST 可以其實就是指代 HTTP 協(xié)議。
02、使用方式不同
03、面向對象不同
從設計上來看,RPC,所謂的遠程過程調用 ,是面向方法的 ,REST:所謂的 Representational state transfer ,是面向資源的,除此之外,還有一種叫做 SOA,所謂的面向服務的架構,它是面向消息的,這個接觸不多,就不多說了。
04、序列化協(xié)議不同
接口調用通常包含兩個部分,序列化和通信協(xié)議。
通信協(xié)議,上面已經提及了,REST 是 基于 HTTP 協(xié)議,而 RPC 可以基于 TCP/UDP,也可以基于 HTTP 協(xié)議進行傳輸的。
常見的序列化協(xié)議,有:json、xml、hession、protobuf、thrift、text、bytes等,REST 通常使用的是 JSON或者XML,而 RPC 使用的是 JSON-RPC,或者 XML-RPC。
通過以上幾點,我們知道了 REST 和 RPC 之間有很明顯的差異。
然后第二個問題:為什么要采用RPC呢?
那到底為何要使用 RPC,單純的依靠RESTful API不可以嗎?為什么要搞這么多復雜的協(xié)議,渣渣表示真的學不過來了。
關于這一點,以下幾點僅是我的個人猜想,僅供交流哈:
說了這么多,我們該如何選擇這兩者呢?我總結了如下兩點,供你參考:
“遠程調用”意思就是:被調用方法的具體實現不在程序運行本地,而是在別的某個地方(分布到各個服務器),調用者只想要函數運算的結果,卻不需要實現函數的具體細節(jié)。
光說不練嘴把式,接下來,我將分別用三種不同的方式全面地讓你搞明白 rpc 遠程調用是如何實現的。
01、基于 xml-rpc
Python實現 rpc,可以使用標準庫里的 SimpleXMLRPCServer,它是基于XML-RPC 協(xié)議的。
有了這個模塊,開啟一個 rpc server,就變得相當簡單了。執(zhí)行以下代碼:
有了 rpc server,接下來就是 rpc client,由于我們上面使用的是 XML-RPC,所以 rpc clinet 需要使用xmlrpclib 這個庫。
然后,我們通過 server_proxy 對象就可以遠程調用之前的rpc server的函數了。
SimpleXMLRPCServer是一個單線程的服務器。這意味著,如果幾個客戶端同時發(fā)出多個請求,其它的請求就必須等待第一個請求完成以后才能繼續(xù)。
若非要使用 SimpleXMLRPCServer 實現多線程并發(fā),其實也不難。只要將代碼改成如下即可。
02、基于json-rpc
SimpleXMLRPCServer 是基于 xml-rpc 實現的遠程調用,上面我們也提到 除了 xml-rpc 之外,還有 json-rpc 協(xié)議。
那 python 如何實現基于 json-rpc 協(xié)議呢?
答案是很多,很多web框架其自身都自己實現了json-rpc,但我們要獨立這些框架之外,要尋求一種較為干凈的解決方案,我查找到的選擇有兩種
第一種是 jsonrpclib
第二種是 python-jsonrpc
先來看第一種 jsonrpclib
它與 Python 標準庫的 SimpleXMLRPCServer 很類似(因為它的類名就叫做 SimpleJSONRPCServer ,不明真相的人真以為它們是親兄弟)?;蛟S可以說,jsonrpclib 就是仿照 SimpleXMLRPCServer 標準庫來進行編寫的。
它的導入與 SimpleXMLRPCServer 略有不同,因為SimpleJSONRPCServer分布在jsonrpclib庫中。
服務端
客戶端
再來看第二種python-jsonrpc,寫起來貌似有些復雜。
服務端
客戶端
調用過程如下
還記得上面我提到過的 zabbix API,因為我有接觸過,所以也拎出來講講。zabbix API 也是基于 json-rpc 2.0協(xié)議實現的。
因為內容較多,這里只帶大家打個,zabbix 是如何調用的:直接指明要調用 zabbix server 的哪個方法,要傳給這個方法的參數有哪些。
03、基于 zerorpc
以上介紹的兩種rpc遠程調用方式,如果你足夠細心,可以發(fā)現他們都是http+rpc 兩種協(xié)議結合實現的。
接下來,我們要介紹的這種(zerorpc),就不再使用走 http 了。
zerorpc 這個第三方庫,它是基于TCP協(xié)議、 ZeroMQ 和 MessagePack的,速度相對快,響應時間短,并發(fā)高。zerorpc 和 pyjsonrpc 一樣,需要額外安裝,雖然SimpleXMLRPCServer不需要額外安裝,但是SimpleXMLRPCServer性能相對差一些。
調用過程如下
客戶端除了可以使用zerorpc框架實現代碼調用之外,它還支持使用“命令行”的方式調用。
客戶端可以使用命令行,那服務端是不是也可以呢?
是的,通過 Github 上的文檔幾個 demo 可以體驗到這個第三方庫做真的是優(yōu)秀。
比如我們可以用下面這個命令,創(chuàng)建一個rpc server,后面這個 time Python 標準庫中的 time 模塊,zerorpc 會將 time 注冊綁定以供client調用。
經過了上面的學習,我們已經學會了如何使用多種方式實現rpc遠程調用。
通過對比,zerorpc 可以說是脫穎而出,一支獨秀。
為此,我也做了一番思考:
OpenStack 組件繁多,在一個較大的集群內部每個組件內部通過rpc通信頻繁,如果都采用rpc直連調用的方式,連接數會非常地多,開銷大,若有些 server 是單線程的模式,超時會非常的嚴重。
OpenStack 是復雜的分布式集群架構,會有多個 rpc server 同時工作,假設有 server01,server02,server03 三個server,當 rpc client 要發(fā)出rpc請求時,發(fā)給哪個好呢?這是問題一。
你可能會說輪循或者隨機,這樣對大家都公平。這樣的話還會引出另一個問題,倘若請求剛好發(fā)到server01,而server01剛好不湊巧,可能由于機器或者其他因為導致服務沒在工作,那這個rpc消息可就直接失敗了呀。要知道做為一個集群,高可用是基本要求,如果出現剛剛那樣的情況其實是很尷尬的。這是問題二。
集群有可能根據實際需要擴充節(jié)點數量,如果使用直接調用,耦合度太高,不利于部署和生產。這是問題三。
引入消息中間件,可以很好的解決這些問題。
解決問題一:消息只有一份,接收者由AMQP的負載算法決定,默認為在所有Receiver中均勻發(fā)送(round robin)。
解決問題二:有了消息中間件做緩沖站,client 可以任性隨意的發(fā),server 都掛掉了?沒有關系,等 server 正常工作后,自己來消息中間件取就行了。
解決問題三:無論有多少節(jié)點,它們只要認識消息中間件這一個中介就足夠了。
既然講到了消息隊列,如果你之前沒有接觸過這塊內容,最好花幾分鐘的時間跟我好好過下關于消息隊列的幾個基礎概念。
首先,RPC只是定義了一個通信接口,其底層的實現可以各不相同,可以是 socket,也可以是今天要講的 AMQP。
AMQP(Advanced Message Queuing Protocol)是一種基于隊列的可靠消息服務協(xié)議,作為一種通信協(xié)議,AMQP同樣存在多個實現,如Apache Qpid,RabbitMQ等。
以下是 AMQP 中的幾個必知的概念:
Publisher:消息發(fā)布者
Queue:用來保存消息的存儲空間,消息沒有被receiver前,保存在隊列中。
Exchange:用來接收Publisher發(fā)出的消息,根據Routing key 轉發(fā)消息到對應的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進行遠程調用的。如若你對此沒有興趣(我知道很多人對此都沒有興趣,所以不浪費大家時間),可以直接跳過這一節(jié),進入下一節(jié)。
目前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協(xié)議提供慣用的高級接口,使Python中的消息傳遞盡可能簡單,并為常見的消息傳遞問題提供經過驗證和測試的解決方案。)
關于oslo_messaging庫,主要提供了兩種獨立的API:
因為 notify 實現是太簡單了,所以這里我就不多說了,如果有人想要看這方面內容,可以收藏我的博客() ,我會更新補充 notify 的內容。
OpenStack RPC 模塊提供了 rpc.call,rpc.cast, rpc.fanout_cast 三種 RPC 調用方法,發(fā)送和接收 RPC 請求。
rpc.call 和 .rpc.cast 從實現代碼上看,他們的區(qū)別很小,就是call調用時候會帶有wait_for_reply=True參數,而cast不帶。
要了解 rpc 的調用機制呢,首先要知道 oslo_messaging 的幾個概念主要方法有四個:
transport:RPC功能的底層實現方法,這里是rabbitmq的消息隊列的訪問路徑
transport 就是定義你如何訪連接消息中間件,比如你使用的是 Rabbitmq,那在 nova.conf中應該有一行transport_url的配置,可以很清楚地看出指定了 rabbitmq 為消息中間件,并配置了連接rabbitmq的user,passwd,主機,端口。
target用來表述 RPC 服務器監(jiān)聽topic,server名稱和server監(jiān)聽的exchange,是否廣播fanout。
rpc server 要獲取消息,需要定義target,就像一個門牌號一樣。
rpc client 要發(fā)送消息,也需要有target,說明消息要發(fā)到哪去。
endpoints:是可供別人遠程調用的對象
RPC服務器暴露出endpoint,每個 endpoint 包涵一系列的可被遠程客戶端通過 transport 調用的方法。直觀理解,可以參考nova-conductor創(chuàng)建rpc server的代碼,這邊的endpoints就是 nova/manager.py:ConductorManager
dispatcher:分發(fā)器,這是 rpc server 才有的概念
只有通過它 server 端才知道接收到的rpc請求,要交給誰處理,怎么處理?
在client端,是這樣指定要調用哪個方法的。
而在server端,是如何知道要執(zhí)行這個方法的呢?這就是dispatcher 要干的事,它從 endpoint 里找到這個方法,然后執(zhí)行,最后返回。
Serializer:在 python 對象和message(notification) 之間數據做序列化或是反序列化的基類。
主要方法有四個:
每個notification listener都和一個executor綁定,來控制收到的notification如何分配。默認情況下,使用的是blocking executor(具體特性參加executor一節(jié))
模仿是一種很高效的學習方法,我這里根據 OpenStack 的調用方式,抽取出核心內容,寫成一個簡單的 demo,有對 OpenStack 感興趣的可以了解一下,大部分人也可以直接跳過這章節(jié)。
注意以下代碼不能直接運行,你還需要配置 rabbitmq 的連接方式,你可以寫在配置文件中,通過 get_transport 從cfg.CONF 中讀取,也可以直接將其寫成url的格式做成參數,傳給 get_transport 。而且還要nova或者其他openstack組件的環(huán)境中運行(因為需要有ctxt這個環(huán)境變量)
簡單的 rpc client
簡單的 rpc server
【End】
熱 文 推 薦
?Facebook 發(fā)幣 Libra;谷歌十億美金為窮人造房;第四代樹莓派 Raspberry Pi 4 發(fā)布 | 開發(fā)者周刊
?WebRTC 將一統(tǒng)實時音視頻天下?
?小米崔寶秋:小米 AIoT 深度擁抱開源
?華為在美研發(fā)機構 Futurewei 意欲分家?
?老司機教你如何寫出沒人敢維護的代碼!
?Python有哪些技術上的優(yōu)點?比其他語言好在哪兒?
?上不了北大“圖靈”、清華“姚班”,AI專業(yè)還能去哪上?
?公鏈史記 | 從鴻蒙初辟到萬物生長的十年激蕩……
?邊緣計算容器化是否有必要?
?馬云曾經偶像,終于把阿里留下的1400億敗光了!
你點的每個“在看”,我都認真當成了喜歡
切換到新語言始終是一大步,尤其是當您的團隊成員只有一個時有該語言的先前經驗?,F在,Stream 的主要編程語言從 Python 切換到了 Go。這篇文章將解釋stream決定放棄 Python 并轉向 Go 的一些原因。
Go 非???。性能類似于 Java 或 C++。對于用例,Go 通常比 Python 快 40 倍。
對于許多應用程序來說,編程語言只是應用程序和數據庫之間的粘合劑。語言本身的性能通常并不重要。然而,Stream 是一個API 提供商,為 700 家公司和超過 5 億最終用戶提供提要和聊天平臺。多年來,我們一直在優(yōu)化 Cassandra、PostgreSQL、Redis 等,但最終,您會達到所使用語言的極限。Python 是一門很棒的語言,但對于序列化/反序列化、排名和聚合等用例,它的性能相當緩慢。我們經常遇到性能問題,Cassandra 需要 1 毫秒來檢索數據,而 Python 會花費接下來的 10 毫秒將其轉換為對象。
看看我如何開始 Go 教程中的一小段 Go 代碼。(這是一個很棒的教程,也是學習 Go 的一個很好的起點。)
如果您是 Go 新手,那么在閱讀那個小代碼片段時不會有太多讓您感到驚訝的事情。它展示了多個賦值、數據結構、指針、格式和一個內置的 HTTP 庫。當我第一次開始編程時,我一直喜歡使用 Python 更高級的功能。Python 允許您在編寫代碼時獲得相當的創(chuàng)意。例如,您可以:
這些功能玩起來很有趣,但是,正如大多數程序員會同意的那樣,在閱讀別人的作品時,它們通常會使代碼更難理解。Go 迫使你堅持基礎。這使得閱讀任何人的代碼并立即了解發(fā)生了什么變得非常容易。 注意:當然,它實際上有多“容易”取決于您的用例。如果你想創(chuàng)建一個基本的 CRUD API,我仍然推薦 Django + DRF或 Rails。
作為一門語言,Go 試圖讓事情變得簡單。它沒有引入許多新概念。重點是創(chuàng)建一種非??焖偾乙子谑褂玫暮唵握Z言。它唯一具有創(chuàng)新性的領域是 goroutine 和通道。(100% 正確CSP的概念始于 1977 年,所以這項創(chuàng)新更多是對舊思想的一種新方法。)Goroutines 是 Go 的輕量級線程方法,通道是 goroutines 之間通信的首選方式。Goroutines 的創(chuàng)建非常便宜,并且只需要幾 KB 的額外內存。因為 Goroutine 非常輕量,所以有可能同時運行數百甚至數千個。您可以使用通道在 goroutine 之間進行通信。Go 運行時處理所有復雜性。goroutines 和基于通道的并發(fā)方法使得使用所有可用的 CPU 內核和處理并發(fā) IO 變得非常容易——所有這些都不會使開發(fā)復雜化。與 Python/Java 相比,在 goroutine 上運行函數需要最少的樣板代碼。您只需在函數調用前加上關鍵字“go”:
Go 的并發(fā)方法很容易使用。與 Node 相比,這是一種有趣的方法,開發(fā)人員必須密切關注異步代碼的處理方式。Go 中并發(fā)的另一個重要方面是競爭檢測器。這樣可以很容易地確定異步代碼中是否存在任何競爭條件。
我們目前用 Go 編寫的最大的微服務編譯需要 4 秒。與以編譯速度慢而聞名的 Java 和 C++ 等語言相比,Go 的快速編譯時間是一項重大的生產力勝利。我喜歡在程序編譯的時候摸魚,但在我還記得代碼應該做什么的同時完成事情會更好。
首先,讓我們從顯而易見的開始:與 C++ 和 Java 等舊語言相比,Go 開發(fā)人員的數量并不多。根據StackOverflow的數據, 38% 的開發(fā)人員知道 Java, 19.3% 的人知道 C++,只有 4.6% 的人知道 Go。GitHub 數據顯示了類似的趨勢:Go 比 Erlang、Scala 和 Elixir 等語言使用更廣泛,但不如 Java 和 C++ 流行。幸運的是,Go 是一種非常簡單易學的語言。它提供了您需要的基本功能,僅此而已。它引入的新概念是“延遲”聲明和內置的并發(fā)管理與“goroutines”和通道。(對于純粹主義者來說:Go 并不是第一種實現這些概念的語言,只是第一種使它們流行起來的語言。)任何加入團隊的 Python、Elixir、C++、Scala 或 Java 開發(fā)人員都可以在一個月內在 Go 上發(fā)揮作用,因為它的簡單性。與許多其他語言相比,我們發(fā)現組建 Go 開發(fā)人員團隊更容易。如果您在博爾德和阿姆斯特丹等競爭激烈的生態(tài)系統(tǒng)中招聘人員,這是一項重要的優(yōu)勢。
對于我們這樣規(guī)模的團隊(約 20 人)來說,生態(tài)系統(tǒng)很重要。如果您必須重新發(fā)明每一個小功能,您根本無法為您的客戶創(chuàng)造價值。Go 對我們使用的工具有很好的支持。實體庫已經可用于 Redis、RabbitMQ、PostgreSQL、模板解析、任務調度、表達式解析和 RocksDB。與 Rust 或 Elixir 等其他較新的語言相比,Go 的生態(tài)系統(tǒng)是一個重大勝利。它當然不如 Java、Python 或 Node 之類的語言好,但它很可靠,而且對于許多基本需求,你會發(fā)現已經有高質量的包可用。
Gofmt 是一個很棒的命令行實用程序,內置在 Go 編譯器中,用于格式化代碼。就功能而言,它與 Python 的 autopep8 非常相似。我們大多數人并不真正喜歡爭論制表符與空格。格式的一致性很重要,但實際的格式標準并不那么重要。Gofmt 通過使用一種正式的方式來格式化您的代碼來避免所有這些討論。
Go 對協(xié)議緩沖區(qū)和 gRPC 具有一流的支持。這兩個工具非常適合構建需要通過 RPC 通信的微服務。您只需要編寫一個清單,在其中定義可以進行的 RPC 調用以及它們采用的參數。然后從這個清單中自動生成服務器和客戶端代碼。生成的代碼既快速又具有非常小的網絡占用空間并且易于使用。從同一個清單中,您甚至可以為許多不同的語言生成客戶端代碼,例如 C++、Java、Python 和 Ruby。因此,內部流量不再有模棱兩可的 REST 端點,您每次都必須編寫幾乎相同的客戶端和服務器代碼。.
Go 沒有像 Rails 用于 Ruby、Django 用于 Python 或 Laravel 用于 PHP 那樣的單一主導框架。這是 Go 社區(qū)內激烈爭論的話題,因為許多人主張你不應該一開始就使用框架。我完全同意這對于某些用例是正確的。但是,如果有人想構建一個簡單的 CRUD API,他們將更容易使用 Django/DJRF、Rails Laravel 或Phoenix。對于 Stream 的用例,我們更喜歡不使用框架。然而,對于許多希望提供簡單 CRUD API 的新項目來說,缺乏主導框架將是一個嚴重的劣勢。
Go 通過簡單地從函數返回錯誤并期望調用代碼來處理錯誤(或將其返回到調用堆棧)來處理錯誤。雖然這種方法有效,但很容易失去問題的范圍,以確保您可以向用戶提供有意義的錯誤。錯誤包通過允許您向錯誤添加上下文和堆棧跟蹤來解決此問題。另一個問題是很容易忘記處理錯誤。像 errcheck 和 megacheck 這樣的靜態(tài)分析工具可以方便地避免犯這些錯誤。雖然這些變通辦法效果很好,但感覺不太對勁。您希望該語言支持正確的錯誤處理。
Go 的包管理絕不是完美的。默認情況下,它無法指定特定版本的依賴項,也無法創(chuàng)建可重現的構建。Python、Node 和 Ruby 都有更好的包管理系統(tǒng)。但是,使用正確的工具,Go 的包管理工作得很好。您可以使用Dep來管理您的依賴項,以允許指定和固定版本。除此之外,我們還貢獻了一個名為的開源工具VirtualGo,它可以更輕松地處理用 Go 編寫的多個項目。
我們進行的一個有趣的實驗是在 Python 中使用我們的排名提要功能并在 Go 中重寫它。看看這個排名方法的例子:
Python 和 Go 代碼都需要執(zhí)行以下操作來支持這種排名方法:
開發(fā) Python 版本的排名代碼大約花了 3 天時間。這包括編寫代碼、單元測試和文檔。接下來,我們花了大約 2 周的時間優(yōu)化代碼。其中一項優(yōu)化是將分數表達式 (simple_gauss(time)*popularity) 轉換為抽象語法樹. 我們還實現了緩存邏輯,可以在未來的特定時間預先計算分數。相比之下,開發(fā)此代碼的 Go 版本大約需要 4 天時間。性能不需要任何進一步的優(yōu)化。因此,雖然 Python 的最初開發(fā)速度更快,但基于 Go 的版本最終需要我們團隊的工作量大大減少。另外一個好處是,Go 代碼的執(zhí)行速度比我們高度優(yōu)化的 Python 代碼快大約 40 倍?,F在,這只是我們通過切換到 Go 體驗到的性能提升的一個示例。
與 Python 相比,我們系統(tǒng)的其他一些組件在 Go 中構建所需的時間要多得多。作為一個總體趨勢,我們看到 開發(fā) Go 代碼需要更多的努力。但是,我們花更少的時間 優(yōu)化 代碼以提高性能。
我們評估的另一種語言是Elixir.。Elixir 建立在 Erlang 虛擬機之上。這是一種迷人的語言,我們之所以考慮它,是因為我們的一名團隊成員在 Erlang 方面擁有豐富的經驗。對于我們的用例,我們注意到 Go 的原始性能要好得多。Go 和 Elixir 都可以很好地服務數千個并發(fā)請求。但是,如果您查看單個請求的性能,Go 對于我們的用例來說要快得多。我們選擇 Go 而不是 Elixir 的另一個原因是生態(tài)系統(tǒng)。對于我們需要的組件,Go 有更成熟的庫,而在許多情況下,Elixir 庫還沒有準備好用于生產環(huán)境。培訓/尋找開發(fā)人員使用 Elixir 也更加困難。這些原因使天平向 Go 傾斜。Elixir 的 Phoenix 框架看起來很棒,絕對值得一看。
Go 是一種非常高性能的語言,對并發(fā)有很好的支持。它幾乎與 C++ 和 Java 等語言一樣快。雖然與 Python 或 Ruby 相比,使用 Go 構建東西確實需要更多時間,但您將節(jié)省大量用于優(yōu)化代碼的時間。我們在Stream有一個小型開發(fā)團隊,為超過 5 億最終用戶提供動力和聊天。Go 結合了 強大的生態(tài)系統(tǒng) 、新開發(fā)人員的 輕松入門、快速的性能 、對并發(fā)的 可靠支持和高效的編程環(huán)境 ,使其成為一個不錯的選擇。Stream 仍然在我們的儀表板、站點和機器學習中利用 Python 來提供個性化的訂閱源. 我們不會很快與 Python 說再見,但今后所有性能密集型代碼都將使用 Go 編寫。我們新的聊天 API也完全用 Go 編寫。
智能合約調用是實現一個 DApp 的關鍵,一個完整的 DApp 包括前端、后端、智能合約及區(qū)塊 鏈系統(tǒng),智能合約的調用是連接區(qū)塊鏈與前后端的關鍵。
我們先來了解一下智能合約調用的基礎原理。智能合約運行在以太坊節(jié)點的 EVM 中。因此要 想調用合約必須要訪問某個節(jié)點。
以后端程序為例,后端服務若想連接節(jié)點有兩種可能,一種是雙 方在同一主機,此時后端連接節(jié)點可以采用 本地 IPC(Inter-Process Communication,進 程間通信)機制,也可以采用 RPC(Remote Procedure Call,遠程過程調用)機制;另 一種情況是雙方不在同一臺主機,此時只能采用 RPC 機制進行通信。
提到 RPC, 讀者應該對 Geth 啟動參數有點印象,Geth 啟動時可以選擇開啟 RPC 服務,對應的 默認服務端口是 8545。。
接著,我們來了解一下智能合約運行的過程。
智能合約的運行過程是后端服務連接某節(jié)點,將 智能合約的調用(交易)發(fā)送給節(jié)點,節(jié)點在驗證了交易的合法性后進行全網廣播,被礦工打包到 區(qū)塊中代表此交易得到確認,至此交易才算完成。
就像數據庫一樣,每個區(qū)塊鏈平臺都會提供主流 開發(fā)語言的 SDK(Software Development Kit,軟件開發(fā)工具包),由于 Geth 本身就是用 Go 語言 編寫的,因此若想使用 Go 語言連接節(jié)點、發(fā)交易,直接在工程內導入 go-ethereum(Geth 源碼) 包就可以了,剩下的問題就是流程和 API 的事情了。
總結一下,智能合約被調用的兩個關鍵點是節(jié)點和 SDK。
由于 IPC 要求后端與節(jié)點必須在同一主機,所以很多時候開發(fā)者都會采用 RPC 模式。除了 RPC,以太坊也為開發(fā)者提供了 json- rpc 接口,本文就不展開討論了。
接下來介紹如何使用 Go 語言,借助 go-ethereum 源碼庫來實現智能合約的調用。這是有固定 步驟的,我們先來說一下總體步驟,以下面的合約為例。
步驟 01:編譯合約,獲取合約 ABI(Application Binary Interface,應用二進制接口)。 單擊【ABI】按鈕拷貝合約 ABI 信息,將其粘貼到文件 calldemo.abi 中(可使用 Go 語言IDE 創(chuàng)建該文件,文件名可自定義,后綴最好使用 abi)。
最好能將 calldemo.abi 單獨保存在一個目錄下,輸入“l(fā)s”命令只能看到 calldemo.abi 文件,參 考效果如下:
步驟 02:獲得合約地址。注意要將合約部署到 Geth 節(jié)點。因此 Environment 選擇為 Web3 Provider。
在【Environment】選項框中選擇“Web3 Provider”,然后單擊【Deploy】按鈕。
部署后,獲得合約地址為:0xa09209c28AEf59a4653b905792a9a910E78E7407。
步驟 03:利用 abigen 工具(Geth 工具包內的可執(zhí)行程序)編譯智能合約為 Go 代碼。abigen 工具的作用是將 abi 文件轉換為 Go 代碼,命令如下:
其中各參數的含義如下。 (1)abi:是指定傳入的 abi 文件。 (2)type:是指定輸出文件中的基本結構類型。 (3)pkg:指定輸出文件 package 名稱。 (4)out:指定輸出文件名。 執(zhí)行后,將在代碼目錄下看到 funcdemo.go 文件,讀者可以打開該文件欣賞一下,注意不要修改它。
步驟 04:創(chuàng)建 main.go,填入如下代碼。 注意代碼中 HexToAddress 函數內要傳入該合約部署后的地址,此地址在步驟 01 中獲得。
步驟 04:設置 go mod,以便工程自動識別。
前面有所提及,若要使用 Go 語言調用智能合約,需要下載 go-ethereum 工程,可以使用下面 的指令:
該指令會自動將 go-ethereum 下載到“$GOPATH/src/github.com/ethereum/go-ethereum”,這樣還算 不錯。不過,Go 語言自 1.11 版本后,增加了 module 管理工程的模式。只要設置好了 go mod,下載 依賴工程的事情就不必關心了。
接下來設置 module 生效和 GOPROXY,命令如下:
在項目工程內,執(zhí)行初始化,calldemo 可以自定義名稱。
步驟 05:運行代碼。執(zhí)行代碼,將看到下面的效果,以及最終輸出的 2020。
上述輸出信息中,可以看到 Go 語言會自動下載依賴文件,這就是 go mod 的神奇之處??吹?2020,相信讀者也知道運行結果是正確的了。
RPC是遠程過程調用(Remote Procedure Call)的縮寫形式。SAP系統(tǒng)RPC調用的原理其實很簡單,有一些類似于三層構架的C/S系統(tǒng),第三方的客戶程序通過接口調用SAP內部的標準或自定義函數,獲得函數返回的數據進行處理后顯示或打印。
進程間通信(IPC)在多任務操作系統(tǒng)或聯網的計算機之間運行的程序和進程所用的通信技術。有兩種類型的進程間通信(IPC)。
本地過程調用(LPC)LPC用在多任務操作系統(tǒng)中,使得同時運行的任務能互相會話。這些任務共享內存空間使任務同步和互相發(fā)送信息。遠程過程調用(RPC)RPC類似于LPC,只是在網上工作。RPC開始是出現在Sun微系統(tǒng)公司和HP公司的運行UNⅨ操作系統(tǒng)的計算機中。
擴展資料
通過IPC和RPC,程序能利用其它程序或計算機處理的進程??蛻魴C/服務器模式計算把遠程過程調用與其它技術(如消息傳遞)一道,作為系統(tǒng)間通信的一種機制??蛻魴C執(zhí)行自己的任務,但靠服務器提供后端文件服務。
RPC為客戶機提供向后端服務器申請服務的通信機制,如圖R-4所示。如果你把客戶機/服務器應用程序想作是一個分離的程序,服務器能運行數據訪問部分,因為它離數據最近,客戶機能運行數據表示和與用戶交互的前端部分。這樣,遠程過程調用可看作是把分割的程序通過網絡重組的部件。LPC有時也稱耦合(Coupling)機制。
用這種方式分割程序,當用戶要訪問數據時就無需每次拷貝整個數據庫或它的大部分程序到用戶系統(tǒng)。其實,服務器只處理請求,甚至只執(zhí)行一些數據計算,把得出的結果再發(fā)送給用戶。因為當數據存放在一個地方時,數據庫同步很容易實現,所以多個用戶可同時訪問相同的數據。
分布式計算環(huán)境是由一個通信系統(tǒng)——網絡連接的計算機集群。很容易把這個網絡看成一個計算平臺,若是對等方式,其中任何一臺計算機都能成為客戶機或服務器。
一些處理任務可被分成獨立運行程序在不同的網絡計算機上并行處理,而獨立的程序被交給最適合這個任務的計算機處理。這種策略可利用計算機空閑資源,提高網絡的效益。一個典型的企業(yè)網包括許多運行著不同操作系統(tǒng)的異構計算機系統(tǒng)。
直接調用so的函數cgo應該繞不開吧,我寫過一個銀行的應用程序調用其特色業(yè)務接口,因為接口只支持c和java,我就封裝了一個c的so,然后用cgo調用后寫了一個RPC供遠程的go語言調用,因為RPC只負責信息交互不負責業(yè)務邏輯,所以寫了不到百行,以后基本不用再改。記住雖然go語言自帶gc,但cgo還是要手工釋放內存哦。