Skip to content

ioc/config/log: IsMyLogger 并发遍历 loggers map 未加锁,导致 fatal error: concurrent map iteration and map write #21

Description

@kylinlingh

third-party/mcube/ioc/config/log 中,Config.loggers 是一个共享的 map[string]*zerolog.Logger,会在运行时被多个并发请求访问。

当前实现存在并发安全问题:

  • Logger(name) 在创建子 logger 时会向 m.loggers 写入,并且这条写路径有加锁
  • IsMyLogger(logger) 会遍历 m.loggers 判断当前 logger 是否属于当前配置,但这条读路径没有加锁

在并发请求场景下,如果一个 goroutine 正在 IsMyLogger() 中遍历 m.loggers,另一个 goroutine 同时在 Logger() 中写入 m.loggers,就会触发 Go runtime panic:

fatal error: concurrent map iteration and map write

 panic 会直接导致整个服务进程退出。

## 原始代码

IsMyLogger 原始实现如下func (m *Config) IsMyLogger(logger *zerolog.Logger) bool {
	if logger == nil || m.root == nil {
		return false
	}

	// 快速检查:是否是 root logger
	if logger == m.root {
		return true
	}

	// 遍历所有存储的 logger 进行比较
	for _, storedLogger := range m.loggers {
		if storedLogger == logger {
			return true
		}
	}

	return false
}

从实现上看,m.loggers 的写操作在 Logger() 中受互斥锁保护,但 IsMyLogger() 对同一个 map 的遍历没有任何同步保护,因此在并发访问时会出现“遍历 map”与“写map”同时发生的情况。

panic 触发方式说明

问题的本质是:

  • goroutine A 在 IsMyLogger() 中执行:
for _, storedLogger := range m.loggers {
	...
}
  • goroutine B 同时在 Logger() 中执行:
m.loggers[name] = &l

Go 的原生 map 不支持“并发遍历 + 并发写入”。一旦这两个路径重叠,就会触发运行时崩溃:

fatal error: concurrent map iteration and map write

影响范围

这是一个进程级崩溃问题,不是普通功能异常。

一旦在高并发场景下命中,整个服务会直接退出,对线上稳定性影响较大。只要业务代码频繁调用 log.FromCtx(...),并且系统会动态创建子 logger,就存在触发风险。

复现思路

可以通过并发执行以下两类操作复现:

  1. 多个 goroutine 调用 Logger(name),不断创建或读取不同名称的子 logger
  2. 多个 goroutine 同时调用 IsMyLogger(logger),对 m.loggers 做遍历判断

当“遍历 map”和“写 map”在时间上重叠时,即可触发 panic。

期望行为

无论在单线程还是高并发请求场景下,日志组件都不应因内部共享 map 的并发访问而触发 runtime panic。

建议修复

建议统一对 m.loggers 的读写做并发保护,例如:

  1. 将当前互斥锁改为 sync.RWMutex
  2. 在 Logger() 中对 map 的读取和写入使用同一把锁保护
  3. 在 IsMyLogger() 中遍历 m.loggers 前增加读锁

或者从设计上避免在 IsMyLogger() 中依赖遍历共享 map 来判断 logger 归属。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions