BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

可缩放RESTful通信新选择:用一台MigratoryData服务器模拟谷歌的搜索补全功能

| 作者 Mihai Rotaru 关注 0 他的粉丝 ,译者 大愚若智 关注 7 他的粉丝 发布于 2017年1月16日. 估计阅读时间: 14 分钟 | QCon北京2018全面起航:开启与Netflix、微软、ThoughtWorks等公司的技术创新之路!

亲爱的读者:我们最近添加了一些个人消息定制功能,您只需选择感兴趣的技术主题,即可获取重要资讯的邮件和网页通知

此文系转载,原作者为MigratoryData公司CTO Mihai Rotaru

对于需要实时通信的网站,使用RESTful HTTP请求响应方法可能显得极不高效。我们提出了一种新方法,并通过一种需要实时通信的功能对其进行了验证,这种功能已经众所周知,并在很多网站中有所运用:搜索框自动补全

作为最繁忙的搜索平台,根据Internet Live Stats估算,谷歌每秒钟大约要处理40,000次用户搜索。假设在每次搜索中自动补全功能产生6个请求,我们的实验表明MigratoryData只需一台1U服务器即可应对该负载。

准确来说,我们证明了通过1U服务器运行的一台MigratoryData服务器可以处理1百万并发用户产生的每秒240,000个自动补全请求,并实现平均11.82毫秒的往返延迟

当前采用的方法及其局限

自动补全功能可以在用户通过搜索框输入查询的过程中提供搜索建议。目前所用的方法主要基于HTTP请求-响应模式,用户每输入一个字符,均需要向Web服务器发送一次HTTP请求,并通过HTTP响应获得搜索建议。这种方法有两个局限:带宽和延迟。

一方面,由于每个自动补全请求只包含少量字节(例如用户在搜索框中输入的字符),但浏览器会自动添加数百字节内容作为HTTP标头。对于用户搜索活动频繁的网站,大量额外的数据意味着带宽的巨大浪费,同时还需要耗费额外的CPU周期以处理这些不必要的HTTP标头。

另一方面,对于每个HTTP请求,都需要在用户和Web服务器之间新建一个TCP连接,甚至可能需要进行TLS/SSL握手。随着用户输入每个字符都进行这样的操作会对延迟产生极高影响(例如用户输入一个字符到看到搜索结果之间的等待时间)。为了消除这种局限可以使用HTTP保活(Keep-Alive)连接,借此在一次超时期间通过同一个TCP连接发送多个HTTP请求。然而尽管如此,当超时值到期后依然需要新建连接。

另一种新方法

为了解决上文提到的RESTful HTTP方法所面临的局限,很多人选择使用WebSocket协议代替HTTP。WebSocket协议在开销方面只增加几字节数据,因此相比HTTP协议数百字节的数据增量,可大幅降低开销。更重要的是,WebSocket协议按照设计可使用持久连接,无需定期重连,可实现更低延迟的通信。

目前有很多WebSocket协议的服务器实现,然而相比RESTful HTTP方法,这些实现在带宽优化方面做的都略显不够,并非所有WebSocket服务器实现能提供同等程度的低延迟和可缩放性。

注意 – 相比Web服务器,WebSocket协议本身无法保证服务器能获得更好缩放性或更低延迟,该协议只能提供实现这些特性的前提。缩放性和延迟的程度取决于具体的WebSocket服务器实现。

MigratoryData Server就是一种此类WebSocket服务器实现。该产品是成功解决C10M问题(单一服务器上千万并发用户)的首个服务器实现

MigratoryData提供了一套通用API,并为大部分主流编程环境,包括Web应用程序提供了所需的库。该产品可暴露一种基于主题(Subject)的发布/订阅通信范式,根据所采用的发布/订阅模式,还可暴露下列异步请求/响应模型:

  • 一个生成方订阅至主题X
  • 消耗方发送包含主题X的请求消息并附加回复主题Y(如果尚未订阅,消耗方可自动订阅主题Y)
  • 生成方收到该消息后,从请求消息中提取出回复的主题Y,并使用包含主题Y的消息作为回复

下文我们将展示这种通过WebSocket实现的请求/响应交互如何作为可缩放的方法取代RESTful HTTP。

性能评测环境配置

我们使用了四台完全相同的计算机,每台装备2颗2.60GHz主频Intel Xeon E5-2670 CPU,以及64GB内存:

  • 计算机A运行一个MigratoryData Server 5.0.20实例
  • 计算机B和计算机C运行两个Requestor工具实例,分别用于打开500,000个并发WebSocket连接,自动补全请求将通过这些连接发送
  • 计算机D运行16个Provider工具实例,用于为每个自动补全请求提供搜索建议

四台计算机均运行CentOS Linux 7.2,使用默认的3.10.0-327.28.3.el7.x86_64内核,未进行任何内核调优。

为了模拟一百万用户中的一位用户N发送一条自动补全请求,Requestor工具会随机选择十六个Provider所订阅的某一主题,例如/s/M。此外Requestor工具会将用户N订阅至主题/c/N(如果尚未订阅),并将具备下列属性的请求消息发布至MigratoryData Server:

  • 主题:/c/N
  • 主题:/s/M
  • 载荷:一个代表搜索查询的32字节随机字符串

订阅至主题/s/M的Provider M将收到上述消息,通过向MigratoryData Server发布具备下列属性的回复消息即可作出回应:

  • 主题:/c/N
  • 载荷:一个代表搜索建议的256字节随机字符串

由于用户N已订阅至主题/c/N,便可收到上述回复信息。往返延迟将按照请求消息的创建完成到用户最终收到回复信息之间的时间差来计算。

注意 – 请求-回复通信的往返延迟包含请求消息从Requestor传递至MigratoryData Server,随后传递至Provider所需的时间,外加回复消息从Provider传递至MigratoryData Server,并最终传递至Requestor所需的时间。

最后需要注意,在上述环境中,有多个代表搜索服务的Provider实例对请求进行均衡。该架构使得搜索服务(包括其搜索缓存)能够横向缩放并模拟RESTful HTTP方法,此外还可通过多个搜索服务对请求进行均衡。

结果总结

每秒钟,两个Requestor实例为从一百万并发用户中随机选择出的240,000个用户处理240,000个自动补全请求,获得搜索建议所需的平均往返延迟为11.8毫秒,其中第95百分位(95th percentile)延迟为20毫秒,第99百分位(99th percentile)延迟为130毫秒(通过超过40亿个请求的结果计算而来)。

指标

数据

并发WebSocket连接数

1,000,016

订阅主题数

1,000,016

每秒请求数

每秒请求240,000条消息

消息总吞吐率(Requestors与Providers收和发)

每秒960,000条消息

平均延迟

11.82毫秒

标准偏差延迟

26.28毫秒

第95百分位延迟

20毫秒

第99百分位延迟

130毫秒

最大延迟

1783毫秒

请求总数

4,084,890,291

硬件

一台1U服务器,装备2颗2.60GHz主频Intel Xeon E5-2670 CPU与64GB内存,Intel X520-DA1 10 GbE网络适配器

操作系统

CentOS Linux 7.2,默认内核3.10.0-327.28.3.el7.x86_64(未进行内核调优)

Java运行时环境

Oracle 1.8.0_40-b25

入站网络利用率(Providers与Requestors总和)

每秒1.06Giga字节

出站网络利用率(Providers与Requestors总和)

每秒1.17Giga字节

CPU利用率

65%

结果

MigratoryData Server可通过JMX和其他协议进行监视。我们使用jconsole工具(包含在Java Development Kit中)进行JMX监视。下列屏幕截图截取自JMX监视过程。

连接和消息

正如评测环境介绍中所述,我们通过两个Requestor实例创建了1,000,000个到MigratoryData服务器的并发WebSocket连接,借此模拟一百万用户。以百万用户中的每个均订阅至不同的主题,随后通过这些主题获得搜索建议。此外我们使用16个Provider实例打开16个到MigratoryData服务器的连接,借此模拟搜索建议服务。这16个服务中的每个均订阅至不同主题,借此响应自动补全请求。如下图所示,JMX的ConnectedSessions属性也显示出共有1,000,016个并发连接。

在评测环境中,用户每秒发出240,000条请求消息。因此每秒传入MigratoryData服务器的消息总数包含来自Requestors的每秒240,000条请求消息,外加来自Providers的每秒240,000条回复消息。

另外每秒传出MigratoryData服务器的消息总数为每秒发送给Requestors的240,000条回复消息,外加每秒发送给Provides的240,000条请求消息。

这些总数(每秒480,000条传出消息外加每秒480,000条传入消息)对应了下列截图中JMX的OutPublishedMessagesPerSecond和InPublishedMessagesPerSecond属性。

因此MigratoyData Server处理传入和传出消息的总吞吐量约为每秒1百万条消息

最后需要注意,该性能评测是在大致5小时内进行完毕的。按照每秒240,000个请求的速度,MigratoryData共处理了超过40亿个请求!

CPU和内存利用率

从截图中可以看到,评测过程中CPU用量始终低于70%。分配给JVM的内存最大值为30GB。最后,由于整个评测是在大约5小时内进行的,因此内存和CPU用量均呈现出规律性变化。

延迟

如上文评测环境介绍中所述,往返延迟是请求从Requestor传递至MigratoryData服务器,后传递至Provider所用时间,外加回复消息从Provider传递至MigratoryData服务器,并最终传递至Requestor所用时间总和。

从该评测中我们计算了每个请求/回复交互的往返延迟,共得出超过40亿个延迟值。此外我们还计算了延迟的平均值、标准偏差,以及最大延迟值。这些有关延迟的统计信息会随着每次新产生的请求/回复交互递增,结合超过40亿个延迟值汇总计算而来。简单总结延迟情况如下:

  • 平均延迟:11.82毫秒
  • 标准偏差延迟:26.28毫秒
  • 最大延迟:1783毫秒

另外我们还使用HdrHistogram库计算了延迟的百分位数。在下图中可以看到请求数(百万计)和往返延迟(毫秒计)在不同百分位下的分布。

例如在上图中可以看到,第95百分位的延迟为20毫秒,第99百分位延迟为130毫秒。因此对于共40亿请求中的38亿个请求,往返延迟均低于20毫秒;而对于共40亿个请求中的39.6亿个请求,往返延迟均不超过130毫秒。

注意 – 通过进一步优化还可降低第99以及更高百分位的延迟。这些值通常会受到JVM垃圾回收机制的影响。在之前针对另一个场景进行的性能评测中我们发现,使用Azul Systems的Zing JVM对垃圾回收进行优化后,可以将第99百分位的延迟从585毫秒降低至25毫秒,最大延迟值则从1700毫秒降低至126毫秒。

结论

本文中,我们为有大量用户、高频请求,以及/或需要低延迟通信的网站提出了一种新的通信架构,并通过搜索框自动补全功能这个用例进行了证实。

我们发现可缩放的WebSocket服务器提供了更易用的编程模型,例如发布-订阅,可以很好地取代目前所采用的RESTfull HTTP架构,在延迟和带宽使用方面均有更出色的表现,同时在编程的复杂度方面也基本持平。

作者Mihai Rotaru阅读英文原文A Scalable Alternative To RESTful Communication: Mimicking Google’s Search Autocomplete With A Single MigratoryData Server

 


感谢陈兴璐对本文的审校。

给InfoQ中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家通过新浪微博(@InfoQ@丁晓昀),微信(微信号:InfoQChina)关注我们。

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我
社区评论

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT