storm示例之DRPC

DRPC(分布式远程过程调用,Distributed Remote Procedure Call)是storm整合流(stream)、Spout、Bolt、Topology而形成的一种模式。引入DRPC旨在借助Storm集群实现远程的并行计算。DRPC客户端只要指定要使用的“函数”(函数实现了特定的功能),并将要计算的内容发送给storm的drpc服务,待服务端调用响应函数计算完成后,客户端会收到相应的返回结果。

DRPC的流程可以用官方给出的下图来阐述。
这里写图片描述

  1. 客户端将计算请求和参数发给DRPC Server
  2. DRPC Spout从DRPC Server接收“函数调用”所需的流,DRPC Server会赋予每个调用一个唯一的ID(request id)
  3. spout将流处理后发给拓扑中的“函数”进行计算
  4. 最终会在拓扑中的最后一个Bolt中,将计算结果返回给DRPC Server,返回结果与之前的request id想对应
  5. DRPC Server会将此次远程过程调用结果返回给客户端

Storm的DRPC服务分为客户度和服务端,服务端创建DRPC拓扑后提交到storm集群,并确保storm集群开启drpc服务。客户端相对独立的角色通过IP,DRPC服务端口,向拓扑提交计算参数,并获取计算结果。

DRPC拓扑的创建
DRPC拓扑与普通的拓扑区别仅仅在于构造拓扑所需的方法不同,storm提供了LinearDRPCTopologyBuilder方法来构造DRPC服务端。(LinearDRPCTopologyBuilder至少在0.9.6之后已经被废弃,响应的DRPC也由Trident实现)。
下面仍以旧版本的LinearDRPCTopologyBuilder来构造拓扑,至少可以了解DRPC的相关原理,也有助于理解之后的Trident。下面的代码修改于storm给出的示例代码BasicDRPCTopology。

package test.storm.starter;

import org.apache.storm.Config;
import org.apache.storm.LocalCluster;
import org.apache.storm.LocalDRPC;
import org.apache.storm.StormSubmitter;
import org.apache.storm.drpc.LinearDRPCTopologyBuilder;
import org.apache.storm.topology.BasicOutputCollector;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.base.BaseBasicBolt;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Tuple;
import org.apache.storm.tuple.Values;

public class BasicDRPCTopology {

    public static class ExclaimBolt extends BaseBasicBolt {
        @Override
        public void execute(Tuple tuple, BasicOutputCollector collector) {
            String input = tuple.getString(1);
            collector.emit(new Values(tuple.getValue(0), input + "!!!"));
        }

        @Override
        public void declareOutputFields(OutputFieldsDeclarer declarer) {
            declarer.declare(new Fields("id", "exclaim"));
        }
    }

    public static class StarBolt extends BaseBasicBolt {
        @Override
        public void execute(Tuple tuple, BasicOutputCollector collector) {
            String input = tuple.getString(1);
            collector.emit(new Values(tuple.getValue(0), input + "***"));
        }

        @Override
        public void declareOutputFields(OutputFieldsDeclarer declarer) {
            declarer.declare(new Fields("id", "result"));
        }
    }

    public static void main(String[] args) throws Exception {

        LinearDRPCTopologyBuilder builder = new LinearDRPCTopologyBuilder("exclamation");
        builder.addBolt(new ExclaimBolt(), 3);
        builder.addBolt(new StarBolt(), 3).shuffleGrouping();

        Config conf = new Config();

        if (args == null || args.length == 0) {
            LocalDRPC drpc = new LocalDRPC();
            LocalCluster cluster = new LocalCluster();

            cluster.submitTopology("drpc-demo", conf, builder.createLocalTopology(drpc));

            for (String word : new String[]{ "hello", "goodbye" }) {
                System.out.println("Result for \"" + word + "\": " + drpc.execute("exclamation", word));
            }

            Thread.sleep(10000);
            drpc.shutdown();
            cluster.shutdown();
        } else {
            conf.setNumWorkers(3);//进程数为3
            StormSubmitter.submitTopologyWithProgressBar(args[0], conf, builder.createRemoteTopology());
        }
    }
}

代码注释:
ExclaimBolt继承自BaseBasicBolt,BaseBasicBolt对于发送的每个元组封装了自动的进行ack()或者fail(),确保了可靠性。
execute方法会被不停的调用,前面曾提及Bolt的接收的元组第一个字段是DRPC Server提供的request ID,第二个字段是待计算的参数。ExclaimBolt将请求的参数加上”!!!”之后,和request ID拼成新的元组发出。
StarBolt和ExclaimBolt完全类似,但是它是拓扑中的最后一个bolt,它处理后的元组将以Fields(“id”, “result”)为字段名返回给DRPC Server。

DRPC构造器:创建函数名为”exclamation”线性DRPC构造器

LinearDRPCTopologyBuilder builder = new LinearDRPCTopologyBuilder("exclamation");

addBolt方法将bolt依次添加到DRPC构造器列表中,其第一个参数为实现了Bolt接口的方法,第二个参数为计算的并行度。
拓扑的创建使用createRemoteTopology方法,而不是createTopology方法。

提交拓扑到生产环境
将上述代码打包后提交到集群中,为了使用drpc服务,应首先确保已经使用 storm drpc开启drpc服务。

storm dprc //开启drpc服务
storm jar basicdrpc.jar test.storm.starter.BasicDRPCTopology BasicDRPC//将当前目录下的basicdrpc.jar提交到拓扑,拓扑名为BasicDRPC

DRPC客户端

//for storm-1.0.2及以上
依赖的jar包(jar包来源于storm安装包lib目录下)
log4j-api-2.1.jar
log4j-core-2.1.jar
log4j-slf4j-impl-2.1.jar
slf4j-api-1.7.7.jar
storm-core-1.0.2.jar

package test.TestDRPC;

import java.util.Map;
import org.apache.storm.utils.DRPCClient;
import org.apache.storm.utils.Utils;

public class TestDRPC {

    public static void main(String[] args) throws Exception {

        Map conf = Utils.readDefaultConfig();

        DRPCClient client = new DRPCClient(conf,"localhost",3772);//3772是drpc对外默认的服务端口

        //for storm-0.9.6
        //DRPCClient client = new DRPCClient("localhost",3772);

        String arr[] = new String []{"hello","world","storm","java","drpc"};
        for(String str:arr)
        {
            System.out.println("DRPC result:" + client.execute("exclamation", str));
        }
    }
}

随着storm版本的更新,DRPCClient的构造方法也发生了变化,相对于storm-0.9.6需要传入当前环境的参数。
execute()方法的第一个参数是函数名,也就是LinearDRPCTopologyBuilder builder = new LinearDRPCTopologyBuilder(“exclamation”);定义的函数名。
第二个参数就是需要exclamation计算的参数。
将客户端代码打成“可执行”的jar包,假设名为testDRPC.jar

(xxx@AS6U3.amd64)[root@xx xx]# java -jar testDRPC.jar
DRPC result:hello!!!***
DRPC result:world!!!***
DRPC result:storm!!!***
DRPC result:java!!!***
DRPC result:drpc!!!***

当然你要确保执行testDRPC.jar的服务是和storm集群是可以正常通信的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值