這是一個類似 ELK 的 monitor,他可以很輕鬆的建置並偵測到 CPU & Memory 等 Matrix 的資訊,如果是自己的 side project 很推薦使用,因為他有 100GB 每月使用量,比起你自架來得省事省時間。但 ELK 也是很推薦,畢竟是 open source 但需要考慮的事情就會變多,ex database storage size, data rotation time, Infra Problems。
packagearticleimport ("fmt""sync""testing")typeMutexChannelExamplestruct { lock sync.Mutex ArrInt []int updated chanbool}func (m *MutexChannelExample) InsetValue(val int) { m.lock.Lock()defer m.lock.Unlock() m.ArrInt =append(m.ArrInt, val) m.updated <-true}func (m *MutexChannelExample) ReadValue() int { m.lock.Lock()defer m.lock.Unlock()return m.ArrInt[len(m.ArrInt)-1]}funcTestMutexChannelExample(t *testing.T) { m :=&MutexChannelExample{ ArrInt: make([]int, 0), updated: make(chanbool), }gofunc() {for<-m.updated {// When m.ReadValue() is called, it will lock. However, in// line 44, m.InsetValue inputs a bool into the channel. // Consequently, line 19 waits for the value to be // retrieved and released, triggering another call to // m.ReadValue(), which results in a deadlock. fmt.Println(m.ReadValue()) } }()for i :=0; i <10; i++ { m.InsetValue(i) fmt.Println("do once ===>") }}
CPU & RAM usage is high, but it is expected to be low
在使用 Time 套件的時候,需要非常小心,以time.Tick為例,當他沒有被執行完成的時候,不會觸發 garbage recycle 所以cpu 不會被release 因此 cpu memory 都不會因為func結束而釋出資源。
packagearticleimport ("fmt""runtime""testing""time")typeTickUsageExamplestruct {}func (e *TickUsageExample) RaiseGoroutine(c chanbool) {gofunc() { time.Sleep(time.Microsecond *900) c <-true }()select {case<-time.Tick(time.Second):returncase<-c:return }}funcTestTickUsageExample(t *testing.T) { forever :=make(chanbool) ex :=TickUsageExample{}for i :=0; i <1; i++ {go ex.RaiseGoroutine(make(chanbool)) } fmt.Println("goruntine number:= ", runtime.NumGoroutine()) time.Sleep(time.Second) fmt.Println("goruntine number:= ", runtime.NumGoroutine())<-forever}
Linux Out-Of-Memory Killer
當我們使用記憶體,到達os 的上限的時候,linux os 會將最不健康的 process 刪除,因此要注要在使用Goroutine的時候,需要考慮到他的記憶體使用率,以免踩到!
packagearticleimport ("sync""testing""time""github.com/panjf2000/ants/v2")funcTestPool(t *testing.T) {var wg sync.WaitGroup// it can adjusted the pool size, expired_time, log... a lots of opts. pool, _ := ants.NewPool(10, ants.WithPreAlloc(true))for i :=0; i <100; i++ { pool.Submit(func() {defer wg.Done()var arr []string=make([]string, 100000) arr[0] ="test_str" time.Sleep(time.Second *10) }) wg.Add(1) } wg.Wait()}
Use to write the unit-test to find out the deadlock situation
預防或者發現Deadlock的狀況,最簡單的方式就是透過 unit-test ,透過測試容易使得這一類問題提早發現。Deadlock 往往都是在真的 program 上線了之後才會發現有這樣的問題。
How to find out:
Write the edge case for each func
撰寫Edge case test (極端測試) 在每一隻Goroutine程式,好處是可以去發現 deadlock的狀況,也比較能夠發現 Resource Usage (CPU, Memory) 的問題
Integration and Pression Test
整合測試與壓力測試實際上在軟體開發中非常重要,做這樣的測試的前提是,要使用 Monitor 工具,觀察每一個 Transaction (程式行為)的執行時間,還有執行片段。透過觀察Metrix的變化,是一個有效debug 的方式。