写点什么

FlightCaster 秘笈——Clojure 和 Rails

2009 年 11 月 16 日

Clojure 是 JVM 上的LISP,由Rich Hickey创建。过去一年中,它之所以受到广泛关注,最主要的原因是其并发特性,如支持软件事务存储(Software Transactional Memory——STM)及其他强大的数据结构。所以最近函数式语言颇吸引眼球,这也是很正常的。在 Clojure 1.0 发布几个月之后,用 Clojure 实现的现实项目也终于出现了。

FlightCaster 是一个新站点,用来提供航班延误预告。它的 Web 前台是用 Rails开发的,部署在Heroku上。后台处理数据的程序则是用Clojure开发的,用到了 Hadoop Cascading Cloudera 以及其他工具。

我们就该项目采访了Bradford Cross,了解用于开发 FlightCaster 的架构,如何用 Clojure 实现它,以及 OOP 程序员采用 Clojure 和 Lisp 时应该掌握的使用技巧。

InfoQ:你能解释一下 FlightCaster,也就是其分析部件,都做些什么吗?

Flightcaster 实时预测航班延误时间。其分析工作涉及到统计推断及机器学习技术的应用。关于航班延误预测的精确技术并不存在,即使其存在,我也没什么可说的。 :-)

InfoQ:你们的架构是什么?你们在 Clojure 群中发表的文章中,提到了 Hadoop 之上的一层 Cloudera ?它们是怎么组织在一起的?

Cloudera 非常强大,为需要使用 Hadoop 开发大规模分布式处理的人们提供服务、Hadoop 分发、部署脚本及 AMI(Amazon Machine Instances)。我们使用 Cloudera 将 Hadoop 集群部署在 EC2 上,用于进行数据处理和分析工作,结点数介于 10 到 100 之间。我们发现 使用 Cloudera 分发可以减少把 Hadoop 部署在 EC2 上的复杂性。我们只有两个人从事研究方面的工作,因此采用 Cloudera 对我们帮助很大。

InfoQ:FlightCaster 的哪一部分是用 Clojure 写的?

基础设施的另一个关键部件是 Cascading;在 Hadoop 上非常棒的一层,其增加了附加抽象概念和功能。我们向那些正在用 Hadoop 进行大量数据处理和挖掘的人强烈推荐 Casading。 我们所有的 Clojure 都是运行在 Cascading 上的。

该系统里有两个主要部分是用 Clojure 编写的。 一是把数据预处理并转换成适当视图用以分析的所有操作。包括过滤、多阶段分布式连接(destributed join)等等。把来自异质数据源的适当视图转变为非结构数据是非常复杂的。例如,我们不得不把时间序列视图构建到数据中,因为我们大量的分析需要考虑时 间因素。任何构建过这类系统的人都知道数据处理的工作量到底有多大,而 Clojure + Cascading 帮了大忙。

二是所有的统计推断和机器学习代码。如果该系统存在这一部分,我们将更深入介绍系统的这一部分。假定该系统存在这一部分,它应该能从 Clojure 优秀的 功能抽象、宏系统、丰富的不可变数据结构和序列处理类库、解构(destructuring)、组成复杂多阶段计算(中间可能出错)的单体抽象 (monadic abstractions)等诸多特性中获益良多。

InfoQ:你们用到了 Clojure 的并发和 STM 特性吗?

尽管这些特性很酷,但我们没有用 Clojures 构建并发特性。相反,我们利用了 Clojures 的另一个特性,务实的选择将其构建在 JVM 上。我们只是 把并行和分布式计算委托给 Cascading + Hadoop,我们在这两者之上又加了一层,使用起来很友好,如果有时间,我们会将其开源。

InfoQ:你能简要介绍一下你们的 Clojure 代码是如何组织的吗?比如,如何使用命名空间、muti-methods(多重分派)、macros(宏)等等。

过往函数式编程的经验使我们能够将代码组织成非常“函数”的形式。我们使用命名空间的方式与在其它语言中使用命名空间的方式相同。我们尽量少用 macros 和 muti-methods,就算用也只是在适合的地方使用。人们对 Lisp 的所有印象就是其有大量的 macros 和 meta-sauce。 尽管从某些方面来说这是对的,但是用 FP 基础构建块,你能走得更远;如 lambdas、HOFs、currying、partial application 等等。 我不能算是精通 monad,但是我觉得 mondads 和 multi-methods 及 macros 都差不多。这些抽象概念不但功能强大,而且也很酷,吸引 了不少眼球。当这些抽象概念有助于简化开发时,我就会设法使用这些工具。但是这要求思维缜密,使用原始的函数编程方式及数据结构你也能做得很好。

最后谈一下 Clojure 中的 monads,有些人认为 monads 是用于状态的,可是 Clojure 已经有了许多有效方法来处理状态,为什么还要用 monads。我们没有使用过 state monad,但是用过许多其他很有用的 monads。我很欣赏 Brian Beckman 对 monads 的描述:他们只是伪装的函数合成物而已。使用这一概念的最大好处是,能够安全构造出中间可能失败或碰到空值的多阶段计算。

虽然 Destructuring bind 看起来并不像 macros 和 monads 那样引人注目,但在实践中它实际上是一个非常强大的抽象概念。Rich 选择从模式匹配中解耦 destructuring bind 的方法非常聪明。我相信很快在 Clojure 里就会有 ML 风格的模式匹配,这一切正在实现中。

InfoQ:你提到过用于将数据格式输入到 Clojure 数据结构的 Clojure reader:你在使用 Reader macros 吗?

Clojure 没有 reader macros,我们也压根不需要。要读写 Clojure 数据结构,我们只需使用 print-dup 语句即可,它可以让我们定义 multimethods 来 分派 printers。只有在你需要读写没有内建的类型时,才真正需要实现 Printer。例如,我们有一个针对 joda-time 日期的特殊 printer,那么我们也将以一种特殊的方式将他们读回。

InfoQ:你提到过编写 Clojure 数据结构——你是用其来序列化传输、存储或其它用途的数据吗?

我们将 Clojure 数据结构用作通信和存储的中间表示。例如,我们所有数据转换工作的输出都是 Clojure 数据结构形式,这种中间表示遍布于我们所有 的 Hadoop 工作中。这是我们置于 Cascading 和 Haooop 之上的那一层东西的关键,可以让我们免于处理 Hadoop 输入格式。

InfoQ:你们有什么想加到 Clojure 或 Clojure 生态系统中的东西么(类库、工具……)?

有人提议加个高质量的 destructuring 模式匹配工具,这个东西挺有用。但我对局部改进更感兴趣。我们没有用模式匹配,而且 Clojure 有许多很好的抽象概念,因而并不会缺失太多模式匹配,但是我认为它还是让很多地方的代码更加整洁了。 如果 Rich 开放该 reader,我想一定很酷,或许这将帮助为模式匹配和 monad 实现创建良好的语法。其次,Clojure 是我第一次使用 Lisp,因此我并没有使用 reader macros 的经验,因此,在这方面我并不在行。

如果 Rich 不保留竖线也挺好,这样我们可以将它作为我们核心 DSL 的一部分,用来作为条件概率记号。 :-)

InfoQ:对于你所使用的 Clojure 类库,你有什么建议?

使用 Clojure 的第一个建议是:Clojure-core 和 Clojure-contrib 都很小,因此最好通读全部代码。从中你将发现非常好的东西。留意所有神奇的数据结构及数据结构处理函数。例 如,Clojure 有一个友好的 Set 及 Set 操作实现,以及一些准关系代数实现。 我把 Clojure 看作是一种面向函数编程的数据结构。

Clojure 拥有一套神奇的数据结构。此外,所有这些数据结构都有书面陈述,因此 reader 和 destructuring 都很自然。所有这些结合在一起让人非常愉快。

传承自 ML 的函数语言中,函数是类型签名。而在 Clojure 中,函数是数据结构拓扑签名。

InfoQ:FlightCaster 的 Web 前台是用 Rails 编写的,部署在 Heroku 上。为什么选择 Rails 和 Heroku?

当我开始介入 FlightCaster 开发时,已经定下来用 Heroku 和 Rails 了。这一决定是有道理的:Ruby 和 Rails 生态环境生产效率比较 高,并且为构建 WebApp 铺平了道路。Heroku 和 Rails 对团队来说是很自然的选择,因为创始人中有两个具有 Rails 开发经验,Herkou 的 创始人之一还是我们 CEO 的密友。:-) Flightcaster 和 Heroku 共处一室,这太棒了!拥有这种内部联系有益无害。

InfoQ:你们是如何将 Web UI 与 Clojure 后台进行集成的?

Rails 不只是 Web 前台,而且还是 WebServer。我们使用 Clojure 来进行数据处理和机器学习研究。我们使用一种非常简单的策略来实现集成:我们让 Clojure 代码产生预告模型的 json 中间表示,然后把它推向 Ruby 端,以 json 格式来读取这些数据。

Clojure 第一本书的作者——Stuart Halloway ,最近发表了一篇文章介绍了使用Clojure 的不同技巧。该文章提供了Clojure 中的封装、多态等一些例子——那些拥有OOP 背景的开发者会对此产生兴趣(这是类和继承之外的生活)。

要了解更多Clojure 方面的信息,请参见InfoQ 的 interview with Rich Hickey ,其中谈及了 STM、并发性及 multimethod。 Rich 关于 Clojure 的视频讲解提供了有关 Clojure 特性及其设计原则的更多详细内容。

查看英文原文: Clojure and Rails - the Secret Sauce Behind FlightCaster


感谢刘申对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家加入到 InfoQ 中文站用户讨论组中与我们的编辑和其他读者朋友交流。

2009 年 11 月 16 日 18:193826
用户头像

发布了 150 篇内容, 共 36.3 次阅读, 收获喜欢 4 次。

关注

评论

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

架构实战营 - 模块二作业

Sun

架构实战营 - 模块二作业

凯迪

架构实战营

阿里巴巴用实践告诉你,架构师到底需要掌握什么样的技术?

Java架构师迁哥

模块2-微信朋友圈高性能架构设计

yu

架构实战营 模块二:学习总结

👈

架构实战营

让孩子爱上阅读(二)

高彪

读书笔记 【4 月日更】

Docker容器的安装和使用

攻城狮Chova

Docker 容器 【4 月日更】 镜像仓库

业务架构训练营第 0 期模块二作业

目标一个亿

Github接近10w点赞!阿里巴巴内部Java面试参考指南

云流

Java 程序员 架构 面试

我是如何从零开始学Python: (1)如何选择合适的Python学习工具?

广之巅

Python 【4 月日更】

Linux ifconfig 命令

一个大红包

4月日更

WEB-API的设计与开发

墨凡

HTTP 软件设计 web tech

2020从干饭人到打工人

空城机

生活 生活记录 杂记 4月日更

重读《重构2》- 引入参数对象

顿晓

重构 4月日更

如何做向上管理?

石云升

28天写作 职场经验 4月日更 向上管理

【LeetCode】存在重复元素 III Java题解

HQ数字卡

算法 LeetCode 4月日更

架构实战营 模块二:课后作业

👈

架构实战营

模块2作业

灯火阑珊

这套Java面试题推出第二天就惨遭全网封杀!已帮我拿下15个Offer

Java架构追梦

Java 阿里巴巴 架构 面试题总结 金三银四

wkhtmltopdf实践

风翱

【4 月日更】 wkhtmltopdf

陪伴的进化

小天同学

陪伴 爱情 个人感悟 4月日更 亲情

采访彩食鲜 CTO 乔新亮:数字时代,企业如何完成数字化转型?(采访提纲)

xcbeyond

数字化转型 4月日更 人物访谈

阿里遭拒,90天深造357页微服务手册,获京东offer

Crud的程序员

Java 编程 程序员 架构 微服务

Flutter 学习笔记(二) Container 组件

U+2647

flutter 四月日更

Nacos实践

程序员架构进阶

源码分析 nacos 微服务治理 28天写作 四月日更

Seldon 使用 (三): 模型服务如何运行

托内多

tensorflow kubeflow Kubernetes PyTorch seldon

华为“引商”,VR“刻羽”,共觅知音人

脑极体

阿里致敬武侠首发“Java架构修炼笔记”,深入内核,拒绝蒙圈

Java架构师迁哥

Spark运行状态监控与优化

小舰

【4 月日更】

架构实战营 - 模块 2- 作业

冬天的树

nginx反向代理和负载均衡策略实战案例

赖猫

nginx Nginx源码

演讲经验交流会|ArchSummit 上海站

演讲经验交流会|ArchSummit 上海站

FlightCaster秘笈——Clojure和Rails-InfoQ