Cascalog:基于 Clojure 的 Hadoop 查询语言

原文:http://nathanmarz.com/blog/introducing-cascalog-a-clojure-based-query-language-for-hado.html

我非常兴奋地告诉大家,Cascalog开源了!Cascalog受Datalog启发,是一种基于Clojure、运行于Hadoop平台上的查询语言。

特点

  • 简单 - 使用相同的语法编写函数、过滤规则、聚合运算;数据联合(join)变得简单而自然。
  • 表达能力强 - 强大的逻辑组合条件,你可以在查询语句中任意编写Clojure函数。
  • 交互性 - 可以在Clojure REPL中执行查询语句。
  • 可扩展 - Cascalog的查询语句是一组MapReduce脚本。
  • 任意数据源 - HDFS、数据库、本地数据、以及任何能够使用Cascading的Tap读取的数据。
  • 正确处理空值 - 空值往往让事情变得棘手。Cascalog提供了内置的“非空变量”来自动过滤空值。
  • 与Cascading结合 - 使用Cascalog定义的流程可以在Cascading中直接使用,反之亦然。
  • 与Clojure结合 - 能够使用普通的Clojure函数来编写操作流程、过滤规则,又因为Cascalog是一种Clojure DSL,因此也能在其他Clojure代码中使用。

阅读全文

Clojure 实战(5):Storm 实时计算框架

Storm简介

上一章介绍的Hadoop工具能够对海量数据进行批量处理,采用分布式的并行计算架构,只需使用其提供的MapReduce API编写脚本即可。但随着人们对数据实时性的要求越来越高,如实时日志分析、实时推荐系统等,Hadoop就无能为力了。

这时,Storm诞生了。它的设计初衷就是提供一套分布式的实时计算框架,实现低延迟、高并发的海量数据处理,被誉为“Realtime Hadoop”。它提供了简单易用的API接口用于编写实时处理脚本;能够和现有各类消息系统整合;提供了HA、容错、事务、RPC等高级特性。

Storm的官网是:storm-project.net,它的Wiki上有非常详尽的说明文档。

Storm与Clojure

Storm的主要贡献者Nathan Marz徐明明都是活跃的Clojure开发者,因此在Storm框架中也提供了原生的Clojure DSL。本文就将介绍如何使用这套DSL来编写Storm处理脚本。

Storm集群的安装配置这里不会讲述,具体请参考这篇文档。下文的脚本都运行在“本地模式”之下,因此即使不搭建集群也可以运行和调试。

阅读全文

Perl 入门实战:JVM 监控脚本(下)

套接字

使用套接字(Socket)进行网络通信的基本流程是:

  • 服务端:监听端口、等待连接、接收请求、发送应答;
  • 客户端:连接服务端、发送请求、接收应答。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
use IO::Socket::INET;

my $server = IO::Socket::INET->new(
LocalPort => 10060,
Type => SOCK_STREAM,
Reuse => 1,
Listen => SOMAXCONN
) || die "服务创建失败\n";

while (my $client = $server->accept()) {

my $line = <$client>;
chomp($line);

if ($line =~ /^JVMPORT ([0-9]+)$/) {
print "RECV $1\n";
print $client "OK\n";
} else {
print "ERROR $line\n";
print $client "ERROR\n";
}

close($client);
}

close($server);

阅读全文

fork() 与僵尸进程

使用fork()函数派生出多个子进程来并行执行程序的不同代码块,是一种常用的编程泛型。特别是在网络编程中,父进程初始化后派生出指定数量的子进程,共同监听网络端口并处理请求,从而达到扩容的目的。

但是,在使用fork()函数时若处理不当,很容易产生僵尸进程。根据UNIX系统的定义,僵尸进程是指子进程退出后,它的父进程没有“等待”该子进程,这样的子进程就会成为僵尸进程。何谓“等待”?僵尸进程的危害是什么?以及要如何避免?这就是本文将要阐述的内容。

fork()函数

下面这段C语言代码展示了fork()函数的使用方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// myfork.c

#include <unistd.h>
#include <stdio.h>

int main(int argc, char **argv) {
while (1) {
pid_t pid = fork();
if (pid > 0) {
// 主进程
sleep(5);
} else if (pid == 0) {
// 子进程
return 0;
} else {
fprintf(stderr, "fork error\n");
return 2;
}
}
}

阅读全文

Perl 入门实战:JVM 监控脚本(上)

由于最近在搭建Zabbix监控服务,需要制作各类监控的模板,如iostat、Nginx、MySQL等,因此会写一些脚本来完成数据采集的工作。又因为近期对Perl语言比较感兴趣,因此决定花些时间学一学,写一个脚本来练练手,于是就有了这样一份笔记。

需求描述

我们将编写一个获取JVM虚拟机状态信息的脚本:

  1. 启动一个服务进程,通过套接字接收形如“JVMPORT 2181”的请求;
  2. 执行netstat命令,根据端口获取进程号;
  3. 执行jstat命令获取JVM的GC信息;jstack获取线程信息;ps -o pcpu,rss获取CPU和内存使用情况;
  4. 将以上信息返回给客户端;

之所以需要这样一个服务是因为Zabbix Agent会运行在zabbix用户下,无法获取运行在其他用户下的JVM信息。

此外,Zabbix Agent也需要编写一个脚本来调用上述服务,这个在文章末尾会给出范例代码。

阅读全文

柯里化与偏应用(JavaScript 描述)

原文:http://raganwald.com/2013/03/07/currying-and-partial-application.html

上周末我参加了wroc_love.rb大会,其间Steve Klabnik的一张PPT中提到了偏应用(Partial Application)柯里化(Currying),并说这两者之间的区别如今已经不重要了。但是我不这么认为。

在这周发布的博文中,我用五种方式对this和闭包做了解释,但只有三到四种提到了柯里化。所以这篇博文就重点来谈谈这个。

函数参数的个数

在讲解之前,我们先明确一些术语。函数定义时会写明它所接收的参数个数(Arity)。“一元函数”(Unary)接收一个参数,“多元函数”(Polyadic)接收多个参数。还有一些特殊的名称,如“二元函数”(Binary)接收两个参数,“三元函数”(Ternary)接收三个参数等。你可以对照希腊语或拉丁语词汇来创造这些特殊的名称。

有些函数能够接收不定数量的参数,我们称之为“可变参数函数”(Variadic)。不过这类函数、以及不接收参数的函数并不是本文讨论的重点。

阅读全文

Clojure 实战(4):编写 Hadoop MapReduce 脚本

Hadoop简介

众所周知,我们已经进入了大数据时代,每天都有PB级的数据需要处理、分析,从中提取出有用的信息。Hadoop就是这一时代背景下的产物。它是Apache基金会下的开源项目,受Google两篇论文的启发,采用分布式的文件系统HDFS,以及通用的MapReduce解决方案,能够在数千台物理节点上进行分布式并行计算。

对于Hadoop的介绍这里不再赘述,读者可以访问其官网,或阅读Hadoop权威指南

Hadoop项目是由Java语言编写的,运行在JVM之上,因此我们可以直接使用Clojure来编写MapReduce脚本,这也是本文的主题。Hadoop集群的搭建不在本文讨论范围内,而且运行MapReduce脚本也无需搭建测试环境。

阅读全文

Clojure 代码规范

原文地址:https://github.com/bbatsov/clojure-style-guide

这份Clojure代码规范旨在提供一系列的最佳实践,让现实工作中的Clojure程序员能够写出易于维护的代码,并能与他人协作和共享。一份反应真实需求的代码规范才能被人接收,而那些理想化的、甚至部分观点遭到程序员拒绝的代码规范注定不会长久——无论它有多出色。

这份规范由多个章节组成,每个章节包含一组相关的规则。我会尝试去描述每条规则背后的理念(过于明显的理念我就省略了)。

这些规则并不是我凭空想象的,它们出自于我作为一个专业软件开发工程师长久以来的工作积累,以及Clojure社区成员们的反馈和建议,还有各种广为流传的Clojure编程学习资源,如《Clojure Programming》《The Joy of Clojure》等。

这份规范还处于编写阶段,部分章节有所缺失,内容并不完整;部分规则没有示例,或者示例还不能完全将其描述清楚。未来这些问题都会得到改进,只是请你了解这一情况。

阅读全文

Nginx 热升级

系统管理员可以使用Nginx提供的信号机制来对其进行维护,比较常用的是kill -HUP <master pid>命令,它能通知Nginx使用新的配置文件启动工作进程,并逐个关闭旧进程,完成平滑切换。当需要对Nginx进行版本升级或增减模块时,为了不丢失请求,可以结合使用USR2WINCH等信号进行平滑过度,达到热升级的目的。如果中途遇到问题,也能立刻回退至原版本。

操作步骤

1、备份原Nginx二进制文件;

2、编译新Nginx源码,安装路径需与旧版一致;

3、向主进程发送USR2信号,Nginx会启动一个新版本的master进程和工作进程,和旧版一起处理请求:

1
2
3
4
5
6
7
8
9
prey:~ root# ps -ef|grep nginx
127 1 nginx: master process /usr/local/nginx-1.2.4/sbin/nginx
129 127 nginx: worker process
prey:~ root# kill -USR2 127
prey:~ root# ps -ef|grep nginx
127 1 nginx: master process /usr/local/nginx-1.2.4/sbin/nginx
129 127 nginx: worker process
5180 127 nginx: master process /usr/local/nginx-1.2.4/sbin/nginx
5182 5180 nginx: worker process

阅读全文

Clojure 实战(3):使用 Noir 框架开发博客(下)

Session和Cookie

做网络编程的人肯定对这两个概念不陌生,因此这里就不介绍它们的定义和作用了。我们要实现的需求也很简单:用户通过一个表单登录,在当前窗口中保持登录状态,并可以选择“记住我”来免去关闭并新开窗口之后的重登录。显然,前者使用Session,后者使用Cookie。下面我们就来看Noir对这两者的支持。

Session

1
2
3
4
(require 'noir.session)
(noir.session/put! :username "john")
(noir.session/get :username "nobody")
(noir.session/clear!)

很简单的API。注意put!函数中的!,和之前遇到的?一样,这种特殊字符是合法的函数名,但!习惯用来表示该方法会改变某个对象的状态,这里put!就表示会改变Session的状态。

Noir还提供了一种“闪信(Flash)”机制,主要用于在页面跳转之间暂存消息。如用户登录后会跳转到首页,如果想在首页显示“登录成功”的信息,就需要用到闪信了。闪信的API也放置在noir.session命名空间下:

1
2
(noir.session/flash-put! "登录成功")
(noir.session/flash-get)

闪信的生命周期是一次请求,即在设置了闪信后的下一个请求中,可以多次flash-get,但再下一次请求就获取不到值了。

阅读全文