网站最常用的两个指标
pv: count(session_id)
uv: count(distinct session_id)
session_id是针对浏览器来说的,用户一进来就有
多线程下,注意线程安全问题
一:pv统计
方案分析
如何下是否可行:
1,定义static long PV,Synchronized控制累计操作
Synchronized和lock在单jvm下有效,但在多jvm下无效
可行的两个方案:
1,shuffleGrouping下,pv* Executor并发数
2,bolt1进行多并发局部汇总,bolt2单线程进行全局汇总
其中2最常用,因为存在你先按地区分,然后进行汇总的情况。就必须用fieldgrouping,不能用shufflegrouping
对于这种情况就比如下面两个代码
package visits; import backtype.storm.task.OutputCollector; import backtype.storm.task.TopologyContext; import backtype.storm.topology.IRichBolt; import backtype.storm.topology.OutputFieldsDeclarer; import backtype.storm.tuple.Fields; import backtype.storm.tuple.Tuple; import backtype.storm.tuple.Values; import java.util.Map; /** * Created by Administrator on 2016/10/6. */ public class PVBolt1 implements IRichBolt { /* 这种irichbolt形式就是成功的时候要显性的调ack方法 失败的时候掉fail方法 */ private static final long serialVersionUID = 1L; OutputCollector collector = null; @Override public void prepare(Map map, TopologyContext topologyContext, OutputCollector outputCollector) { //初始化方法 this.collector = outputCollector; } String logString = null; String sessionid = null; //static long Pv = 0; long Pv = 0; @Override public void execute(Tuple tuple) { logString = tuple.getString(0); sessionid = logString.split("\t")[1]; /* *//* 这种多线程下做计算我们还必须得有synchronized使它线程安全 这样肯定就和单线程一样 然而还是不够健全,因为synchronized和lock在单jvm下有效,单在多jvm下无效 *//* synchronized (this){ if(sessionid != null){ Pv ++; } }*/ //shuffleGrouping下,pv* Executor并发数就是统计的pv //因为shufflegrouping是平均分配,而我们有两个线程 // if(sessionid != null){ Pv ++; } collector.emit(new Values(Thread.currentThread().getId(),Pv)); //System.out.println("pv = "+ Pv * 2); System.out.println("threadid = "+ Thread.currentThread().getId()+" : pv="+Pv); } @Override public void cleanup() { } @Override public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) { /* 定义下输出类型 */ outputFieldsDeclarer.declare(new Fields("threadId", "pv")); } @Override public Map<String, Object> getComponentConfiguration() { return null; } }
package visits; import backtype.storm.task.OutputCollector; import backtype.storm.task.TopologyContext; import backtype.storm.topology.IRichBolt; import backtype.storm.topology.OutputFieldsDeclarer; import backtype.storm.tuple.Tuple; import java.util.HashMap; import java.util.Iterator; import java.util.Map; /** * Created by Administrator on 2016/10/6. * 汇总端得到的数据:每个线程发过来一个汇总数 */ public class PVSumBolt implements IRichBolt { /* 这种irichbolt形式就是成功的时候要显性的调ack方法 失败的时候掉fail方法 */ private static final long serialVersionUID = 1L; Map<Long, Long> counts = new HashMap<Long, Long>(); @Override public void prepare(Map map, TopologyContext topologyContext, OutputCollector outputCollector) { } //static long Pv = 0; long Pv = 0; @Override public void execute(Tuple tuple) { long threadID = tuple.getLong(0); long pv = tuple.getLong(1); counts.put(threadID, pv); long word_sum = 0; //获得总数,遍历counts的values,进行sum Iterator<Long> i = counts.values().iterator(); while(i.hasNext()){ word_sum += i.next(); } /* *//* 这种多线程下做计算我们还必须得有synchronized使它线程安全 这样肯定就和单线程一样 然而还是不够健全,因为synchronized和lock在单jvm下有效,单在多jvm下无效 *//* synchronized (this){ if(sessionid != null){ Pv ++; } }*/ //shuffleGrouping下,pv* Executor并发数就是统计的pv //因为shufflegrouping是平均分配,而我们有两个线程 // System.out.println("pv = "+ Pv * 2); } @Override public void cleanup() { } @Override public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) { } @Override public Map<String, Object> getComponentConfiguration() { return null; } }
TopologyBuilder builder = new TopologyBuilder(); builder.setSpout("spout", new MySpout(), 1); builder.setBolt("bolt", new PVBolt1(), 4).shuffleGrouping("spout"); /* 对单线程来讲,什么grouping都是一样的。。 */ builder.setBolt("sumBolt", new PVSumBolt(), 1).shuffleGrouping("bolt");
线程不安全:
多线程处理的结果和单线程一样,一样就是安全,不一样就是不安全