前言
在 4 月 27 日举办的 Gopher China 2019 中,国内 Go 语言专家,Bilibili 架构师毛剑进行了题为《 Go 业务基础库之 Error & Context 》的演讲,主要探讨两个问题:
1. 在业务的基础库中,经常需要针对异常进行处理;
这次分享针对业务逻辑的异常处理,异常日志记录,异常信息关联,
业务错误码,以及基于Go,error的特点如何来使用解决这类问题;
2. 在Go引入context以后,我们如何改造自己的基础库。
利用context上下文解决元数据传递,超时传递,
在启动新的goroutine时候,如何保证上下文传递到位。
本文是他演讲的第一部分——Error 篇,以下为演讲实录。
毛剑:我之前讲过的一些 Topic 偏整体架构,比如微服务。这次讲的会比较详细一点。因为在整个微服务体系下,很多框架理念大家熟悉了,我也讲很多次了,所以想尝试一下讲比较细节的点,比如说 Go 里面很细节的点,或者在我们做业务的一些基础库或者公共库有一些什么需要注意的。我在听国外讲师分享的时候,发现他们非常非常细节的,比如说可能就讲讲 Go Test。
这次我大概会分两块 Go 里面两个重点,一个是 Error,一个是 Context。
No.1
Error
Error 有几个点是让我们日常开发觉得比较麻烦的。首先是错误检查和打印,其次是业务的错误码设计。我们经常在代码里面到处都是 return error 这个非常麻烦,每个地方都要处理。这个有利有弊。我自己理解的是每一行代码或者每一个函数调用结束以后,应该对它负责,所以尽早处理掉函数的错误也好,异常也好。
对于一个程序来说,这种错误我们应该进行保护,比如说你的程序因为遇到一些问题让你业务退出了,这个对于业务是有影响的。对于一个函数我们要尽快处理,对于一个程序我们要做保护编程。
首先业务开发会分层,Dao 或者 Service,然后开发同学在各个层都打日志,一个业务上线以后,有可能打几十个错误日志,这些日志散落在系统里面,你要查的时候要把整个上下文关联起来看非常麻烦。因为时间顺序是错乱的,非常难找。
其次即便看到日志以后还要猜,到底是哪一个地方代码出的问题,如果偏底层抛出来的错误会非常麻烦定位。还有根因的丢失,有一些错误如果要包装,要附带一些消息,原始的 error 就不见了。我们可能需要基于原始的 error 做等值的判断,就会比较麻烦。
另外业务里面 API 肯定有错误码,100、200,返回-001都有可能,客户端同学要给予这些错误做逻辑调整。API里面的错误 HINT 分两种,一种是面向终端用户,他可能想看到的是更友好的一些错误提示,而不是偏程序的消息展示。另外一种包含一些附带逻辑处理的数据(比如失败后的Retry策略等)。
针对这几个问题,我聊聊自己怎么考虑和解决的。