如何从 Golang 程序中设置 ulimit -n?

14

我的目的是在golang程序中设置ulimit -n,这样我就不必全局设置,而是将其限制在程序内部。

我发现可以使用系统调用setrlimit和getrlimit来实现这一点。(http://linux.die.net/man/2/setrlimit

但是当我尝试编写一个示例程序时,我遇到了一个错误,提示设置值无效。

package main

import (
    "fmt"
    "syscall"
)

func main() {
    var rLimit syscall.Rlimit

    err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)

    if err != nil {
        fmt.Println("Error Getting Rlimit ", err)
    }
    fmt.Println(rLimit)

    rLimit.Max = 999999
    rLimit.Cur = 999999

    err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)
    if err != nil {
        fmt.Println("Error Setting Rlimit ", err)
    }

    err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
    if err != nil {
        fmt.Println("Error Getting Rlimit ", err)
    }
    fmt.Println("Rlimit Final", rLimit)
}

得到的输出为:

george@george-Not-Specified ~/work/odesk/progium/trial $ ./getRlimit 
{4294963002032703 0}
Error Setting Rlimit  invalid argument
Rlimit Final {4294963002032703 999999}
george@george-Not-Specified ~/work/odesk/progium/trial $ sudo ./getRlimit 
[sudo] password for george: 
{4294963002032703 0}
Error Setting Rlimit  invalid argument 
Rlimit Final {4294963002032703 999999}
george@george-Not-Specified ~/work/odesk/progium/trial $ uname -a
Linux george-Not-Specified 3.5.0-17-generic #28-Ubuntu SMP Tue Oct 9 19:32:08 UTC 2012 i686 i686 i686 GNU/Linux
george@george-Not-Specified ~/work/odesk/progium/trial $ 

所以我成功设置了rlimit,但是在设置限制时出现了错误并返回了一个错误消息。即使它失败了,当我再次获取该值时,最大值已经改变,但CUR值仍然保持不变。这个错误可能是由于我的内核存在问题还是坏的程序导致的?在哪里可以找到更多信息并如何处理这样的问题呢?

更新:

修复后正常运行。

george@george-Not-Specified ~/work/odesk/progium/trial $ go build getRlimit.go 
george@george-Not-Specified ~/work/odesk/progium/trial $ ./getRlimit 
{1024 4096}
Error Setting Rlimit  operation not permitted
Rlimit Final {1024 4096}
george@george-Not-Specified ~/work/odesk/progium/trial $ sudo ./getRlimit                                                                                               
[sudo] password for george: 
{1024 4096}
Rlimit Final {999999 999999}
george@george-Not-Specified ~/work/odesk/progium/trial $ uname -a
Linux george-Not-Specified 3.5.0-17-generic #28-Ubuntu SMP Tue Oct 9 19:32:08 UTC 2012    i686 i686 i686 GNU/Linux
george@george-Not-Specified ~/work/odesk/progium/trial $ go version
go version devel +7c42cfa28e24 Tue Jul 30 14:22:14 2013 +1000 linux/386
1个回答

33

它按预期工作。

setrlimit(2)

软限制是内核强制执行的相应资源的值。硬限制作为软限制的上限:非特权进程只能将其软限制设置为从0到硬限制范围内的值,并(不可逆地)降低其硬限制。 特权进程(在Linux下:具有CAP_SYS_RESOURCE功能的进程)可以对任一限制值进行任意更改。

rlimit.go

package main

import (
    "fmt"
    "syscall"
)

func main() {
    var rLimit syscall.Rlimit
    err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
    if err != nil {
        fmt.Println("Error Getting Rlimit ", err)
    }
    fmt.Println(rLimit)
    rLimit.Max = 999999
    rLimit.Cur = 999999
    err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)
    if err != nil {
        fmt.Println("Error Setting Rlimit ", err)
    }
    err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
    if err != nil {
        fmt.Println("Error Getting Rlimit ", err)
    }
    fmt.Println("Rlimit Final", rLimit)
}

输出:

$ uname -a
Linux peterSO 3.8.0-26-generic #38-Ubuntu SMP Mon Jun 17 21:43:33 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
$ go build rlimit.go
$ ./rlimit
{1024 4096}
Error Setting Rlimit  operation not permitted
Rlimit Final {1024 4096}
$ sudo ./rlimit
[sudo] password for peterSO:
{1024 4096}
Rlimit Final {999999 999999}

更新:

我已经成功地在 linux/amd64 上运行了 rlimit.go,而你在 linux/386 上失败了。这是因为在 Linux 32 位发行版中,GetrlimitSetrlimit 存在 Go Bug。这些 Bug 已被修复。

使用 Go default 分支的 tip(以包括 Bug 修复),运行以下命令,并用结果更新你的问题。

$ uname -a
Linux peterSO 3.8.0-26-generic #38-Ubuntu SMP Mon Jun 17 21:46:08 UTC 2013 i686 i686 i686 GNU/Linux
$ go version
go version devel +ba52f6399462 Thu Jul 25 09:56:06 2013 -0400 linux/386
$ ulimit -Sn
1024
$ ulimit -Hn
4096
$ go build rlimit.go
$ ./rlimit
{1024 4096}
Error Setting Rlimit  operation not permitted
Rlimit Final {1024 4096}
$ sudo ./rlimit
[sudo] password for peterSO: 
{1024 4096}
Rlimit Final {999999 999999}
$ 

@GeorgeThomas,正如PeterSO所指出的那样:您是否正在使用超级用户权限运行应用程序? - elithrar
@GeorgeThomas:是的。你的uname输出显示为i686,而我的则是x86_64。我必须设置一个32位的虚拟机来完成调试。 - peterSO
我也在想当前值的价值。ulimit -n返回999999,但这是不同的。 - George Thomas
@GeorgeThomas:这是一个Go linux/386 bug。我正在努力修复它。 - peterSO
@GeorgeThomas:看看我的更新答案。我修复了一些关于linux/386 Go的错误。 - peterSO
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接