Golang | Web开发之Gin多服务配置及优雅关闭平滑重启

news2024/11/20 3:20:45

欢迎关注「全栈工程师修炼指南」公众号

点击 👇 下方卡片 即可关注我哟!

设为星标⭐每天带你 基础入门 到 进阶实践 再到 放弃学习

专注 企业运维实践、网络安全、系统运维、应用开发、物联网实战、全栈文章 等知识分享

  花开堪折直须折,莫待无花空折枝 


作者主页:[ https://www.weiyigeek.top ]  

博客:[ https://blog.weiyigeek.top ]

作者<安全开发运维>学习交流群,回复【学习交流群】即可加入


文章目录:

0x00 如何自定义Gin服务配置及其启动多个服务?

0x01 如何优雅的关闭或者重启Gin应用程序?

1.使用 chan 通道监听中断信号(SIGINT和SIGTERM)

2.使用 os/exec 包来执行Gin平滑重启

3.使用 fvbock/endless 包实现访问指定路由平滑重启Gin服务

0x00 如何自定义Gin服务配置及其启动多个服务?

描述: 在Gin的生产环境中通常会自定义HTTP配置以达到最优性能,此处我们简单一下 Server 结构体中可配置的参数项。

// A Server defines parameters for running an HTTP server.
// The zero value for Server is a valid configuration.
type Server struct {
  // 配置监听地址:端口,默认是:8080
	Addr string
  // 要调用的处理程序,http.DefaultServeMux如果为nil
	Handler Handler
  // 如果为true,则将“OPTIONS*”请求传递给Handler 
	DisableGeneralOptionsHandler bool
  // 提供TLS配置
	TLSConfig *tls.Config
  //读取整个请求(包括正文)的最长持续时间。
	ReadTimeout time.Duration
  // 读取整请求(Header)的最长持续时间。
	ReadHeaderTimeout time.Duration
  // 超时写入响应之前的最长持续时间
	WriteTimeout time.Duration
  // 启用保持活动时等待下一个请求的最长时间
	IdleTimeout time.Duration
  // 控制服务器解析请求标头的键和值(包括请求行)时读取的最大字节数 (通常情况下不进行设置) 
	MaxHeaderBytes int
  // 在发生ALPN协议升级时接管所提供TLS连接的所有权。
	TLSNextProto map[string]func(*Server, *tls.Conn, Handler)
  // 指定了一个可选的回调函数,当客户端连接更改状态时调用该函数
	ConnState func(net.Conn, ConnState)
  // 为接受连接的错误、处理程序的意外行为以及潜在的FileSystem错误指定了一个可选的记录器
  ErrorLog *log.Logger
  // 返回/此服务器上传入请求的基本上下文
	BaseContext func(net.Listener) context.Context
  // 指定一个函数来修改用于新连接c的上下
	ConnContext func(ctx context.Context, c net.Conn) context.Context
  // 当服务器处于关闭状态时为true
	inShutdown atomic.Bool
	disableKeepAlives atomic.Bool
	nextProtoOnce     sync.Once // guards setupHTTP2_* init
	nextProtoErr      error     // result of http2.ConfigureServer if used
	mu         sync.Mutex
	listeners  map[*net.Listener]struct{}
	activeConn map[*conn]struct{}
	onShutdown []func()
	listenerGroup sync.WaitGroup
}

模块更新

go get -u golang.org/x/sync/errgroup
go mod tidy

示例代码:

package main

import (
	"log"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"golang.org/x/sync/errgroup"
)

// 处理属于同一总体任务的子任务的goroutine的集合
var (
	g errgroup.Group
)

// s2 Gin 服务的 Handler
func router02() http.Handler {
	e := gin.New()
	e.Use(gin.Recovery())
	e.GET("/", func(c *gin.Context) {
		c.JSON(
			http.StatusOK,
			gin.H{
				"code": http.StatusOK,
				"msg":  "Welcome server 02 blog.weiyigeek.top",
			},
		)
	})
	return e
}

func main() {
	// Default返回一个Engine实例,该实例已连接Logger和Recovery中间件。
	router := gin.Default()

	// Gin 服务s1.用于运行HTTP服务器的参数 (常规参数)
	s1 := &http.Server{
		// Gin运行的监听端口
		Addr: ":8080",
		// 要调用的处理程序,http.DefaultServeMux如果为nil
		Handler: router,
		// ReadTimeout是读取整个请求(包括正文)的最长持续时间。
		ReadTimeout: 5 * time.Second,
		// WriteTimeout是超时写入响应之前的最长持续时间
		WriteTimeout: 10 * time.Second,
		// MaxHeaderBytes控制服务器解析请求标头的键和值(包括请求行)时读取的最大字节数 (通常情况下不进行设置)
		MaxHeaderBytes: 1 << 20,
	}

	// Go在一个新的goroutine中调用给定的函数,此处将Go语言的并发体现的淋漓尽致。
	g.Go(func() error {
		return s1.ListenAndServe()
	})

	// 配置Gin中间件
	// Recovery返回一个中间件,该中间件可以从任何exception中恢复,并在出现exception时写入500。
	router.Use(gin.Recovery())

	// 服务s1的路由
	router.GET("/", func(c *gin.Context) {
		c.JSON(
			http.StatusOK,
			gin.H{
				"code": http.StatusOK,
				"msg":  "Welcome server 01 www.weiyigeek.top",
			},
		)
	})

	// Gin 服务s1.定义了不同的监听端口以及Handler
	s2 := &http.Server{
		Addr:         ":8081",
		Handler:      router02(),
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 10 * time.Second,
	}
	g.Go(func() error {
		return s2.ListenAndServe()
	})

	if err := g.Wait(); err != nil {
		log.Fatal(err)
	}
}

偷偷的告诉你哟?极客全栈修炼】微信小程序已经上线了,

可直接在微信里面直接浏览博主博客了哟,后续将上线更多有趣的小工具。


执行结果:

9b29c34347d2eba226b503385be130b5.png


0x01 如何优雅的关闭或者重启Gin应用程序?

1.使用 chan 通道监听中断信号(SIGINT和SIGTERM)

描述: 在Go Gin中,可以使用以下代码实现优雅地重启或停止, 确保所有连接都被正确关闭,避免数据丢失或损坏。

代码示例:

package main

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

	"github.com/gin-gonic/gin"
)

func main() {
	// 创建 Gin 实例
	router := gin.Default()

	// 添加路由
	router.GET("/", func(c *gin.Context) {
		c.String(http.StatusOK, "Hello, World! weiyigeek.top")
	})

	// 创建 HTTP Server
	srv := &http.Server{
		Addr:    ":8080",
		Handler: router,
	}

  // 开启一个goroutine启动服务 启动 HTTP Server
	go func() {
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Fatalf("listen: %s\n", err)
		}
	}()

	// 等待中断信号
	quit := make(chan os.Signal)
	// kill 默认会发送 syscall.SIGTERM 信号
	// kill -2 发送 syscall.SIGINT 信号,我们常用的Ctrl+C就是触发系统SIGINT信号
	// kill -9 发送 syscall.SIGKILL 信号,但是不能被捕获,所以不需要添加它
	// signal.Notify把收到的 syscall.SIGINT或syscall.SIGTERM 信号转发给quit
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) // 此处不会阻塞
	<-quit    // 阻塞在此,当接收到上述两种信号时才会往下执行
	log.Println("Shutdown Server ...")

	// 创建一个 5 秒的超时上下文
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	// 关闭 HTTP Server
  // 	// 5秒内优雅关闭服务(将未处理完的请求处理完再关闭服务),超过5秒就超时退出
	if err := srv.Shutdown(ctx); err != nil {
		log.Fatal("Server Shutdown:", err)
	}
	log.Println("Server exiting")
}

代码解析:
首先创建了一个Gin实例和一个HTTP Server,然后启动HTTP Server。接下来,使用signal.Notify()函数监听中断信号(SIGINT和SIGTERM),当接收到中断信号时,服务器会进入优雅关闭流程,即先关闭HTTP Server,然后等待5秒钟,最后退出程序。

在关闭HTTP Server时,我们使用了srv.Shutdown()函数,它会优雅地关闭HTTP Server并等待所有连接关闭。如果在5秒钟内没有关闭完所有连接,函数会返回错误。

知识补充: 使用os/signal包实现对信号的处理, 最常见的信号列表。

bcbc58ee17922779c92a699099e0978f.png

2.使用 os/exec 包来执行Gin平滑重启

描述: 在Linux的Go-gin环境中我们可以使用 os/exec 包来执行重启命令,然后在 Gin 中定义一个路由,使得访问该路由时会执行重启命令。

代码示例:

package main

import (
  "fmt"
  "net/http"
  "os"
  "os/exec"

  "github.com/gin-gonic/gin"
)

func main() {
  r := gin.Default()
  // 重启的路由 /restart
  r.GET("/restart", func(c *gin.Context) {
    cmd := exec.Command("killall", "-HUP", "appweiyigeek")
    err := cmd.Run()
    if err != nil {
      fmt.Println("Error executing restart command:", err)
      c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to restart Gin server."})
      return
    }
    c.JSON(http.StatusOK, gin.H{"message": "Gin server restarted successfully."})
  })

  r.Run(":8080")
}

编译执行:

go build ./main.go -o appweiyigeek
./appweiyigeek

在上面的例子中,我们定义了一个路由 /restart,当访问该路由时,它会执行 killall -HUP appweiyigeek 命令来重启 Gin 服务, 这里的appweiyigeek应该替换为你实际的 Gin 应用程序的名称。

温馨提示: 此种重启方式可能会导致请求失败或者超时,因为它会强制关闭正在处理的连接, 如果你需要更加优雅的重启方式,可以考虑使用优雅重启的方式。

3.使用 fvbock/endless 包实现访问指定路由平滑重启Gin服务

描述: 由于endless在windows环境是不支持,所以博主针对下述代码在Linux环境下载并编译成二进制文件打包到Linux环境运行进行验证。

依赖下载:

go get -u github.com/fvbock/endless
go mod tidy

代码示例:

package main

import (
	"fmt"
	"log"
	"net/http"
	"os/exec"
	"strconv"
	"syscall"

	"github.com/fvbock/endless"
	"github.com/gin-gonic/gin"
)

func main() {
	pid := syscall.Getpid()

	// 1.默认的Gin引擎
	router := gin.Default()

	// 传统方式
	// server := &http.Server{
	// 	Addr:         ":8080",
	// 	Handler:      router,
	// 	ReadTimeout:  5 * time.Second,
	// 	WriteTimeout: 10 * time.Second,
	// }

	// 2.获取 Pid
	router.GET("/pid", func(c *gin.Context) {
		pid = syscall.Getpid()
		fmt.Println("Pid:", pid)
		c.JSON(http.StatusOK,
			gin.H{
				"code": http.StatusOK,
				"msg":  fmt.Sprintf("Gin Server Pid ->  %d.", pid),
			})
	})

	// 3.重启 Gin 服务
	router.POST("/restart", func(c *gin.Context) {
		pid = syscall.Getpid()
		fmt.Println("Restarting Gin Server.......", pid)
		err := exec.Command("kill", "-1", strconv.Itoa(pid)).Run()
		if err != nil {
			fmt.Println("Error executing restart command:", err)
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to restart Gin server."})
			return
		}
		c.JSON(http.StatusOK, gin.H{"message": "Gin server restarted successfully.", "pid": pid})
	})

	// 4.使用endless侦听TCP网络地址addr,然后使用处理程序调用Serve来处理传入连接上的请求
	err := endless.ListenAndServe(":8080", router)
	if err != nil || err != http.ErrServerClosed {
		log.Println("err:", err)
	}

	// 5.引入了endless扩展,将原本的Run方式启动项目改成了ListenAndServe方式所有此处主席掉
	// router.Run(":8080")
}

编译构建:

# 切换编译在Linux平台的64位可执行程序环境
go env -w CGO_ENABLED=0 GOOS=linux GOARCH=amd64

# 编译
go build -o endless-test-1 .\main.go

# 执行验证
chmod +x endless-test-1
nohup ./endless-test-1 &
[1] 1147978

2a959d90cb6844ac6b72df3427d705a9.png

执行效果:

# GET 请求 10.20.176.101:8080/pid
# POST 请求 10.20.176.101:8080/restart

33299088e0978487543abd7840a49921.png

请求restart后可以看见go-gin已经平滑重启了是不是很方便,效果如下。

62f355d47ca812955c92095ebe610e3e.png

亲,文章就要看完了,不关注一下【全栈工程师修炼指南】吗?

2bbd455fac2079ddbf17483167a98a4a.jpeg

知识扩展:

  • 3、Windows下编译Mac, Linux平台的64位可执行程序:

$ go env -w CGO_ENABLED=0 GOOS=darwin3 GOARCH=amd64 
$ go env -w CGO_ENABLED=0 GOOS=linux GOARCH=amd64
  • 2、Linux下编译Mac, Windows平台的64位可执行程序:

$ go env -w CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 
$ go env -w CGO_ENABLED=0 GOOS=windows GOARCH=amd64
  • 1、Mac下编译Linux, Windows平台的64位可执行程序:

$ go env -w CGO_ENABLED=0 GOOS=linux GOARCH=amd64
$ go env -w CGO_ENABLED=0 GOOS=windows GOARCH=amd64

本文至此完毕,更多技术文章,尽情等待下篇好文!

原文地址: https://blog.weiyigeek.top/2023/6-2-745.html

如果此篇文章对你有帮助,请你将它分享给更多的人! 

b9b9f576743861eeccc707bd9f905e2a.gif

01adbdb6830230caebe2ed3c8f28b232.png 学习书籍推荐 往期发布文章 01b09483f7f760de481abcb1ac57fa1c.png

公众号回复【0008】获取【Ubuntu22.04安装与加固脚本】

公众号回复【10001】获取【WinServer安全加固脚本】

公众号回复【10002】获取【KylinOS银河麒麟安全加固脚本】

公众号回复【0011】获取【k8S二进制安装部署教程】

公众号回复【0014】获取【Nginx学习之路汇总】

公众号回复【0015】获取【Jenkins学习之路汇总】

公众号回复【10005】获取【adb工具刷抖音赚米】

 热文推荐  

  • Golang | Web开发之Gin框架快速入门基础实践

  • Go开发学习 | 如何快速读取json/yaml/ini等格式的配置文件使用示例

  • Go开发学习 | 如何使用Gomail.v2模块包发送邮箱验证码消息及附件学习记录

  • Go开发学习 | 如何使用日志记录模块包针对日志按天数、按大小分隔文件示例

  • 开发基础 | Golang语言的RESTfulAPI接口设计规范快速入门

欢迎长按(扫描)二维码 取更多渠道哟!

dbd207e106e0a48406a9750ed05431a5.jpeg0b5419e973b02e086b76644e131bcd82.jpeg48fbe350e70acdc3d73aca437045c4c9.jpeg

f02584cec2101277ad678f224be23c4f.gif

欢迎关注 【全栈工程师修炼指南】(^U^)ノ~YO

添加作者微信【weiyigeeker 】 一起学习交流吧!

关注回复【学习交流群】即可加入【安全运维沟通交流小群

温馨提示: 由于作者水平有限,本章错漏缺点在所难免,希望读者批评指正,若有问题或建议请在文章末尾留下您宝贵的经验知识,或联系邮箱地址

master@weiyigeek.top 或 关注公众号 [全栈工程师修炼指南] 留言。

点个【赞 + 在看】吧!

点击【"阅读原文"】获取更多有趣的知识!   

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/641081.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大数据基础环境与常用软件搭建

大数据基础环境的搭建需要以下步骤&#xff1a; 安装操作系统&#xff1a;大数据环境通常使用Linux操作系统&#xff0c;推荐使用CentOS或Ubuntu。 安装Java环境&#xff1a;大数据软件通常需要Java环境支持&#xff0c;可以安装OpenJDK或Oracle JDK。 安装Hadoop&#xff1a…

【Android开发基础】多线程-Handle消息机制

文章目录 一、引言二、认识1、为什么要用Handle2、原理图3、关键对象&#xff08;1&#xff09;Message&#xff08;消息类&#xff09;&#xff08;2&#xff09;Handler&#xff08;消息机制&#xff09;&#xff08;3&#xff09;MessageQueue&#xff08;消息处理类&#x…

轻量级报表解决方案Telerik Reporting,轻松完成嵌入式报表交互!

开发者可以通过多种方式与集成在应用程序中的Telerik报表进行交互&#xff0c;从“只是阅读它”到更改报表中包含的数据。 但是要注意&#xff1a;开发者所能做的一些事情将取决于报表是如何创建的&#xff0c;以及它是如何嵌入到应用程序UI中的。因此(和任何应用程序一样)&am…

关于数据库SQL优化

简介 在项目上线初期&#xff0c;业务数据量相对较少&#xff0c;SQL的执行效率对程序运行效率的影响可能不太明显&#xff0c;因此开发和运维人员可能无法判断SQL对程序的运行效率有多大。但随着时间的积累&#xff0c;业务数据量的增多&#xff0c;SQL的执行效率对程序的运行…

假如不干技术,多年学的知识会不会白费?

【1】 有位匿名朋友&#xff0c;在星球中提问&#xff1a; 沈老师&#xff0c;作为一个开发&#xff0c;如果离开了公司&#xff0c;不再做技术&#xff0c;感觉这么多年学的知识都白费了&#xff0c;什么都用不上了&#xff0c;你怎么看&#xff1f; 我的一些思考&#xff0c;…

智能驾考远程监控方案4G工业路由器物联网应用

随着全民经济增长生活水平提高&#xff0c;汽车保有量也随之增长&#xff0c;需要驾驶机动车前提是需要经过标准的驾考培训获得机动车驾驶证后&#xff0c;才能够驾车上路。参加过驾考的朋友们都知道&#xff0c;科目一与科目四都是上机考试&#xff0c;而科目二和科目三则是在…

C#实战:Dapper操作PostgreSQL笔记

目录 一、PostgreSQL简介 二、PostgreSQL组成 三、PostgreSQL的主要优点 四、PostgreSQL的使用场景 五、示例 1、安装dapper&#xff0c;目前本案例安装的版本是1.50.2 2、安装PostgreSQL驱动 3、数据库链接示例 4、通过SQL查询数据列表写法 5、插入示例写法 一、PostgreSQL简介…

Triton教程 -- 快速开始

Triton教程 – 快速开始 文章目录 Triton教程 -- 快速开始创建模型存储库启动 Triton在带 GPU 的系统上运行在纯 CPU 系统上运行验证 Triton 是否正常运行发送推理请求 Triton 推理服务器的新手&#xff0c;想快速部署您的模型吗&#xff1f; 利用这些教程开始您的 Triton 之旅…

FasterTransformer 004 open_attention.h forward

initialize forward() https://github1s.com/NVIDIA/FasterTransformer/blob/v1.0/fastertransformer/cuda/open_attention.h#L149-L217 使用cuBLAS库执行矩阵乘法运算&#xff0c;并对cublasGemmEx&#xff08;&#xff09;进行三个单独的调用。这些操作包括将属性核与输入张…

<Linux开发>驱动开发 -之-内核定时器与中断

&#xff1c;Linux开发&#xff1e;驱动开发 -之-内核定时器与中断 交叉编译环境搭建&#xff1a; &#xff1c;Linux开发&#xff1e; linux开发工具-之-交叉编译环境搭建 uboot移植可参考以下&#xff1a; &#xff1c;Linux开发&#xff1e; -之-系统移植 uboot移植过程详…

Linux系统下安装Kubernetes(超详细。。。)

一、安装Kubernetes前的准备 1.1 准备Hosts文件 &#xff08;注意&#xff0c;请根据Linux虚拟机的IP地址&#xff0c;修改以下命令后再执行&#xff09; cat >>/etc/hosts<<EOF 192.168.100.146 deploy EOF 1.2 检查虚拟机的hostname cat /etc/hostname验证…

Charles抓包配置

这里写目录标题 一、Windows抓包配置1、Help-SSL Proxying-install Charles Root Certificate2、安装并导入证书&#xff0c;按下方各图完成证书导入后&#xff0c;正常情况下&#xff0c;会显示该证书没有问题。3、SSL证书过期解决办法a、可在windows的设置中搜索证书关键字&a…

c++ nlohmann/json 及修改json文件中个别关键字

(2条消息) nlohmann json使用_nlohmann::json_蜗牛单行道的博客-CSDN博客json为JavaScript object notation 是一种数据格式&#xff0c;逐渐替换掉了传统的xml 。json数据格式的属性名称和字符串值需要用双引号引起来&#xff0c;用单引号或者不用引号会导致读取数据错误。jso…

Django-初

文章目录 一、Django框架介绍二、后台管理第一步:项目的创建与运行第二步:应用的创建和使用第三步: 项目的数据库模型第四步: 启用后台Admin站点管理 三、前台管理第一步: URLconf 路由管理第二步: 视图函数处理业务逻辑第三步: 模板管理实现好看的HTML页面&#xff08;可参考菜…

网络计算模式期末复习(一)

C/S架构 C/S架构即客户端/服务端架构。客户端包含一个或多个在用户电脑上运行的程序&#xff0c;客户端程序发送请求和从服务器接收的数据。服务器端主要提供数据管理、数据共享、数据及系统维护和并发控制等。 B/S架构 B/S架构即浏览器/服务器架构&#xff0c;是随着Intern…

图片上添加贴纸怎么做?这几种方法很简单

在图片上添加贴纸是一种非常实用的图片编辑技巧&#xff0c;通过添加贴纸&#xff0c;图片可以变得更加生动有趣&#xff0c;吸引人们的眼球。贴纸可以是各种形状、颜色和大小&#xff0c;从而丰富图片的视觉效果。例如&#xff0c;在一张风景照片中添加一只卡通动物的图案&…

python中golbal的使用

简介 global关键字定义了一种在局部定义全局变量的方法 python中变量分为全局变量和局部变量&#xff0c;局部变量也叫做内部变量内部变量只能被内部使用&#xff0c;无法被其他函数或者对象使用 使用 简单使用 def fn():global fn_varfn_var "Hello World"fn1()…

为什么网红餐饮都做不长久?如何解决网红餐饮店所面临的问题?

随着社交媒体的兴起&#xff0c;网红餐饮在近年来越来越受到人们的关注。这些网红餐饮通常有着独特的装修风格、口味或者服务方式&#xff0c;吸引了大量的消费者前来体验。然而&#xff0c;有越来越多的网红餐饮因为各种原因而不得不倒闭&#xff0c;这引发了人们对于网红餐饮…

cajviewer怎么转换成pdf格式,分享几个方法给大家!

CAJViewer是一款常用的文献阅读软件&#xff0c;它主要用于打开和阅读中国知网等数据库中的CAJ格式文件。然而&#xff0c;有时候我们可能需要将这些CAJ文件转换为PDF格式&#xff0c;以便更方便地与他人分享或者进行打印。本文将介绍两到三种将CAJViewer文件转换为PDF格式的方…

华为OD机试真题2022Q4 A + 2023 B卷(JavaJavaScript)

大家好&#xff0c;我是哪吒。 五月份之前&#xff0c;如果你参加华为OD机试&#xff0c;收到的应该是2022Q4或2023Q1&#xff0c;这两个都是A卷题。 5月10日之后&#xff0c;很多小伙伴收到的是B卷&#xff0c;那么恭喜你看到本文了&#xff0c;抓紧刷题吧。B卷新题库正在更…