LoginSignup
8
1

More than 5 years have passed since last update.

Go Panic でパニック

Last updated at Posted at 2018-12-13

streampack の Tana です。

streampack ではライブの一機能の一つで Websocket を使ってユーザーとインタラクティブなやり取り機能を提供してます。

Websocket はコネクションを貼り続けるため、 Maximum接続数の閾値テストしているとたまに落ちることがありました。

goroutine 5774 [running]:
runtime.throw(0xe2c371, 0x15)
/usr/lib/golang/src/runtime/panic.go:605 +0x95 fp=0xc4234a76f0 sp=0xc4234a76d0 pc=0x42c0d5
runtime.mapassign_fast64ptr(0xcfcc20, 0xc420320180, 0xc423490280, 0xc42334dc00)
/usr/lib/golang/src/runtime/hashmap_fast.go:695 +0x3d2 fp=0xc4234a7750 sp=0xc4234a76f0 pc=0x40e452
main.websocketHandler(0x7fd1be198e18, 0xc42325d3f0, 0xc42334dc00)
... 

急に負荷をかけすぎたため、たまたまかなと思いつつも、また再現。

エラーも大量にエラーが出て追いにくく、うーんと悩んでたところ、

fatal error: concurrent map writes

と出てました。

どうも、同時に map を書き込みに関するエラー のようです

よくよく調べてみると、

Maps are not safe for concurrent use: it's not defined what happens when you read and > write to them simultaneously. If you need to read from and write to a map from concurrently executing goroutines, the accesses must be mediated by some kind of synchronization mechanism. One common way to protect maps is with sync.RWMutex.

ソース: source: https://blog.golang.org/go-maps-in-action

他にも同様な経験されたケースが多々ありました。

つまり、map を操作する場合は sync.RWMutex などのライブラリを使って、
Read/Write する際は排他的に Lock/Unlock する必要がありました。

var clients = make(map[*websocket.Conn]bool)
var ClientMutex struct {
  sync.Mutex
}

ClientMutex.Lock()  // ロック
clients[ws] = true
ClientMutex.Unlock() // アンロック

また、下記のように -race オプションをつけると Warning でアドバイスしてくれます。

$ go run -race main.go

goroutine 内でごにょごにょ map を Read/Write している場合は注意しましょう。

8
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
1