<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          「GoCN酷Go推薦」Go原生RPC與ARPC的簡(jiǎn)單使用

          共 3796字,需瀏覽 8分鐘

           ·

          2021-10-13 02:52

          什么是 RPC?


          RPC叫做遠(yuǎn)程過(guò)程調(diào)用,意思是兩臺(tái)不同服務(wù)器上的服務(wù),可以互相像調(diào)用函數(shù)一樣調(diào)用。

          我用HTTP API不一樣能達(dá)到同樣的效果嗎?


          其實(shí)對(duì)于新人來(lái)說(shuō),兩臺(tái)服務(wù)器之間的數(shù)據(jù)交互,用HTTP提供的API真的可以解決,但效率不高,延遲也高,且連接不會(huì)復(fù)用,因?yàn)榇蠹叶贾繦TTP是無(wú)狀態(tài)傳輸協(xié)議,每次傳輸都不知道對(duì)方是誰(shuí),因此,體現(xiàn)在以下方面:

          • 每次要獲取數(shù)據(jù)前,都會(huì)進(jìn)行三次握手確認(rèn)與四次揮手的過(guò)程。
          • 不能建立長(zhǎng)連接進(jìn)行通信,多次請(qǐng)求
          • 數(shù)據(jù)轉(zhuǎn)換效率低,無(wú)論是使用form表單或者json傳輸,都不如直接傳輸二進(jìn)制數(shù)據(jù)來(lái)得快,序列化與反序列化資源占用高

          快速使用原生RPC


          首先通訊雙方都應(yīng)擁有同樣結(jié)構(gòu)體,所以服務(wù)端與客戶端都創(chuàng)建創(chuàng)建 go_rpc -----> RpcParams.go:

          package?go_rpc

          type?MyWayRpc?struct{?//?客戶端要傳輸?shù)臄?shù)據(jù),也是服務(wù)端要接收的數(shù)據(jù)
          ???Name?string
          ???Age?int
          }

          type?MyWayRpcReply?struct{?//?服務(wù)端要返回的數(shù)據(jù),也是客戶端想要獲得的結(jié)果
          ???SystemInfo?string
          }

          服務(wù)端編寫(xiě)main.go文件 :

          package?main

          import?(
          ???"go_rpc"
          ???"fmt"
          ???"log"
          ???"net"
          ???"net/rpc"
          ???"runtime"
          )

          //?其實(shí)按照web?api中,我們應(yīng)當(dāng)把TakeMyWayRpc結(jié)構(gòu)體和?GetSystem方法寫(xiě)在單獨(dú)的控制器中,這里為了代碼演示就寫(xiě)在main包下了

          type?TakeMyWayRpc?struct{}

          func?(t?TakeMyWayRpc)?GetSystem(arg?*go_rpc.MyWayRpc,?result?*go_rpc.MyWayRpcReply)?error?{
          ???fmt.Println("客戶端發(fā)送了:",arg.Name,arg.Age)
          ???//返回給服務(wù)端的
          ???result.SystemInfo?=?runtime.GOOS
          ???return?nil
          }

          func?main()?{
          ???tmwr?:=?new(TakeMyWayRpc)
          ???err?:=?rpc.Register(tmwr)?//?注冊(cè)RPC可以一次性注冊(cè)多個(gè)RPC服務(wù),可以用FOR注冊(cè)多個(gè)結(jié)構(gòu)體,用web?api的話就是注冊(cè)多個(gè)控制器
          ???if?err?!=nil{
          ??????log.Fatalln("注冊(cè)方法時(shí)出現(xiàn)問(wèn)題:",err)
          ???}
          ???l,?err?:=?net.Listen("tcp",?":30001")?//?從這里就可以看出,實(shí)際上RPC的底層也是基于TCP鏈接的,我們這里開(kāi)放30001端口,供客戶端連入
          ???defer?l.Close()
          ???if?err?!=?nil?{
          ??????fmt.Println("監(jiān)聽(tīng)失敗,端口可能已經(jīng)被占用")
          ???}
          ???fmt.Println("正在監(jiān)聽(tīng)30001端口")
          ???for?{
          ??????var?conn?net.Conn
          ??????conn,?err?=?l.Accept()
          ??????if?err?!=nil{
          ?????????log.Fatalln("創(chuàng)建句柄失敗")
          ??????}
          ??????go?rpc.ServeConn(conn)
          ???}
          }

          開(kāi)始在另外一臺(tái)服務(wù)器上寫(xiě)客戶端的main.go:

          package?main

          import?(
          ???"go_rpc"
          ???"log"
          ???"net/rpc"
          )

          func?main()?{
          ???client?,?err?:=?rpc.Dial("tcp","服務(wù)端IP:30001")
          ???if?err?!=nil{
          ??????log.Fatalln("這里試試用錯(cuò)誤的東西:",err)
          ???}
          ???defer?client.Close()

          ???var?myWayRpcArg?go_rpc.MyWayRpc?//?初始化客戶端要發(fā)送的內(nèi)容
          ???var?myWayRpcReply?go_rpc.MyWayRpcReply?//?初始化服務(wù)端要返回的內(nèi)容
          ?
          ???//?填客戶端要發(fā)送的內(nèi)容
          ???myWayRpcArg.Name?=?"安彥飛啊"
          ???myWayRpcArg.Age?=?31

          ???if?err?=?client.Call("TakeMyWayRpc.GetSystem",myWayRpcArg,&myWayRpcReply);err?!=nil{?//?直接開(kāi)始發(fā)送給服務(wù)端,并獲得服務(wù)端的響應(yīng)
          ??????log.Fatalln("返回服務(wù)端數(shù)據(jù)錯(cuò)誤:",err)
          ???}
          ???log.Println("返回成功,",myWayRpcReply)
          }

          RPC演示:

          為什么需要APRC:


          很好,通過(guò)上面的例子,已經(jīng)可以寫(xiě)出RPC的信息交互了,但如果遇到需要服務(wù)端主動(dòng)給客戶端發(fā)消息,客戶端異步調(diào)用服務(wù)端的函數(shù),這些就不是原生RPC能夠做到的了

          我們做一個(gè)ARPC的簡(jiǎn)單示例:


          使用ARPC前應(yīng)當(dāng)先:

          go?get?github.com/lesismal/arpc

          其實(shí)ARPC看上去更像是服務(wù)端定義了一個(gè)ROUTER,客戶端去根據(jù)路由尋址找到了這個(gè)函數(shù)

          首先還是看服務(wù)端的實(shí)現(xiàn),服務(wù)端main.go如下:

          package?main

          import?(
          ?"github.com/lesismal/arpc"
          ?"log"
          ?"runtime"
          )

          func?main()?{
          ?server?:=?arpc.NewServer()
          ?registerHandler?:=?server.Handler

          ?testStruct?:=?new(TestArpcStruct)

          ?registerHandler.Handle(?//?若這里有多個(gè),就像寫(xiě)router
          ???"/TestArpcStruct.GetSystem",
          ??testStruct.GetSystem,
          ??)
          ?server.Run(":8888")
          }

          type?TestArpcStruct?struct{}

          func?(TestArpcStruct)?GetSystem(ctx?*arpc.Context)??{
          ?var?str?string
          ?if?err?:=?ctx.Bind(&str);err?==nil{
          ??log.Println(str)
          ??ctx.Write(runtime.GOOS)
          ?}
          }

          然后寫(xiě)客戶端的代碼:

          package?main

          import?(
          ?"github.com/lesismal/arpc"
          ?"log"
          ?"net"
          ?"time"
          )

          func?main()?{
          ?client?,?err?:=?arpc.NewClient(func()?(net.Conn,?error)?{
          ??return?net.DialTimeout("tcp","localhost:8888",3?*?time.Second)
          ?})
          ?if?err?!=nil{
          ??panic(err)
          ?}
          ?defer?client.Stop()

          ?req?:=?"hello"
          ?resp?:=?""
          ?err??=?client.Call("/TestArpcStruct.GetSystem",&req,&resp,5?*?time.Second)
          ?if?err?!=?nil?{
          ??log.Fatalf("Call?failed:?%v",?err)
          ?}?else?{
          ??log.Printf("Call?Response:?\"%v\"",?resp)
          ?}
          }

          最后也能和RPC一樣,得到東西:

          客戶端發(fā)出hello,服務(wù)端str獲得了hello并打印,且像客戶端發(fā)送了當(dāng)前服務(wù)器的運(yùn)行系統(tǒng)名runtime.GOOS,客戶端:Call Response : windows/linux 這樣的結(jié)果

          總結(jié)


          其實(shí)ARPC還有很多其他功能,比如還可以提供給WS的調(diào)用方法等,官方壓測(cè)后性能與RPC幾乎持平,甚至比RPC更高。

          我們?cè)谑褂靡豁?xiàng)新技術(shù)之前,一定要弄明白這項(xiàng)新技術(shù)為什么會(huì)被發(fā)明出來(lái),解決了什么痛點(diǎn),提升了怎樣的性能,努力思考實(shí)際應(yīng)用場(chǎng)景在哪里,比如ARPC可以用到即時(shí)通訊,可以復(fù)用連接池,不用資源一直申請(qǐng)與釋放,監(jiān)控?cái)?shù)據(jù)的實(shí)時(shí)展示等。

          參考鏈接


          https://github.com/lesismal/arpc


          《酷Go推薦》招募:


          各位Gopher同學(xué),最近我們社區(qū)打算推出一個(gè)類(lèi)似GoCN每日新聞的新欄目《酷Go推薦》,主要是每周推薦一個(gè)庫(kù)或者好的項(xiàng)目,然后寫(xiě)一點(diǎn)這個(gè)庫(kù)使用方法或者優(yōu)點(diǎn)之類(lèi)的,這樣可以真正的幫助到大家能夠?qū)W習(xí)到

          新的庫(kù),并且知道怎么用。


          大概規(guī)則和每日新聞?lì)愃疲绻麍?bào)名人多的話每個(gè)人一個(gè)月輪到一次,歡迎大家報(bào)名!戳「閱讀原文」,即可報(bào)名


          掃碼也可以加入 GoCN 的大家族喲~



          瀏覽 69
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  狠狠干狠狠撸 | 国内色情一级视频 | 久久国产高清视频免费看 | 国产成人精品一区二区三区四区五区 | 日本黄在线观看 |