国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

字節(jié)微服務(wù)HTTP框架Hertz使用與源碼分析|擁抱開源

這篇具有很好參考價值的文章主要介紹了字節(jié)微服務(wù)HTTP框架Hertz使用與源碼分析|擁抱開源。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

一、前言

大家好,這里是白澤,今天介紹一個自己參與過一些維護(hù)的 HTTP 框架。

Hertz[h??ts] 是一個 Golang 微服務(wù) HTTP 框架,在設(shè)計之初參考了其他開源框架 fasthttp、gin、echo 的優(yōu)勢, 并結(jié)合字節(jié)跳動內(nèi)部的需求,使其具有高易用性、高性能、高擴展性等特點,目前在字節(jié)跳動內(nèi)部已廣泛使用。 如今越來越多的微服務(wù)選擇使用 Golang,如果對微服務(wù)性能有要求,又希望框架能夠充分滿足內(nèi)部的可定制化需求,Hertz 會是一個不錯的選擇。

對于源碼該如何閱讀,本身就值得思考。這篇文章我將以第一次閱讀Hertz源碼的視角,分享自己的思考過程,也借此梳理一下自己閱讀源碼的方法論。

接下來需要你對應(yīng)打開Hertz的官方文檔,以及在本地克隆Hertz的代碼倉庫,我們開始吧。

Hertz倉庫地址:https://github.com/cloudwego/hertz

Hertz文檔地址:https://www.cloudwego.io/zh/docs/hertz/getting-started/

二、架構(gòu)設(shè)計

字節(jié)微服務(wù)HTTP框架Hertz使用與源碼分析|擁抱開源,golang,微服務(wù),http,開源

這是一張Hertz官方文檔的架構(gòu)設(shè)計圖,圖中的一個個組件對應(yīng)hertz源碼包內(nèi)的一個個package文件夾,實現(xiàn)了對應(yīng)的功能,如下:

字節(jié)微服務(wù)HTTP框架Hertz使用與源碼分析|擁抱開源,golang,微服務(wù),http,開源

三、快速開始

接下來按照文檔的指示,通過hertz的命令行工具初始化一個最簡單的hertz項目,先觀其形,再會其意。

對應(yīng)文檔地址:https://www.cloudwego.io/zh/docs/hertz/getting-started/

# 安裝hertz的命令行工具,用于生成hertz初始代碼
go install github.com/cloudwego/hertz/cmd/hz@latest
# 通過hz工具生成代碼,如果創(chuàng)建的項目不在GOPATH/src路徑下,則需要額外聲明-module參數(shù)
hz new -module hertz-study

字節(jié)微服務(wù)HTTP框架Hertz使用與源碼分析|擁抱開源,golang,微服務(wù),http,開源

此時按照文檔指示,對項目進(jìn)行編譯運行可以訪問這個HTTP服務(wù)了,它默認(rèn)實現(xiàn)了一個/ping接口。

curl http://127.0.0.1:8888/ping
# 響應(yīng)
{"message":"pong"}% 

四、源碼解析

server概覽

首先看一下main.go函數(shù),這是hertz服務(wù)的啟動入口,大概可以猜測內(nèi)容是:1. 初始化了一個默認(rèn)的hz服務(wù);2. 完成了一些注冊工作;3. 啟動hz服務(wù)(HTTP服務(wù))。

func main() {
   h := server.Default()
?
   register(h)
   h.Spin()
}

回想剛剛這個 http://127.0.0.1:8888/ping 的接口服務(wù),它所聲明的IP和Port并未由你手動指定,并且/ping接口也不是你編寫的,或許是這個server.Default()的作用。

反之我如果需要指定HTTP服務(wù)啟動的各種定制化的配置,是否是給這個server.Default()傳參數(shù)?又或者是換一個創(chuàng)建h的方法?

Default()

// Default creates a hertz instance with default middlewares.
func Default(opts ...config.Option) *Hertz {
   h := New(opts...)
   h.Use(recovery.Recovery())
?
   return h
}

查看Default()方法,發(fā)現(xiàn)確實可以傳入?yún)?shù)(猜測就是可以自定義配置的內(nèi)容),然后我們進(jìn)一步分析New方法的內(nèi)容,它接受了一個不定長度的Option數(shù)組為參。

// Option is the only struct that can be used to set Options.
type Option struct {
  F func(o *Options)
}
?
// New creates a hertz instance without any default config.
func New(opts ...config.Option) *Hertz {
  options := config.NewOptions(opts)
  h := &Hertz{
    Engine: route.NewEngine(options),
  }
  return h
}

接著我們再進(jìn)入config.NewOptions方法觀察這個Option切片將如何把我們自定義的內(nèi)容應(yīng)用到Hertz服務(wù)的初始化上去。

func NewOptions(opts []Option) *Options {
   options := &Options{
      KeepAliveTimeout: defaultKeepAliveTimeout,
      ReadTimeout: defaultReadTimeout,
      IdleTimeout: defaultReadTimeout,
      RedirectTrailingSlash: true,
      RedirectFixedPath: false,
      HandleMethodNotAllowed: false,
      UseRawPath: false,
      RemoveExtraSlash: false,
      UnescapePathValues: true,
      DisablePreParseMultipartForm: false,
      Network: defaultNetwork,
      Addr: defaultAddr,
      MaxRequestBodySize: defaultMaxRequestBodySize,
      MaxKeepBodySize: defaultMaxRequestBodySize,
      GetOnly: false,
      DisableKeepalive: false,
      StreamRequestBody: false,
      NoDefaultServerHeader: false,
      ExitWaitTimeout: defaultWaitExitTimeout,
      TLS: nil,
      ReadBufferSize: defaultReadBufferSize,
      ALPN: false,
      H2C: false,
      Tracers: []interface{}{},
      TraceLevel: new(interface{}),
      Registry: registry.NoopRegistry,
   }
   // 將自定義配置應(yīng)用上去的方法
   options.Apply(opts)
   return options
}
?
func (o *Options) Apply(opts []Option) {
  for _, op := range opts {
    op.F(o)
  }
}

通過觀察config.NewOptions源碼,它首先初始化了一個Options結(jié)構(gòu),這個結(jié)構(gòu)存放了Hertz服務(wù)的各種初始化信息,此時的Options的各個屬性都是默認(rèn)固定的,直到調(diào)用了options.Apply(opts)方法,將自定義的配置應(yīng)用上去。

并且應(yīng)用上去的方式很特別,它將這個默認(rèn)創(chuàng)建的Options結(jié)構(gòu)的指針作為參數(shù)傳遞給每一個你聲明的Option的F方法,通過F方法的調(diào)用去為Options結(jié)構(gòu)賦值,因為是指針,自然能將所有的賦值應(yīng)用到同一個Options上去。

而具體的Option的F方法如何定義,則可以靈活實現(xiàn),這也是Hertz擁有良好擴展性的原因之一。

// Default creates a hertz instance with default middlewares.
func Default(opts ...config.Option) *Hertz {
  // h是*Hertz類型,是框架的核心結(jié)構(gòu)
   h := New(opts...)
   h.Use(recovery.Recovery())
?
   return h
}

此時注意到還有一個h.Use(recovery.Recovery())方法,寫法很像是gin框架的中間件使用方式。

// Recovery returns a middleware that recovers from any panic and writes a 500 if there was one.
func Recovery() app.HandlerFunc {
   return func(c context.Context, ctx *app.RequestContext) {
      defer func() {
         if err := recover(); err != nil {
            stack := stack(3)
?
            hlog.CtxErrorf(c, "[Recovery] %s panic recovered:\n%s\n%s\n",
               timeFormat(time.Now()), err, stack)
            ctx.AbortWithStatus(consts.StatusInternalServerError)
         }
      }()
      ctx.Next(c)
   }
}

通過閱讀注釋確實發(fā)現(xiàn)這是個中間件,用于從panic中recover。

register()

func main() {
   h := server.Default()
?
   register(h)
   h.Spin()
}

回到最初的main方法中,經(jīng)過分析我們知道了Default方法大致完成了默認(rèn)(自定義)Hertz結(jié)構(gòu)的聲明,下面看一下register函數(shù)的內(nèi)容

// register registers all routers.
func register(r *server.Hertz) {
?
   router.GeneratedRegister(r)
?
   customizedRegister(r)
}
?
// GeneratedRegister registers routers generated by IDL.
func GeneratedRegister(r *server.Hertz) {
  //INSERT_POINT: DO NOT DELETE THIS LINE!
}
?
// customizeRegister registers customize routers.
func customizedRegister(r *server.Hertz) {
  r.GET("/ping", handler.Ping)
?
  // your code ...
}

register(h)的工作是路由注冊(也就是接口的聲明),內(nèi)部完成了兩種類型的注冊,GeneratedRegister()的注釋指出這部分路由是由IDL生成的,關(guān)于IDL先賣個關(guān)子,你只要知道IDL描述了接口交互的結(jié)構(gòu)。

customizedRegister()則是用于注冊自定義的路由接口,并且初始化了一個你熟悉的/ping,當(dāng)然也你可以在這里注冊自己需要的路由,使用的方式也與gin很相似。

Spin()

最后分析一下main方法中的的第三部分,Spin方法。

// Spin runs the server until catching os.Signal or error returned by h.Run().
func (h *Hertz) Spin() {
   errCh := make(chan error)
   h.initOnRunHooks(errCh)
   go func() {
      // 核心方法
      errCh <- h.Run()
   }()
?
   signalWaiter := waitSignal
   if h.signalWaiter != nil {
      signalWaiter = h.signalWaiter
   }
?
   if err := signalWaiter(errCh); err != nil {
      hlog.Errorf("HERTZ: Receive close signal: error=%v", err)
      if err := h.Engine.Close(); err != nil {
         hlog.Errorf("HERTZ: Close error=%v", err)
      }
      return
   }
?
   hlog.Infof("HERTZ: Begin graceful shutdown, wait at most num=%d seconds...", h.GetOptions().ExitWaitTimeout/time.Second)
?
   ctx, cancel := context.WithTimeout(context.Background(), h.GetOptions().ExitWaitTimeout)
   defer cancel()
?
   if err := h.Shutdown(ctx); err != nil {
      hlog.Errorf("HERTZ: Shutdown error=%v", err)
   }
}

完成了一系列的初始化和聲明操作之后,Spin()負(fù)責(zé)觸發(fā)Hertz的運行,并且處理運行過程中的各種異常。其核心是errCh <- h.Run()

func (engine *Engine) Run() (err error) {
   if err = engine.Init(); err != nil {
      return err
   }
?
   if !atomic.CompareAndSwapUint32(&engine.status, statusInitialized, statusRunning) {
      return errAlreadyRunning
   }
   defer atomic.StoreUint32(&engine.status, statusClosed)
?
   // trigger hooks if any
   ctx := context.Background()
   for i := range engine.OnRun {
      if err = engine.OnRun[i](ctx); err != nil {
         return err
      }
   }
?
   return engine.listenAndServe()
}

再看到末尾的engine.listenAndServe()方法,這是一個接口,查看其實現(xiàn)類,發(fā)現(xiàn)可以追溯到standard和netpoll兩個包。

字節(jié)微服務(wù)HTTP框架Hertz使用與源碼分析|擁抱開源,golang,微服務(wù),http,開源

作為一個HTTP服務(wù),最重要的就是提供網(wǎng)絡(luò)通信交互能力,Hertz使用了可插拔的自研網(wǎng)絡(luò)庫netpoll負(fù)責(zé)網(wǎng)絡(luò)通信,進(jìn)一步優(yōu)化了性能,這部分也將在后續(xù)的文章著重分析。

至此Hertz服務(wù)開始運行,你可以通過控制臺請求:

curl http://127.0.0.1:8888/ping
{"message":"pong"}% 

五、小結(jié)

使用hz工具生成最簡易的Hertz代碼后,本文粗淺地分析了main方法的內(nèi)容,將其分為三個部分,服務(wù)配置聲明Default()、路由注冊register()、HTTP服務(wù)啟動Spin()

雖然沒有提及Hertz框架架構(gòu)圖當(dāng)中的各種類型的package,但是其實處處有它們的身影,后續(xù)文章將以此文為基礎(chǔ),深入分析框架的各個功能組件,揭開Hertz的神秘面紗。

感興趣可以關(guān)注公眾號 「白澤talk」,白澤目前也打算打造一個氛圍良好的行業(yè)交流群,文章的更新也會提前預(yù)告,歡迎加入:622383022。文章來源地址http://www.zghlxwxcb.cn/news/detail-804388.html

到了這里,關(guān)于字節(jié)微服務(wù)HTTP框架Hertz使用與源碼分析|擁抱開源的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • C++輕量級Web服務(wù)器TinyWebServer源碼分析之http篇

    C++輕量級Web服務(wù)器TinyWebServer源碼分析之http篇

    http類這篇個人覺得是最難同時也是最繁瑣的一篇,本篇在基礎(chǔ)知識方面,包括epoll、HTTP報文格式、狀態(tài)碼和有限狀態(tài)機,不做贅述,所有源碼分析的篇章基礎(chǔ)知識會做單開一篇或者讀者可以看 小白一文看懂社長服務(wù)器 來補基礎(chǔ)知識。真的佩服那個叫社長的男人,我讀代碼且

    2024年02月10日
    瀏覽(27)
  • 小研究 - Android 字節(jié)碼動態(tài)分析分布式框架(四)

    小研究 - Android 字節(jié)碼動態(tài)分析分布式框架(四)

    安卓平臺是個多進(jìn)程同時運行的系統(tǒng),它還缺少合適的動態(tài)分析接口。因此,在安卓平臺上進(jìn)行全面的動態(tài)分析具有高難度和挑戰(zhàn)性。已有的研究大多是針對一些安全問題的分析方法或者框架,無法為實現(xiàn)更加靈活、通用的動態(tài)分析工具的開發(fā)提供支持。此外,很多研究只是

    2024年02月12日
    瀏覽(22)
  • 小研究 - Android 字節(jié)碼動態(tài)分析分布式框架(五)

    小研究 - Android 字節(jié)碼動態(tài)分析分布式框架(五)

    安卓平臺是個多進(jìn)程同時運行的系統(tǒng),它還缺少合適的動態(tài)分析接口。因此,在安卓平臺上進(jìn)行全面的動態(tài)分析具有高難度和挑戰(zhàn)性。已有的研究大多是針對一些安全問題的分析方法或者框架,無法為實現(xiàn)更加靈活、通用的動態(tài)分析工具的開發(fā)提供支持。此外,很多研究只是

    2024年02月10日
    瀏覽(22)
  • 【Tars-go】騰訊微服務(wù)框架學(xué)習(xí)使用02-- http 服務(wù)

    官方文檔說http這里是在net/http原生包的基礎(chǔ)上做了修改。 官方給的案例: 可以看到 在初始化了 TarsHttpMux , 再將 TarsHttpMux 注冊到tars框架中作為servant就可以啟動http服務(wù)。 TarsHttpMux 是什么: 可以看出 TarsHttpMux 確實就只是對 http.ServeMux 做了個包裝加入了 Conf 并加入了上報狀態(tài)信

    2024年04月16日
    瀏覽(27)
  • http服務(wù)(Apache 2.4.57)源碼編譯及使用

    這里安裝的是Apache 2.4.57版本 下載地址

    2024年02月11日
    瀏覽(17)
  • Android 計時器Chronometer 使用及源碼分析(1),android音視頻框架

    Android 計時器Chronometer 使用及源碼分析(1),android音視頻框架

    @Override protected?void?onCreate(Bundle?savedInstanceState)?{ super.onCreate(savedInstanceState); setContentView(R.layout.activity_textview_chronometer);//加載布局文件 initView(); } private?void?initView()?{ btn_start?=?findViewById(R.id.btn_start); btn_stop?=?findViewById(R.id.btn_stop); btn_reset?=?findViewById(R.id.btn_reset); chronome

    2024年04月14日
    瀏覽(28)
  • 基于 Hertz 和 Kitex 的 Go 微服務(wù)項目 | 開源項目推薦

    基于 Hertz 和 Kitex 的 Go 微服務(wù)項目 | 開源項目推薦

    FreeCar 是一個基于 Hertz 與 Kitex 的全棧微服務(wù)項目,歡迎 Star。 項目地址:CyanAsterisk/FreeCar Hertz 是一個超大規(guī)模的企業(yè)級微服務(wù) HTTP 框架,具有高易用性、易擴展、低時延等特點。 Hertz 默認(rèn)使用自研的高性能網(wǎng)絡(luò)庫 Netpoll,在一些特殊場景中,相較于 go net,Hertz 在 QPS、時延上

    2024年02月07日
    瀏覽(26)
  • 【微服務(wù)】spring 條件注解從使用到源碼分析詳解

    目錄 一、前言 二、spring 條件注解概述 2.1 條件注解@Conditional介紹 2.2 @Conditional擴展注解

    2024年02月11日
    瀏覽(23)
  • 【微服務(wù)】Spring條件注解從使用到源碼分析詳解

    【微服務(wù)】Spring條件注解從使用到源碼分析詳解

    ??歡迎來到架構(gòu)設(shè)計專欄~【微服務(wù)】Spring條件注解從使用到源碼分析詳解 ☆* o(≧▽≦)o *☆嗨~我是IT·陳寒?? ?博客主頁:IT·陳寒的博客 ??該系列文章專欄:架構(gòu)設(shè)計 ??其他專欄:Java學(xué)習(xí)路線 Java面試技巧 Java實戰(zhàn)項目 AIGC人工智能 數(shù)據(jù)結(jié)構(gòu)學(xué)習(xí) ??文章作者技術(shù)和水平

    2024年02月08日
    瀏覽(20)
  • Web端服務(wù)器推送技術(shù)原理分析及dwr框架簡單的使用(1)

    Web端服務(wù)器推送技術(shù)原理分析及dwr框架簡單的使用(1)

    隨著?Ajax技術(shù)的興起,讓廣大開發(fā)人員又一次看到了使用瀏覽器來替代桌面應(yīng)用的機會,并且這次機會非常大。Ajax將整個頁面的刷新變成頁面局部的刷新,并且數(shù)據(jù)的傳送是以異步方式進(jìn)行,這使得網(wǎng)絡(luò)延遲帶來的視覺差異將會消失。 但是,在瀏覽器中的?Ajax應(yīng)用中存在一

    2024年04月25日
    瀏覽(20)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包