重學(xué)Go語言之如何開發(fā)RPC應(yīng)用
對RPC的理解
什么是RPC
RPC
是Remote Procedure Call
的縮寫,中文譯為遠程過程調(diào)用,通俗一點來說就是通過網(wǎng)絡(luò)調(diào)用部署在遠程服務(wù)器上的函數(shù)或方法,如下圖所示:
RPC與HTTP
談到RPC
,往往會讓人聯(lián)想到另一種調(diào)用遠程服務(wù)的方式:HTTP
。
那為什么有了HTTP
,還需要RPC
呢?
其實使用RPC
在不同主機進程間通訊的時間要早于HTTP
出現(xiàn)的時間。
因此,應(yīng)該這么問:既然有了RPC
為何還需要HTTP
呢?
我們知道,任何網(wǎng)絡(luò)應(yīng)用程序之間通訊都是基于TCP
協(xié)議(當(dāng)然可以是UDP
)。
TCP
是傳輸層協(xié)議,其作用之一便是將從網(wǎng)絡(luò)層接收的數(shù)據(jù)傳給應(yīng)用層。
HTTP
是一個應(yīng)用層協(xié)議,HTTP
協(xié)議規(guī)定一條HTTP
報文由請求行、請求頭和消息體組成,因此每條HTTP
報文都有固定的格式。
使用RPC
的方式進行通訊時,傳輸層依然是TCP
協(xié)議,但是應(yīng)用層則需要通訊雙方約定好數(shù)據(jù)格式,相當(dāng)于自定義一個應(yīng)用層協(xié)議,因此RPC
有各種不同的實現(xiàn),并沒有統(tǒng)一的規(guī)范。
gRPC框架的使用
gRPC
是一個高性能開源的RPC
框架,支持Go
,C++
,Java
,PHP
,Ruby
,Python
等不同編程語言。
圖片來自于grpc官網(wǎng)
Protocol Buffers
Protocol Buffers
是Google
開發(fā)的一種與語言、平臺無關(guān)的數(shù)據(jù)序列化機制,這種機制由幾個部分組成:
protoc
編譯器,用于編譯.proto
文件。- 以
.proto
為后綴的IDL
聲明文件,用于定義一個RPC
服務(wù)。 - 底層支持通訊并進行編碼與解碼的庫。
Protocal Buffers
有以下幾個特征:
Protocal Buffers
和JSON
類似,用于序列化數(shù)據(jù),不過與比于JSON
其體積更小,因此傳輸也更快。- 支持多種編程語言。
- 可以非常快速傳輸與解析。
.proto文件
.proto
文件用于聲明使用gRPC
進行通訊服務(wù)名稱、請求數(shù)據(jù)類型、順序與響應(yīng)數(shù)據(jù)類型、順序等信息。
.proto
文件的第一行必須是:
syntax = "proto3";
如果沒有聲明為proto3
,編譯器會以proto2
的語法解析.proto
文件。
message
關(guān)鍵字用于定義一個消息類型:
message SearchRequest { string query = 1; int32 page_number = 2; int32 results_per_page = 3; }
同一個.proto
文件里可以定義多個消息類型:
message SearchRequest { string query = 1; int32 page_number = 2; int32 results_per_page = 3; } message SearchResponse { //... }
service
關(guān)鍵字用于聲明一個服務(wù),格式如下:
service Search { rpc Search (SearchRequest) returns (SearchReply) {} }
編寫好的.proto
文件,要使用protoc
編譯進行編譯,生成目標語言的代碼。
開發(fā)工具安裝
當(dāng)然在開發(fā)之前,除了安裝Go語言環(huán)境外,還需要安裝以下幾個工具:
- protoc
- protoc-gen-go
- protoc-gen-go-grpc
protoc
protoc
是.proto
文件的編譯器,其作用是將.proto
文件中聲明的信息轉(zhuǎn)為目標語言的代碼。
protoc
可以從以下地址下載:https://github.com/protocolbuffers/protobuf/releases
下載后,將其配置到PATH
路徑下即可。
protoc-gen-go與protoc-gen-go-grpc
如果要protoc
編譯器可以生成go
代碼,還需要安裝protoc-gen-go
和protoc-gen-go-grpc
插件。
protoc-gen-go
與protoc-gen-go-grpc
插件用于生成go
以及grpc
代碼,這兩個插件由protoc
命令調(diào)用。
使用go install
將兩個命令安裝到GOPATH/bin
目錄下:
$?go?install?google.golang.org/protobuf/cmd/protoc-gen-go@latest $?go?install?google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
GOPATH/bin目錄要配置到PATH目錄下
案例實戰(zhàn)
安裝了相關(guān)工具以及了解了Protocol Buffers
與.proto
文件,下面我們通過一個實際案例來了解RPC
應(yīng)用的開發(fā)。
創(chuàng)建項目
首先執(zhí)行以下命令創(chuàng)建一個Go項目:
$?mkdir?test $?cd?test $?go?mod?init?test
定義.proto文件
用gRPC
開發(fā)RPC
應(yīng)用的第一件事就是定義.proto
文件,在這個項目中,我們在user
目錄下創(chuàng)建user.proto
文件:
$?mkdir?user $?touch?user.proto
在user.proto
文件中輸入以下代碼:
syntax = "proto3"; option go_package = "test/user"; //定義兩個服務(wù) service User { rpc GetUser (UserId) returns (UserInfoReply) {} rpc AddUser (AddUserRequest) returns(UserId){} } message UserId { int32 id = 1; } message UserInfoReply { int32 id = 1; string name = 2; string email = 3; } message AddUserRequest { string name = 1; string email = 2; }
編譯.proto文件:
.proto
文件編寫完成后,執(zhí)行protoc
命令編譯該文件,生成目標語言代碼:
protoc?--go_out=.?--go_opt=paths=source_relative?\ ????--go-grpc_out=.?--go-grpc_opt=paths=source_relative?\ ????user/user.proto
編譯成功后會在user
目錄生成user.pb.go
和user_grpc.pb.go
兩個文件。
編寫服務(wù)端代碼
下面是gRPC
應(yīng)用的服務(wù)端代碼:
package?main import?( ?"context" ?"log" ?"net" ?"test/user" ?"google.golang.org/grpc" ) type?userServer?struct?{ ?user.UnimplementedUserServer } //[1] func?(s?*userServer)?GetUser(ctx?context.Context,?in?*user.UserId)?(*user.UserInfoReply,?error)?{ ?log.Printf("請求用戶id為:?%d",?in.GetId()) ?return?&user.UserInfoReply{Id:?1,?Name:?"程序員讀書",?Email:?"test@163.com"},?nil } //[2] func?(s?*userServer)?AddUser(ctx?context.Context,?in?*user.AddUserRequest)?(*user.UserId,?error)?{ ?log.Printf("你要添加的用戶名稱為:?%s,郵箱為:%s",?in.GetName(),?in.GetEmail()) ?return?&user.UserId{Id:?2},?nil } func?main()?{ ?listen,?err?:=?net.Listen("tcp",?":50051") ?if?err?!=?nil?{ ??log.Fatalf("failed?to?listen:?%v",?err) ?} ?s?:=?grpc.NewServer() ?user.RegisterUserServer(s,?&userServer{}) ?log.Printf("server?listening?at?%v",?listen.Addr()) ?if?err?:=?s.Serve(listen);?err?!=?nil?{ ??log.Fatalf("failed?to?serve:?%v",?err) ?} }
在上面的代碼中,主要完成以下幾件事:
- 創(chuàng)建一個監(jiān)聽器監(jiān)聽
50051
端口 - 通過
grpc.NewServer()
創(chuàng)建RPC
服務(wù)器,將服務(wù)對象userServer
綁定服務(wù)器 - 將監(jiān)聽器傳給
RPC
服務(wù)器以啟動服務(wù)。
編寫客戶端代碼
package?main import?( ?"context" ?"log" ?"os" ?"time" ?"test/user" ?"google.golang.org/grpc" ) func?main()?{ ?conn,?err?:=?grpc.Dial("localhost:50051",?grpc.WithInsecure(),?grpc.WithBlock()) ?if?err?!=?nil?{ ??log.Fatalf("did?not?connect:?%v",?err) ?} ?defer?conn.Close() ??ctx,?cancel?:=?context.WithTimeout(context.Background(),?time.Second) ?defer?cancel() ?u?:=?user.NewUserClient(conn) ?userInfo,?err?:=?u.GetUser(ctx,?&user.UserId{Id:?1}) ?if?err?!=?nil?{ ??log.Fatalf("user?nto?found:?%v",?err) ?} ??userId,err?:=?u.AddUser(ctx,&user.AddUserRequest{Name:"test",Email:"test@test.com"}) }
小結(jié)
本文主要介紹了使用gRPC
與Go語言進行RPC
應(yīng)用的開發(fā),總結(jié)起來就是以下幾點:
- 通過網(wǎng)絡(luò)調(diào)用遠程主機的函數(shù),稱為
RPC
。 gRPC
是一個實現(xiàn)RPC的框架,支持多種編程語言。gRpc
使用.proto
文件描述一個RPC
服務(wù),并用protoc
命令生成目標語言的代碼。
到此這篇關(guān)于重學(xué)Go語言之如何開發(fā)RPC應(yīng)用的文章就介紹到這了,更多相關(guān)Go RPC內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決golang處理http response碰到的問題和需要注意的點
這篇文章主要介紹了解決golang處理http response碰到的問題和需要注意的點,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12vscode插件設(shè)置之Golang開發(fā)環(huán)境配置全過程
go語言開發(fā)選擇vscode作為IDE工具也是一個不錯的選擇,下面這篇文章主要給大家介紹了關(guān)于vscode插件設(shè)置之Golang開發(fā)環(huán)境配置的相關(guān)資料,文中通過圖文介紹的非常詳細,需要的朋友可以參考下2022-12-12Go語言學(xué)習(xí)之函數(shù)的定義與使用詳解
這篇文章主要為大家詳細介紹Go語言中函數(shù)的定義與使用,文中的示例代碼講解詳細,對我們學(xué)習(xí)Go語言有一定幫助,需要的可以參考一下2022-04-04深入分析Go?實現(xiàn)?MySQL?數(shù)據(jù)庫事務(wù)
本文深入分析了Go語言實現(xiàn)MySQL數(shù)據(jù)庫事務(wù)的原理和實現(xiàn)方式,包括事務(wù)的ACID特性、事務(wù)的隔離級別、事務(wù)的實現(xiàn)方式等。同時,本文還介紹了Go語言中的事務(wù)處理機制和相關(guān)的API函數(shù),以及如何使用Go語言實現(xiàn)MySQL數(shù)據(jù)庫事務(wù)。2023-06-06