微服务将系统拆分为可独立部署的服务,每个服务围绕业务能力构建、独立扩展与演进。本章以第 04.1 章的"循序渐进+可运行示例"的风格,讲解服务注册与发现、负载均衡、分布式协调与事务的基础落地方式,并完成一个最小可用的"网关调用用户服务"的示例。
1 微服务基础概念
1.1 服务接口与生命周期
go
type Service interface {
Name() string
Version() string
Start() error
Stop() error
Health() error
}
type BaseService struct {
name string
version string
srv *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 健康检查端点
go
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 注册表与服务信息
go
type ServiceInfo struct {
Name string
Version string
Address string // host
Port int
Tags []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 客户端发现与调用
go
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.Reader
if 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 负载均衡实现(轮询)
go
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 等)。
go
type DistLock interface {
TryLock(key string, ttl time.Duration) bool
Unlock(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 分布式事务入门(两阶段思想)
接口化事务参与者与事务管理器,结合持久化与消息队列可进一步增强。本章提供概念与最小骨架示例。
go
type TxParticipant interface {
ID() string
Prepare(ctx context.Context, txID string) error
Commit(ctx context.Context, txID string) error
Rollback(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)
go
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 网关服务(转发到用户服务)
go
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 启动主函数
go
func main() {
reg := NewRegistry()
startUserService(reg)
startGateway(reg)
log.Println("网关: http://localhost:8080/api/user")
select{} // 阻塞主协程
}
至此,我们实现了最小可用的注册、发现与负载均衡链路。生产环境中可将注册中心替换为 Consul/Etcd/Kubernetes,加入健康上报、摘除、熔断与重试策略。