DEV Community

Cover image for Implementation of the core structure of the high-performance Go HTTP framework Hertz for beginners
L2ncE
L2ncE

Posted on

Implementation of the core structure of the high-performance Go HTTP framework Hertz for beginners

Hertz

Hertz is an ultra-large-scale enterprise-level microservice HTTP framework, featuring high ease of use, easy expansion, and low latency etc.

Hertz uses the self-developed high-performance network library Netpoll by default. In some special scenarios, Hertz has certain advantages in QPS and latency compared to go net. For performance data, please refer to the echo data below.

performance

In internal practice, for some typical services, such as services with a high proportion of frameworks, gateways and other services, after migrating Hertz, compared to the Gin framework, the resource usage is significantly reduced. For more information, see hertz-benchmark.

Hz

Hertz provides an easy-to-use command line tool Hz. Users only need to provide an IDL. According to the defined interface information, Hz can generate project scaffolding with one click, and use Hertz out of the box; Hz also provides update capabilities. The IDL of Hz can update the scaffolding if it changes. Currently Hz supports both Thrift and Protobuf IDL definitions. The command line tool has built-in rich options that can be used according to your needs. At the same time, it relies on the official Protobuf compiler and the self-developed Thriftgo compiler at the bottom, both of which support custom generated code plugins. If you feel that the default template cannot meet the needs, you can customize the generated template.

For more information, see.

Implementation of the core structure

Hertz

To learn a framework, you must first learn its core structure, and the core structure and entry of the Hertz framework is the file hertz.go with the same name as itself. The document is not lengthy, it can be said to be short and concise.

The core structure is at the beginning of the file with a prominent line of comments.

// Hertz is the core struct of hertz.
type Hertz struct {
   *route.Engine
}
Enter fullscreen mode Exit fullscreen mode

The comment means that the Hertz structure here is the core structure of the entire framework. The structure encapsulates the Engine under route, and the engine contains all the methods. If you want to use this framework, you must rely on this engine.

New

// 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
}
Enter fullscreen mode Exit fullscreen mode

New is the constructor of the engine. You can create a new Engine instance and it will not contain the default configuration, but you can customize the relevant configuration yourself, and the instance will be returned after construction.

Default

Usually we use Default instead of New directly in our development, because Default will use the default middleware Recovery, and the Gin framework will also have log middleware.

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

   return h
}
Enter fullscreen mode Exit fullscreen mode

When calling the Default function, an instance of Engine will be created first, and the Recovery middleware will be used. The implementation of Recovery is very simple. Use defer to mount the error recovery function, and call recover in this function (), catch panic, and print the stack information in the log, returning Internal Server Error to the user. It is possible to avoid the entire program terminating due to panic.

In addition, Default also supports custom configuration information.

In the code implementation, we will first make a channel and run a goroutine to wait for receiving information. When receiving the closing signal, we will gracefully close the program. And about the waitSignal among them, we will continue to interpret it below.

SetCustomSignalWaiter

SetCustomSignalWaiter sets the signal waiter function. If Default one is not met the requirement, set this function to customize. Hertz will exit immediately if f returns an error, otherwise it will exit gracefully.

func (h *Hertz) SetCustomSignalWaiter(f func(err chan error) error) {
    h.signalWaiter = f
}
Enter fullscreen mode Exit fullscreen mode

waitSignal

In this function, we will wait for the signal and have a select to correspond to the next operation, including forced exit and graceful exit, and err will be returned if there is an error.

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
}
Enter fullscreen mode Exit fullscreen mode

Summary

After that, we have already read the source code of hertz.go, but there may still be some things that you don't understand if you only see the source code. Next, we will use the example of CloudWeGo to further see how it is used.

Example

Let's look directly at 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()
}
Enter fullscreen mode Exit fullscreen mode

Entering the first line of the main function tells that using Default will have its own error recovery middleware. If you want a pure instance, please use New. Next he calls server.Default(), which is followed by a route for a GET request, which prints "Hello hertz!". Finally called Spin(), waiting for the signal.

Summary

You can check out the cloudwego/hertz for more information. I'm sure the documentation has answers to all your questions.

Reference List

Top comments (0)