由于使用go语言实现storm的拓扑结构,因此使用go实现了spout和bolt,运行时出现如下问题。
Caused by: java.io.IOException: Unexpected token LEFT BRACE({) at position 12.
at org.apache.storm.multilang.JsonSerializer.readMessage(JsonSerializer.java:172) ~[storm-core-1.2.2.jar:1.2.2]
at org.apache.storm.multilang.JsonSerializer.readShellMsg(JsonSerializer.java:104) ~[storm-core-1.2.2.jar:1.2.2]
at org.apache.storm.utils.ShellProcess.readShellMsg(ShellProcess.java:125) ~[storm-core-1.2.2.jar:1.2.2]
at org.apache.storm.task.ShellBolt$BoltReaderRunnable.run(ShellBolt.java:330) ~[storm-core-1.2.2.jar:1.2.2]
... 1 more
Caused by: org.apache.storm.shade.org.json.simple.parser.ParseException
at org.apache.storm.shade.org.json.simple.parser.JSONParser.parse(Unknown Source) ~[storm-core-1.2.2.jar:1.2.2]
at org.apache.storm.shade.org.json.simple.parser.JSONParser.parse(Unknown Source) ~[storm-core-1.2.2.jar:1.2.2]
at org.apache.storm.shade.org.json.simple.parser.JSONParser.parse(Unknown Source) ~[storm-core-1.2.2.jar:1.2.2]
at org.apache.storm.shade.org.json.simple.JSONValue.parseWithException(Unknown Source) ~[storm-core-1.2.2.jar:1.2.2]
at org.apache.storm.multilang.JsonSerializer.readMessage(JsonSerializer.java:170) ~[storm-core-1.2.2.jar:1.2.2]
at org.apache.storm.multilang.JsonSerializer.readShellMsg(JsonSerializer.java:104) ~[storm-core-1.2.2.jar:1.2.2]
at org.apache.storm.utils.ShellProcess.readShellMsg(ShellProcess.java:125) ~[storm-core-1.2.2.jar:1.2.2]
at org.apache.storm.task.ShellBolt$BoltReaderRunnable.run(ShellBolt.java:330) ~[storm-core-1.2.2.jar:1.2.2]
... 1 more
阅读代码发现没有问题,改问题困扰一天,最后发现是代码里有一句fmt.Printf.
ShellBolt通过通过Shell命令,启动新的进程,并通过该进程的stdIn,stdOut,stdErr和其进行交互。这样做可能可回导致一下三个问题:
1)潜藏风险
交互完全是读写进程的StdIn,StdOut;这就对编程者提出了要求,不能私自向stdIn和StdOUt上输出东西,也就是说在程序中绝对不能有printf,scanf,cout,cin,System.Out,System.in之类的。
这一点,对于小规模程序或者完全新开发的程序可以进行约定。可是对于打响程序,或者基于已有程序进行重构的时候就变得不靠谱了,只有上帝才知道有没有人偷偷的写了stdin或stdout,这必然会导致程序崩溃。而且你根本无从查起。
2)效率低
还是交互,通过读写进程的StdIn,StdOut交互,所有数据必须是文本的,Storm中通过Json编码实现。而编码解码,写Stdio,Stdout,这种交互方式的效率无疑是比较低的。
3)僵尸进程
ShellBolt根据Shell命令,启动新的进程,而目前还没有很好的方法保证它会杀死所有他启动的进程。本人在使用的过程中就经常发现一个topology停止后,后台经常会驻留有还没有死掉的进程。
4)占用资源
ShellBolt根据Shell命令,启动新的进程。也即是说在task较多时,它会启动很多进程,比较占用资源。当然这个不能说是缺点,因为进程是独立空间,当你的程序需要的资源比较多时,启动单独的进程是很好的选择。