1 介绍
1.1 定义
01.技术概述
a.框架定义
go-micro是一个基于Go语言的微服务开发框架,它提供了一套完整的工具链和运行时环境,用于构建和管理分布式系统中的微服务。该框架由Asim Aslam创建,旨在简化微服务的开发、部署和维护工作。
b.设计哲学
a.核心理念
go-micro的设计理念是"简单胜于复杂",它通过插件化架构和接口驱动设计,为开发者提供灵活、可扩展的微服务解决方案。框架遵循Go语言的简洁哲学,通过最小化配置和约定优于配置的原则,让开发者专注于业务逻辑实现。
b.架构原则
采用微内核架构模式,所有核心功能都通过接口定义,具体实现可插拔。这种设计确保了框架的高扩展性和可定制性,开发者可以根据需求选择或替换不同的组件实现。
c.技术特点
a.功能说明
go-micro提供了服务发现、负载均衡、消息编码、RPC通信、同步/异步消息处理、插件系统等微服务开发所需的核心功能。它支持多种传输协议(HTTP、gRPC、消息队列等)和编码格式(JSON、Protobuf、Msgpack等),适应不同的应用场景。
b.代码示例
---
// go-micro基础服务示例
package main
import (
"context"
"fmt"
"time"
"github.com/micro/go-micro/v2"
"github.com/micro/go-micro/v2/server"
)
// Greeter 服务接口定义
type GreeterHandler interface {
Hello(ctx context.Context, req *HelloRequest, rsp *HelloResponse) error
}
// HelloRequest 请求结构
type HelloRequest struct {
Name string `json:"name"`
}
// HelloResponse 响应结构
type HelloResponse struct {
Greeting string `json:"greeting"`
}
// Greeter 实现服务处理器
type Greeter struct{}
// Hello 方法实现Greeter接口
func (g *Greeter) Hello(ctx context.Context, req *HelloRequest, rsp *HelloResponse) error {
fmt.Printf("接收到请求: %v\n", req.Name)
rsp.Greeting = "Hello " + req.Name
return nil
}
func main() {
// 创建微服务
service := micro.NewService(
micro.Name("greeter.service"), // 服务名称
micro.Version("latest"), // 服务版本
micro.Metadata(map[string]string{
"type": "greeter", // 服务元数据
}),
)
// 初始化服务
service.Init()
// 注册服务处理器
_ = server.RegisterHandler(
service.Server(),
new(Greeter),
)
// 启动服务
if err := service.Run(); err != nil {
fmt.Println("服务启动失败:", err)
}
}
---
02.框架定位
a.市场定位
go-micro定位为生产级微服务框架,介于轻量级库和重量级平台之间,提供企业级功能的同时保持开发的简洁性。它既适合初创公司的快速原型开发,也满足大型企业复杂的分布式系统需求。
b.竞品对比
a.与Spring Cloud对比
go-micro相比Spring Cloud具有更轻量、性能更好、资源占用更少的特点,适合云原生和容器化部署。Spring Cloud生态更成熟,但配置复杂、资源消耗大,go-micro则专注核心功能,学习曲线平缓。
b.与Go-kit对比
go-micro提供完整的开箱即用解决方案,而Go-kit更像一个工具包,需要更多手工组装。go-micro统一了接口和规范,Go-kit则提供更高的灵活性但需要更多开发工作。
c.与gRPC对比
go-micro基于gRPC但做了大量扩展,添加了服务发现、负载均衡、熔断器等功能。gRPC仅专注于RPC通信,go-micro提供了完整的微服务运行时环境。
c.应用价值
a.开发效率
通过标准化接口和插件系统,go-micro显著提升了微服务开发效率。开发者无需重复实现基础功能,可以专注于业务逻辑,平均可减少40-60%的样板代码编写工作。
b.运维友好
内置的服务发现、健康检查、监控追踪等运维特性,使得基于go-micro开发的微服务具有良好的可观测性和可维护性。框架与Docker、Kubernetes等云原生技术深度集成,适合现代DevOps流程。
1.2 核心概念
01.微服务架构概念
a.服务拆分
a.功能说明
微服务架构将单一应用拆分为多个小型、独立的服务,每个服务围绕特定业务功能构建。go-micro支持这种架构模式,提供服务定义、注册、发现等基础功能,确保服务之间的松耦合和高内聚。
b.代码示例
---
// 用户服务示例
package userservice
import (
"context"
"errors"
"github.com/micro/go-micro/v2"
)
// UserService 用户服务接口
type UserService interface {
CreateUser(ctx context.Context, req *CreateUserRequest, rsp *UserResponse) error
GetUser(ctx context.Context, req *GetUserRequest, rsp *UserResponse) error
UpdateUser(ctx context.Context, req *UpdateUserRequest, rsp *UserResponse) error
DeleteUser(ctx context.Context, req *DeleteUserRequest, rsp *EmptyResponse) error
}
// User 用户实体
type User struct {
ID string `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
Phone string `json:"phone"`
Address string `json:"address"`
}
// CreateUserRequest 创建用户请求
type CreateUserRequest struct {
Username string `json:"username" validate:"required,min=3,max=50"`
Email string `json:"email" validate:"required,email"`
Phone string `json:"phone" validate:"required"`
Address string `json:"address"`
}
// 实现用户服务
type userServiceHandler struct {
userRepo UserRepository // 用户仓储接口
}
func NewUserServiceHandler(repo UserRepository) UserService {
return &userServiceHandler{
userRepo: repo,
}
}
func (h *userServiceHandler) CreateUser(ctx context.Context, req *CreateUserRequest, rsp *UserResponse) error {
// 参数验证
if err := validateUser(req); err != nil {
return err
}
// 检查用户名是否已存在
exists, err := h.userRepo.ExistsByUsername(ctx, req.Username)
if err != nil {
return err
}
if exists {
return errors.New("用户名已存在")
}
// 创建用户
user := &User{
ID: generateID(),
Username: req.Username,
Email: req.Email,
Phone: req.Phone,
Address: req.Address,
}
if err := h.userRepo.Create(ctx, user); err != nil {
return err
}
rsp.User = user
return nil
}
---
b.服务自治
a.功能说明
每个微服务都是独立开发、部署和扩展的单元,拥有自己的数据存储和业务逻辑。go-micro通过服务注册发现机制实现服务间的透明通信,每个服务可以独立选择技术栈和数据存储方案。
b.技术实现
go-micro使用Registry接口实现服务注册与发现,支持多种注册中心(etcd、Consul、Kubernetes等)。服务启动时自动注册,客户端通过服务名称进行调用,实现位置透明性。
c.去中心化治理
go-micro采用去中心化的治理模式,每个服务独立管理自己的配置、监控、日志等。框架提供标准化的插件接口,支持统一的管理工具,但不强制使用特定的技术栈。
02.go-micro核心接口
a.Service接口
a.功能说明
Service是go-micro的核心接口,代表一个微服务实例。它提供了服务的生命周期管理、配置管理、客户端初始化等基础功能。Service接口是整个框架的入口点,开发者通过Service创建和管理自己的微服务。
b.核心方法
Service接口包含Init()、Run()、Stop()、Client()、Server()等方法。Init()用于初始化服务配置,Run()启动服务并处理请求,Stop()优雅关闭服务,Client()和Server()分别获取客户端和服务端实例。
c.代码示例
---
// Service接口使用示例
package main
import (
"context"
"log"
"github.com/micro/go-micro/v2"
"github.com/micro/go-micro/v2/config"
"github.com/micro/go-micro/v2/config/source/file"
)
func main() {
// 加载配置文件
config.Load(file.NewSource(
file.WithPath("config.json"),
))
// 创建服务实例
service := micro.NewService(
micro.Name("user.service"), // 服务名称
micro.Version("1.0.0"), // 服务版本
micro.Address(":8080"), // 监听地址
micro.Metadata(map[string]string{ // 服务元数据
"description": "用户管理服务",
"author": "team",
}),
)
// 初始化服务(解析命令行参数、加载配置等)
service.Init(
micro.Action(func(c *cli.Context) error {
log.Printf("服务 %s 正在启动...", c.String("service"))
return nil
}),
)
// 获取服务配置
log.Printf("服务名称: %s", service.Options().Name)
log.Printf("服务版本: %s", service.Options().Version)
log.Printf("监听地址: %s", service.Options().Address)
// 获取客户端和服务端实例
client := service.Client()
server := service.Server()
log.Printf("客户端类型: %T", client)
log.Printf("服务端类型: %T", server)
// 注册服务处理器
registerHandlers(server)
// 启动服务
if err := service.Run(); err != nil {
log.Fatal("服务启动失败: ", err)
}
}
func registerHandlers(server server.Server) {
// 注册各种服务处理器
// 例如:userHandler, orderHandler等
}
---
b.Client接口
a.功能说明
Client接口定义了微服务客户端的行为,提供了服务调用、负载均衡、服务发现等功能。客户端通过服务名称发起调用,无需关心服务的实际地址,实现了位置透明性。
b.调用机制
Client使用Selector接口进行服务发现,通过LoadBalancer进行负载均衡,支持多种调用方式(同步、异步、消息等)。它还提供了中间件机制,可以在调用前后执行额外逻辑。
c.Server接口
a.功能说明
Server接口定义了服务端的行为,负责接收请求、路由处理、响应返回等功能。它支持多种传输协议和编码格式,可以处理来自不同客户端的请求。
b.处理流程
Server接收到请求后,通过Codec解码请求,路由到对应的处理器,执行业务逻辑,然后编码响应并返回。整个过程支持中间件拦截,可以实现日志记录、权限验证等功能。
03.通信模型
a.RPC通信
a.功能说明
go-micro基于RPC模型实现服务间通信,提供了透明的远程方法调用能力。开发者调用远程服务就像调用本地方法一样,框架自动处理序列化、网络传输、反序列化等底层细节。
b.调用模式
支持同步调用、异步调用、单向调用等多种模式。同步调用等待响应返回,异步调用使用回调或Future获取结果,单向调用不等待响应。
c.代码示例
---
// RPC调用示例
package main
import (
"context"
"fmt"
"time"
"github.com/micro/go-micro/v2"
"github.com/micro/go-micro/v2/client"
)
type GreeterRequest struct {
Name string `json:"name"`
}
type GreeterResponse struct {
Message string `json:"message"`
}
func main() {
// 创建服务
service := micro.NewService(micro.Name("caller.service"))
service.Init()
// 创建客户端
greeterClient := service.Client().Client("greeter.service")
// 同步调用
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
req := &GreeterRequest{Name: "World"}
rsp := &GreeterResponse{}
// 执行RPC调用
err := greeterClient.Call(ctx, "Greeter.Hello", req, rsp)
if err != nil {
fmt.Printf("RPC调用失败: %v\n", err)
return
}
fmt.Printf("同步调用响应: %s\n", rsp.Message)
// 异步调用
go func() {
asyncReq := &GreeterRequest{Name: "Async"}
asyncRsp := &GreeterResponse{}
// 异步执行调用
err := greeterClient.Call(context.Background(), "Greeter.Hello", asyncReq, asyncRsp)
if err != nil {
fmt.Printf("异步调用失败: %v\n", err)
return
}
fmt.Printf("异步调用响应: %s\n", asyncRsp.Message)
}()
// 使用选项自定义调用
opts := []client.CallOption{
client.WithContentType("application/json"),
client.WithRequestTimeout(3 * time.Second),
client.WithRetries(3),
}
err = greeterClient.Call(ctx, "Greeter.Hello", req, rsp, opts...)
if err != nil {
fmt.Printf("带选项的RPC调用失败: %v\n", err)
return
}
fmt.Printf("带选项的调用响应: %s\n", rsp.Message)
// 保持主程序运行
time.Sleep(2 * time.Second)
}
---
b.消息驱动
a.功能说明
go-micro支持异步消息驱动的通信模式,通过Broker接口实现发布订阅机制。这种模式适合事件驱动的架构,可以实现服务间的解耦和异步处理。
b.实现方式
框架提供了Publish和Subscribe方法,支持多种消息中间件(RabbitMQ、Kafka、NATS等)。消息可以持久化,支持重试和死信队列处理,确保消息的可靠传递。
04.插件化架构
a.接口设计
go-micro采用接口驱动的设计模式,所有核心功能都定义了标准接口,包括Transport、Codec、Registry、Selector、Broker等。这种设计使得具体实现可以灵活替换,满足不同场景的需求。
b.实现机制
插件通过Go接口实现,框架在启动时动态加载不同的实现。开发者可以选择使用官方提供的实现,也可以根据接口规范开发自定义插件,实现特定功能需求。
1.3 优缺点
01.优势
a.高性能表现
a.零内存分配设计
go-micro在网络通信和消息处理方面采用零内存分配设计,通过对象池和缓冲区复用技术,大幅减少GC压力。在并发处理请求时,性能表现优异,可处理数万级别的并发连接。
b.高效的序列化
a.功能说明
框架支持多种高性能序列化格式,包括Protobuf、Msgpack、JSON等。其中Protobuf采用代码生成机制,序列化性能比JSON高3-5倍,网络传输效率显著提升。
b.性能测试
---
// 性能测试示例
package main
import (
"bytes"
"testing"
"time"
"github.com/golang/protobuf/proto"
"github.com/tinylib/msgp/msgp"
"github.com/vmihailenco/msgpack/v5"
)
// 测试数据结构
type TestUser struct {
ID int64 `json:"id" protobuf:"varint,1"`
Username string `json:"username" protobuf:"bytes,2"`
Email string `json:"email" protobuf:"bytes,3"`
Age int32 `json:"age" protobuf:"varint,4"`
Active bool `json:"active" protobuf:"varint,5"`
}
// 生成测试数据
func generateTestData() *TestUser {
return &TestUser{
ID: 12345,
Username: "testuser_long_name_for_performance_test",
Email: "[email protected]",
Age: 25,
Active: true,
}
}
// JSON序列化测试
func BenchmarkJSONMarshal(b *testing.B) {
user := generateTestData()
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_, _ = json.Marshal(user)
}
}
// JSON反序列化测试
func BenchmarkJSONUnmarshal(b *testing.B) {
user := generateTestData()
data, _ := json.Marshal(user)
b.ResetTimer()
b.ReportAllocs()
result := &TestUser{}
for i := 0; i < b.N; i++ {
_ = json.Unmarshal(data, result)
}
}
// Protobuf序列化测试
func BenchmarkProtoMarshal(b *testing.B) {
user := generateTestData()
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_, _ = proto.Marshal(user)
}
}
// Protobuf反序列化测试
func BenchmarkProtoUnmarshal(b *testing.B) {
user := generateTestData()
data, _ := proto.Marshal(user)
b.ResetTimer()
b.ReportAllocs()
result := &TestUser{}
for i := 0; i < b.N; i++ {
_ = proto.Unmarshal(data, result)
}
}
// Msgpack序列化测试
func BenchmarkMsgpackMarshal(b *testing.B) {
user := generateTestData()
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_, _ = msgpack.Marshal(user)
}
}
// 压力测试
func TestConcurrencyPerformance(t *testing.T) {
const numGoroutines = 100
const numRequests = 1000
user := generateTestData()
start := time.Now()
done := make(chan bool, numGoroutines)
for i := 0; i < numGoroutines; i++ {
go func() {
for j := 0; j < numRequests; j++ {
data, _ := json.Marshal(user)
result := &TestUser{}
_ = json.Unmarshal(data, result)
}
done <- true
}()
}
// 等待所有goroutine完成
for i := 0; i < numGoroutines; i++ {
<-done
}
duration := time.Since(start)
totalRequests := numGoroutines * numRequests
qps := float64(totalRequests) / duration.Seconds()
t.Logf("并发性能测试完成")
t.Logf("总请求数: %d", totalRequests)
t.Logf("总耗时: %v", duration)
t.Logf("QPS: %.2f", qps)
}
---
c.网络传输优化
go-micro支持连接池管理、HTTP/2、TCP_NODELAY等网络优化技术,减少网络延迟和连接开销。在分布式环境中,网络传输效率提升20-30%。
b.开发效率
a.代码生成工具
a.功能说明
go-micro提供了proto文件代码生成工具,可以根据服务定义自动生成客户端和服务端代码。开发者只需要定义服务接口和消息格式,框架自动生成完整的RPC通信代码。
b.工具使用
使用protoc工具配合go-micro插件,可以生成类型安全的Go代码,减少手工编写的工作量,同时避免运行时错误。
b.中间件生态
a.功能说明
丰富的中间件生态支持日志记录、监控追踪、权限验证、限流熔断等横切关注点。开发者可以通过组合中间件快速实现复杂的功能需求。
b.实现示例
---
// 中间件示例
package middleware
import (
"context"
"time"
"github.com/micro/go-micro/v2/server"
)
// LoggingMiddleware 日志中间件
func LoggingMiddleware() server.HandlerWrapper {
return func(fn server.HandlerFunc) server.HandlerFunc {
return func(ctx context.Context, req server.Request, rsp interface{}) error {
start := time.Now()
// 记录请求开始
log.Printf("开始处理请求: %s.%s", req.Service(), req.Endpoint())
// 执行业务逻辑
err := fn(ctx, req, rsp)
// 记录请求结束
duration := time.Since(start)
log.Printf("请求处理完成: %s.%s, 耗时: %v, 错误: %v",
req.Service(), req.Endpoint(), duration, err)
return err
}
}
}
// MetricsMiddleware 监控中间件
func MetricsMiddleware(counter prometheus.Counter) server.HandlerWrapper {
return func(fn server.HandlerFunc) server.HandlerFunc {
return func(ctx context.Context, req server.Request, rsp interface{}) error {
// 增加请求计数
counter.Inc()
// 执行业务逻辑
err := fn(ctx, req, rsp)
return err
}
}
}
// RateLimitMiddleware 限流中间件
func RateLimitMiddleware(limiter *rate.Limiter) server.HandlerWrapper {
return func(fn server.HandlerFunc) server.HandlerFunc {
return func(ctx context.Context, req server.Request, rsp interface{}) error {
// 检查限流
if !limiter.Allow() {
return errors.New("请求频率过高,已被限流")
}
return fn(ctx, req, rsp)
}
}
}
---
c.云原生支持
a.容器化适配
go-micro生成的服务镜像通常只有10-20MB,相比Java服务的数百MB镜像,大幅减少了存储和传输开销。服务启动时间通常在秒级,适合快速扩缩容。
b.Kubernetes集成
a.功能说明
深度集成Kubernetes,支持服务发现、配置管理、健康检查等原生功能。服务可以通过Kubernetes API进行服务注册,实现与Kubernetes生态的无缝集成。
b.配置管理
支持ConfigMap和Secret管理,支持热重载配置,无需重启服务即可应用新的配置。
02.缺点
a.学习曲线
a.微服务概念要求
a.知识背景要求
开发者需要理解分布式系统、服务发现、负载均衡、熔断器等微服务概念,这些概念对单体应用开发者来说有一定学习成本。通常需要1-2个月的实践才能熟练掌握。
b.最佳实践
微服务架构的服务拆分、数据一致性、分布式事务等问题的最佳实践仍在发展中,需要团队不断探索和总结经验。
b.调试复杂性
a.分布式追踪
微服务的调试相比单体应用更加复杂,需要借助链路追踪工具(如Jaeger、Zipkin)来跟踪请求在多个服务间的流转路径。
b.日志聚合
日志分散在多个服务实例中,需要ELK、Fluentd等日志聚合工具来统一收集和分析,增加了运维复杂度。
c.环境管理
a.多环境配置
开发、测试、生产环境需要不同的配置管理策略,每个服务可能依赖不同的数据库、缓存等资源,环境搭建和管理工作量显著增加。
b.版本兼容性
微服务的版本升级需要考虑向后兼容性,特别是在升级过程中可能存在多个版本同时运行的情况,需要仔细设计接口版本策略。
b.运维成本
a.监控复杂度
a.多维度监控
需要对每个服务进行性能监控、错误监控、业务指标监控,监控系统的复杂度和数据量成倍增长。通常需要Prometheus、Grafana等专业监控工具。
b.告警配置
告警规则需要针对每个服务单独配置,误报和漏报的风险增加,需要精细的告警策略和阈值调优。
b.部署管理
a.自动化要求
微服务的部署需要高度自动化的CI/CD流水线,包括自动构建、测试、部署、回滚等功能,对DevOps能力要求较高。
b.服务治理
服务间的依赖关系复杂,需要服务网格(Service Mesh)或API网关来统一管理流量、安全、监控等服务治理功能。
c.数据一致性
a.分布式事务
a.CAP理论限制
分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)三者不能同时满足,go-micro本身不提供分布式事务解决方案,需要开发者根据业务需求选择合适的一致性策略。
b.最终一致性
大多数微服务系统采用最终一致性模型,通过事件驱动、补偿事务等技术来保证数据最终一致,但这增加了业务逻辑的复杂性。
b.数据同步
a.跨服务数据访问
不同服务的数据存储在独立的数据库中,跨服务的数据访问需要通过API或消息队列实现,相比单体应用的直接数据库访问,性能和复杂度都有所增加。
b.数据冗余
为了提高性能和可用性,可能需要在多个服务中冗余存储相同的数据,数据同步和一致性问题需要特别关注。
03.适用性分析
a.适合场景
a.复杂业务系统
适合业务复杂度高、需要多人协作开发的大型系统,可以通过服务拆分降低系统的复杂度和耦合度。
b.高可用性要求
适合对可用性要求很高的系统,单个服务的故障不会影响整个系统的运行,便于实现故障隔离和快速恢复。
c.技术异构环境
适合需要使用多种技术栈的环境,每个服务可以选择最适合的技术栈,避免技术选型的妥协。
b.不推荐场景
a.简单业务系统
对于业务逻辑简单、团队规模小的项目,微服务架构可能过度复杂,增加了不必要的开发和运维成本。
b.初创项目
初创项目应该优先考虑快速验证商业模式,单体架构更适合快速迭代和调整,等到业务成熟后再考虑微服务拆分。
c.技术团队不成熟
如果团队缺乏分布式系统的开发和运维经验,直接采用微服务架构可能导致项目失败,建议先从简单架构开始逐步演进。
1.4 使用场景
01.电商系统
a.系统架构
a.功能说明
电商系统是微服务架构的典型应用场景,通常包含用户服务、商品服务、订单服务、支付服务、库存服务、物流服务等模块。go-micro可以帮助构建高性能、可扩展的电商微服务系统。
b.服务拆分示例
---
// 电商系统微服务定义
package ecommerce
import (
"context"
"github.com/micro/go-micro/v2"
)
// 用户服务
type UserService interface {
Register(ctx context.Context, req *RegisterRequest, rsp *UserResponse) error
Login(ctx context.Context, req *LoginRequest, rsp *LoginResponse) error
GetProfile(ctx context.Context, req *GetUserRequest, rsp *UserResponse) error
UpdateProfile(ctx context.Context, req *UpdateUserRequest, rsp *UserResponse) error
}
// 商品服务
type ProductService interface {
CreateProduct(ctx context.Context, req *CreateProductRequest, rsp *ProductResponse) error
GetProduct(ctx context.Context, req *GetProductRequest, rsp *ProductResponse) error
SearchProducts(ctx context.Context, req *SearchRequest, rsp *SearchResponse) error
UpdateInventory(ctx context.Context, req *UpdateInventoryRequest, rsp *ProductResponse) error
}
// 订单服务
type OrderService interface {
CreateOrder(ctx context.Context, req *CreateOrderRequest, rsp *OrderResponse) error
GetOrder(ctx context.Context, req *GetOrderRequest, rsp *OrderResponse) error
ListOrders(ctx context.Context, req *ListOrdersRequest, rsp *ListOrdersResponse) error
CancelOrder(ctx context.Context, req *CancelOrderRequest, rsp *OrderResponse) error
}
// 支付服务
type PaymentService interface {
ProcessPayment(ctx context.Context, req *PaymentRequest, rsp *PaymentResponse) error
RefundPayment(ctx context.Context, req *RefundRequest, rsp *RefundResponse) error
GetPaymentStatus(ctx context.Context, req *PaymentStatusRequest, rsp *PaymentStatusResponse) error
}
// 库存服务
type InventoryService interface {
ReserveStock(ctx context.Context, req *ReserveStockRequest, rsp *StockResponse) error
ReleaseStock(ctx context.Context, req *ReleaseStockRequest, rsp *StockResponse) error
GetStock(ctx context.Context, req *GetStockRequest, rsp *StockResponse) error
}
// 物流服务
type ShippingService interface {
CreateShipment(ctx context.Context, req *CreateShipmentRequest, rsp *ShipmentResponse) error
TrackShipment(ctx context.Context, req *TrackShipmentRequest, rsp *TrackingResponse) error
UpdateStatus(ctx context.Context, req *UpdateStatusRequest, rsp *ShipmentResponse) error
}
// 实现订单服务
type orderServiceHandler struct {
userService UserService // 用户服务客户端
productService ProductService // 商品服务客户端
paymentService PaymentService // 支付服务客户端
inventoryService InventoryService // 库存服务客户端
shippingService ShippingService // 物流服务客户端
}
func NewOrderServiceHandler(service micro.Service) OrderService {
return &orderServiceHandler{
userService: service.Client().Client("user.service"),
productService: service.Client().Client("product.service"),
paymentService: service.Client().Client("payment.service"),
inventoryService: service.Client().Client("inventory.service"),
shippingService: service.Client().Client("shipping.service"),
}
}
func (h *orderServiceHandler) CreateOrder(ctx context.Context, req *CreateOrderRequest, rsp *OrderResponse) error {
// 1. 验证用户信息
userReq := &GetUserRequest{UserId: req.UserId}
userRsp := &UserResponse{}
if err := h.userService.Call(ctx, "User.GetProfile", userReq, userRsp); err != nil {
return err
}
// 2. 检查商品库存
for _, item := range req.Items {
stockReq := &GetStockRequest{ProductId: item.ProductId}
stockRsp := &StockResponse{}
if err := h.inventoryService.Call(ctx, "Inventory.GetStock", stockReq, stockRsp); err != nil {
return err
}
if stockRsp.Available < item.Quantity {
return errors.New("商品库存不足")
}
}
// 3. 计算订单总额
totalAmount := calculateTotalAmount(req.Items)
// 4. 创建订单
order := &Order{
OrderId: generateOrderId(),
UserId: req.UserId,
Items: req.Items,
TotalAmount: totalAmount,
Status: "pending",
}
// 5. 预留库存
for _, item := range req.Items {
reserveReq := &ReserveStockRequest{
ProductId: item.ProductId,
Quantity: item.Quantity,
OrderId: order.OrderId,
}
reserveRsp := &StockResponse{}
if err := h.inventoryService.Call(ctx, "Inventory.ReserveStock", reserveReq, reserveRsp); err != nil {
return err
}
}
// 6. 处理支付
paymentReq := &PaymentRequest{
OrderId: order.OrderId,
UserId: req.UserId,
Amount: totalAmount,
PaymentInfo: req.PaymentInfo,
}
paymentRsp := &PaymentResponse{}
if err := h.paymentService.Call(ctx, "Payment.ProcessPayment", paymentReq, paymentRsp); err != nil {
// 支付失败,释放库存
for _, item := range req.Items {
releaseReq := &ReleaseStockRequest{
ProductId: item.ProductId,
Quantity: item.Quantity,
OrderId: order.OrderId,
}
h.inventoryService.Call(ctx, "Inventory.ReleaseStock", releaseReq, nil)
}
return err
}
// 7. 更新订单状态
order.Status = "paid"
order.PaymentId = paymentRsp.PaymentId
rsp.Order = order
return nil
}
---
b.技术优势
a.高并发处理
电商系统的促销活动期间会有大量的并发请求,go-micro的高性能特性和负载均衡能力可以应对流量峰值,通过水平扩展服务实例来提高系统容量。
b.业务隔离
不同的业务模块独立部署,一个服务的故障不会影响整个系统的运行。例如,支付服务故障不会影响用户浏览商品,提高了系统的可用性。
02.金融科技系统
a.系统特点
a.功能说明
金融科技系统对安全性、可靠性和性能要求极高,包括账户管理、交易处理、风控系统、清算结算、客户服务等模块。go-micro提供了强大的安全保障和高性能处理能力。
b.安全实现
---
// 金融系统安全中间件
package fintech
import (
"context"
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"errors"
"time"
"github.com/micro/go-micro/v2/server"
)
// AuthMiddleware 认证中间件
func AuthMiddleware(secretKey string) server.HandlerWrapper {
return func(fn server.HandlerFunc) server.HandlerFunc {
return func(ctx context.Context, req server.Request, rsp interface{}) error {
// 验证请求签名
signature := req.Metadata()["X-Signature"]
timestamp := req.Metadata()["X-Timestamp"]
if signature == "" || timestamp == "" {
return errors.New("缺少认证信息")
}
// 验证时间戳防止重放攻击
ts, err := time.Parse(time.RFC3339, timestamp)
if err != nil || time.Since(ts) > 5*time.Minute {
return errors.New("请求时间戳无效或已过期")
}
// 验证签名
if !validateSignature(req, signature, secretKey) {
return errors.New("签名验证失败")
}
// 执行业务逻辑
return fn(ctx, req, rsp)
}
}
}
// RateLimitMiddleware 限流中间件
func RateLimitMiddleware(limiter *TokenBucket) server.HandlerWrapper {
return func(fn server.HandlerFunc) server.HandlerFunc {
return func(ctx context.Context, req server.Request, rsp interface{}) error {
if !limiter.Allow(getClientIP(req)) {
return errors.New("请求频率过高")
}
return fn(ctx, req, rsp)
}
}
}
// AuditMiddleware 审计中间件
func AuditMiddleware(auditLogger AuditLogger) server.HandlerWrapper {
return func(fn server.HandlerFunc) server.HandlerFunc {
return func(ctx context.Context, req server.Request, rsp interface{}) error {
// 记录审计日志
auditLog := &AuditLog{
Timestamp: time.Now(),
Service: req.Service(),
Method: req.Endpoint(),
ClientIP: getClientIP(req),
UserAgent: req.Metadata()["User-Agent"],
RequestID: req.Metadata()["X-Request-ID"],
}
// 执行业务逻辑
err := fn(ctx, req, rsp)
// 记录结果
auditLog.Success = err == nil
if err != nil {
auditLog.Error = err.Error()
}
auditLogger.Log(auditLog)
return err
}
}
}
// 交易服务实现
type TransactionService struct {
accountService AccountService
riskControlService RiskControlService
complianceService ComplianceService
}
func (t *TransactionService) ProcessTransaction(ctx context.Context, req *TransactionRequest, rsp *TransactionResponse) error {
// 1. 风险控制检查
riskReq := &RiskCheckRequest{
UserId: req.UserId,
Amount: req.Amount,
Merchant: req.Merchant,
Location: req.Location,
}
riskRsp := &RiskCheckResponse{}
if err := t.riskControlService.Check(ctx, riskReq, riskRsp); err != nil {
return err
}
if riskRsp.RiskScore > 80 {
return errors.New("交易风险过高,已拒绝")
}
// 2. 合规性检查
complianceReq := &ComplianceCheckRequest{
UserId: req.UserId,
Amount: req.Amount,
Counterpart: req.Counterpart,
}
complianceRsp := &ComplianceCheckResponse{}
if err := t.complianceService.Check(ctx, complianceReq, complianceRsp); err != nil {
return err
}
if !complianceRsp.Compliant {
return errors.New("交易不满足合规要求")
}
// 3. 执行交易
transaction := &Transaction{
TransactionId: generateTransactionId(),
UserId: req.UserId,
Amount: req.Amount,
Currency: req.Currency,
Status: "processing",
CreatedAt: time.Now(),
}
// 4. 更新账户余额
accountReq := &UpdateBalanceRequest{
AccountId: req.AccountId,
Amount: -req.Amount,
Reason: "交易扣款",
}
accountRsp := &UpdateBalanceResponse{}
if err := t.accountService.UpdateBalance(ctx, accountReq, accountRsp); err != nil {
transaction.Status = "failed"
transaction.Error = err.Error()
// 回滚操作...
return err
}
transaction.Status = "completed"
rsp.Transaction = transaction
return nil
}
---
b.合规要求
a.数据安全
金融数据需要严格的加密存储和传输,go-micro支持TLS加密通信,可以集成各种加密库来保护敏感数据。
b.审计追踪
所有操作都需要完整的审计日志,包括用户行为、系统操作、数据变更等。go-micro的中间件机制便于实现统一的审计功能。
03.物联网系统
a.架构特点
a.设备接入层
IoT系统需要处理大量设备的接入,包括设备注册、身份验证、数据采集等功能。go-micro的高并发特性适合处理海量设备的连接请求。
b.数据处理层
设备产生的数据需要实时处理、分析和存储,包括数据清洗、规则引擎、告警处理等功能。微服务架构可以按业务领域拆分处理逻辑。
b.实现示例
---
// IoT设备管理服务
package iot
import (
"context"
"encoding/json"
"time"
"github.com/micro/go-micro/v2"
"github.com/micro/go-micro/v2/broker"
)
// DeviceService 设备服务接口
type DeviceService interface {
RegisterDevice(ctx context.Context, req *RegisterDeviceRequest, rsp *DeviceResponse) error
UpdateDeviceStatus(ctx context.Context, req *UpdateStatusRequest, rsp *DeviceResponse) error
GetDevice(ctx context.Context, req *GetDeviceRequest, rsp *DeviceResponse) error
ListDevices(ctx context.Context, req *ListDevicesRequest, rsp *ListDevicesResponse) error
}
// DataService 数据服务接口
type DataService interface {
ProcessData(ctx context.Context, req *ProcessDataRequest, rsp *DataResponse) error
QueryData(ctx context.Context, req *QueryDataRequest, rsp *QueryDataResponse) error
AggregateData(ctx context.Context, req *AggregateRequest, rsp *AggregateResponse) error
}
// AlertService 告警服务接口
type AlertService interface {
CreateAlert(ctx context.Context, req *CreateAlertRequest, rsp *AlertResponse) error
AcknowledgeAlert(ctx context.Context, req *AcknowledgeRequest, rsp *AlertResponse) error
GetAlerts(ctx context.Context, req *GetAlertsRequest, rsp *GetAlertsResponse) error
}
// 设备数据结构
type Device struct {
DeviceId string `json:"device_id"`
DeviceType string `json:"device_type"`
Name string `json:"name"`
Location string `json:"location"`
Status string `json:"status"` // online, offline, error
LastSeen time.Time `json:"last_seen"`
Metadata map[string]string `json:"metadata"`
Sensors []Sensor `json:"sensors"`
}
// 传感器数据
type SensorData struct {
DeviceId string `json:"device_id"`
SensorId string `json:"sensor_id"`
Timestamp time.Time `json:"timestamp"`
Value interface{} `json:"value"`
Unit string `json:"unit"`
Quality string `json:"quality"` // good, bad, uncertain
Metadata map[string]interface{} `json:"metadata"`
}
// 实现设备服务
type deviceServiceHandler struct {
deviceRepo DeviceRepository
broker broker.Broker
dataService DataService
alertService AlertService
}
func (h *deviceServiceHandler) ProcessDeviceMessage(ctx context.Context, msg *DeviceMessage) error {
// 1. 验证设备
device, err := h.deviceRepo.GetById(ctx, msg.DeviceId)
if err != nil {
return err
}
if device.Status != "online" {
// 更新设备状态为在线
updateReq := &UpdateStatusRequest{
DeviceId: msg.DeviceId,
Status: "online",
LastSeen: time.Now(),
}
h.UpdateDeviceStatus(ctx, updateReq, &DeviceResponse{})
}
// 2. 处理传感器数据
for _, data := range msg.SensorData {
// 转发到数据处理服务
processReq := &ProcessDataRequest{
DeviceId: data.DeviceId,
SensorId: data.SensorId,
Value: data.Value,
Timestamp: data.Timestamp,
Unit: data.Unit,
}
go func(d *SensorData) {
processRsp := &DataResponse{}
if err := h.dataService.ProcessData(ctx, processReq, processRsp); err != nil {
// 处理失败,记录日志
log.Printf("处理设备数据失败: %v", err)
}
}(&data)
// 3. 检查告警规则
alertReq := &CheckAlertRequest{
DeviceId: data.DeviceId,
SensorId: data.SensorId,
Value: data.Value,
Timestamp: data.Timestamp,
}
go func(d *SensorData) {
alertRsp := &CheckAlertResponse{}
if err := h.alertService.CheckRules(ctx, alertReq, alertRsp); err != nil {
log.Printf("检查告警规则失败: %v", err)
return
}
if alertRsp.AlertTriggered {
// 发布告警消息
alertMsg := &AlertMessage{
DeviceId: d.DeviceId,
SensorId: d.SensorId,
Value: d.Value,
RuleId: alertRsp.RuleId,
Severity: alertRsp.Severity,
Message: alertRsp.Message,
Timestamp: time.Now(),
}
if body, err := json.Marshal(alertMsg); err == nil {
h.broker.Publish("iot.alerts", &broker.Message{
Body: body,
})
}
}
}(&data)
}
return nil
}
// 消息订阅处理
func (h *deviceServiceHandler) SubscribeToDeviceMessages(service micro.Service) error {
// 订阅设备消息
_, err := service.Options().Broker.Subscribe("iot.device.data", func(p broker.Event) error {
var msg DeviceMessage
if err := json.Unmarshal(p.Message().Body, &msg); err != nil {
return err
}
return h.ProcessDeviceMessage(context.Background(), &msg)
})
return err
}
---
c.扩展性考虑
IoT系统的设备数量会持续增长,微服务架构支持独立扩展各个组件。数据处理服务可以根据数据量增加实例,设备管理服务可以根据设备数量进行扩展。
04.内容分发网络
a.系统需求
a.全球分布
CDN需要在全球范围内部署节点,提供就近的内容访问服务。go-micro的服务发现和负载均衡能力适合构建分布式的内容分发网络。
b.低延迟要求
内容分发对延迟要求极高,go-micro的高性能网络处理和连接池管理可以满足低延迟的服务需求。
b.架构设计
a.边缘节点服务
每个边缘节点运行相同的服务实例,包括内容缓存、预取、健康检查等功能。
b.中心管理服务
负责节点管理、内容分发策略、流量调度等核心功能。
c.监控分析服务
实时监控节点状态、流量统计、性能指标等数据。
1.5 架构原理
01.微内核架构设计
a.核心组件抽象
a.接口驱动设计
go-micro采用微内核架构模式,将系统的核心功能抽象为标准接口,包括Service、Client、Server、Transport、Codec、Registry、Broker、Selector等。这种设计确保了框架的可扩展性和可定制性。
b.插件化实现
所有具体实现都通过接口规范,可以作为插件动态加载和替换。开发者可以根据需求选择合适的实现,或者开发自定义插件。
c.代码示例
---
// 核心接口定义
package go.micro
// Service 服务接口
type Service interface {
Init(...Option) error
Options() Options
Client() Client
Server() Server
Run() error
Stop() error
String() string
}
// Client 客户端接口
type Client interface {
Init(...Option) error
Options() Options
NewRequest(service, endpoint string, req interface{}, reqOpts ...RequestOption) Request
Call(ctx context.Context, req Request, rsp interface{}, opts ...CallOption) error
Stream(ctx context.Context, req Request, opts ...CallOption) (Stream, error)
Publish(ctx context.Context, p Message, opts ...PublishOption) error
String() string
}
// Server 服务端接口
type Server interface {
Init(...Option) error
Options() Options
Handle(Handler) error
NewHandler(h interface{}, opts ...HandlerOption) Handler
Subscribe(Subscriber) error
NewSubscriber(topic string, sb interface{}, opts ...SubscriberOption) Subscriber
Start() error
Stop() error
String() string
}
// Transport 传输层接口
type Transport interface {
Init(...Option) error
Options() Options
Dial(addr string, opts ...DialOption) (Client, error)
Listen(addr string, opts ...ListenOption) (Listener, error)
String() string
}
// Codec 编码器接口
type Codec interface {
Marshal(v interface{}) ([]byte, error)
Unmarshal(data []byte, v interface{}) error
String() string
}
// Registry 注册中心接口
type Registry interface {
Init(...Option) error
Options() Options
Register(*Service, ...RegisterOption) error
Deregister(*Service, ...DeregisterOption) error
GetService(string) ([]*Service, error)
ListServices() ([]*Service, error)
Watch(...WatchOption) (Watcher, error)
String() string
}
// Broker 消息代理接口
type Broker interface {
Init(...Option) error
Options() Options
Address() string
Connect() error
Disconnect() error
Publish(topic string, m *Message, opts ...PublishOption) error
Subscribe(topic string, h Handler, opts ...SubscribeOption) (Subscriber, error)
String() string
}
// 选择器接口
type Selector interface {
Init(opts ...SelectorOption) error
Options() SelectorOptions
Select(service string, opts ...SelectOption) (Next, error)
Mark(service string, node *registry.Node, err error)
Reset(service string)
Close() error
String() string
}
---
b.组件协同机制
a.服务启动流程
a.功能说明
服务启动时,go-micro按照初始化、配置加载、组件注册、服务注册、监听启动等步骤有序执行各个组件的初始化工作。
b.初始化序列
---
// 服务启动流程示例
package main
import (
"context"
"fmt"
"log"
"os"
"os/signal"
"syscall"
"github.com/micro/go-micro/v2"
"github.com/micro/go-micro/v2/config"
"github.com/micro/go-micro/v2/config/source/file"
"github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/transport"
)
// 自定义初始化器
type customInitializer struct {
configPath string
registry registry.Registry
transport transport.Transport
}
func NewCustomInitializer(configPath string) *customInitializer {
return &customInitializer{
configPath: configPath,
}
}
func (ci *customInitializer) Init(service micro.Service) error {
// 1. 加载配置
if err := ci.loadConfig(); err != nil {
return fmt.Errorf("加载配置失败: %v", err)
}
// 2. 初始化日志系统
if err := ci.initLogger(); err != nil {
return fmt.Errorf("初始化日志系统失败: %v", err)
}
// 3. 初始化注册中心
if err := ci.initRegistry(service); err != nil {
return fmt.Errorf("初始化注册中心失败: %v", err)
}
// 4. 初始化传输层
if err := ci.initTransport(service); err != nil {
return fmt.Errorf("初始化传输层失败: %v", err)
}
// 5. 初始化监控
if err := ci.initMetrics(service); err != nil {
return fmt.Errorf("初始化监控系统失败: %v", err)
}
// 6. 初始化健康检查
if err := ci.initHealthCheck(service); err != nil {
return fmt.Errorf("初始化健康检查失败: %v", err)
}
return nil
}
func (ci *customInitializer) loadConfig() error {
// 加载配置文件
err := config.Load(file.NewSource(
file.WithPath(ci.configPath),
))
if err != nil {
return err
}
// 验证配置
return ci.validateConfig()
}
func (ci *customInitializer) initLogger() error {
// 配置日志级别和格式
logger.Init(logger.WithLevel(logger.InfoLevel))
return nil
}
func (ci *customInitializer) initRegistry(service micro.Service) error {
// 这里可以初始化自定义的注册中心
// 例如:etcd、consul、kubernetes等
return nil
}
func (ci *customInitializer) initTransport(service micro.Service) error {
// 这里可以初始化自定义的传输层
// 例如:HTTP、gRPC、QUIC等
return nil
}
func (ci *customInitializer) initMetrics(service micro.Service) error {
// 初始化监控系统
// 例如:Prometheus、Jaeger等
return nil
}
func (ci *customInitializer) initHealthCheck(service micro.Service) error {
// 初始化健康检查
return nil
}
func (ci *customInitializer) validateConfig() error {
// 验证必要的配置项
requiredFields := []string{"service.name", "service.version"}
for _, field := range requiredFields {
if val := config.Get(field); val.String() == "" {
return fmt.Errorf("缺少必要的配置项: %s", field)
}
}
return nil
}
func main() {
// 创建自定义初始化器
initializer := NewCustomInitializer("config.json")
// 创建服务实例
service := micro.NewService(
micro.Name("example.service"),
micro.Version("1.0.0"),
micro.AfterStart(func() error {
log.Println("服务启动完成")
return nil
}),
micro.BeforeStop(func() error {
log.Println("服务即将停止")
return nil
}),
)
// 初始化服务
if err := service.Init(); err != nil {
log.Fatal("服务初始化失败: ", err)
}
// 应用自定义初始化
if err := initializer.Init(service); err != nil {
log.Fatal("自定义初始化失败: ", err)
}
// 注册服务处理器
registerHandlers(service)
// 设置优雅关闭
setupGracefulShutdown(service)
// 启动服务
log.Println("正在启动服务...")
if err := service.Run(); err != nil {
log.Fatal("服务运行失败: ", err)
}
}
func registerHandlers(service micro.Service) {
// 注册各种服务处理器
}
func setupGracefulShutdown(service micro.Service) {
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-c
log.Println("接收到关闭信号,正在优雅关闭...")
if err := service.Stop(); err != nil {
log.Printf("服务停止时发生错误: %v", err)
}
os.Exit(0)
}()
}
---
02.分层架构模型
a.应用层
a.功能说明
应用层包含具体的业务逻辑实现,开发者在这一层实现各种服务接口和业务处理功能。go-micro通过代码生成工具自动生成接口代码,开发者只需实现业务逻辑。
b.业务服务示例
---
// 用户服务实现
package userservice
import (
"context"
"errors"
"time"
"github.com/micro/go-micro/v2"
"github.com/micro/go-micro/v2/auth"
"github.com/micro/go-micro/v2/logger"
)
// UserService 用户服务接口
type UserService interface {
CreateUser(ctx context.Context, req *CreateUserRequest, rsp *UserResponse) error
GetUser(ctx context.Context, req *GetUserRequest, rsp *UserResponse) error
UpdateUser(ctx context.Context, req *UpdateUserRequest, rsp *UserResponse) error
DeleteUser(ctx context.Context, req *DeleteUserRequest, rsp *EmptyResponse) error
ListUsers(ctx context.Context, req *ListUsersRequest, rsp *ListUsersResponse) error
}
// 用户服务实现
type userService struct {
userRepo UserRepository
authService auth.Auth
eventBus EventBus
cache Cache
validator Validator
}
func NewUserService(
repo UserRepository,
authService auth.Auth,
eventBus EventBus,
cache Cache,
validator Validator,
) UserService {
return &userService{
userRepo: repo,
authService: authService,
eventBus: eventBus,
cache: cache,
validator: validator,
}
}
func (s *userService) CreateUser(ctx context.Context, req *CreateUserRequest, rsp *UserResponse) error {
// 1. 参数验证
if err := s.validator.Validate(req); err != nil {
logger.Errorf("参数验证失败: %v", err)
return err
}
// 2. 检查用户名是否已存在
exists, err := s.userRepo.ExistsByUsername(ctx, req.Username)
if err != nil {
logger.Errorf("检查用户名存在性失败: %v", err)
return err
}
if exists {
return errors.New("用户名已存在")
}
// 3. 检查邮箱是否已存在
exists, err = s.userRepo.ExistsByEmail(ctx, req.Email)
if err != nil {
logger.Errorf("检查邮箱存在性失败: %v", err)
return err
}
if exists {
return errors.New("邮箱已存在")
}
// 4. 创建用户实体
user := &User{
ID: s.generateUserID(),
Username: req.Username,
Email: req.Email,
Password: s.hashPassword(req.Password),
Phone: req.Phone,
Address: req.Address,
Status: "active",
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
// 5. 保存到数据库
if err := s.userRepo.Create(ctx, user); err != nil {
logger.Errorf("保存用户失败: %v", err)
return err
}
// 6. 生成认证token
token, err := s.authService.GenerateToken(user.ID, user.Username)
if err != nil {
logger.Errorf("生成认证token失败: %v", err)
return err
}
// 7. 缓存用户信息
if err := s.cache.Set(ctx, user.ID, user, time.Hour); err != nil {
logger.Warnf("缓存用户信息失败: %v", err)
}
// 8. 发布用户创建事件
event := &UserCreatedEvent{
UserID: user.ID,
Username: user.Username,
Email: user.Email,
CreatedAt: user.CreatedAt,
}
if err := s.eventBus.Publish(ctx, "user.created", event); err != nil {
logger.Warnf("发布用户创建事件失败: %v", err)
}
// 9. 构建响应
rsp.User = &UserInfo{
ID: user.ID,
Username: user.Username,
Email: user.Email,
Phone: user.Phone,
Address: user.Address,
Status: user.Status,
Token: token,
}
logger.Infof("用户创建成功: %s", user.ID)
return nil
}
func (s *userService) GetUser(ctx context.Context, req *GetUserRequest, rsp *UserResponse) error {
// 1. 从缓存获取用户信息
var user *User
if err := s.cache.Get(ctx, req.UserID, &user); err == nil {
rsp.User = s.buildUserInfo(user)
return nil
}
// 2. 从数据库获取用户信息
user, err := s.userRepo.GetByID(ctx, req.UserID)
if err != nil {
logger.Errorf("获取用户信息失败: %v", err)
return err
}
// 3. 缓存用户信息
if err := s.cache.Set(ctx, req.UserID, user, time.Hour); err != nil {
logger.Warnf("缓存用户信息失败: %v", err)
}
// 4. 构建响应
rsp.User = s.buildUserInfo(user)
return nil
}
// 辅助方法
func (s *userService) generateUserID() string {
return generateUUID()
}
func (s *userService) hashPassword(password string) string {
return bcryptHash(password)
}
func (s *userService) buildUserInfo(user *User) *UserInfo {
return &UserInfo{
ID: user.ID,
Username: user.Username,
Email: user.Email,
Phone: user.Phone,
Address: user.Address,
Status: user.Status,
}
}
---
b.框架层
a.核心功能抽象
框架层提供了微服务运行时的核心功能,包括服务注册发现、负载均衡、RPC通信、消息处理等。这些功能通过标准接口暴露,支持多种实现方式。
b.中间件支持
框架层支持中间件模式,可以在请求处理的不同阶段插入自定义逻辑,如认证、授权、日志、监控等。
c.基础层
a.网络通信
基础层负责底层网络通信,包括TCP/UDP协议处理、HTTP/gRPC协议支持、连接池管理等。
b.序列化机制
支持多种序列化格式(JSON、Protobuf、Msgpack等),可以根据性能需求选择合适的编码方式。
03.组件交互流程
a.服务调用流程
a.客户端请求处理
客户端发起请求时,通过Selector选择目标服务实例,使用LoadBalancer进行负载均衡,通过Transport建立连接,使用Codec编码请求数据,发送到服务端。
b.服务端响应处理
服务端接收请求后,通过Codec解码请求数据,路由到对应的处理器,执行业务逻辑,然后编码响应数据并返回给客户端。
c.代码示例
---
// 完整的服务调用流程示例
package main
import (
"context"
"fmt"
"time"
"github.com/micro/go-micro/v2"
"github.com/micro/go-micro/v2/client"
"github.com/micro/go-micro/v2/metadata"
"github.com/micro/go-micro/v2/selector"
"github.com/micro/go-micro/v2/transport"
)
// 客户端调用流程
func demonstrateClientCallFlow(service micro.Service) {
// 1. 创建客户端
client := service.Client()
// 2. 创建请求
req := client.NewRequest("user.service", "User.GetUser", &GetUserRequest{
UserID: "12345",
})
// 3. 设置请求元数据
ctx := metadata.NewContext(context.Background(), map[string]string{
"X-Request-ID": generateRequestID(),
"X-User-ID": "12345",
"X-Trace-ID": generateTraceID(),
})
// 4. 设置调用选项
opts := []client.CallOption{
client.WithContentType("application/json"),
client.WithRequestTimeout(5 * time.Second),
client.WithRetries(3),
client.WithBackoff(func(ctx context.Context, req client.Request, attempts int) time.Duration {
return time.Duration(attempts) * 100 * time.Millisecond
}),
}
// 5. 执行调用
var rsp GetUserResponse
err := client.Call(ctx, req, &rsp, opts...)
if err != nil {
fmt.Printf("服务调用失败: %v\n", err)
return
}
fmt.Printf("调用成功,用户信息: %+v\n", rsp.User)
}
// 自定义选择器
type customSelector struct {
selector.Selector
strategy string
}
func NewCustomSelector(strategy string) selector.Selector {
return &customSelector{
strategy: strategy,
}
}
func (cs *customSelector) Select(service string, opts ...selector.SelectOption) (selector.Next, error) {
switch cs.strategy {
case "round_robin":
return cs.roundRobinSelect(service, opts...)
case "random":
return cs.randomSelect(service, opts...)
case "weighted":
return cs.weightedSelect(service, opts...)
default:
return cs.Selector.Select(service, opts...)
}
}
func (cs *customSelector) roundRobinSelect(service string, opts ...selector.SelectOption) (selector.Next, error) {
// 实现轮询选择逻辑
services, err := cs.getServices(service, opts...)
if err != nil {
return nil, err
}
if len(services) == 0 {
return nil, selector.ErrNotFound
}
// 简单的轮询实现
index := time.Now().UnixNano() % int64(len(services))
node := services[index].Nodes[0]
return func() (*registry.Node, error) {
return node, nil
}, nil
}
func (cs *customSelector) weightedSelect(service string, opts ...selector.SelectOption) (selector.Next, error) {
// 实现加权选择逻辑
services, err := cs.getServices(service, opts...)
if err != nil {
return nil, err
}
if len(services) == 0 {
return nil, selector.ErrNotFound
}
// 根据权重选择节点
totalWeight := 0
nodes := []*registry.Node{}
for _, svc := range services {
for _, node := range svc.Nodes {
weight := getNodeWeight(node)
totalWeight += weight
// 根据权重重复添加节点
for i := 0; i < weight; i++ {
nodes = append(nodes, node)
}
}
}
if totalWeight == 0 {
return nil, selector.ErrNotFound
}
// 随机选择
index := int(time.Now().UnixNano()) % len(nodes)
selectedNode := nodes[index]
return func() (*registry.Node, error) {
return selectedNode, nil
}, nil
}
func (cs *customSelector) getServices(service string, opts ...selector.SelectOption) ([]*registry.Service, error) {
// 从注册中心获取服务列表
// 这里简化实现
return cs.Selector.Select(service, opts...)
}
func getNodeWeight(node *registry.Node) int {
// 从节点元数据获取权重
if weightStr, ok := node.Metadata["weight"]; ok {
if weight, err := strconv.Atoi(weightStr); err == nil {
return weight
}
}
return 1 // 默认权重
}
// 自定义传输层
type customTransport struct {
transport.Transport
compression string
}
func NewCustomTransport(compression string) transport.Transport {
return &customTransport{
compression: compression,
}
}
func (ct *customTransport) Dial(addr string, opts ...transport.DialOption) (transport.Client, error) {
// 添加压缩支持
client, err := ct.Transport.Dial(addr, opts...)
if err != nil {
return nil, err
}
return &customClient{
Client: client,
compression: ct.compression,
}, nil
}
type customClient struct {
transport.Client
compression string
}
func (cc *customClient) Send(m *transport.Message) error {
// 添加压缩逻辑
if cc.compression == "gzip" {
if compressed, err := compressData(m.Body); err == nil {
m.Body = compressed
m.Header["Content-Encoding"] = "gzip"
}
}
return cc.Client.Send(m)
}
func compressData(data []byte) ([]byte, error) {
// 实现gzip压缩
// 这里简化实现
return data, nil
}
---
b.消息处理流程
a.发布订阅机制
生产者通过Broker发布消息到指定主题,消费者订阅主题接收消息。Broker负责消息的路由、持久化和分发。
b.消息传递保证
支持至少一次、最多一次等消息传递语义,提供重试、死信队列等机制确保消息可靠传递。
1.6 插件化设计
01.插件系统架构
a.接口标准
a.插件接口定义
go-micro的核心插件系统基于Go语言接口机制,每个核心功能都定义了标准接口,包括Transport、Codec、Registry、Broker、Selector、Server、Client等。这种设计确保了不同实现的互操作性。
b.插件生命周期
插件具有完整的生命周期管理,包括初始化、启动、运行、停止和销毁等阶段。框架提供了统一的插件管理机制,确保插件能够正确地集成到服务中。
c.代码示例
---
// 插件接口定义
package plugin
import "context"
// Plugin 基础插件接口
type Plugin interface {
// Name 返回插件名称
Name() string
// Version 返回插件版本
Version() string
// Description 返回插件描述
Description() string
// Init 初始化插件
Init(ctx context.Context, config map[string]interface{}) error
// Start 启动插件
Start(ctx context.Context) error
// Stop 停止插件
Stop(ctx context.Context) error
// Cleanup 清理插件资源
Cleanup(ctx context.Context) error
}
// ConfigurablePlugin 可配置插件接口
type ConfigurablePlugin interface {
Plugin
// SetConfig 设置插件配置
SetConfig(config map[string]interface{}) error
// GetConfig 获取插件配置
GetConfig() map[string]interface{}
}
// HealthCheckPlugin 健康检查插件接口
type HealthCheckPlugin interface {
Plugin
// HealthCheck 执行健康检查
HealthCheck(ctx context.Context) error
// HealthStatus 获取健康状态
HealthStatus() HealthStatus
}
// MetricsPlugin 监控插件接口
type MetricsPlugin interface {
Plugin
// IncrementCounter 增加计数器
IncrementCounter(name string, labels map[string]string, value float64)
// RecordTimer 记录计时器
RecordTimer(name string, labels map[string]string, duration time.Duration)
// SetGauge 设置仪表盘值
SetGauge(name string, labels map[string]string, value float64)
}
// LoggingPlugin 日志插件接口
type LoggingPlugin interface {
Plugin
// Debug 记录调试日志
Debug(msg string, fields ...interface{})
// Info 记录信息日志
Info(msg string, fields ...interface{})
// Warn 记录警告日志
Warn(msg string, fields ...interface{})
// Error 记录错误日志
Error(msg string, fields ...interface{})
// Fatal 记录致命错误日志
Fatal(msg string, fields ...interface{})
}
// 插件管理器
type PluginManager struct {
plugins map[string]Plugin
order []string // 插件启动顺序
mu sync.RWMutex
}
func NewPluginManager() *PluginManager {
return &PluginManager{
plugins: make(map[string]Plugin),
order: make([]string, 0),
}
}
func (pm *PluginManager) RegisterPlugin(plugin Plugin) error {
pm.mu.Lock()
defer pm.mu.Unlock()
name := plugin.Name()
if _, exists := pm.plugins[name]; exists {
return fmt.Errorf("插件 %s 已存在", name)
}
pm.plugins[name] = plugin
pm.order = append(pm.order, name)
return nil
}
func (pm *PluginManager) GetPlugin(name string) (Plugin, bool) {
pm.mu.RLock()
defer pm.mu.RUnlock()
plugin, exists := pm.plugins[name]
return plugin, exists
}
func (pm *PluginManager) StartAll(ctx context.Context) error {
pm.mu.RLock()
defer pm.mu.RUnlock()
for _, name := range pm.order {
plugin := pm.plugins[name]
if err := plugin.Start(ctx); err != nil {
return fmt.Errorf("启动插件 %s 失败: %v", name, err)
}
}
return nil
}
func (pm *PluginManager) StopAll(ctx context.Context) error {
pm.mu.RLock()
defer pm.mu.RUnlock()
// 按相反顺序停止插件
for i := len(pm.order) - 1; i >= 0; i-- {
name := pm.order[i]
plugin := pm.plugins[name]
if err := plugin.Stop(ctx); err != nil {
return fmt.Errorf("停止插件 %s 失败: %v", name, err)
}
}
return nil
}
---
b.插件发现机制
a.自动发现
go-micro支持通过Go的import机制自动发现插件,开发者只需导入插件包,插件会自动注册到框架中。
b.配置驱动
支持通过配置文件指定要加载的插件,包括插件类型、实现类、配置参数等信息,实现灵活的插件组合。
02.核心插件类型
a.Transport插件
a.功能说明
Transport插件负责底层网络通信,支持HTTP、gRPC、TCP、UDP、QUIC等多种协议。开发者可以根据性能和功能需求选择合适的传输协议。
b.HTTP传输实现
---
// HTTP传输插件实现
package httptransport
import (
"bufio"
"compress/gzip"
"context"
"crypto/tls"
"fmt"
"io"
"net"
"net/http"
"sync"
"time"
"github.com/micro/go-micro/v2/transport"
)
type httpTransport struct {
opts transport.Options
mu sync.RWMutex
}
type httpClient struct {
client *http.Client
addr string
conn net.Conn
dialOpts transport.DialOptions
timeout time.Duration
}
type httpListener struct {
listener net.Listener
addr string
opts transport.ListenOptions
}
func NewHTTPTransport(opts ...transport.Option) transport.Transport {
h := &httpTransport{
opts: transport.Options{
Timeout: transport.DefaultTimeout,
},
}
for _, o := range opts {
o(&h.opts)
}
return h
}
func (h *httpTransport) Init(opts ...transport.Option) error {
for _, o := range opts {
o(&h.opts)
}
return nil
}
func (h *httpTransport) Options() transport.Options {
return h.opts
}
func (h *httpTransport) Dial(addr string, opts ...transport.DialOption) (transport.Client, error) {
var dopts transport.DialOptions
for _, o := range opts {
o(&dopts)
}
// 创建HTTP客户端
client := &http.Client{
Timeout: h.opts.Timeout,
Transport: &http.Transport{
DialContext: (&net.Dialer{
Timeout: h.opts.Timeout,
KeepAlive: 30 * time.Second,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: dopts.InsecureSkipVerify,
},
DisableCompression: false,
},
}
// 如果设置了流式传输
if dopts.Stream {
conn, err := net.DialTimeout("tcp", addr, h.opts.Timeout)
if err != nil {
return nil, err
}
return &httpClient{
client: client,
addr: addr,
conn: conn,
dialOpts: dopts,
timeout: h.opts.Timeout,
}, nil
}
return &httpClient{
client: client,
addr: addr,
dialOpts: dopts,
timeout: h.opts.Timeout,
}, nil
}
func (h *httpTransport) Listen(addr string, opts ...transport.ListenOption) (transport.Listener, error) {
var lopts transport.ListenOptions
for _, o := range opts {
o(&lopts)
}
var listener net.Listener
var err error
// TLS配置
if lopts.TLSConfig != nil {
listener, err = tls.Listen("tcp", addr, lopts.TLSConfig)
} else {
listener, err = net.Listen("tcp", addr)
}
if err != nil {
return nil, err
}
return &httpListener{
listener: listener,
addr: listener.Addr().String(),
opts: lopts,
}, nil
}
func (c *httpClient) Send(m *transport.Message) error {
// 序列化消息体
body, err := json.Marshal(m.Body)
if err != nil {
return err
}
// 创建HTTP请求
req, err := http.NewRequest("POST", fmt.Sprintf("http://%s/", c.addr), bytes.NewReader(body))
if err != nil {
return err
}
// 设置请求头
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Micro-Service", m.Header["Micro-Service"])
req.Header.Set("Micro-Method", m.Header["Micro-Method"])
req.Header.Set("Micro-Id", m.Header["Micro-Id"])
// 设置压缩
if c.dialOpts.Compression {
req.Header.Set("Content-Encoding", "gzip")
req.Header.Set("Accept-Encoding", "gzip")
var buf bytes.Buffer
gz := gzip.NewWriter(&buf)
if _, err := gz.Write(body); err != nil {
return err
}
if err := gz.Close(); err != nil {
return err
}
req.Body = io.NopCloser(&buf)
}
// 发送请求
resp, err := c.client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
// 检查响应状态
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("HTTP请求失败: %s", resp.Status)
}
return nil
}
func (c *httpClient) Recv(m *transport.Message) error {
// 在流式传输模式下接收数据
if c.conn != nil {
reader := bufio.NewReader(c.conn)
line, err := reader.ReadString('\n')
if err != nil {
return err
}
var response map[string]interface{}
if err := json.Unmarshal([]byte(line), &response); err != nil {
return err
}
m.Body = response
return nil
}
return fmt.Errorf("非流式传输模式不支持Recv")
}
func (c *httpClient) Close() error {
if c.conn != nil {
return c.conn.Close()
}
return nil
}
func (l *httpListener) Addr() string {
return l.addr
}
func (l *httpListener) Close() error {
return l.listener.Close()
}
func (l *httpListener) Accept(fn func(transport.Socket)) error {
server := &http.Server{
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// 读取请求体
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
r.Body.Close()
// 处理压缩
if r.Header.Get("Content-Encoding") == "gzip" {
reader, err := gzip.NewReader(bytes.NewReader(body))
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
body, err = io.ReadAll(reader)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
reader.Close()
}
// 解析消息
var msgBody interface{}
if err := json.Unmarshal(body, &msgBody); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// 创建传输消息
msg := &transport.Message{
Header: map[string]string{
"Micro-Service": r.Header.Get("Micro-Service"),
"Micro-Method": r.Header.Get("Micro-Method"),
"Micro-Id": r.Header.Get("Micro-Id"),
},
Body: msgBody,
}
// 创建socket包装器
socket := &httpSocket{
conn: nil,
local: l.listener.Addr().String(),
remote: r.RemoteAddr,
}
// 调用处理函数
fn(socket)
// 发送响应
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]interface{}{
"status": "success",
})
}),
}
return server.Serve(l.listener)
}
type httpSocket struct {
conn net.Conn
local string
remote string
}
func (s *httpSocket) Local() string {
return s.local
}
func (s *httpSocket) Remote() string {
return s.remote
}
func (s *httpSocket) Recv(m *transport.Message) error {
return fmt.Errorf("HTTP传输不支持Recv方法")
}
func (s *httpSocket) Send(m *transport.Message) error {
return fmt.Errorf("HTTP传输不支持Send方法")
}
func (s *httpSocket) Close() error {
if s.conn != nil {
return s.conn.Close()
}
return nil
}
func (h *httpTransport) String() string {
return "http"
}
---
b.Codec插件
a.功能说明
Codec插件负责消息的序列化和反序列化,支持JSON、Protobuf、Msgpack、XML等多种格式。不同的Codec在性能、可读性、兼容性方面各有优势。
b.Protobuf编解码器
---
// Protobuf编解码器插件
package protobufcodec
import (
"bytes"
"fmt"
"io"
"sync"
"github.com/golang/protobuf/jsonpb"
"github.com/golang/protobuf/proto"
"github.com/micro/go-micro/v2/codec"
)
type protobufCodec struct {
sync.Mutex
jsonpbMarshaler *jsonpb.Marshaler
jsonpbUnmarshaler *jsonpb.Unmarshaler
}
func (c *protobufCodec) Marshal(v interface{}) ([]byte, error) {
if m, ok := v.(proto.Message); ok {
// 直接使用protobuf二进制格式
return proto.Marshal(m)
}
// 对于非protobuf消息,转换为protobuf兼容格式
if pb, ok := v.(*codec.Frame); ok {
return pb.Data, nil
}
return nil, fmt.Errorf("不支持的类型: %T", v)
}
func (c *protobufCodec) Unmarshal(data []byte, v interface{}) error {
if m, ok := v.(proto.Message); ok {
// 直接解析protobuf二进制格式
return proto.Unmarshal(data, m)
}
if pb, ok := v.(*codec.Frame); ok {
pb.Data = data
return nil
}
return fmt.Errorf("不支持的类型: %T", v)
}
func (c *protobufCodec) String() string {
return "protobuf"
}
// 支持JSON格式的protobuf编解码器
type protoJSONCodec struct {
sync.Mutex
marshaler *jsonpb.Marshaler
unmarshaler *jsonpb.Unmarshaler
}
func NewProtoJSONCodec() codec.Codec {
return &protoJSONCodec{
marshaler: &jsonpb.Marshaler{
EmitDefaults: true,
OrigName: true,
},
unmarshaler: &jsonpb.Unmarshaler{
AllowUnknownFields: true,
},
}
}
func (c *protoJSONCodec) Marshal(v interface{}) ([]byte, error) {
c.Lock()
defer c.Unlock()
if m, ok := v.(proto.Message); ok {
var buf bytes.Buffer
if err := c.marshaler.Marshal(&buf, m); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
return nil, fmt.Errorf("不支持的类型: %T", v)
}
func (c *protoJSONCodec) Unmarshal(data []byte, v interface{}) error {
c.Lock()
defer c.Unlock()
if m, ok := v.(proto.Message); ok {
return c.unmarshaler.Unmarshal(bytes.NewReader(data), m)
}
return fmt.Errorf("不支持的类型: %T", v)
}
func (c *protoJSONCodec) String() string {
return "proto-json"
}
// 自定义压缩编解码器
type compressedCodec struct {
codec codec.Codec
compressor Compressor
}
type Compressor interface {
Compress(data []byte) ([]byte, error)
Decompress(data []byte) ([]byte, error)
}
func NewCompressedCodec(c codec.Codec, comp Compressor) codec.Codec {
return &compressedCodec{
codec: c,
compressor: comp,
}
}
func (c *compressedCodec) Marshal(v interface{}) ([]byte, error) {
// 先序列化
data, err := c.codec.Marshal(v)
if err != nil {
return nil, err
}
// 再压缩
return c.compressor.Compress(data)
}
func (c *compressedCodec) Unmarshal(data []byte, v interface{}) error {
// 先解压
decompressed, err := c.compressor.Decompress(data)
if err != nil {
return err
}
// 再反序列化
return c.codec.Unmarshal(decompressed, v)
}
func (c *compressedCodec) String() string {
return fmt.Sprintf("compressed-%s", c.codec.String())
}
---
c.Registry插件
a.功能说明
Registry插件实现服务注册与发现功能,支持etcd、Consul、Kubernetes、Zookeeper等多种注册中心。开发者可以根据基础设施和运维需求选择合适的注册中心。
b.etcd注册中心实现
---
// etcd注册中心插件
package etcdregistry
import (
"context"
"encoding/json"
"fmt"
"strings"
"sync"
"time"
clientv3 "go.etcd.io/etcd/client/v3"
"go.etcd.io/etcd/client/v3/concurrency"
"github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/registry"
)
type etcdRegistry struct {
client *clientv3.Client
options registry.Options
mutex sync.Mutex
// 服务缓存
services map[string]*registry.Service
watchers map[string]*etcdWatcher
// 租约管理
leases map[string]clientv3.LeaseID
}
type etcdWatcher struct {
registry *etcdRegistry
service string
ch clientv3.WatchChan
cancel context.CancelFunc
}
func NewRegistry(opts ...registry.Option) registry.Registry {
options := registry.Options{
Timeout: time.Second * 30,
}
for _, o := range opts {
o(&options)
}
return &etcdRegistry{
options: options,
services: make(map[string]*registry.Service),
watchers: make(map[string]*etcdWatcher),
leases: make(map[string]clientv3.LeaseID),
}
}
func (e *etcdRegistry) Init(opts ...registry.Option) error {
for _, o := range opts {
o(&e.options)
}
// 创建etcd客户端
endpoints := strings.Split(e.options.Addrs[0], ",")
client, err := clientv3.New(clientv3.Config{
Endpoints: endpoints,
DialTimeout: e.options.Timeout,
Username: e.options.Context.Value("username").(string),
Password: e.options.Context.Value("password").(string),
})
if err != nil {
return fmt.Errorf("创建etcd客户端失败: %v", err)
}
e.client = client
return nil
}
func (e *etcdRegistry) Options() registry.Options {
return e.options
}
func (e *etcdRegistry) Register(s *registry.Service, opts ...registry.RegisterOption) error {
e.mutex.Lock()
defer e.mutex.Unlock()
var options registry.RegisterOptions
for _, o := range opts {
o(&options)
}
// 创建租约
ctx, cancel := context.WithTimeout(context.Background(), e.options.Timeout)
defer cancel()
lease, err := e.client.Grant(ctx, int64(options.TTL.Seconds()))
if err != nil {
return fmt.Errorf("创建租约失败: %v", err)
}
// 注册服务节点
for _, node := range s.Nodes {
serviceData := ®istry.Service{
Name: s.Name,
Version: s.Version,
Metadata: s.Metadata,
Nodes: []*registry.Node{node},
}
data, err := json.Marshal(serviceData)
if err != nil {
return fmt.Errorf("序列化服务数据失败: %v", err)
}
key := fmt.Sprintf("/micro-registry/%s/%s/%s", s.Name, s.Version, node.Id)
ctx, cancel = context.WithTimeout(context.Background(), e.options.Timeout)
_, err = e.client.Put(ctx, key, string(data), clientv3.WithLease(lease.ID))
cancel()
if err != nil {
return fmt.Errorf("注册服务节点失败: %v", err)
}
}
// 续租
if options.TTL > 0 {
e.leases[s.Name] = lease.ID
go e.keepAlive(lease.ID, options.TTL)
}
// 更新缓存
e.services[s.Name] = s
logger.Infof("服务注册成功: %s", s.Name)
return nil
}
func (e *etcdRegistry) Deregister(s *registry.Service, opts ...registry.DeregisterOption) error {
e.mutex.Lock()
defer e.mutex.Unlock()
for _, node := range s.Nodes {
key := fmt.Sprintf("/micro-registry/%s/%s/%s", s.Name, s.Version, node.Id)
ctx, cancel := context.WithTimeout(context.Background(), e.options.Timeout)
_, err := e.client.Delete(ctx, key)
cancel()
if err != nil {
logger.Errorf("删除服务节点失败: %v", err)
continue
}
}
// 撤销租约
if leaseID, exists := e.leases[s.Name]; exists {
ctx, cancel := context.WithTimeout(context.Background(), e.options.Timeout)
_, err := e.client.Revoke(ctx, leaseID)
cancel()
if err != nil {
logger.Errorf("撤销租约失败: %v", err)
}
delete(e.leases, s.Name)
}
// 删除缓存
delete(e.services, s.Name)
logger.Infof("服务注销成功: %s", s.Name)
return nil
}
func (e *etcdRegistry) GetService(name string) ([]*registry.Service, error) {
e.mutex.Lock()
defer e.mutex.Unlock()
// 先检查缓存
if service, exists := e.services[name]; exists {
return []*registry.Service{service}, nil
}
// 从etcd获取服务
key := fmt.Sprintf("/micro-registry/%s/", name)
ctx, cancel := context.WithTimeout(context.Background(), e.options.Timeout)
resp, err := e.client.Get(ctx, key, clientv3.WithPrefix())
cancel()
if err != nil {
return nil, fmt.Errorf("获取服务失败: %v", err)
}
if len(resp.Kvs) == 0 {
return nil, registry.ErrNotFound
}
// 解析服务数据
services := make(map[string]*registry.Service)
for _, kv := range resp.Kvs {
var service registry.Service
if err := json.Unmarshal(kv.Value, &service); err != nil {
logger.Errorf("解析服务数据失败: %v", err)
continue
}
if existing, exists := services[service.Version]; exists {
existing.Nodes = append(existing.Nodes, service.Nodes...)
} else {
services[service.Version] = &service
}
}
// 构建结果
result := make([]*registry.Service, 0, len(services))
for _, service := range services {
result = append(result, service)
}
// 更新缓存
if len(result) > 0 {
e.services[name] = result[0]
}
return result, nil
}
func (e *etcdRegistry) ListServices() ([]*registry.Service, error) {
key := "/micro-registry/"
ctx, cancel := context.WithTimeout(context.Background(), e.options.Timeout)
resp, err := e.client.Get(ctx, key, clientv3.WithPrefix())
cancel()
if err != nil {
return nil, fmt.Errorf("获取服务列表失败: %v", err)
}
services := make(map[string]*registry.Service)
for _, kv := range resp.Kvs {
parts := strings.Split(string(kv.Key), "/")
if len(parts) < 4 {
continue
}
serviceName := parts[2]
var service registry.Service
if err := json.Unmarshal(kv.Value, &service); err != nil {
logger.Errorf("解析服务数据失败: %v", err)
continue
}
if existing, exists := services[serviceName]; exists {
existing.Nodes = append(existing.Nodes, service.Nodes...)
} else {
services[serviceName] = &service
}
}
result := make([]*registry.Service, 0, len(services))
for _, service := range services {
result = append(result, service)
}
return result, nil
}
func (e *etcdRegistry) Watch(opts ...registry.WatchOption) (registry.Watcher, error) {
var options registry.WatchOptions
for _, o := range opts {
o(&options)
}
ctx, cancel := context.WithCancel(context.Background())
key := "/micro-registry/"
if options.Service != "" {
key += options.Service + "/"
}
watchCh := e.client.Watch(ctx, key, clientv3.WithPrefix())
watcher := &etcdWatcher{
registry: e,
service: options.Service,
ch: watchCh,
cancel: cancel,
}
e.watchers[options.Service] = watcher
return watcher, nil
}
func (e *etcdRegistry) keepAlive(leaseID clientv3.LeaseID, ttl time.Duration) {
ticker := time.NewTicker(ttl / 3)
defer ticker.Stop()
for {
select {
case <-ticker.C:
ctx, cancel := context.WithTimeout(context.Background(), e.options.Timeout)
_, err := e.client.KeepAliveOnce(ctx, leaseID)
cancel()
if err != nil {
logger.Errorf("续租失败: %v", err)
return
}
}
}
}
func (e *etcdRegistry) String() string {
return "etcd"
}
---
1.7 生态系统
01.核心工具链
a.micro命令行工具
a.功能说明
micro是go-micro生态系统的命令行工具,提供服务创建、构建、运行、部署等功能。开发者可以通过micro命令快速搭建微服务开发环境,管理服务生命周期。
b.常用命令示例
---
# micro命令行工具使用示例
package main
import (
"fmt"
"os"
"os/exec"
"strings"
)
// MicroCmd 封装micro命令行工具
type MicroCmd struct {
binaryPath string
config *Config
}
type Config struct {
Registry string `json:"registry"`
Transport string `json:"transport"`
Broker string `json:"broker"`
Codec string `json:"codec"`
Client *ClientConfig `json:"client"`
Server *ServerConfig `json:"server"`
Plugins map[string]string `json:"plugins"`
}
type ClientConfig struct {
RequestTimeout string `json:"request_timeout"`
Retries int `json:"retries"`
PoolSize int `json:"pool_size"`
}
type ServerConfig struct {
Address string `json:"address"`
Advertise string `json:"advertise"`
MaxConcurrency int `json:"max_concurrency"`
Middleware []string `json:"middleware"`
}
func NewMicroCmd(config *Config) *MicroCmd {
return &MicroCmd{
binaryPath: "micro", // 假设micro在PATH中
config: config,
}
}
// NewService 创建新服务
func (m *MicroCmd) NewService(serviceName, serviceType string) error {
var args []string
args = append(args, "new")
args = append(args, serviceType)
args = append(args, serviceName)
// 设置命名空间
if namespace := os.Getenv("MICRO_NAMESPACE"); namespace != "" {
args = append(args, "--namespace", namespace)
}
return m.runCommand(args...)
}
// RunService 运行服务
func (m *MicroCmd) RunService(servicePath string, args ...string) error {
cmdArgs := []string{"run", servicePath}
cmdArgs = append(cmdArgs, args...)
// 添加配置参数
if m.config.Registry != "" {
cmdArgs = append(cmdArgs, "--registry", m.config.Registry)
}
if m.config.Transport != "" {
cmdArgs = append(cmdArgs, "--transport", m.config.Transport)
}
if m.config.Broker != "" {
cmdArgs = append(cmdArgs, "--broker", m.config.Broker)
}
if m.config.Codec != "" {
cmdArgs = append(cmdArgs, "--codec", m.config.Codec)
}
return m.runCommand(cmdArgs...)
}
// BuildService 构建服务
func (m *MicroCmd) BuildService(servicePath, output string) error {
args := []string{"build", servicePath}
if output != "" {
args = append(args, "--output", output)
}
return m.runCommand(args...)
}
// ListServices 列出所有服务
func (m *MicroCmd) ListServices() error {
args := []string{"list", "services"}
return m.runCommand(args...)
}
// GetService 获取服务详情
func (m *MicroCmd) GetService(serviceName string) error {
args := []string{"get", "service", serviceName}
return m.runCommand(args...)
}
// CallService 调用服务
func (m *MicroCmd) CallService(serviceName, method string, data interface{}) error {
args := []string{"call", serviceName, method}
// 序列化请求数据
if data != nil {
jsonData, err := json.Marshal(data)
if err != nil {
return fmt.Errorf("序列化请求数据失败: %v", err)
}
args = append(args, string(jsonData))
}
return m.runCommand(args...)
}
// StreamService 流式调用服务
func (m *MicroCmd) StreamService(serviceName, method string) error {
args := []string{"stream", serviceName, method}
return m.runCommand(args...)
}
// PublishEvent 发布事件
func (m *MicroCmd) PublishEvent(topic string, event interface{}) error {
args := []string{"publish", topic}
if event != nil {
jsonData, err := json.Marshal(event)
if err != nil {
return fmt.Errorf("序列化事件数据失败: %v", err)
}
args = append(args, string(jsonData))
}
return m.runCommand(args...)
}
// SubscribeEvent 订阅事件
func (m *MicroCmd) SubscribeEvent(topic string) error {
args := []string{"subscribe", topic}
return m.runCommand(args...)
}
// HealthCheck 健康检查
func (m *MicroCmd) HealthCheck() error {
args := []string{"health"}
return m.runCommand(args...)
}
// Stats 统计信息
func (m *MicroCmd) Stats() error {
args := []string{"stats"}
return m.runCommand(args...)
}
// runCommand 执行命令
func (m *MicroCmd) runCommand(args ...string) error {
cmd := exec.Command(m.binaryPath, args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin
fmt.Printf("执行命令: %s %s\n", m.binaryPath, strings.Join(args, " "))
return cmd.Run()
}
// 使用示例
func ExampleMicroCmd() {
config := &Config{
Registry: "etcd",
Transport: "http",
Broker: "nats",
Codec: "json",
Client: &ClientConfig{
RequestTimeout: "30s",
Retries: 3,
PoolSize: 100,
},
Server: &ServerConfig{
Address: ":8080",
MaxConcurrency: 1000,
Middleware: []string{"logger", "metrics", "recovery"},
},
Plugins: map[string]string{
"monitoring": "prometheus",
"tracing": "jaeger",
},
}
microCmd := NewMicroCmd(config)
// 创建新服务
if err := microCmd.NewService("user-service", "service"); err != nil {
fmt.Printf("创建服务失败: %v\n", err)
return
}
// 构建服务
if err := microCmd.BuildService("user-service", "user-service"); err != nil {
fmt.Printf("构建服务失败: %v\n", err)
return
}
// 运行服务
go func() {
if err := microCmd.RunService("user-service"); err != nil {
fmt.Printf("运行服务失败: %v\n", err)
}
}()
// 等待服务启动
time.Sleep(5 * time.Second)
// 调用服务
reqData := map[string]interface{}{
"name": "John Doe",
"email": "[email protected]",
}
if err := microCmd.CallService("user-service", "User.Create", reqData); err != nil {
fmt.Printf("调用服务失败: %v\n", err)
}
// 发布事件
event := map[string]interface{}{
"type": "user.created",
"user_id": "12345",
"timestamp": time.Now().Unix(),
}
if err := microCmd.PublishEvent("user.events", event); err != nil {
fmt.Printf("发布事件失败: %v\n", err)
}
}
---
b.protoc代码生成工具
a.功能说明
go-micro使用Protocol Buffers定义服务接口,通过protoc工具生成Go代码。生成的代码包括客户端和服务端接口定义、消息结构体、序列化代码等。
b.代码生成配置
---
// protoc代码生成配置示例
syntax = "proto3";
package user;
option go_package = "github.com/example/user/proto/user";
import "google/protobuf/timestamp.proto";
// 用户服务定义
service UserService {
rpc CreateUser(CreateUserRequest) returns (CreateUserResponse);
rpc GetUser(GetUserRequest) returns (GetUserResponse);
rpc UpdateUser(UpdateUserRequest) returns (UpdateUserResponse);
rpc DeleteUser(DeleteUserRequest) returns (DeleteUserResponse);
rpc ListUsers(ListUsersRequest) returns (ListUsersResponse);
rpc SearchUsers(SearchUsersRequest) returns (SearchUsersResponse);
}
// 用户消息定义
message User {
string id = 1;
string username = 2;
string email = 3;
string phone = 4;
string address = 5;
string avatar = 6;
UserStatus status = 7;
google.protobuf.Timestamp created_at = 8;
google.protobuf.Timestamp updated_at = 9;
google.protobuf.Timestamp deleted_at = 10;
map<string, string> metadata = 11;
}
enum UserStatus {
USER_STATUS_UNSPECIFIED = 0;
USER_STATUS_ACTIVE = 1;
USER_STATUS_INACTIVE = 2;
USER_STATUS_SUSPENDED = 3;
USER_STATUS_DELETED = 4;
}
// 创建用户请求
message CreateUserRequest {
string username = 1;
string email = 2;
string phone = 3;
string address = 4;
string avatar = 5;
map<string, string> metadata = 6;
}
// 创建用户响应
message CreateUserResponse {
User user = 1;
string message = 2;
}
// 获取用户请求
message GetUserRequest {
string user_id = 1;
string username = 2;
string email = 3;
bool include_deleted = 4;
}
// 获取用户响应
message GetUserResponse {
User user = 1;
}
// 更新用户请求
message UpdateUserRequest {
string user_id = 1;
string username = 2;
string email = 3;
string phone = 4;
string address = 5;
string avatar = 6;
map<string, string> metadata = 7;
repeated string update_fields = 8;
}
// 更新用户响应
message UpdateUserResponse {
User user = 1;
string message = 2;
}
// 删除用户请求
message DeleteUserRequest {
string user_id = 1;
bool soft_delete = 2;
}
// 删除用户响应
message DeleteUserResponse {
string message = 1;
}
// 列出用户请求
message ListUsersRequest {
int32 page = 1;
int32 page_size = 2;
string sort_by = 3;
string sort_order = 4;
UserStatus status = 5;
google.protobuf.Timestamp created_after = 6;
google.protobuf.Timestamp created_before = 7;
repeated string fields = 8;
}
// 列出用户响应
message ListUsersResponse {
repeated User users = 1;
int32 total_count = 2;
int32 page = 3;
int32 page_size = 4;
bool has_next = 5;
bool has_prev = 6;
}
// 搜索用户请求
message SearchUsersRequest {
string query = 1;
repeated string search_fields = 2;
int32 page = 3;
int32 page_size = 4;
string sort_by = 5;
string sort_order = 6;
UserStatus status = 7;
repeated string fields = 8;
}
// 搜索用户响应
message SearchUsersResponse {
repeated User users = 1;
int32 total_count = 2;
int32 page = 3;
int32 page_size = 4;
bool has_next = 5;
bool has_prev = 6;
repeated string search_suggestions = 7;
}
// 生成命令
// protoc --proto_path=. --go_out=. --go-grpc_out=. --micro_out=. user.proto
---
c.micro Web界面
a.功能说明
micro提供了一个Web管理界面,可以查看服务列表、调用服务、查看监控数据、管理配置等。这个界面对于开发调试和运维监控非常有用。
b.界面功能
服务列表展示所有注册的服务,包括服务名称、版本、节点信息、健康状态等。服务调用界面允许直接在Web上测试服务接口。监控页面展示服务的性能指标和调用链路。
02.第三方集成
a.监控与追踪
a.Prometheus集成
Prometheus是一个开源的监控系统,go-micro提供了Prometheus插件,可以收集服务的指标数据,包括请求计数、响应时间、错误率等。
b.Jaeger集成
Jaeger是分布式追踪系统,go-micro通过OpenTracing接口集成Jaeger,实现请求链路的跟踪和分析。
c.集成实现示例
---
// 监控与追踪集成示例
package monitoring
import (
"context"
"time"
"github.com/micro/go-micro/v2/server"
"github.com/opentracing/opentracing-go"
"github.com/opentracing/opentracing-go/ext"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
jaegerconfig "github.com/uber/jaeger-client-go/config"
)
// Prometheus指标定义
var (
// 请求计数器
requestsTotal = promauto.NewCounterVec(prometheus.CounterOpts{
Name: "micro_requests_total",
Help: "Total number of requests",
}, []string{"service", "method", "status"})
// 请求持续时间
requestDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{
Name: "micro_request_duration_seconds",
Help: "Request duration in seconds",
Buckets: prometheus.DefBuckets,
}, []string{"service", "method"})
// 活跃连接数
activeConnections = promauto.NewGaugeVec(prometheus.GaugeOpts{
Name: "micro_active_connections",
Help: "Number of active connections",
}, []string{"service"})
// 错误计数器
errorsTotal = promauto.NewCounterVec(prometheus.CounterOpts{
Name: "micro_errors_total",
Help: "Total number of errors",
}, []string{"service", "method", "error_type"})
)
// Prometheus监控中间件
func PrometheusMiddleware(serviceName string) server.HandlerWrapper {
return func(fn server.HandlerFunc) server.HandlerFunc {
return func(ctx context.Context, req server.Request, rsp interface{}) error {
start := time.Now()
// 增加活跃连接数
activeConnections.WithLabelValues(serviceName).Inc()
defer activeConnections.WithLabelValues(serviceName).Dec()
// 记录请求开始
method := req.Endpoint()
// 执行请求
err := fn(ctx, req, rsp)
// 记录指标
duration := time.Since(start).Seconds()
status := "success"
if err != nil {
status = "error"
errorsTotal.WithLabelValues(serviceName, method, getErrorType(err)).Inc()
}
requestsTotal.WithLabelValues(serviceName, method, status).Inc()
requestDuration.WithLabelValues(serviceName, method).Observe(duration)
return err
}
}
}
// Jaeger追踪中间件
func JaegerMiddleware(serviceName string, tracer opentracing.Tracer) server.HandlerWrapper {
return func(fn server.HandlerFunc) server.HandlerFunc {
return func(ctx context.Context, req server.Request, rsp interface{}) error {
method := req.Endpoint()
// 开始span
span, ctx := opentracing.StartSpanFromContext(ctx, method)
defer span.Finish()
// 设置span标签
span.SetTag("service", serviceName)
span.SetTag("method", method)
ext.Component.Set(span, "go-micro")
// 记录请求信息
if reqBytes, err := json.Marshal(req.Body()); err == nil {
span.SetTag("request.body", string(reqBytes))
}
// 执行请求
err := fn(ctx, req, rsp)
// 记录结果
if err != nil {
ext.Error.Set(span, true)
span.SetTag("error.message", err.Error())
}
return err
}
}
}
// 初始化Jaeger追踪器
func InitJaeger(serviceName string) (opentracing.Tracer, io.Closer, error) {
config := jaegerconfig.Configuration{
ServiceName: serviceName,
Sampler: &jaegerconfig.SamplerConfig{
Type: jaegerconfig.SamplerTypeConst,
Param: 1,
},
Reporter: &jaegerconfig.ReporterConfig{
LogSpans: true,
LocalAgentHostPort: "localhost:6831",
},
}
tracer, closer, err := config.NewTracer()
if err != nil {
return nil, nil, err
}
opentracing.SetGlobalTracer(tracer)
return tracer, closer, nil
}
// 自定义指标收集器
type MetricsCollector struct {
serviceName string
registry *prometheus.Registry
}
func NewMetricsCollector(serviceName string) *MetricsCollector {
registry := prometheus.NewRegistry()
registry.MustRegister(requestsTotal, requestDuration, activeConnections, errorsTotal)
return &MetricsCollector{
serviceName: serviceName,
registry: registry,
}
}
func (mc *MetricsCollector) RecordRequest(method, status string, duration time.Duration) {
requestsTotal.WithLabelValues(mc.serviceName, method, status).Inc()
requestDuration.WithLabelValues(mc.serviceName, method).Observe(duration.Seconds())
}
func (mc *MetricsCollector) RecordError(method, errorType string) {
errorsTotal.WithLabelValues(mc.serviceName, method, errorType).Inc()
}
func (mc *MetricsCollector) IncrementConnections() {
activeConnections.WithLabelValues(mc.serviceName).Inc()
}
func (mc *MetricsCollector) DecrementConnections() {
activeConnections.WithLabelValues(mc.serviceName).Dec()
}
func (mc *MetricsCollector) GetRegistry() *prometheus.Registry {
return mc.registry
}
// 辅助函数
func getErrorType(err error) string {
switch {
case err == nil:
return "none"
case err == context.DeadlineExceeded:
return "timeout"
case err == context.Canceled:
return "canceled"
default:
return "unknown"
}
}
---
b.日志聚合
a.ELK Stack集成
go-micro可以与Elasticsearch、Logstash、Kibana组成的ELK Stack集成,实现日志的收集、存储、搜索和可视化分析。
b.Fluentd集成
Fluentd是开源的数据收集器,可以作为log收集的替代方案,支持多种数据源和输出目标。
c.配置管理
a.Consul KV集成
Consul提供的键值存储可以用于服务配置管理,支持配置的热更新和版本控制。
b.etcd集成
etcd不仅是服务注册中心,也可以用于配置存储和管理,提供强一致性的配置服务。
d.API网关集成
a.Kong集成
Kong是一个云原生API网关,可以与go-micro服务无缝集成,提供认证、限流、监控等网关功能。
b.Traefik集成
Traefik是一个现代的HTTP反向代理和负载均衡器,可以自动发现go-micro服务并进行路由配置。
03.社区与支持
a.开源社区
a.GitHub项目
go-micro是一个开源项目,托管在GitHub上,拥有活跃的开发者社区。项目定期发布新版本,修复bug并添加新功能。
b.贡献指南
项目提供了详细的贡献指南,欢迎开发者提交代码、报告bug、改进文档。社区有严格的代码审查流程,确保代码质量。
b.商业支持
a.Micro公司
go-micro背后的Micro公司提供商业支持服务,包括技术支持、咨询服务、培训服务等。企业用户可以购买商业支持获得更好的服务保障。
b.企业版功能
Micro公司提供的企业版包含额外的功能,如安全认证、高级监控、企业级部署工具等。
c.学习资源
a.官方文档
go-micro提供详细的官方文档,包括快速开始指南、API参考、最佳实践等。文档定期更新,与代码版本保持同步。
b.社区教程
社区成员编写了大量教程和博客文章,分享使用经验和最佳实践。这些资源涵盖了从入门到高级的各个层面。
c.示例项目
官方和社区提供了多个示例项目,展示如何在不同场景下使用go-micro。这些项目是学习go-micro的很好起点。
1.8 版本演进
01.版本历史
a.go-micro v1.x
a.功能说明
go-micro v1.x是早期版本,提供了基础的微服务框架功能,包括RPC通信、服务发现、消息传输等核心特性。这个版本奠定了框架的基础架构,后续版本都在此基础上发展。
b.技术特点
v1.x版本采用相对简单的架构设计,主要关注核心功能的实现。性能优化和扩展性相对有限,但已经能满足基本的微服务开发需求。
c.限制与问题
早期版本在性能、可扩展性、配置灵活性等方面存在一些限制,这些限制在后续版本中得到了改进和解决。
b.go-micro v2.x
a.重大改进
v2.x版本是go-micro的重大升级,引入了全新的架构设计和API。改进了性能、可扩展性、易用性等各个方面,是当前主流使用的版本。
b.架构重构
对核心架构进行了全面重构,采用更模块化的设计,提高了代码的可维护性和扩展性。同时优化了内存使用和网络性能。
c.API变更
提供了更简洁、更直观的API设计,减少了样板代码的编写量。同时保持了向后兼容性,使迁移更加容易。
c.go-micro v3.x(开发中)
a.云原生增强
v3.x版本将进一步增强云原生特性,深度集成Kubernetes生态系统,提供更好的容器化支持。
b.性能优化
继续优化性能,特别是在高并发场景下的表现。引入更高效的序列化机制和连接管理策略。
d.微服务治理
增强微服务治理能力,包括服务网格集成、更强大的监控追踪、自动化运维等功能。
02.核心特性演进
a.服务发现机制
a.早期实现
最初版本的服务发现机制相对简单,主要基于内存实现,适合单机或小规模部署场景。功能有限但够用。
b.分布式实现
随着版本演进,引入了etcd、Consul等分布式注册中心的支持,实现了真正的分布式服务发现。支持服务健康检查、故障转移等高级特性。
c.云原生集成
最新版本深度集成了Kubernetes的服务发现机制,可以直接使用Kubernetes的原生服务注册和发现能力。
d.代码示例
---
// 服务发现机制演进示例
package servicediscovery
import (
"context"
"fmt"
"time"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/selector"
)
// v1.x 简单服务发现
type SimpleServiceDiscovery struct {
services map[string][]*registry.Service
mutex sync.RWMutex
}
func NewSimpleServiceDiscovery() *SimpleServiceDiscovery {
return &SimpleServiceDiscovery{
services: make(map[string][]*registry.Service),
}
}
func (s *SimpleServiceDiscovery) Register(service *registry.Service) error {
s.mutex.Lock()
defer s.mutex.Unlock()
if _, exists := s.services[service.Name]; !exists {
s.services[service.Name] = make([]*registry.Service, 0)
}
s.services[service.Name] = append(s.services[service.Name], service)
return nil
}
func (s *SimpleServiceDiscovery) GetService(name string) ([]*registry.Service, error) {
s.mutex.RLock()
defer s.mutex.RUnlock()
services, exists := s.services[name]
if !exists || len(services) == 0 {
return nil, fmt.Errorf("服务 %s 未找到", name)
}
return services, nil
}
// v2.x 分布式服务发现
type DistributedServiceDiscovery struct {
registry registry.Registry
selector selector.Selector
cache *ServiceCache
}
type ServiceCache struct {
services map[string]*CacheEntry
mutex sync.RWMutex
ttl time.Duration
}
type CacheEntry struct {
services []*registry.Service
expires time.Time
}
func NewDistributedServiceDiscovery(reg registry.Registry) *DistributedServiceDiscovery {
return &DistributedServiceDiscovery{
registry: reg,
selector: selector.NewSelector(selector.Registry(reg)),
cache: &ServiceCache{
services: make(map[string]*CacheEntry),
ttl: time.Minute * 5,
},
}
}
func (d *DistributedServiceDiscovery) Register(service *registry.Service, opts ...registry.RegisterOption) error {
// 注册到分布式注册中心
err := d.registry.Register(service, opts...)
if err != nil {
return fmt.Errorf("注册服务失败: %v", err)
}
// 更新缓存
d.updateCache(service.Name, []*registry.Service{service})
return nil
}
func (d *DistributedServiceDiscovery) GetService(name string) ([]*registry.Service, error) {
// 先检查缓存
if services, err := d.getFromCache(name); err == nil {
return services, nil
}
// 从注册中心获取
services, err := d.registry.GetService(name)
if err != nil {
return nil, err
}
// 更新缓存
d.updateCache(name, services)
return services, nil
}
func (d *DistributedServiceDiscovery) SelectNext(serviceName string) (selector.Next, error) {
return d.selector.Select(serviceName)
}
func (d *DistributedServiceDiscovery) updateCache(name string, services []*registry.Service) {
d.cache.mutex.Lock()
defer d.cache.mutex.Unlock()
d.cache.services[name] = &CacheEntry{
services: services,
expires: time.Now().Add(d.cache.ttl),
}
}
func (d *DistributedServiceDiscovery) getFromCache(name string) ([]*registry.Service, error) {
d.cache.mutex.RLock()
defer d.cache.mutex.RUnlock()
entry, exists := d.cache.services[name]
if !exists || time.Now().After(entry.expires) {
return nil, fmt.Errorf("缓存过期或不存在")
}
return entry.services, nil
}
// v3.x 云原生服务发现
type CloudNativeServiceDiscovery struct {
k8sClient kubernetes.Interface
namespace string
labelSelector string
watcher *ServiceWatcher
}
type ServiceWatcher struct {
informer cache.SharedIndexInformer
handlers map[string]func([]*registry.Service)
mutex sync.RWMutex
}
func NewCloudNativeServiceDiscovery(config *rest.Config, namespace string) (*CloudNativeServiceDiscovery, error) {
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, fmt.Errorf("创建Kubernetes客户端失败: %v", err)
}
return &CloudNativeServiceDiscovery{
k8sClient: clientset,
namespace: namespace,
watcher: NewServiceWatcher(),
}, nil
}
func (c *CloudNativeServiceDiscovery) GetService(name string) ([]*registry.Service, error) {
// 从Kubernetes获取服务
svc, err := c.k8sClient.CoreV1().Services(c.namespace).Get(context.Background(), name, metav1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("获取Kubernetes服务失败: %v", err)
}
// 获取服务关联的端点
endpoints, err := c.k8sClient.CoreV1().Endpoints(c.namespace).Get(context.Background(), name, metav1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("获取服务端点失败: %v", err)
}
// 转换为go-micro服务格式
services := c.convertToMicroServices(svc, endpoints)
return services, nil
}
func (c *CloudNativeServiceDiscovery) WatchService(name string, handler func([]*registry.Service)) error {
return c.watcher.Watch(name, handler)
}
func (c *CloudNativeServiceDiscovery) convertToMicroServices(svc *corev1.Service, endpoints *corev1.Endpoints) []*registry.Service {
services := make([]*registry.Service, 0)
for _, subset := range endpoints.Subsets {
for _, addr := range subset.Addresses {
node := ®istry.Node{
Id: fmt.Sprintf("%s-%s", svc.Name, addr.IP),
Address: fmt.Sprintf("%s:%d", addr.IP, svc.Spec.Ports[0].Port),
Metadata: map[string]string{
"k8s-service": svc.Name,
"k8s-namespace": svc.Namespace,
"k8s-pod": addr.TargetRef.Name,
},
}
service := ®istry.Service{
Name: svc.Name,
Version: svc.Annotations["version"],
Nodes: []*registry.Node{node},
Metadata: svc.Annotations,
}
services = append(services, service)
}
}
return services
}
func NewServiceWatcher() *ServiceWatcher {
return &ServiceWatcher{
handlers: make(map[string]func([]*registry.Service)),
}
}
func (w *ServiceWatcher) Watch(name string, handler func([]*registry.Service)) error {
w.mutex.Lock()
defer w.mutex.Unlock()
w.handlers[name] = handler
return nil
}
func (w *ServiceWatcher) notify(name string, services []*registry.Service) {
w.mutex.RLock()
handler, exists := w.handlers[name]
w.mutex.RUnlock()
if exists {
handler(services)
}
}
---
b.传输层演进
a.从HTTP到HTTP/2
早期版本只支持HTTP/1.1,性能相对较低。v2.x引入了HTTP/2支持,通过多路复用和头部压缩显著提升了性能。
b.gRPC原生支持
集成gRPC传输协议,提供高性能的二进制传输接口。支持流式RPC,适合大数据传输和实时通信场景。
c.自定义协议支持
增强了对自定义传输协议的支持,开发者可以实现专用的传输协议以满足特殊需求。
03.性能优化历程
a.内存管理优化
a.对象池化
引入对象池技术,重用频繁创建的对象,减少内存分配和垃圾回收压力。特别是在高并发场景下,性能提升明显。
b.零拷贝优化
在消息序列化和网络传输过程中,采用零拷贝技术减少内存复制操作,提高数据处理效率。
c.内存分配策略
优化内存分配策略,减少小对象频繁分配造成的内存碎片。使用内存预分配和批量处理技术提高性能。
b.网络性能优化
a.连接池管理
实现智能连接池管理,支持连接复用、健康检查、自动扩缩容等功能。减少连接建立和销毁的开销。
b.异步I/O处理
支持异步非阻塞I/O处理,提高并发处理能力。在事件驱动的处理模式下,单机可以处理数万个并发连接。
c.负载均衡算法
实现多种负载均衡算法,包括轮询、随机、加权、最少连接等。支持自定义负载均衡策略,适应不同的业务场景。
04.生态系统发展
a.插件生态
a.官方插件库
随着版本演进,官方提供的插件越来越丰富,涵盖了注册中心、消息队列、数据库、监控等各个方面。
b.社区贡献
社区贡献了大量高质量插件,扩展了go-micro的应用场景和功能边界。这些插件丰富了整个生态系统。
c.插件标准
建立了标准化的插件开发规范,使插件开发更加规范化和简单化。降低了插件开发的学习成本。
b.工具链完善
a.开发工具
从基础的micro命令行工具,发展出完整的开发工具链,包括代码生成、调试工具、测试工具等。
b.运维工具
提供了丰富的运维工具,包括服务部署、监控告警、日志收集、配置管理等。支持自动化运维和CI/CD集成。
c.管理界面
开发了Web管理界面,提供直观的服务管理和监控功能。降低了运维门槛,提高了管理效率。
05.未来发展方向
a.云原生深化
a.Kubernetes集成
进一步深化与Kubernetes的集成,支持Operator模式、自定义资源定义等高级特性。实现更紧密的云原生生态整合。
b.服务网格
集成主流的服务网格技术,如Istio、Linkerd等,提供统一的服务治理能力。支持流量管理、安全策略、可观测性等功能。
c.Serverless支持
支持Serverless架构模式,与Function-as-a-Service平台集成。实现事件驱动的微服务架构。
b.智能化运维
a.自动扩缩容
基于机器学习的智能扩缩容策略,根据业务流量自动调整服务实例数量。提高资源利用率,降低运维成本。
b.故障预测
利用AI技术进行故障预测和自动恢复。在故障发生前采取预防措施,提高系统的可靠性。
c.性能优化
智能性能调优,自动识别性能瓶颈并提供优化建议。持续优化系统性能,保持最佳运行状态。
c.多语言支持
a.跨语言通信
支持多语言微服务的互操作,实现不同编程语言服务的无缝通信。扩大go-micro的适用范围。
b.多语言SDK
提供多语言的SDK,让不同语言的开发者都能方便地使用go-micro生态系统。降低技术选型的限制。
c.统一治理
实现跨语言服务的统一治理,包括服务发现、负载均衡、监控追踪等功能。保证多语言环境的一致性体验。
2 核心组件
2.1 汇总:8个核心组件
01.go-micro核心组件架构
a.组件概述
go-micro框架由8个核心组件构成,这些组件共同构成了一个完整的微服务运行时环境。每个组件都有明确的职责和标准接口,可以独立替换和扩展,这种模块化设计确保了框架的高度可定制性。
b.组件关系图
a.架构层次
Service位于最顶层,是框架的入口点,负责整合所有其他组件。Client和Server分别处理客户端请求和服务端响应,它们都依赖于Transport进行网络通信。
Codec负责数据序列化和反序列化,Registry提供服务注册发现功能,Broker处理消息传递,Selector实现服务选择和负载均衡。
b.协同机制
各组件通过标准接口进行交互,形成了松耦合的架构。开发者可以根据具体需求选择不同的实现组合,构建适合自己业务场景的微服务解决方案。
02.Service组件
a.功能定位
Service是go-micro的核心入口,代表一个完整的微服务实例。它整合了其他所有组件,提供服务的生命周期管理、配置管理、客户端初始化等基础功能。
b.核心职责
a.服务生命周期管理
负责服务的初始化、启动、运行和停止等全生命周期管理。提供了BeforeStart、AfterStart、BeforeStop、AfterStop等钩子函数,支持在关键节点执行自定义逻辑。
b.组件协调
协调Client、Server、Registry等组件的初始化和运行。确保各个组件能够正确协作,形成完整的服务功能。
c.配置管理
统一管理服务配置,包括服务名称、版本、元数据、监听地址等。支持多种配置来源,如命令行参数、环境变量、配置文件等。
03.Client组件
a.功能定位
Client是客户端组件,负责发起服务调用请求。它封装了服务发现、负载均衡、消息编码、网络传输等复杂的客户端逻辑,提供简单易用的调用接口。
b.核心功能
a.服务调用
提供同步、异步、流式等多种调用模式。支持设置超时、重试、上下文传播等高级特性。
b.服务发现
通过Registry和Selector组件自动发现目标服务实例,实现位置透明的服务调用。
c.负载均衡
在多个服务实例间进行负载均衡,支持轮询、随机、加权、最少连接等多种策略。
04.Server组件
a.功能定位
Server是服务端组件,负责接收和处理客户端请求。它提供服务注册、请求路由、处理器管理等功能,是微服务对外提供功能的入口。
b.核心功能
a.请求处理
接收来自Client的请求,解析请求头和请求体,路由到对应的处理器方法。
b.服务注册
启动时自动向Registry注册服务信息,包括服务名称、版本、地址、元数据等。
c.处理器管理
管理注册的处理器和方法,支持RPC处理器和消息订阅处理器。
05.Transport组件
a.功能定位
Transport是网络传输层组件,负责底层网络通信。它抽象了网络传输的细节,支持多种传输协议和通信模式。
b.支持的协议
a.HTTP/HTTPS
基于HTTP协议的传输实现,支持HTTP/1.1和HTTP/2。易于调试和监控,适合大多数应用场景。
b.gRPC
基于HTTP/2的高性能RPC框架,支持流式传输和双向通信。性能优异,适合高并发和大数据传输场景。
c.TCP/UDP
原始TCP/UDP传输实现,适合需要完全控制网络协议的场景。
06.Codec组件
a.功能定位
Codec是编解码组件,负责数据的序列化和反序列化。它抽象了数据格式转换的细节,支持多种数据编码格式。
b.支持的格式
a.JSON
轻量级文本格式,人类可读性好,调试方便。性能适中,适合大多数应用场景。
b.Protobuf
Google开发的高性能二进制格式,序列化速度快,数据体积小。适合高性能和大数据量场景。
c.Msgpack
高效的二进制序列化格式,性能接近Protobuf但更简单易用。
d.XML
结构化文本格式,自描述性强,适合与其他系统集成。
07.Registry组件
a.功能定位
Registry是服务注册中心组件,负责服务的注册、发现和管理。它维护了所有可用服务的信息,是微服务架构的核心基础设施。
b.支持的实现
a.etcd
分布式键值存储系统,提供强一致性和高可用性。适合需要强一致性的生产环境。
b.Consul
HashiCorp开发的服务网格解决方案,提供服务发现、健康检查、KV存储等功能。
c.Kubernetes
云原生平台的内置服务发现机制,与Kubernetes生态系统深度集成。
08.Broker组件
a.功能定位
Broker是消息代理组件,负责消息的发布和订阅。它实现了发布订阅模式,支持异步消息处理,是实现事件驱动架构的关键组件。
b.支持的实现
a.RabbitMQ
功能丰富的消息队列系统,支持多种消息模式和路由策略。
b.Kafka
分布式流处理平台,高吞吐量,支持大数据流处理。
c.NATS
轻量级消息系统,简单易用,性能优秀。
09.Selector组件
a.功能定位
Selector是服务选择器组件,负责从多个服务实例中选择合适的目标。它与Registry配合工作,实现智能的负载均衡和服务选择。
b.选择策略
a.轮询策略
按顺序轮流选择服务实例,实现简单的负载均衡。
b.随机策略
随机选择服务实例,在大量实例的情况下分布更均匀。
c.加权策略
根据服务实例的性能或权重进行选择,支持流量分配。
d.最少连接策略
选择当前连接数最少的实例,适合连接敏感的服务。
10.组件协同示例
a.完整服务调用流程
---
// 完整的组件协同示例
package components
import (
"context"
"fmt"
"time"
"github.com/micro/go-micro/v2"
"github.com/micro/go-micro/v2/client"
"github.com/micro/go-micro/v2/codec"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/selector"
"github.com/micro/go-micro/v2/server"
"github.com/micro/go-micro/v2/transport"
)
// ComponentDemo 演示组件协同
type ComponentDemo struct {
service micro.Service // Service组件
client client.Client // Client组件
server server.Server // Server组件
registry registry.Registry // Registry组件
selector selector.Selector // Selector组件
codec codec.Codec // Codec组件
transport transport.Transport // Transport组件
broker broker.Broker // Broker组件
}
func NewComponentDemo() *ComponentDemo {
// 创建各个组件
reg := registry.NewRegistry(registry.Addrs("localhost:2379")) // etcd
sel := selector.NewSelector(selector.Registry(reg))
trans := transport.NewTransport()
cod := codec.NewCodec()
brk := broker.NewBroker()
// 创建服务实例
service := micro.NewService(
micro.Name("demo.service"),
micro.Version("1.0.0"),
micro.Registry(reg),
micro.Transport(trans),
micro.Codec(cod),
micro.Broker(brk),
micro.Selector(sel),
)
return &ComponentDemo{
service: service,
client: service.Client(),
server: service.Server(),
registry: reg,
selector: sel,
codec: cod,
transport: trans,
broker: brk,
}
}
// 演示服务注册流程
func (cd *ComponentDemo) demonstrateServiceRegistration() error {
// 1. 通过Server组件注册处理器
handler := &DemoHandler{}
if err := cd.server.Handle(
cd.server.NewHandler(handler),
); err != nil {
return fmt.Errorf("注册处理器失败: %v", err)
}
// 2. 通过Registry组件注册服务
service := ®istry.Service{
Name: "demo.service",
Version: "1.0.0",
Nodes: []*registry.Node{
{
Id: "node-1",
Address: "localhost:8080",
Metadata: map[string]string{
"protocol": "http",
"weight": "10",
},
},
},
}
if err := cd.registry.Register(service); err != nil {
return fmt.Errorf("注册服务失败: %v", err)
}
fmt.Println("服务注册成功")
return nil
}
// 演示服务调用流程
func (cd *ComponentDemo) demonstrateServiceCall() error {
// 1. 通过Codec组件编码请求
reqData := &DemoRequest{
Name: "Hello World",
Count: 42,
}
reqBytes, err := cd.codec.Marshal(reqData)
if err != nil {
return fmt.Errorf("编码请求失败: %v", err)
}
// 2. 通过Selector组件选择服务实例
next, err := cd.selector.Select("demo.service")
if err != nil {
return fmt.Errorf("选择服务失败: %v", err)
}
node, err := next()
if err != nil {
return fmt.Errorf("获取服务节点失败: %v", err)
}
fmt.Printf("选择的服务节点: %s\n", node.Address)
// 3. 通过Transport组件建立连接
conn, err := cd.transport.Dial(node.Address)
if err != nil {
return fmt.Errorf("建立连接失败: %v", err)
}
defer conn.Close()
// 4. 通过Client组件发送请求
req := cd.client.NewRequest(
"demo.service",
"Demo.Echo",
reqData,
client.WithContentType("application/json"),
)
var rsp DemoResponse
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := cd.client.Call(ctx, req, &rsp); err != nil {
return fmt.Errorf("调用服务失败: %v", err)
}
fmt.Printf("服务调用成功,响应: %+v\n", rsp)
return nil
}
// 演示消息发布订阅流程
func (cd *ComponentDemo) demonstrateMessagePubSub() error {
// 1. 通过Broker组件发布消息
event := &DemoEvent{
Type: "user.created",
UserID: "12345",
Timestamp: time.Now().Unix(),
Data: map[string]interface{}{
"username": "john.doe",
"email": "[email protected]",
},
}
if err := cd.broker.Connect(); err != nil {
return fmt.Errorf("连接消息代理失败: %v", err)
}
eventBytes, err := cd.codec.Marshal(event)
if err != nil {
return fmt.Errorf("编码事件失败: %v", err)
}
if err := cd.broker.Publish("demo.events", &broker.Message{
Body: eventBytes,
}); err != nil {
return fmt.Errorf("发布事件失败: %v", err)
}
// 2. 通过Broker组件订阅消息
if err := cd.broker.Subscribe("demo.events", func(p broker.Event) error {
var receivedEvent DemoEvent
if err := cd.codec.Unmarshal(p.Message().Body, &receivedEvent); err != nil {
return fmt.Errorf("解码事件失败: %v", err)
}
fmt.Printf("接收到事件: %+v\n", receivedEvent)
return nil
}); err != nil {
return fmt.Errorf("订阅事件失败: %v", err)
}
fmt.Println("消息发布订阅设置完成")
return nil
}
// 演示组件协同
func (cd *ComponentDemo) demonstrateComponentCoordination() error {
fmt.Println("=== 演示go-micro核心组件协同 ===")
// 1. 演示服务注册
fmt.Println("\n1. 演示服务注册...")
if err := cd.demonstrateServiceRegistration(); err != nil {
return fmt.Errorf("服务注册演示失败: %v", err)
}
// 2. 演示服务调用
fmt.Println("\n2. 演示服务调用...")
if err := cd.demonstrateServiceCall(); err != nil {
return fmt.Errorf("服务调用演示失败: %v", err)
}
// 3. 演示消息发布订阅
fmt.Println("\n3. 演示消息发布订阅...")
if err := cd.demonstrateMessagePubSub(); err != nil {
return fmt.Errorf("消息发布订阅演示失败: %v", err)
}
fmt.Println("\n=== 组件协同演示完成 ===")
return nil
}
// 演示数据结构
type DemoRequest struct {
Name string `json:"name"`
Count int `json:"count"`
}
type DemoResponse struct {
Message string `json:"message"`
Timestamp time.Time `json:"timestamp"`
Success bool `json:"success"`
}
type DemoEvent struct {
Type string `json:"type"`
UserID string `json:"user_id"`
Timestamp int64 `json:"timestamp"`
Data map[string]interface{} `json:"data"`
}
type DemoHandler struct{}
func (h *DemoHandler) Echo(ctx context.Context, req *DemoRequest, rsp *DemoResponse) error {
rsp.Message = fmt.Sprintf("Echo: %s (count: %d)", req.Name, req.Count)
rsp.Timestamp = time.Now()
rsp.Success = true
return nil
}
func RunComponentDemo() {
demo := NewComponentDemo()
if err := demo.demonstrateComponentCoordination(); err != nil {
fmt.Printf("组件协同演示失败: %v\n", err)
return
}
fmt.Println("所有演示完成成功")
}
---
2.2 Service服务
01.Service接口定义
a.核心方法
Service接口定义了微服务的基础行为,包括Init()、Options()、Client()、Server()、Run()、Stop()等核心方法。这些方法构成了服务的完整生命周期管理。
Init()方法负责服务的初始化工作,包括解析命令行参数、加载配置文件、设置默认选项等。Options()返回当前服务的配置选项,允许在运行时查看和修改服务配置。
Client()和Server()分别返回客户端和服务端实例,它们是服务与外部世界交互的主要接口。Run()启动服务并开始监听请求,Stop()优雅关闭服务。
b.代码示例
---
// Service接口详细实现
package service
import (
"context"
"fmt"
"sync"
"time"
"github.com/micro/go-micro/v2"
"github.com/micro/go-micro/v2/client"
"github.com/micro/go-micro/v2/config"
"github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/server"
"github.com/micro/go-micro/v2/transport"
)
// microService Service接口的具体实现
type microService struct {
opts micro.Options
once sync.Once
mu sync.RWMutex
// 运行时状态
running bool
startedAt time.Time
stoppedAt time.Time
// 组件实例
client client.Client
server server.Server
cmd *cmd
config config.Config
// 生命周期钩子
beforeStart []func() error
afterStart []func() error
beforeStop []func() error
afterStop []func() error
}
// NewService 创建新的服务实例
func NewService(opts ...micro.Option) micro.Service {
// 创建默认选项
options := micro.NewOptions()
// 应用用户提供的选项
for _, o := range opts {
o(&options)
}
// 创建服务实例
service := µService{
opts: options,
client: options.Client,
server: options.Server,
config: options.Config,
}
// 初始化命令行处理器
service.cmd = newCmd(service)
return service
}
// Init 初始化服务
func (s *microService) Init(opts ...micro.Option) error {
s.mu.Lock()
defer s.mu.Unlock()
// 应用选项
for _, o := range opts {
o(&s.opts)
}
// 解析命令行参数
if err := s.cmd.Init(opts...); err != nil {
return fmt.Errorf("解析命令行参数失败: %v", err)
}
// 初始化日志
if err := s.initLogger(); err != nil {
return fmt.Errorf("初始化日志系统失败: %v", err)
}
// 初始化配置
if err := s.initConfig(); err != nil {
return fmt.Errorf("初始化配置系统失败: %v", err)
}
// 初始化客户端
if err := s.initClient(); err != nil {
return fmt.Errorf("初始化客户端失败: %v", err)
}
// 初始化服务端
if err := s.initServer(); err != nil {
return fmt.Errorf("初始化服务端失败: %v", err)
}
// 初始化注册中心
if err := s.initRegistry(); err != nil {
return fmt.Errorf("初始化注册中心失败: %v", err)
}
logger.Infof("服务 %s 初始化完成", s.opts.Name)
return nil
}
// Options 获取服务选项
func (s *microService) Options() micro.Options {
s.mu.RLock()
defer s.mu.RUnlock()
return s.opts
}
// Client 获取客户端实例
func (s *microService) Client() client.Client {
s.mu.RLock()
defer s.mu.RUnlock()
return s.client
}
// Server 获取服务端实例
func (s *microService) Server() server.Server {
s.mu.RLock()
defer s.mu.RUnlock()
return s.server
}
// Run 运行服务
func (s *microService) Run() error {
s.mu.Lock()
if s.running {
s.mu.Unlock()
return fmt.Errorf("服务已在运行")
}
s.running = true
s.startedAt = time.Now()
s.mu.Unlock()
// 执行启动前钩子
for _, hook := range s.beforeStart {
if err := hook(); err != nil {
logger.Errorf("执行启动前钩子失败: %v", err)
return err
}
}
logger.Infof("正在启动服务 %s...", s.opts.Name)
// 启动注册中心
if s.opts.Registry != nil {
if err := s.opts.Registry.Init(); err != nil {
return fmt.Errorf("初始化注册中心失败: %v", err)
}
// 注册服务
if err := s.registerService(); err != nil {
return fmt.Errorf("注册服务失败: %v", err)
}
}
// 启动服务端
if err := s.server.Start(); err != nil {
return fmt.Errorf("启动服务端失败: %v", err)
}
// 执行启动后钩子
for _, hook := range s.afterStart {
if err := hook(); err != nil {
logger.Errorf("执行启动后钩子失败: %v", err)
}
}
logger.Infof("服务 %s 启动成功,监听地址: %s", s.opts.Name, s.opts.Address)
// 等待中断信号
return s.waitForShutdown()
}
// Stop 停止服务
func (s *microService) Stop() error {
s.mu.Lock()
if !s.running {
s.mu.Unlock()
return nil
}
s.running = false
s.stoppedAt = time.Now()
s.mu.Unlock()
logger.Infof("正在停止服务 %s...", s.opts.Name)
// 执行停止前钩子
for _, hook := range s.beforeStop {
if err := hook(); err != nil {
logger.Errorf("执行停止前钩子失败: %v", err)
}
}
var errors []error
// 注销服务
if s.opts.Registry != nil {
if err := s.deregisterService(); err != nil {
logger.Errorf("注销服务失败: %v", err)
errors = append(errors, err)
}
}
// 停止服务端
if err := s.server.Stop(); err != nil {
logger.Errorf("停止服务端失败: %v", err)
errors = append(errors, err)
}
// 关闭注册中心
if s.opts.Registry != nil {
if err := s.opts.Registry.Close(); err != nil {
logger.Errorf("关闭注册中心失败: %v", err)
errors = append(errors, err)
}
}
// 执行停止后钩子
for _, hook := range s.afterStop {
if err := hook(); err != nil {
logger.Errorf("执行停止后钩子失败: %v", err)
errors = append(errors, err)
}
}
if len(errors) > 0 {
return fmt.Errorf("停止服务时发生错误: %v", errors)
}
logger.Infof("服务 %s 已停止", s.opts.Name)
return nil
}
// String 返回服务字符串表示
func (s *microService) String() string {
return fmt.Sprintf("micro.Service{name=%s, version=%s, address=%s}",
s.opts.Name, s.opts.Version, s.opts.Address)
}
// 初始化方法
func (s *microService) initLogger() error {
if s.opts.Logger != nil {
return s.opts.Logger.Init()
}
return nil
}
func (s *microService) initConfig() error {
if s.opts.Config != nil {
return s.opts.Config.Load()
}
return nil
}
func (s *microService) initClient() error {
if s.opts.Client != nil {
return s.opts.Client.Init()
}
return nil
}
func (s *microService) initServer() error {
if s.opts.Server != nil {
return s.opts.Server.Init()
}
return nil
}
func (s *microService) initRegistry() error {
if s.opts.Registry != nil {
return s.opts.Registry.Init()
}
return nil
}
// 注册服务
func (s *microService) registerService() error {
service := ®istry.Service{
Name: s.opts.Name,
Version: s.opts.Version,
Metadata: s.opts.Metadata,
Nodes: []*registry.Node{
{
Id: s.opts.Name + "-" + s.opts.Version + "-" + s.opts.Id,
Address: s.opts.Address,
Metadata: s.opts.Metadata,
},
},
}
return s.opts.Registry.Register(service)
}
// 注销服务
func (s *microService) deregisterService() error {
service := ®istry.Service{
Name: s.opts.Name,
Version: s.opts.Version,
Nodes: []*registry.Node{
{
Id: s.opts.Name + "-" + s.opts.Version + "-" + s.opts.Id,
Address: s.opts.Address,
},
},
}
return s.opts.Registry.Deregister(service)
}
// 等待关闭信号
func (s *microService) waitForShutdown() error {
// 这里可以实现优雅关闭逻辑
// 监听SIGINT、SIGTERM等信号
select {
case <-s.cmd.Context().Done():
logger.Info("接收到关闭信号,正在停止服务...")
return s.Stop()
}
}
// 生命周期钩子方法
func (s *microService) BeforeStart(fn func() error) {
s.mu.Lock()
defer s.mu.Unlock()
s.beforeStart = append(s.beforeStart, fn)
}
func (s *microService) AfterStart(fn func() error) {
s.mu.Lock()
defer s.mu.Unlock()
s.afterStart = append(s.afterStart, fn)
}
func (s *microService) BeforeStop(fn func() error) {
s.mu.Lock()
defer s.mu.Unlock()
s.beforeStop = append(s.beforeStop, fn)
}
func (s *microService) AfterStop(fn func() error) {
s.mu.Lock()
defer s.mu.Unlock()
s.afterStop = append(s.afterStop, fn)
}
// 运行时状态查询
func (s *microService) IsRunning() bool {
s.mu.RLock()
defer s.mu.RUnlock()
return s.running
}
func (s *microService) StartTime() time.Time {
s.mu.RLock()
defer s.mu.RUnlock()
return s.startedAt
}
func (s *microService) StopTime() time.Time {
s.mu.RLock()
defer s.mu.RUnlock()
return s.stoppedAt
}
func (s *microService) Uptime() time.Duration {
s.mu.RLock()
defer s.mu.RUnlock()
if s.running {
return time.Since(s.startedAt)
}
return s.stoppedAt.Sub(s.startedAt)
}
---
02.服务配置管理
a.配置选项
go-micro提供了丰富的配置选项,包括服务名称、版本、监听地址、元数据、注册中心、传输协议、编码格式等。这些配置可以通过选项模式进行设置。
b.配置来源
支持多种配置来源,包括命令行参数、环境变量、配置文件、远程配置中心等。配置按优先级合并,后加载的配置会覆盖先加载的配置。
c.代码示例
---
// 服务配置管理示例
package config
import (
"flag"
"fmt"
"os"
"strconv"
"time"
"github.com/micro/go-micro/v2"
"github.com/micro/go-micro/v2/config"
"github.com/micro/go-micro/v2/config/source"
"github.com/micro/go-micro/v2/config/source/file"
"github.com/micro/go-micro/v2/config/source/memory"
)
// ConfigStruct 服务配置结构
type ConfigStruct struct {
// 基础配置
Name string `json:"name" yaml:"name"`
Version string `json:"version" yaml:"version"`
Address string `json:"address" yaml:"address"`
Id string `json:"id" yaml:"id"`
// 网络配置
Advertise string `json:"advertise" yaml:"advertise"`
TLS *TLSConfig `json:"tls" yaml:"tls"`
// 注册中心配置
Registry *RegistryConfig `json:"registry" yaml:"registry"`
// 传输层配置
Transport *TransportConfig `json:"transport" yaml:"transport"`
// 编解码配置
Codec string `json:"codec" yaml:"codec"`
// 中间件配置
Middleware []string `json:"middleware" yaml:"middleware"`
// 元数据配置
Metadata map[string]string `json:"metadata" yaml:"metadata"`
// 健康检查配置
HealthCheck *HealthCheckConfig `json:"health_check" yaml:"health_check"`
// 监控配置
Metrics *MetricsConfig `json:"metrics" yaml:"metrics"`
// 日志配置
Logger *LoggerConfig `json:"logger" yaml:"logger"`
}
// TLS配置
type TLSConfig struct {
CertFile string `json:"cert_file" yaml:"cert_file"`
KeyFile string `json:"key_file" yaml:"key_file"`
CAFile string `json:"ca_file" yaml:"ca_file"`
}
// 注册中心配置
type RegistryConfig struct {
Type string `json:"type" yaml:"type"`
Address []string `json:"address" yaml:"address"`
Timeout time.Duration `json:"timeout" yaml:"timeout"`
TLS *TLSConfig `json:"tls" yaml:"tls"`
Options map[string]interface{} `json:"options" yaml:"options"`
}
// 传输层配置
type TransportConfig struct {
Type string `json:"type" yaml:"type"`
Timeout time.Duration `json:"timeout" yaml:"timeout"`
TLS *TLSConfig `json:"tls" yaml:"tls"`
}
// 健康检查配置
type HealthCheckConfig struct {
Interval time.Duration `json:"interval" yaml:"interval"`
Timeout time.Duration `json:"timeout" yaml:"timeout"`
Address string `json:"address" yaml:"address"`
}
// 监控配置
type MetricsConfig struct {
Enabled bool `json:"enabled" yaml:"enabled"`
Type string `json:"type" yaml:"type"`
Address string `json:"address" yaml:"address"`
Interval time.Duration `json:"interval" yaml:"interval"`
Options map[string]interface{} `json:"options" yaml:"options"`
}
// 日志配置
type LoggerConfig struct {
Level string `json:"level" yaml:"level"`
Format string `json:"format" yaml:"format"`
Output string `json:"output" yaml:"output"`
}
// ConfigManager 配置管理器
type ConfigManager struct {
config config.Config
sources []source.Source
}
// NewConfigManager 创建配置管理器
func NewConfigManager() *ConfigManager {
return &ConfigManager{
sources: make([]source.Source, 0),
}
}
// LoadFromMemory 从内存加载配置
func (cm *ConfigManager) LoadFromMemory(data map[string]interface{}) error {
source := memory.NewSource(memory.WithJSON(data))
cm.sources = append(cm.sources, source)
return cm.load()
}
// LoadFromFile 从文件加载配置
func (cm *ConfigManager) LoadFromFile(filepath string) error {
source := file.NewSource(file.WithPath(filepath))
cm.sources = append(cm.sources, source)
return cm.load()
}
// LoadFromEnvironment 从环境变量加载配置
func (cm *ConfigManager) LoadFromEnvironment() error {
envConfig := make(map[string]interface{})
// 读取环境变量
if name := os.Getenv("MICRO_SERVICE_NAME"); name != "" {
envConfig["name"] = name
}
if version := os.Getenv("MICRO_SERVICE_VERSION"); version != "" {
envConfig["version"] = version
}
if address := os.Getenv("MICRO_SERVICE_ADDRESS"); address != "" {
envConfig["address"] = address
}
if registry := os.Getenv("MICRO_REGISTRY"); registry != "" {
if envConfig["registry"] == nil {
envConfig["registry"] = make(map[string]interface{})
}
reg := envConfig["registry"].(map[string]interface{})
reg["type"] = registry
if addr := os.Getenv("MICRO_REGISTRY_ADDRESS"); addr != "" {
reg["address"] = []string{addr}
}
}
if len(envConfig) > 0 {
return cm.LoadFromMemory(envConfig)
}
return nil
}
// LoadFromFlags 从命令行参数加载配置
func (cm *ConfigManager) LoadFromFlags() error {
flagConfig := make(map[string]interface{})
// 定义命令行参数
name := flag.String("name", "", "服务名称")
version := flag.String("version", "", "服务版本")
address := flag.String("address", "", "服务监听地址")
registry := flag.String("registry", "", "注册中心类型")
registryAddr := flag.String("registry_address", "", "注册中心地址")
flag.Parse()
if *name != "" {
flagConfig["name"] = *name
}
if *version != "" {
flagConfig["version"] = *version
}
if *address != "" {
flagConfig["address"] = *address
}
if *registry != "" {
if flagConfig["registry"] == nil {
flagConfig["registry"] = make(map[string]interface{})
}
reg := flagConfig["registry"].(map[string]interface{})
reg["type"] = *registry
if *registryAddr != "" {
reg["address"] = []string{*registryAddr}
}
}
if len(flagConfig) > 0 {
return cm.LoadFromMemory(flagConfig)
}
return nil
}
// Load 加载配置
func (cm *ConfigManager) load() error {
if cm.config == nil {
cm.config = config.NewConfig()
}
return cm.config.Load(cm.sources...)
}
// Get 获取配置
func (cm *ConfigManager) Get(path string, out interface{}) error {
return cm.config.Get(path).Scan(out)
}
// Set 设置配置
func (cm *ConfigManager) Set(path string, value interface{}) error {
return cm.config.Set(path, value)
}
// Watch 监听配置变化
func (cm *ConfigManager) Watch(path string, callback func(interface{})) error {
return cm.config.Watch(path, func(reader config.Reader) {
var value interface{}
if err := reader.Scan(&value); err == nil {
callback(value)
}
})
}
// BuildServiceOptions 构建服务选项
func (cm *ConfigManager) BuildServiceOptions() ([]micro.Option, error) {
var cfg ConfigStruct
// 解析完整配置
if err := cm.Get("", &cfg); err != nil {
return nil, fmt.Errorf("解析配置失败: %v", err)
}
var options []micro.Option
// 基础选项
if cfg.Name != "" {
options = append(options, micro.Name(cfg.Name))
}
if cfg.Version != "" {
options = append(options, micro.Version(cfg.Version))
}
if cfg.Address != "" {
options = append(options, micro.Address(cfg.Address))
}
if cfg.Id != "" {
options = append(options, micro.Id(cfg.Id))
}
if len(cfg.Metadata) > 0 {
options = append(options, micro.Metadata(cfg.Metadata))
}
// 传输层选项
if cfg.Transport != nil {
// 根据类型创建传输层
switch cfg.Transport.Type {
case "http":
options = append(options, micro.Transport(transport.NewTransport()))
case "grpc":
options = append(options, micro.Transport(grpc.NewTransport()))
default:
options = append(options, micro.Transport(transport.NewTransport()))
}
}
// 编解码器选项
if cfg.Codec != "" {
switch cfg.Codec {
case "json":
options = append(options, micro.Codec("json"))
case "proto":
options = append(options, micro.Codec("proto"))
default:
options = append(options, micro.Codec("json"))
}
}
// 注册中心选项
if cfg.Registry != nil {
switch cfg.Registry.Type {
case "etcd":
options = append(options, micro.Registry(etcd.NewRegistry(
registry.Addrs(cfg.Registry.Address...),
registry.Timeout(cfg.Registry.Timeout),
)))
case "consul":
options = append(options, micro.Registry(consul.NewRegistry(
registry.Addrs(cfg.Registry.Address...),
)))
case "kubernetes":
options = append(options, micro.Registry(kubernetes.NewRegistry()))
default:
options = append(options, micro.Registry(memory.NewRegistry()))
}
}
return options, nil
}
// 使用示例
func ExampleConfigUsage() {
configManager := NewConfigManager()
// 加载不同来源的配置
configManager.LoadFromEnvironment()
configManager.LoadFromFlags()
configManager.LoadFromFile("config.yaml")
// 构建服务选项
options, err := configManager.BuildServiceOptions()
if err != nil {
fmt.Printf("构建服务选项失败: %v\n", err)
return
}
// 创建服务
service := micro.NewService(options...)
// 初始化服务
if err := service.Init(); err != nil {
fmt.Printf("初始化服务失败: %v\n", err)
return
}
fmt.Println("服务配置加载成功")
}
---
03.服务生命周期管理
a.启动阶段
服务启动包括初始化、组件创建、服务注册、监听启动等步骤。每个步骤都有对应的钩子函数,允许在关键节点插入自定义逻辑。
b.运行阶段
服务运行期间会处理客户端请求、发送心跳、更新服务状态等。同时会监控组件健康状态,确保服务正常运行。
c.停止阶段
服务停止时执行优雅关闭,包括停止接收新请求、处理完现有请求、注销服务、释放资源等步骤。
2.3 Client客户端
01.Client接口定义
a.核心功能
Client是go-micro的客户端组件,负责发起服务调用请求。它封装了服务发现、负载均衡、消息编码、网络传输等复杂的客户端逻辑,提供简单易用的调用接口。
b.主要方法
a.NewRequest()方法创建请求对象,需要指定服务名称、方法名和请求体。Call()方法执行同步调用,Stream()方法执行流式调用,Publish()方法发布消息到指定主题。
b.调用选项
支持丰富的调用选项,包括超时设置、重试次数、内容类型、请求头设置等。这些选项允许精细控制每次调用的行为。
c.代码示例
---
// Client接口详细实现
package client
import (
"context"
"fmt"
"sync"
"time"
"github.com/micro/go-micro/v2/client"
"github.com/micro/go-micro/v2/codec"
"github.com/micro/go-micro/v2/metadata"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/selector"
"github.com/micro/go-micro/v2/transport"
)
// microClient Client接口的具体实现
type microClient struct {
opts client.Options
once sync.Once
mu sync.RWMutex
// 运行时状态
wrappers []client.CallWrapper
// 组件实例
codec codec.Codec
selector selector.Selector
transport transport.Transport
// 统计信息
stats *ClientStats
}
// ClientStats 客户端统计信息
type ClientStats struct {
TotalRequests int64 `json:"total_requests"`
SuccessfulCalls int64 `json:"successful_calls"`
FailedCalls int64 `json:"failed_calls"`
AverageLatency time.Duration `json:"average_latency"`
TotalLatency time.Duration `json:"total_latency"`
mu sync.RWMutex
}
// NewClient 创建新的客户端实例
func NewClient(opts ...client.Option) client.Client {
// 创建默认选项
options := client.NewOptions()
// 应用用户提供的选项
for _, o := range opts {
o(&options)
}
return µClient{
opts: options,
wrappers: options.Wrappers,
codec: options.Codec,
selector: options.Selector,
transport: options.Transport,
stats: &ClientStats{},
}
}
// Init 初始化客户端
func (c *microClient) Init(opts ...client.Option) error {
c.mu.Lock()
defer c.mu.Unlock()
// 应用选项
for _, o := range opts {
o(&c.opts)
}
// 初始化选择器
if c.selector != nil {
if err := c.selector.Init(); err != nil {
return fmt.Errorf("初始化选择器失败: %v", err)
}
}
// 初始化传输层
if c.transport != nil {
if err := c.transport.Init(); err != nil {
return fmt.Errorf("初始化传输层失败: %v", err)
}
}
return nil
}
// Options 获取客户端选项
func (c *microClient) Options() client.Options {
c.mu.RLock()
defer c.mu.RUnlock()
return c.opts
}
// NewRequest 创建新请求
func (c *microClient) NewRequest(service, endpoint string, req interface{}, opts ...client.RequestOption) client.Request {
// 创建默认选项
options := client.NewRequestOptions()
// 应用请求选项
for _, o := range opts {
o(&options)
}
// 编码请求体
var body []byte
var err error
if options.Codec != nil {
body, err = options.Codec.Marshal(req)
} else {
body, err = c.codec.Marshal(req)
}
if err != nil {
return &request{
service: service,
endpoint: endpoint,
body: req,
err: err,
}
}
return &request{
service: service,
endpoint: endpoint,
body: req,
data: body,
header: options.Header,
opts: options,
}
}
// Call 执行远程调用
func (c *microClient) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
start := time.Now()
defer func() {
c.recordStats(time.Since(start), nil)
}()
// 创建默认调用选项
options := c.defaultCallOptions()
// 应用调用选项
for _, o := range opts {
o(&options)
}
// 应用调用包装器
if len(c.wrappers) > 0 {
return c.wrapAndCall(ctx, req, rsp, options)
}
return c.call(ctx, req, rsp, options)
}
// Stream 执行流式调用
func (c *microClient) Stream(ctx context.Context, req client.Request, opts ...client.CallOption) (client.Stream, error) {
// 创建默认调用选项
options := c.defaultCallOptions()
options.Stream = true
// 应用调用选项
for _, o := range opts {
o(&options)
}
// 应用调用包装器
if len(c.wrappers) > 0 {
return c.wrapAndStream(ctx, req, options)
}
return c.stream(ctx, req, options)
}
// Publish 发布消息
func (c *microClient) Publish(ctx context.Context, msg client.Message, opts ...client.PublishOption) error {
// 创建默认发布选项
options := client.NewPublishOptions()
// 应用发布选项
for _, o := range opts {
o(&options)
}
// 编码消息体
body, err := c.codec.Marshal(msg.Payload())
if err != nil {
return fmt.Errorf("编码消息失败: %v", err)
}
// 创建传输消息
tMsg := &transport.Message{
Header: make(map[string]string),
Body: body,
}
// 设置消息头
for k, v := range msg.Headers() {
tMsg.Header[k] = v
}
// 添加元数据
if md, ok := metadata.FromContext(ctx); ok {
for k, v := range md {
tMsg.Header[k] = v
}
}
// 发布消息
return c.opts.Broker.Publish(msg.Topic(), &broker.Message{
Header: tMsg.Header,
Body: tMsg.Body,
})
}
// String 返回客户端字符串表示
func (c *microClient) String() string {
return "micro.Client"
}
// defaultCallOptions 获取默认调用选项
func (c *microClient) defaultCallOptions() client.CallOptions {
return client.CallOptions{
ContentType: c.opts.ContentType,
RequestTimeout: c.opts.RequestTimeout,
DialTimeout: c.opts.DialTimeout,
Retries: c.opts.Retries,
Backoff: c.opts.Backoff,
Stream: false,
Transport: c.opts.Transport,
SelectorOptions: c.opts.SelectorOptions,
}
}
// call 执行实际调用
func (c *microClient) call(ctx context.Context, req client.Request, rsp interface{}, opts client.CallOptions) error {
// 选择服务实例
next, err := c.selectService(req.Service(), opts.SelectorOptions)
if err != nil {
return fmt.Errorf("选择服务失败: %v", err)
}
// 执行调用(带重试)
var callErr error
for i := 0; i < opts.Retries+1; i++ {
callErr = c.callInstance(ctx, next, req, rsp, opts)
if callErr == nil {
break
}
// 检查是否需要重试
if i < opts.Retries && c.shouldRetry(callErr) {
if opts.Backoff != nil {
time.Sleep(opts.Backoff(ctx, req, i))
}
continue
}
}
c.recordStats(time.Since(req.(*request).startTime), callErr)
return callErr
}
// callInstance 调用特定实例
func (c *microClient) callInstance(ctx context.Context, next selector.Next, req client.Request, rsp interface{}, opts client.CallOptions) error {
// 获取服务节点
node, err := next()
if err != nil {
return fmt.Errorf("获取服务节点失败: %v", err)
}
// 创建传输客户端
conn, err := c.transport.Dial(node.Address, transport.WithTimeout(opts.DialTimeout))
if err != nil {
return fmt.Errorf("建立连接失败: %v", err)
}
defer conn.Close()
// 准备请求消息
tMsg := &transport.Message{
Header: make(map[string]string),
Body: req.(*request).data,
}
// 设置请求头
tMsg.Header["Content-Type"] = opts.ContentType
tMsg.Header["Micro-Service"] = req.Service()
tMsg.Header["Micro-Method"] = req.Endpoint()
tMsg.Header["Micro-Id"] = generateRequestID()
// 添加元数据
if md, ok := metadata.FromContext(ctx); ok {
for k, v := range md {
tMsg.Header[k] = v
}
}
// 发送请求
if err := conn.Send(tMsg); err != nil {
return fmt.Errorf("发送请求失败: %v", err)
}
// 接收响应
var respMsg transport.Message
if err := conn.Recv(&respMsg); err != nil {
return fmt.Errorf("接收响应失败: %v", err)
}
// 解码响应
if err := c.codec.Unmarshal(respMsg.Body, rsp); err != nil {
return fmt.Errorf("解码响应失败: %v", err)
}
return nil
}
// stream 执行流式调用
func (c *microClient) stream(ctx context.Context, req client.Request, opts client.CallOptions) (client.Stream, error) {
// 选择服务实例
next, err := c.selectService(req.Service(), opts.SelectorOptions)
if err != nil {
return nil, fmt.Errorf("选择服务失败: %v", err)
}
// 获取服务节点
node, err := next()
if err != nil {
return nil, fmt.Errorf("获取服务节点失败: %v", err)
}
// 建立流式连接
conn, err := c.transport.Dial(node.Address, transport.WithStream())
if err != nil {
return nil, fmt.Errorf("建立流式连接失败: %v", err)
}
// 发送初始化请求
tMsg := &transport.Message{
Header: map[string]string{
"Content-Type": opts.ContentType,
"Micro-Service": req.Service(),
"Micro-Method": req.Endpoint(),
"Micro-Id": generateRequestID(),
"Micro-Stream": "true",
},
Body: req.(*request).data,
}
if err := conn.Send(tMsg); err != nil {
conn.Close()
return nil, fmt.Errorf("发送流式初始化请求失败: %v", err)
}
return &stream{
conn: conn,
req: req,
ctx: ctx,
}, nil
}
// selectService 选择服务
func (c *microClient) selectService(service string, opts selector.SelectOptions) (selector.Next, error) {
if c.selector == nil {
return nil, fmt.Errorf("选择器未初始化")
}
// 创建选择选项
sopts := []selector.SelectOption{
selector.WithStrategy(opts.Strategy),
}
// 应用选择器选项
for _, o := range opts.Options {
o(sopts)
}
return c.selector.Select(service, sopts...)
}
// wrapAndCall 使用包装器调用
func (c *microClient) wrapAndCall(ctx context.Context, req client.Request, rsp interface{}, opts client.CallOption) error {
// 创建调用函数
callFunc := func(ctx context.Context, req client.Request, rsp interface{}, opts client.CallOption) error {
return c.call(ctx, req, rsp, opts)
}
// 应用包装器
for i := len(c.wrappers) - 1; i >= 0; i-- {
callFunc = c.wrappers[i](callFunc)
}
return callFunc(ctx, req, rsp, opts)
}
// wrapAndStream 使用包装器流式调用
func (c *microClient) wrapAndStream(ctx context.Context, req client.Request, opts client.CallOption) (client.Stream, error) {
// 创建流式调用函数
streamFunc := func(ctx context.Context, req client.Request, opts client.CallOption) (client.Stream, error) {
return c.stream(ctx, req, opts)
}
// 应用包装器(简化实现)
return streamFunc(ctx, req, opts)
}
// shouldRetry 判断是否应该重试
func (c *microClient) shouldRetry(err error) bool {
// 这里可以根据错误类型判断是否需要重试
// 例如:网络错误、超时错误等
return true
}
// recordStats 记录统计信息
func (c *microClient) recordStats(latency time.Duration, err error) {
c.stats.mu.Lock()
defer c.stats.mu.Unlock()
c.stats.TotalRequests++
c.stats.TotalLatency += latency
c.stats.AverageLatency = c.stats.TotalLatency / time.Duration(c.stats.TotalRequests)
if err != nil {
c.stats.FailedCalls++
} else {
c.stats.SuccessfulCalls++
}
}
// GetStats 获取统计信息
func (c *microClient) GetStats() *ClientStats {
c.stats.mu.RLock()
defer c.stats.mu.RUnlock()
// 返回统计信息的副本
return &ClientStats{
TotalRequests: c.stats.TotalRequests,
SuccessfulCalls: c.stats.SuccessfulCalls,
FailedCalls: c.stats.FailedCalls,
AverageLatency: c.stats.AverageLatency,
TotalLatency: c.stats.TotalLatency,
}
}
// request 请求实现
type request struct {
service string
endpoint string
body interface{}
data []byte
header map[string]string
opts client.RequestOptions
err error
startTime time.Time
}
func (r *request) Service() string {
return r.service
}
func (r *request) Method() string {
return r.endpoint
}
func (r *request) Endpoint() string {
return r.endpoint
}
func (r *request) ContentType() string {
if r.opts.Codec != nil {
return r.opts.Codec.String()
}
return "application/json"
}
func (r *request) Body() interface{} {
return r.body
}
func (r *request) Header() map[string]string {
return r.header
}
func (r *request) Error() error {
return r.err
}
// stream 流实现
type stream struct {
conn transport.Client
req client.Request
ctx context.Context
mu sync.Mutex
closed bool
}
func (s *stream) Context() context.Context {
return s.ctx
}
func (s *stream) Request() client.Request {
return s.req
}
func (s *stream) Send(msg interface{}) error {
s.mu.Lock()
defer s.mu.Unlock()
if s.closed {
return fmt.Errorf("流已关闭")
}
// 编码消息
data, err := json.Marshal(msg)
if err != nil {
return fmt.Errorf("编码流消息失败: %v", err)
}
// 发送消息
return s.conn.Send(&transport.Message{
Body: data,
})
}
func (s *stream) Recv(msg interface{}) error {
s.mu.Lock()
defer s.mu.Unlock()
if s.closed {
return fmt.Errorf("流已关闭")
}
// 接收消息
var tMsg transport.Message
if err := s.conn.Recv(&tMsg); err != nil {
return fmt.Errorf("接收流消息失败: %v", err)
}
// 解码消息
return json.Unmarshal(tMsg.Body, msg)
}
func (s *stream) Error() error {
return s.conn.Error()
}
func (s *stream) Close() error {
s.mu.Lock()
defer s.mu.Unlock()
if s.closed {
return nil
}
s.closed = true
return s.conn.Close()
}
// 辅助函数
func generateRequestID() string {
return fmt.Sprintf("%d", time.Now().UnixNano())
}
---
02.客户端调用模式
a.同步调用
同步调用是最常用的调用模式,客户端发送请求后等待响应返回。适用于需要立即获取结果的操作,如用户查询、数据验证等。
b.异步调用
异步调用允许客户端发送请求后立即返回,不需要等待响应。适用于耗时较长的操作,如大数据处理、文件上传等。
c.流式调用
流式调用支持双向数据流,客户端和服务端可以持续发送数据。适用于实时通信、数据流处理等场景。
d.代码示例
---
// 客户端调用模式示例
package callpatterns
import (
"context"
"fmt"
"sync"
"time"
"github.com/micro/go-micro/v2"
"github.com/micro/go-micro/v2/client"
)
// CallPatternDemo 调用模式演示
type CallPatternDemo struct {
client client.Client
}
func NewCallPatternDemo(service micro.Service) *CallPatternDemo {
return &CallPatternDemo{
client: service.Client(),
}
}
// SyncCall 同步调用示例
func (cpd *CallPatternDemo) SyncCall() error {
fmt.Println("=== 同步调用示例 ===")
// 创建请求
req := cpd.client.NewRequest("user.service", "User.GetUser", &GetUserRequest{
UserID: "12345",
})
// 设置超时
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// 发起同步调用
var rsp GetUserResponse
err := cpd.client.Call(ctx, req, &rsp, client.WithRetries(3))
if err != nil {
return fmt.Errorf("同步调用失败: %v", err)
}
fmt.Printf("同步调用成功: %+v\n", rsp)
return nil
}
// AsyncCall 异步调用示例
func (cpd *CallPatternDemo) AsyncCall() error {
fmt.Println("=== 异步调用示例 ===")
// 创建请求
req := cpd.client.NewRequest("order.service", "Order.CreateOrder", &CreateOrderRequest{
UserID: "12345",
ProductID: "prod-001",
Quantity: 2,
TotalAmount: 199.99,
})
// 发起异步调用
go func() {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
var rsp CreateOrderResponse
err := cpd.client.Call(ctx, req, &rsp, client.WithRetries(5))
if err != nil {
fmt.Printf("异步调用失败: %v\n", err)
return
}
fmt.Printf("异步调用成功: %+v\n", rsp)
}()
fmt.Println("异步调用已发起,继续执行其他操作...")
// 模拟其他工作
time.Sleep(2 * time.Second)
fmt.Println("其他操作完成")
return nil
}
// StreamCall 流式调用示例
func (cpd *CallPatternDemo) StreamCall() error {
fmt.Println("=== 流式调用示例 ===")
// 创建流式请求
req := cpd.client.NewRequest("data.service", "Data.ProcessStream", &StreamRequest{
DataSource: "user_logs",
Filters: []string{"error", "warning"},
})
// 建立流式连接
stream, err := cpd.client.Stream(context.Background(), req)
if err != nil {
return fmt.Errorf("建立流式连接失败: %v", err)
}
defer stream.Close()
// 启动数据接收协程
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
for {
var data StreamData
err := stream.Recv(&data)
if err != nil {
fmt.Printf("接收流数据结束: %v\n", err)
break
}
fmt.Printf("接收到流数据: %+v\n", data)
// 处理数据
if err := cpd.processStreamData(&data); err != nil {
fmt.Printf("处理流数据失败: %v\n", err)
}
}
}()
// 发送控制命令
commands := []string{"start", "pause", "resume", "stop"}
for _, cmd := range commands {
time.Sleep(time.Second)
controlReq := &ControlRequest{
Command: cmd,
Timestamp: time.Now().Unix(),
}
if err := stream.Send(controlReq); err != nil {
fmt.Printf("发送控制命令失败: %v\n", err)
break
}
fmt.Printf("发送控制命令: %s\n", cmd)
}
// 等待接收完成
wg.Wait()
return nil
}
// BatchCall 批量调用示例
func (cpd *CallPatternDemo) BatchCall() error {
fmt.Println("=== 批量调用示例 ===")
userIDs := []string{"12345", "67890", "11111", "22222"}
var wg sync.WaitGroup
results := make([]*GetUserResponse, len(userIDs))
errors := make([]error, len(userIDs))
start := time.Now()
for i, userID := range userIDs {
wg.Add(1)
go func(index int, id string) {
defer wg.Done()
req := cpd.client.NewRequest("user.service", "User.GetUser", &GetUserRequest{
UserID: id,
})
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
var rsp GetUserResponse
err := cpd.client.Call(ctx, req, &rsp)
if err != nil {
errors[index] = fmt.Errorf("调用用户 %s 失败: %v", id, err)
return
}
results[index] = &rsp
}(i, userID)
}
wg.Wait()
duration := time.Since(start)
fmt.Printf("批量调用完成,耗时: %v\n", duration)
// 检查结果
successCount := 0
for i, result := range results {
if result != nil {
fmt.Printf("用户 %s: %s\n", userIDs[i], result.User.Username)
successCount++
} else {
fmt.Printf("用户 %s 获取失败: %v\n", userIDs[i], errors[i])
}
}
fmt.Printf("批量调用统计: 成功 %d/%d\n", successCount, len(userIDs))
return nil
}
// CircuitBreakerCall 熔断器调用示例
func (cpd *CallPatternDemo) CircuitBreakerCall() error {
fmt.Println("=== 熔断器调用示例 ===")
// 创建熔断器
circuitBreaker := NewCircuitBreaker(
WithMaxRequests(5),
WithInterval(30*time.Second),
WithTimeout(60*time.Second),
WithReadyToTrip(func(counts Counts) bool {
return counts.ConsecutiveFailures > 5
}),
)
for i := 0; i < 20; i++ {
req := cpd.client.NewRequest("unstable.service", "Unstable.Operation", &UnstableRequest{
OperationID: fmt.Sprintf("op-%d", i),
})
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
// 通过熔断器执行调用
var rsp UnstableResponse
result := circuitBreaker.Execute(func() (interface{}, error) {
err := cpd.client.Call(ctx, req, &rsp)
return &rsp, err
})
if result.Err != nil {
fmt.Printf("调用 %d 失败: %v, 熔断器状态: %s\n",
i, result.Err, circuitBreaker.State().String())
} else {
response := result.Result.(*UnstableResponse)
fmt.Printf("调用 %d 成功: %s\n", i, response.Message)
}
time.Sleep(500 * time.Millisecond)
}
return nil
}
// RetryCall 重试调用示例
func (cpd *CallPatternDemo) RetryCall() error {
fmt.Println("=== 重试调用示例 ===")
req := cpd.client.NewRequest("flaky.service", "Flaky.UnreliableOperation", &FlakyRequest{
Attempt: 1,
})
// 自定义重试策略
backoff := func(ctx context.Context, req client.Request, attempts int) time.Duration {
// 指数退避 + 随机抖动
delay := time.Duration(attempts*attempts) * time.Second
jitter := time.Duration(rand.Intn(1000)) * time.Millisecond
return delay + jitter
}
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
var rsp FlakyResponse
err := cpd.client.Call(ctx, req, &rsp,
client.WithRetries(10),
client.WithBackoff(backoff),
client.WithRequestTimeout(5*time.Second),
)
if err != nil {
return fmt.Errorf("重试调用最终失败: %v", err)
}
fmt.Printf("重试调用成功: %+v\n", rsp)
return nil
}
// 处理流数据
func (cpd *CallPatternDemo) processStreamData(data *StreamData) error {
fmt.Printf("处理流数据: ID=%s, Type=%s, Timestamp=%d\n",
data.ID, data.Type, data.Timestamp)
return nil
}
// 数据结构定义
type GetUserRequest struct {
UserID string `json:"user_id"`
}
type GetUserResponse struct {
User *UserInfo `json:"user"`
}
type UserInfo struct {
ID string `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
}
type CreateOrderRequest struct {
UserID string `json:"user_id"`
ProductID string `json:"product_id"`
Quantity int `json:"quantity"`
TotalAmount float64 `json:"total_amount"`
}
type CreateOrderResponse struct {
OrderID string `json:"order_id"`
Status string `json:"status"`
CreateAt int64 `json:"created_at"`
}
type StreamRequest struct {
DataSource string `json:"data_source"`
Filters []string `json:"filters"`
}
type StreamData struct {
ID string `json:"id"`
Type string `json:"type"`
Timestamp int64 `json:"timestamp"`
Data map[string]interface{} `json:"data"`
}
type ControlRequest struct {
Command string `json:"command"`
Timestamp int64 `json:"timestamp"`
}
type UnstableRequest struct {
OperationID string `json:"operation_id"`
}
type UnstableResponse struct {
Message string `json:"message"`
Success bool `json:"success"`
}
type FlakyRequest struct {
Attempt int `json:"attempt"`
}
type FlakyResponse struct {
Attempt int `json:"attempt"`
Success bool `json:"success"`
RandomFloat float64 `json:"random_float"`
}
// CircuitBreaker 简化实现
type CircuitBreaker struct {
maxRequests uint32
interval time.Duration
timeout time.Duration
readyToTrip func(counts Counts) bool
state int32
generation uint64
counts Counts
}
type Counts struct {
Requests uint32
TotalSuccesses uint32
TotalFailures uint32
ConsecutiveSuccesses uint32
ConsecutiveFailures uint32
}
func NewCircuitBreaker(opts ...CircuitBreakerOption) *CircuitBreaker {
cb := &CircuitBreaker{
maxRequests: 1,
interval: 0,
timeout: 60 * time.Second,
}
for _, opt := range opts {
opt(cb)
}
return cb
}
type CircuitBreakerOption func(*CircuitBreaker)
func WithMaxRequests(maxRequests uint32) CircuitBreakerOption {
return func(cb *CircuitBreaker) {
cb.maxRequests = maxRequests
}
}
func WithInterval(interval time.Duration) CircuitBreakerOption {
return func(cb *CircuitBreaker) {
cb.interval = interval
}
}
func WithTimeout(timeout time.Duration) CircuitBreakerOption {
return func(cb *CircuitBreaker) {
cb.timeout = timeout
}
}
func WithReadyToTrip(readyToTrip func(counts Counts) bool) CircuitBreakerOption {
return func(cb *CircuitBreaker) {
cb.readyToTrip = readyToTrip
}
}
func (cb *CircuitBreaker) Execute(req func() (interface{}, error) (Result, error) {
// 简化实现,实际需要完整的状态管理
result, err := req()
return Result{Result: result, Err: err}, nil
}
func (cb *CircuitBreaker) State() State {
return StateClosed // 简化实现
}
type Result struct {
Result interface{}
Err error
}
type State int
const (
StateClosed State = iota
StateHalfOpen
StateOpen
)
func (s State) String() string {
switch s {
case StateClosed:
return "Closed"
case StateHalfOpen:
return "HalfOpen"
case StateOpen:
return "Open"
default:
return "Unknown"
}
}
// 运行示例
func RunCallPatternDemo() {
service := micro.NewService(micro.Name("demo.client"))
service.Init()
demo := NewCallPatternDemo(service)
// 运行各种调用模式示例
if err := demo.SyncCall(); err != nil {
fmt.Printf("同步调用示例失败: %v\n", err)
}
if err := demo.AsyncCall(); err != nil {
fmt.Printf("异步调用示例失败: %v\n", err)
}
if err := demo.StreamCall(); err != nil {
fmt.Printf("流式调用示例失败: %v\n", err)
}
if err := demo.BatchCall(); err != nil {
fmt.Printf("批量调用示例失败: %v\n", err)
}
if err := demo.CircuitBreakerCall(); err != nil {
fmt.Printf("熔断器调用示例失败: %v\n", err)
}
if err := demo.RetryCall(); err != nil {
fmt.Printf("重试调用示例失败: %v\n", err)
}
}
---
03.客户端高级特性
a.调用包装器
Client支持调用包装器模式,可以在调用前后执行额外逻辑。常用的包装器包括日志记录、监控统计、权限验证、熔断器等。
b.负载均衡策略
支持多种负载均衡策略,包括轮询、随机、加权、最少连接等。可以根据服务特性选择合适的策略。
c.超时与重试
支持调用级别的超时设置和重试策略,包括重试次数、退避算法等。确保在网络不稳定情况下的调用可靠性。
2.4 Server服务器
01.Server接口定义
a.核心功能
Server是go-micro的服务端组件,负责接收和处理客户端请求。它提供服务注册、请求路由、处理器管理等功能,是微服务对外提供功能的入口。
b.主要方法
Init()方法初始化服务器配置,Options()返回当前配置选项。Handle()和NewHandler()用于注册RPC处理器,Subscribe()和NewSubscriber()用于注册消息订阅处理器。
Start()和Stop()方法控制服务器的运行状态。服务器启动时向注册中心注册服务,停止时注销服务。
c.代码示例
---
// Server接口详细实现
package server
import (
"context"
"fmt"
"sync"
"time"
"github.com/micro/go-micro/v2/server"
"github.com/micro/go-micro/v2/codec"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/transport"
)
// microServer Server接口的具体实现
type microServer struct {
opts server.Options
mu sync.RWMutex
// 运行时状态
running bool
startedAt time.Time
stoppedAt time.Time
// 组件实例
transport transport.Transport
codec codec.Codec
registry registry.Registry
// 处理器管理
handlers map[string]server.Handler
subscribers map[string][]server.Subscriber
// 中间件
wrappers []server.HandlerWrapper
// 统计信息
stats *ServerStats
// 退出通道
exit chan chan error
}
// ServerStats 服务器统计信息
type ServerStats struct {
TotalRequests int64 `json:"total_requests"`
SuccessfulCalls int64 `json:"successful_calls"`
FailedCalls int64 `json:"failed_calls"`
AverageLatency time.Duration `json:"average_latency"`
TotalLatency time.Duration `json:"total_latency"`
ActiveConnections int64 `json:"active_connections"`
mu sync.RWMutex
}
// NewServer 创建新的服务器实例
func NewServer(opts ...server.Option) server.Server {
// 创建默认选项
options := server.NewOptions()
// 应用用户提供的选项
for _, o := range opts {
o(&options)
}
return µServer{
opts: options,
transport: options.Transport,
codec: options.Codec,
registry: options.Registry,
handlers: make(map[string]server.Handler),
subscribers: make(map[string][]server.Subscriber),
wrappers: options.Wrappers,
stats: &ServerStats{},
exit: make(chan chan error),
}
}
// Init 初始化服务器
func (s *microServer) Init(opts ...server.Option) error {
s.mu.Lock()
defer s.mu.Unlock()
// 应用选项
for _, o := range opts {
o(&s.opts)
}
// 初始化传输层
if s.transport != nil {
if err := s.transport.Init(); err != nil {
return fmt.Errorf("初始化传输层失败: %v", err)
}
}
// 初始化编解码器
if s.codec == nil {
s.codec = s.opts.Codec
}
return nil
}
// Options 获取服务器选项
func (s *microServer) Options() server.Options {
s.mu.RLock()
defer s.mu.RUnlock()
return s.opts
}
// Handle 注册处理器
func (s *microServer) Handle(h server.Handler) error {
s.mu.Lock()
defer s.mu.Unlock()
if h == nil {
return fmt.Errorf("处理器不能为空")
}
// 获取处理器信息
handlerInfo := getHandlerInfo(h)
// 注册处理器
s.handlers[handlerInfo.Name] = h
fmt.Printf("注册处理器: %s\n", handlerInfo.Name)
return nil
}
// NewHandler 创建处理器
func (s *microServer) NewHandler(h interface{}, opts ...server.HandlerOption) server.Handler {
// 创建默认处理器选项
options := server.NewHandlerOptions()
// 应用选项
for _, o := range opts {
o(&options)
}
// 创建处理器
handler := &handler{
handler: h,
opts: options,
metadata: options.Metadata,
}
return handler
}
// Subscribe 注册订阅者
func (s *microServer) Subscribe(sub server.Subscriber) error {
s.mu.Lock()
defer s.mu.Unlock()
if sub == nil {
return fmt.Errorf("订阅者不能为空")
}
topic := sub.Topic()
s.subscribers[topic] = append(s.subscribers[topic], sub)
fmt.Printf("注册订阅者: %s\n", topic)
return nil
}
// NewSubscriber 创建订阅者
func (s *microServer) NewSubscriber(topic string, sb interface{}, opts ...server.SubscriberOption) server.Subscriber {
// 创建默认订阅者选项
options := server.NewSubscriberOptions()
// 应用选项
for _, o := range opts {
o(&options)
}
// 创建订阅者
subscriber := &subscriber{
topic: topic,
subscriber: sb,
opts: options,
queue: options.Queue,
}
return subscriber
}
// Start 启动服务器
func (s *microServer) Start() error {
s.mu.Lock()
if s.running {
s.mu.Unlock()
return fmt.Errorf("服务器已在运行")
}
s.running = true
s.startedAt = time.Now()
s.mu.Unlock()
fmt.Printf("正在启动服务器 %s...\n", s.opts.Name)
// 创建监听器
listener, err := s.transport.Listen(s.opts.Address)
if err != nil {
return fmt.Errorf("创建监听器失败: %v", err)
}
// 注册服务
if s.registry != nil {
if err := s.registerService(); err != nil {
listener.Close()
return fmt.Errorf("注册服务失败: %v", err)
}
}
// 启动监听
go s.acceptLoop(listener)
fmt.Printf("服务器启动成功,监听地址: %s\n", listener.Addr())
return nil
}
// Stop 停止服务器
func (s *microServer) Stop() error {
s.mu.Lock()
if !s.running {
s.mu.Unlock()
return nil
}
s.running = false
s.stoppedAt = time.Now()
s.mu.Unlock()
fmt.Printf("正在停止服务器 %s...\n", s.opts.Name)
// 关闭监听器
close(s.exit)
// 注销服务
if s.registry != nil {
if err := s.deregisterService(); err != nil {
fmt.Printf("注销服务失败: %v\n", err)
}
}
// 关闭传输层
if s.transport != nil {
s.transport.Close()
}
fmt.Printf("服务器 %s 已停止\n", s.opts.Name)
return nil
}
// String 返回服务器字符串表示
func (s *microServer) String() string {
return fmt.Sprintf("micro.Server{name=%s, address=%s}", s.opts.Name, s.opts.Address)
}
// registerService 注册服务
func (s *microServer) registerService() error {
service := ®istry.Service{
Name: s.opts.Name,
Version: s.opts.Version,
Metadata: s.opts.Metadata,
Nodes: []*registry.Node{
{
Id: generateNodeID(s.opts.Name, s.opts.Version),
Address: s.opts.Address,
Metadata: s.opts.Metadata,
},
},
}
return s.registry.Register(service)
}
// deregisterService 注销服务
func (s *microServer) deregisterService() error {
service := ®istry.Service{
Name: s.opts.Name,
Version: s.opts.Version,
Nodes: []*registry.Node{
{
Id: generateNodeID(s.opts.Name, s.opts.Version),
Address: s.opts.Address,
},
},
}
return s.registry.Deregister(service)
}
// acceptLoop 接受连接循环
func (s *microServer) acceptLoop(listener transport.Listener) {
for {
conn, err := listener.Accept()
if err != nil {
select {
case <-s.exit:
return
default:
fmt.Printf("接受连接失败: %v\n", err)
continue
}
}
go s.handleConnection(conn)
}
}
// handleConnection 处理连接
func (s *microServer) handleConnection(conn transport.Socket) {
defer conn.Close()
s.stats.mu.Lock()
s.stats.ActiveConnections++
s.stats.mu.Unlock()
defer func() {
s.stats.mu.Lock()
s.stats.ActiveConnections--
s.stats.mu.Unlock()
}()
for {
var msg transport.Message
if err := conn.Recv(&msg); err != nil {
break
}
go s.handleMessage(conn, &msg)
}
}
// handleMessage 处理消息
func (s *microServer) handleMessage(conn transport.Socket, msg *transport.Message) {
start := time.Now()
defer func() {
s.recordStats(time.Since(start), nil)
}()
// 提取服务信息
serviceName := msg.Header["Micro-Service"]
method := msg.Header["Micro-Method"]
requestID := msg.Header["Micro-Id"]
fmt.Printf("处理请求: Service=%s, Method=%s, RequestID=%s\n",
serviceName, method, requestID)
// 查找处理器
handler, exists := s.findHandler(serviceName, method)
if !exists {
s.sendError(conn, msg, fmt.Sprintf("未找到处理器: %s.%s", serviceName, method))
return
}
// 解码请求
req, err := s.decodeRequest(msg, handler)
if err != nil {
s.sendError(conn, msg, fmt.Sprintf("解码请求失败: %v", err))
return
}
// 创建响应对象
rsp := s.createResponse(handler)
// 执行处理器
ctx := s.createContext(msg)
err = s.executeHandler(ctx, handler, req, rsp)
if err != nil {
s.sendError(conn, msg, fmt.Sprintf("执行处理器失败: %v", err))
return
}
// 发送响应
if err := s.sendResponse(conn, msg, rsp); err != nil {
fmt.Printf("发送响应失败: %v\n", err)
}
}
// findHandler 查找处理器
func (s *microServer) findHandler(serviceName, method string) (server.Handler, bool) {
s.mu.RLock()
defer s.mu.RUnlock()
for _, handler := range s.handlers {
handlerInfo := getHandlerInfo(handler)
if handlerInfo.Service == serviceName {
for _, handlerMethod := range handlerInfo.Methods {
if handlerMethod == method {
return handler, true
}
}
}
}
return nil, false
}
// decodeRequest 解码请求
func (s *microServer) decodeRequest(msg *transport.Message, handler server.Handler) (interface{}, error) {
// 根据处理器类型创建请求对象
handlerInfo := getHandlerInfo(handler)
reqType := handlerInfo.RequestType
if reqType == nil {
return nil, nil
}
req := reflect.New(reqType).Interface()
if err := s.codec.Unmarshal(msg.Body, req); err != nil {
return nil, err
}
return req, nil
}
// createResponse 创建响应对象
func (s *microServer) createResponse(handler server.Handler) interface{} {
handlerInfo := getHandlerInfo(handler)
rspType := handlerInfo.ResponseType
if rspType == nil {
return nil
}
return reflect.New(rspType).Interface()
}
// createContext 创建上下文
func (s *microServer) createContext(msg *transport.Message) context.Context {
ctx := context.Background()
// 添加元数据
md := metadata.Metadata{}
for k, v := range msg.Header {
if strings.HasPrefix(k, "Micro-") {
continue
}
md[k] = v
}
if len(md) > 0 {
ctx = metadata.NewContext(ctx, md)
}
return ctx
}
// executeHandler 执行处理器
func (s *microServer) executeHandler(ctx context.Context, handler server.Handler, req, rsp interface{}) error {
// 应用包装器
var h server.HandlerFunc = func(ctx context.Context, req server.Request, rsp interface{}) error {
// 调用实际处理器方法
return callHandlerMethod(handler, req, rsp)
}
// 应用包装器
for i := len(s.wrappers) - 1; i >= 0; i-- {
h = s.wrappers[i](h)
}
// 创建请求对象
request := &request{
service: getHandlerInfo(handler).Service,
method: getHandlerInfo(handler).Methods[0], // 简化处理
body: req,
header: make(map[string]string),
}
return h(ctx, request, rsp)
}
// sendResponse 发送响应
func (s *microServer) sendResponse(conn transport.Socket, req *transport.Message, rsp interface{}) error {
// 编码响应
data, err := s.codec.Marshal(rsp)
if err != nil {
return err
}
// 创建响应消息
respMsg := &transport.Message{
Header: map[string]string{
"Content-Type": "application/json",
"Micro-Id": req.Header["Micro-Id"],
},
Body: data,
}
return conn.Send(respMsg)
}
// sendError 发送错误响应
func (s *microServer) sendError(conn transport.Socket, req *transport.Message, errorMsg string) {
errorResp := map[string]interface{}{
"error": errorMsg,
"code": 500,
"id": req.Header["Micro-Id"],
"detail": "Internal Server Error",
}
data, _ := json.Marshal(errorResp)
respMsg := &transport.Message{
Header: map[string]string{
"Content-Type": "application/json",
"Micro-Error": "true",
"Micro-Id": req.Header["Micro-Id"],
},
Body: data,
}
conn.Send(respMsg)
}
// recordStats 记录统计信息
func (s *microServer) recordStats(latency time.Duration, err error) {
s.stats.mu.Lock()
defer s.stats.mu.Unlock()
s.stats.TotalRequests++
s.stats.TotalLatency += latency
s.stats.AverageLatency = s.stats.TotalLatency / time.Duration(s.stats.TotalRequests)
if err != nil {
s.stats.FailedCalls++
} else {
s.stats.SuccessfulCalls++
}
}
// GetStats 获取统计信息
func (s *microServer) GetStats() *ServerStats {
s.stats.mu.RLock()
defer s.stats.mu.RUnlock()
return &ServerStats{
TotalRequests: s.stats.TotalRequests,
SuccessfulCalls: s.stats.SuccessfulCalls,
FailedCalls: s.stats.FailedCalls,
AverageLatency: s.stats.AverageLatency,
TotalLatency: s.stats.TotalLatency,
ActiveConnections: s.stats.ActiveConnections,
}
}
// 辅助类型和方法
type handler struct {
handler interface{}
opts server.HandlerOptions
metadata map[string]string
}
type subscriber struct {
topic string
subscriber interface{}
opts server.SubscriberOptions
queue string
}
type request struct {
service string
method string
body interface{}
header map[string]string
}
func (r *request) Service() string {
return r.service
}
func (r *request) Method() string {
return r.method
}
func (r *request) Endpoint() string {
return r.method
}
func (r *request) ContentType() string {
return r.header["Content-Type"]
}
func (r *request) Body() interface{} {
return r.body
}
func (r *request) Header() map[string]string {
return r.header
}
func (r *request) Error() error {
return nil
}
// HandlerInfo 处理器信息
type HandlerInfo struct {
Name string
Service string
Methods []string
RequestType reflect.Type
ResponseType reflect.Type
}
func getHandlerInfo(h server.Handler) *HandlerInfo {
// 简化实现,实际需要通过反射获取详细信息
return &HandlerInfo{
Name: "handler",
Service: "service",
Methods: []string{"Method1", "Method2"},
}
}
func callHandlerMethod(handler server.Handler, req, rsp interface{}) error {
// 简化实现,实际需要通过反射调用具体方法
return nil
}
func generateNodeID(serviceName, version string) string {
return fmt.Sprintf("%s-%s-%d", serviceName, version, time.Now().UnixNano())
}
---
02.处理器注册与管理
a.RPC处理器
RPC处理器处理远程过程调用请求,通过反射机制自动路由到对应的方法。处理器需要符合特定的接口规范,每个方法接收context、请求对象和响应对象作为参数。
b.消息订阅处理器
消息订阅处理器处理发布订阅模式的消息,可以订阅特定主题并处理接收到的消息。支持队列模式,多个订阅者可以竞争消费同一个主题的消息。
c.代码示例
---
// 处理器注册与管理示例
package handlers
import (
"context"
"encoding/json"
"fmt"
"reflect"
"sync"
"github.com/micro/go-micro/v2/server"
)
// HandlerManager 处理器管理器
type HandlerManager struct {
mu sync.RWMutex
handlers map[string]*HandlerInfo
server server.Server
}
// HandlerInfo 处理器信息
type HandlerInfo struct {
Name string `json:"name"`
Service string `json:"service"`
Instance interface{} `json:"-"`
Methods map[string]*MethodInfo `json:"methods"`
Metadata map[string]string `json:"metadata"`
Interceptors []MethodInterceptor `json:"-"`
}
// MethodInfo 方法信息
type MethodInfo struct {
Name string `json:"name"`
RequestType reflect.Type `json:"request_type"`
ResponseType reflect.Type `json:"response_type"`
Handler MethodHandler `json:"-"`
Options []MethodOption `json:"options"`
}
// MethodHandler 方法处理器类型
type MethodHandler func(ctx context.Context, req interface{}, rsp interface{}) error
// MethodInterceptor 方法拦截器
type MethodInterceptor interface {
Intercept(ctx context.Context, req interface{}, rsp interface{}, handler MethodHandler) error
}
// MethodOption 方法选项
type MethodOption func(*MethodInfo)
// NewHandlerManager 创建处理器管理器
func NewHandlerManager(server server.Server) *HandlerManager {
return &HandlerManager{
handlers: make(map[string]*HandlerInfo),
server: server,
}
}
// RegisterHandler 注册处理器
func (hm *HandlerManager) RegisterHandler(handler interface{}, opts ...server.HandlerOption) error {
hm.mu.Lock()
defer hm.mu.Unlock()
// 创建处理器实例
h := hm.server.NewHandler(handler, opts...)
// 分析处理器信息
info := hm.analyzeHandler(handler)
// 保存处理器信息
hm.handlers[info.Name] = info
// 注册到服务器
return hm.server.Handle(h)
}
// RegisterInterceptor 注册拦截器
func (hm *HandlerManager) RegisterInterceptor(interceptor MethodInterceptor) {
hm.mu.Lock()
defer hm.mu.Unlock()
// 为所有已注册的处理器添加拦截器
for _, info := range hm.handlers {
info.Interceptors = append(info.Interceptors, interceptor)
}
}
// analyzeHandler 分析处理器
func (hm *HandlerManager) analyzeHandler(handler interface{}) *HandlerInfo {
handlerType := reflect.TypeOf(handler)
handlerValue := reflect.ValueOf(handler)
info := &HandlerInfo{
Name: handlerType.Elem().Name(),
Service: hm.getServiceName(handlerType),
Instance: handler,
Methods: make(map[string]*MethodInfo),
Metadata: make(map[string]string),
}
// 分析方法
for i := 0; i < handlerType.NumMethod(); i++ {
method := handlerType.Method(i)
if hm.isValidHandlerMethod(method) {
methodInfo := hm.analyzeMethod(method, handlerValue)
info.Methods[method.Name] = methodInfo
}
}
return info
}
// getServiceName 获取服务名称
func (hm *HandlerManager) getServiceName(handlerType reflect.Type) string {
// 可以通过结构体标签、命名约定等方式获取服务名称
if handlerType.Kind() == reflect.Ptr {
handlerType = handlerType.Elem()
}
// 简化实现:使用类型名转换为小写
name := handlerType.Name()
return strings.ToLower(name)
}
// isValidHandlerMethod 检查是否为有效的处理器方法
func (hm *HandlerManager) isValidHandlerMethod(method reflect.Method) bool {
if method.PkgPath != "" {
return false // 非导出方法
}
methodType := method.Type
if methodType.NumIn() != 4 {
return false // 参数数量不对
}
// 检查参数类型
if methodType.In(0) != reflect.TypeOf((*context.Context)(nil)).Elem() {
return false
}
if methodType.In(1).Kind() != reflect.Ptr {
return false
}
if methodType.In(2).Kind() != reflect.Ptr {
return false
}
// 检查返回值
if methodType.NumOut() != 1 {
return false
}
if !methodType.Out(0).Implements(reflect.TypeOf((*error)(nil)).Elem()) {
return false
}
return true
}
// analyzeMethod 分析方法
func (hm *HandlerManager) analyzeMethod(method reflect.Method, handlerValue reflect.Value) *MethodInfo {
methodType := method.Type
info := &MethodInfo{
Name: method.Name,
RequestType: methodType.In(1).Elem(),
ResponseType: methodType.In(2).Elem(),
}
// 创建处理器函数
info.Handler = func(ctx context.Context, req interface{}, rsp interface{}) error {
// 准备参数
args := make([]reflect.Value, 4)
args[0] = reflect.ValueOf(ctx)
args[1] = reflect.ValueOf(req)
args[2] = reflect.ValueOf(rsp)
// 调用方法
results := handlerValue.Method(method.Index).Call(args)
// 处理返回值
if len(results) > 0 {
if err, ok := results[0].Interface().(error); ok {
return err
}
}
return nil
}
return info
}
// GetHandlerInfo 获取处理器信息
func (hm *HandlerManager) GetHandlerInfo(name string) (*HandlerInfo, bool) {
hm.mu.RLock()
defer hm.mu.RUnlock()
info, exists := hm.handlers[name]
return info, exists
}
// ListHandlers 列出所有处理器
func (hm *HandlerManager) ListHandlers() []*HandlerInfo {
hm.mu.RLock()
defer hm.mu.RUnlock()
handlers := make([]*HandlerInfo, 0, len(hm.handlers))
for _, info := range hm.handlers {
handlers = append(handlers, info)
}
return handlers
}
// 用户服务处理器示例
type UserService struct {
userRepo UserRepository
authService AuthService
eventBus EventBus
}
// CreateUser 创建用户方法
func (us *UserService) CreateUser(ctx context.Context, req *CreateUserRequest, rsp *CreateUserResponse) error {
fmt.Printf("创建用户请求: %+v\n", req)
// 参数验证
if err := us.validateCreateUserRequest(req); err != nil {
return fmt.Errorf("参数验证失败: %v", err)
}
// 检查用户名是否已存在
exists, err := us.userRepo.ExistsByUsername(ctx, req.Username)
if err != nil {
return fmt.Errorf("检查用户名失败: %v", err)
}
if exists {
return fmt.Errorf("用户名已存在")
}
// 创建用户
user := &User{
ID: us.generateUserID(),
Username: req.Username,
Email: req.Email,
Phone: req.Phone,
Address: req.Address,
Status: "active",
CreatedAt: time.Now(),
}
if err := us.userRepo.Create(ctx, user); err != nil {
return fmt.Errorf("创建用户失败: %v", err)
}
// 生成认证token
token, err := us.authService.GenerateToken(user.ID, user.Username)
if err != nil {
return fmt.Errorf("生成token失败: %v", err)
}
// 发布用户创建事件
event := &UserCreatedEvent{
UserID: user.ID,
Username: user.Username,
Email: user.Email,
}
if err := us.eventBus.Publish(ctx, "user.created", event); err != nil {
fmt.Printf("发布事件失败: %v\n", err)
}
// 构建响应
rsp.User = &UserInfo{
ID: user.ID,
Username: user.Username,
Email: user.Email,
Phone: user.Phone,
Address: user.Address,
Status: user.Status,
}
rsp.Token = token
rsp.Message = "用户创建成功"
return nil
}
// GetUser 获取用户方法
func (us *UserService) GetUser(ctx context.Context, req *GetUserRequest, rsp *GetUserResponse) error {
fmt.Printf("获取用户请求: %+v\n", req)
user, err := us.userRepo.GetByID(ctx, req.UserID)
if err != nil {
return fmt.Errorf("获取用户失败: %v", err)
}
rsp.User = &UserInfo{
ID: user.ID,
Username: user.Username,
Email: user.Email,
Phone: user.Phone,
Address: user.Address,
Status: user.Status,
}
return nil
}
// UpdateUser 更新用户方法
func (us *UserService) UpdateUser(ctx context.Context, req *UpdateUserRequest, rsp *UpdateUserResponse) error {
fmt.Printf("更新用户请求: %+v\n", req)
user, err := us.userRepo.GetByID(ctx, req.UserID)
if err != nil {
return fmt.Errorf("获取用户失败: %v", err)
}
// 更新字段
if req.Username != "" {
user.Username = req.Username
}
if req.Email != "" {
user.Email = req.Email
}
if req.Phone != "" {
user.Phone = req.Phone
}
if req.Address != "" {
user.Address = req.Address
}
user.UpdatedAt = time.Now()
if err := us.userRepo.Update(ctx, user); err != nil {
return fmt.Errorf("更新用户失败: %v", err)
}
rsp.User = &UserInfo{
ID: user.ID,
Username: user.Username,
Email: user.Email,
Phone: user.Phone,
Address: user.Address,
Status: user.Status,
}
rsp.Message = "用户更新成功"
return nil
}
// DeleteUser 删除用户方法
func (us *UserService) DeleteUser(ctx context.Context, req *DeleteUserRequest, rsp *DeleteUserResponse) error {
fmt.Printf("删除用户请求: %+v\n", req)
if err := us.userRepo.Delete(ctx, req.UserID); err != nil {
return fmt.Errorf("删除用户失败: %v", err)
}
rsp.Message = "用户删除成功"
return nil
}
// ListUsers 列出用户方法
func (us *UserService) ListUsers(ctx context.Context, req *ListUsersRequest, rsp *ListUsersResponse) error {
fmt.Printf("列出用户请求: %+v\n", req)
users, total, err := us.userRepo.List(ctx, req.Page, req.PageSize, req.Filter)
if err != nil {
return fmt.Errorf("列出用户失败: %v", err)
}
userInfos := make([]*UserInfo, len(users))
for i, user := range users {
userInfos[i] = &UserInfo{
ID: user.ID,
Username: user.Username,
Email: user.Email,
Phone: user.Phone,
Address: user.Address,
Status: user.Status,
}
}
rsp.Users = userInfos
rsp.TotalCount = total
rsp.Page = req.Page
rsp.PageSize = req.PageSize
return nil
}
// validateCreateUserRequest 验证创建用户请求
func (us *UserService) validateCreateUserRequest(req *CreateUserRequest) error {
if req.Username == "" {
return fmt.Errorf("用户名不能为空")
}
if len(req.Username) < 3 {
return fmt.Errorf("用户名长度不能少于3个字符")
}
if req.Email == "" {
return fmt.Errorf("邮箱不能为空")
}
if !us.isValidEmail(req.Email) {
return fmt.Errorf("邮箱格式不正确")
}
return nil
}
// isValidEmail 检查邮箱格式
func (us *UserService) isValidEmail(email string) bool {
// 简化实现,实际应该使用正则表达式或专门的库
return strings.Contains(email, "@")
}
// generateUserID 生成用户ID
func (us *UserService) generateUserID() string {
return fmt.Sprintf("user_%d", time.Now().UnixNano())
}
// 拦截器示例
type LoggingInterceptor struct{}
func (li *LoggingInterceptor) Intercept(ctx context.Context, req interface{}, rsp interface{}, handler MethodHandler) error {
start := time.Now()
// 记录请求日志
reqData, _ := json.Marshal(req)
fmt.Printf("请求开始: %s\n", string(reqData))
// 执行处理器
err := handler(ctx, req, rsp)
// 记录响应日志
duration := time.Since(start)
rspData, _ := json.Marshal(rsp)
if err != nil {
fmt.Printf("请求失败: 耗时=%v, 错误=%v, 响应=%s\n", duration, err, string(rspData))
} else {
fmt.Printf("请求成功: 耗时=%v, 响应=%s\n", duration, string(rspData))
}
return err
}
type AuthInterceptor struct {
authService AuthService
}
func (ai *AuthInterceptor) Intercept(ctx context.Context, req interface{}, rsp interface{}, handler MethodHandler) error {
// 从上下文获取认证信息
if token := getAuthToken(ctx); token != "" {
// 验证token
userID, err := ai.authService.ValidateToken(token)
if err != nil {
return fmt.Errorf("认证失败: %v", err)
}
// 将用户ID添加到上下文
ctx = context.WithValue(ctx, "userID", userID)
}
return handler(ctx, req, rsp)
}
// 仓储和接口定义
type UserRepository interface {
Create(ctx context.Context, user *User) error
GetByID(ctx context.Context, userID string) (*User, error)
Update(ctx context.Context, user *User) error
Delete(ctx context.Context, userID string) error
List(ctx context.Context, page, pageSize int, filter map[string]interface{}) ([]*User, int64, error)
ExistsByUsername(ctx context.Context, username string) (bool, error)
}
type AuthService interface {
GenerateToken(userID, username string) (string, error)
ValidateToken(token string) (string, error)
}
type EventBus interface {
Publish(ctx context.Context, topic string, event interface{}) error
}
// 数据结构定义
type User struct {
ID string `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
Phone string `json:"phone"`
Address string `json:"address"`
Status string `json:"status"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
type CreateUserRequest struct {
Username string `json:"username" validate:"required,min=3,max=50"`
Email string `json:"email" validate:"required,email"`
Phone string `json:"phone"`
Address string `json:"address"`
}
type CreateUserResponse struct {
User *UserInfo `json:"user"`
Token string `json:"token"`
Message string `json:"message"`
}
type GetUserRequest struct {
UserID string `json:"user_id" validate:"required"`
}
type GetUserResponse struct {
User *UserInfo `json:"user"`
}
type UpdateUserRequest struct {
UserID string `json:"user_id" validate:"required"`
Username string `json:"username"`
Email string `json:"email"`
Phone string `json:"phone"`
Address string `json:"address"`
}
type UpdateUserResponse struct {
User *UserInfo `json:"user"`
Message string `json:"message"`
}
type DeleteUserRequest struct {
UserID string `json:"user_id" validate:"required"`
}
type DeleteUserResponse struct {
Message string `json:"message"`
}
type ListUsersRequest struct {
Page int `json:"page" validate:"min=1"`
PageSize int `json:"page_size" validate:"min=1,max=100"`
Filter map[string]interface{} `json:"filter"`
}
type ListUsersResponse struct {
Users []*UserInfo `json:"users"`
TotalCount int64 `json:"total_count"`
Page int `json:"page"`
PageSize int `json:"page_size"`
}
type UserInfo struct {
ID string `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
Phone string `json:"phone"`
Address string `json:"address"`
Status string `json:"status"`
}
type UserCreatedEvent struct {
UserID string `json:"user_id"`
Username string `json:"username"`
Email string `json:"email"`
}
// 辅助函数
func getAuthToken(ctx context.Context) string {
// 从上下文中获取token
if token, ok := ctx.Value("authToken").(string); ok {
return token
}
return ""
}
// 使用示例
func ExampleHandlerUsage() {
service := micro.NewService(micro.Name("user.service"))
service.Init()
// 创建处理器管理器
handlerManager := NewHandlerManager(service.Server())
// 创建用户服务实例
userHandler := &UserService{
userRepo: &MockUserRepository{},
authService: &MockAuthService{},
eventBus: &MockEventBus{},
}
// 注册拦截器
handlerManager.RegisterInterceptor(&LoggingInterceptor{})
handlerManager.RegisterInterceptor(&AuthInterceptor{authService: &MockAuthService{}})
// 注册处理器
if err := handlerManager.RegisterHandler(userHandler); err != nil {
fmt.Printf("注册处理器失败: %v\n", err)
return
}
// 列出处理器信息
handlers := handlerManager.ListHandlers()
for _, handler := range handlers {
fmt.Printf("处理器: %s, 服务: %s, 方法数: %d\n",
handler.Name, handler.Service, len(handler.Methods))
for _, method := range handler.Methods {
fmt.Printf(" 方法: %s\n", method.Name)
}
}
}
---
2.5 Codec编码器
01.Codec接口定义
a.核心功能
Codec是go-micro的编解码组件,负责数据的序列化和反序列化。它抽象了数据格式转换的细节,支持多种数据编码格式,可以在不同的格式间灵活切换。
b.接口方法
Marshal()方法将Go对象序列化为字节数组,Unmarshal()方法将字节数组反序列化为Go对象。String()方法返回编码器的名称标识。
编解码器需要处理各种数据类型,包括基本类型、结构体、切片、映射等,并正确处理空值和嵌套结构。
c.代码示例
---
// Codec接口详细实现
package codec
import (
"bytes"
"encoding/gob"
"encoding/json"
"fmt"
"io"
"reflect"
"github.com/micro/go-micro/v2/codec"
)
// JSON编解码器
type jsonCodec struct {
// 可配置的编码选项
escapeHTML bool
indent string
}
// NewJSONCodec 创建JSON编解码器
func NewJSONCodec(opts ...JSONOption) codec.Codec {
options := &jsonOptions{
escapeHTML: true,
indent: "",
}
for _, opt := range opts {
opt(options)
}
return &jsonCodec{
escapeHTML: options.escapeHTML,
indent: options.indent,
}
}
// JSONOption JSON编解码器选项
type JSONOption func(*jsonOptions)
type jsonOptions struct {
escapeHTML bool
indent string
}
// WithEscapeHTML 设置是否转义HTML字符
func WithEscapeHTML(escape bool) JSONOption {
return func(o *jsonOptions) {
o.escapeHTML = escape
}
}
// WithIndent 设置缩进字符串
func WithIndent(indent string) JSONOption {
return func(o *jsonOptions) {
o.indent = indent
}
}
func (c *jsonCodec) Marshal(v interface{}) ([]byte, error) {
if v == nil {
return nil, nil
}
// 特殊处理bytes类型
if data, ok := v.([]byte); ok {
return data, nil
}
// 特殊处理codec.Frame类型
if frame, ok := v.(*codec.Frame); ok {
return frame.Data, nil
}
// 使用JSON序列化
var buf bytes.Buffer
encoder := json.NewEncoder(&buf)
encoder.SetEscapeHTML(c.escapeHTML)
if c.indent != "" {
encoder.SetIndent("", c.indent)
}
if err := encoder.Encode(v); err != nil {
return nil, fmt.Errorf("JSON序列化失败: %v", err)
}
// 去除末尾的换行符
data := buf.Bytes()
if len(data) > 0 && data[len(data)-1] == '\n' {
data = data[:len(data)-1]
}
return data, nil
}
func (c *jsonCodec) Unmarshal(data []byte, v interface{}) error {
if len(data) == 0 {
return nil
}
// 特殊处理bytes类型
if ptr, ok := v.(*[]byte); ok {
*ptr = make([]byte, len(data))
copy(*ptr, data)
return nil
}
// 特殊处理codec.Frame类型
if frame, ok := v.(*codec.Frame); ok {
frame.Data = make([]byte, len(data))
copy(frame.Data, data)
return nil
}
// 使用JSON反序列化
decoder := json.NewDecoder(bytes.NewReader(data))
if err := decoder.Decode(v); err != nil && err != io.EOF {
return fmt.Errorf("JSON反序列化失败: %v", err)
}
return nil
}
func (c *jsonCodec) String() string {
return "json"
}
// Gob编解码器
type gobCodec struct{}
// NewGobCodec 创建Gob编解码器
func NewGobCodec() codec.Codec {
return &gobCodec{}
}
func (c *gobCodec) Marshal(v interface{}) ([]byte, error) {
if v == nil {
return nil, nil
}
// 特殊处理bytes类型
if data, ok := v.([]byte); ok {
return data, nil
}
// 特殊处理codec.Frame类型
if frame, ok := v.(*codec.Frame); ok {
return frame.Data, nil
}
var buf bytes.Buffer
encoder := gob.NewEncoder(&buf)
if err := encoder.Encode(v); err != nil {
return nil, fmt.Errorf("Gob序列化失败: %v", err)
}
return buf.Bytes(), nil
}
func (c *gobCodec) Unmarshal(data []byte, v interface{}) error {
if len(data) == 0 {
return nil
}
// 特殊处理bytes类型
if ptr, ok := v.(*[]byte); ok {
*ptr = make([]byte, len(data))
copy(*ptr, data)
return nil
}
// 特殊处理codec.Frame类型
if frame, ok := v.(*codec.Frame); ok {
frame.Data = make([]byte, len(data))
copy(frame.Data, data)
return nil
}
decoder := gob.NewDecoder(bytes.NewReader(data))
return decoder.Decode(v)
}
func (c *gobCodec) String() string {
return "gob"
}
// 自定义二进制编解码器
type binaryCodec struct {
order binary.ByteOrder
}
// NewBinaryCodec 创建二进制编解码器
func NewBinaryCodec(order binary.ByteOrder) codec.Codec {
if order == nil {
order = binary.LittleEndian
}
return &binaryCodec{
order: order,
}
}
func (c *binaryCodec) Marshal(v interface{}) ([]byte, error) {
if v == nil {
return nil, nil
}
// 特殊处理bytes类型
if data, ok := v.([]byte); ok {
return data, nil
}
// 特殊处理codec.Frame类型
if frame, ok := v.(*codec.Frame); ok {
return frame.Data, nil
}
// 使用反射处理各种类型
val := reflect.ValueOf(v)
return c.marshalValue(val)
}
func (c *binaryCodec) Unmarshal(data []byte, v interface{}) error {
if len(data) == 0 {
return nil
}
// 特殊处理bytes类型
if ptr, ok := v.(*[]byte); ok {
*ptr = make([]byte, len(data))
copy(*ptr, data)
return nil
}
// 特殊处理codec.Frame类型
if frame, ok := v.(*codec.Frame); ok {
frame.Data = make([]byte, len(data))
copy(frame.Data, data)
return nil
}
// 使用反射处理各种类型
val := reflect.ValueOf(v)
if val.Kind() != reflect.Ptr || val.IsNil() {
return fmt.Errorf("需要非nil的指针")
}
return c.unmarshalValue(data, val.Elem())
}
func (c *binaryCodec) marshalValue(val reflect.Value) ([]byte, error) {
switch val.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return c.marshalInt(val.Int(), val.Type().Bits()), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return c.marshalUint(val.Uint(), val.Type().Bits()), nil
case reflect.Float32, reflect.Float64:
return c.marshalFloat(val.Float(), val.Type().Bits()), nil
case reflect.Bool:
if val.Bool() {
return []byte{1}, nil
}
return []byte{0}, nil
case reflect.String:
str := val.String()
data := make([]byte, 4+len(str))
c.order.PutUint32(data[:4], uint32(len(str)))
copy(data[4:], str)
return data, nil
case reflect.Slice:
if val.Type().Elem().Kind() == reflect.Uint8 {
// bytes类型
return val.Bytes(), nil
}
return c.marshalSlice(val)
case reflect.Struct:
return c.marshalStruct(val)
case reflect.Ptr:
if val.IsNil() {
return []byte{}, nil
}
return c.marshalValue(val.Elem())
default:
return nil, fmt.Errorf("不支持的类型: %v", val.Kind())
}
}
func (c *binaryCodec) unmarshalValue(data []byte, val reflect.Value) error {
if len(data) == 0 {
return nil
}
switch val.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return c.unmarshalInt(data, val)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return c.unmarshalUint(data, val)
case reflect.Float32, reflect.Float64:
return c.unmarshalFloat(data, val)
case reflect.Bool:
if len(data) < 1 {
return fmt.Errorf("数据不足")
}
val.SetBool(data[0] != 0)
return nil
case reflect.String:
if len(data) < 4 {
return fmt.Errorf("字符串数据不足")
}
strLen := int(c.order.Uint32(data[:4]))
if len(data) < 4+strLen {
return fmt.Errorf("字符串数据不足")
}
val.SetString(string(data[4 : 4+strLen]))
return nil
case reflect.Slice:
if val.Type().Elem().Kind() == reflect.Uint8 {
// bytes类型
val.SetBytes(data)
return nil
}
return c.unmarshalSlice(data, val)
case reflect.Struct:
return c.unmarshalStruct(data, val)
case reflect.Ptr:
if val.IsNil() {
val.Set(reflect.New(val.Type().Elem()))
}
return c.unmarshalValue(data, val.Elem())
default:
return fmt.Errorf("不支持的类型: %v", val.Kind())
}
}
func (c *binaryCodec) marshalInt(n int64, bits int) []byte {
switch bits {
case 8:
return []byte{byte(n)}
case 16:
data := make([]byte, 2)
c.order.PutUint16(data, uint16(n))
return data
case 32:
data := make([]byte, 4)
c.order.PutUint32(data, uint32(n))
return data
case 64:
data := make([]byte, 8)
c.order.PutUint64(data, uint64(n))
return data
default:
return []byte{byte(n)}
}
}
func (c *binaryCodec) marshalUint(n uint64, bits int) []byte {
switch bits {
case 8:
return []byte{byte(n)}
case 16:
data := make([]byte, 2)
c.order.PutUint16(data, uint16(n))
return data
case 32:
data := make([]byte, 4)
c.order.PutUint32(data, uint32(n))
return data
case 64:
data := make([]byte, 8)
c.order.PutUint64(data, n)
return data
default:
return []byte{byte(n)}
}
}
func (c *binaryCodec) marshalFloat(n float64, bits int) []byte {
switch bits {
case 32:
data := make([]byte, 4)
c.order.PutUint32(data, math.Float32bits(float32(n)))
return data
case 64:
data := make([]byte, 8)
c.order.PutUint64(data, math.Float64bits(n))
return data
default:
data := make([]byte, 8)
c.order.PutUint64(data, math.Float64bits(n))
return data
}
}
func (c *binaryCodec) unmarshalInt(data []byte, val reflect.Value) error {
switch val.Type().Bits() {
case 8:
if len(data) < 1 {
return fmt.Errorf("int8数据不足")
}
val.SetInt(int64(data[0]))
return nil
case 16:
if len(data) < 2 {
return fmt.Errorf("int16数据不足")
}
val.SetInt(int64(int16(c.order.Uint16(data[:2]))))
return nil
case 32:
if len(data) < 4 {
return fmt.Errorf("int32数据不足")
}
val.SetInt(int64(int32(c.order.Uint32(data[:4]))))
return nil
case 64:
if len(data) < 8 {
return fmt.Errorf("int64数据不足")
}
val.SetInt(int64(c.order.Uint64(data[:8])))
return nil
default:
return fmt.Errorf("不支持的int位数: %d", val.Type().Bits())
}
}
func (c *binaryCodec) unmarshalUint(data []byte, val reflect.Value) error {
switch val.Type().Bits() {
case 8:
if len(data) < 1 {
return fmt.Errorf("uint8数据不足")
}
val.SetUint(uint64(data[0]))
return nil
case 16:
if len(data) < 2 {
return fmt.Errorf("uint16数据不足")
}
val.SetUint(uint64(c.order.Uint16(data[:2])))
return nil
case 32:
if len(data) < 4 {
return fmt.Errorf("uint32数据不足")
}
val.SetUint(uint64(c.order.Uint32(data[:4])))
return nil
case 64:
if len(data) < 8 {
return fmt.Errorf("uint64数据不足")
}
val.SetUint(c.order.Uint64(data[:8]))
return nil
default:
return fmt.Errorf("不支持的uint位数: %d", val.Type().Bits())
}
}
func (c *binaryCodec) unmarshalFloat(data []byte, val reflect.Value) error {
switch val.Type().Bits() {
case 32:
if len(data) < 4 {
return fmt.Errorf("float32数据不足")
}
bits := c.order.Uint32(data[:4])
val.SetFloat(float64(math.Float32frombits(bits)))
return nil
case 64:
if len(data) < 8 {
return fmt.Errorf("float64数据不足")
}
bits := c.order.Uint64(data[:8])
val.SetFloat(math.Float64frombits(bits))
return nil
default:
return fmt.Errorf("不支持的float位数: %d", val.Type().Bits())
}
}
func (c *binaryCodec) marshalSlice(val reflect.Value) ([]byte, error) {
length := val.Len()
if length == 0 {
return []byte{0, 0, 0, 0}, nil
}
// 计算总大小
totalSize := 4 // 长度前缀
elemSize, err := c.getElementSize(val.Type().Elem())
if err != nil {
return nil, err
}
totalSize += length * elemSize
data := make([]byte, totalSize)
c.order.PutUint32(data[:4], uint32(length))
offset := 4
for i := 0; i < length; i++ {
elemData, err := c.marshalValue(val.Index(i))
if err != nil {
return nil, err
}
copy(data[offset:], elemData)
offset += elemSize
}
return data, nil
}
func (c *binaryCodec) unmarshalSlice(data []byte, val reflect.Value) error {
if len(data) < 4 {
return fmt.Errorf("slice数据不足")
}
length := int(c.order.Uint32(data[:4]))
if length == 0 {
val.Set(reflect.MakeSlice(val.Type(), 0, 0))
return nil
}
elemType := val.Type().Elem()
elemSize, err := c.getElementSize(elemType)
if err != nil {
return err
}
expectedSize := 4 + length*elemSize
if len(data) < expectedSize {
return fmt.Errorf("slice数据不足")
}
slice := reflect.MakeSlice(val.Type(), length, length)
offset := 4
for i := 0; i < length; i++ {
elem := slice.Index(i)
if err := c.unmarshalValue(data[offset:offset+elemSize], elem); err != nil {
return err
}
offset += elemSize
}
val.Set(slice)
return nil
}
func (c *binaryCodec) marshalStruct(val reflect.Value) ([]byte, error) {
typ := val.Type()
numFields := val.NumField()
data := make([]byte, 0)
for i := 0; i < numFields; i++ {
field := val.Field(i)
if !field.CanInterface() {
continue
}
fieldData, err := c.marshalValue(field)
if err != nil {
return nil, fmt.Errorf("序列化字段%s失败: %v", typ.Field(i).Name, err)
}
data = append(data, fieldData...)
}
return data, nil
}
func (c *binaryCodec) unmarshalStruct(data []byte, val reflect.Value) error {
typ := val.Type()
numFields := val.NumField()
offset := 0
for i := 0; i < numFields; i++ {
field := val.Field(i)
if !field.CanInterface() || !field.CanSet() {
continue
}
fieldSize, err := c.getElementSize(field.Type())
if err != nil {
return fmt.Errorf("获取字段%s大小失败: %v", typ.Field(i).Name, err)
}
if offset+fieldSize > len(data) {
return fmt.Errorf("struct数据不足")
}
if err := c.unmarshalValue(data[offset:offset+fieldSize], field); err != nil {
return fmt.Errorf("反序列化字段%s失败: %v", typ.Field(i).Name, err)
}
offset += fieldSize
}
return nil
}
func (c *binaryCodec) getElementSize(typ reflect.Type) (int, error) {
switch typ.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return typ.Bits() / 8, nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return typ.Bits() / 8, nil
case reflect.Float32, reflect.Float64:
return typ.Bits() / 8, nil
case reflect.Bool:
return 1, nil
case reflect.String:
return -1, nil // 字符串长度可变
case reflect.Slice:
if typ.Elem().Kind() == reflect.Uint8 {
return -1, nil // bytes长度可变
}
elemSize, err := c.getElementSize(typ.Elem())
if err != nil {
return 0, err
}
return -1, nil // slice长度可变
case reflect.Struct:
totalSize := 0
for i := 0; i < typ.NumField(); i++ {
fieldSize, err := c.getElementSize(typ.Field(i).Type)
if err != nil {
return 0, err
}
if fieldSize < 0 {
return 0, fmt.Errorf("struct包含可变长度字段")
}
totalSize += fieldSize
}
return totalSize, nil
default:
return 0, fmt.Errorf("不支持的类型: %v", typ.Kind())
}
}
func (c *binaryCodec) String() string {
return "binary"
}
// 压缩编解码器包装器
type compressedCodec struct {
codec codec.Codec
compressor Compressor
}
// Compressor 压缩器接口
type Compressor interface {
Compress(data []byte) ([]byte, error)
Decompress(data []byte) ([]byte, error)
}
// NewCompressedCodec 创建压缩编解码器
func NewCompressedCodec(c codec.Codec, compressor Compressor) codec.Codec {
return &compressedCodec{
codec: c,
compressor: compressor,
}
}
func (c *compressedCodec) Marshal(v interface{}) ([]byte, error) {
// 先序列化
data, err := c.codec.Marshal(v)
if err != nil {
return nil, err
}
// 再压缩
return c.compressor.Compress(data)
}
func (c *compressedCodec) Unmarshal(data []byte, v interface{}) error {
// 先解压
decompressed, err := c.compressor.Decompress(data)
if err != nil {
return err
}
// 再反序列化
return c.codec.Unmarshal(decompressed, v)
}
func (c *compressedCodec) String() string {
return fmt.Sprintf("compressed-%s", c.codec.String())
}
---
02.编解码器性能对比
a.序列化性能
不同编解码器在序列化性能上有显著差异。二进制格式(如Protobuf、Gob)通常比文本格式(如JSON)更快,因为避免了文本解析的开销。
b.数据大小
二进制格式通常产生更小的数据,节省网络传输带宽和存储空间。JSON格式由于字段名和缩进等额外信息,数据大小相对较大。
c.可读性
JSON格式具有最好的可读性,便于调试和人工检查。二进制格式需要专门的工具才能查看内容。
d.性能测试代码示例
---
// 编解码器性能测试示例
package performance
import (
"bytes"
"encoding/json"
"testing"
"time"
"github.com/golang/protobuf/proto"
"github.com/tinylib/msgp/msgp"
"github.com/vmihailenco/msgpack/v5"
)
// 测试数据结构
type TestData struct {
ID int64 `json:"id" protobuf:"varint,1"`
Name string `json:"name" protobuf:"bytes,2"`
Email string `json:"email" protobuf:"bytes,3"`
Age int32 `json:"age" protobuf:"varint,4"`
Active bool `json:"active" protobuf:"varint,5"`
Tags []string `json:"tags" protobuf:"bytes,6"`
Metadata map[string]interface{} `json:"metadata" protobuf:"bytes,7"`
Created time.Time `json:"created" protobuf:"bytes,8"`
}
// 生成测试数据
func generateTestData() *TestData {
return &TestData{
ID: 123456789,
Name: "Test User",
Email: "[email protected]",
Age: 25,
Active: true,
Tags: []string{"go", "microservices", "performance"},
Metadata: map[string]interface{}{
"version": "1.0",
"env": "production",
"cluster": "main",
},
Created: time.Now(),
}
}
// JSON性能测试
func BenchmarkJSONMarshal(b *testing.B) {
data := generateTestData()
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_, _ = json.Marshal(data)
}
}
func BenchmarkJSONUnmarshal(b *testing.B) {
data := generateTestData()
jsonBytes, _ := json.Marshal(data)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
var result TestData
_ = json.Unmarshal(jsonBytes, &result)
}
}
// Gob性能测试
func BenchmarkGobMarshal(b *testing.B) {
data := generateTestData()
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
var buf bytes.Buffer
encoder := gob.NewEncoder(&buf)
_ = encoder.Encode(data)
}
}
func BenchmarkGobUnmarshal(b *testing.B) {
data := generateTestData()
var buf bytes.Buffer
encoder := gob.NewEncoder(&buf)
encoder.Encode(data)
gobBytes := buf.Bytes()
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
var result TestData
decoder := gob.NewDecoder(bytes.NewReader(gobBytes))
_ = decoder.Decode(&result)
}
}
// MessagePack性能测试
func BenchmarkMsgpackMarshal(b *testing.B) {
data := generateTestData()
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_, _ = msgpack.Marshal(data)
}
}
func BenchmarkMsgpackUnmarshal(b *testing.B) {
data := generateTestData()
msgpackBytes, _ := msgpack.Marshal(data)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
var result TestData
_ = msgpack.Unmarshal(msgpackBytes, &result)
}
}
// MsgPack性能测试(tinylib/msgp版本)
func BenchmarkMsgpMarshal(b *testing.B) {
data := generateTestData()
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_, _ = data.MarshalMsg(nil)
}
}
func BenchmarkMsgpUnmarshal(b *testing.B) {
data := generateTestData()
msgpBytes, _ := data.MarshalMsg(nil)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
var result TestData
_, _ = result.UnmarshalMsg(msgpBytes)
}
}
// 内存使用对比测试
func BenchmarkDataSize(b *testing.B) {
data := generateTestData()
// JSON大小
jsonBytes, _ := json.Marshal(data)
fmt.Printf("JSON大小: %d bytes\n", len(jsonBytes))
// Gob大小
var buf bytes.Buffer
encoder := gob.NewEncoder(&buf)
encoder.Encode(data)
fmt.Printf("Gob大小: %d bytes\n", buf.Len())
// MessagePack大小
msgpackBytes, _ := msgpack.Marshal(data)
fmt.Printf("MessagePack大小: %d bytes\n", len(msgpackBytes))
// MsgPack大小
msgpBytes, _ := data.MarshalMsg(nil)
fmt.Printf("MsgPack大小: %d bytes\n", len(msgpBytes))
}
// 并发性能测试
func BenchmarkConcurrentMarshal(b *testing.B) {
data := generateTestData()
b.ResetTimer()
b.ReportAllocs()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_, _ = json.Marshal(data)
}
})
}
func BenchmarkConcurrentUnmarshal(b *testing.B) {
data := generateTestData()
jsonBytes, _ := json.Marshal(data)
b.ResetTimer()
b.ReportAllocs()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
var result TestData
_ = json.Unmarshal(jsonBytes, &result)
}
})
}
// 大数据性能测试
func BenchmarkLargeDataMarshal(b *testing.B) {
data := generateLargeTestData(10000) // 10000条记录
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_, _ = json.Marshal(data)
}
}
func BenchmarkLargeDataUnmarshal(b *testing.B) {
data := generateLargeTestData(10000)
jsonBytes, _ := json.Marshal(data)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
var result []*TestData
_ = json.Unmarshal(jsonBytes, &result)
}
}
// 生成大数据测试集
func generateLargeTestData(count int) []*TestData {
data := make([]*TestData, count)
for i := 0; i < count; i++ {
data[i] = &TestData{
ID: int64(i),
Name: fmt.Sprintf("User%d", i),
Email: fmt.Sprintf("user%[email protected]", i),
Age: 20 + i%50,
Active: i%2 == 0,
Tags: []string{"tag1", "tag2", fmt.Sprintf("tag%d", i%10)},
Metadata: map[string]interface{}{
"index": i,
"group": fmt.Sprintf("group%d", i%10),
"priority": i % 5,
},
Created: time.Now().Add(time.Duration(i) * time.Hour),
}
}
return data
}
// 性能分析工具
type PerformanceAnalyzer struct {
marshalTimes []time.Duration
unmarshalTimes []time.Duration
dataSizes []int
}
func NewPerformanceAnalyzer() *PerformanceAnalyzer {
return &PerformanceAnalyzer{
marshalTimes: make([]time.Duration, 0),
unmarshalTimes: make([]time.Duration, 0),
dataSizes: make([]int, 0),
}
}
func (pa *PerformanceAnalyzer) AnalyzeCodec(name string, marshalFunc func() ([]byte, error), unmarshalFunc func([]byte) error) error {
// 预热
for i := 0; i < 100; i++ {
data, _ := marshalFunc()
unmarshalFunc(data)
}
// 测试序列化性能
marshalStart := time.Now()
var totalDataSize int64
iterations := 10000
for i := 0; i < iterations; i++ {
data, err := marshalFunc()
if err != nil {
return err
}
totalDataSize += int64(len(data))
pa.dataSizes = append(pa.dataSizes, len(data))
}
marshalDuration := time.Since(marshalStart)
// 准备反序列化测试数据
testData, err := marshalFunc()
if err != nil {
return err
}
// 测试反序列化性能
unmarshalStart := time.Now()
for i := 0; i < iterations; i++ {
if err := unmarshalFunc(testData); err != nil {
return err
}
}
unmarshalDuration := time.Since(unmarshalStart)
// 计算统计数据
avgMarshalTime := marshalDuration / time.Duration(iterations)
avgUnmarshalTime := unmarshalDuration / time.Duration(iterations)
avgDataSize := float64(totalDataSize) / float64(iterations)
marshalThroughput := float64(totalDataSize) / marshalDuration.Seconds() / (1024 * 1024) // MB/s
unmarshalThroughput := float64(totalDataSize) / unmarshalDuration.Seconds() / (1024 * 1024) // MB/s
fmt.Printf("\n=== %s 编解码器性能分析 ===\n", name)
fmt.Printf("序列化:\n")
fmt.Printf(" 平均耗时: %v\n", avgMarshalTime)
fmt.Printf(" 吞吐量: %.2f MB/s\n", marshalThroughput)
fmt.Printf(" 平均数据大小: %.2f bytes\n", avgDataSize)
fmt.Printf("反序列化:\n")
fmt.Printf(" 平均耗时: %v\n", avgUnmarshalTime)
fmt.Printf(" 吞吐量: %.2f MB/s\n", unmarshalThroughput)
return nil
}
// 运行性能分析
func RunCodecPerformanceAnalysis() {
analyzer := NewPerformanceAnalyzer()
data := generateTestData()
// 分析JSON
analyzer.AnalyzeCodec("JSON", func() ([]byte, error) {
return json.Marshal(data)
}, func(data []byte) error {
var result TestData
return json.Unmarshal(data, &result)
})
// 分析MessagePack
analyzer.AnalyzeCodec("MessagePack", func() ([]byte, error) {
return msgpack.Marshal(data)
}, func(data []byte) error {
var result TestData
return msgpack.Unmarshal(data, &result)
})
}
---
03.自定义编解码器
a.开发指南
开发自定义编解码器需要实现Codec接口的Marshal、Unmarshal和String方法。Marshal方法将Go对象转换为字节数组,Unmarshal方法执行相反操作。
b.特殊类型处理
需要特别注意特殊类型的处理,如nil值、[]byte类型、自定义类型等。可以参考标准库的json包和gob包的实现。
c.性能优化
对于性能要求高的场景,可以使用对象池、缓冲区重用等技术优化性能。避免不必要的内存分配和数据复制。
2.6 Transport传输层
01.Transport接口定义
a.核心功能
Transport是go-micro的网络传输层组件,负责底层网络通信。它抽象了网络传输的细节,支持多种传输协议和通信模式,包括同步调用、异步调用、流式传输等。
b.接口方法
Init()方法初始化传输层配置,Options()返回当前选项。Dial()方法创建客户端连接,Listen()方法创建服务端监听器。
String()方法返回传输层的名称标识。传输层需要处理连接管理、数据传输、错误处理等底层网络细节。
c.代码示例
---
// Transport接口详细实现
package transport
import (
"context"
"crypto/tls"
"fmt"
"net"
"sync"
"time"
"github.com/micro/go-micro/v2/transport"
)
// HTTP传输层实现
type httpTransport struct {
opts transport.Options
mu sync.RWMutex
// TLS配置
tlsConfig *tls.Config
// 连接池
pool *ConnectionPool
// 统计信息
stats *TransportStats
}
// TransportStats 传输层统计信息
type TransportStats struct {
TotalConnections int64 `json:"total_connections"`
ActiveConnections int64 `json:"active_connections"`
FailedConnections int64 `json:"failed_connections"`
TotalBytesSent int64 `json:"total_bytes_sent"`
TotalBytesReceived int64 `json:"total_bytes_received"`
AverageLatency time.Duration `json:"average_latency"`
ConnectionDurations []time.Duration `json:"connection_durations"`
mu sync.RWMutex
}
// ConnectionPool 连接池
type ConnectionPool struct {
mu sync.RWMutex
conns map[string][]*httpSocket
maxSize int
maxIdle time.Duration
stats *PoolStats
}
type PoolStats struct {
Created int64 `json:"created"`
Reused int64 `json:"reused"`
Destroyed int64 `json:"destroyed"`
}
// NewHTTPTransport 创建HTTP传输层
func NewHTTPTransport(opts ...transport.Option) transport.Transport {
// 创建默认选项
options := transport.NewOptions()
// 应用用户提供的选项
for _, o := range opts {
o(&options)
}
return &httpTransport{
opts: options,
pool: NewConnectionPool(100, 30*time.Minute),
stats: &TransportStats{},
}
}
// Init 初始化传输层
func (t *httpTransport) Init(opts ...transport.Option) error {
t.mu.Lock()
defer t.mu.Unlock()
// 应用选项
for _, o := range opts {
o(&t.opts)
}
// 初始化TLS配置
if t.opts.TLSConfig != nil {
t.tlsConfig = t.opts.TLSConfig
} else {
// 创建默认TLS配置
t.tlsConfig = &tls.Config{
InsecureSkipVerify: false,
MinVersion: tls.VersionTLS12,
}
}
return nil
}
// Options 获取传输层选项
func (t *httpTransport) Options() transport.Options {
t.mu.RLock()
defer t.mu.RUnlock()
return t.opts
}
// Dial 创建客户端连接
func (t *httpTransport) Dial(addr string, opts ...transport.DialOption) (transport.Client, error) {
start := time.Now()
defer func() {
t.recordConnectionTime(time.Since(start))
}()
// 创建默认拨号选项
options := transport.DialOptions{
Timeout: t.opts.Timeout,
}
// 应用拨号选项
for _, o := range opts {
o(&options)
}
// 尝试从连接池获取连接
if !options.Stream {
if conn := t.pool.Get(addr); conn != nil {
t.stats.mu.Lock()
t.stats.ActiveConnections++
t.stats.mu.Unlock()
return conn, nil
}
}
// 创建新连接
var netConn net.Conn
var err error
if t.tlsConfig != nil {
// TLS连接
dialer := &net.Dialer{
Timeout: options.Timeout,
}
netConn, err = tls.DialWithDialer(dialer, "tcp", addr, t.tlsConfig)
} else {
// 普通TCP连接
netConn, err = net.DialTimeout("tcp", addr, options.Timeout)
}
if err != nil {
t.stats.mu.Lock()
t.stats.FailedConnections++
t.stats.mu.Unlock()
return nil, fmt.Errorf("建立连接失败: %v", err)
}
// 创建传输层客户端
client := &httpSocket{
conn: netConn,
local: netConn.LocalAddr().String(),
remote: addr,
timeout: options.Timeout,
stream: options.Stream,
buffer: make([]byte, 4096),
}
// 如果支持KeepAlive,设置socket选项
if tcpConn, ok := netConn.(*net.TCPConn); ok {
tcpConn.SetKeepAlive(true)
tcpConn.SetKeepAlivePeriod(30 * time.Second)
}
t.stats.mu.Lock()
t.stats.TotalConnections++
t.stats.ActiveConnections++
t.stats.mu.Unlock()
// 添加到连接池(如果是非流式连接)
if !options.Stream {
t.pool.Put(addr, client)
}
return client, nil
}
// Listen 创建服务端监听器
func (t *httpTransport) Listen(addr string, opts ...transport.ListenOption) (transport.Listener, error) {
// 创建默认监听选项
options := transport.ListenOptions{}
// 应用监听选项
for _, o := range opts {
o(&options)
}
var netListener net.Listener
var err error
if t.tlsConfig != nil {
// TLS监听器
netListener, err = tls.Listen("tcp", addr, t.tlsConfig)
} else {
// 普通TCP监听器
netListener, err = net.Listen("tcp", addr)
}
if err != nil {
return nil, fmt.Errorf("创建监听器失败: %v", err)
}
// 包装为传输层监听器
return &httpListener{
listener: netListener,
addr: netListener.Addr().String(),
opts: options,
stats: t.stats,
}, nil
}
// String 返回传输层名称
func (t *httpTransport) String() string {
return "http"
}
// recordConnectionTime 记录连接时间
func (t *httpTransport) recordConnectionTime(duration time.Duration) {
t.stats.mu.Lock()
defer t.stats.mu.Unlock()
t.stats.ConnectionDurations = append(t.stats.ConnectionDurations, duration)
// 只保留最近1000个连接时间记录
if len(t.stats.ConnectionDurations) > 1000 {
t.stats.ConnectionDurations = t.stats.ConnectionDurations[1:]
}
// 计算平均延迟
var total time.Duration
for _, d := range t.stats.ConnectionDurations {
total += d
}
t.stats.AverageLatency = total / time.Duration(len(t.stats.ConnectionDurations))
}
// GetStats 获取统计信息
func (t *httpTransport) GetStats() *TransportStats {
t.stats.mu.RLock()
defer t.stats.mu.RUnlock()
return &TransportStats{
TotalConnections: t.stats.TotalConnections,
ActiveConnections: t.stats.ActiveConnections,
FailedConnections: t.stats.FailedConnections,
TotalBytesSent: t.stats.TotalBytesSent,
TotalBytesReceived: t.stats.TotalBytesReceived,
AverageLatency: t.stats.AverageLatency,
ConnectionDurations: append([]time.Duration(nil), t.stats.ConnectionDurations...),
}
}
// NewConnectionPool 创建连接池
func NewConnectionPool(maxSize int, maxIdle time.Duration) *ConnectionPool {
return &ConnectionPool{
conns: make(map[string][]*httpSocket),
maxSize: maxSize,
maxIdle: maxIdle,
stats: &PoolStats{},
}
}
// Get 从连接池获取连接
func (p *ConnectionPool) Get(addr string) *httpSocket {
p.mu.Lock()
defer p.mu.Unlock()
conns, exists := p.conns[addr]
if !exists || len(conns) == 0 {
return nil
}
// 获取最后一个连接
conn := conns[len(conns)-1]
conns = conns[:len(conns)-1]
p.conns[addr] = conns
// 检查连接是否仍然有效
if !conn.isValid() {
p.stats.Destroyed++
conn.Close()
return nil
}
p.stats.Reused++
return conn
}
// Put 将连接放回连接池
func (p *ConnectionPool) Put(addr string, conn *httpSocket) {
p.mu.Lock()
defer p.mu.Unlock()
// 检查连接池大小限制
total := 0
for _, conns := range p.conns {
total += len(conns)
}
if total >= p.maxSize {
p.stats.Destroyed++
conn.Close()
return
}
// 添加到对应地址的连接列表
if p.conns[addr] == nil {
p.conns[addr] = make([]*httpSocket, 0)
}
p.conns[addr] = append(p.conns[addr], conn)
p.stats.Created++
}
// GetPoolStats 获取连接池统计信息
func (p *ConnectionPool) GetPoolStats() *PoolStats {
p.mu.RLock()
defer p.mu.RUnlock()
return &PoolStats{
Created: p.stats.Created,
Reused: p.stats.Reused,
Destroyed: p.stats.Destroyed,
}
}
// httpSocket HTTP客户端实现
type httpSocket struct {
conn net.Conn
local string
remote string
timeout time.Duration
stream bool
buffer []byte
mu sync.RWMutex
closed bool
}
func (s *httpSocket) Local() string {
return s.local
}
func (s *httpSocket) Remote() string {
return s.remote
}
func (s *httpSocket) Send(msg *transport.Message) error {
s.mu.Lock()
defer s.mu.Unlock()
if s.closed {
return fmt.Errorf("连接已关闭")
}
// 设置超时
if s.timeout > 0 {
s.conn.SetWriteDeadline(time.Now().Add(s.timeout))
}
// 构建HTTP请求
request := fmt.Sprintf(
"POST / HTTP/1.1\r\n"+
"Host: %s\r\n"+
"Content-Type: %s\r\n"+
"Content-Length: %d\r\n"+
"Connection: %s\r\n",
s.remote,
msg.Header["Content-Type"],
len(msg.Body),
"keep-alive",
)
// 添加自定义头部
for k, v := range msg.Header {
if k != "Content-Type" {
request += fmt.Sprintf("%s: %s\r\n", k, v)
}
}
request += "\r\n" + string(msg.Body)
// 发送请求
_, err := s.conn.Write([]byte(request))
if err != nil {
s.Close()
return fmt.Errorf("发送数据失败: %v", err)
}
return nil
}
func (s *httpSocket) Recv(msg *transport.Message) error {
s.mu.Lock()
defer s.mu.Unlock()
if s.closed {
return fmt.Errorf("连接已关闭")
}
// 设置超时
if s.timeout > 0 {
s.conn.SetReadDeadline(time.Now().Add(s.timeout))
}
// 读取响应头
reader := bufio.NewReader(s.conn)
resp, err := http.ReadResponse(reader, nil)
if err != nil {
s.Close()
return fmt.Errorf("读取响应失败: %v", err)
}
defer resp.Body.Close()
// 读取响应体
body, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("读取响应体失败: %v", err)
}
// 设置消息头部
msg.Header = make(map[string]string)
for k, v := range resp.Header {
if len(v) > 0 {
msg.Header[k] = v[0]
}
}
// 设置消息体
msg.Body = body
return nil
}
func (s *httpSocket) Close() error {
s.mu.Lock()
defer s.mu.Unlock()
if s.closed {
return nil
}
s.closed = true
return s.conn.Close()
}
func (s *httpSocket) isValid() bool {
// 检查连接是否仍然有效
if s.closed {
return false
}
// 发送零字节数据包检查连接
s.conn.SetWriteDeadline(time.Now().Add(time.Second))
_, err := s.conn.Write([]byte{})
if err != nil {
return false
}
return true
}
// httpListener HTTP服务端实现
type httpListener struct {
listener net.Listener
addr string
opts transport.ListenOptions
stats *TransportStats
mu sync.RWMutex
closed bool
}
func (l *httpListener) Addr() string {
return l.addr
}
func (l *httpListener) Close() error {
l.mu.Lock()
defer l.mu.Unlock()
if l.closed {
return nil
}
l.closed = true
return l.listener.Close()
}
func (l *httpListener) Accept(fn func(transport.Socket)) error {
for {
conn, err := l.listener.Accept()
if err != nil {
l.mu.RLock()
closed := l.closed
l.mu.RUnlock()
if closed {
return nil
}
return fmt.Errorf("接受连接失败: %v", err)
}
// 创建传输层socket
socket := &httpSocket{
conn: conn,
local: conn.LocalAddr().String(),
remote: conn.RemoteAddr().String(),
timeout: l.opts.Timeout,
}
// 更新统计信息
l.stats.mu.Lock()
l.stats.ActiveConnections++
l.stats.TotalConnections++
l.stats.mu.Unlock()
// 在新的goroutine中处理连接
go l.handleConnection(socket, fn)
}
}
func (l *httpListener) handleConnection(socket transport.Socket, fn func(transport.Socket)) {
defer func() {
socket.Close()
l.stats.mu.Lock()
l.stats.ActiveConnections--
l.stats.mu.Unlock()
}()
// 调用处理函数
fn(socket)
}
// gRPC传输层实现
type grpcTransport struct {
opts transport.Options
mu sync.RWMutex
}
// NewGRPCTransport 创建gRPC传输层
func NewGRPCTransport(opts ...transport.Option) transport.Transport {
options := transport.NewOptions()
for _, o := range opts {
o(&options)
}
return &grpcTransport{
opts: options,
}
}
func (t *grpcTransport) Init(opts ...transport.Option) error {
t.mu.Lock()
defer t.mu.Unlock()
for _, o := range opts {
o(&t.opts)
}
return nil
}
func (t *grpcTransport) Options() transport.Options {
t.mu.RLock()
defer t.mu.RUnlock()
return t.opts
}
func (t *grpcTransport) Dial(addr string, opts ...transport.DialOption) (transport.Client, error) {
// 创建gRPC客户端连接
conn, err := grpc.Dial(addr,
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithBlock(),
)
if err != nil {
return nil, fmt.Errorf("gRPC连接失败: %v", err)
}
return &grpcSocket{
conn: conn,
local: conn.Target(),
remote: addr,
}, nil
}
func (t *grpcTransport) Listen(addr string, opts ...transport.ListenOption) (transport.Listener, error) {
// 创建gRPC服务端监听器
lis, err := net.Listen("tcp", addr)
if err != nil {
return nil, fmt.Errorf("gRPC监听失败: %v", err)
}
return &grpcListener{
listener: lis,
addr: lis.Addr().String(),
}, nil
}
func (t *grpcTransport) String() string {
return "grpc"
}
// grpcSocket gRPC客户端实现
type grpcSocket struct {
conn *grpc.ClientConn
local string
remote string
mu sync.RWMutex
closed bool
}
func (s *grpcSocket) Local() string {
return s.local
}
func (s *grpcSocket) Remote() string {
return s.remote
}
func (s *grpcSocket) Send(msg *transport.Message) error {
s.mu.Lock()
defer s.mu.Unlock()
if s.closed {
return fmt.Errorf("连接已关闭")
}
// gRPC流式发送实现
// 这里简化实现,实际需要完整的gRPC流处理
return nil
}
func (s *grpcSocket) Recv(msg *transport.Message) error {
s.mu.Lock()
defer s.mu.Unlock()
if s.closed {
return fmt.Errorf("连接已关闭")
}
// gRPC流式接收实现
// 这里简化实现,实际需要完整的gRPC流处理
return nil
}
func (s *grpcSocket) Close() error {
s.mu.Lock()
defer s.mu.Unlock()
if s.closed {
return nil
}
s.closed = true
return s.conn.Close()
}
// grpcListener gRPC服务端实现
type grpcListener struct {
listener net.Listener
addr string
server *grpc.Server
mu sync.RWMutex
closed bool
}
func (l *grpcListener) Addr() string {
return l.addr
}
func (l *grpcListener) Close() error {
l.mu.Lock()
defer l.mu.Unlock()
if l.closed {
return nil
}
l.closed = true
if l.server != nil {
l.server.GracefulStop()
}
return l.listener.Close()
}
func (l *grpcListener) Accept(fn func(transport.Socket)) error {
// 创建gRPC服务器
l.server = grpc.NewServer()
// 注册服务(简化实现)
// 实际需要注册具体的gRPC服务
// 启动gRPC服务器
return l.server.Serve(l.listener)
}
---
02.传输层协议支持
a.HTTP/HTTPS协议
HTTP是最常用的传输协议,具有良好的兼容性和可调试性。HTTPS基于TLS提供安全传输,支持双向证书认证和加密通信。
b.gRPC协议
gRPC基于HTTP/2,支持高效的二进制传输和双向流式通信。提供自动代码生成、类型安全、连接复用等特性。
c.TCP/UDP协议
原始TCP/UDP协议提供最大灵活性,适合需要完全控制网络协议的场景。可以实现自定义的协议格式和通信模式。
d.协议选择指南
---
// 传输层协议选择指南
package transportguide
import (
"context"
"fmt"
"time"
"github.com/micro/go-micro/v2/transport"
)
// ProtocolConfig 协议配置
type ProtocolConfig struct {
Protocol string `json:"protocol"`
Address string `json:"address"`
Timeout time.Duration `json:"timeout"`
TLS *TLSConfig `json:"tls"`
Compression bool `json:"compression"`
KeepAlive bool `json:"keep_alive"`
MaxConnections int `json:"max_connections"`
}
type TLSConfig struct {
Enabled bool `json:"enabled"`
CertFile string `json:"cert_file"`
KeyFile string `json:"key_file"`
CAFile string `json:"ca_file"`
ServerName string `json:"server_name"`
SkipVerify bool `json:"skip_verify"`
MinVersion string `json:"min_version"`
}
// TransportFactory 传输层工厂
type TransportFactory struct {
configs map[string]*ProtocolConfig
}
func NewTransportFactory() *TransportFactory {
return &TransportFactory{
configs: make(map[string]*ProtocolConfig),
}
}
func (tf *TransportFactory) RegisterProtocol(name string, config *ProtocolConfig) {
tf.configs[name] = config
}
func (tf *TransportFactory) CreateTransport(protocolName string) (transport.Transport, error) {
config, exists := tf.configs[protocolName]
if !exists {
return nil, fmt.Errorf("未知协议: %s", protocolName)
}
switch config.Protocol {
case "http":
return tf.createHTTPTransport(config)
case "https":
return tf.createHTTPSTransport(config)
case "grpc":
return tf.createGRPCTransport(config)
case "tcp":
return tf.createTCPTransport(config)
case "udp":
return tf.createUDPTransport(config)
default:
return nil, fmt.Errorf("不支持的协议: %s", config.Protocol)
}
}
func (tf *TransportFactory) createHTTPTransport(config *ProtocolConfig) (transport.Transport, error) {
var opts []transport.Option
// 设置超时
if config.Timeout > 0 {
opts = append(opts, transport.WithTimeout(config.Timeout))
}
// 设置连接复用
if config.KeepAlive {
opts = append(opts, transport.WithDialOption(transport.WithDialTimeout(config.Timeout)))
}
return transport.NewHTTPTransport(opts...), nil
}
func (tf *TransportFactory) createHTTPSTransport(config *ProtocolConfig) (transport.Transport, error) {
if config.TLS == nil || !config.TLS.Enabled {
return nil, fmt.Errorf("HTTPS需要TLS配置")
}
// 加载TLS配置
tlsConfig, err := tf.loadTLSConfig(config.TLS)
if err != nil {
return nil, fmt.Errorf("加载TLS配置失败: %v", err)
}
var opts []transport.Option
opts = append(opts, transport.WithTLSConfig(tlsConfig))
if config.Timeout > 0 {
opts = append(opts, transport.WithTimeout(config.Timeout))
}
return transport.NewHTTPTransport(opts...), nil
}
func (tf *TransportFactory) createGRPCTransport(config *ProtocolConfig) (transport.Transport, error) {
var opts []transport.Option
if config.Timeout > 0 {
opts = append(opts, transport.WithTimeout(config.Timeout))
}
return transport.NewGRPCTransport(opts...), nil
}
func (tf *TransportFactory) createTCPTransport(config *ProtocolConfig) (transport.Transport, error) {
var opts []transport.Option
if config.Timeout > 0 {
opts = append(opts, transport.WithTimeout(config.Timeout))
}
return transport.NewTCPTransport(opts...), nil
}
func (tf *TransportFactory) createUDPTransport(config *ProtocolConfig) (transport.Transport, error) {
var opts []transport.Option
if config.Timeout > 0 {
opts = append(opts, transport.WithTimeout(config.Timeout))
}
return transport.NewUDPTransport(opts...), nil
}
func (tf *TransportFactory) loadTLSConfig(tlsConfig *TLSConfig) (*tls.Config, error) {
config := &tls.Config{
ServerName: tlsConfig.ServerName,
InsecureSkipVerify: tlsConfig.SkipVerify,
}
// 设置最小版本
if tlsConfig.MinVersion != "" {
switch tlsConfig.MinVersion {
case "1.0":
config.MinVersion = tls.VersionTLS10
case "1.1":
config.MinVersion = tls.VersionTLS11
case "1.2":
config.MinVersion = tls.VersionTLS12
case "1.3":
config.MinVersion = tls.VersionTLS13
default:
config.MinVersion = tls.VersionTLS12
}
}
// 加载证书和私钥
if tlsConfig.CertFile != "" && tlsConfig.KeyFile != "" {
cert, err := tls.LoadX509KeyPair(tlsConfig.CertFile, tlsConfig.KeyFile)
if err != nil {
return nil, fmt.Errorf("加载证书失败: %v", err)
}
config.Certificates = []tls.Certificate{cert}
}
// 加载CA证书
if tlsConfig.CAFile != "" {
caCert, err := os.ReadFile(tlsConfig.CAFile)
if err != nil {
return nil, fmt.Errorf("读取CA证书失败: %v", err)
}
caCertPool := x509.NewCertPool()
if !caCertPool.AppendCertsFromPEM(caCert) {
return nil, fmt.Errorf("解析CA证书失败")
}
config.RootCAs = caCertPool
}
return config, nil
}
// ProtocolBenchmark 协议性能基准测试
type ProtocolBenchmark struct {
factory *TransportFactory
}
func NewProtocolBenchmark() *ProtocolBenchmark {
return &ProtocolBenchmark{
factory: NewTransportFactory(),
}
}
func (pb *ProtocolBenchmark) BenchmarkProtocols() error {
// 注册各种协议配置
pb.factory.RegisterProtocol("http", &ProtocolConfig{
Protocol: "http",
Address: "localhost:8080",
Timeout: 30 * time.Second,
})
pb.factory.RegisterProtocol("https", &ProtocolConfig{
Protocol: "https",
Address: "localhost:8443",
Timeout: 30 * time.Second,
TLS: &TLSConfig{
Enabled: true,
SkipVerify: true,
},
})
pb.factory.RegisterProtocol("grpc", &ProtocolConfig{
Protocol: "grpc",
Address: "localhost:9090",
Timeout: 30 * time.Second,
})
// 运行基准测试
protocols := []string{"http", "https", "grpc"}
for _, protocol := range protocols {
if err := pb.benchmarkProtocol(protocol); err != nil {
fmt.Printf("协议 %s 基准测试失败: %v\n", protocol, err)
}
}
return nil
}
func (pb *ProtocolBenchmark) benchmarkProtocol(protocol string) error {
fmt.Printf("开始协议 %s 基准测试\n", protocol)
// 创建传输层
tp, err := pb.factory.CreateTransport(protocol)
if err != nil {
return fmt.Errorf("创建传输层失败: %v", err)
}
// 测试连接建立时间
connectionTimes := make([]time.Duration, 100)
for i := 0; i < 100; i++ {
start := time.Now()
client, err := tp.Dial("localhost:8080")
connectionTimes[i] = time.Since(start)
if client != nil {
client.Close()
}
if err != nil {
fmt.Printf("连接失败: %v\n", err)
continue
}
}
// 计算统计数据
var totalTime time.Duration
var minTime, maxTime time.Duration = connectionTimes[0], connectionTimes[0]
for _, t := range connectionTimes {
totalTime += t
if t < minTime {
minTime = t
}
if t > maxTime {
maxTime = t
}
}
avgTime := totalTime / time.Duration(len(connectionTimes))
fmt.Printf("协议 %s 性能统计:\n", protocol)
fmt.Printf(" 平均连接时间: %v\n", avgTime)
fmt.Printf(" 最小连接时间: %v\n", minTime)
fmt.Printf(" 最大连接时间: %v\n", maxTime)
return nil
}
// 使用示例
func ExampleTransportUsage() {
// 创建传输层工厂
factory := NewTransportFactory()
// 注册协议配置
factory.RegisterProtocol("production_http", &ProtocolConfig{
Protocol: "http",
Address: "0.0.0.0:8080",
Timeout: 30 * time.Second,
Compression: true,
KeepAlive: true,
})
factory.RegisterProtocol("production_https", &ProtocolConfig{
Protocol: "https",
Address: "0.0.0.0:8443",
Timeout: 30 * time.Second,
Compression: true,
KeepAlive: true,
TLS: &TLSConfig{
Enabled: true,
CertFile: "/path/to/cert.pem",
KeyFile: "/path/to/key.pem",
CAFile: "/path/to/ca.pem",
MinVersion: "1.2",
},
})
factory.RegisterProtocol("production_grpc", &ProtocolConfig{
Protocol: "grpc",
Address: "0.0.0.0:9090",
Timeout: 30 * time.Second,
MaxConnections: 1000,
})
// 根据环境创建传输层
environment := os.Getenv("ENVIRONMENT")
var transport transport.Transport
var err error
switch environment {
case "production":
transport, err = factory.CreateTransport("production_https")
case "development":
transport, err = factory.CreateTransport("production_http")
case "testing":
transport, err = factory.CreateTransport("production_grpc")
default:
transport, err = transport.NewHTTPTransport()
}
if err != nil {
fmt.Printf("创建传输层失败: %v\n", err)
return
}
fmt.Printf("创建传输层成功: %s\n", transport.String())
// 运行性能测试
benchmark := NewProtocolBenchmark()
if err := benchmark.BenchmarkProtocols(); err != nil {
fmt.Printf("性能测试失败: %v\n", err)
}
}
---
03.传输层高级特性
a.连接池管理
实现智能连接池管理,支持连接复用、健康检查、自动扩缩容等功能。减少连接建立和销毁的开销,提高性能。
b.压缩支持
支持数据压缩传输,减少网络传输量。可以在传输层透明地处理数据的压缩和解压缩。
c.安全传输
支持TLS/SSL加密传输,提供双向认证、证书验证等安全特性。确保数据传输的机密性和完整性。
2.7 附:组件协同机制
01.组件间通信架构
a.通信模式
go-micro的各组件通过明确的接口进行交互,形成松耦合的架构。Service作为协调者,统一管理Client、Server、Registry、Transport等组件的生命周期和交互。
b.数据流分析
a.请求处理流程
客户端请求从Client组件开始,经过服务发现(Registry)、服务选择(Selector)、连接建立(Transport)、数据编码(Codec),最终到达Server组件处理。
b.响应处理流程
响应数据按照相反的路径返回,从Server经过编码、传输,到达Client的响应处理逻辑。
c.代码示例
---
// 组件协同机制详细实现
package coordination
import (
"context"
"fmt"
"sync"
"time"
"github.com/micro/go-micro/v2"
"github.com/micro/go-micro/v2/client"
"github.com/micro/go-micro/v2/codec"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/selector"
"github.com/micro/go-micro/v2/server"
"github.com/micro/go-micro/v2/transport"
)
// ComponentCoordinator 组件协调器
type ComponentCoordinator struct {
mu sync.RWMutex
// 核心组件
service micro.Service
client client.Client
server server.Server
registry registry.Registry
selector selector.Selector
codec codec.Codec
transport transport.Transport
// 协调配置
config *CoordinationConfig
// 监控和统计
monitor *CoordinationMonitor
// 事件总线
eventBus *EventBus
// 生命周期状态
state CoordinatorState
}
// CoordinationConfig 协调配置
type CoordinationConfig struct {
// 组件发现配置
AutoDiscoverComponents bool `json:"auto_discover_components"`
ComponentHealthCheck time.Duration `json:"component_health_check"`
// 负载均衡配置
LoadBalanceStrategy string `json:"load_balance_strategy"`
RetryPolicy string `json:"retry_policy"`
// 监控配置
EnableMonitoring bool `json:"enable_monitoring"`
MetricsInterval time.Duration `json:"metrics_interval"`
HealthCheckInterval time.Duration `json:"health_check_interval"`
// 容错配置
EnableCircuitBreaker bool `json:"enable_circuit_breaker"`
EnableRetry bool `json:"enable_retry"`
MaxRetries int `json:"max_retries"`
RetryBackoff string `json:"retry_backoff"`
// 性能优化配置
EnableConnectionPool bool `json:"enable_connection_pool"`
MaxConnections int `json:"max_connections"`
ConnectionTimeout time.Duration `json:"connection_timeout"`
}
// CoordinatorState 协调器状态
type CoordinatorState int
const (
StateUninitialized CoordinatorState = iota
StateInitializing
StateReady
StateRunning
StateStopping
StateStopped
StateError
)
// CoordinationMonitor 协调监控器
type CoordinationMonitor struct {
mu sync.RWMutex
// 组件健康状态
componentHealth map[string]*ComponentHealth
// 性能指标
metrics *CoordinationMetrics
// 告警规则
alertRules []*AlertRule
// 事件处理器
eventHandlers []EventHandler
}
// ComponentHealth 组件健康状态
type ComponentHealth struct {
Name string `json:"name"`
Status HealthStatus `json:"status"`
LastCheck time.Time `json:"last_check"`
ResponseTime time.Duration `json:"response_time"`
ErrorCount int64 `json:"error_count"`
Uptime time.Duration `json:"uptime"`
Details map[string]interface{} `json:"details"`
}
type HealthStatus string
const (
StatusHealthy HealthStatus = "healthy"
StatusUnhealthy HealthStatus = "unhealthy"
StatusUnknown HealthStatus = "unknown"
)
// CoordinationMetrics 协调指标
type CoordinationMetrics struct {
// 请求指标
TotalRequests int64 `json:"total_requests"`
SuccessfulRequests int64 `json:"successful_requests"`
FailedRequests int64 `json:"failed_requests"`
AverageLatency time.Duration `json:"average_latency"`
// 组件指标
ComponentMetrics map[string]*ComponentMetrics `json:"component_metrics"`
// 系统指标
SystemMetrics *SystemMetrics `json:"system_metrics"`
}
// ComponentMetrics 组件指标
type ComponentMetrics struct {
Name string `json:"name"`
Type string `json:"type"`
RequestCount int64 `json:"request_count"`
ErrorCount int64 `json:"error_count"`
AverageLatency time.Duration `json:"average_latency"`
LastUsed time.Time `json:"last_used"`
Connections int64 `json:"connections"`
MemoryUsage int64 `json:"memory_usage"`
}
// SystemMetrics 系统指标
type SystemMetrics struct {
CPUUsage float64 `json:"cpu_usage"`
MemoryUsage int64 `json:"memory_usage"`
GoroutineCount int `json:"goroutine_count"`
HeapSize int64 `json:"heap_size"`
GCPauses int64 `json:"gc_pauses"`
}
// EventBus 事件总线
type EventBus struct {
mu sync.RWMutex
topics map[string][]EventHandler
}
type EventHandler func(*Event)
type Event struct {
Type string `json:"type"`
Source string `json:"source"`
Timestamp time.Time `json:"timestamp"`
Data map[string]interface{} `json:"data"`
}
// AlertRule 告警规则
type AlertRule struct {
Name string `json:"name"`
Condition string `json:"condition"`
Threshold float64 `json:"threshold"`
Component string `json:"component"`
Metric string `json:"metric"`
Operator string `json:"operator"`
Enabled bool `json:"enabled"`
Severity string `json:"severity"`
Description string `json:"description"`
}
// NewComponentCoordinator 创建组件协调器
func NewComponentCoordinator(service micro.Service, config *CoordinationConfig) *ComponentCoordinator {
coordinator := &ComponentCoordinator{
service: service,
client: service.Client(),
server: service.Server(),
registry: service.Options().Registry,
selector: service.Options().Selector,
codec: service.Options().Codec,
transport: service.Options().Transport,
config: config,
state: StateUninitialized,
eventBus: NewEventBus(),
monitor: NewCoordinationMonitor(),
}
return coordinator
}
// Initialize 初始化协调器
func (cc *ComponentCoordinator) Initialize() error {
cc.mu.Lock()
defer cc.mu.Unlock()
if cc.state != StateUninitialized {
return fmt.Errorf("协调器已初始化,当前状态: %v", cc.state)
}
cc.setState(StateInitializing)
// 初始化组件监控
if err := cc.initializeMonitoring(); err != nil {
cc.setState(StateError)
return fmt.Errorf("初始化监控失败: %v", err)
}
// 初始化组件健康检查
if err := cc.initializeHealthChecks(); err != nil {
cc.setState(StateError)
return fmt.Errorf("初始化健康检查失败: %v", err)
}
// 初始化事件处理器
if err := cc.initializeEventHandlers(); err != nil {
cc.setState(StateError)
return fmt.Errorf("初始化事件处理器失败: %v", err)
}
// 初始化容错机制
if err := cc.initializeFaultTolerance(); err != nil {
cc.setState(StateError)
return fmt.Errorf("初始化容错机制失败: %v", err)
}
// 初始化性能优化
if err := cc.initializePerformanceOptimization(); err != nil {
cc.setState(StateError)
return fmt.Errorf("初始化性能优化失败: %v", err)
}
cc.setState(StateReady)
return nil
}
// Start 启动协调器
func (cc *ComponentCoordinator) Start() error {
cc.mu.Lock()
defer cc.mu.Unlock()
if cc.state != StateReady {
return fmt.Errorf("协调器未就绪,当前状态: %v", cc.state)
}
cc.setState(StateRunning)
// 启动监控
if cc.config.EnableMonitoring {
go cc.startMonitoring()
}
// 启动健康检查
go cc.startHealthChecks()
// 启动事件处理
go cc.startEventProcessing()
// 发布启动事件
cc.publishEvent("coordinator.started", map[string]interface{}{
"timestamp": time.Now(),
"config": cc.config,
})
return nil
}
// Stop 停止协调器
func (cc *ComponentCoordinator) Stop() error {
cc.mu.Lock()
defer cc.mu.Unlock()
if cc.state != StateRunning {
return nil
}
cc.setState(StateStopping)
// 发布停止事件
cc.publishEvent("coordinator.stopping", map[string]interface{}{
"timestamp": time.Now(),
})
// 清理资源
cc.cleanup()
cc.setState(StateStopped)
return nil
}
// ProcessRequest 处理请求(展示组件协同)
func (cc *ComponentCoordinator) ProcessRequest(ctx context.Context, req *Request) (*Response, error) {
start := time.Now()
requestID := generateRequestID()
// 发布请求开始事件
cc.publishEvent("request.started", map[string]interface{}{
"request_id": requestID,
"service": req.Service,
"method": req.Method,
"timestamp": start,
})
// 1. 服务发现和选择
node, err := cc.selectServiceNode(req.Service)
if err != nil {
cc.publishEvent("request.service_discovery_failed", map[string]interface{}{
"request_id": requestID,
"error": err.Error(),
})
return nil, fmt.Errorf("服务发现失败: %v", err)
}
// 2. 建立连接
conn, err := cc.establishConnection(node)
if err != nil {
cc.publishEvent("request.connection_failed", map[string]interface{}{
"request_id": requestID,
"node": node.Address,
"error": err.Error(),
})
return nil, fmt.Errorf("建立连接失败: %v", err)
}
defer conn.Close()
// 3. 编码请求
encodedReq, err := cc.encodeRequest(req)
if err != nil {
cc.publishEvent("request.encoding_failed", map[string]interface{}{
"request_id": requestID,
"error": err.Error(),
})
return nil, fmt.Errorf("编码请求失败: %v", err)
}
// 4. 发送请求
if err := cc.sendRequest(conn, encodedReq); err != nil {
cc.publishEvent("request.send_failed", map[string]interface{}{
"request_id": requestID,
"error": err.Error(),
})
return nil, fmt.Errorf("发送请求失败: %v", err)
}
// 5. 接收响应
encodedResp, err := cc.receiveResponse(conn)
if err != nil {
cc.publishEvent("request.receive_failed", map[string]interface{}{
"request_id": requestID,
"error": err.Error(),
})
return nil, fmt.Errorf("接收响应失败: %v", err)
}
// 6. 解码响应
response, err := cc.decodeResponse(encodedResp)
if err != nil {
cc.publishEvent("request.decoding_failed", map[string]interface{}{
"request_id": requestID,
"error": err.Error(),
})
return nil, fmt.Errorf("解码响应失败: %v", err)
}
// 更新指标
duration := time.Since(start)
cc.updateMetrics(req.Service, duration, nil)
// 发布请求完成事件
cc.publishEvent("request.completed", map[string]interface{}{
"request_id": requestID,
"duration": duration,
"success": true,
})
return response, nil
}
// selectServiceNode 选择服务节点
func (cc *ComponentCoordinator) selectServiceNode(serviceName string) (*registry.Node, error) {
// 使用Selector组件选择服务节点
next, err := cc.selector.Select(serviceName)
if err != nil {
return nil, err
}
// 获取节点
node, err := next()
if err != nil {
return nil, err
}
return node, nil
}
// establishConnection 建立连接
func (cc *ComponentCoordinator) establishConnection(node *registry.Node) (transport.Client, error) {
// 使用Transport组件建立连接
conn, err := cc.transport.Dial(node.Address,
transport.WithTimeout(cc.config.ConnectionTimeout),
)
if err != nil {
return nil, err
}
return conn, nil
}
// encodeRequest 编码请求
func (cc *ComponentCoordinator) encodeRequest(req *Request) ([]byte, error) {
// 使用Codec组件编码请求
data, err := cc.codec.Marshal(req)
if err != nil {
return nil, err
}
return data, nil
}
// decodeResponse 解码响应
func (cc *ComponentCoordinator) decodeResponse(data []byte) (*Response, error) {
// 使用Codec组件解码响应
var response Response
err := cc.codec.Unmarshal(data, &response)
if err != nil {
return nil, err
}
return &response, nil
}
// sendRequest 发送请求
func (cc *ComponentCoordinator) sendRequest(conn transport.Client, data []byte) error {
msg := &transport.Message{
Header: map[string]string{
"Content-Type": "application/json",
"X-Request-ID": generateRequestID(),
},
Body: data,
}
return conn.Send(msg)
}
// receiveResponse 接收响应
func (cc *ComponentCoordinator) receiveResponse(conn transport.Client) ([]byte, error) {
var msg transport.Message
if err := conn.Recv(&msg); err != nil {
return nil, err
}
return msg.Body, nil
}
// initializeMonitoring 初始化监控
func (cc *ComponentCoordinator) initializeMonitoring() error {
if !cc.config.EnableMonitoring {
return nil
}
// 初始化组件健康监控
cc.monitor.componentHealth = make(map[string]*ComponentHealth)
// 初始化指标收集
cc.monitor.metrics = &CoordinationMetrics{
ComponentMetrics: make(map[string]*ComponentMetrics),
SystemMetrics: &SystemMetrics{},
}
return nil
}
// initializeHealthChecks 初始化健康检查
func (cc *ComponentCoordinator) initializeHealthChecks() error {
// 注册组件健康检查
components := []string{"client", "server", "registry", "selector", "codec", "transport"}
for _, component := range components {
health := &ComponentHealth{
Name: component,
Status: StatusUnknown,
LastCheck: time.Now(),
ResponseTime: 0,
ErrorCount: 0,
Uptime: 0,
Details: make(map[string]interface{}),
}
cc.monitor.componentHealth[component] = health
}
return nil
}
// initializeEventHandlers 初始化事件处理器
func (cc *ComponentCoordinator) initializeEventHandlers() error {
// 注册默认事件处理器
cc.eventBus.Subscribe("component.error", cc.handleComponentError)
cc.eventBus.Subscribe("component.warning", cc.handleComponentWarning)
cc.eventBus.Subscribe("request.failed", cc.handleRequestFailure)
cc.eventBus.Subscribe("system.threshold_exceeded", cc.handleSystemThreshold)
return nil
}
// initializeFaultTolerance 初始化容错机制
func (cc *ComponentCoordinator) initializeFaultTolerance() error {
if cc.config.EnableCircuitBreaker {
// 初始化熔断器
if err := cc.initializeCircuitBreaker(); err != nil {
return err
}
}
if cc.config.EnableRetry {
// 初始化重试机制
if err := cc.initializeRetryPolicy(); err != nil {
return err
}
}
return nil
}
// initializePerformanceOptimization 初始化性能优化
func (cc *ComponentCoordinator) initializePerformanceOptimization() error {
if cc.config.EnableConnectionPool {
// 初始化连接池
if err := cc.initializeConnectionPool(); err != nil {
return err
}
}
return nil
}
// startMonitoring 启动监控
func (cc *ComponentCoordinator) startMonitoring() {
ticker := time.NewTicker(cc.config.MetricsInterval)
defer ticker.Stop()
for {
select {
case <-ticker.C:
cc.collectMetrics()
cc.checkAlerts()
}
}
}
// startHealthChecks 启动健康检查
func (cc *ComponentCoordinator) startHealthChecks() {
ticker := time.NewTicker(cc.config.HealthCheckInterval)
defer ticker.Stop()
for {
select {
case <-ticker.C:
cc.performHealthChecks()
}
}
}
// startEventProcessing 启动事件处理
func (cc *ComponentCoordinator) startEventProcessing() {
// 事件处理循环
for {
// 处理事件队列中的事件
time.Sleep(time.Second)
}
}
// collectMetrics 收集指标
func (cc *ComponentCoordinator) collectMetrics() {
// 收集系统指标
cc.collectSystemMetrics()
// 收集组件指标
cc.collectComponentMetrics()
// 发布指标事件
cc.publishEvent("metrics.collected", map[string]interface{}{
"timestamp": time.Now(),
"metrics": cc.monitor.metrics,
})
}
// performHealthChecks 执行健康检查
func (cc *ComponentCoordinator) performHealthChecks() {
cc.mu.RLock()
defer cc.mu.RUnlock()
for component, health := range cc.monitor.componentHealth {
start := time.Now()
// 执行健康检查
status, err := cc.checkComponentHealth(component)
responseTime := time.Since(start)
health.LastCheck = time.Now()
health.ResponseTime = responseTime
if err != nil {
health.Status = StatusUnhealthy
health.ErrorCount++
health.Details["last_error"] = err.Error()
cc.publishEvent("component.unhealthy", map[string]interface{}{
"component": component,
"error": err.Error(),
})
} else {
health.Status = status
health.Details["last_check"] = "success"
}
// 更新运行时间
if health.Uptime == 0 {
health.Uptime = responseTime
} else {
health.Uptime += responseTime
}
}
}
// checkComponentHealth 检查组件健康状态
func (cc *ComponentCoordinator) checkComponentHealth(component string) (HealthStatus, error) {
switch component {
case "client":
return cc.checkClientHealth()
case "server":
return cc.checkServerHealth()
case "registry":
return cc.checkRegistryHealth()
case "selector":
return cc.checkSelectorHealth()
case "codec":
return cc.checkCodecHealth()
case "transport":
return cc.checkTransportHealth()
default:
return StatusUnknown, fmt.Errorf("未知组件: %s", component)
}
}
// 各种组件健康检查方法
func (cc *ComponentCoordinator) checkClientHealth() (HealthStatus, error) {
// 检查客户端组件健康状态
if cc.client == nil {
return StatusUnhealthy, fmt.Errorf("客户端未初始化")
}
// 执行简单的健康检查请求
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// 创建测试请求
req := cc.client.NewRequest("health.service", "Health.Check", map[string]interface{}{})
var rsp map[string]interface{}
err := cc.client.Call(ctx, req, &rsp)
if err != nil {
return StatusUnhealthy, err
}
return StatusHealthy, nil
}
func (cc *ComponentCoordinator) checkServerHealth() (HealthStatus, error) {
// 检查服务端组件健康状态
if cc.server == nil {
return StatusUnhealthy, fmt.Errorf("服务端未初始化")
}
// 检查服务端是否正在运行
options := cc.server.Options()
if options.Address == "" {
return StatusUnhealthy, fmt.Errorf("服务端地址未配置")
}
return StatusHealthy, nil
}
func (cc *ComponentCoordinator) checkRegistryHealth() (HealthStatus, error) {
// 检查注册中心健康状态
if cc.registry == nil {
return StatusUnhealthy, fmt.Errorf("注册中心未初始化")
}
// 尝试获取服务列表
services, err := cc.registry.ListServices()
if err != nil {
return StatusUnhealthy, err
}
if len(services) == 0 {
return StatusHealthy, fmt.Errorf("注册中心无服务")
}
return StatusHealthy, nil
}
func (cc *ComponentCoordinator) checkSelectorHealth() (HealthStatus, error) {
// 检查选择器健康状态
if cc.selector == nil {
return StatusUnhealthy, fmt.Errorf("选择器未初始化")
}
return StatusHealthy, nil
}
func (cc *ComponentCoordinator) checkCodecHealth() (HealthStatus, error) {
// 检查编解码器健康状态
if cc.codec == nil {
return StatusUnhealthy, fmt.Errorf("编解码器未初始化")
}
// 测试编码解码
testData := map[string]interface{}{"test": "health_check"}
data, err := cc.codec.Marshal(testData)
if err != nil {
return StatusUnhealthy, err
}
var result map[string]interface{}
err = cc.codec.Unmarshal(data, &result)
if err != nil {
return StatusUnhealthy, err
}
return StatusHealthy, nil
}
func (cc *ComponentCoordinator) checkTransportHealth() (HealthStatus, error) {
// 检查传输层健康状态
if cc.transport == nil {
return StatusUnhealthy, fmt.Errorf("传输层未初始化")
}
return StatusHealthy, nil
}
// 事件处理器
func (cc *ComponentCoordinator) handleComponentError(event *Event) {
fmt.Printf("组件错误事件: %+v\n", event)
}
func (cc *ComponentCoordinator) handleComponentWarning(event *Event) {
fmt.Printf("组件警告事件: %+v\n", event)
}
func (cc *ComponentCoordinator) handleRequestFailure(event *Event) {
fmt.Printf("请求失败事件: %+v\n", event)
}
func (cc *ComponentCoordinator) handleSystemThreshold(event *Event) {
fmt.Printf("系统阈值超限事件: %+v\n", event)
}
// publishEvent 发布事件
func (cc *ComponentCoordinator) publishEvent(eventType string, data map[string]interface{}) {
event := &Event{
Type: eventType,
Source: "coordinator",
Timestamp: time.Now(),
Data: data,
}
cc.eventBus.Publish(eventType, event)
}
// setState 设置状态
func (cc *ComponentCoordinator) setState(state CoordinatorState) {
oldState := cc.state
cc.state = state
fmt.Printf("协调器状态变更: %v -> %v\n", oldState, state)
cc.publishEvent("coordinator.state_changed", map[string]interface{}{
"old_state": oldState,
"new_state": state,
"timestamp": time.Now(),
})
}
// cleanup 清理资源
func (cc *ComponentCoordinator) cleanup() {
// 清理连接池
// 清理监控资源
// 清理事件处理器
}
// NewCoordinationMonitor 创建协调监控器
func NewCoordinationMonitor() *CoordinationMonitor {
return &CoordinationMonitor{
componentHealth: make(map[string]*ComponentHealth),
metrics: &CoordinationMetrics{
ComponentMetrics: make(map[string]*ComponentMetrics),
SystemMetrics: &SystemMetrics{},
},
alertRules: make([]*AlertRule, 0),
eventHandlers: make([]EventHandler, 0),
}
}
// NewEventBus 创建事件总线
func NewEventBus() *EventBus {
return &EventBus{
topics: make(map[string][]EventHandler),
}
}
func (eb *EventBus) Subscribe(topic string, handler EventHandler) {
eb.mu.Lock()
defer eb.mu.Unlock()
if eb.topics[topic] == nil {
eb.topics[topic] = make([]EventHandler, 0)
}
eb.topics[topic] = append(eb.topics[topic], handler)
}
func (eb *EventBus) Publish(topic string, event *Event) {
eb.mu.RLock()
handlers := eb.topics[topic]
eb.mu.RUnlock()
for _, handler := range handlers {
go handler(event)
}
}
// 辅助函数
func generateRequestID() string {
return fmt.Sprintf("%d", time.Now().UnixNano())
}
// 请求数据结构
type Request struct {
Service string `json:"service"`
Method string `json:"method"`
Data map[string]interface{} `json:"data"`
Headers map[string]string `json:"headers"`
}
// 响应数据结构
type Response struct {
Data interface{} `json:"data"`
Error string `json:"error"`
Headers map[string]string `json:"headers"`
Code int `json:"code"`
}
---
3 服务发现与注册
3.1 Registry注册中心
01.Registry接口定义
a.核心功能
Registry是go-micro的服务注册中心组件,负责服务的注册、发现和管理。它维护了所有可用服务的信息,是微服务架构的核心基础设施。Registry提供了统一的服务接口,支持多种注册中心实现。
b.接口方法
Register()方法注册服务实例,Deregister()方法注销服务实例,GetService()方法根据服务名称获取服务信息,ListServices()方法列出所有服务。
Watch()方法监听服务变化事件,支持实时获取服务状态变化。Registry接口提供了服务生命周期的完整管理能力。
c.代码示例
---
// Registry接口详细实现
package registry
import (
"context"
"fmt"
"sync"
"time"
"github.com/micro/go-micro/v2/registry"
)
// microRegistry Registry接口的具体实现
type microRegistry struct {
opts registry.Options
mu sync.RWMutex
// 服务存储
services map[string]*registry.Service
watchers map[string][]registry.Watcher
// 监控统计
stats *RegistryStats
// 事件通道
eventChan chan *RegistryEvent
// 运行状态
running bool
ctx context.Context
cancel context.CancelFunc
}
// RegistryStats 注册中心统计信息
type RegistryStats struct {
TotalRegistrations int64 `json:"total_registrations"`
TotalDeregistrations int64 `json:"total_deregistrations"`
TotalQueries int64 `json:"total_queries"`
ActiveServices int64 `json:"active_services"`
ActiveNodes int64 `json:"active_nodes"`
AverageLatency time.Duration `json:"average_latency"`
ErrorCount int64 `json:"error_count"`
mu sync.RWMutex
}
// RegistryEvent 注册中心事件
type RegistryEvent struct {
Type EventType `json:"type"`
Service *registry.Service `json:"service"`
Timestamp time.Time `json:"timestamp"`
Source string `json:"source"`
}
type EventType string
const (
EventTypeRegister EventType = "register"
EventTypeDeregister EventType = "deregister"
EventTypeUpdate EventType = "update"
)
// NewRegistry 创建新的注册中心实例
func NewRegistry(opts ...registry.Option) registry.Registry {
options := registry.NewOptions()
for _, o := range opts {
o(&options)
}
ctx, cancel := context.WithCancel(context.Background())
return µRegistry{
opts: options,
services: make(map[string]*registry.Service),
watchers: make(map[string][]registry.Watcher),
stats: &RegistryStats{},
eventChan: make(chan *RegistryEvent, 1000),
running: false,
ctx: ctx,
cancel: cancel,
}
}
// Init 初始化注册中心
func (r *microRegistry) Init(opts ...registry.Option) error {
r.mu.Lock()
defer r.mu.Unlock()
for _, o := range opts {
o(&r.opts)
}
return nil
}
// Options 获取注册中心选项
func (r *microRegistry) Options() registry.Options {
r.mu.RLock()
defer r.mu.RUnlock()
return r.opts
}
// Register 注册服务
func (r *microRegistry) Register(service *registry.Service, opts ...registry.RegisterOption) error {
start := time.Now()
defer func() {
r.recordQueryTime(time.Since(start))
}()
// 创建默认注册选项
options := registry.RegisterOptions{
TTL: r.opts.TTL,
}
// 应用注册选项
for _, o := range opts {
o(&options)
}
r.mu.Lock()
defer r.mu.Unlock()
// 验证服务信息
if err := r.validateService(service); err != nil {
r.recordError()
return fmt.Errorf("服务验证失败: %v", err)
}
// 生成服务ID
serviceID := r.generateServiceID(service)
// 检查服务是否已存在
existingService, exists := r.services[serviceID]
if exists {
// 更新现有服务
updatedService := r.mergeService(existingService, service)
r.services[serviceID] = updatedService
// 发布更新事件
r.publishEvent(&RegistryEvent{
Type: EventTypeUpdate,
Service: updatedService,
Timestamp: time.Now(),
Source: "registry",
})
} else {
// 注册新服务
r.services[serviceID] = r.copyService(service)
// 发布注册事件
r.publishEvent(&RegistryEvent{
Type: EventTypeRegister,
Service: r.copyService(service),
Timestamp: time.Now(),
Source: "registry",
})
// 更新统计信息
r.updateStats()
}
// 如果设置了TTL,启动TTL管理
if options.TTL > 0 {
r.startTTLManager(serviceID, options.TTL)
}
return nil
}
// Deregister 注销服务
func (r *microRegistry) Deregister(service *registry.Service, opts ...registry.DeregisterOption) error {
start := time.Now()
defer func() {
r.recordQueryTime(time.Since(start))
}()
r.mu.Lock()
defer r.mu.Unlock()
// 生成服务ID
serviceID := r.generateServiceID(service)
// 检查服务是否存在
if _, exists := r.services[serviceID]; !exists {
r.recordError()
return fmt.Errorf("服务不存在: %s", serviceID)
}
// 获取服务信息用于事件发布
existingService := r.copyService(r.services[serviceID])
// 注销服务
delete(r.services, serviceID)
// 发布注销事件
r.publishEvent(&RegistryEvent{
Type: EventTypeDeregister,
Service: existingService,
Timestamp: time.Now(),
Source: "registry",
})
// 更新统计信息
r.updateStats()
return nil
}
// GetService 获取服务信息
func (r *microRegistry) GetService(name string) ([]*registry.Service, error) {
start := time.Now()
defer func() {
r.recordQueryTime(time.Since(start))
}()
r.mu.RLock()
defer r.mu.RUnlock()
if name == "" {
r.recordError()
return nil, fmt.Errorf("服务名称不能为空")
}
var services []*registry.Service
// 查找匹配的服务
for _, service := range r.services {
if service.Name == name {
services = append(services, r.copyService(service))
}
}
if len(services) == 0 {
r.recordError()
return nil, registry.ErrNotFound
}
return services, nil
}
// ListServices 列出所有服务
func (r *microRegistry) ListServices() ([]*registry.Service, error) {
start := time.Now()
defer func() {
r.recordQueryTime(time.Since(start))
}()
r.mu.RLock()
defer r.mu.RUnlock()
services := make([]*registry.Service, 0, len(r.services))
for _, service := range r.services {
services = append(services, r.copyService(service))
}
return services, nil
}
// Watch 监听服务变化
func (r *microRegistry) Watch(opts ...registry.WatchOption) (registry.Watcher, error) {
// 创建默认监听选项
options := registry.WatchOptions{
Service: "*",
}
// 应用监听选项
for _, o := range opts {
o(&options)
}
// 创建监听器
watcher := ®istryWatcher{
service: options.Service,
registry: r,
events: make(chan *registry.Result, 100),
exit: make(chan struct{}),
}
r.mu.Lock()
r.watchers[options.Service] = append(r.watchers[options.Service], watcher)
r.mu.Unlock()
return watcher, nil
}
// String 返回注册中心名称
func (r *microRegistry) String() string {
return "memory"
}
// validateService 验证服务信息
func (r *microRegistry) validateService(service *registry.Service) error {
if service == nil {
return fmt.Errorf("服务不能为空")
}
if service.Name == "" {
return fmt.Errorf("服务名称不能为空")
}
if service.Nodes == nil || len(service.Nodes) == 0 {
return fmt.Errorf("服务节点不能为空")
}
for _, node := range service.Nodes {
if node.Id == "" {
return fmt.Errorf("节点ID不能为空")
}
if node.Address == "" {
return fmt.Errorf("节点地址不能为空")
}
}
return nil
}
// generateServiceID 生成服务ID
func (r *microRegistry) generateServiceID(service *registry.Service) string {
return fmt.Sprintf("%s:%s", service.Name, service.Version)
}
// mergeService 合并服务信息
func (r *microRegistry) mergeService(existing, new *registry.Service) *registry.Service {
merged := r.copyService(existing)
// 合并元数据
if new.Metadata != nil {
if merged.Metadata == nil {
merged.Metadata = make(map[string]string)
}
for k, v := range new.Metadata {
merged.Metadata[k] = v
}
}
// 合并节点信息
existingNodes := make(map[string]*registry.Node)
for _, node := range merged.Nodes {
existingNodes[node.Id] = node
}
// 添加新节点或更新现有节点
for _, newNode := range new.Nodes {
existingNodes[newNode.Id] = newNode
}
// 重建节点列表
merged.Nodes = make([]*registry.Node, 0, len(existingNodes))
for _, node := range existingNodes {
merged.Nodes = append(merged.Nodes, node)
}
return merged
}
// copyService 复制服务信息
func (r *microRegistry) copyService(service *registry.Service) *registry.Service {
if service == nil {
return nil
}
copy := ®istry.Service{
Name: service.Name,
Version: service.Version,
Metadata: make(map[string]string),
}
// 复制元数据
if service.Metadata != nil {
for k, v := range service.Metadata {
copy.Metadata[k] = v
}
}
// 复制节点
copy.Nodes = make([]*registry.Node, len(service.Nodes))
for i, node := range service.Nodes {
copy.Nodes[i] = ®istry.Node{
Id: node.Id,
Address: node.Address,
Metadata: make(map[string]string),
}
// 复制节点元数据
if node.Metadata != nil {
for k, v := range node.Metadata {
copy.Nodes[i].Metadata[k] = v
}
}
}
return copy
}
// publishEvent 发布事件
func (r *microRegistry) publishEvent(event *RegistryEvent) {
select {
case r.eventChan <- event:
default:
// 事件通道已满,丢弃事件
r.recordError()
}
// 通知监听器
r.notifyWatchers(event)
}
// notifyWatchers 通知监听器
func (r *microRegistry) notifyWatchers(event *RegistryEvent) {
r.mu.RLock()
defer r.mu.RUnlock()
for service, watchers := range r.watchers {
// 检查监听器是否对此服务感兴趣
if service == "*" || service == event.Service.Name {
for _, watcher := range watchers {
go func(w registry.Watcher) {
if err := w.Next(®istry.Result{
Action: r.convertEventType(event.Type),
Service: r.copyService(event.Service),
}); err != nil {
r.recordError()
}
}(watcher)
}
}
}
}
// convertEventType 转换事件类型
func (r *microRegistry) convertEventType(eventType EventType) string {
switch eventType {
case EventTypeRegister:
return "create"
case EventTypeDeregister:
return "delete"
case EventTypeUpdate:
return "update"
default:
return "unknown"
}
}
// startTTLManager 启动TTL管理器
func (r *microRegistry) startTTLManager(serviceID string, ttl time.Duration) {
go func() {
timer := time.NewTimer(ttl)
defer timer.Stop()
select {
case <-timer.C:
r.mu.Lock()
if service, exists := r.services[serviceID]; exists {
// TTL过期,自动注销服务
delete(r.services, serviceID)
// 发布注销事件
r.publishEvent(&RegistryEvent{
Type: EventTypeDeregister,
Service: service,
Timestamp: time.Now(),
Source: "ttl_manager",
})
}
r.mu.Unlock()
case <-r.ctx.Done():
return
}
}()
}
// recordQueryTime 记录查询时间
func (r *microRegistry) recordQueryTime(duration time.Duration) {
r.stats.mu.Lock()
defer r.stats.mu.Unlock()
r.stats.TotalQueries++
// 简单计算平均延迟
totalQueries := r.stats.TotalQueries
currentAvg := r.stats.AverageLatency
r.stats.AverageLatency = time.Duration(
(int64(currentAvg)*(totalQueries-1) + int64(duration)) / totalQueries,
)
}
// recordError 记录错误
func (r *microRegistry) recordError() {
r.stats.mu.Lock()
defer r.stats.mu.Unlock()
r.stats.ErrorCount++
}
// updateStats 更新统计信息
func (r *microRegistry) updateStats() {
r.stats.mu.Lock()
defer r.stats.mu.Unlock()
// 计算活跃服务数
r.stats.ActiveServices = int64(len(r.services))
// 计算活跃节点数
var totalNodes int64
for _, service := range r.services {
totalNodes += int64(len(service.Nodes))
}
r.stats.ActiveNodes = totalNodes
}
// GetStats 获取统计信息
func (r *microRegistry) GetStats() *RegistryStats {
r.stats.mu.RLock()
defer r.stats.mu.RUnlock()
return &RegistryStats{
TotalRegistrations: r.stats.TotalRegistrations,
TotalDeregistrations: r.stats.TotalDeregistrations,
TotalQueries: r.stats.TotalQueries,
ActiveServices: r.stats.ActiveServices,
ActiveNodes: r.stats.ActiveNodes,
AverageLatency: r.stats.AverageLatency,
ErrorCount: r.stats.ErrorCount,
}
}
// registryWatcher 注册中心监听器
type registryWatcher struct {
service string
registry *microRegistry
events chan *registry.Result
exit chan struct{}
mu sync.Mutex
closed bool
}
func (w *registryWatcher) Next() (*registry.Result, error) {
select {
case event := <-w.events:
return event, nil
case <-w.exit:
return nil, registry.ErrWatcherStopped
}
}
func (w *registryWatcher) Stop() {
w.mu.Lock()
defer w.mu.Unlock()
if w.closed {
return
}
w.closed = true
close(w.exit)
// 从注册中心移除监听器
w.registry.mu.Lock()
defer w.registry.mu.Unlock()
watchers := w.registry.watchers[w.service]
for i, watcher := range watchers {
if watcher == w {
w.registry.watchers[w.service] = append(
watchers[:i],
watchers[i+1:]...,
)
break
}
}
}
---
02.服务注册策略
a.健康检查
服务注册时可以配置健康检查机制,定期检查服务实例的健康状态。不健康的实例会被自动从服务列表中移除,确保客户端只访问可用的服务。
b.TTL机制
支持TTL(Time To Live)机制,服务实例需要定期续期以保持注册状态。超过TTL未续期的服务实例会被自动清理。
c.元数据管理
服务注册时可以携带丰富的元数据信息,包括版本、环境、权重、区域等。这些信息可以用于服务选择和负载均衡策略。
d.代码示例
---
// 服务注册策略示例
package registration
import (
"context"
"fmt"
"time"
"github.com/micro/go-micro/v2/registry"
)
// ServiceRegistrationStrategy 服务注册策略
type ServiceRegistrationStrategy struct {
registry registry.Registry
serviceName string
version string
nodeID string
address string
metadata map[string]string
// 健康检查配置
healthCheck *HealthCheckConfig
// TTL配置
ttl time.Duration
// 重试配置
retryConfig *RetryConfig
// 注册状态
registered bool
ticker *time.Ticker
stopChan chan struct{}
mu sync.RWMutex
}
// HealthCheckConfig 健康检查配置
type HealthCheckConfig struct {
Enabled bool `json:"enabled"`
Interval time.Duration `json:"interval"`
Timeout time.Duration `json:"timeout"`
FailureThreshold int `json:"failure_threshold"`
SuccessThreshold int `json:"success_threshold"`
Endpoint string `json:"endpoint"`
ExpectedStatus int `json:"expected_status"`
CheckMethod string `json:"check_method"`
}
// RetryConfig 重试配置
type RetryConfig struct {
Enabled bool `json:"enabled"`
MaxAttempts int `json:"max_attempts"`
Backoff time.Duration `json:"backoff"`
MaxBackoff time.Duration `json:"max_backoff"`
Multiplier float64 `json:"multiplier"`
}
// NewServiceRegistrationStrategy 创建服务注册策略
func NewServiceRegistrationStrategy(
registry registry.Registry,
serviceName, version string,
opts ...RegistrationOption,
) *ServiceRegistrationStrategy {
strategy := &ServiceRegistrationStrategy{
registry: registry,
serviceName: serviceName,
version: version,
nodeID: generateNodeID(),
metadata: make(map[string]string),
healthCheck: &HealthCheckConfig{
Enabled: true,
Interval: 30 * time.Second,
Timeout: 5 * time.Second,
FailureThreshold: 3,
SuccessThreshold: 2,
Endpoint: "/health",
ExpectedStatus: 200,
CheckMethod: "GET",
},
ttl: 60 * time.Second,
retryConfig: &RetryConfig{
Enabled: true,
MaxAttempts: 3,
Backoff: 1 * time.Second,
MaxBackoff: 30 * time.Second,
Multiplier: 2.0,
},
stopChan: make(chan struct{}),
}
for _, opt := range opts {
opt(strategy)
}
return strategy
}
// RegistrationOption 注册选项
type RegistrationOption func(*ServiceRegistrationStrategy)
func WithAddress(address string) RegistrationOption {
return func(s *ServiceRegistrationStrategy) {
s.address = address
}
}
func WithNodeID(nodeID string) RegistrationOption {
return func(s *ServiceRegistrationStrategy) {
s.nodeID = nodeID
}
}
func WithMetadata(metadata map[string]string) RegistrationOption {
return func(s *ServiceRegistrationStrategy) {
for k, v := range metadata {
s.metadata[k] = v
}
}
}
func WithHealthCheck(config *HealthCheckConfig) RegistrationOption {
return func(s *ServiceRegistrationStrategy) {
s.healthCheck = config
}
}
func WithTTL(ttl time.Duration) RegistrationOption {
return func(s *ServiceRegistrationStrategy) {
s.ttl = ttl
}
}
func WithRetryConfig(config *RetryConfig) RegistrationOption {
return func(s *ServiceRegistrationStrategy) {
s.retryConfig = config
}
}
// Register 注册服务
func (s *ServiceRegistrationStrategy) Register() error {
s.mu.Lock()
defer s.mu.Unlock()
if s.registered {
return fmt.Errorf("服务已注册")
}
// 创建服务信息
service := ®istry.Service{
Name: s.serviceName,
Version: s.version,
Metadata: s.metadata,
Nodes: []*registry.Node{
{
Id: s.nodeID,
Address: s.address,
Metadata: map[string]string{
"protocol": "http",
"health_check": fmt.Sprintf("%t", s.healthCheck.Enabled),
"ttl_enabled": fmt.Sprintf("%t", s.ttl > 0),
"registered_at": time.Now().Format(time.RFC3339),
},
},
},
}
// 注册服务(带重试)
err := s.executeWithRetry(func() error {
return s.registry.Register(service, registry.RegisterTTL(s.ttl))
})
if err != nil {
return fmt.Errorf("注册服务失败: %v", err)
}
s.registered = true
// 启动健康检查
if s.healthCheck.Enabled {
go s.startHealthCheck()
}
// 启动TTL续期
if s.ttl > 0 {
go s.startTTLRenewal(service)
}
fmt.Printf("服务注册成功: %s@%s\n", s.serviceName, s.address)
return nil
}
// Deregister 注销服务
func (s *ServiceRegistrationStrategy) Deregister() error {
s.mu.Lock()
defer s.mu.Unlock()
if !s.registered {
return nil
}
// 停止后台任务
close(s.stopChan)
if s.ticker != nil {
s.ticker.Stop()
}
// 创建服务信息用于注销
service := ®istry.Service{
Name: s.serviceName,
Version: s.version,
Nodes: []*registry.Node{
{
Id: s.nodeID,
Address: s.address,
},
},
}
// 注销服务(带重试)
err := s.executeWithRetry(func() error {
return s.registry.Deregister(service)
})
if err != nil {
return fmt.Errorf("注销服务失败: %v", err)
}
s.registered = false
fmt.Printf("服务注销成功: %s@%s\n", s.serviceName, s.address)
return nil
}
// startHealthCheck 启动健康检查
func (s *ServiceRegistrationStrategy) startHealthCheck() {
ticker := time.NewTicker(s.healthCheck.Interval)
defer ticker.Stop()
failureCount := 0
successCount := 0
for {
select {
case <-ticker.C:
healthy := s.performHealthCheck()
if healthy {
successCount++
failureCount = 0
// 达到成功阈值,恢复服务状态
if successCount >= s.healthCheck.SuccessThreshold {
s.markServiceHealthy()
}
} else {
failureCount++
successCount = 0
// 达到失败阈值,标记服务为不健康
if failureCount >= s.healthCheck.FailureThreshold {
s.markServiceUnhealthy()
// 如果连续失败次数过多,考虑重新注册
if failureCount >= s.healthCheck.FailureThreshold*2 {
s.reregisterService()
failureCount = 0
}
}
}
case <-s.stopChan:
return
}
}
}
// performHealthCheck 执行健康检查
func (s *ServiceRegistrationStrategy) performHealthCheck() bool {
ctx, cancel := context.WithTimeout(context.Background(), s.healthCheck.Timeout)
defer cancel()
// 创建HTTP请求
req, err := http.NewRequest(
s.healthCheck.CheckMethod,
fmt.Sprintf("http://%s%s", s.address, s.healthCheck.Endpoint),
nil,
)
if err != nil {
fmt.Printf("创建健康检查请求失败: %v\n", err)
return false
}
// 发送请求
resp, err := http.DefaultClient.Do(req.WithContext(ctx))
if err != nil {
fmt.Printf("健康检查请求失败: %v\n", err)
return false
}
defer resp.Body.Close()
// 检查响应状态
return resp.StatusCode == s.healthCheck.ExpectedStatus
}
// markServiceHealthy 标记服务为健康
func (s *ServiceRegistrationStrategy) markServiceHealthy() {
fmt.Printf("服务健康检查通过: %s@%s\n", s.serviceName, s.address)
// 可以更新服务元数据标记健康状态
}
// markServiceUnhealthy 标记服务为不健康
func (s *ServiceRegistrationStrategy) markServiceUnhealthy() {
fmt.Printf("服务健康检查失败: %s@%s\n", s.serviceName, s.address)
// 可以更新服务元数据标记不健康状态,或者暂时从注册中心移除
}
// startTTLRenewal 启动TTL续期
func (s *ServiceRegistrationStrategy) startTTLRenewal(service *registry.Service) {
// 续期间隔为TTL的2/3
renewalInterval := s.ttl * 2 / 3
s.ticker = time.NewTicker(renewalInterval)
for {
select {
case <-s.ticker.C:
// 续期服务注册
err := s.registry.Register(service, registry.RegisterTTL(s.ttl))
if err != nil {
fmt.Printf("TTL续期失败: %v\n", err)
} else {
fmt.Printf("TTL续期成功: %s@%s\n", s.serviceName, s.address)
}
case <-s.stopChan:
return
}
}
}
// reregisterService 重新注册服务
func (s *ServiceRegistrationStrategy) reregisterService() {
fmt.Printf("尝试重新注册服务: %s@%s\n", s.serviceName, s.address)
// 先注销现有服务
service := ®istry.Service{
Name: s.serviceName,
Version: s.version,
Nodes: []*registry.Node{
{
Id: s.nodeID,
Address: s.address,
},
},
}
s.registry.Deregister(service)
// 重新注册
if err := s.registry.Register(service, registry.RegisterTTL(s.ttl)); err != nil {
fmt.Printf("重新注册服务失败: %v\n", err)
} else {
fmt.Printf("重新注册服务成功: %s@%s\n", s.serviceName, s.address)
}
}
// executeWithRetry 执行带重试的操作
func (s *ServiceRegistrationStrategy) executeWithRetry(operation func() error) error {
if !s.retryConfig.Enabled {
return operation()
}
var lastErr error
backoff := s.retryConfig.Backoff
for attempt := 1; attempt <= s.retryConfig.MaxAttempts; attempt++ {
err := operation()
if err == nil {
return nil
}
lastErr = err
fmt.Printf("操作失败(尝试 %d/%d): %v\n", attempt, s.retryConfig.MaxAttempts, err)
if attempt < s.retryConfig.MaxAttempts {
// 等待退避时间
time.Sleep(backoff)
// 计算下次退避时间
backoff = time.Duration(float64(backoff) * s.retryConfig.Multiplier)
if backoff > s.retryConfig.MaxBackoff {
backoff = s.retryConfig.MaxBackoff
}
}
}
return fmt.Errorf("操作在%d次尝试后仍然失败: %v", s.retryConfig.MaxAttempts, lastErr)
}
// IsRegistered 检查服务是否已注册
func (s *ServiceRegistrationStrategy) IsRegistered() bool {
s.mu.RLock()
defer s.mu.RUnlock()
return s.registered
}
// GetServiceInfo 获取服务信息
func (s *ServiceRegistrationStrategy) GetServiceInfo() map[string]interface{} {
s.mu.RLock()
defer s.mu.RUnlock()
return map[string]interface{}{
"service_name": s.serviceName,
"version": s.version,
"node_id": s.nodeID,
"address": s.address,
"metadata": s.metadata,
"registered": s.registered,
"health_check": s.healthCheck,
"ttl": s.ttl,
"retry_config": s.retryConfig,
}
}
// generateNodeID 生成节点ID
func generateNodeID() string {
return fmt.Sprintf("%s-%d", getHostname(), time.Now().UnixNano())
}
// getHostname 获取主机名
func getHostname() string {
hostname, _ := os.Hostname()
if hostname == "" {
hostname = "unknown"
}
return hostname
}
// 使用示例
func ExampleServiceRegistration() {
// 创建注册中心
reg := registry.NewRegistry()
// 创建服务注册策略
strategy := NewServiceRegistrationStrategy(
reg,
"user.service",
"1.0.0",
WithAddress("localhost:8080"),
WithMetadata(map[string]string{
"environment": "production",
"region": "us-west-2",
"weight": "10",
}),
WithHealthCheck(&HealthCheckConfig{
Enabled: true,
Interval: 15 * time.Second,
Timeout: 3 * time.Second,
FailureThreshold: 2,
SuccessThreshold: 1,
Endpoint: "/health",
ExpectedStatus: 200,
}),
WithTTL(90 * time.Second),
WithRetryConfig(&RetryConfig{
Enabled: true,
MaxAttempts: 5,
Backoff: 500 * time.Millisecond,
MaxBackoff: 10 * time.Second,
Multiplier: 1.5,
}),
)
// 注册服务
if err := strategy.Register(); err != nil {
fmt.Printf("注册服务失败: %v\n", err)
return
}
// 等待一段时间
time.Sleep(2 * time.Minute)
// 注销服务
if err := strategy.Deregister(); err != nil {
fmt.Printf("注销服务失败: %v\n", err)
return
}
}
---
3.2 Selector选择器
01.Selector接口定义
a.核心功能
Selector是go-micro的服务选择器组件,负责从多个服务实例中选择合适的目标。它与Registry配合工作,实现智能的负载均衡和服务选择策略。
b.接口方法
Init()方法初始化选择器配置,Options()返回当前选项。Select()方法根据服务名称选择下一个服务实例。
Mark()方法标记服务节点的调用结果,Reset()方法重置选择器状态。Close()方法清理选择器资源。
c.代码示例
---
// Selector接口详细实现
package selector
import (
"context"
"fmt"
"math/rand"
"sort"
"sync"
"time"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/selector"
)
// microSelector Selector接口的具体实现
type microSelector struct {
opts selector.Options
mu sync.RWMutex
// 服务缓存
cache map[string]*serviceCache
// 统计信息
stats *SelectorStats
// 策略实现
strategies map[string]SelectionStrategy
// 节点状态跟踪
nodeTracker *NodeTracker
}
// SelectorStats 选择器统计信息
type SelectorStats struct {
TotalSelections int64 `json:"total_selections"`
SuccessfulCalls int64 `json:"successful_calls"`
FailedCalls int64 `json:"failed_calls"`
CacheHits int64 `json:"cache_hits"`
CacheMisses int64 `json:"cache_misses"`
mu sync.RWMutex
}
// serviceCache 服务缓存
type serviceCache struct {
services []*registry.Service
nodes []*WeightedNode
lastUsed time.Time
ttl time.Duration
mu sync.RWMutex
}
// WeightedNode 带权重的节点
type WeightedNode struct {
Node *registry.Node
Weight int
LastUsed time.Time
Stats *NodeStats
mu sync.RWMutex
}
// NodeStats 节点统计信息
type NodeStats struct {
RequestCount int64 `json:"request_count"`
SuccessCount int64 `json:"success_count"`
FailureCount int64 `json:"failure_count"`
AverageLatency time.Duration `json:"average_latency"`
LastSuccess time.Time `json:"last_success"`
LastFailure time.Time `json:"last_failure"`
HealthStatus HealthStatus `json:"health_status"`
mu sync.RWMutex
}
// NodeTracker 节点跟踪器
type NodeTracker struct {
nodes map[string]*NodeStatus
mu sync.RWMutex
}
// NodeStatus 节点状态
type NodeStatus struct {
Node *registry.Node
HealthStatus HealthStatus
LastCheck time.Time
FailureCount int64
SuccessCount int64
IsCircuitOpen bool
CircuitOpenedAt time.Time
mu sync.RWMutex
}
// SelectionStrategy 选择策略接口
type SelectionStrategy interface {
Select(nodes []*WeightedNode) (*WeightedNode, error)
String() string
}
// NewSelector 创建新的选择器实例
func NewSelector(opts ...selector.Option) selector.Selector {
options := selector.NewOptions()
for _, o := range opts {
o(&options)
}
s := µSelector{
opts: options,
cache: make(map[string]*serviceCache),
stats: &SelectorStats{},
strategies: make(map[string]SelectionStrategy),
nodeTracker: NewNodeTracker(),
}
// 注册默认策略
s.registerDefaultStrategies()
return s
}
// Init 初始化选择器
func (s *microSelector) Init(opts ...selector.Option) error {
s.mu.Lock()
defer s.mu.Unlock()
for _, o := range opts {
o(&s.opts)
}
return nil
}
// Options 获取选择器选项
func (s *microSelector) Options() selector.Options {
s.mu.RLock()
defer s.mu.RUnlock()
return s.opts
}
// Select 选择服务节点
func (s *microSelector) Select(service string, opts ...selector.SelectOption) (selector.Next, error) {
// 创建默认选择选项
options := selector.SelectOptions{
Strategy: s.opts.Strategy,
}
// 应用选择选项
for _, o := range opts {
o(&options)
}
// 获取服务节点
nodes, err := s.getNodes(service)
if err != nil {
s.recordFailure()
return nil, err
}
// 过滤健康节点
healthyNodes := s.filterHealthyNodes(nodes)
if len(healthyNodes) == 0 {
s.recordFailure()
return nil, selector.ErrNotFound
}
// 应用权重策略
weightedNodes := s.applyWeights(healthyNodes, options)
// 获取选择策略
strategy := s.getStrategy(options.Strategy)
// 创建选择函数
return func() (*registry.Node, error) {
node, err := strategy.Select(weightedNodes)
if err != nil {
s.recordFailure()
return nil, err
}
// 记录使用
s.recordSelection()
node.recordUsage()
return node.Node, nil
}, nil
}
// Mark 标记节点状态
func (s *microSelector) Mark(service string, node *registry.Node, err error) {
// 更新节点跟踪器
s.nodeTracker.MarkNode(node.ID(), err)
// 更新缓存中的节点统计
s.mu.RLock()
if cache, exists := s.cache[service]; exists {
cache.mu.RLock()
for _, weightedNode := range cache.nodes {
if weightedNode.Node.ID == node.ID {
weightedNode.recordResult(err)
break
}
}
cache.mu.RUnlock()
}
s.mu.RUnlock()
if err != nil {
s.recordFailure()
} else {
s.recordSuccess()
}
}
// Reset 重置选择器状态
func (s *microSelector) Reset(service string) {
s.mu.Lock()
defer s.mu.Unlock()
delete(s.cache, service)
s.nodeTracker.Reset(service)
}
// Close 关闭选择器
func (s *microSelector) Close() error {
s.mu.Lock()
defer s.mu.Unlock()
s.cache = make(map[string]*serviceCache)
s.nodeTracker.ResetAll()
return nil
}
// String 返回选择器名称
func (s *microSelector) String() string {
return "micro"
}
// getNodes 获取服务节点
func (s *microSelector) getNodes(service string) ([]*WeightedNode, error) {
s.mu.RLock()
cache, exists := s.cache[service]
s.mu.RUnlock()
// 检查缓存
if exists && !cache.isExpired() {
s.recordCacheHit()
return cache.getNodes(), nil
}
s.recordCacheMiss()
// 从注册中心获取服务
services, err := s.opts.Registry.GetService(service)
if err != nil {
return nil, err
}
// 构建节点列表
var nodes []*WeightedNode
for _, svc := range services {
for _, node := range svc.Nodes {
weightedNode := &WeightedNode{
Node: node,
Weight: s.calculateWeight(node),
LastUsed: time.Now(),
Stats: &NodeStats{
HealthStatus: HealthStatusUnknown,
},
}
nodes = append(nodes, weightedNode)
}
}
// 更新缓存
s.mu.Lock()
s.cache[service] = &serviceCache{
services: services,
nodes: nodes,
lastUsed: time.Now(),
ttl: s.opts.CacheTTL,
}
s.mu.Unlock()
return nodes, nil
}
// filterHealthyNodes 过滤健康节点
func (s *microSelector) filterHealthyNodes(nodes []*WeightedNode) []*WeightedNode {
var healthy []*WeightedNode
for _, node := range nodes {
status := s.nodeTracker.GetNodeStatus(node.Node.ID)
// 检查熔断器状态
if status.IsCircuitOpen {
// 检查是否可以尝试恢复
if time.Since(status.CircuitOpenedAt) > s.opts.CircuitBreakerTimeout {
status.IsCircuitOpen = false
status.FailureCount = 0
} else {
continue // 跳过熔断的节点
}
}
// 检查健康状态
if status.HealthStatus == HealthStatusHealthy ||
status.HealthStatus == HealthStatusUnknown {
healthy = append(healthy, node)
}
}
return healthy
}
// applyWeights 应用权重策略
func (s *microSelector) applyWeights(nodes []*WeightedNode, options selector.SelectOptions) []*WeightedNode {
if !options.RegistryOptions.EnableWeighted {
// 如果未启用权重,设置默认权重
for _, node := range nodes {
node.Weight = 1
}
return nodes
}
// 应用动态权重
for _, node := range nodes {
node.Weight = s.calculateDynamicWeight(node)
}
// 按权重排序
sort.Slice(nodes, func(i, j int) bool {
return nodes[i].Weight > nodes[j].Weight
})
return nodes
}
// calculateWeight 计算节点权重
func (s *microSelector) calculateWeight(node *registry.Node) int {
// 从元数据获取权重
if weightStr, ok := node.Metadata["weight"]; ok {
if weight, err := strconv.Atoi(weightStr); err == nil {
return weight
}
}
// 默认权重
return 1
}
// calculateDynamicWeight 计算动态权重
func (s *microSelector) calculateDynamicWeight(node *WeightedNode) int {
node.mu.RLock()
defer node.mu.RUnlock()
baseWeight := s.calculateWeight(node.Node)
stats := node.Stats
// 基于成功率和延迟调整权重
if stats.RequestCount > 0 {
successRate := float64(stats.SuccessCount) / float64(stats.RequestCount)
// 成功率越高权重越大
weightMultiplier := successRate
// 延迟越低权重越大
if stats.AverageLatency > 0 {
latencyScore := float64(time.Second) / float64(stats.AverageLatency)
weightMultiplier *= latencyScore
}
return int(float64(baseWeight) * weightMultiplier)
}
return baseWeight
}
// getStrategy 获取选择策略
func (s *microSelector) getStrategy(strategyName string) SelectionStrategy {
s.mu.RLock()
defer s.mu.RUnlock()
strategy, exists := s.strategies[strategyName]
if !exists {
return s.strategies["random"] // 默认策略
}
return strategy
}
// registerDefaultStrategies 注册默认策略
func (s *microSelector) registerDefaultStrategies() {
s.strategies["random"] = &RandomStrategy{}
s.strategies["round_robin"] = &RoundRobinStrategy{}
s.strategies["weighted"] = &WeightedStrategy{}
s.strategies["least_conn"] = &LeastConnStrategy{}
}
// recordSelection 记录选择统计
func (s *microSelector) recordSelection() {
s.stats.mu.Lock()
s.stats.TotalSelections++
s.stats.mu.Unlock()
}
// recordSuccess 记录成功统计
func (s *microSelector) recordSuccess() {
s.stats.mu.Lock()
s.stats.SuccessfulCalls++
s.stats.mu.Unlock()
}
// recordFailure 记录失败统计
func (s *microSelector) recordFailure() {
s.stats.mu.Lock()
s.stats.FailedCalls++
s.stats.mu.Unlock()
}
// recordCacheHit 记录缓存命中
func (s *microSelector) recordCacheHit() {
s.stats.mu.Lock()
s.stats.CacheHits++
s.stats.mu.Unlock()
}
// recordCacheMiss 记录缓存未命中
func (s *microSelector) recordCacheMiss() {
s.stats.mu.Lock()
s.stats.CacheMisses++
s.stats.mu.Unlock()
}
// GetStats 获取统计信息
func (s *microSelector) GetStats() *SelectorStats {
s.stats.mu.RLock()
defer s.stats.mu.RUnlock()
return &SelectorStats{
TotalSelections: s.stats.TotalSelections,
SuccessfulCalls: s.stats.SuccessfulCalls,
FailedCalls: s.stats.FailedCalls,
CacheHits: s.stats.CacheHits,
CacheMisses: s.stats.CacheMisses,
}
}
// serviceCache 方法
func (c *serviceCache) isExpired() bool {
c.mu.RLock()
defer c.mu.RUnlock()
return time.Since(c.lastUsed) > c.ttl
}
func (c *serviceCache) getNodes() []*WeightedNode {
c.mu.RLock()
defer c.mu.RUnlock()
return c.nodes
}
// WeightedNode 方法
func (n *WeightedNode) recordUsage() {
n.mu.Lock()
defer n.mu.Unlock()
n.LastUsed = time.Now()
n.Stats.RequestCount++
}
func (n *WeightedNode) recordResult(err error) {
n.mu.Lock()
defer n.mu.Unlock()
if err != nil {
n.Stats.FailureCount++
n.Stats.LastFailure = time.Now()
} else {
n.Stats.SuccessCount++
n.Stats.LastSuccess = time.Now()
}
// 更新健康状态
n.updateHealthStatus()
}
func (n *WeightedNode) updateHealthStatus() {
total := n.Stats.RequestCount
if total == 0 {
n.Stats.HealthStatus = HealthStatusUnknown
return
}
successRate := float64(n.Stats.SuccessCount) / float64(total)
if successRate >= 0.9 {
n.Stats.HealthStatus = HealthStatusHealthy
} else if successRate >= 0.5 {
n.Stats.HealthStatus = HealthStatusDegraded
} else {
n.Stats.HealthStatus = HealthStatusUnhealthy
}
}
// NewNodeTracker 创建节点跟踪器
func NewNodeTracker() *NodeTracker {
return &NodeTracker{
nodes: make(map[string]*NodeStatus),
}
}
func (nt *NodeTracker) MarkNode(nodeID string, err error) {
nt.mu.Lock()
defer nt.mu.Unlock()
status, exists := nt.nodes[nodeID]
if !exists {
status = &NodeStatus{
HealthStatus: HealthStatusUnknown,
LastCheck: time.Now(),
}
nt.nodes[nodeID] = status
}
status.LastCheck = time.Now()
if err != nil {
status.FailureCount++
status.LastFailure = time.Now()
// 检查是否需要打开熔断器
if status.FailureCount >= 5 && status.FailureCount-status.SuccessCount >= 3 {
status.IsCircuitOpen = true
status.CircuitOpenedAt = time.Now()
}
} else {
status.SuccessCount++
status.LastSuccess = time.Now()
// 检查是否可以关闭熔断器
if status.IsCircuitOpen && status.SuccessCount >= 3 {
status.IsCircuitOpen = false
}
}
// 更新健康状态
nt.updateNodeHealthStatus(status)
}
func (nt *NodeTracker) GetNodeStatus(nodeID string) *NodeStatus {
nt.mu.RLock()
defer nt.mu.RUnlock()
status, exists := nt.nodes[nodeID]
if !exists {
return &NodeStatus{
HealthStatus: HealthStatusUnknown,
LastCheck: time.Now(),
}
}
return status
}
func (nt *NodeTracker) Reset(service string) {
nt.mu.Lock()
defer nt.mu.Unlock()
for nodeID, status := range nt.nodes {
// 重置相关服务的节点状态
// 这里简化处理,实际可能需要更复杂的逻辑
status.FailureCount = 0
status.SuccessCount = 0
status.IsCircuitOpen = false
status.HealthStatus = HealthStatusUnknown
}
}
func (nt *NodeTracker) ResetAll() {
nt.mu.Lock()
defer nt.mu.Unlock()
for _, status := range nt.nodes {
status.FailureCount = 0
status.SuccessCount = 0
status.IsCircuitOpen = false
status.HealthStatus = HealthStatusUnknown
}
}
func (nt *NodeTracker) updateNodeHealthStatus(status *NodeStatus) {
total := status.SuccessCount + status.FailureCount
if total == 0 {
status.HealthStatus = HealthStatusUnknown
return
}
successRate := float64(status.SuccessCount) / float64(total)
if successRate >= 0.95 {
status.HealthStatus = HealthStatusHealthy
} else if successRate >= 0.8 {
status.HealthStatus = HealthStatusDegraded
} else {
status.HealthStatus = HealthStatusUnhealthy
}
}
// 健康状态常量
type HealthStatus string
const (
HealthStatusHealthy HealthStatus = "healthy"
HealthStatusUnhealthy HealthStatus = "unhealthy"
HealthStatusDegraded HealthStatus = "degraded"
HealthStatusUnknown HealthStatus = "unknown"
)
// 选择策略实现
type RandomStrategy struct{}
func (rs *RandomStrategy) Select(nodes []*WeightedNode) (*WeightedNode, error) {
if len(nodes) == 0 {
return nil, selector.ErrNotFound
}
// 简单随机选择
index := rand.Intn(len(nodes))
return nodes[index], nil
}
func (rs *RandomStrategy) String() string {
return "random"
}
type RoundRobinStrategy struct {
counter int64
mu sync.Mutex
}
func (rrs *RoundRobinStrategy) Select(nodes []*WeightedNode) (*WeightedNode, error) {
if len(nodes) == 0 {
return nil, selector.ErrNotFound
}
rrs.mu.Lock()
index := int(rrs.counter % int64(len(nodes)))
rrs.counter++
rrs.mu.Unlock()
return nodes[index], nil
}
func (rrs *RoundRobinStrategy) String() string {
return "round_robin"
}
type WeightedStrategy struct{}
func (ws *WeightedStrategy) Select(nodes []*WeightedNode) (*WeightedNode, error) {
if len(nodes) == 0 {
return nil, selector.ErrNotFound
}
// 计算总权重
totalWeight := 0
for _, node := range nodes {
totalWeight += node.Weight
}
if totalWeight == 0 {
// 如果所有权重都为0,随机选择
index := rand.Intn(len(nodes))
return nodes[index], nil
}
// 按权重选择
random := rand.Intn(totalWeight)
currentWeight := 0
for _, node := range nodes {
currentWeight += node.Weight
if random < currentWeight {
return node, nil
}
}
// 默认返回最后一个节点
return nodes[len(nodes)-1], nil
}
func (ws *WeightedStrategy) String() string {
return "weighted"
}
type LeastConnStrategy struct{}
func (lcs *LeastConnStrategy) Select(nodes []*WeightedNode) (*WeightedNode, error) {
if len(nodes) == 0 {
return nil, selector.ErrNotFound
}
// 选择连接数最少的节点
var selected *WeightedNode
minConnections := int64(^uint64(0) >> 1)
for _, node := range nodes {
node.mu.RLock()
connections := node.Stats.RequestCount - node.Stats.FailureCount
node.mu.RUnlock()
if connections < minConnections {
minConnections = connections
selected = node
}
}
if selected == nil {
// 如果没有找到,随机选择
index := rand.Intn(len(nodes))
return nodes[index], nil
}
return selected, nil
}
func (lcs *LeastConnStrategy) String() string {
return "least_conn"
}
---
02.负载均衡策略
a.轮询策略
按顺序轮流选择服务实例,实现简单且均匀的负载分配。适合处理能力相近的服务实例。
b.随机策略
随机选择服务实例,在大量实例的情况下分布更均匀。适合无状态服务。
c.加权策略
根据服务实例的性能或权重进行选择,支持流量分配。可以根据服务器的处理能力分配不同的权重。
d.最少连接策略
选择当前连接数最少的实例,适合连接敏感的服务。确保负载分布与实际处理能力相匹配。
e.代码示例
---
// 负载均衡策略示例
package loadbalancer
import (
"fmt"
"math/rand"
"sync"
"time"
"github.com/micro/go-micro/v2/selector"
)
// LoadBalancer 负载均衡器
type LoadBalancer struct {
mu sync.RWMutex
// 节点列表
nodes []*Node
// 策略
strategy Strategy
// 统计信息
stats *LoadBalancerStats
// 配置
config *LoadBalancerConfig
}
// Node 节点信息
type Node struct {
ID string `json:"id"`
Address string `json:"address"`
Weight int `json:"weight"`
Metadata map[string]interface{} `json:"metadata"`
// 运行时统计
stats *NodeStats
mu sync.RWMutex
}
// NodeStats 节点统计
type NodeStats struct {
RequestCount int64 `json:"request_count"`
SuccessCount int64 `json:"success_count"`
FailureCount int64 `json:"failure_count"`
ActiveRequests int64 `json:"active_requests"`
AverageLatency time.Duration `json:"average_latency"`
TotalLatency time.Duration `json:"total_latency"`
LastUsed time.Time `json:"last_used"`
mu sync.RWMutex
}
// LoadBalancerStats 负载均衡器统计
type LoadBalancerStats struct {
TotalRequests int64 `json:"total_requests"`
SuccessfulRequests int64 `json:"successful_requests"`
FailedRequests int64 `json:"failed_requests"`
AverageLatency time.Duration `json:"average_latency"`
Strategy string `json:"strategy"`
mu sync.RWMutex
}
// LoadBalancerConfig 负载均衡器配置
type LoadBalancerConfig struct {
Strategy string `json:"strategy"`
HealthCheckInterval time.Duration `json:"health_check_interval"`
FailureThreshold int `json:"failure_threshold"`
RecoveryTimeout time.Duration `json:"recovery_timeout"`
EnableWeighted bool `json:"enable_weighted"`
EnableDynamicWeight bool `json:"enable_dynamic_weight"`
WeightUpdateInterval time.Duration `json:"weight_update_interval"`
StatsReportingInterval time.Duration `json:"stats_reporting_interval"`
}
// Strategy 负载均衡策略接口
type Strategy interface {
Select(nodes []*Node) (*Node, error)
String() string
UpdateStats(node *Node, success bool, latency time.Duration)
}
// NewLoadBalancer 创建负载均衡器
func NewLoadBalancer(nodes []*Node, config *LoadBalancerConfig) *LoadBalancer {
if config == nil {
config = &LoadBalancerConfig{
Strategy: "round_robin",
HealthCheckInterval: 30 * time.Second,
FailureThreshold: 3,
RecoveryTimeout: 60 * time.Second,
EnableWeighted: false,
EnableDynamicWeight: false,
WeightUpdateInterval: 60 * time.Second,
StatsReportingInterval: 10 * time.Second,
}
}
lb := &LoadBalancer{
nodes: nodes,
config: config,
stats: &LoadBalancerStats{},
}
// 初始化策略
lb.strategy = lb.createStrategy(config.Strategy)
// 启动后台任务
go lb.healthCheckLoop()
if config.EnableDynamicWeight {
go lb.weightUpdateLoop()
}
go lb.statsReportingLoop()
return lb
}
// Select 选择节点
func (lb *LoadBalancer) Select() (*Node, error) {
lb.mu.RLock()
defer lb.mu.RUnlock()
if len(lb.nodes) == 0 {
return nil, fmt.Errorf("没有可用节点")
}
// 过滤健康节点
healthyNodes := lb.filterHealthyNodes()
if len(healthyNodes) == 0 {
return nil, fmt.Errorf("没有健康节点")
}
// 使用策略选择节点
node, err := lb.strategy.Select(healthyNodes)
if err != nil {
return nil, fmt.Errorf("策略选择失败: %v", err)
}
// 增加活跃请求计数
node.mu.Lock()
node.stats.ActiveRequests++
node.stats.LastUsed = time.Now()
node.mu.Unlock()
return node, nil
}
// RecordResult 记录调用结果
func (lb *LoadBalancer) RecordResult(nodeID string, success bool, latency time.Duration) {
lb.mu.Lock()
defer lb.mu.Unlock()
// 查找节点
var node *Node
for _, n := range lb.nodes {
if n.ID == nodeID {
node = n
break
}
}
if node == nil {
return
}
// 更新节点统计
node.mu.Lock()
node.stats.RequestCount++
node.stats.ActiveRequests--
node.stats.TotalLatency += latency
if success {
node.stats.SuccessCount++
} else {
node.stats.FailureCount++
}
// 计算平均延迟
if node.stats.RequestCount > 0 {
node.stats.AverageLatency = node.stats.TotalLatency / time.Duration(node.stats.RequestCount)
}
node.mu.Unlock()
// 更新策略统计
if lb.strategy != nil {
lb.strategy.UpdateStats(node, success, latency)
}
// 更新负载均衡器统计
lb.updateStats(success, latency)
}
// AddNode 添加节点
func (lb *LoadBalancer) AddNode(node *Node) {
lb.mu.Lock()
defer lb.mu.Unlock()
// 初始化节点统计
node.stats = &NodeStats{}
lb.nodes = append(lb.nodes, node)
}
// RemoveNode 移除节点
func (lb *LoadBalancer) RemoveNode(nodeID string) {
lb.mu.Lock()
defer lb.mu.Unlock()
for i, node := range lb.nodes {
if node.ID == nodeID {
lb.nodes = append(lb.nodes[:i], lb.nodes[i+1:]...)
break
}
}
}
// GetStats 获取统计信息
func (lb *LoadBalancer) GetStats() *LoadBalancerStats {
lb.stats.mu.RLock()
defer lb.stats.mu.RUnlock()
// 创建统计信息副本
stats := &LoadBalancerStats{
TotalRequests: lb.stats.TotalRequests,
SuccessfulRequests: lb.stats.SuccessfulRequests,
FailedRequests: lb.stats.FailedRequests,
AverageLatency: lb.stats.AverageLatency,
Strategy: lb.strategy.String(),
}
// 添加节点统计
lb.mu.RLock()
for _, node := range lb.nodes {
node.mu.RLock()
stats.TotalRequests += node.stats.RequestCount
stats.SuccessfulRequests += node.stats.SuccessCount
stats.FailedRequests += node.stats.FailureCount
node.mu.RUnlock()
}
lb.mu.RUnlock()
// 计算平均延迟
if stats.TotalRequests > 0 {
var totalLatency time.Duration
lb.mu.RLock()
for _, node := range lb.nodes {
node.mu.RLock()
totalLatency += node.stats.TotalLatency
node.mu.RUnlock()
}
lb.mu.RUnlock()
stats.AverageLatency = totalLatency / time.Duration(stats.TotalRequests)
}
return stats
}
// createStrategy 创建策略
func (lb *LoadBalancer) createStrategy(strategyName string) Strategy {
switch strategyName {
case "random":
return &RandomStrategy{}
case "round_robin":
return &RoundRobinStrategy{}
case "weighted":
return &WeightedStrategy{enableDynamic: lb.config.EnableDynamicWeight}
case "least_conn":
return &LeastConnStrategy{}
case "response_time":
return &ResponseTimeStrategy{}
case "consistent_hash":
return NewConsistentHashStrategy()
default:
return &RoundRobinStrategy{}
}
}
// filterHealthyNodes 过滤健康节点
func (lb *LoadBalancer) filterHealthyNodes() []*Node {
var healthy []*Node
for _, node := range lb.nodes {
if lb.isNodeHealthy(node) {
healthy = append(healthy, node)
}
}
return healthy
}
// isNodeHealthy 检查节点健康状态
func (lb *LoadBalancer) isNodeHealthy(node *Node) bool {
node.mu.RLock()
defer node.mu.RUnlock()
// 检查失败阈值
if node.stats.FailureCount >= int64(lb.config.FailureThreshold) {
// 检查是否需要恢复
if time.Since(node.stats.LastUsed) > lb.config.RecoveryTimeout {
return true // 给节点恢复的机会
}
return false
}
// 检查成功率
if node.stats.RequestCount > 10 {
successRate := float64(node.stats.SuccessCount) / float64(node.stats.RequestCount)
if successRate < 0.5 {
return false
}
}
return true
}
// updateStats 更新统计信息
func (lb *LoadBalancer) updateStats(success bool, latency time.Duration) {
lb.stats.mu.Lock()
defer lb.stats.mu.Unlock()
lb.stats.TotalRequests++
if success {
lb.stats.SuccessfulRequests++
} else {
lb.stats.FailedRequests++
}
// 简单计算平均延迟
if lb.stats.TotalRequests > 0 {
totalRequests := float64(lb.stats.TotalRequests)
currentAvg := float64(lb.stats.AverageLatency)
newLatency := float64(latency)
lb.stats.AverageLatency = time.Duration((currentAvg*(totalRequests-1) + newLatency) / totalRequests)
}
}
// healthCheckLoop 健康检查循环
func (lb *LoadBalancer) healthCheckLoop() {
ticker := time.NewTicker(lb.config.HealthCheckInterval)
defer ticker.Stop()
for range ticker.C {
lb.performHealthChecks()
}
}
// performHealthChecks 执行健康检查
func (lb *LoadBalancer) performHealthChecks() {
lb.mu.RLock()
nodes := make([]*Node, len(lb.nodes))
copy(nodes, lb.nodes)
lb.mu.RUnlock()
for _, node := range nodes {
go lb.checkNodeHealth(node)
}
}
// checkNodeHealth 检查单个节点健康
func (lb *LoadBalancer) checkNodeHealth(node *Node) {
// 执行健康检查
healthy := lb.performHealthCheck(node)
// 更新节点状态
if !healthy {
node.mu.Lock()
node.stats.FailureCount++
node.mu.Unlock()
} else {
node.mu.Lock()
node.stats.SuccessCount++
node.mu.Unlock()
}
}
// performHealthCheck 执行健康检查
func (lb *LoadBalancer) performHealthCheck(node *Node) bool {
// 这里实现具体的健康检查逻辑
// 可以发送HTTP请求、TCP连接检查等
return true // 简化实现
}
// weightUpdateLoop 权重更新循环
func (lb *LoadBalancer) weightUpdateLoop() {
ticker := time.NewTicker(lb.config.WeightUpdateInterval)
defer ticker.Stop()
for range ticker.C {
lb.updateWeights()
}
}
// updateWeights 更新权重
func (lb *LoadBalancer) updateWeights() {
lb.mu.Lock()
defer lb.mu.Unlock()
for _, node := range lb.nodes {
newWeight := lb.calculateWeight(node)
if newWeight != node.Weight {
node.Weight = newWeight
}
}
}
// calculateWeight 计算权重
func (lb *LoadBalancer) calculateWeight(node *Node) int {
node.mu.RLock()
defer node.mu.RUnlock()
if !lb.config.EnableDynamicWeight {
return node.Weight
}
// 基于成功率和延迟计算权重
if node.stats.RequestCount == 0 {
return node.Weight
}
successRate := float64(node.stats.SuccessCount) / float64(node.stats.RequestCount)
latencyScore := float64(time.Second) / float64(node.stats.AverageLatency)
// 综合评分
score := successRate * latencyScore * 100
return int(score)
}
// statsReportingLoop 统计报告循环
func (lb *LoadBalancer) statsReportingLoop() {
ticker := time.NewTicker(lb.config.StatsReportingInterval)
defer ticker.Stop()
for range ticker.C {
stats := lb.GetStats()
fmt.Printf("负载均衡器统计: 总请求=%d, 成功=%d, 失败=%d, 平均延迟=%v, 策略=%s\n",
stats.TotalRequests, stats.SuccessfulRequests, stats.FailedRequests,
stats.AverageLatency, stats.Strategy)
}
}
// 策略实现
// RandomStrategy 随机策略
type RandomStrategy struct{}
func (rs *RandomStrategy) Select(nodes []*Node) (*Node, error) {
if len(nodes) == 0 {
return nil, fmt.Errorf("没有可用节点")
}
index := rand.Intn(len(nodes))
return nodes[index], nil
}
func (rs *RandomStrategy) String() string {
return "random"
}
func (rs *RandomStrategy) UpdateStats(node *Node, success bool, latency time.Duration) {
// 随机策略不需要更新内部状态
}
// RoundRobinStrategy 轮询策略
type RoundRobinStrategy struct {
counter int64
mu sync.Mutex
}
func (rrs *RoundRobinStrategy) Select(nodes []*Node) (*Node, error) {
if len(nodes) == 0 {
return nil, fmt.Errorf("没有可用节点")
}
rrs.mu.Lock()
index := int(rrs.counter % int64(len(nodes)))
rrs.counter++
rrs.mu.Unlock()
return nodes[index], nil
}
func (rrs *RoundRobinStrategy) String() string {
return "round_robin"
}
func (rrs *RoundRobinStrategy) UpdateStats(node *Node, success bool, latency time.Duration) {
// 轮询策略不需要更新内部状态
}
// WeightedStrategy 加权策略
type WeightedStrategy struct {
mu sync.Mutex
enableDynamic bool
}
func (ws *WeightedStrategy) Select(nodes []*Node) (*Node, error) {
if len(nodes) == 0 {
return nil, fmt.Errorf("没有可用节点")
}
// 计算总权重
totalWeight := 0
for _, node := range nodes {
totalWeight += node.Weight
}
if totalWeight == 0 {
// 如果所有权重都为0,随机选择
index := rand.Intn(len(nodes))
return nodes[index], nil
}
// 按权重选择
random := rand.Intn(totalWeight)
currentWeight := 0
for _, node := range nodes {
currentWeight += node.Weight
if random < currentWeight {
return node, nil
}
}
return nodes[len(nodes)-1], nil
}
func (ws *WeightedStrategy) String() string {
return "weighted"
}
func (ws *WeightedStrategy) UpdateStats(node *Node, success bool, latency time.Duration) {
// 如果启用动态权重,这里可以更新权重逻辑
}
// LeastConnStrategy 最少连接策略
type LeastConnStrategy struct{}
func (lcs *LeastConnStrategy) Select(nodes []*Node) (*Node, error) {
if len(nodes) == 0 {
return nil, fmt.Errorf("没有可用节点")
}
var selected *Node
minConnections := int64(^uint64(0) >> 1)
for _, node := range nodes {
node.mu.RLock()
activeRequests := node.stats.ActiveRequests
node.mu.RUnlock()
if activeRequests < minConnections {
minConnections = activeRequests
selected = node
}
}
if selected == nil {
// 如果没有找到,随机选择
index := rand.Intn(len(nodes))
return nodes[index], nil
}
return selected, nil
}
func (lcs *LeastConnStrategy) String() string {
return "least_conn"
}
func (lcs *LeastConnStrategy) UpdateStats(node *Node, success bool, latency time.Duration) {
// 最少连接策略不需要更新内部状态
}
// ResponseTimeStrategy 响应时间策略
type ResponseTimeStrategy struct{}
func (rts *ResponseTimeStrategy) Select(nodes []*Node) (*Node, error) {
if len(nodes) == 0 {
return nil, fmt.Errorf("没有可用节点")
}
var selected *Node
minLatency := time.Duration(^uint64(0) >> 1)
for _, node := range nodes {
node.mu.RLock()
avgLatency := node.stats.AverageLatency
node.mu.RUnlock()
if avgLatency == 0 {
// 如果没有历史数据,选择此节点
selected = node
break
}
if avgLatency < minLatency {
minLatency = avgLatency
selected = node
}
}
if selected == nil {
// 如果没有找到,随机选择
index := rand.Intn(len(nodes))
return nodes[index], nil
}
return selected, nil
}
func (rts *ResponseTimeStrategy) String() string {
return "response_time"
}
func (rts *ResponseTimeStrategy) UpdateStats(node *Node, success bool, latency time.Duration) {
// 响应时间策略不需要更新内部状态
}
// ConsistentHashStrategy 一致性哈希策略
type ConsistentHashStrategy struct {
ring *ConsistentHashRing
mu sync.RWMutex
}
func NewConsistentHashStrategy() *ConsistentHashStrategy {
return &ConsistentHashStrategy{
ring: NewConsistentHashRing(150), // 虚拟节点数
}
}
func (chs *ConsistentHashStrategy) Select(nodes []*Node) (*Node, error) {
if len(nodes) == 0 {
return nil, fmt.Errorf("没有可用节点")
}
chs.mu.Lock()
defer chs.mu.Unlock()
// 更新哈希环
chs.ring.Update(nodes)
// 生成请求的key(这里简化处理)
key := generateRequestKey()
// 从哈希环获取节点
node := chs.ring.Get(key)
if node == nil {
return nil, fmt.Errorf("哈希环中没有节点")
}
return node, nil
}
func (chs *ConsistentHashStrategy) String() string {
return "consistent_hash"
}
func (chs *ConsistentHashStrategy) UpdateStats(node *Node, success bool, latency time.Duration) {
// 一致性哈希策略不需要更新内部状态
}
// ConsistentHashRing 一致性哈希环
type ConsistentHashRing struct {
nodes []*Node
keys []uint32
mu sync.RWMutex
virtualNodes int
}
func NewConsistentHashRing(virtualNodes int) *ConsistentHashRing {
return &ConsistentHashRing{
virtualNodes: virtualNodes,
}
}
func (chr *ConsistentHashRing) Update(nodes []*Node) {
chr.mu.Lock()
defer chr.mu.Unlock()
chr.nodes = make([]*Node, len(nodes))
copy(chr.nodes, nodes)
chr.keys = make([]uint32, 0)
for _, node := range nodes {
for i := 0; i < chr.virtualNodes; i++ {
key := chr.hashKey(fmt.Sprintf("%s-%d", node.ID, i))
chr.keys = append(chr.keys, key)
}
}
sort.Slice(chr.keys, func(i, j int) bool {
return chr.keys[i] < chr.keys[j]
})
}
func (chr *ConsistentHashRing) Get(key string) *Node {
chr.mu.RLock()
defer chr.mu.RUnlock()
if len(chr.nodes) == 0 {
return nil
}
hash := chr.hashKey(key)
// 二分查找
idx := chr.search(hash)
if idx == len(chr.keys) {
idx = 0
}
// 找到对应的节点
virtualNodeIndex := idx / chr.virtualNodes
if virtualNodeIndex >= len(chr.nodes) {
virtualNodeIndex = 0
}
return chr.nodes[virtualNodeIndex]
}
func (chr *ConsistentHashRing) search(hash uint32) int {
idx := sort.Search(len(chr.keys), func(i int) bool {
return chr.keys[i] >= hash
})
return idx
}
func (chr *ConsistentHashRing) hashKey(key string) uint32 {
// 简化的哈希函数
hash := uint32(2166136261)
for _, c := range key {
hash ^= uint32(c)
hash *= 16777619
}
return hash
}
// generateRequestKey 生成请求key
func generateRequestKey() string {
return fmt.Sprintf("request-%d", time.Now().UnixNano())
}
// 使用示例
func ExampleLoadBalancer() {
// 创建节点
nodes := []*Node{
{ID: "node1", Address: "localhost:8001", Weight: 1},
{ID: "node2", Address: "localhost:8002", Weight: 2},
{ID: "node3", Address: "localhost:8003", Weight: 1},
}
// 创建配置
config := &LoadBalancerConfig{
Strategy: "weighted",
HealthCheckInterval: 30 * time.Second,
FailureThreshold: 3,
EnableDynamicWeight: true,
WeightUpdateInterval: 60 * time.Second,
}
// 创建负载均衡器
lb := NewLoadBalancer(nodes, config)
// 模拟请求
for i := 0; i < 100; i++ {
node, err := lb.Select()
if err != nil {
fmt.Printf("选择节点失败: %v\n", err)
continue
}
fmt.Printf("选择节点: %s (%s)\n", node.ID, node.Address)
// 模拟调用
success := rand.Float32() > 0.1 // 90%成功率
latency := time.Duration(50+rand.Intn(200)) * time.Millisecond
lb.RecordResult(node.ID, success, latency)
}
// 获取统计信息
stats := lb.GetStats()
fmt.Printf("负载均衡器统计: %+v\n", stats)
}
---
3.3 etcd集成
01.etcd注册中心实现
a.功能特性
etcd是一个分布式键值存储系统,go-micro通过etcd实现服务注册与发现。etcd提供强一致性、高可用性和分布式锁等特性,适合需要强一致性的生产环境。
b.核心组件
a.Client连接管理
etcd注册中心需要管理与etcd集群的连接,支持多节点配置、连接池管理、自动故障转移等功能。
b.服务注册实现
服务信息以JSON格式存储在etcd中,使用特定的目录结构。支持TTL机制、健康检查、元数据管理等功能。
c.服务发现实现
通过etcd的Watch机制监听服务变化,实时获取服务列表。支持前缀匹配、事件过滤、版本控制等功能。
c.代码示例
---
// etcd注册中心详细实现
package etcdregistry
import (
"context"
"encoding/json"
"fmt"
"path"
"strings"
"sync"
"time"
clientv3 "go.etcd.io/etcd/client/v3"
"go.etcd.io/etcd/client/v3/concurrency"
"github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/registry"
)
// etcdRegistry etcd注册中心实现
type etcdRegistry struct {
opts registry.Options
mu sync.RWMutex
// etcd客户端
client *clientv3.Client
// 配置
config *etcdConfig
// 监控统计
stats *etcdStats
// 运行状态
running bool
ctx context.Context
cancel context.CancelFunc
}
// etcdConfig etcd配置
type etcdConfig struct {
Endpoints []string `json:"endpoints"`
Username string `json:"username"`
Password string `json:"password"`
DialTimeout time.Duration `json:"dial_timeout"`
RequestTimeout time.Duration `json:"request_timeout"`
ConnectionTimeout time.Duration `json:"connection_timeout"`
KeepAliveTime time.Duration `json:"keep_alive_time"`
KeepAliveTimeout time.Duration `json:"keep_alive_timeout"`
AutoSyncInterval time.Duration `json:"auto_sync_interval"`
MaxCallSendMsgSize int `json:"max_call_send_msg_size"`
TLS *tls.Config `json:"tls"`
}
// etcdStats etcd统计信息
type etcdStats struct {
TotalRegistrations int64 `json:"total_registrations"`
TotalDeregistrations int64 `json:"total_deregistrations"`
TotalQueries int64 `json:"total_queries"`
TotalWatchers int64 `json:"total_watchers"`
ActiveServices int64 `json:"active_services"`
AverageLatency time.Duration `json:"average_latency"`
ErrorCount int64 `json:"error_count"`
ConnectionErrors int64 `json:"connection_errors"`
mu sync.RWMutex
}
// 服务注册键前缀
const (
servicePrefix = "/micro-registry"
keySeparator = "/"
)
// NewEtcdRegistry 创建etcd注册中心
func NewEtcdRegistry(opts ...registry.Option) registry.Registry {
options := registry.NewOptions()
for _, o := range opts {
o(&options)
}
ctx, cancel := context.WithCancel(context.Background())
return &etcdRegistry{
opts: options,
config: parseEtcdConfig(options),
stats: &etcdStats{},
ctx: ctx,
cancel: cancel,
}
}
// Init 初始化etcd注册中心
func (e *etcdRegistry) Init(opts ...registry.Option) error {
e.mu.Lock()
defer e.mu.Unlock()
for _, o := range opts {
o(&e.opts)
}
// 更新配置
e.config = parseEtcdConfig(e.opts)
// 创建etcd客户端
if err := e.createClient(); err != nil {
return fmt.Errorf("创建etcd客户端失败: %v", err)
}
e.running = true
logger.Infof("etcd注册中心初始化成功: %v", e.config.Endpoints)
return nil
}
// Options 获取注册中心选项
func (e *etcdRegistry) Options() registry.Options {
e.mu.RLock()
defer e.mu.RUnlock()
return e.opts
}
// Register 注册服务
func (e *etcdRegistry) Register(service *registry.Service, opts ...registry.RegisterOption) error {
start := time.Now()
defer func() {
e.recordQueryTime(time.Since(start))
}()
// 创建默认注册选项
options := registry.RegisterOptions{
TTL: e.opts.TTL,
}
for _, o := range opts {
o(&options)
}
// 验证服务信息
if err := e.validateService(service); err != nil {
e.recordError()
return fmt.Errorf("服务验证失败: %v", err)
}
// 为每个节点注册服务
var errors []error
for _, node := range service.Nodes {
nodeService := ®istry.Service{
Name: service.Name,
Version: service.Version,
Metadata: service.Metadata,
Nodes: []*registry.Node{node},
}
if err := e.registerNode(nodeService, options.TTL); err != nil {
logger.Errorf("注册节点 %s 失败: %v", node.Id, err)
errors = append(errors, err)
} else {
logger.Infof("注册节点成功: %s", node.Id)
}
}
if len(errors) > 0 {
e.recordError()
return fmt.Errorf("部分节点注册失败: %v", errors)
}
// 更新统计
e.updateStats()
return nil
}
// Deregister 注销服务
func (e *etcdRegistry) Deregister(service *registry.Service, opts ...registry.DeregisterOption) error {
start := time.Now()
defer func() {
e.recordQueryTime(time.Since(start))
}()
// 为每个节点注销服务
var errors []error
for _, node := range service.Nodes {
if err := e.deregisterNode(service.Name, service.Version, node.Id); err != nil {
logger.Errorf("注销节点 %s 失败: %v", node.Id, err)
errors = append(errors, err)
} else {
logger.Infof("注销节点成功: %s", node.Id)
}
}
if len(errors) > 0 {
e.recordError()
return fmt.Errorf("部分节点注销失败: %v", errors)
}
// 更新统计
e.updateStats()
return nil
}
// GetService 获取服务信息
func (e *etcdRegistry) GetService(name string) ([]*registry.Service, error) {
start := time.Now()
defer func() {
e.recordQueryTime(time.Since(start))
}()
if name == "" {
e.recordError()
return nil, fmt.Errorf("服务名称不能为空")
}
// 构建查询前缀
prefix := e.buildServicePrefix(name)
// 查询etcd
resp, err := e.client.Get(e.ctx, prefix, clientv3.WithPrefix())
if err != nil {
e.recordError()
return nil, fmt.Errorf("查询服务失败: %v", err)
}
if len(resp.Kvs) == 0 {
return nil, registry.ErrNotFound
}
// 解析服务信息
services, err := e.parseServiceResponse(resp.Kvs)
if err != nil {
e.recordError()
return nil, fmt.Errorf("解析服务信息失败: %v", err)
}
return services, nil
}
// ListServices 列出所有服务
func (e *etcdRegistry) ListServices() ([]*registry.Service, error) {
start := time.Now()
defer func() {
e.recordQueryTime(time.Since(start))
}()
// 查询所有服务
resp, err := e.client.Get(e.ctx, servicePrefix, clientv3.WithPrefix())
if err != nil {
e.recordError()
return nil, fmt.Errorf("查询服务列表失败: %v", err)
}
if len(resp.Kvs) == 0 {
return []*registry.Service{}, nil
}
// 解析服务信息
services, err := e.parseServiceResponse(resp.Kvs)
if err != nil {
e.recordError()
return nil, fmt.Errorf("解析服务信息失败: %v", err)
}
return services, nil
}
// Watch 监听服务变化
func (e *etcdRegistry) Watch(opts ...registry.WatchOption) (registry.Watcher, error) {
// 创建默认监听选项
options := registry.WatchOptions{
Service: "*",
}
for _, o := range opts {
o(&options)
}
// 创建监听器
watcher := &etcdWatcher{
registry: e,
service: options.Service,
events: make(chan *registry.Result, 100),
exit: make(chan struct{}),
stopChan: make(chan struct{}),
}
// 启动监听
go watcher.watch()
return watcher, nil
}
// String 返回注册中心名称
func (e *etcdRegistry) String() string {
return "etcd"
}
// createClient 创建etcd客户端
func (e *etcdRegistry) createClient() error {
if e.client != nil {
e.client.Close()
}
// 创建客户端配置
clientConfig := clientv3.Config{
Endpoints: e.config.Endpoints,
DialTimeout: e.config.DialTimeout,
Username: e.config.Username,
Password: e.config.Password,
TLS: e.config.TLS,
}
// 创建客户端
client, err := clientv3.New(clientConfig)
if err != nil {
return fmt.Errorf("创建etcd客户端失败: %v", err)
}
e.client = client
return nil
}
// registerNode 注册节点
func (e *etcdRegistry) registerNode(service *registry.Service, ttl time.Duration) error {
// 序列化服务信息
data, err := json.Marshal(service)
if err != nil {
return fmt.Errorf("序列化服务信息失败: %v", err)
}
// 构建键
key := e.buildNodeKey(service.Name, service.Version, service.Nodes[0].Id)
// 创建lease(如果需要TTL)
var leaseID clientv3.LeaseID
if ttl > 0 {
lease, err := e.client.Grant(e.ctx, int64(ttl.Seconds()))
if err != nil {
return fmt.Errorf("创建lease失败: %v", err)
}
leaseID = lease.ID
// 启动lease续期
go e.keepAlive(leaseID, ttl)
}
// 设置键值
ctx, cancel := context.WithTimeout(e.ctx, e.config.RequestTimeout)
defer cancel()
var op clientv3.Op
if leaseID > 0 {
op = clientv3.OpPut(key, string(data), clientv3.WithLease(leaseID))
} else {
op = clientv3.OpPut(key, string(data))
}
_, err = e.client.Do(ctx, op)
if err != nil {
return fmt.Errorf("注册节点失败: %v", err)
}
logger.Infof("etcd注册节点成功: %s", key)
return nil
}
// deregisterNode 注销节点
func (e *etcdRegistry) deregisterNode(serviceName, version, nodeID string) error {
key := e.buildNodeKey(serviceName, version, nodeID)
ctx, cancel := context.WithTimeout(e.ctx, e.config.RequestTimeout)
defer cancel()
_, err := e.client.Delete(ctx, key)
if err != nil {
return fmt.Errorf("删除节点失败: %v", err)
}
logger.Infof("etcd删除节点成功: %s", key)
return nil
}
// buildServicePrefix 构建服务前缀
func (e *etcdRegistry) buildServicePrefix(serviceName string) string {
return path.Join(servicePrefix, serviceName)
}
// buildNodeKey 构建节点键
func (e *etcdRegistry) buildNodeKey(serviceName, version, nodeID string) string {
return path.Join(servicePrefix, serviceName, version, nodeID)
}
// parseServiceResponse 解析服务响应
func (e *etcdRegistry) parseServiceResponse(kvs []*mvccpb.KeyValue) ([]*registry.Service, error) {
services := make(map[string]*registry.Service)
for _, kv := range kvs {
// 解析键获取服务信息
serviceName, version, err := e.parseKey(string(kv.Key))
if err != nil {
logger.Errorf("解析键失败: %v", err)
continue
}
// 解析值
var service registry.Service
if err := json.Unmarshal(kv.Value, &service); err != nil {
logger.Errorf("解析服务值失败: %v", err)
continue
}
// 合并服务
key := fmt.Sprintf("%s:%s", serviceName, version)
if existing, exists := services[key]; exists {
// 合并节点
existing.Nodes = append(existing.Nodes, service.Nodes...)
} else {
services[key] = &service
}
}
// 转换为切片
result := make([]*registry.Service, 0, len(services))
for _, service := range services {
result = append(result, service)
}
return result, nil
}
// parseKey 解析键获取服务信息
func (e *etcdRegistry) parseKey(key string) (serviceName, version string, err error) {
parts := strings.Split(key, keySeparator)
if len(parts) < 4 || parts[0] != servicePrefix {
return "", "", fmt.Errorf("无效的服务键格式: %s", key)
}
return parts[1], parts[2], nil
}
// keepAlive 保持lease活跃
func (e *etcdRegistry) keepAlive(leaseID clientv3.LeaseID, ttl time.Duration) {
// 续期间隔为TTL的2/3
interval := ttl * 2 / 3
ticker := time.NewTicker(interval)
defer ticker.Stop()
ch, kaerr := e.client.KeepAlive(e.ctx, leaseID)
if kaerr != nil {
logger.Errorf("保持lease活跃失败: %v", kaerr)
return
}
for {
select {
case <-ticker.C:
// 备用续期机制
_, err := e.client.KeepAliveOnce(e.ctx, leaseID)
if err != nil {
logger.Errorf("续期lease失败: %v", err)
return
}
logger.Debugf("续期lease成功: %d", leaseID)
case ka := <-ch:
if ka.TTL == int64(0) {
logger.Errorf("lease已过期: %d", leaseID)
return
}
case <-e.ctx.Done():
return
}
}
}
// validateService 验证服务信息
func (e *etcdRegistry) validateService(service *registry.Service) error {
if service == nil {
return fmt.Errorf("服务不能为空")
}
if service.Name == "" {
return fmt.Errorf("服务名称不能为空")
}
if service.Version == "" {
return fmt.Errorf("服务版本不能为空")
}
if service.Nodes == nil || len(service.Nodes) == 0 {
return fmt.Errorf("服务节点不能为空")
}
for _, node := range service.Nodes {
if node.Id == "" {
return fmt.Errorf("节点ID不能为空")
}
if node.Address == "" {
return fmt.Errorf("节点地址不能为空")
}
}
return nil
}
// parseEtcdConfig 解析etcd配置
func parseEtcdConfig(opts registry.Options) *etcdConfig {
config := &etcdConfig{
Endpoints: []string{"127.0.0.1:2379"},
DialTimeout: 5 * time.Second,
RequestTimeout: 3 * time.Second,
ConnectionTimeout: 2 * time.Second,
KeepAliveTime: 30 * time.Second,
KeepAliveTimeout: 5 * time.Second,
AutoSyncInterval: 10 * time.Second,
MaxCallSendMsgSize: 2 * 1024 * 1024, // 2MB
}
// 从选项中提取配置
if addrs := opts.Addrs; len(addrs) > 0 {
config.Endpoints = addrs
}
// 从上下文中提取认证信息
if opts.Context != nil {
if username, ok := opts.Context.Value("username").(string); ok {
config.Username = username
}
if password, ok := opts.Context.Value("password").(string); ok {
config.Password = password
}
}
return config
}
// recordQueryTime 记录查询时间
func (e *etcdRegistry) recordQueryTime(duration time.Duration) {
e.stats.mu.Lock()
defer e.stats.mu.Unlock()
e.stats.TotalQueries++
// 计算平均延迟
totalQueries := e.stats.TotalQueries
currentAvg := e.stats.AverageLatency
e.stats.AverageLatency = time.Duration(
(int64(currentAvg)*(totalQueries-1) + int64(duration)) / totalQueries,
)
}
// recordError 记录错误
func (e *etcdRegistry) recordError() {
e.stats.mu.Lock()
defer e.stats.mu.Unlock()
e.stats.ErrorCount++
}
// updateStats 更新统计信息
func (e *etcdRegistry) updateStats() {
e.stats.mu.Lock()
defer e.stats.mu.Unlock()
// 简单的统计更新
// 实际实现中可以添加更详细的统计
}
// GetStats 获取统计信息
func (e *etcdRegistry) GetStats() *etcdStats {
e.stats.mu.RLock()
defer e.stats.mu.RUnlock()
return &etcdStats{
TotalRegistrations: e.stats.TotalRegistrations,
TotalDeregistrations: e.stats.TotalDeregistrations,
TotalQueries: e.stats.TotalQueries,
TotalWatchers: e.stats.TotalWatchers,
ActiveServices: e.stats.ActiveServices,
AverageLatency: e.stats.AverageLatency,
ErrorCount: e.stats.ErrorCount,
ConnectionErrors: e.stats.ConnectionErrors,
}
}
// etcdWatcher etcd监听器
type etcdWatcher struct {
registry *etcdRegistry
service string
events chan *registry.Result
exit chan struct{}
stopChan chan struct{}
mu sync.Mutex
closed bool
}
func (w *etcdWatcher) Next() (*registry.Result, error) {
select {
case event := <-w.events:
return event, nil
case <-w.exit:
return nil, registry.ErrWatcherStopped
}
}
func (w *etcdWatcher) Stop() {
w.mu.Lock()
defer w.mu.Unlock()
if w.closed {
return
}
w.closed = true
close(w.stopChan)
close(w.exit)
}
func (w *etcdWatcher) watch() {
// 构建监听前缀
var prefix string
if w.service == "*" {
prefix = servicePrefix
} else {
prefix = path.Join(servicePrefix, w.service)
}
// 创建watch客户端
rch := w.registry.client.Watch(w.registry.ctx, prefix, clientv3.WithPrefix())
for {
select {
case <-w.stopChan:
return
case wresp := <-rch:
if wresp.Err() != nil {
w.registry.recordError()
return
}
// 处理事件
for _, event := range wresp.Events {
w.handleEvent(event)
}
}
}
}
func (w *etcdWatcher) handleEvent(event *clientv3.Event) {
var action string
switch event.Type {
case mvccpb.PUT:
if event.IsCreate() {
action = "create"
} else {
action = "update"
}
case mvccpb.DELETE:
action = "delete"
default:
return
}
// 解析服务信息
if event.Type == mvccpb.PUT && event.Kv.Value != nil {
var service registry.Service
if err := json.Unmarshal(event.Kv.Value, &service); err != nil {
w.registry.recordError()
return
}
result := ®istry.Result{
Action: action,
Service: &service,
}
select {
case w.events <- result:
default:
// 事件队列已满,丢弃事件
}
} else if event.Type == mvccpb.DELETE {
key := string(event.Kv.Key)
serviceName, version, err := w.registry.parseKey(key)
if err != nil {
w.registry.recordError()
return
}
service := ®istry.Service{
Name: serviceName,
Version: version,
Nodes: []*registry.Node{},
}
result := ®istry.Result{
Action: action,
Service: service,
}
select {
case w.events <- result:
default:
// 事件队列已满,丢弃事件
}
}
}
// 使用示例
func ExampleEtcdRegistry() {
// 创建etcd注册中心
reg := NewEtcdRegistry(
registry.Addrs([]string{"localhost:2379"}),
)
// 初始化
if err := reg.Init(); err != nil {
fmt.Printf("初始化etcd注册中心失败: %v\n", err)
return
}
// 注册服务
service := ®istry.Service{
Name: "user.service",
Version: "1.0.0",
Nodes: []*registry.Node{
{
Id: "node-1",
Address: "localhost:8001",
Metadata: map[string]string{
"protocol": "http",
},
},
},
}
if err := reg.Register(service, registry.RegisterTTL(60*time.Second)); err != nil {
fmt.Printf("注册服务失败: %v\n", err)
return
}
// 获取服务
services, err := reg.GetService("user.service")
if err != nil {
fmt.Printf("获取服务失败: %v\n", err)
return
}
fmt.Printf("获取到服务: %+v\n", services)
// 监听服务变化
watcher, err := reg.Watch(registry.WatchService("user.service"))
if err != nil {
fmt.Printf("创建监听器失败: %v\n", err)
return
}
go func() {
for {
result, err := watcher.Next()
if err != nil {
fmt.Printf("监听结束: %v\n", err)
break
}
fmt.Printf("服务事件: %s - %+v\n", result.Action, result.Service)
}
}()
// 等待一段时间
time.Sleep(2 * time.Minute)
// 注销服务
if err := reg.Deregister(service); err != nil {
fmt.Printf("注销服务失败: %v\n", err)
return
}
// 关闭监听器
watcher.Stop()
}
---
02.etcd配置与部署
a.集群配置
etcd支持集群模式,建议部署奇数个节点(3、5、7个)以保证高可用性。节点间需要网络互通,建议部署在不同的故障域中。
b.安全配置
启用TLS加密传输,配置客户端证书认证。设置防火墙规则,限制etcd集群的网络访问。定期备份etcd数据。
c.性能优化
合理设置心跳间隔、快照频率、存储配额等参数。使用SSD存储提高性能。配置适当的连接池和超时时间。
d.代码示例
---
// etcd配置与部署示例
package etcdconfig
import (
"crypto/tls"
"crypto/x509"
"encoding/pem"
"fmt"
"io/ioutil"
"net"
"os"
"time"
clientv3 "go.etcd.io/etcd/client/v3"
"go.etcd.io/etcd/client/v3/snapshot"
)
// EtcdClusterConfig etcd集群配置
type EtcdClusterConfig struct {
// 集群节点配置
Nodes []EtcdNode `json:"nodes"`
// 安全配置
Security *SecurityConfig `json:"security"`
// 性能配置
Performance *PerformanceConfig `json:"performance"`
// 监控配置
Monitoring *MonitoringConfig `json:"monitoring"`
// 备份配置
Backup *BackupConfig `json:"backup"`
}
// EtcdNode etcd节点配置
type EtcdNode struct {
Name string `json:"name"`
Address string `json:"address"`
PeerURL string `json:"peer_url"`
ClientURL string `json:"client_url"`
DataDir string `json:"data_dir"`
}
// SecurityConfig 安全配置
type SecurityConfig struct {
EnableTLS bool `json:"enable_tls"`
AutoTLS bool `json:"auto_tls"`
CertFile string `json:"cert_file"`
KeyFile string `json:"key_file"`
TrustedCAFile string `json:"trusted_ca_file"`
ClientCertAuth bool `json:"client_cert_auth"`
ClientCertFile string `json:"client_cert_file"`
ClientKeyFile string `json:"client_key_file"`
CipherSuites []string `json:"cipher_suites"`
MinVersion string `json:"min_version"`
}
// PerformanceConfig 性能配置
type PerformanceConfig struct {
HeartbeatInterval time.Duration `json:"heartbeat_interval"`
ElectionTimeout time.Duration `json:"election_timeout"`
MaxSnapshots int `json:"max_snapshots"`
MaxWALs int `json:"max_wals"`
MaxRequestBytes int64 `json:"max_request_bytes"`
QuotaBackendBytes int64 `json:"quota_backend_bytes"`
AutoCompactionMode string `json:"auto_compaction_mode"`
AutoCompactionRetention string `json:"auto_compaction_retention"`
SnapshotCount int `json:"snapshot_count"`
SnapshotCatchUpEntries int `json:"snapshot_catch_up_entries"`
}
// MonitoringConfig 监控配置
type MonitoringConfig struct {
EnableMetrics bool `json:"enable_metrics"`
MetricsURL string `json:"metrics_url"`
HealthCheckURL string `json:"health_check_url"`
Debug bool `json:"debug"`
LogLevel string `json:"log_level"`
LogOutputs []string `json:"log_outputs"`
EnablePProf bool `json:"enable_pprof"`
PProfAddress string `json:"pprof_address"`
}
// BackupConfig 备份配置
type BackupConfig struct {
Enable bool `json:"enable"`
Schedule string `json:"schedule"`
BackupDir string `json:"backup_dir"`
RetentionDays int `json:"retention_days"`
EncryptionKey string `json:"encryption_key"`
Compression bool `json:"compression"`
VerifyBackup bool `json:"verify_backup"`
}
// EtcdClusterManager etcd集群管理器
type EtcdClusterManager struct {
config *EtcdClusterConfig
mu sync.RWMutex
}
// NewEtcdClusterManager 创建etcd集群管理器
func NewEtcdClusterManager(config *EtcdClusterConfig) *EtcdClusterManager {
return &EtcdClusterManager{
config: config,
}
}
// GenerateClusterConfig 生成集群配置
func (m *EtcdClusterManager) GenerateClusterConfig() error {
// 生成TLS证书(如果启用)
if m.config.Security.EnableTLS && m.config.Security.AutoTLS {
if err := m.generateCertificates(); err != nil {
return fmt.Errorf("生成TLS证书失败: %v", err)
}
}
// 生成etcd配置文件
for _, node := range m.config.Nodes {
if err := m.generateNodeConfig(node); err != nil {
return fmt.Errorf("生成节点配置失败: %v", err)
}
}
// 生成systemd服务文件
for _, node := range m.config.Nodes {
if err := m.generateSystemdService(node); err != nil {
return fmt.Errorf("生成systemd服务失败: %v", err)
}
}
return nil
}
// generateCertificates 生成TLS证书
func (m *EtcdClusterManager) generateCertificates() error {
// CA证书
caCert, caKey, err := m.generateCACertificate()
if err != nil {
return fmt.Errorf("生成CA证书失败: %v", err)
}
// 节点证书
for _, node := range m.config.Nodes {
cert, key, err := m.generateNodeCertificate(caCert, caKey, node)
if err != nil {
return fmt.Errorf("生成节点证书失败: %v", err)
}
// 保存证书文件
if err := m.saveCertificateFiles(node, caCert, caKey, cert, key); err != nil {
return fmt.Errorf("保存证书文件失败: %v", err)
}
}
return nil
}
// generateCACertificate 生成CA证书
func (m *EtcdClusterManager) generateCACertificate() (*x509.Certificate, *rsa.PrivateKey, error) {
caTemplate := &x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{
CommonName: "etcd-ca",
Organization: []string{"etcd"},
Country: []string{"CN"},
},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(10, 0, 0),
KeyUsage: x509.KeyUsageKeyCertSign | x509.KeyUsageCRLSign,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
BasicConstraintsValid: true,
IsCA: true,
MaxPathLen: 2,
}
// 生成私钥
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return nil, nil, err
}
// 创建证书
certBytes, err := x509.CreateCertificate(rand.Reader, caTemplate, caTemplate, &privateKey.PublicKey)
if err != nil {
return nil, nil, err
}
cert, err := x509.ParseCertificate(certBytes)
if err != nil {
return nil, nil, err
}
return cert, privateKey, nil
}
// generateNodeCertificate 生成节点证书
func (m *EtcdClusterManager) generateNodeCertificate(caCert *x509.Certificate, caKey *rsa.PrivateKey, node EtcdNode) (*x509.Certificate, *rsa.PrivateKey, error) {
nodeTemplate := &x509.Certificate{
SerialNumber: big.NewInt(time.Now().Unix()),
Subject: pkix.Name{
CommonName: node.Name,
Organization: []string{"etcd"},
Country: []string{"CN"},
},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(1, 0, 0),
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
DNSNames: []string{node.Address, node.Name},
}
// 生成私钥
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return nil, nil, err
}
// 创建证书
certBytes, err := x509.CreateCertificate(rand.Reader, nodeTemplate, caCert, &privateKey.PublicKey)
if err != nil {
return nil, nil, err
}
cert, err := x509.ParseCertificate(certBytes)
if err != nil {
return nil, nil, err
}
return cert, privateKey, nil
}
// saveCertificateFiles 保存证书文件
func (m *EtcdClusterManager) saveCertificateFiles(node EtcdNode, caCert *x509.Certificate, caKey *rsa.PrivateKey, cert *x509.Certificate, key *rsa.PrivateKey) error {
// 创建证书目录
certDir := "/etc/etcd/certs"
if err := os.MkdirAll(certDir, 0755); err != nil {
return err
}
// 保存CA证书
caCertFile := path.Join(certDir, "ca.crt")
if err := ioutil.WriteFile(caCertFile, pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: caCert.Raw}), 0644); err != nil {
return err
}
// 保存CA私钥
caKeyFile := path.Join(certDir, "ca.key")
caKeyBytes := x509.MarshalPKCS1PrivateKey(caKey)
if err := ioutil.WriteFile(caKeyFile, pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: caKeyBytes}), 0600); err != nil {
return err
}
// 保存节点证书
certFile := path.Join(certDir, fmt.Sprintf("%s.crt", node.Name))
if err := ioutil.WriteFile(certFile, pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}), 0644); err != nil {
return err
}
// 保存节点私钥
keyFile := path.Join(certDir, fmt.Sprintf("%s.key", node.Name))
keyBytes := x509.MarshalPKCS1PrivateKey(key)
if err := ioutil.WriteFile(keyFile, pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: keyBytes}), 0600); err != nil {
return err
}
fmt.Printf("证书文件已保存: %s\n", certDir)
return nil
}
// generateNodeConfig 生成节点配置
func (m *EtcdClusterManager) generateNodeConfig(node EtcdNode) error {
config := m.buildNodeConfig(node)
configPath := fmt.Sprintf("/etc/etcd/etcd.conf.yaml")
return ioutil.WriteFile(configPath, []byte(config), 0644)
}
// buildNodeConfig 构建节点配置
func (m *EtcdClusterManager) buildNodeConfig(node EtcdNode) string {
config := fmt.Sprintf(`name: %s
data-dir: %s
listen-peer-urls: %s
listen-client-urls: %s
initial-advertise-peer-urls: %s
initial-cluster: %s
initial-cluster-state: new
`, node.Name, node.DataDir, node.PeerURL, node.ClientURL, node.PeerURL, m.buildInitialCluster(), m.buildInitialClusterState())
// 添加安全配置
if m.config.Security.EnableTLS {
config += fmt.Sprintf(`
client-transport-security:
cert-file: %s
key-file: %s
client-cert-auth: %t
trusted-ca-file: %s
auto-tls: %t
`, m.config.Security.CertFile, m.config.Security.KeyFile,
m.config.Security.ClientCertAuth, m.config.Security.TrustedCAFile,
m.config.Security.AutoTLS)
if m.config.Security.CipherSuites != nil {
config += fmt.Sprintf(" cipher-suites: [%s]\n", strings.Join(m.config.Security.CipherSuites, ","))
}
if m.config.Security.MinVersion != "" {
config += fmt.Sprintf(" min-version: %s\n", m.config.Security.MinVersion)
}
}
// 添加性能配置
if m.config.Performance != nil {
config += fmt.Sprintf(`
heartbeat-interval: %v
election-timeout: %v
max-snapshots: %d
max-wals: %d
max-request-bytes: %d
quota-backend-bytes: %d
auto-compaction-mode: %s
auto-compaction-retention: %s
snapshot-count: %d
snapshot-catch-up-entries: %d
`, m.config.Performance.HeartbeatInterval,
m.config.Performance.ElectionTimeout,
m.config.Performance.MaxSnapshots,
m.config.Performance.MaxWALs,
m.config.Performance.MaxRequestBytes,
m.config.Performance.QuotaBackendBytes,
m.config.Performance.AutoCompactionMode,
m.config.Performance.AutoCompactionRetention,
m.config.Performance.SnapshotCount,
m.config.Performance.SnapshotCatchUpEntries)
}
// 添加监控配置
if m.config.Monitoring != nil {
config += fmt.Sprintf(`
enable-pprof: %t
pprof-address: %s
metrics: %s
debug: %v
log-level: %s
log-outputs: [%s]
`, m.config.Monitoring.EnablePProf,
m.config.Monitoring.PProfAddress,
m.config.Monitoring.MetricsURL,
m.config.Monitoring.Debug,
m.config.Monitoring.LogLevel,
strings.Join(m.config.Monitoring.LogOutputs, ","))
}
return config
}
// buildInitialCluster 构建初始集群配置
func (m *EtcdClusterManager) buildInitialCluster() string {
var members []string
for _, node := range m.config.Nodes {
members = append(members, fmt.Sprintf("%s=%s", node.Name, node.PeerURL))
}
return strings.Join(members, ",")
}
// buildInitialClusterState 构建初始集群状态
func (m *EtcdClusterManager) buildInitialClusterState() string {
if len(m.config.Nodes) == 1 {
return "new"
}
return "existing"
}
// generateSystemdService 生成systemd服务文件
func (m *EtcdClusterManager) generateSystemdService(node EtcdNode) error {
serviceContent := m.buildSystemdService(node)
servicePath := fmt.Sprintf("/etc/systemd/system/etcd-%s.service", node.Name)
return ioutil.WriteFile(servicePath, []byte(serviceContent), 0644)
}
// buildSystemdService 构建systemd服务文件
func (m *EtcdClusterManager) buildSystemdService(node EtcdNode) string {
return fmt.Sprintf(`[Unit]
Description=etcd Key-Value Store
Documentation=https://github.com/etcd-io/etcd
After=network.target
Wants=network-online.target
[Service]
Type=notify
User=etcd
ExecStart=/usr/local/bin/etcd --config-file=/etc/etcd/etcd.conf
Restart=always
RestartSec=10
LimitNOFILE=40000
TimeoutStartSec=0
[Install]
WantedBy=multi-user.target
`)
}
// DeployCluster 部署集群
func (m *EtcdClusterManager) DeployCluster() error {
fmt.Println("开始部署etcd集群...")
// 检查网络连通性
for _, node := range m.config.Nodes {
if err := m.checkNodeConnectivity(node); err != nil {
return fmt.Errorf("检查节点 %s 连通性失败: %v", node.Address, err)
}
}
// 启动服务
for _, node := range m.config.Nodes {
if err := m.startNodeService(node); err != nil {
return fmt.Errorf("启动节点 %s 服务失败: %v", node.Name, err)
}
}
// 等待集群就绪
if err := m.waitForClusterReady(); err != nil {
return fmt.Errorf("等待集群就绪失败: %v", err)
}
// 验证集群状态
if err := m.verifyClusterHealth(); err != nil {
return fmt.Errorf("验证集群健康状态失败: %v", err)
}
fmt.Println("etcd集群部署成功")
return nil
}
// checkNodeConnectivity 检查节点连通性
func (m *EtcdClusterManager) checkNodeConnectivity(node EtcdNode) error {
timeout := 5 * time.Second
_, err := net.DialTimeout("tcp", node.Address, timeout)
return err
}
// startNodeService 启动节点服务
func (m *EtcdClusterManager) startNodeService(node EtcdNode) error {
// 使用SSH或配置管理工具启动服务
fmt.Printf("启动节点 %s 服务...\n", node.Name)
return nil // 简化实现
}
// waitForClusterReady 等待集群就绪
func (m *EtcdClusterManager) waitForClusterReady() error {
// 创建etcd客户端连接到第一个节点
if len(m.config.Nodes) == 0 {
return fmt.Errorf("没有可用的节点")
}
clientConfig := clientv3.Config{
Endpoints: []string{m.config.Nodes[0].ClientURL},
DialTimeout: 5 * time.Second,
}
if m.config.Security.EnableTLS {
clientConfig.TLS = m.buildTLSConfig()
}
client, err := clientv3.New(clientConfig)
if err != nil {
return fmt.Errorf("创建etcd客户端失败: %v", err)
}
defer client.Close()
// 检查集群健康状态
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
ticker := time.NewTicker(2 * time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
resp, err := client.Cluster.MemberList(ctx)
if err != nil {
continue
}
// 检查是否所有节点都加入了集群
if len(resp.Members) >= len(m.config.Nodes) {
return nil
}
case <-ctx.Done():
return fmt.Errorf("等待集群就绪超时")
}
}
}
// verifyClusterHealth 验证集群健康状态
func (m *EtcdClusterManager) verifyClusterHealth() error {
// 创建etcd客户端
endpoints := make([]string, len(m.config.Nodes))
for i, node := range m.config.Nodes {
endpoints[i] = node.ClientURL
}
clientConfig := clientv3.Config{
Endpoints: endpoints,
DialTimeout: 5 * time.Second,
}
if m.config.Security.EnableTLS {
clientConfig.TLS = m.buildTLSConfig()
}
client, err := clientv3.New(clientConfig)
if err != nil {
return fmt.Errorf("创建etcd客户端失败: %v", err)
}
defer client.Close()
// 检查集群状态
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
resp, err := client.Cluster.MemberList(ctx)
if err != nil {
return fmt.Errorf("获取集群成员列表失败: %v", err)
}
if len(resp.Members) != len(m.config.Nodes) {
return fmt.Errorf("集群成员数量不正确,期望: %d, 实际: %d", len(m.config.Nodes), len(resp.Members))
}
// 检查每个成员的健康状态
for _, member := range resp.Members {
if !member.IsLearner && member.ID != resp.Header.MemberId {
return fmt.Errorf("节点 %s 不是健康的learner", member.GetName())
}
}
fmt.Printf("集群健康检查通过,成员数量: %d\n", len(resp.Members))
return nil
}
// buildTLSConfig 构建TLS配置
func (m *EtcdClusterManager) buildTLSConfig() *tls.Config {
config := &tls.Config{
InsecureSkipVerify: false,
MinVersion: tls.VersionTLS12,
}
// 加载CA证书
if m.config.Security.TrustedCAFile != "" {
caCert, err := ioutil.ReadFile(m.config.Security.TrustedCAFile)
if err != nil {
return nil
}
caCertPool := x509.NewCertPool()
if !caCertPool.AppendCertsFromPEM(caCert) {
return nil
}
config.RootCAs = caCertPool
}
// 加载客户端证书
if m.config.Security.ClientCertAuth {
cert, err := tls.LoadX509KeyPair(
m.config.Security.ClientCertFile,
m.config.Security.ClientKeyFile,
)
if err != nil {
return nil
}
config.Certificates = []tls.Certificate{cert}
}
return config
}
// 备份和恢复功能
type EtcdBackupManager struct {
config *EtcdClusterConfig
mu sync.RWMutex
}
func NewEtcdBackupManager(config *EtcdClusterConfig) *EtcdBackupManager {
return &EtcdBackupManager{
config: config,
}
}
// CreateSnapshot 创建快照
func (m *EtcdBackupManager) CreateSnapshot() error {
if m.config.Backup == nil || !m.config.Backup.Enable {
return fmt.Errorf("备份功能未启用")
}
// 创建etcd客户端
client, err := m.createClient()
if err != nil {
return fmt.Errorf("创建etcd客户端失败: %v", err)
}
defer client.Close()
// 备份目录
backupDir := m.config.Backup.BackupDir
if err := os.MkdirAll(backupDir, 0755); err != nil {
return fmt.Errorf("创建备份目录失败: %v", err)
}
// 生成快照文件名
timestamp := time.Now().Format("20060102-150405")
snapshotFile := path.Join(backupDir, fmt.Sprintf("etcd-snapshot-%s.db", timestamp))
// 创建快照
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
status := snapshot.NewStatus(client)
if err := status.Save(ctx, snapshotFile); err != nil {
return fmt.Errorf("创建快照失败: %v", err)
}
// 验证备份
if m.config.Backup.VerifyBackup {
if err := m.VerifySnapshot(snapshotFile); err != nil {
return fmt.Errorf("验证快照失败: %v", err)
}
}
fmt.Printf("快照创建成功: %s\n", snapshotFile)
return nil
}
// RestoreSnapshot 恢复快照
func (m *EtcdBackupManager) RestoreSnapshot(snapshotFile string) error {
// 验证快照文件
if err := m.VerifySnapshot(snapshotFile); err != nil {
return fmt.Errorf("验证快照文件失败: %v", err)
}
// 创建etcd客户端
client, err := m.createClient()
if err != nil {
return fmt.Errorf("创建etcd客户端失败: %v", err)
}
defer client.Close()
// 恢复快照
status := snapshot.NewStatus(client)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
defer cancel()
if err := status.Restore(ctx, snapshotFile); err != nil {
return fmt.Errorf("恢复快照失败: %v", err)
}
fmt.Printf("快照恢复成功: %s\n", snapshotFile)
return nil
}
// VerifySnapshot 验证快照
func (m *EtcdBackupManager) VerifySnapshot(snapshotFile string) error {
// 简化的验证逻辑
file, err := os.Open(snapshotFile)
if err != nil {
return fmt.Errorf("打开快照文件失败: %v", err)
}
defer file.Close()
// 检查文件大小
fileInfo, err := file.Stat()
if err != nil {
return fmt.Errorf("获取文件信息失败: %v", err)
}
if fileInfo.Size() == 0 {
return fmt.Errorf("快照文件为空")
}
fmt.Printf("快照验证通过: %s (大小: %d bytes)\n", snapshotFile, fileInfo.Size())
return nil
}
// createClient 创建etcd客户端
func (m *EtcdBackupManager) createClient() (*clientv3.Client, error) {
endpoints := make([]string, len(m.config.Nodes))
for i, node := range m.config.Nodes {
endpoints[i] = node.ClientURL
}
clientConfig := clientv3.Config{
Endpoints: endpoints,
DialTimeout: 10 * time.Second,
}
if m.config.Security.EnableTLS {
clientConfig.TLS = m.buildTLSConfig()
}
return clientv3.New(clientConfig)
}
// buildTLSConfig 构建TLS配置
func (m *EtcdBackupManager) buildTLSConfig() *tls.Config {
// 实现TLS配置构建逻辑
return nil
}
// 使用示例
func ExampleEtcdDeployment() {
// 创建集群配置
config := &EtcdClusterConfig{
Nodes: []EtcdNode{
{
Name: "etcd1",
Address: "192.168.1.10:2380",
PeerURL: "http://192.168.1.10:2380",
ClientURL: "http://192.168.1.10:2379",
DataDir: "/var/lib/etcd",
},
{
Name: "etcd2",
Address: "192.168.1.11:2380",
PeerURL: "http://192.168.1.11:2380",
ClientURL: "http://192.168.1.11:2379",
DataDir: "/var/lib/etcd",
},
{
Name: "etcd3",
Address: "192.168.1.12:2380",
PeerURL: "http://192.168.1.12:2380",
ClientURL: "http://192.168.1.12:2379",
DataDir: "/var/lib/etcd",
},
},
Security: &SecurityConfig{
EnableTLS: true,
AutoTLS: true,
TrustedCAFile: "/etc/etcd/certs/ca.crt",
},
Performance: &PerformanceConfig{
HeartbeatInterval: 150 * time.Millisecond,
ElectionTimeout: 5 * time.Second,
MaxSnapshots: 5,
MaxWALs: 5,
MaxRequestBytes: 1572864,
QuotaBackendBytes: 8589934592,
AutoCompactionMode: "periodic",
AutoCompactionRetention: "1h",
SnapshotCount: 100000,
SnapshotCatchUpEntries: 100000,
},
Monitoring: &MonitoringConfig{
EnableMetrics: true,
MetricsURL: "http://localhost:2379/metrics",
HealthCheckURL: "http://localhost:2379/health",
Debug: true,
LogLevel: "info",
LogOutputs: []string{"stderr"},
EnablePProf: true,
PProfAddress: "localhost:6060",
},
Backup: &BackupConfig{
Enable: true,
Schedule: "0 2 * * *",
BackupDir: "/backup/etcd",
RetentionDays: 30,
Compression: true,
VerifyBackup: true,
},
}
// 创建集群管理器
manager := NewEtcdClusterManager(config)
// 生成配置文件
if err := manager.GenerateClusterConfig(); err != nil {
fmt.Printf("生成配置失败: %v\n", err)
return
}
// 部署集群
if err := manager.DeployCluster(); err != nil {
fmt.Printf("部署集群失败: %v\n", err)
return
}
// 创建备份管理器
backupManager := NewEtcdBackupManager(config)
// 创建备份
if err := backupManager.CreateSnapshot(); err != nil {
fmt.Printf("创建备份失败: %v\n", err)
}
}
---
3.4 Consul集成
01.Consul简介
a.功能说明
Consul是HashiCorp公司开源的服务发现和配置工具,具有分布式高可用、支持多数据中心、健康检查、服务网格等特性。
b.主要功能
a.服务发现与注册
提供自动服务注册和发现机制,支持DNS和HTTP接口查询。
b.健康检查
支持HTTP、TCP、gRPC等多种健康检查方式,自动故障检测和恢复。
c.KV存储
提供分布式键值存储,用于动态配置和服务协调。
d.多数据中心支持
支持跨数据中心的部署和故障转移,提供全球化服务能力。
e.服务网格集成
原生支持Consul Connect,提供服务间安全通信和流量管理。
f.动态配置
支持配置热更新,无需重启服务即可应用新配置。
c.技术优势
a.高可用性
基于Raft算法实现强一致性,保证集群高可用和数据一致性。
b.易用性
提供简洁的API和Web UI,降低部署和运维复杂度。
c.扩展性
支持水平扩展,可通过增加节点提升集群处理能力。
d.安全性
内置ACL访问控制和Gossip协议加密,保障服务安全。
02.go-micro Consul实现
a.核心架构设计
a.注册中心接口
实现go-micro的Registry接口,提供标准的服务注册发现能力。
b.监听器机制
支持服务变更的实时监听,实现动态服务发现。
c.健康检查集成
与Consul健康检查深度集成,提供准确的服务状态。
b.主要组件实现
a.代码示例
---
package consul
import (
"context"
"encoding/json"
"fmt"
"strconv"
"strings"
"sync"
"time"
"github.com/hashicorp/consul/api"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/util/log"
)
const (
defaultTTL = 30 * time.Second
defaultInterval = 10 * time.Second
)
// consulRegistry Consul注册中心实现
type consulRegistry struct {
client *api.Client
opts registry.Options
register map[string]uint64
mu sync.RWMutex
checkTimeout time.Duration
queryOptions *api.QueryOptions
}
// consulWatcher 服务监听器
type consulWatcher struct {
wo registry.WatchOptions
ch chan *registry.Result
exit chan struct{}
registry *consulRegistry
}
// NewRegistry 创建Consul注册中心
func NewRegistry(opts ...registry.Option) registry.Registry {
options := registry.Options{
Context: context.Background(),
}
for _, o := range opts {
o(&options)
}
var config *api.Config
if c, ok := options.Context.Value("consul_config").(*api.Config); ok {
config = c
} else {
config = api.DefaultConfig()
}
// 设置Consul地址
if len(options.Addrs) > 0 {
config.Address = options.Addrs[0]
}
client, err := api.NewClient(config)
if err != nil {
log.Fatalf("could not create consul client: %v", err)
}
cr := &consulRegistry{
client: client,
opts: options,
register: make(map[string]uint64),
checkTimeout: 30 * time.Second,
queryOptions: &api.QueryOptions{},
}
// 配置查询选项
if timeout, ok := options.Context.Value("consul_query_timeout").(time.Duration); ok {
cr.queryOptions.WaitTime = timeout
}
return cr
}
---
b.服务注册实现
a.功能说明
实现服务的自动注册,支持多节点注册和健康检查配置。
b.代码示例
---
// Register 注册服务
func (c *consulRegistry) Register(s *registry.Service, opts ...registry.RegisterOption) error {
var options registry.RegisterOptions
for _, o := range opts {
o(&options)
}
if len(s.Nodes) == 0 {
return fmt.Errorf("require at least one node")
}
// 注册所有节点
for _, node := range s.Nodes {
// 构建服务ID
serviceID := c.buildServiceID(s.Name, node.Id)
// 构建服务注册信息
registration := &api.AgentServiceRegistration{
ID: serviceID,
Name: s.Name,
Tags: c.buildTags(s, node),
Port: node.Port,
Address: node.Address,
Meta: c.buildMetadata(s, node),
}
// 配置健康检查
check := c.buildHealthCheck(s, node)
if check != nil {
registration.Check = check
}
// 注册服务
if err := c.client.Agent().ServiceRegister(registration); err != nil {
return fmt.Errorf("could not register service %s: %v", s.Name, err)
}
// 记录注册信息
c.mu.Lock()
c.register[serviceID] = registration.ModifyIndex
c.mu.Unlock()
log.Logf("registered service %s with id %s", s.Name, serviceID)
}
// 设置TTL
if options.TTL > 0 {
go c.ttl(s.Name, options.TTL)
}
return nil
}
---
c.服务发现实现
a.功能说明
实现服务的动态发现,支持服务查询和列表获取。
b.代码示例
---
// GetService 获取服务
func (c *consulRegistry) GetService(name string, opts ...registry.GetOption) ([]*registry.Service, error) {
services, _, err := c.client.Health().Service(name, "", true, c.queryOptions)
if err != nil {
return nil, err
}
serviceMap := make(map[string]*registry.Service)
for _, service := range services {
// 构建节点信息
node := ®istry.Node{
Id: c.extractNodeID(service.Service.ID),
Address: service.Service.Address,
Port: service.Service.Port,
Metadata: parseMetadata(service.Service.Meta),
}
// 构建服务信息
if _, ok := serviceMap[service.Service.Service]; !ok {
serviceMap[service.Service.Service] = ®istry.Service{
Name: service.Service.Service,
Version: service.Service.ServiceVersion,
Metadata: parseMetadata(service.Service.Meta),
Endpoints: parseEndpoints(service.Service.Tags),
}
}
serviceMap[service.Service.Service].Nodes = append(
serviceMap[service.Service.Service].Nodes, node)
}
// 转换为切片
var result []*registry.Service
for _, service := range serviceMap {
result = append(result, service)
}
return result, nil
}
---
d.健康检查实现
a.功能说明
构建Consul健康检查配置,支持HTTP、TCP、gRPC等多种检查方式。
b.代码示例
---
// buildHealthCheck 构建健康检查
func (c *consulRegistry) buildHealthCheck(s *registry.Service, node *registry.Node) *api.AgentServiceCheck {
check := &api.AgentServiceCheck{
DeregisterCriticalServiceAfter: "30s",
}
// 根据元数据配置健康检查
if timeout, ok := s.Metadata["consul_check_timeout"].(string); ok {
if duration, err := time.ParseDuration(timeout); err == nil {
check.Timeout = duration.String()
}
}
if interval, ok := s.Metadata["consul_check_interval"].(string); ok {
if duration, err := time.ParseDuration(interval); err == nil {
check.Interval = duration.String()
}
}
// 配置HTTP检查
if http, ok := s.Metadata["consul_check_http"].(string); ok {
check.HTTP = fmt.Sprintf("http://%s:%d%s", node.Address, node.Port, http)
return check
}
// 配置TCP检查
if tcp, ok := s.Metadata["consul_check_tcp"].(bool); ok && tcp {
check.TCP = fmt.Sprintf("%s:%d", node.Address, node.Port)
return check
}
// 配置gRPC检查
if grpc, ok := s.Metadata["consul_check_grpc"].(bool); ok && grpc {
check.GRPC = fmt.Sprintf("%s:%d", node.Address, node.Port)
return check
}
// 默认TCP检查
check.TCP = fmt.Sprintf("%s:%d", node.Address, node.Port)
check.Interval = defaultInterval.String()
check.Timeout = "5s"
return check
}
---
03.Consul监听器实现
a.监听器架构
a.功能说明
实现服务变更的实时监听,提供服务上线、下线、更新等事件的及时通知。
b.核心机制
a.阻塞查询
使用Consul的阻塞查询机制,实现高效的服务变更检测。
b.事件通道
通过channel传递服务变更事件,支持并发处理。
c.错误处理
完善的错误处理和重连机制,确保监听器的稳定性。
b.监听器实现
a.代码示例
---
// run 运行监听器
func (cw *consulWatcher) run() {
var lastIndex uint64
for {
select {
case <-cw.exit:
return
default:
// 构建查询选项
queryOpts := api.QueryOptions{
WaitIndex: lastIndex,
WaitTime: 30 * time.Second,
}
// 获取服务列表
if len(cw.wo.Service) > 0 {
services, meta, err := cw.registry.client.Health().Service(
cw.wo.Service, "", true, &queryOpts)
if err != nil {
log.Logf("error watching service %s: %v", cw.wo.Service, err)
time.Sleep(time.Second)
continue
}
if meta.LastIndex > lastIndex {
lastIndex = meta.LastIndex
cw.notifyServices(cw.wo.Service, services)
}
} else {
// 监听所有服务
services, meta, err := cw.registry.client.Catalog().Services(&queryOpts)
if err != nil {
log.Logf("error watching services: %v", err)
time.Sleep(time.Second)
continue
}
if meta.LastIndex > lastIndex {
lastIndex = meta.LastIndex
cw.notifyAllServices(services)
}
}
}
}
}
---
b.事件通知机制
a.功能说明
将服务变更转换为标准事件格式,通过通道传递给消费者。
b.代码示例
---
// notifyServices 通知服务变化
func (cw *consulWatcher) notifyServices(serviceName string, services []*api.ServiceEntry) {
serviceMap := make(map[string]*registry.Service)
for _, entry := range services {
if entry.Service.Service != serviceName {
continue
}
// 构建节点信息
node := ®istry.Node{
Id: cw.registry.extractNodeID(entry.Service.ID),
Address: entry.Service.Address,
Port: entry.Service.Port,
Metadata: parseMetadata(entry.Service.Meta),
}
// 构建服务信息
if _, ok := serviceMap[entry.Service.Service]; !ok {
serviceMap[entry.Service.Service] = ®istry.Service{
Name: entry.Service.Service,
Version: entry.Service.ServiceVersion,
Metadata: parseMetadata(entry.Service.Meta),
Endpoints: parseEndpoints(entry.Service.Tags),
}
}
serviceMap[entry.Service.Service].Nodes = append(
serviceMap[entry.Service.Service].Nodes, node)
}
// 发送结果
for _, service := range serviceMap {
select {
case cw.ch <- ®istry.Result{
Action: "update",
Service: service,
}:
default:
log.Logf("watcher channel full, dropping result")
}
}
}
---
04.高级功能实现
a.服务网格支持
a.功能说明
支持Consul Connect服务网格,提供服务间的安全通信和流量管理。
b.代码示例
---
// ServiceMeshConfig 服务网格配置
type ServiceMeshConfig struct {
EnableProxy bool
ProxyPort int
ExposePaths []string
Upstreams []UpstreamConfig
Connect bool
SidecarService *api.AgentServiceRegistration
}
// EnableServiceMesh 启用服务网格
func (c *consulRegistry) EnableServiceMesh(s *registry.Service, config *ServiceMeshConfig) error {
for _, node := range s.Nodes {
// 构建sidecar服务注册
sidecar := &api.AgentServiceRegistration{
Kind: api.ServiceKindConnectProxy,
Name: s.Name,
ID: c.buildServiceID(s.Name, node.Id) + "-sidecar",
Port: config.ProxyPort,
Proxy: &api.AgentServiceConnectProxyConfig{
DestinationServiceName: s.Name,
LocalServiceAddress: node.Address,
LocalServicePort: node.Port,
Upstreams: c.buildUpstreams(config.Upstreams),
Config: map[string]interface{}{
"protocol": "http",
},
},
}
if err := c.client.Agent().ServiceRegister(sidecar); err != nil {
return fmt.Errorf("could not register sidecar: %v", err)
}
}
return nil
}
---
b.多数据中心支持
a.功能说明
支持多数据中心部署,实现跨数据中心的故障转移和负载均衡。
b.代码示例
---
// MultiDCConfig 多数据中心配置
type MultiDCConfig struct {
PrimaryDC string
SecondaryDCs []string
Replication bool
}
// EnableMultiDC 启用多数据中心
func (c *consulRegistry) EnableMultiDC(config *MultiDCConfig) error {
for _, dc := range config.SecondaryDCs {
// 配置数据中心间的服务复制
if config.Replication {
if err := c.setupReplication(config.PrimaryDC, dc); err != nil {
return fmt.Errorf("could not setup replication to %s: %v", dc, err)
}
}
}
return nil
}
---
05.使用示例
a.服务注册示例
a.功能说明
展示如何在go-micro中使用Consul进行服务注册和发现。
b.代码示例
---
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/micro/go-micro/v2"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/server"
)
// 服务配置
const (
serviceName = "user.service"
serviceVersion = "latest"
consulAddr = "localhost:8500"
)
func main() {
// 创建Consul注册中心
consulReg := consul.NewRegistry(
registry.Addrs(consulAddr),
registry.TTL(time.Second*30),
)
// 创建服务
service := micro.NewService(
micro.Name(serviceName),
micro.Version(serviceVersion),
micro.Registry(consulReg),
micro.Server(
server.Address(":8080"),
),
)
// 初始化服务
service.Init()
// 注册服务处理器
if err := service.Server().Handle(
service.Server().NewHandler(&UserHandler{}),
); err != nil {
log.Fatal(err)
}
// 启动服务
if err := service.Run(); err != nil {
log.Fatal(err)
}
}
// UserHandler 用户服务处理器
type UserHandler struct{}
func (h *UserHandler) GetUser(ctx context.Context, req *GetUserRequest, rsp *GetUserResponse) error {
rsp.User = &User{
ID: req.Id,
Name: "John Doe",
Email: "[email protected]",
}
return nil
}
---
b.客户端调用示例
a.功能说明
展示客户端如何通过Consul发现并调用服务。
b.代码示例
---
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/micro/go-micro/v2"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/client"
)
func main() {
// 创建Consul注册中心
consulReg := consul.NewRegistry(
registry.Addrs(consulAddr),
)
// 创建服务
service := micro.NewService(
micro.Name("user.client"),
micro.Registry(consulReg),
)
service.Init()
// 创建客户端
userClient := service.Client().Client("user.service")
// 调用服务
var rsp GetUserResponse
err := userClient.Call(context.Background(), "UserHandler.GetUser", &GetUserRequest{
Id: "123",
}, &rsp, client.WithRetries(3))
if err != nil {
log.Fatalf("Error calling user service: %v", err)
}
fmt.Printf("User: %+v\n", rsp.User)
}
---
c.服务监听示例
a.功能说明
展示如何监听服务变更事件,实现动态配置更新。
b.代码示例
---
// watchServices 监听服务变化
func watchServices() {
// 创建注册中心
reg := consul.NewRegistry()
// 创建监听器
watcher, err := reg.Watch(registry.WatchService("user.service"))
if err != nil {
log.Fatal(err)
}
defer watcher.Stop()
// 监听变化
for {
result, err := watcher.Next()
if err != nil {
log.Printf("Watcher error: %v", err)
break
}
switch result.Action {
case "create", "update":
log.Printf("Service %s updated: %v", result.Service.Name, result.Service.Nodes)
case "delete":
log.Printf("Service %s deleted", result.Service.Name)
}
}
}
---
06.性能优化
a.连接池优化
a.功能说明
使用连接池管理Consul客户端连接,提升性能和资源利用率。
b.代码示例
---
type consulPool struct {
clients chan *api.Client
factory func() (*api.Client, error)
}
func newConsulPool(size int, factory func() (*api.Client, error)) *consulPool {
pool := &consulPool{
clients: make(chan *api.Client, size),
factory: factory,
}
// 预创建连接
for i := 0; i < size; i++ {
if client, err := factory(); err == nil {
pool.clients <- client
}
}
return pool
}
func (p *consulPool) Get() (*api.Client, error) {
select {
case client := <-p.clients:
return client, nil
default:
return p.factory()
}
}
func (p *consulPool) Put(client *api.Client) {
select {
case p.clients <- client:
default:
// 池满,丢弃连接
}
}
---
b.缓存优化
a.功能说明
实现服务发现结果的本地缓存,减少对Consul的频繁查询。
b.代码示例
---
type serviceCache struct {
services map[string]*registry.Service
ttl time.Duration
lastUpdate time.Time
mu sync.RWMutex
}
func newServiceCache(ttl time.Duration) *serviceCache {
return &serviceCache{
services: make(map[string]*registry.Service),
ttl: ttl,
}
}
func (sc *serviceCache) Get(name string) (*registry.Service, bool) {
sc.mu.RLock()
defer sc.mu.RUnlock()
if service, ok := sc.services[name]; ok {
if time.Since(sc.lastUpdate) < sc.ttl {
return service, true
}
}
return nil, false
}
func (sc *serviceCache) Set(name string, service *registry.Service) {
sc.mu.Lock()
defer sc.mu.Unlock()
sc.services[name] = service
sc.lastUpdate = time.Now()
}
---
07.总结与最佳实践
a.部署建议
a.集群部署
建议部署3或5个节点的Consul集群,确保高可用性。
b.网络规划
确保节点间网络互通,配置合适的Gossip通信端口。
c.存储配置
使用持久化存储,配置适当的快照和备份策略。
b.性能调优
a.查询优化
使用阻塞查询和合理的超时配置,减少不必要的轮询。
b.缓存策略
实现多级缓存,平衡数据一致性和查询性能。
c.批量操作
在可能的场景下使用批量API,减少网络开销。
c.安全配置
a.ACL控制
配置细粒度的访问控制,限制不必要的权限。
b.加密通信
启用TLS加密,保护网络传输的数据安全。
c.密钥管理
使用Consul的加密功能保护敏感配置信息。
3.5 Kubernetes集成
01.Kubernetes简介
a.功能说明
Kubernetes是一个开源的容器编排平台,提供了服务发现、负载均衡、存储编排、自动部署和回滚等完整的容器管理能力。
b.服务发现特点
a.内置DNS服务发现
Kubernetes集群内置DNS服务,提供自动的服务名解析和负载均衡。
b.Service和Endpoints资源
通过Service和Endpoints资源对象实现服务抽象和端点管理。
c.支持多种服务类型
支持ClusterIP、NodePort、LoadBalancer、ExternalName等多种服务类型。
d.健康检查和自动恢复
内置健康检查机制,支持存活探针和就绪探针,实现故障自动恢复。
e.跨命名空间服务发现
支持命名空间隔离,同时提供跨命名空间的服务发现能力。
c.技术优势
a.云原生支持
原生支持容器化部署,提供完整的云原生微服务解决方案。
b.自动扩缩容
支持水平Pod自动扩缩容,根据负载自动调整服务实例数量。
c.服务网格集成
可与Istio等服务网格集成,提供高级流量管理和安全能力。
d.多租户支持
通过命名空间实现资源隔离和多租户部署。
02.go-micro Kubernetes实现
a.核心架构设计
a.注册中心适配器
实现go-micro的Registry接口,适配Kubernetes的Service和Endpoints。
b.Informer机制
使用Kubernetes Informer机制,实现高效的服务变更监听。
c.资源管理
自动管理Service、Pod、Deployment等Kubernetes资源。
b.主要组件实现
a.代码示例
---
package k8s
import (
"context"
"encoding/json"
"fmt"
"strconv"
"strings"
"sync"
"time"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/cache"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/util/log"
)
const (
defaultNamespace = "default"
serviceLabel = "micro.service"
versionLabel = "micro.version"
portName = "micro-http"
)
// k8sRegistry Kubernetes注册中心实现
type k8sRegistry struct {
client kubernetes.Interface
opts registry.Options
namespace string
watchers map[string]*k8sWatcher
mu sync.RWMutex
informer cache.SharedIndexInformer
stopCh chan struct{}
}
// k8sWatcher Kubernetes服务监听器
type k8sWatcher struct {
wo registry.WatchOption
ch chan *registry.Result
exit chan struct{}
registry *k8sRegistry
}
// NewRegistry 创建Kubernetes注册中心
func NewRegistry(opts ...registry.Option) registry.Registry {
options := registry.Options{
Context: context.Background(),
}
for _, o := range opts {
o(&options)
}
var config *rest.Config
if cfg, ok := options.Context.Value("k8s_config").(*rest.Config); ok {
config = cfg
} else {
// 使用集群内配置
var err error
config, err = rest.InClusterConfig()
if err != nil {
log.Fatalf("could not create kubernetes config: %v", err)
}
}
client, err := kubernetes.NewForConfig(config)
if err != nil {
log.Fatalf("could not create kubernetes client: %v", err)
}
// 获取命名空间
namespace := defaultNamespace
if ns, ok := options.Context.Value("k8s_namespace").(string); ok {
namespace = ns
}
kr := &k8sRegistry{
client: client,
opts: options,
namespace: namespace,
watchers: make(map[string]*k8sWatcher),
stopCh: make(chan struct{}),
}
// 初始化Informer
kr.initInformer()
return kr
}
---
b.服务注册实现
a.功能说明
实现服务在Kubernetes中的自动注册,创建Service和Pod资源。
b.代码示例
---
// Register 注册服务
func (k *k8sRegistry) Register(s *registry.Service, opts ...registry.RegisterOption) error {
var options registry.RegisterOptions
for _, o := range opts {
o(&options)
}
if len(s.Nodes) == 0 {
return fmt.Errorf("require at least one node")
}
// 创建Kubernetes Service
service := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: s.Name,
Namespace: k.namespace,
Labels: map[string]string{
serviceLabel: s.Name,
versionLabel: s.Version,
},
Annotations: k.buildAnnotations(s),
},
Spec: corev1.ServiceSpec{
Type: corev1.ServiceTypeClusterIP,
Selector: k.buildPodSelector(s),
Ports: k.buildServicePorts(s),
},
}
_, err := k.client.CoreV1().Services(k.namespace).Create(context.TODO(), service, metav1.CreateOptions{})
if err != nil {
return fmt.Errorf("could not create service %s: %v", s.Name, err)
}
// 为每个节点创建Pod
for _, node := range s.Nodes {
pod := &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: k.buildPodName(s.Name, node.Id),
Namespace: k.namespace,
Labels: map[string]string{
serviceLabel: s.Name,
versionLabel: s.Version,
"micro.node": node.Id,
},
Annotations: k.buildPodAnnotations(s, node),
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: s.Name,
Image: k.getImageFromNode(node),
Ports: k.buildContainerPorts(s, node),
Env: k.buildEnvironment(s, node),
LivenessProbe: k.buildLivenessProbe(s, node),
ReadinessProbe: k.buildReadinessProbe(s, node),
Resources: k.buildResources(s, node),
},
},
RestartPolicy: corev1.RestartPolicyAlways,
},
}
_, err := k.client.CoreV1().Pods(k.namespace).Create(context.TODO(), pod, metav1.CreateOptions{})
if err != nil {
return fmt.Errorf("could not create pod %s: %v", pod.Name, err)
}
}
log.Logf("registered service %s in kubernetes", s.Name)
return nil
}
---
c.服务发现实现
a.功能说明
实现基于Kubernetes Service和Endpoints的服务发现功能。
b.代码示例
---
// GetService 获取服务
func (k *k8sRegistry) GetService(name string, opts ...registry.GetOption) ([]*registry.Service, error) {
service, err := k.client.CoreV1().Services(k.namespace).Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("could not get service %s: %v", name, err)
}
// 获取Endpoints
endpoints, err := k.client.CoreV1().Endpoints(k.namespace).Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("could not get endpoints for service %s: %v", name, err)
}
// 转换为registry.Service
registryService := k.convertToRegistryService(service, endpoints)
if registryService == nil {
return nil, fmt.Errorf("no ready endpoints for service %s", name)
}
return []*registry.Service{registryService}, nil
}
---
d.健康检查实现
a.功能说明
集成Kubernetes的Probe机制,实现容器级别的健康检查。
b.代码示例
---
// buildLivenessProbe 构建存活探针
func (k *k8sRegistry) buildLivenessProbe(s *registry.Service, node *registry.Node) *corev1.Probe {
return &corev1.Probe{
ProbeHandler: corev1.ProbeHandler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/health",
Port: intstr.FromInt(node.Port),
},
},
InitialDelaySeconds: 30,
PeriodSeconds: 10,
TimeoutSeconds: 5,
SuccessThreshold: 1,
FailureThreshold: 3,
}
}
// buildReadinessProbe 构建就绪探针
func (k *k8sRegistry) buildReadinessProbe(s *registry.Service, node *registry.Node) *corev1.Probe {
return &corev1.Probe{
ProbeHandler: corev1.ProbeHandler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/ready",
Port: intstr.FromInt(node.Port),
},
},
InitialDelaySeconds: 5,
PeriodSeconds: 5,
TimeoutSeconds: 3,
SuccessThreshold: 1,
FailureThreshold: 3,
}
}
---
03.Kubernetes监听器实现
a.监听器架构
a.功能说明
基于Kubernetes Informer机制,实现高效的资源变更监听。
b.核心机制
a.Informer机制
使用SharedIndexInformer实现高效的资源缓存和变更通知。
b.事件处理
支持Add、Update、Delete事件的独立处理。
c.事件路由
将Kubernetes事件转换为标准的注册中心事件。
b.监听器实现
a.代码示例
---
// initInformer 初始化Informer
func (k *k8sRegistry) initInformer() {
factory := informers.NewSharedInformerFactoryWithOptions(
k.client,
time.Minute*10,
informers.WithNamespace(k.namespace),
)
k.informer = factory.Core().V1().Services().Informer()
k.informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: k.handleServiceAdd,
UpdateFunc: k.handleServiceUpdate,
DeleteFunc: k.handleServiceDelete,
})
go k.informer.Run(k.stopCh)
}
// handleServiceAdd 处理服务添加
func (k *k8sRegistry) handleServiceAdd(obj interface{}) {
service := obj.(*corev1.Service)
if !k.isMicroService(service) {
return
}
registryService := k.convertServiceToRegistry(service)
if registryService == nil {
return
}
k.notifyWatchers("create", registryService)
}
// handleServiceUpdate 处理服务更新
func (k *k8sRegistry) handleServiceUpdate(oldObj, newObj interface{}) {
service := newObj.(*corev1.Service)
if !k.isMicroService(service) {
return
}
registryService := k.convertServiceToRegistry(service)
if registryService == nil {
return
}
k.notifyWatchers("update", registryService)
}
// handleServiceDelete 处理服务删除
func (k *k8sRegistry) handleServiceDelete(obj interface{}) {
service := obj.(*corev1.Service)
if !k.isMicroService(service) {
return
}
registryService := k.convertServiceToRegistry(service)
if registryService == nil {
return
}
k.notifyWatchers("delete", registryService)
}
---
b.事件转换机制
a.功能说明
将Kubernetes Service和Endpoints对象转换为标准的registry.Service格式。
b.代码示例
---
// convertToRegistryService 转换为registry.Service
func (k *k8sRegistry) convertToRegistryService(service *corev1.Service, endpoints *corev1.Endpoints) *registry.Service {
if len(endpoints.Subsets) == 0 {
return nil
}
registryService := ®istry.Service{
Name: service.Name,
Version: service.Labels[versionLabel],
Metadata: k.convertAnnotationsToMetadata(service.Annotations),
Endpoints: k.convertEndpointsToEndpoints(service),
}
// 转换节点信息
for _, subset := range endpoints.Subsets {
for _, addr := range subset.Addresses {
for _, port := range subset.Ports {
node := ®istry.Node{
Id: k.extractNodeID(addr.TargetRef, service.Name),
Address: addr.IP,
Port: int(port.Port),
Metadata: map[string]interface{}{
"target_ref_kind": addr.TargetRef.Kind,
"target_ref_name": addr.TargetRef.Name,
"target_ref_namespace": addr.TargetRef.Namespace,
"target_ref_uid": addr.TargetRef.UID,
},
}
registryService.Nodes = append(registryService.Nodes, node)
}
}
}
if len(registryService.Nodes) == 0 {
return nil
}
return registryService
}
---
04.高级功能实现
a.Headless Service支持
a.功能说明
支持无头服务,实现StatefulSet和有状态应用的直接访问。
b.代码示例
---
// RegisterHeadlessService 注册Headless Service
func (k *k8sRegistry) RegisterHeadlessService(s *registry.Service) error {
service := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: s.Name,
Namespace: k.namespace,
Labels: map[string]string{
serviceLabel: s.Name,
versionLabel: s.Version,
},
Annotations: k.buildAnnotations(s),
},
Spec: corev1.ServiceSpec{
Type: corev1.ServiceTypeClusterIP,
ClusterIP: "None", // Headless Service
Selector: k.buildPodSelector(s),
Ports: k.buildServicePorts(s),
},
}
_, err := k.client.CoreV1().Services(k.namespace).Create(context.TODO(), service, metav1.CreateOptions{})
return err
}
---
b.多命名空间支持
a.功能说明
支持跨命名空间的服务注册和发现,实现多租户环境的服务管理。
b.代码示例
---
// GetServiceFromNamespace 从指定命名空间获取服务
func (k *k8sRegistry) GetServiceFromNamespace(name, namespace string) ([]*registry.Service, error) {
service, err := k.client.CoreV1().Services(namespace).Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
return nil, err
}
endpoints, err := k.client.CoreV1().Endpoints(namespace).Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
return nil, err
}
registryService := k.convertToRegistryService(service, endpoints)
if registryService == nil {
return nil, fmt.Errorf("no ready endpoints for service %s", name)
}
return []*registry.Service{registryService}, nil
}
---
c.资源管理优化
a.功能说明
实现Kubernetes资源的批量操作和生命周期管理。
b.代码示例
---
// BatchRegister 批量注册服务
func (k *k8sRegistry) BatchRegister(services []*registry.Service) error {
for _, service := range services {
if err := k.Register(service); err != nil {
log.Logf("failed to register service %s: %v", service.Name, err)
continue
}
}
return nil
}
// BatchDeregister 批量注销服务
func (k *k8sRegistry) BatchDeregister(services []*registry.Service) error {
for _, service := range services {
if err := k.Deregister(service); err != nil {
log.Logf("failed to deregister service %s: %v", service.Name, err)
}
}
return nil
}
---
05.使用示例
a.服务注册示例
a.功能说明
展示如何在go-micro中集成Kubernetes注册中心,实现云原生服务部署。
b.代码示例
---
package main
import (
"context"
"log"
"github.com/micro/go-micro/v2"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/server"
"k8s.io/client-go/rest"
)
func main() {
// 使用集群内配置
config, err := rest.InClusterConfig()
if err != nil {
log.Fatal(err)
}
// 创建Kubernetes注册中心
k8sReg := k8s.NewRegistry(
registry.Context("k8s_config", config),
registry.Context("k8s_namespace", "default"),
)
// 创建服务
service := micro.NewService(
micro.Name("user.service"),
micro.Version("latest"),
micro.Registry(k8sReg),
micro.Server(
server.Address(":8080"),
),
)
service.Init()
// 注册处理器
if err := service.Server().Handle(
service.Server().NewHandler(&UserHandler{}),
); err != nil {
log.Fatal(err)
}
// 启动服务
if err := service.Run(); err != nil {
log.Fatal(err)
}
}
---
b.Kubernetes部署示例
a.功能说明
提供完整的Kubernetes部署文件示例,包括Service和Deployment配置。
b.代码示例
---
apiVersion: v1
kind: Service
metadata:
name: user-service
labels:
micro.service: user-service
micro.version: latest
annotations:
micro.endpoint.0: "UserHandler.GetUser"
micro.endpoint.1: "UserHandler.CreateUser"
spec:
type: ClusterIP
selector:
micro.service: user-service
micro.version: latest
ports:
- name: micro-http
port: 8080
targetPort: 8080
protocol: TCP
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
spec:
replicas: 3
selector:
matchLabels:
micro.service: user-service
micro.version: latest
template:
metadata:
labels:
micro.service: user-service
micro.version: latest
annotations:
micro.node.env: production
spec:
containers:
- name: user-service
image: user-service:latest
ports:
- name: micro-http
containerPort: 8080
protocol: TCP
env:
- name: MICRO_SERVER_NAME
value: "user-service"
- name: MICRO_SERVER_VERSION
value: "latest"
- name: MICRO_SERVER_ADDRESS
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: MICRO_SERVER_PORT
value: "8080"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
---
06.性能优化
a.缓存优化
a.功能说明
实现服务发现结果的本地缓存,减少对Kubernetes API的频繁调用。
b.代码示例
---
type serviceCache struct {
services map[string]*registry.Service
lastUpdate time.Time
ttl time.Duration
mu sync.RWMutex
}
func (k *k8sRegistry) newServiceCache(ttl time.Duration) *serviceCache {
return &serviceCache{
services: make(map[string]*registry.Service),
ttl: ttl,
}
}
func (sc *serviceCache) Get(name string) (*registry.Service, bool) {
sc.mu.RLock()
defer sc.mu.RUnlock()
if service, ok := sc.services[name]; ok {
if time.Since(sc.lastUpdate) < sc.ttl {
return service, true
}
}
return nil, false
}
func (sc *serviceCache) Set(name string, service *registry.Service) {
sc.mu.Lock()
defer sc.mu.Unlock()
sc.services[name] = service
sc.lastUpdate = time.Now()
}
---
b.资源优化
a.功能说明
优化Kubernetes资源配置,合理设置资源限制和请求。
b.代码示例
---
// buildResources 构建资源限制
func (k *k8sRegistry) buildResources(s *registry.Service, node *registry.Node) corev1.ResourceRequirements {
return corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("100m"),
corev1.ResourceMemory: resource.MustParse("128Mi"),
},
Limits: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("500m"),
corev1.ResourceMemory: resource.MustParse("512Mi"),
},
}
}
---
c.连接优化
a.功能说明
优化Kubernetes客户端连接,使用连接池和请求合并。
b.代码示例
---
// 使用客户端重试和超时配置
func (k *k8sRegistry) getClientConfig() *rest.Config {
config := k.config
config.Timeout = 30 * time.Second
config.RetryBackoff = &wait.Backoff{
Duration: 100 * time.Millisecond,
Factor: 1.5,
Steps: 5,
Jitter: 0.1,
}
return config
}
---
07.总结与最佳实践
a.部署策略
a.镜像管理
使用多阶段构建优化镜像大小,实现快速的容器启动。
b.配置管理
使用ConfigMap和Secret管理配置,避免硬编码配置信息。
c.网络策略
配置NetworkPolicy实现网络隔离和安全控制。
b.运维管理
a.监控告警
集成Prometheus和Grafana进行监控和告警。
b.日志收集
使用EFK栈进行日志收集和分析。
c.故障排查
掌握kubectl和Kubernetes Dashboard的使用技巧。
c.性能调优
a.资源配置
根据应用特性合理设置CPU和内存资源。
b.扩缩容策略
配置合适的HPA策略,实现自动扩缩容。
c.网络优化
优化服务发现和负载均衡策略,提升服务性能。
3.6 自定义注册中心
01.自定义注册中心概述
a.功能说明
go-micro提供灵活的插件机制,允许开发者实现自定义注册中心来满足特定需求。自定义注册中心需要实现registry.Registry接口。
b.接口设计
a.基础接口要求
必须实现registry.Registry接口的所有方法,包括服务注册、注销、查询、监听等核心功能。
b.扩展接口支持
可选实现自定义扩展方法,如服务过滤、健康检查、指标收集等高级特性。
c.插件机制集成
通过go-micro的插件系统无缝集成,支持配置注入和生命周期管理。
c.应用场景
a.特殊存储需求
需要将服务信息存储到特定数据库或存储系统中。
b.企业集成要求
需要与现有企业服务注册中心集成。
c.定制化功能
需要实现特殊的服务发现逻辑或扩展功能。
d.设计原则
a.接口一致性
严格遵循registry.Registry接口规范,确保兼容性。
b.性能优化
针对具体场景优化性能,如缓存、索引、批量操作等。
c.高可用设计
支持集群部署和故障恢复机制。
d.可观测性
提供完整的监控指标和日志记录功能。
02.注册中心接口扩展
a.自定义接口定义
a.功能说明
定义扩展接口,在标准registry.Registry基础上增加自定义功能。
b.代码示例
---
// 自定义注册中心接口扩展
type CustomRegistry interface {
registry.Registry
// 扩展方法
WatchWithOptions(opts ...registry.WatchOption) (registry.Watcher, error)
RegisterWithMetadata(s *registry.Service, metadata map[string]interface{}, opts ...registry.RegisterOption) error
GetServiceWithMetadata(name string, metadata map[string]string) ([]*registry.Service, error)
HealthCheck() error
GetMetrics() *RegistryMetrics
}
// RegistryMetrics 注册中心指标
type RegistryMetrics struct {
ServicesCount int64
NodesCount int64
RegisterRequests int64
DeregisterRequests int64
GetRequests int64
WatchRequests int64
ErrorCount int64
LastUpdateTime time.Time
}
// ServiceFilter 服务过滤器
type ServiceFilter struct {
Name string
Version string
Tags []string
Metadata map[string]string
Predicate func(*registry.Service) bool
}
// NodeFilter 节点过滤器
type NodeFilter struct {
ID string
Address string
Port int
Tags []string
Metadata map[string]string
Predicate func(*registry.Node) bool
}
---
b.数据结构设计
a.服务记录结构
定义服务记录的完整结构,包括服务信息和元数据。
b.监听器管理
管理服务变化监听器的生命周期和通知机制。
c.指标收集
收集注册中心的运行指标和性能数据。
03.基础实现架构
a.核心结构设计
a.功能说明
实现自定义注册中心的核心数据结构和管理组件。
b.代码示例
---
// customRegistry 自定义注册中心实现
type customRegistry struct {
opts registry.Options
services map[string]*serviceRecord
watchers map[string][]*customWatcher
mu sync.RWMutex
metrics *RegistryMetrics
metricsMu sync.RWMutex
ctx context.Context
cancel context.CancelFunc
}
// serviceRecord 服务记录
type serviceRecord struct {
service *registry.Service
timestamp time.Time
metadata map[string]interface{}
}
// customWatcher 自定义监听器
type customWatcher struct {
opts registry.WatchOptions
ch chan *registry.Result
exit chan struct{}
registry *customRegistry
lastIndex uint64
}
---
b.构造函数实现
a.功能说明
实现自定义注册中心的创建和初始化逻辑。
b.代码示例
---
// NewCustomRegistry 创建自定义注册中心
func NewCustomRegistry(opts ...registry.Option) CustomRegistry {
options := registry.Options{
Context: context.Background(),
}
for _, o := range opts {
o(&options)
}
ctx, cancel := context.WithCancel(options.Context)
cr := &customRegistry{
opts: options,
services: make(map[string]*serviceRecord),
watchers: make(map[string][]*customWatcher),
metrics: &RegistryMetrics{
LastUpdateTime: time.Now(),
},
ctx: ctx,
cancel: cancel,
}
// 启动清理协程
go cr.cleanup()
return cr
}
---
04.核心功能实现
a.服务注册功能
a.功能说明
实现服务注册的核心逻辑,包括参数验证、记录更新和监听器通知。
b.代码示例
---
// Register 注册服务
func (cr *customRegistry) Register(s *registry.Service, opts ...registry.RegisterOption) error {
var options registry.RegisterOptions
for _, o := range opts {
o(&options)
}
if s == nil || len(s.Nodes) == 0 {
return fmt.Errorf("invalid service")
}
cr.mu.Lock()
defer cr.mu.Unlock()
// 更新服务记录
record := &serviceRecord{
service: s,
timestamp: time.Now(),
metadata: make(map[string]interface{}),
}
cr.services[s.Name] = record
// 更新指标
cr.updateMetrics(func(m *RegistryMetrics) {
m.ServicesCount = int64(len(cr.services))
var nodeCount int
for _, r := range cr.services {
nodeCount += len(r.service.Nodes)
}
m.NodesCount = int64(nodeCount)
m.RegisterRequests++
m.LastUpdateTime = time.Now()
})
// 通知监听器
cr.notifyWatchers("create", s)
log.Logf("registered service: %s", s.Name)
return nil
}
---
b.服务查询功能
a.功能说明
实现服务查询和列表功能,支持单个服务查询和全量服务列表。
b.代码示例
---
// GetService 获取服务
func (cr *customRegistry) GetService(name string, opts ...registry.GetOption) ([]*registry.Service, error) {
cr.mu.RLock()
defer cr.mu.RUnlock()
// 更新指标
cr.updateMetrics(func(m *RegistryMetrics) {
m.GetRequests++
})
record, exists := cr.services[name]
if !exists {
return nil, fmt.Errorf("service not found: %s", name)
}
// 深拷贝服务以避免并发修改
service := cr.deepCopyService(record.service)
return []*registry.Service{service}, nil
}
// ListServices 列出所有服务
func (cr *customRegistry) ListServices() ([]*registry.Service, error) {
cr.mu.RLock()
defer cr.mu.RUnlock()
// 更新指标
cr.updateMetrics(func(m *RegistryMetrics) {
m.GetRequests++
})
var services []*registry.Service
for _, record := range cr.services {
service := cr.deepCopyService(record.service)
services = append(services, service)
}
return services, nil
}
---
c.服务监听功能
a.功能说明
实现服务变化的监听机制,支持订阅和取消订阅操作。
b.代码示例
---
// Watch 监听服务变化
func (cr *customRegistry) Watch(opts ...registry.WatchOption) (registry.Watcher, error) {
var options registry.WatchOptions
for _, o := range opts {
o(&options)
}
cr.mu.Lock()
defer cr.mu.Unlock()
watcher := &customWatcher{
opts: options,
ch: make(chan *registry.Result, 10),
exit: make(chan struct{}),
registry: cr,
}
// 添加到监听器列表
cr.watchers[options.Service] = append(cr.watchers[options.Service], watcher)
// 更新指标
cr.updateMetrics(func(m *RegistryMetrics) {
m.WatchRequests++
})
return watcher, nil
}
---
05.监听器实现
a.监听器接口实现
a.功能说明
实现监听器的核心方法,包括获取下一个变化和停止监听。
b.代码示例
---
// Next 获取下一个变化
func (cw *customWatcher) Next() (*registry.Result, error) {
for {
select {
case <-cw.exit:
return nil, registry.ErrWatcherStopped
case res := <-cw.ch:
return res, nil
case <-time.After(30 * time.Second):
// 超时检查,确保监听器仍然活跃
if cw.isStopped() {
return nil, registry.ErrWatcherStopped
}
}
}
}
// Stop 停止监听
func (cw *customWatcher) Stop() {
select {
case <-cw.exit:
return
default:
close(cw.exit)
}
// 从注册中心移除监听器
cw.registry.mu.Lock()
defer cw.registry.mu.Unlock()
watchers := cw.registry.watchers[cw.opts.Service]
for i, w := range watchers {
if w == cw {
cw.registry.watchers[cw.opts.Service] = append(watchers[:i], watchers[i+1:]...)
break
}
}
}
// isStopped 检查是否已停止
func (cw *customWatcher) isStopped() bool {
select {
case <-cw.exit:
return true
default:
return false
}
}
---
b.通知机制实现
a.功能说明
实现服务变化时通知所有相关监听器的机制。
b.代码示例
---
// notifyWatchers 通知监听器
func (cr *customRegistry) notifyWatchers(action string, service *registry.Service) {
for serviceName, watchers := range cr.watchers {
// 检查是否需要通知此监听器
if serviceName == "" || serviceName == service.Name {
for _, watcher := range watchers {
select {
case watcher.ch <- ®istry.Result{
Action: action,
Service: cr.deepCopyService(service),
}:
default:
// 通道满,记录警告
log.Logf("watcher channel full, dropping notification")
cr.updateMetrics(func(m *RegistryMetrics) {
m.ErrorCount++
})
}
}
}
}
}
---
06.高级功能实现
a.服务过滤功能
a.功能说明
实现基于条件的服务过滤功能,支持按名称、版本、标签等条件过滤。
b.代码示例
---
// FilterServices 过滤服务
func (cr *customRegistry) FilterServices(filter *ServiceFilter) ([]*registry.Service, error) {
cr.mu.RLock()
defer cr.mu.RUnlock()
var services []*registry.Service
for _, record := range cr.services {
service := record.service
if cr.serviceMatchesFilter(service, filter) {
filteredService := cr.filterServiceNodes(service, filter)
services = append(services, filteredService)
}
}
return services, nil
}
// serviceMatchesFilter 检查服务是否匹配过滤器
func (cr *customRegistry) serviceMatchesFilter(service *registry.Service, filter *ServiceFilter) bool {
// 名称过滤
if filter.Name != "" && service.Name != filter.Name {
return false
}
// 版本过滤
if filter.Version != "" && service.Version != filter.Version {
return false
}
// 标签过滤
if len(filter.Tags) > 0 {
if !cr.containsAllTags(service.Endpoints, filter.Tags) {
return false
}
}
// 元数据过滤
if len(filter.Metadata) > 0 {
if !cr.metadataMatches(service.Metadata, filter.Metadata) {
return false
}
}
// 自定义谓词过滤
if filter.Predicate != nil && !filter.Predicate(service) {
return false
}
return true
}
---
b.健康检查功能
a.功能说明
实现服务健康检查机制,定期检查服务节点状态。
b.代码示例
---
// HealthChecker 健康检查器
type HealthChecker interface {
CheckHealth(service *registry.Service) error
IsHealthy(service *registry.Service) bool
}
// defaultHealthChecker 默认健康检查器
type defaultHealthChecker struct {
timeout time.Duration
}
// NewDefaultHealthChecker 创建默认健康检查器
func NewDefaultHealthChecker(timeout time.Duration) HealthChecker {
return &defaultHealthChecker{
timeout: timeout,
}
}
// CheckHealth 检查服务健康状态
func (hc *defaultHealthChecker) CheckHealth(service *registry.Service) error {
ctx, cancel := context.WithTimeout(context.Background(), hc.timeout)
defer cancel()
// 对每个节点进行健康检查
for _, node := range service.Nodes {
err := hc.checkNodeHealth(ctx, node)
if err != nil {
return fmt.Errorf("node %s unhealthy: %v", node.Id, err)
}
}
return nil
}
// checkNodeHealth 检查节点健康状态
func (hc *defaultHealthChecker) checkNodeHealth(ctx context.Context, node *registry.Node) error {
// 实现TCP连接检查
address := fmt.Sprintf("%s:%d", node.Address, node.Port)
conn, err := net.DialTimeout("tcp", address, hc.timeout)
if err != nil {
return err
}
defer conn.Close()
return nil
}
---
c.持久化支持
a.功能说明
实现服务数据持久化功能,支持文件、数据库等多种存储方式。
b.代码示例
---
// Persistence 持久化接口
type Persistence interface {
Save(services map[string]*serviceRecord) error
Load() (map[string]*serviceRecord, error)
}
// FilePersistence 文件持久化
type FilePersistence struct {
filePath string
mu sync.RWMutex
}
// Save 保存服务到文件
func (fp *FilePersistence) Save(services map[string]*serviceRecord) error {
fp.mu.Lock()
defer fp.mu.Unlock()
data, err := json.MarshalIndent(services, "", " ")
if err != nil {
return err
}
return os.WriteFile(fp.filePath, data, 0644)
}
// Load 从文件加载服务
func (fp *FilePersistence) Load() (map[string]*serviceRecord, error) {
fp.mu.RLock()
defer fp.mu.RUnlock()
data, err := os.ReadFile(fp.filePath)
if err != nil {
if os.IsNotExist(err) {
return make(map[string]*serviceRecord), nil
}
return nil, err
}
var services map[string]*serviceRecord
err = json.Unmarshal(data, &services)
if err != nil {
return nil, err
}
return services, nil
}
---
07.使用示例
a.基础使用示例
a.功能说明
展示如何创建和使用自定义注册中心进行服务注册和发现。
b.代码示例
---
package main
import (
"context"
"log"
"time"
"github.com/micro/go-micro/v2"
"github.com/micro/go-micro/v2/registry"
)
func main() {
// 创建自定义注册中心
customReg := custom.NewCustomRegistry(
registry.Context("custom.option1", "value1"),
registry.Context("custom.option2", "value2"),
)
// 启用持久化
persistence := custom.NewFilePersistence("/tmp/services.json")
if err := customReg.EnablePersistence(persistence); err != nil {
log.Printf("failed to enable persistence: %v", err)
}
// 创建服务
service := micro.NewService(
micro.Name("user.service"),
micro.Version("latest"),
micro.Registry(customReg),
micro.RegisterTTL(time.Second*30),
)
service.Init()
// 注册处理器
if err := service.Server().Handle(
service.Server().NewHandler(&UserHandler{}),
); err != nil {
log.Fatal(err)
}
// 启动服务
if err := service.Run(); err != nil {
log.Fatal(err)
}
}
---
b.扩展功能使用示例
a.功能说明
展示如何使用自定义注册中心的扩展功能,如元数据查询、服务过滤等。
b.代码示例
---
// 使用扩展功能
func useExtendedFeatures() {
customReg := custom.NewCustomRegistry()
// 带元数据注册
service := ®istry.Service{
Name: "advanced.service",
Version: "v1.0.0",
Nodes: []*registry.Node{
{
Id: "node1",
Address: "localhost",
Port: 8080,
},
},
}
metadata := map[string]interface{}{
"region": "us-west",
"environment": "production",
"created_at": time.Now(),
}
if err := customReg.RegisterWithMetadata(service, metadata); err != nil {
log.Printf("failed to register with metadata: %v", err)
}
// 按元数据查询
services, err := customReg.GetServiceWithMetadata("advanced.service", map[string]string{
"region": "us-west",
})
if err != nil {
log.Printf("failed to get service with metadata: %v", err)
}
log.Printf("Found %d services", len(services))
// 过滤服务
filter := &custom.ServiceFilter{
Name: "advanced.service",
Version: "v1.0.0",
Metadata: map[string]string{
"environment": "production",
},
}
filteredServices, err := customReg.FilterServices(filter)
if err != nil {
log.Printf("failed to filter services: %v", err)
}
log.Printf("Filtered %d services", len(filteredServices))
// 健康检查
if err := customReg.HealthCheck(); err != nil {
log.Printf("health check failed: %v", err)
}
// 获取指标
metrics := customReg.GetMetrics()
log.Printf("Registry metrics: %+v", metrics)
}
---
08.性能优化和监控
a.性能优化策略
a.功能说明
实现多种性能优化策略,如缓存、索引、连接池等。
b.代码示例
---
// OptimizedRegistry 优化的注册中心
type OptimizedRegistry struct {
*customRegistry
// 缓存
serviceCache map[string]*registry.Service
cacheTTL time.Duration
lastCacheUpdate time.Time
// 索引
nameIndex map[string][]*registry.Service
tagIndex map[string][]*registry.Service
// 性能监控
requestLatency prometheus.HistogramVec
errorCounter prometheus.CounterVec
}
// GetService 优化的服务获取
func (or *OptimizedRegistry) GetService(name string, opts ...registry.GetOption) ([]*registry.Service, error) {
start := time.Now()
defer func() {
duration := time.Since(start)
status := "success"
or.requestLatency.WithLabelValues("get_service", status).Observe(duration.Seconds())
}()
// 检查缓存
if service, ok := or.getCachedService(name); ok {
return []*registry.Service{service}, nil
}
// 从底层注册中心获取
services, err := or.customRegistry.GetService(name, opts...)
if err != nil {
status = "error"
or.errorCounter.WithLabelValues("get_service", "not_found").Inc()
return nil, err
}
// 更新缓存
if len(services) > 0 {
or.setCachedService(name, services[0])
}
return services, nil
}
---
b.监控指标实现
a.功能说明
实现完整的监控指标收集,包括请求延迟、错误率、资源使用等。
b.代码示例
---
// initMetrics 初始化指标
func (or *OptimizedRegistry) initMetrics() {
or.requestLatency = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "registry_request_duration_seconds",
Help: "Registry request latency",
},
[]string{"method", "status"},
)
or.errorCounter = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "registry_errors_total",
Help: "Registry error count",
},
[]string{"method", "error_type"},
)
prometheus.MustRegister(or.requestLatency, or.errorCounter)
}
---
4 消息与事件处理
4.1 Broker接口设计与实现
01.Broker接口设计概述
a.核心抽象层
Broker接口是go-micro消息系统的核心抽象,定义了消息发布和订阅的标准方法,为不同消息中间件提供统一接口。
b.接口功能
a.消息发布
提供异步消息发布能力,支持多种编解码器和传输选项。
b.消息订阅
实现消息监听和处理,支持过滤器和错误处理机制。
c.连接管理
管理与消息中间件的连接生命周期。
d.配置管理
提供灵活的配置选项和参数管理。
c.设计原则
a.接口统一
为所有消息中间件提供一致的API接口。
b.高度可配置
支持丰富的配置选项满足不同场景需求。
c.类型安全
通过泛型确保消息类型安全。
d.扩展性
支持自定义编解码器和中间件。
02.核心接口定义
a.Message消息接口
a.功能说明
定义消息的基本结构和操作方法。
b.代码示例
---
// Message 消息接口
type Message interface {
// Header 消息头
Header() map[string]string
// Body 消息体
Body() []byte
// Codec 编解码器
Codec() codec.Marshaler
}
---
b.Broker消息中间件接口
a.功能说明
定义消息中间件的核心操作接口。
b.代码示例
---
// Broker 消息中间件接口
type Broker interface {
// Name 返回Broker名称
Name() string
// Options 返回配置选项
Options() Options
// Address 返回连接地址
Address() string
// Connect 连接到消息中间件
Connect(...Option) error
// Disconnect 断开连接
Disconnect() error
// Init 初始化
Init(...Option) error
// Publish 发布消息
Publish(topic string, msg Message, opts ...PublishOption) error
// Subscribe 订阅消息
Subscribe(topic string, handler Handler, opts ...SubscribeOption) (Subscriber, error)
// String 返回字符串表示
String() string
}
---
c.Subscriber订阅者接口
a.功能说明
定义消息订阅者的操作接口。
b.代码示例
---
// Subscriber 订阅者接口
type Subscriber interface {
// Topic 返回主题
Topic() string
// Unsubscribe 取消订阅
Unsubscribe() error
// Options 返回订阅选项
Options() SubscribeOptions
}
---
d.Event事件接口
a.功能说明
定义事件处理的操作接口。
b.代码示例
---
// Event 事件接口
type Event interface {
// Topic 主题
Topic() string
// Message 消息
Message() Message
// Ack 确认消息
Ack() error
// Nack 拒绝消息
Nack() error
}
---
03.配置选项系统
a.Options配置结构
a.功能说明
定义Broker的完整配置选项结构。
b.代码示例
---
// Options Broker配置选项
type Options struct {
Codecs map[string]codec.Marshaler
Context context.Context
ContentType string
SubscribeOptions SubscribeOptions
PublishOptions PublishOptions
}
---
b.PublishOptions发布选项
a.功能说明
定义消息发布的详细配置选项。
b.代码示例
---
// PublishOptions 发布选项
type PublishOptions struct {
// 发布上下文
Context context.Context
// 消息头
Headers map[string]string
// 消息体编解码器
Codec codec.Marshaler
// 发布超时
Timeout time.Duration
// 消息TTL
TTL time.Duration
// 消息优先级
Priority int
// 是否等待确认
WaitForAck bool
}
---
c.SubscribeOptions订阅选项
a.功能说明
定义消息订阅的详细配置选项。
b.代码示例
---
// SubscribeOptions 订阅选项
type SubscribeOptions struct {
// 订阅上下文
Context context.Context
// 自动确认
AutoAck bool
// 订阅队列
Queue string
// 订阅组
Group string
// 错误处理器
ErrorHandler ErrorHandler
// 消息处理器
Handler Handler
// 订阅过滤器
Filter Filter
}
---
04.处理器和过滤器定义
a.Handler消息处理器
a.功能说明
定义消息处理器的函数类型。
b.代码示例
---
// Handler 消息处理器
type Handler func(Message) error
---
b.ErrorHandler错误处理器
a.功能说明
定义错误处理器的函数类型。
b.代码示例
---
// ErrorHandler 错误处理器
type ErrorHandler func(Message, error) error
---
c.Filter消息过滤器
a.功能说明
定义消息过滤器的函数类型。
b.代码示例
---
// Filter 消息过滤器
type Filter func(Message) bool
---
05.错误定义
a.核心错误类型
a.功能说明
定义Broker操作的核心错误类型。
b.代码示例
---
var (
ErrInvalidMessage = errors.New("invalid message")
ErrNotConnected = errors.New("not connected")
ErrPublishTimeout = errors.New("publish timeout")
)
---
06.默认实现架构
a.defaultBroker结构
a.功能说明
实现内存消息中间件的默认结构。
b.代码示例
---
// defaultBroker 默认Broker实现
type defaultBroker struct {
sync.RWMutex
opts Options
subscribers map[string][]*subscriber
running bool
exit chan struct{}
}
---
b.subscriber订阅者实现
a.功能说明
实现内存模式下的订阅者结构。
b.代码示例
---
// subscriber 订阅者实现
type subscriber struct {
topic string
handler Handler
opts SubscribeOptions
exit chan struct{}
}
---
c.message消息实现
a.功能说明
实现内存模式下的消息结构。
b.代码示例
---
// message 消息实现
type message struct {
headers map[string]string
body []byte
codec codec.Marshaler
}
---
07.Broker构造函数
a.NewBroker创建函数
a.功能说明
实现默认Broker的创建逻辑,包括初始化配置和编解码器。
b.代码示例
---
// NewBroker 创建默认Broker
func NewBroker(opts ...Option) Broker {
options := Options{
Codecs: make(map[string]codec.Marshaler),
Context: context.Background(),
ContentType: "application/json",
}
for _, o := range opts {
o(&options)
}
// 注册默认编解码器
if _, ok := options.Codecs[options.ContentType]; !ok {
options.Codecs[options.ContentType] = &json.Codec{}
}
return &defaultBroker{
opts: options,
subscribers: make(map[string][]*subscriber),
exit: make(chan struct{}),
}
}
---
08.连接管理实现
a.Connect连接方法
a.功能说明
实现连接到消息中间件的逻辑,包括状态管理和配置应用。
b.代码示例
---
// Connect 连接到消息中间件
func (b *defaultBroker) Connect(opts ...Option) error {
b.Lock()
defer b.Unlock()
if b.running {
return nil
}
for _, o := range opts {
o(&b.opts)
}
b.running = true
log.Logf("broker connected")
return nil
}
---
b.Disconnect断开连接方法
a.功能说明
实现断开连接的逻辑,包括资源清理和状态更新。
b.代码示例
---
// Disconnect 断开连接
func (b *defaultBroker) Disconnect() error {
b.Lock()
defer b.Unlock()
if !b.running {
return nil
}
close(b.exit)
b.running = false
log.Logf("broker disconnected")
return nil
}
---
09.消息发布实现
a.Publish发布方法
a.功能说明
实现消息发布的完整逻辑,包括参数验证、选项处理和异步投递。
b.代码示例
---
// Publish 发布消息
func (b *defaultBroker) Publish(topic string, msg Message, opts ...PublishOption) error {
b.RLock()
defer b.RUnlock()
if !b.running {
return ErrNotConnected
}
options := PublishOptions{
Context: b.opts.Context,
Timeout: time.Second * 5,
WaitForAck: false,
}
for _, o := range opts {
o(&options)
}
if msg == nil {
return ErrInvalidMessage
}
// 获取消息内容
body := msg.Body()
if len(body) == 0 {
return ErrInvalidMessage
}
// 设置消息头
headers := make(map[string]string)
for k, v := range msg.Header() {
headers[k] = v
}
// 应用发布选项
if options.Headers != nil {
for k, v := range options.Headers {
headers[k] = v
}
}
// 添加时间戳
headers["timestamp"] = time.Now().Format(time.RFC3339)
headers["content-type"] = b.opts.ContentType
// 创建新的消息
newMsg := &message{
headers: headers,
body: body,
codec: b.opts.Codecs[b.opts.ContentType],
}
// 异步发布消息
go func() {
b.publishToSubscribers(topic, newMsg, options)
}()
return nil
}
---
b.publishToSubscribers订阅者通知
a.功能说明
实现向所有订阅者投递消息的逻辑,包括并发控制和错误处理。
b.代码示例
---
// publishToSubscribers 发布消息到订阅者
func (b *defaultBroker) publishToSubscribers(topic string, msg *message, opts PublishOptions) {
b.RLock()
subs := b.subscribers[topic]
b.RUnlock()
var wg sync.WaitGroup
semaphore := make(chan struct{}, 100) // 限制并发数
for _, sub := range subs {
select {
case <-sub.exit:
continue
default:
wg.Add(1)
semaphore <- struct{}{}
go func(s *subscriber) {
defer wg.Done()
defer func() { <-semaphore }()
b.deliverMessage(s, msg, opts)
}(sub)
}
}
wg.Wait()
if opts.WaitForAck {
// 等待所有确认
time.Sleep(time.Millisecond * 100)
}
}
---
c.deliverMessage消息投递
a.功能说明
实现单个消息的投递逻辑,包括过滤器和错误处理。
b.代码示例
---
// deliverMessage 投递消息
func (b *defaultBroker) deliverMessage(sub *subscriber, msg *message, opts PublishOptions) {
defer func() {
if r := recover(); r != nil {
log.Logf("message delivery panic: %v", r)
if sub.opts.ErrorHandler != nil {
sub.opts.ErrorHandler(msg, fmt.Errorf("panic: %v", r))
}
}
}()
// 应用过滤器
if sub.opts.Filter != nil && !sub.opts.Filter(msg) {
return
}
// 处理消息
err := sub.handler(msg)
if err != nil {
log.Logf("message handler error: %v", err)
if sub.opts.ErrorHandler != nil {
sub.opts.ErrorHandler(msg, err)
}
}
}
---
10.消息订阅实现
a.Subscribe订阅方法
a.功能说明
实现消息订阅的完整逻辑,包括订阅者创建和管理。
b.代码示例
---
// Subscribe 订阅消息
func (b *defaultBroker) Subscribe(topic string, handler Handler, opts ...SubscribeOption) (Subscriber, error) {
b.Lock()
defer b.Unlock()
options := SubscribeOptions{
Context: b.opts.Context,
AutoAck: true,
Handler: handler,
Queue: "",
Group: "",
ErrorHandler: func(msg Message, err error) error {
log.Logf("subscriber error: %v", err)
return nil
},
}
for _, o := range opts {
o(&options)
}
if handler == nil {
return nil, ErrInvalidMessage
}
sub := &subscriber{
topic: topic,
handler: handler,
opts: options,
exit: make(chan struct{}),
}
b.subscribers[topic] = append(b.subscribers[topic], sub)
// 启动订阅协程
go b.runSubscriber(sub)
log.Logf("subscribed to topic: %s", topic)
return sub, nil
}
---
b.runSubscriber订阅者运行
a.功能说明
实现订阅者的运行逻辑,包括连接状态监控和生命周期管理。
b.代码示例
---
// runSubscriber 运行订阅者
func (b *defaultBroker) runSubscriber(sub *subscriber) {
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-sub.exit:
return
case <-ticker.C:
// 定期检查连接状态
b.RLock()
running := b.running
b.RUnlock()
if !running {
return
}
}
}
}
---
11.选项函数实现
a.发布选项函数
a.功能说明
实现各种发布选项的配置函数。
b.代码示例
---
// WithPublishContext 设置发布上下文
func WithPublishContext(ctx context.Context) PublishOption {
return func(o *PublishOptions) {
o.Context = ctx
}
}
// WithPublishHeaders 设置消息头
func WithPublishHeaders(headers map[string]string) PublishOption {
return func(o *PublishOptions) {
o.Headers = headers
}
}
// WithPublishTimeout 设置发布超时
func WithPublishTimeout(timeout time.Duration) PublishOption {
return func(o *PublishOptions) {
o.Timeout = timeout
}
}
---
b.订阅选项函数
a.功能说明
实现各种订阅选项的配置函数。
b.代码示例
---
// WithSubscribeContext 设置订阅上下文
func WithSubscribeContext(ctx context.Context) SubscribeOption {
return func(o *SubscribeOptions) {
o.Context = ctx
}
}
// WithAutoAck 设置自动确认
func WithAutoAck(autoAck bool) SubscribeOption {
return func(o *SubscribeOptions) {
o.AutoAck = autoAck
}
}
// WithQueue 设置队列
func WithQueue(queue string) SubscribeOption {
return func(o *SubscribeOptions) {
o.Queue = queue
}
}
---
12.消息工具函数
a.NewMessage消息创建函数
a.功能说明
实现消息的创建逻辑,支持各种选项配置。
b.代码示例
---
// NewMessage 创建消息
func NewMessage(contentType string, body []byte, opts ...MessageOption) Message {
headers := make(map[string]string)
options := MessageOptions{
Headers: headers,
Codec: &json.Codec{},
}
for _, o := range opts {
o(&options)
}
return &message{
headers: options.Headers,
body: body,
codec: options.Codec,
}
}
---
b.MessageHeader消息头设置函数
a.功能说明
实现消息头的设置功能。
b.代码示例
---
// MessageHeader 设置消息头
func MessageHeader(key, value string) MessageOption {
return func(o *MessageOptions) {
if o.Headers == nil {
o.Headers = make(map[string]string)
}
o.Headers[key] = value
}
}
---
c.MessageCodec编解码器设置函数
a.功能说明
实现消息编解码器的设置功能。
b.代码示例
---
// MessageCodec 设置编解码器
func MessageCodec(codec codec.Marshaler) MessageOption {
return func(o *MessageOptions) {
o.Codec = codec
}
}
---
13.使用示例
a.基础Broker使用示例
a.功能说明
展示如何创建和使用Broker进行消息发布和订阅。
b.代码示例
---
func main() {
// 创建Broker
br := broker.NewBroker(
broker.WithCodec("application/json", &json.Codec{}),
broker.WithCodec("application/proto", &proto.Codec{}),
broker.WithContentType("application/json"),
)
// 连接Broker
if err := br.Connect(); err != nil {
fmt.Printf("failed to connect broker: %v\n", err)
return
}
defer br.Disconnect()
// 发布消息
go publishMessages(br)
// 订阅消息
subscribeMessages(br)
// 等待
time.Sleep(time.Minute)
}
---
b.消息发布示例
a.功能说明
展示详细的消息发布流程和配置选项。
b.代码示例
---
func publishMessages(br broker.Broker) {
ticker := time.NewTicker(time.Second * 5)
defer ticker.Stop()
for i := 0; i < 10; i++ {
select {
case <-ticker.C:
// 创建消息
msg := broker.NewMessage("application/json", []byte(fmt.Sprintf(`{"id": %d, "message": "hello world"}`, i)),
broker.MessageHeader("source", "publisher"),
broker.MessageHeader("version", "1.0"),
)
// 发布消息
err := br.Publish("test.topic", msg,
broker.WithPublishHeaders(map[string]string{
"publisher": "example",
"timestamp": time.Now().Format(time.RFC3339),
}),
broker.WithPublishTimeout(time.Second*10),
)
if err != nil {
fmt.Printf("failed to publish message: %v\n", err)
} else {
fmt.Printf("published message: %d\n", i)
}
}
}
}
---
c.消息订阅示例
a.功能说明
展示详细的消息订阅流程和配置选项。
b.代码示例
---
func subscribeMessages(br broker.Broker) {
// 订阅消息
sub, err := br.Subscribe("test.topic", func(msg broker.Message) error {
// 处理消息
fmt.Printf("received message: %s\n", string(msg.Body()))
fmt.Printf("headers: %v\n", msg.Header())
// 解析消息
var data struct {
ID int `json:"id"`
Message string `json:"message"`
}
if err := json.Unmarshal(msg.Body(), &data); err != nil {
return fmt.Errorf("failed to unmarshal message: %v", err)
}
fmt.Printf("processed message: id=%d, message=%s\n", data.ID, data.Message)
return nil
},
broker.WithQueue("worker"),
broker.WithGroup("consumer"),
broker.WithAutoAck(true),
broker.WithFilter(func(msg broker.Message) bool {
// 过滤消息
source := msg.Header()["source"]
return source == "publisher"
}),
broker.WithErrorHandler(func(msg broker.Message, err error) error {
fmt.Printf("message error: %v\n", err)
return nil // 返回nil继续处理其他消息
}),
)
if err != nil {
fmt.Printf("failed to subscribe: %v\n", err)
return
}
defer sub.Unsubscribe()
fmt.Printf("subscribed to topic: %s\n", sub.Topic())
}
---
4.2 RabbitMQ集成
01.RabbitMQ概述
a.核心概念
RabbitMQ是一个功能强大的开源消息代理,实现了AMQP(高级消息队列协议)标准。它提供了可靠的消息传递、灵活的路由、集群支持和高可用性。
b.核心组件
a.Producer消息生产者
负责创建和发送消息到交换机的应用程序。
b.Consumer消息消费者
从队列接收消息并进行处理的应用程序。
c.Queue消息队列
存储消息直到消费者接收的缓冲区。
d.Exchange消息交换机
接收来自生产者的消息并将它们路由到队列。
e.Binding绑定关系
建立交换机和队列之间的路由规则。
f.Routing Key路由键
用于消息路由的标识符。
g.Virtual Host虚拟主机
提供多租户隔离的逻辑分组。
c.交换机类型
a.Direct直接交换
精确匹配路由键进行消息路由。
b.Topic主题交换
支持通配符模式的灵活路由。
c.Fanout扇形交换
将消息广播到所有绑定的队列。
d.Headers头部交换
基于消息头属性进行路由匹配。
02.RabbitMQ Broker实现架构
a.核心结构设计
a.功能说明
设计RabbitMQ Broker的核心数据结构和组件管理。
b.代码示例
---
// rabbitmqBroker RabbitMQ Broker实现
type rabbitmqBroker struct {
sync.RWMutex
options broker.Options
connection *amqp.Connection
channel *amqp.Channel
connected bool
consumers map[string][]*rabbitmqSubscriber
exchanges map[string]bool
queues map[string]bool
prefetch int
reconnect bool
reconnectInterval time.Duration
}
// rabbitmqSubscriber RabbitMQ订阅者
type rabbitmqSubscriber struct {
topic string
handler broker.Handler
opts broker.SubscribeOptions
queue string
bindingKey string
tag string
exit chan struct{}
broker *rabbitmqBroker
}
// rabbitmqMessage RabbitMQ消息
type rabbitmqMessage struct {
headers map[string]string
body []byte
delivery *amqp.Delivery
codec codec.Marshaler
}
---
b.构造函数实现
a.功能说明
实现RabbitMQ Broker的创建逻辑,包括默认配置和初始化。
b.代码示例
---
// NewBroker 创建RabbitMQ Broker
func NewBroker(opts ...broker.Option) broker.Broker {
options := broker.Options{
Codecs: make(map[string]codec.Marshaler),
Context: context.Background(),
ContentType: "application/json",
}
for _, o := range opts {
o(&options)
}
// 注册默认编解码器
if _, ok := options.Codecs[options.ContentType]; !ok {
options.Codecs[options.ContentType] = &jsonCodec{}
}
return &rabbitmqBroker{
options: options,
consumers: make(map[string][]*rabbitmqSubscriber),
exchanges: make(map[string]bool),
queues: make(map[string]bool),
prefetch: 10,
reconnect: true,
reconnectInterval: time.Second * 5,
}
}
---
03.连接管理实现
a.Connect连接方法
a.功能说明
实现与RabbitMQ服务器的连接建立,包括连接配置和QoS设置。
b.代码示例
---
// Connect 连接到RabbitMQ
func (r *rabbitmqBroker) Connect(opts ...broker.Option) error {
r.Lock()
defer r.Unlock()
if r.connected {
return nil
}
for _, o := range opts {
o(&r.options)
}
var err error
url := r.Address()
// 连接到RabbitMQ
r.connection, err = amqp.Dial(url)
if err != nil {
return fmt.Errorf("failed to connect to RabbitMQ: %v", err)
}
// 创建通道
r.channel, err = r.connection.Channel()
if err != nil {
r.connection.Close()
return fmt.Errorf("failed to create channel: %v", err)
}
// 设置QoS
if err := r.channel.Qos(r.prefetch, 0, false); err != nil {
r.channel.Close()
r.connection.Close()
return fmt.Errorf("failed to set QoS: %v", err)
}
r.connected = true
// 启动重连协程
if r.reconnect {
go r.reconnectLoop()
}
log.Logf("connected to RabbitMQ at %s", url)
return nil
}
---
b.Disconnect断开连接方法
a.功能说明
实现连接关闭和资源清理逻辑。
b.代码示例
---
// Disconnect 断开连接
func (r *rabbitmqBroker) Disconnect() error {
r.Lock()
defer r.Unlock()
if !r.connected {
return nil
}
r.connected = false
// 关闭所有订阅者
for _, subscribers := range r.consumers {
for _, sub := range subscribers {
close(sub.exit)
}
}
// 关闭通道和连接
if r.channel != nil {
r.channel.Close()
}
if r.connection != nil {
r.connection.Close()
}
log.Logf("disconnected from RabbitMQ")
return nil
}
---
04.消息发布实现
a.Publish发布方法
a.功能说明
实现消息发布的核心逻辑,包括交换机声明、消息构建和发送。
b.代码示例
---
// Publish 发布消息
func (r *rabbitmqBroker) Publish(topic string, msg broker.Message, opts ...broker.PublishOption) error {
r.RLock()
if !r.connected {
r.RUnlock()
return fmt.Errorf("not connected to RabbitMQ")
}
channel := r.channel
r.RUnlock()
options := broker.PublishOptions{
Context: r.options.Context,
Headers: make(map[string]string),
Timeout: time.Second * 5,
WaitForAck: false,
}
for _, o := range opts {
o(&options)
}
if msg == nil {
return broker.ErrInvalidMessage
}
// 确保交换机存在
if err := r.declareExchange(topic); err != nil {
return fmt.Errorf("failed to declare exchange: %v", err)
}
// 构建消息头
headers := make(amqp.Table)
for k, v := range msg.Header() {
headers[k] = v
}
// 应用发布选项
for k, v := range options.Headers {
headers[k] = v
}
// 添加go-micro特定头部
headers["micro.timestamp"] = time.Now().Format(time.RFC3339)
headers["micro.content_type"] = r.options.ContentType
// 获取消息内容
body := msg.Body()
if len(body) == 0 {
return broker.ErrInvalidMessage
}
// 设置发布选项
publishing := amqp.Publishing{
Headers: headers,
ContentType: r.options.ContentType,
Body: body,
DeliveryMode: amqp.Persistent, // 持久化消息
Timestamp: time.Now(),
}
// 设置TTL
if options.TTL > 0 {
publishing.Expiration = fmt.Sprintf("%d", int(options.TTL.Milliseconds()))
}
// 设置优先级
if options.Priority > 0 {
publishing.Priority = uint8(options.Priority)
}
// 发布消息
err := channel.Publish(
topic, // exchange
"", // routing key
false, // mandatory
false, // immediate
publishing, // message
)
if err != nil {
return fmt.Errorf("failed to publish message: %v", err)
}
log.Logf("published message to topic %s", topic)
return nil
}
---
b.交换机声明方法
a.功能说明
实现RabbitMQ交换机的声明和管理。
b.代码示例
---
// declareExchange 声明交换机
func (r *rabbitmqBroker) declareExchange(topic string) error {
if r.exchanges[topic] {
return nil
}
err := r.channel.ExchangeDeclare(
topic, // name
"topic", // type
true, // durable
false, // auto-deleted
false, // internal
false, // no-wait
nil, // arguments
)
if err != nil {
return err
}
r.exchanges[topic] = true
return nil
}
---
05.消息订阅实现
a.Subscribe订阅方法
a.功能说明
实现消息订阅的完整流程,包括队列声明、绑定和消费。
b.代码示例
---
// Subscribe 订阅消息
func (r *rabbitmqBroker) Subscribe(topic string, handler broker.Handler, opts ...broker.SubscribeOption) (broker.Subscriber, error) {
r.Lock()
defer r.Unlock()
options := broker.SubscribeOptions{
Context: r.options.Context,
AutoAck: true,
Queue: "",
Group: "",
ErrorHandler: func(msg broker.Message, err error) error {
log.Logf("subscriber error: %v", err)
return nil
},
}
for _, o := range opts {
o(&options)
}
if handler == nil {
return nil, broker.ErrInvalidMessage
}
// 确保交换机存在
if err := r.declareExchange(topic); err != nil {
return nil, fmt.Errorf("failed to declare exchange: %v", err)
}
// 生成队列名称
queueName := options.Queue
if queueName == "" {
if options.Group != "" {
queueName = fmt.Sprintf("%s.%s", topic, options.Group)
} else {
queueName = fmt.Sprintf("%s.%s", topic, fmt.Sprintf("%d", time.Now().UnixNano()))
}
}
// 声明队列
if err := r.declareQueue(queueName, options); err != nil {
return nil, fmt.Errorf("failed to declare queue: %v", err)
}
// 绑定队列到交换机
bindingKey := ""
if options.Group != "" {
bindingKey = options.Group
}
if err := r.bindQueue(queueName, topic, bindingKey); err != nil {
return nil, fmt.Errorf("failed to bind queue: %v", err)
}
// 开始消费消息
msgs, err := r.channel.Consume(
queueName, // queue
"", // consumer
options.AutoAck, // auto-ack
false, // exclusive
false, // no-local
false, // no-wait
nil, // args
)
if err != nil {
return nil, fmt.Errorf("failed to start consuming: %v", err)
}
// 创建订阅者
sub := &rabbitmqSubscriber{
topic: topic,
handler: handler,
opts: options,
queue: queueName,
bindingKey: bindingKey,
tag: msgs.ConsumerTag,
exit: make(chan struct{}),
broker: r,
}
// 添加到订阅者列表
r.consumers[topic] = append(r.consumers[topic], sub)
// 启动消息处理协程
go r.handleMessages(sub, msgs)
log.Logf("subscribed to topic %s with queue %s", topic, queueName)
return sub, nil
}
---
b.队列声明方法
a.功能说明
实现RabbitMQ队列的声明和配置。
b.代码示例
---
// declareQueue 声明队列
func (r *rabbitmqBroker) declareQueue(name string, opts broker.SubscribeOptions) error {
if r.queues[name] {
return nil
}
arguments := amqp.Table{}
// 设置TTL
if ttl, ok := opts.Context.Value("queue_ttl").(time.Duration); ok {
arguments["x-message-ttl"] = int(ttl.Milliseconds())
}
// 设置最大长度
if maxLength, ok := opts.Context.Value("queue_max_length").(int); ok {
arguments["x-max-length"] = maxLength
}
// 设置死信交换机
if dlx, ok := opts.Context.Value("queue_dlx").(string); ok {
arguments["x-dead-letter-exchange"] = dlx
if dlrk, ok := opts.Context.Value("queue_dlrk").(string); ok {
arguments["x-dead-letter-routing-key"] = dlrk
}
}
_, err := r.channel.QueueDeclare(
name, // name
opts.Queue == "", // durable: 非临时队列才持久化
opts.Queue == "", // auto-delete: 临时队列自动删除
false, // exclusive
false, // no-wait
arguments, // arguments
)
if err != nil {
return err
}
r.queues[name] = true
return nil
}
---
c.消息处理方法
a.功能说明
实现消息接收和处理的逻辑循环。
b.代码示例
---
// handleMessages 处理消息
func (r *rabbitmqBroker) handleMessages(sub *rabbitmqSubscriber, msgs <-chan amqp.Delivery) {
for {
select {
case <-sub.exit:
return
case delivery, ok := <-msgs:
if !ok {
return
}
// 转换AMQP消息为go-micro消息
msg := &rabbitmqMessage{
headers: r.convertAMQPHeaders(delivery.Headers),
body: delivery.Body,
delivery: &delivery,
codec: r.options.Codecs[r.options.ContentType],
}
// 处理消息
if err := sub.handler(msg); err != nil {
log.Logf("message handler error: %v", err)
if sub.opts.ErrorHandler != nil {
sub.opts.ErrorHandler(msg, err)
}
// 如果不是自动确认,拒绝消息
if !sub.opts.AutoAck {
delivery.Nack(false, false) // 不重新入队
}
} else {
// 如果不是自动确认,确认消息
if !sub.opts.AutoAck {
delivery.Ack(false)
}
}
}
}
}
---
06.消息和订阅者实现
a.rabbitmqMessage方法
a.功能说明
实现消息接口的所有方法,提供消息头、消息体和编解码器访问。
b.代码示例
---
// Header 返回消息头
func (m *rabbitmqMessage) Header() map[string]string {
return m.headers
}
// Body 返回消息体
func (m *rabbitmqMessage) Body() []byte {
return m.body
}
// Codec 返回编解码器
func (m *rabbitmqMessage) Codec() codec.Marshaler {
return m.codec
}
---
b.rabbitmqSubscriber方法
a.功能说明
实现订阅者接口的所有方法,包括主题查询、取消订阅和选项访问。
b.代码示例
---
// Topic 返回订阅者主题
func (s *rabbitmqSubscriber) Topic() string {
return s.topic
}
// Unsubscribe 取消订阅
func (s *rabbitmqSubscriber) Unsubscribe() error {
select {
case <-s.exit:
return nil
default:
close(s.exit)
}
// 从消费者标签取消
s.broker.Lock()
defer s.broker.Unlock()
if s.broker.channel != nil && s.tag != "" {
if err := s.broker.channel.Cancel(s.tag, false); err != nil {
log.Logf("failed to cancel consumer: %v", err)
}
}
// 从订阅者列表移除
if subs, exists := s.broker.consumers[s.topic]; exists {
for i, sub := range subs {
if sub == s {
s.broker.consumers[s.topic] = append(subs[:i], subs[i+1:]...)
break
}
}
}
log.Logf("unsubscribed from topic %s", s.topic)
return nil
}
// Options 返回订阅选项
func (s *rabbitmqSubscriber) Options() broker.SubscribeOptions {
return s.opts
}
---
07.高级功能实现
a.死信队列支持
a.功能说明
实现死信队列的配置和管理,用于处理无法正常消费的消息。
b.代码示例
---
// ConfigureDeadLetterExchange 配置死信交换机
func (r *rabbitmqBroker) ConfigureDeadLetterExchange(dlx, dlxRoutingKey string) error {
// 声明死信交换机
err := r.channel.ExchangeDeclare(
dlx, // name
"direct", // type
true, // durable
false, // auto-deleted
false, // internal
false, // no-wait
nil, // arguments
)
if err != nil {
return err
}
// 声明死信队列
_, err = r.channel.QueueDeclare(
dlx+".queue", // name
true, // durable
false, // auto-delete
false, // exclusive
false, // no-wait
nil, // arguments
)
if err != nil {
return err
}
// 绑定死信队列到交换机
err = r.channel.QueueBind(
dlx+".queue", // queue
dlxRoutingKey, // routing key
dlx, // exchange
false, // no-wait
nil, // arguments
)
if err != nil {
return err
}
return nil
}
---
b.消息优先级支持
a.功能说明
实现消息优先级队列的声明和优先级消息发布。
b.代码示例
---
// PublishWithPriority 发布带优先级的消息
func (r *rabbitmqBroker) PublishWithPriority(topic string, msg broker.Message, priority int) error {
return r.Publish(topic, msg,
broker.WithPublishPriority(priority),
)
}
// DeclarePriorityQueue 声明优先级队列
func (r *rabbitmqBroker) DeclarePriorityQueue(name string, maxPriority int) error {
args := amqp.Table{
"x-max-priority": maxPriority,
}
_, err := r.channel.QueueDeclare(
name, // name
true, // durable
false, // auto-delete
false, // exclusive
false, // no-wait
args, // arguments
)
return err
}
---
c.延迟消息支持
a.功能说明
使用死信交换机实现消息延迟发送功能。
b.代码示例
---
// PublishDelayed 发布延迟消息
func (r *rabbitmqBroker) PublishDelayed(topic string, msg broker.Message, delay time.Duration) error {
// 使用死信交换机实现延迟消息
delayedExchange := "delayed.exchange"
delayedQueue := "delayed.queue"
dlx := topic
dlrk := ""
// 声明延迟交换机
err := r.channel.ExchangeDeclare(
delayedExchange, // name
"direct", // type
true, // durable
false, // auto-delete
false, // internal
false, // no-wait
nil, // arguments
)
if err != nil {
return err
}
// 声明延迟队列
args := amqp.Table{
"x-message-ttl": int(delay.Milliseconds()),
"x-dead-letter-exchange": dlx,
"x-dead-letter-routing-key": dlrk,
}
_, err = r.channel.QueueDeclare(
delayedQueue, // name
true, // durable
false, // auto-delete
false, // exclusive
false, // no-wait
args, // arguments
)
if err != nil {
return err
}
// 绑定延迟队列到延迟交换机
err = r.channel.QueueBind(
delayedQueue, // queue
delayedQueue, // routing key
delayedExchange, // exchange
false, // no-wait
nil, // arguments
)
if err != nil {
return err
}
// 发布消息到延迟交换机
headers := amqp.Table{}
for k, v := range msg.Header() {
headers[k] = v
}
err = r.channel.Publish(
delayedExchange, // exchange
delayedQueue, // routing key
false, // mandatory
false, // immediate
amqp.Publishing{
Headers: headers,
ContentType: r.options.ContentType,
Body: msg.Body(),
DeliveryMode: amqp.Persistent,
Timestamp: time.Now(),
},
)
return err
}
---
08.使用示例
a.基础使用示例
a.功能说明
展示RabbitMQ Broker的基本创建、连接、发布和订阅流程。
b.代码示例
---
func main() {
// 创建RabbitMQ Broker
br := rabbitmq.NewBroker(
broker.WithContext(context.Background()),
broker.WithAddrs("amqp://guest:guest@localhost:5672/"),
broker.WithContentType("application/json"),
)
// 连接Broker
if err := br.Connect(); err != nil {
fmt.Printf("failed to connect: %v\n", err)
return
}
defer br.Disconnect()
// 发布消息
go publishMessages(br)
// 订阅消息
subscribeMessages(br)
// 等待
time.Sleep(time.Minute)
}
func publishMessages(br broker.Broker) {
ticker := time.NewTicker(time.Second * 3)
defer ticker.Stop()
for i := 0; i < 20; i++ {
select {
case <-ticker.C:
// 创建消息
msg := broker.NewMessage("application/json", []byte(fmt.Sprintf(`{
"id": %d,
"message": "Hello RabbitMQ",
"timestamp": "%s"
}`, i, time.Now().Format(time.RFC3339Nano))))
// 发布消息
err := br.Publish("test.topic", msg,
broker.WithPublishHeaders(map[string]string{
"publisher": "example",
"version": "1.0",
}),
broker.WithPublishTTL(time.Minute*5),
broker.WithPublishPriority(i%10+1),
)
if err != nil {
fmt.Printf("publish error: %v\n", err)
} else {
fmt.Printf("published message %d\n", i)
}
}
}
}
func subscribeMessages(br broker.Broker) {
// 订阅消息
sub, err := br.Subscribe("test.topic", func(msg broker.Message) error {
fmt.Printf("received message: %s\n", string(msg.Body()))
fmt.Printf("headers: %v\n", msg.Header())
// 模拟处理时间
time.Sleep(time.Millisecond * 100)
// 如果消息ID是奇数,返回错误进行重试
headers := msg.Header()
if idStr := headers["message_id"]; idStr != "" {
if idStr[len(idStr)-1]%2 == '1' {
return fmt.Errorf("processing failed for message %s", idStr)
}
}
return nil
},
broker.WithQueue("test.worker"),
broker.WithGroup("consumer.group"),
broker.WithAutoAck(false), // 手动确认
broker.WithErrorHandler(func(msg broker.Message, err error) error {
fmt.Printf("message processing error: %v\n", err)
// 这里可以实现重试逻辑或记录到死信队列
return nil
}),
)
if err != nil {
fmt.Printf("subscribe error: %v\n", err)
return
}
defer sub.Unsubscribe()
fmt.Printf("subscribed to topic: %s\n", sub.Topic())
}
---
b.死信队列示例
a.功能说明
展示死信队列的配置和使用,用于处理消费失败的消息。
b.代码示例
---
func setupDeadLetterQueue(br broker.Broker) {
// 配置死信交换机和队列
if rb, ok := br.(*rabbitmq.RabbitMQBroker); ok {
// 配置死信交换机
err := rb.ConfigureDeadLetterExchange("test.dlx", "test.dlq")
if err != nil {
fmt.Printf("failed to configure dead letter exchange: %v\n", err)
return
}
// 订阅死信队列处理失败消息
sub, err := br.Subscribe("test.dlx", func(msg broker.Message) error {
fmt.Printf("processing dead letter message: %s\n", string(msg.Body()))
fmt.Printf("original headers: %v\n", msg.Header())
// 记录失败消息到日志或数据库
logDeadLetterMessage(msg)
return nil
},
broker.WithQueue("test.dead.letter"),
broker.WithAutoAck(true),
)
if err != nil {
fmt.Printf("failed to subscribe dead letter queue: %v\n", err)
return
}
defer sub.Unsubscribe()
}
}
---
09.监控和运维
a.连接状态监控
a.功能说明
实现连接状态的持续监控和自动重连机制。
b.代码示例
---
// MonitorConnection 监控连接状态
func (r *rabbitmqBroker) MonitorConnection() {
ticker := time.NewTicker(time.Second * 30)
defer ticker.Stop()
for {
select {
case <-ticker.C:
r.RLock()
connected := r.connected
r.RUnlock()
if !connected {
log.Logf("RabbitMQ connection lost, attempting reconnect...")
if err := r.Connect(); err != nil {
log.Logf("reconnect failed: %v", err)
}
}
// 检查连接健康状态
if r.connection != nil {
if r.connection.IsClosed() {
log.Logf("RabbitMQ connection is closed")
r.Lock()
r.connected = false
r.Unlock()
}
}
}
}
}
---
b.重连机制实现
a.功能说明
实现自动重连循环,确保连接断开后能够自动恢复。
b.代码示例
---
// reconnectLoop 重连循环
func (r *rabbitmqBroker) reconnectLoop() {
ticker := time.NewTicker(r.reconnectInterval)
defer ticker.Stop()
for {
select {
case <-ticker.C:
r.RLock()
connected := r.connected
r.RUnlock()
if !connected {
log.Logf("attempting to reconnect to RabbitMQ...")
if err := r.Connect(); err != nil {
log.Logf("reconnect failed: %v", err)
}
}
}
}
}
---
c.消息统计功能
a.功能说明
实现消息处理统计信息的收集和报告。
b.代码示例
---
// MessageStats 消息统计
type MessageStats struct {
PublishedCount int64
ConsumedCount int64
ErrorCount int64
QueueSize int64
}
// GetStats 获取统计信息
func (r *rabbitmqBroker) GetStats() (*MessageStats, error) {
// 实现统计信息收集
stats := &MessageStats{}
// 这里可以通过RabbitMQ管理API获取详细信息
// 或使用内部计数器来追踪消息统计
return stats, nil
}
---
4.3 NATS集成
01.NATS概述
a.核心特性
NATS是一个轻量级、高性能的云原生消息系统,专为现代分布式系统设计。它提供了简单的API、极低的延迟和高吞吐量,支持多种消息传递模式。
b.技术优势
a.高性能
每秒可处理数百万条消息,延迟极低。
b.轻量级
单个二进制文件,资源占用少,部署简单。
c.简单易用
简洁的API和协议,易于集成和使用。
d.云原生
支持容器化和微服务架构,适合云环境部署。
e.多协议
支持NATS Protocol、MQTT等多种协议。
f.安全性
支持TLS、用户认证和权限控制等安全特性。
c.服务类型
a.NATS Server
基础消息服务,提供发布订阅功能。
b.NATS Streaming
持久化流处理,提供消息持久化和重放功能。
c.JetStream
新一代持久化存储引擎,提供企业级特性。
02.NATS Broker实现架构
a.核心结构设计
a.功能说明
设计NATS Broker的核心数据结构和组件管理,支持普通NATS和JetStream两种模式。
b.代码示例
---
// natsBroker NATS Broker实现
type natsBroker struct {
sync.RWMutex
options broker.Options
conn *nats.Conn
js nats.JetStreamContext
connected bool
subscribers map[string][]*natsSubscriber
natsOptions []nats.Option
reconnectWait time.Duration
maxReconnects int
useJetStream bool
streamConfig *nats.StreamConfig
}
// natsSubscriber NATS订阅者
type natsSubscriber struct {
topic string
handler broker.Handler
opts broker.SubscribeOptions
sub *nats.Subscription
jsSub nats.JetStreamSubscription
exit chan struct{}
broker *natsBroker
useStream bool
}
// natsMessage NATS消息
type natsMessage struct {
headers map[string]string
body []byte
msg *nats.Msg
codec codec.Marshaler
}
---
b.构造函数实现
a.功能说明
实现NATS Broker的创建逻辑,包括默认配置、选项解析和JetStream支持。
b.代码示例
---
// NewBroker 创建NATS Broker
func NewBroker(opts ...broker.Option) broker.Broker {
options := broker.Options{
Codecs: make(map[string]codec.Marshaler),
Context: context.Background(),
ContentType: "application/json",
}
for _, o := range opts {
o(&options)
}
// 注册默认编解码器
if _, ok := options.Codecs[options.ContentType]; !ok {
options.Codecs[options.ContentType] = &jsonCodec{}
}
nb := &natsBroker{
options: options,
subscribers: make(map[string][]*natsSubscriber),
natsOptions: []nats.Option{},
reconnectWait: 2 * time.Second,
maxReconnects: 5,
useJetStream: false,
}
// 解析配置选项
nb.parseOptions()
return nb
}
---
03.连接管理实现
a.Connect连接方法
a.功能说明
实现与NATS服务器的连接建立,支持普通连接和JetStream初始化。
b.代码示例
---
// Connect 连接到NATS
func (n *natsBroker) Connect(opts ...broker.Option) error {
n.Lock()
defer n.Unlock()
if n.connected {
return nil
}
for _, o := range opts {
o(&n.options)
}
var err error
addresses := n.Address()
// 连接到NATS服务器
n.conn, err = nats.Connect(addresses, n.natsOptions...)
if err != nil {
return fmt.Errorf("failed to connect to NATS: %v", err)
}
// 如果启用JetStream
if n.useJetStream {
n.js, err = n.conn.JetStream(nats.PublishAsyncMaxPending(256))
if err != nil {
n.conn.Close()
return fmt.Errorf("failed to create JetStream context: %v", err)
}
// 创建流配置
if err := n.setupJetStream(); err != nil {
log.Logf("failed to setup JetStream: %v", err)
}
}
n.connected = true
log.Logf("connected to NATS at %s", addresses)
return nil
}
---
b.选项解析方法
a.功能说明
实现NATS连接和JetStream配置选项的解析和应用。
b.代码示例
---
// parseOptions 解析配置选项
func (n *natsBroker) parseOptions() {
// 连接重配置
if reconnectWait, ok := n.options.Context.Value("nats_reconnect_wait").(time.Duration); ok {
n.reconnectWait = reconnectWait
}
if maxReconnects, ok := n.options.Context.Value("nats_max_reconnects").(int); ok {
n.maxReconnects = maxReconnects
}
// JetStream配置
if useJetStream, ok := n.options.Context.Value("nats_use_jetstream").(bool); ok {
n.useJetStream = useJetStream
}
// 流配置
if streamConfig, ok := n.options.Context.Value("nats_stream_config").(*nats.StreamConfig); ok {
n.streamConfig = streamConfig
}
// NATS连接选项
n.natsOptions = []nats.Option{
nats.ReconnectWait(n.reconnectWait),
nats.MaxReconnects(n.maxReconnects),
nats.DisconnectErrHandler(func(nc *nats.Conn, err error) {
log.Logf("NATS disconnected: %v", err)
}),
nats.ReconnectHandler(func(nc *nats.Conn) {
log.Logf("NATS reconnected to %v", nc.ConnectedUrl())
}),
nats.ErrorHandler(func(nc *nats.Conn, sub *nats.Subscription, err error) {
log.Logf("NATS error: %v", err)
}),
}
// TLS配置
if tlsConfig, ok := n.options.Context.Value("nats_tls_config").(*tls.Config); ok {
n.natsOptions = append(n.natsOptions, nats.Secure(tlsConfig))
}
// 认证配置
if user, ok := n.options.Context.Value("nats_user").(string); ok {
if password, ok := n.options.Context.Value("nats_password").(string); ok {
n.natsOptions = append(n.natsOptions, nats.UserInfo(user, password))
}
}
if token, ok := n.options.Context.Value("nats_token").(string); ok {
n.natsOptions = append(n.natsOptions, nats.Token(token))
}
if credFile, ok := n.options.Context.Value("nats_creds_file").(string); ok {
n.natsOptions = append(n.natsOptions, nats.UserCredentials(credFile))
}
}
---
c.JetStream配置方法
a.功能说明
实现JetStream流的创建和配置管理。
b.代码示例
---
// setupJetStream 设置JetStream
func (n *natsBroker) setupJetStream() error {
if n.streamConfig == nil {
// 使用默认流配置
n.streamConfig = &nats.StreamConfig{
Name: "MICRO_STREAM",
Subjects: []string{"micro.>"},
Retention: nats.WorkQueuePolicy,
Storage: nats.FileStorage,
Replicas: 1,
}
}
// 添加流
_, err := n.js.AddStream(*n.streamConfig)
if err != nil && !strings.Contains(err.Error(), "stream name already in use") {
return fmt.Errorf("failed to add stream: %v", err)
}
return nil
}
---
04.消息发布实现
a.Publish发布方法
a.功能说明
实现消息发布的核心逻辑,支持普通NATS和JetStream两种发布模式。
b.代码示例
---
// Publish 发布消息
func (n *natsBroker) Publish(topic string, msg broker.Message, opts ...broker.PublishOption) error {
n.RLock()
if !n.connected {
n.RUnlock()
return fmt.Errorf("not connected to NATS")
}
conn := n.conn
js := n.js
useJetStream := n.useJetStream
n.RUnlock()
options := broker.PublishOptions{
Context: n.options.Context,
Headers: make(map[string]string),
Timeout: time.Second * 5,
WaitForAck: false,
}
for _, o := range opts {
o(&options)
}
if msg == nil {
return broker.ErrInvalidMessage
}
// 构建消息头
headers := make(map[string]string)
for k, v := range msg.Header() {
headers[k] = v
}
// 应用发布选项
for k, v := range options.Headers {
headers[k] = v
}
// 添加NATS特定头部
headers["nats.timestamp"] = time.Now().Format(time.RFC3339)
headers["nats.content_type"] = n.options.ContentType
// 获取消息内容
body := msg.Body()
if len(body) == 0 {
return broker.ErrInvalidMessage
}
// 创建NATS消息
natsMsg := &nats.Msg{
Subject: topic,
Data: body,
Header: n.convertToNatsHeader(headers),
}
// 发布消息
var err error
if useJetStream && js != nil {
// 使用JetStream发布
publishOptions := []nats.PubOpt{}
if options.TTL > 0 {
publishOptions = append(publishOptions, nats.MsgTTL(options.TTL))
}
if options.WaitForAck {
_, err = js.PublishMsg(natsMsg, publishOptions...)
} else {
// 异步发布
if js.PublishAsyncMsg(natsMsg, publishOptions...) != nil {
err = fmt.Errorf("publish async failed")
}
}
} else {
// 使用普通NATS发布
err = conn.PublishMsg(natsMsg)
}
if err != nil {
return fmt.Errorf("failed to publish message: %v", err)
}
log.Logf("published message to topic %s", topic)
return nil
}
---
b.消息头转换方法
a.功能说明
实现go-micro消息头到NATS消息头的格式转换。
b.代码示例
---
// convertToNatsHeader 转换为NATS消息头
func (n *natsBroker) convertToNatsHeader(headers map[string]string) nats.Header {
natsHeader := make(nats.Header)
for k, v := range headers {
natsHeader[k] = []string{v}
}
return natsHeader
}
---
05.消息订阅实现
a.Subscribe订阅方法
a.功能说明
实现消息订阅的完整流程,支持普通NATS和JetStream两种订阅模式。
b.代码示例
---
// Subscribe 订阅消息
func (n *natsBroker) Subscribe(topic string, handler broker.Handler, opts ...broker.SubscribeOption) (broker.Subscriber, error) {
n.Lock()
defer n.Unlock()
options := broker.SubscribeOptions{
Context: n.options.Context,
AutoAck: true,
Queue: "",
Group: "",
ErrorHandler: func(msg broker.Message, err error) error {
log.Logf("subscriber error: %v", err)
return nil
},
}
for _, o := range opts {
o(&options)
}
if handler == nil {
return nil, broker.ErrInvalidMessage
}
var sub *nats.Subscription
var jsSub nats.JetStreamSubscription
var err error
// 使用JetStream还是普通NATS
if n.useJetStream && n.js != nil {
// JetStream订阅
subject := topic
queue := ""
if options.Queue != "" {
queue = options.Queue
}
// 配置消费者
consumerConfig := &nats.ConsumerConfig{
DeliverPolicy: nats.DeliverAllPolicy,
AckPolicy: nats.AckExplicitPolicy,
AckWait: 30 * time.Second,
MaxDeliver: 3,
}
// 配置流
streamConfig := n.getStreamConfig(topic)
jsSub, err = n.js.QueueSubscribe(subject, queue, func(msg *nats.Msg) {
n.handleMessage(sub, msg, handler, options)
}, nats.Durable(options.Group), consumerConfig)
if err != nil {
return nil, fmt.Errorf("failed to create JetStream subscription: %v", err)
}
} else {
// 普通NATS订阅
subject := topic
var queue string
if options.Queue != "" {
queue = options.Queue
}
if queue != "" {
sub, err = n.conn.QueueSubscribe(subject, queue, func(msg *nats.Msg) {
n.handleMessage(nil, msg, handler, options)
})
} else {
sub, err = n.conn.Subscribe(subject, func(msg *nats.Msg) {
n.handleMessage(nil, msg, handler, options)
})
}
if err != nil {
return nil, fmt.Errorf("failed to create NATS subscription: %v", err)
}
}
// 创建订阅者
ns := &natsSubscriber{
topic: topic,
handler: handler,
opts: options,
sub: sub,
jsSub: jsSub,
exit: make(chan struct{}),
broker: n,
useStream: n.useJetStream,
}
// 添加到订阅者列表
n.subscribers[topic] = append(n.subscribers[topic], ns)
log.Logf("subscribed to topic %s", topic)
return ns, nil
}
---
b.消息处理方法
a.功能说明
实现消息接收、转换和业务处理的统一逻辑。
b.代码示例
---
// handleMessage 处理消息
func (n *natsBroker) handleMessage(sub *nats.Subscription, msg *nats.Msg, handler broker.Handler, opts broker.SubscribeOptions) {
// 转换NATS消息为go-micro消息
headers := make(map[string]string)
if msg.Header != nil {
for k, v := range msg.Header {
if len(v) > 0 {
headers[k] = v[0]
}
}
}
microMsg := &natsMessage{
headers: headers,
body: msg.Data,
msg: msg,
codec: n.options.Codecs[n.options.ContentType],
}
// 处理消息
if err := handler(microMsg); err != nil {
log.Logf("message handler error: %v", err)
if opts.ErrorHandler != nil {
opts.ErrorHandler(microMsg, err)
}
// 如果是JetStream且不是自动确认,拒绝消息
if sub != nil && !opts.AutoAck {
msg.Nak()
}
} else {
// 如果是JetStream且不是自动确认,确认消息
if sub != nil && !opts.AutoAck {
msg.Ack()
}
}
}
---
06.消息和订阅者实现
a.natsMessage方法
a.功能说明
实现消息接口的所有方法,提供消息头、消息体和编解码器访问。
b.代码示例
---
// Header 返回消息头
func (m *natsMessage) Header() map[string]string {
return m.headers
}
// Body 返回消息体
func (m *natsMessage) Body() []byte {
return m.body
}
// Codec 返回编解码器
func (m *natsMessage) Codec() codec.Marshaler {
return m.codec
}
---
b.natsSubscriber方法
a.功能说明
实现订阅者接口的所有方法,包括主题查询、取消订阅和选项访问。
b.代码示例
---
// Topic 返回订阅者主题
func (s *natsSubscriber) Topic() string {
return s.topic
}
// Unsubscribe 取消订阅
func (s *natsSubscriber) Unsubscribe() error {
select {
case <-s.exit:
return nil
default:
close(s.exit)
}
var err error
if s.useStream && s.jsSub != nil {
err = s.jsSub.Unsubscribe()
} else if s.sub != nil {
err = s.sub.Unsubscribe()
}
if err != nil {
log.Logf("failed to unsubscribe: %v", err)
}
// 从订阅者列表移除
s.broker.Lock()
defer s.broker.Unlock()
if subs, exists := s.broker.subscribers[s.topic]; exists {
for i, sub := range subs {
if sub == s {
s.broker.subscribers[s.topic] = append(subs[:i], subs[i+1:]...)
break
}
}
}
log.Logf("unsubscribed from topic %s", s.topic)
return nil
}
// Options 返回订阅选项
func (s *natsSubscriber) Options() broker.SubscribeOptions {
return s.opts
}
---
07.JetStream高级功能
a.流管理功能
a.功能说明
实现JetStream流的创建、删除、查询等管理操作。
b.代码示例
---
// CreateStream 创建流
func (n *natsBroker) CreateStream(config *nats.StreamConfig) error {
if n.js == nil {
return fmt.Errorf("JetStream not initialized")
}
_, err := n.js.AddStream(*config)
return err
}
// DeleteStream 删除流
func (n *natsBroker) DeleteStream(streamName string) error {
if n.js == nil {
return fmt.Errorf("JetStream not initialized")
}
return n.js.DeleteStream(streamName)
}
// ListStreams 列出所有流
func (n *natsBroker) ListStreams() ([]*nats.StreamInfo, error) {
if n.js == nil {
return nil, fmt.Errorf("JetStream not initialized")
}
return n.js.Streams()
}
// GetStreamInfo 获取流信息
func (n *natsBroker) GetStreamInfo(streamName string) (*nats.StreamInfo, error) {
if n.js == nil {
return nil, fmt.Errorf("JetStream not initialized")
}
return n.js.StreamInfo(streamName)
}
---
b.消费者管理功能
a.功能说明
实现JetStream消费者的创建、删除、查询等管理操作。
b.代码示例
---
// CreateConsumer 创建消费者
func (n *natsBroker) CreateConsumer(streamName string, config *nats.ConsumerConfig) error {
if n.js == nil {
return fmt.Errorf("JetStream not initialized")
}
_, err := n.js.AddConsumer(streamName, *config)
return err
}
// DeleteConsumer 删除消费者
func (n *natsBroker) DeleteConsumer(streamName, consumerName string) error {
if n.js == nil {
return fmt.Errorf("JetStream not initialized")
}
return n.js.DeleteConsumer(streamName, consumerName)
}
// GetConsumerInfo 获取消费者信息
func (n *natsBroker) GetConsumerInfo(streamName, consumerName string) (*nats.ConsumerInfo, error) {
if n.js == nil {
return nil, fmt.Errorf("JetStream not initialized")
}
return n.js.ConsumerInfo(streamName, consumerName)
}
---
c.键值存储功能
a.功能说明
实现JetStream键值存储的封装和使用。
b.代码示例
---
// KeyValStore 键值存储封装
type KeyValStore struct {
kv nats.KeyValue
}
// NewKeyValStore 创建键值存储
func (n *natsBroker) NewKeyValStore(bucket string) (*KeyValStore, error) {
if n.js == nil {
return nil, fmt.Errorf("JetStream not initialized")
}
kv, err := n.js.KeyValue(bucket)
if err != nil {
return nil, err
}
return &KeyValStore{kv: kv}, nil
}
// Put 存储键值
func (kvs *KeyValStore) Put(key string, value string) error {
_, err := kvs.kv.Put(key, []byte(value))
return err
}
// Get 获取值
func (kvs *KeyValStore) Get(key string) (string, error) {
entry, err := kvs.kv.Get(key)
if err != nil {
return "", err
}
return string(entry.Value()), nil
}
// Delete 删除键
func (kvs *KeyValStore) Delete(key string) error {
return kvs.kv.Delete(key)
}
// Keys 列出所有键
func (kvs *KeyValStore) Keys() ([]string, error) {
keys := make([]string, 0)
watcher, err := kvs.kv.WatchAll()
if err != nil {
return nil, err
}
defer watcher.Stop()
for entry := range watcher.Updates() {
if entry == nil {
break
}
keys = append(keys, entry.Key())
}
return keys, nil
}
---
d.对象存储功能
a.功能说明
实现JetStream对象存储的封装和使用。
b.代码示例
---
// ObjectStore 对象存储封装
type ObjectStore struct {
obj nats.ObjectStore
}
// NewObjectStore 创建对象存储
func (n *natsBroker) NewObjectStore(bucket string) (*ObjectStore, error) {
if n.js == nil {
return nil, fmt.Errorf("JetStream not initialized")
}
obj, err := n.js.ObjectStore(bucket)
if err != nil {
return nil, err
}
return &ObjectStore{obj: obj}, nil
}
// Put 存储对象
func (os *ObjectStore) Put(key string, data []byte, opts ...nats.ObjectMetaOpt) (*nats.ObjectInfo, error) {
return os.obj.Put(key, data, opts...)
}
// Get 获取对象
func (os *ObjectStore) Get(key string) (*nats.ObjectInfo, []byte, error) {
info, err := os.obj.Get(key)
if err != nil {
return nil, nil, err
}
data := make([]byte, info.Size)
_, err = info.Read(data)
if err != nil {
return nil, nil, err
}
return info, data, nil
}
// Delete 删除对象
func (os *ObjectStore) Delete(key string) error {
return os.obj.Delete(key)
}
// List 列出所有对象
func (os *ObjectStore) List() ([]*nats.ObjectInfo, error) {
infos := make([]*nats.ObjectInfo, 0)
watcher, err := os.obj.Watch()
if err != nil {
return nil, err
}
defer watcher.Stop()
for info := range watcher.Updates() {
if info == nil {
break
}
infos = append(infos, info)
}
return infos, nil
}
---
08.使用示例
a.基础使用示例
a.功能说明
展示NATS Broker的基本创建、连接、发布和订阅流程,包括JetStream配置。
b.代码示例
---
func main() {
// 创建NATS Broker
br := nats.NewBroker(
broker.WithContext(context.Background()),
broker.WithAddrs("nats://localhost:4222"),
broker.WithContext("nats_use_jetstream", true),
broker.WithContext("nats_reconnect_wait", 2*time.Second),
broker.WithContext("nats_max_reconnects", 5),
)
// 连接Broker
if err := br.Connect(); err != nil {
fmt.Printf("failed to connect: %v\n", err)
return
}
defer br.Disconnect()
// 发布消息
go publishMessages(br)
// 订阅消息
subscribeMessages(br)
// 等待
time.Sleep(time.Minute)
}
func publishMessages(br broker.Broker) {
ticker := time.NewTicker(time.Second * 2)
defer ticker.Stop()
for i := 0; i < 30; i++ {
select {
case <-ticker.C:
// 创建消息
message := map[string]interface{}{
"id": i,
"message": "Hello NATS JetStream",
"timestamp": time.Now().Format(time.RFC3339Nano),
}
data, _ := json.Marshal(message)
msg := broker.NewMessage("application/json", data)
// 发布消息
err := br.Publish("test.topic", msg,
broker.WithPublishHeaders(map[string]string{
"publisher": "example",
"version": "1.0",
"priority": fmt.Sprintf("%d", i%5+1),
}),
broker.WithPublishTTL(time.Minute*10),
broker.WithWaitForAck(true),
)
if err != nil {
fmt.Printf("publish error: %v\n", err)
} else {
fmt.Printf("published message %d\n", i)
}
}
}
}
func subscribeMessages(br broker.Broker) {
// 订阅消息
sub, err := br.Subscribe("test.topic", func(msg broker.Message) error {
fmt.Printf("received message: %s\n", string(msg.Body()))
fmt.Printf("headers: %v\n", msg.Header())
// 解析消息
var data map[string]interface{}
if err := json.Unmarshal(msg.Body(), &data); err != nil {
return fmt.Errorf("failed to unmarshal message: %v", err)
}
fmt.Printf("processed message: id=%v, message=%v\n", data["id"], data["message"])
return nil
},
broker.WithQueue("test.worker"),
broker.WithGroup("consumer.group"),
broker.WithAutoAck(false), // 手动确认
broker.WithErrorHandler(func(msg broker.Message, err error) error {
fmt.Printf("message processing error: %v\n", err)
return nil
}),
)
if err != nil {
fmt.Printf("subscribe error: %v\n", err)
return
}
defer sub.Unsubscribe()
fmt.Printf("subscribed to topic: %s\n", sub.Topic())
}
---
b.JetStream高级示例
a.功能说明
展示JetStream的流管理、键值存储和对象存储等高级功能。
b.代码示例
---
func jetStreamExample(br broker.Broker) {
if nb, ok := br.(*nats.NatsBroker); ok {
// 创建自定义流配置
streamConfig := &nats.StreamConfig{
Name: "CUSTOM_STREAM",
Subjects: []string{"custom.>"},
Retention: nats.LimitsPolicy,
Storage: nats.FileStorage,
MaxBytes: 1024 * 1024 * 100, // 100MB
MaxAge: time.Hour * 24,
Replicas: 1,
}
// 创建流
if err := nb.CreateStream(streamConfig); err != nil {
fmt.Printf("failed to create stream: %v\n", err)
return
}
// 创建键值存储
kvStore, err := nb.NewKeyValStore("MY_BUCKET")
if err != nil {
fmt.Printf("failed to create KV store: %v\n", err)
return
}
// 使用键值存储
kvStore.Put("config.timeout", "30s")
timeout, _ := kvStore.Get("config.timeout")
fmt.Printf("Config timeout: %s\n", timeout)
// 创建对象存储
objStore, err := nb.NewObjectStore("FILES")
if err != nil {
fmt.Printf("failed to create object store: %v\n", err)
return
}
// 存储文件
fileData := []byte("This is a test file content")
_, err = objStore.Put("test.txt", fileData)
if err != nil {
fmt.Printf("failed to store object: %v\n", err)
}
// 获取文件
info, data, err := objStore.Get("test.txt")
if err == nil {
fmt.Printf("File %s: %s (size: %d)\n", info.Name, string(data), info.Size)
}
}
}
---
09.监控和运维
a.连接监控功能
a.功能说明
实现NATS连接状态的持续监控和健康检查。
b.代码示例
---
// MonitorConnection 监控连接状态
func (n *natsBroker) MonitorConnection() {
ticker := time.NewTicker(time.Second * 10)
defer ticker.Stop()
for {
select {
case <-ticker.C:
n.RLock()
connected := n.connected
conn := n.conn
n.RUnlock()
if !connected || conn == nil {
log.Logf("NATS connection lost, attempting reconnect...")
if err := n.Connect(); err != nil {
log.Logf("reconnect failed: %v", err)
}
} else {
switch conn.Status() {
case nats.CONNECTED:
log.Logf("NATS connection healthy")
case nats.RECONNECTING:
log.Logf("NATS reconnecting...")
case nats.CLOSED:
log.Logf("NATS connection closed")
}
}
}
}
}
---
b.性能统计功能
a.功能说明
实现NATS连接和消息处理的统计信息收集。
b.代码示例
---
// Stats NATS统计信息
type Stats struct {
Connections int
Subscribers int
MsgsIn uint64
MsgsOut uint64
BytesIn uint64
BytesOut uint64
Errors uint64
}
// GetStats 获取统计信息
func (n *natsBroker) GetStats() *Stats {
n.RLock()
defer n.RUnlock()
stats := &Stats{
Connections: 0,
Subscribers: 0,
}
if n.conn != nil {
connStats := n.conn.Stats()
stats.MsgsIn = connStats.InMsgs
stats.MsgsOut = connStats.OutMsgs
stats.BytesIn = connStats.InBytes
stats.BytesOut = connStats.OutBytes
stats.Errors = connStats.Errors
}
for _, subs := range n.subscribers {
stats.Subscribers += len(subs)
}
return stats
}
---
4.4 事件驱动架构
01.事件驱动架构概述
a.核心概念
事件驱动架构(Event-Driven Architecture, EDA)是一种以事件为核心驱动的系统架构模式,通过事件的发布、订阅和处理来实现系统间的松耦合通信。
b.主要特点
a.异步通信
基于事件的异步消息传递,提高系统响应性能和资源利用率。
b.松耦合
服务间通过事件接口而非直接调用,降低系统耦合度,提高可维护性。
c.可扩展性
支持动态添加事件消费者,系统具有良好的横向扩展能力。
d.实时性
事件实时传播和处理,支持低延迟的业务场景。
e.可追溯性
完整的事件日志和审计,便于问题排查和业务分析。
c.常见模式
a.Event Sourcing
事件溯源模式,通过存储所有事件来重建系统状态。
b.CQRS
命令查询职责分离,读写操作使用不同的数据模型。
c.Event Notification
事件通知模式,简单的发布订阅机制。
d.Event-Carried State Transfer
事件携带状态传输,减少后续查询需求。
e.Saga Pattern
长事务管理,通过补偿操作保证分布式事务一致性。
02.事件模型设计
a.核心接口设计
a.Event事件接口
定义事件的基本属性和方法,包括ID、类型、数据、时间戳等。
b.EventHandler事件处理器
处理特定类型事件的接口,支持类型判断和处理逻辑。
c.EventPublisher事件发布器
负责事件的发布和传输,支持同步和异步发布。
d.EventStore事件存储
事件的持久化存储,支持事件流查询和时间范围查询。
b.基础实现
a.BaseEvent基础事件
提供事件的基本实现,支持选项模式进行配置。
b.事件选项模式
通过函数选项模式灵活配置事件属性。
c.代码示例
---
package event
import (
"context"
"encoding/json"
"fmt"
"time"
"github.com/micro/go-micro/v2/codec"
"github.com/micro/go-micro/v2/uuid"
)
// Event 事件接口
type Event interface {
// ID 事件ID
ID() string
// Type 事件类型
Type() string
// Source 事件源
Source() string
// Timestamp 事件时间戳
Timestamp() time.Time
// Data 事件数据
Data() interface{}
// Metadata 事件元数据
Metadata() map[string]interface{}
// Version 事件版本
Version() string
// CorrelationID 关联ID
CorrelationID() string
// CausationID 因果ID
CausationID() string
}
// EventHandler 事件处理器
type EventHandler interface {
// Handle 处理事件
Handle(ctx context.Context, event Event) error
// CanHandle 判断是否能处理事件
CanHandle(eventType string) bool
}
// EventPublisher 事件发布器
type EventPublisher interface {
// Publish 发布事件
Publish(ctx context.Context, event Event) error
// PublishAsync 异步发布事件
PublishAsync(ctx context.Context, event Event) error
}
// EventStore 事件存储
type EventStore interface {
// Save 保存事件
Save(ctx context.Context, event Event) error
// Load 加载事件流
Load(ctx context.Context, aggregateID string, fromVersion int) ([]Event, error)
// GetEventsByType 按类型获取事件
GetEventsByType(ctx context.Context, eventType string, limit int) ([]Event, error)
// GetEventsByTimeRange 按时间范围获取事件
GetEventsByTimeRange(ctx context.Context, start, end time.Time) ([]Event, error)
}
// BaseEvent 基础事件实现
type BaseEvent struct {
id string `json:"id"`
eventType string `json:"type"`
source string `json:"source"`
timestamp time.Time `json:"timestamp"`
data interface{} `json:"data"`
metadata map[string]interface{} `json:"metadata"`
version string `json:"version"`
correlationID string `json:"correlation_id"`
causationID string `json:"causation_id"`
}
// NewEvent 创建事件
func NewEvent(eventType, source string, data interface{}, opts ...EventOption) Event {
event := &BaseEvent{
id: uuid.New().String(),
eventType: eventType,
source: source,
timestamp: time.Now(),
data: data,
metadata: make(map[string]interface{}),
version: "1.0",
correlationID: uuid.New().String(),
causationID: "",
}
for _, opt := range opts {
opt(event)
}
return event
}
// ID 返回事件ID
func (e *BaseEvent) ID() string {
return e.id
}
// Type 返回事件类型
func (e *BaseEvent) Type() string {
return e.eventType
}
// Source 返回事件源
func (e *BaseEvent) Source() string {
return e.source
}
// Timestamp 返回时间戳
func (e *BaseEvent) Timestamp() time.Time {
return e.timestamp
}
// Data 返回事件数据
func (e *BaseEvent) Data() interface{} {
return e.data
}
// Metadata 返回元数据
func (e *BaseEvent) Metadata() map[string]interface{} {
return e.metadata
}
// Version 返回版本
func (e *BaseEvent) Version() string {
return e.version
}
// CorrelationID 返回关联ID
func (e *BaseEvent) CorrelationID() string {
return e.correlationID
}
// CausationID 返回因果ID
func (e *BaseEvent) CausationID() string {
return e.causationID
}
// EventOption 事件选项
type EventOption func(*BaseEvent)
// WithEventID 设置事件ID
func WithEventID(id string) EventOption {
return func(e *BaseEvent) {
e.id = id
}
}
// WithEventTimestamp 设置时间戳
func WithEventTimestamp(timestamp time.Time) EventOption {
return func(e *BaseEvent) {
e.timestamp = timestamp
}
}
// WithEventMetadata 设置元数据
func WithEventMetadata(metadata map[string]interface{}) EventOption {
return func(e *BaseEvent) {
for k, v := range metadata {
e.metadata[k] = v
}
}
}
// WithEventVersion 设置版本
func WithEventVersion(version string) EventOption {
return func(e *BaseEvent) {
e.version = version
}
}
// WithCorrelationID 设置关联ID
func WithCorrelationID(correlationID string) EventOption {
return func(e *BaseEvent) {
e.correlationID = correlationID
}
}
// WithCausationID 设置因果ID
func WithCausationID(causationID string) EventOption {
return func(e *BaseEvent) {
e.causationID = causationID
}
}
---
03.事件处理器实现
a.处理器注册表
a.EventHandlerRegistry
管理事件处理器的注册和查找,支持按事件类型分类存储。
b.类型安全注册
支持强类型的事件处理器注册,避免运行时类型错误。
b.基础处理器实现
a.BaseEventHandler
提供处理器的基础功能,包括类型判断和错误处理。
b.AsyncEventHandler
异步事件处理器,支持并发处理提高性能。
c.EventHandlerChain
事件处理器链,支持多个处理器串联处理。
c.代码示例
---
// EventHandlerRegistry 事件处理器注册表
type EventHandlerRegistry struct {
handlers map[string][]EventHandler
}
// NewEventHandlerRegistry 创建事件处理器注册表
func NewEventHandlerRegistry() *EventHandlerRegistry {
return &EventHandlerRegistry{
handlers: make(map[string][]EventHandler),
}
}
// Register 注册事件处理器
func (r *EventHandlerRegistry) Register(handler EventHandler) {
eventTypes := getSupportedEventTypes(handler)
for _, eventType := range eventTypes {
r.handlers[eventType] = append(r.handlers[eventType], handler)
}
}
// RegisterForType 为特定类型注册事件处理器
func (r *EventHandlerRegistry) RegisterForType(eventType string, handler EventHandler) {
r.handlers[eventType] = append(r.handlers[eventType], handler)
}
// GetHandlers 获取事件处理器
func (r *EventHandlerRegistry) GetHandlers(eventType string) []EventHandler {
return r.handlers[eventType]
}
// getSupportedEventTypes 获取支持的事件类型
func getSupportedEventTypes(handler EventHandler) []string {
if typedHandler, ok := handler.(TypedEventHandler); ok {
return typedHandler.SupportedEventTypes()
}
return []string{}
}
// TypedEventHandler 支持类型的事件处理器
type TypedEventHandler interface {
EventHandler
// SupportedEventTypes 支持的事件类型
SupportedEventTypes() []string
}
// BaseEventHandler 基础事件处理器
type BaseEventHandler struct {
supportedTypes []string
}
// NewBaseEventHandler 创建基础事件处理器
func NewBaseEventHandler(eventTypes ...string) *BaseEventHandler {
return &BaseEventHandler{
supportedTypes: eventTypes,
}
}
// CanHandle 判断是否能处理事件
func (h *BaseEventHandler) CanHandle(eventType string) bool {
for _, t := range h.supportedTypes {
if t == eventType {
return true
}
}
return false
}
// SupportedEventTypes 返回支持的事件类型
func (h *BaseEventHandler) SupportedEventTypes() []string {
return h.supportedTypes
}
// AsyncEventHandler 异步事件处理器
type AsyncEventHandler struct {
EventHandler
concurrency int
queue chan Event
ctx context.Context
cancel context.CancelFunc
}
// NewAsyncEventHandler 创建异步事件处理器
func NewAsyncEventHandler(handler EventHandler, concurrency int) *AsyncEventHandler {
ctx, cancel := context.WithCancel(context.Background())
asyncHandler := &AsyncEventHandler{
EventHandler: handler,
concurrency: concurrency,
queue: make(chan Event, 1000),
ctx: ctx,
cancel: cancel,
}
// 启动工作协程
for i := 0; i < concurrency; i++ {
go asyncHandler.worker()
}
return asyncHandler
}
// worker 工作协程
func (h *AsyncEventHandler) worker() {
for {
select {
case <-h.ctx.Done():
return
case event := <-h.queue:
if err := h.EventHandler.Handle(h.ctx, event); err != nil {
log.Printf("Async event handler error: %v", err)
}
}
}
}
// Handle 异步处理事件
func (h *AsyncEventHandler) Handle(ctx context.Context, event Event) error {
select {
case h.queue <- event:
return nil
default:
return fmt.Errorf("event queue is full")
}
}
// Stop 停止异步处理器
func (h *AsyncEventHandler) Stop() {
h.cancel()
}
// EventHandlerChain 事件处理器链
type EventHandlerChain struct {
handlers []EventHandler
}
// NewEventHandlerChain 创建事件处理器链
func NewEventHandlerChain(handlers ...EventHandler) *EventHandlerChain {
return &EventHandlerChain{
handlers: handlers,
}
}
// Add 添加处理器
func (c *EventHandlerChain) Add(handler EventHandler) {
c.handlers = append(c.handlers, handler)
}
// Handle 链式处理事件
func (c *EventHandlerChain) Handle(ctx context.Context, event Event) error {
var lastErr error
for _, handler := range c.handlers {
if !handler.CanHandle(event.Type()) {
continue
}
if err := handler.Handle(ctx, event); err != nil {
lastErr = err
log.Printf("Event handler chain error: %v", err)
}
}
return lastErr
}
// CanHandle 检查链中是否有处理器能处理事件
func (c *EventHandlerChain) CanHandle(eventType string) bool {
for _, handler := range c.handlers {
if handler.CanHandle(eventType) {
return true
}
}
return false
}
---
04.事件发布器实现
a.Broker发布器
a.BrokerEventPublisher
基于消息代理的事件发布器,支持多种消息中间件。
b.消息转换
将事件转换为标准的消息格式,添加必要的头信息。
b.事件聚合器
a.EventAggregator
支持同时向多个发布器发布事件,提高可靠性。
b.异步发布
提供异步发布能力,不阻塞主业务流程。
c.代码示例
---
// BrokerEventPublisher 基于Broker的事件发布器
type BrokerEventPublisher struct {
broker broker.Broker
codec codec.Marshaler
publisher string
}
// NewBrokerEventPublisher 创建事件发布器
func NewBrokerEventPublisher(b broker.Broker, codec codec.Marshaler, publisher string) *BrokerEventPublisher {
return &BrokerEventPublisher{
broker: b,
codec: codec,
publisher: publisher,
}
}
// Publish 发布事件
func (p *BrokerEventPublisher) Publish(ctx context.Context, event Event) error {
// 序列化事件
data, err := p.codec.Marshal(event)
if err != nil {
return fmt.Errorf("failed to marshal event: %v", err)
}
// 创建消息
msg := broker.NewMessage("application/json", data,
broker.MessageHeader("event_type", event.Type()),
broker.MessageHeader("event_source", event.Source()),
broker.MessageHeader("event_id", event.ID()),
broker.MessageHeader("correlation_id", event.CorrelationID()),
broker.MessageHeader("causation_id", event.CausationID()),
broker.MessageHeader("publisher", p.publisher),
broker.MessageHeader("version", event.Version()),
broker.MessageHeader("timestamp", event.Timestamp().Format(time.RFC3339Nano)),
)
// 发布到事件主题
topic := fmt.Sprintf("events.%s", event.Type())
return p.broker.Publish(topic, msg)
}
// PublishAsync 异步发布事件
func (p *BrokerEventPublisher) PublishAsync(ctx context.Context, event Event) error {
go func() {
if err := p.Publish(ctx, event); err != nil {
log.Printf("Failed to publish event asynchronously: %v", err)
}
}()
return nil
}
// EventAggregator 事件聚合器
type EventAggregator struct {
publishers []EventPublisher
}
// NewEventAggregator 创建事件聚合器
func NewEventAggregator(publishers ...EventPublisher) *EventAggregator {
return &EventAggregator{
publishers: publishers,
}
}
// Add 添加发布器
func (a *EventAggregator) Add(publisher EventPublisher) {
a.publishers = append(a.publishers, publisher)
}
// Publish 发布事件到所有发布器
func (a *EventAggregator) Publish(ctx context.Context, event Event) error {
var errors []error
for _, publisher := range a.publishers {
if err := publisher.Publish(ctx, event); err != nil {
errors = append(errors, err)
}
}
if len(errors) > 0 {
return fmt.Errorf("failed to publish to some publishers: %v", errors)
}
return nil
}
// PublishAsync 异步发布事件到所有发布器
func (a *EventAggregator) PublishAsync(ctx context.Context, event Event) error {
go func() {
if err := a.Publish(ctx, event); err != nil {
log.Printf("Failed to aggregate publish event: %v", err)
}
}()
return nil
}
---
05.事件存储实现
a.内存存储
a.MemoryEventStore
基于内存的事件存储实现,适用于开发测试环境。
b.并发安全
使用读写锁保证并发访问的安全性。
b.聚合根管理
a.AggregateRoot
实现DDD中的聚合根模式,管理领域对象的状态变化。
b.事件快照
支持事件快照机制,优化事件回放性能。
c.代码示例
---
// MemoryEventStore 内存事件存储
type MemoryEventStore struct {
events map[string][]Event
mu sync.RWMutex
}
// NewMemoryEventStore 创建内存事件存储
func NewMemoryEventStore() *MemoryEventStore {
return &MemoryEventStore{
events: make(map[string][]Event),
}
}
// Save 保存事件
func (s *MemoryEventStore) Save(ctx context.Context, event Event) error {
s.mu.Lock()
defer s.mu.Unlock()
aggregateID := event.Metadata()["aggregate_id"].(string)
if aggregateID == "" {
aggregateID = event.Source()
}
if s.events[aggregateID] == nil {
s.events[aggregateID] = make([]Event, 0)
}
s.events[aggregateID] = append(s.events[aggregateID], event)
return nil
}
// Load 加载事件流
func (s *MemoryEventStore) Load(ctx context.Context, aggregateID string, fromVersion int) ([]Event, error) {
s.mu.RLock()
defer s.mu.RUnlock()
events, exists := s.events[aggregateID]
if !exists {
return nil, fmt.Errorf("aggregate not found: %s", aggregateID)
}
if fromVersion > 0 && fromVersion <= len(events) {
return events[fromVersion-1:], nil
}
return events, nil
}
// GetEventsByType 按类型获取事件
func (s *MemoryEventStore) GetEventsByType(ctx context.Context, eventType string, limit int) ([]Event, error) {
s.mu.RLock()
defer s.mu.RUnlock()
var result []Event
count := 0
for _, events := range s.events {
for _, event := range events {
if event.Type() == eventType {
result = append(result, event)
count++
if limit > 0 && count >= limit {
return result, nil
}
}
}
}
return result, nil
}
// GetEventsByTimeRange 按时间范围获取事件
func (s *MemoryEventStore) GetEventsByTimeRange(ctx context.Context, start, end time.Time) ([]Event, error) {
s.mu.RLock()
defer s.mu.RUnlock()
var result []Event
for _, events := range s.events {
for _, event := range events {
timestamp := event.Timestamp()
if timestamp.After(start) && timestamp.Before(end) {
result = append(result, event)
}
}
}
return result, nil
}
// AggregateRoot 聚合根
type AggregateRoot struct {
id string
version int
events []Event
}
// NewAggregateRoot 创建聚合根
func NewAggregateRoot(id string) *AggregateRoot {
return &AggregateRoot{
id: id,
events: make([]Event, 0),
}
}
// ID 返回聚合ID
func (a *AggregateRoot) ID() string {
return a.id
}
// Version 返回版本
func (a *AggregateRoot) Version() int {
return a.version
}
// Events 返回未提交事件
func (a *AggregateRoot) Events() []Event {
return a.events
}
// ApplyEvent 应用事件
func (a *AggregateRoot) ApplyEvent(event Event) {
a.events = append(a.events, event)
a.version++
}
// ClearEvents 清空已提交事件
func (a *AggregateRoot) ClearEvents() {
a.events = make([]Event, 0)
}
// LoadFromHistory 从历史加载事件
func (a *AggregateRoot) LoadFromHistory(events []Event) {
for _, event := range events {
a.ApplyEvent(event)
}
a.ClearEvents()
}
---
06.事件总线实现
a.总线架构
a.EventBus
事件总线是事件驱动架构的核心,协调事件的生产和消费。
b.核心功能
支持事件发布、订阅、处理、过滤、重试等功能。
b.高级特性
a.事件过滤
支持基于类型、内容等条件的事件过滤。
b.重试策略
可配置的重试机制,保证事件处理的可靠性。
c.监控指标
内置事件处理的性能监控和统计。
c.代码示例
---
// EventBus 事件总线
type EventBus struct {
publisher EventPublisher
registry *EventHandlerRegistry
store EventStore
eventFilter EventFilter
retryPolicy *RetryPolicy
metrics *EventMetrics
mu sync.RWMutex
}
// NewEventBus 创建事件总线
func NewEventBus(publisher EventPublisher, store EventStore) *EventBus {
return &EventBus{
publisher: publisher,
registry: NewEventHandlerRegistry(),
store: store,
eventFilter: &DefaultEventFilter{},
retryPolicy: &RetryPolicy{MaxRetries: 3},
metrics: NewEventMetrics(),
}
}
// Publish 发布事件
func (bus *EventBus) Publish(ctx context.Context, event Event) error {
// 记录指标
bus.metrics.EventPublished(event.Type())
// 过滤事件
if !bus.eventFilter.ShouldPublish(event) {
return nil
}
// 保存事件
if err := bus.store.Save(ctx, event); err != nil {
bus.metrics.EventError(event.Type(), "save_error")
return fmt.Errorf("failed to save event: %v", err)
}
// 发布事件
if err := bus.publisher.Publish(ctx, event); err != nil {
bus.metrics.EventError(event.Type(), "publish_error")
return fmt.Errorf("failed to publish event: %v", err)
}
return nil
}
// Subscribe 订阅事件
func (bus *EventBus) Subscribe(eventType string, handler EventHandler) error {
bus.registry.RegisterForType(eventType, handler)
return nil
}
// Handle 处理事件
func (bus *EventBus) Handle(ctx context.Context, event Event) error {
// 记录指标
bus.metrics.EventReceived(event.Type())
// 过滤事件
if !bus.eventFilter.ShouldHandle(event) {
return nil
}
// 获取处理器
handlers := bus.registry.GetHandlers(event.Type())
if len(handlers) == 0 {
log.Printf("No handlers found for event type: %s", event.Type())
return nil
}
// 并发处理事件
var wg sync.WaitGroup
errChan := make(chan error, len(handlers))
for _, handler := range handlers {
wg.Add(1)
go func(h EventHandler) {
defer wg.Done()
if err := bus.handleWithRetry(ctx, h, event); err != nil {
errChan <- err
}
}(handler)
}
wg.Wait()
close(errChan)
// 收集错误
var errors []error
for err := range errChan {
errors = append(errors, err)
bus.metrics.EventError(event.Type(), "handle_error")
}
if len(errors) > 0 {
return fmt.Errorf("event handling errors: %v", errors)
}
bus.metrics.EventHandled(event.Type())
return nil
}
// handleWithRetry 带重试的事件处理
func (bus *EventBus) handleWithRetry(ctx context.Context, handler EventHandler, event Event) error {
var lastErr error
for attempt := 0; attempt <= bus.retryPolicy.MaxRetries; attempt++ {
if attempt > 0 {
// 等待重试间隔
delay := bus.retryPolicy.Delay(attempt)
select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(delay):
}
}
if err := handler.Handle(ctx, event); err != nil {
lastErr = err
log.Printf("Event handler attempt %d failed: %v", attempt+1, err)
continue
}
// 成功处理,返回nil
return nil
}
return fmt.Errorf("max retries exceeded, last error: %v", lastErr)
}
// EventFilter 事件过滤器
type EventFilter interface {
ShouldPublish(event Event) bool
ShouldHandle(event Event) bool
}
// DefaultEventFilter 默认事件过滤器
type DefaultEventFilter struct{}
// ShouldPublish 判断是否应该发布事件
func (f *DefaultEventFilter) ShouldPublish(event Event) bool {
return true // 默认发布所有事件
}
// ShouldHandle 判断是否应该处理事件
func (f *DefaultEventFilter) ShouldHandle(event Event) bool {
return true // 默认处理所有事件
}
// RetryPolicy 重试策略
type RetryPolicy struct {
MaxRetries int
BaseDelay time.Duration
MaxDelay time.Duration
}
// Delay 计算重试延迟
func (p *RetryPolicy) Delay(attempt int) time.Duration {
if p.BaseDelay == 0 {
p.BaseDelay = time.Second
}
if p.MaxDelay == 0 {
p.MaxDelay = time.Minute
}
delay := p.BaseDelay * time.Duration(attempt)
if delay > p.MaxDelay {
delay = p.MaxDelay
}
return delay
}
// EventMetrics 事件指标
type EventMetrics struct {
publishedCount map[string]int64
receivedCount map[string]int64
handledCount map[string]int64
errorCount map[string]map[string]int64
mu sync.RWMutex
}
// NewEventMetrics 创建事件指标
func NewEventMetrics() *EventMetrics {
return &EventMetrics{
publishedCount: make(map[string]int64),
receivedCount: make(map[string]int64),
handledCount: make(map[string]int64),
errorCount: make(map[string]map[string]int64),
}
}
// EventPublished 事件已发布
func (m *EventMetrics) EventPublished(eventType string) {
m.mu.Lock()
defer m.mu.Unlock()
m.publishedCount[eventType]++
}
// EventReceived 事件已接收
func (m *EventMetrics) EventReceived(eventType string) {
m.mu.Lock()
defer m.mu.Unlock()
m.receivedCount[eventType]++
}
// EventHandled 事件已处理
func (m *EventMetrics) EventHandled(eventType string) {
m.mu.Lock()
defer m.mu.Unlock()
m.handledCount[eventType]++
}
// EventError 事件错误
func (m *EventMetrics) EventError(eventType, errorType string) {
m.mu.Lock()
defer m.mu.Unlock()
if m.errorCount[eventType] == nil {
m.errorCount[eventType] = make(map[string]int64)
}
m.errorCount[eventType][errorType]++
}
---
07.使用示例
a.完整示例
a.系统初始化
创建事件总线、注册处理器、启动服务。
b.事件发布
演示如何发布不同类型的事件。
c.事件处理
展示处理器如何接收和处理事件。
b.代码示例
---
package main
import (
"context"
"fmt"
"time"
"github.com/micro/go-micro/v2/broker"
"github.com/micro/go-micro/v2/broker/memory"
"github.com/micro/go-micro/v2/codec/json"
"github.com/micro/go-micro/v2/event"
)
func main() {
// 创建内存Broker
br := memory.NewBroker()
if err := br.Connect(); err != nil {
fmt.Printf("failed to connect broker: %v\n", err)
return
}
defer br.Disconnect()
// 创建事件总线
eventBus := event.NewEventBus(
event.NewBrokerEventPublisher(br, &json.Codec{}, "example-service"),
event.NewMemoryEventStore(),
)
// 注册事件处理器
registerEventHandlers(eventBus)
// 发布事件
publishEvents(eventBus)
// 等待事件处理
time.Sleep(time.Second * 5)
}
func registerEventHandlers(eventBus *event.EventBus) {
// 用户事件处理器
userHandler := &UserEventHandler{}
eventBus.Subscribe("user.created", userHandler)
eventBus.Subscribe("user.updated", userHandler)
eventBus.Subscribe("user.deleted", userHandler)
// 订单事件处理器
orderHandler := &OrderEventHandler{}
eventBus.Subscribe("order.created", orderHandler)
eventBus.Subscribe("order.paid", orderHandler)
eventBus.Subscribe("order.shipped", orderHandler)
}
func publishEvents(eventBus *event.EventBus) {
// 发布用户创建事件
userCreatedEvent := event.NewEvent("user.created", "user-service",
UserCreatedData{
UserID: "123",
Email: "[email protected]",
Name: "John Doe",
CreatedAt: time.Now(),
},
event.WithEventMetadata(map[string]interface{}{
"aggregate_id": "user-123",
"version": "1",
}),
)
if err := eventBus.Publish(context.Background(), userCreatedEvent); err != nil {
fmt.Printf("failed to publish user created event: %v\n", err)
}
// 发布订单创建事件
orderCreatedEvent := event.NewEvent("order.created", "order-service",
OrderCreatedData{
OrderID: "456",
UserID: "123",
Total: 99.99,
CreatedAt: time.Now(),
},
event.WithCorrelationID(userCreatedEvent.ID()),
event.WithEventMetadata(map[string]interface{}{
"aggregate_id": "order-456",
"version": "1",
}),
)
if err := eventBus.Publish(context.Background(), orderCreatedEvent); err != nil {
fmt.Printf("failed to publish order created event: %v\n", err)
}
}
// UserCreatedData 用户创建数据
type UserCreatedData struct {
UserID string `json:"user_id"`
Email string `json:"email"`
Name string `json:"name"`
CreatedAt time.Time `json:"created_at"`
}
// OrderCreatedData 订单创建数据
type OrderCreatedData struct {
OrderID string `json:"order_id"`
UserID string `json:"user_id"`
Total float64 `json:"total"`
CreatedAt time.Time `json:"created_at"`
}
// UserEventHandler 用户事件处理器
type UserEventHandler struct{}
// Handle 处理用户事件
func (h *UserEventHandler) Handle(ctx context.Context, evt event.Event) error {
switch evt.Type() {
case "user.created":
return h.handleUserCreated(ctx, evt)
case "user.updated":
return h.handleUserUpdated(ctx, evt)
case "user.deleted":
return h.handleUserDeleted(ctx, evt)
default:
return fmt.Errorf("unknown user event type: %s", evt.Type())
}
}
// CanHandle 判断是否能处理事件
func (h *UserEventHandler) CanHandle(eventType string) bool {
return eventType == "user.created" ||
eventType == "user.updated" ||
eventType == "user.deleted"
}
func (h *UserEventHandler) handleUserCreated(ctx context.Context, evt event.Event) error {
var data UserCreatedData
if err := json.Unmarshal(evt.Data().([]byte), &data); err != nil {
return fmt.Errorf("failed to unmarshal user created data: %v", err)
}
fmt.Printf("User created: ID=%s, Email=%s, Name=%s\n", data.UserID, data.Email, data.Name)
// 这里可以执行用户创建后的业务逻辑
// 例如:发送欢迎邮件、创建用户档案等
return nil
}
func (h *UserEventHandler) handleUserUpdated(ctx context.Context, evt event.Event) error {
fmt.Printf("User updated: %s\n", evt.ID())
return nil
}
func (h *UserEventHandler) handleUserDeleted(ctx context.Context, evt event.Event) error {
fmt.Printf("User deleted: %s\n", evt.ID())
return nil
}
// OrderEventHandler 订单事件处理器
type OrderEventHandler struct{}
// Handle 处理订单事件
func (h *OrderEventHandler) Handle(ctx context.Context, evt event.Event) error {
switch evt.Type() {
case "order.created":
return h.handleOrderCreated(ctx, evt)
case "order.paid":
return h.handleOrderPaid(ctx, evt)
case "order.shipped":
return h.handleOrderShipped(ctx, evt)
default:
return fmt.Errorf("unknown order event type: %s", evt.Type())
}
}
// CanHandle 判断是否能处理事件
func (h *OrderEventHandler) CanHandle(eventType string) bool {
return eventType == "order.created" ||
eventType == "order.paid" ||
eventType == "order.shipped"
}
func (h *OrderEventHandler) handleOrderCreated(ctx context.Context, evt event.Event) error {
var data OrderCreatedData
if err := json.Unmarshal(evt.Data().([]byte), &data); err != nil {
return fmt.Errorf("failed to unmarshal order created data: %v", err)
}
fmt.Printf("Order created: ID=%s, UserID=%s, Total=%.2f\n", data.OrderID, data.UserID, data.Total)
// 这里可以执行订单创建后的业务逻辑
// 例如:库存预留、发送订单确认等
return nil
}
func (h *OrderEventHandler) handleOrderPaid(ctx context.Context, evt event.Event) error {
fmt.Printf("Order paid: %s\n", evt.ID())
return nil
}
func (h *OrderEventHandler) handleOrderShipped(ctx context.Context, evt event.Event) error {
fmt.Printf("Order shipped: %s\n", evt.ID())
return nil
}
---
08.总结
a.架构优势
a.解耦性
事件驱动架构实现了系统的松耦合,提高了可维护性和扩展性。
b.可扩展性
支持水平扩展,能够处理大规模并发事件。
c.容错性
通过异步处理和重试机制,提高了系统的容错能力。
b.适用场景
a.复杂业务流程
适合涉及多个服务协作的复杂业务场景。
b.实时性要求高
满足对实时性要求较高的业务需求。
c.数据一致性
通过事件溯源保证数据的最终一致性。
c.实施建议
a.事件设计
合理设计事件结构,避免事件粒度过细或过粗。
b.错误处理
完善的错误处理和补偿机制,确保系统稳定性。
c.监控运维
建立完善的监控体系,及时发现和解决问题。
4.5 消息模式实现
01.发布订阅模式
a.模式概述
发布订阅模式(Publish-Subscribe Pattern)是一种消息传递模式,其中发送者(发布者)将消息发送到特定主题,接收者(订阅者)订阅感兴趣的主题接收消息。
b.主要特点
a.解耦
发布者和订阅者完全解耦,无需直接通信。
b.一对多
一个消息可以发送给多个订阅者。
c.动态
订阅者可以动态订阅和取消订阅。
d.异步
消息异步传递,提高系统性能。
c.核心组件
a.Topic主题接口
定义主题的基本操作,包括发布、订阅、取消订阅等。
b.Message消息接口
定义消息的基本属性,包括ID、载荷、头信息等。
c.MessageHandler消息处理器
处理特定类型消息的接口。
d.Subscription订阅接口
管理订阅状态和生命周期。
d.代码示例
---
package pubsub
import (
"context"
"fmt"
"sync"
"time"
"github.com/micro/go-micro/v2/broker"
"github.com/micro/go-micro/v2/util/log"
)
// Topic 主题接口
type Topic interface {
// Name 主题名称
Name() string
// Publish 发布消息
Publish(ctx context.Context, message Message) error
// Subscribe 订阅主题
Subscribe(ctx context.Context, handler MessageHandler) (Subscription, error)
// Unsubscribe 取消订阅
Unsubscribe(subscription Subscription) error
// Subscribers 获取订阅者数量
Subscribers() int
}
// Message 消息接口
type Message interface {
// ID 消息ID
ID() string
// Payload 消息载荷
Payload() []byte
// Headers 消息头
Headers() map[string]string
// Timestamp 消息时间戳
Timestamp() time.Time
// Topic 消息主题
Topic() string
}
// MessageHandler 消息处理器
type MessageHandler interface {
// Handle 处理消息
Handle(ctx context.Context, message Message) error
// CanHandle 判断是否能处理消息
CanHandle(message Message) bool
}
// Subscription 订阅接口
type Subscription interface {
// ID 订阅ID
ID() string
// Topic 主题名称
Topic() string
// Handler 处理器
Handler() MessageHandler
// Active 是否活跃
Active() bool
// Close 关闭订阅
Close() error
}
// BaseTopic 基础主题实现
type BaseTopic struct {
name string
broker broker.Broker
subscribers map[string]*BaseSubscription
mu sync.RWMutex
}
// NewBaseTopic 创建基础主题
func NewBaseTopic(name string, b broker.Broker) *BaseTopic {
return &BaseTopic{
name: name,
broker: b,
subscribers: make(map[string]*BaseSubscription),
}
}
// Name 返回主题名称
func (t *BaseTopic) Name() string {
return t.name
}
// Publish 发布消息
func (t *BaseTopic) Publish(ctx context.Context, message Message) error {
if message.Topic() != t.name {
return fmt.Errorf("message topic mismatch: expected %s, got %s", t.name, message.Topic())
}
// 创建broker消息
brokerMsg := broker.NewMessage("application/json", message.Payload(),
broker.MessageHeader("message_id", message.ID()),
broker.MessageHeader("topic", message.Topic()),
broker.MessageHeader("timestamp", message.Timestamp().Format(time.RFC3339Nano)),
)
// 添加消息头
for k, v := range message.Headers() {
brokerMsg = brokerMsg.(*broker.BaseMessage).WithHeader(k, v)
}
// 发布到broker
return t.broker.Publish(t.name, brokerMsg)
}
// Subscribe 订阅主题
func (t *BaseTopic) Subscribe(ctx context.Context, handler MessageHandler) (Subscription, error) {
sub := &BaseSubscription{
id: generateID(),
topic: t.name,
handler: handler,
active: true,
exit: make(chan struct{}),
}
// 订阅broker消息
brokerSub, err := t.broker.Subscribe(t.name, func(brokerMsg broker.Message) error {
if !sub.active {
return nil
}
// 转换broker消息为topic消息
message := &BaseMessage{
id: brokerMsg.Header()["message_id"],
payload: brokerMsg.Body(),
headers: brokerMsg.Header(),
timestamp: parseTimestamp(brokerMsg.Header()["timestamp"]),
topic: t.name,
}
// 处理消息
return t.handleMessage(ctx, sub, message)
})
if err != nil {
return nil, fmt.Errorf("failed to subscribe to broker: %v", err)
}
sub.brokerSubscription = brokerSub
t.mu.Lock()
t.subscribers[sub.id] = sub
t.mu.Unlock()
return sub, nil
}
// Unsubscribe 取消订阅
func (t *BaseTopic) Unsubscribe(subscription Subscription) error {
sub, ok := subscription.(*BaseSubscription)
if !ok {
return fmt.Errorf("invalid subscription type")
}
t.mu.Lock()
defer t.mu.Unlock()
if existingSub, exists := t.subscribers[sub.id]; exists && existingSub == sub {
sub.active = false
close(sub.exit)
if sub.brokerSubscription != nil {
sub.brokerSubscription.Unsubscribe()
}
delete(t.subscribers, sub.id)
return nil
}
return fmt.Errorf("subscription not found")
}
// Subscribers 获取订阅者数量
func (t *BaseTopic) Subscribers() int {
t.mu.RLock()
defer t.mu.RUnlock()
return len(t.subscribers)
}
// handleMessage 处理消息
func (t *BaseTopic) handleMessage(ctx context.Context, sub *BaseSubscription, message Message) error {
// 检查处理器是否能处理消息
if !sub.handler.CanHandle(message) {
return nil
}
// 处理消息
return sub.handler.Handle(ctx, message)
}
// BaseSubscription 基础订阅实现
type BaseSubscription struct {
id string
topic string
handler MessageHandler
active bool
brokerSubscription broker.Subscriber
exit chan struct{}
mu sync.RWMutex
}
// ID 返回订阅ID
func (s *BaseSubscription) ID() string {
return s.id
}
// Topic 返回主题名称
func (s *BaseSubscription) Topic() string {
return s.topic
}
// Handler 返回处理器
func (s *BaseSubscription) Handler() MessageHandler {
return s.handler
}
// Active 返回是否活跃
func (s *BaseSubscription) Active() bool {
s.mu.RLock()
defer s.mu.RUnlock()
return s.active
}
// Close 关闭订阅
func (s *BaseSubscription) Close() error {
s.mu.Lock()
defer s.mu.Unlock()
if !s.active {
return nil
}
s.active = false
close(s.exit)
if s.brokerSubscription != nil {
return s.brokerSubscription.Unsubscribe()
}
return nil
}
// BaseMessage 基础消息实现
type BaseMessage struct {
id string
payload []byte
headers map[string]string
timestamp time.Time
topic string
}
// ID 返回消息ID
func (m *BaseMessage) ID() string {
return m.id
}
// Payload 返回消息载荷
func (m *BaseMessage) Payload() []byte {
return m.payload
}
// Headers 返回消息头
func (m *BaseMessage) Headers() map[string]string {
return m.headers
}
// Timestamp 返回时间戳
func (m *BaseMessage) Timestamp() time.Time {
return m.timestamp
}
// Topic 返回主题名称
func (m *BaseMessage) Topic() string {
return m.topic
}
// NewMessage 创建消息
func NewMessage(topic string, payload []byte, headers map[string]string) Message {
if headers == nil {
headers = make(map[string]string)
}
return &BaseMessage{
id: generateID(),
payload: payload,
headers: headers,
timestamp: time.Now(),
topic: topic,
}
}
// generateID 生成唯一ID
func generateID() string {
return fmt.Sprintf("%d", time.Now().UnixNano())
}
// parseTimestamp 解析时间戳
func parseTimestamp(timestampStr string) time.Time {
if timestampStr == "" {
return time.Now()
}
if timestamp, err := time.Parse(time.RFC3339Nano, timestampStr); err == nil {
return timestamp
}
return time.Now()
}
---
02.点对点模式
a.模式概述
点对点模式(Point-to-Point Pattern)中,消息发送者将消息发送到队列,接收者从队列中获取并处理消息。每个消息只能被一个接收者处理。
b.核心组件
a.Queue队列接口
定义队列的基本操作,包括发送、接收、关闭等。
b.Worker工作器接口
定义工作器的生命周期管理。
c.Message消息接口
增强的消息接口,支持优先级、重试、确认等特性。
c.实现机制
a.并发处理
支持多个工作器并发处理队列中的消息。
b.重试机制
内置消息重试机制,保证消息处理的可靠性。
c.负载均衡
工作器间的负载均衡,提高处理效率。
d.代码示例
---
package p2p
import (
"context"
"fmt"
"sync"
"time"
"github.com/micro/go-micro/v2/broker"
"github.com/micro/go-micro/v2/util/log"
)
// Queue 队列接口
type Queue interface {
// Name 队列名称
Name() string
// Send 发送消息
Send(ctx context.Context, message Message) error
// Receive 接收消息
Receive(ctx context.Context) (Message, error)
// Close 关闭队列
Close() error
// Size 获取队列大小
Size() int64
}
// Worker 工作器接口
type Worker interface {
// ID 工作器ID
ID() string
// Start 启动工作器
Start(ctx context.Context) error
// Stop 停止工作器
Stop() error
// Active 是否活跃
Active() bool
}
// Message 消息接口
type Message interface {
// ID 消息ID
ID() string
// Payload 消息载荷
Payload() []byte
// Priority 消息优先级
Priority() int
// Attempts 重试次数
Attempts() int
// MaxAttempts 最大重试次数
MaxAttempts() int
// Timestamp 消息时间戳
Timestamp() time.Time
// Ack 确认消息
Ack() error
// Nack 拒绝消息
Nack() error
}
// BaseQueue 基础队列实现
type BaseQueue struct {
name string
broker broker.Broker
mu sync.RWMutex
active bool
pending chan *QueueMessage
workers []*BaseWorker
}
// QueueMessage 队列消息
type QueueMessage struct {
id string
payload []byte
priority int
attempts int
maxAttempts int
timestamp time.Time
ackFunc func() error
nackFunc func() error
}
// NewBaseQueue 创建基础队列
func NewBaseQueue(name string, b broker.Broker) *BaseQueue {
return &BaseQueue{
name: name,
broker: b,
active: true,
pending: make(chan *QueueMessage, 1000),
workers: make([]*BaseWorker, 0),
}
}
// Name 返回队列名称
func (q *BaseQueue) Name() string {
return q.name
}
// Send 发送消息
func (q *BaseQueue) Send(ctx context.Context, message Message) error {
if !q.active {
return fmt.Errorf("queue is not active")
}
// 创建broker消息
brokerMsg := broker.NewMessage("application/json", message.Payload(),
broker.MessageHeader("message_id", message.ID()),
broker.MessageHeader("priority", fmt.Sprintf("%d", message.Priority())),
broker.MessageHeader("attempts", fmt.Sprintf("%d", message.Attempts())),
broker.MessageHeader("max_attempts", fmt.Sprintf("%d", message.MaxAttempts())),
broker.MessageHeader("timestamp", message.Timestamp().Format(time.RFC3339Nano)),
)
// 发布到broker队列
return q.broker.Publish(q.name, brokerMsg, broker.WithQueue(q.name))
}
// Receive 接收消息
func (q *BaseQueue) Receive(ctx context.Context) (Message, error) {
select {
case <-ctx.Done():
return nil, ctx.Err()
case msg := <-q.pending:
return msg, nil
}
}
// Close 关闭队列
func (q *BaseQueue) Close() error {
q.mu.Lock()
defer q.mu.Unlock()
if !q.active {
return nil
}
q.active = false
close(q.pending)
// 停止所有工作器
for _, worker := range q.workers {
worker.Stop()
}
return nil
}
// Size 获取队列大小
func (q *BaseQueue) Size() int64 {
q.mu.RLock()
defer q.mu.RUnlock()
return int64(len(q.pending))
}
// AddWorker 添加工作器
func (q *BaseQueue) AddWorker(worker *BaseWorker) {
q.mu.Lock()
defer q.mu.Unlock()
q.workers = append(q.workers, worker)
}
// BaseWorker 基础工作器实现
type BaseWorker struct {
id string
queue *BaseQueue
handler MessageHandler
active bool
ctx context.Context
cancel context.CancelFunc
subscription broker.Subscriber
}
// MessageHandler 消息处理器
type MessageHandler interface {
// Handle 处理消息
Handle(ctx context.Context, message Message) error
}
// NewBaseWorker 创建基础工作器
func NewBaseWorker(id string, queue *BaseQueue, handler MessageHandler) *BaseWorker {
return &BaseWorker{
id: id,
queue: queue,
handler: handler,
active: false,
}
}
// ID 返回工作器ID
func (w *BaseWorker) ID() string {
return w.id
}
// Start 启动工作器
func (w *BaseWorker) Start(ctx context.Context) error {
if w.active {
return fmt.Errorf("worker is already active")
}
w.ctx, w.cancel = context.WithCancel(ctx)
w.active = true
// 订阅队列消息
sub, err := w.queue.broker.Subscribe(w.queue.name, func(brokerMsg broker.Message) error {
if !w.active {
return nil
}
return w.handleBrokerMessage(brokerMsg)
}, broker.WithQueue(w.queue.name))
if err != nil {
return fmt.Errorf("failed to subscribe to queue: %v", err)
}
w.subscription = sub
// 启动处理协程
go w.run()
log.Logf("worker %s started for queue %s", w.id, w.queue.name)
return nil
}
// Stop 停止工作器
func (w *BaseWorker) Stop() error {
if !w.active {
return nil
}
w.active = false
w.cancel()
if w.subscription != nil {
w.subscription.Unsubscribe()
}
log.Logf("worker %s stopped", w.id)
return nil
}
// Active 返回是否活跃
func (w *BaseWorker) Active() bool {
return w.active
}
// run 运行工作器
func (w *BaseWorker) run() {
for {
select {
case <-w.ctx.Done():
return
default:
// 工作器的主要处理逻辑在handleBrokerMessage中
time.Sleep(time.Millisecond * 10)
}
}
}
// handleBrokerMessage 处理broker消息
func (w *BaseWorker) handleBrokerMessage(brokerMsg broker.Message) error {
// 解析消息头
messageID := brokerMsg.Header()["message_id"]
priority := parseInt(brokerMsg.Header()["priority"], 0)
attempts := parseInt(brokerMsg.Header()["attempts"], 0)
maxAttempts := parseInt(brokerMsg.Header()["max_attempts"], 3)
timestamp := parseTimestamp(brokerMsg.Header()["timestamp"])
// 创建队列消息
queueMsg := &QueueMessage{
id: messageID,
payload: brokerMsg.Body(),
priority: priority,
attempts: attempts,
maxAttempts: maxAttempts,
timestamp: timestamp,
}
// 设置确认和拒绝函数
queueMsg.ackFunc = func() error {
// 消息处理成功,不需要额外操作
return nil
}
queueMsg.nackFunc = func() error {
// 消息处理失败,重新入队
if queueMsg.attempts < queueMsg.maxAttempts {
queueMsg.attempts++
return w.queue.Send(w.ctx, queueMsg)
}
return nil // 超过最大重试次数,丢弃消息
}
// 发送到待处理通道
select {
case w.queue.pending <- queueMsg:
// 异步处理消息
go w.processMessage(w.ctx, queueMsg)
default:
// 队列满,拒绝消息
return fmt.Errorf("queue is full")
}
return nil
}
// processMessage 处理消息
func (w *BaseWorker) processMessage(ctx context.Context, message *QueueMessage) {
// 调用处理器
err := w.handler.Handle(ctx, message)
if err != nil {
log.Logf("worker %s failed to process message %s: %v", w.id, message.id, err)
message.nackFunc()
} else {
message.ackFunc()
}
}
// ID 返回消息ID
func (m *QueueMessage) ID() string {
return m.id
}
// Payload 返回消息载荷
func (m *QueueMessage) Payload() []byte {
return m.payload
}
// Priority 返回优先级
func (m *QueueMessage) Priority() int {
return m.priority
}
// Attempts 返回重试次数
func (m *QueueMessage) Attempts() int {
return m.attempts
}
// MaxAttempts 返回最大重试次数
func (m *QueueMessage) MaxAttempts() int {
return m.maxAttempts
}
// Timestamp 返回时间戳
func (m *QueueMessage) Timestamp() time.Time {
return m.timestamp
}
// Ack 确认消息
func (m *QueueMessage) Ack() error {
if m.ackFunc != nil {
return m.ackFunc()
}
return nil
}
// Nack 拒绝消息
func (m *QueueMessage) Nack() error {
if m.nackFunc != nil {
return m.nackFunc()
}
return nil
}
// parseInt 解析整数
func parseInt(s string, defaultValue int) int {
if value, err := fmt.Sscanf(s, "%d", new(int)); err == nil && value == 1 {
var result int
fmt.Sscanf(s, "%d", &result)
return result
}
return defaultValue
}
---
03.请求响应模式
a.模式概述
请求响应模式(Request-Reply Pattern)允许客户端发送请求并等待响应,提供同步通信能力。
b.核心特性
a.同步调用
支持同步和异步两种调用方式。
b.超时控制
可配置的请求超时机制。
c.错误处理
完善的错误传递和处理机制。
c.实现架构
a.RequestReplyServer
请求响应服务器,负责处理请求和响应。
b.RequestReplyClient
请求响应客户端,发送请求并接收响应。
c.处理器注册
支持动态注册不同服务的处理器。
d.代码示例
---
package requestreply
import (
"context"
"fmt"
"sync"
"time"
"github.com/micro/go-micro/v2/broker"
"github.com/micro/go-micro/v2/codec"
"github.com/micro/go-micro/v2/util/log"
)
// Request 请求接口
type Request interface {
// ID 请求ID
ID() string
// Service 目标服务
Service() string
// Method 方法名
Method() string
// Payload 请求数据
Payload() []byte
// Headers 请求头
Headers() map[string]string
// Timeout 超时时间
Timeout() time.Duration
}
// Response 响应接口
type Response interface {
// ID 请求ID
ID() string
// Payload 响应数据
Payload() []byte
// Headers 响应头
Headers() map[string]string
// Error 错误信息
Error() error
// Timestamp 响应时间戳
Timestamp() time.Time
}
// RequestHandler 请求处理器
type RequestHandler interface {
// Handle 处理请求
Handle(ctx context.Context, request Request) (Response, error)
// CanHandle 判断是否能处理请求
CanHandle(service, method string) bool
}
// RequestClient 请求客户端
type RequestClient interface {
// Call 调用服务
Call(ctx context.Context, request Request) (Response, error)
// CallAsync 异步调用
CallAsync(ctx context.Context, request Request) (<-chan Response, error)
}
// BaseRequest 基础请求实现
type BaseRequest struct {
id string
service string
method string
payload []byte
headers map[string]string
timeout time.Duration
}
// NewRequest 创建请求
func NewRequest(service, method string, payload []byte, timeout time.Duration) Request {
return &BaseRequest{
id: generateID(),
service: service,
method: method,
payload: payload,
headers: make(map[string]string),
timeout: timeout,
}
}
// ID 返回请求ID
func (r *BaseRequest) ID() string {
return r.id
}
// Service 返回目标服务
func (r *BaseRequest) Service() string {
return r.service
}
// Method 返回方法名
func (r *BaseRequest) Method() string {
return r.method
}
// Payload 返回请求数据
func (r *BaseRequest) Payload() []byte {
return r.payload
}
// Headers 返回请求头
func (r *BaseRequest) Headers() map[string]string {
return r.headers
}
// Timeout 返回超时时间
func (r *BaseRequest) Timeout() time.Duration {
return r.timeout
}
// BaseResponse 基础响应实现
type BaseResponse struct {
id string
payload []byte
headers map[string]string
err error
timestamp time.Time
}
// NewResponse 创建响应
func NewResponse(id string, payload []byte, err error) Response {
return &BaseResponse{
id: id,
payload: payload,
headers: make(map[string]string),
err: err,
timestamp: time.Now(),
}
}
// ID 返回请求ID
func (r *BaseResponse) ID() string {
return r.id
}
// Payload 返回响应数据
func (r *BaseResponse) Payload() []byte {
return r.payload
}
// Headers 返回响应头
func (r *BaseResponse) Headers() map[string]string {
return r.headers
}
// Error 返回错误信息
func (r *BaseResponse) Error() error {
return r.err
}
// Timestamp 返回响应时间戳
func (r *BaseResponse) Timestamp() time.Time {
return r.timestamp
}
// RequestReplyServer 请求响应服务器
type RequestReplyServer struct {
broker broker.Broker
codec codec.Marshaler
handlers map[string]RequestHandler
requests map[string]chan Response
mu sync.RWMutex
}
// NewRequestReplyServer 创建请求响应服务器
func NewRequestReplyServer(b broker.Broker, codec codec.Marshaler) *RequestReplyServer {
return &RequestReplyServer{
broker: b,
codec: codec,
handlers: make(map[string]RequestHandler),
requests: make(map[string]chan Response),
}
}
// RegisterHandler 注册处理器
func (s *RequestReplyServer) RegisterHandler(service string, handler RequestHandler) error {
s.mu.Lock()
defer s.mu.Unlock()
s.handlers[service] = handler
// 订阅服务请求
requestTopic := fmt.Sprintf("request.%s", service)
responseTopic := fmt.Sprintf("response.%s", service)
// 订阅请求消息
_, err := s.broker.Subscribe(requestTopic, func(msg broker.Message) error {
return s.handleRequest(msg, responseTopic)
})
if err != nil {
return fmt.Errorf("failed to subscribe to requests: %v", err)
}
// 订阅响应消息(用于客户端)
_, err = s.broker.Subscribe(responseTopic, func(msg broker.Message) error {
return s.handleResponse(msg)
})
if err != nil {
return fmt.Errorf("failed to subscribe to responses: %v", err)
}
return nil
}
// handleRequest 处理请求
func (s *RequestReplyServer) handleRequest(brokerMsg broker.Message, responseTopic string) error {
// 解析请求
var request BaseRequest
if err := s.codec.Unmarshal(brokerMsg.Body(), &request); err != nil {
return fmt.Errorf("failed to unmarshal request: %v", err)
}
// 设置请求头
request.headers = brokerMsg.Header()
// 查找处理器
s.mu.RLock()
handler, exists := s.handlers[request.service]
s.mu.RUnlock()
if !exists || !handler.CanHandle(request.service, request.method) {
// 发送错误响应
response := NewResponse(request.id, nil, fmt.Errorf("handler not found for service %s", request.service))
return s.sendResponse(responseTopic, response)
}
// 处理请求
ctx := context.Background()
if request.timeout > 0 {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, request.timeout)
defer cancel()
}
response, err := handler.Handle(ctx, &request)
if err != nil {
response = NewResponse(request.id, nil, err)
}
// 发送响应
return s.sendResponse(responseTopic, response)
}
// handleResponse 处理响应
func (s *RequestReplyServer) handleResponse(brokerMsg broker.Message) error {
// 解析响应
var response BaseResponse
if err := s.codec.Unmarshal(brokerMsg.Body(), &response); err != nil {
return fmt.Errorf("failed to unmarshal response: %v", err)
}
// 设置响应头
response.headers = brokerMsg.Header()
// 查找等待响应的请求
s.mu.RLock()
ch, exists := s.requests[response.id]
s.mu.RUnlock()
if exists {
select {
case ch <- &response:
default:
// 通道已满或关闭
}
}
return nil
}
// sendResponse 发送响应
func (s *RequestReplyServer) sendResponse(topic string, response Response) error {
data, err := s.codec.Marshal(response)
if err != nil {
return fmt.Errorf("failed to marshal response: %v", err)
}
msg := broker.NewMessage("application/json", data)
return s.broker.Publish(topic, msg)
}
// RequestReplyClient 请求响应客户端
type RequestReplyClient struct {
broker broker.Broker
codec codec.Marshaler
server *RequestReplyServer
timeout time.Duration
}
// NewRequestReplyClient 创建请求响应客户端
func NewRequestReplyClient(b broker.Broker, codec codec.Marshaler, server *RequestReplyServer) *RequestReplyClient {
return &RequestReplyClient{
broker: b,
codec: codec,
server: server,
timeout: time.Second * 30,
}
}
// Call 调用服务
func (c *RequestReplyClient) Call(ctx context.Context, request Request) (Response, error) {
// 序列化请求
data, err := c.codec.Marshal(request)
if err != nil {
return nil, fmt.Errorf("failed to marshal request: %v", err)
}
// 创建响应通道
ch := make(chan Response, 1)
c.server.mu.Lock()
c.server.requests[request.ID()] = ch
c.server.mu.Unlock()
defer func() {
c.server.mu.Lock()
delete(c.server.requests, request.ID())
c.server.mu.Unlock()
}()
// 发送请求
requestTopic := fmt.Sprintf("request.%s", request.Service())
msg := broker.NewMessage("application/json", data)
if err := c.broker.Publish(requestTopic, msg); err != nil {
return nil, fmt.Errorf("failed to publish request: %v", err)
}
// 等待响应
timeout := request.Timeout()
if timeout <= 0 {
timeout = c.timeout
}
select {
case response := <-ch:
return response, nil
case <-time.After(timeout):
return nil, fmt.Errorf("request timeout")
case <-ctx.Done():
return nil, ctx.Err()
}
}
// CallAsync 异步调用
func (c *RequestReplyClient) CallAsync(ctx context.Context, request Request) (<-chan Response, error) {
// 序列化请求
data, err := c.codec.Marshal(request)
if err != nil {
return nil, fmt.Errorf("failed to marshal request: %v", err)
}
// 创建响应通道
ch := make(chan Response, 1)
c.server.mu.Lock()
c.server.requests[request.ID()] = ch
c.server.mu.Unlock()
// 发送请求
requestTopic := fmt.Sprintf("request.%s", request.Service())
msg := broker.NewMessage("application/json", data)
if err := c.broker.Publish(requestTopic, msg); err != nil {
c.server.mu.Lock()
delete(c.server.requests, request.ID())
c.server.mu.Unlock()
return nil, fmt.Errorf("failed to publish request: %v", err)
}
return ch, nil
}
---
04.使用示例
a.完整演示
a.发布订阅模式演示
创建主题、注册处理器、发布消息。
b.点对点模式演示
创建队列、启动工作器、发送任务。
c.请求响应模式演示
创建服务器和客户端、注册处理器、发送请求。
b.代码示例
---
package main
import (
"context"
"fmt"
"math/rand"
"time"
"github.com/micro/go-micro/v2/broker/memory"
"github.com/micro/go-micro/v2/codec/json"
"github.com/micro/go-micro/v2/pubsub"
"github.com/micro/go-micro/v2/p2p"
"github.com/micro/go-micro/v2/requestreply"
)
func main() {
// 创建内存Broker
br := memory.NewBroker()
if err := br.Connect(); err != nil {
fmt.Printf("failed to connect broker: %v\n", err)
return
}
defer br.Disconnect()
// 演示发布订阅模式
demonstratePubSub(br)
// 演示点对点模式
demonstrateP2P(br)
// 演示请求响应模式
demonstrateRequestReply(br)
}
func demonstratePubSub(b broker.Broker) {
fmt.Println("=== 发布订阅模式演示 ===")
// 创建主题
topic := pubsub.NewBaseTopic("notifications", b)
// 创建消息处理器
handler := &NotificationHandler{}
// 订阅主题
subscription, err := topic.Subscribe(context.Background(), handler)
if err != nil {
fmt.Printf("failed to subscribe: %v\n", err)
return
}
defer subscription.Close()
// 发布消息
for i := 0; i < 5; i++ {
message := pubsub.NewMessage("notifications", []byte(fmt.Sprintf("通知消息 %d", i)),
map[string]string{
"type": "info",
"priority": "normal",
"timestamp": time.Now().Format(time.RFC3339),
},
)
if err := topic.Publish(context.Background(), message); err != nil {
fmt.Printf("failed to publish message: %v\n", err)
} else {
fmt.Printf("已发布消息: %d\n", i)
}
time.Sleep(time.Millisecond * 500)
}
time.Sleep(time.Second * 2)
}
func demonstrateP2P(b broker.Broker) {
fmt.Println("\n=== 点对点模式演示 ===")
// 创建队列
queue := p2p.NewBaseQueue("tasks", b)
// 创建消息处理器
handler := &TaskHandler{}
// 创建工作器
worker1 := p2p.NewBaseWorker("worker1", queue, handler)
worker2 := p2p.NewBaseWorker("worker2", queue, handler)
// 启动工作器
ctx := context.Background()
worker1.Start(ctx)
worker2.Start(ctx)
defer worker1.Stop()
defer worker2.Stop()
// 发送任务到队列
for i := 0; i < 10; i++ {
task := &TaskMessage{
ID: fmt.Sprintf("task-%d", i),
Type: "process",
Payload: fmt.Sprintf("任务数据 %d", i),
Priority: i % 3,
}
if err := queue.Send(ctx, task); err != nil {
fmt.Printf("failed to send task: %v\n", err)
} else {
fmt.Printf("已发送任务: %s\n", task.ID)
}
time.Sleep(time.Millisecond * 200)
}
time.Sleep(time.Second * 3)
}
func demonstrateRequestReply(b broker.Broker) {
fmt.Println("\n=== 请求响应模式演示 ===")
codec := &json.Codec{}
// 创建服务器
server := requestreply.NewRequestReplyServer(b, codec)
// 注册处理器
userHandler := &UserServiceHandler{}
if err := server.RegisterHandler("user", userHandler); err != nil {
fmt.Printf("failed to register handler: %v\n", err)
return
}
// 创建客户端
client := requestreply.NewRequestReplyClient(b, codec, server)
// 发送请求
for i := 0; i < 3; i++ {
request := requestreply.NewRequest("user", "GetUser",
[]byte(fmt.Sprintf(`{"user_id": "%d"}`, i+1)),
time.Second*5)
response, err := client.Call(context.Background(), request)
if err != nil {
fmt.Printf("request failed: %v\n", err)
} else {
if response.Error() != nil {
fmt.Printf("request returned error: %v\n", response.Error())
} else {
fmt.Printf("请求响应: %s\n", string(response.Payload()))
}
}
time.Sleep(time.Millisecond * 500)
}
time.Sleep(time.Second * 2)
}
// NotificationHandler 通知处理器
type NotificationHandler struct{}
// Handle 处理通知消息
func (h *NotificationHandler) Handle(ctx context.Context, message pubsub.Message) error {
fmt.Printf("收到通知: %s, 类型: %s\n", string(message.Payload()), message.Headers()["type"])
return nil
}
// CanHandle 判断是否能处理消息
func (h *NotificationHandler) CanHandle(message pubsub.Message) bool {
return message.Topic() == "notifications"
}
// TaskHandler 任务处理器
type TaskHandler struct{}
// Handle 处理任务消息
func (h *TaskHandler) Handle(ctx context.Context, message p2p.Message) error {
fmt.Printf("处理任务: %s, 优先级: %d, 尝试次数: %d\n",
string(message.Payload()), message.Priority(), message.Attempts())
// 模拟任务处理时间
time.Sleep(time.Millisecond * 100)
return nil
}
// TaskMessage 任务消息
type TaskMessage struct {
ID string
Type string
Payload string
Priority int
}
func (t *TaskMessage) ID() string { return t.ID }
func (t *TaskMessage) Payload() []byte { return []byte(t.Payload) }
func (t *TaskMessage) Priority() int { return t.Priority }
func (t *TaskMessage) Attempts() int { return 0 }
func (t *TaskMessage) MaxAttempts() int { return 3 }
func (t *TaskMessage) Timestamp() time.Time { return time.Now() }
func (t *TaskMessage) Ack() error { return nil }
func (t *TaskMessage) Nack() error { return nil }
// UserServiceHandler 用户服务处理器
type UserServiceHandler struct{}
// Handle 处理用户请求
func (h *UserServiceHandler) Handle(ctx context.Context, request requestreply.Request) (requestreply.Response, error) {
switch request.Method() {
case "GetUser":
// 模拟获取用户信息
userData := fmt.Sprintf(`{"id": "%s", "name": "用户%d", "email": "user%[email protected]"}`,
string(request.Payload()), rand.Intn(1000), rand.Intn(1000))
return requestreply.NewResponse(request.ID(), []byte(userData), nil), nil
default:
return nil, fmt.Errorf("unknown method: %s", request.Method())
}
}
// CanHandle 判断是否能处理请求
func (h *UserServiceHandler) CanHandle(service, method string) bool {
return service == "user" && method == "GetUser"
}
---
05.总结
a.模式对比
a.发布订阅模式
适用于一对多的广播场景,解耦性最好。
b.点对点模式
适用于任务队列和可靠消息传递,保证消息被处理。
c.请求响应模式
适用于需要同步响应的场景,支持超时控制。
b.适用场景
a.实时通知
使用发布订阅模式实现系统间的实时通知。
b.任务处理
使用点对点模式实现异步任务处理和负载均衡。
c.服务调用
使用请求响应模式实现微服务间的同步调用。
c.最佳实践
a.模式选择
根据业务需求选择合适的消息模式。
b.错误处理
实现完善的错误处理和重试机制。
c.监控运维
建立消息队列的监控和告警机制。
消息模式的实现为微服务架构提供了丰富的通信选择,包括发布订阅、点对点和请求响应等模式,满足了不同场景下的通信需求。
4.6 消息监控与治理
01.消息监控系统
a.核心概念
消息监控系统负责监控消息的流动、处理状态和性能指标,为运维人员提供实时的系统健康状况视图。
b.监控核心指标
消息吞吐量 - 每秒处理的消息数量
消息延迟 - 消息从发布到处理的端到端时间
错误率 - 消息处理失败的比例
队列深度 - 待处理消息的队列长度
消费者状态 - 消费者的活跃度和健康状况
资源使用 - CPU、内存、网络等资源消耗
c.核心组件
a.消息监控器
负责协调指标收集、告警检查和指标导出的核心组件,提供统一的监控入口。
b.指标收集器
从不同数据源收集性能指标的接口,支持Broker指标、Prometheus等多种收集器。
c.指标导出器
将收集到的指标导出到外部系统的接口,支持日志、HTTP、文件等多种导出方式。
d.告警系统
基于规则触发告警的智能通知系统,支持邮件、Webhook、Slack等多种通知方式。
02.指标收集器实现
a.功能说明
指标收集器负责从不同的数据源收集性能指标,为监控系统提供数据支持。
b.收集器类型
a.Broker指标收集器
直接从消息代理收集连接状态、队列深度等基础指标。
b.Prometheus收集器
从Prometheus时间序列数据库收集格式化指标数据。
c.核心功能
可插拔的收集器接口设计,支持自定义收集器实现。
统一的指标数据结构,便于后续处理和分析。
错误处理和重试机制,确保数据收集的可靠性。
d.代码示例
---
package monitoring
import (
"context"
"encoding/json"
"fmt"
"sync"
"time"
"github.com/micro/go-micro/v2/broker"
"github.com/micro/go-micro/v2/util/log"
)
// MessageMetrics 消息指标
type MessageMetrics struct {
// 基础指标
MessageCount int64 `json:"message_count"`
ErrorCount int64 `json:"error_count"`
SuccessCount int64 `json:"success_count"`
RetryCount int64 `json:"retry_count"`
// 性能指标
AvgProcessingTime float64 `json:"avg_processing_time"`
MinProcessingTime float64 `json:"min_processing_time"`
MaxProcessingTime float64 `json:"max_processing_time"`
// 队列指标
QueueDepth int64 `json:"queue_depth"`
ConsumerCount int `json:"consumer_count"`
// 时间范围
StartTime time.Time `json:"start_time"`
LastUpdateTime time.Time `json:"last_update_time"`
// 分维度指标
ByTopic map[string]*TopicMetrics `json:"by_topic"`
ByConsumer map[string]*ConsumerMetrics `json:"by_consumer"`
}
// TopicMetrics 主题指标
type TopicMetrics struct {
Topic string `json:"topic"`
PublishCount int64 `json:"publish_count"`
ConsumeCount int64 `json:"consume_count"`
ErrorCount int64 `json:"error_count"`
AvgLatency float64 `json:"avg_latency"`
LastMessageTime time.Time `json:"last_message_time"`
ActiveSubscribers int `json:"active_subscribers"`
}
// ConsumerMetrics 消费者指标
type ConsumerMetrics struct {
ConsumerID string `json:"consumer_id"`
Topic string `json:"topic"`
ProcessedCount int64 `json:"processed_count"`
ErrorCount int64 `json:"error_count"`
LastProcessTime time.Time `json:"last_process_time"`
IsHealthy bool `json:"is_healthy"`
LastError string `json:"last_error,omitempty"`
}
// MessageMonitor 消息监控器
type MessageMonitor struct {
broker broker.Broker
metrics *MessageMetrics
mu sync.RWMutex
collectors []MetricCollector
exporters []MetricsExporter
alertRules []AlertRule
ticker *time.Ticker
ctx context.Context
cancel context.CancelFunc
}
// MetricCollector 指标收集器接口
type MetricCollector interface {
// Collect 收集指标
Collect(ctx context.Context) (*MessageMetrics, error)
// Name 收集器名称
Name() string
}
// MetricsExporter 指标导出器接口
type MetricsExporter interface {
// Export 导出指标
Export(metrics *MessageMetrics) error
// Name 导出器名称
Name() string
}
// AlertRule 告警规则
type AlertRule struct {
Name string `json:"name"`
Condition AlertCondition `json:"condition"`
Threshold float64 `json:"threshold"`
Duration time.Duration `json:"duration"`
Severity AlertSeverity `json:"severity"`
Description string `json:"description"`
Actions []AlertAction `json:"actions"`
}
// AlertCondition 告警条件
type AlertCondition string
const (
ConditionErrorRate AlertCondition = "error_rate"
ConditionAvgLatency AlertCondition = "avg_latency"
ConditionQueueDepth AlertCondition = "queue_depth"
ConditionConsumerDown AlertCondition = "consumer_down"
ConditionMessageThroughput AlertCondition = "message_throughput"
)
// AlertSeverity 告警严重级别
type AlertSeverity string
const (
SeverityLow AlertSeverity = "low"
SeverityMedium AlertSeverity = "medium"
SeverityHigh AlertSeverity = "high"
SeverityCritical AlertSeverity = "critical"
)
// AlertAction 告警动作
type AlertAction interface {
// Execute 执行告警动作
Execute(alert *Alert) error
}
// Alert 告警信息
type Alert struct {
RuleName string `json:"rule_name"`
Severity AlertSeverity `json:"severity"`
Message string `json:"message"`
Details map[string]string `json:"details"`
Timestamp time.Time `json:"timestamp"`
Resolved bool `json:"resolved"`
}
// NewMessageMonitor 创建消息监控器
func NewMessageMonitor(b broker.Broker) *MessageMonitor {
ctx, cancel := context.WithCancel(context.Background())
return &MessageMonitor{
broker: b,
metrics: &MessageMetrics{
StartTime: time.Now(),
LastUpdateTime: time.Now(),
ByTopic: make(map[string]*TopicMetrics),
ByConsumer: make(map[string]*ConsumerMetrics),
MinProcessingTime: float64(time.Hour), // 初始为最大值
},
collectors: make([]MetricCollector, 0),
exporters: make([]MetricsExporter, 0),
alertRules: make([]AlertRule, 0),
ctx: ctx,
cancel: cancel,
}
}
// Start 启动监控器
func (m *MessageMonitor) Start() error {
m.ticker = time.NewTicker(time.Second * 10)
go m.run()
return nil
}
// Stop 停止监控器
func (m *MessageMonitor) Stop() error {
if m.ticker != nil {
m.ticker.Stop()
}
m.cancel()
return nil
}
// AddCollector 添加指标收集器
func (m *MessageMonitor) AddCollector(collector MetricCollector) {
m.mu.Lock()
defer m.mu.Unlock()
m.collectors = append(m.collectors, collector)
}
// AddExporter 添加指标导出器
func (m *MessageMonitor) AddExporter(exporter MetricsExporter) {
m.mu.Lock()
defer m.mu.Unlock()
m.exporters = append(m.exporters, exporter)
}
// AddAlertRule 添加告警规则
func (m *MessageMonitor) AddAlertRule(rule AlertRule) {
m.mu.Lock()
defer m.mu.Unlock()
m.alertRules = append(m.alertRules, rule)
}
// RecordMessage 记录消息
func (m *MessageMonitor) RecordMessage(topic string, processingTime time.Duration, isError bool) {
m.mu.Lock()
defer m.mu.Unlock()
now := time.Now()
// 更新全局指标
m.metrics.MessageCount++
m.metrics.LastUpdateTime = now
if isError {
m.metrics.ErrorCount++
} else {
m.metrics.SuccessCount++
}
// 更新处理时间统计
procTimeMs := float64(processingTime.Nanoseconds()) / 1e6
m.metrics.AvgProcessingTime = (m.metrics.AvgProcessingTime*float64(m.metrics.MessageCount-1) + procTimeMs) / float64(m.metrics.MessageCount)
if procTimeMs < m.metrics.MinProcessingTime {
m.metrics.MinProcessingTime = procTimeMs
}
if procTimeMs > m.metrics.MaxProcessingTime {
m.metrics.MaxProcessingTime = procTimeMs
}
// 更新主题指标
if m.metrics.ByTopic[topic] == nil {
m.metrics.ByTopic[topic] = &TopicMetrics{
Topic: topic,
LastMessageTime: now,
}
}
topicMetrics := m.metrics.ByTopic[topic]
topicMetrics.LastMessageTime = now
if isError {
topicMetrics.ErrorCount++
} else {
topicMetrics.ConsumeCount++
}
}
// RecordPublish 记录发布
func (m *MessageMonitor) RecordPublish(topic string) {
m.mu.Lock()
defer m.mu.Unlock()
now := time.Now()
// 更新主题发布指标
if m.metrics.ByTopic[topic] == nil {
m.metrics.ByTopic[topic] = &TopicMetrics{
Topic: topic,
LastMessageTime: now,
}
}
m.metrics.ByTopic[topic].PublishCount++
}
// RecordConsumer 记录消费者状态
func (m *MessageMonitor) RecordConsumer(consumerID, topic string, isHealthy bool, lastError string) {
m.mu.Lock()
defer m.mu.Unlock()
key := fmt.Sprintf("%s:%s", consumerID, topic)
if m.metrics.ByConsumer[key] == nil {
m.metrics.ByConsumer[key] = &ConsumerMetrics{
ConsumerID: consumerID,
Topic: topic,
IsHealthy: isHealthy,
}
}
consumerMetrics := m.metrics.ByConsumer[key]
consumerMetrics.IsHealthy = isHealthy
consumerMetrics.LastProcessTime = time.Now()
if !isHealthy && lastError != "" {
consumerMetrics.LastError = lastError
}
}
// GetMetrics 获取指标
func (m *MessageMonitor) GetMetrics() *MessageMetrics {
m.mu.RLock()
defer m.mu.RUnlock()
// 深拷贝指标
data, _ := json.Marshal(m.metrics)
var result MessageMetrics
json.Unmarshal(data, &result)
return &result
}
// run 运行监控循环
func (m *MessageMonitor) run() {
for {
select {
case <-m.ctx.Done():
return
case <-m.ticker.C:
m.collectAndProcess()
}
}
}
// collectAndProcess 收集和处理指标
func (m *MessageMonitor) collectAndProcess() {
ctx := m.ctx
// 收集指标
for _, collector := range m.collectors {
metrics, err := collector.Collect(ctx)
if err != nil {
log.Logf("Failed to collect metrics from %s: %v", collector.Name(), err)
continue
}
// 合并指标
m.mergeMetrics(metrics)
}
// 检查告警
m.checkAlerts()
// 导出指标
currentMetrics := m.GetMetrics()
for _, exporter := range m.exporters {
if err := exporter.Export(currentMetrics); err != nil {
log.Logf("Failed to export metrics to %s: %v", exporter.Name(), err)
}
}
}
// mergeMetrics 合并指标
func (m *MessageMonitor) mergeMetrics(other *MessageMetrics) {
m.mu.Lock()
defer m.mu.Unlock()
// 合并全局指标
m.metrics.MessageCount += other.MessageCount
m.metrics.ErrorCount += other.ErrorCount
m.metrics.SuccessCount += other.SuccessCount
// 合并主题指标
for topic, topicMetrics := range other.ByTopic {
if m.metrics.ByTopic[topic] == nil {
m.metrics.ByTopic[topic] = &TopicMetrics{
Topic: topic,
}
}
existing := m.metrics.ByTopic[topic]
existing.PublishCount += topicMetrics.PublishCount
existing.ConsumeCount += topicMetrics.ConsumeCount
existing.ErrorCount += topicMetrics.ErrorCount
}
// 合并消费者指标
for key, consumerMetrics := range other.ByConsumer {
m.metrics.ByConsumer[key] = consumerMetrics
}
}
// checkAlerts 检查告警
func (m *MessageMonitor) checkAlerts() {
metrics := m.GetMetrics()
for _, rule := range m.alertRules {
alert := m.evaluateAlertRule(&rule, metrics)
if alert != nil {
m.triggerAlert(alert)
}
}
}
// evaluateAlertRule 评估告警规则
func (m *MessageMonitor) evaluateAlertRule(rule *AlertRule, metrics *MessageMetrics) *Alert {
switch rule.Condition {
case ConditionErrorRate:
if metrics.MessageCount > 0 {
errorRate := float64(metrics.ErrorCount) / float64(metrics.MessageCount)
if errorRate > rule.Threshold {
return &Alert{
RuleName: rule.Name,
Severity: rule.Severity,
Message: fmt.Sprintf("Error rate %.2f", errorRate*100, rule.Threshold*100),
Details: map[string]string{"error_count": fmt.Sprintf("%d", metrics.ErrorCount)},
Timestamp: time.Now(),
}
}
}
case ConditionAvgLatency:
if metrics.AvgProcessingTime > rule.Threshold {
return &Alert{
RuleName: rule.Name,
Severity: rule.Severity,
Message: fmt.Sprintf("Average processing time %.2fms exceeds threshold %.2fms", metrics.AvgProcessingTime, rule.Threshold),
Details: map[string]string{"avg_processing_time": fmt.Sprintf("%.2f", metrics.AvgProcessingTime)},
Timestamp: time.Now(),
}
}
case ConditionQueueDepth:
if metrics.QueueDepth > int64(rule.Threshold) {
return &Alert{
RuleName: rule.Name,
Severity: rule.Severity,
Message: fmt.Sprintf("Queue depth %d exceeds threshold %.0f", metrics.QueueDepth, rule.Threshold),
Details: map[string]string{"queue_depth": fmt.Sprintf("%d", metrics.QueueDepth)},
Timestamp: time.Now(),
}
}
case ConditionConsumerDown:
for _, consumer := range metrics.ByConsumer {
if !consumer.IsHealthy {
return &Alert{
RuleName: rule.Name,
Severity: rule.Severity,
Message: fmt.Sprintf("Consumer %s is down", consumer.ConsumerID),
Details: map[string]string{"consumer_id": consumer.ConsumerID, "last_error": consumer.LastError},
Timestamp: time.Now(),
}
}
}
}
return nil
}
// triggerAlert 触发告警
func (m *MessageMonitor) triggerAlert(alert *Alert) {
// 执行告警动作
for _, rule := range m.alertRules {
if rule.Name == alert.RuleName {
for _, action := range rule.Actions {
if err := action.Execute(alert); err != nil {
log.Logf("Failed to execute alert action: %v", err)
}
}
break
}
}
}
// BrokerMetricsCollector Broker指标收集器
type BrokerMetricsCollector struct {
broker broker.Broker
}
// NewBrokerMetricsCollector 创建Broker指标收集器
func NewBrokerMetricsCollector(b broker.Broker) *BrokerMetricsCollector {
return &BrokerMetricsCollector{
broker: b,
}
}
// Collect 收集指标
func (c *BrokerMetricsCollector) Collect(ctx context.Context) (*MessageMetrics, error) {
metrics := &MessageMetrics{
StartTime: time.Now(),
LastUpdateTime: time.Now(),
ByTopic: make(map[string]*TopicMetrics),
ByConsumer: make(map[string]*ConsumerMetrics),
}
// 这里可以根据具体的Broker实现收集指标
// 例如:连接状态、队列深度等
return metrics, nil
}
// Name 返回收集器名称
func (c *BrokerMetricsCollector) Name() string {
return "broker_metrics"
}
// PrometheusCollector Prometheus指标收集器
type PrometheusCollector struct {
registry *prometheus.Registry
}
// NewPrometheusCollector 创建Prometheus收集器
func NewPrometheusCollector() *PrometheusCollector {
return &PrometheusCollector{
registry: prometheus.NewRegistry(),
}
}
// Collect 收集指标
func (c *PrometheusCollector) Collect(ctx context.Context) (*MessageMetrics, error) {
// 实现Prometheus指标收集逻辑
return nil, nil
}
// Name 返回收集器名称
func (c *PrometheusCollector) Name() string {
return "prometheus"
}
---
03.指标导出器实现
a.功能说明
指标导出器负责将收集到的性能指标发送到外部系统,实现监控数据的持久化和可视化。
b.导出器类型
a.日志导出器
将指标数据以结构化日志形式输出到标准日志。
b.HTTP导出器
通过HTTP API将指标数据推送到远程监控系统。
c.文件导出器
将指标数据保存到本地文件,支持JSON格式。
c.导出特性
支持多种数据格式和传输协议。
内置重试和错误处理机制。
可配置的导出频率和批量处理。
d.代码示例
---
// LogExporter 日志导出器
type LogExporter struct {
formatter func(*MessageMetrics) string
}
// NewLogExporter 创建日志导出器
func NewLogExporter() *LogExporter {
return &LogExporter{
formatter: defaultLogFormatter,
}
}
// Export 导出指标
func (e *LogExporter) Export(metrics *MessageMetrics) error {
logStr := e.formatter(metrics)
log.Logf("Message Metrics: %s", logStr)
return nil
}
// Name 返回导出器名称
func (e *LogExporter) Name() string {
return "log"
}
// defaultLogFormatter 默认日志格式化器
func defaultLogFormatter(metrics *MessageMetrics) string {
return fmt.Sprintf(
"Messages: %d, Errors: %d, Success: %d, AvgLatency: %.2fms, Topics: %d, Consumers: %d",
metrics.MessageCount,
metrics.ErrorCount,
metrics.SuccessCount,
metrics.AvgProcessingTime,
len(metrics.ByTopic),
len(metrics.ByConsumer),
)
}
// HTTPExporter HTTP导出器
type HTTPExporter struct {
endpoint string
client *http.Client
}
// NewHTTPExporter 创建HTTP导出器
func NewHTTPExporter(endpoint string) *HTTPExporter {
return &HTTPExporter{
endpoint: endpoint,
client: &http.Client{Timeout: time.Second * 10},
}
}
// Export 导出指标
func (e *HTTPExporter) Export(metrics *MessageMetrics) error {
data, err := json.Marshal(metrics)
if err != nil {
return fmt.Errorf("failed to marshal metrics: %v", err)
}
resp, err := e.client.Post(e.endpoint, "application/json", bytes.NewBuffer(data))
if err != nil {
return fmt.Errorf("failed to send metrics: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
return fmt.Errorf("export failed with status: %d", resp.StatusCode)
}
return nil
}
// Name 返回导出器名称
func (e *HTTPExporter) Name() string {
return "http"
}
// FileExporter 文件导出器
type FileExporter struct {
filePath string
mu sync.Mutex
}
// NewFileExporter 创建文件导出器
func NewFileExporter(filePath string) *FileExporter {
return &FileExporter{
filePath: filePath,
}
}
// Export 导出指标
func (e *FileExporter) Export(metrics *MessageMetrics) error {
e.mu.Lock()
defer e.mu.Unlock()
data, err := json.MarshalIndent(metrics, "", " ")
if err != nil {
return fmt.Errorf("failed to marshal metrics: %v", err)
}
return os.WriteFile(e.filePath, data, 0644)
}
// Name 返回导出器名称
func (e *FileExporter) Name() string {
return "file"
}
---
04.告警动作实现
a.功能说明
告警动作负责在监控系统检测到异常情况时,通过各种渠道及时通知相关人员。
b.告警方式
a.邮件告警
通过SMTP协议发送结构化告警邮件,支持自定义收件人列表。
b.Webhook告警
通过HTTP POST请求将告警信息推送到指定的Webhook端点。
c.Slack告警
将告警信息发送到Slack频道,支持富文本格式和颜色标识。
c.告警特性
基于严重级别的颜色标识和优先级处理。
支持告警模板和自定义消息格式。
内置重试机制和错误处理。
d.代码示例
---
// EmailAlertAction 邮件告警动作
type EmailAlertAction struct {
smtpHost string
smtpPort int
username string
password string
from string
to []string
subject string
}
// NewEmailAlertAction 创建邮件告警动作
func NewEmailAlertAction(smtpHost string, smtpPort int, username, password, from string, to []string) *EmailAlertAction {
return &EmailAlertAction{
smtpHost: smtpHost,
smtpPort: smtpPort,
username: username,
password: password,
from: from,
to: to,
subject: "Message System Alert",
}
}
// Execute 执行邮件告警
func (a *EmailAlertAction) Execute(alert *Alert) error {
// 实现邮件发送逻辑
message := fmt.Sprintf("Alert: %s\nSeverity: %s\nMessage: %s\nTime: %s",
alert.RuleName, alert.Severity, alert.Message, alert.Timestamp.Format(time.RFC3339))
// 这里应该实现实际的邮件发送逻辑
log.Logf("Email alert: %s", message)
return nil
}
// WebhookAlertAction Webhook告警动作
type WebhookAlertAction struct {
url string
headers map[string]string
}
// NewWebhookAlertAction 创建Webhook告警动作
func NewWebhookAlertAction(url string, headers map[string]string) *WebhookAlertAction {
return &WebhookAlertAction{
url: url,
headers: headers,
}
}
// Execute 执行Webhook告警
func (a *WebhookAlertAction) Execute(alert *Alert) error {
data, err := json.Marshal(alert)
if err != nil {
return fmt.Errorf("failed to marshal alert: %v", err)
}
req, err := http.NewRequest("POST", a.url, bytes.NewBuffer(data))
if err != nil {
return fmt.Errorf("failed to create request: %v", err)
}
req.Header.Set("Content-Type", "application/json")
for k, v := range a.headers {
req.Header.Set(k, v)
}
client := &http.Client{Timeout: time.Second * 10}
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("failed to send webhook: %v", err)
}
defer resp.Body.Close()
return nil
}
// SlackAlertAction Slack告警动作
type SlackAlertAction struct {
webhookURL string
channel string
username string
}
// NewSlackAlertAction 创建Slack告警动作
func NewSlackAlertAction(webhookURL, channel, username string) *SlackAlertAction {
return &SlackAlertAction{
webhookURL: webhookURL,
channel: channel,
username: username,
}
}
// Execute 执行Slack告警
func (a *SlackAlertAction) Execute(alert *Alert) error {
payload := map[string]interface{}{
"channel": a.channel,
"username": a.username,
"text": fmt.Sprintf("🚨 Alert: %s", alert.RuleName),
"attachments": []map[string]interface{}{
{
"color": a.getSlackColor(alert.Severity),
"fields": []map[string]interface{}{
{
"title": "Severity",
"value": string(alert.Severity),
"short": true,
},
{
"title": "Message",
"value": alert.Message,
"short": false,
},
{
"title": "Time",
"value": alert.Timestamp.Format(time.RFC3339),
"short": true,
},
},
},
},
}
data, err := json.Marshal(payload)
if err != nil {
return fmt.Errorf("failed to marshal slack payload: %v", err)
}
resp, err := http.Post(a.webhookURL, "application/json", bytes.NewBuffer(data))
if err != nil {
return fmt.Errorf("failed to send slack alert: %v", err)
}
defer resp.Body.Close()
return nil
}
// getSlackColor 获取Slack颜色
func (a *SlackAlertAction) getSlackColor(severity AlertSeverity) string {
switch severity {
case SeverityLow:
return "good"
case SeverityMedium:
return "warning"
case SeverityHigh, SeverityCritical:
return "danger"
default:
return "warning"
}
}
---
05.消息治理策略
a.功能说明
消息治理策略通过预定义的规则对消息进行控制和约束,确保消息系统的安全和稳定。
b.治理策略类型
a.限流策略
基于时间窗口和速率限制的消息流量控制策略。
b.消息大小策略
对消息载荷大小进行限制的策略,防止超大消息影响系统性能。
c.策略执行机制
可插拔的策略接口,支持自定义治理规则。
基于上下文的策略评估和决策。
灵活的策略动作类型,包括允许、拒绝、修改、延迟等。
d.代码示例
---
// MessageGovernance 消息治理
type MessageGovernance struct {
policies []GovernancePolicy
monitor *MessageMonitor
enforcer PolicyEnforcer
}
// GovernancePolicy 治理策略
type GovernancePolicy interface {
// Name 策略名称
Name() string
// Evaluate 评估策略
Evaluate(ctx context.Context, message *MessageContext) *PolicyDecision
}
// MessageContext 消息上下文
type MessageContext struct {
MessageID string `json:"message_id"`
Topic string `json:"topic"`
Headers map[string]string `json:"headers"`
Payload []byte `json:"payload"`
ProducerID string `json:"producer_id"`
ConsumerID string `json:"consumer_id,omitempty"`
Timestamp time.Time `json:"timestamp"`
RetryCount int `json:"retry_count"`
}
// PolicyDecision 策略决策
type PolicyDecision struct {
Action PolicyAction `json:"action"`
Reason string `json:"reason"`
Parameters map[string]interface{} `json:"parameters,omitempty"`
}
// PolicyAction 策略动作
type PolicyAction string
const (
ActionAllow PolicyAction = "allow"
ActionDeny PolicyAction = "deny"
ActionModify PolicyAction = "modify"
ActionDelay PolicyAction = "delay"
ActionRetry PolicyAction = "retry"
ActionQuarantine PolicyAction = "quarantine"
)
// PolicyEnforcer 策略执行器
type PolicyEnforcer interface {
// Enforce 执行策略
Enforce(ctx context.Context, decision *PolicyDecision, message *MessageContext) error
}
// RateLimitPolicy 限流策略
type RateLimitPolicy struct {
Name string `json:"name"`
LimitPerSec int `json:"limit_per_sec"`
Window time.Duration `json:"window"`
counters map[string]*RateCounter
mu sync.RWMutex
}
// RateCounter 速率计数器
type RateCounter struct {
Count int `json:"count"`
StartTime time.Time `json:"start_time"`
}
// NewRateLimitPolicy 创建限流策略
func NewRateLimitPolicy(name string, limitPerSec int, window time.Duration) *RateLimitPolicy {
return &RateLimitPolicy{
Name: name,
LimitPerSec: limitPerSec,
Window: window,
counters: make(map[string]*RateCounter),
}
}
// Name 返回策略名称
func (p *RateLimitPolicy) Name() string {
return p.Name
}
// Evaluate 评估限流策略
func (p *RateLimitPolicy) Evaluate(ctx context.Context, message *MessageContext) *PolicyDecision {
key := message.Topic
if producerID := message.Headers["producer_id"]; producerID != "" {
key = fmt.Sprintf("%s:%s", key, producerID)
}
p.mu.Lock()
defer p.mu.Unlock()
now := time.Now()
counter := p.counters[key]
if counter == nil || now.Sub(counter.StartTime) > p.Window {
p.counters[key] = &RateCounter{
Count: 1,
StartTime: now,
}
return &PolicyDecision{Action: ActionAllow}
}
if counter.Count >= p.LimitPerSec {
return &PolicyDecision{
Action: ActionDeny,
Reason: fmt.Sprintf("Rate limit exceeded: %d requests per %v", p.LimitPerSec, p.Window),
}
}
counter.Count++
return &PolicyDecision{Action: ActionAllow}
}
// MessageSizePolicy 消息大小策略
type MessageSizePolicy struct {
Name string `json:"name"`
MaxSize int `json:"max_size"`
}
// NewMessageSizePolicy 创建消息大小策略
func NewMessageSizePolicy(name string, maxSize int) *MessageSizePolicy {
return &MessageSizePolicy{
Name: name,
MaxSize: maxSize,
}
}
// Name 返回策略名称
func (p *MessageSizePolicy) Name() string {
return p.Name
}
// Evaluate 评估消息大小策略
func (p *MessageSizePolicy) Evaluate(ctx context.Context, message *MessageContext) *PolicyDecision {
messageSize := len(message.Payload)
if messageSize > p.MaxSize {
return &PolicyDecision{
Action: ActionDeny,
Reason: fmt.Sprintf("Message size %d exceeds limit %d", messageSize, p.MaxSize),
}
}
return &PolicyDecision{Action: ActionAllow}
}
---
06.使用示例
a.功能说明
完整的监控和治理系统使用示例,展示如何集成各个组件实现全面的消息监控能力。
b.系统集成步骤
创建和配置消息Broker实例。
初始化消息监控器,添加收集器和导出器。
配置告警规则和治理策略。
启动监控系统并开始收集指标。
c.实际应用场景
模拟消息处理过程,记录性能指标。
演示告警触发和通知机制。
展示治理策略的评估和执行过程。
d.代码示例
---
package main
import (
"context"
"fmt"
"time"
"github.com/micro/go-micro/v2/broker/memory"
"github.com/micro/go-micro/v2/monitoring"
)
func main() {
// 创建Broker
br := memory.NewBroker()
if err := br.Connect(); err != nil {
fmt.Printf("failed to connect broker: %v\n", err)
return
}
defer br.Disconnect()
// 创建消息监控器
monitor := monitoring.NewMessageMonitor(br)
// 添加指标收集器
monitor.AddCollector(monitoring.NewBrokerMetricsCollector(br))
// 添加指标导出器
monitor.AddExporter(monitoring.NewLogExporter())
monitor.AddExporter(monitoring.NewFileExporter("/tmp/message_metrics.json"))
// 添加告警规则
errorRateRule := monitoring.AlertRule{
Name: "High Error Rate",
Condition: monitoring.ConditionErrorRate,
Threshold: 0.1, // 10%
Duration: time.Minute * 5,
Severity: monitoring.SeverityHigh,
Description: "Error rate is too high",
Actions: []monitoring.AlertAction{
monitoring.NewWebhookAlertAction("http://localhost:8080/webhook", map[string]string{
"Authorization": "Bearer token123",
}),
},
}
monitor.AddAlertRule(errorRateRule)
// 启动监控器
if err := monitor.Start(); err != nil {
fmt.Printf("failed to start monitor: %v\n", err)
return
}
defer monitor.Stop()
// 模拟消息处理
simulateMessageProcessing(monitor)
time.Sleep(time.Minute)
}
func simulateMessageProcessing(monitor *monitoring.MessageMonitor) {
// 模拟消息发布和消费
for i := 0; i < 100; i++ {
topic := "test.topic"
// 记录发布
monitor.RecordPublish(topic)
// 模拟消息处理时间
processingTime := time.Duration(rand.Intn(100)) * time.Millisecond
isError := rand.Float32() < 0.05 // 5%错误率
// 记录消息处理
monitor.RecordMessage(topic, processingTime, isError)
// 模拟消费者状态
consumerID := fmt.Sprintf("consumer-%d", i%3)
isHealthy := rand.Float32() > 0.02 // 98%健康率
lastError := ""
if !isHealthy {
lastError = "Connection timeout"
}
monitor.RecordConsumer(consumerID, topic, isHealthy, lastError)
time.Sleep(time.Millisecond * 100)
}
}
// MessageGovernanceExample 消息治理示例
func MessageGovernanceExample() {
// 创建治理策略
rateLimitPolicy := monitoring.NewRateLimitPolicy("api_rate_limit", 100, time.Second)
messageSizePolicy := monitoring.NewMessageSizePolicy("message_size_limit", 1024*1024) // 1MB
// 模拟消息治理
ctx := context.Background()
message := &monitoring.MessageContext{
MessageID: "msg-123",
Topic: "api.requests",
Headers: map[string]string{"producer_id": "service-a"},
Payload: make([]byte, 512*1024), // 512KB
ProducerID: "service-a",
Timestamp: time.Now(),
RetryCount: 0,
}
// 评估限流策略
decision1 := rateLimitPolicy.Evaluate(ctx, message)
fmt.Printf("Rate limit decision: %s - %s\n", decision1.Action, decision1.Reason)
// 评估消息大小策略
decision2 := messageSizePolicy.Evaluate(ctx, message)
fmt.Printf("Message size decision: %s - %s\n", decision2.Action, decision2.Reason)
}
---
5 客户端与负载均衡
5.1 请求处理流程
01.请求处理架构
a.架构说明
go-micro客户端请求处理采用分层架构,每层负责特定的功能,确保请求能够可靠高效地从客户端传递到服务端。
b.接口定义代码
---
package client
import (
"context"
"fmt"
"sync"
"time"
"github.com/micro/go-micro/v2/codec"
"github.com/micro/go-micro/v2/errors"
"github.com/micro/go-micro/v2/metadata"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/selector"
"github.com/micro/go-micro/v2/transport"
"github.com/micro/go-micro/v2/util/log"
)
// Request 请求接口
type Request interface {
// Service 目标服务
Service() string
// Method 调用方法
Method() string
// Endpoint 端点信息
Endpoint() string
// ContentType 内容类型
ContentType() string
// Body 请求体
Body() interface{}
// Codec 编解码器
Codec() codec.Codec
}
// Response 响应接口
type Response interface {
// StatusCode 状态码
StatusCode() int
// Header 响应头
Header() metadata.Metadata
// Body 响应体
Body() interface{}
}
// Client 客户端接口
type Client interface {
// Call 调用服务
Call(ctx context.Context, req Request, rsp interface{}, opts ...CallOption) error
// Stream 流式调用
Stream(ctx context.Context, req Request, opts ...CallOption) (Stream, error)
// Publish 发布消息
Publish(ctx context.Context, msg Message, opts ...PublishOption) error
// Options 客户端选项
Options() Options
}
// Stream 流接口
type Stream interface {
// Context 上下文
Context() context.Context
// Request 请求
Request() Request
// Send 发送消息
Send(msg interface{}) error
// Recv 接收消息
Recv(msg interface{}) error
// Error 错误信息
Error() error
// Close 关闭流
Close() error
}
// Message 消息接口
type Message interface {
// Topic 主题
Topic() string
// Payload 负载
Payload() interface{}
// ContentType 内容类型
ContentType() string
// Metadata 元数据
Metadata() map[string]string
}
// CallOption 调用选项
type CallOption func(*CallOptions)
// CallOptions 调用选项
type CallOptions struct {
// 其他选项
SelectOptions selector.Options
TransportOptions transport.Options
// 上下文
Context context.Context
// 服务名称
Service string
// 方法名称
Method string
// 地址
Address string
// 请求头
Header metadata.Metadata
// 请求超时
RequestTimeout time.Duration
// 拨号超时
DialTimeout time.Duration
// 重试次数
Retries int
// 跳过服务发现
SkipLookup bool
// 跳过负载均衡
SkipBalancer bool
// 流式调用
Stream bool
// 响应式调用
Reactive bool
}
// Options 客户端选项
type Options struct {
// 编解码器
Codec codec.Codec
// 内容类型
ContentType string
// 服务发现
Registry registry.Registry
// 选择器
Selector selector.Selector
// 传输层
Transport transport.Transport
// 拦截器
Wrappers []Wrapper
// 拦截器链
WrappersChain []Wrapper
// 连接池
Pool Pool
// 拨号选项
DialOptions []DialOption
// 调用选项
CallOptions []CallOption
// 发布选项
PublishOptions []PublishOption
// 上下文
Context context.Context
// 其他选项
//...
}
// rpcClient RPC客户端实现
type rpcClient struct {
opts Options
routes map[string]map[string][]*resolver
mu sync.RWMutex
}
// resolver 解析器
type resolver struct {
cc *poolConn
opts selector.Options
address string
}
// NewClient 创建客户端
func NewClient(opts ...Option) Client {
options := Options{
Codec: &json.Codec{},
ContentType: "application/json",
Registry: registry.DefaultRegistry,
Selector: selector.NewSelector(),
Transport: transport.DefaultTransport,
Wrappers: []Wrapper{},
Context: context.Background(),
}
for _, o := range opts {
o(&options)
}
// 创建连接池
if options.Pool == nil {
options.Pool = newPool(options)
}
return &rpcClient{
opts: options,
routes: make(map[string]map[string][]*resolver),
}
}
---
02.请求处理流程实现
a.核心流程代码
---
// Call RPC调用实现
func (r *rpcClient) Call(ctx context.Context, req Request, rsp interface{}, opts ...CallOption) error {
// 准备调用选项
callOpts := r.prepareCallOptions(req, opts...)
// 执行请求处理流程
return r.processRequest(ctx, req, rsp, callOpts)
}
// prepareCallOptions 准备调用选项
func (r *rpcClient) prepareCallOptions(req Request, opts []CallOption) *CallOptions {
// 创建默认调用选项
callOpts := &CallOptions{
SelectOptions: selector.DefaultSelectOptions,
Context: r.opts.Context,
Service: req.Service(),
Method: req.Method(),
RequestTimeout: time.Second * 30,
Retries: DefaultRetries,
}
// 应用传入选项
for _, o := range opts {
o(callOpts)
}
// 设置内容类型
if callOpts.Context == nil {
callOpts.Context = context.Background()
}
// 合并元数据
if callOpts.Header == nil {
callOpts.Header = make(metadata.Metadata)
}
return callOpts
}
// processRequest 处理请求的核心流程
func (r *rpcClient) processRequest(ctx context.Context, req Request, rsp interface{}, callOpts *CallOptions) error {
// 步骤1: 获取可用的服务节点
nodes, err := r.getServiceNodes(ctx, req.Service(), callOpts)
if err != nil {
return errors.InternalServerError("go.micro.client", "failed to get service nodes: %v", err)
}
if len(nodes) == 0 {
return errors.NotFound("go.micro.client", "service %s not found", req.Service())
}
// 步骤2: 负载均衡选择节点
node, err := r.selectNode(nodes, callOpts)
if err != nil {
return errors.InternalServerError("go.micro.client", "failed to select node: %v", err)
}
// 步骤3: 获取连接
conn, err := r.getOrCreateConnection(node, callOpts)
if err != nil {
return errors.InternalServerError("go.micro.client", "failed to get connection: %v", err)
}
// 步骤4: 执行调用
err = r.executeCall(ctx, conn, req, rsp, callOpts)
if err != nil {
// 步骤5: 错误处理和重试
return r.handleErrorWithRetry(ctx, err, req, rsp, nodes, callOpts)
}
return nil
}
// getServiceNodes 获取服务节点
func (r *rpcClient) getServiceNodes(ctx context.Context, service string, callOpts *CallOptions) ([]*registry.Node, error) {
// 如果指定了地址,直接使用
if callOpts.Address != "" {
return []*registry.Node{
{
Id: callOpts.Address,
Address: callOpts.Address,
},
}, nil
}
// 从注册中心获取服务
services, err := r.opts.Registry.GetService(service, registry.GetContext(ctx))
if err != nil {
return nil, err
}
if len(services) == 0 {
return nil, fmt.Errorf("service not found: %s", service)
}
// 收集所有节点
var nodes []*registry.Node
for _, service := range services {
nodes = append(nodes, service.Nodes...)
}
return nodes, nil
}
// selectNode 选择节点
func (r *rpcClient) selectNode(nodes []*registry.Node, callOpts *CallOptions) (*registry.Node, error) {
// 使用选择器选择节点
next, err := r.opts.Selector.Select(req.Service(), callOpts.SelectOptions)
if err != nil {
return nil, err
}
// 获取选中的节点
node, err := next()
if err != nil {
return nil, err
}
return node, nil
}
// getOrCreateConnection 获取或创建连接
func (r *rpcClient) getOrCreateConnection(node *registry.Node, callOpts *CallOptions) (ClientConn, error) {
// 构建连接地址
address := node.Address
if node.Port > 0 {
address = fmt.Sprintf("%s:%d", node.Address, node.Port)
}
// 从连接池获取连接
conn, err := r.opts.Pool.Get(address, r.poolOptions(callOpts))
if err != nil {
return nil, fmt.Errorf("failed to get connection from pool: %v", err)
}
return conn, nil
}
// poolOptions 构建连接池选项
func (r *rpcClient) poolOptions(callOpts *CallOptions) *poolOptions {
return &poolOptions{
Timeout: callOpts.DialTimeout,
MaxRetries: callOpts.Retries,
TLSConfig: r.opts.Transport.Options().TLSConfig,
Codec: r.opts.Codec,
ContentType: callOpts.ContentType,
Headers: callOpts.Header,
}
}
// executeCall 执行RPC调用
func (r *rpcClient) executeCall(ctx context.Context, conn ClientConn, req Request, rsp interface{}, callOpts *CallOption) error {
// 创建请求
request := &transport.Message{
Header: make(map[string]string),
Body: req.Body(),
}
// 设置请求头
request.Header["Content-Type"] = req.ContentType()
request.Header["Micro-Service"] = req.Service()
request.Header["Micro-Method"] = req.Method()
// 复制调用选项中的头部
for k, v := range callOpts.Header {
request.Header[k] = v
}
// 应用包装器
for _, wrapper := range r.opts.Wrappers {
err := wrapper.Call(ctx, req, rsp, callOpts, func(ctx context.Context, req Request, rsp interface{}) error {
return conn.Call(ctx, request, rsp)
})
if err != nil {
return err
}
return nil
}
// 如果没有包装器,直接调用
return conn.Call(ctx, request, rsp)
}
// handleErrorWithRetry 错误处理和重试
func (r *rpcClient) handleErrorWithRetry(ctx context.Context, err error, req Request, rsp interface{}, nodes []*registry.Node, callOpts *CallOption) error {
// 检查是否需要重试
if callOpts.Retries <= 0 {
return err
}
// 检查错误类型
if !r.isRetryableError(err) {
return err
}
// 执行重试
return r.retryCall(ctx, req, rsp, nodes, callOpts, 0)
}
// retryCall 重试调用
func (r *rpcClient) retryCall(ctx context.Context, req Request, rsp interface{}, nodes []*registry.Node, callOpts *CallOption, attempt int) error {
if attempt >= callOpts.Retries {
return fmt.Errorf("max retries (%d) exceeded", callOpts.Retries)
}
// 等待重试间隔
time.Sleep(r.calculateBackoff(attempt))
// 选择新的节点
node, err := r.selectNode(nodes, callOpts)
if err != nil {
return r.retryCall(ctx, req, rsp, nodes, callOpts, attempt+1)
}
// 获取新的连接
conn, err := r.getOrCreateConnection(node, callOpts)
if err != nil {
return r.retryCall(ctx, req, rsp, nodes, callOpts, attempt+1)
}
// 执行调用
err = r.executeCall(ctx, conn, req, rsp, callOpts)
if err != nil {
if r.isRetryableError(err) {
return r.retryCall(ctx, req, rsp, nodes, callOpts, attempt+1)
}
return err
}
return nil
}
// isRetryableError 判断是否为可重试错误
func (r *rpcClient) isRetryableError(err error) bool {
// 检查错误类型
merr, ok := err.(*errors.Error)
if !ok {
return false
}
// 网络错误、超时错误等可以重试
switch merr.Code {
case errors.InternalServerError,
errors.Timeout,
errors.BadRequest,
errors.NotFound,
errors.ServiceUnavailable:
return true
default:
return false
}
}
// calculateBackoff 计算退避时间
func (r *rpcClient) calculateBackoff(attempt int) time.Duration {
// 指数退避 + 随机抖动
base := time.Duration(100) * time.Millisecond
max := time.Duration(5) * time.Second
backoff := base * time.Duration(1<<uint(attempt))
if backoff > max {
backoff = max
}
// 添加随机抖动
jitter := time.Duration(rand.Float64() * float64(backoff) * 0.1)
return backoff + jitter
}
---
03.请求上下文管理
a.上下文结构
---
// RequestContext 请求上下文
type RequestContext struct {
// 请求ID
RequestID string
// 追踪ID
TraceID string
// 跨度ID
SpanID string
// 父跨度ID
ParentSpanID string
// 用户ID
UserID string
// 租户ID
TenantID string
// 请求开始时间
StartTime time.Time
// 超时时间
Timeout time.Duration
// 元数据
Metadata map[string]interface{}
// 标签
Tags map[string]string
}
// NewRequestContext 创建请求上下文
func NewRequestContext(ctx context.Context) *RequestContext {
reqCtx := &RequestContext{
RequestID: generateRequestID(),
TraceID: generateTraceID(),
SpanID: generateSpanID(),
StartTime: time.Now(),
Timeout: time.Second * 30,
Metadata: make(map[string]interface{}),
Tags: make(map[string]string),
}
// 从上下文中提取现有信息
if md, ok := metadata.FromContext(ctx); ok {
if traceID, exists := md["X-Trace-Id"]; exists {
reqCtx.TraceID = traceID
}
if spanID, exists := md["X-Span-Id"]; exists {
reqCtx.SpanID = spanID
}
if userID, exists := md["X-User-Id"]; exists {
reqCtx.UserID = userID
}
if tenantID, exists := md["X-Tenant-Id"]; exists {
reqCtx.TenantID = tenantID
}
}
return reqCtx
}
// ToMetadata 转换为元数据
func (rc *RequestContext) ToMetadata() metadata.Metadata {
md := make(metadata.Metadata)
md["X-Request-Id"] = rc.RequestID
md["X-Trace-Id"] = rc.TraceID
md["X-Span-Id"] = rc.SpanID
md["X-Parent-Span-Id"] = rc.ParentSpanID
md["X-Start-Time"] = rc.StartTime.Format(time.RFC3339Nano)
md["X-Timeout"] = rc.Timeout.String()
if rc.UserID != "" {
md["X-User-Id"] = rc.UserID
}
if rc.TenantID != "" {
md["X-Tenant-Id"] = rc.TenantID
}
// 添加标签
for k, v := range rc.Tags {
md[fmt.Sprintf("X-Tag-%s", k)] = v
}
return md
}
// RequestContextFromMetadata 从元数据创建请求上下文
func RequestContextFromMetadata(md metadata.Metadata) *RequestContext {
reqCtx := &RequestContext{
RequestID: md["X-Request-Id"],
TraceID: md["X-Trace-Id"],
SpanID: md["X-Span-Id"],
ParentSpanID: md["X-Parent-Span-Id"],
UserID: md["X-User-Id"],
TenantID: md["X-Tenant-Id"],
Tags: make(map[string]string),
Metadata: make(map[string]interface{}),
}
if startTimeStr := md["X-Start-Time"]; startTimeStr != "" {
if startTime, err := time.Parse(time.RFC3339Nano, startTimeStr); err == nil {
reqCtx.StartTime = startTime
}
}
if timeoutStr := md["X-Timeout"]; timeoutStr != "" {
if timeout, err := time.ParseDuration(timeoutStr); err == nil {
reqCtx.Timeout = timeout
}
}
// 提取标签
for k, v := range md {
if strings.HasPrefix(k, "X-Tag-") {
tagKey := strings.TrimPrefix(k, "X-Tag-")
reqCtx.Tags[tagKey] = v
}
}
return reqCtx
}
---
04.请求拦截器
a.拦截器接口
---
// Interceptor 拦截器接口
type Interceptor interface {
// Intercept 拦截处理
Intercept(ctx context.Context, req Request, rsp Response, next NextHandler) error
}
// NextHandler 下一个处理器
type NextHandler func(ctx context.Context, req Request, rsp Response) error
// InterceptorChain 拦截器链
type InterceptorChain struct {
interceptors []Interceptor
}
// NewInterceptorChain 创建拦截器链
func NewInterceptorChain(interceptors ...Interceptor) *InterceptorChain {
return &InterceptorChain{
interceptors: interceptors,
}
}
// Execute 执行拦截器链
func (ic *InterceptorChain) Execute(ctx context.Context, req Request, rsp Response) error {
if len(ic.interceptors) == 0 {
return nil
}
// 创建执行链
return ic.executeAt(0, ctx, req, rsp)
}
// executeAt 在指定位置执行拦截器
func (ic *InterceptorChain) executeAt(index int, ctx context.Context, req Request, rsp Response) error {
if index >= len(ic.interceptors) {
return nil
}
interceptor := ic.interceptors[index]
return interceptor.Intercept(ctx, req, rsp, func(ctx context.Context, req Request, rsp Response) error {
return ic.executeAt(index+1, ctx, req, rsp)
})
}
// LoggingInterceptor 日志拦截器
type LoggingInterceptor struct{}
// NewLoggingInterceptor 创建日志拦截器
func NewLoggingInterceptor() *LoggingInterceptor {
return &LoggingInterceptor{}
}
// Intercept 拦截处理
func (i *LoggingInterceptor) Intercept(ctx context.Context, req Request, rsp Response, next NextHandler) error {
start := time.Now()
// 记录请求开始
log.Logf("Starting request to %s.%s", req.Service(), req.Method())
// 执行下一个拦截器
err := next(ctx, req, rsp)
// 记录请求结束
duration := time.Since(start)
if err != nil {
log.Logf("Request to %s.%s failed after %v: %v", req.Service(), req.Method(), duration, err)
} else {
log.Logf("Request to %s.%s completed in %v", req.Service(), req.Method(), duration)
}
return err
}
// MetricsInterceptor 指标拦截器
type MetricsInterceptor struct {
registry *prometheus.Registry
requestDuration *prometheus.HistogramVec
requestTotal *prometheus.CounterVec
}
// NewMetricsInterceptor 创建指标拦截器
func NewMetricsInterceptor() *MetricsInterceptor {
duration := prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "client_request_duration_seconds",
Help: "Client request duration in seconds",
},
[]string{"service", "method"},
)
total := prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "client_requests_total",
Help: "Total number of client requests",
},
[]string{"service", "method", "status"},
)
return &MetricsInterceptor{
requestDuration: duration,
requestTotal: total,
}
}
// Intercept 拦截处理
func (i *MetricsInterceptor) Intercept(ctx context.Context, req Request, rsp Response, next NextHandler) error {
start := time.Now()
// 执行下一个拦截器
err := next(ctx, req, rsp)
// 记录指标
duration := time.Since(start).Seconds()
service := req.Service()
method := req.Method()
i.requestDuration.WithLabelValues(service, method).Observe(duration)
status := "success"
if err != nil {
status = "error"
}
i.requestTotal.WithLabelValues(service, method, status).Inc()
return err
}
---
05.使用示例
a.基础示例
---
package main
import (
"context"
"fmt"
"time"
"github.com/micro/go-micro/v2/client"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/selector"
)
func main() {
// 创建客户端
c := client.NewClient(
client.WithRegistry(registry.DefaultRegistry),
client.WithSelector(selector.NewSelector()),
client.WithWrapper(client.LoggingInterceptor{}),
client.WithWrapper(client.MetricsInterceptor{}),
)
// 创建请求上下文
ctx := context.Background()
req := &client.Request{
Service: "user.service",
Method: "GetUser",
Body: map[string]string{"user_id": "123"},
}
// 调用服务
var rsp map[string]interface{}
err := c.Call(ctx, req, &rsp,
client.WithRequestTimeout(time.Second*10),
client.WithRetries(3),
client.WithHeader(map[string]string{
"X-User-Id": "user123",
"X-Tenant-Id": "tenant456",
}),
)
if err != nil {
fmt.Printf("Call failed: %v\n", err)
return
}
fmt.Printf("Response: %+v\n", rsp)
}
// 高级用法示例
func advancedClientExample() {
// 创建拦截器链
interceptors := client.NewInterceptorChain(
client.NewLoggingInterceptor(),
client.NewMetricsInterceptor(),
&AuthInterceptor{},
&RateLimitInterceptor{},
)
// 创建客户端
c := client.NewClient(
client.WithInterceptorChain(interceptors),
client.WithPoolSize(100),
client.WithPoolTTL(time.Minute*5),
client.WithDialTimeout(time.Second*5),
client.WithRequestTimeout(time.Second*30),
)
// 批量调用
batchCall(c)
}
// AuthInterceptor 认证拦截器
type AuthInterceptor struct{}
func (a *AuthInterceptor) Intercept(ctx context.Context, req client.Request, rsp client.Response, next client.NextHandler) error {
// 检查认证信息
token := ctx.Value("auth_token")
if token == nil {
return fmt.Errorf("authentication required")
}
// 执行下一个拦截器
return next(ctx, req, rsp)
}
// RateLimitInterceptor 限流拦截器
type RateLimitInterceptor struct{}
func (r *RateLimitInterceptor) Intercept(ctx context.Context, req client.Request, rsp client.Response, next client.NextHandler) error {
// 检查限流
if !r.checkRateLimit(req.Service()) {
return fmt.Errorf("rate limit exceeded")
}
// 执行下一个拦截器
return next(ctx, req, rsp)
}
func (r *RateLimitInterceptor) checkRateLimit(service string) bool {
// 实现限流逻辑
return true
}
---
b.总结
请求处理流程为go-micro客户端提供了完整的请求生命周期管理,从请求准备到响应处理,包含了服务发现负载均衡连接管理错误处理等核心功能,确保了微服务间通信的可靠性和高效性。
5.2 LoadBalancer负载均衡
01.负载均衡概述
a.核心概念
负载均衡是微服务架构中的关键组件,负责将客户端请求分发到多个服务实例,提高系统的可用性可靠性和性能。go-micro提供了多种负载均衡策略,支持动态配置和自定义扩展。
b.负载均衡目标
高可用性方面避免单点故障,性能优化方面合理分配请求负载,弹性扩展方面支持服务的动态扩缩容,故障隔离方面自动排除故障节点,流量控制方面支持流量分配和限流。
c.负载均衡策略
支持的策略包括随机策略Random轮询策略RoundRobin加权轮询WeightRoundRobin最少连接LeastConnection一致性哈希ConsistentHash响应时间加权ResponseTimeWeighted。
02.负载均衡接口设计
a.接口定义
---
package selector
import (
"context"
"fmt"
"math/rand"
"sort"
"sync"
"time"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/util/log"
)
// Selector 选择器接口
type Selector interface {
// Init 初始化
Init(opts ...Option) error
// Options 返回选项
Options() Options
// Select 选择节点
Select(service string, opts ...SelectOption) (Next, error)
// String 返回字符串表示
String() string
}
// Next 下一个节点选择器
type Next func() (*registry.Node, error)
// Option 配置选项
type Option func(*Options)
// Options 选择器选项
type Options struct {
Registry registry.Registry
Strategy Strategy
}
// SelectOption 选择选项
type SelectOption func(*SelectOptions)
// SelectOptions 选择选项
type SelectOptions struct {
Strategy Strategy
// 其他选项
}
// Strategy 负载均衡策略接口
type Strategy interface {
// Select 选择节点
Select(services []*registry.Service) Next
// String 返回策略名称
String() string
}
// registrySelector 注册中心选择器
type registrySelector struct {
opts Options
cache map[string][]*registry.Service
mu sync.RWMutex
watcher registry.Watcher
ttl time.Duration
}
// NewSelector 创建选择器
func NewSelector(opts ...Option) Selector {
options := Options{
Registry: registry.DefaultRegistry,
Strategy: &RoundRobinStrategy{},
}
for _, o := range opts {
o(&options)
}
s := ®istrySelector{
opts: options,
cache: make(map[string][]*registry.Service),
ttl: time.Minute,
}
// 启动缓存更新
go s.run()
return s
}
// Init 初始化
func (s *registrySelector) Init(opts ...Option) error {
for _, o := range opts {
o(&s.opts)
}
return nil
}
// Options 返回选项
func (s *registrySelector) Options() Options {
return s.opts
}
// Select 选择服务节点
func (s *registrySelector) Select(service string, opts ...SelectOption) (Next, error) {
selectOpts := SelectOptions{
Strategy: s.opts.Strategy,
}
for _, o := range opts {
o(&selectOpts)
}
// 获取服务列表
services, err := s.getServices(service)
if err != nil {
return nil, err
}
if len(services) == 0 {
return nil, fmt.Errorf("no services available")
}
// 应用策略
return selectOpts.Strategy.Select(services), nil
}
// String 返回字符串表示
func (s *registrySelector) String() string {
return "registry"
}
// getServices 获取服务列表
func (s *registrySelector) getServices(service string) ([]*registry.Service, error) {
s.mu.RLock()
services, ok := s.cache[service]
s.mu.RUnlock()
if ok && len(services) > 0 {
return services, nil
}
// 从注册中心获取
services, err := s.opts.Registry.GetService(service)
if err != nil {
return nil, err
}
// 更新缓存
s.mu.Lock()
s.cache[service] = services
s.mu.Unlock()
return services, nil
}
// run 运行缓存更新
func (s *registrySelector) run() {
ticker := time.NewTicker(s.ttl)
defer ticker.Stop()
for {
select {
case <-ticker.C:
s.refreshCache()
}
}
}
// refreshCache 刷新缓存
func (s *registrySelector) refreshCache() {
s.mu.Lock()
defer s.mu.Unlock()
for service := range s.cache {
services, err := s.opts.Registry.GetService(service)
if err != nil {
log.Logf("Failed to refresh service %s: %v", service, err)
continue
}
s.cache[service] = services
}
}
---
03.负载均衡策略实现
a.轮询策略
---
// RoundRobinStrategy 轮询策略
type RoundRobinStrategy struct {
counters map[string]uint64
mu sync.Mutex
}
// NewRoundRobinStrategy 创建轮询策略
func NewRoundRobinStrategy() *RoundRobinStrategy {
return &RoundRobinStrategy{
counters: make(map[string]uint64),
}
}
// Select 选择节点
func (r *RoundRobinStrategy) Select(services []*registry.Service) Next {
if len(services) == 0 {
return nil
}
// 收集所有节点
var nodes []*registry.Node
for _, service := range services {
nodes = append(nodes, service.Nodes...)
}
if len(nodes) == 0 {
return nil
}
return func() (*registry.Node, error) {
r.mu.Lock()
defer r.mu.Unlock()
// 轮询选择
index := r.counters["roundrobin"] % uint64(len(nodes))
r.counters["roundrobin"]++
return nodes[index], nil
}
}
// String 返回策略名称
func (r *RoundRobinStrategy) String() string {
return "round_robin"
}
// RandomStrategy 随机策略
type RandomStrategy struct {
rand *rand.Rand
}
// NewRandomStrategy 创建随机策略
func NewRandomStrategy() *RandomStrategy {
return &RandomStrategy{
rand: rand.New(rand.NewSource(time.Now().UnixNano())),
}
}
// Select 选择节点
func (r *RandomStrategy) Select(services []*registry.Service) Next {
if len(services) == 0 {
return nil
}
var nodes []*registry.Node
for _, service := range services {
nodes = append(nodes, service.Nodes...)
}
if len(nodes) == 0 {
return nil
}
return func() (*registry.Node, error) {
index := r.rand.Intn(len(nodes))
return nodes[index], nil
}
}
// String 返回策略名称
func (r *RandomStrategy) String() string {
return "random"
}
---
b.加权轮询策略
---
// WeightRoundRobinStrategy 加权轮询策略
type WeightRoundRobinStrategy struct {
weights map[string]int
counters map[string]int
mu sync.Mutex
}
// NewWeightRoundRobinStrategy 创建加权轮询策略
func NewWeightRoundRobinStrategy() *WeightRoundRobinStrategy {
return &WeightRoundRobinStrategy{
weights: make(map[string]int),
counters: make(map[string]int),
}
}
// Select 选择节点
func (w *WeightRoundRobinStrategy) Select(services []*registry.Service) Next {
if len(services) == 0 {
return nil
}
// 构建带权重的节点列表
type weightedNode struct {
node *registry.Node
weight int
}
var weightedNodes []weightedNode
totalWeight := 0
for _, service := range services {
for _, node := range service.Nodes {
weight := w.getNodeWeight(node)
weightedNodes = append(weightedNodes, weightedNode{
node: node,
weight: weight,
})
totalWeight += weight
}
}
if len(weightedNodes) == 0 {
return nil
}
return func() (*registry.Node, error) {
w.mu.Lock()
defer w.mu.Unlock()
counter := w.counters["weighted_round_robin"]
w.counters["weighted_round_robin"]++
// 加权轮询选择
currentWeight := 0
for _, wn := range weightedNodes {
currentWeight += wn.weight
if counter < currentWeight {
return wn.node, nil
}
}
// 如果超出范围,重置计数器
w.counters["weighted_round_robin"] = 0
return weightedNodes[0].node, nil
}
}
// getNodeWeight 获取节点权重
func (w *WeightRoundRobinStrategy) getNodeWeight(node *registry.Node) int {
// 从元数据获取权重,默认为1
if weightStr, ok := node.Metadata["weight"]; ok {
if weight, err := fmt.Sscanf(weightStr, "%d", new(int)); err == nil && weight > 0 {
var result int
fmt.Sscanf(weightStr, "%d", &result)
return result
}
}
return 1
}
// String 返回策略名称
func (w *WeightRoundRobinStrategy) String() string {
return "weighted_round_robin"
}
---
c.最少连接策略
---
// LeastConnectionStrategy 最少连接策略
type LeastConnectionStrategy struct {
connections map[string]int
mu sync.RWMutex
}
// NewLeastConnectionStrategy 创建最少连接策略
func NewLeastConnectionStrategy() *LeastConnectionStrategy {
return &LeastConnectionStrategy{
connections: make(map[string]int),
}
}
// Select 选择节点
func (l *LeastConnectionStrategy) Select(services []*registry.Service) Next {
if len(services) == 0 {
return nil
}
var nodes []*registry.Node
for _, service := range services {
nodes = append(nodes, service.Nodes...)
}
if len(nodes) == 0 {
return nil
}
return func() (*registry.Node, error) {
l.mu.RLock()
defer l.mu.RUnlock()
// 找到连接数最少的节点
minConnections := int(^uint(0) >> 1) // 最大int值
var selectedNode *registry.Node
for _, node := range nodes {
connections := l.connections[node.Id]
if connections < minConnections {
minConnections = connections
selectedNode = node
}
}
if selectedNode != nil {
// 增加连接计数
l.mu.RUnlock()
l.mu.Lock()
l.connections[selectedNode.Id]++
l.mu.Unlock()
l.mu.RLock()
}
return selectedNode, nil
}
}
// ReleaseConnection 释放连接
func (l *LeastConnectionStrategy) ReleaseConnection(nodeID string) {
l.mu.Lock()
defer l.mu.Unlock()
if l.connections[nodeID] > 0 {
l.connections[nodeID]--
}
}
// String 返回策略名称
func (l *LeastConnectionStrategy) String() string {
return "least_connection"
}
---
d.一致性哈希策略
---
// ConsistentHashStrategy 一致性哈希策略
type ConsistentHashStrategy struct {
hash func(data []byte) uint32
replicas int
keys []int // 哈希环
hashMap map[int]string
nodeMap map[string]*registry.Node
}
// NewConsistentHashStrategy 创建一致性哈希策略
func NewConsistentHashStrategy(replicas int, fn func([]byte) uint32) *ConsistentHashStrategy {
if fn == nil {
fn = crc32.ChecksumIEEE
}
return &ConsistentHashStrategy{
hash: fn,
replicas: replicas,
hashMap: make(map[int]string),
nodeMap: make(map[string]*registry.Node),
}
}
// Select 选择节点
func (c *ConsistentHashStrategy) Select(services []*registry.Service) Next {
if len(services) == 0 {
return nil
}
// 添加节点到哈希环
var nodes []*registry.Node
for _, service := range services {
nodes = append(nodes, service.Nodes...)
}
c.addNodes(nodes)
return func() (*registry.Node, error) {
// 这里需要从上下文获取请求的键值
// 简化实现,使用随机键值
key := fmt.Sprintf("%d", time.Now().UnixNano())
return c.GetNode(key), nil
}
}
// GetNode 根据键获取节点
func (c *ConsistentHashStrategy) GetNode(key string) *registry.Node {
if len(c.keys) == 0 {
return nil
}
hash := int(c.hash([]byte(key)))
idx := sort.Search(len(c.keys), func(i int) bool {
return c.keys[i] >= hash
})
if idx == len(c.keys) {
idx = 0
}
nodeKey := c.hashMap[c.keys[idx]]
return c.nodeMap[nodeKey]
}
// addNodes 添加节点到哈希环
func (c *ConsistentHashStrategy) addNodes(nodes []*registry.Node) {
for _, node := range nodes {
for i := 0; i < c.replicas; i++ {
hash := int(c.hash([]byte(strconv.Itoa(i) + node.Id)))
c.keys = append(c.keys, hash)
c.hashMap[hash] = node.Id
}
c.nodeMap[node.Id] = node
}
sort.Ints(c.keys)
}
// String 返回策略名称
func (c *ConsistentHashStrategy) String() string {
return "consistent_hash"
}
---
e.响应时间加权策略
---
// ResponseTimeWeightedStrategy 响应时间加权策略
type ResponseTimeWeightedStrategy struct {
responseTimes map[string]time.Duration
mu sync.RWMutex
}
// NewResponseTimeWeightedStrategy 创建响应时间加权策略
func NewResponseTimeWeightedStrategy() *ResponseTimeWeightedStrategy {
return &ResponseTimeWeightedStrategy{
responseTimes: make(map[string]time.Duration),
}
}
// Select 选择节点
func (r *ResponseTimeWeightedStrategy) Select(services []*registry.Service) Next {
if len(services) == 0 {
return nil
}
var nodes []*registry.Node
for _, service := range services {
nodes = append(nodes, service.Nodes...)
}
if len(nodes) == 0 {
return nil
}
return func() (*registry.Node, error) {
r.mu.RLock()
defer r.mu.RUnlock()
// 计算权重(响应时间越短权重越高)
type weightedNode struct {
node *registry.Node
weight float64
}
var weightedNodes []weightedNode
totalWeight := 0.0
for _, node := range nodes {
responseTime := r.responseTimes[node.Id]
if responseTime == 0 {
responseTime = time.Second // 默认响应时间
}
// 权重与响应时间成反比
weight := 1.0 / responseTime.Seconds()
weightedNodes = append(weightedNodes, weightedNode{
node: node,
weight: weight,
})
totalWeight += weight
}
// 根据权重选择节点
randWeight := rand.Float64() * totalWeight
currentWeight := 0.0
for _, wn := range weightedNodes {
currentWeight += wn.weight
if randWeight <= currentWeight {
return wn.node, nil
}
}
return weightedNodes[0].node, nil
}
}
// UpdateResponseTime 更新响应时间
func (r *ResponseTimeWeightedStrategy) UpdateResponseTime(nodeID string, responseTime time.Duration) {
r.mu.Lock()
defer r.mu.Unlock()
// 使用指数加权移动平均
oldTime := r.responseTimes[nodeID]
if oldTime == 0 {
r.responseTimes[nodeID] = responseTime
} else {
// 0.7的新响应时间 + 0.3的旧响应时间
r.responseTimes[nodeID] = time.Duration(float64(responseTime)*0.7 + float64(oldTime)*0.3)
}
}
// String 返回策略名称
func (r *ResponseTimeWeightedStrategy) String() string {
return "response_time_weighted"
}
---
04.自定义负载均衡策略
a.自定义策略实现
---
// CustomStrategy 自定义策略示例
type CustomStrategy struct {
// 自定义配置
config map[string]interface{}
// 节点健康状态
health map[string]bool
// 节点性能指标
metrics map[string]*NodeMetrics
mu sync.RWMutex
}
// NodeMetrics 节点指标
type NodeMetrics struct {
RequestCount int64
ErrorCount int64
AvgResponseTime time.Duration
LastUpdateTime time.Time
}
// NewCustomStrategy 创建自定义策略
func NewCustomStrategy(config map[string]interface{}) *CustomStrategy {
return &CustomStrategy{
config: config,
health: make(map[string]bool),
metrics: make(map[string]*NodeMetrics),
}
}
// Select 选择节点
func (c *CustomStrategy) Select(services []*registry.Service) Next {
if len(services) == 0 {
return nil
}
// 构建候选节点
var candidates []*registry.Node
for _, service := range services {
for _, node := range service.Nodes {
if c.isNodeHealthy(node.Id) {
candidates = append(candidates, node)
}
}
}
if len(candidates) == 0 {
// 如果没有健康节点,返回所有节点
for _, service := range services {
candidates = append(candidates, service.Nodes...)
}
}
return func() (*registry.Node, error) {
return c.selectBestNode(candidates), nil
}
}
// selectBestNode 选择最佳节点
func (c *CustomStrategy) selectBestNode(nodes []*registry.Node) *registry.Node {
if len(nodes) == 0 {
return nil
}
if len(nodes) == 1 {
return nodes[0]
}
// 根据自定义算法选择最佳节点
var bestNode *registry.Node
bestScore := 0.0
for _, node := range nodes {
score := c.calculateNodeScore(node)
if score > bestScore {
bestScore = score
bestNode = node
}
}
return bestNode
}
// calculateNodeScore 计算节点评分
func (c *CustomStrategy) calculateNodeScore(node *registry.Node) float64 {
c.mu.RLock()
defer c.mu.RUnlock()
metrics, exists := c.metrics[node.Id]
if !exists {
return 0.5 // 默认分数
}
// 计算综合评分
// 评分因素:错误率、响应时间、请求频率
errorRate := float64(metrics.ErrorCount) / float64(metrics.RequestCount)
if metrics.RequestCount == 0 {
errorRate = 0
}
// 错误率越低分数越高
errorScore := (1.0 - errorRate) * 0.4
// 响应时间越短分数越高
responseScore := 0.3
if metrics.AvgResponseTime > 0 {
responseScore = 0.3 / (1.0 + metrics.AvgResponseTime.Seconds())
}
// 请求频率适中分数较高
requestScore := 0.3
requestRate := float64(metrics.RequestCount) / time.Since(metrics.LastUpdateTime).Seconds()
if requestRate > 0 && requestRate < 100 {
requestScore = 0.3
} else {
requestScore = 0.1
}
return errorScore + responseScore + requestScore
}
// isNodeHealthy 检查节点是否健康
func (c *CustomStrategy) isNodeHealthy(nodeID string) bool {
c.mu.RLock()
defer c.mu.RUnlock()
return c.health[nodeID]
}
// UpdateNodeHealth 更新节点健康状态
func (c *CustomStrategy) UpdateNodeHealth(nodeID string, healthy bool) {
c.mu.Lock()
defer c.mu.Unlock()
c.health[nodeID] = healthy
}
// UpdateNodeMetrics 更新节点指标
func (c *CustomStrategy) UpdateNodeMetrics(nodeID string, responseTime time.Duration, isError bool) {
c.mu.Lock()
defer c.mu.Unlock()
metrics, exists := c.metrics[nodeID]
if !exists {
metrics = &NodeMetrics{
LastUpdateTime: time.Now(),
}
c.metrics[nodeID] = metrics
}
metrics.RequestCount++
if isError {
metrics.ErrorCount++
}
// 更新平均响应时间
if metrics.AvgResponseTime == 0 {
metrics.AvgResponseTime = responseTime
} else {
// 指数移动平均
metrics.AvgResponseTime = time.Duration(
float64(responseTime)*0.3 + float64(metrics.AvgResponseTime)*0.7,
)
}
metrics.LastUpdateTime = time.Now()
}
// String 返回策略名称
func (c *CustomStrategy) String() string {
return "custom"
}
---
05.负载均衡配置和管理
a.负载均衡器管理
---
// LoadBalancer 负载均衡器
type LoadBalancer struct {
selector Selector
strategies map[string]Strategy
current string
mu sync.RWMutex
config *LoadBalancerConfig
}
// LoadBalancerConfig 负载均衡器配置
type LoadBalancerConfig struct {
DefaultStrategy string `json:"default_strategy"`
Strategies map[string]interface{} `json:"strategies"`
HealthCheck HealthCheckConfig `json:"health_check"`
Metrics MetricsConfig `json:"metrics"`
}
// HealthCheckConfig 健康检查配置
type HealthCheckConfig struct {
Enabled bool `json:"enabled"`
Interval time.Duration `json:"interval"`
Timeout time.Duration `json:"timeout"`
Retries int `json:"retries"`
Threshold float64 `json:"threshold"`
}
// MetricsConfig 指标配置
type MetricsConfig struct {
Enabled bool `json:"enabled"`
Interval time.Duration `json:"interval"`
Retention time.Duration `json:"retention"`
}
// NewLoadBalancer 创建负载均衡器
func NewLoadBalancer(selector Selector, config *LoadBalancerConfig) *LoadBalancer {
lb := &LoadBalancer{
selector: selector,
strategies: make(map[string]Strategy),
current: config.DefaultStrategy,
config: config,
}
// 注册内置策略
lb.strategies["round_robin"] = NewRoundRobinStrategy()
lb.strategies["random"] = NewRandomStrategy()
lb.strategies["weighted_round_robin"] = NewWeightRoundRobinStrategy()
lb.strategies["least_connection"] = NewLeastConnectionStrategy()
lb.strategies["consistent_hash"] = NewConsistentHashStrategy(150, nil)
lb.strategies["response_time_weighted"] = NewResponseTimeWeightedStrategy()
// 启动健康检查
if config.HealthCheck.Enabled {
go lb.runHealthCheck()
}
return lb
}
// SelectNode 选择节点
func (lb *LoadBalancer) SelectNode(service string, opts ...SelectOption) (*registry.Node, error) {
lb.mu.RLock()
strategy := lb.strategies[lb.current]
lb.mu.RUnlock()
if strategy == nil {
return nil, fmt.Errorf("strategy not found: %s", lb.current)
}
// 使用策略选择节点
next, err := lb.selector.Select(service, WithStrategy(strategy))
if err != nil {
return nil, err
}
return next()
}
// SetStrategy 设置负载均衡策略
func (lb *LoadBalancer) SetStrategy(strategyName string) error {
lb.mu.Lock()
defer lb.mu.Unlock()
if _, exists := lb.strategies[strategyName]; !exists {
return fmt.Errorf("strategy not found: %s", strategyName)
}
lb.current = strategyName
return nil
}
// RegisterStrategy 注册自定义策略
func (lb *LoadBalancer) RegisterStrategy(name string, strategy Strategy) {
lb.mu.Lock()
defer lb.mu.Unlock()
lb.strategies[name] = strategy
}
// runHealthCheck 运行健康检查
func (lb *LoadBalancer) runHealthCheck() {
ticker := time.NewTicker(lb.config.HealthCheck.Interval)
defer ticker.Stop()
for range ticker.C {
lb.performHealthCheck()
}
}
// performHealthCheck 执行健康检查
func (lb *LoadBalancer) performHealthCheck() {
// 实现健康检查逻辑
// 检查各个服务的节点健康状态
}
---
06.使用示例
a.基础使用示例
---
package main
import (
"context"
"fmt"
"time"
"github.com/micro/go-micro/v2/selector"
"github.com/micro/go-micro/v2/registry"
)
func main() {
// 创建选择器
sel := selector.NewSelector(
selector.WithRegistry(registry.DefaultRegistry),
selector.WithStrategy(selector.NewRoundRobinStrategy()),
)
// 使用不同策略
demonstrateStrategies(sel)
// 自定义策略示例
customStrategyExample()
}
func demonstrateStrategies(sel selector.Selector) {
strategies := map[string]selector.Strategy{
"round_robin": selector.NewRoundRobinStrategy(),
"random": selector.NewRandomStrategy(),
"weighted_round_robin": selector.NewWeightRoundRobinStrategy(),
"least_connection": selector.NewLeastConnectionStrategy(),
"consistent_hash": selector.NewConsistentHashStrategy(150, nil),
"response_time_weighted": selector.NewResponseTimeWeightedStrategy(),
}
serviceName := "user.service"
for name, strategy := range strategies {
fmt.Printf("Testing strategy: %s\n", name)
// 创建新的选择器实例
testSel := selector.NewSelector(
selector.WithStrategy(strategy),
)
// 选择节点
next, err := testSel.Select(serviceName)
if err != nil {
fmt.Printf("Failed to select with %s: %v\n", name, err)
continue
}
// 模拟多次选择
for i := 0; i < 5; i++ {
node, err := next()
if err != nil {
fmt.Printf("Selection %d failed: %v\n", i, err)
continue
}
fmt.Printf(" Selection %d: %s\n", i, node.Address)
}
fmt.Println()
}
}
func customStrategyExample() {
// 创建自定义策略配置
config := map[string]interface{}{
"health_check_interval": time.Second * 30,
"metrics_window": time.Minute * 5,
"error_threshold": 0.1,
}
// 创建自定义策略
customStrategy := NewCustomStrategy(config)
// 创建选择器
sel := selector.NewSelector(
selector.WithStrategy(customStrategy),
)
// 模拟使用自定义策略
next, err := sel.Select("user.service")
if err != nil {
fmt.Printf("Failed to select with custom strategy: %v\n", err)
return
}
for i := 0; i < 3; i++ {
node, err := next()
if err != nil {
fmt.Printf("Selection %d failed: %v\n", i, err)
continue
}
fmt.Printf("Custom strategy selected: %s\n", node.Address)
// 模拟更新节点指标
responseTime := time.Duration(rand.Intn(1000)) * time.Millisecond
isError := rand.Float32() < 0.1
customStrategy.UpdateNodeMetrics(node.Id, responseTime, isError)
customStrategy.UpdateNodeHealth(node.Id, !isError)
}
}
// 高级配置示例
func advancedLoadBalancerExample() {
// 创建负载均衡器配置
config := &LoadBalancerConfig{
DefaultStrategy: "response_time_weighted",
Strategies: map[string]interface{}{
"custom": map[string]interface{}{
"health_check_interval": "30s",
"error_threshold": 0.1,
},
},
HealthCheck: HealthCheckConfig{
Enabled: true,
Interval: time.Second * 30,
Timeout: time.Second * 5,
Retries: 3,
Threshold: 0.8,
},
Metrics: MetricsConfig{
Enabled: true,
Interval: time.Second * 10,
Retention: time.Hour * 24,
},
}
// 创建负载均衡器
lb := NewLoadBalancer(selector.DefaultSelector, config)
// 注册自定义策略
customStrategy := NewCustomStrategy(config.Strategies["custom"].(map[string]interface{}))
lb.RegisterStrategy("custom", customStrategy)
// 动态切换策略
lb.SetStrategy("custom")
// 使用负载均衡器
for i := 0; i < 10; i++ {
node, err := lb.SelectNode("user.service")
if err != nil {
fmt.Printf("Selection %d failed: %v\n", i, err)
continue
}
fmt.Printf("Load balancer selected: %s\n", node.Address)
time.Sleep(time.Millisecond * 100)
}
}
---
b.总结
负载均衡机制为go-micro提供了灵活的服务节点选择策略,通过多种内置算法和自定义扩展能力,能够适应不同的业务场景和性能要求,确保微服务系统的高可用性和性能优化。
5.3 Pool连接池管理
01.连接池概述
a.核心功能
连接池管理是客户端性能优化的关键组件,通过复用网络连接减少连接建立和销毁的开销,提高通信效率和系统吞吐量。核心功能包括连接复用重用已建立的连接减少开销,连接限制控制最大连接数防止资源耗尽,连接健康检查监控连接状态和可用性,生命周期管理自动创建维护和销毁连接,负载分散在多个连接间分散请求负载,故障恢复自动检测和替换故障连接。
b.连接池特性
支持多种协议HTTP或gRPC或TCP等,可配置的连接参数和超时设置,连接预热和空闲连接管理,连接泄漏检测和防护,实时监控和统计指标。
02.连接池接口设计
a.接口定义
---
package pool
import (
"context"
"fmt"
"net"
"sync"
"sync/atomic"
"time"
"github.com/micro/go-micro/v2/codec"
"github.com/micro/go-micro/v2/transport"
"github.com/micro/go-micro/v2/util/log"
)
// Pool 连接池接口
type Pool interface {
// Get 获取连接
Get(address string, opts ...PoolOption) (Conn, error)
// Release 释放连接
Release(conn Conn) error
// Close 关闭连接池
Close() error
// Stats 获取连接池统计信息
Stats() *PoolStats
// String 返回连接池字符串表示
String() string
}
// Conn 连接接口
type Conn interface {
// ID 连接ID
ID() string
// Address 连接地址
Address() string
// LocalAddress 本地地址
LocalAddress() string
// RemoteAddress 远程地址
RemoteAddress() string
// IsAlive 检查连接是否存活
IsAlive() bool
// Close 关闭连接
Close() error
// Call 发送请求
Call(ctx context.Context, req *transport.Message, rsp interface{}, opts ...CallOption) error
// Stream 创建流
Stream(ctx context.Context, req *transport.Message) (Stream, error)
}
// Stream 流接口
type Stream interface {
// Context 上下文
Context() context.Context
// Request 请求
Request() *transport.Message
// Send 发送消息
Send(msg interface{}) error
// Recv 接收消息
Recv(msg interface{}) error
// Error 错误信息
Error() error
// Close 关闭流
Close() error
}
// CallOption 调用选项
type CallOption func(*CallOptions)
// CallOptions 调用选项
type CallOptions struct {
// 请求超时
RequestTimeout time.Duration
// 编解码器
Codec codec.Codec
// 其他选项
}
// PoolOption 连接池选项
type PoolOption func(*PoolOptions)
// PoolOptions 连接池选项
type PoolOptions struct {
// 传输层
Transport transport.Transport
// 编解码器
Codec codec.Codec
// TLS配置
TLSConfig *tls.Config
// 拨号超时
DialTimeout time.Duration
// 连接超时
ConnectTimeout time.Duration
// 请求超时
RequestTimeout time.Duration
// 最大空闲时间
MaxIdleTime time.Duration
// 最大连接数
MaxConnections int
// 最大空闲连接数
MaxIdleConnections int
// 连接池大小
PoolSize int
// 健康检查间隔
HealthCheckInterval time.Duration
// 心跳间隔
HeartbeatInterval time.Duration
}
// PoolStats 连接池统计信息
type PoolStats struct {
// 总连接数
TotalConnections int64
// 活跃连接数
ActiveConnections int64
// 空闲连接数
IdleConnections int64
// 创建连接数
CreatedConnections int64
// 销毁连接数
DestroyedConnections int64
// 获取连接次数
GetRequests int64
// 释放连接次数
ReleaseRequests int64
// 连接错误数
ConnectionErrors int64
// 最后更新时间
LastUpdateTime time.Time
}
// defaultPool 默认连接池实现
type defaultPool struct {
options PoolOptions
connections map[string]*connectionPool
mu sync.RWMutex
closed bool
stats *PoolStats
cleanup *time.Ticker
done chan struct{}
}
// connectionPool 单个地址的连接池
type connectionPool struct {
address string
options PoolOptions
idleConns []*poolConn
activeConns map[string]*poolConn
mu sync.Mutex
maxSize int
maxIdleSize int
idleTimeout time.Duration
created int64
destroyed int64
stats *PoolStats
}
// poolConn 连接池中的连接
type poolConn struct {
conn Conn
created time.Time
lastUsed time.Time
inUse bool
useCount int64
errorCount int64
}
// NewPool 创建连接池
func NewPool(opts ...PoolOption) Pool {
options := PoolOptions{
Transport: transport.DefaultTransport,
Codec: &json.Codec{},
DialTimeout: time.Second * 5,
ConnectTimeout: time.Second * 3,
RequestTimeout: time.Second * 30,
MaxIdleTime: time.Minute * 5,
MaxConnections: 100,
MaxIdleConnections: 10,
PoolSize: 10,
HealthCheckInterval: time.Second * 30,
HeartbeatInterval: time.Second * 15,
}
for _, o := range opts {
o(&options)
}
p := &defaultPool{
options: options,
connections: make(map[string]*connectionPool),
stats: &PoolStats{
LastUpdateTime: time.Now(),
},
cleanup: time.NewTicker(time.Minute),
done: make(chan struct{}),
}
// 启动清理协程
go p.runCleanup()
return p
}
// Get 获取连接
func (p *defaultPool) Get(address string, opts ...PoolOption) (Conn, error) {
if p.closed {
return nil, fmt.Errorf("connection pool is closed")
}
// 合并选项
options := p.options
for _, o := range opts {
o(&options)
}
// 获取或创建地址连接池
cp := p.getOrCreateConnectionPool(address, options)
if cp == nil {
return nil, fmt.Errorf("failed to get connection pool for address: %s", address)
}
// 从连接池获取连接
conn, err := cp.get()
if err != nil {
return nil, err
}
// 更新统计信息
atomic.AddInt64(&p.stats.GetRequests, 1)
return conn, nil
}
// Release 释放连接
func (p *defaultPool) Release(conn Conn) error {
if p.closed {
return fmt.Errorf("connection pool is closed")
}
// 根据连接地址找到对应的连接池
cp := p.getConnectionPool(conn.Address())
if cp == nil {
// 连接不属于任何连接池,直接关闭
return conn.Close()
}
err := cp.release(conn)
if err == nil {
// 更新统计信息
atomic.AddInt64(&p.stats.ReleaseRequests, 1)
}
return err
}
// Close 关闭连接池
func (p *defaultPool) Close() error {
if p.closed {
return nil
}
p.closed = true
close(p.done)
p.mu.Lock()
defer p.mu.Unlock()
// 关闭所有连接池
for _, cp := range p.connections {
cp.close()
}
p.connections = make(map[string]*connectionPool)
return nil
}
// Stats 获取连接池统计信息
func (p *defaultPool) Stats() *PoolStats {
p.mu.RLock()
defer p.mu.RUnlock()
stats := &PoolStats{
LastUpdateTime: time.Now(),
}
// 聚合所有连接池的统计信息
for _, cp := range p.connections {
cpStats := cp.stats()
stats.TotalConnections += cpStats.TotalConnections
stats.ActiveConnections += cpStats.ActiveConnections
stats.IdleConnections += cpStats.IdleConnections
stats.CreatedConnections += cpStats.CreatedConnections
stats.DestroyedConnections += cpStats.DestroyedConnections
stats.ConnectionErrors += cpStats.ConnectionErrors
}
stats.GetRequests = atomic.LoadInt64(&p.stats.GetRequests)
stats.ReleaseRequests = atomic.LoadInt64(&p.stats.ReleaseRequests)
return stats
}
// String 返回连接池字符串表示
func (p *defaultPool) String() string {
return "default_connection_pool"
}
// getOrCreateConnectionPool 获取或创建连接池
func (p *defaultPool) getOrCreateConnectionPool(address string, options PoolOptions) *connectionPool {
p.mu.Lock()
defer p.mu.Unlock()
if cp, exists := p.connections[address]; exists {
return cp
}
// 创建新的连接池
cp := &connectionPool{
address: address,
options: options,
idleConns: make([]*poolConn, 0),
activeConns: make(map[string]*poolConn),
maxSize: options.PoolSize,
maxIdleSize: options.MaxIdleConnections,
idleTimeout: options.MaxIdleTime,
stats: &PoolStats{
LastUpdateTime: time.Now(),
},
}
p.connections[address] = cp
return cp
}
// getConnectionPool 获取连接池
func (p *defaultPool) getConnectionPool(address string) *connectionPool {
p.mu.RLock()
defer p.mu.RUnlock()
return p.connections[address]
}
// runCleanup 运行清理协程
func (p *defaultPool) runCleanup() {
for {
select {
case <-p.done:
return
case <-p.cleanup.C:
p.cleanupIdleConnections()
}
}
}
// cleanupIdleConnections 清理空闲连接
func (p *defaultPool) cleanupIdleConnections() {
p.mu.RLock()
defer p.mu.RUnlock()
for _, cp := range p.connections {
cp.cleanupIdleConnections()
}
}
---
03.连接池实现
a.核心方法实现
---
// get 获取连接
func (cp *connectionPool) get() (Conn, error) {
cp.mu.Lock()
defer cp.mu.Unlock()
// 尝试从空闲连接中获取
for len(cp.idleConns) > 0 {
pc := cp.idleConns[0]
cp.idleConns = cp.idleConns[1:]
// 检查连接是否仍然有效
if pc.conn.IsAlive() {
pc.inUse = true
pc.lastUsed = time.Now()
atomic.AddInt64(&pc.useCount, 1)
cp.activeConns[pc.conn.ID()] = pc
return pc.conn, nil
}
// 连接已失效,关闭并销毁
pc.conn.Close()
cp.destroyed++
}
// 检查是否可以创建新连接
if len(cp.activeConns) >= cp.maxSize {
return nil, fmt.Errorf("connection pool exhausted for address: %s", cp.address)
}
// 创建新连接
conn, err := cp.createConnection()
if err != nil {
atomic.AddInt64(&cp.stats.ConnectionErrors, 1)
return nil, fmt.Errorf("failed to create connection: %v", err)
}
// 包装连接
pc := &poolConn{
conn: conn,
created: time.Now(),
lastUsed: time.Now(),
inUse: true,
}
atomic.AddInt64(&pc.useCount, 1)
cp.activeConns[conn.ID()] = pc
cp.created++
return conn, nil
}
// release 释放连接
func (cp *connectionPool) release(conn Conn) error {
cp.mu.Lock()
defer cp.mu.Unlock()
pc, exists := cp.activeConns[conn.ID()]
if !exists {
return fmt.Errorf("connection not found in active connections: %s", conn.ID())
}
delete(cp.activeConns, conn.ID())
pc.inUse = false
pc.lastUsed = time.Now()
// 检查连接是否仍然有效
if !conn.IsAlive() {
conn.Close()
cp.destroyed++
return nil
}
// 检查空闲连接数量
if len(cp.idleConns) >= cp.maxIdleSize {
// 空闲连接过多,关闭连接
conn.Close()
cp.destroyed++
return nil
}
// 放回空闲连接池
cp.idleConns = append(cp.idleConns, pc)
return nil
}
// createConnection 创建新连接
func (cp *connectionPool) createConnection() (Conn, error) {
ctx, cancel := context.WithTimeout(context.Background(), cp.options.DialTimeout)
defer cancel()
// 创建传输连接
transportConn, err := cp.options.Transport.Dial(cp.address, transport.WithTimeout(cp.options.ConnectTimeout))
if err != nil {
return nil, err
}
// 创建连接包装器
conn := &transportConn{
transport: cp.options.Transport,
socket: transportConn,
address: cp.address,
codec: cp.options.Codec,
requestTimeout: cp.options.RequestTimeout,
id: generateConnID(),
created: time.Now(),
}
// 启动健康检查
go cp.healthCheck(conn)
return conn, nil
}
// close 关闭连接池
func (cp *connectionPool) close() error {
cp.mu.Lock()
defer cp.mu.Unlock()
// 关闭所有空闲连接
for _, pc := range cp.idleConns {
pc.conn.Close()
}
cp.idleConns = cp.idleConns[:0]
// 关闭所有活跃连接
for _, pc := range cp.activeConns {
pc.conn.Close()
}
cp.activeConns = make(map[string]*poolConn)
return nil
}
// cleanupIdleConnections 清理空闲连接
func (cp *connectionPool) cleanupIdleConnections() {
cp.mu.Lock()
defer cp.mu.Unlock()
now := time.Now()
keepConns := cp.idleConns[:0]
for _, pc := range cp.idleConns {
// 检查是否超时
if now.Sub(pc.lastUsed) > cp.idleTimeout {
pc.conn.Close()
cp.destroyed++
continue
}
// 检查连接是否仍然有效
if !pc.conn.IsAlive() {
pc.conn.Close()
cp.destroyed++
continue
}
keepConns = append(keepConns, pc)
}
cp.idleConns = keepConns
}
// healthCheck 健康检查
func (cp *connectionPool) healthCheck(conn Conn) {
ticker := time.NewTicker(cp.options.HealthCheckInterval)
defer ticker.Stop()
for {
select {
case <-ticker.C:
if !conn.IsAlive() {
log.Logf("Connection %s health check failed", conn.ID())
return
}
// 发送心跳
if err := cp.sendHeartbeat(conn); err != nil {
log.Logf("Heartbeat failed for connection %s: %v", conn.ID(), err)
return
}
case <-time.After(cp.options.HeartbeatInterval):
// 超时检查
if !conn.IsAlive() {
return
}
}
}
}
// sendHeartbeat 发送心跳
func (cp *connectionPool) sendHeartbeat(conn Conn) error {
// 创建心跳消息
req := &transport.Message{
Header: map[string]string{
"Micro-Method": "health_check",
"Micro-Heartbeat": "true",
},
Body: []byte("ping"),
}
// 发送心跳请求
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
defer cancel()
// 这里简化实现,实际应该使用conn.Call方法
// return conn.Call(ctx, req, nil)
return nil
}
// stats 获取连接池统计信息
func (cp *connectionPool) stats() *PoolStats {
cp.mu.Lock()
defer cp.mu.Unlock()
return &PoolStats{
TotalConnections: int64(len(cp.activeConns) + len(cp.idleConns)),
ActiveConnections: int64(len(cp.activeConns)),
IdleConnections: int64(len(cp.idleConns)),
CreatedConnections: cp.created,
DestroyedConnections: cp.destroyed,
ConnectionErrors: atomic.LoadInt64(&cp.stats.ConnectionErrors),
LastUpdateTime: time.Now(),
}
}
---
04.连接实现
a.传输层连接
---
// transportConn 传输层连接实现
type transportConn struct {
transport transport.Transport
socket transport.Client
address string
codec codec.Codec
requestTimeout time.Duration
id string
created time.Time
lastUsed time.Time
mu sync.RWMutex
streamCount int64
}
// ID 返回连接ID
func (c *transportConn) ID() string {
return c.id
}
// Address 返回连接地址
func (c *transportConn) Address() string {
return c.address
}
// LocalAddress 返回本地地址
func (c *transportConn) LocalAddress() string {
if c.socket != nil {
return c.socket.Local()
}
return ""
}
// RemoteAddress 返回远程地址
func (c *transportConn) RemoteAddress() string {
if c.socket != nil {
return c.socket.Remote()
}
return ""
}
// IsAlive 检查连接是否存活
func (c *transportConn) IsAlive() bool {
c.mu.RLock()
defer c.mu.RUnlock()
if c.socket == nil {
return false
}
// 检查连接状态
return !c.socket.Closed()
}
// Close 关闭连接
func (c *transportConn) Close() error {
c.mu.Lock()
defer c.mu.Unlock()
if c.socket != nil {
return c.socket.Close()
}
return nil
}
// Call 发送请求
func (c *transportConn) Call(ctx context.Context, req *transport.Message, rsp interface{}, opts ...CallOption) error {
c.mu.Lock()
defer c.mu.Unlock()
if c.socket == nil || c.socket.Closed() {
return fmt.Errorf("connection is closed")
}
// 合并选项
options := CallOptions{
RequestTimeout: c.requestTimeout,
Codec: c.codec,
}
for _, o := range opts {
o(&options)
}
// 设置请求超时
if options.RequestTimeout > 0 {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, options.RequestTimeout)
defer cancel()
}
// 发送请求
err := c.socket.Send(req)
if err != nil {
return fmt.Errorf("failed to send request: %v", err)
}
// 接收响应
var response transport.Message
err = c.socket.Recv(&response)
if err != nil {
return fmt.Errorf("failed to receive response: %v", err)
}
// 解码响应
if rsp != nil && len(response.Body) > 0 {
err = options.Codec.Unmarshal(response.Body, rsp)
if err != nil {
return fmt.Errorf("failed to unmarshal response: %v", err)
}
}
c.lastUsed = time.Now()
return nil
}
// Stream 创建流
func (c *transportConn) Stream(ctx context.Context, req *transport.Message) (Stream, error) {
c.mu.Lock()
defer c.mu.Unlock()
if c.socket == nil || c.socket.Closed() {
return nil, fmt.Errorf("connection is closed")
}
// 创建流
stream := &transportStream{
conn: c,
request: req,
ctx: ctx,
done: make(chan struct{}),
}
// 发送流请求
err := c.socket.Send(req)
if err != nil {
return nil, fmt.Errorf("failed to send stream request: %v", err)
}
// 增加流计数
atomic.AddInt64(&c.streamCount, 1)
return stream, nil
}
// transportStream 传输层流实现
type transportStream struct {
conn *transportConn
request *transport.Message
ctx context.Context
done chan struct{}
mu sync.Mutex
err error
}
// Context 上下文
func (s *transportStream) Context() context.Context {
return s.ctx
}
// Request 请求
func (s *transportStream) Request() *transport.Message {
return s.request
}
// Send 发送消息
func (s *transportStream) Send(msg interface{}) error {
s.mu.Lock()
defer s.mu.Unlock()
if s.err != nil {
return s.err
}
select {
case <-s.done:
return s.err
case <-s.ctx.Done():
return s.ctx.Err()
default:
}
// 序列化消息
data, err := s.conn.codec.Marshal(msg)
if err != nil {
return fmt.Errorf("failed to marshal message: %v", err)
}
// 创建流消息
streamMsg := &transport.Message{
Header: s.request.Header,
Body: data,
}
// 发送消息
return s.conn.socket.Send(streamMsg)
}
// Recv 接收消息
func (s *transportStream) Recv(msg interface{}) error {
s.mu.Lock()
defer s.mu.Unlock()
if s.err != nil {
return s.err
}
select {
case <-s.done:
return s.err
case <-s.ctx.Done():
return s.ctx.Err()
default:
}
// 接收消息
var response transport.Message
err := s.conn.socket.Recv(&response)
if err != nil {
s.setError(err)
return err
}
// 解码消息
if msg != nil && len(response.Body) > 0 {
err = s.conn.codec.Unmarshal(response.Body, msg)
if err != nil {
s.setError(err)
return fmt.Errorf("failed to unmarshal message: %v", err)
}
}
return nil
}
// Error 错误信息
func (s *transportStream) Error() error {
s.mu.Lock()
defer s.mu.Unlock()
return s.err
}
// Close 关闭流
func (s *transportStream) Close() error {
s.mu.Lock()
defer s.mu.Unlock()
select {
case <-s.done:
return s.err
default:
close(s.done)
s.conn.socket.Close()
atomic.AddInt64(&s.conn.streamCount, -1)
return s.err
}
}
// setError 设置错误
func (s *transportStream) setError(err error) {
s.mu.Lock()
defer s.mu.Unlock()
s.err = err
close(s.done)
}
// generateConnID 生成连接ID
func generateConnID() string {
return fmt.Sprintf("conn_%d_%d", time.Now().UnixNano(), rand.Int63())
}
---
05.连接池配置选项
a.配置选项定义
---
// WithTransport 设置传输层
func WithTransport(t transport.Transport) PoolOption {
return func(o *PoolOptions) {
o.Transport = t
}
}
// WithCodec 设置编解码器
func WithCodec(codec codec.Codec) PoolOption {
return func(o *PoolOptions) {
o.Codec = codec
}
}
// WithTLSConfig 设置TLS配置
func WithTLSConfig(config *tls.Config) PoolOption {
return func(o *PoolOptions) {
o.TLSConfig = config
}
}
// WithDialTimeout 设置拨号超时
func WithDialTimeout(timeout time.Duration) PoolOption {
return func(o *PoolOptions) {
o.DialTimeout = timeout
}
}
// WithConnectTimeout 设置连接超时
func WithConnectTimeout(timeout time.Duration) PoolOption {
return func(o *PoolOptions) {
o.ConnectTimeout = timeout
}
}
// WithRequestTimeout 设置请求超时
func WithRequestTimeout(timeout time.Duration) PoolOption {
return func(o *PoolOptions) {
o.RequestTimeout = timeout
}
}
// WithMaxIdleTime 设置最大空闲时间
func WithMaxIdleTime(timeout time.Duration) PoolOption {
return func(o *PoolOptions) {
o.MaxIdleTime = timeout
}
}
// WithMaxConnections 设置最大连接数
func WithMaxConnections(max int) PoolOption {
return func(o *PoolOptions) {
o.MaxConnections = max
}
}
// WithMaxIdleConnections 设置最大空闲连接数
func WithMaxIdleConnections(max int) PoolOption {
return func(o *PoolOptions) {
o.MaxIdleConnections = max
}
}
// WithPoolSize 设置连接池大小
func WithPoolSize(size int) PoolOption {
return func(o *PoolOptions) {
o.PoolSize = size
}
}
// WithHealthCheckInterval 设置健康检查间隔
func WithHealthCheckInterval(interval time.Duration) PoolOption {
return func(o *PoolOptions) {
o.HealthCheckInterval = interval
}
}
// WithHeartbeatInterval 设置心跳间隔
func WithHeartbeatInterval(interval time.Duration) PoolOption {
return func(o *PoolOptions) {
o.HeartbeatInterval = interval
}
}
---
06.使用示例
a.基础示例
---
package main
import (
"context"
"fmt"
"time"
"github.com/micro/go-micro/v2/pool"
"github.com/micro/go-micro/v2/transport"
"github.com/micro/go-micro/v2/codec/json"
"crypto/tls"
)
func main() {
// 创建连接池
p := pool.NewPool(
pool.WithMaxConnections(100),
pool.WithMaxIdleConnections(10),
pool.WithDialTimeout(time.Second*5),
pool.WithConnectTimeout(time.Second*3),
pool.WithRequestTimeout(time.Second*30),
pool.WithMaxIdleTime(time.Minute*5),
pool.WithHealthCheckInterval(time.Second*30),
pool.WithHeartbeatInterval(time.Second*15),
)
// 使用连接池
demonstratePoolUsage(p)
// 监控连接池状态
monitorPool(p)
}
func demonstratePoolUsage(p pool.Pool) {
addresses := []string{
"localhost:8080",
"localhost:8081",
"localhost:8082",
}
// 并发获取连接
for i := 0; i < 50; i++ {
go func(id int) {
address := addresses[id%len(addresses)]
// 获取连接
conn, err := p.Get(address)
if err != nil {
fmt.Printf("Failed to get connection %d: %v\n", id, err)
return
}
fmt.Printf("Worker %d got connection: %s (ID: %s)\n", id, address, conn.ID())
// 模拟使用连接
time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
// 调用远程服务
err = callRemoteService(conn, id)
if err != nil {
fmt.Printf("Worker %d call failed: %v\n", id, err)
}
// 释放连接
err = p.Release(conn)
if err != nil {
fmt.Printf("Worker %d failed to release connection: %v\n", id, err)
}
}(i)
}
// 等待所有goroutine完成
time.Sleep(time.Second * 10)
}
func callRemoteService(conn pool.Conn, workerID int) error {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
// 创建请求
req := &transport.Message{
Header: map[string]string{
"Content-Type": "application/json",
"Worker-ID": fmt.Sprintf("%d", workerID),
},
Body: []byte(fmt.Sprintf(`{"message": "Hello from worker %d"}`, workerID)),
}
// 发送请求
var response map[string]interface{}
err := conn.Call(ctx, req, &response)
if err != nil {
return fmt.Errorf("call failed: %v", err)
}
fmt.Printf("Worker %d received response: %+v\n", workerID, response)
return nil
}
func monitorPool(p pool.Pool) {
ticker := time.NewTicker(time.Second * 2)
defer ticker.Stop()
for i := 0; i < 10; i++ {
select {
case <-ticker.C:
stats := p.Stats()
fmt.Printf("Pool Stats[%d]:\n", i)
fmt.Printf(" Total Connections: %d\n", stats.TotalConnections)
fmt.Printf(" Active Connections: %d\n", stats.ActiveConnections)
fmt.Printf(" Idle Connections: %d\n", stats.IdleConnections)
fmt.Printf(" Created Connections: %d\n", stats.CreatedConnections)
fmt.Printf(" Destroyed Connections: %d\n", stats.DestroyedConnections)
fmt.Printf(" Get Requests: %d\n", stats.GetRequests)
fmt.Printf(" Release Requests: %d\n", stats.ReleaseRequests)
fmt.Printf(" Connection Errors: %d\n", stats.ConnectionErrors)
fmt.Println()
}
}
}
// 高级配置示例
func advancedPoolExample() {
// 创建TLS配置
tlsConfig := &tls.Config{
InsecureSkipVerify: false,
MinVersion: tls.VersionTLS12,
}
// 创建自定义传输层
transport := transport.NewTransport(
transport.WithTLSConfig(tlsConfig),
transport.WithTimeout(time.Second*10),
)
// 创建高级连接池
p := pool.NewPool(
pool.WithTransport(transport),
pool.WithCodec(&json.Codec{}),
pool.WithTLSConfig(tlsConfig),
pool.WithMaxConnections(200),
pool.WithMaxIdleConnections(20),
pool.WithPoolSize(50),
pool.WithDialTimeout(time.Second*10),
pool.WithConnectTimeout(time.Second*5),
pool.WithRequestTimeout(time.Minute),
pool.WithMaxIdleTime(time.Minute*10),
pool.WithHealthCheckInterval(time.Second*10),
pool.WithHeartbeatInterval(time.Second*5),
)
// 流式连接示例
demonstrateStreaming(p)
}
func demonstrateStreaming(p pool.Pool) {
conn, err := p.Get("localhost:8080")
if err != nil {
fmt.Printf("Failed to get connection: %v\n", err)
return
}
defer p.Release(conn)
// 创建流
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
defer cancel()
req := &transport.Message{
Header: map[string]string{
"Content-Type": "application/json",
"Stream": "true",
},
Body: []byte(`{"action": "start_stream"}`),
}
stream, err := conn.Stream(ctx, req)
if err != nil {
fmt.Printf("Failed to create stream: %v\n", err)
return
}
defer stream.Close()
// 发送多个消息
for i := 0; i < 5; i++ {
message := map[string]interface{}{
"sequence": i,
"data": fmt.Sprintf("Message %d", i),
}
err := stream.Send(message)
if err != nil {
fmt.Printf("Failed to send message %d: %v\n", i, err)
break
}
// 接收响应
var response map[string]interface{}
err = stream.Recv(&response)
if err != nil {
fmt.Printf("Failed to receive response %d: %v\n", i, err)
break
}
fmt.Printf("Stream response: %+v\n", response)
time.Sleep(time.Millisecond * 500)
}
}
---
b.总结
连接池管理为go-micro客户端提供了高效的连接复用和管理机制,通过合理的配置和优化,可以显著提升微服务通信的性能和稳定性,同时有效控制系统资源消耗。
5.4 Wrapper包装器模式
01.包装器模式概述
a.核心概念
包装器模式WrapperPattern是go-micro客户端框架中的重要设计模式,通过在客户端调用链中插入包装器来增强功能,如日志记录性能监控认证授权限流控制等。包装器模式特点包括链式调用支持多个包装器串联执行,功能增强在不修改原有逻辑的基础上添加新功能,可插拔包装器可以动态添加和移除,透明性对调用者透明不影响原有接口,可组合多个包装器可以组合使用。
b.常用包装器类型
常用的包装器类型包括日志包装器记录请求和响应日志,监控包装器收集性能指标和统计数据,认证包装器添加认证信息,限流包装器控制请求频率,熔断包装器实现熔断机制,重试包装器自动重试失败的请求,缓存包装器缓存响应结果。
02.包装器接口设计
a.接口定义
---
package wrapper
import (
"context"
"fmt"
"sync"
"time"
"github.com/micro/go-micro/v2/client"
"github.com/micro/go-micro/v2/codec"
"github.com/micro/go-micro/v2/errors"
"github.com/micro/go-micro/v2/metadata"
"github.com/micro/go-micro/v2/util/log"
)
// Wrapper 客户端包装器接口
type Wrapper interface {
// Call 包装RPC调用
Call(ctx context.Context, req client.Request, rsp interface{}, callFunc client.CallFunc) error
}
// WrapperFunc 包装器函数类型
type WrapperFunc func(ctx context.Context, req client.Request, rsp interface{}, callFunc client.CallFunc) error
// Call 实现Wrapper接口
func (wf WrapperFunc) Call(ctx context.Context, req client.Request, rsp interface{}, callFunc client.CallFunc) error {
return wf(ctx, req, rsp, callFunc)
}
// Chain 包装器链
type Chain struct {
wrappers []Wrapper
}
// NewChain 创建包装器链
func NewChain(wrappers ...Wrapper) Chain {
return Chain{wrappers: wrappers}
}
// Call 执行包装器链
func (c Chain) Call(ctx context.Context, req client.Request, rsp interface{}, callFunc client.CallFunc) error {
// 构建调用链
for i := len(c.wrappers) - 1; i >= 0; i-- {
wrapper := c.wrappers[i]
currentCallFunc := callFunc
callFunc = func(ctx context.Context, req client.Request, rsp interface{}) error {
return wrapper.Call(ctx, req, rsp, currentCallFunc)
}
}
return callFunc(ctx, req, rsp)
}
// Metrics 监控指标
type Metrics struct {
// 请求计数
RequestCount int64
// 错误计数
ErrorCount int64
// 成功计数
SuccessCount int64
// 总延迟
TotalLatency time.Duration
// 最大延迟
MaxLatency time.Duration
// 最小延迟
MinLatency time.Duration
// 最后更新时间
LastUpdateTime time.Time
mu sync.RWMutex
}
// NewMetrics 创建监控指标
func NewMetrics() *Metrics {
return &Metrics{
MinLatency: time.Hour, // 初始化为最大值
LastUpdateTime: time.Now(),
}
}
// RecordRequest 记录请求
func (m *Metrics) RecordRequest(latency time.Duration, success bool) {
m.mu.Lock()
defer m.mu.Unlock()
m.RequestCount++
m.LastUpdateTime = time.Now()
if success {
m.SuccessCount++
} else {
m.ErrorCount++
}
m.TotalLatency += latency
if latency > m.MaxLatency {
m.MaxLatency = latency
}
if latency < m.MinLatency {
m.MinLatency = latency
}
}
// GetStats 获取统计信息
func (m *Metrics) GetStats() map[string]interface{} {
m.mu.RLock()
defer m.mu.RUnlock()
stats := map[string]interface{}{
"request_count": m.RequestCount,
"error_count": m.ErrorCount,
"success_count": m.SuccessCount,
"error_rate": float64(m.ErrorCount) / float64(m.RequestCount),
"avg_latency": float64(m.TotalLatency.Nanoseconds()) / float64(m.RequestCount) / 1e6, // ms
"max_latency": m.MaxLatency.Nanoseconds() / 1e6, // ms
"min_latency": m.MinLatency.Nanoseconds() / 1e6, // ms
"last_update": m.LastUpdateTime,
}
if m.RequestCount > 0 {
stats["success_rate"] = float64(m.SuccessCount) / float64(m.RequestCount)
}
return stats
}
// Reset 重置指标
func (m *Metrics) Reset() {
m.mu.Lock()
defer m.mu.Unlock()
m.RequestCount = 0
m.ErrorCount = 0
m.SuccessCount = 0
m.TotalLatency = 0
m.MaxLatency = time.Hour
m.MinLatency = time.Hour
m.LastUpdateTime = time.Now()
}
---
03.通用包装器实现
a.日志包装器
---
// LoggingWrapper 日志包装器
type LoggingWrapper struct {
logger Logger
enabled bool
}
// Logger 日志接口
type Logger interface {
Logf(format string, args ...interface{})
Debugf(format string, args ...interface{})
}
// NewLoggingWrapper 创建日志包装器
func NewLoggingWrapper(logger Logger) *LoggingWrapper {
return &LoggingWrapper{
logger: logger,
enabled: true,
}
}
// Call 日志包装器调用
func (w *LoggingWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, callFunc client.CallFunc) error {
if !w.enabled {
return callFunc(ctx, req, rsp)
}
start := time.Now()
// 记录请求开始
w.logger.Logf("Calling service: %s, method: %s", req.Service(), req.Method())
// 执行调用
err := callFunc(ctx, req, rsp)
// 记录调用结果
latency := time.Since(start)
if err != nil {
w.logger.Logf("Call failed: service=%s, method=%s, latency=%v, error=%v",
req.Service(), req.Method(), latency, err)
} else {
w.logger.Logf("Call succeeded: service=%s, method=%s, latency=%v",
req.Service(), req.Method(), latency)
}
return err
}
// SetEnabled 设置是否启用
func (w *LoggingWrapper) SetEnabled(enabled bool) {
w.enabled = enabled
}
---
b.监控包装器
---
// MetricsWrapper 监控包装器
type MetricsWrapper struct {
metrics *Metrics
tags map[string]string
}
// NewMetricsWrapper 创建监控包装器
func NewMetricsWrapper(tags map[string]string) *MetricsWrapper {
return &MetricsWrapper{
metrics: NewMetrics(),
tags: tags,
}
}
// Call 监控包装器调用
func (w *MetricsWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, callFunc client.CallFunc) error {
start := time.Now()
// 执行调用
err := callFunc(ctx, req, rsp)
// 记录指标
latency := time.Since(start)
success := err == nil
w.metrics.RecordRequest(latency, success)
// 可以发送指标到监控系统
w.sendMetrics(req, latency, success)
return err
}
// sendMetrics 发送指标
func (w *MetricsWrapper) sendMetrics(req client.Request, latency time.Duration, success bool) {
// 这里可以实现发送到Prometheus、InfluxDB等监控系统
stats := w.metrics.GetStats()
log.Logf("Metrics: %+v", stats)
}
// GetMetrics 获取指标
func (w *MetricsWrapper) GetMetrics() *Metrics {
return w.metrics
}
// ResetMetrics 重置指标
func (w *MetricsWrapper) ResetMetrics() {
w.metrics.Reset()
}
---
c.认证包装器
---
// AuthWrapper 认证包装器
type AuthWrapper struct {
tokenProvider TokenProvider
enabled bool
}
// TokenProvider 令牌提供者接口
type TokenProvider interface {
GetToken(ctx context.Context) (string, error)
RefreshToken(ctx context.Context) error
}
// NewAuthWrapper 创建认证包装器
func NewAuthWrapper(provider TokenProvider) *AuthWrapper {
return &AuthWrapper{
tokenProvider: provider,
enabled: true,
}
}
// Call 认证包装器调用
func (w *AuthWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, callFunc client.CallFunc) error {
if !w.enabled {
return callFunc(ctx, req, rsp)
}
// 获取认证令牌
token, err := w.tokenProvider.GetToken(ctx)
if err != nil {
return fmt.Errorf("failed to get auth token: %v", err)
}
// 将令牌添加到上下文
md, ok := metadata.FromContext(ctx)
if !ok {
md = metadata.Metadata{}
}
md["Authorization"] = "Bearer " + token
ctx = metadata.NewContext(ctx, md)
// 执行调用
err = callFunc(ctx, req, rsp)
if err != nil {
// 检查是否是认证错误,尝试刷新令牌
if w.isAuthError(err) {
if refreshErr := w.tokenProvider.RefreshToken(ctx); refreshErr == nil {
// 重新获取令牌并重试
if newToken, tokenErr := w.tokenProvider.GetToken(ctx); tokenErr == nil {
md["Authorization"] = "Bearer " + newToken
ctx = metadata.NewContext(ctx, md)
return callFunc(ctx, req, rsp)
}
}
}
}
return err
}
// isAuthError 检查是否是认证错误
func (w *AuthWrapper) isAuthError(err error) bool {
if err == nil {
return false
}
merr, ok := err.(*errors.Error)
if !ok {
return false
}
// 检查错误码是否表示认证失败
return merr.Code == 401 || merr.Code == 403
}
// SetEnabled 设置是否启用
func (w *AuthWrapper) SetEnabled(enabled bool) {
w.enabled = enabled
}
---
04.高级包装器实现
a.限流包装器
---
// RateLimitWrapper 限流包装器
type RateLimitWrapper struct {
limiter RateLimiter
}
// RateLimiter 限流器接口
type RateLimiter interface {
Allow(key string) bool
Wait(ctx context.Context, key string) error
}
// NewRateLimitWrapper 创建限流包装器
func NewRateLimitWrapper(limiter RateLimiter) *RateLimitWrapper {
return &RateLimitWrapper{
limiter: limiter,
}
}
// Call 限流包装器调用
func (w *RateLimitWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, callFunc client.CallFunc) error {
// 构建限流键
key := fmt.Sprintf("%s:%s", req.Service(), req.Method())
// 尝试获取许可
err := w.limiter.Wait(ctx, key)
if err != nil {
return fmt.Errorf("rate limit exceeded: %v", err)
}
// 执行调用
return callFunc(ctx, req, rsp)
}
// TokenBucketLimiter 令牌桶限流器
type TokenBucketLimiter struct {
buckets map[string]*TokenBucket
mu sync.RWMutex
}
// TokenBucket 令牌桶
type TokenBucket struct {
capacity int
tokens int
rate time.Duration
lastTime time.Time
mu sync.Mutex
}
// NewTokenBucketLimiter 创建令牌桶限流器
func NewTokenBucketLimiter() *TokenBucketLimiter {
return &TokenBucketLimiter{
buckets: make(map[string]*TokenBucket),
}
}
// Allow 检查是否允许
func (l *TokenBucketLimiter) Allow(key string) bool {
bucket := l.getOrCreateBucket(key, 10, time.Second) // 默认10个令牌,每秒补充1个
return bucket.consume()
}
// Wait 等待许可
func (l *TokenBucketLimiter) Wait(ctx context.Context, key string) error {
bucket := l.getOrCreateBucket(key, 10, time.Second)
for {
if bucket.consume() {
return nil
}
select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(bucket.rate):
// 继续尝试
}
}
}
// getOrCreateBucket 获取或创建令牌桶
func (l *TokenBucketLimiter) getOrCreateBucket(key string, capacity int, rate time.Duration) *TokenBucket {
l.mu.RLock()
bucket, exists := l.buckets[key]
l.mu.RUnlock()
if exists {
return bucket
}
l.mu.Lock()
defer l.mu.Unlock()
// 双重检查
if bucket, exists := l.buckets[key]; exists {
return bucket
}
bucket = &TokenBucket{
capacity: capacity,
tokens: capacity,
rate: rate,
lastTime: time.Now(),
}
l.buckets[key] = bucket
return bucket
}
// consume 消费令牌
func (tb *TokenBucket) consume() bool {
tb.mu.Lock()
defer tb.mu.Unlock()
// 补充令牌
now := time.Now()
elapsed := now.Sub(tb.lastTime)
tokensToAdd := int(elapsed / tb.rate)
if tokensToAdd > 0 {
tb.tokens += tokensToAdd
if tb.tokens > tb.capacity {
tb.tokens = tb.capacity
}
tb.lastTime = now
}
// 检查是否有可用令牌
if tb.tokens > 0 {
tb.tokens--
return true
}
return false
}
---
b.熔断器包装器
---
// CircuitBreakerWrapper 熔断器包装器
type CircuitBreakerWrapper struct {
breaker CircuitBreaker
}
// CircuitBreaker 熔断器接口
type CircuitBreaker interface {
Call(ctx context.Context, req client.Request, callFunc client.CallFunc) error
State() CircuitBreakerState
Reset()
}
// CircuitBreakerState 熔断器状态
type CircuitBreakerState int
const (
StateClosed CircuitBreakerState = iota
StateOpen
StateHalfOpen
)
// NewCircuitBreakerWrapper 创建熔断器包装器
func NewCircuitBreakerWrapper(breaker CircuitBreaker) *CircuitBreakerWrapper {
return &CircuitBreakerWrapper{
breaker: breaker,
}
}
// Call 熔断器包装器调用
func (w *CircuitBreakerWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, callFunc client.CallFunc) error {
return w.breaker.Call(ctx, req, func(ctx context.Context, req client.Request, rsp interface{}) error {
return callFunc(ctx, req, rsp)
})
}
// DefaultCircuitBreaker 默认熔断器实现
type DefaultCircuitBreaker struct {
maxFailures int
timeout time.Duration
resetTimeout time.Duration
failures int
lastFailTime time.Time
state CircuitBreakerState
mu sync.RWMutex
}
// NewDefaultCircuitBreaker 创建默认熔断器
func NewDefaultCircuitBreaker(maxFailures int, timeout, resetTimeout time.Duration) *DefaultCircuitBreaker {
return &DefaultCircuitBreaker{
maxFailures: maxFailures,
timeout: timeout,
resetTimeout: resetTimeout,
state: StateClosed,
}
}
// Call 熔断器调用
func (cb *DefaultCircuitBreaker) Call(ctx context.Context, req client.Request, callFunc client.CallFunc) error {
cb.mu.RLock()
state := cb.state
cb.mu.RUnlock()
switch state {
case StateOpen:
if time.Since(cb.lastFailTime) > cb.resetTimeout {
cb.setState(StateHalfOpen)
} else {
return fmt.Errorf("circuit breaker is open")
}
case StateHalfOpen:
// 半开状态,允许少量请求通过
}
// 执行调用
err := callFunc(ctx, req, req)
cb.mu.Lock()
defer cb.mu.Unlock()
if err != nil {
cb.onFailure()
return err
}
cb.onSuccess()
return nil
}
// State 获取状态
func (cb *DefaultCircuitBreaker) State() CircuitBreakerState {
cb.mu.RLock()
defer cb.mu.RUnlock()
return cb.state
}
// Reset 重置熔断器
func (cb *DefaultCircuitBreaker) Reset() {
cb.mu.Lock()
defer cb.mu.Unlock()
cb.state = StateClosed
cb.failures = 0
}
// onSuccess 成功处理
func (cb *DefaultCircuitBreaker) onSuccess() {
if cb.state == StateHalfOpen {
cb.setState(StateClosed)
}
cb.failures = 0
}
// onFailure 失败处理
func (cb *DefaultCircuitBreaker) onFailure() {
cb.failures++
cb.lastFailTime = time.Now()
if cb.failures >= cb.maxFailures {
cb.setState(StateOpen)
}
}
// setState 设置状态
func (cb *DefaultCircuitBreaker) setState(state CircuitBreakerState) {
cb.state = state
log.Logf("Circuit breaker state changed to %v", state)
}
---
c.缓存包装器
---
// CacheWrapper 缓存包装器
type CacheWrapper struct {
cache Cache
ttl time.Duration
keyFunc func(req client.Request) string
}
// Cache 缓存接口
type Cache interface {
Get(key string) (interface{}, bool)
Set(key string, value interface{}, ttl time.Duration)
Delete(key string)
}
// NewCacheWrapper 创建缓存包装器
func NewCacheWrapper(cache Cache, ttl time.Duration, keyFunc func(req client.Request) string) *CacheWrapper {
return &CacheWrapper{
cache: cache,
ttl: ttl,
keyFunc: keyFunc,
}
}
// Call 缓存包装器调用
func (w *CacheWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, callFunc client.CallFunc) error {
// 检查缓存
if w.cache != nil {
cacheKey := w.keyFunc(req)
if cached, found := w.cache.Get(cacheKey); found {
// 从缓存中获取结果
return w.copyResponse(cached, rsp)
}
}
// 执行调用
err := callFunc(ctx, req, rsp)
if err != nil {
return err
}
// 缓存响应
if w.cache != nil {
cacheKey := w.keyFunc(req)
w.cache.Set(cacheKey, w.cloneResponse(rsp), w.ttl)
}
return nil
}
// copyResponse 复制响应
func (w *CacheWrapper) copyResponse(cached interface{}, rsp interface{}) error {
// 这里需要实现响应数据的深拷贝
// 简化实现
return nil
}
// cloneResponse 克隆响应
func (w *CacheWrapper) cloneResponse(rsp interface{}) interface{} {
// 这里需要实现响应数据的克隆
// 简化实现
return rsp
}
---
05.包装器管理
a.管理器实现
---
// WrapperManager 包装器管理器
type WrapperManager struct {
globalWrappers []Wrapper
serviceWrappers map[string][]Wrapper
methodWrappers map[string]map[string][]Wrapper
mu sync.RWMutex
}
// NewWrapperManager 创建包装器管理器
func NewWrapperManager() *WrapperManager {
return &WrapperManager{
globalWrappers: make([]Wrapper, 0),
serviceWrappers: make(map[string][]Wrapper),
methodWrappers: make(map[string]map[string][]Wrapper),
}
}
// AddGlobalWrapper 添加全局包装器
func (wm *WrapperManager) AddGlobalWrapper(wrapper Wrapper) {
wm.mu.Lock()
defer wm.mu.Unlock()
wm.globalWrappers = append(wm.globalWrappers, wrapper)
}
// AddServiceWrapper 添加服务包装器
func (wm *WrapperManager) AddServiceWrapper(service string, wrapper Wrapper) {
wm.mu.Lock()
defer wm.mu.Unlock()
if wm.serviceWrappers[service] == nil {
wm.serviceWrappers[service] = make([]Wrapper, 0)
}
wm.serviceWrappers[service] = append(wm.serviceWrappers[service], wrapper)
}
// AddMethodWrapper 添加方法包装器
func (wm *WrapperManager) AddMethodWrapper(service, method string, wrapper Wrapper) {
wm.mu.Lock()
defer wm.mu.Unlock()
if wm.methodWrappers[service] == nil {
wm.methodWrappers[service] = make(map[string][]Wrapper)
}
if wm.methodWrappers[service][method] == nil {
wm.methodWrappers[service][method] = make([]Wrapper, 0)
}
wm.methodWrappers[service][method] = append(wm.methodWrappers[service][method], wrapper)
}
// GetWrappers 获取包装器列表
func (wm *WrapperManager) GetWrappers(req client.Request) []Wrapper {
wm.mu.RLock()
defer wm.mu.RUnlock()
var wrappers []Wrapper
// 添加全局包装器
wrappers = append(wrappers, wm.globalWrappers...)
// 添加服务包装器
if serviceWrappers, exists := wm.serviceWrappers[req.Service()]; exists {
wrappers = append(wrappers, serviceWrappers...)
}
// 添加方法包装器
if methodMap, exists := wm.methodWrappers[req.Service()]; exists {
if methodWrappers, exists := methodMap[req.Method()]; exists {
wrappers = append(wrappers, methodWrappers...)
}
}
return wrappers
}
// ClearWrappers 清除包装器
func (wm *WrapperManager) ClearWrappers() {
wm.mu.Lock()
defer wm.mu.Unlock()
wm.globalWrappers = wm.globalWrappers[:0]
wm.serviceWrappers = make(map[string][]Wrapper)
wm.methodWrappers = make(map[string]map[string][]Wrapper)
}
// GetWrapperCount 获取包装器数量
func (wm *WrapperManager) GetWrapperCount() int {
wm.mu.RLock()
defer wm.mu.RUnlock()
count := len(wm.globalWrappers)
for _, wrappers := range wm.serviceWrappers {
count += len(wrappers)
}
for _, methodMap := range wm.methodWrappers {
for _, wrappers := range methodMap {
count += len(wrappers)
}
}
return count
}
---
06.使用示例
a.基础示例
---
package main
import (
"context"
"fmt"
"time"
"github.com/micro/go-micro/v2/client"
"github.com/micro/go-micro/v2/wrapper"
)
func main() {
// 创建包装器管理器
manager := wrapper.NewWrapperManager()
// 添加全局包装器
logger := &ConsoleLogger{}
manager.AddGlobalWrapper(wrapper.NewLoggingWrapper(logger))
manager.AddGlobalWrapper(wrapper.NewMetricsWrapper(map[string]string{
"service": "global",
"version": "1.0",
}))
// 添加服务包装器
authProvider := &MockTokenProvider{}
manager.AddServiceWrapper("user.service", wrapper.NewAuthWrapper(authProvider))
manager.AddServiceWrapper("user.service", wrapper.NewRateLimitWrapper(
wrapper.NewTokenBucketLimiter(),
))
// 添加方法包装器
manager.AddMethodWrapper("user.service", "GetUser", wrapper.NewCacheWrapper(
&MockCache{}, time.Minute*5, func(req client.Request) string {
return fmt.Sprintf("%s:%s", req.Service(), req.Method())
},
))
// 模拟客户端调用
demonstrateWrapperUsage(manager)
}
func demonstrateWrapperUsage(manager *WrapperManager) {
// 创建请求
req := &client.Request{
Service: "user.service",
Method: "GetUser",
Body: map[string]string{"user_id": "123"},
}
// 获取包装器
wrappers := manager.GetWrappers(req)
fmt.Printf("Found %d wrappers for %s.%s\n", len(wrappers), req.Service(), req.Method())
// 创建包装器链
chain := wrapper.NewChain(wrappers...)
// 模拟调用函数
callFunc := func(ctx context.Context, req client.Request, rsp interface{}) error {
fmt.Printf("Executing actual call to %s.%s\n", req.Service(), req.Method())
time.Sleep(time.Millisecond * 100) // 模拟网络延迟
return nil
}
// 执行包装器链
ctx := context.Background()
var rsp interface{}
start := time.Now()
err := chain.Call(ctx, req, &rsp, callFunc)
latency := time.Since(start)
if err != nil {
fmt.Printf("Call failed: %v\n", err)
} else {
fmt.Printf("Call succeeded in %v\n", latency)
}
}
// ConsoleLogger 控制台日志器
type ConsoleLogger struct{}
func (l *ConsoleLogger) Logf(format string, args ...interface{}) {
fmt.Printf("[LOG] "+format+"\n", args...)
}
func (l *ConsoleLogger) Debugf(format string, args ...interface{}) {
fmt.Printf("[DEBUG] "+format+"\n", args...)
}
// MockTokenProvider 模拟令牌提供者
type MockTokenProvider struct{}
func (p *MockTokenProvider) GetToken(ctx context.Context) (string, error) {
return "mock-token-123", nil
}
func (p *MockTokenProvider) RefreshToken(ctx context.Context) error {
fmt.Println("Refreshing token...")
return nil
}
// MockCache 模拟缓存
type MockCache struct {
data map[string]interface{}
}
func NewMockCache() *MockCache {
return &MockCache{
data: make(map[string]interface{}),
}
}
func (c *MockCache) Get(key string) (interface{}, bool) {
value, exists := c.data[key]
return value, exists
}
func (c *MockCache) Set(key string, value interface{}, ttl time.Duration) {
c.data[key] = value
fmt.Printf("Cached: %s (TTL: %v)\n", key, ttl)
}
func (c *MockCache) Delete(key string) {
delete(c.data, key)
}
---
b.高级示例
---
// 高级包装器示例
func advancedWrapperExample() {
// 创建熔断器
breaker := wrapper.NewDefaultCircuitBreaker(5, time.Second*10, time.Minute)
// 创建监控指标收集器
metricsCollector := &PrometheusMetricsCollector{}
// 组合多个包装器
wrappers := []wrapper.Wrapper{
wrapper.NewLoggingWrapper(&ConsoleLogger{}),
wrapper.NewMetricsWrapper(map[string]string{
"service": "advanced",
}),
wrapper.NewRateLimitWrapper(wrapper.NewTokenBucketLimiter()),
wrapper.NewCircuitBreakerWrapper(breaker),
}
// 创建包装器链
chain := wrapper.NewChain(wrappers...)
// 模拟多次调用
for i := 0; i < 20; i++ {
req := &client.Request{
Service: "advanced.service",
Method: "Process",
Body: map[string]interface{}{"id": i},
}
ctx := context.Background()
callFunc := func(ctx context.Context, req client.Request, rsp interface{}) error {
// 模拟随机失败
if i%7 == 0 {
return fmt.Errorf("simulated error")
}
time.Sleep(time.Millisecond * 50)
return nil
}
err := chain.Call(ctx, req, nil, callFunc)
if err != nil {
fmt.Printf("Call %d failed: %v\n", i, err)
} else {
fmt.Printf("Call %d succeeded\n", i)
}
time.Sleep(time.Millisecond * 100)
}
// 输出熔断器状态
fmt.Printf("Circuit breaker state: %v\n", breaker.State())
}
// PrometheusMetricsCollector Prometheus指标收集器
type PrometheusMetricsCollector struct{}
func (c *PrometheusMetricsCollector) CollectMetrics(service string, method string, latency time.Duration, success bool) {
// 实现发送到Prometheus
fmt.Printf("Prometheus metrics: service=%s, method=%s, latency=%v, success=%v\n",
service, method, latency, success)
}
---
c.总结
包装器模式为go-micro客户端提供了强大的功能扩展能力,通过链式包装器组合,可以在不修改核心业务逻辑的情况下,灵活地添加日志记录性能监控认证授权限流控制熔断保护等功能,大大提升了系统的可观测性和可靠性。
5.5 超时与重试机制
01.超时机制概述
a.核心特点
超时机制是分布式系统中保证系统响应性和稳定性的关键组件,通过设置合理的时间限制来防止请求无限等待,保护系统资源不被长时间占用。超时机制特点包括防止阻塞避免请求因网络问题或服务故障而无限等待,资源保护及时释放被阻塞的资源避免资源泄漏,快速失败快速返回错误提高系统响应性,用户体验提供明确的超时反馈改善用户体验,级联控制防止超时传递导致的问题扩散。
b.超时类型
支持的超时类型包括连接超时建立连接的最大等待时间,请求超时完整请求处理的最大等待时间,读取超时读取响应数据的最大等待时间,写入超时发送请求数据的最大等待时间,总体超时从请求开始到结束的总时间限制。
02.超时管理实现
a.超时配置和管理器
---
package timeout
import (
"context"
"fmt"
"sync"
"time"
"github.com/micro/go-micro/v2/errors"
"github.com/micro/go-micro/v2/util/log"
)
// TimeoutConfig 超时配置
type TimeoutConfig struct {
// 连接超时
ConnectTimeout time.Duration
// 读取超时
ReadTimeout time.Duration
// 写入超时
WriteTimeout time.Duration
// 总体超时
TotalTimeout time.Duration
// 默认超时
DefaultTimeout time.Duration
}
// DefaultTimeoutConfig 默认超时配置
func DefaultTimeoutConfig() *TimeoutConfig {
return &TimeoutConfig{
ConnectTimeout: time.Second * 5,
ReadTimeout: time.Second * 30,
WriteTimeout: time.Second * 10,
TotalTimeout: time.Second * 60,
DefaultTimeout: time.Second * 30,
}
}
// TimeoutManager 超时管理器
type TimeoutManager struct {
config *TimeoutConfig
handlers map[string]TimeoutHandler
mu sync.RWMutex
metrics *TimeoutMetrics
}
// TimeoutHandler 超时处理器接口
type TimeoutHandler interface {
// HandleTimeout 处理超时
HandleTimeout(ctx context.Context, req *Request, err error) error
// Name 处理器名称
Name() string
}
// TimeoutMetrics 超时指标
type TimeoutMetrics struct {
TotalRequests int64
Timeouts int64
ConnectionTimeouts int64
ReadTimeouts int64
WriteTimeouts int64
TimeoutRate float64
AvgTimeoutDuration time.Duration
mu sync.RWMutex
}
// NewTimeoutManager 创建超时管理器
func NewTimeoutManager(config *TimeoutConfig) *TimeoutManager {
if config == nil {
config = DefaultTimeoutConfig()
}
return &TimeoutManager{
config: config,
handlers: make(map[string]TimeoutHandler),
metrics: &TimeoutMetrics{},
}
}
// CreateContext 创建带超时的上下文
func (tm *TimeoutManager) CreateContext(parent context.Context, req *Request) (context.Context, context.CancelFunc) {
timeout := tm.getTimeout(req)
// 检查是否已有超时设置
if existingDeadline, exists := parent.Deadline(); exists {
remainingTime := time.Until(existingDeadline)
if remainingTime < timeout {
// 使用现有的较短超时
return context.WithCancel(parent)
}
}
return context.WithTimeout(parent, timeout)
}
// getTimeout 获取请求超时时间
func (tm *TimeoutManager) getTimeout(req *Request) time.Duration {
// 检查请求特定的超时
if req.Timeout > 0 {
return req.Timeout
}
// 检查方法特定的超时
if methodTimeout, exists := tm.config.MethodTimeouts[req.Method]; exists {
return methodTimeout
}
// 检查服务特定的超时
if serviceTimeout, exists := tm.config.ServiceTimeouts[req.Service]; exists {
return serviceTimeout
}
// 使用默认超时
return tm.config.DefaultTimeout
}
// HandleTimeout 处理超时
func (tm *TimeoutManager) HandleTimeout(ctx context.Context, req *Request, err error) error {
tm.mu.RLock()
defer tm.mu.RUnlock()
// 更新指标
tm.updateMetrics(err)
// 检查错误类型
timeoutType := tm.getTimeoutType(err)
switch timeoutType {
case "connect":
return tm.handleConnectTimeout(ctx, req, err)
case "read":
return tm.handleReadTimeout(ctx, req, err)
case "write":
return tm.handleWriteTimeout(ctx, req, err)
case "total":
return tm.handleTotalTimeout(ctx, req, err)
default:
return err
}
}
// getTimeoutType 获取超时类型
func (tm *TimeoutManager) getTimeoutType(err error) string {
if err == nil {
return ""
}
// 检查是否是上下文超时
if err == context.DeadlineExceeded {
return "total"
}
// 检查错误信息
errMsg := err.Error()
if contains(errMsg, "timeout") || contains(errMsg, "deadline") {
if contains(errMsg, "connect") {
return "connect"
} else if contains(errMsg, "read") {
return "read"
} else if contains(errMsg, "write") {
return "write"
}
return "total"
}
return ""
}
// handleConnectTimeout 处理连接超时
func (tm *TimeoutManager) handleConnectTimeout(ctx context.Context, req *Request, err error) error {
log.Logf("Connection timeout for %s.%s: %v", req.Service, req.Method, err)
// 记录指标
atomic.AddInt64(&tm.metrics.ConnectionTimeouts, 1)
// 返回格式化的错误
return errors.Timeout(req.Service, "connect_timeout", err.Error())
}
// handleReadTimeout 处理读取超时
func (tm *TimeoutManager) handleReadTimeout(ctx context.Context, req *Request, err error) error {
log.Logf("Read timeout for %s.%s: %v", req.Service, req.Method, err)
// 记录指标
atomic.AddInt64(&tm.metrics.ReadTimeouts, 1)
// 返回格式化的错误
return errors.Timeout(req.Service, "read_timeout", err.Error())
}
// handleWriteTimeout 处理写入超时
func (tm *TimeoutManager) handleWriteTimeout(ctx context.Context, req *Request, err error) error {
log.Logf("Write timeout for %s.%s: %v", req.Service, req.Method, err)
// 记录指标
atomic.AddInt64(&tm.metrics.WriteTimeouts, 1)
// 返回格式化的错误
return errors.Timeout(req.Service, "write_timeout", err.Error())
}
// handleTotalTimeout 处理总体超时
func (tm *TimeoutManager) handleTotalTimeout(ctx context.Context, req *Request, err error) error {
log.Logf("Total timeout for %s.%s: %v", req.Service, req.Method, err)
// 记录指标
atomic.AddInt64(&tm.metrics.Timeouts, 1)
// 返回格式化的错误
return errors.Timeout(req.Service, "total_timeout", err.Error())
}
// updateMetrics 更新指标
func (tm *TimeoutManager) updateMetrics(err error) {
atomic.AddInt64(&tm.metrics.TotalRequests, 1)
if tm.getTimeoutType(err) != "" {
atomic.AddInt64(&tm.metrics.Timeouts, 1)
}
}
// GetMetrics 获取超时指标
func (tm *TimeoutManager) GetMetrics() *TimeoutMetrics {
tm.mu.RLock()
defer tm.mu.RUnlock()
total := atomic.LoadInt64(&tm.metrics.TotalRequests)
timeouts := atomic.LoadInt64(&tm.metrics.Timeouts)
timeoutRate := 0.0
if total > 0 {
timeoutRate = float64(timeouts) / float64(total)
}
return &TimeoutMetrics{
TotalRequests: total,
Timeouts: timeouts,
ConnectionTimeouts: atomic.LoadInt64(&tm.metrics.ConnectionTimeouts),
ReadTimeouts: atomic.LoadInt64(&tm.metrics.ReadTimeouts),
WriteTimeouts: atomic.LoadInt64(&tm.metrics.WriteTimeouts),
TimeoutRate: timeoutRate,
}
}
// AddHandler 添加超时处理器
func (tm *TimeoutManager) AddHandler(name string, handler TimeoutHandler) {
tm.mu.Lock()
defer tm.mu.Unlock()
tm.handlers[name] = handler
}
// RemoveHandler 移除超时处理器
func (tm *TimeoutManager) RemoveHandler(name string) {
tm.mu.Lock()
defer tm.mu.Unlock()
delete(tm.handlers, name)
}
// contains 检查字符串包含
func contains(s, substr string) bool {
return len(s) >= len(substr) && (s == substr ||
(len(s) > len(substr) &&
(s[:len(substr)] == substr ||
s[len(s)-len(substr):] == substr ||
indexOfSubstring(s, substr) >= 0)))
}
// indexOfSubstring 查找子字符串位置
func indexOfSubstring(s, substr string) int {
for i := 0; i <= len(s)-len(substr); i++ {
if s[i:i+len(substr)] == substr {
return i
}
}
return -1
}
---
03.重试机制实现
a.重试配置和管理器
---
package retry
import (
"context"
"fmt"
"math"
"math/rand"
"strings"
"sync"
"time"
"github.com/micro/go-micro/v2/errors"
"github.com/micro/go-micro/v2/util/log"
)
// RetryConfig 重试配置
type RetryConfig struct {
// 最大重试次数
MaxRetries int
// 初始重试间隔
InitialInterval time.Duration
// 最大重试间隔
MaxInterval time.Duration
// 重试间隔倍数
Multiplier float64
// 随机化因子
RandomizationFactor float64
// 最大重试时间
MaxElapsedTime time.Duration
// 重试条件判断器
RetryCondition RetryCondition
}
// RetryCondition 重试条件接口
type RetryCondition interface {
// ShouldRetry 判断是否应该重试
ShouldRetry(ctx context.Context, req *Request, attempt int, err error) bool
}
// DefaultRetryConfig 默认重试配置
func DefaultRetryConfig() *RetryConfig {
return &RetryConfig{
MaxRetries: 3,
InitialInterval: time.Millisecond * 100,
MaxInterval: time.Second * 10,
Multiplier: 2.0,
RandomizationFactor: 0.1,
MaxElapsedTime: time.Minute * 1,
RetryCondition: &DefaultRetryCondition{},
}
}
// RetryManager 重试管理器
type RetryManager struct {
config *RetryConfig
handlers map[string]RetryHandler
mu sync.RWMutex
metrics *RetryMetrics
}
// RetryHandler 重试处理器接口
type RetryHandler interface {
// OnRetry 重试回调
OnRetry(ctx context.Context, req *Request, attempt int, err error)
// Name 处理器名称
Name() string
}
// RetryMetrics 重试指标
type RetryMetrics struct {
TotalRequests int64
TotalRetries int64
MaxRetries int64
SuccessAfterRetry int64
RetryRate float64
mu sync.RWMutex
}
// Request 请求结构
type Request struct {
Service string
Method string
Body interface{}
Timeout time.Duration
Metadata map[string]string
}
// NewRetryManager 创建重试管理器
func NewRetryManager(config *RetryConfig) *RetryManager {
if config == nil {
config = DefaultRetryConfig()
}
return &RetryManager{
config: config,
handlers: make(map[string]RetryHandler),
metrics: &RetryMetrics{},
}
}
// Execute 执行带重试的请求
func (rm *RetryManager) Execute(ctx context.Context, req *Request, callFunc CallFunc) error {
startTime := time.Now()
var lastError error
attempt := 0
// 总重试时间检查
if rm.config.MaxElapsedTime > 0 {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, rm.config.MaxElapsedTime)
defer cancel()
}
for {
// 检查上下文是否取消
select {
case <-ctx.Done():
return ctx.Err()
default:
}
// 执行请求
err := callFunc(ctx, req)
if err == nil {
// 请求成功
rm.recordSuccess(attempt)
return nil
}
lastError = err
attempt++
// 记录重试
rm.recordRetry()
// 检查是否应该重试
if !rm.shouldRetry(ctx, req, attempt, err) {
break
}
// 调用重试处理器
rm.notifyHandlers(ctx, req, attempt, err)
// 计算重试间隔
interval := rm.calculateRetryInterval(attempt)
// 等待重试间隔
select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(interval):
// 继续重试
}
// 检查是否超过最大重试次数
if attempt >= rm.config.MaxRetries {
break
}
}
// 记录失败
rm.recordFailure(attempt)
// 返回最后的错误
return rm.formatRetryError(req, attempt, lastError)
}
// shouldRetry 判断是否应该重试
func (rm *RetryManager) shouldRetry(ctx context.Context, req *Request, attempt int, err error) bool {
// 检查重试次数
if attempt >= rm.config.MaxRetries {
return false
}
// 检查上下文
select {
case <-ctx.Done():
return false
default:
}
// 使用重试条件判断
if rm.config.RetryCondition != nil {
return rm.config.RetryCondition.ShouldRetry(ctx, req, attempt, err)
}
// 默认重试条件
return rm.isRetryableError(err)
}
// isRetryableError 判断错误是否可重试
func (rm *RetryManager) isRetryableError(err error) bool {
if err == nil {
return false
}
// 检查是否是上下文取消
if err == context.Canceled || err == context.DeadlineExceeded {
return false
}
// 检查微服务错误
if merr, ok := err.(*errors.Error); ok {
switch merr.Code {
case 408, // Request Timeout
429, // Too Many Requests
500, // Internal Server Error
502, // Bad Gateway
503, // Service Unavailable
504: // Gateway Timeout
return true
case 400, // Bad Request
401, // Unauthorized
403, // Forbidden
404: // Not Found
return false
default:
return merr.Code >= 500
}
}
// 检查错误消息
errMsg := strings.ToLower(err.Error())
retryableErrors := []string{
"timeout",
"connection refused",
"connection reset",
"temporary failure",
"network is unreachable",
"no such host",
"connection timed out",
"read timeout",
"write timeout",
}
for _, retryableErr := range retryableErrors {
if strings.Contains(errMsg, retryableErr) {
return true
}
}
return false
}
// calculateRetryInterval 计算重试间隔
func (rm *RetryManager) calculateRetryInterval(attempt int) time.Duration {
if attempt <= 0 {
return rm.config.InitialInterval
}
// 指数退避
interval := float64(rm.config.InitialInterval) * math.Pow(rm.config.Multiplier, float64(attempt-1))
// 应用最大间隔限制
if interval > float64(rm.config.MaxInterval) {
interval = float64(rm.config.MaxInterval)
}
// 添加随机化
if rm.config.RandomizationFactor > 0 {
min := interval * (1 - rm.config.RandomizationFactor)
max := interval * (1 + rm.config.RandomizationFactor)
interval = min + rand.Float64()*(max-min)
}
return time.Duration(interval)
}
// formatRetryError 格式化重试错误
func (rm *RetryManager) formatRetryError(req *Request, attempt int, err error) error {
errorMsg := fmt.Sprintf("Request failed after %d attempts: %v", attempt, err)
// 如果是微服务错误,包装错误
if merr, ok := err.(*errors.Error); ok {
merr.Detail = errorMsg
return merr
}
// 创建新的错误
return errors.InternalServerError(req.Service, errorMsg)
}
// recordSuccess 记录成功
func (rm *RetryManager) recordSuccess(attempt int) {
rm.mu.Lock()
defer rm.mu.Unlock()
atomic.AddInt64(&rm.metrics.TotalRequests, 1)
if attempt > 0 {
atomic.AddInt64(&rm.metrics.SuccessAfterRetry, 1)
}
}
// recordRetry 记录重试
func (rm *RetryManager) recordRetry() {
atomic.AddInt64(&rm.metrics.TotalRetries, 1)
}
// recordFailure 记录失败
func (rm *RetryManager) recordFailure(attempt int) {
rm.mu.Lock()
defer rm.mu.Unlock()
atomic.AddInt64(&rm.metrics.TotalRequests, 1)
currentMax := atomic.LoadInt64(&rm.metrics.MaxRetries)
if int64(attempt) > currentMax {
atomic.StoreInt64(&rm.metrics.MaxRetries, int64(attempt))
}
}
// notifyHandlers 通知处理器
func (rm *RetryManager) notifyHandlers(ctx context.Context, req *Request, attempt int, err error) {
rm.mu.RLock()
handlers := make([]RetryHandler, 0, len(rm.handlers))
for _, handler := range rm.handlers {
handlers = append(handlers, handler)
}
rm.mu.RUnlock()
for _, handler := range handlers {
handler.OnRetry(ctx, req, attempt, err)
}
}
// GetMetrics 获取重试指标
func (rm *RetryManager) GetMetrics() *RetryMetrics {
rm.mu.RLock()
defer rm.mu.RUnlock()
total := atomic.LoadInt64(&rm.metrics.TotalRequests)
retries := atomic.LoadInt64(&rm.metrics.TotalRetries)
retryRate := 0.0
if total > 0 {
retryRate = float64(retries) / float64(total)
}
return &RetryMetrics{
TotalRequests: total,
TotalRetries: retries,
MaxRetries: atomic.LoadInt64(&rm.metrics.MaxRetries),
SuccessAfterRetry: atomic.LoadInt64(&rm.metrics.SuccessAfterRetry),
RetryRate: retryRate,
}
}
// AddHandler 添加重试处理器
func (rm *RetryManager) AddHandler(name string, handler RetryHandler) {
rm.mu.Lock()
defer rm.mu.Unlock()
rm.handlers[name] = handler
}
// RemoveHandler 移除重试处理器
func (rm *RetryManager) RemoveHandler(name string) {
rm.mu.Lock()
defer rm.mu.Unlock()
delete(rm.handlers, name)
}
---
04.默认实现
a.默认重试条件和处理器
---
// DefaultRetryCondition 默认重试条件
type DefaultRetryCondition struct{}
// ShouldRetry 判断是否应该重试
func (d *DefaultRetryCondition) ShouldRetry(ctx context.Context, req *Request, attempt int, err error) bool {
// 检查重试次数
if attempt >= 3 {
return false
}
// 检查上下文
select {
case <-ctx.Done():
return false
default:
}
// 检查错误类型
if err == nil {
return false
}
// 检查是否是超时错误
if err == context.DeadlineExceeded {
return false
}
// 检查微服务错误
if merr, ok := err.(*errors.Error); ok {
// 只重试服务器错误
return merr.Code >= 500
}
// 默认重试网络相关错误
errMsg := strings.ToLower(err.Error())
return strings.Contains(errMsg, "timeout") ||
strings.Contains(errMsg, "connection") ||
strings.Contains(errMsg, "network")
}
// Name 返回名称
func (d *DefaultRetryCondition) Name() string {
return "default_retry_condition"
}
// LoggingRetryHandler 日志重试处理器
type LoggingRetryHandler struct{}
// NewLoggingRetryHandler 创建日志重试处理器
func NewLoggingRetryHandler() *LoggingRetryHandler {
return &LoggingRetryHandler{}
}
// OnRetry 重试回调
func (h *LoggingRetryHandler) OnRetry(ctx context.Context, req *Request, attempt int, err error) {
log.Logf("Retry attempt %d for %s.%s: %v", attempt, req.Service, req.Method, err)
}
// Name 返回处理器名称
func (h *LoggingRetryHandler) Name() string {
return "logging_retry_handler"
}
// MetricsRetryHandler 指标重试处理器
type MetricsRetryHandler struct {
metrics map[string]*RetryMetrics
mu sync.RWMutex
}
// NewMetricsRetryHandler 创建指标重试处理器
func NewMetricsRetryHandler() *MetricsRetryHandler {
return &MetricsRetryHandler{
metrics: make(map[string]*RetryMetrics),
}
}
// OnRetry 重试回调
func (h *MetricsRetryHandler) OnRetry(ctx context.Context, req *Request, attempt int, err error) {
key := fmt.Sprintf("%s.%s", req.Service, req.Method)
h.mu.Lock()
if h.metrics[key] == nil {
h.metrics[key] = &RetryMetrics{}
}
h.metrics[key].TotalRequests++
h.metrics[key].TotalRetries++
h.mu.Unlock()
}
// Name 返回处理器名称
func (h *MetricsRetryHandler) Name() string {
return "metrics_retry_handler"
}
// GetMetrics 获取指标
func (h *MetricsRetryHandler) GetMetrics(service, method string) *RetryMetrics {
h.mu.RLock()
defer h.mu.RUnlock()
key := fmt.Sprintf("%s.%s", service, method)
if metrics, exists := h.metrics[key]; exists {
return metrics
}
return &RetryMetrics{}
}
---
05.组合使用示例
a.基础使用示例
---
package main
import (
"context"
"fmt"
"time"
"github.com/micro/go-micro/v2/timeout"
"github.com/micro/go-micro/v2/retry"
)
func main() {
// 创建超时管理器
timeoutConfig := &timeout.TimeoutConfig{
ConnectTimeout: time.Second * 3,
ReadTimeout: time.Second * 10,
WriteTimeout: time.Second * 5,
TotalTimeout: time.Second * 30,
DefaultTimeout: time.Second * 15,
ServiceTimeouts: map[string]time.Duration{
"user.service": time.Second * 20,
"order.service": time.Second * 10,
},
MethodTimeouts: map[string]time.Duration{
"GetUser": time.Second * 5,
"ProcessOrder": time.Second * 30,
},
}
timeoutManager := timeout.NewTimeoutManager(timeoutConfig)
// 创建重试管理器
retryConfig := &retry.RetryConfig{
MaxRetries: 3,
InitialInterval: time.Millisecond * 200,
MaxInterval: time.Second * 5,
Multiplier: 2.0,
RandomizationFactor: 0.1,
MaxElapsedTime: time.Minute * 2,
RetryCondition: &retry.DefaultRetryCondition{},
}
retryManager := retry.NewRetryManager(retryConfig)
// 添加处理器
retryManager.AddHandler("logging", retry.NewLoggingRetryHandler())
retryManager.AddHandler("metrics", retry.NewMetricsRetryHandler())
// 模拟使用
demonstrateUsage(timeoutManager, retryManager)
}
func demonstrateUsage(timeoutMgr *timeout.TimeoutManager, retryMgr *retry.RetryManager) {
// 创建请求
req := &retry.Request{
Service: "user.service",
Method: "GetUser",
Body: map[string]string{"user_id": "123"},
Timeout: time.Second * 10,
Metadata: map[string]string{
"request_id": "req-123",
},
}
ctx := context.Background()
// 创建带超时的上下文
timeoutCtx, cancel := timeoutMgr.CreateContext(ctx, &timeout.Request{
Service: req.Service,
Method: req.Method,
Timeout: req.Timeout,
})
defer cancel()
// 模拟调用函数
callFunc := func(ctx context.Context, req *retry.Request) error {
// 模拟网络延迟和随机失败
delay := time.Duration(rand.Intn(1000)) * time.Millisecond
time.Sleep(delay)
if rand.Float32() < 0.3 { // 30%的失败率
return fmt.Errorf("simulated network error")
}
fmt.Printf("Call succeeded for %s.%s\n", req.Service, req.Method)
return nil
}
// 执行带超时和重试的调用
start := time.Now()
err := retryMgr.Execute(timeoutCtx, req, callFunc)
elapsed := time.Since(start)
if err != nil {
// 处理超时错误
if timeoutErr := timeoutMgr.HandleTimeout(timeoutCtx, &timeout.Request{
Service: req.Service,
Method: req.Method,
}, err); timeoutErr != nil {
fmt.Printf("Timeout error: %v\n", timeoutErr)
} else {
fmt.Printf("Call failed: %v\n", err)
}
} else {
fmt.Printf("Call succeeded in %v\n", elapsed)
}
// 输出统计信息
printStats(timeoutMgr, retryMgr)
}
func printStats(timeoutMgr *timeout.TimeoutManager, retryMgr *retry.RetryManager) {
fmt.Println("\n=== Timeout Statistics ===")
timeoutMetrics := timeoutMgr.GetMetrics()
fmt.Printf("Total Requests: %d\n", timeoutMetrics.TotalRequests)
fmt.Printf("Timeouts: %d\n", timeoutMetrics.Timeouts)
fmt.Printf("Connection Timeouts: %d\n", timeoutMetrics.ConnectionTimeouts)
fmt.Printf("Read Timeouts: %d\n", timeoutMetrics.ReadTimeouts)
fmt.Printf("Write Timeouts: %d\n", timeoutMetrics.WriteTimeouts)
fmt.Printf("Timeout Rate: %.2f\n", retryMetrics.RetryRate*100)
}
---
b.最佳实践
超时设置最佳实践包括分层超时连接超时小于读取超时小于总体超时,服务差异化根据服务特性设置不同的超时时间,超时传递确保超时在调用链中正确传递,监控告警监控超时率并设置告警阈值。重试策略最佳实践包括指数退避使用指数退避算法避免雪崩,随机抖动添加随机因子分散重试时间,错误分类只对可重试的错误进行重试,熔断保护结合熔断器防止无限重试。
c.总结
超时与重试机制为go-micro客户端提供了强大的容错能力,通过合理的配置和策略,可以显著提高系统的稳定性和可用性,确保在部分服务故障时系统仍能正常运行。
5.6 熔断器模式
01.熔断器模式概述
a.核心机制
熔断器模式(Circuit Breaker Pattern)是微服务架构中的核心容错机制,通过在服务调用失败时快速返回错误,避免级联故障,保护整个系统的稳定性。
b.核心作用
a.故障隔离
防止故障服务影响整个系统。
b.快速失败
避免长时间等待不可用的服务。
c.自动恢复
服务恢复后自动恢复正常调用。
d.降级保护
在服务不可用时提供备选方案。
e.系统保护
防止资源耗尽和性能下降。
c.熔断器状态
a.关闭状态(Closed)
正常状态,允许请求通过。
b.打开状态(Open)
熔断状态,直接返回错误。
c.半开状态(Half-Open)
测试状态,允许少量请求通过。
02.熔断器接口设计
a.状态定义
a.功能说明
定义熔断器的三种核心状态,包括关闭、半开和打开状态,以及状态的字符串表示方法。
b.代码示例
---
package circuitbreaker
import (
"context"
"fmt"
"sync"
"sync/atomic"
"time"
"github.com/micro/go-micro/v2/errors"
"github.com/micro/go-micro/v2/util/log"
)
// State 熔断器状态
type State int
const (
StateClosed State = iota
StateHalfOpen
StateOpen
)
// String 返回状态字符串
func (s State) String() string {
switch s {
case StateClosed:
return "CLOSED"
case StateHalfOpen:
return "HALF_OPEN"
case StateOpen:
return "OPEN"
default:
return "UNKNOWN"
}
}
---
b.熔断器接口
a.功能说明
定义熔断器的核心接口,包括调用执行、状态获取、重置、指标获取、就绪检查和名称获取等方法。
b.代码示例
---
// CircuitBreaker 熔断器接口
type CircuitBreaker interface {
// Call 执行调用
Call(ctx context.Context, req *Request, callFunc CallFunc) error
// State 获取当前状态
State() State
// Reset 重置熔断器
Reset()
// Metrics 获取指标
Metrics() *Metrics
// IsReady 检查是否准备好接受请求
IsReady() bool
// Name 熔断器名称
Name() string
}
// Request 请求结构
type Request struct {
Service string
Method string
Body interface{}
Timeout time.Duration
}
// CallFunc 调用函数类型
type CallFunc func(ctx context.Context, req *Request) error
---
c.指标结构
a.功能说明
定义熔断器的指标结构,用于记录总请求数、成功数、失败数、超时数、熔断触发次数以及状态变更时间。
b.代码示例
---
// Metrics 熔断器指标
type Metrics struct {
// 总请求数
Requests int64
// 成功请求数
Successes int64
// 失败请求数
Failures int64
// 超时请求数
Timeouts int64
// 熔断触发次数
Trips int64
// 当前状态
State State
// 最后状态变更时间
LastStateChange time.Time
}
---
d.配置结构
a.功能说明
定义熔断器的配置参数,包括名称、失败阈值、成功阈值、超时阈值、打开状态持续时间、半开状态最大请求数、采样率和启用标志。
b.代码示例
---
// Config 熔断器配置
type Config struct {
// 名称
Name string
// 失败阈值
FailureThreshold int
// 成功阈值
SuccessThreshold int
// 超时阈值
TimeoutThreshold time.Duration
// 打开状态持续时间
OpenDuration time.Duration
// 半开状态最大请求数
HalfOpenMaxRequests int
// 采样率
SampleRate float64
// 是否启用
Enabled bool
}
// DefaultConfig 默认配置
func DefaultConfig() *Config {
return &Config{
Name: "default",
FailureThreshold: 5,
SuccessThreshold: 3,
TimeoutThreshold: time.Second * 30,
OpenDuration: time.Minute * 1,
HalfOpenMaxRequests: 3,
SampleRate: 1.0,
Enabled: true,
}
}
---
e.熔断器实现
a.结构定义
定义熔断器的内部实现结构,包含配置、状态、计数器、互斥锁等核心字段。
b.创建方法
提供创建熔断器实例的工厂方法,初始化默认状态并启动后台监控。
c.代码示例
---
// circuitBreaker 熔断器实现
type circuitBreaker struct {
config *Config
state State
failures int64
successes int64
timeout int64
requests int64
generation int64
lastChange time.Time
mu sync.RWMutex
metrics *Metrics
startTime time.Time
}
// NewCircuitBreaker 创建熔断器
func NewCircuitBreaker(config *Config) CircuitBreaker {
if config == nil {
config = DefaultConfig()
}
cb := &circuitBreaker{
config: config,
state: StateClosed,
failures: 0,
successes: 0,
timeout: 0,
requests: 0,
startTime: time.Now(),
lastChange: time.Now(),
metrics: &Metrics{
State: StateClosed,
LastStateChange: time.Now(),
},
}
// 启动后台监控
go cb.monitor()
return cb
}
---
f.核心方法实现
a.Call方法
执行带熔断保护的调用,检查熔断器状态、执行实际调用、更新指标并根据结果触发状态变更。
b.代码示例
---
// Call 执行调用
func (cb *circuitBreaker) Call(ctx context.Context, req *Request, callFunc CallFunc) error {
if !cb.config.Enabled {
return callFunc(ctx, req)
}
cb.mu.Lock()
currentState := cb.state
generation := cb.generation
cb.mu.Unlock()
// 检查是否允许请求
if !cb.canRequest(currentState) {
return errors.ServiceUnavailable(req.Service, "circuit breaker is open", "")
}
start := time.Now()
err := callFunc(ctx, req)
duration := time.Since(start)
// 更新指标
cb.updateMetrics(req, err, duration)
// 检查是否需要状态变更
cb.checkStateChange(generation, err, duration)
return err
}
// State 获取当前状态
func (cb *circuitBreaker) State() State {
cb.mu.RLock()
defer cb.mu.RUnlock()
return cb.state
}
// Reset 重置熔断器
func (cb *circuitBreaker) Reset() {
cb.mu.Lock()
defer cb.mu.Unlock()
cb.state = StateClosed
cb.failures = 0
cb.successes = 0
cb.timeout = 0
cb.requests = 0
cb.generation++
cb.lastChange = time.Now()
cb.metrics.State = StateClosed
cb.metrics.LastStateChange = time.Now()
log.Logf("Circuit breaker %s reset", cb.config.Name)
}
// Metrics 获取指标
func (cb *circuitBreaker) Metrics() *Metrics {
cb.mu.RLock()
defer cb.mu.RUnlock()
// 复制指标
metrics := &Metrics{
Requests: atomic.LoadInt64(&cb.metrics.Requests),
Successes: atomic.LoadInt64(&cb.metrics.Successes),
Failures: atomic.LoadInt64(&cb.metrics.Failures),
Timeouts: atomic.LoadInt64(&cb.metrics.Timeouts),
Trips: atomic.LoadInt64(&cb.metrics.Trips),
State: cb.state,
LastStateChange: cb.metrics.LastStateChange,
}
return metrics
}
// IsReady 检查是否准备好接受请求
func (cb *circuitBreaker) IsReady() bool {
if !cb.config.Enabled {
return true
}
cb.mu.RLock()
defer cb.mu.RUnlock()
return cb.state != StateOpen
}
// Name 返回熔断器名称
func (cb *circuitBreaker) Name() string {
return cb.config.Name
}
---
g.辅助方法
a.功能说明
实现请求检查、指标更新、超时判断和状态变更检查等辅助功能。
b.代码示例
---
// canRequest 检查是否可以发送请求
func (cb *circuitBreaker) canRequest(state State) bool {
switch state {
case StateClosed:
return true
case StateOpen:
return false
case StateHalfOpen:
return atomic.LoadInt64(&cb.requests) < int64(cb.config.HalfOpenMaxRequests)
default:
return false
}
}
// updateMetrics 更新指标
func (cb *circuitBreaker) updateMetrics(req *Request, err error, duration time.Duration) {
atomic.AddInt64(&cb.metrics.Requests, 1)
atomic.AddInt64(&cb.requests, 1)
if err != nil {
atomic.AddInt64(&cb.metrics.Failures, 1)
if cb.isTimeout(err, duration) {
atomic.AddInt64(&cb.metrics.Timeouts, 1)
atomic.AddInt64(&cb.timeout, 1)
} else {
atomic.AddInt64(&cb.failures, 1)
}
} else {
atomic.AddInt64(&cb.metrics.Successes, 1)
atomic.AddInt64(&cb.successes, 1)
}
}
// isTimeout 检查是否为超时错误
func (cb *circuitBreaker) isTimeout(err error, duration time.Duration) bool {
return err == context.DeadlineExceeded || duration >= cb.config.TimeoutThreshold
}
// checkStateChange 检查状态变更
func (cb *circuitBreaker) checkStateChange(generation int64, err error, duration time.Duration) {
cb.mu.Lock()
defer cb.mu.Unlock()
// 如果代数不一致,说明状态已经变更
if generation != cb.generation {
return
}
switch cb.state {
case StateClosed:
if cb.shouldTrip(err, duration) {
cb.trip()
}
case StateHalfOpen:
if err == nil {
if cb.successes >= int64(cb.config.SuccessThreshold) {
cb.reset()
}
} else {
cb.trip()
}
case StateOpen:
// 检查是否可以转为半开状态
if time.Since(cb.lastChange) >= cb.config.OpenDuration {
cb.halfOpen()
}
}
}
---
h.状态转换方法
a.功能说明
实现熔断器的状态转换逻辑,包括判断是否应该触发熔断、触发熔断、重置和切换到半开状态。
b.代码示例
---
// shouldTrip 判断是否应该触发熔断
func (cb *circuitBreaker) shouldTrip(err error, duration time.Duration) bool {
// 检查失败次数
if cb.failures >= int64(cb.config.FailureThreshold) {
return true
}
// 检查超时次数
if cb.timeout >= int64(cb.config.FailureThreshold) {
return true
}
// 检查失败率
total := cb.successes + cb.failures + cb.timeout
if total > 0 {
failureRate := float64(cb.failures+cb.timeout) / float64(total)
if failureRate >= 0.5 {
return true
}
}
return false
}
// trip 触发熔断器
func (cb *circuitBreaker) trip() {
cb.state = StateOpen
cb.generation++
cb.lastChange = time.Now()
cb.metrics.State = StateOpen
cb.metrics.LastStateChange = time.Now()
cb.metrics.Trips++
atomic.AddInt64(&cb.metrics.Trips, 1)
log.Logf("Circuit breaker %s tripped (State: OPEN)", cb.config.Name)
}
// reset 重置到关闭状态
func (cb *circuitBreaker) reset() {
cb.state = StateClosed
cb.failures = 0
cb.successes = 0
cb.timeout = 0
cb.requests = 0
cb.generation++
cb.lastChange = time.Now()
cb.metrics.State = StateClosed
cb.metrics.LastStateChange = time.Now()
log.Logf("Circuit breaker %s reset (State: CLOSED)", cb.config.Name)
}
// halfOpen 切换到半开状态
func (cb *circuitBreaker) halfOpen() {
cb.state = StateHalfOpen
cb.generation++
cb.lastChange = time.Now()
cb.requests = 0
cb.successes = 0
cb.metrics.State = StateHalfOpen
cb.metrics.LastStateChange = time.Now()
log.Logf("Circuit breaker %s half-open (State: HALF_OPEN)", cb.config.Name)
}
---
i.监控方法
a.功能说明
实现后台监控功能,定期检查熔断器状态并在打开状态持续时间达到阈值时自动切换到半开状态。
b.代码示例
---
// monitor 监控熔断器状态
func (cb *circuitBreaker) monitor() {
ticker := time.NewTicker(time.Second * 10)
defer ticker.Stop()
for {
select {
case <-ticker.C:
cb.checkAutoReset()
}
}
}
// checkAutoReset 检查自动重置
func (cb *circuitBreaker) checkAutoReset() {
cb.mu.Lock()
defer cb.mu.Unlock()
if cb.state == StateOpen {
if time.Since(cb.lastChange) >= cb.config.OpenDuration {
cb.halfOpen()
}
}
}
---
03.高级熔断器实现
a.高级熔断器结构
a.功能说明
扩展基础熔断器,添加钩子和策略支持,实现更灵活的熔断控制和监控。
b.代码示例
---
// AdvancedCircuitBreaker 高级熔断器
type AdvancedCircuitBreaker struct {
*circuitBreaker
hooks []Hook
strategies []Strategy
}
// Hook 钩子接口
type Hook interface {
// BeforeCall 调用前钩子
BeforeCall(ctx context.Context, req *Request)
// AfterCall 调用后钩子
AfterCall(ctx context.Context, req *Request, err error, duration time.Duration)
// OnStateChange 状态变更钩子
OnStateChange(oldState, newState State)
}
// Strategy 策略接口
type Strategy interface {
// ShouldTrip 判断是否应该触发熔断
ShouldTrip(metrics *Metrics) bool
// ShouldReset 判断是否应该重置
ShouldReset(metrics *Metrics) bool
}
// NewAdvancedCircuitBreaker 创建高级熔断器
func NewAdvancedCircuitBreaker(config *Config) *AdvancedCircuitBreaker {
cb := &circuitBreaker{
config: config,
state: StateClosed,
metrics: &Metrics{
State: StateClosed,
LastStateChange: time.Now(),
},
}
return &AdvancedCircuitBreaker{
circuitBreaker: cb,
hooks: make([]Hook, 0),
strategies: make([]Strategy, 0),
}
}
// AddHook 添加钩子
func (acb *AdvancedCircuitBreaker) AddHook(hook Hook) {
acb.hooks = append(acb.hooks, hook)
}
// AddStrategy 添加策略
func (acb *AdvancedCircuitBreaker) AddStrategy(strategy Strategy) {
acb.strategies = append(acb.strategies, strategy)
}
// Call 执行调用(高级版本)
func (acb *AdvancedCircuitBreaker) Call(ctx context.Context, req *Request, callFunc CallFunc) error {
if !acb.config.Enabled {
return callFunc(ctx, req)
}
// 调用前钩子
for _, hook := range acb.hooks {
hook.BeforeCall(ctx, req)
}
start := time.Now()
err := acb.circuitBreaker.Call(ctx, req, callFunc)
duration := time.Since(start)
// 调用后钩子
for _, hook := range acb.hooks {
hook.AfterCall(ctx, req, err, duration)
}
return err
}
---
b.日志钩子实现
a.功能说明
实现日志钩子,在调用前后和状态变更时记录日志信息。
b.代码示例
---
// LoggingHook 日志钩子
type LoggingHook struct {
logger Logger
}
// NewLoggingHook 创建日志钩子
func NewLoggingHook(logger Logger) *LoggingHook {
return &LoggingHook{logger: logger}
}
// BeforeCall 调用前钩子
func (h *LoggingHook) BeforeCall(ctx context.Context, req *Request) {
h.logger.Logf("Calling %s.%s", req.Service, req.Method)
}
// AfterCall 调用后钩子
func (h *LoggingHook) AfterCall(ctx context.Context, req *Request, err error, duration time.Duration) {
if err != nil {
h.logger.Logf("Call failed: %s.%s, duration=%v, error=%v", req.Service, req.Method, duration, err)
} else {
h.logger.Logf("Call succeeded: %s.%s, duration=%v", req.Service, req.Method, duration)
}
}
// OnStateChange 状态变更钩子
func (h *LoggingHook) OnStateChange(oldState, newState State) {
h.logger.Logf("Circuit breaker state changed: %s -> %s", oldState, newState)
}
---
c.指标钩子实现
a.功能说明
实现指标钩子,收集请求、成功、失败、延迟等关键指标。
b.代码示例
---
// MetricsHook 指标钩子
type MetricsHook struct {
collector MetricsCollector
}
// NewMetricsHook 创建指标钩子
func NewMetricsHook(collector MetricsCollector) *MetricsHook {
return &MetricsHook{collector: collector}
}
// BeforeCall 调用前钩子
func (h *MetricsHook) BeforeCall(ctx context.Context, req *Request) {
h.collector.IncrementRequest(req.Service, req.Method)
}
// AfterCall 调用后钩子
func (h *MetricsHook) AfterCall(ctx context.Context, req *Request, err error, duration time.Duration) {
if err != nil {
h.collector.IncrementError(req.Service, req.Method)
} else {
h.collector.IncrementSuccess(req.Service, req.Method)
}
h.collector.RecordLatency(req.Service, req.Method, duration)
}
// OnStateChange 状态变更钩子
func (h *MetricsHook) OnStateChange(oldState, newState State) {
h.collector.RecordStateChange(string(oldState), string(newState))
}
---
d.错误率策略
a.功能说明
基于错误率判断是否应该触发熔断或重置,支持配置错误率阈值和最小请求数。
b.代码示例
---
// ErrorRateStrategy 错误率策略
type ErrorRateStrategy struct {
ErrorRateThreshold float64
MinRequests int64
}
// NewErrorRateStrategy 创建错误率策略
func NewErrorRateStrategy(threshold float64, minRequests int64) *ErrorRateStrategy {
return &ErrorRateStrategy{
ErrorRateThreshold: threshold,
MinRequests: minRequests,
}
}
// ShouldTrip 判断是否应该触发熔断
func (s *ErrorRateStrategy) ShouldTrip(metrics *Metrics) bool {
if metrics.Requests < s.MinRequests {
return false
}
errorRate := float64(metrics.Failures+metrics.Timeouts) / float64(metrics.Requests)
return errorRate >= s.ErrorRateThreshold
}
// ShouldReset 判断是否应该重置
func (s *ErrorRateStrategy) ShouldReset(metrics *Metrics) bool {
if metrics.State == StateClosed {
return false
}
// 如果错误率低于阈值,可以重置
if metrics.Requests >= s.MinRequests {
errorRate := float64(metrics.Failures+metrics.Timeouts) / float64(metrics.Requests)
return errorRate < s.ErrorRateThreshold*0.5
}
return false
}
---
e.滑动窗口策略
a.功能说明
基于滑动窗口统计失败次数,判断是否应该触发熔断,支持配置窗口大小、失败数量和最小请求数。
b.代码示例
---
// SlidingWindowStrategy 滑动窗口策略
type SlidingWindowStrategy struct {
WindowSize time.Duration
FailureCount int
MinRequests int
}
// NewSlidingWindowStrategy 创建滑动窗口策略
func NewSlidingWindowStrategy(windowSize time.Duration, failureCount, minRequests int) *SlidingWindowStrategy {
return &SlidingWindowStrategy{
WindowSize: windowSize,
FailureCount: failureCount,
MinRequests: minRequests,
}
}
// ShouldTrip 判断是否应该触发熔断
func (s *SlidingWindowStrategy) ShouldTrip(metrics *Metrics) bool {
// 这里需要实现滑动窗口逻辑
// 简化实现,使用总请求计数
return metrics.Failures+metrics.Timeouts >= int64(s.FailureCount) && metrics.Requests >= int64(s.MinRequests)
}
// ShouldReset 判断是否应该重置
func (s *SlidingWindowStrategy) ShouldReset(metrics *Metrics) bool {
return metrics.State != StateClosed && metrics.Requests >= int64(s.MinRequests)
}
---
04.熔断器管理器
a.管理器结构
a.功能说明
统一管理多个熔断器实例,提供自动创建、配置管理和指标聚合功能。
b.代码示例
---
// CircuitBreakerManager 熔断器管理器
type CircuitBreakerManager struct {
breakers map[string]CircuitBreaker
factory CircuitBreakerFactory
config *ManagerConfig
mu sync.RWMutex
}
// ManagerConfig 管理器配置
type ManagerConfig struct {
DefaultConfig *Config
AutoCreate bool
MetricsEnabled bool
MonitorInterval time.Duration
}
// CircuitBreakerFactory 熔断器工厂接口
type CircuitBreakerFactory interface {
CreateCircuitBreaker(service, method string, config *Config) CircuitBreaker
}
// DefaultFactory 默认工厂
type DefaultFactory struct{}
// CreateCircuitBreaker 创建熔断器
func (f *DefaultFactory) CreateCircuitBreaker(service, method string, config *Config) CircuitBreaker {
if config == nil {
config = DefaultConfig()
}
config.Name = fmt.Sprintf("%s:%s", service, method)
return NewCircuitBreaker(config)
}
---
b.管理器创建和基本方法
a.功能说明
创建熔断器管理器实例,并提供获取熔断器、执行调用等基本方法。
b.代码示例
---
// NewCircuitBreakerManager 创建熔断器管理器
func NewCircuitBreakerManager(config *ManagerConfig) *CircuitBreakerManager {
if config == nil {
config = &ManagerConfig{
DefaultConfig: DefaultConfig(),
AutoCreate: true,
MetricsEnabled: true,
MonitorInterval: time.Minute,
}
}
manager := &CircuitBreakerManager{
breakers: make(map[string]CircuitBreaker),
factory: &DefaultFactory{},
config: config,
}
// 启动监控
if config.MetricsEnabled {
go manager.monitor()
}
return manager
}
// GetCircuitBreaker 获取熔断器
func (m *CircuitBreakerManager) GetCircuitBreaker(service, method string) CircuitBreaker {
key := fmt.Sprintf("%s:%s", service, method)
m.mu.RLock()
cb, exists := m.breakers[key]
m.mu.RUnlock()
if exists {
return cb
}
// 自动创建
if m.config.AutoCreate {
m.mu.Lock()
defer m.mu.Unlock()
// 双重检查
if cb, exists := m.breakers[key]; exists {
return cb
}
cb = m.factory.CreateCircuitBreaker(service, method, m.config.DefaultConfig)
m.breakers[key] = cb
return cb
}
return nil
}
// Call 执行带熔断器的调用
func (m *CircuitBreakerManager) Call(ctx context.Context, service, method string, req *Request, callFunc CallFunc) error {
cb := m.GetCircuitBreaker(service, method)
if cb == nil {
// 没有熔断器,直接调用
return callFunc(ctx, req)
}
// 设置服务和方法
req.Service = service
req.Method = method
return cb.Call(ctx, req, callFunc)
}
---
c.管理方法
a.功能说明
提供获取所有熔断器、重置所有熔断器和获取聚合指标等管理功能。
b.代码示例
---
// GetAllBreakers 获取所有熔断器
func (m *CircuitBreakerManager) GetAllBreakers() map[string]CircuitBreaker {
m.mu.RLock()
defer m.mu.RUnlock()
breakers := make(map[string]CircuitBreaker)
for k, v := range m.breakers {
breakers[k] = v
}
return breakers
}
// ResetAllBreakers 重置所有熔断器
func (m *CircuitBreakerManager) ResetAllBreakers() {
m.mu.RLock()
defer m.mu.RUnlock()
for _, cb := range m.breakers {
cb.Reset()
}
}
// GetAggregatedMetrics 获取聚合指标
func (m *CircuitBreakerManager) GetAggregatedMetrics() *AggregatedMetrics {
m.mu.RLock()
defer m.mu.RUnlock()
aggregated := &AggregatedMetrics{
TotalBreakers: len(m.breakers),
StateCounts: make(map[State]int),
}
for _, cb := range m.breakers {
metrics := cb.Metrics()
aggregated.Requests += metrics.Requests
aggregated.Successes += metrics.Successes
aggregated.Failures += metrics.Failures
aggregated.Timeouts += metrics.Timeouts
aggregated.Trips += metrics.Trips
aggregated.StateCounts[metrics.State]++
}
return aggregated
}
// AggregatedMetrics 聚合指标
type AggregatedMetrics struct {
TotalBreakers int
Requests int64
Successes int64
Failures int64
Timeouts int64
Trips int64
StateCounts map[State]int
}
---
d.监控功能
a.功能说明
定期监控所有熔断器的状态和指标,输出统计信息。
b.代码示例
---
// monitor 监控熔断器
func (m *CircuitBreakerManager) monitor() {
ticker := time.NewTicker(m.config.MonitorInterval)
defer ticker.Stop()
for {
select {
case <-ticker.C:
m.checkAndReport()
}
}
}
// checkAndReport 检查并报告
func (m *CircuitBreakerManager) checkAndReport() {
metrics := m.GetAggregatedMetrics()
log.Logf("Circuit breaker metrics: Total=%d, Requests=%d, Successes=%d, Failures=%d, Timeouts=%d, Trips=%d",
metrics.TotalBreakers, metrics.Requests, metrics.Successes, metrics.Failures, metrics.Timeouts, metrics.Trips)
for state, count := range metrics.StateCounts {
log.Logf("State %s: %d breakers", state, count)
}
}
---
05.使用示例
a.基础使用示例
a.功能说明
演示如何创建熔断器管理器并进行基本的服务调用,模拟随机失败场景并观察熔断器行为。
b.代码示例
---
package main
import (
"context"
"fmt"
"math/rand"
"time"
"github.com/micro/go-micro/v2/circuitbreaker"
)
func main() {
// 创建熔断器管理器
manager := circuitbreaker.NewCircuitBreakerManager(&circuitbreaker.ManagerConfig{
DefaultConfig: &circuitbreaker.Config{
FailureThreshold: 5,
SuccessThreshold: 3,
TimeoutThreshold: time.Second * 30,
OpenDuration: time.Minute * 1,
HalfOpenMaxRequests: 3,
},
AutoCreate: true,
MetricsEnabled: true,
MonitorInterval: time.Second * 30,
})
// 模拟使用
demonstrateCircuitBreaker(manager)
}
func demonstrateCircuitBreaker(manager *circuitbreaker.CircuitBreakerManager) {
service := "user.service"
method := "GetUser"
// 模拟多次调用
for i := 0; i < 20; i++ {
req := &circuitbreaker.Request{
Service: service,
Method: method,
Body: map[string]string{"user_id": fmt.Sprintf("user-%d", i)},
Timeout: time.Second * 5,
}
ctx := context.Background()
err := manager.Call(ctx, service, method, req, func(ctx context.Context, req *circuitbreaker.Request) error {
// 模拟网络延迟
time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
// 模拟随机失败
if rand.Float32() < 0.3 {
return fmt.Errorf("simulated error for request %d", i)
}
fmt.Printf("Request %d succeeded\n", i)
return nil
})
if err != nil {
fmt.Printf("Request %d failed: %v\n", i, err)
}
time.Sleep(time.Millisecond * 500)
}
// 等待一段时间观察熔断器状态
time.Sleep(time.Second * 10)
// 输出聚合指标
printAggregatedMetrics(manager)
}
func printAggregatedMetrics(manager *circuitbreaker.CircuitBreakerManager) {
metrics := manager.GetAggregatedMetrics()
fmt.Println("\n=== Aggregated Circuit Breaker Metrics ===")
fmt.Printf("Total Breakers: %d\n", metrics.TotalBreakers)
fmt.Printf("Total Requests: %d\n", metrics.Requests)
fmt.Printf("Successes: %d\n", metrics.Successes)
fmt.Printf("Failures: %d\n", metrics.Failures)
fmt.Printf("Timeouts: %d\n", metrics.Timeouts)
fmt.Printf("Trips: %d\n", metrics.Trips)
fmt.Println("\n=== State Distribution ===")
for state, count := range metrics.StateCounts {
fmt.Printf("%s: %d\n", state, count)
}
}
---
b.高级熔断器示例
a.功能说明
演示如何使用高级熔断器,包括添加钩子和策略,模拟不同类型的错误场景。
b.代码示例
---
// 高级熔断器示例
func advancedCircuitBreakerExample() {
// 创建高级熔断器
config := &circuitbreaker.Config{
Name: "advanced",
FailureThreshold: 10,
SuccessThreshold: 5,
TimeoutThreshold: time.Second * 20,
OpenDuration: time.Second * 30,
HalfOpenMaxRequests: 5,
Enabled: true,
}
advancedCB := circuitbreaker.NewAdvancedCircuitBreaker(config)
// 添加钩子
advancedCB.AddHook(circuitbreaker.NewLoggingHook(&ConsoleLogger{}))
advancedCB.AddHook(circuitbreaker.NewMetricsHook(&PrometheusCollector{}))
// 添加策略
advancedCB.AddStrategy(circuitbreaker.NewErrorRateStrategy(0.5, 10))
advancedCB.AddStrategy(circuitbreaker.NewSlidingWindowStrategy(time.Minute, 5, 20))
// 模拟调用
simulateAdvancedCalls(advancedCB)
// 获取指标
metrics := advancedCB.Metrics()
fmt.Printf("Advanced circuit breaker metrics: %+v\n", metrics)
}
func simulateAdvancedCalls(cb *circuitbreaker.CircuitBreaker) {
for i := 0; i < 50; i++ {
req := &circuitbreaker.Request{
Service: "advanced.service",
Method: "Process",
Body: map[string]interface{}{"id": i},
Timeout: time.Second * 2,
}
ctx := context.Background()
err := cb.Call(ctx, req, func(ctx context.Context, req *circuitbreaker.Request) error {
// 模拟不同类型的错误
rand.Seed(time.Now().UnixNano())
r := rand.Float32()
if r < 0.1 {
return fmt.Errorf("timeout error")
} else if r < 0.2 {
return fmt.Errorf("connection refused")
} else if r < 0.25 {
return fmt.Errorf("server error")
}
time.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond)
return nil
})
if err != nil {
fmt.Printf("Advanced call %d failed: %v (State: %s)\n", i, err, cb.State())
} else {
fmt.Printf("Advanced call %d succeeded (State: %s)\n", i, cb.State())
}
time.Sleep(time.Millisecond * 200)
}
}
---
c.辅助类实现
a.功能说明
实现控制台日志器和Prometheus指标收集器,用于演示钩子功能。
b.代码示例
---
// ConsoleLogger 控制台日志器
type ConsoleLogger struct{}
func (l *ConsoleLogger) Logf(format string, args ...interface{}) {
fmt.Printf("[LOG] "+format+"\n", args...)
}
// PrometheusCollector Prometheus指标收集器
type PrometheusCollector struct{}
func (c *PrometheusCollector) IncrementRequest(service, method string) {
fmt.Printf("Prometheus: IncrementRequest %s.%s\n", service, method)
}
func (c *PrometheusCollector) IncrementSuccess(service, method string) {
fmt.Printf("Prometheus: IncrementSuccess %s.%s\n", service, method)
}
func (c *PrometheusCollector) IncrementError(service, method string) {
fmt.Printf("Prometheus: IncrementError %s.%s\n", service, method)
}
func (c *PrometheusCollector) RecordLatency(service, method string, duration time.Duration) {
fmt.Printf("Prometheus: RecordLatency %s.%s = %v\n", service, method, duration)
}
func (c *PrometheusCollector) RecordStateChange(oldState, newState string) {
fmt.Printf("Prometheus: StateChange %s -> %s\n", oldState, newState)
}
---
d.最佳实践示例
a.功能说明
演示熔断器的最佳实践,包括为不同服务设置不同阈值、实现降级策略和监控告警。
b.代码示例
---
// 熔断器模式最佳实践示例
func bestPracticesExample() {
// 1. 为不同的服务设置不同的阈值
serviceConfigs := map[string]*circuitbreaker.Config{
"critical.service": {
Name: "critical",
FailureThreshold: 10,
SuccessThreshold: 5,
OpenDuration: time.Second * 30,
},
"background.service": {
Name: "background",
FailureThreshold: 5,
SuccessThreshold: 2,
OpenDuration: time.Minute * 2,
},
}
for serviceName, config := range serviceConfigs {
cb := circuitbreaker.NewCircuitBreaker(config)
fmt.Printf("Created circuit breaker for %s with failure threshold: %d\n",
serviceName, config.FailureThreshold)
}
// 2. 实现降级策略
implementFallback(manager)
// 3. 监控和告警
implementMonitoring(manager)
}
func implementFallback(manager *circuitbreaker.CircuitBreakerManager) {
// 为关键服务实现降级
service := "user.service"
method := "GetUser"
req := &circuitbreaker.Request{
Service: service,
Method: method,
Body: map[string]string{"user_id": "123"},
}
ctx := context.Background()
err := manager.Call(ctx, service, method, req, func(ctx context.Context, req *circuitbreaker.Request) error {
// 主要服务调用
return callMainService(ctx, req)
})
if err != nil {
// 服务失败,调用降级逻辑
fmt.Printf("Main service failed, calling fallback: %v\n", err)
return callFallbackService(ctx, req)
}
}
func callMainService(ctx context.Context, req *circuitbreaker.Request) error {
// 模拟主要服务调用
time.Sleep(time.Millisecond * 100)
if rand.Float32() < 0.3 {
return fmt.Errorf("main service error")
}
return nil
}
func callFallbackService(ctx context.Context, req *circuitbreaker.Request) error {
// 降级逻辑:从缓存获取或返回默认值
fmt.Println("Using fallback service")
return nil
}
func implementMonitoring(manager *circuitbreaker.CircuitBreakerManager) {
// 定期检查熔断器状态
ticker := time.NewTicker(time.Minute)
defer ticker.Stop()
for i := 0; i < 5; i++ {
select {
case <-ticker.C:
checkCircuitBreakerHealth(manager)
case <-time.After(time.Second * 10):
break
}
}
}
func checkCircuitBreakerHealth(manager *circuitbreaker.CircuitBreakerManager) {
breakers := manager.GetAllBreakers()
openCount := 0
halfOpenCount := 0
for _, cb := range breakers {
state := cb.State()
if state == circuitbreaker.StateOpen {
openCount++
} else if state == circuitbreaker.StateHalfOpen {
halfOpenCount++
}
}
totalBreakers := len(breakers)
if totalBreakers > 0 {
openRate := float64(openCount) / float64(totalBreakers)
if openRate > 0.2 {
fmt.Printf("ALERT: High circuit breaker open rate: %.2f%% (%d/%d)\n",
openRate*100, openCount, totalBreakers)
}
}
fmt.Printf("Circuit breaker health: Total=%d, Open=%d, Half-Open=%d\n",
totalBreakers, openCount, halfOpenCount)
}
---
06.最佳实践
a.配置最佳实践
a.合理阈值
根据服务特性设置合适的失败阈值,不同类型服务采用不同的配置策略。
b.快速失败
设置合理的超时时间,避免长时间等待不可用的服务,降低系统资源消耗。
c.渐进恢复
通过半开状态逐步恢复服务,避免服务恢复时的流量冲击。
d.差异化配置
不同优先级的服务使用不同策略,关键服务设置更高的容错阈值。
b.监控和告警
a.实时监控
监控熔断器状态变化,及时发现服务异常。
b.指标收集
收集成功率、失败率等关键指标,分析服务健康状况。
c.告警机制
熔断器打开率过高时及时告警,快速响应故障。
d.自动化恢复
结合健康检查自动恢复服务,减少人工干预。
c.总结
熔断器模式为go-micro客户端提供了强大的故障隔离和快速失败机制,通过智能的状态管理和策略配置,有效防止了级联故障,保护了整个微服务系统的稳定性和可用性。
6 第6章 插件与扩展
6.1 插件系统架构
01.插件系统核心组件
a.插件管理器(Plugin Manager)
a.功能说明
go-micro采用微内核架构,核心框架提供基础功能,所有扩展功能都通过插件系统实现。插件系统支持动态加载、卸载和热插拔,为框架提供强大的可扩展性。插件管理器负责插件的完整生命周期管理,包括发现、加载、初始化、注册、运行、卸载和清理。
b.代码示例
---
// plugin/manager.go
package plugin
import (
"context"
"fmt"
"path/filepath"
"plugin"
"sync"
"time"
)
// 插件管理器接口
type PluginManager interface {
// 插件管理
LoadPlugin(path string) (Plugin, error)
UnloadPlugin(name string) error
GetPlugin(name string) (Plugin, bool)
ListPlugins() []Plugin
// 插件发现
DiscoverPlugins(dirs []string) error
ReloadPlugin(name string) error
// 生命周期管理
InitializePlugins(ctx context.Context) error
StartPlugins(ctx context.Context) error
StopPlugins(ctx context.Context) error
ShutdownPlugins(ctx context.Context) error
// 监控和状态
GetPluginStatus(name string) PluginStatus
GetAllPluginStatus() map[string]PluginStatus
EnablePluginMetrics(pluginName string)
DisablePluginMetrics(pluginName string)
// 配置管理
UpdatePluginConfig(name string, config interface{}) error
GetPluginConfig(name string) (interface{}, error)
}
// 插件管理器实现
type pluginManager struct {
plugins map[string]Plugin
pluginConfigs map[string]interface{}
pluginMetrics map[string]*PluginMetrics
pluginStates map[string]PluginState
pluginHooks map[string][]PluginHook
mu sync.RWMutex
config *PluginManagerConfig
logger Logger
eventBus EventBus
dependencyResolver DependencyResolver
}
// 插件管理器配置
type PluginManagerConfig struct {
PluginDirs []string `yaml:"plugin_dirs"`
AutoLoad bool `yaml:"auto_load"`
AutoStart bool `yaml:"auto_start"`
EnableMetrics bool `yaml:"enable_metrics"`
EnableHooks bool `yaml:"enable_hooks"`
LoadTimeout time.Duration `yaml:"load_timeout"`
StartTimeout time.Duration `yaml:"start_timeout"`
StopTimeout time.Duration `yaml:"stop_timeout"`
MaxConcurrentLoads int `yaml:"max_concurrent_loads"`
PluginValidation PluginValidation `yaml:"plugin_validation"`
Security SecurityConfig `yaml:"security"`
}
// 插件验证配置
type PluginValidation struct {
RequireSignature bool `yaml:"require_signature"`
AllowedAuthors []string `yaml:"allowed_authors"`
BlockedAuthors []string `yaml:"blocked_authors"`
RequiredVersion string `yaml:"required_version"`
CheckDependencies bool `yaml:"check_dependencies"`
}
// 安全配置
type SecurityConfig struct {
EnableSandbox bool `yaml:"enable_sandbox"`
SandboxConfig string `yaml:"sandbox_config"`
ResourceLimits ResourceLimits `yaml:"resource_limits"`
AllowedFunctions []string `yaml:"allowed_functions"`
BlockedFunctions []string `yaml:"blocked_functions"`
}
// 资源限制
type ResourceLimits struct {
MaxMemory int64 `yaml:"max_memory"`
MaxCPU int `yaml:"max_cpu"`
MaxFiles int `yaml:"max_files"`
MaxGoroutine int `yaml:"max_goroutines"`
}
// 创建插件管理器
func NewPluginManager(config *PluginManagerConfig, logger Logger, eventBus EventBus) PluginManager {
if config == nil {
config = &PluginManagerConfig{
PluginDirs: []string{"./plugins", "/usr/local/go-micro/plugins"},
AutoLoad: false,
AutoStart: false,
EnableMetrics: true,
EnableHooks: true,
LoadTimeout: 30 * time.Second,
StartTimeout: 60 * time.Second,
StopTimeout: 30 * time.Second,
MaxConcurrentLoads: 5,
}
}
return &pluginManager{
plugins: make(map[string]Plugin),
pluginConfigs: make(map[string]interface{}),
pluginMetrics: make(map[string]*PluginMetrics),
pluginStates: make(map[string]PluginState),
pluginHooks: make(map[string][]PluginHook),
config: config,
logger: logger,
eventBus: eventBus,
dependencyResolver: NewDependencyResolver(),
}
}
// 加载插件
func (pm *pluginManager) LoadPlugin(path string) (Plugin, error) {
pm.mu.Lock()
defer pm.mu.Unlock()
ctx, cancel := context.WithTimeout(context.Background(), pm.config.LoadTimeout)
defer cancel()
return pm.loadPluginWithContext(ctx, path)
}
// 带上下文加载插件
func (pm *pluginManager) loadPluginWithContext(ctx context.Context, path string) (Plugin, error) {
// 检查插件是否已加载
if name := filepath.Base(path); pm.isPluginLoaded(name) {
return nil, fmt.Errorf("plugin %s already loaded", name)
}
// 验证插件路径
if err := pm.validatePluginPath(path); err != nil {
return nil, fmt.Errorf("plugin path validation failed: %w", err)
}
// 加载Go插件
goPlugin, err := plugin.Open(path)
if err != nil {
return nil, fmt.Errorf("failed to open plugin: %w", err)
}
// 查找插件导出符号
symPlugin, err := goPlugin.Lookup("NewPlugin")
if err != nil {
return nil, fmt.Errorf("plugin does not export NewPlugin symbol: %w", err)
}
// 类型断言检查
newPluginFunc, ok := symPlugin.(func() Plugin)
if !ok {
return nil, fmt.Errorf("plugin NewPlugin symbol has wrong signature")
}
// 创建插件实例
pluginInstance := newPluginFunc()
if pluginInstance == nil {
return nil, fmt.Errorf("plugin factory returned nil")
}
// 获取插件元数据
metadata := pluginInstance.GetMetadata()
// 验证插件元数据
if err := pm.validatePluginMetadata(metadata); err != nil {
return nil, fmt.Errorf("plugin metadata validation failed: %w", err)
}
// 检查依赖关系
if err := pm.dependencyResolver.ResolveDependencies(metadata); err != nil {
return nil, fmt.Errorf("dependency resolution failed: %w", err)
}
// 初始化插件
if err := pluginInstance.Initialize(ctx, nil); err != nil {
return nil, fmt.Errorf("plugin initialization failed: %w", err)
}
// 注册插件
pluginName := metadata.Name
pm.plugins[pluginName] = pluginInstance
pm.pluginStates[pluginName] = PluginStateLoaded
pm.pluginConfigs[pluginName] = metadata.DefaultConfig
// 创建插件指标
if pm.config.EnableMetrics {
pm.pluginMetrics[pluginName] = NewPluginMetrics(pluginName)
}
// 发送插件加载事件
if pm.config.EnableHooks {
pm.eventBus.Publish(PluginLoadedEvent{
PluginName: pluginName,
Metadata: metadata,
Timestamp: time.Now(),
})
}
pm.logger.Info("Plugin loaded successfully",
String("plugin_name", pluginName),
String("version", metadata.Version),
String("path", path))
return pluginInstance, nil
}
// 卸载插件
func (pm *pluginManager) UnloadPlugin(name string) error {
pm.mu.Lock()
defer pm.mu.Unlock()
plugin, exists := pm.plugins[name]
if !exists {
return fmt.Errorf("plugin %s not found", name)
}
// 检查插件状态
state := pm.pluginStates[name]
if state == PluginStateRunning {
return fmt.Errorf("cannot unload running plugin %s, stop it first", name)
}
ctx, cancel := context.WithTimeout(context.Background(), pm.config.StopTimeout)
defer cancel()
// 清理插件资源
if err := plugin.Cleanup(ctx); err != nil {
pm.logger.Warn("Plugin cleanup failed",
String("plugin_name", name),
Error("error", err))
}
// 移除插件
delete(pm.plugins, name)
delete(pm.pluginConfigs, name)
delete(pm.pluginStates, name)
delete(pm.pluginMetrics, name)
delete(pm.pluginHooks, name)
// 发送插件卸载事件
if pm.config.EnableHooks {
pm.eventBus.Publish(PluginUnloadedEvent{
PluginName: name,
Timestamp: time.Now(),
})
}
pm.logger.Info("Plugin unloaded successfully", String("plugin_name", name))
return nil
}
// 获取插件
func (pm *pluginManager) GetPlugin(name string) (Plugin, bool) {
pm.mu.RLock()
defer pm.mu.RUnlock()
plugin, exists := pm.plugins[name]
return plugin, exists
}
// 列出所有插件
func (pm *pluginManager) ListPlugins() []Plugin {
pm.mu.RLock()
defer pm.mu.RUnlock()
plugins := make([]Plugin, 0, len(pm.plugins))
for _, plugin := range pm.plugins {
plugins = append(plugins, plugin)
}
return plugins
}
// 发现插件
func (pm *pluginManager) DiscoverPlugins(dirs []string) error {
pm.mu.Lock()
defer pm.mu.Unlock()
for _, dir := range dirs {
if err := pm.discoverPluginsInDir(dir); err != nil {
pm.logger.Warn("Failed to discover plugins in directory",
String("directory", dir),
Error("error", err))
}
}
return nil
}
// 在目录中发现插件
func (pm *pluginManager) discoverPluginsInDir(dir string) error {
entries, err := filepath.Glob(filepath.Join(dir, "*.so"))
if err != nil {
return fmt.Errorf("failed to glob plugin files: %w", err)
}
for _, entry := range entries {
if pm.config.AutoLoad {
if _, err := pm.loadPluginWithContext(context.Background(), entry); err != nil {
pm.logger.Warn("Failed to auto-load plugin",
String("path", entry),
Error("error", err))
}
}
}
return nil
}
// 重载插件
func (pm *pluginManager) ReloadPlugin(name string) error {
// 获取当前插件信息
plugin, exists := pm.GetPlugin(name)
if !exists {
return fmt.Errorf("plugin %s not found", name)
}
metadata := plugin.GetMetadata()
oldPath := metadata.Path
// 停止插件
if err := pm.StopPlugin(name); err != nil {
pm.logger.Warn("Failed to stop plugin for reload",
String("plugin_name", name),
Error("error", err))
}
// 卸载插件
if err := pm.UnloadPlugin(name); err != nil {
return fmt.Errorf("failed to unload plugin %s: %w", name, err)
}
// 重新加载插件
if _, err := pm.LoadPlugin(oldPath); err != nil {
return fmt.Errorf("failed to reload plugin %s: %w", name, err)
}
pm.logger.Info("Plugin reloaded successfully", String("plugin_name", name))
return nil
}
// 初始化所有插件
func (pm *pluginManager) InitializePlugins(ctx context.Context) error {
pm.mu.RLock()
plugins := make(map[string]Plugin)
for name, plugin := range pm.plugins {
plugins[name] = plugin
}
pm.mu.RUnlock()
for name, plugin := range plugins {
if err := plugin.Initialize(ctx, pm.pluginConfigs[name]); err != nil {
pm.logger.Error("Failed to initialize plugin",
String("plugin_name", name),
Error("error", err))
return fmt.Errorf("failed to initialize plugin %s: %w", name, err)
}
pm.mu.Lock()
pm.pluginStates[name] = PluginStateInitialized
pm.mu.Unlock()
}
return nil
}
// 启动所有插件
func (pm *pluginManager) StartPlugins(ctx context.Context) error {
pm.mu.RLock()
plugins := make(map[string]Plugin)
for name, plugin := range pm.plugins {
plugins[name] = plugin
}
pm.mu.RUnlock()
for name, plugin := range plugins {
startCtx, cancel := context.WithTimeout(ctx, pm.config.StartTimeout)
if err := plugin.Start(startCtx); err != nil {
cancel()
pm.logger.Error("Failed to start plugin",
String("plugin_name", name),
Error("error", err))
return fmt.Errorf("failed to start plugin %s: %w", name, err)
}
cancel()
pm.mu.Lock()
pm.pluginStates[name] = PluginStateRunning
pm.mu.Unlock()
}
return nil
}
// 停止插件
func (pm *pluginManager) StopPlugin(name string) error {
pm.mu.Lock()
defer pm.mu.Unlock()
plugin, exists := pm.plugins[name]
if !exists {
return fmt.Errorf("plugin %s not found", name)
}
state := pm.pluginStates[name]
if state != PluginStateRunning {
return fmt.Errorf("plugin %s is not running", name)
}
ctx, cancel := context.WithTimeout(context.Background(), pm.config.StopTimeout)
defer cancel()
if err := plugin.Stop(ctx); err != nil {
pm.logger.Error("Failed to stop plugin",
String("plugin_name", name),
Error("error", err))
return fmt.Errorf("failed to stop plugin %s: %w", name, err)
}
pm.pluginStates[name] = PluginStateStopped
pm.logger.Info("Plugin stopped successfully", String("plugin_name", name))
return nil
}
// 停止所有插件
func (pm *pluginManager) StopPlugins(ctx context.Context) error {
pm.mu.RLock()
plugins := make(map[string]Plugin)
for name, plugin := range pm.plugins {
plugins[name] = plugin
}
pm.mu.RUnlock()
for name, plugin := range plugins {
stopCtx, cancel := context.WithTimeout(ctx, pm.config.StopTimeout)
if err := plugin.Stop(stopCtx); err != nil {
cancel()
pm.logger.Warn("Failed to stop plugin",
String("plugin_name", name),
Error("error", err))
continue
}
cancel()
pm.mu.Lock()
pm.pluginStates[name] = PluginStateStopped
pm.mu.Unlock()
}
return nil
}
// 关闭所有插件
func (pm *pluginManager) ShutdownPlugins(ctx context.Context) error {
return pm.StopPlugins(ctx)
}
// 辅助方法
func (pm *pluginManager) isPluginLoaded(name string) bool {
_, exists := pm.plugins[name]
return exists
}
func (pm *pluginManager) validatePluginPath(path string) error {
if path == "" {
return fmt.Errorf("plugin path cannot be empty")
}
// 检查文件扩展名
ext := filepath.Ext(path)
if ext != ".so" {
return fmt.Errorf("plugin must have .so extension, got %s", ext)
}
return nil
}
func (pm *pluginManager) validatePluginMetadata(metadata *PluginMetadata) error {
if metadata == nil {
return fmt.Errorf("plugin metadata is nil")
}
if metadata.Name == "" {
return fmt.Errorf("plugin name cannot be empty")
}
if metadata.Version == "" {
return fmt.Errorf("plugin version cannot be empty")
}
// 检查签名
if pm.config.PluginValidation.RequireSignature {
if metadata.Signature == "" {
return fmt.Errorf("plugin signature is required")
}
// 验证签名逻辑
}
return nil
}
// 启用插件指标
func (pm *pluginManager) EnablePluginMetrics(pluginName string) {
pm.mu.Lock()
defer pm.mu.Unlock()
if _, exists := pm.pluginMetrics[pluginName]; !exists {
pm.pluginMetrics[pluginName] = NewPluginMetrics(pluginName)
}
}
// 禁用插件指标
func (pm *pluginManager) DisablePluginMetrics(pluginName string) {
pm.mu.Lock()
defer pm.mu.Unlock()
delete(pm.pluginMetrics, pluginName)
}
---
b.插件接口定义(Plugin Interface)
a.功能说明
定义标准的插件接口,确保所有插件的兼容性和一致性。
b.代码示例
---
// plugin/interface.go
package plugin
import (
"context"
"time"
)
// 插件基础接口
type Plugin interface {
// 生命周期管理
Initialize(ctx context.Context, config interface{}) error
Start(ctx context.Context) error
Stop(ctx context.Context) error
Cleanup(ctx context.Context) error
// 元数据信息
GetMetadata() *PluginMetadata
GetName() string
GetVersion() string
GetDescription() string
GetAuthor() string
// 状态管理
GetState() PluginState
IsRunning() bool
IsHealthy() bool
// 配置管理
UpdateConfig(config interface{}) error
GetConfig() interface{}
// 健康检查
HealthCheck(ctx context.Context) error
}
// 插件状态
type PluginState int
const (
PluginStateUnloaded PluginState = iota
PluginStateLoaded
PluginStateInitialized
PluginStateStarting
PluginStateRunning
PluginStateStopping
PluginStateStopped
PluginStateError
)
func (s PluginState) String() string {
switch s {
case PluginStateUnloaded:
return "unloaded"
case PluginStateLoaded:
return "loaded"
case PluginStateInitialized:
return "initialized"
case PluginStateStarting:
return "starting"
case PluginStateRunning:
return "running"
case PluginStateStopping:
return "stopping"
case PluginStateStopped:
return "stopped"
case PluginStateError:
return "error"
default:
return "unknown"
}
}
// 插件元数据
type PluginMetadata struct {
// 基本信息
Name string `json:"name" yaml:"name"`
Version string `json:"version" yaml:"version"`
Description string `json:"description" yaml:"description"`
Author string `json:"author" yaml:"author"`
License string `json:"license" yaml:"license"`
Homepage string `json:"homepage" yaml:"homepage"`
Path string `json:"path" yaml:"path"`
// 依赖信息
Dependencies []PluginDependency `json:"dependencies" yaml:"dependencies"`
ConflictWith []string `json:"conflict_with" yaml:"conflict_with"`
// 配置信息
DefaultConfig interface{} `json:"default_config" yaml:"default_config"`
ConfigSchema interface{} `json:"config_schema" yaml:"config_schema"`
// 版本信息
MinGoVersion string `json:"min_go_version" yaml:"min_go_version"`
MaxGoVersion string `json:"max_go_version" yaml:"max_go_version"`
FrameworkVersion string `json:"framework_version" yaml:"framework_version"`
// 安全信息
Signature string `json:"signature,omitempty" yaml:"signature"`
SignatureTime time.Time `json:"signature_time,omitempty" yaml:"signature_time"`
Checksum string `json:"checksum,omitempty" yaml:"checksum"`
SecurityLevel string `json:"security_level,omitempty" yaml:"security_level"`
// 标签和分类
Tags []string `json:"tags" yaml:"tags"`
Category string `json:"category" yaml:"category"`
Priority int `json:"priority" yaml:"priority"`
// 资源需求
ResourceRequirements ResourceRequirements `json:"resource_requirements" yaml:"resource_requirements"`
// 时间信息
CreatedAt time.Time `json:"created_at" yaml:"created_at"`
UpdatedAt time.Time `json:"updated_at" yaml:"updated_at"`
BuildTime time.Time `json:"build_time" yaml:"build_time"`
}
// 插件依赖
type PluginDependency struct {
Name string `json:"name" yaml:"name"`
Version string `json:"version" yaml:"version"`
Type string `json:"type" yaml:"type"` // required, optional
}
// 资源需求
type ResourceRequirements struct {
MinMemoryMB int64 `json:"min_memory_mb" yaml:"min_memory_mb"`
MaxMemoryMB int64 `json:"max_memory_mb" yaml:"max_memory_mb"`
MinCPUCores int `json:"min_cpu_cores" yaml:"min_cpu_cores"`
MaxCPUCores int `json:"max_cpu_cores" yaml:"max_cpu_cores"`
DiskSpaceMB int64 `json:"disk_space_mb" yaml:"disk_space_mb"`
}
// 插件状态信息
type PluginStatus struct {
Name string `json:"name"`
State PluginState `json:"state"`
Version string `json:"version"`
StartTime *time.Time `json:"start_time,omitempty"`
LastActivity *time.Time `json:"last_activity,omitempty"`
Error string `json:"error,omitempty"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
Health HealthStatus `json:"health"`
Config interface{} `json:"config,omitempty"`
}
// 健康状态
type HealthStatus struct {
IsHealthy bool `json:"is_healthy"`
LastCheck time.Time `json:"last_check"`
Message string `json:"message,omitempty"`
CheckDuration time.Duration `json:"check_duration"`
}
// 插件事件
type PluginEvent interface {
GetType() string
GetPluginName() string
GetTimestamp() time.Time
GetData() interface{}
}
// 插件加载事件
type PluginLoadedEvent struct {
PluginName string `json:"plugin_name"`
Metadata *PluginMetadata `json:"metadata"`
Timestamp time.Time `json:"timestamp"`
}
func (e PluginLoadedEvent) GetType() string {
return "plugin.loaded"
}
func (e PluginLoadedEvent) GetPluginName() string {
return e.PluginName
}
func (e PluginLoadedEvent) GetTimestamp() time.Time {
return e.Timestamp
}
func (e PluginLoadedEvent) GetData() interface{} {
return e.Metadata
}
// 插件卸载事件
type PluginUnloadedEvent struct {
PluginName string `json:"plugin_name"`
Timestamp time.Time `json:"timestamp"`
}
func (e PluginUnloadedEvent) GetType() string {
return "plugin.unloaded"
}
func (e PluginUnloadedEvent) GetPluginName() string {
return e.PluginName
}
func (e PluginUnloadedEvent) GetTimestamp() time.Time {
return e.Timestamp
}
func (e PluginUnloadedEvent) GetData() interface{} {
return nil
}
// 插件错误事件
type PluginErrorEvent struct {
PluginName string `json:"plugin_name"`
Error string `json:"error"`
Timestamp time.Time `json:"timestamp"`
Context map[string]interface{} `json:"context,omitempty"`
}
func (e PluginErrorEvent) GetType() string {
return "plugin.error"
}
func (e PluginErrorEvent) GetPluginName() string {
return e.PluginName
}
func (e PluginErrorEvent) GetTimestamp() time.Time {
return e.Timestamp
}
func (e PluginErrorEvent) GetData() interface{} {
return e.Context
}
// 插件钩子接口
type PluginHook interface {
BeforeLoad(ctx context.Context, metadata *PluginMetadata) error
AfterLoad(ctx context.Context, plugin Plugin) error
BeforeUnload(ctx context.Context, plugin Plugin) error
AfterUnload(ctx context.Context, pluginName string) error
OnError(ctx context.Context, pluginName string, err error) error
}
// 事件总线接口
type EventBus interface {
Publish(event PluginEvent)
Subscribe(eventType string, handler func(PluginEvent)) error
Unsubscribe(eventType string, handler func(PluginEvent)) error
}
// 依赖解析器接口
type DependencyResolver interface {
ResolveDependencies(metadata *PluginMetadata) error
CheckConflicts(metadata *PluginMetadata) error
GetDependencyGraph() map[string][]string
ValidateDependencyGraph() error
}
// 日志接口
type Logger interface {
Debug(msg string, fields ...Field)
Info(msg string, fields ...Field)
Warn(msg string, fields ...Field)
Error(msg string, fields ...Field)
}
// 日志字段
type Field interface{}
func String(key, value string) Field { return fmt.Sprintf("%s=%s", key, value) }
func Int(key string, value int) Field { return fmt.Sprintf("%s=%d", key, value) }
func Duration(key string, value time.Duration) Field { return fmt.Sprintf("%s=%v", key, value) }
func Time(key string, value time.Time) Field { return fmt.Sprintf("%s=%v", key, value) }
func Error(key string, value error) Field { return fmt.Sprintf("%s=%v", key, value) }
---
c.插件加载器(Plugin Loader)
a.功能说明
插件加载器负责动态加载插件代码,处理依赖关系,并提供安全的执行环境。
b.代码示例
---
// plugin/loader.go
package plugin
import (
"context"
"crypto/sha256"
"fmt"
"io"
"os"
"path/filepath"
"plugin"
"sync"
"time"
)
// 插件加载器接口
type PluginLoader interface {
LoadFromFile(path string) (plugin.Plugin, error)
LoadFromMemory(data []byte) (plugin.Plugin, error)
ValidatePlugin(plugin.Plugin) error
SecureLoad(path string, options *SecureLoadOptions) (plugin.Plugin, error)
}
// 安全加载选项
type SecureLoadOptions struct {
EnableSandbox bool
SandboxConfig *SandboxConfig
VerifySignature bool
ExpectedChecksum string
MaxMemorySize int64
Timeout time.Duration
}
// 沙箱配置
type SandboxConfig struct {
AllowedPaths []string `yaml:"allowed_paths"`
BlockedPaths []string `yaml:"blocked_paths"`
NetworkAccess bool `yaml:"network_access"`
FileSystemAccess bool `yaml:"file_system_access"`
MaxMemory int64 `yaml:"max_memory"`
MaxCPU int `yaml:"max_cpu"`
}
// 插件加载器实现
type pluginLoader struct {
config *LoaderConfig
logger Logger
signature SignatureVerifier
sandbox SandboxManager
cache *PluginCache
mu sync.RWMutex
}
// 加载器配置
type LoaderConfig struct {
CacheEnabled bool `yaml:"cache_enabled"`
CacheDirectory string `yaml:"cache_directory"`
CacheMaxSize int64 `yaml:"cache_max_size"`
CacheTTL time.Duration `yaml:"cache_ttl"`
VerifyChecksum bool `yaml:"verify_checksum"`
VerifySignature bool `yaml:"verify_signature"`
EnableSandbox bool `yaml:"enable_sandbox"`
MaxLoadTime time.Duration `yaml:"max_load_time"`
MaxMemorySize int64 `yaml:"max_memory_size"`
ParallelLoading bool `yaml:"parallel_loading"`
MaxConcurrent int `yaml:"max_concurrent"`
}
// 签名验证器接口
type SignatureVerifier interface {
Verify(data []byte, signature string) error
VerifyWithPublicKey(data []byte, signature string, publicKey string) error
}
// 沙箱管理器接口
type SandboxManager interface {
CreateSandbox(config *SandboxConfig) (Sandbox, error)
DestroySandbox(sandboxID string) error
GetSandbox(sandboxID string) (Sandbox, bool)
}
// 沙箱接口
type Sandbox interface {
GetID() string
Execute(plugin.Plugin) (interface{}, error)
GetResourceUsage() ResourceUsage
Stop() error
}
// 资源使用情况
type ResourceUsage struct {
MemoryUsage int64 `json:"memory_usage"`
CPUUsage float64 `json:"cpu_usage"`
FileHandles int `json:"file_handles"`
}
// 插件缓存
type PluginCache struct {
entries map[string]*CacheEntry
mu sync.RWMutex
config *CacheConfig
}
// 缓存条目
type CacheEntry struct {
Plugin plugin.Plugin
LoadTime time.Time
AccessTime time.Time
Checksum string
Size int64
}
// 缓存配置
type CacheConfig struct {
MaxSize int64
TTL time.Duration
CleanupInterval time.Duration
}
// 创建插件加载器
func NewPluginLoader(config *LoaderConfig, logger Logger) PluginLoader {
if config == nil {
config = &LoaderConfig{
CacheEnabled: true,
CacheDirectory: "./plugin_cache",
CacheMaxSize: 100 * 1024 * 1024, // 100MB
CacheTTL: time.Hour,
VerifyChecksum: true,
VerifySignature: false,
EnableSandbox: false,
MaxLoadTime: 30 * time.Second,
MaxMemorySize: 50 * 1024 * 1024, // 50MB
ParallelLoading: false,
MaxConcurrent: 3,
}
}
return &pluginLoader{
config: config,
logger: logger,
cache: NewPluginCache(config),
}
}
// 从文件加载插件
func (pl *pluginLoader) LoadFromFile(path string) (plugin.Plugin, error) {
// 检查文件是否存在
if _, err := os.Stat(path); os.IsNotExist(err) {
return nil, fmt.Errorf("plugin file does not exist: %s", path)
}
// 检查缓存
if pl.config.CacheEnabled {
if cachedPlugin := pl.checkCache(path); cachedPlugin != nil {
pl.logger.Debug("Plugin loaded from cache", String("path", path))
return cachedPlugin, nil
}
}
// 验证文件大小
if err := pl.validateFileSize(path); err != nil {
return nil, fmt.Errorf("file size validation failed: %w", err)
}
// 计算文件校验和
checksum, err := pl.calculateChecksum(path)
if err != nil {
return nil, fmt.Errorf("failed to calculate checksum: %w", err)
}
// 加载插件
ctx, cancel := context.WithTimeout(context.Background(), pl.config.MaxLoadTime)
defer cancel()
goPlugin, err := pl.loadPluginWithContext(ctx, path)
if err != nil {
return nil, fmt.Errorf("failed to load plugin: %w", err)
}
// 验证插件
if err := pl.ValidatePlugin(goPlugin); err != nil {
return nil, fmt.Errorf("plugin validation failed: %w", err)
}
// 添加到缓存
if pl.config.CacheEnabled {
pl.addToCache(path, goPlugin, checksum)
}
pl.logger.Info("Plugin loaded successfully", String("path", path))
return goPlugin, nil
}
// 从内存加载插件
func (pl *pluginLoader) LoadFromMemory(data []byte) (plugin.Plugin, error) {
// 验证数据大小
if int64(len(data)) > pl.config.MaxMemorySize {
return nil, fmt.Errorf("plugin data exceeds maximum size limit: %d", len(data))
}
// 创建临时文件
tmpFile, err := os.CreateTemp("", "plugin-*.so")
if err != nil {
return nil, fmt.Errorf("failed to create temporary file: %w", err)
}
defer os.Remove(tmpFile.Name())
// 写入数据到临时文件
if _, err := tmpFile.Write(data); err != nil {
tmpFile.Close()
return nil, fmt.Errorf("failed to write plugin data: %w", err)
}
tmpFile.Close()
// 从文件加载
return pl.LoadFromFile(tmpFile.Name())
}
// 验证插件
func (pl *pluginLoader) ValidatePlugin(goPlugin plugin.Plugin) error {
// 检查必需的导出符号
symbols := []string{"NewPlugin"}
for _, symbol := range symbols {
if _, err := goPlugin.Lookup(symbol); err != nil {
return fmt.Errorf("missing required symbol: %s", symbol)
}
}
// 验证插件接口实现
newPluginSym, err := goPlugin.Lookup("NewPlugin")
if err != nil {
return fmt.Errorf("plugin does not export NewPlugin: %w", err)
}
newPluginFunc, ok := newPluginSym.(func() Plugin)
if !ok {
return fmt.Errorf("NewPlugin has wrong signature")
}
// 创建插件实例进行基础验证
pluginInstance := newPluginFunc()
if pluginInstance == nil {
return fmt.Errorf("plugin factory returned nil")
}
// 验证元数据
metadata := pluginInstance.GetMetadata()
if metadata == nil {
return fmt.Errorf("plugin metadata is nil")
}
if metadata.Name == "" {
return fmt.Errorf("plugin name cannot be empty")
}
if metadata.Version == "" {
return fmt.Errorf("plugin version cannot be empty")
}
return nil
}
// 安全加载插件
func (pl *pluginLoader) SecureLoad(path string, options *SecureLoadOptions) (plugin.Plugin, error) {
if options == nil {
options = &SecureLoadOptions{
EnableSandbox: false,
Timeout: pl.config.MaxLoadTime,
MaxMemorySize: pl.config.MaxMemorySize,
}
}
// 验证校验和
if options.VerifySignature && options.ExpectedChecksum != "" {
actualChecksum, err := pl.calculateChecksum(path)
if err != nil {
return nil, fmt.Errorf("failed to calculate checksum: %w", err)
}
if actualChecksum != options.ExpectedChecksum {
return nil, fmt.Errorf("checksum mismatch: expected %s, got %s",
options.ExpectedChecksum, actualChecksum)
}
}
// 验证文件大小
if err := pl.validateFileSize(path); err != nil {
return nil, fmt.Errorf("file validation failed: %w", err)
}
// 加载插件
ctx, cancel := context.WithTimeout(context.Background(), options.Timeout)
defer cancel()
goPlugin, err := pl.loadPluginWithContext(ctx, path)
if err != nil {
return nil, fmt.Errorf("failed to load plugin: %w", err)
}
// 验证插件
if err := pl.ValidatePlugin(goPlugin); err != nil {
return nil, fmt.Errorf("plugin validation failed: %w", err)
}
// 如果启用沙箱,在沙箱中运行插件
if options.EnableSandbox && pl.sandbox != nil {
sandbox, err := pl.sandbox.CreateSandbox(options.SandboxConfig)
if err != nil {
return nil, fmt.Errorf("failed to create sandbox: %w", err)
}
// 在沙箱中验证插件
if _, err := sandbox.Execute(goPlugin); err != nil {
sandbox.Stop()
return nil, fmt.Errorf("plugin execution in sandbox failed: %w", err)
}
// 清理沙箱
if err := sandbox.Stop(); err != nil {
pl.logger.Warn("Failed to stop sandbox", Error("error", err))
}
}
return goPlugin, nil
}
// 带上下文加载插件
func (pl *pluginLoader) loadPluginWithContext(ctx context.Context, path string) (plugin.Plugin, error) {
resultChan := make(chan plugin.Plugin, 1)
errorChan := make(chan error, 1)
go func() {
goPlugin, err := plugin.Open(path)
if err != nil {
errorChan <- err
return
}
resultChan <- goPlugin
}()
select {
case goPlugin := <-resultChan:
return goPlugin, nil
case err := <-errorChan:
return nil, err
case <-ctx.Done():
return nil, fmt.Errorf("plugin loading timed out")
}
}
// 辅助方法
func (pl *pluginLoader) validateFileSize(path string) error {
fileInfo, err := os.Stat(path)
if err != nil {
return fmt.Errorf("failed to get file info: %w", err)
}
if fileInfo.Size() > pl.config.MaxMemorySize {
return fmt.Errorf("plugin file size %d exceeds maximum limit %d",
fileInfo.Size(), pl.config.MaxMemorySize)
}
return nil
}
func (pl *pluginLoader) calculateChecksum(path string) (string, error) {
file, err := os.Open(path)
if err != nil {
return "", fmt.Errorf("failed to open file: %w", err)
}
defer file.Close()
hash := sha256.New()
if _, err := io.Copy(hash, file); err != nil {
return "", fmt.Errorf("failed to calculate hash: %w", err)
}
return fmt.Sprintf("%x", hash.Sum(nil)), nil
}
func (pl *pluginLoader) checkCache(path string) plugin.Plugin {
pl.cache.mu.RLock()
defer pl.cache.mu.RUnlock()
entry, exists := pl.cache.entries[path]
if !exists {
return nil
}
// 检查缓存是否过期
if time.Since(entry.LoadTime) > pl.config.CacheTTL {
delete(pl.cache.entries, path)
return nil
}
// 检查文件是否被修改
fileInfo, err := os.Stat(path)
if err != nil || fileInfo.ModTime().After(entry.LoadTime) {
delete(pl.cache.entries, path)
return nil
}
entry.AccessTime = time.Now()
return entry.Plugin
}
func (pl *pluginLoader) addToCache(path string, goPlugin plugin.Plugin, checksum string) {
pl.cache.mu.Lock()
defer pl.cache.mu.Unlock()
fileInfo, _ := os.Stat(path)
pl.cache.entries[path] = &CacheEntry{
Plugin: goPlugin,
LoadTime: time.Now(),
AccessTime: time.Now(),
Checksum: checksum,
Size: fileInfo.Size(),
}
}
// 创建插件缓存
func NewPluginCache(config *LoaderConfig) *PluginCache {
cacheConfig := &CacheConfig{
MaxSize: config.CacheMaxSize,
TTL: config.CacheTTL,
CleanupInterval: 30 * time.Minute,
}
cache := &PluginCache{
entries: make(map[string]*CacheEntry),
config: cacheConfig,
}
// 启动清理协程
go cache.startCleanup()
return cache
}
func (pc *PluginCache) startCleanup() {
ticker := time.NewTicker(pc.config.CleanupInterval)
defer ticker.Stop()
for range ticker.C {
pc.cleanup()
}
}
func (pc *PluginCache) cleanup() {
pc.mu.Lock()
defer pc.mu.Unlock()
now := time.Now()
for path, entry := range pc.entries {
if now.Sub(entry.LoadTime) > pc.config.TTL {
delete(pc.entries, path)
}
}
}
---
d.依赖解析器(Dependency Resolver)
a.功能说明
依赖解析器负责处理插件间的依赖关系,确保插件按正确的顺序加载和运行。
b.代码示例
---
// plugin/dependency.go
package plugin
import (
"fmt"
"sort"
"strings"
"sync"
)
// 依赖解析器实现
type dependencyResolver struct {
dependencyGraph map[string][]string
loadedPlugins map[string]bool
mu sync.RWMutex
logger Logger
}
// 创建依赖解析器
func NewDependencyResolver() DependencyResolver {
return &dependencyResolver{
dependencyGraph: make(map[string][]string),
loadedPlugins: make(map[string]bool),
}
}
// 解析依赖关系
func (dr *dependencyResolver) ResolveDependencies(metadata *PluginMetadata) error {
dr.mu.Lock()
defer dr.mu.Unlock()
pluginName := metadata.Name
// 检查循环依赖
if err := dr.checkCircularDependency(pluginName, metadata.Dependencies); err != nil {
return fmt.Errorf("circular dependency detected: %w", err)
}
// 构建依赖图
dr.dependencyGraph[pluginName] = make([]string, 0)
for _, dep := range metadata.Dependencies {
dr.dependencyGraph[pluginName] = append(dr.dependencyGraph[pluginName], dep.Name)
}
// 验证依赖关系
return dr.validateDependencies(pluginName, metadata.Dependencies)
}
// 检查冲突
func (dr *dependencyResolver) CheckConflicts(metadata *PluginMetadata) error {
dr.mu.RLock()
defer dr.mu.RUnlock()
// 检查冲突插件
for _, conflictName := range metadata.ConflictWith {
if dr.isPluginLoaded(conflictName) {
return fmt.Errorf("plugin %s conflicts with already loaded plugin %s",
metadata.Name, conflictName)
}
}
return nil
}
// 获取依赖图
func (dr *dependencyResolver) GetDependencyGraph() map[string][]string {
dr.mu.RLock()
defer dr.mu.RUnlock()
graph := make(map[string][]string)
for plugin, deps := range dr.dependencyGraph {
graph[plugin] = append([]string(nil), deps...)
}
return graph
}
// 验证依赖图
func (dr *dependencyResolver) ValidateDependencyGraph() error {
dr.mu.RLock()
defer dr.mu.RUnlock()
// 检查循环依赖
visited := make(map[string]bool)
recStack := make(map[string]bool)
for plugin := range dr.dependencyGraph {
if !visited[plugin] {
if dr.hasCycle(plugin, visited, recStack) {
return fmt.Errorf("circular dependency detected in dependency graph")
}
}
}
return nil
}
// 获取加载顺序
func (dr *dependencyResolver) GetLoadOrder(plugins []string) ([]string, error) {
dr.mu.RLock()
defer dr.mu.RUnlock()
// 拓扑排序获取加载顺序
return dr.topologicalSort(plugins)
}
// 辅助方法
func (dr *dependencyResolver) checkCircularDependency(pluginName string, dependencies []PluginDependency) error {
visited := make(map[string]bool)
recStack := make(map[string]bool)
return dr.hasCircularDependencyHelper(pluginName, dependencies, visited, recStack)
}
func (dr *dependencyResolver) hasCircularDependencyHelper(
pluginName string,
dependencies []PluginDependency,
visited map[string]bool,
recStack map[string]bool,
) error {
if recStack[pluginName] {
return fmt.Errorf("circular dependency involving plugin %s", pluginName)
}
if visited[pluginName] {
return nil
}
visited[pluginName] = true
recStack[pluginName] = true
// 检查依赖的插件
for _, dep := range dependencies {
if depDeps, exists := dr.dependencyGraph[dep.Name]; exists {
depDependencies := make([]PluginDependency, len(depDeps))
for i, depName := range depDeps {
depDependencies[i] = PluginDependency{Name: depName}
}
if err := dr.hasCircularDependencyHelper(dep.Name, depDependencies, visited, recStack); err != nil {
return err
}
}
}
recStack[pluginName] = false
return nil
}
func (dr *dependencyResolver) validateDependencies(pluginName string, dependencies []PluginDependency) error {
for _, dep := range dependencies {
if dep.Name == pluginName {
return fmt.Errorf("plugin %s cannot depend on itself", pluginName)
}
// 检查版本兼容性
if dep.Version != "" {
if err := dr.checkVersionCompatibility(dep.Name, dep.Version); err != nil {
return fmt.Errorf("version incompatibility for dependency %s: %w", dep.Name, err)
}
}
// 检查必需依赖
if dep.Type == "required" && !dr.isPluginAvailable(dep.Name) {
return fmt.Errorf("required dependency %s is not available", dep.Name)
}
}
return nil
}
func (dr *dependencyResolver) isPluginLoaded(pluginName string) bool {
return dr.loadedPlugins[pluginName]
}
func (dr *dependencyResolver) isPluginAvailable(pluginName string) bool {
_, exists := dr.dependencyGraph[pluginName]
return exists
}
func (dr *dependencyResolver) checkVersionCompatibility(pluginName, requiredVersion string) error {
// 简化的版本检查逻辑
// 实际实现应该使用语义化版本检查库
if strings.Contains(requiredVersion, ">=") {
// 实现版本比较逻辑
}
return nil
}
func (dr *dependencyResolver) hasCycle(plugin string, visited map[string]bool, recStack map[string]bool) bool {
if recStack[plugin] {
return true
}
if visited[plugin] {
return false
}
visited[plugin] = true
recStack[plugin] = true
for _, dep := range dr.dependencyGraph[plugin] {
if dr.hasCycle(dep, visited, recStack) {
return true
}
}
recStack[plugin] = false
return false
}
func (dr *dependencyResolver) topologicalSort(plugins []string) ([]string, error) {
// 计算入度
inDegree := make(map[string]int)
for _, plugin := range plugins {
inDegree[plugin] = 0
}
for _, plugin := range plugins {
for _, dep := range dr.dependencyGraph[plugin] {
if _, exists := inDegree[dep]; exists {
inDegree[dep]++
}
}
}
// 拓扑排序
queue := make([]string, 0)
for plugin, degree := range inDegree {
if degree == 0 {
queue = append(queue, plugin)
}
}
result := make([]string, 0)
for len(queue) > 0 {
current := queue[0]
queue = queue[1:]
result = append(result, current)
for _, dep := range dr.dependencyGraph[current] {
inDegree[dep]--
if inDegree[dep] == 0 {
queue = append(queue, dep)
}
}
}
if len(result) != len(plugins) {
return nil, fmt.Errorf("circular dependency detected")
}
return result, nil
}
// 标记插件为已加载
func (dr *dependencyResolver) MarkPluginLoaded(pluginName string) {
dr.mu.Lock()
defer dr.mu.Unlock()
dr.loadedPlugins[pluginName] = true
}
// 标记插件为未加载
func (dr *dependencyResolver) MarkPluginUnloaded(pluginName string) {
dr.mu.Lock()
defer dr.mu.Unlock()
dr.loadedPlugins[pluginName] = false
}
---
02.插件生命周期管理
a.生命周期状态转换
a.功能说明
插件在其生命周期中会经历多个状态,包括创建、加载、初始化、运行、停止和清理。
b.代码示例
---
// plugin/lifecycle.go
package plugin
import (
"context"
"fmt"
"sync"
"time"
)
// 插件生命周期管理器
type PluginLifecycleManager struct {
stateMachine *PluginStateMachine
eventHandlers map[PluginEventType][]PluginEventHandler
stateHistory map[string][]PluginStateTransition
mu sync.RWMutex
logger Logger
config *LifecycleConfig
}
// 插件状态机
type PluginStateMachine struct {
currentStates map[string]PluginState
validTransitions map[PluginState][]PluginState
mu sync.RWMutex
}
// 生命周期配置
type LifecycleConfig struct {
TransitionTimeout time.Duration `yaml:"transition_timeout"`
RetryAttempts int `yaml:"retry_attempts"`
EnableHistory bool `yaml:"enable_history"`
MaxHistorySize int `yaml:"max_history_size"`
StateCheckInterval time.Duration `yaml:"state_check_interval"`
}
// 插件事件类型
type PluginEventType string
const (
EventInitialize PluginEventType = "initialize"
EventStart PluginEventType = "start"
EventStop PluginEventType = "stop"
EventCleanup PluginEventType = "cleanup"
EventError PluginEventType = "error"
EventReload PluginEventType = "reload"
)
// 插件事件处理器接口
type PluginEventHandler interface {
Handle(ctx context.Context, event PluginStateEvent) error
GetEventTypes() []PluginEventType
}
// 插件状态事件
type PluginStateEvent struct {
PluginName string `json:"plugin_name"`
EventType PluginEventType `json:"event_type"`
FromState PluginState `json:"from_state"`
ToState PluginState `json:"to_state"`
Timestamp time.Time `json:"timestamp"`
Error error `json:"error,omitempty"`
Context map[string]interface{} `json:"context,omitempty"`
}
// 插件状态转换记录
type PluginStateTransition struct {
FromState PluginState `json:"from_state"`
ToState PluginState `json:"to_state"`
Timestamp time.Time `json:"timestamp"`
Duration time.Duration `json:"duration"`
Error string `json:"error,omitempty"`
TriggeredBy string `json:"triggered_by"`
}
// 创建插件生命周期管理器
func NewPluginLifecycleManager(config *LifecycleConfig, logger Logger) *PluginLifecycleManager {
if config == nil {
config = &LifecycleConfig{
TransitionTimeout: 30 * time.Second,
RetryAttempts: 3,
EnableHistory: true,
MaxHistorySize: 100,
StateCheckInterval: 5 * time.Second,
}
}
return &PluginLifecycleManager{
stateMachine: NewPluginStateMachine(),
eventHandlers: make(map[PluginEventType][]PluginEventHandler),
stateHistory: make(map[string][]PluginStateTransition),
logger: logger,
config: config,
}
}
// 创建插件状态机
func NewPluginStateMachine() *PluginStateMachine {
validTransitions := map[PluginState][]PluginState{
PluginStateUnloaded: {
PluginStateLoaded,
},
PluginStateLoaded: {
PluginStateInitialized,
PluginStateError,
},
PluginStateInitialized: {
PluginStateStarting,
PluginStateError,
},
PluginStateStarting: {
PluginStateRunning,
PluginStateError,
},
PluginStateRunning: {
PluginStateStopping,
PluginStateError,
},
PluginStateStopping: {
PluginStateStopped,
PluginStateError,
},
PluginStateStopped: {
PluginStateLoaded,
PluginStateUnloaded,
},
PluginStateError: {
PluginStateLoaded,
PluginStateUnloaded,
},
}
return &PluginStateMachine{
currentStates: make(map[string]PluginState),
validTransitions: validTransitions,
}
}
// 初始化插件
func (plm *PluginLifecycleManager) InitializePlugin(ctx context.Context, plugin Plugin) error {
return plm.transitionState(ctx, plugin, EventInitialize, func() error {
return plugin.Initialize(ctx, plugin.GetConfig())
})
}
// 启动插件
func (plm *PluginLifecycleManager) StartPlugin(ctx context.Context, plugin Plugin) error {
return plm.transitionState(ctx, plugin, EventStart, func() error {
return plugin.Start(ctx)
})
}
// 停止插件
func (plm *PluginLifecycleManager) StopPlugin(ctx context.Context, plugin Plugin) error {
return plm.transitionState(ctx, plugin, EventStop, func() error {
return plugin.Stop(ctx)
})
}
// 清理插件
func (plm *PluginLifecycleManager) CleanupPlugin(ctx context.Context, plugin Plugin) error {
return plm.transitionState(ctx, plugin, EventCleanup, func() error {
return plugin.Cleanup(ctx)
})
}
// 状态转换
func (plm *PluginLifecycleManager) transitionState(
ctx context.Context,
plugin Plugin,
eventType PluginEventType,
action func() error,
) error {
pluginName := plugin.GetName()
currentState := plm.stateMachine.GetState(pluginName)
// 确定目标状态
targetState := plm.getTargetState(eventType)
if targetState == PluginState(-1) {
return fmt.Errorf("invalid event type: %s", eventType)
}
// 验证状态转换
if !plm.stateMachine.CanTransition(currentState, targetState) {
return fmt.Errorf("cannot transition from %s to %s", currentState, targetState)
}
// 创建上下文和超时
ctx, cancel := context.WithTimeout(ctx, plm.config.TransitionTimeout)
defer cancel()
// 记录状态转换开始
startTime := time.Now()
if plm.config.EnableHistory {
plm.recordStateTransition(pluginName, currentState, targetState, startTime, "", eventType.String())
}
// 执行前置事件处理器
if err := plm.handleEvent(ctx, PluginStateEvent{
PluginName: pluginName,
EventType: eventType,
FromState: currentState,
ToState: targetState,
Timestamp: startTime,
}); err != nil {
plm.logger.Error("Pre-event handler failed",
String("plugin_name", pluginName),
String("event_type", string(eventType)),
Error("error", err))
return fmt.Errorf("pre-event handler failed: %w", err)
}
// 执行状态转换动作
var actionErr error
for attempt := 0; attempt <= plm.config.RetryAttempts; attempt++ {
actionErr = action()
if actionErr == nil {
break
}
if attempt < plm.config.RetryAttempts {
plm.logger.Warn("Plugin state transition failed, retrying",
String("plugin_name", pluginName),
String("event_type", string(eventType)),
Int("attempt", attempt+1),
Error("error", actionErr))
select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(time.Second):
continue
}
}
}
if actionErr != nil {
// 转换到错误状态
errorState := PluginStateError
plm.stateMachine.SetState(pluginName, errorState)
// 记录错误状态转换
if plm.config.EnableHistory {
plm.recordStateTransition(pluginName, targetState, errorState, startTime, actionErr.Error(), eventType.String())
}
// 执行错误事件处理器
plm.handleEvent(ctx, PluginStateEvent{
PluginName: pluginName,
EventType: EventError,
FromState: targetState,
ToState: errorState,
Timestamp: time.Now(),
Error: actionErr,
})
return fmt.Errorf("state transition failed after %d attempts: %w", plm.config.RetryAttempts+1, actionErr)
}
// 更新状态
plm.stateMachine.SetState(pluginName, targetState)
// 记录成功状态转换
duration := time.Since(startTime)
if plm.config.EnableHistory {
plm.recordStateTransition(pluginName, currentState, targetState, startTime, "", eventType.String())
}
// 执行后置事件处理器
if err := plm.handleEvent(ctx, PluginStateEvent{
PluginName: pluginName,
EventType: eventType,
FromState: currentState,
ToState: targetState,
Timestamp: time.Now(),
}); err != nil {
plm.logger.Warn("Post-event handler failed",
String("plugin_name", pluginName),
String("event_type", string(eventType)),
Error("error", err))
}
plm.logger.Info("Plugin state transition completed",
String("plugin_name", pluginName),
String("from_state", currentState.String()),
String("to_state", targetState.String()),
Duration("duration", duration))
return nil
}
// 获取目标状态
func (plm *PluginLifecycleManager) getTargetState(eventType PluginEventType) PluginState {
switch eventType {
case EventInitialize:
return PluginStateInitialized
case EventStart:
return PluginStateRunning
case EventStop:
return PluginStateStopped
case EventCleanup:
return PluginStateLoaded
default:
return PluginState(-1)
}
}
// 注册事件处理器
func (plm *PluginLifecycleManager) RegisterEventHandler(handler PluginEventHandler) {
plm.mu.Lock()
defer plm.mu.Unlock()
for _, eventType := range handler.GetEventTypes() {
plm.eventHandlers[eventType] = append(plm.eventHandlers[eventType], handler)
}
}
// 处理事件
func (plm *PluginLifecycleManager) handleEvent(ctx context.Context, event PluginStateEvent) error {
plm.mu.RLock()
handlers := plm.eventHandlers[event.EventType]
plm.mu.RUnlock()
for _, handler := range handlers {
if err := handler.Handle(ctx, event); err != nil {
return err
}
}
return nil
}
// 记录状态转换
func (plm *PluginLifecycleManager) recordStateTransition(
pluginName string,
fromState, toState PluginState,
startTime time.Time,
errorMsg, triggeredBy string,
) {
plm.mu.Lock()
defer plm.mu.Unlock()
transition := PluginStateTransition{
FromState: fromState,
ToState: toState,
Timestamp: startTime,
Duration: time.Since(startTime),
Error: errorMsg,
TriggeredBy: triggeredBy,
}
if _, exists := plm.stateHistory[pluginName]; !exists {
plm.stateHistory[pluginName] = make([]PluginStateTransition, 0)
}
plm.stateHistory[pluginName] = append(plm.stateHistory[pluginName], transition)
// 限制历史记录大小
if len(plm.stateHistory[pluginName]) > plm.config.MaxHistorySize {
plm.stateHistory[pluginName] = plm.stateHistory[pluginName][1:]
}
}
// 获取插件状态
func (psm *PluginStateMachine) GetState(pluginName string) PluginState {
psm.mu.RLock()
defer psm.mu.RUnlock()
if state, exists := psm.currentStates[pluginName]; exists {
return state
}
return PluginStateUnloaded
}
// 设置插件状态
func (psm *PluginStateMachine) SetState(pluginName string, state PluginState) {
psm.mu.Lock()
defer psm.mu.Unlock()
psm.currentStates[pluginName] = state
}
// 检查是否可以转换状态
func (psm *PluginStateMachine) CanTransition(fromState, toState PluginState) bool {
psm.mu.RLock()
defer psm.mu.RUnlock()
validStates, exists := psm.validTransitions[fromState]
if !exists {
return false
}
for _, validState := range validStates {
if validState == toState {
return true
}
}
return false
}
// 获取所有插件状态
func (psm *PluginStateMachine) GetAllStates() map[string]PluginState {
psm.mu.RLock()
defer psm.mu.RUnlock()
states := make(map[string]PluginState)
for name, state := range psm.currentStates {
states[name] = state
}
return states
}
---
03.插件监控与指标
a.插件指标收集器
a.功能说明
插件指标收集器负责收集插件的运行时指标,包括性能指标、资源使用情况和错误统计。
b.代码示例
---
// plugin/metrics.go
package plugin
import (
"context"
"sync"
"time"
)
// 插件指标收集器
type PluginMetricsCollector struct {
metrics map[string]*PluginMetrics
aggregator MetricsAggregator
exporters []MetricsExporter
collectInterval time.Duration
mu sync.RWMutex
logger Logger
}
// 插件指标
type PluginMetrics struct {
PluginName string `json:"plugin_name"`
// 基础指标
RequestCount int64 `json:"request_count"`
ErrorCount int64 `json:"error_count"`
TotalDuration time.Duration `json:"total_duration"`
AverageDuration time.Duration `json:"average_duration"`
MinDuration time.Duration `json:"min_duration"`
MaxDuration time.Duration `json:"max_duration"`
// 资源指标
MemoryUsage int64 `json:"memory_usage"`
CPUUsage float64 `json:"cpu_usage"`
GoroutineCount int `json:"goroutine_count"`
FileDescriptors int `json:"file_descriptors"`
// 状态指标
Uptime time.Duration `json:"uptime"`
LastActivity time.Time `json:"last_activity"`
StartTime time.Time `json:"start_time"`
RestartCount int64 `json:"restart_count"`
// 健康指标
HealthCheckCount int64 `json:"health_check_count"`
HealthCheckFailures int64 `json:"health_check_failures"`
LastHealthCheck time.Time `json:"last_health_check"`
IsHealthy bool `json:"is_healthy"`
// 时间戳
LastUpdated time.Time `json:"last_updated"`
// 统计数据
Durations []time.Duration `json:"-"` // 内部使用,不导出
mu sync.RWMutex
}
// 指标聚合器接口
type MetricsAggregator interface {
Aggregate(metrics map[string]*PluginMetrics) *AggregatedMetrics
GetAggregationWindow() time.Duration
SetAggregationWindow(window time.Duration)
}
// 聚合指标
type AggregatedMetrics struct {
TotalPlugins int `json:"total_plugins"`
RunningPlugins int `json:"running_plugins"`
TotalRequests int64 `json:"total_requests"`
TotalErrors int64 `json:"total_errors"`
AverageDuration time.Duration `json:"average_duration"`
TotalMemoryUsage int64 `json:"total_memory_usage"`
AverageCPUUsage float64 `json:"average_cpu_usage"`
HealthScore float64 `json:"health_score"`
Timestamp time.Time `json:"timestamp"`
}
// 指标导出器接口
type MetricsExporter interface {
Export(ctx context.Context, metrics map[string]*PluginMetrics) error
GetType() string
IsEnabled() bool
}
// 创建插件指标收集器
func NewPluginMetricsCollector(collectInterval time.Duration, logger Logger) *PluginMetricsCollector {
return &PluginMetricsCollector{
metrics: make(map[string]*PluginMetrics),
collectInterval: collectInterval,
logger: logger,
aggregator: NewDefaultMetricsAggregator(),
exporters: make([]MetricsExporter, 0),
}
}
// 创建插件指标
func NewPluginMetrics(pluginName string) *PluginMetrics {
now := time.Now()
return &PluginMetrics{
PluginName: pluginName,
MinDuration: time.Hour, // 初始化为大值
StartTime: now,
LastActivity: now,
LastUpdated: now,
LastHealthCheck: now,
IsHealthy: true,
Durations: make([]time.Duration, 0, 1000),
}
}
// 注册插件指标
func (pmc *PluginMetricsCollector) RegisterPlugin(pluginName string) {
pmc.mu.Lock()
defer pmc.mu.Unlock()
if _, exists := pmc.metrics[pluginName]; !exists {
pmc.metrics[pluginName] = NewPluginMetrics(pluginName)
pmc.logger.Debug("Plugin metrics registered", String("plugin_name", pluginName))
}
}
// 注销插件指标
func (pmc *PluginMetricsCollector) UnregisterPlugin(pluginName string) {
pmc.mu.Lock()
defer pmc.mu.Unlock()
delete(pmc.metrics, pluginName)
pmc.logger.Debug("Plugin metrics unregistered", String("plugin_name", pluginName))
}
// 记录请求
func (pmc *PluginMetricsCollector) RecordRequest(pluginName string, duration time.Duration, err error) {
pmc.mu.RLock()
metrics, exists := pmc.metrics[pluginName]
pmc.mu.RUnlock()
if !exists {
return
}
metrics.mu.Lock()
defer metrics.mu.Unlock()
metrics.RequestCount++
metrics.LastActivity = time.Now()
metrics.LastUpdated = time.Now()
if err != nil {
metrics.ErrorCount++
}
metrics.TotalDuration += duration
metrics.Durations = append(metrics.Durations, duration)
// 更新最大最小时间
if duration > metrics.MaxDuration {
metrics.MaxDuration = duration
}
if duration < metrics.MinDuration {
metrics.MinDuration = duration
}
// 计算平均时间
metrics.AverageDuration = time.Duration(int64(metrics.TotalDuration) / metrics.RequestCount)
// 限制durations数组大小
if len(metrics.Durations) > 1000 {
metrics.Durations = metrics.Durations[1:]
}
}
// 更新资源指标
func (pmc *PluginMetricsCollector) UpdateResourceMetrics(pluginName string, memory int64, cpu float64, goroutines, fds int) {
pmc.mu.RLock()
metrics, exists := pmc.metrics[pluginName]
pmc.mu.RUnlock()
if !exists {
return
}
metrics.mu.Lock()
defer metrics.mu.Unlock()
metrics.MemoryUsage = memory
metrics.CPUUsage = cpu
metrics.GoroutineCount = goroutines
metrics.FileDescriptors = fds
metrics.LastUpdated = time.Now()
}
// 更新健康状态
func (pmc *PluginMetricsCollector) UpdateHealthStatus(pluginName string, isHealthy bool, checkDuration time.Duration) {
pmc.mu.RLock()
metrics, exists := pmc.metrics[pluginName]
pmc.mu.RUnlock()
if !exists {
return
}
metrics.mu.Lock()
defer metrics.mu.Unlock()
metrics.HealthCheckCount++
metrics.LastHealthCheck = time.Now()
metrics.LastUpdated = time.Now()
if !isHealthy {
metrics.HealthCheckFailures++
}
metrics.IsHealthy = isHealthy
}
// 记录重启
func (pmc *PluginMetricsCollector) RecordRestart(pluginName string) {
pmc.mu.RLock()
metrics, exists := pmc.metrics[pluginName]
pmc.mu.RUnlock()
if !exists {
return
}
metrics.mu.Lock()
defer metrics.mu.Unlock()
metrics.RestartCount++
metrics.StartTime = time.Now()
metrics.LastUpdated = time.Now()
}
// 获取插件指标
func (pmc *PluginMetricsCollector) GetMetrics(pluginName string) (*PluginMetrics, bool) {
pmc.mu.RLock()
defer pmc.mu.RUnlock()
metrics, exists := pmc.metrics[pluginName]
if !exists {
return nil, false
}
// 返回副本
metrics.mu.RLock()
defer metrics.mu.RUnlock()
copy := *metrics
copy.Durations = make([]time.Duration, len(metrics.Durations))
copySlice(copy.Durations, metrics.Durations)
return ©, true
}
// 获取所有指标
func (pmc *PluginMetricsCollector) GetAllMetrics() map[string]*PluginMetrics {
pmc.mu.RLock()
defer pmc.mu.RUnlock()
allMetrics := make(map[string]*PluginMetrics)
for name, metrics := range pmc.metrics {
metrics.mu.RLock()
copy := *metrics
copy.Durations = make([]time.Duration, len(metrics.Durations))
copySlice(copy.Durations, metrics.Durations)
metrics.mu.RUnlock()
allMetrics[name] = ©
}
return allMetrics
}
// 添加指标导出器
func (pmc *PluginMetricsCollector) AddExporter(exporter MetricsExporter) {
pmc.mu.Lock()
defer pmc.mu.Unlock()
pmc.exporters = append(pmc.exporters, exporter)
pmc.logger.Info("Metrics exporter added", String("type", exporter.GetType()))
}
// 启动指标收集
func (pmc *PluginMetricsCollector) Start(ctx context.Context) {
ticker := time.NewTicker(pmc.collectInterval)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
pmc.collectAndExport(ctx)
}
}
}
// 收集和导出指标
func (pmc *PluginMetricsCollector) collectAndExport(ctx context.Context) {
// 更新运行时指标
pmc.updateRuntimeMetrics()
// 获取所有指标
allMetrics := pmc.GetAllMetrics()
// 导出指标
for _, exporter := range pmc.exporters {
if exporter.IsEnabled() {
if err := exporter.Export(ctx, allMetrics); err != nil {
pmc.logger.Warn("Failed to export metrics",
String("exporter_type", exporter.GetType()),
Error("error", err))
}
}
}
}
// 更新运行时指标
func (pmc *PluginMetricsCollector) updateRuntimeMetrics() {
pmc.mu.RLock()
defer pmc.mu.RUnlock()
now := time.Now()
for name, metrics := range pmc.metrics {
metrics.mu.Lock()
// 更新运行时间
if !metrics.StartTime.IsZero() {
metrics.Uptime = now.Sub(metrics.StartTime)
}
metrics.LastUpdated = now
metrics.mu.Unlock()
}
}
// 获取聚合指标
func (pmc *PluginMetricsCollector) GetAggregatedMetrics() *AggregatedMetrics {
allMetrics := pmc.GetAllMetrics()
return pmc.aggregator.Aggregate(allMetrics)
}
// 辅助函数
func copySlice(dst, src []time.Duration) {
for i, v := range src {
dst[i] = v
}
}
---
6.2 身份认证中间件
01.认证架构设计
a.认证方式
a.JWT认证
JSON Web Token令牌认证。
b.Session认证
基于Session的会话认证。
c.OAuth2认证
OAuth2.0第三方授权认证。
d.API Key认证
API密钥认证方式。
e.认证架构示例
---
// auth/jwt_auth.go
package auth
import (
"context"
"crypto/rsa"
"fmt"
"time"
"github.com/golang-jwt/jwt/v5"
)
// JWT认证器
type JWTAuthenticator struct {
privateKey *rsa.PrivateKey
publicKey *rsa.PublicKey
issuer string
audience []string
expirationTime time.Duration
refreshTime time.Duration
algorithm jwt.SigningMethod
signingKey []byte
signingKeyID string
keyRotationTime time.Duration
lastKeyRotation time.Time
mu sync.RWMutex
}
// JWT配置
type JWTConfig struct {
PrivateKeyPath string `yaml:"private_key_path"`
PublicKeyPath string `yaml:"public_key_path"`
Issuer string `yaml:"issuer"`
Audience []string `yaml:"audience"`
ExpirationTime time.Duration `yaml:"expiration_time"`
RefreshTime time.Duration `yaml:"refresh_time"`
Algorithm string `yaml:"algorithm"`
SigningKey string `yaml:"signing_key"`
KeyRotationTime time.Duration `yaml:"key_rotation_time"`
}
// JWT声明
type CustomClaims struct {
UserID string `json:"user_id"`
Username string `json:"username"`
Email string `json:"email"`
Roles []string `json:"roles"`
Permissions []string `json:"permissions"`
TokenType string `json:"token_type"`
DeviceID string `json:"device_id"`
IPAddress string `json:"ip_address"`
Metadata map[string]string `json:"metadata"`
jwt.RegisteredClaims
}
// 创建JWT认证器
func NewJWTAuthenticator(config *JWTConfig) (*JWTAuthenticator, error) {
auth := &JWTAuthenticator{
issuer: config.Issuer,
audience: config.Audience,
expirationTime: config.ExpirationTime,
refreshTime: config.RefreshTime,
lastKeyRotation: time.Now(),
}
// 设置签名算法
switch config.Algorithm {
case "RS256":
auth.algorithm = jwt.SigningMethodRS256
case "RS384":
auth.algorithm = jwt.SigningMethodRS384
case "RS512":
auth.algorithm = jwt.SigningMethodRS512
case "HS256":
auth.algorithm = jwt.SigningMethodHS256
auth.signingKey = []byte(config.SigningKey)
case "HS384":
auth.algorithm = jwt.SigningMethodHS384
auth.signingKey = []byte(config.SigningKey)
case "HS512":
auth.algorithm = jwt.SigningMethodHS512
auth.signingKey = []byte(config.SigningKey)
default:
return nil, fmt.Errorf("unsupported algorithm: %s", config.Algorithm)
}
// 加载密钥对(RSA算法)
if strings.HasPrefix(config.Algorithm, "RS") {
privateKey, err := loadPrivateKey(config.PrivateKeyPath)
if err != nil {
return nil, fmt.Errorf("failed to load private key: %w", err)
}
publicKey, err := loadPublicKey(config.PublicKeyPath)
if err != nil {
return nil, fmt.Errorf("failed to load public key: %w", err)
}
auth.privateKey = privateKey
auth.publicKey = publicKey
}
return auth, nil
}
// 生成访问令牌
func (auth *JWTAuthenticator) GenerateAccessToken(ctx context.Context, user *User) (string, error) {
now := time.Now()
expiresAt := now.Add(auth.expirationTime)
claims := &CustomClaims{
UserID: user.ID,
Username: user.Username,
Email: user.Email,
Roles: user.Roles,
Permissions: user.Permissions,
TokenType: "access",
DeviceID: getDeviceIDFromContext(ctx),
IPAddress: getIPAddressFromContext(ctx),
Metadata: user.Metadata,
RegisteredClaims: jwt.RegisteredClaims{
Issuer: auth.issuer,
Subject: user.ID,
Audience: auth.audience,
ExpiresAt: jwt.NewNumericDate(expiresAt),
NotBefore: jwt.NewNumericDate(now),
IssuedAt: jwt.NewNumericDate(now),
ID: generateTokenID(),
},
}
// 检查是否需要密钥轮换
if auth.keyRotationTime > 0 && time.Since(auth.lastKeyRotation) > auth.keyRotationTime {
if err := auth.rotateKeys(); err != nil {
return "", fmt.Errorf("key rotation failed: %w", err)
}
}
// 生成令牌
token := jwt.NewWithClaims(auth.algorithm, claims)
var tokenString string
var err error
if auth.privateKey != nil {
tokenString, err = token.SignedString(auth.privateKey)
} else {
tokenString, err = token.SignedString(auth.signingKey)
}
if err != nil {
return "", fmt.Errorf("failed to sign token: %w", err)
}
return tokenString, nil
}
// 生成刷新令牌
func (auth *JWTAuthenticator) GenerateRefreshToken(ctx context.Context, user *User) (string, error) {
now := time.Now()
expiresAt := now.Add(auth.refreshTime * 7) // 刷新令牌有效期为访问令牌的7倍
claims := &CustomClaims{
UserID: user.ID,
Username: user.Username,
TokenType: "refresh",
DeviceID: getDeviceIDFromContext(ctx),
IPAddress: getIPAddressFromContext(ctx),
RegisteredClaims: jwt.RegisteredClaims{
Issuer: auth.issuer,
Subject: user.ID,
Audience: auth.audience,
ExpiresAt: jwt.NewNumericDate(expiresAt),
NotBefore: jwt.NewNumericDate(now),
IssuedAt: jwt.NewNumericDate(now),
ID: generateTokenID(),
},
}
token := jwt.NewWithClaims(auth.algorithm, claims)
var tokenString string
var err error
if auth.privateKey != nil {
tokenString, err = token.SignedString(auth.privateKey)
} else {
tokenString, err = token.SignedString(auth.signingKey)
}
if err != nil {
return "", fmt.Errorf("failed to sign refresh token: %w", err)
}
return tokenString, nil
}
// 验证令牌
func (auth *JWTAuthenticator) ValidateToken(tokenString string) (*CustomClaims, error) {
// 解析令牌
token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
// 验证签名算法
if token.Method != auth.algorithm {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
// 返回验证密钥
if auth.publicKey != nil {
return auth.publicKey, nil
}
return auth.signingKey, nil
})
if err != nil {
return nil, fmt.Errorf("failed to parse token: %w", err)
}
// 验证令牌有效性
if !token.Valid {
return nil, fmt.Errorf("invalid token")
}
claims, ok := token.Claims.(*CustomClaims)
if !ok {
return nil, fmt.Errorf("invalid token claims")
}
// 验证发行者
if claims.Issuer != auth.issuer {
return nil, fmt.Errorf("invalid issuer")
}
// 验证受众
if !auth.validateAudience(claims.Audience) {
return nil, fmt.Errorf("invalid audience")
}
// 验证过期时间
if !claims.VerifyExpiresAt(jwt.NewNumericDate(time.Now())) {
return nil, fmt.Errorf("token expired")
}
// 验证生效时间
if !claims.VerifyNotBefore(jwt.NewNumericDate(time.Now())) {
return nil, fmt.Errorf("token not valid yet")
}
return claims, nil
}
// 刷新令牌
func (auth *JWTAuthenticator) RefreshToken(ctx context.Context, refreshToken string) (string, string, error) {
// 验证刷新令牌
claims, err := auth.ValidateToken(refreshToken)
if err != nil {
return "", "", fmt.Errorf("invalid refresh token: %w", err)
}
// 验证令牌类型
if claims.TokenType != "refresh" {
return "", "", fmt.Errorf("not a refresh token")
}
// 从数据库获取用户信息
user, err := auth.getUserByID(ctx, claims.UserID)
if err != nil {
return "", "", fmt.Errorf("failed to get user: %w", err)
}
// 验证用户状态
if !user.IsActive() {
return "", "", fmt.Errorf("user is not active")
}
// 生成新的访问令牌和刷新令牌
accessToken, err := auth.GenerateAccessToken(ctx, user)
if err != nil {
return "", "", fmt.Errorf("failed to generate access token: %w", err)
}
newRefreshToken, err := auth.GenerateRefreshToken(ctx, user)
if err != nil {
return "", "", fmt.Errorf("failed to generate refresh token: %w", err)
}
return accessToken, newRefreshToken, nil
}
// 撤销令牌
func (auth *JWTAuthenticator) RevokeToken(ctx context.Context, tokenString string) error {
// 解析令牌获取JTI
token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, nil)
if err != nil {
return fmt.Errorf("failed to parse token: %w", err)
}
claims, ok := token.Claims.(*CustomClaims)
if !ok {
return fmt.Errorf("invalid token claims")
}
// 将JTI添加到黑名单
if err := auth.addToBlacklist(ctx, claims.ID, claims.ExpiresAt.Time); err != nil {
return fmt.Errorf("failed to add token to blacklist: %w", err)
}
return nil
}
// 验证受众
func (auth *JWTAuthenticator) validateAudience(audience jwt.ClaimStrings) bool {
if len(auth.audience) == 0 {
return true
}
for _, aud := range auth.audience {
for _, tokenAud := range audience {
if aud == tokenAud {
return true
}
}
}
return false
}
// 密钥轮换
func (auth *JWTAuthenticator) rotateKeys() error {
auth.mu.Lock()
defer auth.mu.Unlock()
// 生成新的密钥对
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return fmt.Errorf("failed to generate private key: %w", err)
}
publicKey := &privateKey.PublicKey
// 保存新密钥
if err := auth.saveNewKeys(privateKey, publicKey); err != nil {
return fmt.Errorf("failed to save new keys: %w", err)
}
// 更新密钥
oldPrivateKey := auth.privateKey
oldPublicKey := auth.publicKey
auth.privateKey = privateKey
auth.publicKey = publicKey
auth.lastKeyRotation = time.Now()
// 平滑过渡:保留旧密钥一段时间
go func() {
time.Sleep(time.Hour)
// 删除旧密钥
auth.deleteOldKeys(oldPrivateKey, oldPublicKey)
}()
return nil
}
// 检查令牌是否在黑名单中
func (auth *JWTAuthenticator) isTokenBlacklisted(ctx context.Context, jti string) (bool, error) {
// 从Redis或数据库检查黑名单
exists, err := auth.checkBlacklist(ctx, jti)
if err != nil {
return false, fmt.Errorf("failed to check blacklist: %w", err)
}
return exists, nil
}
// 添加到黑名单
func (auth *JWTAuthenticator) addToBlacklist(ctx context.Context, jti string, expiresAt time.Time) error {
// 将JTI添加到Redis或数据库黑名单中
return auth.saveToBlacklist(ctx, jti, expiresAt)
}
// 从黑名单中移除
func (auth *JWTAuthenticator) removeFromBlacklist(ctx context.Context, jti string) error {
// 从Redis或数据库黑名单中移除
return auth.deleteFromBlacklist(ctx, jti)
}
// 获取用户信息
func (auth *JWTAuthenticator) getUserByID(ctx context.Context, userID string) (*User, error) {
// 从数据库获取用户信息
return nil, nil
}
// 保存新密钥
func (auth *JWTAuthenticator) saveNewKeys(privateKey *rsa.PrivateKey, publicKey *rsa.PublicKey) error {
// 保存新密钥到文件或密钥管理系统
return nil
}
// 删除旧密钥
func (auth *JWTAuthenticator) deleteOldKeys(privateKey *rsa.PrivateKey, publicKey *rsa.PublicKey) error {
// 删除旧密钥文件
return nil
}
// 检查黑名单
func (auth *JWTAuthenticator) checkBlacklist(ctx context.Context, jti string) (bool, error) {
// 检查Redis或数据库中的黑名单
return false, nil
}
// 保存到黑名单
func (auth *JWTAuthenticator) saveToBlacklist(ctx context.Context, jti string, expiresAt time.Time) error {
// 保存到Redis或数据库黑名单
return nil
}
// 从黑名单删除
func (auth *JWTAuthenticator) deleteFromBlacklist(ctx context.Context, jti string) error {
// 从Redis或数据库黑名单中删除
return nil
}
// 加载私钥
func loadPrivateKey(path string) (*rsa.PrivateKey, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, err
}
block, _ := pem.Decode(data)
if block == nil {
return nil, fmt.Errorf("failed to decode PEM block")
}
key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
// 尝试PKCS8格式
keyInterface, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("failed to parse private key: %w", err)
}
var ok bool
key, ok = keyInterface.(*rsa.PrivateKey)
if !ok {
return nil, fmt.Errorf("not an RSA private key")
}
}
return key, nil
}
// 加载公钥
func loadPublicKey(path string) (*rsa.PublicKey, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, err
}
block, _ := pem.Decode(data)
if block == nil {
return nil, fmt.Errorf("failed to decode PEM block")
}
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
// 尝试PKCS1格式
pubInterface, err := x509.ParsePKCS1PublicKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("failed to parse public key: %w", err)
}
var ok bool
pub, ok = pubInterface.(*rsa.PublicKey)
if !ok {
return nil, fmt.Errorf("not an RSA public key")
}
return pub, nil
}
rsaPub, ok := pub.(*rsa.PublicKey)
if !ok {
return nil, fmt.Errorf("not an RSA public key")
}
return rsaPub, nil
}
// 用户信息
type User struct {
ID string `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
Roles []string `json:"roles"`
Permissions []string `json:"permissions"`
Metadata map[string]string `json:"metadata"`
Status string `json:"status"`
}
func (u *User) IsActive() bool {
return u.Status == "active"
}
// 生成令牌ID
func generateTokenID() string {
return fmt.Sprintf("jti_%d_%d", time.Now().UnixNano(), rand.Int())
}
// 从上下文获取设备ID
func getDeviceIDFromContext(ctx context.Context) string {
if deviceID, ok := ctx.Value("device_id").(string); ok {
return deviceID
}
return ""
}
// 从上下文获取IP地址
func getIPAddressFromContext(ctx context.Context) string {
if ip, ok := ctx.Value("ip_address").(string); ok {
return ip
}
return ""
}
// Session认证器
type SessionAuthenticator struct {
store SessionStore
sessionName string
cookieName string
cookieDomain string
cookiePath string
cookieSecure bool
cookieHTTPOnly bool
maxAge time.Duration
idleTimeout time.Duration
absoluteTimeout time.Duration
}
// Session配置
type SessionConfig struct {
Store SessionStore `yaml:"-"`
SessionName string `yaml:"session_name"`
CookieName string `yaml:"cookie_name"`
CookieDomain string `yaml:"cookie_domain"`
CookiePath string `yaml:"cookie_path"`
CookieSecure bool `yaml:"cookie_secure"`
CookieHTTPOnly bool `yaml:"cookie_http_only"`
MaxAge time.Duration `yaml:"max_age"`
IdleTimeout time.Duration `yaml:"idle_timeout"`
AbsoluteTimeout time.Duration `yaml:"absolute_timeout"`
}
// 创建Session认证器
func NewSessionAuthenticator(config *SessionConfig) *SessionAuthenticator {
return &SessionAuthenticator{
store: config.Store,
sessionName: config.SessionName,
cookieName: config.CookieName,
cookieDomain: config.CookieDomain,
cookiePath: config.CookiePath,
cookieSecure: config.CookieSecure,
cookieHTTPOnly: config.CookieHTTPOnly,
maxAge: config.MaxAge,
idleTimeout: config.IdleTimeout,
absoluteTimeout: config.AbsoluteTimeout,
}
}
// 创建Session
func (auth *SessionAuthenticator) CreateSession(ctx context.Context, user *User) (*Session, error) {
sessionID := generateSessionID()
now := time.Now()
session := &Session{
ID: sessionID,
UserID: user.ID,
Username: user.Username,
Email: user.Email,
Roles: user.Roles,
CreatedAt: now,
LastAccess: now,
Data: make(map[string]interface{}),
}
// 设置用户数据
session.Set("user", user)
// 保存Session
if err := auth.store.Set(ctx, sessionID, session, auth.maxAge); err != nil {
return nil, fmt.Errorf("failed to save session: %w", err)
}
return session, nil
}
// 验证Session
func (auth *SessionAuthenticator) ValidateSession(ctx context.Context, sessionID string) (*Session, error) {
session, err := auth.store.Get(ctx, sessionID)
if err != nil {
return nil, fmt.Errorf("failed to get session: %w", err)
}
if session == nil {
return nil, fmt.Errorf("session not found")
}
// 检查空闲超时
if auth.idleTimeout > 0 && time.Since(session.LastAccess) > auth.idleTimeout {
auth.store.Delete(ctx, sessionID)
return nil, fmt.Errorf("session idle timeout")
}
// 检查绝对超时
if auth.absoluteTimeout > 0 && time.Since(session.CreatedAt) > auth.absoluteTimeout {
auth.store.Delete(ctx, sessionID)
return nil, fmt.Errorf("session absolute timeout")
}
// 更新最后访问时间
session.LastAccess = time.Now()
auth.store.Set(ctx, sessionID, session, auth.maxAge)
return session, nil
}
// 销毁Session
func (auth *SessionAuthenticator) DestroySession(ctx context.Context, sessionID string) error {
return auth.store.Delete(ctx, sessionID)
}
// 刷新Session
func (auth *SessionAuthenticator) RefreshSession(ctx context.Context, sessionID string) error {
session, err := auth.store.Get(ctx, sessionID)
if err != nil {
return fmt.Errorf("failed to get session: %w", err)
}
if session == nil {
return fmt.Errorf("session not found")
}
session.LastAccess = time.Now()
return auth.store.Set(ctx, sessionID, session, auth.maxAge)
}
// Session接口
type Session struct {
ID string `json:"id"`
UserID string `json:"user_id"`
Username string `json:"username"`
Email string `json:"email"`
Roles []string `json:"roles"`
CreatedAt time.Time `json:"created_at"`
LastAccess time.Time `json:"last_access"`
Data map[string]interface{} `json:"data"`
mu sync.RWMutex
}
// 设置Session数据
func (s *Session) Set(key string, value interface{}) {
s.mu.Lock()
defer s.mu.Unlock()
s.Data[key] = value
}
// 获取Session数据
func (s *Session) Get(key string) (interface{}, bool) {
s.mu.RLock()
defer s.mu.RUnlock()
value, exists := s.Data[key]
return value, exists
}
// 删除Session数据
func (s *Session) Delete(key string) {
s.mu.Lock()
defer s.mu.Unlock()
delete(s.Data, key)
}
// 清空Session数据
func (s *Session) Clear() {
s.mu.Lock()
defer s.mu.Unlock()
s.Data = make(map[string]interface{})
}
// Session存储接口
type SessionStore interface {
Set(ctx context.Context, sessionID string, session *Session, ttl time.Duration) error
Get(ctx context.Context, sessionID string) (*Session, error)
Delete(ctx context.Context, sessionID string) error
List(ctx context.Context, userID string) ([]*Session, error)
Cleanup(ctx context.Context) error
}
// 生成Session ID
func generateSessionID() string {
return fmt.Sprintf("sess_%d_%d", time.Now().UnixNano(), rand.Int())
}
---
b.JWT认证实现
a.令牌生成
生成访问令牌和刷新令牌。
b.令牌验证
验证JWT令牌的有效性。
c.令牌刷新
刷新过期的令牌。
d.黑名单管理
管理被撤销的令牌。
e.JWT认证示例
---
// auth/jwt_middleware.go
package auth
import (
"context"
"net/http"
"strings"
"github.com/go-kratos/kratos/v2/middleware"
"github.com/go-kratos/kratos/v2/transport"
)
// JWT认证中间件
type JWTAuthenticationMiddleware struct {
authenticator *JWTAuthenticator
config *JWTMiddlewareConfig
excludePaths []string
tokenExtractor TokenExtractor
errorHandler AuthenticationErrorHandler
}
// JWT中间件配置
type JWTMiddlewareConfig struct {
TokenHeader string `yaml:"token_header"`
TokenPrefix string `yaml:"token_prefix"`
CookieName string `yaml:"cookie_name"`
QueryParam string `yaml:"query_param"`
ExcludePaths []string `yaml:"exclude_paths"`
ValidateUser bool `yaml:"validate_user"`
ValidateIP bool `yaml:"validate_ip"`
ValidateDevice bool `yaml:"validate_device"`
AllowExpiredRefresh bool `yaml:"allow_expired_refresh"`
ErrorOnMissingToken bool `yaml:"error_on_missing_token"`
}
// 创建JWT认证中间件
func NewJWTAuthenticationMiddleware(
authenticator *JWTAuthenticator,
config *JWTMiddlewareConfig,
) *JWTAuthenticationMiddleware {
if config == nil {
config = &JWTMiddlewareConfig{
TokenHeader: "Authorization",
TokenPrefix: "Bearer ",
CookieName: "access_token",
QueryParam: "token",
ExcludePaths: []string{},
ValidateUser: true,
ValidateIP: false,
ValidateDevice: false,
AllowExpiredRefresh: false,
ErrorOnMissingToken: true,
}
}
return &JWTAuthenticationMiddleware{
authenticator: authenticator,
config: config,
excludePaths: config.ExcludePaths,
tokenExtractor: NewDefaultTokenExtractor(config),
errorHandler: NewDefaultAuthenticationErrorHandler(),
}
}
// 中间件实现
func (m *JWTAuthenticationMiddleware) Handle(ctx context.Context, req interface{}, next middleware.Handler) (interface{}, error) {
// 检查是否在排除路径中
if m.isExcludedPath(ctx) {
return next.Handle(ctx, req)
}
// 提取令牌
token, err := m.tokenExtractor.ExtractToken(ctx, req)
if err != nil {
if m.config.ErrorOnMissingToken {
return nil, m.errorHandler.HandleError(ctx, AuthenticationError{
Type: ErrorTypeMissingToken,
Message: "Authentication token is missing",
Err: err,
})
}
// 不强制要求令牌,继续执行
return next.Handle(ctx, req)
}
if token == "" {
if m.config.ErrorOnMissingToken {
return nil, m.errorHandler.HandleError(ctx, AuthenticationError{
Type: ErrorTypeMissingToken,
Message: "Authentication token is missing",
})
}
return next.Handle(ctx, req)
}
// 验证令牌
claims, err := m.authenticator.ValidateToken(token)
if err != nil {
// 检查是否是刷新令牌错误
if strings.Contains(err.Error(), "expired") && m.config.AllowExpiredRefresh {
if refreshToken, refreshErr := m.extractRefreshToken(ctx, req); refreshErr == nil {
return m.handleExpiredToken(ctx, refreshToken, next)
}
}
return nil, m.errorHandler.HandleError(ctx, AuthenticationError{
Type: ErrorTypeInvalidToken,
Message: "Invalid authentication token",
Err: err,
})
}
// 验证用户
if m.config.ValidateUser {
if err := m.validateUser(ctx, claims); err != nil {
return nil, m.errorHandler.HandleError(ctx, AuthenticationError{
Type: ErrorTypeUserValidationFailed,
Message: "User validation failed",
Err: err,
})
}
}
// 验证IP地址
if m.config.ValidateIP {
if err := m.validateIP(ctx, claims); err != nil {
return nil, m.errorHandler.HandleError(ctx, AuthenticationError{
Type: ErrorTypeIPValidationFailed,
Message: "IP address validation failed",
Err: err,
})
}
}
// 验证设备
if m.config.ValidateDevice {
if err := m.validateDevice(ctx, claims); err != nil {
return nil, m.errorHandler.HandleError(ctx, AuthenticationError{
Type: ErrorTypeDeviceValidationFailed,
Message: "Device validation failed",
Err: err,
})
}
}
// 检查令牌是否在黑名单中
if blacklisted, err := m.authenticator.isTokenBlacklisted(ctx, claims.ID); err != nil {
return nil, m.errorHandler.HandleError(ctx, AuthenticationError{
Type: ErrorTypeBlacklistedToken,
Message: "Token is blacklisted",
Err: err,
})
} else if blacklisted {
return nil, m.errorHandler.HandleError(ctx, AuthenticationError{
Type: ErrorTypeBlacklistedToken,
Message: "Token is blacklisted",
})
}
// 将用户信息添加到上下文
ctx = m.setClaimsToContext(ctx, claims)
ctx = m.setUserToContext(ctx, claims.UserID)
// 记录认证日志
m.logAuthentication(ctx, claims)
// 执行下一个中间件
return next.Handle(ctx, req)
}
// 处理过期的令牌
func (m *JWTAuthenticationMiddleware) handleExpiredToken(
ctx context.Context,
refreshToken string,
next middleware.Handler,
) (interface{}, error) {
// 尝试刷新令牌
accessToken, newRefreshToken, err := m.authenticator.RefreshToken(ctx, refreshToken)
if err != nil {
return nil, m.errorHandler.HandleError(ctx, AuthenticationError{
Type: ErrorTypeTokenRefreshFailed,
Message: "Failed to refresh token",
Err: err,
})
}
// 验证新的访问令牌
claims, err := m.authenticator.ValidateToken(accessToken)
if err != nil {
return nil, m.errorHandler.HandleError(ctx, AuthenticationError{
Type: ErrorTypeInvalidToken,
Message: "Invalid refreshed token",
Err: err,
})
}
// 将新令牌添加到响应头
if tr, ok := transport.FromServerContext(ctx); ok && tr.Kind() == transport.KindHTTP {
if httpTr, ok := tr.(transport.Transporter); ok {
httpTr.ReplyHeader().Set("New-Access-Token", accessToken)
httpTr.ReplyHeader().Set("New-Refresh-Token", newRefreshToken)
}
}
// 设置用户信息到上下文
ctx = m.setClaimsToContext(ctx, claims)
ctx = m.setUserToContext(ctx, claims.UserID)
// 执行下一个中间件
return next.Handle(ctx, nil)
}
// 检查是否在排除路径中
func (m *JWTAuthenticationMiddleware) isExcludedPath(ctx context.Context) bool {
path := getPathFromContext(ctx)
for _, excludePath := range m.excludePaths {
if strings.HasPrefix(path, excludePath) {
return true
}
}
return false
}
// 验证用户
func (m *JWTAuthenticationMiddleware) validateUser(ctx context.Context, claims *CustomClaims) error {
// 从数据库获取用户信息
user, err := m.authenticator.getUserByID(ctx, claims.UserID)
if err != nil {
return fmt.Errorf("failed to get user: %w", err)
}
// 检查用户状态
if !user.IsActive() {
return fmt.Errorf("user is not active")
}
// 检查用户角色和权限
if err := m.validateUserRoles(user, claims.Roles); err != nil {
return fmt.Errorf("user roles validation failed: %w", err)
}
return nil
}
// 验证用户角色
func (m *JWTAuthenticationMiddleware) validateUserRoles(user *User, tokenRoles []string) error {
// 检查令牌中的角色是否存在于用户的角色中
for _, tokenRole := range tokenRoles {
found := false
for _, userRole := range user.Roles {
if tokenRole == userRole {
found = true
break
}
}
if !found {
return fmt.Errorf("role %s not found in user roles", tokenRole)
}
}
return nil
}
// 验证IP地址
func (m *JWTAuthenticationMiddleware) validateIP(ctx context.Context, claims *CustomClaims) error {
currentIP := getIPAddressFromContext(ctx)
if currentIP == "" {
return nil // 如果无法获取当前IP,跳过验证
}
if claims.IPAddress != "" && claims.IPAddress != currentIP {
return fmt.Errorf("IP address mismatch: expected %s, got %s", claims.IPAddress, currentIP)
}
return nil
}
// 验证设备
func (m *JWTAuthenticationMiddleware) validateDevice(ctx context.Context, claims *CustomClaims) error {
currentDeviceID := getDeviceIDFromContext(ctx)
if currentDeviceID == "" {
return nil // 如果无法获取设备ID,跳过验证
}
if claims.DeviceID != "" && claims.DeviceID != currentDeviceID {
return fmt.Errorf("device ID mismatch: expected %s, got %s", claims.DeviceID, currentDeviceID)
}
return nil
}
// 将声明添加到上下文
func (m *JWTAuthenticationMiddleware) setClaimsToContext(ctx context.Context, claims *CustomClaims) context.Context {
return context.WithValue(ctx, "jwt_claims", claims)
}
// 将用户ID添加到上下文
func (m *JWTAuthenticationMiddleware) setUserToContext(ctx context.Context, userID string) context.Context {
return context.WithValue(ctx, "user_id", userID)
}
// 提取刷新令牌
func (m *JWTAuthenticationMiddleware) extractRefreshToken(ctx context.Context, req interface{}) (string, error) {
// 从Cookie中提取
if tr, ok := transport.FromServerContext(ctx); ok && tr.Kind() == transport.KindHTTP {
if httpTr, ok := tr.(transport.Transporter); ok {
cookie, err := httpTr.Request().Cookie("refresh_token")
if err == nil && cookie != nil {
return cookie.Value, nil
}
}
}
// 从请求头中提取
if tr, ok := transport.FromServerContext(ctx); ok {
refreshToken := tr.RequestHeader().Get("Refresh-Token")
if refreshToken != "" {
return refreshToken, nil
}
}
return "", fmt.Errorf("refresh token not found")
}
// 记录认证日志
func (m *JWTAuthenticationMiddleware) logAuthentication(ctx context.Context, claims *CustomClaims) {
// 记录认证成功日志
if logger := getLoggerFromContext(ctx); logger != nil {
logger.Info("Authentication successful",
String("user_id", claims.UserID),
String("username", claims.Username),
String("token_type", claims.TokenType),
String("issuer", claims.Issuer),
String("audience", strings.Join(claims.Audience, ",")),
)
}
}
// 令牌提取器接口
type TokenExtractor interface {
ExtractToken(ctx context.Context, req interface{}) (string, error)
}
// 默认令牌提取器
type DefaultTokenExtractor struct {
config *JWTMiddlewareConfig
}
func NewDefaultTokenExtractor(config *JWTMiddlewareConfig) *DefaultTokenExtractor {
return &DefaultTokenExtractor{
config: config,
}
}
func (e *DefaultTokenExtractor) ExtractToken(ctx context.Context, req interface{}) (string, error) {
// 从请求头中提取
if tr, ok := transport.FromServerContext(ctx); ok {
authHeader := tr.RequestHeader().Get(e.config.TokenHeader)
if authHeader != "" {
if strings.HasPrefix(authHeader, e.config.TokenPrefix) {
return strings.TrimPrefix(authHeader, e.config.TokenPrefix), nil
}
return authHeader, nil
}
}
// 从Cookie中提取
if tr, ok := transport.FromServerContext(ctx); ok && tr.Kind() == transport.KindHTTP {
if httpTr, ok := tr.(transport.Transporter); ok {
cookie, err := httpTr.Request().Cookie(e.config.CookieName)
if err == nil && cookie != nil {
return cookie.Value, nil
}
}
}
// 从查询参数中提取
if tr, ok := transport.FromServerContext(ctx); ok && tr.Kind() == transport.KindHTTP {
if httpTr, ok := tr.(transport.Transporter); ok {
token := httpTr.Request().URL.Query().Get(e.config.QueryParam)
if token != "" {
return token, nil
}
}
}
return "", nil
}
// 认证错误处理器接口
type AuthenticationErrorHandler interface {
HandleError(ctx context.Context, err AuthenticationError) error
}
// 默认认证错误处理器
type DefaultAuthenticationErrorHandler struct{}
func NewDefaultAuthenticationErrorHandler() *DefaultAuthenticationErrorHandler {
return &DefaultAuthenticationErrorHandler{}
}
func (h *DefaultAuthenticationErrorHandler) HandleError(ctx context.Context, err AuthenticationError) error {
// 记录错误日志
if logger := getLoggerFromContext(ctx); logger != nil {
logger.Error("Authentication error",
String("error_type", string(err.Type)),
String("message", err.Message),
Error("error", err.Err),
)
}
// 返回认证错误
return NewAuthenticationError(err.Type, err.Message)
}
// 认证错误
type AuthenticationError struct {
Type AuthenticationErrorType
Message string
Err error
}
type AuthenticationErrorType string
const (
ErrorTypeMissingToken AuthenticationErrorType = "MISSING_TOKEN"
ErrorTypeInvalidToken AuthenticationErrorType = "INVALID_TOKEN"
ErrorTypeExpiredToken AuthenticationErrorType = "EXPIRED_TOKEN"
ErrorTypeBlacklistedToken AuthenticationErrorType = "BLACKLISTED_TOKEN"
ErrorTypeTokenRefreshFailed AuthenticationErrorType = "TOKEN_REFRESH_FAILED"
ErrorTypeUserValidationFailed AuthenticationErrorType = "USER_VALIDATION_FAILED"
ErrorTypeIPValidationFailed AuthenticationErrorType = "IP_VALIDATION_FAILED"
ErrorTypeDeviceValidationFailed AuthenticationErrorType = "DEVICE_VALIDATION_FAILED"
)
func NewAuthenticationError(errorType AuthenticationErrorType, message string) error {
return &AuthenticationError{
Type: errorType,
Message: message,
}
}
func (e *AuthenticationError) Error() string {
return e.Message
}
func (e *AuthenticationError) Unwrap() error {
return e.Err
}
// 辅助函数
func getPathFromContext(ctx context.Context) string {
if tr, ok := transport.FromServerContext(ctx); ok && tr.Kind() == transport.KindHTTP {
if httpTr, ok := tr.(transport.Transporter); ok {
return httpTr.Request().URL.Path
}
}
return ""
}
func getIPAddressFromContext(ctx context.Context) string {
if ip, ok := ctx.Value("ip_address").(string); ok {
return ip
}
// 从传输层获取IP
if tr, ok := transport.FromServerContext(ctx); ok && tr.Kind() == transport.KindHTTP {
if httpTr, ok := tr.(transport.Transporter); ok {
// 从X-Forwarded-For头部获取
if xff := httpTr.Request().Header.Get("X-Forwarded-For"); xff != "" {
return strings.Split(xff, ",")[0]
}
// 从X-Real-IP头部获取
if xri := httpTr.Request().Header.Get("X-Real-IP"); xri != "" {
return xri
}
// 从RemoteAddr获取
return httpTr.Request().RemoteAddr
}
}
return ""
}
func getDeviceIDFromContext(ctx context.Context) string {
if deviceID, ok := ctx.Value("device_id").(string); ok {
return deviceID
}
// 从User-Agent头部推断设备ID
if tr, ok := transport.FromServerContext(ctx); ok && tr.Kind() == transport.KindHTTP {
if httpTr, ok := tr.(transport.Transporter); ok {
userAgent := httpTr.Request().Header.Get("User-Agent")
if userAgent != "" {
// 简单的设备ID生成逻辑
return fmt.Sprintf("device_%x", md5.Sum([]byte(userAgent)))
}
}
}
return ""
}
func getLoggerFromContext(ctx context.Context) Logger {
if logger, ok := ctx.Value("logger").(Logger); ok {
return logger
}
return nil
}
// 创建JWT认证中间件的工厂函数
func NewJWTAuthenticationMiddlewareFactory() middleware.Factory {
return func(config interface{}) (middleware.Middleware, error) {
jwtConfig, ok := config.(*JWTConfig)
if !ok {
return nil, fmt.Errorf("invalid JWT config")
}
authenticator, err := NewJWTAuthenticator(jwtConfig)
if err != nil {
return nil, fmt.Errorf("failed to create JWT authenticator: %w", err)
}
middlewareConfig := &JWTMiddlewareConfig{
TokenHeader: "Authorization",
TokenPrefix: "Bearer ",
CookieName: "access_token",
ExcludePaths: []string{"/health", "/metrics"},
}
return NewJWTAuthenticationMiddleware(authenticator, middlewareConfig), nil
}
}
---
6.3 权限控制中间件
01.RBAC权限模型
a.角色定义
a.基础角色
系统管理员、普通用户、访客等。
b.自定义角色
业务相关的角色定义。
c.角色层次
支持角色继承和层次关系。
d.RBAC模型示例
---
// rbac/model.go
package rbac
import (
"context"
"fmt"
"time"
)
// 用户角色关联表
type UserRole struct {
ID uint64 `gorm:"primaryKey" json:"id"`
UserID uint64 `gorm:"not null;index" json:"user_id"`
RoleID uint64 `gorm:"not null;index" json:"role_id"`
CreatedAt time.Time `gorm:"not null" json:"created_at"`
ExpiresAt *time.Time `gorm:"index" json:"expires_at,omitempty"`
CreatedBy uint64 `json:"created_by"`
IsActive bool `gorm:"default:true" json:"is_active"`
Metadata string `gorm:"type:json" json:"metadata,omitempty"`
// 关联
User *User `gorm:"foreignKey:UserID" json:"user,omitempty"`
Role *Role `gorm:"foreignKey:RoleID" json:"role,omitempty"`
}
// 角色权限关联表
type RolePermission struct {
ID uint64 `gorm:"primaryKey" json:"id"`
RoleID uint64 `gorm:"not null;index" json:"role_id"`
PermissionID uint64 `gorm:"not null;index" json:"permission_id"`
CreatedAt time.Time `gorm:"not null" json:"created_at"`
CreatedBy uint64 `json:"created_by"`
// 关联
Role *Role `gorm:"foreignKey:RoleID" json:"role,omitempty"`
Permission *Permission `gorm:"foreignKey:PermissionID" json:"permission,omitempty"`
}
// 用户模型
type User struct {
ID uint64 `gorm:"primaryKey" json:"id"`
Username string `gorm:"size:50;not null;uniqueIndex" json:"username"`
Email string `gorm:"size:100;not null;uniqueIndex" json:"email"`
Password string `gorm:"size:255;not null" json:"-"`
Status string `gorm:"size:20;default:active" json:"status"`
CreatedAt time.Time `gorm:"not null" json:"created_at"`
UpdatedAt time.Time `gorm:"not null" json:"updated_at"`
Metadata string `gorm:"type:json" json:"metadata,omitempty"`
// 关联
Roles []*Role `gorm:"many2many:user_roles;constraint:OnDelete:CASCADE" json:"roles,omitempty"`
Permissions []*Permission `gorm:"many2many:user_permissions;constraint:OnDelete:CASCADE" json:"permissions,omitempty"`
}
// 角色模型
type Role struct {
ID uint64 `gorm:"primaryKey" json:"id"`
Name string `gorm:"size:50;not null;uniqueIndex" json:"name"`
Code string `gorm:"size:50;not null;uniqueIndex" json:"code"`
Description string `gorm:"type:text" json:"description"`
ParentID *uint64 `gorm:"index" json:"parent_id,omitempty"`
Level int `gorm:"default:0" json:"level"`
Sort int `gorm:"default:0" json:"sort"`
IsSystem bool `gorm:"default:false" json:"is_system"`
IsActive bool `gorm:"default:true" json:"is_active"`
CreatedAt time.Time `gorm:"not null" json:"created_at"`
UpdatedAt time.Time `gorm:"not null" json:"updated_at"`
CreatedBy uint64 `json:"created_by"`
// 关联
Parent *Role `gorm:"foreignKey:ParentID" json:"parent,omitempty"`
Children []*Role `gorm:"foreignKey:ParentID" json:"children,omitempty"`
Users []*User `gorm:"many2many:user_roles;constraint:OnDelete:CASCADE" json:"users,omitempty"`
Permissions []*Permission `gorm:"many2many:role_permissions;constraint:OnDelete:CASCADE" json:"permissions,omitempty"`
}
// 权限模型
type Permission struct {
ID uint64 `gorm:"primaryKey" json:"id"`
Name string `gorm:"size:100;not null;uniqueIndex" json:"name"`
Code string `gorm:"size:100;not null;uniqueIndex" json:"code"`
Resource string `gorm:"size:100;not null;index" json:"resource"`
Action string `gorm:"size:50;not null;index" json:"action"`
Description string `gorm:"type:text" json:"description"`
Type string `gorm:"size:20;default:normal" json:"type"`
IsSystem bool `gorm:"default:false" json:"is_system"`
IsActive bool `gorm:"default:true" json:"is_active"`
CreatedAt time.Time `gorm:"not null" json:"created_at"`
UpdatedAt time.Time `gorm:"not null" json:"updated_at"`
CreatedBy uint64 `json:"created_by"`
// 关联
Roles []*Role `gorm:"many2many:role_permissions;constraint:OnDelete:CASCADE" json:"roles,omitempty"`
Users []*User `gorm:"many2many:user_permissions;constraint:OnDelete:CASCADE" json:"users,omitempty"`
}
// 资源模型
type Resource struct {
ID uint64 `gorm:"primaryKey" json:"id"`
Name string `gorm:"size:100;not null;uniqueIndex" json:"name"`
Code string `gorm:"size:100;not null;uniqueIndex" json:"code"`
Type string `gorm:"size:50;not null" json:"type"`
Path string `gorm:"size:255" json:"path"`
Description string `gorm:"type:text" json:"description"`
IsActive bool `gorm:"default:true" json:"is_active"`
CreatedAt time.Time `gorm:"not null" json:"created_at"`
UpdatedAt time.Time `gorm:"not null" json:"updated_at"`
CreatedBy uint64 `json:"created_by"`
// 关联
Permissions []*Permission `gorm:"foreignKey:ResourceID" json:"permissions,omitempty"`
}
// 权限策略
type Policy struct {
ID uint64 `gorm:"primaryKey" json:"id"`
Name string `gorm:"size:100;not null;uniqueIndex" json:"name"`
Code string `gorm:"size:100;not null;uniqueIndex" json:"code"`
Description string `gorm:"type:text" json:"description"`
Rules string `gorm:"type:json;not null" json:"rules"`
IsEnabled bool `gorm:"default:true" json:"is_enabled"`
Priority int `gorm:"default:0" json:"priority"`
CreatedAt time.Time `gorm:"not null" json:"created_at"`
UpdatedAt time.Time `gorm:"not null" json:"updated_at"`
CreatedBy uint64 `json:"created_by"`
// 关联
Users []*User `gorm:"many2many:user_policies;constraint:OnDelete:CASCADE" json:"users,omitempty"`
Roles []*Role `gorm:"many2many:role_policies;constraint:OnDelete:CASCADE" json:"roles,omitempty"`
}
// 用户策略关联表
type UserPolicy struct {
ID uint64 `gorm:"primaryKey" json:"id"`
UserID uint64 `gorm:"not null;index" json:"user_id"`
PolicyID uint64 `gorm:"not null;index" json:"policy_id"`
CreatedAt time.Time `gorm:"not null" json:"created_at"`
CreatedBy uint64 `json:"created_by"`
// 关联
User *User `gorm:"foreignKey:UserID" json:"user,omitempty"`
Policy *Policy `gorm:"foreignKey:PolicyID" json:"policy,omitempty"`
}
// 角色策略关联表
type RolePolicy struct {
ID uint64 `gorm:"primaryKey" json:"id"`
RoleID uint64 `gorm:"not null;index" json:"role_id"`
PolicyID uint64 `gorm:"not null;index" json:"policy_id"`
CreatedAt time.Time `gorm:"not null" json:"created_at"`
CreatedBy uint64 `json:"created_by"`
// 关联
Role *Role `gorm:"foreignKey:RoleID" json:"role,omitempty"`
Policy *Policy `gorm:"foreignKey:PolicyID" json:"policy,omitempty"`
}
// 访问记录
type AccessLog struct {
ID uint64 `gorm:"primaryKey" json:"id"`
UserID uint64 `gorm:"index" json:"user_id"`
Username string `gorm:"size:50" json:"username"`
Resource string `gorm:"size:100;index" json:"resource"`
Action string `gorm:"size:50;index" json:"action"`
Object string `gorm:"size:255" json:"object"`
IPAddress string `gorm:"size:45" json:"ip_address"`
UserAgent string `gorm:"size:500" json:"user_agent"`
Result string `gorm:"size:20" json:"result"`
Reason string `gorm:"size:255" json:"reason,omitempty"`
RequestID string `gorm:"size:64" json:"request_id"`
TraceID string `gorm:"size:64" json:"trace_id"`
CreatedAt time.Time `gorm:"not null;index" json:"created_at"`
// 关联
User *User `gorm:"foreignKey:UserID" json:"user,omitempty"`
}
// 角色验证方法
func (u *User) HasRole(roleCode string) bool {
for _, role := range u.Roles {
if role.Code == roleCode {
return true
}
}
return false
}
// 权限验证方法
func (u *User) HasPermission(permissionCode string) bool {
for _, permission := range u.Permissions {
if permission.Code == permissionCode {
return true
}
}
return false
}
// 检查是否有资源的特定操作权限
func (u *User) CanAccess(resource, action string) bool {
// 检查直接权限
for _, permission := range u.Permissions {
if permission.Resource == resource && permission.Action == action {
return true
}
}
// 检查角色权限
for _, role := range u.Roles {
for _, permission := range role.Permissions {
if permission.Resource == resource && permission.Action == action {
return true
}
}
}
return false
}
// 检查是否为管理员
func (u *User) IsAdmin() bool {
return u.HasRole("admin") || u.HasRole("administrator")
}
// 检查是否为超级管理员
func (u *User) IsSuperAdmin() bool {
return u.HasRole("super_admin")
}
// 角色验证方法
func (r *Role) HasPermission(permissionCode string) bool {
for _, permission := range r.Permissions {
if permission.Code == permissionCode {
return true
}
}
return false
}
// 检查角色是否为系统角色
func (r *Role) IsSystem() bool {
return r.IsSystem
}
// 获取角色所有子角色(递归)
func (r *Role) GetAllChildren() []*Role {
var children []*Role
for _, child := range r.Children {
children = append(children, child)
children = append(children, child.GetAllChildren()...)
}
return children
}
// 检查角色是否继承自指定父角色
func (r *Role) InheritsFrom(parentCode string) bool {
current := r.Parent
for current != nil {
if current.Code == parentCode {
return true
}
current = current.Parent
}
return false
}
---
b.权限验证器
a.权限检查
检查用户是否有特定权限。
b.角色验证
检查用户是否具有特定角色。
c.资源访问控制
控制用户对资源的访问。
d.权限验证器示例
---
// rbac/validator.go
package rbac
import (
"context"
"fmt"
"strings"
"sync"
"time"
"github.com/go-redis/redis/v8"
"gorm.io/gorm"
)
// 权限验证器接口
interface PermissionValidator {
// 基础权限检查
HasPermission(ctx context.Context, userID uint64, permission string) (bool, error)
HasRole(ctx context.Context, userID uint64, role string) (bool, error)
CanAccess(ctx context.Context, userID uint64, resource, action string) (bool, error)
// 批量权限检查
HasPermissions(ctx context.Context, userID uint64, permissions []string) (map[string]bool, error)
HasRoles(ctx context.Context, userID uint64, roles []string) (map[string]bool, error)
// 高级权限检查
CheckPolicy(ctx context.Context, userID uint64, resource, action string, object interface{}) (bool, error)
EvaluateRules(ctx context.Context, userID uint64, rules []Rule) (bool, error)
// 缓存管理
InvalidateUserCache(ctx context.Context, userID uint64) error
WarmupUserCache(ctx context.Context, userID uint64) error
// 统计信息
GetValidationStats(ctx context.Context) (*ValidationStats, error)
}
// 规则接口
interface Rule {
Evaluate(ctx context.Context, user *User, resource, action string, object interface{}) (bool, error)
GetName() string
GetDescription() string
}
// 权限验证器实现
type PermissionValidatorImpl struct {
db *gorm.DB
cache *redis.Client
config *ValidatorConfig
ruleEngine RuleEngine
logger Logger
stats *ValidationStats
mu sync.RWMutex
}
// 验证器配置
type ValidatorConfig struct {
CacheEnabled bool `yaml:"cache_enabled"`
CacheTTL time.Duration `yaml:"cache_ttl"`
CachePrefix string `yaml:"cache_prefix"`
EnablePolicyEngine bool `yaml:"enable_policy_engine"`
EnableAuditLog bool `yaml:"enable_audit_log"`
MaxCacheSize int `yaml:"max_cache_size"`
CacheCleanupInterval time.Duration `yaml:"cache_cleanup_interval"`
DefaultDeny bool `yaml:"default_deny"`
EnableInheritance bool `yaml:"enable_inheritance"`
PolicyEvaluationMode string `yaml:"policy_evaluation_mode"`
}
// 验证统计
type ValidationStats struct {
TotalChecks int64 `json:"total_checks"`
CacheHits int64 `json:"cache_hits"`
CacheMisses int64 `json:"cache_misses"`
PermissionChecks int64 `json:"permission_checks"`
RoleChecks int64 `json:"role_checks"`
PolicyEvaluations int64 `json:"policy_evaluations"`
AccessGranted int64 `json:"access_granted"`
AccessDenied int64 `json:"access_denied"`
AvgResponseTime time.Duration `json:"avg_response_time"`
LastCleanupTime time.Time `json:"last_cleanup_time"`
mu sync.RWMutex
}
// 创建权限验证器
func NewPermissionValidator(
db *gorm.DB,
cache *redis.Client,
config *ValidatorConfig,
logger Logger,
) *PermissionValidatorImpl {
if config == nil {
config = &ValidatorConfig{
CacheEnabled: true,
CacheTTL: 5 * time.Minute,
CachePrefix: "rbac:",
EnablePolicyEngine: true,
EnableAuditLog: true,
MaxCacheSize: 10000,
CacheCleanupInterval: 10 * time.Minute,
DefaultDeny: true,
EnableInheritance: true,
PolicyEvaluationMode: "deny_overrides",
}
}
validator := &PermissionValidatorImpl{
db: db,
cache: cache,
config: config,
ruleEngine: NewRuleEngine(),
logger: logger,
stats: &ValidationStats{},
}
// 启动缓存清理协程
if config.CacheEnabled && config.CacheCleanupInterval > 0 {
go validator.startCacheCleanup()
}
return validator
}
// 检查用户是否有权限
func (v *PermissionValidatorImpl) HasPermission(ctx context.Context, userID uint64, permission string) (bool, error) {
start := time.Now()
defer func() {
v.recordResponseTime(time.Since(start))
}()
// 检查缓存
if v.config.CacheEnabled {
cached, err := v.getPermissionFromCache(ctx, userID, permission)
if err == nil && cached != nil {
v.stats.CacheHits++
return *cached, nil
}
v.stats.CacheMisses++
}
// 从数据库查询
hasPermission, err := v.checkPermissionFromDB(ctx, userID, permission)
if err != nil {
v.logger.Error("Failed to check permission from DB",
Uint64("user_id", userID),
String("permission", permission),
Error("error", err))
return v.config.DefaultDeny, err
}
// 更新缓存
if v.config.CacheEnabled {
v.setPermissionToCache(ctx, userID, permission, hasPermission)
}
v.stats.PermissionChecks++
if hasPermission {
v.stats.AccessGranted++
} else {
v.stats.AccessDenied++
}
return hasPermission, nil
}
// 批量检查权限
func (v *PermissionValidatorImpl) HasPermissions(ctx context.Context, userID uint64, permissions []string) (map[string]bool, error) {
results := make(map[string]bool)
var missingPermissions []string
// 首先检查缓存
if v.config.CacheEnabled {
for _, permission := range permissions {
cached, err := v.getPermissionFromCache(ctx, userID, permission)
if err == nil && cached != nil {
results[permission] = *cached
v.stats.CacheHits++
} else {
missingPermissions = append(missingPermissions, permission)
v.stats.CacheMisses++
}
}
} else {
missingPermissions = permissions
}
// 从数据库查询缺失的权限
if len(missingPermissions) > 0 {
dbResults, err := v.checkPermissionsFromDB(ctx, userID, missingPermissions)
if err != nil {
v.logger.Error("Failed to check permissions from DB",
Uint64("user_id", userID),
Strings("permissions", missingPermissions),
Error("error", err))
return results, err
}
for permission, hasPermission := range dbResults {
results[permission] = hasPermission
// 更新缓存
if v.config.CacheEnabled {
v.setPermissionToCache(ctx, userID, permission, hasPermission)
}
}
}
v.stats.PermissionChecks += int64(len(permissions))
return results, nil
}
// 检查用户角色
func (v *PermissionValidatorImpl) HasRole(ctx context.Context, userID uint64, role string) (bool, error) {
start := time.Now()
defer func() {
v.recordResponseTime(time.Since(start))
}()
// 检查缓存
if v.config.CacheEnabled {
cached, err := v.getRoleFromCache(ctx, userID, role)
if err == nil && cached != nil {
v.stats.CacheHits++
return *cached, nil
}
v.stats.CacheMisses++
}
// 从数据库查询
hasRole, err := v.checkRoleFromDB(ctx, userID, role)
if err != nil {
v.logger.Error("Failed to check role from DB",
Uint64("user_id", userID),
String("role", role),
Error("error", err))
return false, err
}
// 更新缓存
if v.config.CacheEnabled {
v.setRoleToCache(ctx, userID, role, hasRole)
}
v.stats.RoleChecks++
return hasRole, nil
}
// 批量检查角色
func (v *PermissionValidatorImpl) HasRoles(ctx context.Context, userID uint64, roles []string) (map[string]bool, error) {
results := make(map[string]bool)
var missingRoles []string
// 首先检查缓存
if v.config.CacheEnabled {
for _, role := range roles {
cached, err := v.getRoleFromCache(ctx, userID, role)
if err == nil && cached != nil {
results[role] = *cached
v.stats.CacheHits++
} else {
missingRoles = append(missingRoles, role)
v.stats.CacheMisses++
}
}
} else {
missingRoles = roles
}
// 从数据库查询缺失的角色
if len(missingRoles) > 0 {
dbResults, err := v.checkRolesFromDB(ctx, userID, missingRoles)
if err != nil {
v.logger.Error("Failed to check roles from DB",
Uint64("user_id", userID),
Strings("roles", missingRoles),
Error("error", err))
return results, err
}
for role, hasRole := range dbResults {
results[role] = hasRole
// 更新缓存
if v.config.CacheEnabled {
v.setRoleToCache(ctx, userID, role, hasRole)
}
}
}
v.stats.RoleChecks += int64(len(roles))
return results, nil
}
// 检查资源访问权限
func (v *PermissionValidatorImpl) CanAccess(ctx context.Context, userID uint64, resource, action string) (bool, error) {
start := time.Now()
defer func() {
v.recordResponseTime(time.Since(start))
}()
// 构建权限代码
permissionCode := fmt.Sprintf("%s:%s", resource, action)
// 检查直接权限
hasPermission, err := v.HasPermission(ctx, userID, permissionCode)
if err != nil {
return v.config.DefaultDeny, err
}
if hasPermission {
return true, nil
}
// 如果启用继承,检查父级权限
if v.config.EnableInheritance {
parentPermissions := v.getParentPermissions(resource, action)
for _, parentPermission := range parentPermissions {
if hasPermission, err := v.HasPermission(ctx, userID, parentPermission); err != nil {
continue
} else if hasPermission {
return true, nil
}
}
}
// 检查通配符权限
wildcardPermission := fmt.Sprintf("%s:*", resource)
if hasPermission, err := v.HasPermission(ctx, userID, wildcardPermission); err == nil && hasPermission {
return true, nil
}
allResourcePermission := fmt.Sprintf("*:%s", action)
if hasPermission, err := v.HasPermission(ctx, userID, allResourcePermission); err == nil && hasPermission {
return true, nil
}
// 检查超级权限
if hasPermission, err := v.HasPermission(ctx, userID, "*:*"); err == nil && hasPermission {
return true, nil
}
return v.config.DefaultDeny, nil
}
// 策略评估
func (v *PermissionValidatorImpl) CheckPolicy(ctx context.Context, userID uint64, resource, action string, object interface{}) (bool, error) {
if !v.config.EnablePolicyEngine {
return v.CanAccess(ctx, userID, resource, action)
}
start := time.Now()
defer func() {
v.recordResponseTime(time.Since(start))
}()
// 获取用户信息
user, err := v.getUser(ctx, userID)
if err != nil {
v.logger.Error("Failed to get user for policy evaluation",
Uint64("user_id", userID),
Error("error", err))
return v.config.DefaultDeny, err
}
// 评估策略
result, err := v.ruleEngine.Evaluate(ctx, user, resource, action, object)
if err != nil {
v.logger.Error("Policy evaluation failed",
Uint64("user_id", userID),
String("resource", resource),
String("action", action),
Error("error", err))
return v.config.DefaultDeny, err
}
v.stats.PolicyEvaluations++
return result, nil
}
// 规则评估
func (v *PermissionValidatorImpl) EvaluateRules(ctx context.Context, userID uint64, rules []Rule) (bool, error) {
user, err := v.getUser(ctx, userID)
if err != nil {
return v.config.DefaultDeny, err
}
for _, rule := range rules {
result, err := rule.Evaluate(ctx, user, "", "", nil)
if err != nil {
v.logger.Error("Rule evaluation failed",
String("rule", rule.GetName()),
Error("error", err))
continue
}
// 根据评估模式处理结果
if v.config.PolicyEvaluationMode == "deny_overrides" && !result {
return false, nil
} else if v.config.PolicyEvaluationMode == "allow_overrides" && result {
return true, nil
}
}
return !v.config.DefaultDeny, nil
}
// 从数据库检查权限
func (v *PermissionValidatorImpl) checkPermissionFromDB(ctx context.Context, userID uint64, permission string) (bool, error) {
var count int64
// 检查直接权限
err := v.db.WithContext(ctx).Table("user_permissions").
Joins("JOIN permissions ON user_permissions.permission_id = permissions.id").
Where("user_permissions.user_id = ? AND permissions.code = ? AND permissions.is_active = ?", userID, permission, true).
Count(&count).Error
if err != nil {
return false, err
}
if count > 0 {
return true, nil
}
// 检查角色权限
err = v.db.WithContext(ctx).Table("user_roles").
Joins("JOIN role_permissions ON user_roles.role_id = role_permissions.role_id").
Joins("JOIN permissions ON role_permissions.permission_id = permissions.id").
Where("user_roles.user_id = ? AND permissions.code = ? AND user_roles.is_active = ? AND permissions.is_active = ?", userID, permission, true, true).
Count(&count).Error
if err != nil {
return false, err
}
return count > 0, nil
}
// 从数据库批量检查权限
func (v *PermissionValidatorImpl) checkPermissionsFromDB(ctx context.Context, userID uint64, permissions []string) (map[string]bool, error) {
results := make(map[string]bool)
// 检查直接权限
var directPermissions []struct {
Code string `json:"code"`
}
err := v.db.WithContext(ctx).Table("user_permissions").
Joins("JOIN permissions ON user_permissions.permission_id = permissions.id").
Where("user_permissions.user_id = ? AND permissions.code IN ? AND permissions.is_active = ?", userID, permissions, true).
Select("permissions.code").
Find(&directPermissions).Error
if err != nil {
return results, err
}
for _, perm := range directPermissions {
results[perm.Code] = true
}
// 检查角色权限
var rolePermissions []struct {
Code string `json:"code"`
}
err = v.db.WithContext(ctx).Table("user_roles").
Joins("JOIN role_permissions ON user_roles.role_id = role_permissions.role_id").
Joins("JOIN permissions ON role_permissions.permission_id = permissions.id").
Where("user_roles.user_id = ? AND permissions.code IN ? AND user_roles.is_active = ? AND permissions.is_active = ?", userID, permissions, true, true).
Select("DISTINCT permissions.code").
Find(&rolePermissions).Error
if err != nil {
return results, err
}
for _, perm := range rolePermissions {
results[perm.Code] = true
}
return results, nil
}
// 从数据库检查角色
func (v *PermissionValidatorImpl) checkRoleFromDB(ctx context.Context, userID uint64, role string) (bool, error) {
var count int64
err := v.db.WithContext(ctx).Table("user_roles").
Joins("JOIN roles ON user_roles.role_id = roles.id").
Where("user_roles.user_id = ? AND roles.code = ? AND roles.is_active = ?", userID, role, true).
Count(&count).Error
if err != nil {
return false, err
}
return count > 0, nil
}
// 从数据库批量检查角色
func (v *PermissionValidatorImpl) checkRolesFromDB(ctx context.Context, userID uint64, roles []string) (map[string]bool, error) {
results := make(map[string]bool)
var userRoles []struct {
Code string `json:"code"`
}
err := v.db.WithContext(ctx).Table("user_roles").
Joins("JOIN roles ON user_roles.role_id = roles.id").
Where("user_roles.user_id = ? AND roles.code IN ? AND roles.is_active = ?", userID, roles, true).
Select("roles.code").
Find(&userRoles).Error
if err != nil {
return results, err
}
for _, role := range userRoles {
results[role.Code] = true
}
return results, nil
}
// 获取用户信息
func (v *PermissionValidatorImpl) getUser(ctx context.Context, userID uint64) (*User, error) {
var user User
err := v.db.WithContext(ctx).
Preload("Roles").
Preload("Roles.Permissions").
Preload("Permissions").
First(&user, userID).Error
if err != nil {
return nil, err
}
return &user, nil
}
// 获取父级权限
func (v *PermissionValidatorImpl) getParentPermissions(resource, action string) []string {
// 简化实现,实际应该根据资源层次结构计算
parts := strings.Split(resource, ".")
if len(parts) <= 1 {
return nil
}
parentResource := strings.Join(parts[:len(parts)-1], ".")
return []string{
fmt.Sprintf("%s:%s", parentResource, action),
}
}
// 缓存操作
func (v *PermissionValidatorImpl) getPermissionFromCache(ctx context.Context, userID uint64, permission string) (*bool, error) {
key := fmt.Sprintf("%spermission:%d:%s", v.config.CachePrefix, userID, permission)
val, err := v.cache.Get(ctx, key).Result()
if err != nil {
return nil, err
}
if val == "" {
return nil, nil
}
var result bool
err = json.Unmarshal([]byte(val), &result)
return &result, err
}
func (v *PermissionValidatorImpl) setPermissionToCache(ctx context.Context, userID uint64, permission string, hasPermission bool) {
key := fmt.Sprintf("%spermission:%d:%s", v.config.CachePrefix, userID, permission)
data, _ := json.Marshal(hasPermission)
v.cache.Set(ctx, key, string(data), v.config.CacheTTL)
}
func (v *PermissionValidatorImpl) getRoleFromCache(ctx context.Context, userID uint64, role string) (*bool, error) {
key := fmt.Sprintf("%srole:%d:%s", v.config.CachePrefix, userID, role)
val, err := v.cache.Get(ctx, key).Result()
if err != nil {
return nil, err
}
if val == "" {
return nil, nil
}
var result bool
err = json.Unmarshal([]byte(val), &result)
return &result, err
}
func (v *PermissionValidatorImpl) setRoleToCache(ctx context.Context, userID uint64, role string, hasRole bool) {
key := fmt.Sprintf("%srole:%d:%s", v.config.CachePrefix, userID, role)
data, _ := json.Marshal(hasRole)
v.cache.Set(ctx, key, string(data), v.config.CacheTTL)
}
// 清除用户缓存
func (v *PermissionValidatorImpl) InvalidateUserCache(ctx context.Context, userID uint64) error {
pattern := fmt.Sprintf("%s*:%d:*", v.config.CachePrefix, userID)
keys, err := v.cache.Keys(ctx, pattern).Result()
if err != nil {
return err
}
if len(keys) > 0 {
return v.cache.Del(ctx, keys...).Err()
}
return nil
}
// 预热用户缓存
func (v *PermissionValidatorImpl) WarmupUserCache(ctx context.Context, userID uint64) error {
user, err := v.getUser(ctx, userID)
if err != nil {
return err
}
// 预热角色缓存
for _, role := range user.Roles {
v.setRoleToCache(ctx, userID, role.Code, true)
}
// 预热权限缓存
for _, permission := range user.Permissions {
v.setPermissionToCache(ctx, userID, permission.Code, true)
}
return nil
}
// 启动缓存清理
func (v *PermissionValidatorImpl) startCacheCleanup() {
ticker := time.NewTicker(v.config.CacheCleanupInterval)
defer ticker.Stop()
for range ticker.C {
v.cleanupExpiredCache()
}
}
// 清理过期缓存
func (v *PermissionValidatorImpl) cleanupExpiredCache() {
// 这里实现清理逻辑,例如清理过期的访问日志等
v.stats.LastCleanupTime = time.Now()
}
// 记录响应时间
func (v *PermissionValidatorImpl) recordResponseTime(duration time.Duration) {
v.mu.Lock()
defer v.mu.Unlock()
v.stats.TotalChecks++
total := v.stats.AvgResponseTime * time.Duration(v.stats.TotalChecks-1)
v.stats.AvgResponseTime = (total + duration) / time.Duration(v.stats.TotalChecks)
}
// 获取验证统计
func (v *PermissionValidatorImpl) GetValidationStats(ctx context.Context) (*ValidationStats, error) {
v.mu.RLock()
defer v.mu.RUnlock()
// 复制统计信息
stats := &ValidationStats{
TotalChecks: v.stats.TotalChecks,
CacheHits: v.stats.CacheHits,
CacheMisses: v.stats.CacheMisses,
PermissionChecks: v.stats.PermissionChecks,
RoleChecks: v.stats.RoleChecks,
PolicyEvaluations: v.stats.PolicyEvaluations,
AccessGranted: v.stats.AccessGranted,
AccessDenied: v.stats.AccessDenied,
AvgResponseTime: v.stats.AvgResponseTime,
LastCleanupTime: v.stats.LastCleanupTime,
}
return stats, nil
}
// 记录访问日志
func (v *PermissionValidatorImpl) logAccess(ctx context.Context, userID uint64, resource, action, object, result, reason string) {
if !v.config.EnableAuditLog {
return
}
username := ""
user, err := v.getUser(ctx, userID)
if err == nil {
username = user.Username
}
accessLog := &AccessLog{
UserID: userID,
Username: username,
Resource: resource,
Action: action,
Object: object,
IPAddress: getIPAddressFromContext(ctx),
UserAgent: getUserAgentFromContext(ctx),
Result: result,
Reason: reason,
RequestID: getRequestIDFromContext(ctx),
TraceID: getTraceIDFromContext(ctx),
CreatedAt: time.Now(),
}
// 异步写入数据库
go func() {
v.db.Create(accessLog)
}()
}
---
6.4 自定义Codec
01.编解码器概述
a.编解码器接口定义
a.功能说明
Codec是go-micro中负责数据序列化和反序列化的核心组件,用于在网络传输前后对数据进行编码和解码操作。go-micro内置支持多种编解码格式,同时提供自定义Codec接口,允许开发者实现特定的序列化方案。
b.核心特性
多格式支持JSON、Protobuf、Msgpack、XML等,自定义扩展支持实现自定义编解码逻辑,性能优化可选择高性能序列化方案,版本兼容支持数据格式版本演进,压缩集成内置数据压缩功能,类型安全强类型数据绑定和验证。
b.编解码器接口设计
---
// codec/interface.go
package codec
import (
"context"
"io"
"reflect"
)
// Codec 编解码器接口
type Codec interface {
// 编码接口
Marshal(ctx context.Context, v interface{}) ([]byte, error)
MarshalToWriter(ctx context.Context, v interface{}, w io.Writer) error
// 解码接口
Unmarshal(ctx context.Context, data []byte, v interface{}) error
UnmarshalFromReader(ctx context.Context, r io.Reader, v interface{}) error
// 流式编解码
NewEncoder(w io.Writer) Encoder
NewDecoder(r io.Reader) Decoder
// 元数据信息
Name() string
ContentType() string
Version() string
// 配置管理
Configure(options map[string]interface{}) error
GetOptions() map[string]interface{}
}
// Encoder 流式编码器接口
type Encoder interface {
Encode(v interface{}) error
Close() error
}
// Decoder 流式解码器接口
type Decoder interface {
Decode(v interface{}) error
Close() error
}
// CodecFactory 编解码器工厂接口
type CodecFactory interface {
NewCodec(options map[string]interface{}) (Codec, error)
GetSupportedTypes() []string
GetDefaultOptions() map[string]interface{}
}
---
02.JSON编解码器实现
a.基础JSON Codec
---
// codec/json.go
package codec
import (
"context"
"encoding/json"
"io"
)
// JSONCodec JSON编解码器
type JSONCodec struct {
options *JSONOptions
}
// JSONOptions JSON编解码器选项
type JSONOptions struct {
EscapeHTML bool `json:"escape_html"`
Indent string `json:"indent"`
SortKeys bool `json:"sort_keys"`
UseNumber bool `json:"use_number"`
DisallowUnknown bool `json:"disallow_unknown"`
CustomTags map[string]string `json:"custom_tags"`
TypeRegistry map[string]reflect.Type `json:"-"`
Compression CompressionType `json:"compression"`
}
// CompressionType 压缩类型
type CompressionType string
const (
CompressionNone CompressionType = "none"
CompressionGzip CompressionType = "gzip"
CompressionLZ4 CompressionType = "lz4"
CompressionSnappy CompressionType = "snappy"
)
// NewJSONCodec 创建JSON编解码器
func NewJSONCodec(options map[string]interface{}) (Codec, error) {
opts := &JSONOptions{
EscapeHTML: true,
SortKeys: false,
UseNumber: false,
DisallowUnknown: false,
Compression: CompressionNone,
CustomTags: make(map[string]string),
TypeRegistry: make(map[string]reflect.Type),
}
// 应用选项配置
if err := applyOptions(options, opts); err != nil {
return nil, err
}
return &JSONCodec{options: opts}, nil
}
// Marshal JSON编码
func (j *JSONCodec) Marshal(ctx context.Context, v interface{}) ([]byte, error) {
var data []byte
var err error
// 使用自定义配置
if j.options.Indent != "" {
data, err = json.MarshalIndent(v, "", j.options.Indent)
} else {
data, err = json.Marshal(v)
}
if err != nil {
return nil, err
}
// 应用压缩
if j.options.Compression != CompressionNone {
data, err = compressData(j.options.Compression, data)
if err != nil {
return nil, err
}
}
return data, nil
}
// MarshalToWriter 写入到流
func (j *JSONCodec) MarshalToWriter(ctx context.Context, v interface{}, w io.Writer) error {
data, err := j.Marshal(ctx, v)
if err != nil {
return err
}
_, err = w.Write(data)
return err
}
// Unmarshal JSON解码
func (j *JSONCodec) Unmarshal(ctx context.Context, data []byte, v interface{}) error {
// 解压数据
if j.options.Compression != CompressionNone {
decompressed, err := decompressData(j.options.Compression, data)
if err != nil {
return err
}
data = decompressed
}
// 使用自定义解码器
decoder := json.NewDecoder(bytes.NewReader(data))
decoder.UseNumber = j.options.UseNumber
return decoder.Decode(v)
}
// Name 编解码器名称
func (j *JSONCodec) Name() string {
return "json"
}
// ContentType 内容类型
func (j *JSONCodec) ContentType() string {
return "application/json"
}
// Version 版本信息
func (j *JSONCodec) Version() string {
return "1.0.0"
}
// Configure 配置编解码器
func (j *JSONCodec) Configure(options map[string]interface{}) error {
return applyOptions(options, j.options)
}
// GetOptions 获取配置选项
func (j *JSONCodec) GetOptions() map[string]interface{} {
return map[string]interface{}{
"escape_html": j.options.EscapeHTML,
"indent": j.options.Indent,
"sort_keys": j.options.SortKeys,
"use_number": j.options.UseNumber,
"disallow_unknown": j.options.DisallowUnknown,
"compression": string(j.options.Compression),
}
}
---
03.Protobuf编解码器
a.Protobuf Codec实现
---
// codec/protobuf.go
package codec
import (
"context"
"encoding/json"
"io"
"google.golang.org/protobuf/proto"
)
// ProtobufCodec Protobuf编解码器
type ProtobufCodec struct {
options *ProtobufOptions
}
// ProtobufOptions Protobuf编解码器选项
type ProtobufOptions struct {
UseJSONFormat bool `json:"use_json_format"`
ValidationEnabled bool `json:"validation_enabled"`
MaxMessageSize int64 `json:"max_message_size"`
Compression CompressionType `json:"compression"`
TypeMapping map[string]string `json:"type_mapping"`
}
// NewProtobufCodec 创建Protobuf编解码器
func NewProtobufCodec(options map[string]interface{}) (Codec, error) {
opts := &ProtobufOptions{
UseJSONFormat: false,
ValidationEnabled: true,
MaxMessageSize: 10 * 1024 * 1024, // 10MB
Compression: CompressionNone,
TypeMapping: make(map[string]string),
}
if err := applyProtobufOptions(options, opts); err != nil {
return nil, err
}
return &ProtobufCodec{options: opts}, nil
}
// Marshal Protobuf编码
func (p *ProtobufCodec) Marshal(ctx context.Context, v interface{}) ([]byte, error) {
msg, ok := v.(proto.Message)
if !ok {
return nil, ErrNotProtobufMessage
}
var data []byte
var err error
if p.options.UseJSONFormat {
// 使用JSON格式
data, err = json.Marshal(msg)
} else {
// 使用二进制格式
data, err = proto.Marshal(msg)
}
if err != nil {
return nil, err
}
// 检查消息大小
if p.options.MaxMessageSize > 0 && int64(len(data)) > p.options.MaxMessageSize {
return nil, ErrMessageTooLarge
}
// 应用压缩
if p.options.Compression != CompressionNone {
data, err = compressData(p.options.Compression, data)
if err != nil {
return nil, err
}
}
return data, nil
}
// Unmarshal Protobuf解码
func (p *ProtobufCodec) Unmarshal(ctx context.Context, data []byte, v interface{}) error {
// 解压数据
if p.options.Compression != CompressionNone {
decompressed, err := decompressData(p.options.Compression, data)
if err != nil {
return err
}
data = decompressed
}
msg, ok := v.(proto.Message)
if !ok {
return ErrNotProtobufMessage
}
var err error
if p.options.UseJSONFormat {
// 使用JSON格式
err = json.Unmarshal(data, msg)
} else {
// 使用二进制格式
err = proto.Unmarshal(data, msg)
}
return err
}
// Name 编解码器名称
func (p *ProtobufCodec) Name() string {
return "protobuf"
}
// ContentType 内容类型
func (p *ProtobufCodec) ContentType() string {
if p.options.UseJSONFormat {
return "application/json"
}
return "application/x-protobuf"
}
// Version 版本信息
func (p *ProtobufCodec) Version() string {
return "1.0.0"
}
---
04.编解码器管理
a.编解码器注册中心
---
// codec/manager.go
package codec
import (
"context"
"errors"
"sync"
)
// Manager 编解码器管理器
type Manager struct {
codecs map[string]CodecFactory
defaults map[string]string
mu sync.RWMutex
logger Logger
}
// NewManager 创建编解码器管理器
func NewManager(logger Logger) *Manager {
m := &Manager{
codecs: make(map[string]CodecFactory),
defaults: make(map[string]string),
logger: logger,
}
// 注册内置编解码器
m.registerBuiltinCodecs()
return m
}
// registerBuiltinCodecs 注册内置编解码器
func (m *Manager) registerBuiltinCodecs() {
// 注册JSON编解码器
m.RegisterFactory("json", &JSONFactory{})
m.SetDefault("json", "json")
// 注册Protobuf编解码器
m.RegisterFactory("protobuf", &ProtobufFactory{})
// 注册Msgpack编解码器
m.RegisterFactory("msgpack", &MsgpackFactory{})
}
// RegisterFactory 注册编解码器工厂
func (m *Manager) RegisterFactory(name string, factory CodecFactory) {
m.mu.Lock()
defer m.mu.Unlock()
m.codecs[name] = factory
m.logger.Debug("Codec factory registered", String("name", name))
}
// GetCodec 获取编解码器
func (m *Manager) GetCodec(name string, options map[string]interface{}) (Codec, error) {
m.mu.RLock()
defer m.mu.RUnlock()
factory, exists := m.codecs[name]
if !exists {
return nil, ErrCodecNotFound
}
return factory.NewCodec(options)
}
// GetDefaultCodec 获取默认编解码器
func (m *Manager) GetDefaultCodec(contentType string, options map[string]interface{}) (Codec, error) {
name := m.getDefaultCodecName(contentType)
if name == "" {
name = "json" // 默认使用JSON
}
return m.GetCodec(name, options)
}
// SetDefault 设置默认编解码器
func (m *Manager) SetDefault(contentType, codecName string) {
m.mu.Lock()
defer m.mu.Unlock()
m.defaults[contentType] = codecName
}
// getDefaultCodecName 获取默认编解码器名称
func (m *Manager) getDefaultCodecName(contentType string) string {
if name, exists := m.defaults[contentType]; exists {
return name
}
// 根据内容类型推断
switch contentType {
case "application/json":
return "json"
case "application/x-protobuf":
return "protobuf"
case "application/x-msgpack":
return "msgpack"
default:
return "json"
}
}
// 错误定义
var (
ErrCodecNotFound = errors.New("codec not found")
ErrNotProtobufMessage = errors.New("value is not a protobuf message")
ErrMessageTooLarge = errors.New("message size exceeds limit")
)
---
6.5 监控与链路追踪
01.监控系统架构
a.监控组件概述
a.功能说明
go-micro的监控系统提供全面的服务可观测性,包括指标收集、分布式追踪、日志聚合和健康检查等功能。监控系统采用插件化架构,支持多种监控后端和追踪标准,为微服务提供完整的运维支持。
b.核心组件
Metrics Collection指标收集器收集性能和业务指标,Distributed Tracing分布式追踪跟踪请求链路,Log Aggregation日志聚合集中管理服务日志,Health Checking健康检查监控服务状态,Alert Management告警管理异常情况及时通知,Visualization可视化界面监控数据展示。
b.监控接口设计
---
// monitor/interface.go
package monitor
import (
"context"
"time"
)
// Monitor 监控接口
type Monitor interface {
// 指标收集
Counter(name string, tags map[string]string) Counter
Gauge(name string, tags map[string]string) Gauge
Histogram(name string, tags map[string]string) Histogram
Summary(name string, tags map[string]string) Summary
// 追踪功能
StartSpan(ctx context.Context, operationName string) (Span, context.Context)
Inject(span Span, headers map[string]string) error
Extract(headers map[string]string) (Span, error)
// 日志记录
Logger(name string) Logger
// 健康检查
RegisterHealthCheck(name string, checker HealthChecker) error
UnregisterHealthCheck(name string) error
// 生命周期管理
Start(ctx context.Context) error
Stop(ctx context.Context) error
}
// Counter 计数器接口
type Counter interface {
Inc()
Add(value float64)
WithTags(tags map[string]string) Counter
}
// Gauge 仪表盘接口
type Gauge interface {
Set(value float64)
Inc()
Dec()
WithTags(tags map[string]string) Gauge
}
// Histogram 直方图接口
type Histogram interface {
Observe(value float64)
WithTags(tags map[string]string) Histogram
}
// Summary 摘要接口
type Summary interface {
Observe(value float64)
WithTags(tags map[string]string) Summary
}
// Span 追踪跨度接口
type Span interface {
SetOperationName(operationName string)
SetTag(key string, value interface{})
SetBaggageItem(key, value string)
Finish()
FinishWithOptions(opts FinishOptions)
Context() SpanContext
}
// SpanContext 跨度上下文
type SpanContext interface {
TraceID() string
SpanID() string
BaggageItems() map[string]string
WithTraceID(traceID string) SpanContext
WithSpanID(spanID string) SpanContext
}
// Logger 日志接口
type Logger interface {
Debug(msg string, fields ...Field)
Info(msg string, fields ...Field)
Warn(msg string, fields ...Field)
Error(msg string, fields ...Field)
Fatal(msg string, fields ...Field)
With(fields ...Field) Logger
}
// HealthChecker 健康检查接口
type HealthChecker interface {
Name() string
Check(ctx context.Context) HealthStatus
}
// HealthStatus 健康状态
type HealthStatus struct {
Status string `json:"status"` // healthy, unhealthy, unknown
Message string `json:"message,omitempty"`
Details map[string]interface{} `json:"details,omitempty"`
Time time.Time `json:"time"`
}
// FinishOptions 完成选项
type FinishOptions struct {
FinishTime time.Time
LogData map[string]interface{}
Error error
}
// Field 日志字段
type Field struct {
Key string
Value interface{}
}
---
02.Prometheus指标收集
a.Prometheus监控实现
---
// monitor/prometheus.go
package monitor
import (
"context"
"fmt"
"sync"
"time"
"github.com/prometheus/client_golang/api"
v1 "github.com/prometheus/client_golang/api/prometheus/v1"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prometheus/client_golang/prometheus/push"
)
// PrometheusMonitor Prometheus监控实现
type PrometheusMonitor struct {
config *PrometheusConfig
registry *prometheus.Registry
counters map[string]*prometheus.CounterVec
gauges map[string]*prometheus.GaugeVec
histograms map[string]*prometheus.HistogramVec
summaries map[string]*prometheus.SummaryVec
mu sync.RWMutex
logger Logger
pusher *push.Pusher
}
// PrometheusConfig Prometheus配置
type PrometheusConfig struct {
Enabled bool `yaml:"enabled"`
ServerAddress string `yaml:"server_address"`
Namespace string `yaml:"namespace"`
Subsystem string `yaml:"subsystem"`
PushEnabled bool `yaml:"push_enabled"`
PushAddress string `yaml:"push_address"`
PushInterval time.Duration `yaml:"push_interval"`
Buckets []float64 `yaml:"buckets"`
Objectives map[float64]float64 `yaml:"objectives"`
DefaultLabels map[string]string `yaml:"default_labels"`
EnableHistogram bool `yaml:"enable_histogram"`
EnableSummary bool `yaml:"enable_summary"`
}
// NewPrometheusMonitor 创建Prometheus监控
func NewPrometheusMonitor(config *PrometheusConfig, logger Logger) *PrometheusMonitor {
if config == nil {
config = &PrometheusConfig{
Enabled: true,
Namespace: "gomicro",
Subsystem: "service",
PushEnabled: false,
PushInterval: 30 * time.Second,
Buckets: prometheus.DefBuckets,
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
DefaultLabels: make(map[string]string),
EnableHistogram: true,
EnableSummary: true,
}
}
monitor := &PrometheusMonitor{
config: config,
registry: prometheus.NewRegistry(),
counters: make(map[string]*prometheus.CounterVec),
gauges: make(map[string]*prometheus.GaugeVec),
histograms: make(map[string]*prometheus.HistogramVec),
summaries: make(map[string]*prometheus.SummaryVec),
logger: logger,
}
// 注册默认指标
monitor.registerDefaultMetrics()
return monitor
}
// registerDefaultMetrics 注册默认指标
func (pm *PrometheusMonitor) registerDefaultMetrics() {
// Go运行时指标
pm.registry.MustRegister(prometheus.NewGoMetricsCollector())
// 进程指标
pm.registry.MustRegister(prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{
Namespace: pm.config.Namespace,
Subsystem: pm.config.Subsystem,
}))
// 自定义默认指标
pm.Counter("requests_total", map[string]string{
"service": pm.config.Subsystem,
"method": "total",
})
pm.Counter("errors_total", map[string]string{
"service": pm.config.Subsystem,
"type": "total",
})
pm.Histogram("request_duration_seconds", map[string]string{
"service": pm.config.Subsystem,
})
}
// Counter 创建计数器
func (pm *PrometheusMonitor) Counter(name string, tags map[string]string) Counter {
pm.mu.Lock()
defer pm.mu.Unlock()
key := pm.buildMetricKey(name, tags)
if counter, exists := pm.counters[key]; exists {
return &PrometheusCounter{
counter: counter.With(tags),
}
}
counter := promauto.With(pm.registry).NewCounterVec(
prometheus.CounterOpts{
Name: pm.buildMetricName(name),
Help: fmt.Sprintf("Counter metric for %s", name),
ConstLabels: pm.config.DefaultLabels,
},
pm.getLabelNames(tags),
)
pm.counters[key] = counter
return &PrometheusCounter{
counter: counter.With(tags),
}
}
// Gauge 创建仪表盘
func (pm *PrometheusMonitor) Gauge(name string, tags map[string]string) Gauge {
pm.mu.Lock()
defer pm.mu.Unlock()
key := pm.buildMetricKey(name, tags)
if gauge, exists := pm.gauges[key]; exists {
return &PrometheusGauge{
gauge: gauge.With(tags),
}
}
gauge := promauto.With(pm.registry).NewGaugeVec(
prometheus.GaugeOpts{
Name: pm.buildMetricName(name),
Help: fmt.Sprintf("Gauge metric for %s", name),
ConstLabels: pm.config.DefaultLabels,
},
pm.getLabelNames(tags),
)
pm.gauges[key] = gauge
return &PrometheusGauge{
gauge: gauge.With(tags),
}
}
// Histogram 创建直方图
func (pm *PrometheusMonitor) Histogram(name string, tags map[string]string) Histogram {
pm.mu.Lock()
defer pm.mu.Unlock()
key := pm.buildMetricKey(name, tags)
if histogram, exists := pm.histograms[key]; exists {
return &PrometheusHistogram{
histogram: histogram.With(tags),
}
}
histogram := promauto.With(pm.registry).NewHistogramVec(
prometheus.HistogramOpts{
Name: pm.buildMetricName(name),
Help: fmt.Sprintf("Histogram metric for %s", name),
ConstLabels: pm.config.DefaultLabels,
Buckets: pm.config.Buckets,
},
pm.getLabelNames(tags),
)
pm.histograms[key] = histogram
return &PrometheusHistogram{
histogram: histogram.With(tags),
}
}
// Summary 创建摘要
func (pm *PrometheusMonitor) Summary(name string, tags map[string]string) Summary {
pm.mu.Lock()
defer pm.mu.Unlock()
key := pm.buildMetricKey(name, tags)
if summary, exists := pm.summaries[key]; exists {
return &PrometheusSummary{
summary: summary.With(tags),
}
}
summary := promauto.With(pm.registry).NewSummaryVec(
prometheus.SummaryOpts{
Name: pm.buildMetricName(name),
Help: fmt.Sprintf("Summary metric for %s", name),
ConstLabels: pm.config.DefaultLabels,
Objectives: pm.config.Objectives,
},
pm.getLabelNames(tags),
)
pm.summaries[key] = summary
return &PrometheusSummary{
summary: summary.With(tags),
}
}
// buildMetricKey 构建指标键
func (pm *PrometheusMonitor) buildMetricKey(name string, tags map[string]string) string {
return fmt.Sprintf("%s:%v", name, tags)
}
// buildMetricName 构建指标名称
func (pm *PrometheusMonitor) buildMetricName(name string) string {
if pm.config.Subsystem != "" {
return fmt.Sprintf("%s_%s_%s", pm.config.Namespace, pm.config.Subsystem, name)
}
return fmt.Sprintf("%s_%s", pm.config.Namespace, name)
}
// getLabelNames 获取标签名称
func (pm *PrometheusMonitor) getLabelNames(tags map[string]string) []string {
labelNames := make([]string, 0, len(tags)+len(pm.config.DefaultLabels))
// 添加默认标签名称
for key := range pm.config.DefaultLabels {
labelNames = append(labelNames, key)
}
// 添加自定义标签名称
for key := range tags {
labelNames = append(labelNames, key)
}
return labelNames
}
// Start 启动监控
func (pm *PrometheusMonitor) Start(ctx context.Context) error {
if !pm.config.Enabled {
return nil
}
pm.logger.Info("Prometheus monitor started",
String("namespace", pm.config.Namespace),
String("subsystem", pm.config.Subsystem))
// 启动推送模式
if pm.config.PushEnabled {
go pm.startPushLoop(ctx)
}
return nil
}
// Stop 停止监控
func (pm *PrometheusMonitor) Stop(ctx context.Context) error {
if pm.config.PushEnabled && pm.pusher != nil {
if err := pm.pusher.Push(); err != nil {
pm.logger.Warn("Failed to push metrics on stop", Error("error", err))
}
}
pm.logger.Info("Prometheus monitor stopped")
return nil
}
// startPushLoop 启动推送循环
func (pm *PrometheusMonitor) startPushLoop(ctx context.Context) {
ticker := time.NewTicker(pm.config.PushInterval)
defer ticker.Stop()
pm.pusher = push.New(pm.config.PushAddress, pm.config.Subsystem).
Gatherer(pm.registry).
Format(push.TextFormat)
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
if err := pm.pusher.Push(); err != nil {
pm.logger.Warn("Failed to push metrics", Error("error", err))
}
}
}
}
// PrometheusCounter Prometheus计数器实现
type PrometheusCounter struct {
counter prometheus.Counter
}
func (pc *PrometheusCounter) Inc() {
pc.counter.Inc()
}
func (pc *PrometheusCounter) Add(value float64) {
pc.counter.Add(value)
}
func (pc *PrometheusCounter) WithTags(tags map[string]string) Counter {
// 这里需要重新创建带标签的计数器
// 简化实现,实际应该从monitor获取
return pc
}
// PrometheusGauge Prometheus仪表盘实现
type PrometheusGauge struct {
gauge prometheus.Gauge
}
func (pg *PrometheusGauge) Set(value float64) {
pg.gauge.Set(value)
}
func (pg *PrometheusGauge) Inc() {
pg.gauge.Inc()
}
func (pg *PrometheusGauge) Dec() {
pg.gauge.Dec()
}
func (pg *PrometheusGauge) WithTags(tags map[string]string) Gauge {
// 简化实现
return pg
}
---
03.Jaeger分布式追踪
a.Jaeger追踪实现
---
// monitor/jaeger.go
package monitor
import (
"context"
"fmt"
"time"
"github.com/opentracing/opentracing-go"
"github.com/uber/jaeger-client-go"
"github.com/uber/jaeger-client-go/config"
"github.com/uber/jaeger-lib/metrics"
)
// JaegerTracer Jaeger追踪器
type JaegerTracer struct {
tracer opentracing.Tracer
closer io.Closer
config *JaegerConfig
logger Logger
}
// JaegerConfig Jaeger配置
type JaegerConfig struct {
Enabled bool `yaml:"enabled"`
ServiceName string `yaml:"service_name"`
AgentHost string `yaml:"agent_host"`
AgentPort int `yaml:"agent_port"`
CollectorEndpoint string `yaml:"collector_endpoint"`
SamplerType string `yaml:"sampler_type"`
SamplerParam float64 `yaml:"sampler_param"`
SamplerManagerHost string `yaml:"sampler_manager_host"`
SamplerManagerPort int `yaml:"sampler_manager_port"`
SpansPerSecond float64 `yaml:"spans_per_second"`
TraceID128Bit bool `yaml:"trace_id_128_bit"`
ZipkinHTTPRT bool `yaml:"zipkin_http_rt"`
DebugMode bool `yaml:"debug_mode"`
Tags map[string]string `yaml:"tags"`
}
// NewJaegerTracer 创建Jaeger追踪器
func NewJaegerTracer(config *JaegerConfig, logger Logger) (*JaegerTracer, error) {
if !config.Enabled {
return &JaegerTracer{
config: config,
logger: logger,
}, nil
}
cfg := &config.Configuration{
ServiceName: config.ServiceName,
Sampler: &config.SamplerConfig{
Type: config.SamplerType,
Param: config.SamplerParam,
},
Reporter: &config.ReporterConfig{
LogSpans: true,
LocalAgentHostPort: fmt.Sprintf("%s:%d", config.AgentHost, config.AgentPort),
},
Headers: &config.HeadersConfig{},
}
// 设置收集器端点
if config.CollectorEndpoint != "" {
cfg.Reporter.CollectorEndpoint = config.CollectorEndpoint
}
// 设置采样管理器
if config.SamplerManagerHost != "" && config.SamplerManagerPort != 0 {
cfg.Sampler.SamplingServerURL = fmt.Sprintf("http://%s:%d/sampling",
config.SamplerManagerHost, config.SamplerManagerPort)
}
// 设置全局标签
tags := make(opentracing.Tags)
for k, v := range config.Tags {
tags[k] = v
}
tracer, closer, err := cfg.NewTracer(
config.Logger(jaeger.NullLogger),
config.Metrics(metrics.NullFactory),
config.ZipkinSharedRPCSpan(true),
)
if err != nil {
return nil, fmt.Errorf("failed to create Jaeger tracer: %w", err)
}
opentracing.SetGlobalTracer(tracer)
return &JaegerTracer{
tracer: tracer,
closer: closer,
config: config,
logger: logger,
}, nil
}
// StartSpan 开始追踪
func (jt *JaegerTracer) StartSpan(ctx context.Context, operationName string) (Span, context.Context) {
if !jt.config.Enabled {
return &NoopSpan{}, ctx
}
span, ctx := opentracing.StartSpanFromContext(ctx, operationName)
return &JaegerSpan{span: span}, ctx
}
// Inject 注入追踪信息
func (jt *JaegerTracer) Inject(span Span, headers map[string]string) error {
if !jt.config.Enabled {
return nil
}
jaegerSpan, ok := span.(*JaegerSpan)
if !ok {
return ErrInvalidSpanType
}
return jt.tracer.Inject(
jaegerSpan.span.Context(),
opentracing.TextMap,
opentracing.TextMapCarrier(headers),
)
}
// Extract 提取追踪信息
func (jt *JaegerTracer) Extract(headers map[string]string) (Span, error) {
if !jt.config.Enabled {
return &NoopSpan{}, nil
}
spanContext, err := jt.tracer.Extract(
opentracing.TextMap,
opentracing.TextMapCarrier(headers),
)
if err != nil {
return nil, err
}
span := jt.tracer.StartSpan("extracted", opentracing.FollowsFrom(spanContext))
return &JaegerSpan{span: span}, nil
}
// Close 关闭追踪器
func (jt *JaegerTracer) Close() error {
if jt.closer != nil {
return jt.closer.Close()
}
return nil
}
// JaegerSpan Jaeger跨度实现
type JaegerSpan struct {
span opentracing.Span
}
func (js *JaegerSpan) SetOperationName(operationName string) {
js.span.SetOperationName(operationName)
}
func (js *JaegerSpan) SetTag(key string, value interface{}) {
js.span.SetTag(key, value)
}
func (js *JaegerSpan) SetBaggageItem(key, value string) {
js.span.SetBaggageItem(key, value)
}
func (js *JaegerSpan) Finish() {
js.span.Finish()
}
func (js *JaegerSpan) FinishWithOptions(opts FinishOptions) {
if opts.FinishTime.IsZero() {
opts.FinishTime = time.Now()
}
js.span.FinishWithOptions(opentracing.FinishOptions{
FinishTime: opts.FinishTime,
LogRecords: []opentracing.LogRecord{
{
Timestamp: time.Now(),
Fields: opts.LogData,
},
},
Error: opts.Error,
})
}
func (js *JaegerSpan) Context() SpanContext {
spanCtx := js.span.Context()
return &JaegerSpanContext{context: spanCtx}
}
// JaegerSpanContext Jaeger跨度上下文实现
type JaegerSpanContext struct {
context opentracing.SpanContext
}
func (jsc *JaegerSpanContext) TraceID() string {
if jaegerCtx, ok := jsc.context.(jaeger.SpanContext); ok {
return jaegerCtx.TraceID().String()
}
return ""
}
func (jsc *JaegerSpanContext) SpanID() string {
if jaegerCtx, ok := jsc.context.(jaeger.SpanContext); ok {
return jaegerCtx.SpanID().String()
}
return ""
}
func (jsc *JaegerSpanContext) BaggageItems() map[string]string {
items := make(map[string]string)
jsc.context.ForeachBaggageItem(func(key, value string) bool {
items[key] = value
return true
})
return items
}
// NoopSpan 空操作跨度实现
type NoopSpan struct{}
func (ns *NoopSpan) SetOperationName(operationName string) {}
func (ns *NoopSpan) SetTag(key string, value interface{}) {}
func (ns *NoopSpan) SetBaggageItem(key, value string) {}
func (ns *NoopSpan) Finish() {}
func (ns *NoopSpan) FinishWithOptions(opts FinishOptions) {}
func (ns *NoopSpan) Context() SpanContext { return &NoopSpanContext{} }
// NoopSpanContext 空操作跨度上下文实现
type NoopSpanContext struct{}
func (nsc *NoopSpanContext) TraceID() string { return "" }
func (nsc *NoopSpanContext) SpanID() string { return "" }
func (nsc *NoopSpanContext) BaggageItems() map[string]string { return make(map[string]string) }
---
04.健康检查系统
a.健康检查实现
---
// monitor/health.go
package monitor
import (
"context"
"sync"
"time"
)
// HealthChecker 健康检查器
type HealthChecker interface {
Name() string
Check(ctx context.Context) HealthStatus
}
// HealthManager 健康检查管理器
type HealthManager struct {
checkers map[string]HealthChecker
results map[string]HealthStatus
mu sync.RWMutex
logger Logger
config *HealthConfig
}
// HealthConfig 健康检查配置
type HealthConfig struct {
Enabled bool `yaml:"enabled"`
CheckInterval time.Duration `yaml:"check_interval"`
Timeout time.Duration `yaml:"timeout"`
SuccessThreshold int `yaml:"success_threshold"`
FailureThreshold int `yaml:"failure_threshold"`
DefaultTTL time.Duration `yaml:"default_ttl"`
GracePeriod time.Duration `yaml:"grace_period"`
}
// NewHealthManager 创建健康检查管理器
func NewHealthManager(config *HealthConfig, logger Logger) *HealthManager {
if config == nil {
config = &HealthConfig{
Enabled: true,
CheckInterval: 30 * time.Second,
Timeout: 5 * time.Second,
SuccessThreshold: 1,
FailureThreshold: 3,
DefaultTTL: 60 * time.Second,
GracePeriod: 30 * time.Second,
}
}
return &HealthManager{
checkers: make(map[string]HealthChecker),
results: make(map[string]HealthStatus),
logger: logger,
config: config,
}
}
// RegisterHealthCheck 注册健康检查
func (hm *HealthManager) RegisterHealthCheck(name string, checker HealthChecker) error {
hm.mu.Lock()
defer hm.mu.Unlock()
if _, exists := hm.checkers[name]; exists {
return ErrHealthCheckerExists
}
hm.checkers[name] = checker
hm.logger.Info("Health checker registered", String("name", name))
// 立即执行一次检查
ctx, cancel := context.WithTimeout(context.Background(), hm.config.Timeout)
defer cancel()
go func() {
status := checker.Check(ctx)
hm.updateResult(name, status)
}()
return nil
}
// UnregisterHealthCheck 注销健康检查
func (hm *HealthManager) UnregisterHealthCheck(name string) error {
hm.mu.Lock()
defer hm.mu.Unlock()
if _, exists := hm.checkers[name]; !exists {
return ErrHealthCheckerNotFound
}
delete(hm.checkers, name)
delete(hm.results, name)
hm.logger.Info("Health checker unregistered", String("name", name))
return nil
}
// Start 开始健康检查
func (hm *HealthManager) Start(ctx context.Context) error {
if !hm.config.Enabled {
return nil
}
hm.logger.Info("Health manager started")
go hm.checkLoop(ctx)
return nil
}
// Stop 停止健康检查
func (hm *HealthManager) Stop(ctx context.Context) error {
hm.logger.Info("Health manager stopped")
return nil
}
// checkLoop 检查循环
func (hm *HealthManager) checkLoop(ctx context.Context) {
ticker := time.NewTicker(hm.config.CheckInterval)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
hm.performChecks(ctx)
}
}
}
// performChecks 执行所有检查
func (hm *HealthManager) performChecks(ctx context.Context) {
hm.mu.RLock()
checkers := make(map[string]HealthChecker)
for name, checker := range hm.checkers {
checkers[name] = checker
}
hm.mu.RUnlock()
var wg sync.WaitGroup
for name, checker := range checkers {
wg.Add(1)
go func(name string, checker HealthChecker) {
defer wg.Done()
checkCtx, cancel := context.WithTimeout(ctx, hm.config.Timeout)
defer cancel()
status := checker.Check(checkCtx)
hm.updateResult(name, status)
}(name, checker)
}
wg.Wait()
}
// updateResult 更新检查结果
func (hm *HealthManager) updateResult(name string, status HealthStatus) {
hm.mu.Lock()
defer hm.mu.Unlock()
hm.results[name] = status
if status.Status == "unhealthy" {
hm.logger.Warn("Health check failed",
String("name", name),
String("message", status.Message))
}
}
// GetStatus 获取健康状态
func (hm *HealthManager) GetStatus(name string) (HealthStatus, bool) {
hm.mu.RLock()
defer hm.mu.RUnlock()
status, exists := hm.results[name]
return status, exists
}
// GetAllStatus 获取所有健康状态
func (hm *HealthManager) GetAllStatus() map[string]HealthStatus {
hm.mu.RLock()
defer hm.mu.RUnlock()
results := make(map[string]HealthStatus)
for name, status := range hm.results {
results[name] = status
}
return results
}
// IsHealthy 检查整体健康状态
func (hm *HealthManager) IsHealthy() bool {
hm.mu.RLock()
defer hm.mu.RUnlock()
for _, status := range hm.results {
if status.Status == "unhealthy" {
return false
}
}
return true
}
// DatabaseHealthChecker 数据库健康检查器
type DatabaseHealthChecker struct {
name string
db *sql.DB
timeout time.Duration
}
func NewDatabaseHealthChecker(name string, db *sql.DB, timeout time.Duration) *DatabaseHealthChecker {
return &DatabaseHealthChecker{
name: name,
db: db,
timeout: timeout,
}
}
func (dhc *DatabaseHealthChecker) Name() string {
return dhc.name
}
func (dhc *DatabaseHealthChecker) Check(ctx context.Context) HealthStatus {
ctx, cancel := context.WithTimeout(ctx, dhc.timeout)
defer cancel()
err := dhc.db.PingContext(ctx)
if err != nil {
return HealthStatus{
Status: "unhealthy",
Message: fmt.Sprintf("Database connection failed: %v", err),
Time: time.Now(),
Details: map[string]interface{}{
"error": err.Error(),
},
}
}
// 检查连接池状态
stats := dhc.db.Stats()
details := map[string]interface{}{
"open_connections": stats.OpenConnections,
"in_use": stats.InUse,
"idle": stats.Idle,
}
return HealthStatus{
Status: "healthy",
Message: "Database connection is healthy",
Time: time.Now(),
Details: details,
}
}
// HTTPHealthChecker HTTP健康检查器
type HTTPHealthChecker struct {
name string
client *http.Client
url string
timeout time.Duration
}
func NewHTTPHealthChecker(name, url string, timeout time.Duration) *HTTPHealthChecker {
return &HTTPHealthChecker{
name: name,
client: &http.Client{Timeout: timeout},
url: url,
timeout: timeout,
}
}
func (hhc *HTTPHealthChecker) Name() string {
return hhc.name
}
func (hhc *HTTPHealthChecker) Check(ctx context.Context) HealthStatus {
req, err := http.NewRequestWithContext(ctx, "GET", hhc.url, nil)
if err != nil {
return HealthStatus{
Status: "unhealthy",
Message: fmt.Sprintf("Failed to create request: %v", err),
Time: time.Now(),
}
}
resp, err := hhc.client.Do(req)
if err != nil {
return HealthStatus{
Status: "unhealthy",
Message: fmt.Sprintf("HTTP request failed: %v", err),
Time: time.Now(),
}
}
defer resp.Body.Close()
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
return HealthStatus{
Status: "healthy",
Message: "HTTP endpoint is healthy",
Time: time.Now(),
Details: map[string]interface{}{
"status_code": resp.StatusCode,
},
}
}
return HealthStatus{
Status: "unhealthy",
Message: fmt.Sprintf("HTTP endpoint returned status code: %d", resp.StatusCode),
Time: time.Now(),
Details: map[string]interface{}{
"status_code": resp.StatusCode,
},
}
}
---
6.6 配置管理插件
01.配置管理系统概述
a.配置管理架构
a.功能说明
配置管理插件提供统一的配置管理能力,支持多种配置源、动态配置更新、配置版本控制和配置验证等功能。系统采用分层架构设计,支持配置的集中管理、分发和热更新,为微服务提供灵活的配置解决方案。
b.核心特性
多源配置支持文件、环境变量、配置中心、数据库等多种配置源,动态更新支持运行时配置热更新无需重启服务,配置合并智能配置合并和覆盖策略,配置验证支持配置格式验证和业务规则验证,版本控制配置变更历史记录和回滚机制,加密存储敏感配置的加密存储和传输,权限控制基于角色的配置访问权限管理。
b.配置接口设计
---
// config/interface.go
package config
import (
"context"
"time"
)
// Manager 配置管理器接口
type Manager interface {
// 配置获取
Get(key string) interface{}
GetString(key string) string
GetInt(key string) int
GetInt64(key string) int64
GetBool(key string) bool
GetFloat64(key string) float64
GetDuration(key string) time.Duration
GetStringMap(key string) map[string]interface{}
GetStringMapString(key string) map[string]string
// 配置监听
Watch(key string, handler ChangeHandler) error
WatchPrefix(prefix string, handler ChangeHandler) error
WatchAll(handler ChangeHandler) error
// 配置操作
Set(key string, value interface{}) error
Delete(key string) error
Exists(key string) bool
// 配置管理
LoadSources(sources ...Source) error
LoadFile(path string, format Format) error
LoadEnv(prefix string) error
LoadRemote(configPath string, options RemoteOptions) error
// 生命周期管理
Start(ctx context.Context) error
Stop(ctx context.Context) error
// 配置验证
Validate() error
SetValidator(validator Validator)
}
// Source 配置源接口
type Source interface {
Read() (map[string]interface{}, error)
Watch(ctx context.Context, handler ChangeHandler) error
IsWatcher() bool
GetFormat() Format
GetMetadata() SourceMetadata
}
// Format 配置格式
type Format string
const (
FormatJSON Format = "json"
FormatYAML Format = "yaml"
FormatTOML Format = "toml"
FormatXML Format = "xml"
FormatINI Format = "ini"
FormatENV Format = "env"
FormatProtobuf Format = "protobuf"
)
// SourceMetadata 配置源元数据
type SourceMetadata struct {
Name string `json:"name"`
Type string `json:"type"`
Format Format `json:"format"`
Path string `json:"path"`
Priority int `json:"priority"`
Tags []string `json:"tags"`
Properties map[string]string `json:"properties"`
LastUpdated time.Time `json:"last_updated"`
}
// ChangeHandler 配置变更处理器
type ChangeHandler interface {
Handle(ctx context.Context, event ChangeEvent) error
}
// ChangeEvent 配置变更事件
type ChangeEvent struct {
Key string `json:"key"`
OldValue interface{} `json:"old_value,omitempty"`
NewValue interface{} `json:"new_value"`
Timestamp time.Time `json:"timestamp"`
Source string `json:"source"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
}
// Validator 配置验证器接口
type Validator interface {
Validate(key string, value interface{}) error
ValidateAll(config map[string]interface{}) error
}
// RemoteOptions 远程配置选项
type RemoteOptions struct {
Provider string `yaml:"provider"`
Address string `yaml:"address"`
Namespace string `yaml:"namespace"`
Auth AuthConfig `yaml:"auth"`
Timeout time.Duration `yaml:"timeout"`
RetryInterval time.Duration `yaml:"retry_interval"`
Headers map[string]string `yaml:"headers"`
}
// AuthConfig 认证配置
type AuthConfig struct {
Type string `yaml:"type"`
Username string `yaml:"username"`
Password string `yaml:"password"`
Token string `yaml:"token"`
Metadata map[string]string `yaml:"metadata"`
}
---
02.配置源实现
a.文件配置源
---
// config/file_source.go
package config
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"sync"
"time"
"gopkg.in/yaml.v2"
"github.com/BurntSushi/toml"
"github.com/fsnotify/fsnotify"
)
// FileSource 文件配置源
type FileSource struct {
path string
format Format
watcher *fsnotify.Watcher
mu sync.RWMutex
handlers []ChangeHandler
metadata SourceMetadata
logger Logger
lastRead time.Time
lastHash string
}
// FileOptions 文件配置选项
type FileOptions struct {
WatchEnabled bool `yaml:"watch_enabled"`
WatchInterval time.Duration `yaml:"watch_interval"`
CheckHash bool `yaml:"check_hash"`
BackupEnabled bool `yaml:"backup_enabled"`
BackupDir string `yaml:"backup_dir"`
ReloadOnError bool `yaml:"reload_on_error"`
MaxFileSize int64 `yaml:"max_file_size"`
EnableGlob bool `yaml:"enable_glob"`
GlobPattern string `yaml:"glob_pattern"`
}
// NewFileSource 创建文件配置源
func NewFileSource(path string, format Format, options *FileOptions, logger Logger) (*FileSource, error) {
if options == nil {
options = &FileOptions{
WatchEnabled: true,
WatchInterval: 1 * time.Second,
CheckHash: true,
ReloadOnError: false,
MaxFileSize: 10 * 1024 * 1024, // 10MB
}
}
// 检查文件是否存在
if _, err := os.Stat(path); os.IsNotExist(err) {
return nil, fmt.Errorf("config file does not exist: %s", path)
}
source := &FileSource{
path: path,
format: format,
handlers: make([]ChangeHandler, 0),
metadata: SourceMetadata{
Name: filepath.Base(path),
Type: "file",
Format: format,
Path: path,
Priority: 100,
Tags: []string{"file", "local"},
},
logger: logger,
}
// 初始化文件监控
if options.WatchEnabled {
if err := source.initWatcher(); err != nil {
logger.Warn("Failed to initialize file watcher",
String("path", path),
Error("error", err))
}
}
return source, nil
}
// Read 读取配置
func (fs *FileSource) Read() (map[string]interface{}, error) {
fs.mu.Lock()
defer fs.mu.Unlock()
// 检查文件大小
fileInfo, err := os.Stat(fs.path)
if err != nil {
return nil, fmt.Errorf("failed to stat config file: %w", err)
}
if fileInfo.Size() > 10*1024*1024 { // 10MB limit
return nil, fmt.Errorf("config file too large: %d bytes", fileInfo.Size())
}
// 读取文件内容
data, err := ioutil.ReadFile(fs.path)
if err != nil {
return nil, fmt.Errorf("failed to read config file: %w", err)
}
// 检查文件哈希(如果启用)
hash := fmt.Sprintf("%x", md5.Sum(data))
if fs.lastHash != "" && fs.lastHash == hash {
// 文件内容没有变化,返回缓存
return nil, ErrConfigUnchanged
}
// 解析配置
var config map[string]interface{}
switch fs.format {
case FormatJSON:
if err := json.Unmarshal(data, &config); err != nil {
return nil, fmt.Errorf("failed to parse JSON config: %w", err)
}
case FormatYAML:
if err := yaml.Unmarshal(data, &config); err != nil {
return nil, fmt.Errorf("failed to parse YAML config: %w", err)
}
case FormatTOML:
if err := toml.Unmarshal(data, &config); err != nil {
return nil, fmt.Errorf("failed to parse TOML config: %w", err)
}
default:
return nil, fmt.Errorf("unsupported config format: %s", fs.format)
}
// 更新元数据
fs.lastRead = time.Now()
fs.lastHash = hash
fs.metadata.LastUpdated = fs.lastRead
fs.logger.Debug("Config file read successfully",
String("path", fs.path),
String("format", string(fs.format)),
String("hash", hash))
return config, nil
}
// Watch 监控配置变更
func (fs *FileSource) Watch(ctx context.Context, handler ChangeHandler) error {
fs.mu.Lock()
defer fs.mu.Unlock()
fs.handlers = append(fs.handlers, handler)
if fs.watcher == nil {
return fmt.Errorf("file watcher not initialized")
}
go fs.watchLoop(ctx)
return nil
}
// initWatcher 初始化文件监控
func (fs *FileSource) initWatcher() error {
watcher, err := fsnotify.NewWatcher()
if err != nil {
return fmt.Errorf("failed to create file watcher: %w", err)
}
fs.watcher = watcher
// 添加文件监控
if err := watcher.Add(fs.path); err != nil {
watcher.Close()
return fmt.Errorf("failed to add file to watcher: %w", err)
}
return nil
}
// watchLoop 监控循环
func (fs *FileSource) watchLoop(ctx context.Context) {
for {
select {
case <-ctx.Done():
if fs.watcher != nil {
fs.watcher.Close()
}
return
case event, ok := <-fs.watcher.Events:
if !ok {
return
}
if event.Op&fsnotify.Write == fsnotify.Write {
fs.handleFileChange(ctx, event.Name)
}
case err, ok := <-fs.watcher.Errors:
if !ok {
return
}
fs.logger.Warn("File watcher error",
String("path", fs.path),
Error("error", err))
}
}
}
// handleFileChange 处理文件变更
func (fs *FileSource) handleFileChange(ctx context.Context, filename string) {
// 读取新配置
newConfig, err := fs.Read()
if err != nil {
if err != ErrConfigUnchanged {
fs.logger.Error("Failed to read changed config file",
String("filename", filename),
Error("error", err))
}
return
}
// 触发变更事件
event := ChangeEvent{
Key: filename,
NewValue: newConfig,
Timestamp: time.Now(),
Source: fs.metadata.Name,
Metadata: map[string]interface{}{
"file_type": "config",
"size": len(fmt.Sprintf("%v", newConfig)),
},
}
// 通知所有处理器
for _, handler := range fs.handlers {
if err := handler.Handle(ctx, event); err != nil {
fs.logger.Error("Failed to handle config change",
String("handler", fmt.Sprintf("%T", handler)),
Error("error", err))
}
}
fs.logger.Info("Config file changed and reloaded",
String("filename", filename))
}
// IsWatcher 是否支持监控
func (fs *FileSource) IsWatcher() bool {
return fs.watcher != nil
}
// GetFormat 获取格式
func (fs *FileSource) GetFormat() Format {
return fs.format
}
// GetMetadata 获取元数据
func (fs *FileSource) GetMetadata() SourceMetadata {
return fs.metadata
}
// Close 关闭配置源
func (fs *FileSource) Close() error {
if fs.watcher != nil {
return fs.watcher.Close()
}
return nil
}
---
b.远程配置源
---
// config/remote_source.go
package config
import (
"context"
"encoding/json"
"fmt"
"time"
)
// RemoteSource 远程配置源
type RemoteSource struct {
options RemoteOptions
client HTTPClient
cache map[string]interface{}
mu sync.RWMutex
handlers []ChangeHandler
metadata SourceMetadata
logger Logger
}
// NewRemoteSource 创建远程配置源
func NewRemoteSource(configPath string, options RemoteOptions, logger Logger) (*RemoteSource, error) {
client := &http.Client{
Timeout: options.Timeout,
}
source := &RemoteSource{
options: options,
client: client,
cache: make(map[string]interface{}),
handlers: make([]ChangeHandler, 0),
metadata: SourceMetadata{
Name: options.Provider,
Type: "remote",
Format: FormatJSON, // 默认JSON格式
Path: configPath,
Priority: 200,
Tags: []string{"remote", "cloud"},
},
logger: logger,
}
// 初始加载配置
if _, err := source.Read(); err != nil {
return nil, fmt.Errorf("failed to load initial config: %w", err)
}
return source, nil
}
// Read 读取远程配置
func (rs *RemoteSource) Read() (map[string]interface{}, error) {
req, err := http.NewRequest("GET", rs.buildURL(), nil)
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
// 添加认证头
rs.addAuthHeaders(req)
// 添加自定义头
for key, value := range rs.options.Headers {
req.Header.Add(key, value)
}
resp, err := rs.client.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to fetch remote config: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("remote config request failed with status: %d", resp.StatusCode)
}
var config map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&config); err != nil {
return nil, fmt.Errorf("failed to decode remote config: %w", err)
}
// 更新缓存
rs.mu.Lock()
rs.cache = config
rs.metadata.LastUpdated = time.Now()
rs.mu.Unlock()
rs.logger.Debug("Remote config loaded successfully",
String("provider", rs.options.Provider),
String("url", rs.buildURL()))
return config, nil
}
// Watch 监控远程配置变更
func (rs *RemoteSource) Watch(ctx context.Context, handler ChangeHandler) error {
rs.mu.Lock()
defer rs.mu.Unlock()
rs.handlers = append(rs.handlers, handler)
// 启动定期检查
go rs.watchLoop(ctx)
return nil
}
// watchLoop 监控循环
func (rs *RemoteSource) watchLoop(ctx context.Context) {
ticker := time.NewTicker(rs.options.RetryInterval)
defer ticker.Stop()
var lastHash string
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
newConfig, err := rs.Read()
if err != nil {
rs.logger.Warn("Failed to fetch remote config",
String("provider", rs.options.Provider),
Error("error", err))
continue
}
// 计算配置哈希
data, _ := json.Marshal(newConfig)
currentHash := fmt.Sprintf("%x", md5.Sum(data))
if lastHash != "" && lastHash != currentHash {
// 配置已变更,触发变更事件
rs.mu.RLock()
oldConfig := rs.cache
rs.mu.RUnlock()
event := ChangeEvent{
Key: rs.options.Address,
OldValue: oldConfig,
NewValue: newConfig,
Timestamp: time.Now(),
Source: rs.metadata.Name,
Metadata: map[string]interface{}{
"provider": rs.options.Provider,
"namespace": rs.options.Namespace,
},
}
// 通知所有处理器
for _, handler := range rs.handlers {
if err := handler.Handle(ctx, event); err != nil {
rs.logger.Error("Failed to handle remote config change",
String("handler", fmt.Sprintf("%T", handler)),
Error("error", err))
}
}
rs.logger.Info("Remote config changed",
String("provider", rs.options.Provider))
}
lastHash = currentHash
}
}
}
// buildURL 构建请求URL
func (rs *RemoteSource) buildURL() string {
if rs.options.Namespace != "" {
return fmt.Sprintf("%s/api/v1/config/%s/%s",
rs.options.Address, rs.options.Namespace, rs.metadata.Path)
}
return fmt.Sprintf("%s/api/v1/config/%s",
rs.options.Address, rs.metadata.Path)
}
// addAuthHeaders 添加认证头
func (rs *RemoteSource) addAuthHeaders(req *http.Request) {
switch rs.options.Auth.Type {
case "basic":
req.SetBasicAuth(rs.options.Auth.Username, rs.options.Auth.Password)
case "bearer":
req.Header.Add("Authorization", "Bearer "+rs.options.Auth.Token)
case "apikey":
req.Header.Add("X-API-Key", rs.options.Auth.Token)
}
// 添加自定义认证元数据
for key, value := range rs.options.Auth.Metadata {
req.Header.Add(key, value)
}
}
// IsWatcher 是否支持监控
func (rs *RemoteSource) IsWatcher() bool {
return true
}
// GetFormat 获取格式
func (rs *RemoteSource) GetFormat() Format {
return rs.metadata.Format
}
// GetMetadata 获取元数据
func (rs *RemoteSource) GetMetadata() SourceMetadata {
return rs.metadata
}
---
03.配置验证与加密
a.配置验证器
---
// config/validator.go
package config
import (
"fmt"
"reflect"
"regexp"
"strconv"
"time"
)
// DefaultValidator 默认配置验证器
type DefaultValidator struct {
rules map[string][]ValidationRule
schema ValidatorSchema
}
// ValidationRule 验证规则
type ValidationRule struct {
Name string `json:"name"`
Type string `json:"type"`
Required bool `json:"required"`
Min interface{} `json:"min,omitempty"`
Max interface{} `json:"max,omitempty"`
Pattern string `json:"pattern,omitempty"`
Enum []string `json:"enum,omitempty"`
DefaultValue interface{} `json:"default_value,omitempty"`
Description string `json:"description,omitempty"`
}
// ValidatorSchema 验证器模式
type ValidatorSchema struct {
Version string `json:"version"`
Description string `json:"description"`
Properties map[string]ValidationRule `json:"properties"`
Required []string `json:"required"`
}
// NewDefaultValidator 创建默认验证器
func NewDefaultValidator(schema *ValidatorSchema) *DefaultValidator {
validator := &DefaultValidator{
rules: make(map[string][]ValidationRule),
}
if schema != nil {
validator.schema = *schema
for key, rule := range schema.Properties {
validator.rules[key] = append(validator.rules[key], rule)
}
}
return validator
}
// Validate 验证单个配置项
func (dv *DefaultValidator) Validate(key string, value interface{}) error {
rules, exists := dv.rules[key]
if !exists {
return nil // 没有规则则跳过验证
}
for _, rule := range rules {
if err := dv.validateRule(key, value, rule); err != nil {
return err
}
}
return nil
}
// ValidateAll 验证所有配置
func (dv *DefaultValidator) ValidateAll(config map[string]interface{}) error {
// 检查必需字段
for _, key := range dv.schema.Required {
if _, exists := config[key]; !exists {
return &ValidationError{
Key: key,
Message: fmt.Sprintf("required field '%s' is missing", key),
Rule: "required",
}
}
}
// 验证每个字段
for key, value := range config {
if err := dv.Validate(key, value); err != nil {
return err
}
}
return nil
}
// validateRule 验证规则
func (dv *DefaultValidator) validateRule(key string, value interface{}, rule ValidationRule) error {
// 检查必需字段
if rule.Required && (value == nil || value == "") {
return &ValidationError{
Key: key,
Message: fmt.Sprintf("field '%s' is required", key),
Rule: rule.Name,
}
}
if value == nil {
return nil
}
// 类型验证
if err := dv.validateType(key, value, rule.Type); err != nil {
return err
}
// 范围验证
if err := dv.validateRange(key, value, rule); err != nil {
return err
}
// 模式验证
if err := dv.validatePattern(key, value, rule); err != nil {
return err
}
// 枚举验证
if err := dv.validateEnum(key, value, rule); err != nil {
return err
}
return nil
}
// validateType 验证类型
func (dv *DefaultValidator) validateType(key string, value interface{}, expectedType string) error {
var actualType string
switch value.(type) {
case string:
actualType = "string"
case int, int32, int64:
actualType = "integer"
case float32, float64:
actualType = "number"
case bool:
actualType = "boolean"
case []interface{}:
actualType = "array"
case map[string]interface{}:
actualType = "object"
case time.Time, *time.Time:
actualType = "time"
default:
actualType = reflect.TypeOf(value).String()
}
if actualType != expectedType {
return &ValidationError{
Key: key,
Message: fmt.Sprintf("field '%s' type mismatch: expected %s, got %s", key, expectedType, actualType),
Rule: "type",
}
}
return nil
}
// validateRange 验证范围
func (dv *DefaultValidator) validateRange(key string, value interface{}, rule ValidationRule) error {
if rule.Min == nil && rule.Max == nil {
return nil
}
switch v := value.(type) {
case string:
length := len(v)
if rule.Min != nil && int64(length) < rule.Min.(int64) {
return &ValidationError{
Key: key,
Message: fmt.Sprintf("field '%s' length %d is less than minimum %d", key, length, rule.Min),
Rule: "min_length",
}
}
if rule.Max != nil && int64(length) > rule.Max.(int64) {
return &ValidationError{
Key: key,
Message: fmt.Sprintf("field '%s' length %d exceeds maximum %d", key, length, rule.Max),
Rule: "max_length",
}
}
case int, int32, int64:
intValue := reflect.ValueOf(v).Int()
if rule.Min != nil && intValue < rule.Min.(int64) {
return &ValidationError{
Key: key,
Message: fmt.Sprintf("field '%s' value %d is less than minimum %d", key, intValue, rule.Min),
Rule: "min_value",
}
}
if rule.Max != nil && intValue > rule.Max.(int64) {
return &ValidationError{
Key: key,
Message: fmt.Sprintf("field '%s' value %d exceeds maximum %d", key, intValue, rule.Max),
Rule: "max_value",
}
}
case float32, float64:
floatValue := reflect.ValueOf(v).Float()
if rule.Min != nil && floatValue < rule.Min.(float64) {
return &ValidationError{
Key: key,
Message: fmt.Sprintf("field '%s' value %f is less than minimum %f", key, floatValue, rule.Min),
Rule: "min_value",
}
}
if rule.Max != nil && floatValue > rule.Max.(float64) {
return &ValidationError{
Key: key,
Message: fmt.Sprintf("field '%s' value %f exceeds maximum %f", key, floatValue, rule.Max),
Rule: "max_value",
}
}
}
return nil
}
// validatePattern 验证模式
func (dv *DefaultValidator) validatePattern(key string, value interface{}, rule ValidationRule) error {
if rule.Pattern == "" {
return nil
}
strValue, ok := value.(string)
if !ok {
return nil // 模式验证只适用于字符串
}
regex, err := regexp.Compile(rule.Pattern)
if err != nil {
return fmt.Errorf("invalid regex pattern: %w", err)
}
if !regex.MatchString(strValue) {
return &ValidationError{
Key: key,
Message: fmt.Sprintf("field '%s' value '%s' does not match pattern '%s'", key, strValue, rule.Pattern),
Rule: "pattern",
}
}
return nil
}
// validateEnum 验证枚举
func (dv *DefaultValidator) validateEnum(key string, value interface{}, rule ValidationRule) error {
if len(rule.Enum) == 0 {
return nil
}
strValue := fmt.Sprintf("%v", value)
for _, enumValue := range rule.Enum {
if strValue == enumValue {
return nil
}
}
return &ValidationError{
Key: key,
Message: fmt.Sprintf("field '%s' value '%s' is not in allowed values %v", key, strValue, rule.Enum),
Rule: "enum",
}
}
// ValidationError 验证错误
type ValidationError struct {
Key string `json:"key"`
Message string `json:"message"`
Rule string `json:"rule"`
Value interface{} `json:"value,omitempty"`
}
func (ve *ValidationError) Error() string {
return ve.Message
}
// AddRule 添加验证规则
func (dv *DefaultValidator) AddRule(key string, rule ValidationRule) {
dv.rules[key] = append(dv.rules[key], rule)
}
// SetSchema 设置验证模式
func (dv *DefaultValidator) SetSchema(schema ValidatorSchema) {
dv.schema = schema
dv.rules = make(map[string][]ValidationRule)
for key, rule := range schema.Properties {
dv.rules[key] = append(dv.rules[key], rule)
}
}
---
04.配置管理器实现
a.默认配置管理器
---
// config/manager.go
package config
import (
"context"
"fmt"
"sync"
"time"
)
// DefaultManager 默认配置管理器
type DefaultManager struct {
sources []Source
config map[string]interface{}
cache map[string]interface{}
watchers map[string][]ChangeHandler
mu sync.RWMutex
validator Validator
logger Logger
options *ManagerOptions
ctx context.Context
cancel context.CancelFunc
}
// ManagerOptions 管理器选项
type ManagerOptions struct {
WatchInterval time.Duration `yaml:"watch_interval"`
ReloadOnFailure bool `yaml:"reload_on_failure"`
EnableCache bool `yaml:"enable_cache"`
CacheSize int `yaml:"cache_size"`
CacheTTL time.Duration `yaml:"cache_ttl"`
MergeStrategy string `yaml:"merge_strategy"`
PrefixSeparator string `yaml:"prefix_separator"`
}
// NewDefaultManager 创建默认配置管理器
func NewDefaultManager(options *ManagerOptions, logger Logger) *DefaultManager {
if options == nil {
options = &ManagerOptions{
WatchInterval: 30 * time.Second,
ReloadOnFailure: false,
EnableCache: true,
CacheSize: 1000,
CacheTTL: 5 * time.Minute,
MergeStrategy: "override",
PrefixSeparator: ".",
}
}
ctx, cancel := context.WithCancel(context.Background())
return &DefaultManager{
sources: make([]Source, 0),
config: make(map[string]interface{}),
cache: make(map[string]interface{}),
watchers: make(map[string][]ChangeHandler),
logger: logger,
options: options,
ctx: ctx,
cancel: cancel,
}
}
// LoadSources 加载配置源
func (dm *DefaultManager) LoadSources(sources ...Source) error {
dm.mu.Lock()
defer dm.mu.Unlock()
// 按优先级排序配置源
sortedSources := make([]Source, len(sources))
copy(sortedSources, sources)
sort.Slice(sortedSources, func(i, j int) bool {
return sortedSources[i].GetMetadata().Priority > sortedSources[j].GetMetadata().Priority
})
// 加载每个配置源
for _, source := range sortedSources {
config, err := source.Read()
if err != nil {
if !dm.options.ReloadOnFailure {
return fmt.Errorf("failed to load config from source %s: %w", source.GetMetadata().Name, err)
}
dm.logger.Warn("Failed to load config source",
String("name", source.GetMetadata().Name),
Error("error", err))
continue
}
// 合并配置
if err := dm.mergeConfig(config, source.GetMetadata()); err != nil {
return fmt.Errorf("failed to merge config from source %s: %w", source.GetMetadata().Name, err)
}
dm.sources = append(dm.sources, source)
// 启动监控
if source.IsWatcher() {
if err := source.Watch(dm.ctx, dm); err != nil {
dm.logger.Warn("Failed to start watching config source",
String("name", source.GetMetadata().Name),
Error("error", err))
}
}
dm.logger.Info("Config source loaded",
String("name", source.GetMetadata().Name),
String("type", source.GetMetadata().Type))
}
// 验证配置
if dm.validator != nil {
if err := dm.validator.ValidateAll(dm.config); err != nil {
return fmt.Errorf("config validation failed: %w", err)
}
}
return nil
}
// mergeConfig 合并配置
func (dm *DefaultManager) mergeConfig(newConfig map[string]interface{}, metadata SourceMetadata) error {
switch dm.options.MergeStrategy {
case "override":
return dm.overrideMerge(newConfig)
case "deep":
return dm.deepMerge(newConfig)
default:
return dm.overrideMerge(newConfig)
}
}
// overrideMerge 覆盖合并
func (dm *DefaultManager) overrideMerge(newConfig map[string]interface{}) error {
for key, value := range newConfig {
dm.config[key] = value
}
return nil
}
// deepMerge 深度合并
func (dm *DefaultManager) deepMerge(newConfig map[string]interface{}) error {
for key, value := range newConfig {
if existingValue, exists := dm.config[key]; exists {
if existingMap, ok := existingValue.(map[string]interface{}); ok {
if newMap, ok := value.(map[string]interface{}); ok {
// 递归合并嵌套对象
merged := make(map[string]interface{})
for k, v := range existingMap {
merged[k] = v
}
for k, v := range newMap {
merged[k] = v
}
dm.config[key] = merged
continue
}
}
}
dm.config[key] = value
}
return nil
}
// Get 获取配置值
func (dm *DefaultManager) Get(key string) interface{} {
dm.mu.RLock()
defer dm.mu.RUnlock()
// 检查缓存
if dm.options.EnableCache {
if cached, exists := dm.cache[key]; exists {
return cached
}
}
value := dm.getValueByKey(key, dm.config)
// 更新缓存
if dm.options.EnableCache {
dm.cache[key] = value
}
return value
}
// GetString 获取字符串配置
func (dm *DefaultManager) GetString(key string) string {
value := dm.Get(key)
if value == nil {
return ""
}
return fmt.Sprintf("%v", value)
}
// GetInt 获取整数配置
func (dm *DefaultManager) GetInt(key string) int {
value := dm.Get(key)
if value == nil {
return 0
}
switch v := value.(type) {
case int:
return v
case int32:
return int(v)
case int64:
return int(v)
case float64:
return int(v)
case string:
if intValue, err := strconv.Atoi(v); err == nil {
return intValue
}
}
return 0
}
// GetBool 获取布尔配置
func (dm *DefaultManager) GetBool(key string) bool {
value := dm.Get(key)
if value == nil {
return false
}
switch v := value.(type) {
case bool:
return v
case string:
return v == "true" || v == "1" || v == "on"
}
return false
}
// getValueByKey 根据键获取值
func (dm *DefaultManager) getValueByKey(key string, config map[string]interface{}) interface{} {
if value, exists := config[key]; exists {
return value
}
// 支持嵌套键,如 "database.host"
keys := strings.Split(key, dm.options.PrefixSeparator)
current := config
for i, k := range keys {
if value, exists := current[k]; exists {
if i == len(keys)-1 {
return value
}
if nextMap, ok := value.(map[string]interface{}); ok {
current = nextMap
} else {
return nil
}
} else {
return nil
}
}
return nil
}
// Watch 监控配置变更
func (dm *DefaultManager) Watch(key string, handler ChangeHandler) error {
dm.mu.Lock()
defer dm.mu.Unlock()
if _, exists := dm.watchers[key]; !exists {
dm.watchers[key] = make([]ChangeHandler, 0)
}
dm.watchers[key] = append(dm.watchers[key], handler)
dm.logger.Debug("Config watcher registered",
String("key", key),
String("handler", fmt.Sprintf("%T", handler)))
return nil
}
// Handle 处理配置变更事件
func (dm *DefaultManager) Handle(ctx context.Context, event ChangeEvent) error {
dm.mu.Lock()
defer dm.mu.Unlock()
// 更新配置
if event.NewValue != nil {
if newConfig, ok := event.NewValue.(map[string]interface{}); ok {
if err := dm.mergeConfig(newConfig, SourceMetadata{
Name: event.Source,
LastUpdated: event.Timestamp,
}); err != nil {
return err
}
// 清除缓存
if dm.options.EnableCache {
dm.cache = make(map[string]interface{})
}
}
}
// 通知相关监控器
for key, handlers := range dm.watchers {
if strings.HasPrefix(event.Key, key) || key == "*" {
for _, handler := range handlers {
if err := handler.Handle(ctx, event); err != nil {
dm.logger.Error("Config change handler failed",
String("key", key),
Error("error", err))
}
}
}
}
dm.logger.Info("Config change handled",
String("key", event.Key),
String("source", event.Source))
return nil
}
// SetValidator 设置验证器
func (dm *DefaultManager) SetValidator(validator Validator) {
dm.mu.Lock()
defer dm.mu.Unlock()
dm.validator = validator
}
// Start 启动配置管理器
func (dm *DefaultManager) Start(ctx context.Context) error {
dm.logger.Info("Config manager started")
return nil
}
// Stop 停止配置管理器
func (dm *DefaultManager) Stop(ctx context.Context) error {
dm.cancel()
dm.logger.Info("Config manager stopped")
return nil
}
---