這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
最近使用go寫了一個爬蟲監控系統,每秒大概處理十次請求,得到資料後進行資料庫處理,並將資料轉寄給websocket到前端展示。
開始測試的時候沒有問題,但是一上線接受真是資料時就會運行半小時後出現無法響應服務還有出了我有一句列印請求的body在列印資訊我的其他邏輯全部沒有運行了,最開始百思不得其解。
最開始My Code是這樣子的:
func (this *MainController) Post() { defer this.Ctx.Request.Body.Close() body, err := ioutil.ReadAll(this.Ctx.Request.Body) fmt.Println(string(body)) go RecodeBody(body) if err == nil && body != nil { models.Messages <- body: this.Data["json"] = "ok" } else { this.Data["json"] = "fail" } this.ServeJSON()}
然後我再RecodeBody()方法中進行一些邏輯處理之後並在資料庫操作之前也有可能向models.Messages中寫入。
models.Messages 是一個有1000緩衝的channel並是轉寄訊息到websocket的緩衝。
在第一次實際資料測試時運行半小時後出現只答應請求body的情況之後思考了半天終於找到了問題的所在:
問題出在了當向websocket寫入資訊時如果因為網路或者串連數較多時可能一條訊息要花比接受一天訊息的時間去處理,等到半個小時的時候channel的緩衝裝滿了,導致堵塞,於是this.ServeJSON()不能運行所以無法返回資訊。然後應為我的邏輯處理函數中也會向channel寫入資訊,也導致堵塞。所以導致了我伺服器約等於死點的假象。
我想導致我遇到這個問題的主要原因是自己對go channel的不夠瞭解還有寫代碼時急於實現功能而沒有去注意代碼的邏輯與品質。
知道了問題所在問題總是好解決的,於是我把給Messages發送訊息全部交給了RecodeBody()函數,並也通過一個channel給它船體資料,並給這個channel發送資訊加上default以避免堵塞。
func (this *MainController) Post() { defer this.Ctx.Request.Body.Close() body, err := ioutil.ReadAll(this.Ctx.Request.Body) fmt.Println(string(body)) if err == nil && body != nil { select { case models.PS <- body: this.Data["json"] = "ok" default: this.Data["json"] = "server is busy" } } else { this.Data["json"] = "fail" } this.ServeJSON()}
這樣子就無論如何都不會出現無響應的情況,除非你的機器實在是受不了那麼大的並發量。
總結:
在處理有一定並發量的時候使用channel時,寫入資訊到channel時勁量使用
select {
case models.PS <- body:
this.Data["json"] = "ok"
default:
this.Data["json"] = "server is busy"
}
格式,以免當channel因為消費不及時導致緩衝用光的情況而沒有提示資訊,讓你不好追溯問題所在。