Go 原生 RPC 與 APRC 的簡單使用
Go 原生 RPC 與 ARPC 的簡單使用
什麼是 RPC?
RPC 叫做遠端過程呼叫,意思是兩臺不同伺服器上的服務,可以互相像呼叫函式一樣呼叫。
我用 HTTP API 不一樣能達到同樣的效果嗎?
其實對於新人來說,兩臺伺服器之間的資料互動,用 HTTP 提供的 API 真的可以解決,但效率不高,延遲也高,且連線不會複用,因為大家都知道 HTTP 是無狀態傳輸協議,每次傳輸都不知道對方是誰,因此,體現在以下方面:
- 每次要獲取資料前,都會進行三次握手確認與四次揮手的過程。
- 不能建立長連線進行通訊,多次請求
- 資料轉換效率低,無論是使用 form 表單或者 json 傳輸,都不如直接傳輸二進位制資料來得快,序列化與反序列化資源佔用高
快速使用原生 RPC
首先通訊雙方都應擁有同樣結構體,所以服務端與客戶端都建立建立 go_rpc -----> RpcParams.go:
package go_rpc
type MyWayRpc struct{ // 客戶端要傳輸的資料,也是服務端要接收的資料
Name string
Age int
}
type MyWayRpcReply struct{ // 服務端要返回的資料,也是客戶端想要獲得的結果
SystemInfo string
}
服務端編寫 main.go 檔案 :
package main
import (
"go_rpc"
"fmt"
"log"
"net"
"net/rpc"
"runtime"
)
// 其實按照web api中,我們應當把TakeMyWayRpc結構體和 GetSystem方法寫在單獨的控制器中,這裡為了程式碼演示就寫在main包下了
type TakeMyWayRpc struct{}
func (t TakeMyWayRpc) GetSystem(arg *go_rpc.MyWayRpc, result *go_rpc.MyWayRpcReply) error {
fmt.Println("客戶端傳送了:",arg.Name,arg.Age)
//返回給服務端的
result.SystemInfo = runtime.GOOS
return nil
}
func main() {
tmwr := new(TakeMyWayRpc)
err := rpc.Register(tmwr) // 註冊RPC可以一次性註冊多個RPC服務,可以用FOR註冊多個結構體,用web api的話就是註冊多個控制器
if err !=nil{
log.Fatalln("註冊方法時出現問題:",err)
}
l, err := net.Listen("tcp", ":30001") // 從這裡就可以看出,實際上RPC的底層也是基於TCP連結的,我們這裡開放30001埠,供客戶端連入
defer l.Close()
if err != nil {
fmt.Println("監聽失敗,埠可能已經被佔用")
}
fmt.Println("正在監聽30001埠")
for {
var conn net.Conn
conn, err = l.Accept()
if err !=nil{
log.Fatalln("建立控制程式碼失敗")
}
go rpc.ServeConn(conn)
}
}
開始在另外一臺伺服器上寫客戶端的 main.go:
package main
import (
"go_rpc"
"log"
"net/rpc"
)
func main() {
client , err := rpc.Dial("tcp","服務端IP:30001")
if err !=nil{
log.Fatalln("這裡試試用錯誤的東西:",err)
}
defer client.Close()
var myWayRpcArg go_rpc.MyWayRpc // 初始化客戶端要傳送的內容
var myWayRpcReply go_rpc.MyWayRpcReply // 初始化服務端要返回的內容
// 填客戶端要傳送的內容
myWayRpcArg.Name = "安彥飛啊"
myWayRpcArg.Age = 31
if err = client.Call("TakeMyWayRpc.GetSystem",myWayRpcArg,&myWayRpcReply);err !=nil{ // 直接開始傳送給服務端,並獲得服務端的響應
log.Fatalln("返回服務端資料錯誤:",err)
}
log.Println("返回成功,",myWayRpcReply)
}
RPC 演示:
為什麼需要 APRC:
很好,通過上面的例子,已經可以寫出 RPC 的資訊互動了,但如果遇到需要服務端主動給客戶端發訊息,客戶端非同步呼叫服務端的函式,這些就不是原生 RPC 能夠做到的了
我們做一個 ARPC 的簡單示例:
使用 ARPC 前應當先:
go get github.com/lesismal/arpc
其實 ARPC 看上去更像是服務端定義了一個 ROUTER,客戶端去根據路由定址找到了這個函式
首先還是看服務端的實現,服務端 main.go 如下:
package main
import (
"github.com/lesismal/arpc"
"log"
"runtime"
)
func main() {
server := arpc.NewServer()
registerHandler := server.Handler
testStruct := new(TestArpcStruct)
registerHandler.Handle( // 若這裡有多個,就像寫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)
}
}
然後寫客戶端的程式碼:
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 一樣,得到東西:
客戶端發出 hello,服務端 str 獲得了 hello 並列印,且像客戶端傳送了當前伺服器的執行系統名 runtime.GOOS,客戶端:Call Response : windows/linux 這樣的結果
總結
其實 ARPC 還有很多其他功能,比如還可以提供給 WS 的呼叫方法等,官方壓測後效能與 RPC 幾乎持平,甚至比 RPC 更高。
我們在使用一項新技術之前,一定要弄明白這項新技術為什麼會被發明出來,解決了什麼痛點,提升了怎樣的效能,努力思考實際應用場景在哪裡,比如 ARPC 可以用到即時通訊,可以複用連線池,不用資源一直申請與釋放,監控資料的實時展示等。
參考連結
https://github.com/lesismal/arpc
- 加微信實戰群請加微信(註明:實戰群):gocnio
相關文章
- Java使用Netty實現簡單的RPCJavaNettyRPC
- golang如何使用原生RPC及微服務簡述GolangRPC微服務
- rpc的正確開啟方式|讀懂Go原生net/rpc包RPCGo
- 手寫簡單的RPCRPC
- Java 簡單的rpc 一JavaRPC
- RPC簡單介紹RPC
- Go 實現簡易 RPC 框架GoRPC框架
- netty 實現簡單的rpc呼叫NettyRPC
- webase go-sdk 簡單使用WebGo
- go語言實現自己的RPC:go rpc codecGoRPC
- Go標準包——net/rpc包的使用GoRPC
- 使用Netty和動態代理實現一個簡單的RPCNettyRPC
- 徒手擼一個簡單的RPC框架RPC框架
- Go RpcGoRPC
- RPC模式的介紹以及簡單的實現RPC模式
- 使用原生 cookieStore 方法,讓 Cookie 操作更簡單Cookie
- RediSearch的簡單使用與總結Redis
- SparkSQL部署與簡單使用SparkSQL
- 配置中心之Nacos簡介,使用及Go簡單整合Go
- 自己用 Netty 實現一個簡單的 RPCNettyRPC
- channel的單向用法與select,range簡單使用
- 簡單的 Go 入門教程Go
- go-zero學習之訂單rpc服務GoRPC
- twirp: 支援protobuf服務定義的簡單RPC框架RPC框架
- JDBC入門與簡單使用JDBC
- 使用 Go 語言實現簡單的文字識別(OCR)Go
- 使用frida rpc不還原token演算法抓取APP最簡單的Hook方法RPC演算法APPHook
- Go 世界如此簡單!Go
- 原生小程式最最簡單的分享功能
- Mac下PostgreSQL的安裝與簡單使用MacSQL
- 關於 RabbitMQ 的安裝與簡單使用MQ
- python的下載安裝與簡單使用Python
- 從零開始實現簡單 RPC 框架 1:RPC 框架的結構和設計RPC框架
- 原生Ajax的簡單使用:XMLHttpRequest物件,方法,屬性,HelloWorld,資料格式XMLHTTP物件
- [譯] 如何使用原生 JavaScript 構建簡單的 Chrome 擴充套件程式JavaScriptChrome套件
- 基於 Hyperf 的 RPC 簡單微服務架構試探RPC微服務架構
- Go的第一個Hello程式 簡簡單單 - 快快樂樂Go
- 簡單易懂的 Go 泛型使用和實現原理介紹Go泛型