转载请注明出处:http://blog.youkuaiyun.com/lonelytrooper/article/details/9988951
启动循环并读写元组
这是最重要的步骤,所有的工作在这里完成。本步骤的实现取决于是否你正在开发一个spout或bolt。
如果是spout,你应该启动发送元组。如果是bolt,循环并读取元组,处理并发射,ack或fail。
我们看一下发射数字的spout的实现:
$from =intval($argv[1]);
$to =intval($argv[2]);
while(true) {
$msg =read_msg();
$cmd =json_decode($msg,true);
if ($cmd['command']=='next') {
if ($from<$to) {
storm_emit(array("$from"));
$task_ids =read_msg();
$from++;
} else{
sleep(1);
}
}
storm_sync();
}
从命令行参数获取from和to并且开始迭代。每次你从storm获取一条next消息都意味着你准备发射一个新的元组。
一旦你发射了所有的数字并且没有更多的元组要发射,就休眠一段时间。
为了确保脚本为下一个元组准备好了,Storm在发送下一个之前等待行sync\n。为读取命令,只需调用read_msg()并用JSON解码它。
如果是bolts,有一些小不同。
while(true) {
$msg =read_msg();
$tuple =json_decode($msg,true, 512, JSON_BIGINT_AS_STRING);
if (!empty($tuple["id"])) {
if (isPrime($tuple["tuple"][0])) {
storm_emit(array($tuple["tuple"][0]));
}
storm_ack($tuple["id"]);
}
}
循环,从标准输入读取元 组。一旦获取消息,就用JSON解码它。如果是一个元组,处理,检查是否是质数。
如果是质数,发射该数;否则忽略它。在任何情况下,ack元组。
json_decode函数内JSON_BIGINT_AS_STRING的使用是Java和PHP转换的变通方案。Java发送非常大的数字,它们被以较低的精度编码成PHP,这会导致问题。为解决这个问题,当在JSON消息中打印数字时,告诉PHP解码大数字为字符串并避免使用双引号。该参数工作需要PHP5.4.0或更高的版本。
类似emit,ack,fail和log的消息有如下结构:
Emit
{
"command": "emit",
"tuple": ["foo","bar"]
}
这里的数组包含你要为元组发送的值。
Ack
{
"command": "ack",
"id": 123456789
}
这里的id是你正在处理的元组的ID。
Fail
{
"command": "fail",
"id": 123456789
}
同emit,id是你正在处理的元组的ID。
Log
{
"command": "log",
"msg": "somemessage to be logged by storm."
}
把它放到一起使得你有了下边的PHP脚本。
对于你的spout:
<?php
function read_msg() {
$msg ="";
while(true) {
$l =fgets(STDIN);
$line =substr($l,0,-1);
if ($line=="end") {
break;
}
$msg ="$msg$line\n";
}
return substr($msg,0, -1);
}
function write_line($line) {
echo("$line\n");
}
function storm_emit($tuple) {
$msg =array("command"=> "emit","tuple"=> $tuple);
storm_send($msg);
}
function storm_send($json) {
write_line(json_encode($json));
write_line("end");
}
function storm_sync() {
storm_send(array("command"=> "sync"));
}
function storm_log($msg) {
$msg =array("command"=> "log","msg"=> $msg);
storm_send($msg);
flush();
}
$config =json_decode(read_msg(),true);
$heartbeatdir =$config['pidDir'];
$pid =getmypid();
fclose(fopen("$heartbeatdir/$pid","w"));
storm_send(["pid"=>$pid]);
flush();
$from =intval($argv[1]);
$to =intval($argv[2]);
while(true) {
$msg =read_msg();
$cmd =json_decode($msg,true);
if ($cmd['command']=='next') {
if ($from<$to) {
storm_emit(array("$from"));
$task_ids =read_msg();
$from++;
} else{
sleep(1);
}
}
storm_sync();
}
?>
对于你的bolt:
<?php
function isPrime($number) {
if ($number<2) {
return false;
}
if ($number==2) {
return true;
}
for ($i=2;$i<=$number-1;$i++) {
if ($number% $i == 0) {
return false;
}
}
return true;
}
function read_msg() {
$msg ="";
while(true) {
$l =fgets(STDIN);
$line =substr($l,0,-1);
if ($line=="end") {
break;
}
$msg ="$msg$line\n";
}
return substr($msg,0, -1);
}
function write_line($line) {
echo("$line\n");
}
function storm_emit($tuple) {
$msg =array("command"=> "emit","tuple"=> $tuple);
storm_send($msg);
}
function storm_send($json) {
write_line(json_encode($json));
write_line("end");
}
function storm_ack($id) {
storm_send(["command"=>"ack","id"=>"$id"]);
}
function storm_log($msg) {
$msg =array("command"=> "log","msg"=> "$msg");
storm_send($msg);
}
$config =json_decode(read_msg(),true);
$heartbeatdir =$config['pidDir'];
$pid =getmypid();
fclose(fopen("$heartbeatdir/$pid","w"));
storm_send(["pid"=>$pid]);
flush();
while(true) {
$msg =read_msg();
$tuple =json_decode($msg,true, 512, JSON_BIGINT_AS_STRING);
if (!empty($tuple["id"])) {
if (isPrime($tuple["tuple"][0])) {
storm_emit(array($tuple["tuple"][0]));
}
storm_ack($tuple["id"]);
}
}
?>