数据采集:将数据从一个地方采集到另一个地方
将数据进行了复制
大数据的数据采集:将各种需要处理的数据源复制到大数据仓库中
实现:实时数据流的数据采集,可以将不同各种数据源的数据采集到各种目标地
数据源:文件、网络端口
Flume:实时
目标地:HDFS、Hbase、Hive、Kafka
特点:
功能全面
所有的读取和写入的程序,都已经封装好了
只需要配置从哪读,写入哪里,就要可以实现采集
允许自定义开发
如果功能不能满足实际的业务需求,Flume提供各种接口,允许自定义开发
基于Java开发的应用程序
开发相对简单
所有功能都封装好了,只要调用即可
写一个配置文件:从哪读,都谁,写到哪去
可以实现分布式采集
分布式采集:每一台机器都可以用Flume进行采集
注意:Flume不是分布式架构
应用于实时数据流采集场景
基于文件或者网络协议端口的数据流采集
美团的Flume设计架构
Agent:每个Agent就是一个Flume的程序,每个Agent由三部分组成:source、Channel、Sink
Source:负责读取数据,Source会动态监听数据源,将数据源新增的数据实时采集变成Event数据流,将每个Event发送到Channel中
Channel:临时缓存数据,将source发送过来的event的数据缓存起来 ,供Sink取数据
内存、文件(磁盘)
Sink:负责发送数据,从Channel中读取采集到的数据,将数据写入目标地
sink主动到Channel中读取数据
Event:用于构建每一条数据的对象,每一条数据就会变成一个Event,进行传递,最终写入目标
组成
Event
Map head;
byte[] body; //每一条数据的字节流
step1:开发一个Flume的参数配置文件
properties格式的文件:
#step1:定义一个agent:agent的名称、定义source、channel、sink
#step2:定义source:读什么、读哪
#step3:定义channel:缓存在什么地方
#step4:定义sink:写入什么地方
step2:运行flume的agent程序
flume -ng
Usage:bin/flume-ng [options]...
为什么叫Flume-ng?
flume-ng agent -c -f -n
agent:表示要运行一个Flume程序
一个程序文件中可以有多个agent程序,通过名字来区别
需求:采集Hive的日志、临时缓存在内存中、将日志写入Flume的日志中并打印在命令中
source:采集一个文件数据
创建测试目录:
cd /export/server/flume-1.6.0-cdh5.14.0-bin
mkdir usercase
复制官方示例:
cp conf/flume-conf.properties.template usercase/hive-mem-log.properties
hive-mem-log.properties:采集hive的日志临时缓存在内存中最终打印在日志中
Chanel:Flume提供了各种channel应用缓存数据
开发配置文件hive-mem-log.properties
# The configuration file needs to define the sources,
# the channels and the sinks.
# Sources, channels and sinks are defined per a1,
# in this case called 'a1'
#define the agent
a1.sources = s1
a1.channels = c1
a1.sinks = k1
#define the source
a1.sources.s1.type = exec
a1.sources.s1.command = tail -f /export/server/hive-1.1.0-cdh5.14.0/logs/hiveserver2.log
#define the channel
a1.channels.c1.type = memory
a1.channels.c1.capacity = 10000
#define the sink
a1.sinks.k1.type = logger
#bond
a1.sources.s1.channels = c1
a1.sinks.k1.channel = c1
运行
#1.切换到指定目录
cd /export/server/flume-1.6.0-cdh5.14.0-bin/
#2.运行agent程序
flume-ng agent -c conf/ -f usercase/hive-mem-log.properties -n a1 -Dflume.root.logger=INFO,console
功能:通过执行一条Linux命令来实现数据量动态采集
应用场景:实现动态监听采集(单个文件)的数据
功能:从Apache Flume1.7版本开始支持,动态监听采集多个文件
测试实现
需求:让Flume动态监听一个文件和一个目录下的所有文件
准备
cd /export/server/flume-1.6.0-cdh5.14.0-bin
mkdir position
mkdir -p /export/data/flume
echo " " >> /export/data/flume/bigdata01.txt
mkdir -p /export/data/flume/bigdata
开发
cp usercase/hive-mem-log.properties usercase/taildir-mem-log.properties
taildir-mem-log.properties
# define sourceName/channelName/sinkName for the agent
a1.sources = s1
a1.channels = c1
a1.sinks = k1
# define the s1
a1.sources.s1.type = TAILDIR
#指定一个元数据记录文件
a1.sources.s1.positionFile = /export/server/flume-1.6.0-cdh5.14.0-bin/position/taildir_position.json
#将所有需要监控的数据源变成一个组,这个组内有两个数据源
a1.sources.s1.filegroups = f1 f2
#指定了f1是谁:监控一个文件
a1.sources.s1.filegroups.f1 = /export/data/flume/bigdata01.txt
#指定f1采集到的数据的header中包含一个KV对
a1.sources.s1.headers.f1.headerKey1 = value1
#指定f2是谁:监控一个目录下的所有文件
a1.sources.s1.filegroups.f2 = /export/data/flume/bigdata/.*
#指定f2采集到的数据的header中包含一个KV对
a1.sources.s1.headers.f2.headerKey1 = value2
a1.sources.s1.fileHeader = true
# define the c1
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
# def the k1
a1.sinks.k1.type = logger
#source、channel、sink bond
a1.sources.s1.channels = c1
a1.sinks.k1.channel = c1
运行
flume-ng agent -c conf/ -f usercase/taildir-mem-log.properties -n a1 -Dflume.root.logger=INFO,console
元数据文件的功能:/export/server/flume-1.6.0-cdh5.14.0-bin/position/taildir_position.json
问题:如果Flume程序故障,重启Flume程序,已经被采集过的数据还要不要采集?
需求:不需要,不能导致数据重复
功能:记录Flume所监听的每个文件已经被采集的位置
[
{"inode":34599996,"pos":14,"file":"/export/data/flume/bigdata01.txt"},{"inode":67595704,"pos":19,"file":"/export/data/flume/bigdata/test01.txt"},{"inode":67805657,"pos":7,"file":"/export/data/flume/bigdata/test02.txt"}
]
Kafka Source:监听读取Kafka数据
Spooldir Source:监控一个目录,只要这个目录中产生一个文件,就会采集一个文件
缺点:不能动态监控文件,被采集的文件是不能发生变化的
mem Channel:将数据缓存在内存中
特点:读写快、容量小、安全性较差
应用:小数据量的高性能的传输
file Channel:将数据缓存在文件中
特点:读写相对慢、容量大、安全性较高
应用:数据量大,读写性能要求不高的场景下
常用属性
capacity:缓存大小:指定Channel中最多存储多少条event
transactionCapacity:每次传输的大小
问题:为什么离线采集不直接写入Hive,使用Hive sink
解决:如果要实现将数据直接放入Hive表?
HDFS Sink功能:将Flume采集的数据写入HDFS
问题:Flume作为HDFS客户端,写入HDFS数据
解决
hdfs://node1:8020/nginx/log
手动将需要的jar包放入Flume的lib目录下
需求:将Hive的日志动态采集写入HDFS
cp hive-mem-log.properties hive-mem-hdfs.properties
# The configuration file needs to define the sources,
# the channels and the sinks.
# Sources, channels and sinks are defined per a1,
# in this case called 'a1'
#定义当前的agent的名称,以及对应source、channel、sink的名字
a1.sources = s1
a1.channels = c1
a1.sinks = k1
#定义s1:从哪读数据,读谁
a1.sources.s1.type = exec
a1.sources.s1.command = tail -f /export/server/hive-1.1.0-cdh5.14.0/logs/hiveserver2.log
#定义c1:缓存在什么地方
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
#定义k1:将数据发送给谁
a1.sinks.k1.type = hdfs
a1.sinks.k1.hdfs.path = hdfs://node1:8020/flume/test1
#s1将数据给哪个channel
a1.sources.s1.channels = c1
#k1从哪个channel中取数据
a1.sinks.k1.channel = c1
启动:
flume-ng agent -c conf/ -f usercase/hive-mem-hdfs.properties -n a1 -Dflume.root.logger=INFO,console
问题:Flume默认写入HDFS上会产生很多小文件,都在1KB左右,不利用HDFS存储
解决:指定文件大小
hdfs.rollInterval 30 每隔多长时间产生一个文件,单位为s
hdfs.rollSize 1024 每个文件多大产生一个文件,字节
hdfs.rollCount 10 多少个event生成一个文件
如果不想使用某种规则,需要关闭,设置为0
cp hive-mem-hdfs.properties hive-mem-size.properties
hive-mem-size.properties
# The configuration file needs to define the sources,
# the channels and the sinks.
# Sources, channels and sinks are defined per a1,
# in this case called 'a1'
#定义当前的agent的名称,以及对应source、channel、sink的名字
a1.sources = s1
a1.channels = c1
a1.sinks = k1
#定义s1:从哪读数据,读谁
a1.sources.s1.type = exec
a1.sources.s1.command = tail -f /export/server/hive-1.1.0-cdh5.14.0/logs/hiveserver2.log
#定义c1:缓存在什么地方
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
#定义k1:将数据发送给谁
a1.sinks.k1.type = hdfs
a1.sinks.k1.hdfs.path = hdfs://node1:8020/flume/test2
#指定按照时间生成文件,一般关闭
a1.sinks.k1.hdfs.rollInterval = 0
#指定文件大小生成文件,一般120 ~ 125M对应的字节数
a1.sinks.k1.hdfs.rollSize = 10240
#指定event个数生成文件,一般关闭
a1.sinks.k1.hdfs.rollCount = 0
#s1将数据给哪个channel
a1.sources.s1.channels = c1
#k1从哪个channel中取数据
a1.sinks.k1.channel = c1
指定分区
cp hive-mem-hdfs.properties hive-mem-part.properties
运行:
flume-ng agent -c conf/ -f usercase/hive-mem-part.properties -n a1 -Dflume.root.logger=INFO,console
#指定生成的文件的前缀
a1.sinks.k1.hdfs.filePrefix = nginx
#指定生成的文件的后缀
a1.sinks.k1.hdfs.fileSuffix = .log
#指定写入HDFS的文件的类型:普通的文件
a1.sinks.k1.hdfs.fileType = DataStream
Flume架构
a1.sources = s1
a1.channels = c1 c2
a1.sinks = k1 k2
Flume Channel Selectors
a1.sources = r1
a1.channels = c1 c2 c3 c4
a1.sources.r1.selector.type = multiplexing
a1.sources.r1.selector.header = state
a1.sources.r1.selector.mapping.CZ = c1
a1.sources.r1.selector.mapping.US = c2 c3
a1.sources.r1.selector.default = c4
Flume Interceptors:拦截器
a1.sources = r1
a1.channels = c1
a1.sources.r1.channels = c1
a1.sources.r1.type = seq
a1.sources.r1.interceptors = i1
a1.sources.r1.interceptors.i1.type = timestamp
Sink processor
- 功能:实现collect架构中的高可用和负载均衡
- 高可用failover:两个sink,一个工作,一个不工作
a1.sinkgroups = g1
a1.sinkgroups.g1.sinks = k1 k2
a1.sinkgroups.g1.processor.type = failover
a1.sinkgroups.g1.processor.priority.k1 = 5
a1.sinkgroups.g1.processor.priority.k2 = 10
a1.sinkgroups.g1.processor.maxpenalty = 10000
a1.sinkgroups = g1
a1.sinkgroups.g1.sinks = k1 k2
a1.sinkgroups.g1.processor.type = load_balance
a1.sinkgroups.g1.processor.selector = random
功能
本质
应用
测试
sqoop list-databases --connect jdbc:mysql://node3:3306 --username root --password 123456
准备数据:
create database sqoopTest;
use sqoopTest;
CREATE TABLE `tb_tohdfs` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`age` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into tb_tohdfs values(null,"laoda",18);
insert into tb_tohdfs values(null,"laoer",19);
insert into tb_tohdfs values(null,"laosan",20);
insert into tb_tohdfs values(null,"laosi",21);
导入语法:
#查看sqoop import帮助
sqoop import --help
测试导入
sqoop import \
--connect jdbc:mysql://node3:3306/sqoopTest \
--username root \
--password 123456 \
--table tb_tohdfs \
--target-dir /sqoop/import/test01
sqoop import \
--connect jdbc:mysql://node3:3306/sqoopTest \
--username root \
--password 123456 \
--table tb_tohdfs \
--columns id,name \
--delete-target-dir \
--target-dir /sqoop/import/test01 \
--fields-terminated-by '\t' \
-m 1
sqoop import \
--connect jdbc:mysql://node3:3306/sqoopTest \
--username root \
--password 123456 \
--table tb_tohdfs \
--where 'id > 2' \
--delete-target-dir \
--target-dir /sqoop/import/test01 \
--fields-terminated-by '\t' \
-m 1
sqoop import \
--connect jdbc:mysql://node3:3306/sqoopTest \
--username root \
--password 123456 \
--table tb_tohdfs \
--columns id,name \
--where 'id > 2' \
--delete-target-dir \
--target-dir /sqoop/import/test01 \
--fields-terminated-by '\t' \
-m 1
sqoop import \
--connect jdbc:mysql://node3:3306/sqoopTest \
--username root \
--password 123456 \
--table tb_tohdfs \
-e 'select id,name from tb_tohdfs where id>2 and $CONDITIONS' \
--delete-target-dir \
--target-dir /sqoop/import/test01 \
--fields-terminated-by '\t' \
-m 1
准备数据
use default;
create table fromsqoop(
id int,
name string,
age int
);
sqoop import \
--connect jdbc:mysql://node3:3306/sqoopTest \
--username root \
--password 123456 \
--table tb_tohdfs \
--hive-import \
--hive-database default \
--hive-table fromsqoop \
--fields-terminated-by '\001' \
-m 1
–hive-import \:表示导入Hive表
–hive-database default \:表示指定导入哪个Hive的数据库
–hive-table fromsqoop \:表示指定导入哪个Hive的表
–fields-terminated-by ‘\001’ \:指定Hive表的分隔符,一定要与Hive表的分隔符一致
原理
step1:将MySQL的数据通过MapReduce先导入HDFS
step2:将HDFS上导入的这个文件通过load命令加载到了Hive表中
2.hcatalog导入
sqoop import \
--connect jdbc:mysql://node3:3306/sqoopTest \
--username root \
--password 123456 \
--table tb_tohdfs \
--hcatalog-database default \
--hcatalog-table fromsqoop \
--fields-terminated-by '\001' \
-m 1
原理
增量需求
+----+--------+-----+
| 1 | laoda | 18 |
| 2 | laoer | 19 |
| 3 | laosan | 20 |
| 4 | laosi | 21 |
+----+--------+-----+
sqoop import --connect jdbc:mysql://node3:3306/sqoopTest --username root --password 123456 --table tb_tohdfs --target-dir /sqoop/import/test02 -m 1
+----+--------+-----+
| 5 | laowu | 22 |
| 6 | laoliu | 23 |
| 7 | laoqi | 24 |
| 8 | laoba | 25 |
+----+--------+-----+
sqoop import --connect jdbc:mysql://node3:3306/sqoopTest --username root --password 123456 --table tb_tohdfs --target-dir /sqoop/import/test02 -m 1
Sqoop中的两种增量方式
设计:用于对某一列值进行判断,只要大于上一次的值就会被导入
参数
Incremental import arguments:
--check-column Source column to check for incremental
change
--incremental Define an incremental import of type
'append' or 'lastmodified'
--last-value Last imported value in the incremental
check column
–check-column :按照哪一列进行增量导入
–last-value:用于指定上一次的值
–incremental:增量的方式
append
lastmodified
1.append
sqoop import \
--connect jdbc:mysql://node3:3306/sqoopTest \
--username root \
--password 123456 \
--table tb_tohdfs \
--target-dir /sqoop/import/test02 \
--fields-terminated-by '\t' \
--check-column id \
--incremental append \
--last-value 1 \
-m 1
insert into tb_tohdfs values(null,"laowu",22);
insert into tb_tohdfs values(null,"laoliu",23);
insert into tb_tohdfs values(null,"laoqi",24);
insert into tb_tohdfs values(null,"laoba",25);
sqoop import \
--connect jdbc:mysql://node3:3306/sqoopTest \
--username root \
--password 123456 \
--table tb_tohdfs \
--target-dir /sqoop/import/test02 \
--fields-terminated-by '\t' \
--incremental append \
--check-column id \
--last-value 4 \
-m 1
CREATE TABLE `tb_lastmode` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`word` varchar(200) NOT NULL,
`lastmode` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into tb_lastmode values(null,'hadoop',null);
insert into tb_lastmode values(null,'spark',null);
insert into tb_lastmode values(null,'hbase',null);
sqoop import \
--connect jdbc:mysql://node3:3306/sqoopTest \
--username root \
--password 123456 \
--table tb_lastmode \
--target-dir /sqoop/import/test03 \
--fields-terminated-by '\t' \
--incremental lastmodified \
--check-column lastmode \
--last-value '2021-05-12 21:55:30' \
-m 1
insert into tb_lastmode values(null,'hive',null);
update tb_lastmode set word = 'sqoop' where id = 1;
第二次采集
sqoop import \
--connect jdbc:mysql://node3:3306/sqoopTest \
--username root \
--password 123456 \
--table tb_lastmode \
--target-dir /sqoop/import/test03 \
--fields-terminated-by '\t' \
--merge-key id \
--incremental lastmodified \
--check-column lastmode \
--last-value '2021-05-12 22:01:47' \
-m 1
sqoop import \
--connect jdbc:mysql://node3:3306/sqoopTest \
--username root \
--password 123456 \
-e 'select id,name from tb_tohdfs where id > 12 and $CONDITIONS' \
--delete-target-dir \
--target-dir /sqoop/import/test01 \
--fields-terminated-by '\t' \
-m 1
准备数据
use sqoopTest;
CREATE TABLE `tb_url` (
`id` int(11) NOT NULL,
`url` varchar(200) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Hive中创建表,并加载数据
vim /export/data/lateral.txt
1 http://facebook.com/path/p1.php?query=1
2 http://www.baidu.com/news/index.jsp?uuid=frank
3 http://www.jd.com/index?source=baidu
use default;
create table tb_url(
id int,
url string
) row format delimited fields terminated by '\t';
load data local inpath '/export/data/lateral.txt' into table tb_url;
sqoop export \
--connect jdbc:mysql://node3:3306/sqoopTest \
--username root \
--password 123456 \
--table tb_url \
--export-dir /user/hive/warehouse/tb_url \
--input-fields-terminated-by '\t' \
-m 1
增量导出场景
--第一天:10号处理9号
id daystr UV PV IP
1 2020-11-09 1000 10000 500
insert into result
select id,daystr,uv,pv ,ip from datatable where daystr=昨天的日期
--第二天:11号处理10号
id daystr UV PV IP
1 2020-11-09 1000 10000 500
2 2020-11-10 2000 20000 1000
MySQL:存储每一天的结果
1 2020-11-09 1000 10000 500
增量导出方式
1.updateonly
1 http://www.itcast.com/path/p1.php?query=1
2 http://www.baidu.com/news/index.jsp?uuid=frank
3 http://www.jd.com/index?source=baidu
4 http://www.heima.com
load data local inpath '/export/data/lateral.txt' overwrite into table tb_url;
sqoop export \
--connect jdbc:mysql://node3:3306/sqoopTest \
--username root \
--password 123456 \
--table tb_url \
--export-dir /user/hive/warehouse/tb_url \
--input-fields-terminated-by '\t' \
--update-key id \
--update-mode updateonly \
-m 1;
1 http://bigdata.itcast.com/path/p1.php?query=1
2 http://www.baidu.com/news/index.jsp?uuid=frank
3 http://www.jd.com/index?source=baidu
4 http://www.heima.com
load data local inpath '/export/data/lateral.txt' overwrite into table tb_url;
sqoop export \
--connect jdbc:mysql://node3:3306/sqoopTest \
--username root \
--password 123456 \
--table tb_url \
--export-dir /user/hive/warehouse/tb_url \
--input-fields-terminated-by '\t' \
--update-key id \
--update-mode allowinsert \
-m 1
sqoop import \
--connect jdbc:mysql://node3:3306/sqoopTest \
--username root \
--password 123456 \
--table tb_tohdfs \
--target-dir /sqoop/import/test04 \
--fields-terminated-by '\t' \
--incremental append \
--check-column id \
--last-value 4 \
-m 1
insert into tb_tohdfs values(null,'laojiu',26);
insert into tb_tohdfs values(null,'laoshi',27);
sqoop job --create job01 \
-- import \
--connect jdbc:mysql://node3:3306/sqoopTest \
--username root \
--password 123456 \
--table tb_tohdfs \
--target-dir /sqoop/import/test04 \
--fields-terminated-by '\t' \
--incremental append \
--check-column id \
--last-value 8 \
-m 1
创建job,不会运行程序,只是在元数据中记录信息
列举job
sqoop job --list
sqoop job --show jobName
sqoop job --exec jobName
sqoop job --delete jobName
运行job01
sqoop job --exec job01
insert into tb_tohdfs values(null,'laoshiyi',28);
insert into tb_tohdfs values(null,'laoshier',29);
运行job01
sqoop job --exec job01
sqoop job --create job02 \
-- import \
--connect jdbc:mysql://node3:3306/sqoopTest \
--username root \
--password-file file:///export/data/sqoop.passwd \
--table tb_tohdfs \
--target-dir /sqoop/import/test05 \
--fields-terminated-by '\t' \
--incremental append \
--check-column id \
--last-value 4 \
-m 1
#mysql密码
123456
vim /export/data/test.sqoop
import
--connect
jdbc:mysql://node3:3306/sqoopTest
--username
root
--password-file
file:///export/data/sqoop.passwd
--table
tb_tohdfs
--target-dir
/sqoop/import/test05
--fields-terminated-by
'\t'
-m
1
sqoop --options-file /export/data/test.sqoop