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

2023-12-23 07:50

本文主要是介绍成人网站性能提升 20 倍之经验谈 [Python],希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

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

问题是什么?

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

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

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

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

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

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

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

开始

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

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

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

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

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

我的解决办法

想到了这些,我决定把典型的响应流重新打包和解析为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描述符列表里挨个检查 是否有带字节掩码的事件,其优越性真是非同小可啊。

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

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

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

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

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

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

但是我们又遇到另外一个问题:内核的context切换成为了一个负担。结果,我们选择每100毫秒发送一次而不是实时发送。这样可以把小的数据包汇总起来,也避免了context切换的爆炸式出现。

也许更大的一个问题在于服务器架构方面:我们需要一个具备负载均衡和容错能力的服务器集群,毕竟因为服务器功能异常而失去用户不是件好玩的事情。一 开始,我们采用了专职总管服务器的方法,它指定一个”总管“负责通过预测需求来产生和消除播放流。这个方法华丽丽地失败了。实际上,我们尝试过的每个方法 都相当明显地失败了。最后,我们采用了一个相对暴力的方法,在集群的各个节点之间随机地共享播放的流,使流量基本平衡了。

这个方法是有效的,但是也有一些不足:虽然一般情况下它处理的很好,我们也碰到了当所有网站用户(或者相当大比例的用户)观看单个广播流的时候,性 能会变得非常糟糕。好消息是,除了一次市场宣传活动(marketing campaign)之外,这种情况再也没出现过。我们部署了另外一套单独的集群来处理这种情况,但真实的情况是我们先分析了一番,觉得为了一次市场活动而 牺牲付费用户的体验是说不过去的,实际上,这个案例也不是一个真实的事件(虽然说能处理所有想象得到的情况也是很好的)。 

结论

这里有最后结果的一些统计数字:每天在集群里的流量在峰值时是大约10万用户(60%负载),平均是5万。我管理了2个集群(匈牙利和美国),每个 里有大约40台服务器共同承担这个负载。这些集群的总带宽大约是50 Gbps,在负载达到峰值时大约使用了10 Gbps。最后,我努力做到了让每台服务器轻松地能提供10 Gbps带宽,也就等于一台服务器可以承受30万用户同时观看视频流。

已有的FMS集群包含了超过200台服务器,我只需要15台就可以取代他们,而且其中只有10台在真正提供服务。这就等于200除以10,等于 20 倍的性能提高。大概我在这个项目里最大的收获就是我不应让自己受阻于学习新技能的困难。具体说来,Python、转码、面向对象编程,这些都是我在做这个 项目之前缺少专业经验的概念。

这个信念,以及实现你自己的方案的信心,会给你带来很大的回报。

【1】后来,当我们把新代码投入生产,我们又遇到了硬件问题,因为我们使用老的sr2500 Intel架构服务器,由于它们的PCI总线带宽太低,不能支持10 Gbit的以太网卡。没辙,我们只好把它们用在1-4×1 Gbit的以太网池中(把多个网卡的性能汇总为一个虚拟网卡)。最终,我们获得了一些更新的sr2600 i7 Intel架构服务器,它们通过光纤达到了无性能损耗的10 Gbps带宽。所有上述汇总的结果都是基于这样的硬件条件来计算的。

英文原文:GERGELY KALMAN,编译:@老码农的自留地
译文链接:http://blog.jobbole.com/39323/

这篇关于成人网站性能提升 20 倍之经验谈 [Python]的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/527267

相关文章

使用Python绘制蛇年春节祝福艺术图

《使用Python绘制蛇年春节祝福艺术图》:本文主要介绍如何使用Python的Matplotlib库绘制一幅富有创意的“蛇年有福”艺术图,这幅图结合了数字,蛇形,花朵等装饰,需要的可以参考下... 目录1. 绘图的基本概念2. 准备工作3. 实现代码解析3.1 设置绘图画布3.2 绘制数字“2025”3.3

python使用watchdog实现文件资源监控

《python使用watchdog实现文件资源监控》watchdog支持跨平台文件资源监控,可以检测指定文件夹下文件及文件夹变动,下面我们来看看Python如何使用watchdog实现文件资源监控吧... python文件监控库watchdogs简介随着Python在各种应用领域中的广泛使用,其生态环境也

Python中构建终端应用界面利器Blessed模块的使用

《Python中构建终端应用界面利器Blessed模块的使用》Blessed库作为一个轻量级且功能强大的解决方案,开始在开发者中赢得口碑,今天,我们就一起来探索一下它是如何让终端UI开发变得轻松而高... 目录一、安装与配置:简单、快速、无障碍二、基本功能:从彩色文本到动态交互1. 显示基本内容2. 创建链

Java调用Python代码的几种方法小结

《Java调用Python代码的几种方法小结》Python语言有丰富的系统管理、数据处理、统计类软件包,因此从java应用中调用Python代码的需求很常见、实用,本文介绍几种方法从java调用Pyt... 目录引言Java core使用ProcessBuilder使用Java脚本引擎总结引言python

python 字典d[k]中key不存在的解决方案

《python字典d[k]中key不存在的解决方案》本文主要介绍了在Python中处理字典键不存在时获取默认值的两种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录defaultdict:处理找不到的键的一个选择特殊方法__missing__有时候为了方便起见,

使用Python绘制可爱的招财猫

《使用Python绘制可爱的招财猫》招财猫,也被称为“幸运猫”,是一种象征财富和好运的吉祥物,经常出现在亚洲文化的商店、餐厅和家庭中,今天,我将带你用Python和matplotlib库从零开始绘制一... 目录1. 为什么选择用 python 绘制?2. 绘图的基本概念3. 实现代码解析3.1 设置绘图画

Python pyinstaller实现图形化打包工具

《Pythonpyinstaller实现图形化打包工具》:本文主要介绍一个使用PythonPYQT5制作的关于pyinstaller打包工具,代替传统的cmd黑窗口模式打包页面,实现更快捷方便的... 目录1.简介2.运行效果3.相关源码1.简介一个使用python PYQT5制作的关于pyinstall

使用Python实现大文件切片上传及断点续传的方法

《使用Python实现大文件切片上传及断点续传的方法》本文介绍了使用Python实现大文件切片上传及断点续传的方法,包括功能模块划分(获取上传文件接口状态、临时文件夹状态信息、切片上传、切片合并)、整... 目录概要整体架构流程技术细节获取上传文件状态接口获取临时文件夹状态信息接口切片上传功能文件合并功能小

python实现自动登录12306自动抢票功能

《python实现自动登录12306自动抢票功能》随着互联网技术的发展,越来越多的人选择通过网络平台购票,特别是在中国,12306作为官方火车票预订平台,承担了巨大的访问量,对于热门线路或者节假日出行... 目录一、遇到的问题?二、改进三、进阶–展望总结一、遇到的问题?1.url-正确的表头:就是首先ur

基于Python实现PDF动画翻页效果的阅读器

《基于Python实现PDF动画翻页效果的阅读器》在这篇博客中,我们将深入分析一个基于wxPython实现的PDF阅读器程序,该程序支持加载PDF文件并显示页面内容,同时支持页面切换动画效果,文中有详... 目录全部代码代码结构初始化 UI 界面加载 PDF 文件显示 PDF 页面页面切换动画运行效果总结主