The elegant restart the service

Foreword

After each finished updating the code, finished updating the configuration file directly so  ctrl+c really no question, ctrl+cin the end done things?

In this section we briefly about the  ctrl+c signal behind and how to Gingracefully restart the service, which is to  HTTP serve hot update

Project Address: https://github.com/EDDYCJY/go-gin-example

ctrl + c

Kernel sends a signal, in some cases, such as when a process to produce a pipeline has been closed write data SIGPIPEsignal

The terminal performs a specific key combination allows the system to transmit a specific signal to the process, to complete the series of operations

command signal meaning
ctrl + c SIGINT End of compulsory process
ctrl + z SIGTSTP The task is interrupted, the process hangs
ctrl + \ SIGQUIT End of the process and dump core
ctrl + d   EOF
  Sigःuf Terminate the process receive the signal. If the program does not capture the signal, when the signal is received, the process will exit (commonly used to restart, reload process)

So we execute ctrl + cshut down ginwhen the server will force the end of the process, causing the user is visiting and other problems

Common  kill -9 pid will send  SIGKILL a signal to the process, but also a similar result

signal

What this paragraph repeated signal is it?

Signal  Unix , the class  Unix and the other  POSIX one kind of inter-compatible operating system in the process of communication has restricted manner

It is an asynchronous notification mechanism to alert the process of an event (hardware abnormality, abnormal program execution, external signals) has occurred. When a signal is sent to a process, the process of the operating system interrupts the normal flow of control. At this time, any non-atomic operation will be interrupted. If the process is defined signal processing functions, then it will be executed, otherwise execute the default handler

All signals

$ kill -l
 1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP
 6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
63) SIGRTMAX-1	64) SIGRTMAX

How elegant count

purpose

  • Without closing existing connection (program is running)
  • The new process is started and replace the old process
  • The new process takes over a new connection
  • To connect at any time in response to user requests, when a user requests still remain connected to the old process, the new user should request a new process, rejecting the request not appear in the case

Process

1, replace or modify executable profile

2, the amount of the transmission signal SIGHUP

3, reject new connection requests the old process, but to ensure the normal existing connection

4, start a new child process

5, new child process begins Accet

6, the system will transmit a new request for a new child process

7, the old process processed normally ended after all the old connection

A graceful restart

endless

Zero downtime restarts for golang HTTP and HTTPS servers. (for golang 1.3+)

We use  fvbock / endless  to achieve  Golang HTTP/HTTPS service restarts zero downtime

endless server Semaphore monitor the following:

  • syscall.SIGHUP: Trigger  fork child process and restart
  • syscall.SIGUSR1 / syscall.SIGTSTP: to be listening, but will not trigger any action
  • syscall.SIGUSR2: Trigger hammerTime
  • syscall.SIGINT / syscall.SIGTERM: trigger server closes (completes running requests)

endless It was on these positive signals amount of monitoring, management and control of the complete series of actions

installation

go get -u github.com/fvbock/endless

write

Open the  gin-blog  the  main.gofile, modify the file:

package main

import (
    "fmt"
    "log"
    "syscall"

    "github.com/fvbock/endless"

    "gin-blog/routers"
    "gin-blog/pkg/setting"
)

func main() {
    endless.DefaultReadTimeOut = setting.ReadTimeout
    endless.DefaultWriteTimeOut = setting.WriteTimeout
    endless.DefaultMaxHeaderBytes = 1 << 20
    endPoint := fmt.Sprintf(":%d", setting.HTTPPort)

    server := endless.NewServer(endPoint, routers.InitRouter())
    server.BeforeBegin = func(add string) {
        log.Printf("Actual pid is %d", syscall.Getpid())
    }

    err := server.ListenAndServe()
    if err != nil {
        log.Printf("Server err: %v", err)
    }
}

endless.NewServer Returns an initialized  endlessServer object,  BeforeBegin the output of the current process  pid, call  ListenAndServe the actual "start" service

verification

Compile
$ go build main.go 
carried out
$ ./main
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
...
Actual pid is 48601

After a successful start, the output pidis 48601; in another terminal execution  kill -1 48601 , inspection prior service terminal effect

[root@localhost go-gin-example]# ./main
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:	export GIN_MODE=release
 - using code:	gin.SetMode(gin.ReleaseMode)

[GIN-debug] GET    /auth                     --> ...
[GIN-debug] GET    /api/v1/tags              --> ...
...

Actual pid is 48601

...

Actual pid is 48755
48601 Received SIGTERM.
48601 [::]:8000 Listener closed.
48601 Waiting for connections to finish...
48601 Serve() returning...
Server err: accept tcp [::]:8000: use of closed network connection

We can see that the command has been suspended, and  fork a new child process  pid is 48755

48601 Received SIGTERM.
48601 [::]:8000 Listener closed.
48601 Waiting for connections to finish...
48601 Serve() returning...
Server err: accept tcp [::]:8000: use of closed network connection

Roughly meaning the main process ( pidto 48601) received  SIGTERM semaphore, turn off the main process of listening and waiting for the completion of the request being executed; this is consistent with our previously described

wake

At this time in  postman the access our interface again, you can pleasantly surprised to find him "Resurrection"!

Actual pid is 48755
48601 Received SIGTERM.
48601 [::]:8000 Listener closed.
48601 Waiting for connections to finish...
48601 Serve() returning...
Server err: accept tcp [::]:8000: use of closed network connection


$ [GIN] 2018/03/15 - 13:00:16 | 200 |     188.096µs |   192.168.111.1 | GET      /api/v1/tags...

This completes a positive flow of

Think about it, every update release, or modify the configuration files, just give the process sends SIGTERM signal, without the need to force the end of the application, how convenient and safe thing!

problem

endless Hot update is to take ran after a fork, the original process out of the way, this does not meet the requirements of the daemon

http.Server - Shutdown()

If you are Golang >= 1.8, you can also consider using  http.Server the  Shutdown  method

package main

import (
	"fmt"
	"net/http"
    "context"
    "log"
    "os"
    "os/signal"
    "time"


	"gin-blog/routers"
	"gin-blog/pkg/setting"
)

func main() {
	router := routers.InitRouter()

	s := &http.Server{
		Addr:           fmt.Sprintf(":%d", setting.HTTPPort),
		Handler:        router,
		ReadTimeout:    setting.ReadTimeout,
		WriteTimeout:   setting.WriteTimeout,
		MaxHeaderBytes: 1 << 20,
	}

    go func() {
        if err := s.ListenAndServe(); err != nil {
            log.Printf("Listen: %s\n", err)
        }
    }()
	
    quit := make(chan os.Signal)
    signal.Notify(quit, os.Interrupt)
    <- quit

    log.Println("Shutdown Server ...")

    ctx, cancel := context.WithTimeout(context.Background(), 5 * time.Second)
    defer cancel()
    if err := s.Shutdown(ctx); err != nil {
        log.Fatal("Server Shutdown:", err)
    }

    log.Println("Server exiting")
}

summary

In the daily service, elegant restart (hot update) is a very important part. And  Golang in  HTTP the heat update service, there are many aspects of the program, we should choose the most appropriate depending on the application scenario

reference

This series of sample code

Further Reading

Guess you like

Origin www.cnblogs.com/sunsky303/p/11121409.html