Storm Multi-Language Protocol
Shell Components
通过类ShellBolt、ShellSpout和ShellProcess实现multiple languages的支持,这些类利用java类ProcessBuilder实现接口IBolt、ISpout和支持通过shell执行脚本/程序的协议。
Output fields
Output fields是topology的Thrift定义的一部分,这意味着在Java中使用多语言时,你需要创建一个扩展ShellBolt、实现IRichBolt的Bolt ,并在declareOutputFields
中定义output fields。
Protocol
一个简单的协议通过执行脚本/程序的STDIN和STDOUT来实现,跟process交互的数据均以JSON编码,使得支持更多的语言称为可能。Packaging Your Stuff
在集群中执行shellcomponent时,在提交给master的jar中,shell脚本必须放在目录resources/
下。但在单机上进行开发和测试,
resources
目录需要配置在
classpath
。
The Protocol
注意
-
此protocol的两端使用line-reading机制,因此需要保证在输入中截取中一行并将之添加至输出。
-
所有JSON输入和输出以单行终结,分割符不以JSON编码。
-
句点是由script所在STDIN和STDOUT写入的。
Initial Handshake
在两种类型的shellcomponents中进行initialhandshake :
-
STDIN: Setup 信息。包括Stormconfiguration、Topologycontext和一个PIDdirectory的JSON对象,如下:
{
"conf": {
"topology.message.timeout.secs": 3,
// etc
},
"context": {
"task->component": {
"1": "example-spout",
"2": "__acker",
"3": "example-bolt"
},
"taskid": 3
},
"pidDir": "..."
}
你的脚本需要再这个目录下创建一个命名为PID的空文件,这个文件使得supervisor知道PID 以使得以后可以shutdown此进程。
-
STDOUT: 你的PID,在一个JSON 对象,如
{"pid":1234}
。
shellcomponent 将会把此PID 写入它的log。
接下来需要做什么取决于component的类型:
Spouts
Shell spouts是同步的,如下以while(true) 循环进行:
-
STDIN: next、ack或fail命令。
"next" 即为ISpout的nextTuple
,如下:
{"command": "next"}
"ack" 如下:
{"command": "ack", "id": "1231231"}
"fail" 如下:
{"command": "fail", "id": "1231231"}
-
STDOUT: 基于前面命令,你的spout的结果,可为一序列emits和logs.
emit如下:
{
"command": "emit",
// The id for the tuple. Leave this out for an unreliable emit. The id can
// be a string or a number.
"id": "1231231",
// The id of the stream this tuple was emitted to. Leave this empty to emit to default stream.
"stream": "1",
// If doing an emit direct, indicate the task to send the tuple to
"task": 9,
// All the values in this tuple
"tuple": ["field1", 2, 3]
}
若不直接emit,你将立即获得taskids,作为JSON数组的tuple在STDIN上被emit的taskids
"log"记录workerlog上的一条信息,如下:
{
"command": "log",
// the message to log
"msg": "hello world!"
}
-
STDOUT: 一序列emits/ logs之后的"sync"命令,如下:
{"command": "sync"}
sync之后,ShellSpout不再读取你的输出直到发送另一个next、ack或者fail命令。注意,与ISpout相似,
在worker上的所有spouts在next、ack或fail命令之后将被lock直到sync;也如ISpout, 如果next没有emit的tuples,你应该syncing之前sleep一定时间,ShellSpout 并不自动sleep。
Bolts
shell bolt 协议是异步的,一旦可用将在STDIN上接受tuples,你可以在任意时间通过写入STDOUT来emit、ack和fail、log,如下:
-
STDIN: 一个tuple!一个JSON编码的解构体如下:
{
// The tuple's id - this is a string to support languages lacking 64-bit precision
"id": "-6955786537413359385",
// The id of the component that created this tuple
"comp": "1",
// The id of the stream this tuple was emitted to
"stream": "1",
// The id of the task that created this tuple
"task": 9,
// All the values in this tuple
"tuple": ["snow white and the seven dwarfs", "field2", 3]
}
-
STDOUT: 一个ack、fail、emit或log. Emits 如下:
{
"command": "emit",
// The ids of the tuples this output tuples should be anchored to
"anchors": ["1231231", "-234234234"],
// The id of the stream this tuple was emitted to. Leave this empty to emit to default stream.
"stream": "1",
// If doing an emit direct, indicate the task to send the tuple to
"task": 9,
// All the values in this tuple
"tuple": ["field1", 2, 3]
}
如果不直接emit,你将立即获得taskids,作为JSON数组的tuple在STDIN上被emit的taskids。注意: 基于shellbolt协议的异步性质,emitting之后读操作无法接受到taskids,你可以处理前面的emit或一个新tuple来替代读取task ids。你将以对应emits的次序获得taskid列表。
ack 如下:
{
"command": "ack",
// the id of the tuple to ack
"id": "123123"
}
fail如下:
{
"command": "fail",
// the id of the tuple to fail
"id": "123123"
}
"log" 记录workerlog上的一条信息,如下:
{
"command": "log",
// the message to log
"msg": "hello world!"
}
-
注意,0.7.1版本,不再需要shell bolt 的'sync'。