- 内容提要
- 前言
- 作者简介
- 封面简介
- 第1章 理解高性能 Python
- 第2章 通过性能分析找到瓶颈
- 2.1 高效地分析性能
- 2.2 Julia 集合的介绍
- 2.3 计算完整的 Julia 集合
- 2.4 计时的简单方法——打印和修饰
- 2.5 用 UNIX 的 time 命令进行简单的计时
- 2.6 使用 cProfile 模块
- 2.7 用 runsnakerun 对 cProfile 的输出进行可视化
- 2.8 用 line_profiler 进行逐行分析
- 2.9 用 memory_profiler 诊断内存的用量
- 2.10 用 heapy 调查堆上的对象
- 2.11 用 dowser 实时画出变量的实例
- 2.12 用 dis 模块检查 CPython 字节码
- 2.13 在优化期间进行单元测试保持代码的正确性
- 2.14 确保性能分析成功的策略
- 2.15 小结
- 第3章 列表和元组
- 第4章 字典和集合
- 第5章 迭代器和生成器
- 第6章 矩阵和矢量计算
- 第7章 编译成 C
- 第8章 并发
- 第9章 multiprocessing 模块
- 第10章 集群和工作队列
- 第11章 使用更少的 RAM
- 第12章 现场教训
12.4 在 Smesh 的大规模社交媒体分析
Alex Kelly (sme.sh)
在Smesh,我们生产的软件所摄取的数据来自于遍及Web的多种多样的API,过滤、处理并聚合它们,然后使用数据来为各种客户构建定制的应用。例如,我们提供了技术在Beamly的双屏TV应用中推进了推特消息(tweet)的过滤和流化,为移动网络EE运行了一个品牌和营销监控平台,以及为谷歌运行了一堆Adwords数据分析项目。
为了做到那样,我们运行了各种各样的流和轮询服务,经常性地轮询推特(Twitter)、Facebook、YouTube和许多其他内容服务,并每天处理几百万条推特消息。
12.4.1 Python在Smesh中的角色
我们广泛地使用了Python——我们的主要平台和服务使用它来构建。多种不同的可利用的库、工具和框架允许我们为所做的大多数事情来全盘使用它。
这种多样性带给我们能力来(有希望)为工作挑选出合适的工具。例如,我们已经创建了使用每一个Django、Flask和Pyramid的应用。每一个都有它的好处,我们能够为手头的任务挑选出合适的一个。我们为多任务使用Celery,为和AWS交互使用Boto,并为我们数据所需的一切使用PyMongo、MongoEngine、redis-py、Psycopg等。这个列表将不断延伸下去。
12.4.2 平台
我们的主要平台由一个中心Python模块组成,为数据输入、过滤、聚合和处理提供了钩子,还有多种其他的核心函数。项目的具体代码从那个核心中导入功能,然后根据每个应用的需求实现更多具体的数据处理和展现逻辑。
直到现在平台为我们工作良好,并允许我们构建相对复杂的应用来摄取和处理来自多种多样不同源的数据,而没有较多的重复的工作量。无论如何,它不是没有缺点——每个应用依赖于一个公共的核心模块,使得更新代码的过程位于那个模块中,并且让所有使用它的应用保持更新成了一项主要任务。
当前我们工作于一个项目上来重新设计核心软件并且前进到一个更加面向服务的架构(SoA)的方法中去。当平台成长时,寻找合适的时机来做出那种架构变化似乎是大多数软件团队所面临的一项挑战。把组件构建成单独的服务具有开销,并且所需要的用来构建每个服务的深入的领域特定知识经常只有通过一个初始的迭代开发才能掌握,架构的开销对于解决手头的真正问题是一个阻碍。有希望的是,我们已经选择了一个明智的时机来重新审视我们的架构抉择从而继续前进。交给时间来说话。
12.4.3 高性能的实时字符串匹配
我们从推特的流API中消费了许多数据。当我们在推特消息中流动时,我们把输入字符串与一组关键字做匹配,这样我们就知道我们正在跟踪的每条推特消息与哪个词项有关。这不是那种具有低速率的输入或者小关键字集的问题,而是为每秒几百条推特消息与几百个或几千个可能的关键字做匹配,从而问题开始变得棘手。
我们不仅对关键字字符串是否存在于推特消息中感兴趣,而且对更复杂的模式与单词的边界,行的起始和结束以及可选用的作为字符串前缀的 # 和 @ 字符是否匹配感兴趣,这使得问题变得更加棘手。最有效的封装匹配知识的方法就是使用正则表达式。无论如何,在每秒几百条推特消息上运行几千个正则表达式是计算密集型的。之前,我们不得不在集群机器上运行许多工作节点来实时可靠地执行匹配。
知道这是系统中的主要性能瓶颈之后,我们尝试了各种不同方法来提高我们匹配系统的性能:简化正则表达式,运行足够的进程来确保我们充分利用了服务器的所有核,确保我们的所有正则表达式被编译过了,得到了合适的缓存,以及在PyPy下运行匹配任务,而不是在CPython下等。这些中的每一个做法都提升了一点点性能,但是要明白这种方式只是减少了我们的一小部分处理时间。我们正寻找一个数量级的速度提升,而不是一小部分改进。
已经很明显了,比起尝试提高每一次匹配的性能,我们需要在模式匹配发生前,降低问题空间大小。这样我们需要减少要处理的推特消息的数量,或者减少我们所需要去匹配推特消息的正则表达式的数量。抛弃到来的推特消息不是一个选项——那是我们感兴趣的数据。所以,我们想方设法减少我们所需的的模式数量来与到来的推特消息做比较,从而执行匹配。
我们开始看看各种不同的trie树结构来允许我们更高效地在多组字符串之间做模式匹配,并且遇到了Aho-Corasick字符串匹配算法。它被证明对于我们的使用场景是理想的。构建trie树的字典必须是静态的—— 一旦自动化结束,你不能给trie树添加新成员——但对我们来说,这不是问题,因为关键字集合在来自推特的一个会话流的持续时间里是静态的。当我们改变正在跟踪的词项时,我们必须从API断开并重新连接上API,这样我们就能同时重建Aho-Corasick trie树。
使用Aho-Corasick来对照字符串处理输入同时找到所有可能的匹配,在一个时刻每步向前经过输入字串的一个字符,并且沿着trie树向下在下一层找到匹配的节点(或者没有找到,就如在案例中可能的那样)。这样,我们就能很快找到我们的哪一个关键词项可能存在于推特消息中。我们还是无法确切知道,因为Aho-Corasick中纯粹的字串与字串间的匹配不允许应用任何封装在正则表达式中的更复杂的逻辑,但是我们能够把Aho-Corasick匹配作为一个预过滤器来使用。不在字符串中的关键字无法匹配,这样基于出现在文本中的关键字,我们就知道仅仅只须尝试我们所有的正则表达式中的一个小小的子集。我们排除了绝大部分正则表达式并且对每条推特消息只需要处理极少数表达式,而不是对照每条输入评估成百上千个正则表达式。
通过把我们试图为每条推特消息来做匹配的模式数量降低到极少值,我们已经设法达成了我们所寻求的速度提升。依赖于trie树的复杂性以及输入推特消息的平均长度,我们的关键字匹配系统现在比原始的实现要快10到100倍。
如果你正在做许多正则处理,或者其他的模式匹配,我强烈推荐挖掘下各种不同的前缀和后缀trie树的变体,可能会有助于你迅速找到问题的快速解决方案。
12.4.4 报告、监控、调试和部署
我们维护了大量运行于我们的Python软件以及其余支撑它的基础设施之上的不同系统。让它保持上线并无中断运行是有难度的。这里有一些我们在途中所学习到的教训。
无论是在你自己的软件中还是在它运行的基础设施上,Python软件既能实时看到你的系统运行情况,又能看到系统的历史运行情况,真的很强大。我们使用Graphite和collectd、statsd一起来画出运行状况的漂亮图表。这带给我们一种观察趋势的方法,并反溯分析问题来找到根本原因。尽管我们还没有设法实现,但是当你具有超出你所能跟踪的度量指标时,Etsy的Skyline作为一种观察异常的方法看起来很巧妙。另一种有用的工具就是Sentry,一个针对事件日志的大系统,并且跟踪了集群中的机器所产生的异常。
部署可能是痛苦的,无论你用什么来做。我们已经是Puppet、Ansible和Salt的用户。它们各有优缺点,但是没有一个让一个复杂的部署问题变得魔法般的顺利。
为了维持我们一些系统的高可用性,我们跨地理运行了多个分布式的基础设施集群,让一个系统保持活跃,而其他的作为热备份,通过更新到具有低存活期(TTL)的DNS来完成切换。显然那不总是直截了当的,尤其是当你对数据的一致性有强约束时。幸亏我们没有太受影响,从而使方法相对直截了当。它也提供给我们一种相对安全的部署策略,即更新我们的其中一个备份集群,并在推动那个集群活跃和更新其他集群之前执行测试。
也和所有人一样,我们真的受使用Docker所能做的事情的前景所鼓舞。也和很多其他人一样,我们还仅仅处在摸索阶段来探索怎样来使它成为我们部署过程的一部分。无论如何,获得与它的所有二进制依赖以及所包含的系统库一起以轻量级和可重现的方式快速部署我们软件的能力看起来已经近在眼前了。
在服务器层面,有完整的一套例行工具来让生活变得轻松。Monit为你做监控很强大。Upstart和supervisord降低了运行服务的困难。如果你没有使用一个完整的Graphite和collectd设置,Munin对于一些快速而简单的系统级的图表是有用的。Corosync / Pacemaker可能对于跨集群节点运行服务是一个良好的解决方案(例如,你有一些需要运行在某处的服务,而不是运行在所有地方)。
我已尝试过在这里不仅是列举出时髦的术语,而且要向你指出我们每天正使用的软件,真正对我们能够有效部署并运行系统产生重大影响。如果你已经全部听说过它们,我确信你肯定有一套完整的其他有用的窍门要分享,所以请给我写信分享几点。如果不是,就去签出它们——希望其中一些对你有用,就像对我们有用一样。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论