Distributed RPC

来源:互联网 发布:linux c编程 编辑:程序博客网 时间:2024/05/16 07:58

distributedRPC (DRPC)中的思想是对Storm上许多Function计算的并行化。Stormtopologyfunction参数流作为输入,emits这些Function调用的结果作为输出。DRPC并不是Storm的特征,而是由Stormprimitive,即由streams,spouts, bolts, and topologies表达的patternDRPC被打包为独立于Stormlibrary,但非常有用以至于被Storm绑定。

概览

Distributed RPC"DRPC server"协调,DRPC server协调接收一个RPC request,分发requestStorm topology,接收Storm topology的结果并发送结果给等待的clientDistributedRPC调用如同普通的RPCcall,比如,how a client如何计算带有参数"http://twitter.com"function“reach”的结果:

DRPCClient client = new DRPCClient("drpc-host", 3772);String result = client.execute("reach", "http://twitter.com");

distributed RPC 工作流如下:

clientDRPCserver发送需要执行的functionargumentstopology使用DRPCSpoutDRPCserver接收一个Function调用流,每一个function调用被DRPC server打上unique id作为标签,topology计算结果,最后由topology最后一个名为ReturnResultsbolt连接DRPC server并返回Function调用id的结果。DRPCserver用此id匹配client正在等待的结果,unblocks等待的client并发送结果给它。

LinearDRPCTopologyBuilder

Storm中名为LinearDRPCTopologyBuildertopology builder 自动完成DRPC调用几乎全部步骤:

  1. 设置spout

  2. 返回结果给DRPCserver

  3. 赋予bolts功能,为每组tuple实现最终的汇总操作

如下例,实现一个DRPCtopology,为输入参数添加"!"

public static class ExclaimBolt extends BaseBasicBolt {    public void execute(Tuple tuple, BasicOutputCollector collector) {        String input = tuple.getString(1);        collector.emit(new Values(tuple.getValue(0), input + "!"));    }    public void declareOutputFields(OutputFieldsDeclarer declarer) {        declarer.declare(new Fields("id", "result"));    }}public static void main(String[] args) throws Exception {    LinearDRPCTopologyBuilder builder = new LinearDRPCTopologyBuilder("exclamation");//告诉topology需要执行的DRPC function名,DRPC server利用此名与其他Function调用相区分加以协调。
    builder.addBolt(new ExclaimBolt(), 3);//首个bolt带有2-tuple参数,request id和此request的参数;而最后一个bolt emit一个形如[id,result] 2-tuple的输出流;最后,所有中间tuple必须以request id作为第一个Field // ...}
此例,ExclaimBolt为tuple的第二个field添加"!", LinearDRPCTopologyBuilder处理连接DRPC server和返回结果的协调工作。


Local mode DRPC

以上实例的在Local mode下:

LocalDRPC drpc = new LocalDRPC();LocalCluster cluster = new LocalCluster();cluster.submitTopology("drpc-demo", conf, builder.createLocalTopology(drpc));System.out.println("Results for 'hello':" + drpc.execute("exclamation", "hello"));cluster.shutdown();drpc.shutdown();

首先创建一个LocalDRPC对象,在流程中它仿真DRPC server,正如LocalCluster仿真Stormcluster。然后创建LocalClusterlocal mode下运行topology

LinearDRPCTopologyBuilder 分别拥有创建localtopologiesremote topologies的方法。在localmode下,LocalDRPC对象并不绑定任何porttopology知道它通信的对象。这是为什么createLocalTopologyLocalDRPC对象作为输入。发起topology之后,DRPC调用在LocalDRPC上的execute方法。

Remote mode DRPC

在真实的Storm集群上使用DRPC

  1. 发起DRPC server(s)

  2. 配置DRPCservers地址

  3. Storm集群上提交DRPC topologies

发起一个DRPCserver可由storm脚本完成,正如发起Nimbus或者UI:

bin/storm drpc

接下来,在Stormcluster中配置DRPCserver(s)的地址,由此DRPCSpout知道在哪里读取function invocations。这可由storm.yaml文件或topology configurations完成,storm.yaml完成的配置如下:

drpc.servers:  - "drpc1.foo.com"  - "drpc2.foo.com"

最后,StormSubmitter发起DRPCtopologies,以remote mode运行上例:

StormSubmitter.submitTopology("exclamation-drpc", conf, builder.createRemoteTopology());

createRemoteTopology 用于创建适于Storm clusterstopologies

A more complex example

此例需要在Stormcluster上并行计算DRPCfunction。它计算TwitterURLreachreach就是一个人在Twitter上打开此URL的次数,为此:

  1. 获取所有tweeted到此URL的人

  2. 获取这些人的所有followers

  3. followers集合去重

  4. 计算followers集合唯一计数

计算过程中,需要调用上千次database calls并访问千万级的followerrecords,属于密集计算。在单机上,此计算需要花费数分钟;在Storm集群上,可在秒级完成最难的URLreach计算。定义reach topology

LinearDRPCTopologyBuilder builder = new LinearDRPCTopologyBuilder("reach");builder.addBolt(new GetTweeters(), 3);builder.addBolt(new GetFollowers(), 12)        .shuffleGrouping();builder.addBolt(new PartialUniquer(), 6)        .fieldsGrouping(new Fields("id", "follower"));builder.addBolt(new CountAggregator(), 2)        .fieldsGrouping(new Fields("id"));

执行如下4steps:

  1. GetTweeters获取所有tweeted URL的用户,它转换输入流[id,url]为输出流[id,tweeter],每一url tuple将匹配多个tweeter tuples.

  2. GetFollowers获取tweetersfollowers。它转换输入流[id,tweeter]为输出流[id,follower]跨越所有的task,这必然存在重复的followertuples,因为一个人可以follow多个人去tweeted相同的URL

  3. PartialUniquerfolloweridfollowers流分组,有效的将相同的follower化入同一个taskPartialUniquer的每一个task将接受彼此独立的followers集合,OncePartialUniquer一旦为requestid直接接受所有的followertuples,则emitfollowers子集合的去重计数。

  4. 最后,CountAggregator接受每个PartialUniquer部分计数并作总计。

PartialUniquer bolt代码:

public class PartialUniquer extends BaseBatchBolt {    BatchOutputCollector _collector;    Object _id;    Set<String> _followers = new HashSet<String>();    @Override    public void prepare(Map conf, TopologyContext context, BatchOutputCollector collector, Object id) {        _collector = collector;        _id = id;    }    @Override    public void execute(Tuple tuple) {        _followers.add(tuple.getString(1));    }    @Override    public void finishBatch() {        _collector.emit(new Values(_id, _followers.size()));    }    @Override    public void declareOutputFields(OutputFieldsDeclarer declarer) {        declarer.declare(new Fields("id", "partial-count"));    }}

PartialUniquer通过扩展BaseBatchBolt实现接口IBatchBoltbatchbolt提供API将批量tuples作为一个实际单位进行处理,为每一个requestid创建一个batchbolt的新实例,Storm在适当的时候负责清理实例。

PartialUniquerexecute函数接受一follower tuple并将之加入到为此requestid设置的HashSetfinishBatch函数在本task批处理完成后调用,PartialUniqueremits一单个tuple,其中包含follower ids的子集和它的去重计数。

在底层,CoordinatedBolt用于知道一个给定的bolt何时接受到一requestid对应的所有tuplesCoordinatedBolt使用directstreams来管理此协调。

reach计算的每一步都是并行的,定义DRPC Topology是相当简单的。

Non-linear DRPC topologies

LinearDRPCTopologyBuilder仅处理线性DRPCtopologies,其计算为一序列步骤,直接利用CoordinatedBolt因此不能胜任解决bolt之间的分支、合并等复杂计算。


0 0
原创粉丝点击