面试题答案
一键面试1. Context传递方法
- 服务A调用服务B:
在服务A调用服务B时,创建一个顶层的
context.Context
,例如ctx, cancel := context.WithTimeout(context.Background(), timeoutDuration)
,这里timeoutDuration
是整个调用链期望的最长执行时间。然后将ctx
作为参数传递给服务B的调用函数。 - 服务B调用服务C和服务D:
服务B接收到
ctx
后,继续将其传递给服务C和服务D的调用函数。如果服务B内部有自己的并发操作,也需要将ctx
传递给这些并发操作的函数。例如,使用go func(ctx context.Context) { /* 并发操作 */ }(ctx)
来确保在并发环境下也能正确处理context
。 - 服务内部并发操作:
在每个服务内部的并发操作函数中,首先检查
ctx
的状态。例如,在操作开始处添加select { case <-ctx.Done(): return }
,这样当ctx
被取消(超时或手动取消)时,并发操作能够及时退出。
2. 性能优化因素及方法
2.1 减少不必要的Context复制
- 因素:每次传递
context
时,都可能涉及到一定的内存复制开销。如果在调用链中频繁传递大的context
(例如带有很多附加值的context
),会增加性能开销。 - 方法:尽量精简
context
携带的数据,只传递必要的信息。并且在传递context
时,可以考虑使用指针传递,减少内存复制。
2.2 优化并发操作数量
- 因素:过多的并发操作会增加系统的资源竞争,如CPU调度开销、内存占用等,影响整体性能。
- 方法:合理控制并发度。可以使用
sync.Semaphore
或golang.org/x/sync/semaphore
来限制并发操作的数量。例如:
sem := semaphore.NewWeighted(maxConcurrent)
err := sem.Acquire(ctx, 1)
if err != nil {
return err
}
defer sem.Release(1)
这样可以确保在同一时间内只有maxConcurrent
个并发操作执行。
2.3 减少网络开销
- 因素:在微服务架构中,服务间通过网络调用,频繁的网络交互会带来较大的延迟。
- 方法:尽量合并网络请求。如果服务B需要从服务C和服务D获取数据,可以考虑设计一个批量获取数据的接口,减少网络请求次数。另外,优化网络配置,如调整TCP参数等,提高网络传输效率。
2.4 合理设置超时时间
- 因素:超时时间设置过长可能导致资源长时间占用,设置过短可能导致正常业务无法完成。
- 方法:通过性能测试和实际业务场景分析,合理设置每个服务的超时时间以及整个调用链的超时时间。可以采用动态调整的策略,根据系统负载、历史调用时间等因素来动态调整超时时间。