Skip to content

5.5 微服务基础 ​

gRPC 基础 ​

protobuf
// proto/user.proto
syntax = "proto3";
package user;
option go_package = "example.com/user";

service UserService {
    rpc GetUser(GetUserRequest) returns (User);
    rpc ListUsers(ListUsersRequest) returns (ListUsersResponse);
    rpc CreateUser(CreateUserRequest) returns (User);
}

message User {
    int32 id = 1;
    string name = 2;
    string email = 3;
}

message GetUserRequest {
    int32 id = 1;
}

message ListUsersRequest {
    int32 page = 1;
    int32 page_size = 2;
}

message ListUsersResponse {
    repeated User users = 1;
    int32 total = 2;
}
go
// 生成代码
// protoc --go_out=. --go_opt=paths=source_relative \
//        --go-grpc_out=. --go-grpc_opt=paths=source_relative \
//        user.proto

// gRPC 服务器
type UserService struct {
    pb.UnimplementedUserService
}

func (s *UserService) GetUser(ctx context.Context, req *pb.GetUserRequest) (*pb.User, error) {
    return &pb.User{Id: req.Id, Name: "Alice"}, nil
}

lis, _ := net.Listen("tcp", ":50051")
server := grpc.NewServer()
pb.RegisterUserService(server, &UserService{})
server.Serve(lis)

// gRPC 客户端
conn, _ := grpc.Dial("localhost:50051", grpc.WithInsecure())
client := pb.NewUserServiceClient(conn)
resp, _ := client.GetUser(context.Background(), &pb.GetUserRequest{Id: 1})

Protocol Buffers ​

protobuf
// 标量类型
// double, float, int32, int64, uint32, uint64
// sint32, sint64, fixed32, fixed64, sfixed32, sfixed64
// bool, string, bytes

// 字段规则
optional  // 可有可无
repeated  // 数组
oneof     // 多选一

// 枚举
enum Status {
    STATUS_UNKNOWN = 0;
    STATUS_ACTIVE = 1;
}

// Map
map<string, int32> scores = 1;

// 嵌套消息
message Address {
    string street = 1;
    string city = 2;
}

message Person {
    string name = 1;
    Address address = 2;
}

服务发现 ​

go
// etcd 服务发现
import "github.com/etcd-io/etcd/client/v3"

// 服务注册
func RegisterService(etcdClient *clientv3.Client, serviceName, serviceAddr string) {
    key := fmt.Sprintf("/services/%s/%s", serviceName, serviceAddr)
    etcdClient.Put(context.Background(), key, serviceAddr)
}

// 服务发现
func DiscoverService(etcdClient *clientv3.Client, serviceName string) ([]string, error) {
    resp, _ := etcdClient.Get(context.Background(),
        fmt.Sprintf("/services/%s/", serviceName),
        clientv3.WithPrefix())

    var addrs []string
    for _, kv := range resp.Kvs {
        addrs = append(addrs, string(kv.Value))
    }
    return addrs, nil
}

负载均衡 ​

go
// gRPC 负载均衡
conn, _ := grpc.Dial(
    "etcd:///myservice",
    grpc.WithInsecure(),
    grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy":"round_robin"}`),
)

// 客户端负载均衡策略:
// 1. 随机
// 2. 轮询
// 3. 加权
// 4. 最少连接