1. Go 语言错误处理和异常处理机制的运用
- 错误处理(Error Handling):
- 函数返回错误:在 Go 语言中,函数通常会返回一个
error
类型的值来表示操作是否成功。例如,在数据持久化操作(如数据库插入、更新等)中,函数会返回 error
。
func saveTransaction(transaction Transaction) error {
// 数据库操作
err := db.Insert(transaction)
if err != nil {
return err
}
return nil
}
- 错误传播:将错误沿着调用链向上传播,让调用者决定如何处理错误。例如,在微服务的业务逻辑层,如果调用数据持久化函数失败,将错误返回给更高层。
func processTransaction(transaction Transaction) error {
err := saveTransaction(transaction)
if err != nil {
return err
}
// 其他业务逻辑
return nil
}
- 错误包装:使用
fmt.Errorf
函数对错误进行包装,添加更多上下文信息。例如,在调用外部服务失败时,包装错误信息。
func callExternalService() error {
// 调用外部服务
resp, err := http.Get("http://external-service/transaction")
if err != nil {
return fmt.Errorf("failed to call external service: %w", err)
}
return nil
}
- 异常处理(Panic and Recover):
- 谨慎使用 Panic:Panic 用于处理程序遇到无法恢复的错误情况,例如程序逻辑错误、资源严重不足等。在微服务中,一般不轻易使用 Panic,除非是内部严重错误,如配置文件格式错误等。
func loadConfig() {
// 解析配置文件
config, err := parseConfigFile("config.json")
if err != nil {
panic(fmt.Sprintf("failed to load config: %v", err))
}
// 使用配置
}
- Recover:在需要捕获 Panic 并进行恢复的地方使用
recover
,例如在 HTTP 服务器的处理函数中。
func httpHandler(w http.ResponseWriter, r *http.Request) {
defer func() {
if err := recover(); err != nil {
log.Println("Panic occurred:", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
}
}()
// 处理 HTTP 请求的业务逻辑
}
2. 分布式环境下的错误处理流程设计
- 网络故障处理:
- 重试机制:当遇到网络故障(如连接超时、请求失败等)时,使用重试机制。可以使用
time.Sleep
和计数器来实现简单的重试。
func callRemoteServiceWithRetry() error {
maxRetries := 3
for i := 0; i < maxRetries; i++ {
err := callRemoteService()
if err == nil {
return nil
}
if i < maxRetries - 1 {
time.Sleep(time.Second)
}
}
return fmt.Errorf("failed after %d retries", maxRetries)
}
- 断路器模式:使用断路器模式来防止在服务不可用时频繁尝试调用。例如,可以使用
github.com/sony/gobreaker
库。
var cb *gobreaker.CircuitBreaker
func init() {
cb = gobreaker.NewCircuitBreaker(gobreaker.Settings{
Name: "RemoteService",
MaxRequests: 10,
Interval: time.Second * 5,
Timeout: time.Second,
ReadyToTrip: func(counts gobreaker.Counts) bool {
failureRatio := float64(counts.TotalFailures) / float64(counts.Requests)
return counts.Requests >= 10 && failureRatio >= 0.5
},
})
}
func callRemoteService() error {
return cb.Execute(func() error {
// 实际调用远程服务
return nil
})
}
- 服务不可用处理:
- 服务降级:当某个服务不可用时,采用服务降级策略,返回一个默认值或简单的响应,保证系统的基本功能可用。例如,在金融交易系统中,如果交易历史查询服务不可用,可以返回最近一次缓存的交易历史。
- 分布式事务处理:为保证交易的一致性,使用分布式事务框架(如 Apache ShardingSphere-Proxy 的柔性事务等)。在分布式事务中,当某个服务参与事务失败时,根据事务协调器的指令进行回滚或补偿操作。例如,在一个涉及资金转账的分布式事务中,如果目标账户服务不可用,事务协调器会通知源账户服务进行回滚操作,确保资金的一致性。