Apache Storm是目前最流行的实时计算框架之一,基于 streams, spouts, bolts, and topologies这些基本组件,可以组合出一些计算模式,每个模式对应解决一类现实中的问题。
下面介绍几种计算模式,并给出代码示例,希望对读者有所帮助:
模式1: JOIN
Join一般是指基于某个共同的属性,把2类内容合并到一起。传统数据库的join,定义和逻辑都非常明确,有left join, right join , full join 等。
两个实时流之间的join,指的是在某个时间窗口内,两个流根据某些共同的字段来做匹配。比如有这个需求:某个网络广告系统,实时地产生所投放的广告的点击日志和展示日志,需要统计出广告每分钟的点击率(点击量/展示量)。输入是2个日志流点击日志和展示日志,输出是所有广告前一分钟的实时点击率(每5秒刷新一次)。
下面给出一个Join Bolt execute里的代码
@Override public void execute(TupleWindow inputWindow) { Map<String, Integer> pvmap = new HashMap<>(); Map<String, Integer> clickmap = new HashMap<>(); for(Tuple tuple: inputWindow.get()) { if(tuple.getSourceComponent().equalsIgnoreCase("log_pv")) { String brand = tuple.getStringByField("brand"); pvmap.put(brand, (pvmap.get(brand) != null ? pvmap.get(brand) : 0) + 1); } if(tuple.getSourceComponent().equalsIgnoreCase("log_click")) { String brand = tuple.getStringByField("brand"); clickmap.put(brand, (clickmap.get(brand) != null ? clickmap.get(brand) : 0) + 1); } _collector.ack(tuple); } for(String brand : pvmap.keySet()){ _collector.emit(new Values( new Object [] {brand, ((clickmap.get(brand) != null ? clickmap.get(brand) : 0)/(double)pvmap.get(brand))})); } }
模式2: 精简模式
很多时候,实时处理的工作很简单,只是对输入的数据进行筛选、转换格式等,这时候可以用精简模式把代码了减到最少。
看看一个简单的Bolt可以有多简洁:
public class BriefBold extends BaseBasicBolt { @Override public void execute(Tuple tuple, BasicOutputCollector basicOutputCollector) { String v = tuple.getString(0); if (v == null || v.length() <= 5) { } else { basicOutputCollector.emit(new Values(v)); } } @Override public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) { outputFieldsDeclarer.declare(new Fields("value_out")); } }
模式3:TOP N模式
实时地显示排名是个常见的需求,比如阿里巴巴的双十一,需要实时显示前10秒订单数Top 10的商家。这个时候的输入是商家名+成交单数的实时流,输出是排名前十的商家名和成交单数。
最简单的方法是计算并保存所有商家的成交单数,按单数排序并输出前10,可是如果商家非常多,如何“并行”计算呢?
TOP N 模式的逻辑是:首先按商家名进行“feildsGrouping", 可以设置很多个worker同时统计,每个worker保存它所看到的商家名和订单数,并维护一个topN列表,根据设置的实际间隔emit出topN的值。
下面再接一个”globalGrouping“, 也就是这个worker只接收潜在topN的商家信息,归并排序后即可得到最终的topN。
TopN的代码有点复杂,不在这里贴了,推荐一个帖子(storm starter 里演示topN功能的例子就是这个帖子的作者写的)
http://www.michael-noll.com/blog/2013/01/18/implementing-real-time-trending-topics-in-storm/
下面是几个实用工具
1 LRU cache:
Least Recently Used Cache,当cache容量满了以后,删除最少使用的那个值。LRU cache 可以通过java自带的LinkedHashMap很方便地实现。
2 TimeCacheMap: 删除
超过设定时间没有被更新的值
3 Tick tuple: 如何让spout/bolt定时地做一些事?比如隔几秒钟就把数据写入外部数据库,隔一段时间就上报目前的状态等。只需要简单价格配置
conf.put(Config.TOPOLOGY_TICK_TUPLE_FREQ_SECS, seconds);就可以没隔设定的实际收到一个特殊的tuple,然后就可以在execute函数里做设定的定时动作了。