uber.zap性能验证

一、性能基准测试

package test_golang_pool

import (
    "encoding/json"
    "fmt"
    "go.uber.org/zap"
    "go.uber.org/zap/zapcore"
    "os"
    "testing"
)

type User struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

// BenchmarkZapPrint
func BenchmarkZapPrint(b *testing.B) {
    u := &User{Name: "jack", Age: 18}
    fmt.Println(u)
    b.ResetTimer()
    encode := zap.NewProductionEncoderConfig()
    encode.TimeKey = ""
    encode.LevelKey = ""
    encode.CallerKey = ""
    encode.MessageKey = ""
    ee := zapcore.NewJSONEncoder(encode)
    www := zapcore.NewCore(ee, os.Stdout, zap.InfoLevel)
    logger, _ := zap.NewProduction(zap.WrapCore(func(core zapcore.Core) zapcore.Core {
        return www
    }))
    defer logger.Sync()
    for i := 0; i < b.N; i++ {
        var f []zapcore.Field
        f = append(f, zap.Any("message", u))
        logger.Info("success", f...)
    }
}

// BenchmarkSimplePrint
func BenchmarkSimplePrint(b *testing.B) {
    u := &User{Name: "jack", Age: 18}
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        j, _ := json.Marshal(u)
        fmt.Println(string(j))
    }
}

 

二、测试结果

BenchmarkZapPrint-8         406218          2816 ns/op

BenchmarkSimplePrint-8         492658          2441 ns/op

 

三、zap和logrus的性能比较 

//goos: darwin
//goarch: amd64
//pkg: test-pool
//cpu: VirtualApple @ 2.50GHz
//BenchmarkZap
//BenchmarkZap-8        1685895           710.4 ns/op         128 B/op           1 allocs/op
func BenchmarkZap(b *testing.B) {
    b.ReportAllocs()
    b.StopTimer()
    cfg := zap.NewProductionConfig()
    core := zapcore.NewCore(
        zapcore.NewJSONEncoder(cfg.EncoderConfig),
        zapcore.AddSync(io.Discard),
        zapcore.InfoLevel,
    )
    logger := zap.New(core)
    b.StartTimer()
    for i := 0; i < b.N; i++ {
        logger.Info("success",
            zap.String("name", `jack`),
            zap.Int("age", 18),
        )
    }
}

// goos: darwin
// goarch: amd64
// pkg: test-pool
// cpu: VirtualApple @ 2.50GHz
// BenchmarkLogrus
// BenchmarkLogrus-8         437836          2683 ns/op        1246 B/op          20 allocs/op
// BenchmarkLogrus
func BenchmarkLogrus(b *testing.B) {
    b.ReportAllocs()
    b.StopTimer()
    logger := logrus.New()
    logger.SetOutput(io.Discard)
    b.StartTimer()
    for i := 0; i < b.N; i++ {
        logger.WithFields(logrus.Fields{
            "name": "jack",
            "age":  18,
        }).Info("success")
    }
}

 

五、zap输出一行JSON到控制台

var once sync.Once

type School struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

// ZapLogger zap日志对象
var ZapLogger *zap.Logger

func ZapPrintJson() {
    s := &School{
        Name: "jack",
        Age:  18,
    }
    // 输出日志
    f := BuildFiledList(s)
    GetZapLogger().Info("success", f...)
}

func GetZapLogger() *zap.Logger {
    once.Do(func() {
        cfg := zap.NewProductionConfig()
        cfg.EncoderConfig.TimeKey = ""
        cfg.EncoderConfig.LevelKey = ""
        cfg.EncoderConfig.CallerKey = ""
        cfg.EncoderConfig.MessageKey = ""
        core := zapcore.NewCore(
            zapcore.NewJSONEncoder(cfg.EncoderConfig),
            os.Stdout,
            zapcore.InfoLevel,
        )
        ZapLogger = zap.New(core)
    })
    return ZapLogger
}

func BuildFiledList(s *School) []zapcore.Field {
    var f []zapcore.Field
    f = append(f, zap.String("name", s.Name))
    f = append(f, zap.Int("age", s.Age))
    return f
}

 

六、性能快的原因 ???

避免 interface{} 使用强类型设计

封装强类型,无反射

使用零分配内存的 JSON 编码器,尽可能避免序列化开销,它比其他结构化日志包快 4 - 10 倍

使用 sync.Pool 以避免记录消息时的内存分配

避免使用interface{}带来的开销(拆装箱、对象逃逸到堆上)

坚决不用反射,每个要输出的字段(field)在传入时都携带类型信息(这虽然降低了开发者使用zap的体验,但相对于其获得的性能提升,这点体验下降似乎也算不得什么)

使用sync.Pool减少堆内存分配(针对代表一条完整日志消息的zapcore.Entry),降低对GC压

logger 提供快速,分级,结构化的日志记录。所有的方法都是安全的,内存分配很重要,因此它的 API 有意偏向于性能和类型安全

 

七、零内存分配的JSON编码器,给各位演示一下大概的代码:

func GetJSONString() {
    b := buffer.Buffer{}
    // 下面会不断 switch zapField的类型给buff逐行添加数据拼接成json
    b.AppendByte('{')
    last := b.Len() - 1
    if last < 0 {
        return
    }
    switch b.Bytes()[last] {
    case '{', '[', ':', ',', ' ':
        break
    default:
        b.AppendByte(',')
    }
    b.AppendByte('"')
    s := "name"
    b.AppendString(s)
    b.AppendByte('"')
    b.AppendByte(':')
    b.AppendBool(true)
    b.AppendByte('}')
}

 看一下官方包 json.Marshal 用了很多的反射 简单实现一个试试

type L struct {
    Name string `json:"name"`
}

func TestReflect(test *testing.T) {
    l := L{Name: "rose"}
    var t reflect.Type
    t = reflect.TypeOf(l)
    var v reflect.Value
    v = reflect.ValueOf(l)
    json := "{"
    for i := 0; i < t.NumField(); i++ {
        if t.Field(i).Tag.Get("json") != "-" {
            json += "\"" + t.Field(i).Tag.Get("json") + "\":\"" + v.FieldByName(t.Field(i).Name).String() + "\""
        }
    }
    json += "}"
    fmt.Println(json)
}

 

  

https://zhuanlan.zhihu.com/p/390439745

https://copyfuture.com/blogs-details/20210708162035291A

 

 

posted @ 2022-06-15 20:35  许伟强  阅读(306)  评论(0)    收藏  举报