欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

go-micro開(kāi)發(fā)RPC服務(wù)以及運(yùn)行原理介紹

 更新時(shí)間:2022年07月04日 10:00:13   作者:波斯馬  
這篇文章介紹了go-micro開(kāi)發(fā)RPC服務(wù)的方法及其運(yùn)行原理,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

go-micro是一個(gè)知名的golang微服務(wù)框架,最新版本是v4,這篇文章將介紹go-micro v4開(kāi)發(fā)RPC服務(wù)的方法及其運(yùn)作原理。

基本概念

go-micro有幾個(gè)重要的概念,后邊開(kāi)發(fā)RPC服務(wù)和介紹其運(yùn)行原理的時(shí)候會(huì)用到,這里先熟悉下:

  • Service:代表一個(gè)go-micro應(yīng)用程序,Service中包括:Server、Client、Broker、Transport、Registry、Config、Store、Cache等程序運(yùn)行所需的各個(gè)模塊。
  • Server:代表一個(gè)go-micro服務(wù)器,主要函數(shù)包括:Start、Stop、Handle、Subscribe。默認(rèn)創(chuàng)建的Server是 rpcServer。
  • Broker:用于處理異步消息,主要的函數(shù)包括:Connect、Publish、Subscribe。默認(rèn)的Broker是httpBroker。
  • Router:用于消息處理的路由,內(nèi)部包括兩種路由方式:RPC服務(wù)映射serviceMap和消息訂閱器subscribers。
  • Codec:用于消息的編解碼,主要函數(shù)包括:Marshal、Unmarshal默認(rèn)的Codec是json.Marshaler,是基于jsonpb的。RPC服務(wù)是根據(jù)請(qǐng)求頭中的Content-Type自動(dòng)創(chuàng)建的。
  • Registry:用于服務(wù)發(fā)現(xiàn),主要函數(shù)包括:Register、Deregister、GetService、ListServices、Watch。默認(rèn)的Registry是mdns。
  • Selector: 用于從同一個(gè)服務(wù)的多個(gè)實(shí)例之中選擇一個(gè),支持緩存,有隨機(jī)和輪詢兩種策略。
  • Transport:用于同步通信,主要函數(shù)包括:Dial、Listen。它的底層基于Socket的send、recv語(yǔ)義,有多種實(shí)現(xiàn),包括http、grpc、quic等。默認(rèn)的Transport是httpTransport。

開(kāi)發(fā)RPC服務(wù)

RPC全稱是Remote Procedure Call,翻譯過(guò)來(lái)是就是:遠(yuǎn)程過(guò)程調(diào)用,中心思想是:像調(diào)用本地函數(shù)一樣調(diào)用遠(yuǎn)程函數(shù)。常見(jiàn)的Dubbo、Spring Cloud都可以稱為RPC框架,還有最近很流行的gRPC。

使用go-micro創(chuàng)建一個(gè)RPC服務(wù)很簡(jiǎn)單,共分三步走:

1、編寫proto協(xié)議文件

這個(gè)服務(wù)提供的功能很簡(jiǎn)單,名字為Hello,提供一個(gè)方法名字為Say,需要傳入一個(gè)字符串Name,然后返回一個(gè)字符串Message。這個(gè)文件我命名為 hello.proto,放到了項(xiàng)目中的 proto 文件夾中。

syntax = "proto3";

option go_package="/proto";

package Business;

service Hello {
  rpc Say (SayRequest) returns (SayResponse);
}

message SayResponse {
  string Message = 1;
}

message SayRequest {
  string Name = 1;
}

2、生成go-micro服務(wù)端代理

需要首先安裝protoc和兩個(gè)代碼生成插件。

protoc下載地址:https://github.com/protocolbuffers/protobuf/releases,保存到GO PATH/bin目錄中。同時(shí)建議將 GOPATH/bin 添加到環(huán)境變量 PATH 中,方便直接執(zhí)行相關(guān)命令。

兩個(gè)插件直接通過(guò)命令即可安裝:

go install google.golang.org/protobuf/cmd/protoc-gen-go
go install go-micro.dev/v4/cmd/protoc-gen-micro@v4

然后在項(xiàng)目的目錄下執(zhí)行命令:

protoc --go_out=. --go_opt=paths=source_relative --micro_out=. --micro_opt=paths=source_relative proto/hello.proto

然后會(huì)在proto文件夾中生成兩個(gè)文件:hello.pb.go 和 hello.pb.micro.go 。

下個(gè)步驟中就要使用它們來(lái)創(chuàng)建RPC服務(wù)。

3、編寫go-micro服務(wù)

這里先把代碼貼出來(lái),然后再做一個(gè)簡(jiǎn)要說(shuō)明:

package main

import (
	"context"
	"fmt"
	"log"
	"rpchello/proto"

	"go-micro.dev/v4"
	"go-micro.dev/v4/server"
)

type Hello struct{}

func (s *Hello) Say(ctx context.Context, req *proto.SayRequest, rsp *proto.SayResponse) error {
	fmt.Println("request:", req.Name)
	rsp.Message = "Hello " + req.Name
	return nil
}

func main() {
	rpcServer := server.NewServer(
		server.Name("rpchello.service"),
		server.Address("0.0.0.0:8001"),
	)

	proto.RegisterHelloHandler(rpcServer, &Hello{})

	service := micro.NewService(
		micro.Server(rpcServer),
	)

	if err := service.Run(); err != nil {
		log.Fatal(err)
	}
}

上邊我們創(chuàng)建了一個(gè) Hello 類型,然后給它綁定了一個(gè)名為Say的函數(shù)。這個(gè)是和proto協(xié)議對(duì)應(yīng)的,其實(shí)是實(shí)現(xiàn)了生成代碼 hello.pb.micro.go 中的HelloHandler接口:

type HelloHandler interface {
	Say(context.Context, *SayRequest, *SayResponse) error
}

然后main函數(shù)中是我們的重頭戲:先創(chuàng)建一個(gè)Server,默認(rèn)情況下就是rpc Server,設(shè)置它的名字、監(jiān)聽(tīng)地址等參數(shù);然后創(chuàng)建一個(gè)Service,并綁定剛剛創(chuàng)建的Server;然后使用生成的服務(wù)端代理函數(shù)將我們編寫的Hello服務(wù)注冊(cè)到Server中;最后開(kāi)啟運(yùn)行Service。

當(dāng)然只有一個(gè)服務(wù)端沒(méi)有什么意義,還得有客戶端來(lái)訪問(wèn)它。這里也給一個(gè)例子:

package main

import (
	"bufio"
	"context"
	"fmt"
	"os"
	"rpchello/proto"

	"go-micro.dev/v4"
	"go-micro.dev/v4/client"
)

func main() {

	service := micro.NewService(
		micro.Client(client.NewClient()),
	)

	service.Init()
	client := proto.NewHelloService("rpchello.service", service.Client())

	rsp, err := client.Say(context.TODO(), &proto.SayRequest{Name: "BOSSMA"})
	if err != nil {
		fmt.Println(err)
	}

	fmt.Println(rsp)

	fmt.Println("Press Enter key to exit the program...")
	in := bufio.NewReader(os.Stdin)
	_, _, _ = in.ReadLine()
}

這里調(diào)用服務(wù)的時(shí)候沒(méi)有指定服務(wù)的地址和端口,因?yàn)閮?nèi)部走了服務(wù)發(fā)現(xiàn),服務(wù)端會(huì)自動(dòng)注冊(cè)服務(wù),客戶端會(huì)根據(jù)服務(wù)名稱查找到對(duì)應(yīng)的地址和端口。默認(rèn)的服務(wù)發(fā)現(xiàn)機(jī)制使用的是mdns。

RPC服務(wù)的運(yùn)行原理

這里從服務(wù)端的角度進(jìn)行介紹,先來(lái)看一張圖:

請(qǐng)大家參考代碼從上往下看。

NewServer 時(shí)創(chuàng)建一個(gè)rpcServer,這個(gè)rpcServer還會(huì)創(chuàng)建一個(gè)httpTransport用于程序間網(wǎng)絡(luò)通信,并綁定到當(dāng)前rpcServer。

RegisterXXXHandler 時(shí)使用我們編寫的Handler創(chuàng)建一個(gè)內(nèi)部的service實(shí)例,然后注冊(cè)這個(gè)service實(shí)例到rpcServer內(nèi)部的router中,客戶端請(qǐng)求時(shí)會(huì)用到它。這里其實(shí)可以注冊(cè)任意一個(gè)帶方法的類型,并不一定要定義proto協(xié)議,定義它只是為了協(xié)作更方便。

Service.Run 時(shí)會(huì)調(diào)用rpcServer的Start方法,這個(gè)方法內(nèi)部會(huì)調(diào)用其綁定的httpTransport的Listen方法,然后在其創(chuàng)建的Listener上接收客戶端連接,接收方法Accept傳入了當(dāng)前rpcServer的連接處理方法:rpcServer.ServeConn,有連接到來(lái)時(shí)會(huì)調(diào)用它。

當(dāng)客戶端請(qǐng)求來(lái)臨時(shí),客戶端連接被交給rpcServer的ServeConn方法,然后又調(diào)用到HandleEvent方法。

然后進(jìn)入rpcServer內(nèi)部的router的函數(shù)ServeRequest中,通過(guò)分析請(qǐng)求消息,找到請(qǐng)求的服務(wù)名字和方法名字,在router中找到前面注冊(cè)過(guò)的service,通過(guò)servcie.call,再進(jìn)入function.call,最終通過(guò)反射調(diào)用到我們編寫的Handler的業(yè)務(wù)方法。

有的同學(xué)可能會(huì)想,反射不是性能很低嗎?!反射性能低主要是查找方法和字段的時(shí)候,調(diào)用方法的性能并不低,而查找方法和字段等的操作已經(jīng)在RegisterXXXHandler的步驟中做了,并且緩存到了router中,所以性能并不受影響。

到此這篇關(guān)于go-micro開(kāi)發(fā)RPC服務(wù)的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • golang string、int、int64 float 互相轉(zhuǎn)換方式

    golang string、int、int64 float 互相轉(zhuǎn)換方式

    這篇文章主要介紹了golang string、int、int64 float 互相轉(zhuǎn)換方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • Golang獲取本地IP地址方法分享

    Golang獲取本地IP地址方法分享

    這篇文章主要給大家介紹了Golang 獲取本地 IP 地址方法,文中有詳細(xì)的代碼示例,對(duì)我們的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2023-07-07
  • golang使用正則表達(dá)式解析網(wǎng)頁(yè)

    golang使用正則表達(dá)式解析網(wǎng)頁(yè)

    這篇文章主要介紹了golang使用正則表達(dá)式解析網(wǎng)頁(yè),需要的朋友可以參考下
    2015-03-03
  • 安裝GoLang環(huán)境和開(kāi)發(fā)工具的圖文教程

    安裝GoLang環(huán)境和開(kāi)發(fā)工具的圖文教程

    Go是一門由Google開(kāi)發(fā)的編程語(yǔ)言,GoLand的安裝非常簡(jiǎn)單,本文主要介紹了安裝GoLang環(huán)境和開(kāi)發(fā)工具的圖文教程,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-09-09
  • golang flag簡(jiǎn)單用法

    golang flag簡(jiǎn)單用法

    本篇文章介紹了golang flag包的一個(gè)簡(jiǎn)單的用法,希望通過(guò)一個(gè)簡(jiǎn)單的實(shí)例,能讓大家了解它的用法,從中獲得啟發(fā)
    2018-09-09
  • golang環(huán)形隊(duì)列實(shí)現(xiàn)代碼示例

    golang環(huán)形隊(duì)列實(shí)現(xiàn)代碼示例

    這篇文章主要介紹了golang環(huán)形隊(duì)列實(shí)現(xiàn)代碼示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • 詳解Go如何實(shí)現(xiàn)協(xié)程并發(fā)執(zhí)行

    詳解Go如何實(shí)現(xiàn)協(xié)程并發(fā)執(zhí)行

    線程是通過(guò)本地隊(duì)列,全局隊(duì)列或者偷其它線程的方式來(lái)獲取協(xié)程的,目前看來(lái),線程運(yùn)行完一個(gè)協(xié)程后再?gòu)年?duì)列中獲取下一個(gè)協(xié)程執(zhí)行,還只是順序執(zhí)行協(xié)程的,而多個(gè)線程一起這么運(yùn)行也能達(dá)到并發(fā)的效果,接下來(lái)就給給大家詳細(xì)介紹一下Go如何實(shí)現(xiàn)協(xié)程并發(fā)執(zhí)行
    2023-08-08
  • Golang當(dāng)中的定時(shí)器實(shí)例詳解

    Golang當(dāng)中的定時(shí)器實(shí)例詳解

    這篇文章主要給大家介紹了關(guān)于Golang當(dāng)中定時(shí)器的相關(guān)資料,定時(shí)器的實(shí)現(xiàn)大家應(yīng)該都遇到過(guò),最近在學(xué)習(xí)golang,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-07-07
  • 詳解Go中Set的實(shí)現(xiàn)方式

    詳解Go中Set的實(shí)現(xiàn)方式

    這篇文章主要介紹了詳解Go中Set的實(shí)現(xiàn)方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • 重學(xué)Go語(yǔ)言之基礎(chǔ)數(shù)據(jù)類型詳解

    重學(xué)Go語(yǔ)言之基礎(chǔ)數(shù)據(jù)類型詳解

    Go語(yǔ)言有非常強(qiáng)大的數(shù)據(jù)類型系統(tǒng),其支持的數(shù)據(jù)類型大體上可分為四類:基礎(chǔ)數(shù)據(jù)類型、引用數(shù)據(jù)類型、接口類型、復(fù)合類型。本文就來(lái)講講它們各自的用法吧
    2023-02-02

最新評(píng)論