Golang API服务运行数小时后停止监听的解决方法

Golang API服务运行数小时后停止监听的解决方法 大家好,

我有一个为我的安卓应用提供服务的Golang API服务器,它运行在我们的AWS空间。 我启动应用后,服务器最多运行5到6小时就会自动停止。

有时我在终端中看到这条信息: Connection reset by 13.***.***.11 port 22。

有时终端中没有任何显示。

这个问题已经持续几周了,我虽然完成了API开发,但由于这个问题无法部署。

请提供解决方案。

5 回复

连接被 13.**.**.11 端口 22 重置。

这条消息是来自你的程序、标准库还是 panic?同时在你的程序中记录操作日志,以找到程序挂起点的更多细节。

更多关于Golang API服务运行数小时后停止监听的解决方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


感谢您的帮助……我现在明白了应该使用服务在后台运行应用程序。

我对这种服务器端执行还比较陌生。我有使用 Node 的经验,通常使用框架来运行应用程序。Go 语言有类似的框架吗?

如果没有的话,我应该使用 Docker 吗?

由于您没有说明在 Node.js 中使用了哪个框架,我们无法告知 Go 语言中是否有类似的框架。但我可以告诉您,Go 语言确实有用于创建 Web 应用程序或 JSON API 的框架。

您需要自行搜索相关信息。

但即使使用了框架,您仍然需要正确部署应用程序。

在 Node.js 中情况也应该没什么不同,那里同样需要运行服务…

你在终端中看到这个吗?

你是怎么运行那个服务器的?

听起来好像你是通过 ssh 连接到服务器并在 ssh 会话中启动你的应用程序。如果你真的这样做,那么你的应用程序将作为你 ssh 会话中启动的 shell 的子进程运行,一旦会话结束,它的子进程也会随之终止。

请使用适当的 systemd 单元或其他系统服务描述来管理应用程序的启动和停止。

这是一个典型的连接资源泄漏问题,很可能是由于未正确管理HTTP连接或goroutine泄漏导致的。以下是几种可能的解决方案:

1. 配置HTTP服务器超时设置

package main

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

func main() {
    server := &http.Server{
        Addr: ":8080",
        ReadTimeout:  15 * time.Second,
        WriteTimeout: 15 * time.Second,
        IdleTimeout:  60 * time.Second,
        MaxHeaderBytes: 1 << 20,
    }
    
    // 你的路由设置
    http.HandleFunc("/api", yourAPIHandler)
    
    if err := server.ListenAndServe(); err != nil {
        panic(err)
    }
}

2. 使用http.CloseNotifier检测断开连接

func yourAPIHandler(w http.ResponseWriter, r *http.Request) {
    cn, ok := w.(http.CloseNotifier)
    if !ok {
        http.Error(w, "Cannot stream", http.StatusInternalServerError)
        return
    }
    
    // 监听客户端断开连接
    closeNotify := cn.CloseNotify()
    
    go func() {
        <-closeNotify
        // 清理资源
        fmt.Println("Client disconnected")
    }()
    
    // 你的业务逻辑
    w.Write([]byte("Response"))
}

3. 实现连接池和连接复用

import (
    "net"
    "net/http"
    "time"
)

func createHTTPClient() *http.Client {
    return &http.Client{
        Transport: &http.Transport{
            MaxIdleConns:        100,
            MaxIdleConnsPerHost: 100,
            IdleConnTimeout:     90 * time.Second,
            DialContext: (&net.Dialer{
                Timeout:   30 * time.Second,
                KeepAlive: 30 * time.Second,
            }).DialContext,
            TLSHandshakeTimeout: 10 * time.Second,
        },
        Timeout: time.Second * 30,
    }
}

4. 使用context管理请求生命周期

func yourAPIHandler(w http.ResponseWriter, r *http.Request) {
    ctx, cancel := context.WithTimeout(r.Context(), 30*time.Second)
    defer cancel()
    
    // 在goroutine中使用context
    done := make(chan bool)
    
    go func() {
        select {
        case <-ctx.Done():
            // 超时或取消
            return
        case <-done:
            // 正常完成
        }
    }()
    
    // 你的业务逻辑
    // ...
    close(done)
}

5. 添加健康检查和监控

func healthCheckHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusOK)
    w.Write([]byte(`{"status": "healthy"}`))
}

func main() {
    http.HandleFunc("/health", healthCheckHandler)
    http.HandleFunc("/api", yourAPIHandler)
    
    // 定期检查goroutine数量
    go func() {
        ticker := time.NewTicker(5 * time.Minute)
        defer ticker.Stop()
        
        for range ticker.C {
            // 记录监控指标
            fmt.Printf("Goroutines: %d\n", runtime.NumGoroutine())
        }
    }()
    
    log.Fatal(http.ListenAndServe(":8080", nil))
}

6. 完整的服务器配置示例

package main

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

func main() {
    server := &http.Server{
        Addr:         ":8080",
        Handler:      nil, // 设置你的路由
        ReadTimeout:  15 * time.Second,
        WriteTimeout: 15 * time.Second,
        IdleTimeout:  60 * time.Second,
    }
    
    // 优雅关闭
    stop := make(chan os.Signal, 1)
    signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
    
    go func() {
        log.Println("Server starting on :8080")
        if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
            log.Fatalf("Server failed: %v", err)
        }
    }()
    
    <-stop
    log.Println("Shutting down server...")
    
    ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
    defer cancel()
    
    if err := server.Shutdown(ctx); err != nil {
        log.Printf("Server shutdown failed: %v", err)
    }
    log.Println("Server stopped")
}

主要关注点应该是HTTP服务器的超时配置和资源管理。Connection reset by port 22错误通常表示SSH连接问题,可能与你的服务器监控或部署流程有关,但核心问题很可能是应用程序层面的连接管理。

回到顶部