1.RPC简介

1.远程过程调用(Remote Procedure Call,RPC)是一个计算机通信协议。
2.该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程。
3.如果涉及的软件采用面向对象编程,那么远程过程调用也可称为远程调用或远程方法调用。

2.流行的RPC框架的对比

2.微服务--RPC_第1张图片

3.golang中如何实现RPC

Golang中实现RPC比较简单,官方提供了封装好的库,还有第三方库。

官方库:net/rpc
1.net/rpc库使用encoding/gob进行编码
2.支持tcp和http数据传输方式
3.由于其他语言不支持gob编解码方式,所以golang的RPC只支持golang开发的服务端与客户端的交互

官方库:net/jsonrpc
1.jsonrpc采用JSON进行数据编解码,因而支持跨语言调用。
2.jsonrpc库是基于tcp协议实现的,暂不支持http传输方式。

golang的RPC必须符合四个条件才可以:
1.结构体字段首字母要大写,要跨域访问,所以大写。
2.函数名必须首字母大写。
3.函数第一个参数是接收参数,第二个参数是返回给客户端参数,必须是指针类型。
4.函数必须有一个返回值err。

3.1示例1

golang实现RPC程序,实现求矩形面积和周长
//rpcClient/server.go

package main

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

//服务端,求举行面积和周长

//声明矩形对象
type Rect struct {

}

//声明参数结构体,字段首字母大写
type Param struct {
    Width,Height int
}
//golang的RPC必须符合4个条件才可以
//◼ 结构体字段首字母要大写,要跨域访问,所以大写
//◼ 函数名必须首字母大写(可以序列号导出的)
//◼ 函数第一个参数是接收参数,第二个参数是返回给客户端参数,必须是指针类型
//◼ 函数必须有一个返回值error

//定义求矩形面积的方法
func (r Rect) Area(p Param,ret *int)  error{
    *ret = p.Width * p.Height
    return nil
}
//定义求矩形周长的方法
func (r Rect) Perimeter(p Param,ret *int)  error{
    *ret = (p.Width + p.Height)*2
    return nil
}

func main()  {
    //1.注册服务
    rect := new(Rect)
    rpc.Register(rect)
    //2.把服务处理绑定到http协议上
    rpc.HandleHTTP()
    //3.监听服务,等待客户端调用请求面积和周长的方法
    err := http.ListenAndServe(":8080",nil)
    if err != nil{
        log.Fatal(err)
    }
}
//rpcServer/client.go
package main

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

//声明参数结构体,字段首字母大写
type Params struct {
    Width,Height int
}
//调用服务
func main()  {
    //1.链接远程RPC服务
    rp,err := rpc.DialHTTP("tcp","127.0.0.1:8080")
    if err != nil{
        log.Fatal(err)
    }
    //2.调用远程方法
    //定义接收服务端传回来的计算结果的变量
    ret := 0
    //求矩形面积
    err2 := rp.Call("Rect.Area",Params{50,10},&ret)
    if err2 != nil{
        log.Fatal(err2)
    }
    fmt.Println("面积:",ret)

    //求矩形周长
    err3 := rp.Call("Rect.Perimeter",Params{50,10},&ret)
    if err3 != nil{
        log.Fatal(err3)
    }
    fmt.Println("周长:",ret)
}

2.微服务--RPC_第2张图片
2.微服务--RPC_第3张图片

3.2示例2

模仿前面例题,自己实现 RPC 程序,服务端接收 2 个参数,可以做乘法运算,也可以做商和余数的运算,客户端进行传参和访问,得到结果如下:
 9*2 = 18
 9/2,商=4,余数=1

 下面使用net/rpc/jsonrpc库通过json格式编码解码,支持跨语言调用
rpcServer/server.go

package main

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

//结构体,用于注册的
type Arith struct {

}

//声明参数结构体
type ArithRequest struct {
    A,B int
}

//返回给客户端的结果
type ArithResponse struct {
    //乘积
    Pro int
    //商
    Quo int
    //余数
    Rem int
}

//乘法
func (a *Arith) Multiply(req ArithRequest,res *ArithResponse) error  {
    res.Pro = req.A * req.B
    return nil
}
//商和余数
func (a *Arith) Divide(req ArithRequest,res *ArithResponse) error  {
    if req.B == 0{
        return errors.New("除数不能为0")

    }
    //商
    res.Quo = req.A/req.B
    //余数
    res.Rem = req.A%req.B
    return nil

}
func main()  {
    rpc.Register(new(Arith))
    lis,err := net.Listen("tcp",":8080")
    if err != nil{
        log.Fatal(err)
    }
    //循环监听服务
    for{
        conn,err := lis.Accept()
        if err != nil{
            continue
        }
        go func(conn net.Conn) {
            fmt.Println("new client")
            jsonrpc.ServeConn(conn)
        }(conn)
    }
}
rpcClient/client.go

package main

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

//声明参数结构体
type ArithRequest struct {
    A,B int
}

//返回给客户端的结果
type ArithResponse struct {
    //乘积
    Pro int
    //商
    Quo int
    //余数
    Rem int
}
//调用服务
func main()  {
    conn,err := jsonrpc.Dial("tcp",":8080")
    if err != nil{
        log.Fatal(err)
    }
    req := ArithRequest{9,2}
    var res ArithResponse
    err2 := conn.Call("Arith.Multiply", req, &res)
    if err2 != nil {
        log.Fatal(err2)
    }
    fmt.Printf("%d * %d = %d\n", req.A, req.B, res.Pro)
    err3 := conn.Call("Arith.Divide", req, &res)
    if err3 != nil {
        log.Fatal(err3)
    }
    fmt.Printf("%d / %d 商 %d,余数 = %d\n", req.A, req.B, res.Quo, res.Rem)
}

2.微服务--RPC_第4张图片
2.微服务--RPC_第5张图片

3.3RPC调用流程

2.微服务--RPC_第6张图片

1.微服务架构下数据交互一般是对内RPC,对外REST。
2.将业务按功能模块拆分到各个微服务,具有提高项目协作效率、降低模块耦合度、提高系统可用性等优点,但是开发门槛比较高,比如RPC框架的时候,后期的服务监控等工作。
3.一般情况下,我们会将功能代码在本地直接调用,微服务架构下,我们需要将这个函数作为单独的服务运行,客户端通过网络调用。