[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务

一.先创建go-micro服务端

  1. 启动consul

需要先启动consul, consol相关内容见
[golang 微服务] 5. 微服务服务发现介绍,安装以及consul的使用,Consul集群
[golang 微服务] 6. GRPC微服务集群+Consul集群+grpc-consul-resolver案例演示
启动consul命令,这里,使用dev模式: consul agent -dev,启动如下:
[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务_第1张图片

启动后UI界面:

[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务_第2张图片
  1. 启动微服务

这里使用 上一节的goodsinfo微服务,见上一节 [golang 微服务] 7. go-micro框架介绍,go-micro脚手架,go-micro结合consul搭建微服务案例
这里对 .proto进行优化: 统一商品模型,以及增加获取商品相关请求以及响应代码

goodsinfo.proto代码如下:

syntax = "proto3";

package goodsinfo;

option go_package = "./proto;goodsinfo";

//商品相关方法
service Goodsinfo {
    //AddGoods: 定义增加商品的微服务, 这里的写法和gRPC中的写法一致
    rpc AddGoods(AddGoodsRequest) returns (AddGoodsResponse) {}
    //获取商品列表信息
    rpc GetGoods(GetGoodsRequest) returns (GetGoodsResponse) {}
}

//定义GoodsModel结构体,以便增加商品,获取商品数据时使用
message GoodsModel{
    string title = 1;
    double price = 2;
    string content = 3;
}

//增加商品请求: 和gRPC中的写法一致
message AddGoodsRequest {
    GoodsModel parame = 1;
}

//增加商品响应:和gRPC中的写法一致
message AddGoodsResponse {
    string message = 1;
    bool success = 2;
}

//获取商品请求
message GetGoodsRequest {
}
//获取商品响应
message GetGoodsResponse {
    repeated GoodsModel GoodsList = 1;
}
在goodsinfo下执行命令:
protoc --proto_path=. --micro_out=. --go_out=:. proto/goodsinfo.proto
生成对应的.pb.go,.micro.go文件,然后在handler/goodsinfo.go中完善对应的方法:

handler/goodsinfo.go中的代码如下:

package handler

import (
    "context"
    "strconv"
    "go-micro.dev/v4/logger"
    pb "goodsinfo/proto"
)

type Goodsinfo struct{}

//增加商品
func (e *Goodsinfo) AddGoods(ctx context.Context, req *pb.AddGoodsRequest, rsp *pb.AddGoodsResponse) error {
    logger.Infof("request: %v", req)
    //书写返回的逻辑结果
    rsp.Message = "增加成功"
    rsp.Success = true
    return nil
}

//获取商品
func (e *Goodsinfo) GetGoods(ctx context.Context, req *pb.GetGoodsRequest, rsp *pb.GetGoodsResponse) error {
    var tempList []*pb.GoodsModel
    //模拟从数据库中获取商品数据
    for i := 0; i < 10; i++ {
        tempList = append(tempList, &pb.GoodsModel{
            Title:   "第" + strconv.Itoa(i) + "条数据",
            Price:   float64((i + 1) * 2),
            Content: "第" + strconv.Itoa(i) + "内容",
        })
    }
    rsp.GoodsList = tempList
    return nil
}

goodsinfo.pb.go代码如下:

// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
//     protoc-gen-go v1.30.0
//     protoc        v3.15.5
// source: proto/goodsinfo.proto

package goodsinfo

import (
    protoreflect "google.golang.org/protobuf/reflect/protoreflect"
    protoimpl "google.golang.org/protobuf/runtime/protoimpl"
    reflect "reflect"
    sync "sync"
)

const (
    // Verify that this generated code is sufficiently up-to-date.
    _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
    // Verify that runtime/protoimpl is sufficiently up-to-date.
    _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)

// 定义GoodsModel结构体,以便增加商品,获取商品数据时使用
type GoodsModel struct {
    state         protoimpl.MessageState
    sizeCache     protoimpl.SizeCache
    unknownFields protoimpl.UnknownFields

    Title   string  `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
    Price   float64 `protobuf:"fixed64,2,opt,name=price,proto3" json:"price,omitempty"`
    Content string  `protobuf:"bytes,3,opt,name=content,proto3" json:"content,omitempty"`
}

func (x *GoodsModel) Reset() {
    *x = GoodsModel{}
    if protoimpl.UnsafeEnabled {
        mi := &file_proto_goodsinfo_proto_msgTypes[0]
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        ms.StoreMessageInfo(mi)
    }
}

func (x *GoodsModel) String() string {
    return protoimpl.X.MessageStringOf(x)
}

func (*GoodsModel) ProtoMessage() {}

func (x *GoodsModel) ProtoReflect() protoreflect.Message {
    mi := &file_proto_goodsinfo_proto_msgTypes[0]
    if protoimpl.UnsafeEnabled && x != nil {
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        if ms.LoadMessageInfo() == nil {
            ms.StoreMessageInfo(mi)
        }
        return ms
    }
    return mi.MessageOf(x)
}

// Deprecated: Use GoodsModel.ProtoReflect.Descriptor instead.
func (*GoodsModel) Descriptor() ([]byte, []int) {
    return file_proto_goodsinfo_proto_rawDescGZIP(), []int{0}
}

func (x *GoodsModel) GetTitle() string {
    if x != nil {
        return x.Title
    }
    return ""
}

func (x *GoodsModel) GetPrice() float64 {
    if x != nil {
        return x.Price
    }
    return 0
}

func (x *GoodsModel) GetContent() string {
    if x != nil {
        return x.Content
    }
    return ""
}

// 增加商品请求: 和gRPC中的写法一致
type AddGoodsRequest struct {
    state         protoimpl.MessageState
    sizeCache     protoimpl.SizeCache
    unknownFields protoimpl.UnknownFields

    Parame *GoodsModel `protobuf:"bytes,1,opt,name=parame,proto3" json:"parame,omitempty"`
}

func (x *AddGoodsRequest) Reset() {
    *x = AddGoodsRequest{}
    if protoimpl.UnsafeEnabled {
        mi := &file_proto_goodsinfo_proto_msgTypes[1]
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        ms.StoreMessageInfo(mi)
    }
}

func (x *AddGoodsRequest) String() string {
    return protoimpl.X.MessageStringOf(x)
}

func (*AddGoodsRequest) ProtoMessage() {}

func (x *AddGoodsRequest) ProtoReflect() protoreflect.Message {
    mi := &file_proto_goodsinfo_proto_msgTypes[1]
    if protoimpl.UnsafeEnabled && x != nil {
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        if ms.LoadMessageInfo() == nil {
            ms.StoreMessageInfo(mi)
        }
        return ms
    }
    return mi.MessageOf(x)
}

// Deprecated: Use AddGoodsRequest.ProtoReflect.Descriptor instead.
func (*AddGoodsRequest) Descriptor() ([]byte, []int) {
    return file_proto_goodsinfo_proto_rawDescGZIP(), []int{1}
}

func (x *AddGoodsRequest) GetParame() *GoodsModel {
    if x != nil {
        return x.Parame
    }
    return nil
}

// 增加商品响应:和gRPC中的写法一致
type AddGoodsResponse struct {
    state         protoimpl.MessageState
    sizeCache     protoimpl.SizeCache
    unknownFields protoimpl.UnknownFields

    Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
    Success bool   `protobuf:"varint,2,opt,name=success,proto3" json:"success,omitempty"`
}

func (x *AddGoodsResponse) Reset() {
    *x = AddGoodsResponse{}
    if protoimpl.UnsafeEnabled {
        mi := &file_proto_goodsinfo_proto_msgTypes[2]
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        ms.StoreMessageInfo(mi)
    }
}

func (x *AddGoodsResponse) String() string {
    return protoimpl.X.MessageStringOf(x)
}

func (*AddGoodsResponse) ProtoMessage() {}

func (x *AddGoodsResponse) ProtoReflect() protoreflect.Message {
    mi := &file_proto_goodsinfo_proto_msgTypes[2]
    if protoimpl.UnsafeEnabled && x != nil {
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        if ms.LoadMessageInfo() == nil {
            ms.StoreMessageInfo(mi)
        }
        return ms
    }
    return mi.MessageOf(x)
}

// Deprecated: Use AddGoodsResponse.ProtoReflect.Descriptor instead.
func (*AddGoodsResponse) Descriptor() ([]byte, []int) {
    return file_proto_goodsinfo_proto_rawDescGZIP(), []int{2}
}

func (x *AddGoodsResponse) GetMessage() string {
    if x != nil {
        return x.Message
    }
    return ""
}

func (x *AddGoodsResponse) GetSuccess() bool {
    if x != nil {
        return x.Success
    }
    return false
}

// 获取商品请求
type GetGoodsRequest struct {
    state         protoimpl.MessageState
    sizeCache     protoimpl.SizeCache
    unknownFields protoimpl.UnknownFields
}

func (x *GetGoodsRequest) Reset() {
    *x = GetGoodsRequest{}
    if protoimpl.UnsafeEnabled {
        mi := &file_proto_goodsinfo_proto_msgTypes[3]
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        ms.StoreMessageInfo(mi)
    }
}

func (x *GetGoodsRequest) String() string {
    return protoimpl.X.MessageStringOf(x)
}

func (*GetGoodsRequest) ProtoMessage() {}

func (x *GetGoodsRequest) ProtoReflect() protoreflect.Message {
    mi := &file_proto_goodsinfo_proto_msgTypes[3]
    if protoimpl.UnsafeEnabled && x != nil {
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        if ms.LoadMessageInfo() == nil {
            ms.StoreMessageInfo(mi)
        }
        return ms
    }
    return mi.MessageOf(x)
}

// Deprecated: Use GetGoodsRequest.ProtoReflect.Descriptor instead.
func (*GetGoodsRequest) Descriptor() ([]byte, []int) {
    return file_proto_goodsinfo_proto_rawDescGZIP(), []int{3}
}

// 获取商品响应
type GetGoodsResponse struct {
    state         protoimpl.MessageState
    sizeCache     protoimpl.SizeCache
    unknownFields protoimpl.UnknownFields

    GoodsList []*GoodsModel `protobuf:"bytes,1,rep,name=GoodsList,proto3" json:"GoodsList,omitempty"`
}

func (x *GetGoodsResponse) Reset() {
    *x = GetGoodsResponse{}
    if protoimpl.UnsafeEnabled {
        mi := &file_proto_goodsinfo_proto_msgTypes[4]
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        ms.StoreMessageInfo(mi)
    }
}

func (x *GetGoodsResponse) String() string {
    return protoimpl.X.MessageStringOf(x)
}

func (*GetGoodsResponse) ProtoMessage() {}

func (x *GetGoodsResponse) ProtoReflect() protoreflect.Message {
    mi := &file_proto_goodsinfo_proto_msgTypes[4]
    if protoimpl.UnsafeEnabled && x != nil {
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        if ms.LoadMessageInfo() == nil {
            ms.StoreMessageInfo(mi)
        }
        return ms
    }
    return mi.MessageOf(x)
}

// Deprecated: Use GetGoodsResponse.ProtoReflect.Descriptor instead.
func (*GetGoodsResponse) Descriptor() ([]byte, []int) {
    return file_proto_goodsinfo_proto_rawDescGZIP(), []int{4}
}

func (x *GetGoodsResponse) GetGoodsList() []*GoodsModel {
    if x != nil {
        return x.GoodsList
    }
    return nil
}

var File_proto_goodsinfo_proto protoreflect.FileDescriptor

var file_proto_goodsinfo_proto_rawDesc = []byte{
    0x0a, 0x15, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x64, 0x73, 0x69, 0x6e, 0x66,
    0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x67, 0x6f, 0x6f, 0x64, 0x73, 0x69, 0x6e,
    0x66, 0x6f, 0x22, 0x52, 0x0a, 0x0a, 0x47, 0x6f, 0x6f, 0x64, 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x6c,
    0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
    0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18,
    0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x12, 0x18, 0x0a, 0x07,
    0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63,
    0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x40, 0x0a, 0x0f, 0x41, 0x64, 0x64, 0x47, 0x6f, 0x6f,
    0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2d, 0x0a, 0x06, 0x70, 0x61, 0x72,
    0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x67, 0x6f, 0x6f, 0x64,
    0x73, 0x69, 0x6e, 0x66, 0x6f, 0x2e, 0x47, 0x6f, 0x6f, 0x64, 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x6c,
    0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x22, 0x46, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x47,
    0x6f, 0x6f, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07,
    0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d,
    0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73,
    0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73,
    0x22, 0x11, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x47, 0x6f, 0x6f, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75,
    0x65, 0x73, 0x74, 0x22, 0x47, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x47, 0x6f, 0x6f, 0x64, 0x73, 0x52,
    0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x09, 0x47, 0x6f, 0x6f, 0x64, 0x73,
    0x4c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x67, 0x6f, 0x6f,
    0x64, 0x73, 0x69, 0x6e, 0x66, 0x6f, 0x2e, 0x47, 0x6f, 0x6f, 0x64, 0x73, 0x4d, 0x6f, 0x64, 0x65,
    0x6c, 0x52, 0x09, 0x47, 0x6f, 0x6f, 0x64, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x32, 0x99, 0x01, 0x0a,
    0x09, 0x47, 0x6f, 0x6f, 0x64, 0x73, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x45, 0x0a, 0x08, 0x41, 0x64,
    0x64, 0x47, 0x6f, 0x6f, 0x64, 0x73, 0x12, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x64, 0x73, 0x69, 0x6e,
    0x66, 0x6f, 0x2e, 0x41, 0x64, 0x64, 0x47, 0x6f, 0x6f, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
    0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x64, 0x73, 0x69, 0x6e, 0x66, 0x6f, 0x2e, 0x41,
    0x64, 0x64, 0x47, 0x6f, 0x6f, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
    0x00, 0x12, 0x45, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x47, 0x6f, 0x6f, 0x64, 0x73, 0x12, 0x1a, 0x2e,
    0x67, 0x6f, 0x6f, 0x64, 0x73, 0x69, 0x6e, 0x66, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x47, 0x6f, 0x6f,
    0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x64,
    0x73, 0x69, 0x6e, 0x66, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x47, 0x6f, 0x6f, 0x64, 0x73, 0x52, 0x65,
    0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x13, 0x5a, 0x11, 0x2e, 0x2f, 0x70, 0x72,
    0x6f, 0x74, 0x6f, 0x3b, 0x67, 0x6f, 0x6f, 0x64, 0x73, 0x69, 0x6e, 0x66, 0x6f, 0x62, 0x06, 0x70,
    0x72, 0x6f, 0x74, 0x6f, 0x33,
}

var (
    file_proto_goodsinfo_proto_rawDescOnce sync.Once
    file_proto_goodsinfo_proto_rawDescData = file_proto_goodsinfo_proto_rawDesc
)

func file_proto_goodsinfo_proto_rawDescGZIP() []byte {
    file_proto_goodsinfo_proto_rawDescOnce.Do(func() {
        file_proto_goodsinfo_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_goodsinfo_proto_rawDescData)
    })
    return file_proto_goodsinfo_proto_rawDescData
}

var file_proto_goodsinfo_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_proto_goodsinfo_proto_goTypes = []interface{}{
    (*GoodsModel)(nil),       // 0: goodsinfo.GoodsModel
    (*AddGoodsRequest)(nil),  // 1: goodsinfo.AddGoodsRequest
    (*AddGoodsResponse)(nil), // 2: goodsinfo.AddGoodsResponse
    (*GetGoodsRequest)(nil),  // 3: goodsinfo.GetGoodsRequest
    (*GetGoodsResponse)(nil), // 4: goodsinfo.GetGoodsResponse
}
var file_proto_goodsinfo_proto_depIdxs = []int32{
    0, // 0: goodsinfo.AddGoodsRequest.parame:type_name -> goodsinfo.GoodsModel
    0, // 1: goodsinfo.GetGoodsResponse.GoodsList:type_name -> goodsinfo.GoodsModel
    1, // 2: goodsinfo.Goodsinfo.AddGoods:input_type -> goodsinfo.AddGoodsRequest
    3, // 3: goodsinfo.Goodsinfo.GetGoods:input_type -> goodsinfo.GetGoodsRequest
    2, // 4: goodsinfo.Goodsinfo.AddGoods:output_type -> goodsinfo.AddGoodsResponse
    4, // 5: goodsinfo.Goodsinfo.GetGoods:output_type -> goodsinfo.GetGoodsResponse
    4, // [4:6] is the sub-list for method output_type
    2, // [2:4] is the sub-list for method input_type
    2, // [2:2] is the sub-list for extension type_name
    2, // [2:2] is the sub-list for extension extendee
    0, // [0:2] is the sub-list for field type_name
}

func init() { file_proto_goodsinfo_proto_init() }
func file_proto_goodsinfo_proto_init() {
    if File_proto_goodsinfo_proto != nil {
        return
    }
    if !protoimpl.UnsafeEnabled {
        file_proto_goodsinfo_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
            switch v := v.(*GoodsModel); i {
            case 0:
                return &v.state
            case 1:
                return &v.sizeCache
            case 2:
                return &v.unknownFields
            default:
                return nil
            }
        }
        file_proto_goodsinfo_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
            switch v := v.(*AddGoodsRequest); i {
            case 0:
                return &v.state
            case 1:
                return &v.sizeCache
            case 2:
                return &v.unknownFields
            default:
                return nil
            }
        }
        file_proto_goodsinfo_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
            switch v := v.(*AddGoodsResponse); i {
            case 0:
                return &v.state
            case 1:
                return &v.sizeCache
            case 2:
                return &v.unknownFields
            default:
                return nil
            }
        }
        file_proto_goodsinfo_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
            switch v := v.(*GetGoodsRequest); i {
            case 0:
                return &v.state
            case 1:
                return &v.sizeCache
            case 2:
                return &v.unknownFields
            default:
                return nil
            }
        }
        file_proto_goodsinfo_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
            switch v := v.(*GetGoodsResponse); i {
            case 0:
                return &v.state
            case 1:
                return &v.sizeCache
            case 2:
                return &v.unknownFields
            default:
                return nil
            }
        }
    }
    type x struct{}
    out := protoimpl.TypeBuilder{
        File: protoimpl.DescBuilder{
            GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
            RawDescriptor: file_proto_goodsinfo_proto_rawDesc,
            NumEnums:      0,
            NumMessages:   5,
            NumExtensions: 0,
            NumServices:   1,
        },
        GoTypes:           file_proto_goodsinfo_proto_goTypes,
        DependencyIndexes: file_proto_goodsinfo_proto_depIdxs,
        MessageInfos:      file_proto_goodsinfo_proto_msgTypes,
    }.Build()
    File_proto_goodsinfo_proto = out.File
    file_proto_goodsinfo_proto_rawDesc = nil
    file_proto_goodsinfo_proto_goTypes = nil
    file_proto_goodsinfo_proto_depIdxs = nil
}

goodsinfo.pb.micro.go代码如下:

// Code generated by protoc-gen-micro. DO NOT EDIT.
// source: proto/goodsinfo.proto

package goodsinfo

import (
    fmt "fmt"
    proto "google.golang.org/protobuf/proto"
    math "math"
)

import (
    context "context"
    api "go-micro.dev/v4/api"
    client "go-micro.dev/v4/client"
    server "go-micro.dev/v4/server"
)

// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf

// Reference imports to suppress errors if they are not otherwise used.
var _ api.Endpoint
var _ context.Context
var _ client.Option
var _ server.Option

// Api Endpoints for Goodsinfo service

func NewGoodsinfoEndpoints() []*api.Endpoint {
    return []*api.Endpoint{}
}

// Client API for Goodsinfo service

type GoodsinfoService interface {
    // AddGoods: 定义增加商品的微服务, 这里的写法和gRPC中的写法一致
    AddGoods(ctx context.Context, in *AddGoodsRequest, opts ...client.CallOption) (*AddGoodsResponse, error)
    GetGoods(ctx context.Context, in *GetGoodsRequest, opts ...client.CallOption) (*GetGoodsResponse, error)
}

type goodsinfoService struct {
    c    client.Client
    name string
}

func NewGoodsinfoService(name string, c client.Client) GoodsinfoService {
    return &goodsinfoService{
        c:    c,
        name: name,
    }
}

func (c *goodsinfoService) AddGoods(ctx context.Context, in *AddGoodsRequest, opts ...client.CallOption) (*AddGoodsResponse, error) {
    req := c.c.NewRequest(c.name, "Goodsinfo.AddGoods", in)
    out := new(AddGoodsResponse)
    err := c.c.Call(ctx, req, out, opts...)
    if err != nil {
        return nil, err
    }
    return out, nil
}

func (c *goodsinfoService) GetGoods(ctx context.Context, in *GetGoodsRequest, opts ...client.CallOption) (*GetGoodsResponse, error) {
    req := c.c.NewRequest(c.name, "Goodsinfo.GetGoods", in)
    out := new(GetGoodsResponse)
    err := c.c.Call(ctx, req, out, opts...)
    if err != nil {
        return nil, err
    }
    return out, nil
}

// Server API for Goodsinfo service

type GoodsinfoHandler interface {
    // AddGoods: 定义增加商品的微服务, 这里的写法和gRPC中的写法一致
    AddGoods(context.Context, *AddGoodsRequest, *AddGoodsResponse) error
    GetGoods(context.Context, *GetGoodsRequest, *GetGoodsResponse) error
}

func RegisterGoodsinfoHandler(s server.Server, hdlr GoodsinfoHandler, opts ...server.HandlerOption) error {
    type goodsinfo interface {
        AddGoods(ctx context.Context, in *AddGoodsRequest, out *AddGoodsResponse) error
        GetGoods(ctx context.Context, in *GetGoodsRequest, out *GetGoodsResponse) error
    }
    type Goodsinfo struct {
        goodsinfo
    }
    h := &goodsinfoHandler{hdlr}
    return s.Handle(s.NewHandler(&Goodsinfo{h}, opts...))
}

type goodsinfoHandler struct {
    GoodsinfoHandler
}

func (h *goodsinfoHandler) AddGoods(ctx context.Context, in *AddGoodsRequest, out *AddGoodsResponse) error {
    return h.GoodsinfoHandler.AddGoods(ctx, in, out)
}

func (h *goodsinfoHandler) GetGoods(ctx context.Context, in *GetGoodsRequest, out *GetGoodsResponse) error {
    return h.GoodsinfoHandler.GetGoods(ctx, in, out)
}

启动goodsinfo服务端:

[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务_第3张图片

启动后consul UI展示如下:

看到 注册了goodsinfo服务
[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务_第4张图片

goodsinfo详情界面:

[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务_第5张图片

二.使用Go Web框架Gin创建微服务客户端

  1. 搭建Gin框架

上一节的微服务是直接在 main.go中调用的,这里使用使用 Go Web框架Gin创建微服务客户端,
Gin框架需要自己搭建,这里参考 [golang gin框架] 1.Gin环境搭建,程序的热加载,路由GET,POST,PUT,DELETE 里面的内容来进行开发
[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务_第6张图片

搭建好了后,引入相关包:

[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务_第7张图片

测试Gin框架是否ok:

[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务_第8张图片
[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务_第9张图片
  1. 在Gin框架中集成微服务客户端-proto相关

把上面微服务服务端的proto文件夹赋值到项目根目录,如下:
[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务_第10张图片
然后查看相关包,看看是否引入,没有引入的话,在项目main.go所在的目录运行: go mod tidy 即可
  1. 在Gin框架中集成微服务客户端

还是以上面goodsinfo微服务为案例,集成goodsinfo微服务客户端

(1).封装创建consul的服务

参考上一节 goodsinfo客户端代码

上一节客户端代码如下:

package main

import (
    "context"
    "go-micro.dev/v4/registry"
    pb "goodsinfo-client/proto"
    "go-micro.dev/v4"
    "go-micro.dev/v4/logger"
    "github.com/go-micro/plugins/v4/registry/consul"
)

var (
    service = "goodsinfo"
    version = "latest"
)

func main() {
    //集成consul
    consulReg := consul.NewRegistry(
        //指定微服务的ip:  选择注册服务器地址,默认为本机,也可以选择consul集群中的client
        registry.Addrs("127.0.0.1:8500"),
        )
    // Create service
    srv := micro.NewService(
        //注册consul
        micro.Registry(consulReg),
    )

    srv.Init()

    // 创建客户端服务
    c := pb.NewGoodsinfoService(service, srv.Client())

    // Call service
    rsp, err := c.AddGoods(context.Background(), &pb.AddRequest{
        Title: "我是一个商品",
        Price: "20.22",
        Content: "内容展示",
    })
    if err != nil {
        logger.Fatal(err)
    }

    logger.Info(rsp)
}
上述代码分为两部分:第一部分是 集成consul, 第二部分是 创建客户端服务, 当一个项目中存在 多个微服务 时, 都要 使用到第一部分,所以第一部分是 公共的 ,可以把它 封装 一下,然后在各个微服务客户端中调用
在项目的models下创建initGoodsMicro.go,封装集成consul相关逻辑,代码如下:
package models

//微服务客户端配置: 初始化consul配置,当一个项目中多个微服务时,就很方便了
//建议:一个微服务对应一个客户端,这样好管理

import (
    "github.com/go-micro/plugins/v4/registry/consul"
    "go-micro.dev/v4"
    "go-micro.dev/v4/client"
    "go-micro.dev/v4/registry"
)

//MicroClient: 全局变量 在外部的包中可以调用
var MicroClient client.Client

//init 方法: 当程序运行时就会自动执行
func init() {
    consulRegistry := consul.NewRegistry(
        //指定微服务的ip:  选择注册服务器地址,默认为本机,也可以选择consul集群中的client,建议一个微服务对应一个consul集群的client
        registry.Addrs("127.0.0.1:8500"),
    )
    // Create service
    srv := micro.NewService(
        micro.Registry(consulRegistry),
    )
    srv.Init()

    MicroClient = srv.Client()
}

(2).创建Goods相关方法

在controllers/frontend下创建GoodsController,里面有两个方法:Index(获取商品列表),Add(添加商品),代码如下:
package frontend

import (
    "context"
    "gindemo/models"
    pb "gindemo/proto"
    "github.com/gin-gonic/gin"
    log "go-micro.dev/v4/logger"
)

type GoodsController struct{}

//获取商品列表
func (con GoodsController) Index(c *gin.Context) {
    // Create client: 这里的服务名称需要和服务端注册的名称一致
    microClient := pb.NewGoodsinfoService("goodsinfo", models.MicroClient)
    // Call service
    rsp, err := microClient.GetGoods(context.Background(), &pb.GetGoodsRequest{})
    //判断是否获取商品成功: 这里会调用服务端handler/goodsinfo.go中的方法GetGoods()
    if err != nil {
        log.Fatal(err)
    }
    //记录log
    log.Info(rsp)
    //返回
    c.JSON(200, gin.H{
        "result": rsp.GoodsList,
    })
}

//添加商品
func (con GoodsController) Add(c *gin.Context) {
    // Create client
    microClient := pb.NewGoodsinfoService("goodsinfo", models.MicroClient)
    // Call service
    rsp, err := microClient.AddGoods(context.Background(), &pb.AddGoodsRequest{
        Parame: &pb.GoodsModel{
            Title:   "我是一个商品",  //这里的商品数据是模拟数据, 一般项目中是从前端获取
            Price:   12.0,
            Content: "我是一个内容",
        },
    })
    //判断是否增加成功
    if err != nil {
        log.Fatal(err)
    }
    //记录log
    log.Info(rsp)
    //返回
    c.JSON(200, gin.H{
        "message": rsp.Message,
        "success": rsp.Success,
    })
}

(3).在routers/frontendRouters.go中增加路由

package routers

import (
    "gindemo/controllers/frontend"
    "github.com/gin-gonic/gin"
)

func DefaultRoutersInit(r *gin.Engine) {
    defaultRouters := r.Group("/")
    {
        defaultRouters.GET("/", frontend.DefaultController{}.Index)
        //获取商品列表
        defaultRouters.GET("/goods", frontend.GoodsController{}.Index)
        //添加商品
        defaultRouters.GET("/goods/add", frontend.GoodsController{}.Add)
    }
}

(4).查看微服务客户端是否成功

浏览器中访问 http://localhost:8080/goods,http://localhost:8080/goods/add看看是否返回数据
[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务_第11张图片
返回数据成功,说明微服务客户端搭建成功

三.go-micro的负载均衡在项目中的使用

  1. 把goodsinfo微服务放置到另一台服务器上

复制server/goodsinfo微服务服务端代码,把代码放置到 另一台服务器上,然后运行go run main.go把goodsinfo微服务注册到 consul集群中对应的 服务发现里面就可以了,为了区分是来自不同服务器的同一个微服务,这里在handler/goodsinfo.go修改一下,返回的Title进行一个标识,表示调用的是不同服务器上的微服务,达到 负载均衡的效果,代码如下:
package handler

import (
    "context"
    "strconv"
    "go-micro.dev/v4/logger"
    pb "goodsinfo/proto"
)

type Goodsinfo struct{}

//增加商品
func (e *Goodsinfo) AddGoods(ctx context.Context, req *pb.AddGoodsRequest, rsp *pb.AddGoodsResponse) error {
    logger.Infof("request: %v", req)
    //书写返回的逻辑结果
    rsp.Message = "增加成功"
    rsp.Success = true
    return nil
}

//获取商品
func (e *Goodsinfo) GetGoods(ctx context.Context, req *pb.GetGoodsRequest, rsp *pb.GetGoodsResponse) error {
    var tempList []*pb.GoodsModel
    //模拟从数据库中获取商品数据
    for i := 0; i < 10; i++ {
        tempList = append(tempList, &pb.GoodsModel{
            Title:   "goodsinfo1第" + strconv.Itoa(i) + "条数据",  // goodsinfo1或者goodsinfo2代表不同服务器的同一个微服务
            Price:   float64((i + 1) * 2),
            Content: "goodsinfo1第" + strconv.Itoa(i) + "内容",
        })
    }
    rsp.GoodsList = tempList
    return nil
}

main.go中代码:

修改 micro.Address("127.0.0.1:8080"), 这里面的ip表示不同consul集群服务器ip,在这里模拟不同服务器负载均衡,把 micro.Address("127.0.0.1:8080")修改为 micro.Address("127.0.0.1:8081"),表示在不同服务器上的同一个微服务
package main

import (
    "goodsinfo/handler"
    pb "goodsinfo/proto"
    "go-micro.dev/v4"
    "go-micro.dev/v4/logger"
    "github.com/go-micro/plugins/v4/registry/consul"
)

var (
    service = "goodsinfo"
    version = "latest"
)

func main() {
    //集成consul
    consulReg := consul.NewRegistry()
    // Create service
    srv := micro.NewService(
        micro.Address("127.0.0.1:8081"),  //指定微服务的ip:  选择注册服务器地址,也可以不配置,默认为本机,也可以选择consul集群中的client
        micro.Name(service),
        micro.Version(version),
        //注册consul
        micro.Registry(consulReg),
    )
    srv.Init(
        micro.Name(service),
        micro.Version(version),
    )

    // Register handler
    if err := pb.RegisterGoodsinfoHandler(srv.Server(), new(handler.Goodsinfo)); err != nil {
        logger.Fatal(err)
    }
    // Run service
    if err := srv.Run(); err != nil {
        logger.Fatal(err)
    }
}
  1. 启动goodsinfo微服务

启动不同服务器上的goodsinfo微服务
  1. consul UI上查看效果

[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务_第12张图片
[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务_第13张图片
说明微服务启动成功了
  1. 运行客户端代码

运行项目代码: go run main.go,访问http://localhost:8080/goods,这时客户端就会通过轮询的方式查询consul服务器的goodsinfo服务端微服务,可以通过刷新的方式来检测,看看是否轮询查询
[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务_第14张图片
[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务_第15张图片
通过上面的方式检测,发现客户端获取数据是通过轮询的方式从consul的不同微服务服务器上获取数据的,负载均衡操作就完成了

四.Go Web框架(Beego)调用go-micro微服务

  1. 新建beego项目

在新建beego目录之前,需要按照go以及配置其环境变量,见 [go学习笔记.第二章] 2.go语言的开发工具以及安装和配置SDK, 以及bee 工具,bee工具的安装见 Beego之Bee安装(Windows)以及创建,运行项目
在client目录下创建beego项目,使用命令 bee new beegodemo创建一个beego项目,如下图:
[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务_第16张图片

生成的项目目录:

[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务_第17张图片
  1. 初始化项目

先删除go.mod文件,然后通过 go mod init beegodemo, go mod tidy 引入包,重新初始化项目
[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务_第18张图片
  1. 测试项目是否正常

(1).在controllers下新建goods.go

代码如下:
package controllers

//商品相关

import (
    beego "github.com/beego/beego/v2/server/web"
)

type GoodsController struct {
    beego.Controller
}

func (c *GoodsController) Get() {
    c.Data["json"] =map[string]interface{} {
        "message": "get",
    }

    c.ServeJSON()
}

func (c *GoodsController) Add() {
    c.Data["json"] =map[string]interface{} {
        "message": "add",
    }

    c.ServeJSON()
}

(2).设置路由

在routers/routers.go中完善控制器goods.go中的路由方法,代码如下:
package routers

import (
    "beegodemo/controllers"
    beego "github.com/beego/beego/v2/server/web"
)

func init() {
    beego.Router("/", &controllers.MainController{})

    //goods相关路由
    beego.Router("/goods", &controllers.GoodsController{})
    beego.Router("/goods/add", &controllers.GoodsController{}, "get:Add") //这里测试使用get方式,正式项目使用restful模式操作
}

(3).运行

在项目目录下,运行 bee run,然后浏览器中访问:http://127.0.0.1:8080/goods,看看是否正常显示相关数据
[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务_第19张图片
[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务_第20张图片
项目运行正常
  1. 搭建goodsinfo商品微服务beego客户端

(1).引入proto文件

把上面gin项目中的 proto文件复制到beegodemo项目下

(2).引入initGoodsMicro.go

把上面gin项目中的models/ initGoodsMicro.go文件复制到beegodemo项目models下

(3).编写controllers/goods.go代码

完善goods.go下的方法:商品列表方法Get(), 增加商品方法Add(),代码如下:
package controllers

//商品相关

import (
    "context"
    "beegodemo/models"
    pb "beegodemo/proto"
    log "go-micro.dev/v4/logger"
    beego "github.com/beego/beego/v2/server/web"

)

type GoodsController struct {
    beego.Controller
}

//商品列表
func (c *GoodsController) Get() {
    // Create client: 这里的服务名称需要和服务端注册的名称一致
    microClient := pb.NewGoodsinfoService("goodsinfo", models.MicroClient)
    // Call service
    rsp, err := microClient.GetGoods(context.Background(), &pb.GetGoodsRequest{})
    //判断是否获取商品成功: 这里会调用服务端handler/goodsinfo.go中的方法GetGoods()
    if err != nil {
        log.Fatal(err)
    }
    //记录log
    log.Info(rsp)
    //返回
    c.Data["json"] =map[string]interface{} {
        "result": rsp.GoodsList,
    }

    c.ServeJSON()
}

//添加商品
func (c *GoodsController) Add() {
    // Create client
    microClient := pb.NewGoodsinfoService("goodsinfo", models.MicroClient)
    // Call service
    rsp, err := microClient.AddGoods(context.Background(), &pb.AddGoodsRequest{
        Parame: &pb.GoodsModel{
            Title:   "增加一个商品beego",  //这里的商品数据是模拟数据, 一般项目中是从前端获取
            Price:   12.0,
            Content: "我是一个内容beego",
        },
    })
    //判断是否增加成功
    if err != nil {
        log.Fatal(err)
    }
    //记录log
    log.Info(rsp)
    //返回
    c.Data["json"] =map[string]interface{} {
        "message": rsp.Message,
        "success": rsp.Success,
    }
    c.ServeJSON()
}

(4).引入项目所需的包

再次执行命令 go mod tidy引入项目需要的包,在这里可以会出现不能引入包的情况,则需要 手动执行,命令为 go get xxx,也可以参考 https://blog.csdn.net/zhoupenghui168/article/details/131252892#t9

(5).启动微服务服务端

参考第三步骤: 三.go-micro的 负载均衡在项目中的使用
[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务_第21张图片
[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务_第22张图片
查看consul UI,看看goodsinfo微服务是否启动成功
[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务_第23张图片

(6).查看是否能够访问,是否可以负载均衡操作

1).先运行bee run,启动项目

[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务_第24张图片

2).访问

访问http://127.0.0.1:8080/goods,以及http://127.0.0.1:8080/goods/add,看看是否成功
[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务_第25张图片

刷新页面,查看:

[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务_第26张图片
[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务_第27张图片
[golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务_第28张图片
好了,Beego框架调用go-micro微服务功能完成
  1. 总结

Beego框架调用go-micro微服务其实和Gin框架调用go-micro微服务差不多,主要的区别就是需要下载bee工具,以及要引入beego框架所需要的包,然后就是框架的路由操作,返回操作略有不同

[上一节][golang 微服务] 7. go-micro框架介绍,go-micro脚手架,go-micro结合consul搭建微服务案例

[下一节][golang 微服务] 9.go-micro + gorm实现商品微服务的分页查询

你可能感兴趣的:(golang,#,beego框架,#,golang微服务,微服务,Gin,Beego,bee,go,micro)