2015-12-06 5 views
22

私はGo1.5.1プロセス/アプリケーションを持っています。私がそのプロセスで/usr/sbin/lsof -pを実行すると、多くの "プロトコルを特定できません"が表示されます。ソケットがプロトコル(ソケットリーク)を識別できません

monitor_ 13105 root 101u sock  0,6  0t0 16960100 can't identify protocol 
monitor_ 13105 root 102u sock  0,6  0t0 21552427 can't identify protocol 
monitor_ 13105 root 103u sock  0,6  0t0 17565091 can't identify protocol 
monitor_ 13105 root 104u sock  0,6  0t0 18476870 can't identify protocol 

PROCステータス/制限/ FD

[[email protected]_q ~]# cat /proc/13105/status 
Name: monitor_client 
State: S (sleeping) 
Tgid: 13105 
Pid: 13105 
PPid: 13104 
TracerPid: 0 
Uid: 0 0 0 0 
Gid: 0 0 0 0 
Utrace: 0 
FDSize: 16384 
Groups: 
... 


[[email protected]_q ~]# cat /proc/13105/limits 
Limit      Soft Limit   Hard Limit   Units  
Max cpu time    unlimited   unlimited   seconds 
Max file size    unlimited   unlimited   bytes  
Max data size    unlimited   unlimited   bytes  
Max stack size   10485760    unlimited   bytes  
Max core file size  0     unlimited   bytes  
Max resident set   unlimited   unlimited   bytes  
Max processes    3870     3870     processes 
Max open files   9999     9999     files  
Max locked memory   65536    65536    bytes  
Max address space   unlimited   unlimited   bytes  
Max file locks   unlimited   unlimited   locks  
Max pending signals  3870     3870     signals 
Max msgqueue size   819200    819200    bytes  
Max nice priority   0     0      
Max realtime priority  0     0      
Max realtime timeout  unlimited   unlimited   us 

[[email protected]_q ~]# ll /proc/13105/fd/ 
lrwx------ 1 root root 64 Dec 7 00:15 8382 -> socket:[52023221] 
lrwx------ 1 root root 64 Dec 7 00:15 8383 -> socket:[51186627] 
lrwx------ 1 root root 64 Dec 7 00:15 8384 -> socket:[51864232] 
lrwx------ 1 root root 64 Dec 7 00:15 8385 -> socket:[52435453] 
lrwx------ 1 root root 64 Dec 7 00:15 8386 -> socket:[51596071] 
lrwx------ 1 root root 64 Dec 7 00:15 8387 -> socket:[52767667] 
lrwx------ 1 root root 64 Dec 7 00:15 8388 -> socket:[52090632] 
lrwx------ 1 root root 64 Dec 7 00:15 8389 -> socket:[51739068] 
lrwx------ 1 root root 64 Dec 7 00:15 839 -> socket:[22963529] 
lrwx------ 1 root root 64 Dec 7 00:15 8390 -> socket:[52023223] 
lrwx------ 1 root root 64 Dec 7 00:15 8391 -> socket:[52560389] 
lrwx------ 1 root root 64 Dec 7 00:15 8392 -> socket:[52402565] 
... 
netstat -a

しかしには同様の出力はありません。

これらのソケットとは何ですか?また、これらのソケットは何ですか?

monitor_client.go

package main 

import (
    "crypto/tls" 
    "encoding/json" 
    "fmt" 
    "log" 
    "net" 
    "net/http" 
    nurl "net/url" 
    "strconv" 
    "strings" 
    "syscall" 
    "time" 
) 

type Result struct { 
    Error  string  `json:"error"` 
    HttpStatus int   `json:"http_status"` 
    Stime  time.Duration `json:"http_time"` 
} 

//http://stackoverflow.com/questions/20990332/golang-http-timeout-and-goroutines-accumulation 
//http://3.3.3.3/http?host=3.2.4.2&servername=a.test&path=/&port=33&timeout=5&scheme=http 
func MonitorHttp(w http.ResponseWriter, r *http.Request) { 
    var host, servername, path, port, scheme string 
    var timeout int 
    u, err := nurl.Parse(r.RequestURI) 
    if err != nil { 
     log.Fatal(err) 
     return 
    } 
    if host = u.Query().Get("host"); host == "" { 
     host = "127.0.0.0" 
    } 
    if servername = u.Query().Get("servername"); servername == "" { 
     servername = "localhost" 
    } 
    if path = u.Query().Get("path"); path == "" { 
     path = "/" 
    } 
    if port = u.Query().Get("port"); port == "" { 
     port = "80" 
    } 
    if scheme = u.Query().Get("scheme"); scheme == "" { 
     scheme = "http" 
    } 

    if timeout, _ = strconv.Atoi(u.Query().Get("timeout")); timeout == 0 { 
     timeout = 5 
    } 

    //log.Printf("(host)=%s (servername)=%s (path)=%s (port)=%s (timeout)=%d", host, servername, path, port, timeout) 

    w.Header().Set("Content-Type", "application/json") 

    res := httptool(host, port, servername, scheme, path, timeout) 
    result, _ := json.Marshal(res) 
    fmt.Fprintf(w, "%s", result) 
} 

func httptool(ip, port, servername, scheme, path string, timeout int) Result { 

    var result Result 
    startTime := time.Now() 
    host := ip + ":" + port 

    transport := &http.Transport{ 
     TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, 
     DisableKeepAlives: true, 
    } 

    dialer := net.Dialer{ 
     Timeout: time.Duration(timeout) * time.Second, 
     KeepAlive: 0 * time.Second, 
    } 
    transport.Dial = func(network, address string) (net.Conn, error) { 
     return dialer.Dial(network, address) 
    } 

    client := &http.Client{ 
     Transport: transport, 
    } 
    rawquery := "" 
    url := fmt.Sprintf("%s://%s%s%s", scheme, host, path, rawquery) 
    req, err := http.NewRequest("GET", url, nil) 
    if err != nil { 
     result.HttpStatus = -1 
     errs := strings.Split(err.Error(), ": ") 
     result.Error = errs[len(errs)-1] 
     result.Stime = time.Now().Sub(startTime)/time.Millisecond 
     return result 
    } 
    req.Header.Set("User-Agent", "monitor worker") 
    req.Header.Set("Connection", "close") 
    req.Host = servername 
    resp, err := client.Do(req) 
    //https://github.com/Basiclytics/neverdown/blob/master/check.go 
    if err != nil { 
     nerr, ok := err.(*nurl.Error) 
     if ok { 
      switch cerr := nerr.Err.(type) { 
      case *net.OpError: 
       switch cerr.Err.(type) { 
       case *net.DNSError: 
        errs := strings.Split(cerr.Error(), ": ") 
        result.Error = "dns: " + errs[len(errs)-1] 
       default: 
        errs := strings.Split(cerr.Error(), ": ") 
        result.Error = "server: " + errs[len(errs)-1] 
       } 
      default: 
       switch nerr.Err.Error() { 
       case "net/http: request canceled while waiting for connection": 
        errs := strings.Split(cerr.Error(), ": ") 
        result.Error = "timeout: " + errs[len(errs)-1] 

       default: 
        errs := strings.Split(cerr.Error(), ": ") 
        result.Error = "unknown: " + errs[len(errs)-1] 
       } 
      } 

     } else { 
      result.Error = "unknown: " + err.Error() 
     } 
     result.HttpStatus = -2 
     result.Stime = time.Now().Sub(startTime)/time.Millisecond 
     return result 
    } 
    resp.Body.Close() 
    result.HttpStatus = resp.StatusCode 
    result.Error = "noerror" 
    result.Stime = time.Now().Sub(startTime)/time.Millisecond //spend time (ms) 
    return result 
} 

func setRlimit() { 
    var rLimit syscall.Rlimit 
    err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit) 
    if err != nil { 
     log.Printf("Unable to obtain rLimit", err) 
    } 
    if rLimit.Cur < rLimit.Max { 
     rLimit.Max = 9999 
     rLimit.Cur = 9999 
     err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit) 
     if err != nil { 
      log.Printf("Unable to increase number of open files limit", err) 
     } 
    } 
} 

func main() { 
    setRlimit() 
    s := &http.Server{ 
     Addr:   ":59059", 
     ReadTimeout: 7 * time.Second, 
     WriteTimeout: 7 * time.Second, 
    } 
    http.HandleFunc("/http", MonitorHttp) 

    log.Fatal(s.ListenAndServe()) 
} 
+4

なぜ、コールごとにクライアント、ダイヤラ、トランスポートなどのスタック全体を構築していますか?すべてのクライアントに単一のクライアントを使用してみませんか?クライアントは接続プーリングとリサイクルなどを行います。 –

+8

要求がタイムアウトしていないため、ハングした要求はすべてオープンな接続になります。 TCPキープアライブも無効になっているため、接続が切断されることはありません。 – JimB

+0

@JimBあなたの答えに感謝します。 – user587170

答えて

-1

ポイントのカップルがここにあります。

とにかく、あなたの行動を再現できませんでした。can't identify protocolは、通常、正しく閉じられていないソケットに結び付けられています。

コメント者の中には、各ハンドラ内にhttpクライアントを作成する必要はないとの意見がありました。一度作成して再利用するだけです。

第2に、なぜあなた自身のhttp.Client構造体を作成しているのか、なぜキープアライブを無効にしているのかわかりません。 http.Getと一緒に行くことはできませんか?簡単なコードはデバッグが容易です。

第三者が、なぜあなたが上書きしているのかわからないtransport.Dial機能。あなたがそれを行う必要がある場合であっても、(ゴー1.9.2用)のドキュメントは言う:

% go doc http.transport.dial 
type Transport struct { 
    // Dial specifies the dial function for creating unencrypted TCP 
    connections. 
    // 
    // Deprecated: Use DialContext instead, which allows the transport 
    // to cancel dials as soon as they are no longer needed. 
    // If both are set, DialContext takes priority. 
    Dial func(network, addr string) (net.Conn, error) 

ダイヤルの廃止と欠如についてのコメントはあなたの問題の源を指して再利用すること。

要約すると、あなたの靴では、私は2つのことを実行したいとき: *一度だけ実行される、または私は上書きでこの事をクリーンアップすると思います*ちょうどhttp.Get でデフォルトのクライアントを使用したコードへの移行クライアントの作成あなたがそれをしなければならないなら、私はDialContextを提案として使うでしょう。

幸運。

+0

downvotingの根拠は何ですか?私は問題を再現&理解するために真剣な努力を払い、それに基づいてフィードバックを出しました。どのようにdownvoterは、それをより良くするだろうか? –

関連する問題