红帽白皮书新鲜出炉!点击获取,让你的云战略更胜一筹! 了解详情
写点什么

Facebook 如何使用 Haskell 处理垃圾邮件

  • 2015-08-10
  • 本文字数:2122 字

    阅读完需:约 7 分钟

Facebook 使用一个名为 Sigma 的系统打击垃圾邮件、恶意软件及其它恶意行为。该系统的任务是主动发现这些行为,并自动删除检测到的不良内容,避免它们在用户的动态消息中显示。最近,他们完成了为期两年的 Sigma 重新设计工作,用 Haskell 取代了仅在 Facebook 内部使用的 FXL 语言。现在,基于 Haskell 的 Sigma 系统已经应用于生产环境,每秒为 100 多万请求提供服务。对于像 Sigma 这样的大型生产系统而言,Haskell 不是一个常用的选项。Simon Marlow 是一名 Facebook 软件工程师,同时也是 Haskell 社区的领军人物。近日,他撰文解释了他们做出这种选择的原因,并分享了经验。

Sigma 是一个规则引擎,就是说它运行一组规则,Facebook 称之为策略。Sigma 会用那些规则评估 Facebook 上的每次交互,以便识别和阻止恶意交互,防止它们影响 Facebook 用户。策略是持续部署的,任何时候,代码库中的源代码都是 Sigma 中运行的代码。这样,它们可以对新出现的恶意行为作出快速响应。同时,这也要求他们用于编写策略的语言是安全的。

起初,他们使用自己设计的 FXL 语言编写策略,但随着扩展性需求和复杂性的增加,FXL 不再是理想的选择。它缺少一些抽象机制,比如用户定义类型和模块,而且它的实现是以一个解释器为基础,速度不够快。因此,他们希望选用一种现有的语言。下面是他们重点考虑的几个因素:

  1. 纯函数式强类型语言:确保策略不会在无意间相互交互,可以单独测试,并且不会导致 Sigma 系统崩溃;强类型有助于在策略部署到生产环境之前减少许多 Bug;
  2. 自动批处理和并发获取数据:策略通常需要从 Facebook 的其它系统获取数据,为了提高效率,他们希望系统默认使用并发,即隐式并发;
  3. 在几分钟内将修改后的代码推送到生产环境,即他们可以快速部署或更新策略;
  4. 性能:FXL 性能较差,他们需要使用 C++ 开发一些对性能要求较高的功能,增加了变更发布时间;
  5. 支持交互式开发:开发人员可以交互地试验和测试策略代码并立即看到结果。

Haskell 非常适合:它是强类型的纯函数式语言,有成熟的优化编译器和交互式环境(GHCi),并且有他们需要的抽象机制。此外,它还有丰富的库和活跃的开发者社区。因此,上述列表中还有两项特性有待处理:

  • 自动批处理和并发:在 Haskell 中,现有所有的并发抽象都是显式的,就是说需要用户自己指出什么应该并发。但他们希望有一个编程模型,使系统在可以并发的时候自动并发。为此,他们开发了 Haxl 框架。它可以使多个数据获取操作自动批处理和并发执行。感兴趣的读者可以阅读他们先前发表的博文论文以及查看其 GitHub 页面。此外,他们还在 GHC 中实现了 Applicative do-notation
  • 已编译代码的热切换:他们希望任何提交到策略库的新代码尽快在每台机器的 Sigma fleet 上运行。他们希望动态地在运行中的 Sigma 进程中更新已编译的规则。修改正在运行的程序代码非常困难,但他们的情况相对简单:向 Sigma 发起的请求很短暂,所以他们不需要将一个正在运行的请求切换到新代码,而是等待现有的请求结束,然后用新代码为新请求提供服务。目前,他们使用 GHC 内置的运行时链接器加载和卸载代码,而卸载旧版本代码还要用到垃圾收集器

Haskell 位于 Sigma 中两个 C++ 层之间。上面一层是 C++ thrift 服务器。其实,这里也可以用 Haskell 作为 thrift 服务器,但 C++ thrift 服务器更成熟,性能更好,功能更丰富,并且可以与下面的 Haskell 层无缝集成,因为他们可以从 C++ 调用 Haskell。最底层是与外围服务交互的 C++ 客户端代码。他们使用 Haskell 的外部函数接口(FFI)将 C++ 客户端封装成一个 Haxl 数据源,那样,他们就可以从 Haskell 使用它。

他们对 Sigma 所服务的 25 种常见类型的请求进行了测试。结果表明,对于特定的请求,Haskell 的性能是 FXL 的 3 倍。Haskell 的吞吐量整体上比 FXL 高 20% 到 30%。为了,他们做了大量艰苦的工作,优化 Haskell 代码,确定和解决性能瓶颈,其中包括修改 GHC 的堆管理方式修复 Haskell JSON 解析框架 aeson 的一个性能缺陷等。

此外,Simon 还介绍了其它几项重要的工作,包括:

  • 资源限制:为了确保单个请求不因占用过多资源而导致其它请求的响应速度降低,他们在 GHC 中实现了资源分配限制,设定一个线程在被动终止之前可以获得的内存上限。
  • 交互式开发:为了实现交互式开发,他们需要将 GHCi 环境与他们的整个技术栈集成,包括从命令行向其它后台服务发送请求。为此,他们必须让构建系统将代码的所有 C++ 依赖都链接到一个 GHCi 可以加载的共享目录。此外,他们还定制了 GHCi 前端,实现了部分自有命令,简化了工作流程。
  • 打包和构建系统:他们发现,托管在 Hackage 上的 Haskell 开源包变化非常快,而且并不是所有包组合都可以很好地工作。因此,使用这些包意味着更多繁琐的工作。于是,他们切换到了 Stackage 。Stackage 提供了已知可用的包的版本组合。

要了解更多信息,可以查看 Protect the Graph 页面,或者观看他们最近的反垃圾邮件@Scale 活动视频。


感谢郭蕾对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们,并与我们的编辑和其他读者朋友交流(欢迎加入 InfoQ 读者交流群)。

2015-08-10 19:373349
用户头像

发布了 1008 篇内容, 共 372.1 次阅读, 收获喜欢 340 次。

关注

评论

发布
暂无评论
发现更多内容

金3银4面试前,把自己弄成卷王!

小傅哥

面试 小傅哥 金三银四 项目学习

Mybatis常用注解中的SQL注入

编程江湖

HarmonyOS canvas绘制“飞机大战”小游戏,真香!

HarmonyOS开发者

HarmonyOS

[JAVA冷知识]为什么动态加载不适合数组?如何动态加载一个数组?

山河已无恙

Java 2月月更

也谈向上管理

wood

向上管理 300天创作

JVM进阶(十三):阶段学习回顾

No Silver Bullet

JVM 2月月更 回顾

教你从零搭建Web漏洞靶场OWASP Benchmark

华为云开发者联盟

渗透测试 漏洞 安全测试 漏洞靶场

第八节:SpringBoot指定配置文件配置三

入门小站

Java

第1章:初识数据库与MySQL----数据库基本概念

乌龟哥哥

MySQL 2月月更

火遍网络的KPI异常检测到底什么梗?

乌龟哥哥

2月月更

关于大数据计算框架Flink内存管理的原理与实现总结 | 社区征文

张浩_house

大数据 flink 新春征文

新年开工新气象|OceanBase 祝大家开工大吉!

OceanBase 数据库

开源 OceanBase 社区版 开工大吉

Go 语言入门很简单:技巧和窍门(Tips and Tricks)

宇宙之一粟

Go 语言 2月月更

浅谈数仓建设及数据治理 | 社区征文

五分钟学大数据

数仓 新春征文

知名云计算厂商云宏加入龙蜥社区,共同打造信息安全坚实“地基”

OpenAnolis小助手

云计算 Linux 开源 社群运营

蚂蚁大规模 Kubernetes 集群无损升级实践指南【探索篇】

SOFAStack

云原生 etcd #Kubernetes# #k8s SIGMA

在线IEEE浮点二进制计算器工具

入门小站

工具

JVM进阶(十二):JAVA 可视化分析工具

No Silver Bullet

JVM 监控工具 2月月更

王者荣耀商城异地多活架构设计

swallowluo

架构实战营 #架构实战营 「架构实战营」

golang 面试总结

yuexin_tech

golang 面试

云原生时代,软件交付有何不同 | 研发效能提升36计

阿里云云效

阿里云 云原生 持续交付 云平台 研发

vivo直播应用技术实践与探索

vivo互联网技术

RTMP 直播技术

Nodejs内置模块path与fs模块简单使用

编程江湖

nodejs

Nacos服务注册与发现的2种实现方法!

王磊

nacos SpringCloud Alibaba

你使用的是数据结构还是对象?

蜜糖的代码注释

Java 后端开发 2月月更

营销MM让我讲MySQL日志顺序读写及数据文件随机读写原理

华为云开发者联盟

MySQL 磁盘 数据读写 日志顺序读写 数据文件随机读写

混合云模式下,如何定义一款好的 API 网关

API7.ai 技术团队

流量控制 api 网关 微服务治理 Apache APISIX

经验分享 | TDengine在智能船舶领域的实践手册

TDengine

数据库 大数据 tdengine 物联网 时序数据库

try{}catch居然可以隐藏?让我们用函数式接口来实现吧

山河已无恙

Java 2月月更

鸿蒙轻内核源码分析:文件系统FatFS

华为云开发者联盟

鸿蒙 Fat 文件系统 鸿蒙轻内核 FatFS

DDD[0]·序

陆乘风

领域驱动设计 领域驱动设计DDD 领域驱动设计思想

Facebook如何使用Haskell处理垃圾邮件_Meta_谢丽_InfoQ精选文章