|
副问题[/!--empirenews.page--]
这篇文章在medium上很火,作者以现实案例来说明,讲得很好。
我们常常传闻行使Go的goroutine和channel很轻易实现高并发,那是不是所有代码都放在goroutine中运行就可以实现高并发措施了呢?很显然并不是。这篇文章将教各人怎样一步一步写出一个简朴的, 高并发的Go措施。
正文
我在几家差异的公司从事反垃圾邮件,防病毒和反恶意软件的事变高出15年,此刻我知道这些体系最终会由于我们要天天处理赏罚大量数据而变得越来越伟大。
今朝,我是smsjunk.com的CEO和 KnowBe4的首席架构师,他们都是收集安详行业的公司。
风趣的是,在已往的10年里,作为一名软件工程师,我参加过的全部Web后端开拓大部门都是行使RubyonRails完成的。不要误会我的意思,我喜好 RubyonRails,我信托这是一个了不得的生态,可是过了一段时刻,你开始以 Ruby的方法思索和计划体系,忘了怎样高效和本来可以操作多线程、并行、快速执行和小的内存耗损来简化软件架构。多年来,我是一名C/C++,Delphi和 C#开拓职员,并且我刚开始意识到怎样正确的行使器材举办事变也许会有多伟大。
我对互联网中那些说话和框架战役并不太感乐趣,好比哪门说话更好,哪个框架更快。 我始终信托服从,出产力和代码可维护性首要取决于怎样简朴的构建办理方案。
题目
在处理赏罚我们的匿名监测和说明体系时,我们的方针是可以或许处理赏罚来自数百万端点的大量POST哀求。Web处理赏罚措施将收到一个JSON文档,该文档也许包括必要写入 AmazonS3的多个有用内容的荟萃,以便我们的 map-reduce体系稍后对这些数据举办操纵。
传统上,我们会思量建设一个事变层架构,操作诸如以下的技能栈:
- Sidekiq
- Resque
- DelayedJob
- ElasticbeanstalkWorkerTier
- RabbitMQ
- ...
并搭建2个差异的集群,一个用于web前端,一个用于worker,因此我们可以随意扩容呆板来处理赏罚即将到来的哀求。
从一开始,我们的团队就知道我们可以在Go中这样做,由于在接头阶段我们看到这也许是一个很是大流量的体系。我一向在行使Go,约莫快2年时刻了,并且我们也行使Go开拓了一些体系,可是没有一个体系的流量可以或许到达这个数目级。我们起首建设了几个struct来界说我们通过POST挪用吸取到的Web哀求,并将其上传到S3存储中。
- type PayloadCollection struct {
- WindowsVersion string `json:"version"`
- Token string `json:"token"`
- Payloads []Payload `json:"data"`
- }
-
- type Payload struct {
- // [redacted]
- }
-
- func (p *Payload) UploadToS3() error {
- // the storageFolder method ensures that there are no name collision in
- // case we get same timestamp in the key name
- storage_path := fmt.Sprintf("%v/%v", p.storageFolder, time.Now().UnixNano())
-
- bucket := S3Bucket
-
- b := new(bytes.Buffer)
- encodeErr := json.NewEncoder(b).Encode(payload)
- if encodeErr != nil {
- return encodeErr
- }
-
- // Everything we post to the S3 bucket should be marked 'private'
- var acl = s3.Private
- var contentType = "application/octet-stream"
-
- return bucket.PutReader(storage_path, b, int64(b.Len()), contentType, acl, s3.Options{})
- }
Naive的做法-硬核行使Goroutine
最初,我们对POST处理赏罚措施举办了很是简朴粗暴的实现,将每个哀求直接放到新的goroutine中运行:
- 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)
- }
对付一样平常的并发量,这着实是可行的,但这很快就证明不能合用于高并发场景。我们也许有更多的哀求,当我们将第一个版本陈设到出产情形时,我们开始看到的数目级并不是云云,我们低估了并发量。
上述的要领有几个题目。没有步伐节制正在事变的goroutine的数目。并且,因为我们每分钟有100万个POST哀求,以是体系很快就瓦解了。
重来
(编辑:湖南网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|