var acl = s3.Private
var contentType = "application/octet-stream"
return bucket.PutReader(storage_path, b, int64(b.Len()), contentType, acl, s3.Options{})
}
本地Go routines方法
刚开始 , 我们采用了一个非常本地化的POST处理实现,仅仅尝试把发到简单go routine的job并行化go语言并发请求器:
func payloadHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
// Read the body into a string for json decoding
var content = PayloadCollection{}
err := json.NewDecoder(io.LimitReader(r.Body, MaxLength)).Decode(content)
if err != nil {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusBadRequest)
return
}
// Go through each payload and queue items individually to be posted to S3
for _, payload := range content.Payloads {
go payload.UploadToS3()// ----- DON'T DO THIS
}
w.WriteHeader(http.StatusOK)
}
对于中小负载 , 这会对大多数的人适用,但是大规模下,这个方案会很快被证明不是很好用 。我们期望的请求数,不在我们刚开始计划的数量级,当我们把第一个版本部署到生产环境上 。我们完全低估了流量 。
上面的方案在很多地方很不好 。没有办法控制我们产生的go routine的数量 。由于我们收到了每分钟1百万的POST请求,这段代码很快就崩溃了 。
再次尝试
我们需要找一个不同的方式 。自开始我们就讨论过 , 我们需要保持请求处理程序的生命周期很短 , 并且进程在后台产生 。当然,这是你在Ruby on Rails的世界里必须要做的事情,否则你会阻塞在所有可用的工作 web处理器上 , 不管你是使用puma、unicore还是passenger(我们不要讨论JRuby这个话题) 。然后我们需要利用常用的处理方案来做这些,比如Resque、 Sidekiq、 SQS等 。这个列表会继续保留,因为有很多的方案可以实现这些 。
所以,第二次迭代,我们创建了一个缓冲channel,我们可以把job排队,然后把它们上传到S3 。因为我们可以控制我们队列中的item最大值,我们有大量的内存来排列job,我们认为只要把job在channel里面缓冲就可以了 。
var Queue chan Payload
func init() {
Queue = make(chan Payload, MAX_QUEUE)
}
func payloadHandler(w http.ResponseWriter, r *http.Request) {
...
// Go through each payload and queue items individually to be posted to S3
for _, payload := range content.Payloads {
Queue - payload
}
...
}
接下来,我们再从队列中取job,然后处理它们 。我们使用类似于下面的代码:
func StartProcessor() {
for {
select {
case job := -Queue:
job.payload.UploadToS3()// -- STILL NOT GOOD
}
}
}
说实话 , 我不知道我们在想什么 。这肯定是一个满是Red-Bulls的夜晚 。这个方法不会带来什么改善,我们用了一个 有缺陷的缓冲队列并发,仅仅是把问题推迟了 。我们的同步处理器同时仅仅会上传一个数据到S3,因为来到的请求远远大于单核处理器上传到S3的能力,我们的带缓冲channel很快达到了它的极限,然后阻塞了请求处理逻辑的queue更多item的能力 。
我们仅仅避免了问题,同时开始了我们的系统挂掉的倒计时 。当部署了这个有缺陷的版本后 , 我们的延时保持在每分钟以常量增长 。
最好的解决方案
我们讨论过在使用用Go channel时利用一种常用的模式,来创建一个二级channel系统 , 一个来queue job , 另外一个来控制使用多少个worker来并发操作JobQueue 。
推荐阅读
- jquery的放大镜特效,web放大镜效果
- html5中bootstrap用法,html5 bootstrap
- 用java写冰墩墩的源代码,冰墩墩 知乎
- 男运动棉袜子直播卖货话术,直播卖袜子怎么介绍
- vb.net填充字符串 vb 字符串赋值
- 怎么看显卡是否锁定,怎么看显卡功率多少w
- 我的世界国外行尸走肉服务器,我的世界外服行尸走肉服务器
- 关于python函数四类的信息
- element转jquery,ELEMENT品牌