1. Uber 的 zap 庫是如何做到高性能的?

        共 3501字,需瀏覽 8分鐘

         ·

        2021-03-02 16:10

        點(diǎn)擊上方藍(lán)色“Go語言中文網(wǎng)”關(guān)注,每天一起學(xué) Go

        插圖由“go 之旅”提供,原圖由 Renee French 創(chuàng)作

        Go 生態(tài)系統(tǒng)有許多流行的日志庫,選擇一個(gè)可以在所有項(xiàng)目中使用的日志庫對于保持最小的一致性至關(guān)重要。易用性和性能通常是我們在日志庫中考慮的兩個(gè)指標(biāo)。接下來我們回顧一下 Uber[1] 開發(fā)的 Zap[2] 日志庫。

        核心思想

        Zap 基于三個(gè)概念優(yōu)化性能,第一個(gè)是:

        • 避免使用 interface{} 有利于強(qiáng)類型的設(shè)計(jì)。

        這一點(diǎn)隱藏另外兩個(gè)概念:

        • 無反射。反射是有代價(jià)的,而且可以避免,因?yàn)榘軌驔Q定被調(diào)用的類型。

        在 JSON 編碼中沒有額外內(nèi)存分配。如果對標(biāo)準(zhǔn)庫進(jìn)行了優(yōu)化,則可以輕松避免在此處進(jìn)行內(nèi)存分配,因?yàn)?package 包含所有已發(fā)送參數(shù)的類型。

        以上幾點(diǎn),對開發(fā)人員來說成本不高,因此他們需要在記錄消息時(shí)聲明每種類型:

        logger.Info("failed to fetch URL",
         // Structured context as strongly typed Field values.
         zap.String("url"`http://foo.com`),
         zap.Int("attempt"3),
         zap.Duration("backoff", time.Second),
        )

        每個(gè)字段的顯式聲明將允許包在日志記錄過程中高效地工作。讓我們回顧一下包的設(shè)計(jì),以了解這些優(yōu)化將在何處發(fā)生。

        設(shè)計(jì)

        在高亮顯示包的優(yōu)化部分之前,讓我們繪制日志庫的全局工作流:

        Zap 包工作流

        第一步優(yōu)化,為了避免進(jìn)行系統(tǒng)分配,我們看到優(yōu)化使用同步池在記錄消息。每個(gè)要記錄的消息都將重用之前創(chuàng)建的結(jié)構(gòu)體(structure),并將其釋放到池中。

        第二部優(yōu)化,涉及編碼器和 JSON 的存儲方式。要記錄的每個(gè)字段都是強(qiáng)類型的,如前一節(jié)所示。它允許編碼器通過直接將值轉(zhuǎn)儲到緩沖區(qū)來避免反射和分配:

        優(yōu)化過的 JSON 編碼器

        這個(gè)緩沖區(qū)的管理要感謝 sync.Pool.

        最終調(diào)用方的性能/成本的權(quán)衡非常有趣,因?yàn)轱@式聲明每個(gè)字段不需要開發(fā)人員付出太多努力。但是,該庫為 logger 提供了一層封裝,它公開了一個(gè)對開發(fā)人員更友好的接口,您不需要定義要記錄的每個(gè)字段的每種類型。可從 logger.Sugar() 方法中獲取,它將稍微減慢并增加日志庫的分配數(shù)。

        與 Go 生態(tài)系統(tǒng)中可用的其他包相比,所有這些優(yōu)化使包的速度相當(dāng)快,并顯著減少了內(nèi)存分配。讓我們?yōu)g覽并比較一下可用的替代方案。

        其他選擇

        Zap 提供的 基準(zhǔn)[3] 測試清楚地表明 Zerolog[4] 是與 Zap 競爭最激烈的一個(gè)。Zerolog 還提供了結(jié)果非常相似的 基準(zhǔn)[5]

        來自 https://github.com/rs/zerolog 的基準(zhǔn)

        它清楚地展示 Zerolog 和 Zap 在性能方面比其他軟件包要好得多,速度快 5 到 27 倍。

        現(xiàn)在讓我們比較一下用 Zerolog 編寫的同一段代碼:

        l := zerolog.New(zerolog.ConsoleWriter{Out: os.Stderr})
        l.Info().
          Str("url"`http://foo.com`).
          Int("attempt"3).
          Dur("backoff", time.Second).
          Msg("failed to fetch URL")

        寫法上非常接近,并且我們可以看到 Zerolog 也引入強(qiáng)類型參數(shù)以優(yōu)化性能。如 encoder 接口所述,JSON 編碼器還根據(jù)類型轉(zhuǎn)儲數(shù)據(jù):

        zerolog 編碼器接口

        發(fā)送到日志庫的每個(gè)條目( Zerolog 中稱為 event )也使用 sync 包中的池,以避免在記錄消息時(shí)進(jìn)行系統(tǒng)分配。

        正如我們所看到的,這些軟件包非常相似。這解釋了為什么他們的性能很接近。讓我們嘗試另一個(gè)具有不同設(shè)計(jì)的包,以了解在這些包中缺少的優(yōu)化。

        現(xiàn)在讓我們將這些 logger 與 Golang 生態(tài)系統(tǒng)中另一個(gè)著名的包 Logrus[6] 進(jìn)行比較。以下是相同功能的代碼:

        log.SetOutput(os.Stdout)
        log.WithFields(log.Fields{
          "url""http://foo.com",
          "attempt":   3,
          "backoff":   time.Second,
        }).Info("failed to fetch URL")

        在內(nèi)部,Logrus 還將為 entry 對象使用一個(gè)池,但是在檢查與消息一起發(fā)送的字段時(shí)將添加一個(gè)反射層。此反射允許日志庫檢測傳遞給日志庫的所有參數(shù)是否有效,但會稍微減慢執(zhí)行速度。

        另外,與 Zap 或 Zerolog 相反,參數(shù)不是類型化的,這將導(dǎo)致將起始類型轉(zhuǎn)換為空接口,然后返回起始類型以便對其進(jìn)行編碼。

        該包還為鉤子添加了一層額外的鎖,如果需要,可以將其移除,但默認(rèn)情況下會激活。

        沒有優(yōu)化

        閱讀這些庫的編寫方式對于每個(gè) Go 開發(fā)人員來說都是一個(gè)很好的練習(xí),以便了解如何優(yōu)化我們的代碼和潛在的好處。大多數(shù)情況下,對于非關(guān)鍵應(yīng)用程序,您不需要深入研究,但是如果像 Zap 或 Zerolog 這樣的外部包免費(fèi)提供這些優(yōu)化,我們絕對應(yīng)該利用它。如果您想了解使用池的潛在好處,我建議您閱讀我的文章“Understand the design of sync.Pool[7]”.


        via: https://medium.com/a-journey-with-go/go-how-zap-package-is-optimized-dbf72ef48f2d

        作者:Vincent Blanchon[8]譯者:lts8989[9]校對:polaris1119[10]

        本文由 GCTT[11] 原創(chuàng)編譯,Go 中文網(wǎng)[12] 榮譽(yù)推出

        參考資料

        [1]

        Uber: https://github.com/uber-go

        [2]

        Zap: https://github.com/uber-go/zap

        [3]

        基準(zhǔn): https://github.com/uber-go/zap/tree/v1.10.0/benchmarks

        [4]

        Zerolog: https://github.com/rs/zerolog

        [5]

        基準(zhǔn): https://github.com/rs/logbench

        [6]

        Logrus: https://github.com/sirupsen/logrus

        [7]

        Understand the design of sync.Pool: https://medium.com/@blanchon.vincent/go-understand-the-design-of-sync-pool-2dde3024e277

        [8]

        Vincent Blanchon: https://medium.com/@blanchon.vincent

        [9]

        lts8989: https://github.com/lts8989

        [10]

        polaris1119: https://github.com/polaris1119

        [11]

        GCTT: https://github.com/studygolang/GCTT

        [12]

        Go 中文網(wǎng): https://studygolang.com/



        推薦閱讀


        福利

        我為大家整理了一份從入門到進(jìn)階的Go學(xué)習(xí)資料禮包,包含學(xué)習(xí)建議:入門看什么,進(jìn)階看什么。關(guān)注公眾號 「polarisxu」,回復(fù) ebook 獲?。贿€可以回復(fù)「進(jìn)群」,和數(shù)萬 Gopher 交流學(xué)習(xí)。

        瀏覽 99
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. 亚洲色图网站 | 一边喂奶一边挨cao | 尺度大的床戏裸体电影 | 美女一级黄色 | 综合激情AV |