一、大数据技术背景
大数据的维度分为五维:大量、高速、多样、精确、价值。
大数据背景下,就是将数据集进行清洗处理,得到根据业务场景相关的各项指标。还可以通过开发分析引擎对各种指标的数据进行批处理作业,统计查询等。基本包括两大类型:分布式批处理以及实时计算。分布式批处理,可以看成离线处理,将数据收集到1个月一周或者一天进行处理,不要求纳秒/毫秒响应,应对不要求实时性的海量数据运算。这里不做过多讲解,等待小T的下一篇博客吧。
这里重点说下实时计算。
二、什么是实时处理
对于离线处理,自然就会出现实时处理。对于现实中的很多场景都需要进行实时计算处理,比如电信场景,电商猜你喜欢,收费站的分流处理,广告行业的精准投放,用户画像等等,都离不开实时计算的背景。
实时计算,就是需要一个复杂事件的处理引擎,以低延迟闪电速度进行处理以及查询结果,在本篇博客中利用storm进行实时计算的解决方案。
三、什么是storm
storm最初是来自Twitter的一个项目,后来贡献给Apache成为顶级开源项目。storm是一个高度可以扩展,分布式,快速,可靠地实时计算的解决方案的框架。它可以实现创建数据流模型,其中元组持续流过有处理组件集合而成的拓扑结构。可以配置数据来源。本篇讲述的数据来源只有kafka。
下面为storm功能流程图:
四、安装部署讲解。
好了,接下来进入正题了,小T前面写了一些概述性的文字,不喜欢看的同学可以直接看接下来的讲述。
由于本篇讲解的实时计算是基于:flume =>kafka =>storm =>redis进行集成的。
技术流程图如下所示:
接下来小T给大家讲述下各个工具的部署方式:
(1)flume部署安装:
flume的下载地址:http://flume.apache.org/download.html
下载完成后,将压缩包上传至linux服务器指定的目录下,编辑 conf 文件夹内的 flume-conf.properties.template 文件,修改方式如下所示:
a1.sources = taildir
a1.channels = pv-counter uv-counter
a1.sinks = pv-sink uv-sink
# Describe/configure the source
a1.sources.taildir.type = TAILDIR
a1.sources.taildir.positionFile = /home/bigdata/flume/partition/patition.json
a1.sources.taildir.filegroups = f1
a1.sources.taildir.filegroups.f1 = /data/.*.log
a1.sources.taildir.channels = pv-counter uv-counter
# interceptor
a1.sources.taildir.interceptors = interceptor
a1.sources.taildir.interceptors.interceptor.type = regex_extractor
a1.sources.taildir.interceptors.interceptor.regex = .*(pv_viewer|uv_viewer).*
a1.sources.taildir.interceptors.interceptor.serializers = s1
a1.sources.taildir.interceptors.interceptor.serializers.s1.name = key
# selector
a1.sources.taildir.selector.type = multiplexing
a1.sources.taildir.selector.header = key
a1.sources.taildir.selector.mapping.pv_viewer = pv-counter
a1.sources.taildir.selector.mapping.uv_viewer = uv-counter
a1.channels.pv-counte.type = memory
a1.channels.pv-counte.capacity=10000
a1.channels.pv-counte.byteCapacityBufferPercentage=2000
# uv-sink
a1.channels.uv-sink.type = memory
a1.channels.uv-sink.capacity=10000
a1.channels.uv-sink.byteCapacityBufferPercentage=2000
a1.sinks.pv-sink.type = org.apache.flume.sink.kafka.KafkaSink
a1.sinks.pv-sink.kafka.topic = pv-counter
a1.sinks.pv-sink.kafka.bootstrap.servers = 127.0.0.1:9092
a1.sinks.pv-sink.kafka.flumeBatchSize = 2000
a1.sinks.pv-sink.kafka.producer.acks = 1
a1.sinks.pv-sink.channel = pv-counter
# 替换相应的kafka的IP
a1.sinks.uv-sink.type = org.apache.flume.sink.kafka.KafkaSink
a1.sinks.uv-sink.kafka.topic = uv-counter
a1.sinks.uv-sink.kafka.bootstrap.servers = 127.0.0.1:9092
a1.sinks.uv-sink.kafka.flumeBatchSize = 2000
a1.sinks.uv-sink.kafka.producer.acks = 1
a1.sinks.uv-sink.channel = uv-sink
配置简单讲解:将 /data 目录下的 .log结尾的日志中有pv_viewer|uv_viewer 的进行处理,输出到kafak中,对应的topic名字为:pv-counter|uv-counter 。
然后进行执行命令:bin/flume-ng agent --conf conf --conf-file conf/flume-conf.properties --name a1 &
(2)kafka部署安装
kafka的安装利用docker进行构建安装
执行命令:docker pull wurstmeister/kafka,拉取kafka的docker镜像
然后进行执行运行命令:docker run -d --name kafka --publish 9092:9092 --link zookeeper --env KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181 --env KAFKA_ADVERTISED_HOST_NAME=127.0.0.1 --env KAFKA_ADVERTISED_PORT=9092 --volume /etc/localtime:/etc/localtime wurstmeister/kafka:latest
(3)storm安装(此处就按照demo讲解进行单机安装了)
storm下载地址:https://storm.apache.org/downloads.html
配置环境变量参数,修改/etc/profile文件,复制下面的参数:
export STORM_HOME=/home/storm-2.0.0
export PATH=$PATH:$STORM_HOME/bin
记下来修改 /conf 文件夹内的 storm.yaml,复制下面的配置:
storm.zookeeper.servers:
- "localhost"
nimbus.host: "master"
storm.local.dir: "/home/storm-2.0.0/data"
ui.port: 8889
supervisor.slots.ports:
- 6700
- 6701
- 6702
- 6703
ok了,配置完成接下来进行逐一命令启动,命令如下:
storm nimbus & ;
storm supervisor & ;
storm ui & ;
(4)redis部署安装:
redis部署同样利用docker进行简易部署,部署方式如下:
拉取redis的docker镜像:docker pull redis
然后运行docker:docker run -p 6378:6379 --name redisRealtime -v /usr/local/redis/etc/redis.conf:/etc/redis/redis.conf -v /usr/local/redis/data:/data -d redis redis-server /etc/redis/redis.conf --appendonly yes
五:实时计算开发
好了,讲解好了各种工具的部署完成之后,可以进行storm和kafak集成的项目开发了,接下来就是进行各项作业指标的开发。
整合讲解:
前端日志采集之后,通过flume配置对应的counter名称,然后输出到kafak的topic,开发storm和kakfa集成作业,通过topic消费数据,storm利用滑动窗口,进行配置每10秒收集数据,清洗之后,传递给下一个bolt进行内存聚合计算处理,然后存储到redis即可。
附着代码如下:
package cn.sparticles.service;
import cn.sparticles.service.bolt.DayPVViewsBolt;
import cn.sparticles.service.bolt.PVBolt;
import org.apache.storm.Config;
import org.apache.storm.LocalCluster;
import org.apache.storm.StormSubmitter;
import org.apache.storm.kafka.spout.KafkaSpout;
import org.apache.storm.kafka.spout.KafkaSpoutConfig;
import org.apache.storm.topology.TopologyBuilder;
public class MyKafkaTopology {
public static void main(String[] args) throws Exception {
KafkaSpoutConfig.Builder<String,String> builder = KafkaSpoutConfig.builder("127.0.0.1:9092","pv-counter");
builder.setProp("group.id","testStorm");
KafkaSpoutConfig<String, String> kafkaSpoutConfig= builder.build();
TopologyBuilder topologyBuilder = new TopologyBuilder();
topologyBuilder.setSpout("WordCountFileSpout",new KafkaSpout(kafkaSpoutConfig), 4);
topologyBuilder.setBolt("PVCount",new PVBolt()).shuffleGrouping("WordCountFileSpout");
topologyBuilder.setBolt("RedisPVCache",new DayPVViewsBolt()).shuffleGrouping("PVCount");
Config config = new Config();
if(args !=null && args.length > 0){
config.setDebug(false);
StormSubmitter submitter= new StormSubmitter();
submitter.submitTopology("kafkaStromTopo", config, topologyBuilder.createTopology());
}else{
config.setDebug(true);
LocalCluster cluster= new LocalCluster();
cluster.submitTopology("kafkaStromTopo", config, topologyBuilder.createTopology());
}
}
}
package cn.sparticles.service.bolt;
import cn.sparticles.utils.RedisUtil;
import com.google.common.collect.Lists;
import org.apache.commons.lang.StringUtils;
import org.apache.storm.Config;
import org.apache.storm.Constants;
import org.apache.storm.topology.BasicOutputCollector;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.base.BaseBasicBolt;
import org.apache.storm.tuple.Tuple;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DayPVViewsBolt extends BaseBasicBolt {
private List<String> list = Lists.newArrayList();
private String redisKey = "PVDayCount";
@Override
public void execute(Tuple input, BasicOutputCollector collector) {
if (!input.getSourceComponent().equalsIgnoreCase(Constants.SYSTEM_COMPONENT_ID)) { // 如果收到非系统级别的tuple,统计信息到局部变量mids
String logStr = input.getStringByField("logStr");
list.add(logStr);
}
else {
RedisUtil redisUtil = RedisUtil.getInstance();
String count = redisUtil.get(redisKey);
if(StringUtils.isBlank(count)){
count = "0";
}
redisUtil.set(redisKey,String.valueOf(Long.valueOf(count) + list.size()));
}
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer){
}
/**
* 定时任务进行执行
* @return
*/
@Override
public Map<String, Object> getComponentConfiguration() {
Map<String, Object> config = new HashMap<>();
config.put(Config.TOPOLOGY_TICK_TUPLE_FREQ_SECS, 10);
return config;
}
}
package cn.sparticles.service.bolt;
import cn.sparticles.model.LabelCommonModel;
import cn.sparticles.utils.FastJsonUtils;
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 PVBolt extends BaseBasicBolt {
/**
* 进行没10秒一次聚合,聚合完成传递下一个bolt进行redis存储持久化处理
* @param input
* @param collector
*/
@Override
public void execute(Tuple input, BasicOutputCollector collector) {
//进行格式化数据处理
String kafkaTopicMes = (String) input.getValue(4);
LabelCommonModel labelCommonModel = FastJsonUtils.toBean(kafkaTopicMes, LabelCommonModel.class);
collector.emit(new Values(labelCommonModel.getLogStr()));
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer){
declarer.declare(new Fields("logStr"));
}
}
执行之后,可以登录redis看到生成的key-value:
这个是本地运行模式,也可以部署到服务器的storm进行集群/单机处理,利用maven打包上传jar包到linux指定的目录然后执行命令如下:
storm jar storm-realtime.jar cn.sparticles.service.MyKafkaTopology.java pv
附着上github的源码地址:https://github.com/Jamsw/storm-realtime,喜欢的朋友给个星就好了哈~
ok,到这里基础的实时计算架构也算完成了,希望参考的同学可以针对各自的业务进行企业级或者个人版的开发,接下来有兴趣的朋友可以看下一篇讲解下 storm滑动窗口原理。