快捷搜索:  汽车  科技

低功耗通信网络布局:世界上最大的实时

低功耗通信网络布局:世界上最大的实时2016年1月首次推出测试版时,我们决定用托管解决方案来试水。当时Pubnub是最佳选择。但由于信息量巨大,如果继续使用Pubnub,我们将会损失数百万美元。所以在一个月内,我们开始探索开源解决方案。那么,我们是如何从5000条扩到12万条消息,再到1000万条?2016年,我们用Node构建了引用流转化器,好不容易才扩展到每秒12万条消息。2017年3月,我们进入股市之后,需要将其扩展到每秒发送1000万条信息。Node解决方案根本无法完成。我们当时真的束手无策。即便是一些熟悉的技术(比如Ruby、Node.js、Python、 Java)也无法实现扩展。我们必须从零设计构建,当时尝试了Erlang、Elixir和Golang,并决定深入探寻Golang的未知领域,解决这一棘手问题。历史沿袭

全文共2131字,预计学习时长6分钟

低功耗通信网络布局:世界上最大的实时(1)

图源:unsplash

世界上最大的实时、高频、低延迟流媒体系统,每秒钟发送300多万条消息,每月发送13200多亿条消息,这些信息被视作引用流转化器(Quotes Streamers)。本文就将讨论该庞大系统的演变及设计过程。

需求使然

2016年,我们用Node构建了引用流转化器,好不容易才扩展到每秒12万条消息。2017年3月,我们进入股市之后,需要将其扩展到每秒发送1000万条信息。Node解决方案根本无法完成。

我们当时真的束手无策。即便是一些熟悉的技术(比如Ruby、Node.js、Python、 Java)也无法实现扩展。我们必须从零设计构建,当时尝试了Erlang、Elixir和Golang,并决定深入探寻Golang的未知领域,解决这一棘手问题。

历史沿袭

那么,我们是如何从5000条扩到12万条消息,再到1000万条?

2016年1月首次推出测试版时,我们决定用托管解决方案来试水。当时Pubnub是最佳选择。但由于信息量巨大,如果继续使用Pubnub,我们将会损失数百万美元。所以在一个月内,我们开始探索开源解决方案。

从头开始构建系统并不容易。我们探索了所有可能的替代方案,年底,Faye消息系统因其操作简易和轻量级Bayeux协议最后成为首选。

然而,在使用Faye的10个月之后,我们又再次陷入困境。Redis命令的限制是每秒15万次读写。而Faye使用Redis经常超过这个限制,迫使频繁重启。这时我们决定分流Faye,更好地执行Redis命令,我们还扩展了Faye从而利用Redis集群的水平扩展。

仅仅6个月,这种方法也行不通了。资源消耗巨大,水平扩展只能在少数机器上实现。

事已至此,我们决定自己构造系统。在对用例进行了一个月的基准测试之后,我们选择了Golang,而不是Erlang和Elixir。

到2017年底,奇迹出现了。Golang让我们尽可能轻松地实现了水平扩展,在接下来的两年里,我们没怎么进行修复就从18万扩展到300万。到了2020年底,这种方法仍然可行!我们相信它可以在2021年轻而易举扩展到1000万条以上,甚至更多。

低功耗通信网络布局:世界上最大的实时(2)

低功耗通信网络布局:世界上最大的实时(3)

即发即弃

系统中,信息每几毫秒就会更新一次,几秒钟前的东西会变得毫无价值,这也是我们选择在不进行任何类型的存储或缓存的情况下进行设计的原因,这极大地提高了可扩展性。由于以前在Redis上遇到问题,所以我们决定不使用任何内存,除了进程内存。

保持顺序

每条消息其实都是一笔被执行的交易,最新的消息就是最后的交易价格。千万不能把顺序搞乱。

我们最初的想法是保持服务器上的顺序。但是,在高度并发的系统中,任何维持顺序或状态的机制都会给扩展带来阻碍。所以我们选择在客户端进行排序。每条消息都有一个时间戳,客户端只需要舍弃旧消息。

以经典Market Pulse的方式,我们找到了一个非常合适的简单解决方案,这也是为什么引用流转化器运行快的一个关键原因。

低功耗通信网络布局:世界上最大的实时(4)

无DNS或负载平衡器(LBs)

我们决定把LB放在客户端,在Market Pulse的服务器端不使用DNS或LBs。我们的ADN使用简单的循环算法向客户端提供可用服务器列表,从而实现负载平衡。将LB放在QS客户端上,原因有四:

· 最小化跳数

· 尽量减少故障点(即使DNS和LBs出现故障,我们也无法承担后果)

· 在3秒内实现即时故障转移

· 健康检查可靠

我们并不只是依靠服务器启动或简单的心跳机制,不然可能会与上游防火墙断开连接。我们对客户端的健康检查可以确保客户端真正得到想要的消息。

无共享架构

我们希望能够轻而易举地扩展到100台服务器。为此,我们确保每个实例都是完全独立的。

一切都在进程内存中

在设计时,我们确保在存储或任何内存缓存中不保留任何内容。一切都存储在进程内存中。一个进程总会终止,没错,但我们只是把系统设计为可以容错。如果进程终止,就重新创建该进程。当然,用户数据和历史消息记录会丢失。但是没关系,客户端会在3秒内重新连接到另一台正常的服务器。

而这个新进程只是集群的新成员。没有消息历史记录,也没有要从要历史列表中恢复的用户列表。

Golang

我非常喜欢Elixir,它可以很好地实现该操作。但是在基准测试中,在这个特殊用例面前,它的表现却始终无法超越Golang。如果我们需要分布式的发布订阅或渠道,Elixir会更适合。但鉴于我们使用了无共享架构,Golang是满足当前需求的理想选择。

在未来,我们也期待能有其他的开源解决方案。

低功耗通信网络布局:世界上最大的实时(5)

留言点赞关注

我们一起分享AI学习与发展的干货

如转载,请后台留言,遵守转载规范

猜您喜欢: