面试题答案
一键面试关键设计思路
- 信号监听:在每个微服务中监听系统信号,如
SIGTERM
、SIGINT
等,这些信号通常用于通知程序进行优雅关闭。 - 依赖管理:梳理微服务之间的依赖关系,确定关闭顺序。可以通过有向无环图(DAG)来表示微服务的依赖关系,确保在关闭时先关闭被依赖少的微服务。
- 并发任务管理:使用
context
来管理每个微服务内部的并发任务。当接收到关闭信号时,通过context
取消正在运行的并发任务。 - 资源释放:在微服务关闭前,确保释放所有的资源,如数据库连接、网络连接等。
代码框架
以下是一个简单的代码框架示例,展示如何在Go语言微服务中实现优雅关闭:
package main
import (
"context"
"fmt"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
// 创建一个 context 用于管理整个微服务生命周期
ctx, cancel := context.WithCancel(context.Background())
// 启动微服务内部的并发任务
go func(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("Concurrency task is shutting down...")
return
default:
// 模拟业务逻辑
fmt.Println("Concurrency task is running...")
time.Sleep(1 * time.Second)
}
}
}(ctx)
// 监听系统信号
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
sig := <-sigs
fmt.Println()
fmt.Println(sig)
// 接收到信号,取消 context
cancel()
// 等待一段时间让并发任务完成清理工作
time.Sleep(5 * time.Second)
fmt.Println("Microservice is shutting down...")
os.Exit(0)
}()
fmt.Println("Microservice is running...")
select {}
}
解释
- context管理:
context.WithCancel
创建了一个可取消的context
,用于通知并发任务停止。 - 并发任务:在
go
协程中运行模拟的业务逻辑,通过select
语句监听ctx.Done()
信号来决定是否停止。 - 信号监听:使用
signal.Notify
监听SIGINT
和SIGTERM
信号。接收到信号后,取消context
并等待一段时间让并发任务清理。 - 资源释放:在示例中虽未展示具体资源释放,但实际应用中可以在
cancel()
之后添加资源释放逻辑,如关闭数据库连接等。
对于微服务之间的依赖关系管理,可以使用拓扑排序算法(如Kahn算法)来确定关闭顺序。在每个微服务的关闭逻辑中,先等待依赖的微服务关闭完成,再进行自身的关闭操作。