Implementation of the core structure of the high-performance Go HTTP framework Hertz for beginners
Tags: webdev, go, cloudnative, beginners
Published: 2022-10-28 01:54:18

## Hertz

[Hertz](https://github.com/cloudwego/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](https://picture.lanlance.cn/i/2022/10/28/635b27ec63bd9.png)

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](https://github.com/cloudwego/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](https://www.cloudwego.io/zh/blog/2022/06/21/%E8%B6%85%E5%A4%A7%E8%A7%84%E6%A8%A1%E7%9A%84%E4%BC%81%E4%B8%9A%E7%BA%A7%E5%BE%AE%E6%9C%8D%E5%8A%A1-http-%E6%A1%86%E6%9E%B6-hertz-%E6%AD%A3%E5%BC%8F%E5%BC%80%E6%BA%90/).

## 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.

```go
// Hertz is the core struct of hertz.
type Hertz struct {
   *route.Engine
}
```
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

```go
// 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 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.

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

   return h
}
```

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.

```go
func (h *Hertz) SetCustomSignalWaiter(f func(err chan error) error) {
	h.signalWaiter = f
}
```

### 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.

```go
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
}
```

### 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`.

```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()
}
```

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](https://github.com/cloudwego/hertz) for more information. I'm sure the documentation has answers to all your questions.

## Reference List

- [Hertz official document](https://www.cloudwego.io/docs/hertz/)
- [cloudwego/hertz](https://github.com/cloudwego/hertz)