Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE REQUEST] make reuseport/reuseaddress as Listener option. #1544

Closed
Dexus opened this issue Jun 25, 2020 · 6 comments
Closed

[FEATURE REQUEST] make reuseport/reuseaddress as Listener option. #1544

Dexus opened this issue Jun 25, 2020 · 6 comments

Comments

@Dexus
Copy link

Dexus commented Jun 25, 2020

Is your feature request related to a problem? Please describe.
I would like to make my app always up to date but without any losing requests. So i would like to have the option with reuseport/reuseaddress to use the already used Port and address form the currently running instance. So that I can start the updated Server and kill after it the old server.

Describe the solution you'd like
https://github.com/libp2p/go-reuseport

Describe alternatives you've considered
Own Listener but why I should make it my own? Ngnix and other Server also have this option included.

Additional context
Add any other context or screenshots about the feature request here.

@kataras
Copy link
Owner

kataras commented Jun 25, 2020

Hello @Dexus,

For Unix-based systems there is an example already at:

// +build linux darwin dragonfly freebsd netbsd openbsd rumprun

package main

import (
	"github.com/valyala/tcplisten"

	"github.com/kataras/iris/v12"
)

func main() {
	app := iris.New()

	app.Get("/", func(ctx iris.Context) {
		ctx.HTML("<b>Hello World!</b>")
	})

	listenerCfg := tcplisten.Config{
		ReusePort:   true,
		DeferAccept: true,
		FastOpen:    true,
	}

	l, err := listenerCfg.NewListener("tcp4", ":8080")
	if err != nil {
		panic(err)
	}

	app.Run(iris.Listener(l))
}

I didn't know about the libp2p/go-reuseport package, so I tested the windows syscall to create a "reuseport" on windows machines:

package main

import (
	"context"
	"net"
	"syscall"
	"time"

	"github.com/kataras/iris/v12"

	"golang.org/x/sys/windows"
)

func main() {
	app := iris.New()
	startup := time.Now()

	app.Get("/", func(ctx iris.Context) {
		s := startup.Format(ctx.Application().ConfigurationReadOnly().GetTimeFormat())
		ctx.Writef("this server started at: %s\n", s)
	})

	app.Get("/path", func(ctx iris.Context) {
		ctx.Writef("path: %s\n", ctx.Path())
	})

	ln, err := ReusePort("tcp4", ":8080")
	if err != nil {
		panic(err)
	}

	app.Run(iris.Listener(ln))
}

func control(network, address string, c syscall.RawConn) (err error) {
	return c.Control(func(fd uintptr) {
		err = windows.SetsockoptInt(windows.Handle(fd), windows.SOL_SOCKET, windows.SO_REUSEADDR, 1)
	})
}

func ReusePort(network, addr string) (net.Listener, error) {
	cfg := net.ListenConfig{
		Control: control,
	}
	return cfg.Listen(context.Background(), network, addr)
}

The windows behavior is: you can start as many servers as you want pointing to the same port however, all requests communicate with the first server started only, if the first server is terminated, then the requests will be fired to the second server one (try to change the http responses to test it) and so on...

Refs:

@Dexus
Copy link
Author

Dexus commented Jun 25, 2020

I know the example, but it would be nicer if you just used the module, because it runs on all systems, and if you are familiar with the ReUse theme, you know the pitfalls that arise. But it would make it easier if you had the box ready to use. Without the detour to do it yourself.

But it's up to you whether you consider it integrable.

@Dexus
Copy link
Author

Dexus commented Jun 25, 2020

And nobody should expect it to be a "loadbalancer" if you use the same port multiple times...

@kataras
Copy link
Owner

kataras commented Jun 25, 2020

OK, I agree. I must go to a meeting now. Will take a closer look in order to add a feature like this for all supported platforms easy.

@kataras
Copy link
Owner

kataras commented Jun 26, 2020

Hello @Dexus, there is an iris.WithSocketSharding Configurator and Configuration.SocketSharding bool setting now. Works with all registered servers (.Addr/.Listen, .TLS, .AutoTLS, .NewHost, .Server) Example:

app.Listen(":8080", iris.WithSocketSharding)

I've also added comments for "feature details" on the setting itself, such as:

  1. https://stackoverflow.com/a/14388707
  2. https://stackoverflow.com/a/59692868
  3. https://www.nginx.com/blog/socket-sharding-nginx-release-1-9-1/
  4. (BOOK) Learning HTTP/2: A Practical Guide for Beginners: Page 37, To Shard or Not to Shard?

@Dexus
Copy link
Author

Dexus commented Jun 26, 2020

Thank you very much, that will help us to kick out old server without lost requests now.

kataras added a commit that referenced this issue Jul 26, 2020
Former-commit-id: 0384baf593012377a94344d647ca41121294285a
@kataras kataras closed this as completed Aug 2, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants