MST

星途 面试题库

面试题:Go语言Context在分布式系统超时控制的深度剖析

在一个基于微服务架构的分布式系统中,使用Go语言开发。假设一个请求会经过多个微服务处理,每个微服务都有自己的处理逻辑和潜在的超时场景。请阐述如何利用`context.Context`来实现端到端的超时控制,确保整个请求在规定时间(例如5秒)内完成,同时要考虑微服务之间传递`Context`的最佳实践以及如何处理因超时导致的事务回滚等问题,要求给出详细的架构设计和关键代码片段。
11.9万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

架构设计

  1. 入口处设置超时:在接收请求的入口处,创建带有超时的context.Context
  2. 微服务间传递Context:每个微服务在处理请求时,将接收到的Context传递给下一个微服务,确保整个请求链路都能受该Context控制。
  3. 超时处理:每个微服务在处理逻辑中,通过ContextDone通道监听超时信号,一旦超时,停止当前处理并返回。
  4. 事务回滚:如果某个微服务在超时前已经执行了部分事务操作,需要在超时发生时进行回滚。这可以通过在每个微服务中实现补偿机制(如数据库事务回滚、消息队列消息撤回等)来完成。

关键代码片段

  1. 入口处设置超时
package main

import (
    "context"
    "fmt"
    "net/http"
    "time"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        // 设置5秒超时
        ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
        defer cancel()

        err := processRequest(ctx)
        if err != nil {
            http.Error(w, err.Error(), http.StatusGatewayTimeout)
            return
        }
        fmt.Fprintf(w, "Request processed successfully")
    })

    http.ListenAndServe(":8080", nil)
}
  1. 微服务处理函数
func processRequest(ctx context.Context) error {
    // 模拟第一个微服务调用
    err := microservice1(ctx)
    if err != nil {
        return err
    }

    // 模拟第二个微服务调用
    err = microservice2(ctx)
    if err != nil {
        // 这里如果第二个微服务失败,可能需要回滚第一个微服务的操作
        rollbackMicroservice1()
        return err
    }

    return nil
}

func microservice1(ctx context.Context) error {
    select {
    case <-time.After(2 * time.Second):
        // 模拟业务逻辑执行
        fmt.Println("Microservice 1 processed")
        return nil
    case <-ctx.Done():
        return ctx.Err()
    }
}

func microservice2(ctx context.Context) error {
    select {
    case <-time.After(2 * time.Second):
        // 模拟业务逻辑执行
        fmt.Println("Microservice 2 processed")
        return nil
    case <-ctx.Done():
        return ctx.Err()
    }
}

func rollbackMicroservice1() {
    // 实现回滚逻辑,比如数据库事务回滚
    fmt.Println("Rolling back microservice 1")
}

在上述代码中,context.WithTimeout创建了带有超时的Context,在每个微服务函数中,通过select监听ctx.Done()通道来检测是否超时。如果某个微服务处理超时,processRequest函数会捕获错误并进行相应的回滚操作。