Sockets 去,tcp打开的文件太多调试
下面是一个简单的Go http(tcp)连接测试脚本Sockets 去,tcp打开的文件太多调试,sockets,tcp,go,goroutine,Sockets,Tcp,Go,Goroutine,下面是一个简单的Go http(tcp)连接测试脚本 func main() { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Hello, client") })) defer ts.Close() var wg sync.WaitGroup for i := 0; i &l
func main() {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, client")
}))
defer ts.Close()
var wg sync.WaitGroup
for i := 0; i < 2000; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
resp, err := http.Get(ts.URL)
if err != nil {
panic(err)
}
greeting, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
panic(err)
}
fmt.Printf("%s", i, greeting)
}(i)
}
wg.Wait()
}
func main(){
ts:=httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter,r*http.Request){
fmt.Fprintln(w,“你好,客户”)
}))
延迟ts关闭()
var wg sync.WaitGroup
对于i:=0;i<2000;i++{
工作组.添加(1)
go func(i int){
推迟工作组完成()
resp,err:=http.Get(ts.URL)
如果错误!=零{
恐慌(错误)
}
问候语,err:=ioutil.ReadAll(resp.Body)
各自主体关闭()
如果错误!=零{
恐慌(错误)
}
fmt.Printf(“%s”,i,问候语)
}(一)
}
wg.Wait()
}
如果我在Ubuntu中运行它,我会得到:
panic:Gethttp://127.0.0.1:33202: 拨打tcp 127.0.0.1:33202:打开的文件太多
其他帖子说要确保关闭连接,我在这里就是这么做的。
还有人说要增加与ulimit的最大连接限制,或者尝试使用sudo sysctl-w fs.inotify.max_user_watches=100000,但仍然不起作用
如何在一台服务器上运行数百万个tcp连接goroutine?
只有2000个连接才会崩溃
谢谢,我认为您需要更改max文件描述符。我以前在一个开发虚拟机上遇到过同样的问题,需要更改文件描述符max,而不是使用inotify设置
FWIW,你的程序在我的虚拟机上运行良好
·> ulimit -n
120000
但我跑完之后
·> ulimit -n 500
·> ulimit -n
500
我得到:
panic: Get http://127.0.0.1:51227: dial tcp 127.0.0.1:51227: socket: too many open files
**不要落入普拉文所设的陷阱**
注意ulimit
!=<代码>ulimit-n
➜ cmd git:(wip-poop) ✗ ulimit -a
-t: cpu time (seconds) unlimited
-f: file size (blocks) unlimited
-d: data seg size (kbytes) unlimited
-s: stack size (kbytes) 8192
-c: core file size (blocks) 0
-v: address space (kbytes) unlimited
-l: locked-in-memory size (kbytes) unlimited
-u: processes 1418
-n: file descriptors 4864
我还必须手动设置close connection头以避免文件描述符问题:
r, _ := http.NewRequest(http.MethodDelete, url, nil)
r.Close = true
res, err := c.Do(r)
res.Body.Close();
如果没有r.Close=true和res.Body.Close(),我达到了文件描述符的限制。使用这两种方法,我可以根据需要启动任意多个文件。更改ulimit以避免出现“打开的文件太多”的错误
默认情况下,linux的最大ulimit为4096,mac为1024,
您可以通过键入将ulimit更改为4096
ulimit-N4096
对于beyond 4096,您需要修改linux的etc/security文件夹中的limits.conf,并通过添加此行“*hard core 100000”将硬限制设置为100000
我通过添加req.Close=true和req.Header.Set(“连接”,“关闭”)解决了这个问题。我觉得这比换一个ulimit好
来源:如果你想运行数百万个go例程来打开/读取/关闭一个套接字,那么你最好升级你的ulimit,或者打开/读取/关闭套接字并将读取的值传递给go例程,但是我会使用一个缓冲通道来控制你想要打开的文件描述符的数量
const (
// this is where you can specify how many maxFileDescriptors
// you want to allow open
maxFileDescriptors = 100
)
func main() {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, client")
}))
defer ts.Close()
var wg sync.WaitGroup
maxChan := make(chan bool, maxFileDescriptors)
for i := 0; i < 1000; i++ {
maxChan <- true
wg.Add(1)
go func(url string, i int, maxChan chan bool, wg *sync.WaitGroup) {
defer wg.Done()
defer func(maxChan chan bool) { <-maxChan }(maxChan)
resp, err := http.Get(url)
if err != nil {
panic(err)
}
greeting, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
err = resp.Body.Close()
if err != nil {
panic(err)
}
fmt.Printf("%d: %s", i, string(greeting))
}(ts.URL, i, maxChan, &wg)
}
wg.Wait()
}
const(
//在这里可以指定MaxFileDescriptor的数量
//您想允许打开吗
maxFileDescriptors=100
)
func main(){
ts:=httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter,r*http.Request){
fmt.Fprintln(w,“你好,客户”)
}))
延迟ts关闭()
var wg sync.WaitGroup
maxChan:=make(chan bool,maxFileDescriptor)
对于i:=0;i<1000;i++{
默认情况下,maxChanGo的http包不指定请求超时。您应该始终在服务中包含超时。如果客户端不关闭其会话,该怎么办?您的进程将保持命中ulimit的旧会话的活动状态。一个不好的参与者可能会故意打开数千个会话,从而影响服务器。重载服务应该进行调整乌利米特也是,但后援暂停
确保指定超时:
http.DefaultClient.Timeout = time.Minute * 10
您可以通过监视流程打开的文件来验证之前和之后:
lsof -p [PID_ID]
如果你增加你的ulimit,你最终还是会用完文件描述符。尝试使用缓冲通道,并将打开文件的go例程数量限制在ulimit以下。一次打开1000个文件就足够了……太好了,这正是我所寻求的实用智慧。我相信这有一个好处(非常不可能,但可能)竞态条件错误-您应该wg.Add(1)
在go func(…){…}
之外和之前添加(1)
。否则,如果第一个n
goroutine在n+1
第个goroutine开始之前完成(这也是极不可能的),那么wg.Wait()
命令实际上可能在运行n+1
th和其余goroutine之前终止。(它们仍然会运行,但下游代码不会等待它。)
lsof -p [PID_ID]