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

golang http服務(wù)實(shí)現(xiàn)多ip監(jiān)聽,及優(yōu)雅重啟

這篇具有很好參考價(jià)值的文章主要介紹了golang http服務(wù)實(shí)現(xiàn)多ip監(jiān)聽,及優(yōu)雅重啟。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

在工作中,有時(shí)需要對http服務(wù)實(shí)現(xiàn)多監(jiān)聽,http服務(wù)重啟等需求。大多數(shù)web框架只實(shí)現(xiàn)的是單ip監(jiān)聽,要實(shí)現(xiàn)多ip監(jiān)聽就需要循環(huán)監(jiān)聽ip;

而重啟http服務(wù),首先想到的是用endless來優(yōu)雅的實(shí)現(xiàn)服務(wù)的重啟,但是當(dāng)多ip監(jiān)聽時(shí),一個(gè)項(xiàng)目不能用一個(gè)endLess,多了會(huì)報(bào)錯(cuò),且windows環(huán)境也無法實(shí)現(xiàn)重啟;

所以,我在工作中最終使用了gracehttp(grace)來實(shí)現(xiàn)多ip監(jiān)聽及優(yōu)雅的重啟,但是grace也是只能做到linux的重啟和啟動(dòng),應(yīng)為window沒有定義signal,這里需要吐槽一下window;最借鑒了一下另外一個(gè)開源包window gracehttp,是多grace的擴(kuò)展,實(shí)現(xiàn)了http服務(wù)在window的多ip監(jiān)聽,但是重啟一樣報(bào)錯(cuò)(window 不支持signal), 只能再次修改開源包.

話不多說上代碼:

linux版:

//go:build !windows
// +build !windows

package utils

import (
	"crypto/tls"
	"github.com/facebookgo/grace/gracehttp"
	"github.com/labstack/echo/v4"
	"net/http"
	"sync"
	"time"
)

/**
http server 優(yōu)雅地重啟
*/

var grace *GraceHttp
var gOnce sync.Once
var SysRestart = make(chan int)

type GraceHttp struct {
	SrvList sync.Map
}

func NewGrace() *GraceHttp {
	gOnce.Do(func() {
		grace = &GraceHttp{}
	})
	return grace
}

func (g *GraceHttp) AddService(name string, srv *http.Server) {
	g.SrvList.Store(name, srv)
}

func (g *GraceHttp) Run() {
	srvs := make([]*http.Server, 0)
	g.SrvList.Range(func(key, value any) bool {
		srvs = append(srvs, value.(*http.Server))
		g.SrvList.Delete(key)
		return true
	})

    // 調(diào)用grace啟動(dòng)
	if err := gracehttp.ServeWithOptions(srvs); err != nil {
		panic(err)
	}
}

func InitServer(address string, router *echo.Echo, cfg *tls.Config) *http.Server {
	s := &http.Server{
		Addr:           address,
		Handler:        router,
		ReadTimeout:    20 * time.Second,
		WriteTimeout:   20 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	if cfg != nil {
		s.TLSConfig = cfg
	}
	return s
}

windows版:

//go:build windows
// +build windows

package utils

import (
	"crypto/tls"
	"github.com/labstack/echo/v4"
	"net/http"
	"sync"
	"time"
)

var grace *GraceHttp
var gOnce sync.Once
var SysRestart = make(chan int)

type GraceHttp struct {
	SrvList sync.Map
}

func NewGrace() *GraceHttp {
	gOnce.Do(func() {
		grace = &GraceHttp{}
	})
	return grace
}

func (g *GraceHttp) AddService(name string, srv *http.Server) {
	g.SrvList.Store(name, srv)
}

func (g *GraceHttp) Run() {
	srvs := make([]*http.Server, 0)
	g.SrvList.Range(func(key, value any) bool {
		srvs = append(srvs, value.(*http.Server))
		g.SrvList.Delete(key)
		return true
	})
	// g.SrvList = sync.Map{}
    // 使用改版的grace
	if err := Serve(srvs...); err != nil {
		panic(err)
	}
}

func InitServer(address string, router *echo.Echo, cfg *tls.Config) *http.Server {
	s := &http.Server{
		Addr:           address,
		Handler:        router,
		ReadTimeout:    20 * time.Second,
		WriteTimeout:   20 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	if cfg != nil {
		s.TLSConfig = cfg
	}
	return s
}

改版的windows grace,注這是對開源代碼的改版。

package utils

import (
	"bytes"
	"crypto/tls"
	"flag"
	"fmt"
	"github.com/facebookgo/grace/gracenet"
	"github.com/facebookgo/httpdown"
	"log"
	"net"
	"net/http"
	"os"
	"sync"
	"syscall"
)

var (
	verbose    = flag.Bool("gracehttp.log", true, "Enable logging.")
	didInherit = os.Getenv("LISTEN_FDS") != ""
	ppid       = os.Getppid()
)

const SIGUSR2 = syscall.Signal(0x1f)

// An app contains one or more servers and associated configuration.
type app struct {
	servers   []*http.Server
	http      *httpdown.HTTP
	net       *gracenet.Net
	listeners []net.Listener
	sds       []httpdown.Server
	errors    chan error
}

func newApp(servers []*http.Server) *app {
	return &app{
		servers:   servers,
		http:      &httpdown.HTTP{},
		net:       &gracenet.Net{},
		listeners: make([]net.Listener, 0, len(servers)),
		sds:       make([]httpdown.Server, 0, len(servers)),

		// 2x num servers for possible Close or Stop errors + 1 for possible
		// StartProcess error.
		errors: make(chan error, 1+(len(servers)*2)),
	}
}

func (a *app) listen() error {
	for _, s := range a.servers {
		// TODO: default addresses
		l, err := a.net.Listen("tcp", s.Addr)
		if err != nil {
			return err
		}
		if s.TLSConfig != nil {
			l = tls.NewListener(l, s.TLSConfig)
		}
		a.listeners = append(a.listeners, l)
	}
	return nil
}

func (a *app) serve() {
	for i, s := range a.servers {
		a.sds = append(a.sds, a.http.Serve(s, a.listeners[i]))
	}
}

func (a *app) wait() {
	var wg sync.WaitGroup
	fmt.Println("wg lent:", len(a.sds))
	wg.Add(len(a.sds) * 2) // Wait & Stop
	fmt.Printf("wg:%+v", wg)
	go a.signalHandler(&wg)
	for _, s := range a.sds {
		go func(s httpdown.Server) {
			fmt.Println("等待啟動(dòng).........")
			defer wg.Done()
			if err := s.Wait(); err != nil {
				a.errors <- err
			}
		}(s)
	}
	wg.Wait()
}

var WinRestart = make(chan int)

//func (a *app) term(wg *sync.WaitGroup) {
//	for _, s := range a.sds {
//		go func(s httpdown.Server) {
//			defer wg.Done()
//			if err := s.Stop(); err != nil {
//				a.errors <- err
//			}
//		}(s)
//	}
//}

func (a *app) signalHandler(wg *sync.WaitGroup) {
	select {
	case <-WinRestart:
		fmt.Println("收到重啟請求....")
		for _, s := range a.sds {
			fmt.Println("關(guān)閉http。。。。。。。。")
			if err := s.Stop(); err != nil {
				a.errors <- err
			}
			wg.Done()
		}
	}
	SysRestart <- 1
}

// Serve will serve the given http.Servers and will monitor for signals
// allowing for graceful termination (SIGTERM) or restart (SIGUSR2).
func Serve(servers ...*http.Server) error {
	a := newApp(servers)

	// Acquire Listeners
	if err := a.listen(); err != nil {
		return err
	}

	// Some useful logging.
	if *verbose {
		if didInherit {
			if ppid == 1 {
				log.Printf("Listening on init activated %s", pprintAddr(a.listeners))
			} else {
				const msg = "Graceful handoff of %s with new pid %d and old pid %d"
				log.Printf(msg, pprintAddr(a.listeners), os.Getpid(), ppid)
			}
		} else {
			const msg = "Serving %s with pid %d"
			log.Printf(msg, pprintAddr(a.listeners), os.Getpid())
		}
	}

	// Start serving.
	a.serve()

	// Close the parent if we inherited and it wasn't init that started us.
	if didInherit && ppid != 1 {
		if err := terminateProcess(ppid); err != nil {
			return fmt.Errorf("failed to close parent: %s", err)
		}
	}

	waitdone := make(chan struct{})
	go func() {
		defer close(waitdone)
		a.wait()
	}()

	select {
	case err := <-a.errors:
		if err == nil {
			panic("unexpected nil error")
		}
		return err
	case <-waitdone:
		if *verbose {
			log.Printf("Exiting pid %d.", os.Getpid())
		}
		return nil
	}
}

// Used for pretty printing addresses.
func pprintAddr(listeners []net.Listener) []byte {
	var out bytes.Buffer
	for i, l := range listeners {
		if i != 0 {
			fmt.Fprint(&out, ", ")
		}
		fmt.Fprint(&out, l.Addr())
	}
	return out.Bytes()
}

func terminateProcess(pid int) error {
	process, err := os.FindProcess(pid)
	if err != nil {
		return err
	}

	return process.Signal(syscall.SIGTERM)
}

在需要重啟的地方調(diào)用重啟方法:

func Reload() error {
	linuxVersion, err := GetLinuxPlatformFamily()
	if err != nil {
		return err
	}
	var cmd *exec.Cmd
	pid := os.Getpid()
	switch linuxVersion {
	case "windows":
		go func() {
			fmt.Println("發(fā)送重啟命令")
			WinRestart <- 1
		}()
		return nil
	case LINUXRHEL:
		cmd = exec.Command("bash", "-c", "rpm -qa | grep -i supervisor")
	case LINUXDEBIAN:
		cmd = exec.Command("bash", "-c", "service --status-all |grep supervisor")
	}
	var out bytes.Buffer
	var stderr bytes.Buffer
	cmd.Stdout = &out
	cmd.Stderr = &stderr
	cmd.Run()
	// 安裝了supervisor,就讓supervisor拉起,否則重啟
	if out.String() != "" && strings.Contains(out.String(), "[ + ]  supervisor") {
		os.Exit(0)
		return nil
	}

	cmd = exec.Command("kill", "-USR2", strconv.Itoa(pid))
	return cmd.Run()
}

最后在main里面實(shí)現(xiàn)一個(gè)守護(hù)進(jìn)程,進(jìn)行windows的重啟:

// 守護(hù)進(jìn)程用于windows重啟
func (e *Engine) windowsDeamon() {
	if runtime.GOOS == "windows" {
		for {
			select {
			case <-utils.SysRestart:
				fmt.Println("windows deamon program server restart................")
				x.SafeGo(func() {
					e.runBackend()
					e.api.Start()
					utils.NewGrace().Run()
				})
			}
		}
	}
}

最后就實(shí)現(xiàn)了,http 服務(wù)在windows和linux的多ip監(jiān)聽及優(yōu)雅重啟。?

注意事項(xiàng):

在wg.done后面執(zhí)行channel之類的阻塞,可能會(huì)出現(xiàn)wg.done成負(fù)值錯(cuò)誤,需要控制在毫米級以下。?文章來源地址http://www.zghlxwxcb.cn/news/detail-411092.html

到了這里,關(guān)于golang http服務(wù)實(shí)現(xiàn)多ip監(jiān)聽,及優(yōu)雅重啟的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

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

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

相關(guān)文章

  • springboot服務(wù)端接口外網(wǎng)遠(yuǎn)程調(diào)試,并實(shí)現(xiàn)HTTP服務(wù)監(jiān)聽

    springboot服務(wù)端接口外網(wǎng)遠(yuǎn)程調(diào)試,并實(shí)現(xiàn)HTTP服務(wù)監(jiān)聽

    前后端分離項(xiàng)目中,在調(diào)用接口調(diào)試時(shí)候,我們可以通過cpolar內(nèi)網(wǎng)穿透將本地服務(wù)端接口模擬公共網(wǎng)絡(luò)環(huán)境遠(yuǎn)程調(diào)用調(diào)試,本次教程我們以Java服務(wù)端接口為例。 JDK1.8 IDEA SpringBoot Maven Tomcat9.0 Postman 搭建一個(gè)springboot服務(wù)的項(xiàng)目,編寫一個(gè)接口,為了更好直觀看到,這里創(chuàng)建一個(gè)p

    2024年02月11日
    瀏覽(19)
  • springboot服務(wù)端接口公網(wǎng)遠(yuǎn)程調(diào)試 - 實(shí)現(xiàn)HTTP服務(wù)監(jiān)聽【端口映射】

    springboot服務(wù)端接口公網(wǎng)遠(yuǎn)程調(diào)試 - 實(shí)現(xiàn)HTTP服務(wù)監(jiān)聽【端口映射】

    轉(zhuǎn)載自cpolar內(nèi)網(wǎng)穿透的文章:Springboot服務(wù)端接口公網(wǎng)遠(yuǎn)程調(diào)試,并實(shí)現(xiàn)HTTP服務(wù)監(jiān)聽 前后端分離項(xiàng)目中,在調(diào)用接口調(diào)試時(shí)候,我們可以通過cpolar內(nèi)網(wǎng)穿透將本地服務(wù)端接口模擬公共網(wǎng)絡(luò)環(huán)境遠(yuǎn)程調(diào)用調(diào)試,本次教程我們以Java服務(wù)端接口為例。 JDK1.8 IDEA SpringBoot Maven Tomcat9.

    2024年02月06日
    瀏覽(38)
  • 互聯(lián)網(wǎng)大廠技術(shù)-HTTP請求-Springboot整合Feign更優(yōu)雅地實(shí)現(xiàn)Http服務(wù)調(diào)用

    互聯(lián)網(wǎng)大廠技術(shù)-HTTP請求-Springboot整合Feign更優(yōu)雅地實(shí)現(xiàn)Http服務(wù)調(diào)用

    目錄 一、SpringBoot快速整合Feign 1.添加Pom依賴 2.啟動(dòng)類添加注解 3.引用Feign服務(wù) 二、為請求添加Header的3種方式 1.添加固定header 2.通過接口簽名添加header 3.動(dòng)態(tài)添加header 三、為請求添加超時(shí)配置 1.默認(rèn)超時(shí)時(shí)間 3.超時(shí)異常 4.全局超時(shí)配置 5.為單個(gè)服務(wù)設(shè)置超時(shí)配置 四、為請求配

    2024年02月04日
    瀏覽(21)
  • springboot服務(wù)端接口外網(wǎng)遠(yuǎn)程調(diào)試,并實(shí)現(xiàn)HTTP服務(wù)監(jiān)聽 - 內(nèi)網(wǎng)穿透

    springboot服務(wù)端接口外網(wǎng)遠(yuǎn)程調(diào)試,并實(shí)現(xiàn)HTTP服務(wù)監(jiān)聽 - 內(nèi)網(wǎng)穿透

    轉(zhuǎn)載自遠(yuǎn)程內(nèi)網(wǎng)穿透的文章:springboot服務(wù)端接口公網(wǎng)遠(yuǎn)程調(diào)試,并實(shí)現(xiàn)HTTP服務(wù)監(jiān)聽 前后端分離項(xiàng)目中,在調(diào)用接口調(diào)試時(shí)候,我們可以通過cpolar內(nèi)網(wǎng)穿透將本地服務(wù)端接口模擬公共網(wǎng)絡(luò)環(huán)境遠(yuǎn)程調(diào)用調(diào)試,本次教程我們以Java服務(wù)端接口為例。 JDK1.8 IDEA SpringBoot Maven Tomcat9.

    2023年04月22日
    瀏覽(21)
  • 如何在Spring Boot服務(wù)端實(shí)現(xiàn)公網(wǎng)遠(yuǎn)程調(diào)試并進(jìn)行HTTP服務(wù)監(jiān)聽

    如何在Spring Boot服務(wù)端實(shí)現(xiàn)公網(wǎng)遠(yuǎn)程調(diào)試并進(jìn)行HTTP服務(wù)監(jiān)聽

    轉(zhuǎn)載自cpolar內(nèi)網(wǎng)穿透的文章:Springboot服務(wù)端接口公網(wǎng)遠(yuǎn)程調(diào)試,并實(shí)現(xiàn)HTTP服務(wù)監(jiān)聽 前后端分離項(xiàng)目中,在調(diào)用接口調(diào)試時(shí)候,我們可以通過cpolar內(nèi)網(wǎng)穿透將本地服務(wù)端接口模擬公共網(wǎng)絡(luò)環(huán)境遠(yuǎn)程調(diào)用調(diào)試,本次教程我們以Java服務(wù)端接口為例。 JDK1.8 IDEA SpringBoot Maven Tomcat9.

    2024年02月06日
    瀏覽(36)
  • 01、uwsgi、gunicorn如何實(shí)現(xiàn)優(yōu)雅重啟

    在實(shí)際開發(fā)過程中,我們會(huì)不斷迭代升級產(chǎn)品,每次迭代后,都需要在線上服務(wù)器更新代碼。一般小公司的迭代升級,是沒有做到像金絲雀發(fā)布或者使用到kubernetes這些東西的。那如何保證更新的時(shí)候,之前接收到的請求能夠正常處理完成呢,這個(gè)時(shí)候就需要實(shí)現(xiàn)優(yōu)雅重啟了。

    2023年04月10日
    瀏覽(19)
  • 如何通過內(nèi)網(wǎng)穿透實(shí)現(xiàn)外部網(wǎng)絡(luò)對Spring Boot服務(wù)端接口的HTTP監(jiān)聽和調(diào)試?

    如何通過內(nèi)網(wǎng)穿透實(shí)現(xiàn)外部網(wǎng)絡(luò)對Spring Boot服務(wù)端接口的HTTP監(jiān)聽和調(diào)試?

    前后端分離項(xiàng)目中,在調(diào)用接口調(diào)試時(shí)候,我們可以通過cpolar內(nèi)網(wǎng)穿透將本地服務(wù)端接口模擬公共網(wǎng)絡(luò)環(huán)境遠(yuǎn)程調(diào)用調(diào)試,本次教程我們以Java服務(wù)端接口為例。 JDK1.8 IDEA SpringBoot Maven Tomcat9.0 Postman 搭建一個(gè)springboot服務(wù)的項(xiàng)目,編寫一個(gè)接口,為了更好直觀看到,這里創(chuàng)建一個(gè)p

    2024年02月10日
    瀏覽(24)
  • 互聯(lián)網(wǎng)大廠技術(shù)-HTTP請求-Springboot整合Feign更優(yōu)雅地實(shí)現(xiàn)Http服務(wù)調(diào)用
no suitable HttpMessageConverter found for response type

    互聯(lián)網(wǎng)大廠技術(shù)-HTTP請求-Springboot整合Feign更優(yōu)雅地實(shí)現(xiàn)Http服務(wù)調(diào)用 no suitable HttpMessageConverter found for response type

    目錄 一、SpringBoot快速整合Feign 1.添加Pom依賴 2.啟動(dòng)類添加注解 3.引用Feign服務(wù) 二、為請求添加Header的3種方式 1.添加固定header 2.通過接口簽名添加header 3.動(dòng)態(tài)添加header 三、為請求添加超時(shí)配置 1.默認(rèn)超時(shí)時(shí)間 3.超時(shí)異常 4.全局超時(shí)配置 5.為單個(gè)服務(wù)設(shè)置超時(shí)配置 四、為請求配

    2024年02月11日
    瀏覽(23)
  • Golang優(yōu)雅實(shí)現(xiàn)按比例切分流量

    我們在進(jìn)行灰度發(fā)布時(shí),往往需要轉(zhuǎn)發(fā)一部分流量到新上線的服務(wù)上,進(jìn)行小規(guī)模的驗(yàn)證,隨著功能的不斷完善,我們也會(huì)逐漸增加轉(zhuǎn)發(fā)的流量,這就需要按比例去切分流量,那么如何實(shí)現(xiàn)流量切分呢? 我們很容易想到通過生成隨機(jī)數(shù)方式進(jìn)行實(shí)現(xiàn),通過判斷生成隨機(jī)數(shù)是否

    2024年02月04日
    瀏覽(16)
  • golang平滑重啟庫overseer實(shí)現(xiàn)原理

    overseer主要完成了三部分功能: 1、連接的無損關(guān)閉,2、連接的平滑重啟,3、文件變更的自動(dòng)重啟。 下面依次講一下: golang官方的net包是不支持連接的無損關(guān)閉的,當(dāng)主監(jiān)聽協(xié)程退出時(shí),并不會(huì)等待各個(gè)實(shí)際work協(xié)程的處理完成。 以下是golang官方代碼: Go/src/net/http/server.go

    2024年02月07日
    瀏覽(12)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包