Golang中如何实现单服务器/单端口托管多服务

Golang中如何实现单服务器/单端口托管多服务 大家好。虽然我觉得自己问了个有点傻的问题,但我真的很好奇。显然,运行两个不同服务的最佳选择是让它们在不同的地址上运行,但假设我是一个手头拮据的大学生/农民,只想在业余时间构建一些玩具工具,而且以我的收入,确实只能负担得起一台VPS和一瓶可乐。那么,我的想法是,或许可以在不同的端口上运行服务。不过,除此之外,我还在考虑一个更程序化的解决方案。如果我拥有两个不同的“.tk”域名,并将它们指向同一个IP地址,我是否可以通过引荐来源(referrer)来判断我实际使用的是哪个地址?也就是说,“example1.tk”和“example2.tk”可以导向两种完全不同的体验,即使它们运行在同一台服务器的同一个端口上,对吗?有没有一种更合适的方法来实现这一点,而不需要解析请求并消耗大量的CPU周期?


更多关于Golang中如何实现单服务器/单端口托管多服务的实战教程也可以访问 https://www.itying.com/category-94-b0.html

5 回复

试试这个,Traefik

更多关于Golang中如何实现单服务器/单端口托管多服务的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


您可以在不同的非特权端口上运行它们,并在80/443端口上设置第三个服务,这个第三个服务就是所谓的反向代理。它将根据配置的规则,将请求转发给配置好的“后端”服务。

在那之后,我的假设是只需在不同的端口上运行服务。不过,除此之外,我正在考虑一个更程序化的解决方案。

你可以使用 Nginx 并将它们代理到不同的端口。我推荐使用 Cloudflare 来管理 DNS。https://hosting.go4webdev.org/howto

你好 @ashinnv

你有几个选择。

选项1: 通过URL路径区分两个服务。例如,

https://yourdomain.tk/api/service1/...
https://yourdomain.tk/api/service2/...

选项2: 使用子域名。如果你拥有一个域名,可以创建子域名,例如,

https://service1.yourdomain.tk/api/...
https://service2.yourdomain.tk/api/...

通常,每个子域名会解析到一个独立的IP地址,但你也可以让它们解析到同一个IP地址,并通过你的代码根据子域名来路由请求。

选项3: 使用反向代理将请求路由到两个不同的进程——这是 @NobbZ@luk4z7 的建议。(Traefik 就是这样一个反向代理。)

这个选项需要最多的工作量(设置反向代理、管理三个不同的进程……),但作为回报,你获得了更大的灵活性。你可以重启一个服务而不影响另一个,可以相当容易地添加第三个服务,可以实现服务无停机更新:首先在一个不同的端口启动服务的新版本,然后让代理将所有新请求导向这个新版本,当所有现有请求完成后,就可以关闭旧版本的服务。

关于CPU周期:特别是选项1和2,应该不会给你的CPU增加任何显著的负载。换句话说,处理一个请求所需的CPU周期应该远多于路由本身。

如有疑问,请测试和衡量。

在Go中实现单端口托管多服务,最合适的方式是通过HTTP主机头(Host header)进行路由,而不是解析referrer。这种方法效率高且符合HTTP标准。以下是一个简单示例:

package main

import (
    "fmt"
    "net/http"
)

func main() {
    mux := http.NewServeMux()
    
    // 为example1.tk定义处理函数
    mux.HandleFunc("example1.tk/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "欢迎访问服务1")
    })
    
    // 为example2.tk定义处理函数
    mux.HandleFunc("example2.tk/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "欢迎访问服务2")
    })
    
    // 默认处理
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "未知域名")
    })
    
    http.ListenAndServe(":80", mux)
}

对于更复杂的场景,可以使用第三方路由库如gorilla/mux

package main

import (
    "fmt"
    "net/http"
    "github.com/gorilla/mux"
)

func service1Handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "服务1的内容")
}

func service2Handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "服务2的内容")
}

func main() {
    r := mux.NewRouter()
    
    // 基于主机头路由
    r.Host("example1.tk").HandlerFunc(service1Handler)
    r.Host("example2.tk").HandlerFunc(service2Handler)
    
    http.ListenAndServe(":80", r)
}

这种方法消耗的CPU资源极少,因为HTTP主机头是每个请求的标准部分,解析成本可以忽略不计。你只需要将两个域名都指向同一个VPS的IP地址,然后在服务器上配置相应的路由逻辑即可。

回到顶部