[原创翻译]go语言并发一分钟处理一百万请求

首先给出 原文链接.
网上有很多该文章的翻译版本,但是笔者认为机翻痕迹严重,并不利于新手阅读理解
笔者觉得此文写的通俗易懂,言简意赅,于是打算翻译出来供go服务器新手学习参考,好了废话不说,开始正文

在Malwarebytes的工作让我经历的惊人的成长,一年前,在我加入这家公司之前,我在硅谷的主要工作内容就是定制解决方案,以应对快速增长的公司每天数百万的使用频率。我已经在不同的公司从事反病毒和反恶意软件行业工作了12年,我知道这些系统的复杂程度取主要决于我们每天要处理多大量数据。

有趣的是,在过去的9年当中,我从事的所有网站开发都是在Ruby on Rails的方案下实施的。不要误会我的意思,我非常热爱 Ruby on Rails,我认为这是一个令人惊奇的开发方案。但是在一段时间以后,当你开始用Ruby on Rails的思路去思考和设计系统,你就会忘记那些可以利用的多线程、并行,快速执行和小的内存开销的解决方案,而这些将会使你开发的软件高效和简洁。多年来,我一直是一个C / C++、Delphi和C #开发者,我开始意识到,当你使用适合的工具时,事情会是多么的简洁。

作为一个架构师,我不是很在意那些网站之间的关于语言和框架之间孰优孰劣的纷争。我相信,效率,生产力和代码的可维护性主要依赖于如何简单的构建你的解决方案。

一个难题

当我们在进行一个匿名的测试和分析系统时,我们的目标是能够处理来自数百万端点的大量POST请求。web处理程序将接收一个包含众多数据集合的JSON文档,它们将被写入Amazon S3数据库,以供我们的大数据系统进行后续操作

面对这样的需求,通常我们会考虑诸如:
Sidekiq
Resque
DelayedJob
Elasticbeanstalk Worker Tier
RabbitMQ
等等框架和方案...
并且,我们会设置2个不同的集群,一个用于Web前端,另一个用于后台服务,这样我们就可以通过增加减少后台服务器的数量来控制我们能够处理的请求数。但是,从一开始我们的团队就决定采用Go语言作为开发方案,因为经过讨论,我们发现这将会是一个非常庞大的系统。我们已经从事Go语言开发两年,在工作中设计架构了一些系统,但是还没有任何一个系统有如此庞大的数据量。

我们首先创建了一些结构体来定义POST的request中内容,以及一个上传到S3库的方法。

p1.png

小试牛刀

最初我们采取了一个非常简单的POST请求处理实现方案,尝试简单并发goroutine去处理任务

p2.png

对于中等的负载量,这个方案可以满足大多数人的需求。但是当数据量增大的时候,它开始显得不那么好用了。在第一版投入生产环节中,我们预估了一下request的数量,事实上我们完全低估了这个庞大的数据量。

上面的方案在有很多弊端,首先我们无法控制开启的goroutine数量,然后,当请求达到每分钟一百万次的数量级,很快这段代码就崩溃了。

再次尝试

我们需要一个新方案,在一开始的讨论中,我们明确了几点,首先要保证request handler 的生命周期足够短,其次要做到在后台进行异步并发处理。显然如果采用Ruby on Rails的方案,这些都是必要的事情,不然就会阻塞整个网络。那么,我们将不得不采取一些常见的方案来解决这个事情比如使用 Resque, Sidekiq, SQS等等。

所以,第二次迭代的任务就是创建一个用于缓存列队的通道,用来缓存请求,并将它们逐一存入S3服务器。因为我们可以控制队列通道内的最大容量,并且我们有足够大的内存来缓存队列,我们认为这将会一个是极好的方案。


p3.png

然后,为了将任务列队并依次处理,我们用了如下面这样的代码


p4.png

老实的讲,我并不知道我们在想些什么。这将会是一个充满红牛的不眠之夜。这个方案并没有给我们带来任何改进。我们用一个缓存列队代替了有缺陷的并发方案,这仅仅是推迟了问题的产生时间而已。我们的同步处理器每次只能上传一分数据到S3,而队列中传入请求的速度远大于处理器上传数据到S3的数据,很快的我们的队列就达到了极限,从而阻塞了后续的请求添加到队列。我们仅仅简单的去回避问题,这仅仅是开启了一个系统崩溃死亡的倒计时。

p5.png

更好的方案

当我们使用Go的通道时,我们决定利用一个公共模式来创建一个双层的通道系统。一个用来队列任务,而另一个则是控制当前处理队列任务的线程数量。

这个想法是要采用一个合理的可持续的速率并行的上传数据到S3服务器,既不会阻塞服务器的性能,也不会从S3服务器获取上传失败的错误回调。因此,我们构建一个job/worker模型,这看起来有些像Java, C#,等等,而我们则是考虑通过Golang的方式,利用通道来代替它们,去实现一个处理器线程池。

p6.png
p7.png

我们已经修改了我们的网路请求handler来创建一个包含载荷数据的任务实例,我们将它发送到任务队列通道中去,供处理线程们去处理。

p9.png

当我们的网络服务器在初始化的过程中,我们创建了一个名叫Run()的调度器来创建worker线程池,并且开始监听发送到任务队列中的任务。

p11.png

下面是我们调度器的代码实现

p12.png

值得注意的是,我们提供了最大处理线程的并发数量,用来实例化任务处理线程并且将他们添加到我们的任务处理线程池当中。我们使用亚马逊的Elasticbeanstalk服务并且采用了docker化的Go 运行环境,而且我们总是尝试遵循 12要素的方法论(译者注:应该是一种广泛认可的架构设计思路,虽然我没听说过)来配置我们在生产环境中的系统,我们通过环境变量来读取这些值。这样我们就可以控制处理线程数量和任务队列通道的所能承载的最大容量,因此,我们可以快速的改变这些配置而不用重新部署服务器集群

p15.png

最直观的结果

在我们部署完它之后,我们立即发现所有的延迟率都降到了微不足道的数量,我们处理请求的能力激增。


p17.png

在经历了几分钟弹性的负载均衡热身之后,我们看到,我们的ElasticBeanstalk应用每分钟接近响应了一百万的请求。

在我们部署了新代码之后,服务器的数量大幅下降,从100台服务器降到20台服务器。


p19.png

结论

在我的故事中,极简主义总是获胜的一方。我们可以设计一个复杂的系统,具有许多队列,异步的后台处理,复杂的调度,但是我们决定利用Elasticbeanstalk的自动缩放的高效的简洁的能力去实现Golang提供给我们的并发效果。
你并不是每天需要部署一个4服务器的集群,来给亚马逊的S3服务器每分钟写入100万次。
总会有一个合适的工具来解决问题,有时,当你的Ruby Rails系统需要一个功能强大的Web处理程序时,可以稍微考虑一下Ruby生态系统之外的更简单、更强大的替代解决方案。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容