go如何优雅关闭Graceful Shutdown服务

为了实现优雅关闭(Graceful Shutdown)服务,我们需要了解两个重要的概念:闲置连接(idle connections)和上下文(context)。

在 Go 语言中,服务器和客户端之间的连接是通过 net.Conn 实现的,服务器在和客户端建立连接之后就可以可以向客户端发送数据,同时也可以从客户端读取数据。在大多数情况下,服务器与客户端之间的交互是请求/响应(request/response)模式。但是,如果长时间没有数据交互,连接就会变得闲置,此时服务器需要适时地关闭这些闲置的连接。这种被闲置的连接就是闲置连接(idle connections)。

上下文(context)是一种用于设置截止时间、取消信号和元数据信息等的机制。在 Go 语言中,上下文通常用于给多个 goroutine 设置超时,或者用于取消一些不需要的操作。在服务器中,我们可以使用上下文来实现优雅关闭服务的功能。

下面是一个基本的示例,展示如何使用闲置连接和上下文实现优雅关闭服务:

package main

import (
    "context"
    "net/http"
    "os"
    "os/signal"
    "time"
)

func main() {
    server := &http.Server{
        Addr:         ":8080",
        ReadTimeout:  10 * time.Second,
        WriteTimeout: 10 * time.Second,
        IdleTimeout:  30 * time.Second,
    }

    // 启动 HTTP 服务
    go func() {
        if err := server.ListenAndServe(); err != http.ErrServerClosed {
            // 正常情况下,ErrServerClosed 表示服务器已经关闭
            // 如果不是 ErrServerClosed 错误,则表示出现了其他的错误
            panic(err)
        }
    }()

    // 创建一个通道,用于等待操作系统中断信号
    interruptChan := make(chan os.Signal, 1)
    signal.Notify(interruptChan, os.Interrupt)

    <-interruptChan // 等待操作系统中断信号

    // 创建一个上下文,并向它发送一个超时信号
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel() // 释放上下文资源

    // 关闭 HTTP 服务,并等待所有闲置连接关闭
    if err := server.Shutdown(ctx); err != nil {
        panic(err)
    }
}

在上面的示例中,首先我们创建了一个 http.Server 实例,并设置其 ReadTimeout、WriteTimeout 和 IdleTimeout 参数,分别控制读取数据、写入数据和闲置连接的超时时间。需要注意的是,IdleTimeout 的值应该比 ReadTimeout 和 WriteTimeout 的值更大,否则客户端可能会因为比较频繁的重新建立连接而感到不满。

然后,在启动 HTTP 服务之后,我们创建了一个通道 interruptChan,用于等待操作系统的中断信号。当接收到操作系统中断信号时,我们会创建一个上下文 ctx,并向它发送一个超时信号。最后,我们使用 http.Server 的 Shutdown 方法关闭 HTTP 服务,并使用上下文来等待所有闲置连接关闭。

下面是另一个示例,它演示了如何在 HTTP Handler 中使用上下文,并且在多个 goroutine 中使用上下文来实现优雅关闭服务:

package main

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

func main() {
    server := &http.Server{
        Addr:         ":8080",
        ReadTimeout:  10 * time.Second,
        WriteTimeout: 10 * time.Second,
        IdleTimeout:  30 * time.Second,
    }

    // 添加 HTTP Handler,并对处理过程中的上下文进行追踪
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        ctx := r.Context()
        ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
        defer cancel()

        log.Println("handler started")
        defer log.Println("handler finished")

        select {
        case <-time.After(5 * time.Second):
            fmt.Fprintf(w, "Hello World!")
        case <-ctx.Done():
            // 当上下文被取消时,我们可以通过 err 来判断是超时错误还是其他的错误
            err := ctx.Err()
            log.Printf("handler error: %v", err)
            http.Error(w, err.Error(), http.StatusInternalServerError)
        }
    })

    // 启动多个 goroutine,并在启动的时候传递上下文
    ctx, cancel := context.WithCancel(context.Background())
    var wg sync.WaitGroup
    wg.Add(3)
    for i := 0; i < 3; i++ {
        go func(index int) {
            defer wg.Done()

            for {
                select {
                case <-time.After(2 * time.Second):
                    log.Printf("goroutine %d running...", index)
                case <-ctx.Done():
                    log.Printf("goroutine %d stopped", index)
                    return
                }
            }
        }(i)
    }

    // 启动 HTTP 服务
    go func() {
        if err := server.ListenAndServe(); err != http.ErrServerClosed {
            panic(err)
        }
    }()

    // 等待操作系统中断信号
    interruptChan := make(chan os.Signal, 1)
    signal.Notify(interruptChan, os.Interrupt, syscall.SIGTERM)
    <-interruptChan

    // 发送取消信号,并等待所有 goroutine 停止
    cancel()
    wg.Wait()

    // 关闭 HTTP 服务,并等待所有闲置连接关闭
    ctx, cancel = context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()
    if err := server.Shutdown(ctx); err != nil {
        panic(err)
    }
}

在这个示例中,我们不仅在 HTTP Handler 中追踪了上下文,还在多个 goroutine 中使用了上下文。当接收到操作系统中断信号时,我们首先向全局上下文发送取消信号,这样所有的 goroutine 都会随着上下文被取消而停止执行。然后,我们使用上下文来关闭 HTTP 服务,并等待所有闲置连接关闭。

需要注意的是,在上面的两个示例中,我们都使用了 http.Server 的 Shutdown 方法来关闭 HTTP 服务。这个方法会等待所有闲置连接关闭之后再返回。如果你是使用自己的 WebSocket 实现,那么也需要使用类似的方法来关闭 WebSocket。并且在你的 WebSocket 实现中,应该实现对上下文进行追踪,并根据上下文的状态优雅地关闭 WebSocket 服务。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:go如何优雅关闭Graceful Shutdown服务 - Python技术站

(0)
上一篇 2023年5月25日
下一篇 2023年5月25日

相关文章

  • Django点赞的实现示例

    下面是“Django点赞的实现示例”的完整攻略: 1. 创建模型 首先,在Django应用中创建一个模型,用于存储点赞数据。假设我们要实现对文章的点赞功能,那么我们可以创建一个名为Article的模型,并添加一个名为likes的IntegerField类型字段,用来记录文章被点赞的次数。代码示例如下: # models.py from django.db i…

    人工智能概论 2023年5月25日
    00
  • 教你在容器中使用nginx搭建上传下载的文件服务器

    首先我们先来了解一下如何在容器中使用nginx搭建上传下载的文件服务器。 攻略概述 安装Docker 编写nginx配置 构建镜像并运行容器 测试上传及下载功能 安装Docker 安装Docker是本教程搭建文件服务器的前置条件,可以通过以下命令在Ubuntu系统中完成安装: sudo apt update sudo apt install docker.i…

    人工智能概览 2023年5月25日
    00
  • Windows消息传递机制详解

    Windows消息传递机制详解 简介 Windows消息传递机制是Windows操作系统中的一种重要的机制,它是应用程序之间通信的重要手段。本文将详细讲解Windows消息传递机制的核心概念、消息类型以及如何使用消息传递机制进行应用程序之间的通信。 核心概念 在Windows操作系统中,一个应用程序可以同时运行多个窗口,每个窗口都有一个唯一的标识符,称为窗口…

    人工智能概览 2023年5月25日
    00
  • 一次nginx崩溃事件的实战记录

    下面是关于“一次nginx崩溃事件的实战记录”的完整攻略,其中包含了两个示例说明。 一、前言 这是一篇记录Nginx崩溃事件的实战记录,旨在与大家分享如何通过日志分析和排查问题的过程,排除Nginx崩溃的问题。 在此之前,需要对Nginx的主要配置文件有一定的了解,并且对Linux系统的基本操作熟悉。如果您不知道这些,建议先学习相关知识再来阅读本文。 二、问…

    人工智能概览 2023年5月25日
    00
  • 详解SpringBoot通用配置文件(不定时更新)

    详解Spring Boot通用配置文件 1. 前言 在开发基于Spring Boot框架的应用时,通用配置文件是必不可少的。通过通用配置文件,我们可以方便的管理应用所需的基础配置信息,例如数据库连接配置、日志配置、缓存配置等。Spring Boot提供了强大的配置文件管理功能,支持多种配置文件格式,例如Properties和YAML。本文将详细讲解Sprin…

    人工智能概览 2023年5月25日
    00
  • pytorch中交叉熵损失(nn.CrossEntropyLoss())的计算过程详解

    下面是关于“PyTorch中交叉熵损失的计算过程详解”的完整攻略: 什么是交叉熵损失函数? 交叉熵损失函数是用于计算分类问题中的损失值的一种常用损失函数。在PyTorch中,交叉熵损失函数由nn.CrossEntropyLoss()实现。 交叉熵损失函数主要用于处理分类问题。假设我们的任务是将图像分类为0~9中的一个数字,并且我们已经训练好了模型,并对测试图…

    人工智能概论 2023年5月25日
    00
  • LNMP部署及HTTPS服务开启教程

    下面是 LNMP 部署及 HTTPS 服务开启教程的完整攻略。 一、环境准备 操作系统:Ubuntu 18.04 LTS 网络环境:已连接互联网 二、安装Nginx 更新 apt-get 包管理器:sudo apt-get update 安装 Nginx:sudo apt-get install nginx 验证 Nginx 是否安装成功:在浏览器访问服务器…

    人工智能概览 2023年5月25日
    00
  • python中时间转换datetime和pd.to_datetime详析

    Python中时间转换:datetime和pd.to_datetime详析 在Python中,时间的处理是一个常见需求。为了方便处理时间类型变量,Python提供了datetime库来进行时间转换。此外,pandas库也提供了pd.to_datetime函数来进行时间变量的转换。本文将详细介绍datetime和pd.to_datetime的使用方法和区别。 …

    人工智能概论 2023年5月25日
    00
合作推广
合作推广
分享本页
返回顶部