最近使用go写了一个爬虫监控系统,每秒大概处理十次请求,得到数据后进行数据库处理,并将数据转发给websocket到前端展示。
开始测试的时候没有问题,但是一上线接受真是数据时就会运行半小时后出现无法响应服务还有出了我有一句打印请求的body在打印信息我的其他逻辑全部没有运行了,最开始百思不得其解。
最开始我的代码是这样子的:
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因为消费不及时导致缓存用光的情况而没有提示信息,让你不好追溯问题所在。
有疑问加站长微信联系(非本文作者)