Go 语言生产级工程实践指南¶
在工业级微服务开发中,Go 语言以其原生协程并发模型和高性能运行时,成为了 gRPC 技术栈最为普及的一门语言。
1. 推荐工程目录结构¶
遵循标准 Go 工程布局规范(Standard Go Project Layout):
my-grpc-service/
├── api/
│ └── v1/
│ ├── order.proto # 接口定义源文件
│ ├── order.pb.go # protoc 生成的消息代码
│ └── order_grpc.pb.go # protoc 生成的 gRPC 桩代码
├── cmd/
│ ├── server/
│ │ └── main.go # 服务端主入口
│ └── client/
│ └── main.go # 客户端测试或 CLI 工具
├── internal/
│ ├── service/
│ │ └── order_service.go # 业务逻辑与接口实现
│ └── interceptor/
│ ├── logging.go # 日志中间件
│ └── recovery.go # Panic 恢复中间件
├── go.mod
├── go.sum
└── Makefile # 编译生成命令脚本
2. 契约定义 (api/v1/order.proto)¶
syntax = "proto3";
package order.v1;
option go_package = "my-grpc-service/api/v1;orderv1";
service OrderService {
// 一元调用:创建订单
rpc CreateOrder(CreateOrderRequest) returns (CreateOrderResponse);
// 服务端流:实时跟踪订单履约状态流
rpc TrackOrder(TrackOrderRequest) returns (stream TrackOrderResponse);
}
message CreateOrderRequest {
string user_id = 1;
double amount = 2;
repeated string item_ids = 3;
}
message CreateOrderResponse {
string order_id = 1;
string status = 2;
}
message TrackOrderRequest {
string order_id = 1;
}
message TrackOrderResponse {
string status = 1;
string message = 2;
int64 timestamp = 3;
}
编译命令:
protoc -I. \
--go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
api/v1/order.proto
3. 服务端生产级实现 (cmd/server/main.go)¶
涵盖拦截器链、优雅停机(Graceful Shutdown)与标准健康检查(Health Check):
package main
import (
"context"
"fmt"
"log"
"net"
"os"
"os/signal"
"syscall"
"time"
pb "my-grpc-service/api/v1"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/health"
healthpb "google.golang.org/grpc/health/grpc_health_v1"
"google.golang.org/grpc/status"
)
type orderServiceServer struct {
pb.UnimplementedOrderServiceServer
}
func (s *orderServiceServer) CreateOrder(ctx context.Context, req *pb.CreateOrderRequest) (*pb.CreateOrderResponse, error) {
if req.GetUserId() == "" {
return nil, status.Error(codes.InvalidArgument, "user_id 不能为空")
}
orderID := fmt.Sprintf("ord_%d", time.Now().UnixNano())
return &pb.CreateOrderResponse{
OrderId: orderID,
Status: "CREATED",
}, nil
}
func (s *orderServiceServer) TrackOrder(req *pb.TrackOrderRequest, stream pb.OrderService_TrackOrderServer) error {
steps := []string{"订单已确认", "商品拣货中", "顺丰速递已揽件", "派送中", "已签收"}
for _, step := range steps {
// 监听客户端是否提前取消监听
if err := stream.Context().Err(); err != nil {
return status.FromContextError(err).Err()
}
err := stream.Send(&pb.TrackOrderResponse{
Status: step,
Message: fmt.Sprintf("订单 %s 状态已变更: %s", req.GetOrderId(), step),
Timestamp: time.Now().Unix(),
})
if err != nil {
return err
}
time.Sleep(500 * time.Millisecond) // 模拟状态推送间隔
}
return nil
}
func main() {
lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalf("端口监听失败: %v", err)
}
// 创建 gRPC 服务端并挂载拦截器
server := grpc.NewServer()
// 注册业务服务
orderSvc := &orderServiceServer{}
pb.RegisterOrderServiceServer(server, orderSvc)
// 注册官方标准 Health Check 协议服务
healthServer := health.NewServer()
healthServer.SetServingStatus("", healthpb.HealthCheckResponse_SERVING)
healthServer.SetServingStatus("order.v1.OrderService", healthpb.HealthCheckResponse_SERVING)
healthpb.RegisterHealthServer(server, healthServer)
// 协程启动监听
go func() {
log.Println("gRPC 生产服务启动在 :50051 ...")
if err := server.Serve(lis); err != nil && err != grpc.ErrServerStopped {
log.Fatalf("Serve 发生异常: %v", err)
}
}()
// 优雅停机信号监听 (SIGINT, SIGTERM)
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
log.Println("收到关机信号,执行优雅停止...")
// 设置健康检查状态为 NOT_SERVING,通知负载均衡器摘除流量
healthServer.SetServingStatus("", healthpb.HealthCheckResponse_NOT_SERVING)
// GracefulStop 会等待所有活跃 RPC 运行结束并拒绝新请求
server.GracefulStop()
log.Println("gRPC 服务平滑退出完毕")
}
4. 客户端生产级实践 (cmd/client/main.go)¶
涵盖连接单例复用、超时控制与服务流消费:
package main
import (
"context"
"io"
"log"
"time"
pb "my-grpc-service/api/v1"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
func main() {
// 客户端长连接全局复用
conn, err := grpc.Dial(
"localhost:50051",
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
if err != nil {
log.Fatalf("连接失败: %v", err)
}
defer conn.Close()
client := pb.NewOrderServiceClient(conn)
// 1. 一元调用 (必须带超时)
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
createResp, err := client.CreateOrder(ctx, &pb.CreateOrderRequest{
UserId: "u-9988",
Amount: 199.9,
ItemIds: []string{"item-1", "item-2"},
})
if err != nil {
log.Fatalf("创建订单错误: %v", err)
}
log.Printf("订单创建成功: ID=%s, Status=%s", createResp.GetOrderId(), createResp.GetStatus())
// 2. 服务端流式消费
streamCtx, streamCancel := context.WithTimeout(context.Background(), 5*time.Second)
defer streamCancel()
stream, err := client.TrackOrder(streamCtx, &pb.TrackOrderRequest{
OrderId: createResp.GetOrderId(),
})
if err != nil {
log.Fatalf("订阅订单流失败: %v", err)
}
for {
item, err := stream.Recv()
if err == io.EOF {
log.Println("服务端流传输正常结束")
break
}
if err != nil {
log.Fatalf("接收流数据异常: %v", err)
}
log.Printf("[流事件] 状态: %s, 详情: %s", item.GetStatus(), item.GetMessage())
}
}