加入收藏 | 设为首页 | 会员中心 | 我要投稿 应用网_丽江站长网 (http://www.0888zz.com/)- 科技、建站、数据工具、云上网络、机器学习!
当前位置: 首页 > 综合聚焦 > 编程要点 > 语言 > 正文

成人网站性能提升20倍之经验谈

发布时间:2016-09-27 11:29:05 所属栏目:语言 来源:伯乐在线
导读:副标题#e# 色情业是个大行业。互联网上没有多少网站的流量能和最大的色情网站相匹敌。 要搞定这巨大的流量很难。更困难的是,在色情网站上提供的很多内容都是低延迟的实时流媒体而不是简单的静态视频。但是对于所有碰到过的挑战,我很少看到有搞定过它们的
副标题[/!--empirenews.page--]

色情业是个大行业。互联网上没有多少网站的流量能和最大的色情网站相匹敌。

要搞定这巨大的流量很难。更困难的是,在色情网站上提供的很多内容都是低延迟的实时流媒体而不是简单的静态视频。但是对于所有碰到过的挑战,我很少看到有搞定过它们的开发人员写的东西。所以我决定把自己在这方面的经验写出来。

问题是什么?

几年前,我正在为当时全世界访问量排名26的网站工作 — 这里不是说的色情网站排名,而是全世界排名。

当时,该网站通过RTMP(Real Time Messaging protocol)协议响应对色情流媒体的请求。更具体地说,它使用了Adobe的FMS(Flash Media Server)技术为用户提供实时流媒体。基本过程是这样的:

用户请求访问某个实时流媒体 服务器通过一个RTMP session响应,播放请求的视频片段

因为某些原因,FMS对我们并不是一个好的选择,首先是它的成本,包括了购买以下两者:

为每一台运行FMS的服务器购买Windows的版权 大约4000美元一个的FMS特定版权,由于我们的规模,我们必须购买的版权量数以百计,而且每天都在增加。

所有这些费用开始不断累积。撇开成本不提,FMS也是一个比较挫的产品,特别是在它的功能方面(我过一会再详细说这个问题)。所以我决定抛弃FMS,自己从头开始写一个自己的RTMP解析器。

最后,我终于把我们的服务效率提升了大约20倍。

开始

这里涉及到两个核心问题:首先,RTMP和其他的Adobe协议及格式都不是开放的,这就很难使用它们。要是对文件格式都一无所知,你如何能对它进行反向工程或者解析它呢?幸运的是,有一些反向工程的尝试已经在公开领域出现了(并不是Adobe出品的,而是osflash.org,它破解了一些协议),我们的工作就是基于这些成果。

注:Adobe后来发布了所谓的“规格说明书”,比起在非Adobe提供的反向工程wiki和文档中披露的内容,这个说明书里也没有啥新东西。他们给的规格说明书的质量之低劣达到了荒谬的境地,近乎不可能通过该说明书来使用它们的库。而且,协议本身看起来常常也是有意做成具有误导性的。例如:

他们使用29位的整形数。 他们在协议头上所有地方都采用低地址存放最高有效字节(big endian)的格式,除了在某一个字段(而且未标明)上采用低地址存放最低有效字节(little endian)的格式。 他们在传输9K的视频时,不惜耗费计算能力去压缩数据减少空间,这基本上是没意义的,因为他们这么折腾一次也就是减少几位或几个字节,对这样的一个文件大小可以忽略不计了。

还有,RTMP是高度以session为导向的,这使得它基本上不可能对流进行组播。理想状态下,如果多个用户要求观看同一个实时视频流,我们可以直接向他们传回指向单个session的指针,在该session里传输这个视频流(这就是组播的概念)。但是用RTMP的话,我们必须为每一个要求访问特定流的用户创建全新的一个实例。这是完全的浪费。

成人网站 网站性能 网站流量 最大的色情网站

我的解决办法

想到了这些,我决定把典型的响应流重新打包和解析为FLV“标签”(这里的“标签”指某个视频、音频或者元数据)。这些FLV标签可以在RTMP下顺利地传输。

这样一个方法的好处是:

我们只需要给流重新打包一次(重新打包是一个噩梦,因为缺少规格说明,还有前面说到的恶心协议)。 通过套用一个FLV头,我们可以在客户端之间顺畅地重用任何流,而用内部的FLV标签指针(配以某种声明其在流内部确切位置的位移值)就可以访问到真正的内容。

我一开始用我当时最熟悉的C语言进行开发。一段时间后,这个选择变得麻烦了,所以我开始学习Python并移植我的C代码。开发过程加快了,但在做了一些演示版本后,我很快遇到了资源枯竭的问题。Python的socket处理并不适合处理这些类型的情况,具体说,我们发现在自己的Python代码里,每个action都进行了多次系统调用和context切换,这增加了巨大的系统开销。

改进性能:混合使用Python和C

在对代码进行梳理之后,我选择将性能最关键的函数移植到内部完全用C语言编写的一个Python模块中。这基本是底层的东西,具体地说,它利用了内核的epoll机制提供了一个O(log n)的算法复杂度。

在异步socket编程方面,有一些机制可以提供有关特定socket是否可读/可写/出错之类的信息。过去,开发人员们可以用select()系统调用获取这些信息,但很难大规模使用。Poll()是更好的选择,但它仍然不够好,因为你每次调用的时候都要传递一大堆socket描述符。

Epoll的神奇之处在于你只需要登记一个socket,系统会记住这个特定的socket并处理所有内部的杂乱的细节。这样在每次调用的时候就没有传递参数的开销了。而且它适用的规模也大有可观,它只返回你关心的那些socket,相比用其他技术时必须从10万个socket描述符列表里挨个检查是否有带字节掩码的事件,其优越性真是非同小可啊。

不过,为了性能的提高,我们也付出了代价:这个方法采用了完全和以前不同的设计模式。该网站以前的方法是(如果我没记错的话)单个原始进程,在接收和发送时会阻塞。我开发的是一套事件驱动方案,所以为了适应这个新模型,我必须重构其他的代码。

具体地说,在新方法中,我们有一个主循环,它按如下方式处理接收和发送:

成人网站 网站性能 网站流量 最大的色情网站

接收到的数据(作为消息)被传递到RTMP层 RTMP包被解析,从中提取出FLV标签 FLV数据被传输到缓存和组播层,在该层对流进行组织并填充到底层传输缓存中 发送程序为每个客户端保存一个结构,包含了最后一次发送的索引,并尽可能多地向客户端传送数据

这是一个滚动的数据窗口,并包含了某些试探性算法,当客户端速度太慢无法接收时会丢弃一些帧。总体来说运行的很好。

系统层级,架构和硬件问题

(编辑:应用网_丽江站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读