本次项目是基于企业大数据经典案例项目(大数据日志分析),全方位、全流程讲解 大数据项目的业务分析、技术选型、架构设计、集群规划、安装部署、整合继承与开发和web可视化交互设计。
项目代码托管于github,大家可以自行下载。
一、业务需求分析
- 捕获用户浏览日志信息
- 实时分析前20名流量最高的新闻话题
- 实时统计当前线上已曝光的新闻话题
- 统计哪个时段用户浏览量最高
- 生成报表(给销售人员以及Boss参考)
二、系统架构图设计
三、系统数据流程设计
四、集群资源规划设计
五、步骤详解
考虑到实际情况,本人集群配置共三个节点(netcloud03、netcloud04、netcloud05)。
1. Zookeeper分布式集群部署
参考博客
2. Hadoop2.X HA架构与部署
Hadoop 版本选择:
(1)基于Apache厂商的最原始的hadoop版本, 所有发行版均基于这个版本进行改进。
(2)基于Cloudera厂商的cdh版本,Cloudera有免费版和企业版, 企业版只有试用期。不过cdh大部分功能都是免费的。
需要配置的文件(6个文件):
1)修改 hadoo-env.sh(配置java环境变量)、2)修改 hdfs-site.xml (nameservice配置,HA的NameNode,jounalNode、副本数目)、3)修改 core-site.xml (指定NameService) 4)修改mapred-site.xml (指定mr框架为yarn方式)、5)修改yarn-site.xml (指定resourcemanager地址,指定zk集群地址 )6)修改slaves
参考博客
3. HBase分布式集群部署与设计
参考博客
4. Kafka分布式集群部署
参考博客
5. Flume部署及数据采集准备
netcloud03节点用作netcloud04与netcloud05节点的数据合并。
netcloud04节点flume的配置如下:
1)重命名 conf/flume-env.sh.template 为 flume-env.sh
重命名 conf/flume-conf.properties.template 为 flume-conf
2) 在flume-env.sh 中配置JDK安装目录
3) 在flume-conf 中配置
a2.sources = r1
a2.sinks = k1
a2.channels = c1
#source的配置
a2.sources.r1.type = exec
a2.sources.r1.command = tail -F /opt/data/weblog-flume.log
a2.sources.r1.channels = c1
#channel的配置
a2.channels.c1.type = memory
a2.channels.c1.capacity = 1000
a2.channels.c1.transactionCapacity = 1000
a2.channels.c1.keep-alive = 5
#type为avro 表示数据不存储到磁盘而是到 netcloud03节点
a2.sinks.k1.type = avro
a2.sinks.k1.channel = c1
a2.sinks.k1.hostname = netcloud03
a2.sinks.k1.port = 5555
netcloud05节点flume的配置如下:
1)重命名 conf/flume-env.sh.template 为 flume-env.sh
重命名 conf/flume-conf.properties.template 为 flume-conf
2) 在flume-env.sh 中配置JDK安装目录
3) 在flume-conf 中配置 a3为agent的别名 也可以使用官方的默认的值
a3.sources = r1
a3.sinks = k1
a3.channels = c1
#source的配置
a3.sources.r1.type = exec
a3.sources.r1.command = tail -F /opt/data/weblog-flume.log
a3.sources.r1.channels = c1
#channel的配置
a3.channels.c1.type = memory
a3.channels.c1.capacity = 1000
a3.channels.c1.transactionCapacity = 1000
a3.channels.c1.keep-alive = 5
#type为avro 表示数据不存储到磁盘而是到 netcloud03节点
a3.sinks.k1.type = avro
a3.sinks.k1.channel = c1
a3.sinks.k1.hostname = netcloud03
a3.sinks.k1.port = 5555
netcloud04和netcloud05节点可以实时的从磁盘weblog-flume.log 文件中收集数据(模拟程序向文件中生成数据)
netcloud03节点的配置如下
6. Flume+HBase+Kafka集成与开发
版本兼容问题
Flume 1.7.0+Kafka2.11_0.9.0
1. 下载Flume源码并导入Idea开发工具
1)将apache-flume-1.7.0-src.tar.gz源码下载到本地解压
2)通过idea导入flume源码
打开idea开发工具,选择File——》Open
然后找到flume源码解压文件,选中flume-ng-hbase-sink,点击ok加载相应模块的源码。
2. 官方flume与hbase集成的参数介绍
3. 下载日志数据并分析
到搜狗实验室下载用户查询日志
1)介绍
搜索引擎查询日志库设计为包括约1个月(2008年6月)Sogou搜索引擎部分网页查询需求及用户点击情况的网页查询日志数据集合。为进行中文搜索引擎用户行为分析的研究者提供基准研究语料。
2)格式说明
数据格式为:访问时间\t用户ID\t[查询词]\t该URL在返回结果中的排名\t用户点击的顺序号\t用户点击的URL
其中,用户ID是根据用户使用浏览器访问搜索引擎时的Cookie信息自动赋值,即同一次使用浏览器输入的不同查询对应同一个用户ID
4. netcloud03聚合节点与HBase和Kafka的集成配置
netcloud03通过flume接收netcloud04与netcloud05中flume传来的数据,并将其分别发送至hbase与kafka中,配置内容如下
a1.sources = r1
a1.channels = kafkaC hbaseC
a1.sinks = kafkaSink hbaseSink
a1.sources.r1.type = avro
a1.sources.r1.channels = hbaseC kafkaC
a1.sources.r1.bind = netcloud03
a1.sources.r1.port = 5555
a1.sources.r1.threads = 5
#****************************flume + hbase******************************
a1.channels.hbaseC.type = memory
a1.channels.hbaseC.capacity = 10000
a1.channels.hbaseC.transactionCapacity = 10000
a1.channels.hbaseC.keep-alive = 20
a1.sinks.hbaseSink.type = asynchbase
a1.sinks.hbaseSink.table = weblogs
a1.sinks.hbaseSink.columnFamily = info
a1.sinks.hbaseSink.serializer = org.apache.flume.sink.hbase.KfkAsyncHbaseEventSerializer
a1.sinks.hbaseSink.channel = hbaseC
a1.sinks.hbaseSink.serializer.payloadColumn = datetime,userid,searchname,retorder,cliorder,cliurl
#****************************flume + kafka******************************
a1.channels.kafkaC.type = memory
a1.channels.kafkaC.capacity = 10000
a1.channels.kafkaC.transactionCapacity = 10000
a1.channels.kafkaC.keep-alive = 20
a1.sinks.kafkaSink.channel = kafkaC
a1.sinks.kafkaSink.type = org.apache.flume.sink.kafka.KafkaSink
a1.sinks.kafkaSink.brokerList = netcloud03:9092,netcloud04:9092,netcloud05:9092
a1.sinks.kafkaSink.topic = weblogs
a1.sinks.kafkaSink.zookeeperConnect = node5:2181,node6:2181,node7:2181
a1.sinks.kafkaSink.requiredAcks = 1
a1.sinks.kafkaSink.batchSize = 1
a1.sinks.kafkaSink.serializer.class = kafka.serializer.StringEncoder
5. 对日志数据进行格式处理
1)将文件中的tab更换
cat weblog.log|tr "\t" "," > weblog2.log
2)将文件中的空格更换成逗号
cat weblog2.log|tr " " "," > weblog.log
6. 自定义SinkHBase程序设计与开发
1)模仿SimpleAsyncHbaseEventSerializer自定义KfkAsyncHbaseEventSerializer实现类,修改一下代码即可
/**
* 自定义
*/
public class KfkAsyncHbaseEventSerializer implements AsyncHbaseEventSerializer {
// 表名
private byte[] table;
// 列族
private byte[] cf;
// 列值
private byte[] payload;
// 列名
private byte[] payloadColumn;
private byte[] incrementColumn;
// 行键前缀
private String rowPrefix;
private byte[] incrementRow;
// 生成行键的方式
private KeyType keyType;
/*初始化的时候就得到表名和列簇名*/
@Override
public void initialize(byte[] table, byte[] cf) {
this.table = table;
this.cf = cf;
}
/*执行的方法*/
@Override
public List<PutRequest> getActions() {
List<PutRequest> actions = new ArrayList<PutRequest>();
if (payloadColumn != null) {
byte[] rowKey;
try {
/*---------------------------代码修改开始---------------------------------*/
// 解析列字段 a1.sinks.hbaseSink.serializer.payloadColumn = datetime,userid,searchname,retorder,c
String[] columns = new String(payloadColumn).split(",");
// 解析flume采集过来的每行的值
String[] values = new String(payload).split(",");
for (int i = 0; i < columns.length; i++) {
byte[] colColumn = columns[i].getBytes();
byte[] colValue = values[i].getBytes(Charsets.UTF_8);
// 数据校验:字段和值是否对应
if (columns.length != values.length) break;
String datetime = values[0].toString();
String userId = values[1].toString();
rowKey = SimpleRowKeyGenerator.getKfkRowKey(userId, datetime);//获取自定义RowKey
PutRequest putRequest = new PutRequest(table, rowKey, cf,
colColumn, colValue);
actions.add(putRequest);
/*---------------------------代码修改结束---------------------------------*/
}
} catch (Exception e) {
throw new FlumeException("Could not get row key!", e);
}
}
return actions;
}
2)在SimpleRowKeyGenerator类中,根据具体业务自定义Rowkey生成方法
// 根据业务需求自定义rowKey
public static byte[] getKfkRowKey(String userId, String datetime) throws UnsupportedEncodingException {
return (userId + datetime + String.valueOf(System.nanoTime())).getBytes("UTF8");
}
3) 执行命令打包:mvn install -Dmaven.test.skip=true
4) 镜像添加:
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
7. 自定义编译程序打jar包
1)在idea工具中,选择File——》ProjectStructrue
2)左侧选中Artifacts,然后点击右侧的+号,最后选择JAR——》From modules with dependencies
3)然后直接点击ok
4)删除其他依赖包,只把flume-ng-hbase-sink打成jar包就可以了。
5)然后依次点击apply,ok
6)点击build进行编译,会自动打成jar包
7)到项目的apache-flume-1.7.0-src\flume-ng-sinks\flume-ng-hbase-sink\classes\artifacts\flume_ng_hbase_sink_jar目录下找到刚刚打的jar包
8)将打包名字替换为flume自带的包名flume-ng-hbase-sink-1.7.0.jar ,然后上传至flume/lib目录下,覆盖原有的jar包即可。
7. 数据采集/存储/分发完整流程测试
1. 在idea开发工具中构建weblogs项目,编写数据生成模拟程序。
package com.example.weblogs;
import java.io.*;
public class ReadWrite {
static String readFileName;
static String writeFileName;
public static void main(String args[]) {
readFileName = args[0];
writeFileName = args[1];
try {
// readInput();
readFileByLines(readFileName);
} catch (Exception e) {
}
}
public static void readFileByLines(String fileName) {
FileInputStream fis = null;
InputStreamReader isr = null;
BufferedReader br = null;
String tempString = null;
try {
System.out.println("以行为单位读取文件内容,一次读一整行:");
fis = new FileInputStream(fileName);// FileInputStream
// 从文件系统中的某个文件中获取字节
isr = new InputStreamReader(fis, "GBK");
br = new BufferedReader(isr);
int count = 0;
while ((tempString = br.readLine()) != null) {
count++;
// 显示行号
Thread.sleep(300);
String str = new String(tempString.getBytes("UTF8"), "GBK");
System.out.println("row:" + count + ">>>>>>>>" + tempString);
method1(writeFileName, tempString);
}
isr.close();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (isr != null) {
try {
isr.close();
} catch (IOException e1) {
}
}
}
}
public static void method1(String file, String conent) {
BufferedWriter out = null;
try {
out = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(file, true)));
out.write("\n");
out.write(conent);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2. 参照前面idea工具项目打包方式,将该项目打成weblogs.jar包,然后上传至netcloud03节点的/usr/local/data/jars目录下(目录需要提前创建)
3. 将weblogs.jar分发到另外两个节点(netcloud04和netcloud05) 修改权限 : chmod 777 weblogs.jar
1)在另外两个节点上分别创建/usr/local/data/jars目录
mkdir /usr/local/data/jars
2)将weblogs.jar分发到另外两个节点
scp weblogs.jar netcloud04:/usr/local/data/jars
scp weblogs.jar netcloud05:/usr/local/data/jars
4. 编写运行模拟程序的shell脚本
在netcloud04和netcloud05节点的/usr/local/data/目录下,创建weblog-shell.sh脚本。内容为
#/bin/bash
echo "start log......"
#第一个参数是原日志文件,第二个参数是日志生成输出文件
java -jar /usr/local/data/jars/weblogs.jar /usr/local/data/weblog.log /usr/local/data/weblog-flume.log
修改weblog-shell.sh可执行权限
chmod 777 weblog-shell.sh
5. 编写启动flume服务程序的shell脚本
在各节点的flume安装目录下编写flume启动脚本flume-kfk-start.sh。
下面是netcloud03中的配置写法,netcloud04与netcloud05中将a1分别改为a2和a3。
#/bin/bash
echo "flume-1 start ......"
bin/flume-ng agent --conf conf -f conf/flume-conf -n a1 -Dflume.root.logger=INFO,console
6. 编写Kafka Consumer执行脚本kfk-test-consumer.sh。
#/bin/bash
echo "kfk-kafka-consumer.sh start......"
bin/kafka-console-consumer.sh --zookeeper netcloud03:2181,netcloud04:2181,netcloud05:2181 --from-beginning --topic weblogs
7. 将kfk-test-consumer.sh脚本分发另外两个节点
scp kfk-test-consumer.sh netcloud04:/usr/local/kafka_2.10/
scp kfk-test-consumer.sh netcloud05:/usr/local/kafka_2.10/
8. 启动模拟程序并测试
在netcloud04节点启动日志产生脚本,模拟产生日志是否正常。
/usr/local/data/weblog-shell.sh
9. 启动数据采集所有服务
1)启动Zookeeper服务 zkServer.sh start
2)启动hdfs服务 start-dfs.sh start-yarn.sh
3)启动HBase服务 start-hbase.sh
创建hbase业务表
create 'weblogs','info'
4)3台机器启动Kafka服务,并在netcloud03节点创建业务数据topic
bin/kafka-server-start.sh config/server.properties &
bin/kafka-topics.sh --create --zookeeper netcloud03:2181,netcloud04:2181,netcloud05:2181 --topic weblogs --partitions 1 --replication-factor 3
10. 完成数据采集全流程测试
1)在netcloud04和netcloud05节点上完成数据采集。
(1)使用shell脚本模拟日志产生
cd /usr/local/data
./weblog-shell.sh
(2)netcloud04、netcloud05 启动flume采集日志数据发送给聚合节点
2)在netcloud03节点上启动flume聚合脚本,将采集的数据分发到Kafka集群和hbase集群。(Hbase相关类找不到异常,将 Hbase的jar包拷贝到 flume的lib下)
./flume-kfk-start.sh
3)启动Kafka Consumer查看flume日志采集情况
bin/kafka-console-consumer.sh --zookeeper netcloud03:2181,netcloud04:2181,netcloud05:2181 --from-beginning --topic weblogs
4)查看hbase数据写入情况
./hbase-shell
scan 'weblogs
8. MySQL安装
9. Hive与HBase集成进行数据分析
1. Hive安装(本地mysql模式),参考博客
2. Hive与HBase集成
1)在hive-site.xml文件中配置Zookeeper,hive通过这个参数去连接HBase集群。也可以将Hbase的配置文件复制到hive的配 置文件目录下
<property>
<name>hbase.zookeeper.quorum</name>
<value>netcloud03,netcloud04,netcloud05</value>
</property>
2)将hbase的9个包拷贝到hive/lib目录下。如果是CDH版本,已经集成好不需要导包。
export HBASE_HOME=/opt/modules/hbase-0.98.6-cdh5.3.0
export HIVE_HOME=/opt/modules/hive-0.13.1/lib
ln -s $HBASE_HOME/lib/hbase-server-0.98.6-cdh5.3.0.jar $HIVE_HOME/lib/hbase-server-0.98.6-cdh5.3.0.jar
ln -s $HBASE_HOME/lib/hbase-client-0.98.6-cdh5.3.0.jar $HIVE_HOME/lib/hbase-client-0.98.6-cdh5.3.0.jar
ln -s $HBASE_HOME/lib/hbase-protocol-0.98.6-cdh5.3.0.jar $HIVE_HOME/lib/hbase-protocol-0.98.6-cdh5.3.0.jar
ln -s $HBASE_HOME/lib/hbase-it-0.98.6-cdh5.3.0.jar $HIVE_HOME/lib/hbase-it-0.98.6-cdh5.3.0.jar
ln -s $HBASE_HOME/lib/htrace-core-2.04.jar$HIVE_HOME/lib/htrace-core-2.04.jar
ln -s $HBASE_HOME/lib/hbase-hadoop2-compact-0.98.6-cdh5.3.0.jar $HIVE_HOME/lib/hbase-hadoop2-compact-0.98.6-cdh5.3.0.jar
ln -s $HBASE_HOME/lib/hbase-hadoop-compact-0.98.6-cdh5.3.0.jar $HIVE_HOME/lib/hbase-hadoop-compact-0.98.6-cdh5.3.0.jar
ln -s $HBASE_HOME/lib/high-scale-lib-1.1.1.jar $HIVE_HOME/lib/high-scale-lib-1.1.1.jar
ln -s $HBASE_HOME/lib/hbase-common-0.98.6-cdh5.3.0.jar $HIVE_HOME/lib/hbase-common-0.98.6-cdh5.3.0.jar
3)在hive中创建与hbase集成的外部表
CREATE EXTERNAL TABLE weblogs(
id string,
datetime string,
userid string,
searchname string,
retorder string,
cliorder string,
cliurl string
)
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES("hbase.columns.mapping"=
":key,info:datetime,info:userid,info:searchname,info:retorder,info:cliorder,info:cliurl")
TBLPROPERTIES("hbase.table.name"="weblogs");
#查看hbase数据记录
select count(*) from weblogs;
4)netcloud05节点启动hive
执行 命令:hive --service metastore
netcloud03节点启动客户端
执行命令 :hive命令
10. Cloudera HUE大数据可视化分析
参考博客
11. Spark2.X环境准备、编译部署及运行
源码编译的方式参考博客;
预编译安装的方式搭建spark集群参考博客