go微服务json处理慢主因是标准库反射和内存分配,用easyjson预生成编解码代码可将序列化耗时降至1/5,需导出字段、避免interface{}、复用编码器及缓冲区,并配合json.rawmessage延迟解析。

Go微服务里JSON处理慢,八成不是代码写错,而是掉进了标准库的反射和内存分配陷阱。直接换库或改结构体标签就能明显提速,没必要先上profiling。
用 easyjson 替代 json.Marshal 和 json.Unmarshal
标准库每次调用都走反射,easyjson 在编译期为每个结构体生成专用的 MarshalJSON 和 UnmarshalJSON 方法,完全绕过反射。实测在稳定DTO场景下,序列化耗时能降到原生的1/5左右。
- 必须用导出字段(首字母大写),否则生成失败
-
easyjson -all user.go会产出user_easyjson.go,记得go build时包含它 - 不支持嵌套的
interface{}字段,遇到就 panic,得提前 flatten 或改用json.RawMessage - 标签语法和标准库一致,
json:"id,omitempty"这类照常可用
高频接口中禁用 map[string]interface{} 和 interface{}
只要传给 json.Marshal 的是 interface{} 类型,哪怕背后是结构体指针,标准库也必须全程反射。CPU profile 里 reflect.Value.Interface 占比高,基本就是这个原因。
详细的 Three.js 3D 图形参考,涵盖场景设置、相机、几何体、材质、光照、动画、控制器、加载器、数学工具和调试。
- API 响应结构固定?直接定义
type UserResponse struct,别用泛型或 any 接收后再转 - 需要透传未知字段?用
json.RawMessage替代interface{},它只是[]byte包装,零解析、零分配 - 日志或配置项等弱结构数据才考虑
map[string]interface{},别让它进 hot path
复用 json.Encoder/json.Decoder 和缓冲区
每次新建 json.Encoder 都要初始化内部状态,频繁创建销毁还会触发 GC。尤其在 HTTP handler 中,一个请求建一个编码器是常见浪费。
- 用
sync.Pool缓存*json.Encoder或*bytes.Buffer,启动时预热一次 - 缓冲区优先用
bytes.Buffer而非strings.Builder,后者不兼容json.Encoder的io.Writer接口 - 预分配容量:比如常见响应不超过 2KB,就用
bytes.NewBuffer(make([]byte, 0, 2048))
流式处理大 JSON 时别全量加载
微服务间传日志、报表或原始事件数据时,如果用 ioutil.ReadAll 加载整个 body 再解,容易 OOM,且延迟不可控。
- 直接把
http.Request.Body传给json.NewDecoder,它边读边解,内存占用恒定 - 配合
decoder.Token()手动跳过不需要的字段,尤其对嵌套深、体积大的对象 - 用
decoder.More()判断是否还有下一个 JSON 值,适合处理 JSON 数组流
最容易被忽略的是:jsoniter.ConfigFastest 模式下,未注册的自定义类型仍会 fallback 到反射,性能断崖下跌。上线前务必检查所有结构体是否已全局注册类型编码器。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










