Go语言高级编程教程

教程简介

面向有基础的Go语言高级编程教程,深入讲解goroutine、channel高级模式、sync包、context包、接口设计模式、反射机制、CGO调用、pprof性能分析、gRPC微服务开发等进阶内容,配有高性能微服务网关实战项目。

Go 语言高级编程教程

面向有 Go 基础的开发者,深入探讨并发编程、设计模式、性能优化与微服务开发等高级主题。


目录

  1. Goroutine 深入
  2. Channel 高级模式
  3. sync 包详解
  4. context 包详解
  5. 接口设计模式
  6. 反射机制
  7. CGO 调用
  8. 性能分析(pprof)
  9. 测试与基准测试
  10. 微服务开发(gRPC)
  11. 实战项目:高性能微服务网关

1. Goroutine 深入

1.1 Goroutine 的本质

Goroutine 是 Go 运行时管理的轻量级线程,初始栈仅约 2KB(可动态增长),远小于操作系统线程的 1-8MB。每个 Go 程序至少有一个 goroutine(main goroutine),可以轻松创建数十万个并发 goroutine。

package main

import (
    "fmt"
    "runtime"
    "time"
)

func main() {
    fmt.Println("CPU 核心数:", runtime.NumCPU())
    fmt.Println("初始 Goroutine 数:", runtime.NumGoroutine())

    for i := 0; i < 1000; i++ {
        go func(id int) {
            time.Sleep(time.Second)
            fmt.Printf("Goroutine %d 完成\n", id)
        }(i)
    }

    fmt.Println("创建后 Goroutine 数:", runtime.NumGoroutine())
    time.Sleep(2 * time.Second)
}

1.2 Goroutine 泄漏检测

Goroutine 泄漏是生产环境常见的内存问题。当 goroutine 永远阻塞在 channel 操作、锁等待或无限循环中,它占用的内存永远不会释放。

package main

import (
    "fmt"
    "runtime"
    "time"
)

// 故意泄漏的示例
func leakyFunction() {
    ch := make(chan int)
    go func() {
        // 没有人往 ch 发送数据,这个 goroutine 永远阻塞
        val := <-ch
        fmt.Println(val)
    }()
    // ch 被丢弃,goroutine 泄漏
}

// 正确的做法:使用 context 或 done channel
func properFunction(ctx context.Context) {
    ch := make(chan int, 1)
    go func() {
        select {
        case val := <-ch:
            fmt.Println(val)
        case <-ctx.Done():
            fmt.Println("goroutine 正常退出")
            return
        }
    }()
}

func main() {
    fmt.Println("启动前:", runtime.NumGoroutine())

    for i := 0; i < 100; i++ {
        leakyFunction()
    }

    fmt.Println("泄漏后:", runtime.NumGoroutine())

    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    properFunction(ctx)
    time.Sleep(100 * time.Millisecond)
    cancel()
    time.Sleep(100 * time.Millisecond)
    fmt.Println("清理后:", runtime.NumGoroutine())
}

1.3 Goroutine 调度模型:GMP

Go 采用 GMP 调度模型:

  • G (Goroutine):代表一个 goroutine,包含栈、指令指针等
  • M (Machine):代表操作系统线程,执行 G 中的代码
  • P (Processor):代表逻辑处理器,持有本地运行队列
package main

import (
    "fmt"
    "runtime"
)

func main() {
    // 设置最大并行度
    runtime.GOMAXPROCS(4)
    fmt.Println("GOMAXPROCS:", runtime.GOMAXPROCS(0))

    // 查看调度器信息(调试用)
    debug.SetTraceback("all")
}

调度流程简述

  1. 新建的 G 优先放入当前 P 的本地队列
  2. 本地队列满时,部分 G 被转移到全局队列
  3. 空闲的 P 从其他 P 的本地队列"偷取" G(work stealing)
  4. 当 G 进行系统调用阻塞时,M 与 P 解绑,P 绑定空闲 M 继续执行其他 G

1.4 runtime.Goexit 与 runtime.Gosched

package main

import (
    "fmt"
    "runtime"
)

func demoGoexit() {
    defer fmt.Println("defer 在 Goexit 中仍会执行")

    fmt.Println("即将调用 Goexit")
    runtime.Goexit() // 终止当前 goroutine,但 defer 会执行
    fmt.Println("这行永远不会执行")
}

func demoGosched() {
    for i := 0; i < 3; i++ {
        go func(id int) {
            for j := 0; j < 3; j++ {
                fmt.Printf("Goroutine %d: step %d\n", id, j)
                runtime.Gosched() // 主动让出 CPU 时间片
            }
        }(i)
    }
}

func main() {
    // Goexit 示例
    go demoGoexit()
    time.Sleep(time.Second)

    // Gosched 示例
    demoGosched()
    time.Sleep(time.Second)
}

2. Channel 高级模式

2.1 Fan-Out / Fan-In 模式

将一个任务分发给多个 worker(fan-out),再将结果汇聚到一个 channel(fan-in):

package main

import (
    "context"
    "fmt"
    "math/rand"
    "sync"
    "time"
)

// fanIn 将多个 channel 合并为一个
func fanIn(ctx context.Context, channels ...<-chan int) <-chan int {
    var wg sync.WaitGroup
    merged := make(chan int)

    for _, ch := range channels {
        wg.Add(1)
        go func(c <-chan int) {
            defer wg.Done()
            for val := range c {
                select {
                case merged <- val:
                case <-ctx.Done():
                    return
                }
            }
        }(ch)
    }

    go func() {
        wg.Wait()
        close(merged)
    }()

    return merged
}

func worker(ctx context.Context, id int, jobs <-chan int) <-chan int {
    out := make(chan int)
    go func() {
        defer close(out)
        for job := range jobs {
            select {
            case <-ctx.Done():
                return
            default:
                // 模拟处理
                time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
                result := job * job
                fmt.Printf("Worker %d 处理 %d → %d\n", id, job, result)
                select {
                case out <- result:
                case <-ctx.Done():
                    return
                }
            }
        }
    }()
    return out
}

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()

    jobs := make(chan int)

    // 启动 3 个 worker(fan-out)
    workers := make([]<-chan int, 3)
    for i := 0; i < 3; i++ {
        workers[i] = worker(ctx, i, jobs)
    }

    // fan-in 汇聚结果
    results := fanIn(ctx, workers...)

    // 发送任务
    go func() {
        defer close(jobs)
        for i := 1; i <= 10; i++ {
            select {
            case jobs <- i:
            case <-ctx.Done():
                return
            }
        }
    }()

    // 收集结果
    for result := range results {
        fmt.Println("收到结果:", result)
    }
}

2.2 Pipeline 模式

将处理过程串联成管道,每个阶段通过 channel 传递数据:

package main

import (
    "context"
    "fmt"
    "math"
)

// 阶段1:生成数据
func generate(ctx context.Context, nums ...int) <-chan int {
    out := make(chan int)
    go func() {
        defer close(out)
        for _, n := range nums {
            select {
            case out <- n:
            case <-ctx.Done():
                return
            }
        }
    }()
    return out
}

// 阶段2:平方
func square(ctx context.Context, in <-chan int) <-chan int {
    out := make(chan int)
    go func() {
        defer close(out)
        for n := range in {
            select {
            case out <- n * n:
            case <-ctx.Done():
                return
            }
        }
    }()
    return out
}

// 阶段3:过滤奇数
func filterEven(ctx context.Context, in <-chan int) <-chan int {
    out := make(chan int)
    go func() {
        defer close(out)
        for n := range in {
            if n%2 == 0 {
                select {
                case out <- n:
                case <-ctx.Done():
                    return
                }
            }
        }
    }()
    return out
}

func main() {
    ctx := context.Background()

    // 构建管道: generate → square → filterEven
    ch := generate(ctx, 1, 2, 3, 4, 5, 6, 7, 8)
    ch = square(ctx, ch)
    ch = filterEven(ctx, ch)

    for result := range ch {
        fmt.Println(result) // 4, 16, 36, 64
    }
}

2.3 Semaphore 模式(信号量)

使用带缓冲的 channel 控制并发数量:

package main

import (
    "context"
    "fmt"
    "time"
)

// Semaphore 基于 channel 的信号量
type Semaphore struct {
    sem chan struct{}
}

func NewSemaphore(n int) *Semaphore {
    return &Semaphore{sem: make(chan struct{}, n)}
}

func (s *Semaphore) Acquire(ctx context.Context) error {
    select {
    case s.sem <- struct{}{}:
        return nil
    case <-ctx.Done():
        return ctx.Err()
    }
}

func (s *Semaphore) Release() {
    <-s.sem
}

func main() {
    sem := NewSemaphore(3) // 最多 3 个并发
    ctx := context.Background()

    for i := 0; i < 10; i++ {
        go func(id int) {
            if err := sem.Acquire(ctx); err != nil {
                fmt.Printf("任务 %d 获取信号量失败: %v\n", id, err)
                return
            }
            defer sem.Release()

            fmt.Printf("任务 %d 开始执行\n", id)
            time.Sleep(time.Second)
            fmt.Printf("任务 %d 执行完成\n", id)
        }(i)
    }

    time.Sleep(5 * time.Second)
}

2.4 Or-Done Channel

从一个可能被关闭的 channel 中安全读取数据:

package main

import (
    "fmt"
    "sync"
)

func orDone(done <-chan struct{}, c <-chan interface{}) <-chan interface{} {
    valStream := make(chan interface{})
    go func() {
        defer close(valStream)
        for {
            select {
            case <-done:
                return
            case v, ok := <-c:
                if !ok {
                    return
                }
                select {
                case valStream <- v:
                case <-done:
                    return
                }
            }
        }
    }()
    return valStream
}

func main() {
    done := make(chan struct{})
    source := make(chan interface{})

    go func() {
        for i := 0; i < 5; i++ {
            source <- i
        }
        close(source)
    }()

    for val := range orDone(done, source) {
        fmt.Println(val)
    }
}

3. sync 包详解

3.1 sync.Mutex 与 sync.RWMutex

package main

import (
    "fmt"
    "sync"
    "time"
)

// 线程安全的计数器
type SafeCounter struct {
    mu    sync.RWMutex
    items map[string]int
}

func NewSafeCounter() *SafeCounter {
    return &SafeCounter{items: make(map[string]int)}
}

func (c *SafeCounter) Inc(key string) {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.items[key]++
}

func (c *SafeCounter) Get(key string) int {
    c.mu.RLock() // 读锁,允许并发读
    defer c.mu.RUnlock()
    return c.items[key]
}

func main() {
    counter := NewSafeCounter()
    var wg sync.WaitGroup

    // 并发写入
    for i := 0; i < 100; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            key := fmt.Sprintf("key-%d", id%5)
            counter.Inc(key)
        }(i)
    }

    // 并发读取
    for i := 0; i < 50; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            key := fmt.Sprintf("key-%d", id%5)
            _ = counter.Get(key)
        }(i)
    }

    wg.Wait()
    for i := 0; i < 5; i++ {
        fmt.Printf("key-%d: %d\n", i, counter.Get(fmt.Sprintf("key-%d", i)))
    }
}

3.2 sync.WaitGroup

package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    var wg sync.WaitGroup

    urls := []string{
        "https://example.com/api/1",
        "https://example.com/api/2",
        "https://example.com/api/3",
    }

    for _, url := range urls {
        wg.Add(1)
        go func(u string) {
            defer wg.Done()
            // 模拟 HTTP 请求
            time.Sleep(time.Duration(100+len(u)*10) * time.Millisecond)
            fmt.Printf("完成请求: %s\n", u)
        }(url)
    }

    wg.Wait()
    fmt.Println("所有请求完成")
}

3.3 sync.Once

确保函数只执行一次,常用于单例初始化:

package main

import (
    "fmt"
    "sync"
)

type Database struct {
    ConnectionString string
}

var (
    dbInstance *Database
    dbOnce     sync.Once
)

func GetDB() *Database {
    dbOnce.Do(func() {
        fmt.Println("初始化数据库连接(仅执行一次)")
        dbInstance = &Database{
            ConnectionString: "postgres://localhost:5432/mydb",
        }
    })
    return dbInstance
}

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            db := GetDB()
            fmt.Printf("Goroutine %d 获取到 DB: %s\n", id, db.ConnectionString)
        }(i)
    }
    wg.Wait()
}

3.4 sync.Pool

对象池,减少 GC 压力。适合频繁创建和销毁的临时对象:

package main

import (
    "bytes"
    "fmt"
    "sync"
)

var bufferPool = sync.Pool{
    New: func() interface{} {
        fmt.Println("创建新的 buffer")
        return new(bytes.Buffer)
    },
}

func processRequest(data string) string {
    // 从池中获取 buffer
    buf := bufferPool.Get().(*bytes.Buffer)
    defer func() {
        buf.Reset()
        bufferPool.Put(buf) // 用完归还
    }()

    buf.WriteString("处理结果: ")
    buf.WriteString(data)
    return buf.String()
}

func main() {
    // 第一次调用会创建新对象
    fmt.Println(processRequest("hello"))

    // 后续调用可能复用
    fmt.Println(processRequest("world"))

    // GC 可能会清除池中的对象
    // runtime.GC()
    // fmt.Println(processRequest("again"))
}

3.5 sync.Map

并发安全的 map,适合读多写少的场景:

package main

import (
    "fmt"
    "sync"
)

func main() {
    var m sync.Map

    // 存储
    m.Store("name", "Go")
    m.Store("version", 1.22)

    // 读取
    if val, ok := m.Load("name"); ok {
        fmt.Println("name:", val)
    }

    // LoadOrStore: 如果存在返回旧值,不存在则存储
    actual, loaded := m.LoadOrStore("name", "Rust")
    fmt.Printf("actual=%v, loaded=%v\n", actual, loaded) // Go, true

    // 遍历
    m.Range(func(key, value interface{}) bool {
        fmt.Printf("%v: %v\n", key, value)
        return true // 返回 false 停止遍历
    })

    // 删除
    m.Delete("version")
}

3.6 sync.Cond

条件变量,用于 goroutine 之间的协调通知:

package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    var mu sync.Mutex
    cond := sync.NewCond(&mu)
    ready := false

    // 等待者
    go func() {
        mu.Lock()
        for !ready {
            fmt.Println("等待就绪信号...")
            cond.Wait() // 释放锁并等待,被唤醒后重新获取锁
        }
        fmt.Println("收到信号,开始工作")
        mu.Unlock()
    }()

    // 通知者
    time.Sleep(2 * time.Second)
    mu.Lock()
    ready = true
    fmt.Println("发送就绪信号")
    cond.Signal() // 唤醒一个等待者
    // cond.Broadcast() // 唤醒所有等待者
    mu.Unlock()

    time.Sleep(time.Second)
}

4. context 包详解

4.1 Context 基础

Context 用于在 goroutine 之间传递截止时间、取消信号和请求范围的值。

package main

import (
    "context"
    "fmt"
    "time"
)

func worker(ctx context.Context, name string) {
    for {
        select {
        case <-ctx.Done():
            fmt.Printf("%s 收到取消信号: %v\n", name, ctx.Err())
            return
        default:
            fmt.Printf("%s 正在工作...\n", name)
            time.Sleep(500 * time.Millisecond)
        }
    }
}

func main() {
    // WithCancel: 手动取消
    ctx, cancel := context.WithCancel(context.Background())

    go worker(ctx, "worker-1")
    go worker(ctx, "worker-2")

    time.Sleep(2 * time.Second)
    cancel() // 发送取消信号
    time.Sleep(time.Second)
}

4.2 WithTimeout 与 WithDeadline

package main

import (
    "context"
    "fmt"
    "time"
)

func longRunningTask(ctx context.Context) (string, error) {
    // 模拟耗时操作
    select {
    case <-time.After(3 * time.Second):
        return "任务完成", nil
    case <-ctx.Done():
        return "", ctx.Err()
    }
}

func main() {
    // 设置 2 秒超时
    ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
    defer cancel()

    result, err := longRunningTask(ctx)
    if err != nil {
        fmt.Println("错误:", err) // 错误: context deadline exceeded
    } else {
        fmt.Println(result)
    }
}

4.3 WithValue 传递请求数据

package main

import (
    "context"
    "fmt"
)

type contextKey string

const (
    userIDKey   contextKey = "userID"
    requestIDKey contextKey = "requestID"
)

func processRequest(ctx context.Context) {
    userID := ctx.Value(userIDKey).(string)
    requestID := ctx.Value(requestIDKey).(string)

    fmt.Printf("处理请求 %s, 用户: %s\n", requestID, userID)

    // 传递给下游
    processBusinessLogic(ctx)
}

func processBusinessLogic(ctx context.Context) {
    userID := ctx.Value(userIDKey).(string)
    fmt.Printf("业务逻辑执行, 用户: %s\n", userID)
}

func main() {
    ctx := context.Background()
    ctx = context.WithValue(ctx, userIDKey, "user-123")
    ctx = context.WithValue(ctx, requestIDKey, "req-456")

    processRequest(ctx)
}

4.4 Context 传播的最佳实践

package main

import (
    "context"
    "fmt"
    "time"
)

// 错误示例:将 context 存储在结构体中
// type BadService struct {
//     ctx context.Context  // 不要这样做
// }

// 正确示例:将 context 作为函数第一个参数
type GoodService struct {
    name string
}

func (s *GoodService) DoWork(ctx context.Context, input string) (string, error) {
    select {
    case <-ctx.Done():
        return "", ctx.Err()
    case <-time.After(100 * time.Millisecond):
        return fmt.Sprintf("%s processed: %s", s.name, input), nil
    }
}

func main() {
    svc := &GoodService{name: "MyService"}
    ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    defer cancel()

    result, err := svc.DoWork(ctx, "hello")
    if err != nil {
        fmt.Println("错误:", err)
        return
    }
    fmt.Println(result)
}

5. 接口设计模式

5.1 接口隔离原则(ISP)

定义小而精的接口,只包含必要的方法:

package main

import "fmt"

// 不好的设计:大而全的接口
// type DataManager interface {
//     Read() []byte
//     Write(data []byte)
//     Delete() error
//     Backup() error
//     Restore() error
// }

// 好的设计:小接口组合
type Reader interface {
    Read() ([]byte, error)
}

type Writer interface {
    Write(data []byte) error
}

type Closer interface {
    Close() error
}

// 组合接口
type ReadWriter interface {
    Reader
    Writer
}

type ReadWriteCloser interface {
    Reader
    Writer
    Closer
}

// 实现
type FileStore struct {
    name string
}

func (f *FileStore) Read() ([]byte, error) {
    return []byte("data from " + f.name), nil
}

func (f *FileStore) Write(data []byte) error {
    fmt.Printf("写入 %s: %s\n", f.name, data)
    return nil
}

func (f *FileStore) Close() error {
    fmt.Printf("关闭 %s\n", f.name)
    return nil
}

// 函数只接收需要的接口
func processReader(r Reader) {
    data, _ := r.Read()
    fmt.Println("读取到:", string(data))
}

func main() {
    store := &FileStore{name: "test.txt"}
    processReader(store) // 只需要 Read 方法
}

5.2 函数式选项模式

用函数替代复杂的配置结构体:

package main

import (
    "crypto/tls"
    "fmt"
    "time"
)

type Server struct {
    host         string
    port         int
    timeout      time.Duration
    maxConns     int
    tlsConfig    *tls.Config
    enableDebug  bool
}

type Option func(*Server)

func WithHost(host string) Option {
    return func(s *Server) { s.host = host }
}

func WithPort(port int) Option {
    return func(s *Server) { s.port = port }
}

func WithTimeout(timeout time.Duration) Option {
    return func(s *Server) { s.timeout = timeout }
}

func WithMaxConns(n int) Option {
    return func(s *Server) { s.maxConns = n }
}

func WithDebug(enable bool) Option {
    return func(s *Server) { s.enableDebug = enable }
}

func NewServer(opts ...Option) *Server {
    // 默认值
    s := &Server{
        host:     "localhost",
        port:     8080,
        timeout:  30 * time.Second,
        maxConns: 100,
    }

    for _, opt := range opts {
        opt(s)
    }

    return s
}

func main() {
    server := NewServer(
        WithHost("0.0.0.0"),
        WithPort(9090),
        WithTimeout(60*time.Second),
        WithMaxConns(1000),
        WithDebug(true),
    )

    fmt.Printf("Server: %+v\n", server)
}

5.3 接口与依赖注入

package main

import (
    "errors"
    "fmt"
)

// 定义接口
type UserRepository interface {
    FindByID(id string) (*User, error)
    Save(user *User) error
}

type User struct {
    ID    string
    Name  string
    Email string
}

// 服务层依赖接口而非具体实现
type UserService struct {
    repo UserRepository
}

func NewUserService(repo UserRepository) *UserService {
    return &UserService{repo: repo}
}

func (s *UserService) GetUser(id string) (*User, error) {
    if id == "" {
        return nil, errors.New("用户ID不能为空")
    }
    return s.repo.FindByID(id)
}

// 生产环境实现
type PostgresUserRepo struct {
    connectionString string
}

func (r *PostgresUserRepo) FindByID(id string) (*User, error) {
    // 实际数据库查询
    return &User{ID: id, Name: "张三", Email: "zhangsan@example.com"}, nil
}

func (r *PostgresUserRepo) Save(user *User) error {
    fmt.Printf("保存用户到数据库: %+v\n", user)
    return nil
}

// 测试用 Mock
type MockUserRepo struct {
    users map[string]*User
}

func (m *MockUserRepo) FindByID(id string) (*User, error) {
    if user, ok := m.users[id]; ok {
        return user, nil
    }
    return nil, fmt.Errorf("用户 %s 不存在", id)
}

func (m *MockUserRepo) Save(user *User) error {
    m.users[user.ID] = user
    return nil
}

func main() {
    // 生产环境
    repo := &PostgresUserRepo{connectionString: "..."}
    svc := NewUserService(repo)
    user, _ := svc.GetUser("123")
    fmt.Printf("生产环境: %+v\n", user)

    // 测试环境
    mockRepo := &MockUserRepo{
        users: map[string]*User{
            "1": {ID: "1", Name: "测试用户", Email: "test@example.com"},
        },
    }
    testSvc := NewUserService(mockRepo)
    user, _ = testSvc.GetUser("1")
    fmt.Printf("测试环境: %+v\n", user)
}

5.4 类型断言与类型开关

package main

import "fmt"

type Shape interface {
    Area() float64
}

type Circle struct {
    Radius float64
}

func (c Circle) Area() float64 {
    return 3.14159 * c.Radius * c.Radius
}

type Rectangle struct {
    Width, Height float64
}

func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

func describeShape(s Shape) {
    // 类型开关
    switch v := s.(type) {
    case Circle:
        fmt.Printf("圆形,半径 %.2f,面积 %.2f\n", v.Radius, v.Area())
    case Rectangle:
        fmt.Printf("矩形,宽 %.2f 高 %.2f,面积 %.2f\n", v.Width, v.Height, v.Area())
    default:
        fmt.Printf("未知形状: %T\n", v)
    }

    // 类型断言
    if c, ok := s.(Circle); ok {
        fmt.Printf("这是一个圆形,半径: %.2f\n", c.Radius)
    }
}

func main() {
    describeShape(Circle{Radius: 5})
    describeShape(Rectangle{Width: 3, Height: 4})
}

6. 反射机制

6.1 reflect 基础

package main

import (
    "fmt"
    "reflect"
)

type User struct {
    Name  string `json:"name" validate:"required"`
    Age   int    `json:"age" validate:"min=0,max=150"`
    Email string `json:"email" validate:"required,email"`
}

func inspectType(v interface{}) {
    t := reflect.TypeOf(v)
    val := reflect.ValueOf(v)

    fmt.Printf("类型: %s\n", t.Name())
    fmt.Printf("种类: %s\n", t.Kind())

    if t.Kind() == reflect.Ptr {
        t = t.Elem()
        val = val.Elem()
    }

    if t.Kind() == reflect.Struct {
        fmt.Println("字段信息:")
        for i := 0; i < t.NumField(); i++ {
            field := t.Field(i)
            value := val.Field(i)
            fmt.Printf("  %s (%s) = %v | json=%s validate=%s\n",
                field.Name,
                field.Type,
                value,
                field.Tag.Get("json"),
                field.Tag.Get("validate"),
            )
        }
    }
}

func main() {
    user := User{Name: "张三", Age: 25, Email: "zhangsan@example.com"}
    inspectType(user)
}

6.2 反射修改值

package main

import (
    "fmt"
    "reflect"
)

func modifyValue(v interface{}) {
    val := reflect.ValueOf(v)

    // 必须传入指针才能修改
    if val.Kind() != reflect.Ptr {
        fmt.Println("错误:必须传入指针")
        return
    }

    val = val.Elem()

    switch val.Kind() {
    case reflect.String:
        val.SetString("修改后的值")
    case reflect.Int:
        val.SetInt(42)
    case reflect.Struct:
        // 修改结构体字段
        nameField := val.FieldByName("Name")
        if nameField.IsValid() && nameField.CanSet() {
            nameField.SetString("反射修改")
        }
    }
}

func main() {
    // 修改基本类型
    s := "原始值"
    modifyValue(&s)
    fmt.Println(s) // 修改后的值

    n := 0
    modifyValue(&n)
    fmt.Println(n) // 42

    // 修改结构体
    type Person struct {
        Name string
        Age  int
    }
    p := Person{Name: "原始", Age: 20}
    modifyValue(&p)
    fmt.Printf("%+v\n", p) // {Name:反射修改 Age:20}
}

6.3 反射实现通用验证器

package main

import (
    "fmt"
    "reflect"
    "strings"
)

type ValidationError struct {
    Field   string
    Message string
}

func (e ValidationError) Error() string {
    return fmt.Sprintf("%s: %s", e.Field, e.Message)
}

func Validate(s interface{}) []ValidationError {
    var errs []ValidationError
    val := reflect.ValueOf(s)
    typ := reflect.TypeOf(s)

    if typ.Kind() == reflect.Ptr {
        val = val.Elem()
        typ = typ.Elem()
    }

    if typ.Kind() != reflect.Struct {
        return errs
    }

    for i := 0; i < typ.NumField(); i++ {
        field := typ.Field(i)
        value := val.Field(i)
        tag := field.Tag.Get("validate")

        if tag == "" {
            continue
        }

        rules := strings.Split(tag, ",")

        for _, rule := range rules {
            rule = strings.TrimSpace(rule)

            switch {
            case rule == "required":
                if isZero(value) {
                    errs = append(errs, ValidationError{
                        Field:   field.Name,
                        Message: "不能为空",
                    })
                }
            case strings.HasPrefix(rule, "min="):
                // 简化的最小值检查
                if value.Kind() == reflect.Int {
                    // 解析 min 值并比较
                }
            }
        }
    }

    return errs
}

func isZero(v reflect.Value) bool {
    switch v.Kind() {
    case reflect.String:
        return v.String() == ""
    case reflect.Int, reflect.Int64:
        return v.Int() == 0
    case reflect.Bool:
        return !v.Bool()
    case reflect.Slice, reflect.Map:
        return v.IsNil() || v.Len() == 0
    default:
        return v.IsZero()
    }
}

type Request struct {
    Name  string `validate:"required"`
    Email string `validate:"required"`
    Age   int    `validate:"required"`
}

func main() {
    req := Request{Name: "", Email: "test@example.com", Age: 0}
    errs := Validate(req)

    if len(errs) > 0 {
        fmt.Println("验证失败:")
        for _, e := range errs {
            fmt.Printf("  - %s\n", e)
        }
    }
}

7. CGO 调用

7.1 调用 C 标准库

package main

/*
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// C 函数:计算字符串长度
int c_strlen(const char* s) {
    return strlen(s);
}

// C 函数:打印消息
void c_print(const char* msg) {
    printf("C says: %s\n", msg);
}
*/
import "C"
import (
    "fmt"
    "unsafe"
)

func main() {
    // 调用 C 函数
    cStr := C.CString("Hello from Go!")
    defer C.free(unsafe.Pointer(cStr))

    length := C.c_strlen(cStr)
    fmt.Printf("C 字符串长度: %d\n", length)

    C.c_print(cStr)
}

7.2 Go 调用 C 以及 C 调用 Go

package main

/*
#include <stdio.h>

// 声明 Go 函数(在 Go 侧导出)
extern void goCallback(int value);

// C 函数,接受回调
void c_iterate(int n, void (*callback)(int)) {
    for (int i = 0; i < n; i++) {
        callback(i);
    }
}

// 包装函数,调用 Go 回调
static void iterateWithGoCallback(int n) {
    c_iterate(n, goCallback);
}
*/
import "C"
import "fmt"

//export goCallback
func goCallback(value C.int) {
    fmt.Printf("Go 收到回调值: %d\n", int(value))
}

func main() {
    fmt.Println("C 调用 Go 回调:")
    C.iterateWithGoCallback(5)
}

7.3 CGO 性能注意事项

package main

/*
#include <math.h>

double c_sqrt(double x) {
    return sqrt(x);
}
*/
import "C"
import (
    "fmt"
    "math"
    "time"
)

func main() {
    n := 1000000

    // CGO 调用(有开销)
    start := time.Now()
    for i := 0; i < n; i++ {
        C.c_sqrt(C.double(float64(i)))
    }
    cgoTime := time.Since(start)

    // Go 原生调用
    start = time.Now()
    for i := 0; i < n; i++ {
        math.Sqrt(float64(i))
    }
    goTime := time.Since(start)

    fmt.Printf("CGO 调用: %v\n", cgoTime)
    fmt.Printf("Go 原生: %v\n", goTime)
    fmt.Printf("CGO 开销倍数: %.2fx\n", float64(cgoTime)/float64(goTime))
}

8. 性能分析(pprof)

8.1 CPU Profiling

package main

import (
    "fmt"
    "os"
    "runtime/pprof"
    "time"
)

func cpuIntensiveTask() int {
    sum := 0
    for i := 0; i < 10000000; i++ {
        sum += i * i
    }
    return sum
}

func main() {
    // 创建 CPU profile 文件
    f, err := os.Create("cpu.prof")
    if err != nil {
        fmt.Println("创建 profile 文件失败:", err)
        return
    }
    defer f.Close()

    // 开始 CPU profiling
    if err := pprof.StartCPUProfile(f); err != nil {
        fmt.Println("启动 CPU profiling 失败:", err)
        return
    }
    defer pprof.StopCPUProfile()

    // 执行要分析的代码
    for i := 0; i < 10; i++ {
        cpuIntensiveTask()
    }

    fmt.Println("CPU profile 已写入 cpu.prof")
    fmt.Println("分析命令: go tool pprof cpu.prof")
}

8.2 HTTP pprof(生产环境推荐)

package main

import (
    "fmt"
    "math/rand"
    "net/http"
    _ "net/http/pprof" // 导入即注册 pprof 路由
    "sync"
    "time"
)

var cache sync.Map

func simulateWork() {
    // 模拟内存分配
    data := make([]byte, 1024*1024)
    for i := range data {
        data[i] = byte(rand.Intn(256))
    }

    // 存入缓存(可能导致内存泄漏)
    key := fmt.Sprintf("key-%d", time.Now().UnixNano())
    cache.Store(key, data)
}

func main() {
    // 启动后台工作
    go func() {
        for {
            simulateWork()
            time.Sleep(100 * time.Millisecond)
        }
    }()

    fmt.Println("pprof 服务启动在 :6060")
    fmt.Println("访问 http://localhost:6060/debug/pprof/ 查看")
    fmt.Println("CPU profile: go tool pprof http://localhost:6060/debug/pprof/profile")
    fmt.Println("Heap profile: go tool pprof http://localhost:6060/debug/pprof/heap")
    fmt.Println("Goroutine: go tool pprof http://localhost:6060/debug/pprof/goroutine")

    if err := http.ListenAndServe(":6060", nil); err != nil {
        fmt.Println("服务启动失败:", err)
    }
}

8.3 内存 Profiling

package main

import (
    "fmt"
    "os"
    "runtime"
    "runtime/pprof"
)

func allocateMemory() [][]byte {
    slices := make([][]byte, 100)
    for i := range slices {
        slices[i] = make([]byte, 1024*1024) // 1MB
    }
    return slices
}

func main() {
    data := allocateMemory()

    // 强制 GC,获取准确的内存统计
    runtime.GC()

    f, err := os.Create("mem.prof")
    if err != nil {
        fmt.Println("创建文件失败:", err)
        return
    }
    defer f.Close()

    if err := pprof.WriteHeapProfile(f); err != nil {
        fmt.Println("写入 heap profile 失败:", err)
        return
    }

    fmt.Println("Heap profile 已写入 mem.prof")
    fmt.Println("分析命令: go tool pprof -alloc_space mem.prof")

    // 防止 data 被优化掉
    _ = data
}

8.4 Trace 分析

package main

import (
    "fmt"
    "os"
    "runtime/trace"
    "time"
)

func main() {
    f, err := os.Create("trace.out")
    if err != nil {
        fmt.Println("创建文件失败:", err)
        return
    }
    defer f.Close()

    // 开始 trace
    if err := trace.Start(f); err != nil {
        fmt.Println("启动 trace 失败:", err)
        return
    }
    defer trace.Stop()

    // 执行要分析的代码
    ch := make(chan int, 10)
    go func() {
        for i := 0; i < 10; i++ {
            ch <- i
            time.Sleep(50 * time.Millisecond)
        }
        close(ch)
    }()

    for v := range ch {
        fmt.Println("收到:", v)
    }

    fmt.Println("Trace 已写入 trace.out")
    fmt.Println("分析命令: go tool trace trace.out")
}

9. 测试与基准测试

9.1 单元测试

// calculator.go
package calculator

func Add(a, b int) int {
    return a + b
}

func Divide(a, b float64) (float64, error) {
    if b == 0 {
        return 0, fmt.Errorf("除数不能为零")
    }
    return a / b, nil
}
// calculator_test.go
package calculator

import (
    "testing"
)

func TestAdd(t *testing.T) {
    result := Add(1, 2)
    if result != 3 {
        t.Errorf("Add(1, 2) = %d; 期望 3", result)
    }
}

func TestDivide(t *testing.T) {
    // 表驱动测试
    tests := []struct {
        name    string
        a, b    float64
        want    float64
        wantErr bool
    }{
        {"正常除法", 10, 2, 5, false},
        {"除以零", 10, 0, 0, true},
        {"负数", -10, 2, -5, false},
        {"小数", 7, 2, 3.5, false},
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            got, err := Divide(tt.a, tt.b)
            if (err != nil) != tt.wantErr {
                t.Errorf("Divide(%v, %v) error = %v, wantErr %v",
                    tt.a, tt.b, err, tt.wantErr)
                return
            }
            if !tt.wantErr && got != tt.want {
                t.Errorf("Divide(%v, %v) = %v, want %v",
                    tt.a, tt.b, got, tt.want)
            }
        })
    }
}

9.2 子测试与并行测试

package user

import (
    "testing"
    "time"
)

func TestUserService(t *testing.T) {
    t.Run("创建用户", func(t *testing.T) {
        t.Parallel() // 并行执行
        time.Sleep(100 * time.Millisecond)
        // 测试创建逻辑
    })

    t.Run("查询用户", func(t *testing.T) {
        t.Parallel()
        time.Sleep(100 * time.Millisecond)
        // 测试查询逻辑
    })

    t.Run("更新用户", func(t *testing.T) {
        t.Parallel()
        time.Sleep(100 * time.Millisecond)
        // 测试更新逻辑
    })
}

9.3 Mock 与接口测试

// email.go
package email

type Sender interface {
    Send(to, subject, body string) error
}

type Service struct {
    sender Sender
}

func NewService(sender Sender) *Service {
    return &Service{sender: sender}
}

func (s *Service) WelcomeEmail(to, name string) error {
    body := "欢迎 " + name + " 加入我们!"
    return s.sender.Send(to, "欢迎邮件", body)
}
// email_test.go
package email

import (
    "errors"
    "testing"
)

type MockSender struct {
    Calls   []SendCall
    FailAll bool
}

type SendCall struct {
    To, Subject, Body string
}

func (m *MockSender) Send(to, subject, body string) error {
    m.Calls = append(m.Calls, SendCall{to, subject, body})
    if m.FailAll {
        return errors.New("发送失败")
    }
    return nil
}

func TestWelcomeEmail(t *testing.T) {
    mock := &MockSender{}
    svc := NewService(mock)

    err := svc.WelcomeEmail("test@example.com", "张三")
    if err != nil {
        t.Fatalf("意外错误: %v", err)
    }

    if len(mock.Calls) != 1 {
        t.Fatalf("期望 1 次调用,实际 %d 次", len(mock.Calls))
    }

    call := mock.Calls[0]
    if call.To != "test@example.com" {
        t.Errorf("收件人: got %s, want test@example.com", call.To)
    }
    if call.Subject != "欢迎邮件" {
        t.Errorf("主题: got %s, want 欢迎邮件", call.Subject)
    }
}

func TestWelcomeEmail_Failure(t *testing.T) {
    mock := &MockSender{FailAll: true}
    svc := NewService(mock)

    err := svc.WelcomeEmail("test@example.com", "张三")
    if err == nil {
        t.Error("期望错误,实际为 nil")
    }
}

9.4 基准测试

package performance

import (
    "strings"
    "testing"
)

// 方法1:字符串拼接
func ConcatStrings(n int) string {
    s := ""
    for i := 0; i < n; i++ {
        s += "a"
    }
    return s
}

// 方法2:strings.Builder
func BuilderStrings(n int) string {
    var b strings.Builder
    b.Grow(n) // 预分配
    for i := 0; i < n; i++ {
        b.WriteByte('a')
    }
    return b.String()
}

// 方法3:bytes.Buffer
func BufferStrings(n int) string {
    buf := make([]byte, 0, n)
    for i := 0; i < n; i++ {
        buf = append(buf, 'a')
    }
    return string(buf)
}

func BenchmarkConcat(b *testing.B) {
    for i := 0; i < b.N; i++ {
        ConcatStrings(1000)
    }
}

func BenchmarkBuilder(b *testing.B) {
    for i := 0; i < b.N; i++ {
        BuilderStrings(1000)
    }
}

func BenchmarkBuffer(b *testing.B) {
    for i := 0; i < b.N; i++ {
        BufferStrings(1000)
    }
}

// 子基准测试
func BenchmarkConcatLengths(b *testing.B) {
    for _, size := range []int{10, 100, 1000, 10000} {
        b.Run(strings.Repeat("a", 1), func(b *testing.B) {
            for i := 0; i < b.N; i++ {
                ConcatStrings(size)
            }
        })
    }
}

运行基准测试:

go test -bench=. -benchmem -count=3
go test -bench=. -cpuprofile=cpu.prof -memprofile=mem.prof

9.5 Example 测试(文档级测试)

package calculator

import "fmt"

func ExampleAdd() {
    fmt.Println(Add(1, 2))
    // Output: 3
}

func ExampleDivide() {
    result, err := Divide(10, 3)
    if err != nil {
        fmt.Println("错误:", err)
        return
    }
    fmt.Printf("%.2f\n", result)
    // Output: 3.33
}

10. 微服务开发(gRPC)

10.1 Protobuf 定义

// user.proto
syntax = "proto3";

package user;

option go_package = "./pb";

service UserService {
    rpc GetUser(GetUserRequest) returns (UserResponse);
    rpc ListUsers(ListUsersRequest) returns (stream UserResponse); // 服务端流
    rpc CreateUser(CreateUserRequest) returns (UserResponse);
}

message GetUserRequest {
    string id = 1;
}

message ListUsersRequest {
    int32 page = 1;
    int32 page_size = 2;
}

message CreateUserRequest {
    string name = 1;
    string email = 2;
    int32 age = 3;
}

message UserResponse {
    string id = 1;
    string name = 2;
    string email = 3;
    int32 age = 4;
}

生成 Go 代码:

protoc --go_out=. --go-grpc_out=. user.proto

10.2 gRPC 服务端实现

package main

import (
    "context"
    "fmt"
    "log"
    "net"

    "google.golang.org/grpc"
    pb "your-module/pb"
)

type userService struct {
    pb.UnimplementedUserServiceServer
    users map[string]*pb.UserResponse
}

func (s *userService) GetUser(ctx context.Context, req *pb.GetUserRequest) (*pb.UserResponse, error) {
    user, ok := s.users[req.Id]
    if !ok {
        return nil, fmt.Errorf("用户 %s 不存在", req.Id)
    }
    return user, nil
}

func (s *userService) ListUsers(req *pb.ListUsersRequest, stream pb.UserService_ListUsersServer) error {
    start := int((req.Page - 1) * req.PageSize)
    count := 0
    for _, user := range s.users {
        if count >= start && count < start+int(req.PageSize) {
            if err := stream.Send(user); err != nil {
                return err
            }
        }
        count++
    }
    return nil
}

func (s *userService) CreateUser(ctx context.Context, req *pb.CreateUserRequest) (*pb.UserResponse, error) {
    id := fmt.Sprintf("user-%d", len(s.users)+1)
    user := &pb.UserResponse{
        Id:    id,
        Name:  req.Name,
        Email: req.Email,
        Age:   req.Age,
    }
    s.users[id] = user
    return user, nil
}

func main() {
    lis, err := net.Listen("tcp", ":50051")
    if err != nil {
        log.Fatalf("监听失败: %v", err)
    }

    srv := grpc.NewServer()
    pb.RegisterUserServiceServer(srv, &userService{
        users: make(map[string]*pb.UserResponse),
    })

    fmt.Println("gRPC 服务启动在 :50051")
    if err := srv.Serve(lis); err != nil {
        log.Fatalf("服务失败: %v", err)
    }
}

10.3 gRPC 客户端

package main

import (
    "context"
    "fmt"
    "io"
    "log"
    "time"

    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials/insecure"
    pb "your-module/pb"
)

func main() {
    conn, err := grpc.Dial("localhost:50051",
        grpc.WithTransportCredentials(insecure.NewCredentials()),
    )
    if err != nil {
        log.Fatalf("连接失败: %v", err)
    }
    defer conn.Close()

    client := pb.NewUserServiceClient(conn)
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()

    // 创建用户
    user, err := client.CreateUser(ctx, &pb.CreateUserRequest{
        Name:  "张三",
        Email: "zhangsan@example.com",
        Age:   25,
    })
    if err != nil {
        log.Fatalf("创建用户失败: %v", err)
    }
    fmt.Printf("创建用户: %+v\n", user)

    // 获取用户
    user, err = client.GetUser(ctx, &pb.GetUserRequest{Id: user.Id})
    if err != nil {
        log.Fatalf("获取用户失败: %v", err)
    }
    fmt.Printf("获取用户: %+v\n", user)

    // 流式获取用户列表
    stream, err := client.ListUsers(ctx, &pb.ListUsersRequest{
        Page:     1,
        PageSize: 10,
    })
    if err != nil {
        log.Fatalf("列表失败: %v", err)
    }

    for {
        user, err := stream.Recv()
        if err == io.EOF {
            break
        }
        if err != nil {
            log.Fatalf("接收失败: %v", err)
        }
        fmt.Printf("流式用户: %+v\n", user)
    }
}

10.4 gRPC 拦截器(中间件)

package main

import (
    "context"
    "log"
    "time"

    "google.golang.org/grpc"
    "google.golang.org/grpc/codes"
    "google.golang.org/grpc/metadata"
    "google.golang.org/grpc/status"
)

// 日志拦截器
func loggingInterceptor(
    ctx context.Context,
    req interface{},
    info *grpc.UnaryServerInfo,
    handler grpc.UnaryHandler,
) (interface{}, error) {
    start := time.Now()

    // 从 metadata 获取请求 ID
    md, _ := metadata.FromIncomingContext(ctx)
    requestID := ""
    if ids := md.Get("x-request-id"); len(ids) > 0 {
        requestID = ids[0]
    }

    log.Printf("[gRPC] %s | %s | 开始", requestID, info.FullMethod)

    // 调用实际处理函数
    resp, err := handler(ctx, req)

    duration := time.Since(start)
    code := codes.OK
    if err != nil {
        code = status.Code(err)
    }

    log.Printf("[gRPC] %s | %s | %v | %v", requestID, info.FullMethod, code, duration)

    return resp, err
}

// 认证拦截器
func authInterceptor(
    ctx context.Context,
    req interface{},
    info *grpc.UnaryServerInfo,
    handler grpc.UnaryHandler,
) (interface{}, error) {
    // 跳过健康检查
    if info.FullMethod == "/grpc.health.v1.Health/Check" {
        return handler(ctx, req)
    }

    md, ok := metadata.FromIncomingContext(ctx)
    if !ok {
        return nil, status.Error(codes.Unauthenticated, "缺少 metadata")
    }

    tokens := md.Get("authorization")
    if len(tokens) == 0 {
        return nil, status.Error(codes.Unauthenticated, "缺少认证信息")
    }

    // 验证 token(简化示例)
    if tokens[0] != "valid-token" {
        return nil, status.Error(codes.Unauthenticated, "认证失败")
    }

    return handler(ctx, req)
}

func main() {
    // 注册拦截器
    srv := grpc.NewServer(
        grpc.UnaryInterceptor(loggingInterceptor),
        // 可以链式组合多个拦截器
        // grpc.ChainUnaryInterceptor(authInterceptor, loggingInterceptor),
    )

    _ = srv
}

11. 实战项目:高性能微服务网关

11.1 项目架构

api-gateway/
├── main.go              # 入口
├── config/
│   └── config.go        # 配置管理
├── gateway/
│   ├── gateway.go       # 网关核心
│   ├── router.go        # 路由匹配
│   ├── middleware.go     # 中间件链
│   └── balancer.go      # 负载均衡
├── proxy/
│   └── proxy.go         # 反向代理
├── ratelimit/
│   └── limiter.go       # 限流器
└── go.mod

11.2 网关核心实现

// gateway/gateway.go
package gateway

import (
    "context"
    "fmt"
    "log"
    "net/http"
    "net/http/httputil"
    "net/url"
    "sync"
    "sync/atomic"
    "time"
)

// Backend 后端服务
type Backend struct {
    URL          *url.URL
    Alive        bool
    Weight       int
    connections  int64
    mu           sync.RWMutex
}

func (b *Backend) SetAlive(alive bool) {
    b.mu.Lock()
    b.Alive = alive
    b.mu.Unlock()
}

func (b *Backend) IsAlive() bool {
    b.mu.RLock()
    defer b.mu.RUnlock()
    return b.Alive
}

func (b *Backend) AddConnection() {
    atomic.AddInt64(&b.connections, 1)
}

func (b *Backend) RemoveConnection() {
    atomic.AddInt64(&b.connections, -1)
}

func (b *Backend) GetConnections() int64 {
    return atomic.LoadInt64(&b.connections)
}

// ServerPool 服务器池
type ServerPool struct {
    backends []*Backend
    current  uint64
    mu       sync.RWMutex
}

func (s *ServerPool) AddBackend(b *Backend) {
    s.mu.Lock()
    s.backends = append(s.backends, b)
    s.mu.Unlock()
}

func (s *ServerPool) GetBackends() []*Backend {
    s.mu.RLock()
    defer s.mu.RUnlock()
    return s.backends
}

// NextIndex 获取下一个索引(轮询)
func (s *ServerPool) NextIndex() int {
    return int(atomic.AddUint64(&s.current, 1) % uint64(len(s.backends)))
}

// GetNextPeer 获取下一个可用后端(加权轮询)
func (s *ServerPool) GetNextPeer() *Backend {
    next := s.NextIndex()
    total := len(s.backends)
    end := next + total

    for i := next; i < end; i++ {
        idx := i % total
        if s.backends[idx].IsAlive() {
            if i != next {
                atomic.StoreUint64(&s.current, uint64(idx))
            }
            return s.backends[idx]
        }
    }
    return nil
}

// Gateway 网关
type Gateway struct {
    pool        *ServerPool
    server      *http.Server
    healthCheck time.Duration
}

func NewGateway(addr string, healthCheck time.Duration) *Gateway {
    return &Gateway{
        pool:        &ServerPool{},
        healthCheck: healthCheck,
        server: &http.Server{
            Addr:         addr,
            ReadTimeout:  10 * time.Second,
            WriteTimeout: 10 * time.Second,
            IdleTimeout:  120 * time.Second,
        },
    }
}

func (g *Gateway) AddBackend(rawURL string, weight int) error {
    u, err := url.Parse(rawURL)
    if err != nil {
        return err
    }
    g.pool.AddBackend(&Backend{
        URL:    u,
        Alive:  true,
        Weight: weight,
    })
    return nil
}

func (g *Gateway) lb(w http.ResponseWriter, r *http.Request) {
    peer := g.pool.GetNextPeer()
    if peer == nil {
        http.Error(w, "服务不可用", http.StatusServiceUnavailable)
        return
    }

    peer.AddConnection()
    defer peer.RemoveConnection()

    proxy := httputil.NewSingleHostReverseProxy(peer.URL)
    proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
        log.Printf("代理错误: %v", err)
        peer.SetAlive(false)
        http.Error(w, "服务错误", http.StatusBadGateway)
    }

    proxy.ServeHTTP(w, r)
}

func (g *Gateway) healthCheckLoop(ctx context.Context) {
    ticker := time.NewTicker(g.healthCheck)
    defer ticker.Stop()

    for {
        select {
        case <-ctx.Done():
            return
        case <-ticker.C:
            for _, b := range g.pool.GetBackends() {
                alive := isBackendAlive(b.URL)
                b.SetAlive(alive)
                status := "down"
                if alive {
                    status = "up"
                }
                log.Printf("后端 %s 状态: %s (连接数: %d)",
                    b.URL, status, b.GetConnections())
            }
        }
    }
}

func isBackendAlive(u *url.URL) bool {
    client := &http.Client{Timeout: 2 * time.Second}
    resp, err := client.Get(u.String() + "/health")
    if err != nil {
        return false
    }
    defer resp.Body.Close()
    return resp.StatusCode == http.StatusOK
}

func (g *Gateway) Start(ctx context.Context) error {
    // 启动健康检查
    go g.healthCheckLoop(ctx)

    g.server.Handler = http.HandlerFunc(g.lb)

    go func() {
        <-ctx.Done()
        shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
        defer cancel()
        g.server.Shutdown(shutdownCtx)
    }()

    log.Printf("网关启动在 %s", g.server.Addr)
    return g.server.ListenAndServe()
}

11.3 中间件链

// gateway/middleware.go
package gateway

import (
    "log"
    "net/http"
    "time"
)

type Middleware func(http.Handler) http.Handler

// Chain 中间件链
func Chain(middlewares ...Middleware) Middleware {
    return func(next http.Handler) http.Handler {
        for i := len(middlewares) - 1; i >= 0; i-- {
            next = middlewares[i](next)
        }
        return next
    }
}

// Logging 日志中间件
func Logging() Middleware {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            start := time.Now()
            next.ServeHTTP(w, r)
            log.Printf("[%s] %s %s %v",
                r.Method, r.URL.Path, r.RemoteAddr, time.Since(start))
        })
    }
}

// Recovery panic 恢复中间件
func Recovery() Middleware {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            defer func() {
                if err := recover(); err != nil {
                    log.Printf("Panic: %v", err)
                    http.Error(w, "Internal Server Error", 500)
                }
            }()
            next.ServeHTTP(w, r)
        })
    }
}

// RateLimit 限流中间件(令牌桶)
func RateLimit(rps int) Middleware {
    limiter := NewTokenBucket(rps)
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            if !limiter.Allow() {
                http.Error(w, "Too Many Requests", http.StatusTooManyRequests)
                return
            }
            next.ServeHTTP(w, r)
        })
    }
}

// CORS 跨域中间件
func CORS() Middleware {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            w.Header().Set("Access-Control-Allow-Origin", "*")
            w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
            w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")

            if r.Method == "OPTIONS" {
                w.WriteHeader(http.StatusOK)
                return
            }

            next.ServeHTTP(w, r)
        })
    }
}

11.4 令牌桶限流器

// ratelimit/limiter.go
package ratelimit

import (
    "sync"
    "time"
)

// TokenBucket 令牌桶限流器
type TokenBucket struct {
    rate       float64   // 每秒产生的令牌数
    capacity   float64   // 桶容量
    tokens     float64   // 当前令牌数
    lastRefill time.Time // 上次补充时间
    mu         sync.Mutex
}

func NewTokenBucket(rate, capacity float64) *TokenBucket {
    return &TokenBucket{
        rate:       rate,
        capacity:   capacity,
        tokens:     capacity,
        lastRefill: time.Now(),
    }
}

func (tb *TokenBucket) Allow() bool {
    tb.mu.Lock()
    defer tb.mu.Unlock()

    now := time.Now()
    elapsed := now.Sub(tb.lastRefill).Seconds()
    tb.lastRefill = now

    // 补充令牌
    tb.tokens += elapsed * tb.rate
    if tb.tokens > tb.capacity {
        tb.tokens = tb.capacity
    }

    if tb.tokens >= 1 {
        tb.tokens--
        return true
    }

    return false
}

// 分布式限流器(基于 Redis 的滑动窗口)
type SlidingWindowLimiter struct {
    window   time.Duration
    maxCount int
    // 实际实现需要 Redis
}

func NewSlidingWindowLimiter(window time.Duration, maxCount int) *SlidingWindowLimiter {
    return &SlidingWindowLimiter{
        window:   window,
        maxCount: maxCount,
    }
}

func (l *SlidingWindowLimiter) Allow(key string) bool {
    // 伪代码:实际需要 Redis ZRANGEBYSCORE + ZADD
    // now := time.Now().UnixMilli()
    // windowStart := now - l.window.Milliseconds()
    //
    // // 删除窗口外的记录
    // redis.ZREMRANGEBYSCORE(key, 0, windowStart)
    //
    // // 计数
    // count := redis.ZCARD(key)
    //
    // if count < l.maxCount {
    //     redis.ZADD(key, now, uuid)
    //     redis.EXPIRE(key, l.window)
    //     return true
    // }
    // return false
    return true
}

11.5 基于前缀树的路由匹配

// gateway/router.go
package gateway

import (
    "net/http"
    "strings"
)

type Route struct {
    Method  string
    Path    string
    Handler http.Handler
}

type Router struct {
    routes []*Route
    trie   *TrieNode
}

type TrieNode struct {
    children map[string]*TrieNode
    handler  http.Handler
    param    string
}

func NewRouter() *Router {
    return &Router{
        trie: &TrieNode{children: make(map[string]*TrieNode)},
    }
}

func (r *Router) Handle(method, path string, handler http.Handler) {
    r.routes = append(r.routes, &Route{
        Method:  method,
        Path:    path,
        Handler: handler,
    })

    // 构建前缀树
    parts := strings.Split(strings.Trim(path, "/"), "/")
    node := r.trie
    for _, part := range parts {
        if node.children[part] == nil {
            node.children[part] = &TrieNode{
                children: make(map[string]*TrieNode),
            }
        }
        node = node.children[part]
    }
    node.handler = handler
}

func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    parts := strings.Split(strings.Trim(req.URL.Path, "/"), "/")
    params := make(map[string]string)

    node := r.trie
    for _, part := range parts {
        if child, ok := node.children[part]; ok {
            node = child
        } else if child, ok := node.children[":"]; ok {
            // 参数匹配
            node = child
            if node.param != "" {
                params[node.param] = part
            }
        } else {
            http.NotFound(w, req)
            return
        }
    }

    if node.handler == nil {
        http.NotFound(w, req)
        return
    }

    // 将参数存入 context
    ctx := req.Context()
    for k, v := range params {
        ctx = context.WithValue(ctx, k, v)
    }
    node.handler.ServeHTTP(w, req.WithContext(ctx))
}

11.6 使用示例

// main.go
package main

import (
    "context"
    "fmt"
    "log"
    "os"
    "os/signal"
    "syscall"
    "time"

    "your-module/gateway"
)

func main() {
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    // 创建网关
    gw := gateway.NewGateway(":8080", 10*time.Second)

    // 添加后端服务
    backends := []struct {
        URL    string
        Weight int
    }{
        {"http://localhost:8081", 5},
        {"http://localhost:8082", 3},
        {"http://localhost:8083", 2},
    }

    for _, b := range backends {
        if err := gw.AddBackend(b.URL, b.Weight); err != nil {
            log.Fatalf("添加后端失败: %v", err)
        }
    }

    // 注册中间件
    handler := gateway.Chain(
        gateway.Recovery(),
        gateway.Logging(),
        gateway.CORS(),
        gateway.RateLimit(1000), // 每秒 1000 请求
    )(gw.Handler())

    gw.SetHandler(handler)

    // 优雅关闭
    go func() {
        sigCh := make(chan os.Signal, 1)
        signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
        <-sigCh
        fmt.Println("\n收到关闭信号,正在优雅关闭...")
        cancel()
    }()

    // 启动网关
    if err := gw.Start(ctx); err != nil {
        log.Fatalf("网关启动失败: %v", err)
    }

    fmt.Println("网关已关闭")
}

11.7 性能优化要点

package main

import (
    "fmt"
    "net"
    "net/http"
    "runtime"
    "sync"
    "time"
)

// 优化1:连接池复用
func createTransport() *http.Transport {
    return &http.Transport{
        MaxIdleConns:        1000,
        MaxIdleConnsPerHost: 100,
        MaxConnsPerHost:     1000,
        IdleConnTimeout:     90 * time.Second,
        DisableCompression:  false,
        // 使用 Unix Domain Socket 减少网络开销
        DialContext: (&net.Dialer{
            Timeout:   5 * time.Second,
            KeepAlive: 30 * time.Second,
        }).DialContext,
    }
}

// 优化2:对象池减少 GC
var (
    responsePool = sync.Pool{
        New: func() interface{} {
            return make([]byte, 0, 4096)
        },
    }
)

// 优化3:并发控制
type ConcurrencyLimiter struct {
    sem chan struct{}
}

func NewConcurrencyLimiter(max int) *ConcurrencyLimiter {
    return &ConcurrencyLimiter{sem: make(chan struct{}, max)}
}

func (cl *ConcurrencyLimiter) Acquire() {
    cl.sem <- struct{}{}
}

func (cl *ConcurrencyLimiter) Release() {
    <-cl.sem
}

func main() {
    // 设置 GOMAXPROCS
    runtime.GOMAXPROCS(runtime.NumCPU())

    // 配置 HTTP 服务器
    srv := &http.Server{
        Addr:    ":8080",
        Handler: http.HandlerFunc(handler),
    }

    // 设置 TCP 优化
    ln, err := net.Listen("tcp", srv.Addr)
    if err != nil {
        log.Fatal(err)
    }

    // 设置 TCP keepalive
    if tcpLn, ok := ln.(*net.TCPListener); ok {
        tcpLn.SetDeadline(time.Time{})
    }

    fmt.Printf("服务器启动在 %s,CPU 核心数: %d\n", srv.Addr, runtime.NumCPU())
    srv.Serve(ln)
}

总结

本教程涵盖了 Go 语言高级编程的核心主题:

主题 关键知识点
Goroutine GMP 调度、泄漏检测、Goexit/Gosched
Channel Fan-Out/Fan-In、Pipeline、信号量、Or-Done
sync 包 Mutex、WaitGroup、Once、Pool、Map、Cond
context 取消传播、超时控制、值传递
接口设计 ISP、函数式选项、依赖注入、类型断言
反射 类型检查、值修改、通用验证器
CGO 调用 C 函数、回调、性能开销
pprof CPU/内存/Trace 分析、HTTP pprof
测试 表驱动、Mock、基准测试、Example
gRPC Protobuf、服务端/客户端、拦截器
实战 微服务网关、限流、路由、性能优化

进一步学习建议

  1. 阅读 Go 官方文档 Effective Go
  2. 研究 Go 语言设计与实现 了解底层原理
  3. 实践开源项目:Kubernetes、etcd、Docker 等
  4. 关注 Go 团队的提案和新版本特性

本教程内容原创,示例代码可直接运行。建议结合实际项目练习,加深理解。

内容声明

本文内容为AI技术学习教程,仅供学习参考。如涉及技术问题,欢迎通过 xurj005@163.com 与我们交流。

目录