一、Storm集成redis前的准备
首先是需要安装storm和redis环境,具体安装方法可分别去http://storm.apache.org/和http://redis.io查询,安装完成之后 需要准备运行所需要的jar包,除了storm本身lib下的jar包外,操作redis还需要guava-12.0.1、jedis-2.7.2、commons-pool2-2.3.jar、hamcrest-core-1.3.jar和storm-redis-0.10.0.jar,将其引入即可
二、代码
具体的实例代码在storm-1.10.0的版本中自带,具体可以去下载storm的1.10.0的源码中自行查找,下面将wordcount的集成实例代码列下,spout/bolt的topology主要需要三个文件,分别为PersistentWordCount.java、WordSpout.java和WordCount.java,代码如下:(对trident感兴趣的,源码中也有实例程序,可自行查找学习)
/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.storm.redis.topology; import backtype.storm.Config; import backtype.storm.LocalCluster; import backtype.storm.StormSubmitter; import backtype.storm.topology.OutputFieldsDeclarer; import backtype.storm.topology.TopologyBuilder; import backtype.storm.tuple.Fields; import backtype.storm.tuple.ITuple; import backtype.storm.tuple.Tuple; import org.apache.storm.redis.bolt.AbstractRedisBolt; import org.apache.storm.redis.bolt.RedisStoreBolt; import org.apache.storm.redis.common.config.JedisClusterConfig; import org.apache.storm.redis.common.config.JedisPoolConfig; import org.apache.storm.redis.common.mapper.RedisDataTypeDescription; import org.apache.storm.redis.common.mapper.RedisStoreMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import redis.clients.jedis.JedisCommands; import redis.clients.jedis.exceptions.JedisConnectionException; import redis.clients.jedis.exceptions.JedisException; public class PersistentWordCount { private static final String WORD_SPOUT = "WORD_SPOUT"; private static final String COUNT_BOLT = "COUNT_BOLT"; private static final String STORE_BOLT = "STORE_BOLT"; private static final String TEST_REDIS_HOST = "127.0.0.1"; private static final int TEST_REDIS_PORT = 6379; public static void main(String[] args) throws Exception { Config config = new Config(); String host = TEST_REDIS_HOST; int port = TEST_REDIS_PORT; if (args.length >= 2) { host = args[0]; port = Integer.parseInt(args[1]); } JedisPoolConfig poolConfig = new JedisPoolConfig.Builder() .setHost(host).setPort(port).build(); WordSpout spout = new WordSpout(); WordCounter bolt = new WordCounter(); RedisStoreMapper storeMapper = setupStoreMapper(); RedisStoreBolt storeBolt = new RedisStoreBolt(poolConfig, storeMapper); // wordSpout ==> countBolt ==> RedisBolt TopologyBuilder builder = new TopologyBuilder(); builder.setSpout(WORD_SPOUT, spout, 1); builder.setBolt(COUNT_BOLT, bolt, 1).fieldsGrouping(WORD_SPOUT, new Fields("word")); builder.setBolt(STORE_BOLT, storeBolt, 1).shuffleGrouping(COUNT_BOLT); if (args.length == 2) { LocalCluster cluster = new LocalCluster(); cluster.submitTopology("test", config, builder.createTopology()); Thread.sleep(30000); cluster.killTopology("test"); cluster.shutdown(); System.exit(0); } else if (args.length == 3) { StormSubmitter.submitTopology(args[2], config, builder.createTopology()); } else { System.out.println("Usage: PersistentWordCount <redis host> <redis port> (topology name)"); } } private static RedisStoreMapper setupStoreMapper() { return new WordCountStoreMapper(); } private static class WordCountStoreMapper implements RedisStoreMapper { private RedisDataTypeDescription description; private final String hashKey = "wordCount"; public WordCountStoreMapper() { description = new RedisDataTypeDescription( RedisDataTypeDescription.RedisDataType.HASH, hashKey); } @Override public RedisDataTypeDescription getDataTypeDescription() { return description; } @Override public String getKeyFromTuple(ITuple tuple) { return tuple.getStringByField("word"); } @Override public String getValueFromTuple(ITuple tuple) { return tuple.getStringByField("count"); } } }
/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.storm.redis.topology; import backtype.storm.spout.SpoutOutputCollector; import backtype.storm.task.TopologyContext; import backtype.storm.topology.IRichSpout; import backtype.storm.topology.OutputFieldsDeclarer; import backtype.storm.tuple.Fields; import backtype.storm.tuple.Values; import java.util.Map; import java.util.Random; import java.util.UUID; public class WordSpout implements IRichSpout { boolean isDistributed; SpoutOutputCollector collector; public static final String[] words = new String[] { "apple", "orange", "pineapple", "banana", "watermelon" }; public WordSpout() { this(true); } public WordSpout(boolean isDistributed) { this.isDistributed = isDistributed; } public boolean isDistributed() { return this.isDistributed; } @SuppressWarnings("rawtypes") public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) { this.collector = collector; } public void close() { } public void nextTuple() { final Random rand = new Random(); final String word = words[rand.nextInt(words.length)]; this.collector.emit(new Values(word), UUID.randomUUID()); Thread.yield(); } public void ack(Object msgId) { } public void fail(Object msgId) { } public void declareOutputFields(OutputFieldsDeclarer declarer) { declarer.declare(new Fields("word")); } @Override public void activate() { } @Override public void deactivate() { } @Override public Map<String, Object> getComponentConfiguration() { return null; } }
/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.storm.redis.topology; import backtype.storm.task.TopologyContext; import backtype.storm.topology.BasicOutputCollector; import backtype.storm.topology.IBasicBolt; import backtype.storm.topology.OutputFieldsDeclarer; import backtype.storm.tuple.Fields; import backtype.storm.tuple.Tuple; import backtype.storm.tuple.Values; import com.google.common.collect.Maps; import java.util.Map; import static backtype.storm.utils.Utils.tuple; public class WordCounter implements IBasicBolt { private Map<String, Integer> wordCounter = Maps.newHashMap(); @SuppressWarnings("rawtypes") public void prepare(Map stormConf, TopologyContext context) { } public void execute(Tuple input, BasicOutputCollector collector) { String word = input.getStringByField("word"); int count; if (wordCounter.containsKey(word)) { count = wordCounter.get(word) + 1; wordCounter.put(word, wordCounter.get(word) + 1); } else { count = 1; } wordCounter.put(word, count); collector.emit(new Values(word, String.valueOf(count))); } public void cleanup() { } public void declareOutputFields(OutputFieldsDeclarer declarer) { declarer.declare(new Fields("word", "count")); } @Override public Map<String, Object> getComponentConfiguration() { return null; } }
三、查看结果
运行PersistentWordCount,在命令行中键入
src/redis-cli
进入到redis的client,输入命令
HGETALL wordCount
即可查看到结果