V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
qloog
V2EX  ›  Go 编程语言

继续分享个 Go 微服务实战 - 关系服务(gRPC)

  •  1
     
  •   qloog · 2023-01-17 15:35:06 +08:00 · 2569 次点击
    这是一个创建于 680 天前的主题,其中的信息可能已经有所发展或是发生改变。

    概要

    关系服务基本也是每个互联网产品里必备的一个服务了,可以更好的增加应用的社交属性。本文主要介绍下如何快速开发一个关系微服务,以及其详细开发流程。

    目录

    调用流程图

    user-service.drawio.png

    技术栈

    接口开发

    使用 proto 方式定义,主要包含以下接口

    relation-proto.png

    开发步骤

    这里详细的记录了开发的步骤,方便参看本项目的同学知道其实现过程。

    1 、生成 proto 模板文件

    eagle proto add api/relation/v1/relation.proto
    

    内容如下

    syntax = "proto3";
    
    package relation.v1;
    
    option go_package = "github.com/go-microservice/relation-service/api/relation/v1;v1";
    option java_multiple_files = true;
    option java_package = "api.relation.v1";
    
    service RelationService {
    	rpc CreateRelation (CreateRelationRequest) returns (CreateRelationReply);
    	rpc UpdateRelation (UpdateRelationRequest) returns (UpdateRelationReply);
    	rpc DeleteRelation (DeleteRelationRequest) returns (DeleteRelationReply);
    	rpc GetRelation (GetRelationRequest) returns (GetRelationReply);
    	rpc ListRelation (ListRelation1Request) returns (ListRelationReply);
    }
    
    message CreateRelation1Request {}
    message CreateRelation1Reply {}
    
    message UpdateRelationRequest {}
    message UpdateRelationReply {}
    
    message DeleteRelationRequest {}
    message DeleteRelationReply {}
    
    message GetRelationRequest {}
    message GetRelationReply {}
    
    message ListRelationRequest {}
    message ListRelationReply {}
    

    然后将方法及 request 改为自己要定义的名称

    2 、为 proto 填充业务方法及字段定义

    vim api/relation/v1/relation.proto
    

    3 、生成 pb 文件

    会生成两个文件 api/relation/v1/relation.pb.goapi/relation/v1/relation_grpc.pb.go

    # 生成所有 proto
    make grpc
    
    # 或者
    # 生成指定 proto 的 pb 文件
    eagle proto client api/relation/v1/relation.proto
    
    # Output
    ll api/relation/v1/
    relation.proto
    relation.pb.go # 新增
    relation_grpc.pb.go # 新增
    

    4 、生成 server 骨架代码

    # 生成骨架代码
    eagle proto server api/relation/v1/relation.proto
    
    # 默认会输出到 internal/service
    # 如果需要指定到对应的目录,可以使用 -t 参数, eg: 
    # eagle proto server -t internal/logic
    
    # 查看
    internal/service/relation_svc.go
    

    5 、注册服务到 gRPC Server

    // internal/server/grpc.go 
    
    import (
    		...
    		v1 "github.com/go-microservice/relation-service/api/relation/v1"
    		...
    )
    
    ...
    
    // NewGRPCServer creates a gRPC server
    func NewGRPCServer(
    	cfg *app.ServerConfig,
    	// 新增
    	svc *service.RelationServiceServer, 
    ) *grpc.Server {
    
    	grpcServer := grpc.NewServer(
    		grpc.Network("tcp"),
    		grpc.Address(cfg.Addr),
    		grpc.Timeout(cfg.WriteTimeout),
    	)
    
    	// register biz service
    	// 新增
    	v1.RegisterRelationServiceServer(grpcServer, svc)
    
    	return grpcServer
    }
    

    6 、在生成的 service 中编写业务逻辑

    在下面生成的 service 里补充自己的业务逻辑

    // vim internal/service/relationservice_grpc.go
    
    package service
    
    import (
    	"context"
    
    	pb "github.com/go-microservice/relation-service/api/relation/v1"
    )
    
    var (
    	_ pb.RelationServiceServer = (*RelationServiceServer)(nil)
    )
    
    type RelationServiceServer struct {
    	pb.UnimplementedRelationServiceServer
    }
    
    func NewRelationServiceServer() *RelationServiceServer {
    	return &RelationServiceServer{}
    }
    
    func (s *RelationServiceServer) CreateRelation(ctx context.Context, req *pb.CreateRelationRequest) (*pb.CreateRelationReply, error) {
    	return &pb.CreateRelationReply{}, nil
    }
    func (s *RelationServiceServer) UpdateRelation(ctx context.Context, req *pb.UpdateRelationRequest) (*pb.UpdateRelationReply, error) {
    	return &pb.UpdateRelationReply{}, nil
    }
    func (s *RelationServiceServer) DeleteRelation(ctx context.Context, req *pb.DeleteRelationRequest) (*pb.DeleteRelationReply, error) {
    	return &pb.DeleteRelationReply{}, nil
    }
    func (s *RelationServiceServer) GetRelation(ctx context.Context, req *pb.GetRelationRequest) (*pb.GetRelationReply, error) {
    	return &pb.GetRelationReply{}, nil
    }
    func (s *RelationServiceServer) ListRelation(ctx context.Context, req *pb.ListRelationRequest) (*pb.ListRelationReply, error) {
    	return &pb.ListRelationReply{}, nil
    }
    

    7 、启动服务

    # 在根目录下运行
    go build
    
    # 启动
    ./relation -c=config -e=dev
    

    确保运行 gRPC server

    // main.go
    
    ...
    eagle.WithServer(
    	// init gRPC server
    	gs,
    ),
    ...
    

    8 、接口调试

    调试工具,这里使用 grpcurl

    # 查看服务列表
    grpcurl -plaintext localhost:9099 list
    
    # Output
    grpc.health.v1.Health
    grpc.reflection.v1alpha.ServerReflection
    relation.v1.RelationService
    
    # 访问关注列表
    grpcurl -plaintext -d '{"user_id":2}' localhost:9099 relation.v1.RelationService/GetFollowingList
    

    参数说明

    • -d 提交的参数,json 格式
    • -plaintext 使用纯文本连接,跳过 TLS

    也可以使用以下工具进行本地测试

    部署

    两种部署方式

    • docker
    • k8s (本地部署可以使用 minikube)

    部署步骤

    • 构建 docker 镜像

      docker build -t relation-service:v1.0.0 -f deploy/docker/Dockerfile .
      
    • 打 docker tag

      docker tag relation-service:v1.0.0 qloog/relation-service:v1.0.0
      
    • push tag 到 docker hub

      docker push qloog/relation-service:v1.0.0
      
    • 部署到 k8s

      kubectl apply -f deploy/k8s/go-deployment.yaml
      kubectl apply -f deploy/k8s/go-service.yaml
      

    以上命令都是一步一步执行的,为了方便期间,这里也提供了一件部署脚本,执行如下

    sh deploy/deploy.sh
    

    项目源码

    最终源码在这里:https://github.com/go-microservice/relation-service

    完结

    到此,开发、测试、部署已经操作完了,后面会继续完善单元测试、监控及部署相关的部分。

    感谢阅读, 祝大家 Happy coding~

    最后预祝大家新年快乐~~

    6 条回复    2023-07-05 10:10:17 +08:00
    Chinsung
        1
    Chinsung  
       2023-01-17 16:58:13 +08:00
    follow 关系的命名有点混乱
    代码注释有点少,感觉你方法的命名不能很好体现方法是干啥的,可读性比较差
    qloog
        2
    qloog  
    OP
       2023-01-17 17:23:12 +08:00
    @Chinsung 感谢反馈。那如何改进呢?有没有具体的建议或参考
    realityone
        3
    realityone  
       2023-01-17 18:23:29 +08:00
    https://v2ex.com/t/881984#reply0

    感觉和你这篇文章差别不大
    qloog
        4
    qloog  
    OP
       2023-01-19 08:47:52 +08:00
    @realityone 嗯,使用一样的框架,所以开发方式基本一样 ,主要是一些功能上的区别。
    Chinsung
        5
    Chinsung  
       2023-01-19 10:51:14 +08:00   ❤️ 1
    @qloog #2 该写注释的地方就都写,你是有些方法里有有些方法里直接 0 注释,follower 和 followed 方法的区别关系,包括入参的命名都可以清晰点,比如 follower.getUserid ,user.getFollowerIds ,这种主被关系明显一点的命名可读性会好很多
    qloog
        6
    qloog  
    OP
       2023-07-05 10:10:17 +08:00
    @Chinsung 感谢建议,后续再优化一下命名。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5753 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 06:36 · PVG 14:36 · LAX 22:36 · JFK 01:36
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.