平滑升级udp研究

7 篇文章 0 订阅
1 篇文章 0 订阅

平滑升级的一般思路

  1. 发布新的bin文件去覆盖老的bin文件(如只需优雅重启,可以跳过这一步)
  2. 发送一个(USR2)信号量,告诉正在运行的进程,进行重启
  3. 正在运行的进程收到信号后,会以子进程的方式启动新的bin文件
  4. 子进程启动成功之后,老进程停止接收新的连接,等待旧连接处理完成(或超时)
  5. 父进程退出,升级完成

golang库

tcp应该有很多成熟的方案,可参照facebook库

注意点

平滑重启有个特点:两个相互独立的进程存在同时 bind、listen 相同的 IP + 端口,对于各个操作系统及版本验证如下:

  1. linux 内核 4.13.0
    设置参数SO_REUSEADDR、SO_REUSEPORT,可以bind、listen成功,新的连接由系统分配到某一个进程;
  2. linux 内核 2.6.32
    不支持SO_REUSEPORT,仅设置参数SO_REUSEADDR时,新进程 bind 失败。经查资料linux 3.9及以后开始支持参数SO_REUSEPORT;

参考资料

  1. fork新进程的方式
  2. Go 语言实现优雅的服务器重启
  3. 平滑重启的系统设置
  4. http热重启
  5. golang平滑重启分析

udp

这里主要总结下udp碰到的坑

udp继承套接字

	if *graceful {
		log.Print("main: Listening to existing file descriptor 3.")
		// cmd.ExtraFiles: If non-nil, entry i becomes file descriptor 3+i.
		// when we put socket FD at the first entry, it will always be 3(0+3)
		f := os.NewFile(3, "")
		listener, err = net.FilePacketConn(f)
		f.Close()
	} else {
		log.Print("main: Listening on a new file descriptor.")
		// listener, err = net.Listen("tcp", addr)
		listener, err = net.ListenPacket("udp", addr)
	}

udp启动子进程继承套接字

	tl, ok := listener.(*net.UDPConn)
	if !ok {
		return errors.New("listener is not tcp listener")
	}

	f, err := tl.File()
	if err != nil {
		return err
	}

	args := []string{"-graceful", "-seq", "1"}
	cmd := exec.Command(os.Args[0], args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	// put socket FD at the first entry
	cmd.ExtraFiles = []*os.File{f}
	cmd.Start()

由于udp无连接,作为服务端,在读取客户端旧连接发送的数据包时,新旧进程会抢占式读取。对单个服务进程来说,有丢包的假象
如果你在其上定制了一层维持连接的协议层,可能由于丢包假象,无法维持连接。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值