一般来说一个端口只能绑定一个进程,然而在 Linux 中其实有一个参数选项 SO_REUSEPORT ,可以让一个端口被多个进程监听,本意是解决 Tcp 的 TIME_WAIT 问题,但是于我看来其实可以做多进程负载到一个端口上。
golang 中可以通过如下实现:
package main
import (
"context"
"fmt"
"golang.org/x/sys/unix"
"net"
"net/http"
"os"
"syscall"
)
func main() {
http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
writer.Write([]byte(fmt.Sprintf("from pid: %d", os.Getpid())))
})
server := &http.Server{Addr: "127.0.0.1:8080", Handler: http.DefaultServeMux}
lc := net.ListenConfig{
Control: func(network, address string, c syscall.RawConn) error {
return c.Control(func(fd uintptr) {
fmt.Println("Control SO_REUSEADDR :", syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1))
fmt.Println("Control SO_REUSEPORT :", syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, unix.SO_REUSEPORT, 1))
})
},
}
lis, err := lc.Listen(context.Background(), "tcp", server.Addr)
if err != nil {
panic(err)
}
panic(server.Serve(lis))
}
目前服务可以运行很多次,每次都运行在一个进程上,但是这些进程都绑定到同一个端口上,确实很神奇,在我测试下来,Linux 上确实是可以做到随机负载,Mac 是不支持随机负载的,只会连接到最后一个启动的进程。
网友评论