Go Web 编程快速入门 12 - 微服务架构:服务发现、负载均衡与分布式系统
微服务将系统拆分为可独立部署的服务,每个服务围绕业务能力构建、独立扩展与演进。本章以第 04.1 章的“循序渐进+可运行示例”的风格,讲解服务注册与发现、负载均衡、分布式协调与事务的基础落地方式,并完成一个最小可用的“网关调用用户服务”的示例。
1 微服务基础概念
1.1 服务接口与生命周期
type Service interface {Name() stringVersion() stringStart() errorStop() errorHealth() error
}type BaseService struct {name    stringversion stringsrv     *http.Server
}func NewBaseService(name, version string, handler http.Handler, addr string) *BaseService {return &BaseService{ name: name, version: version, srv: &http.Server{Addr: addr, Handler: handler} }
}func (s *BaseService) Name() string    { return s.name }
func (s *BaseService) Version() string { return s.version }
func (s *BaseService) Start() error    { go s.srv.ListenAndServe(); return nil }
func (s *BaseService) Stop() error     { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second); defer cancel(); return s.srv.Shutdown(ctx) }
func (s *BaseService) Health() error   { return nil }
1.2 健康检查端点
func HealthHandler(name, version string) http.HandlerFunc {return func(w http.ResponseWriter, r *http.Request) {w.Header().Set("Content-Type", "application/json")_ = json.NewEncoder(w).Encode(map[string]string{"status": "healthy", "service": name, "version": version})}
}
2 服务注册与发现(最小内存注册表)
2.1 注册表与服务信息
type ServiceInfo struct {Name    stringVersion stringAddress string // hostPort    intTags    []string
}type Registry struct { store map[string][]ServiceInfo }func NewRegistry() *Registry { return &Registry{store: make(map[string][]ServiceInfo)} }func (r *Registry) Register(info ServiceInfo) { r.store[info.Name] = append(r.store[info.Name], info) }
func (r *Registry) Discover(name string) []ServiceInfo { return r.store[name] }
2.2 客户端发现与调用
type Client struct { reg *Registry; lb LoadBalancer; httpc *http.Client }func NewClient(reg *Registry, lb LoadBalancer) *Client {return &Client{reg: reg, lb: lb, httpc: &http.Client{Timeout: 3 * time.Second}}
}func (c *Client) CallJSON(ctx context.Context, svcName, path string, req, resp interface{}) error {insts := c.reg.Discover(svcName)if len(insts) == 0 { return fmt.Errorf("未发现服务: %s", svcName) }inst, err := c.lb.Select(insts)if err != nil { return err }url := fmt.Sprintf("http://%s:%d%s", inst.Address, inst.Port, path)var body io.Readerif req != nil { b, _ := json.Marshal(req); body = bytes.NewReader(b) }httpReq, _ := http.NewRequestWithContext(ctx, http.MethodPost, url, body)httpReq.Header.Set("Content-Type", "application/json")httpResp, err := c.httpc.Do(httpReq)if err != nil { return err }defer httpResp.Body.Close()if httpResp.StatusCode >= 400 { return fmt.Errorf("HTTP错误: %s", httpResp.Status) }if resp != nil { return json.NewDecoder(httpResp.Body).Decode(resp) }return nil
}
3 负载均衡实现(轮询)
type LoadBalancer interface { Select([]ServiceInfo) (ServiceInfo, error) }type RoundRobin struct { idx int32 }func (rr *RoundRobin) Select(list []ServiceInfo) (ServiceInfo, error) {if len(list) == 0 { return ServiceInfo{}, fmt.Errorf("无可用实例") }i := atomic.AddInt32(&rr.idx, 1)return list[int(i)%len(list)], nil
}
4 分布式锁与协调(接口与简化实现)
为了讲解思路,我们先定义接口与最小可用实现(内存锁,单实例适用;生产可替换为 Redis/Etcd/ZooKeeper 等)。
type DistLock interface {TryLock(key string, ttl time.Duration) boolUnlock(key string)
}type MemLock struct { m sync.Map }func (l *MemLock) TryLock(key string, ttl time.Duration) bool {_, loaded := l.m.LoadOrStore(key, time.Now().Add(ttl))return !loaded
}
func (l *MemLock) Unlock(key string) { l.m.Delete(key) }
5 分布式事务入门(两阶段思想)
接口化事务参与者与事务管理器,结合持久化与消息队列可进一步增强。本章提供概念与最小骨架示例。
type TxParticipant interface {ID() stringPrepare(ctx context.Context, txID string) errorCommit(ctx context.Context, txID string) errorRollback(ctx context.Context, txID string) error
}type TxManager struct {}func (m *TxManager) TwoPhaseCommit(ctx context.Context, txID string, ps []TxParticipant) error {for _, p := range ps { if err := p.Prepare(ctx, txID); err != nil { for _, rp := range ps { _ = rp.Rollback(ctx, txID) }; return err } }for _, p := range ps { if err := p.Commit(ctx, txID); err != nil { return err } }return nil
}
6 实战:网关调用用户服务
6.1 用户服务(提供 /user/info)
func userHandler(w http.ResponseWriter, r *http.Request) {w.Header().Set("Content-Type", "application/json")_ = json.NewEncoder(w).Encode(map[string]interface{"id": 1, "name": "Alice"})
}func startUserService(reg *Registry) {mux := http.NewServeMux()mux.HandleFunc("/user/info", userHandler)mux.HandleFunc("/health", HealthHandler("user-service", "v1"))svc := NewBaseService("user-service", "v1", mux, ":8081")_ = svc.Start()reg.Register(ServiceInfo{Name: svc.Name(), Version: svc.Version(), Address: "127.0.0.1", Port: 8081})
}
6.2 网关服务(转发到用户服务)
func startGateway(reg *Registry) {client := NewClient(reg, &RoundRobin{})mux := http.NewServeMux()mux.HandleFunc("/api/user", func(w http.ResponseWriter, r *http.Request) {var resp map[string]interface{}if err := client.CallJSON(r.Context(), "user-service", "/user/info", nil, &resp); err != nil {http.Error(w, err.Error(), http.StatusBadGateway); return}w.Header().Set("Content-Type", "application/json")_ = json.NewEncoder(w).Encode(resp)})mux.HandleFunc("/health", HealthHandler("gateway", "v1"))svc := NewBaseService("gateway", "v1", mux, ":8080")_ = svc.Start()
}
6.3 启动主函数
func main() {reg := NewRegistry()startUserService(reg)startGateway(reg)log.Println("网关: http://localhost:8080/api/user")select{} // 阻塞主协程
}
至此,我们实现了最小可用的注册、发现与负载均衡链路。生产环境中可将注册中心替换为 Consul/Etcd/Kubernetes,加入健康上报、摘除、熔断与重试策略。
