Golang学习 Day_20 微服务架构

本文介绍了Go语言中使用net/rpc库创建RPC服务的基本步骤,包括服务端注册方法、监听端口以及客户端调用远程方法。此外,还提到了使用jsonrpc库实现跨语言调用,以及Protobuf作为轻量级序列化工具在RPC中的作用。文章探讨了RPC在不同语言间通信的重要性,并列出了其优缺点。
摘要由CSDN通过智能技术生成

RPC

RPC(Remote Procedure Call)远程过程调用的缩写,通俗的说就是调用远处的一个函数,是分布式系统中不同节点间流行的通信方式。

创建rpc微服务

package main


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


// 定义一个远程调用的方法
type Hello struct{}


// 1、方法只能有两个可序列化的的参数,第二个参数是指针类型
//      req 表示获取客户端传过来的数据
//      res 表示给客户端返回类型(指针类型)
// 2、方法要返回一个error类型,同时必须是公开的方法
// 3、参数类型不能是channel、func类型


func (hl Hello) SayHello(req string, res *string) error {
    fmt.Println(req)
    *res = "你好" + req
    return nil
}


func main() {
    // 1、注册RPC服务
    err1 := rpc.RegisterName("hello", new(Hello))
    if err1 != nil {
        fmt.Println(err1)
    }
    //2、监听端口
    listener, err2 := net.Listen("tcp", "127.0.0.1:8080")
    if err2 != nil {
        fmt.Println(err2)
    }


    // 3、应用退出的时候关闭监听端口
    defer listener.Close()


    for {
        fmt.Println("开始建立连接")
        // 4、建立连接
        conn, err3 := listener.Accept()
        if err3 != nil {
            fmt.Println(err3)
        }
        // 5、绑定服务
        rpc.ServeConn(conn)
    }
}
package main


import (
    "fmt"
    "net/rpc"
)


func main() {
    // 1、通过 rpc.Dial 和 rpc为服务端建立连接


    conn, err1 := rpc.Dial("tcp", "127.0.0.1:8080")
    if err1 != nil {
        fmt.Println(err1)
    }
    // 2、客户端退出的时候关闭连接
    defer conn.Close()


    // 3、调用远程函数
    var reply string //接受返回值


    /*
        Call的三个参数
        1、第一个参数 hello.SayHello hello表示服务器 SayHello方法名称
        2、第二个参数 给服务器的req 传递数据
        3、第三个参数 需要传入地址 获取微服务端返回的数据
    */
    err2 := conn.Call("hello.SayHello", "我是客户端", &reply)
    if err2 != nil {
        fmt.Println(err2)
    }


    // 4、获取微服务返回的数据
    fmt.Println(reply)
}

创建goodsRPC微服务

package main


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


// 1、创建远程调用的函数,函数一般是放在结构体里面
type Goods struct{}


// AddGoods参数对营的结构团体
type AddGoodsReq struct {
    Id      int
    Title   string
    Price   float32
    Content string
}
type AddGoodsRes struct {
    Success bool
    Message string
}


type GetGoodsReq struct {
    Id int
}
type GetGoodsRes struct {
    Id      int
    Title   string
    Price   float32
    Content string
}


func (g Goods) AddGoods(req AddGoodsReq, res *AddGoodsRes) error {
    // 1、执行增加
    fmt.Println(req)
    // 2、返回增加结果
    *res = AddGoodsRes{
        Success: true,
        Message: "增加数据成功",
    }


    return nil
}


func (g Goods) GetGoods(req GetGoodsReq, res *GetGoodsRes) error {
    // 1、执行增加
    fmt.Println(req)
    // 2、返回增加结果
    *res = GetGoodsRes{
        Id:      12,
        Title:   "服务器获取的数据",
        Price:   24.5,
        Content: "我是服务器获取的内容",
    }
    return nil
}


func main() {
    // 1、注册RPC服务
    err1 := rpc.RegisterName("goods", new(Goods))
    if err1 != nil {
        fmt.Println(err1)
    }


    // 2、监听端口
    listener, err2 := net.Listen("tcp", "127.0.0.1:8081")
    if err2 != nil {
        fmt.Println(err2)
    }
    //3、关闭监听
    defer listener.Close()


    for {
        //4、监听客户端链接
        fmt.Println("准备建立连接...")
        conn, err3 := listener.Accept()
        if err3 != nil {
            fmt.Println(err3)
        }
        rpc.ServeConn(conn)
    }
}
package main


import (
    "fmt"
    "net/rpc"
)


type AddGoodsReq struct {
    Id      int
    Title   string
    Price   float32
    Content string
}
type AddGoodsRes struct {
    Success bool
    Message string
}


type GetGoodsReq struct {
    Id int
}
type GetGoodsRes struct {
    Id      int
    Title   string
    Price   float32
    Content string
}


func main() {
    // 1、通过 rpc.Dial 和 rpc为服务端建立连接


    conn, err1 := rpc.Dial("tcp", "127.0.0.1:8081")
    if err1 != nil {
        fmt.Println(err1)
    }
    // 2、客户端退出的时候关闭连接
    defer conn.Close()


    // 3、调用远程函数
    var reply AddGoodsRes //接受返回值
    err2 := conn.Call("goods.AddGoods", AddGoodsReq{
        Id:      10,
        Title:   "商品标题",
        Price:   23.5,
        Content: "商品详情",
    }, &reply)
    if err2 != nil {
        fmt.Println(err2)
    }


    // 4、获取微服务返回的数据
    fmt.Printf("%#v\n", reply)


    var goodsData GetGoodsRes
    err3 := conn.Call("goods.GetGoods", GetGoodsReq{
        Id: 12,
    }, &goodsData)
    if err3 != nil {
        fmt.Println(err2)
    }
    fmt.Printf("%#v\n", reply)
}

net/rpc/jsonrpc库以及RPC跨语言

标准库的RPC默认采用Go语言特有的gob编码,没法实现语言调用,golang官方还提供了net/rpc/jsonrpc库实现RPC方法,JSON RPC采用JSON进行数据编解码,因而支持跨语言调用,但目前jsonrpc库是基于tcp协议实现的,暂时不支持使用http进行数据传输。

package main


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


func main() {
    // 1、通过 rpc.Dial 和 rpc为服务端建立连接


    conn, err1 := net.Dial("tcp", "127.0.0.1:8080")
    if err1 != nil {
        fmt.Println(err1)
    }
    // 2、客户端退出的时候关闭连接
    defer conn.Close()


    // 建立基于json编码的rpc服务
    client := rpc.NewClientWithCodec(jsonrpc.NewClientCodec(conn))


    // 3、调用远程函数
    var reply string //接受返回值


    /*
       Call的三个参数
       1、第一个参数 hello.SayHello hello表示服务器 SayHello方法名称
       2、第二个参数 给服务器的req 传递数据
       3、第三个参数 需要传入地址 获取微服务端返回的数据
    */
    err2 := client.Call("hello.SayHello", "我是客户端", &reply)
    if err2 != nil {
        fmt.Println(err2)
    }


    // 4、获取微服务返回的数据
    fmt.Println(reply)
}
package main


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


// 定义一个远程调用的方法
type Hello struct{}


// 1、方法只能有两个可序列化的的参数,第二个参数是指针类型
//      req 表示获取客户端传过来的数据
//      res 表示给客户端返回类型(指针类型)
// 2、方法要返回一个error类型,同时必须是公开的方法
// 3、参数类型不能是channel、func类型


func (hl Hello) SayHello(req string, res *string) error {
    fmt.Println(req)
    *res = "你好" + req
    return nil
}


func main() {
    // 1、注册RPC服务
    err1 := rpc.RegisterName("hello", new(Hello))
    if err1 != nil {
        fmt.Println(err1)
    }
    //2、监听端口
    listener, err2 := net.Listen("tcp", "127.0.0.1:8080")
    if err2 != nil {
        fmt.Println(err2)
    }


    // 3、应用退出的时候关闭监听端口
    defer listener.Close()


    for {
        fmt.Println("开始建立连接")
        // 4、建立连接
        conn, err3 := listener.Accept()
        if err3 != nil {
            fmt.Println(err3)
        }
        // 5、绑定服务
        rpc.ServeCodec(jsonrpc.NewServerCodec(conn))
    }
}


// jsonrpc 和默认rpc之间的区别:
// jsonrpc中通过

ProtoBuf

Protobuf是Protocol Buffers的简称,是Google公司开发的一种数据描述语言,是一种轻便高效的结构数据存储格式,可以用于结构化数据,或者序列化,适合做数据存储或PRC数据交换。可用于通讯数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式,它是一种灵活,高校,地动画的机制,用于序列化结构化数据,对比于XML和JSON,她更小,更快,更简单。

优势:

  1. 序列化后的体积相比于json和xml很小,适合网络传输
  2. 支持跨平台多语言
  3. 消息格式省级和兼容性很好
  4. 序列化反序列化速度很快,快于json的处理速度

劣势

  1. 应用不够广(相比xml和json)
  2. 二进制格式导致可读性差
  3. 缺乏自描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值