面试题答案
一键面试架构设计
- 入口处设置超时:在接收请求的入口处,创建带有超时的
context.Context
。 - 微服务间传递Context:每个微服务在处理请求时,将接收到的
Context
传递给下一个微服务,确保整个请求链路都能受该Context
控制。 - 超时处理:每个微服务在处理逻辑中,通过
Context
的Done
通道监听超时信号,一旦超时,停止当前处理并返回。 - 事务回滚:如果某个微服务在超时前已经执行了部分事务操作,需要在超时发生时进行回滚。这可以通过在每个微服务中实现补偿机制(如数据库事务回滚、消息队列消息撤回等)来完成。
关键代码片段
- 入口处设置超时
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)
}
- 微服务处理函数
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
函数会捕获错误并进行相应的回滚操作。