Interpretación del marco HTTP de código abierto de bytes Hertz | Implementación de estructura central y entrada

prefacio

Como posible estudiante de segundo año que ha estado en contacto con la comunidad de código abierto durante aproximadamente un año, mientras contribuyo a la comunidad de código abierto, también quiero crear un marco propio: goffee Encontré muchas deficiencias en el proceso de aprender y escribir. CSG está organizando un evento para analizar el código fuente de Hertz. Aproveché esta oportunidad para aprender sobre la implementación interna del marco de nivel empresarial y proporcionar algunas ideas para mi propio marco.

hercios

Hertz es un marco HTTP de microservicio de nivel empresarial de ultra gran escala, que presenta una alta facilidad de uso, fácil expansión y baja latencia.

Hertz utiliza la biblioteca de red de alto rendimiento de desarrollo propio Netpoll de forma predeterminada.En algunos escenarios especiales, Hertz tiene ciertas ventajas en QPS y latencia en comparación con go net. Para obtener información sobre el rendimiento, consulte los datos de Echo a continuación.

imagenEn la práctica interna, algunos servicios típicos, como los servicios con una alta proporción de marcos, puertas de enlace y otros servicios, después de migrar Hertz, en comparación con el marco Gin, el uso de recursos se reduce significativamente y el uso de CPU se reduce en un 30%- 60% con el tamaño del tráfico . Para obtener datos de rendimiento detallados, consulte: github.com/cloudwego/h…

herramienta de línea de comandos

Hertz proporciona una herramienta de línea de comandos fácil de usar Hz. Los usuarios solo necesitan proporcionar un IDL. De acuerdo con la información de la interfaz definida, Hz puede generar andamios de proyectos con un solo clic y usar Hertz listo para usar; Hz también proporciona capacidades de actualización , los usuarios pueden El IDL de Hz puede actualizar el andamiaje si cambia. Actualmente, Hz admite dos definiciones de IDL, Thrift y Protobuf. La herramienta de línea de comandos tiene opciones ricas integradas que se pueden usar según sus necesidades. Al mismo tiempo, se basa en el compilador Protobuf oficial y el compilador Thriftgo de desarrollo propio en la parte inferior, los cuales admiten complementos de código generados personalizados. Si cree que la plantilla predeterminada no puede satisfacer las necesidades, puede personalizar la plantilla generada.

Puede encontrar más información sobre Hertz en mp.weixin.qq.com/s/D1Pol8L9F…

Implementación de Hertz Core Structure and Entry

hercios

Para aprender un marco, primero debe aprender su estructura central, y la estructura central y la entrada del marco de Hertz es el archivo con el mismo nombre hertz.go. El documento no es extenso, y no es exagerado decir que es breve y conciso.

La estructura central está al principio del archivo con una línea prominente de comentarios.

// Hertz is the core struct of hertz.
type Hertz struct {
   *route.Engine
}

El comentario significa que la estructura de Hertz aquí es la estructura central de todo el marco. La estructura está encapsulada routey Engineel motor contiene todos los métodos. Si desea utilizar este marco, debe confiar en este motor.

Nuevo

// 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
}

New es el constructor del motor. Puede crear una nueva Engineinstancia y no contendrá la configuración predeterminada, pero puede personalizar la configuración relevante usted mismo, y la instancia se devolverá después de la construcción.

Defecto

Por lo general, lo usaremos en nuestro desarrollo Defalten lugar de usarlo directamente New, porque Defaltse usará el precio medio predeterminado Recoveryy el marco Gin también tendrá un middleware de registro.

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

   return h
}

Al llamar a Defaultla función, Engineprimero se creará una instancia y se usará el Recoverymiddleware . RecoveryLa implementación es muy simple. Use la función para montar la recuperación de errores, llame a la función recovery ()defer en esta función , capture el pánico e imprima la información de la pila. en el registro El usuario devuelve un  error interno del servidor . Puede evitar la terminación completa del programa debido al pánico .

Además Defalt, también admite información de configuración personalizada.

Girar

在CloudWeGo给的示例代码中我们可以发现在最后一行都会调用Spin(),如果是像我一样平常更多使用Gin框架的同学可能就不太懂它的含义。根据注释所讲,Spin() 运行服务器直到捕获os.SignalSIGTERM触发器立即关闭。SIGHUP|SIGINT触发正常关闭。

// Spin runs the server until catching os.Signal.
// SIGTERM triggers immediately close.
// SIGHUP|SIGINT triggers graceful shutdown.
func (h *Hertz) Spin() {
   errCh := make(chan error)
   go func() {
      errCh <- h.Run()
   }()

   if err := waitSignal(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)
   }
}

在代码实现中我们会先make一个通道,并跑一个携程来等待接收信息,当接受到关闭的信号后就会优雅的关掉程序。这个实现确实是非常优雅,而关于其中的waitSignal我们在下面继续解读。

waitSignal

在这个函数中我们会等待信号,并有一个select来对应接下来的操作,其中有强制退出以及优雅退出,如果有错误也会将err返回回去

func waitSignal(errCh chan error) error {
   signals := make(chan os.Signal, 1)
   signal.Notify(signals, syscall.SIGINT, syscall.SIGHUP, syscall.SIGTERM)

   select {
   case sig := <-signals:
      switch sig {
      case syscall.SIGTERM:
         // force exit
         return errors.New(sig.String()) // nolint
      case syscall.SIGHUP, syscall.SIGINT:
         // graceful shutdown
         return nil
      }
   case err := <-errCh:
      return err
   }

   return nil
}

小结

在此之后我们就已经将hertz.go的源码解读完了,但是只看到源码可能还是会有不懂的地方,我们接下来就用CloudWeGo的例子来进一步看看是怎样使用的

简单实战

我们直接看hertz-examples/hello/main.go

package main

import (
	"context"

	"github.com/cloudwego/hertz/pkg/app"
	"github.com/cloudwego/hertz/pkg/app/server"
	"github.com/cloudwego/hertz/pkg/protocol/consts"
)

func main() {
	// server.Default() creates a Hertz with recovery middleware.
	// If you need a pure hertz, you can use server.New()
	h := server.Default()

	h.GET("/hello", func(ctx context.Context, c *app.RequestContext) {
		c.String(consts.StatusOK, "Hello hertz!")
	})

	h.Spin()
}

进入main函数的第一行就告知了使用Defalt会自带错误恢复中间件,若想要纯净的实例请使用New。接下来他就调用了server.Default(),然后是就是一个GET请求的路由,会打印出"Hello hertz!"。最后调用了Spin(),等待信号

结语

分析了这一个go文件就花费了不少时间,对于源码解读还需要继续努力

Si hay algo que no está claro, no dude en hacerme preguntas y haré todo lo posible para responderlas.

Aquí está mi página de inicio de GitHub  github.com/L2ncE

Bienvenidos a todos a Seguir /Estrella/Tenedor

Este artículo participa en la edición 18 de temas técnicos: charla sobre el marco del lenguaje Go

Supongo que te gusta

Origin juejin.im/post/7120824850003787789
Recomendado
Clasificación