成人网站性能提升 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 panda库从基础到高级操作分析

《pythonpanda库从基础到高级操作分析》本文介绍了Pandas库的核心功能,包括处理结构化数据的Series和DataFrame数据结构,数据读取、清洗、分组聚合、合并、时间序列分析及大数据... 目录1. Pandas 概述2. 基本操作:数据读取与查看3. 索引操作:精准定位数据4. Group

Python pandas库自学超详细教程

《Pythonpandas库自学超详细教程》文章介绍了Pandas库的基本功能、安装方法及核心操作,涵盖数据导入(CSV/Excel等)、数据结构(Series、DataFrame)、数据清洗、转换... 目录一、什么是Pandas库(1)、Pandas 应用(2)、Pandas 功能(3)、数据结构二、安

Python使用Tenacity一行代码实现自动重试详解

《Python使用Tenacity一行代码实现自动重试详解》tenacity是一个专为Python设计的通用重试库,它的核心理念就是用简单、清晰的方式,为任何可能失败的操作添加重试能力,下面我们就来看... 目录一切始于一个简单的 API 调用Tenacity 入门:一行代码实现优雅重试精细控制:让重试按我

Python安装Pandas库的两种方法

《Python安装Pandas库的两种方法》本文介绍了三种安装PythonPandas库的方法,通过cmd命令行安装并解决版本冲突,手动下载whl文件安装,更换国内镜像源加速下载,最后建议用pipli... 目录方法一:cmd命令行执行pip install pandas方法二:找到pandas下载库,然后

Python实现网格交易策略的过程

《Python实现网格交易策略的过程》本文讲解Python网格交易策略,利用ccxt获取加密货币数据及backtrader回测,通过设定网格节点,低买高卖获利,适合震荡行情,下面跟我一起看看我们的第一... 网格交易是一种经典的量化交易策略,其核心思想是在价格上下预设多个“网格”,当价格触发特定网格时执行买

Python标准库之数据压缩和存档的应用详解

《Python标准库之数据压缩和存档的应用详解》在数据处理与存储领域,压缩和存档是提升效率的关键技术,Python标准库提供了一套完整的工具链,下面小编就来和大家简单介绍一下吧... 目录一、核心模块架构与设计哲学二、关键模块深度解析1.tarfile:专业级归档工具2.zipfile:跨平台归档首选3.

使用Python构建智能BAT文件生成器的完美解决方案

《使用Python构建智能BAT文件生成器的完美解决方案》这篇文章主要为大家详细介绍了如何使用wxPython构建一个智能的BAT文件生成器,它不仅能够为Python脚本生成启动脚本,还提供了完整的文... 目录引言运行效果图项目背景与需求分析核心需求技术选型核心功能实现1. 数据库设计2. 界面布局设计3

Python进行JSON和Excel文件转换处理指南

《Python进行JSON和Excel文件转换处理指南》在数据交换与系统集成中,JSON与Excel是两种极为常见的数据格式,本文将介绍如何使用Python实现将JSON转换为格式化的Excel文件,... 目录将 jsON 导入为格式化 Excel将 Excel 导出为结构化 JSON处理嵌套 JSON:

Python操作PDF文档的主流库使用指南

《Python操作PDF文档的主流库使用指南》PDF因其跨平台、格式固定的特性成为文档交换的标准,然而,由于其复杂的内部结构,程序化操作PDF一直是个挑战,本文主要为大家整理了Python操作PD... 目录一、 基础操作1.PyPDF2 (及其继任者 pypdf)2.PyMuPDF / fitz3.Fre

python设置环境变量路径实现过程

《python设置环境变量路径实现过程》本文介绍设置Python路径的多种方法:临时设置(Windows用`set`,Linux/macOS用`export`)、永久设置(系统属性或shell配置文件... 目录设置python路径的方法临时设置环境变量(适用于当前会话)永久设置环境变量(Windows系统