创新方案
用 Go 构建高并发后端服务时:用…
适用于需要用 Go 开发高并发 Web API、微服务、实时系统、数据库后端或云原生服务的场景。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 49/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 85/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
用 Go 构建高并发后端服务时:用 go通用
解决思路
- 用 `go` 关键字启动 goroutine 执行并发任务,例如 `go expensiveComputation(x, y, z)`,让多个计算并发运行。
- 管理 goroutine 生命周期:使用 context 传播取消,确保 goroutine 可退出,避免泄漏;在循环中启动 goroutine 时把循环变量作为参数传入,如 `go func(val string) { ... }(v)`。
- 用 channel 在 goroutine 之间做类型安全通信:无缓冲 `make(chan int)` 用于同步通信,缓冲 `make(chan int, 100)` 用于异步通信,只读类型 `<-chan int`,只写类型 `chan<- int`。
- 用 channel 实现 producer-consumer、fan-out/fan-in、pipeline stages、timeouts/cancellation、semaphores/rate limiting 等模式。
- 用 `select` 多路复用 channel;实现超时时创建 `timeout := make(chan bool, 1)`,在 goroutine 中 `time.Sleep(1 * time.Second)` 后发送,然后在 `select` 中监听目标 channel 和 `timeout`。
- 用 `select` 监听 `ctx.Done()` 和结果 channel 实现 context 取消,如 `case result := <-resultCh: return result` 与 `case <-ctx.Done(): return ctx.Err()`。
- 使用 `context.Context` 接口:调用 `Done()` 获取取消 channel,`Err()` 获取取消原因,`Deadline()` 获取截止时间,`Value(key)` 获取请求范围值。
- 创建 context:使用 `context.Background()` 作为根;用 `context.WithCancel(context.Background())` 并立即 `defer cancel()`;用 `context.WithTimeout(context.Background(), 5*time.Second)`;用 `context.WithDeadline(context.Background(), deadline)`;用 `context.WithValue(parentCtx, key, value)`。
- Context 最佳实践:始终把 context 作为第一个参数,如 `func DoSomething(ctx context.Context, ...)`;创建可取消 context 后立即 `defer cancel()`;沿调用链传播 context;长运行操作检查 `ctx.Done()`;context value 只用于请求范围数据。
- 用 `sync.WaitGroup` 协调 goroutine:循环中 `wg.Add(1)`,goroutine 内 `defer wg.Done()`,最后 `wg.Wait()` 等待全部完成。
- 用 `sync.Mutex` 保护共享状态:在读写共享 map 前后 `serviceMu.Lock()` 和 `defer serviceMu.Unlock()`。
- 读多写少场景用 `sync.RWMutex`:读操作使用 `RLock()`/`RUnlock()`,写操作使用 `Lock()`/`Unlock()`。
- 实现并发 Web 服务器:在 accept 循环中 `rw := l.Accept()`,创建 `conn := newConn(rw, handler)`,然后 `go conn.serve()` 为每个连接并发服务。
- 用 `http.HandleFunc` 注册处理函数,并调用 `http.ListenAndServe` 启动 HTTP 服务,监听 `localhost:8080`。
- 在 handler 中读取 `r.Method`、`r.URL.Path`、`r.URL.Query()`;用 `w.Header().Set` 设置响应头,用 `w.WriteHeader` 设置状态码,用 `fmt.Fprintf` 写响应体。
- 用实现 `ServeHTTP` 的 handler struct 注入依赖,如 `db *sql.DB`、`logger *log.Logger`,供请求处理使用。
- 用 middleware 包装 `http.Handler`:logging middleware 记录 `start := time.Now()`,调用 `next.ServeHTTP(w, r)`,最后记录 `time.Since(start)`。
- 用 auth middleware 读取 `Authorization` header,校验 token,失败时 `http.Error(w, "Unauthorized", http.StatusUnauthorized)`,成功时调用 `next.ServeHTTP(w, r)`。
- 链式组合 middleware:`loggingMiddleware(authMiddleware(corsMiddleware(apiHandler)))`。
- 在 HTTP handler 中使用 context:创建 `ctx, cancel := context.WithCancel(context.Background())` 并 `defer cancel()`,读取 `req.FormValue("q")`,为空返回 400,用 `performSearch(ctx, query)` 执行搜索,错误返回 500,最后 `renderTemplate(w, results)`。
- 实现 context-aware HTTP 请求:在 goroutine 中执行 `c.Do(req)` 并把结果发送到 `ch`,用 `select` 等待 `ctx.Done()` 或 `ch`,并在取消时返回 `ctx.Err()`。
- 实现自定义 Router:用 `map[string]http.HandlerFunc` 保存路由,`ServeHTTP` 根据 `req.URL.Path` 查找 handler,找不到调用 `http.NotFound`。
- 按 RESTful 结构实现路由:`GET /api/users` 对应 listUsers,`GET /api/users/:id` 对应 getUser,`POST /api/users` 对应 createUser,`PUT /api/users/:id` 对应 updateUser,`DELETE /api/users/:id` 对应 deleteUser。
- 实现 pipeline:generator 返回 `<-chan int`,在 goroutine 中发送数据并 `close(out)`;processing stage 对 `range in` 计算并发送;main 中 `for n := range out` 消费结果。
- 对已知容量使用 buffered generator:`out := make(chan int, len(nums))`,同步发送所有值后 `close(out)`,无需额外 goroutine。
- 实现 fan-out:多个 goroutine 从同一个输入 channel 读取并处理,例如 `c1 := sq(in)`、`c2 := sq(in)`。
- 实现 fan-in:编写 `merge(cs ...<-chan int) <-chan int`,用 `sync.WaitGroup` 为每个输入 channel 启动输出 goroutine,最后 `wg.Wait()` 后 `close(out)`。
- 实现显式取消:处理函数增加 `done <-chan struct{}` 参数,发送时使用 `select { case out <- n * n: case <-done: return }`。
- 广播取消:创建 `done := make(chan struct{})`,用 `defer close(done)` 通知所有 goroutine;所有 pipeline 阶段在发送时 select 监听 `done`。
- 实现带取消的 merge:在输出 goroutine 中使用 `select { case out <- n: case <-done: return }`,并 `defer wg.Done()`。
- 实现 worker pool:启动固定数量 worker,如 `for i := 0; i < MaxOutstanding; i++ { go handle(clientRequests) }`;`handle` 中 `for r := range queue { process(r) }`;主 goroutine `<-quit` 等待退出。
- 用 semaphore 限制并发:`var sem = make(chan int, MaxOutstanding)`;在 `handle` 中 `sem <- 1` 获取,`process(r)` 后 `<-sem` 释放。
- 限制 goroutine 创建:在 `for req := range queue` 中先 `sem <- 1`,再 `go func() { process(req); <-sem }()`。
- 实现 query racing:对每个连接 `go func(c Conn) { select { case ch <- c.DoQuery(query): default: } }(conn)`,函数返回 `<-ch` 得到第一个结果。
- 实现串行 MD5 计算:用 `filepath.Walk(root, ...)` 遍历文件,跳过非 regular 文件,读取文件并 `md5.Sum(data)` 存入 map。
- 实现并行 MD5 计算:定义 `result{path, sum, err}`;`sumFiles` 为每个 regular 文件启动 goroutine,用 `select { case c <- result{...}: case <-done: }` 发送结果;Walk 中检查 `done` 提前取消;`MD5All` 创建 `done` 并 `defer close(done)`,range c 收集结果,读取 errc。
- 实现 leaky buffer:创建 `var freeList = make(chan *Buffer, 100)`;server 从 `serverChan` 取 buffer,`process(b)` 后用 `select { case freeList <- b: default: }` 尝试复用,满则交给 GC。
- 初始化数据库连接池:用 `sql.Open` 打开数据库,设置 `db.SetMaxOpenConns(25)`、`db.SetMaxIdleConns(5)`、`db.SetConnMaxLifetime(5 * time.Minute)`、`db.SetConnMaxIdleTime(10 * time.Minute)`,并用 `db.Ping()` 验证连接。
- 执行单行查询:用 `db.QueryRow("SELECT id, name, email FROM users WHERE id = $1", userID).Scan(&user.ID, &user.Name, &user.Email)`,处理 `sql.ErrNoRows`。
- 执行多行查询:用 `db.Query("SELECT id, name, email FROM users")`,`defer rows.Close()`,`for rows.Next()` 中 `rows.Scan`,最后检查 `rows.Err()`。
- 带 context 执行插入/更新:用 `db.QueryRowContext(ctx, query, user.Name, user.Email).Scan(&user.ID)`。
- 处理事务:用 `tx, err := db.BeginTx(ctx, nil)` 开启,`defer tx.Rollback()`,用 `tx.ExecContext` 执行多条 SQL,最后 `tx.Commit()`。
- 使用 prepared statement 批量插入:用 `db.Prepare("INSERT INTO users (name, email) VALUES ($1, $2)")`,`defer stmt.Close()`,循环 `stmt.Exec(user.Name, user.Email)`。
- 定义自定义错误类型:创建 struct 包含字段,实现 `Error() string`,返回 `&ValidationError{Field: "email", Message: "required"}`。
- 包装和解包错误:用 `fmt.Errorf("process data: %w", err)` 包装;用 `errors.Is` 判断 sentinel error;用 `errors.As` 提取 `ValidationError` 字段。
- 定义 sentinel errors:如 `ErrNotFound = errors.New("not found")`、`ErrUnauthorized`、`ErrInvalidInput`;用 `errors.Is(err, ErrNotFound)` 映射 HTTP 状态。
- 写单元测试:调用 `setupTestDB(t)` 并 `defer db.Close()`,执行函数,用 `t.Fatalf` 或 `t.Errorf` 断言结果。
- 写表驱动测试:定义 `[]struct{name string; email string; wantErr bool}`,循环中 `t.Run(tt.name, func(t *testing.T) { ... })` 验证 `validateEmail(tt.email)`。
- 写 benchmark:定义 `func BenchmarkConcurrentMap(b *testing.B)`,在 `b.RunParallel(func(pb *testing.PB) { for pb.Next() { ... } })` 中测试并发 map 加锁。
- 测试 HTTP handler:用 `httptest.NewRequest("GET", "/api/users", nil)` 和 `httptest.NewRecorder()`,调用 handler,检查 `w.Result().StatusCode` 并读取 body 断言。
- 实现优雅关闭:创建 `http.Server{Addr: ":8080", Handler: router}`;goroutine 中 `srv.ListenAndServe()`;用 `signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)` 监听,`<-quit` 后创建 `context.WithTimeout(context.Background(), 30*time.Second)`,调用 `srv.Shutdown(ctx)`。
- 管理配置:定义带环境变量 tag 的 `Config` struct,如 `env:"PORT" envDefault:"8080"`,用 `env.Parse(cfg)` 加载配置。
- 使用结构化日志:用 `slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo}))`;handler 中用 `slog.With("method", r.Method, "path", r.URL.Path, "remote", r.RemoteAddr)` 添加上下文字段。
- 实现健康检查:handler 中调用 `db.Ping()`;失败返回 `http.StatusServiceUnavailable` 和 JSON `status: unhealthy`;成功返回 200 和 `status: healthy`。
- 实现限流:用 `golang.org/x/time/rate`,创建 `rate.NewLimiter(rate.Limit(10), 20)`;middleware 中 `if !limiter.Allow() { http.Error(w, "Too Many Requests", http.StatusTooManyRequests); return }`。
- 实现 panic recovery:用 `defer func() { if err := recover(); err != nil { log.Println("work failed:", err) } }()` 包裹工作函数;server 对每个 work 用 `go safelyDo(work)`。
- 构建服务结构:定义 `UserService` 注入 `db`、`cache`、`logger`;`GetUser` 先查缓存,命中返回;未命中查 DB,成功后 `go s.updateCache(context.Background(), user)` 异步更新缓存。
- 实现 gRPC 服务:嵌入 `pb.UnimplementedUserServiceServer`,在 `GetUser` 中用 `db.QueryRowContext` 查询,错误返回 `status.Errorf(codes.NotFound, "user not found")`。
- 实现服务发现:用 `ServiceRegistry` 保存 `map[string][]string` 并加 `sync.RWMutex`;`Register` 写锁后 append 地址;`Discover` 读锁后无地址报错,随机返回一个地址实现简单轮询。
- 实现断路器:定义 `CircuitBreaker{maxFailures, timeout, failures, lastFailure, state, mu}`;`Call` 在 open 状态下若超过 timeout 转 half-open,否则返回错误;执行 `fn`;失败时计数并在达到 `maxFailures` 后设 open;成功时重置 failures 并设 closed。
- 管理 goroutine:始终考虑生命周期和清理,使用 context 传播取消,避免 goroutine 泄漏,循环闭包显式传值。
- 遵循 channel 最佳实践:从发送方关闭 channel;用缓冲 channel 防止泄漏;用 `select` 加 `default` 做非阻塞操作;注意向已关闭 channel 发送会 panic,接收会返回零值。
- 遵循错误处理:返回错误而不是 panic(真正异常除外);用 `fmt.Errorf("%w", err)` 包装;用自定义错误类型做程序化处理;日志中包含足够上下文。
- 优化性能:频繁分配对象使用 `sync.Pool`;先 profile 再优化,如 `go test -bench . -cpuprofile=cpu.prof`;并发 map 访问考虑 `sync.Map`;已知容量用缓冲 channel;热路径避免不必要分配。
- 组织代码目录:使用 `cmd/server/main.go`、`internal/api`、`internal/service`、`internal/repository`、`internal/middleware`、`pkg/utils`、`migrations`、`config`、`docker`。
- 落实安全:验证所有输入;SQL 使用 prepared statements;实现 rate limiting;生产使用 HTTPS;清理返回客户端的错误消息;用 context timeout 防资源耗尽;实现认证和授权。
- 测试实践:写表驱动测试;测试辅助函数用 `t.Helper()`;mock 外部依赖;HTTP handler 用 `httptest`;性能关键代码写 benchmark;业务逻辑目标 >80% 覆盖率。
- 避免 race condition:共享 map 的读写都用 `sync.Mutex` 包裹,不要裸访问。
- 避免 goroutine 泄漏:对可能无接收者的发送使用缓冲 channel,如 `make(chan int, 1)`,或确保存在接收者。
- 正确关闭 channel:generator 在发送完成后调用 `close(out)`,让 receiver 知道没有更多值。
- 避免无缓冲 channel 死锁:不要在同一 goroutine 中先发送后接收;使用缓冲 channel 或另起 goroutine。
- 同步 channel 操作:确保 happens-before 关系,避免并发 `close(c)` 和 `c <- struct{}{}` 造成 race。
- 使用 `go test -race` 检测竞态。
- 使用 `go tool pprof` 分析性能。
- 使用 `go test -bench` 运行基准测试。
- 使用 `go vet` 和 `staticcheck` 做静态分析。
适用边界 · 注意事项
- 不适用于非 Go 技术栈,或不需要并发、网络服务、数据库后端的简单脚本。
- 不适用于硬实时且不能接受 Go GC 暂停影响的系统。
- 不适用于希望避免微服务与并发复杂度、且团队不熟悉 Go 并发模型的小型项目。