记一次logrus异步日志改造
coding
关键代码
var (
logChannel = make(chan *Entry, 1024*512)
wg sync.WaitGroup
)
// Send log entry to the channel
func sendLog(level logrus.Level, msg string) {
if caller, success := getCaller(3); success {
msg = caller + ":" + msg
}
entry := &Entry{
level: level,
message: msg,
}
logChannel <- entry
}
func init() {
wg.Add(1)
go processLogEntries()
}
func Shutdown() {
close(logChannel)
wg.Wait()
fmt.Println("logging 👋")
}
本次改造的目的是为了优化在高并发下,日志写入对接口性能的影响,由于写入操作是同步的所以影响还是比较明显, 相比于替换速度更快的log库(例如zap),异步写入这一点足以提高不止是一个数量级别的速度。所以这里采用改造已有 logrus 的封装。首先在初始化的时候启动一个 goroutine 用以消化异步的日志,同时设置一个合适的长度的chan用来缓存需要处理的一异步日志,如果 chan 过小,那么再高并发下,有可能 chan 数据过多导致发生阻塞,使得异步日志退化为原始的同步日志。如果chan设置的过大又有可能导致机器内存占用过多,所以一个合适的大小是必要的。同时还需要一个存在一个 Stutdown 函数。用于在关闭服务的时候调用(这里的关闭服务指的是服务收到关闭信号后,后续的关闭逻辑,而不是杀死服务),处理chan中尚未写入的日志。当然,这个封装还是有着提升空间,比如如果可以像zap一样批量写入的话,那么效率可能会更高,也可以chan的大小更改的更小一点。但是zap在字符处理上比 logrus 快的部分,是远远比不上一次架构上异步日志的实现提升的明显。这是存在质变的更改方案。
评论列表