Linux 环境下用 Go 构建分布式系统的实践路线
一、架构与通信选型
二、最小落地示例 主从任务分发
syntax = "proto3";
package core;
option go_package = ".;core";
message Request { string action = 1; }
message Response { string data = 1; }
service NodeService {
rpc ReportStatus(Request) returns (Response);
rpc AssignTask(Request) returns (stream Response);
}
go install google.golang.org/grpc
go install google.golang.org/protobuf/cmd/protoc-gen-go
go install google.golang.org/protobuf/cmd/protoc-gen-go-grpc
mkdir -p core
protoc --go_out=./core --go-grpc_out=./core core/node.proto
// core/master.go
package core
import (
"context"
"net"
"net/http"
"github.com/gin-gonic/gin"
"google.golang.org/grpc"
)
type NodeServiceGrpcServer struct {
UnimplementedNodeServiceServer
CmdChannel chan string
}
func (n *NodeServiceGrpcServer) ReportStatus(ctx context.Context, req *Request) (*Response, error) {
return &Response{Data: "ok"}, nil
}
func (n *NodeServiceGrpcServer) AssignTask(req *Request, srv NodeService_AssignTaskServer) error {
for {
select {
case cmd := <-n.CmdChannel:
if err := srv.Send(&Response{Data: cmd}); err != nil {
return err
}
}
}
}
type MasterNode struct {
api *gin.Engine
ln net.Listener
svr *grpc.Server
nodeSvr *NodeServiceGrpcServer
}
func (n *MasterNode) Init() error {
var err error
n.ln, err = net.Listen("tcp", ":50051")
if err != nil { return err }
n.svr = grpc.NewServer()
n.nodeSvr = &NodeServiceGrpcServer{CmdChannel: make(chan string, 128)}
RegisterNodeServiceServer(n.svr, n.nodeSvr)
n.api = gin.Default()
n.api.POST("/tasks", func(c *gin.Context) {
var p struct{ Cmd string `json:"cmd"` }
if err := c.ShouldBindBodyWithJSON(&p); err != nil {
c.AbortWithStatus(http.StatusBadRequest)
return
}
n.nodeSvr.CmdChannel <- p.Cmd
c.Status(http.StatusOK)
})
return nil
}
func (n *MasterNode) Start() {
go n.svr.Serve(n.ln)
_ = n.api.Run(":9092")
}
// core/worker.go
package core
import (
"context"
"fmt"
"os/exec"
"strings"
"google.golang.org/grpc"
)
type WorkerNode struct {
conn *grpc.ClientConn
c NodeServiceClient
}
func (n *WorkerNode) Init() error {
var err error
n.conn, err = grpc.Dial("localhost:50051", grpc.WithInsecure())
if err != nil { return err }
n.c = NewNodeServiceClient(n.conn)
return nil
}
func (n *WorkerNode) Start() {
fmt.Println("worker started")
_, _ = n.c.ReportStatus(context.Background(), &Request{})
stream, _ := n.c.AssignTask(context.Background(), &Request{})
for {
res, err := stream.Recv()
if err != nil { return }
fmt.Print("received command: ", res.Data)
parts := strings.Fields(res.Data)
if len(parts) > 0 {
_ = exec.Command(parts[0], parts[1:]...).Run()
}
}
}
# 终端1:启动主节点
go run main.go master
# 终端2:启动工作节点
go run main.go worker
# 终端3:下发任务
curl -X POST -H "Content-Type: application/json" \
-d '{"cmd":"touch /tmp/test.txt"}' http://localhost:9092/tasks
该示例展示了基于 gRPC 的主从架构、服务注册/发现可替换为 etcd/Consul,生产环境应加入 TLS、重试、超时、背压与限流 等健壮性机制。
三、服务治理与工程化实践
四、部署与运维要点