mcpField
G
golang-backend-development

golang-backend-development

github.com/manutej开发621.4k 次安装40 周前更新
代码仓库

关于 golang-backend-development

面向 Go 后端开发者的技能指南,涵盖并发编程、Web 服务、数据库集成和部署模式。通过代码示例介绍构建可扩展后端所需的核心模式。

主要功能

  1. 01goroutine 与 channel 并发模式
  2. 02HTTP 服务与 REST API
  3. 03Context 与任务协调
  4. 04工作池和数据处理管线
  5. 05数据库连接管理

适用场景

  1. 01构建并发 HTTP 服务
  2. 02实现微服务和 REST API
  3. 03编写并行数据处理任务

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/manutej/luxor-claude-marketplace --skill golang-backend-development

安装后在 Claude Code 中输入/golang-backend-development确认已加载。

附带文件EXAMPLES.mdREADME.md

详细介绍

Go 后端开发

用于使用 Go 构建生产级后端系统的综合技能。掌握 goroutine、channel、Web 服务器、数据库集成、微服务架构和部署模式,以构建可扩展的并发后端应用程序。

适用场景

在以下情况下使用此技能:

  • 构建高性能 Web 服务器和 REST API
  • 使用 gRPC 或 HTTP 开发微服务架构
  • 使用 goroutine 和 channel 实现并发处理
  • 创建需要高吞吐量的实时系统
  • 构建采用连接池的数据库驱动应用程序
  • 开发用于容器化部署的云原生应用程序
  • 编写对性能要求严苛的后端服务
  • 使用服务发现构建分布式系统
  • 实现事件驱动架构
  • 创建具备网络功能的 CLI 工具和系统实用程序
  • 开发用于实时通信的 WebSocket 服务器
  • 使用并发工作器构建数据处理管道

Go 擅长:

  • 网络编程和 HTTP 服务
  • 使用轻量级 goroutine 进行并发处理
  • 带垃圾回收的系统级编程
  • 跨平台编译
  • 快速编译,加快开发速度
  • 内置测试和基准测试

核心概念

1. Goroutine:轻量级并发

Goroutine 是由 Go 运行时管理的轻量级线程。它们能够以极低的开销实现并发执行。

主要特点:

  • 极其轻量(初始栈约为 2 KB)
  • 由运行时复用到 OS 线程上
  • 可同时运行数千甚至数百万个
  • 由集成调度器进行协作式调度

基本 Goroutine 模式:

func main() {
    // Launch concurrent computation
    go expensiveComputation(x, y, z)
    anotherExpensiveComputation(a, b, c)
}

go 关键字会启动一个新的 goroutine,使 expensiveComputation 能够与 anotherExpensiveComputation 并发运行。这是 Go 并发模型的基础。

常见用例:

  • 后台处理
  • 并发 API 调用
  • 并行数据处理
  • 实时事件处理
  • 服务器中的连接处理
2. Channel:安全通信

Channel 可在 goroutine 之间提供类型安全的通信,在许多场景下无需显式加锁。

Channel 类型:

// Unbuffered channel - synchronous communication
ch := make(chan int)

// Buffered channel - asynchronous up to buffer size
ch := make(chan int, 100)

// Read-only channel
func receive(ch <-chan int) { /* ... */ }

// Write-only channel
func send(ch chan<- int) { /* ... */ }

使用 Channel 进行同步:

func computeAndSend(ch chan int, x, y, z int) {
    ch <- expensiveComputation(x, y, z)
}

func main() {
    ch := make(chan int)
    go computeAndSend(ch, x, y, z)
    v2 := anotherExpensiveComputation(a, b, c)
    v1 := <-ch  // Block until result available
    fmt.Println(v1, v2)
}

此模式可确保两项计算都完成后再继续,Channel 同时提供通信和同步功能。

Channel 模式:

  • 生产者—消费者
  • 扇出/扇入
  • 管道阶段
  • 超时和取消
  • 信号量和速率限制
3. Select 语句:多路复用 Channel

select 语句可以对多个 Channel 操作进行多路复用,类似于用于 Channel 的 switch。

超时实现:

timeout := make(chan bool, 1)
go func() {
    time.Sleep(1 * time.Second)
    timeout <- true
}()

select {
case <-ch:
    // Read from ch succeeded
case <-timeout:
    // Operation timed out
}

基于 Context 的取消:

select {
case result := <-resultCh:
    return result
case <-ctx.Done():
    return ctx.Err()
}
4. Context 包:请求范围的值

context.Context 接口用于管理截止时间、取消信号以及跨 API 边界传递的请求范围值。

Context 接口:

type Context interface {
    // Done returns a channel closed when work should be canceled
    Done() <-chan struct{}

    // Err returns why context was canceled
    Err() error

    // Deadline returns when work should be canceled
    Deadline() (deadline time.Time, ok bool)

    // Value returns request-scoped value
    Value(key any) any
}

创建 Context:

// Background context - never canceled
ctx := context.Background()

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

// With timeout
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

// With deadline
deadline := time.Now().Add(10 * time.Second)
ctx, cancel := context.WithDeadline(context.Background(), deadline)
defer cancel()

// With values
ctx = context.WithValue(parentCtx, key, value)

最佳实践:

  • 始终将 context 作为第一个参数传递:func DoSomething(ctx context.Context, ...)
  • 创建可取消的 context 后,立即调用 defer cancel()
  • 在调用链中传递 context
  • 在长时间运行的操作中检查 ctx.Done()
  • context 值仅用于请求范围的数据,不要用于可选参数
5. WaitGroup:协调 Goroutine

sync.WaitGroup 用于等待一组 goroutine 完成。

基本模式:

var wg sync.WaitGroup

for i := 0; i < 10; i++ {
    wg.Add(1)
    go func(id int) {
        defer wg.Done()
        // Do work
    }(i)
}

wg.Wait()  // Block until all goroutines complete

常见用例:

  • 等待并行任务
  • 协调工作池
  • 确保清理完成
  • 同步关闭
6. Mutex:保护共享状态

需要共享状态时,使用 sync.Mutex 或 sync.RWMutex 进行保护。

Mutex 模式:

var (
    service   map[string]net.Addr
    serviceMu sync.Mutex
)

func RegisterService(name string, addr net.Addr) {
    serviceMu.Lock()
    defer serviceMu.Unlock()
    service[name] = addr
}

func LookupService(name string) net.Addr {
    serviceMu.Lock()
    defer serviceMu.Unlock()
    return service[name]
}

适用于读取密集型工作负载的 RWMutex:

var (
    cache   map[string]interface{}
    cacheMu sync.RWMutex
)

func Get(key string) interface{} {
    cacheMu.RLock()
    defer cacheMu.RUnlock()
    return cache[key]
}

func Set(key string, value interface{}) {
    cacheMu.Lock()
    defer cacheMu.Unlock()
    cache[key] = value
}
7. 并发 Web 服务器模式

Go 处理并发连接的标准模式:

for {
    rw := l.Accept()
    conn := newConn(rw, handler)
    go conn.serve()  // Handle each connection concurrently
}

每个接受的连接都由独立的 goroutine 处理,使服务器能够高效地扩展到数千个并发连接。

Web 服务器开发

HTTP 服务器基础

简单 HTTP 服务器:

package main

import (
    "fmt"
    "net/http"
)

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe("localhost:8080", nil)
}

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "Hello!")
}
请求处理模式

处理函数:

func handler(w http.ResponseWriter, r *http.Request) {
    // Read request
    method := r.Method
    path := r.URL.Path
    query := r.URL.Query()

    // Write response
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusOK)
    fmt.Fprintf(w, `{"message": "success"}`)
}

处理器结构体:

type APIHandler struct {
    db *sql.DB
    logger *log.Logger
}

func (h *APIHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    // Access dependencies
    h.logger.Printf("Request: %s %s", r.Method, r.URL.Path)
    // Handle request
}
中间件模式

日志中间件:

func loggingMiddleware(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 %v", r.Method, r.URL.Path, time.Since(start))
    })
}

// Usage
http.Handle("/api/", loggingMiddleware(apiHandler))

身份验证中间件:

func authMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        token := r.Header.Get("Authorization")
        if !isValidToken(token) {
            http.Error(w, "Unauthorized", http.StatusUnauthorized)
            return
        }
        next.ServeHTTP(w, r)
    })
}

中间件链:

handler := loggingMiddleware(authMiddleware(corsMiddleware(apiHandler)))
http.Handle("/api/", handler)
HTTP 处理器中的上下文

带上下文的 HTTP 请求:

func handleSearch(w http.ResponseWriter, req *http.Request) {
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    // Check query parameter
    query := req.FormValue("q")
    if query == "" {
        http.Error(w, "missing query", http.StatusBadRequest)
        return
    }

    // Perform search with context
    results, err := performSearch(ctx, query)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    // Render results
    renderTemplate(w, results)
}

感知上下文的 HTTP 请求:

func httpDo(ctx context.Context, req *http.Request,
            f func(*http.Response, error) error) error {
    c := &http.Client{}

    // Run request in goroutine
    ch := make(chan error, 1)
    go func() {
        ch <- f(c.Do(req))
    }()

    // Wait for completion or cancellation
    select {
    case <-ctx.Done():
        <-ch  // Wait for f to return
        return ctx.Err()
    case err := <-ch:
        return err
    }
}
路由模式

自定义路由器:

type Router struct {
    routes map[string]http.HandlerFunc
}

func (r *Router) Handle(pattern string, handler http.HandlerFunc) {
    r.routes[pattern] = handler
}

func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    if handler, ok := r.routes[req.URL.Path]; ok {
        handler(w, req)
    } else {
        http.NotFound(w, req)
    }
}

RESTful API 结构:

// GET /api/users
func listUsers(w http.ResponseWriter, r *http.Request) { /* ... */ }

// GET /api/users/:id
func getUser(w http.ResponseWriter, r *http.Request) { /* ... */ }

// POST /api/users
func createUser(w http.ResponseWriter, r *http.Request) { /* ... */ }

// PUT /api/users/:id
func updateUser(w http.ResponseWriter, r *http.Request) { /* ... */ }

// DELETE /api/users/:id
func deleteUser(w http.ResponseWriter, r *http.Request) { /* ... */ }

并发模式

1. 流水线模式

流水线通过通道连接多个阶段来处理数据。

生成器阶段:

func gen(nums ...int) <-chan int {
    out := make(chan int)
    go func() {
        for _, n := range nums {
            out <- n
        }
        close(out)
    }()
    return out
}

处理阶段:

func sq(in <-chan int) <-chan int {
    out := make(chan int)
    go func() {
        for n := range in {
            out <- n * n
        }
        close(out)
    }()
    return out
}

流水线用法:

func main() {
    // Set up pipeline
    c := gen(2, 3)
    out := sq(c)

    // Consume output
    for n := range out {
        fmt.Println(n)  // 4 then 9
    }
}

带缓冲的生成器(无需 goroutine):

func gen(nums ...int) <-chan int {
    out := make(chan int, len(nums))
    for _, n := range nums {
        out <- n
    }
    close(out)
    return out
}
2. 扇出/扇入模式

将工作分发给多个工作器,并合并结果。

扇出:多个工作器:

func main() {
    in := gen(2, 3, 4, 5)

    // Fan out: distribute work across two goroutines
    c1 := sq(in)
    c2 := sq(in)

    // Fan in: merge results
    for n := range merge(c1, c2) {
        fmt.Println(n)
    }
}

合并函数(扇入):

func merge(cs ...<-chan int) <-chan int {
    var wg sync.WaitGroup
    out := make(chan int)

    // Start output goroutine for each input channel
    output := func(c <-chan int) {
        for n := range c {
            out <- n
        }
        wg.Done()
    }

    wg.Add(len(cs))
    for _, c := range cs {
        go output(c)
    }

    // Close out once all outputs are done
    go func() {
        wg.Wait()
        close(out)
    }()
    return out
}
3. 显式取消模式

使用 Done 通道取消:

func sq(done <-chan struct{}, in <-chan int) <-chan int {
    out := make(chan int)
    go func() {
        defer close(out)
        for n := range in {
            select {
            case out <- n * n:
            case <-done:
                return
            }
        }
    }()
    return out
}

广播取消信号:

func main() {
    done := make(chan struct{})
    defer close(done)  // Broadcast to all goroutines

    in := gen(done, 2, 3, 4)
    c1 := sq(done, in)
    c2 := sq(done, in)

    // Process subset of results
    out := merge(done, c1, c2)
    fmt.Println(<-out)

    // done closed on return, canceling all pipeline stages
}

带取消功能的合并:

func merge(done <-chan struct{}, cs ...<-chan int) <-chan int {
    var wg sync.WaitGroup
    out := make(chan int)

    output := func(c <-chan int) {
        defer wg.Done()
        for n := range c {
            select {
            case out <- n:
            case <-done:
                return
            }
        }
    }

    wg.Add(len(cs))
    for _, c := range cs {
        go output(c)
    }

    go func() {
        wg.Wait()
        close(out)
    }()
    return out
}
4. 工作池模式

固定数量的工作器:

func handle(queue chan *Request) {
    for r := range queue {
        process(r)
    }
}

func Serve(clientRequests chan *Request, quit chan bool) {
    // Start handlers
    for i := 0; i < MaxOutstanding; i++ {
        go handle(clientRequests)
    }
    <-quit  // Wait to exit
}

信号量模式:

var sem = make(chan int, MaxOutstanding)

func handle(r *Request) {
    sem <- 1        // Acquire
    process(r)
    <-sem           // Release
}

func Serve(queue chan *Request) {
    for req := range queue {
        go handle(req)
    }
}

限制 goroutine 的创建:

func Serve(queue chan *Request) {
    for req := range queue {
        sem <- 1  // Acquire before creating goroutine
        go func() {
            process(req)
            <-sem  // Release
        }()
    }
}
5. 查询竞速模式

查询多个来源并返回第一个结果:

func Query(conns []Conn, query string) Result {
    ch := make(chan Result)
    for _, conn := range conns {
        go func(c Conn) {
            select {
            case ch <- c.DoQuery(query):
            default:
            }
        }(conn)
    }
    return <-ch
}
6. 并行处理示例

串行计算 MD5:

func MD5All(root string) (map[string][md5.Size]byte, error) {
    m := make(map[string][md5.Size]byte)
    err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
        if err != nil {
            return err
        }
        if !info.Mode().IsRegular() {
            return nil
        }
        data, err := ioutil.ReadFile(path)
        if err != nil {
            return err
        }
        m[path] = md5.Sum(data)
        return nil
    })
    return m, err
}

使用流水线并行计算 MD5:

type result struct {
    path string
    sum  [md5.Size]byte
    err  error
}

func sumFiles(done <-chan struct{}, root string) (<-chan result, <-chan error) {
    c := make(chan result)
    errc := make(chan error, 1)

    go func() {
        defer close(c)
        err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
            if err != nil {
                return err
            }
            if !info.Mode().IsRegular() {
                return nil
            }

            // Start goroutine for each file
            go func() {
                data, err := ioutil.ReadFile(path)
                select {
                case c <- result{path, md5.Sum(data), err}:
                case <-done:
                }
            }()

            // Check for early cancellation
            select {
            case <-done:
                return errors.New("walk canceled")
            default:
                return nil
            }
        })

        select {
        case errc <- err:
        case <-done:
        }
    }()
    return c, errc
}

func MD5All(root string) (map[string][md5.Size]byte, error) {
    done := make(chan struct{})
    defer close(done)

    c, errc := sumFiles(done, root)

    m := make(map[string][md5.Size]byte)
    for r := range c {
        if r.err != nil {
            return nil, r.err
        }
        m[r.path] = r.sum
    }

    if err := <-errc; err != nil {
        return nil, err
    }
    return m, nil
}
7. 漏桶缓冲模式

高效复用缓冲区:

var freeList = make(chan *Buffer, 100)

func server() {
    for {
        b := <-serverChan  // Wait for work
        process(b)

        // Try to reuse buffer
        select {
        case freeList <- b:
            // Buffer on free list
        default:
            // Free list full, GC will reclaim
        }
    }
}

数据库集成

连接管理

数据库连接池:

import "database/sql"

func initDB(dataSourceName string) (*sql.DB, error) {
    db, err := sql.Open("postgres", dataSourceName)
    if err != nil {
        return nil, err
    }

    // Configure connection pool
    db.SetMaxOpenConns(25)
    db.SetMaxIdleConns(5)
    db.SetConnMaxLifetime(5 * time.Minute)
    db.SetConnMaxIdleTime(10 * time.Minute)

    // Verify connection
    if err := db.Ping(); err != nil {
        return nil, err
    }

    return db, nil
}
查询模式

单行查询:

func getUser(db *sql.DB, userID int) (*User, error) {
    user := &User{}
    err := db.QueryRow(
        "SELECT id, name, email FROM users WHERE id = $1",
        userID,
    ).Scan(&user.ID, &user.Name, &user.Email)

    if err == sql.ErrNoRows {
        return nil, fmt.Errorf("user not found")
    }
    if err != nil {
        return nil, err
    }

    return user, nil
}

多行查询:

func listUsers(db *sql.DB) ([]*User, error) {
    rows, err := db.Query("SELECT id, name, email FROM users")
    if err != nil {
        return nil, err
    }
    defer rows.Close()

    var users []*User
    for rows.Next() {
        user := &User{}
        if err := rows.Scan(&user.ID, &user.Name, &user.Email); err != nil {
            return nil, err
        }
        users = append(users, user)
    }

    if err := rows.Err(); err != nil {
        return nil, err
    }

    return users, nil
}

使用上下文执行插入/更新:

func createUser(ctx context.Context, db *sql.DB, user *User) error {
    query := "INSERT INTO users (name, email) VALUES ($1, $2) RETURNING id"
    err := db.QueryRowContext(ctx, query, user.Name, user.Email).Scan(&user.ID)
    return err
}
事务处理
func transferFunds(ctx context.Context, db *sql.DB, from, to int, amount decimal.Decimal) error {
    tx, err := db.BeginTx(ctx, nil)
    if err != nil {
        return err
    }
    defer tx.Rollback()  // Rollback if not committed

    // Debit from account
    _, err = tx.ExecContext(ctx,
        "UPDATE accounts SET balance = balance - $1 WHERE id = $2",
        amount, from)
    if err != nil {
        return err
    }

    // Credit to account
    _, err = tx.ExecContext(ctx,
        "UPDATE accounts SET balance = balance + $1 WHERE id = $2",
        amount, to)
    if err != nil {
        return err
    }

    return tx.Commit()
}
预处理语句
func insertUsers(db *sql.DB, users []*User) error {
    stmt, err := db.Prepare("INSERT INTO users (name, email) VALUES ($1, $2)")
    if err != nil {
        return err
    }
    defer stmt.Close()

    for _, user := range users {
        _, err := stmt.Exec(user.Name, user.Email)
        if err != nil {
            return err
        }
    }

    return nil
}

错误处理

自定义错误类型
type ValidationError struct {
    Field string
    Message string
}

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

// Usage
if email == "" {
    return &ValidationError{Field: "email", Message: "required"}
}
错误包装
import "fmt"

func processData(data []byte) error {
    err := validateData(data)
    if err != nil {
        return fmt.Errorf("process data: %w", err)
    }
    return nil
}

// Unwrapping
if errors.Is(err, ErrValidation) {
    // Handle validation error
}

if errors.As(err, &validationErr) {
    // Access ValidationError fields
}
哨兵错误
var (
    ErrNotFound = errors.New("not found")
    ErrUnauthorized = errors.New("unauthorized")
    ErrInvalidInput = errors.New("invalid input")
)

// Usage
if errors.Is(err, ErrNotFound) {
    http.Error(w, "Resource not found", http.StatusNotFound)
}

测试

单元测试
func TestGetUser(t *testing.T) {
    db := setupTestDB(t)
    defer db.Close()

    user, err := getUser(db, 1)
    if err != nil {
        t.Fatalf("getUser failed: %v", err)
    }

    if user.Name != "John Doe" {
        t.Errorf("expected name John Doe, got %s", user.Name)
    }
}
表驱动测试
func TestValidateEmail(t *testing.T) {
    tests := []struct {
        name    string
        email   string
        wantErr bool
    }{
        {"valid email", "[email protected]", false},
        {"missing @", "userexample.com", true},
        {"empty string", "", true},
        {"missing domain", "user@", true},
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            err := validateEmail(tt.email)
            if (err != nil) != tt.wantErr {
                t.Errorf("validateEmail(%q) error = %v, wantErr %v",
                    tt.email, err, tt.wantErr)
            }
        })
    }
}
基准测试
func BenchmarkConcurrentMap(b *testing.B) {
    m := make(map[string]int)
    var mu sync.Mutex

    b.RunParallel(func(pb *testing.PB) {
        for pb.Next() {
            mu.Lock()
            m["key"]++
            mu.Unlock()
        }
    })
}
HTTP 处理器测试
func TestHandler(t *testing.T) {
    req := httptest.NewRequest("GET", "/api/users", nil)
    w := httptest.NewRecorder()

    handler(w, req)

    resp := w.Result()
    if resp.StatusCode != http.StatusOK {
        t.Errorf("expected status 200, got %d", resp.StatusCode)
    }

    body, _ := ioutil.ReadAll(resp.Body)
    // Assert body content
}

生产环境模式

优雅关闭
func main() {
    srv := &http.Server{
        Addr:    ":8080",
        Handler: router,
    }

    // Start server in goroutine
    go func() {
        if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
            log.Fatalf("listen: %s\n", err)
        }
    }()

    // Wait for interrupt signal
    quit := make(chan os.Signal, 1)
    signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
    <-quit
    log.Println("Shutting down server...")

    // Graceful shutdown with timeout
    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()

    if err := srv.Shutdown(ctx); err != nil {
        log.Fatal("Server forced to shutdown:", err)
    }

    log.Println("Server exited")
}
配置管理
type Config struct {
    ServerPort  int           `env:"PORT" envDefault:"8080"`
    DBHost      string        `env:"DB_HOST" envDefault:"localhost"`
    DBPort      int           `env:"DB_PORT" envDefault:"5432"`
    LogLevel    string        `env:"LOG_LEVEL" envDefault:"info"`
    Timeout     time.Duration `env:"TIMEOUT" envDefault:"30s"`
}

func loadConfig() (*Config, error) {
    cfg := &Config{}
    if err := env.Parse(cfg); err != nil {
        return nil, err
    }
    return cfg, nil
}
结构化日志
import "log/slog"

func setupLogger() *slog.Logger {
    return slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
        Level: slog.LevelInfo,
    }))
}

func handler(w http.ResponseWriter, r *http.Request) {
    logger := slog.With(
        "method", r.Method,
        "path", r.URL.Path,
        "remote", r.RemoteAddr,
    )

    logger.Info("handling request")

    // Process request

    logger.Info("request completed", "status", 200)
}
健康检查
func healthHandler(db *sql.DB) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        // Check database
        if err := db.Ping(); err != nil {
            w.WriteHeader(http.StatusServiceUnavailable)
            json.NewEncoder(w).Encode(map[string]string{
                "status": "unhealthy",
                "error": err.Error(),
            })
            return
        }

        // Check other dependencies...

        w.WriteHeader(http.StatusOK)
        json.NewEncoder(w).Encode(map[string]string{
            "status": "healthy",
        })
    }
}
速率限制
import "golang.org/x/time/rate"

func rateLimitMiddleware(limiter *rate.Limiter) func(http.Handler) http.Handler {
    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)
        })
    }
}

// Usage
limiter := rate.NewLimiter(rate.Limit(10), 20)  // 10 req/sec, burst 20
handler := rateLimitMiddleware(limiter)(apiHandler)
Panic 恢复
func safelyDo(work *Work) {
    defer func() {
        if err := recover(); err != nil {
            log.Println("work failed:", err)
        }
    }()
    do(work)
}

func server(workChan <-chan *Work) {
    for work := range workChan {
        go safelyDo(work)
    }
}

微服务模式

服务结构
type UserService struct {
    db     *sql.DB
    cache  *redis.Client
    logger *slog.Logger
}

func NewUserService(db *sql.DB, cache *redis.Client, logger *slog.Logger) *UserService {
    return &UserService{
        db:     db,
        cache:  cache,
        logger: logger,
    }
}

func (s *UserService) GetUser(ctx context.Context, userID string) (*User, error) {
    // Check cache first
    if user, err := s.getFromCache(ctx, userID); err == nil {
        return user, nil
    }

    // Query database
    user, err := s.getFromDB(ctx, userID)
    if err != nil {
        return nil, err
    }

    // Update cache
    go s.updateCache(context.Background(), user)

    return user, nil
}
gRPC 服务
type server struct {
    pb.UnimplementedUserServiceServer
    db *sql.DB
}

func (s *server) GetUser(ctx context.Context, req *pb.GetUserRequest) (*pb.User, error) {
    user := &pb.User{}
    err := s.db.QueryRowContext(ctx,
        "SELECT id, name, email FROM users WHERE id = $1",
        req.GetId(),
    ).Scan(&user.Id, &user.Name, &user.Email)

    if err != nil {
        return nil, status.Errorf(codes.NotFound, "user not found")
    }

    return user, nil
}
服务发现
type ServiceRegistry struct {
    services map[string][]string
    mu       sync.RWMutex
}

func (r *ServiceRegistry) Register(name, addr string) {
    r.mu.Lock()
    defer r.mu.Unlock()
    r.services[name] = append(r.services[name], addr)
}

func (r *ServiceRegistry) Discover(name string) (string, error) {
    r.mu.RLock()
    defer r.mu.RUnlock()

    addrs := r.services[name]
    if len(addrs) == 0 {
        return "", fmt.Errorf("service %s not found", name)
    }

    // Simple round-robin
    return addrs[rand.Intn(len(addrs))], nil
}
熔断器
type CircuitBreaker struct {
    maxFailures int
    timeout     time.Duration
    failures    int
    lastFailure time.Time
    state       string  // closed, open, half-open
    mu          sync.Mutex
}

func (cb *CircuitBreaker) Call(fn func() error) error {
    cb.mu.Lock()

    if cb.state == "open" {
        if time.Since(cb.lastFailure) > cb.timeout {
            cb.state = "half-open"
        } else {
            cb.mu.Unlock()
            return errors.New("circuit breaker open")
        }
    }

    cb.mu.Unlock()

    err := fn()

    cb.mu.Lock()
    defer cb.mu.Unlock()

    if err != nil {
        cb.failures++
        cb.lastFailure = time.Now()
        if cb.failures >= cb.maxFailures {
            cb.state = "open"
        }
        return err
    }

    cb.failures = 0
    cb.state = "closed"
    return nil
}

最佳实践

1. Goroutine 管理
  • 始终考虑 goroutine 的生命周期和清理
  • 使用上下文传播取消信号
  • 确保所有 goroutine 都能退出,避免 goroutine 泄漏
  • 谨慎处理循环中的闭包——显式传递值

反模式:

for _, v := range values {
    go func() {
        fmt.Println(v)  // All goroutines share same v
    }()
}

正确做法:

for _, v := range values {
    go func(val string) {
        fmt.Println(val)  // Each goroutine gets its own copy
    }(v)
}
2. 通道最佳实践
  • 从发送方关闭通道,而不是接收方
  • 使用带缓冲的通道以防止 goroutine 泄漏
  • 考虑在 select 中使用 default 来执行非阻塞操作
  • 请记住:向已关闭的通道发送数据会触发 panic,接收数据则会返回零值
3. 错误处理
  • 返回错误,不要触发 panic(真正特殊的情况除外)
  • 使用 fmt.Errorf("%w", err) 为错误添加上下文
  • 使用自定义错误类型进行程序化处理
  • 记录错误时提供充分的上下文
4. 性能
  • 对频繁分配的对象使用 sync.Pool
  • 优化前先进行性能分析:go test -bench . -cpuprofile=cpu.prof
  • 对并发映射访问模式,可考虑使用 sync.Map
  • 对容量已知的情况使用带缓冲的通道
  • 避免在热点路径中进行不必要的分配
5. 代码组织
project/
├── cmd/
│   └── server/
│       └── main.go          # Application entry point
├── internal/
│   ├── api/                 # HTTP handlers
│   ├── service/             # Business logic
│   ├── repository/          # Data access
│   └── middleware/          # HTTP middleware
├── pkg/
│   └── utils/               # Public utilities
├── migrations/              # Database migrations
├── config/                  # Configuration files
└── docker/                  # Docker files
6. 安全
  • 验证所有输入
  • 对 SQL 查询使用预处理语句
  • 实施速率限制
  • 在生产环境中使用 HTTPS
  • 清理发送给客户端的错误消息
  • 使用上下文超时以防止资源耗尽
  • 实施适当的身份验证和授权
7. 测试
  • 编写表驱动测试
  • 在测试辅助函数中使用 t.Helper()
  • 模拟外部依赖
  • 使用 httptest 测试 HTTP 处理程序
  • 为性能关键代码编写基准测试
  • 业务逻辑的测试覆盖率目标为 >80%

常见问题

1. 竞态条件

问题:

var service map[string]net.Addr

func RegisterService(name string, addr net.Addr) {
    service[name] = addr  // RACE CONDITION
}

func LookupService(name string) net.Addr {
    return service[name]  // RACE CONDITION
}

解决方案:

var (
    service   map[string]net.Addr
    serviceMu sync.Mutex
)

func RegisterService(name string, addr net.Addr) {
    serviceMu.Lock()
    defer serviceMu.Unlock()
    service[name] = addr
}
2. Goroutine 泄漏

问题:

func process() {
    ch := make(chan int)
    go func() {
        ch <- expensive()  // Blocks forever if no receiver
    }()
    // Returns without reading from ch
}

解决方案:

func process() {
    ch := make(chan int, 1)  // Buffered channel
    go func() {
        ch <- expensive()  // Won't block
    }()
}
3. 未关闭通道

接收方需要知道何时不会再有值发送过来:

func gen(nums ...int) <-chan int {
    out := make(chan int)
    go func() {
        for _, n := range nums {
            out <- n
        }
        close(out)  // IMPORTANT: close when done
    }()
    return out
}
4. 在无缓冲通道上阻塞
// This will deadlock
ch := make(chan int)
ch <- 1  // Blocks forever - no receiver
v := <-ch

使用带缓冲的通道或单独的 goroutine。

5. 未同步的通道操作
c := make(chan struct{})

// RACE CONDITION
go func() { c <- struct{}{} }()
close(c)

通过适当的同步确保存在先行发生关系。

资源和参考资料

官方文档
并发资源
标准库
工具
  • 竞态检测器:go test -race
  • 性能分析器:go tool pprof
  • 基准测试:go test -bench
  • 静态分析:go vet、staticcheck

技能版本:1.0.0 最后更新:2025 年 10 月 技能类别:后端开发、系统编程、并发编程 先决条件:基础编程知识,了解 HTTP,熟悉命令行 推荐后续技能:docker-deployment、kubernetes-orchestration、grpc-microservices

评论

支持 Markdown