面试题答案
一键面试架构设计
- 调用链管理:
- 在每个微服务的入口,创建一个根
context
,并将其传递到后续所有的Go协程中。例如,对于一个HTTP服务,在处理请求的函数中:
func Handler(w http.ResponseWriter, r *http.Request) { ctx := context.Background() // 调用其他函数并传递ctx processRequest(ctx, w, r) }
- 当一个微服务调用另一个微服务时,将当前的
context
传递过去。这样,整个调用链上的所有操作都在同一个context
体系下,便于跟踪和管理。
- 在每个微服务的入口,创建一个根
- 超时控制:
- 在创建
context
时,可以使用context.WithTimeout
函数来设置超时时间。例如:
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel()
- 这个带有超时的
context
会被传递到所有相关的Go协程中。当超时时间到达时,context
会被取消,所有基于这个context
的操作(如HTTP请求、数据库查询等)都应该能够感知到并优雅地结束。
- 在创建
- 错误处理:
- 利用
context
的Done
通道来处理取消和错误情况。当context
被取消(无论是超时还是手动取消),Done
通道会被关闭。在Go协程中,可以监听这个通道:
func doWork(ctx context.Context) error { select { case <-ctx.Done(): return ctx.Err() default: // 正常工作逻辑 return nil } }
- 当某个子操作发生错误时,可以通过返回错误值将错误传递回调用者,调用者可以根据情况决定是否取消整个
context
。例如:
func main() { ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() err := doComplexWork(ctx) if err!= nil { log.Println("Error in doComplexWork:", err) } } func doComplexWork(ctx context.Context) error { err := doSubWork1(ctx) if err!= nil { return err } err = doSubWork2(ctx) if err!= nil { return err } return nil } func doSubWork1(ctx context.Context) error { // 模拟工作 return nil } func doSubWork2(ctx context.Context) error { // 模拟工作 return fmt.Errorf("sub - work 2 failed") }
- 利用
技术实现要点
- 正确传递
context
:确保在整个调用链中,context
被正确地传递,不能遗漏任何可能需要使用context
的函数或Go协程。 - 合理设置超时:根据业务需求,合理设置每个操作的超时时间,避免设置过长导致资源浪费,或过短导致操作失败。
- 及时取消
context
:在不需要继续使用context
时(例如函数返回后),及时调用取消函数(cancel
),释放相关资源。 - 错误处理一致性:在整个系统中,统一错误处理的方式,通过
context.Err()
获取取消原因,并根据业务逻辑决定是否继续执行后续操作。