2017-02-08 9 views
0

囲碁ENVを書き込む:golang要求ヘッダー同時読み取り及び

GOARCH = "AMD64"

GOBIN = "/ルート/"

GOEXE = ""

GOHOSTARCH = "AMD64"

GOHOSTOS = "Linuxの"

GOOS = "Linuxの"

GOPATH = "/データ/ワークスペース/ kubernetes"

GORACE = ""

GOROOT = "は/ usr/local /" 行く

GOTOOLDIR = "は/ usr/local/PKG /ツール/ linux_amd64 /行く"

GO15VENDOREXPERIMENT = "1"

CC = "gccの"

GOGCCFLAGS = " - FPIC -m64 -pthread -fmessage長= 0"

CXX = "G ++"

CGO_ENABLED = "1"

移動バージョン:

go version go1.6.3 linux/amd64

この問題は、高負荷の「パフォーマンステストenv」kube-apiserverで発生します。 KUBE-apiserverパニックと出口:

fatal error: concurrent map read and map write 

goroutine 77930636 [running]: 
runtime.throw(0x2f4c4c0, 0x21) 
    /root/.gvm/gos/go1.6.3/src/runtime/panic.go:547 +0x90 fp=0xca67b477f0  sp=0xca67b477d8 
runtime.mapaccess1_faststr(0x2a8e520, 0xc9e29000f0, 0x2c11220, 0xa, 0x433e360) 
    /root/.gvm/gos/go1.6.3/src/runtime/hashmap_fast.go:202 +0x5b fp=0xca67b47850 sp=0xca67b477f0 
k8s.io/kubernetes/pkg/httplog.(*respLogger).Log(0xcbddf2ae70) 
     /data/gerrit/src/k8s.io/kubernetes/_output/local/go/src/k8s.io/kubernetes/pkg/httplog/log.go:180 +0x43d fp=0xca67b47af8 sp=0xca67b47850 
k8s.io/kubernetes/pkg/apiserver.RecoverPanics.func1(0x7f099f157090, 0xcbddf2ae70, 0xcd7569e380) 
    /data/gerrit/src/k8s.io/kubernetes/_output/local/go/src/k8s.io/kubernetes/pkg/apiserver/handlers.go:174 +0x15d fp=0xca67b47b50 sp=0xca67b47af8 
    net/http.HandlerFunc.ServeHTTP(0xc821a4eac0, 0x7f099f157058, 0xca0f4eb450, 0xcd7569e380) 
    /root/.gvm/gos/go1.6.3/src/net/http/server.go:1618 +0x3a fp=0xca67b47b70 sp=0xca67b47b50 
net/http.serverHandler.ServeHTTP(0xc8215a7b80, 0x7f099f157058, 0xca0f4eb450, 0xcd7569e380) 
    /root/.gvm/gos/go1.6.3/src/net/http/server.go:2081 +0x19e fp=0xca67b47bd0 sp=0xca67b47b70 
net/http.(*conn).serve(0xc8b5d6b980) 
    /root/.gvm/gos/go1.6.3/src/net/http/server.go:1472 +0xf2e fp=0xca67b47f98 sp=0xca67b47bd0 
runtime.goexit() 
    /root/.gvm/gos/go1.6.3/src/runtime/asm_amd64.s:1998 +0x1 fp=0xca67b47fa0 sp=0xca67b47f98 
created by net/http.(*Server).Serve 
    /root/.gvm/gos/go1.6.3/src/net/http/server.go:2137 +0x44e 

対応するソースコード:

PKG/apiserver/handlers.go

145 func RecoverPanics(handler http.Handler) http.Handler { 
146 return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { 
147 defer func() { 
148  if x := recover(); x != nil { 
149   http.Error(w, "apis panic. Look in log for details.", http.StatusInternalServerError) 
150   glog.Errorf("APIServer panic'd on %v %v: %v\n%s\n", req.Method, req.RequestURI, x, debug.Stack()) 
151  } 
152 }() 
153 defer httplog.NewLogged(req, &w).StacktraceWhen(
     httplog.StatusIsNot(
      http.StatusOK, 
      http.StatusCreated, 
      http.StatusAccepted, 
      http.StatusBadRequest, 
      http.StatusMovedPermanently, 
      http.StatusTemporaryRedirect, 
      http.StatusConflict, 
      http.StatusNotFound, 
      http.StatusUnauthorized, 
      http.StatusForbidden, 
      errors.StatusUnprocessableEntity, 
      http.StatusSwitchingProtocols, 
      http.StatusRequestTimeout, 
      errors.StatusTooManyRequests, 
     ), 
170).Log() 

    // Dispatch to the internal handler 
    handler.ServeHTTP(w, req) 
174 }) 
} 

PKG/HTTPLOG/log.go:

159 func (rl *respLogger) Log() { 
160 latency := time.Since(rl.startTime) 
161 if glog.V(2) { 
162  extraInfo := "" 
163  if latency >= time.Millisecond*200 && latency < time.Second { 
     extraInfo = fmt.Sprintf("%d00.Millisecond", latency/(time.Millisecond*100)) 
    } else if latency >= time.Second && latency < time.Minute { // Warning 
     extraInfo = fmt.Sprintf("%d.Second", latency/(time.Second)) 
    } else if latency >= time.Minute { // nce will timeout 
     extraInfo = fmt.Sprintf("%d.Minutes", latency/(time.Minute)) 
    } 
    method := rl.req.Method 
    if len(rl.req.Header["Detailed-Method"]) > 0 { 
     method = rl.req.Header["Detailed-Method"][0] 
    } 

    remoteIP := rl.getXForwardIPAdress(rl.req) 


    if !rl.hijacked { 
     //glog.InfoDepth(1, fmt.Sprintf("%s %s: (%v) %v%v%v [%s %s]", rl.req.Method, rl.req.RequestURI, latency, rl.status, rl.statusStack, rl.addedInfo, rl.req.Header["User-Agent"], rl.req.RemoteAddr)) 
180   glog.InfoDepth(1, fmt.Sprintf("%v %s %s: (%sms) %v%v [%s %s]-%s %v", rl.req.Header["X-Requestid"], method, rl.req.RequestURI, GetMilliLatency(latency), rl.status, rl.addedInfo, rl.req.Header["User-Agent"], remoteIP, extraInfo, rl.statusStack)) 
    } else { 
     //glog.InfoDepth(1, fmt.Sprintf("%s %s: (%v) hijacked [%s %s]", rl.req.Method, rl.req.RequestURI, latency, rl.req.Header["User-Agent"], rl.req.RemoteAddr)) 
     glog.InfoDepth(1, fmt.Sprintf("%v %s %s: (%sms) hijacked [%s %s]-%s", rl.req.Header["X-Requestid"], method, rl.req.RequestURI, GetMilliLatency(latency), rl.req.Header["User-Agent"], remoteIP, extraInfo)) 
    } 
} 

}

handler.ServeHTTPで、request.Headerを変更しました。理由を見つけることができません:

(1) "serveHTTP"と "defer log"は連続して動作します。存在しない "同時読み書き"

(2) "並行読み書き"が存在する場合でも、パニックに対処するための "recover" funcが存在するため、kube-apiserverは終了しません。

質問は私に多くの時間を要しました、誰が私を助けることができますか?ありがとう

+0

レースディテクタのヘルプですか? https://blog.golang.org/race-detector –

+0

ご協力ありがとうございます。私は、-raceオプションを付けてkube-apiserverをビルドし、それを実行しますが、何も起こらず、 "DATA RACE" bla blaはありません。 – Bling

+0

"レースディテクタはその設計上、実際にコードを実行することによって競合状態を検出できるため、現実的な作業負荷の下でレース対応バイナリを実行することが重要です。 そのパニックはただ私たちの "パフォーマンステストenv"で一度起こったもので、簡単に再現することはできません。 – Bling

答えて

0

私は、グローバルタイムアウトハンドラがリクエストに作用しているゴルーチンを実際に止めることができないと考えています。したがって、接続がタイムアウトすると(変更しない限り1m)、エラーが返されます。ゴルーチンが実際に同時に完了すると、接続に書き込むこともできます。これを防ぐためにロックを追加したと思っていましたが、ヘッダーが常にロックによって保護されているとは限りません。クリーンソースツリーでこれを再現できる場合は、Kubernetes github repoで問題を提出してください。

+0

ご協力ありがとうございます。しかし、グローバルタイムアウトハンドラでは、タイムアウトが発生すると、リクエストヘッダを読み込んだり変更したりしません。そして、 "同時マップ読み書き"が起こった場所はちょうど "読み込み"操作をしています。 – Bling

+0

resthandler.goでは、私はそれを処理するときに要求するための自己定義ヘッダーを追加します。 req.Request.Header ["Detailed-Method"] = []文字列{"GET-" + scope.Resource.Resource} ログに出力されるメソッドがk8sではなくhttp-standardであるため、標準。しかし、私はそれが理由だとは思わない(彼らは連続している)。 ハンドラのリクエストを変更しないでください。それは簡単な問題を引き起こす可能性があります。 – Bling

関連する問題