自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Go必知必會(huì):Go RPC揭秘構(gòu)建高效遠(yuǎn)程服務(wù)的指南

開發(fā) 前端
遠(yuǎn)程過程調(diào)用(RPC)是一種強(qiáng)大通信機(jī)制,允許程序像調(diào)用本地過程一樣請求遠(yuǎn)程服務(wù)。它相比 HTTP REST 等協(xié)議,在頻繁遠(yuǎn)程調(diào)用場景中能降低成本、提高效率。

什么是 RPC

遠(yuǎn)程過程調(diào)用(Remote Procedure Call,RPC)是一種強(qiáng)大的通信機(jī)制,它允許程序像調(diào)用本地過程一樣簡單直接地請求遠(yuǎn)程節(jié)點(diǎn)上的服務(wù)。RPC的實(shí)現(xiàn)通常依賴于客戶端與服務(wù)端之間建立的socket連接,這種連接方式相比HTTP REST等通信協(xié)議,在頻繁的遠(yuǎn)程服務(wù)調(diào)用場景中,能夠顯著降低通信成本,提高效率。通過RPC,分布式系統(tǒng)中的各個(gè)組件可以無縫協(xié)作,就像它們運(yùn)行在同一個(gè)地址空間中一樣。

進(jìn)一步地,理解RPC的優(yōu)勢,我們需要將其與本地過程調(diào)用相比較。本地過程調(diào)用是程序內(nèi)部組件間的直接調(diào)用,而RPC則跨越了網(wǎng)絡(luò),允許不同地理位置的節(jié)點(diǎn)進(jìn)行通信。RPC的高效性在于它減少了每次通信所需的開銷,因?yàn)樗苊饬酥貜?fù)的連接建立和HTTP頭部解析。這種優(yōu)化使得RPC成為構(gòu)建高性能分布式系統(tǒng)的理想選擇,特別是在需要快速、可靠地進(jìn)行遠(yuǎn)程服務(wù)調(diào)用的場合。

為什么用RPC

在分布式系統(tǒng)中,遠(yuǎn)程過程調(diào)用(RPC)是一種核心機(jī)制,允許應(yīng)用程序像調(diào)用本地函數(shù)一樣調(diào)用遠(yuǎn)程服務(wù)。HTTP協(xié)議因?yàn)闊o法在同一個(gè)進(jìn)程內(nèi),或者無法在同一個(gè)服務(wù)器上通過本地調(diào)用的方式實(shí)現(xiàn)我們的需求,所以我們需要使用RPC。

RPC的優(yōu)勢及與HTTP對比

RPC(遠(yuǎn)程過程調(diào)用)技術(shù)以其高效性和易用性在分布式系統(tǒng)中得到廣泛應(yīng)用。相較于HTTP等其他通信協(xié)議,RPC具有以下優(yōu)勢。

  1. 性能優(yōu)勢:RPC通常使用二進(jìn)制序列化和壓縮技術(shù),減少了數(shù)據(jù)傳輸?shù)捏w積,同時(shí)減少了解析時(shí)間,提高了通信效率。
  2. 連接復(fù)用:RPC通過建立持久的連接,避免了HTTP協(xié)議中每次請求都需要建立新連接的開銷,從而降低了連接建立和關(guān)閉的頻率,提高了資源利用率。
  3. 實(shí)時(shí)性:由于RPC的連接復(fù)用和高效的序列化機(jī)制,它在實(shí)時(shí)性要求較高的場景中表現(xiàn)更為出色。
  4. 服務(wù)治理:RPC框架通常提供了服務(wù)發(fā)現(xiàn)、負(fù)載均衡、故障轉(zhuǎn)移等高級功能,這些功能在HTTP協(xié)議中通常需要額外的組件來實(shí)現(xiàn)。
  5. 語言無關(guān)性:RPC框架支持多種編程語言,使得不同語言編寫的服務(wù)能夠無縫通信,而HTTP協(xié)議雖然也是語言無關(guān)的,但在服務(wù)間的直接調(diào)用上不如RPC直觀和方便。

與RPC相比,HTTP協(xié)議在以下方面存在一些限制。

  1. 性能開銷:HTTP協(xié)議的文本格式(如JSON、XML)在序列化和反序列化過程中相對RPC的二進(jìn)制協(xié)議有更大的性能開銷。
  2. 連接非持久性:HTTP/1.1雖然支持持久連接,但默認(rèn)情況下每次請求仍然需要建立和關(guān)閉連接,這在高并發(fā)場景下可能導(dǎo)致性能瓶頸。
  3. 服務(wù)治理復(fù)雜性:HTTP協(xié)議本身不包含服務(wù)治理的功能,需要依賴額外的中間件或服務(wù)來實(shí)現(xiàn)。
  4. 語義表達(dá)限制:HTTP協(xié)議的GET、POST等方法在表達(dá)復(fù)雜操作時(shí)可能不夠直觀,而RPC可以定義任意的遠(yuǎn)程調(diào)用方法。

綜上所述,RPC在分布式系統(tǒng)中提供了一種更為高效、靈活的通信方式,尤其是在需要頻繁遠(yuǎn)程服務(wù)調(diào)用的場景中;然而,HTTP協(xié)議由于其廣泛的支持和簡單的語義,仍然在許多場景下被廣泛使用,尤其是在Web服務(wù)和互聯(lián)網(wǎng)通信中。選擇使用RPC還是HTTP,需要根據(jù)具體的應(yīng)用場景和性能需求來決定。

RPC的使用邊界

RPC(遠(yuǎn)程過程調(diào)用)是一種允許程序像調(diào)用本地函數(shù)一樣簡單直接地請求遠(yuǎn)程計(jì)算機(jī)程序上服務(wù)的技術(shù)。它通過封裝遠(yuǎn)程調(diào)用的細(xì)節(jié),為分布式系統(tǒng)中的不同組件提供了一種透明化的通信方式。RPC的優(yōu)勢在于其性能效率、跨語言調(diào)用能力及提高系統(tǒng)可擴(kuò)展性的特點(diǎn)。相較于HTTP REST,RPC通常依賴于客戶端與服務(wù)端之間建立的socket連接,這減少了通信的開銷,尤其是在頻繁的遠(yuǎn)程服務(wù)調(diào)用場景中,RPC的性能優(yōu)勢更加明顯。

RPC的使用邊界主要體現(xiàn)在它適用于內(nèi)部服務(wù)調(diào)用,特別是在公司內(nèi)部的微服務(wù)架構(gòu)中,RPC能夠?qū)崿F(xiàn)高效的服務(wù)治理和負(fù)載均衡。然而,對于對外的異構(gòu)環(huán)境,如瀏覽器接口調(diào)用、APP接口調(diào)用或第三方接口調(diào)用等,RPC可能不如HTTP REST適用。HTTP協(xié)議由于其廣泛的支持和簡單的語義,更適合于跨不同平臺(tái)和語言的網(wǎng)絡(luò)通信。

在技術(shù)選型時(shí),應(yīng)根據(jù)具體的應(yīng)用場景和性能需求來決定使用RPC還是HTTP。例如,在需要高性能、低延遲的內(nèi)部服務(wù)調(diào)用時(shí),RPC可能是更好的選擇;而在需要與外部系統(tǒng)或不同語言編寫的服務(wù)進(jìn)行通信時(shí),HTTP REST可能更加合適。此外,RPC框架如Apache Thrift、gRPC、Dubbo等提供了豐富的功能,包括服務(wù)發(fā)現(xiàn)、負(fù)載均衡、故障轉(zhuǎn)移等,以支持大型分布式系統(tǒng)的構(gòu)建和維護(hù)。

RPC入門實(shí)踐1:net/rpc

Go的net/rpc包提供了一個(gè)基本的RPC框架,支持自定義編碼和解碼。以下是一個(gè)簡單的服務(wù)端和客戶端示例,演示了如何使用net/rpc進(jìn)行乘法和除法運(yùn)算。

基本構(gòu)成

  1. RPC的基本構(gòu)成:服務(wù)端、客戶端
  2. 服務(wù)端基本構(gòu)成:結(jié)構(gòu)體、請求結(jié)構(gòu)體、響應(yīng)結(jié)構(gòu)體
  3. 客戶端基本構(gòu)成:請求結(jié)構(gòu)體、響應(yīng)結(jié)構(gòu)體

代碼示例

rpc_service.go

package main

import (
        "errors"
        "fmt"
        "log"
        "net"
        "net/http"
        "net/rpc"
        "os"
)

type Arith struct {

}

//請求結(jié)構(gòu)體
type ArithRequest struct {
        A int
        B int
}

//響應(yīng)結(jié)構(gòu)體
type ArithResponse struct {
        Pro int //乘積
        Quo int //商
        Rem int //余數(shù)
}

//乘積方法
func (this *Arith) Multiply(req ArithRequest,res *ArithResponse) error{
        res.Pro = req.A * req.B
        return nil
}

//除法運(yùn)算方法
func (this *Arith) Divide(req ArithRequest,res *ArithResponse) error{
        if req.B ==0 {
                return  errors.New("divide by zero")
        }
        res.Quo = req.A / req.B
        res.Rem = req.A % req.B
        return nil
}

func main()  {
        //注冊rpc服務(wù)
        rpc.Register(new(Arith))
        //采用http協(xié)議作為rpc載體
        rpc.HandleHTTP()

        lis,err := net.Listen("tcp","127.0.0.1:8095")
        if err!=nil {
                log.Fatalln("fatal error:",err)
        }

        fmt.Fprintf(os.Stdout,"%s","start connection\n")

        //常規(guī)啟動(dòng)http服務(wù)
        http.Serve(lis,nil)
}

rpc_client.go

package main

import (
        "fmt"
        "log"
        "net/rpc"
)

//算數(shù)運(yùn)算請求結(jié)構(gòu)體
type ArithRequest struct {
        A int
        B int
}

//響應(yīng)結(jié)構(gòu)體
type ArithResponse struct {
        Pro int //乘
        Quo int //商
        Rem int //余數(shù)
}

func main()  {
        conn,err := rpc.DialHTTP("tcp","127.0.0.1:8095")
        if err!=nil {
                log.Fatalln("dialing error:",err)
        }

        req := ArithRequest{10,20}
        var res  ArithResponse

        err = conn.Call("Arith.Multiply",req,&res) //乘法運(yùn)算
        if err!=nil {
                log.Fatalln("arith error:",err)
        }
        fmt.Printf("%d * %d = %d\n",req.A,req.B,res.Pro)

        //除法運(yùn)算
        err = conn.Call("Arith.Divide",req,&res)
        if err!=nil {
                log.Fatalln("arith error:",err)
        }
        fmt.Printf("%d / %d = %d 余數(shù)是:%d",req.A,req.B,res.Quo,res.Rem)
}

運(yùn)行結(jié)果

先啟動(dòng)服務(wù)端,再啟動(dòng)客戶端連接服務(wù)端:

//服務(wù)端console
start connection

//客戶端console
10 * 20 = 200
10 / 20 = 0 余數(shù)是:10

RPC入門實(shí)踐2:net/rpc/jsonrpc

jsonrpc是net/rpc的子集包,使用JSON作為編碼格式,這使得它成為跨語言調(diào)用的理想選擇。

實(shí)現(xiàn)跨語言調(diào)用

jsonrpc_server.go

package main

import (
        "errors"
        "fmt"
        "log"
        "net"
        "net/rpc"
        "net/rpc/jsonrpc"
        "os"
)

type Arith struct {

}

//請求結(jié)構(gòu)體
type ArithRequest struct {
        A int
        B int
}

//響應(yīng)結(jié)構(gòu)體
type ArithResponse struct {
        Pro int //乘積
        Quo int //商
        Rem int //余數(shù)
}

//乘積方法
func (this *Arith) Multiply(req ArithRequest,res *ArithResponse) error{
        res.Pro = req.A * req.B
        return nil
}

//除法運(yùn)算方法
func (this *Arith) Divide(req ArithRequest,res *ArithResponse) error{
        if req.B ==0 {
                return  errors.New("divide by zero")
        }
        res.Quo = req.A / req.B
        res.Rem = req.A % req.B
        return nil
}

func main()  {
        //注冊rpc服務(wù)
        rpc.Register(new(Arith))
        //采用http協(xié)議作為rpc載體
        rpc.HandleHTTP()

        lis,err := net.Listen("tcp","127.0.0.1:8096")
        if err!=nil {
                log.Fatalln("fatal error:",err)
        }

        fmt.Fprintf(os.Stdout,"%s","start connection\n")

        //接收客戶端請求 并發(fā)處理 jsonrpc
        for {
                conn,err :=lis.Accept() //接收客戶端連接請求
                if err!=nil {
                        continue
                }

                //并發(fā)處理客戶端請求
                go func(conn net.Conn) {
                        fmt.Fprintf(os.Stdout,"%s","new client in coming\n")
                        jsonrpc.ServeConn(conn)
                }(conn)
        }

        //常規(guī)啟動(dòng)http服務(wù)
        //http.Serve(lis,nil)
}

jsonrpc_client.go

package main

import (
        "fmt"
        "log"
        "net/rpc/jsonrpc"
)

//算數(shù)運(yùn)算請求結(jié)構(gòu)體
type ArithRequest struct {
        A int
        B int
}

//響應(yīng)結(jié)構(gòu)體
type ArithResponse struct {
        Pro int //乘
        Quo int //商
        Rem int //余數(shù)
}

func main()  {
        // 只有這里不一樣
        conn,err := jsonrpc.Dial("tcp","127.0.0.1:8096")
        if err!=nil {
                log.Fatalln("dialing error:",err)
        }

        req := ArithRequest{9,2}
        var res  ArithResponse

        err = conn.Call("Arith.Multiply",req,&res) //乘法運(yùn)算
        if err!=nil {
                log.Fatalln("arith error:",err)
        }
        fmt.Printf("%d * %d = %d\n",req.A,req.B,res.Pro)

        //除法運(yùn)算
        err = conn.Call("Arith.Divide",req,&res)
        if err!=nil {
                log.Fatalln("arith error:",err)
        }
        fmt.Printf("%d / %d = %d 余數(shù)是:%d",req.A,req.B,res.Quo,res.Rem)
}

運(yùn)行結(jié)果

先啟動(dòng)服務(wù)端,再啟動(dòng)客戶端連接服務(wù)端:

//服務(wù)端console
start connection

//客戶端console
9 * 2 = 18
9 / 2 = 4 余數(shù)是:1

//服務(wù)端console
new client in coming

RPC入門實(shí)踐3:go php跨語言調(diào)用

通過jsonrpc,Go可以輕松與其他支持JSON-RPC協(xié)議的語言(如PHP)進(jìn)行通信。

Go作為服務(wù)端,PHP作為客戶端

jsonrpc_server.go:和入門2服務(wù)端的代碼一樣。

jsonrpc_client.php

<?php


class JsonRPC
{

    private $conn;

    function __construct($host, $port)
    {
        $this->conn = fsockopen($host, $port, $errno, $errstr, 3);
        if (!$this->conn) {
            return false;
        }
    }

    public function Call($method, $params)
    {
        if (!$this->conn) {
            return false;
        }
        $err = fwrite($this->conn, json_encode(array(
                'method' => $method,
                'params' => array($params),
                'id' => 0,
            )) . "\n");
        if ($err === false) {
            return false;
        }
        stream_set_timeout($this->conn, 0, 3000);
        $line = fgets($this->conn);
        if ($line === false) {
            return NULL;
        }
        return json_decode($line, true);
    }
}

$client = new JsonRPC("127.0.0.1", 8096);
$args = array('A' => 9, 'B' => 2);
$r = $client->Call("Arith.Multiply", $args);
printf("%d * %d = %d\n", $args['A'], $args['B'], $r['result']['Pro']);
$r = $client->Call("Arith.Divide", array('A' => 9, 'B' => 2));
printf("%d / %d, Quo is %d, Rem is %d\n", $args['A'], $args['B'], $r['result']['Quo'], $r['result']['Rem']);

運(yùn)行結(jié)果

//本地啟動(dòng)PHP服務(wù):http://127.0.0.1/jsonrpc_client.php,運(yùn)行結(jié)果如下:
9 * 2 = 18 9 / 2, Quo is 4, Rem is 1

總結(jié)

遠(yuǎn)程過程調(diào)用(RPC)是一種強(qiáng)大通信機(jī)制,允許程序像調(diào)用本地過程一樣請求遠(yuǎn)程服務(wù)。它相比 HTTP REST 等協(xié)議,在頻繁遠(yuǎn)程調(diào)用場景中能降低成本、提高效率。

RPC 的優(yōu)勢包括性能高、連接復(fù)用、實(shí)時(shí)性好、服務(wù)治理方便、語言無關(guān)等。與 HTTP 對比,HTTP 在性能開銷、連接持久性等方面有限制。

使用時(shí)應(yīng)根據(jù)應(yīng)用場景和性能需求選擇 RPC 或 HTTP,例如高性能內(nèi)部調(diào)用選 RPC,與外部通信可能 HTTP 更合適。

本文轉(zhuǎn)載自微信公眾號「王中陽」,作者「王中陽」,可以通過以下二維碼關(guān)注。

轉(zhuǎn)載本文請聯(lián)系「王中陽」公眾號。

責(zé)任編輯:武曉燕 來源: 王中陽
相關(guān)推薦

2024-07-26 08:32:44

panic?Go語言

2024-06-13 09:10:22

2024-06-19 10:08:34

GoChannel工具

2022-12-07 09:00:18

錯(cuò)誤異常CGO

2022-12-01 08:15:41

CGOswitcherror

2023-10-13 00:00:00

設(shè)計(jì)模式GO語言

2024-09-27 12:13:26

GoGTokenSSO

2024-09-02 09:00:59

2022-11-03 07:48:27

CSSat-rule

2020-07-10 07:58:14

Linux

2024-06-20 11:49:52

2024-11-15 11:11:48

2024-01-03 07:56:50

2022-05-18 09:01:19

JSONJavaScript

2020-04-10 13:04:19

微服務(wù)架構(gòu)RPC

2018-10-26 14:10:21

2023-05-08 15:25:19

Python編程語言編碼技巧

2023-04-20 14:31:20

Python開發(fā)教程

2023-12-26 12:10:13

2020-07-02 09:55:32

運(yùn)維架構(gòu)技術(shù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號