1.1文章介绍介绍
本文主要介绍大数据相关的技术和项目
1.2
目录
2.2.3 Hadoop 配置文件以及简单的Hadoop 集群搭建
2.2.5 NameNode工作机制SecongdaryNameNode工作流程恢复流程
2.2.12 hadoop的调Yarn调度器,你们使⽤的是哪种策略,为什么?
2.2.13Hadoop、MapReduce数据倾斜怎么处理?
2.2.16 HDFS在上传文件时,其中一个 DataNode 突然挂掉怎么办
2.3.5 ZooKeeper 部署方式有哪几种?集群中角色有哪些?最少要几台机器?
2.5.7 kafka机器数量、副本设定、日志保存时间、硬盘大小
2.5.12 kafka消息数据积压, Kafka消费能力不足怎么处理?
2. 5.14 kafka 的数据是放在磁盘上还是内存上,为什么速度会快?
2.65.3 MySQL 的事务要素ACID以及并发问题,脏读幻读和隔离级别等
2.6.13 sort by 和 order by,group by, distribute by区别?
2.6.18 hive 中drop、truncate和delete区别
2.6.20 hive中count(*)count(1)和count(字段区别)
2.7.7. 热点现象(数据倾斜)怎么产生的,以及解决方法有哪些
2.7.8. HBase 中 compact 用途是什么,什么时候触发,分为哪两种?
2.8.4 简述 Spark的宽窄依赖,以及 的宽窄依赖,以及 Spark如何划分 stage,每个 ,每个 stage又根据什么决定 又根据什么决定 task个数 ?
2.8.5 请列举 Spark的 transformation算子
2.8.9 spark和mapReduce中shuffer区别
2.8.10 简述 Spark中共享变量(广播和累加器)的基本原理与用途
2.8.11 如何使用Spark实现TopN的获取(描述思路或使用伪代码)
2.8.12 hadoop 和 spark 的相同点和不同点?
2.8.19 spark 解决了 hadoop 的哪些问题?
2.8.21 RDD 中 reduceBykey 与 groupByKey 哪个性能好,为什么
2.8.23 SparkStreaming有哪几种方式消费 Kafka中的数据,区别?
2.8.23 介绍一下 cogroup rdd 实现原理,你在什么场景下用过这个 rdd?
2.8.25 Spark SQL 是如何将数据写到 Hive 表的?
2.8.26 通常来说,Spark 与 MapReduce 相比,Spark 运行效率更高。请 说明效率更高来源于 Spark 内置的哪些机制?
2.8.27 Spark Master HA 主从切换过程不会影响到集群已有作业的运行, 为什么?
2.9.4 Flink 相比 Spark Streaming 有什么区别
2.9.8 Flink 中 window 出现数据倾斜怎么解决
2.10.4 Sqoop底层运行的任务是什么 底层运行的任务是什么
2.10.7 Sqoop在导入数据的时候倾斜在导入数据的时候倾斜
2.10.8 Sqoop数据导出Parquet(项目中遇到的问题)
3.2.7 数据仓库每天跑多少张表,大概什么时候运行,运行多久?
3.2.9 数仓中使用的哪种文件存储格式 数仓中使用的哪种文件存储格式?
3.2.7 用一条 SQL 语句查询出每门课都大于 80 分的学生姓名
项目介绍
这是一个基于分布式集群而生的大数据项目。
1.3 项目指标
1.3.1离线指标
日活、月活、周活、留存、留存率、新增(日、周、年)、转化率、流失、回流、七天内连续3天登录(点赞、收藏、评价、购买、加购、下单、活动)、连续3周(月)登录、GMV、复购率、复购率排行、点赞、评论、收藏、领优惠价人数、使用优惠价、沉默、值不值得买、退款人数、退款率topn 热门商品
日活/周活/月活统计
(每日的根据 key 聚合,求 key 的总数)
我们先根据用户ID和访问日期去重,再统计每天的访问用户数。
SELECT COUNT(DISTINCT user_id) AS user_cnt,DATE(create_ts) AS view_day FROM user_trace GROUP BY DATE(create_ts);
2. 用户新增
每日新增(每日活跃设备 left join 每日新增表,如果 join 后,每日新
增表的设备 id 为空,就是新增) 方法1:
select r.date1,ifull(r2.count_num,0) from
record r left join(
select r1.date1,count(*) count_num
from record r1 where r1.date1=(select min(date1) from record group by id)) r2 on r.date1=r2.date1
group by r1.date1
order by r1.date1
方法2:
select date1,sum(case when date_num=1 then 1 else 0 end) from (select date1,row_number()over(partition by user_id order by date) date_num
from login)
group by date1
order by date1
3. 用户留存率
(一周留存)10 日新增设备明细 join 11日活跃设备明细表,就是 10日留存的。注意每日留存,一周留存 。所谓留存,就是指某日创建的账号在后续自然日登录的比例。
比如3月1日新增账号创建数为100,在3月2日这部分用户登录数为51,那么3月1日新增用户的次日留存率为51/100=51%。
1.考虑到用户每天登录的次数不一定只有一次,为了方面后续的数据处理,可以先对登录数据按照日期和用户id进行去重DISTINCT处理;
2.为了计算某条登录日志是该用户创建账号后的第几天登录,我们可以用用户登录日志和账号创建日志进行inner join(这里考虑到不在统计周期内的创建账号的用户数据也会记录在用户登录日志里,所以去掉);
3.然后用登录日期字段和创建账户字段进行差值DATEDIFF获取第几天登录;
4.对于第0天登录的数据则可以理解为新增用户数,第N(≥1)天登录的数据则为这批新增用户后续有登录的用户数;
5.用第N天登录的数据 / 新增用户数 就是对应第N天留存率。
SELECT
create_date
, 新增用户数
, concat(CAST(ROUND((100 * 次日留存) / 新增用户数,2) AS char), '%') 次日留存率
, concat(CAST(ROUND((100 * 3日留存) / 新增用户数,2) AS char), '%') 3日留存率
, concat(CAST(ROUND((100 * 7日留存) / 新增用户数,2) AS char), '%') 7日留存率
FROM
(
SELECT
create_date
, count((CASE WHEN (day_diff = 0) THEN role_id END)) 新增用户数
, count((CASE WHEN (day_diff = 1) THEN role_id END)) 次日留存
, count((CASE WHEN (day_diff = 2) THEN role_id END)) 3日留存
, count((CASE WHEN (day_diff = 7) THEN role_id END)) 7日留存
FROM
(
SELECT
login_log.role_id
, create_date
, DATEDIFF(login_date, create_date) day_diff
FROM
((
SELECT DISTINCT
STR_TO_DATE($part_date, '%Y-%m-%d') login_date
, role_id
FROM
role_login
) login_log
INNER JOIN (
SELECT DISTINCT
STR_TO_DATE($part_date, '%Y-%m-%d') create_date
, role_id
FROM
role_create
) create_log ON (login_log.role_id = create_log.role_id))
) temp_1
GROUP BY create_date
) temp_2
ORDER BY create_date ASC
4. 流量指标分析
观测每日、每小时的访问量(PV)、访问人数(UV)、平均访问量(PV/UV),针对性的开展不同的营销活动,吸引更多的优质流量。
行为转化分析:统计用户不同行为间的转化情况,关注转化率低的环节,优化交易流程,提高转化率
产品贡献定量分析:根据产品贡献程度,调整产品结构,策划营销主题,助力爆款产品
用户价值分析:对用户进行价值分层,针对不同层级的用户施行不同的营销策略
通过对用户价值的细分,进行差异化的惊喜运营,从而提升运营效率和用户体验。RFM模型是衡量客户价值和客户创利能力的重要工具。
一般挽留客户占比34.36%,占比最高。这类用户交易时间间隔长,交易频率低,交易金额小,存在流失风险。可以及时与用户取得联系,明确流失原因或了解用户需要,想办法挽回用户。
一般发展用户占比31.29%,占比排名第二。这类用户交易时间间隔短,但交易频率和交易金额低。可以利用推荐系统推荐其平时浏览的同类商品,或者是与此类用户有相同购买属性人群购买的商品,发送优惠券等,避免用户流失。
重要价值客户占比23.86%。这类用户交易时间间隔短,交易频率高,交易金额大,是高质量用户。应加强交流互动,深入了解用户需求,提供个性化服务,增加用户粘性
R(Recency):最后一次消费时间间隔。R值越小,用户价值越高。
F(Frequency):消费频率。F值越大,用户价值越高。
M(Monetary):消费金额。M值越大,用户价值越高。
浏览量(pv):用户每打开一个页面算作一个浏览,用户对同一个页面多次点击pv累计多次
访客数(uv):同一个用户多次访问只计算一个uv
人均浏览量(pv/uv):每个用户平均浏览次数
1.流量指标分析
每日PV、UV、人均浏览量、成交量、销售额
select日期,sum(behavior_type="pv") as 浏览量,
count(distinct user_id) as 访客数,
sum(behavior_type="pv")/count(distinct user_id) as 人均浏览量,
sum(behavior_type="buy") as 成交量,
sum(if(behavior_type="buy",amount,0)) as 销售额from UserBehavior_newgroup by 日期;
注意:不能用count。count函数是对非空记录进行计数,不区分返回结果。count(behavior_type="pv")与count(behavior_type)是一样的效果,得出的是每日所有行为的统计数。
按日期分组,按用户行为类别计数(即按条件计数)。如果把条件放在where语句中,是先执行where语句后执行select求和,没法动态筛选。考虑把条件放在select语句中作为逻辑判断条件,返回的是1和0的结果,再对返回的结果分组进行聚合运算。
2.行为转化分析
统计每个行为类别的人数
select
behavior_type,
count(distinct user_id) as 用户数from UserBehavior_new group by behavior_type;
转化率=当前行为人数÷上一行为人数
行与行之间没法相除,用开窗函数当前行的上一行数据,即获取上一行为人数。lag(需要返回的字段,1)over(order by ...) 字符串是没法直接排序的,可以对字符进行重编码,用if函数赋值,对数值进行排序。
select
behavior_type,
count(distinct user_id) as 用户人数,
lag(count(distinct user_id),1) over (order by if(behavior_type="pv",0,if(behavior_type="fav",1,if(behavior_type="cart",2,3)))) as 上一行为人数,
count(distinct user_id)/lag(count(distinct user_id),1) over (order by if(behavior_type="pv",0,if(behavior_type="fav",1,if(behavior_type="cart",2,3)))) as 转化率from UserBehavior_newgroup by behavior_type;
浏览—加购—购买的转化率
select 7
behavior_type,
count(distinct user_id) as 用户人数,
lag(count(distinct user_id),1) over (order by if(behavior_type="pv",0,if(behavior_type="cart",1,2))) as 上一行为人数,
ifnull(count(distinct user_id)/lag(count(distinct user_id),1) over (order by if(behavior_type="pv",0,if(behavior_type="cart",1,2))),1) as 转化率from UserBehavior_newwhere behavior_type in ("pv","cart","buy")group by behavior_type;
3.产品贡献定量分析(帕累托分析)
产生购买行为的商品类目
select
item_category,
sum(amount) as 销售额from UserBehavior_newwhere behavior_type="buy"group by item_category;
累计销售额百分比=当前类目商品的累计销售额/所有类目商品的总销售额
select item_category,
sum(amount) as 销售额,
sum(sum(amount)) over (order by sum(amount) desc) as 累计销售额,
sum(sum(amount)) over (order by sum(amount) desc)/(select sum(amount) from UserBehavior_new where behavior_type="buy") as 累计销售额百分比from UserBehavior_newwhere behavior_type="buy"group by item_category;
筛选贡献80%的类目
select *from(select
item_category,
sum(amount) as 销售额,
sum(sum(amount)) over (order by sum(amount) desc) as 累计销售额,
sum(sum(amount)) over (order by sum(amount) desc)/(select sum(amount) from UserBehavior_new where behavior_type="buy") as 累计销售额百分比
from UserBehavior_new
where behavior_type="buy"
group by item_category) as twhere 累计销售额百分比<=0.8;
4.用户价值分析
每个用户消费时间间隔、消费频次、消费金额/* 消费时间间隔R:距离分析时间节点的最后消费时间。 timestampdiff() 消费频次F:对这段时间内的消费次数计数 消费金额M:求和消费金额
select user_id,
max(日期) as 最近一次消费日期,
timestampdiff(day,max(日期),"2014-12-19") as 间隔天数,
count(*) as 消费频次,
sum(amount) as 消费金额from UserBehavior_newwhere behavior_type="buy"group by user_id;
RFM评分/* 实际业务中会根据用户数量分布,制定评分标准。
select
user_id,
timestampdiff(day,max(日期),"2014-12-19") as 间隔天数,
count(*) as 消费频次,
sum(amount) as 消费金额,
case when timestampdiff(day,max(日期),"2014-12-19")<=6 then 5
when timestampdiff(day,max(日期),"2014-12-19")<=12 then 4
when timestampdiff(day,max(日期),"2014-12-19")<=18 then 3
when timestampdiff(day,max(日期),"2014-12-19")<=24 then 2
else 1
end as R评分,
if(count(*)=1,1,if(count(*)=2,2,if(count(*)=3,3,if(count(*)=4,4,5)))) as F评分,
if(sum(amount)<100,1,if(sum(amount)<200,2,if(sum(amount)<300,3,if(sum(amount)<400,4,5)))) as M评分from UserBehavior_newwhere behavior_type="buy"group by user_id;
RFM均值(根据评分计算均值)
select
avg(R评分) as R均值,
avg(F评分) as F均值,
avg(M评分) as M均值from(
select user_id,
case when timestampdiff(day,max(日期),"2014-12-19")<=6 then 5
when timestampdiff(day,max(日期),"2014-12-19")<=12 then 4
when timestampdiff(day,max(日期),"2014-12-19")<=18 then 3
when timestampdiff(day,max(日期),"2014-12-19")<=24 then 2
else 1
end as R评分,
if(count(*)=1,1,if(count(*)=2,2,if(count(*)=3,3,if(count(*)=4,4,5)))) as F评分,
if(sum(amount)<100,1,if(sum(amount)<200,2,if(sum(amount)<300,3,if(sum(amount)<400,4,5)))) as M评分
from UserBehavior_new
where behavior_type="buy"
group by user_id ) as t;
结果:3.5984, 2.1039, 2.2051-- RFM重要程度
select *,
if(R评分>3.5984,"高","低") as R程度,
if(F评分>2.1039,"高","低") as F程度,
if(M评分>2.2051,"高","低") as M程度from(select
user_id,
timestampdiff(day,max(日期),"2014-12-19") as 间隔天数,
count(*) as 消费频次,
sum(amount) as 消费金额,
case when timestampdiff(day,max(日期),"2014-12-19")<=6 then 5
when timestampdiff(day,max(日期),"2014-12-19")<=12 then 4
when timestampdiff(day,max(日期),"2014-12-19")<=18 then 3
when timestampdiff(day,max(日期),"2014-12-19")<=24 then 2
else 1
end as R评分,
if(count(*)=1,1,if(count(*)=2,2,if(count(*)=3,3,if(count(*)=4,4,5)))) as F评分,
if(sum(amount)<100,1,if(sum(amount)<200,2,if(sum(amount)<300,3,if(sum(amount)<400,4,5)))) as M评分from UserBehavior_newwhere behavior_type="buy"group by user_id) as t;
RFM用户价值
select * ,
case
when R程度='高' and F程度='高' and M程度='高' then '重要价值用户'
when R程度='高' and F程度='低' and M程度='高' then '重要发展用户'
when R程度='低' and F程度='高' and M程度='高' then '重要保持用户'
when R程度='低' and F程度='低' and M程度='高' then '重要挽留用户'
when R程度='高' and F程度='高' and M程度='低' then '一般价值用户'
when R程度='高' and F程度='低' and M程度='低' then '一般发展用户'
when R程度='低' and F程度='高' and M程度='低' then '一般保持用户'
else '一般挽留用户'
end as 用户价值分类 from(select *,
if(R评分>3.5984,"高","低") as R程度,
if(F评分>2.1039,"高","低") as F程度,
if(M评分>2.2051,"高","低") as M程度from(select
user_id,
timestampdiff(day,max(日期),"2014-12-19") as 间隔天数,
count(*) as 消费频次,
sum(amount) as 消费金额,
case when timestampdiff(day,max(日期),"2014-12-19")<=6 then 5
when timestampdiff(day,max(日期),"2014-12-19")<=12 then 4
when timestampdiff(day,max(日期),"2014-12-19")<=18 then 3
when timestampdiff(day,max(日期),"2014-12-19")<=24 then 2
else 1
end as R评分,
if(count(*)=1,1,if(count(*)=2,2,if(count(*)=3,3,if(count(*)=4,4,5)))) as F评分,
if(sum(amount)<100,1,if(sum(amount)<200,2,if(sum(amount)<300,3,if(sum(amount)<400,4,5)))) as M评分from UserBehavior_newwhere behavior_type="buy"group by user_id) as t1) as t2;
1.3.2实时指标
1. 每日日活实时统计
2. 每日订单量实时统计
3. 一小时内日活实时统计
4. 一小时内订单数实时统计
5. 一小时内交易额实时统计
6. 一小时内广告点击实时统计
7. 一小时内区域订单数统计
8. 一小时内区域订单额统计
9. 一小时内各品类销售 top3 商品统计
1.3.3最难的两个指标
1. 活跃用户指标
我们经常会算活跃用户,活跃用户是指至少连续 5 天登录账户的用户,返回的
结果表按照 id 排序。
思路:
1. 去重:由于每个人可能一天可能不止登陆一次,需要去重
2. 排序:对每个 ID 的登录日期排序
3. 差值:计算登录日期与排序之间的差值,找到连续登陆的记录
4. 连续登录天数计算:select id, count(*) group by id, 差值(伪代码)
5. 取出登录 5 天以上的记录
6. 通过表合并,取出 id 对应用户名
SELECT DISTINCT b.id, name
FROM
(SELECT id, login_date,
DATE_SUB(login_date,ROW_NUMBER() OVER(PARTITION BY id ORDER BY login_date)) AS
diff
FROM(SELECT DISTINCT id, login_date FROM Logins) a) b
INNER JOIN Accounts ac
ON b.id = ac.id
GROUP BY b.id, diff
HAVING COUNT(b.id) >= 5
注意点:
1. DATE_SUB 的应用:DATE_SUB (DATE,X),注意,X 为正数表示当前日期的前 X 天;
2. 如何找连续日期:通过排序与登录日期之间的差值,因为排序连续,因此若登录日期连续,则差值一致;
3. GROUP BY 和 HAVING 的应用:通过 id 和差值的 GROUP BY,用 COUNT 找到连续天数大于 5 天的 id,注意 COUNT 不是一定要出现在 SELECT 后,可以直接用在 HAVING 中。
1.4项目遇到问题
1.4.1 Sqoop
1.Sqoop 中导入导出 Null 存储一致性问题
原因:Hive 中的 Null 在底层是以“\N”来存储,而 MySQL 中的 Null 在底层就是Null,为了保证数据两端的一致性。
解决:在导出数据时采用--input-null-string 和 input-null-non-string 两个参数。导入数据时采用--null-string 和 --null-non-string。
2.Sqoop 数据导出一致性问题
当 Sqoop 导出数据到 MySql 时,使用 4 个 map 怎么保证数据的一致性
原因:因为在导出数据的过程中 map 任务可能会失败,可以使用—staging-table
– clear-staging
解决:任务执行成功首先在 tmp 临时表中,然后将 tmp 表中的数据复制到目标表中(这个时候可以使用事务,保证事务的一致性)
3.Sqoop 数据导出 Parquet
Ads 层数据用 Sqoop 往 MySql 中导入数据的时候,如果用了 orc(Parquet)不能导入,需转化成 text 格式
1.4.2Flume
1.Flume上传到HDFS出现大量小文件
原因:
1.元数据层面:每个小文件都有一份元数据,其中包括文件路径,文件名,所有者,所属组,权限,创建时间等,这些信息都保存在Namenode内存中。所以小文件过多,会占用Namenode服务器大量内存,影响Namenode性能和使用寿命。
2.计算层面:默认情况下MR会对每个小文件启用一个Map任务计算,非常影响计算性能。同时也影响磁盘寻址时间。
解决:
(1)采用har 归档方式,将小文件归档
(2)采用CombineTextInputFormat
(3)有小文件场景开启JVM 重用;如果没有小文件,不要开启JVM 重用,因为会一直占用使用到的task 卡槽,直到任务完成才释放。
JVM 重用可以使得JVM 实例在同一个job 中重新使用N 次,N 的值可以在Hadoop 的mapred-site.xml 文件中进行配置。通常在10-20 之间
2.Flume挂掉
flume ng 1.7版本后提供Taildir Source 可以读取多个文件最新追加写入的内容!
Taildir Source是可靠的,即使flume出现了故障或挂掉。Taildir Source在工作时,会将读取文件的最后的位置记录在一个json文件中,一旦agent重启,会从之前已经记录的位置,继续执行tail操作!Json文件中,位置是可以修改,修改后,Taildir Source会从修改的位置进行tail操作!如果JSON文件丢失了,此时会重新从每个文件的第一行,重新读取,这会造成数据的重复!
3.Flume优化
1、调整Flume进程的内存大小,建议设置1G~2G,太小的话会导致频繁GC因为Flume进程也是基于Java的,所以就涉及到进程的内存设置,一般建议启动的单个Flume进程(或者说单个Agent)内存设置为1G~2G,内存太小的话会频繁GC,影响Agent的执`行效率。
2、在一台服务器启动多个agent的时候,建议修改配置区分日志文件
1.4.3Kafka
1.kafka挂掉
1) Flume 记录
2) 日志有记录
3) 短期没事
2.Kafka 消息数据积压,Kafka 消费能力不足怎么处理?
1) 如果是 Kafka 消费能力不足,则可以考虑增加 Topic 的分区数,并且同时提升消费组的消费者数量,消费者数=分区数。(两者缺一不可)
2) 如果是下游的数据处理不及时:提高每批次拉取的数量。批次拉取数据过少(拉取数据/处理时间<生产速度),使处理的数据小于生产的数据,也会造成数据积压。
3.Kafka 数据重复
幂等性+ack-1+事务
Kafka数据重复,可以再下一级:SparkStreaming、redis或者hive中dwd层去重,去重的手段:分组、按照id开窗只取第一个值;
4.Kafka丢不丢数据
Ack=0,相当于异步发送,消息发送完毕即offset增加,继续生产。
Ack=1,leader收到leader replica 对一个消息的接受ack才增加offset,然后继续生产。
Ack=-1,leader收到所有replica 对一个消息的接受ack才增加offset,然后继续生产。
5.Kafka单条日志传输大小
Kafka对于消息体的大小默认为单条最大值是1M但是在我们应用场景中,常常会出现一条消息大于1M,如果不对Kafka进行配置。则会出现生产者无法将消息推送到Kafka或消费者无法去消费Kafka里面的数据,这时我们就要对Kafka进行以下配置:server.properties
replica.fetch.max.bytes: 1048576 broker可复制的消息的最大字节数, 默认为1M
message.max.bytes: 1000012 kafka 会接收单个消息size的最大限制, 默认为1M左右
1.4.4Hadoop
1.项目经验之基准测试
搭建完Hadoop集群后需要对HDFS读写性能和MR计算能力测试。测试jar包在hadoop的share文件夹下。
2.Hadoop宕机
1)如果MR造成系统宕机。此时要控制Yarn同时运行的任务数,和每个任务申请的最大内存。调整参数:yarn.scheduler.maximum-allocation-mb(单个任务可申请的最多物理内存量,默认是8192MB)
2)如果写入文件过快造成NameNode宕机。那么调高Kafka的存储大小,控制从Kafka到HDFS的写入速度。例如,可以调整Flume每批次拉取数据量的大小参数batchsize。。
3.Hadoop解决数据倾斜方法
1)提前在map进行combine,减少传输的数据量
在Mapper加上combiner相当于提前进行reduce,即把一个Mapper中的相同key进行了聚合,减少shuffle过程中传输的数据量,以及Reducer端的计算量。
如果导致数据倾斜的key大量分布在不同的mapper的时候,这种方法就不是很有效了。
- 导致数据倾斜的key 大量分布在不同的mapper
(1)局部聚合加全局聚合。
第一次在map阶段对那些导致了数据倾斜的key 加上1到n的随机前缀,这样本来相同的key 也会被分到多个Reducer中进行局部聚合,数量就会大大降低。
第二次mapreduce,去掉key的随机前缀,进行全局聚合。
思想:二次mr,第一次将key随机散列到不同reducer进行处理达到负载均衡目的。第二次再根据去掉key的随机前缀,按原key进行reduce处理。
这个方法进行两次mapreduce,性能稍差。
(2)增加Reducer,提升并行度JobConf.setNumReduceTasks(int)
(3)实现自定义分区
根据数据分布情况,自定义散列函数,将key均匀分配到不同Reducer
4.集群资源分配参数不均
集群有30台机器,跑mr任务的时候发现5个map任务全都分配到了同一台机器上,这个可能是由于什么原因导致的吗?
解决方案:yarn.scheduler.fair.assignmultiple 这个参数默认是开的,需要关掉。
1.5 项目相关流程问题
1. 如何保证你写的 sql 正确性?
我一般是造一些特定的测试数据进行测试。
另外离线数据和实时数据分析的结果比较。
2. 测试数据哪来的?
一部分自己写 Java 程序自己造,一部分从生产环境上取一部分。
3. 测试环境什么样?
测试环境的配置是生产的一半
4. 测试之后如何上线?
上线的时候,将脚本打包,提交 git。先发邮件抄送经理和总监,运维。通过之
后跟运维一 起上线。
5. 你做的项目工作流程是什么?
1. 先与产品讨论,看报表的各个数据从哪些埋点中取
2. 将业务逻辑过程设计好,与产品确定后开始开发
3. 开发出报表 SQL 脚本,并且跑几天的历史数据,观察结果
4. 将报表放入调度任务中,第二天给产品看结果。
5. 周期性将表结果导出或是导入后台数据库,生成可视化报表
6. 项目实际工作流程?
第1步:确定指标的业务口径
由产品经理主导,找到提出该指标的运营负责人沟通。首先要问清楚指标是怎么定义的,比如活跃用户是指启动过APP的用户。设备id 还是用户id。
第2步:需求评审
由产品经理主导设计原型,对于活跃主题,我们最终要展示的是最近n天的活跃用户数变化趋势,效果如下图所示。此处大数据开发工程师、后端开发工程师、前端开发工程师一同参与,一起说明整个功能的价值和详细的操作流程,确保大家理解的一致。
第3步:大数据开发
大数据开发工程师,通过数据同步的工具如Flume、Sqoop等将数据同步到ODS层,然后就是一层一层的通过SQL计算到DWD、DWS层,最后形成可为应用直接服务的数据填充到ADS
第4步:后端开发
后端工程师负责,为大数据工程师提供业务数据接口;
同时还负责读取ADS层分析后,写入MySQL中的数据。
第5步:前端开发
前端工程师负责,前端埋点。
对分析后的结果数据进行可视化展示。
第6步:联调
此时数据开发工程师、前端开发工程师、后端开发工程师都要参与进来。此时会要求大数据开发工程师基于历史的数据执行计算任务,大数据开发工程师承担数据准确性的校验。前后端解决用户操作的相关BUG保证不出现低级的问题完成自测。
第7步:测试
测试工程师对整个大数据系统进行测试。测试的手段包括,边界值、等价类等。
提交测试异常的软件有:禅道、bugzila(测试人员记录测试问题1.0,输入是什么,结果是什么,跟预期不一样->需要开发人员解释,是一个bug,下一个版本解决1.1->测试人员再测试。测试1.1ok->测试经理关闭bug)
第8步:上线
运维工程师会配合我们的前后端开发工程师更新最新的版本到服务器。此时产品经理要找到该指标的负责人长期跟进指标的准确性。重要的指标还要每过一个周期内部再次验证,从而保证数据的准确性。
7.公司项目版本迭代多久一次多久一次 ,迭代到哪个版本?
瀑布式开发、敏捷开发
差不多一个月会迭代一次。每月都有节日(元旦、春节、情人节、3.8妇女节、端午节、618、国庆、中秋、1111/6.1/5.1、生日、周末)新产品、新区域就产品或我们提出优化需求,然后评估时间。每周我们都会开会做下周计划和本周总结。
8.项目开发中每天做什么事?
1)新需求(活动、优化、新产品、新市场)。
2)故障分析:数仓的任何步骤出现问题,需要查看问题,比如日活,月活下降或快速上升等。
3)新技术的预言(比如flink、数仓建模、数据质量、元数据管理)
4)晨会-》10做操-》讨论中午吃什么-》12点出去吃1点-》睡到2点-》3点茶歇水果-》晚上吃啥-》吃加班餐-》开会-》晚上6点吃饭-》7点开始干活-10点-》11点
9.DWD层做了哪些事?
1 数据清洗
(1)空值去除
(2)过滤核心字段无意义的数据,比如订单表中订单id为null,支付表中支付id为空
(3)将用户行为宽表和业务表进行数据一致性处理
2 清洗的手段
Sql、mr、rdd、kettle、Python(项目中采用sql进行清除)
3 清洗掉多少数据算合理
1万条数据清洗掉1条。
4 脱敏
对手机号、身份证号等敏感数据脱敏
5 压缩LZO
6 列式存储parquet
DWD层做了哪些事?
1 DWS层有3-5张宽表(处理100-200个指标70%以上的需求)
具体宽表名称:用户行为宽表,用户购买商品明细行为宽表,商品宽表,购物车宽表,物流宽表、登录注册、售后等。
2 哪个宽表最宽?大概有多少个字段?
最宽的是用户行为宽表。大概有60-100个
项目的收获?
1) 值得保持的优点
- 团队氛围融洽、交流通畅。
- 团队构成比较合理。年轻人技术强力,老人能够把控项目方向。
- 遇到问题及时沟通,群策群力解决问题。
- 有吃苦耐劳的精神,每个人都抱有很高的责任心。能顶住持续高强的压力。
- 公司大环境给予的支持力度大,从技术、工程、到后勤保障都值得称赞。
- 仍需要改进的地方
需求管理:
客户提出来的需求比较零散,需要整理入册,安排优先级。应对其状态进行追踪。保持与客户的互动。
单点作战:
每个人担当的任务没有其他人可以分担,一旦出现问题,项目将受到较大影响。
质量管控:
由于持续高压,导致程序质量多少存在一些问题。
- 项目优化策略
资源隔离:
将耗费性能的处理隔离出来,单独占用资源,以防止资源被其他处理抢占。
热点数据:
将经常访问的数据形成热点数据区,以加快查询速度。(HBase Bucket Cache)
数据分流:
增加后置资源利用率,将一部分企业放置到后置集群进行处理。
采用SSD:
实践证明SSD盘可以非常明显的提高读写速度。
批量写入:
数据写入数据库的处理,尽量使用批量写入的方式。
展示分离:
展示页面所使用的数据与永久持久化的数据可以分离开,以提高展示的性能
1.6 项目组织架构
1框架版本选型
1) Apache:运维麻烦,组件间兼容性需要自己调研。(一般大厂使用,技术实力雄厚,有专业
的运维人员)
2) CDH:国内使用最多的版本,但 CM 不开源,但其实对中、小公司使用来说没有影响(建议使
用)
3) HDP:开源,可以进行二次开发,但是没有 CDH 稳定,国内使用较少
2服务器选型
服务器使用物理机还是云主机?
1) 机器成本考虑:
a. 物理机:以 128G 内存,20 核物理 CPU,40 线程,8THDD 和 2TSSD 硬盘,单台报价 4W 出
头,需考虑托管服务器费用。一般物理机寿命 5 年左右
b. 云主机,以阿里云为例,差不多相同配置,每年 5W
2) 运维成本考虑:
a. 物理机:需要有专业的运维人员
b. 云主机:很多运维工作都由阿里云已经完成,运维相对较轻松
3.集群规模
3.1用户行为数据
- 每天日活跃用户100万,每人一天平均100条:10万*100条=1000万条;
- 每条日志1k左右,每天1亿条:100000000/1024/1024=100G;
- 数仓ODS层采用LZO存储:100G压缩为10G左右;
- 数仓DWD采用LZO加parquest存储,大约10G左右;
- 数仓DWS层轻度聚合存储(目的是为了快速运算,不压缩),50G左右;
- 数仓ADS层数据量很小,忽略不计;
- 保存副本:70G*3=210G
- 半年内不扩容服务器来算:210G*180天=约37T
- 预留30%Buf=37T/0.7=857G,也就大约1T
3.2 Kafka中的数据
- 每天约100G*2(副本)= 200G
- 保存三天200G*3=600G
- 预留20%-30%Buf=54T/0.7=77T
3.3 flume数据
flume缓存的数据比较少,可以忽略不计;
3.4 业务数据
- 每天活跃用户100万,每天下单的用户10万,每人每天产生10条业务数据,每天1K,算下来就是10万*10条*1K=1G
- 数仓四层存储,1G*3=3G
- 保存3个副本:3*3G=9G
- 半年内不扩容服务器来算:9G*180天=1.6T
- 预留20%-30%Buf=1.6T/0.7=2T
3.5 集群总的数据
总数据:53T+1T+2T=56T,因此约8T*10台服务器
(1)每天日活跃用户100万,每人一天平均100条:10万*100条=1000万条
(2)每条日志1k左右,每天1亿条:100000000/1024/1024=100G
(3)半年内不扩容服务器来算:100G*180天=约18T
(4)保存副本:18T*3=54T
(5)预留20%-30%Buf=54T/0.7=77T
(6)因此约8T*10台服务器
4.人员配置参考
属于研发部,我们属于大数据组,其他还有后端项目组,前端组、测试组、UI组等。其他的还有产品部、运营部、人事部、财务部、行政部等。
大数据开发工程师=>大数据组组长=》项目经理=>部门经理=》技术总监CTO 中型公司(5~10人左右):组长1人,离线4人左右(离线处理、数仓),实时2人左右,组长和技术大牛1人兼顾和javaEE、前端。
第2章 涉及技术
2.1 Linux&Shell
2.1.1 Linux常用高级命令
序号 |
命令 |
命令解释 |
1 |
top |
查看内存 |
2 |
df -h |
查看磁盘存储情况 |
3 |
iotop |
查看磁盘IO读写(yum install iotop安装) |
4 |
iotop -o |
直接查看比较高的磁盘读写程序 |
5 |
netstat -tunlp | grep 端口号 |
查看端口占用情况 |
6 |
uptime |
查看报告系统运行时长及平均负载 |
7 |
ps-aux |
查看进程 |
8 |
pwd |
显示工作路径 |
2.1.2 Linux常用工具及写过脚本
1)awk、sed、cut、sort
2)用Shell写过哪些脚本
(1)集群启动,分发脚本
(2)数仓与mysql的导入导出
(3)数仓层级内部的导入
2.1.3 Shell中单引号和双引号区别
(1)单引号不取变量值
(2)双引号取变量值
(3)反引号`,执行引号中命令
(4)双引号内部嵌套单引号,取出变量值
(5)单引号内部嵌套双引号,不取出变量值
2.2 Hadoop
分布式系统基础架构计算平台
2.2.1 Hadoop基本概念
1.Hadoop 是一个处理、存储和计算分析海量的分布式、非结构化数据的开源框架。
2.HDFS是分布式文件存储管理系统。
3.MapReduce是一个分布式运算程序的编程框架
4.yarn是hadoop中的资源管理器,负责任务调度。
2.2.2 Hadoop常用端口号
组件 |
节点 |
默认 端口 |
配置 |
命令解释 |
HDFS |
DataNode |
50010 |
dfs.datanode.address |
datanode服务端口,用于数据传输 |
HDFS |
DataNode |
50075 |
dfs.datanode.http.address |
http服务的端口 |
HDFS |
DataNode |
50475 |
dfs.datanode.https.address |
https服务的端口 |
HDFS |
DataNode |
50020 |
dfs.datanode.ipc.address |
ipc服务的端口 |
HDFS |
NameNode |
50070 |
dfs.namenode.http-address |
http服务的端口 |
HDFS |
NameNode |
50470 |
dfs.namenode.https-address |
https服务的端口 |
HDFS |
NameNode |
8020 |
fs.defaultFS |
接收Client连接的RPC端口,用于获取文件系统metadata信息。 |
HDFS |
NameNode |
9000 |
fs.default.name |
客户端访问集群端口 |
Yarn |
ResourceManager |
8088 |
yarn.resourcemanager.webapp.address |
http服务端口,访问MR执行情况 |
Yarn |
JobHistory Server |
19888 |
mapreduce.jobhistory.webapp.address |
历史服务器http服务端口 |
ZooKeeper |
Server |
2181 |
/etc/zookeeper/conf/zoo.cfg中clientPort=<port> |
对客户端提供服务的端口 |
2.2.3 Hadoop 配置文件以及简单的Hadoop 集群搭建
(1)配置文件:
Hadoop2.x core-site.xml、hdfs-site.xml、mapred-site.xml、yarn-site.xml slaves
Hadoop3.x core-site.xml、hdfs-site.xml、mapred-site.xml、yarn-site.xml workers
(2)简单的集群搭建过程:
JDK 安装
配置SSH 免密登录
配置hadoop 核心文件:
格式化namenode
2.2.4 HDFS 读流程和写流程
1.hdfs上传文件的流程(写流程)
1)客户端通过 Distributed FileSystem 模块向 NameNode 请求上传文件,NameNode 检查目标文件是否已存在,父目录是否存在。
2)NameNode 返回是否可以上传。
3)客户端根据文件大小进行切片,请求第一个 Block 上传到哪几个 DataNode 服务器上。
4)NameNode 返回 3 个 DataNode 节点,分别为 dn1、dn2、dn3。
5)客户端通过 FSDataOutputStream 模块请求 dn1 上传数据,dn1 收到请求会继续调用 dn2,然后 dn2 调用 dn3,将这个通信管道建立完成。
6)dn1、dn2、dn3 逐级应答客户端。
7)客户端开始往 dn1 上传第一个 Block(先从磁盘读取数据放到一个本地内存缓存),以
Packet 为单位,dn1 收到一个 Packet 就会传给 dn2,dn2 传给 dn3;dn1 每传一个 packet 会放入一个应答队列等待应答。
8)当一个 Block 传输完成之后,客户端再次请求 NameNode 上传第二个 Block 的服务器。
(重复执行 3-7 步)。
2.hdfs读取文件的流程(读流程)
1)客户端通过 Distributed FileSystem 向 NameNode 请求下载文件,NameNode 通过查询元 数据,找到文件块所在的 DataNode 地址。
2)挑选一台 DataNode(就近原则,然后随机)服务器,请求读取数据。
3)DataNode 开始传输数据给客户端(从磁盘里面读取数据输入流,以 Packet 为单位来做校验)。
4)客户端以 Packet 为单位接收,先在本地缓存,然后写入目标文件。
2.2.5 NameNode工作机制SecongdaryNameNode工作流程恢复流程
1.NameNode工作机制
第一阶段:NameNode 启动
(1)第一次启动 NameNode 格式化后,创建 Fsimage 和 Edits 文件。如果不是第一次启
动,直接加载编辑日志和镜像文件到内存。
(2)客户端对元数据进行增删改的请求。
(3)NameNode 记录操作日志,更新滚动日志。
(4)NameNode 在内存中对数据进行增删改。
第二阶段:Secondary NameNode 工作
(1)Secondary NameNode 询问 NameNode 是否需要 CheckPoint。直接带回 NameNode
是否检查结果。
- Secondary NameNode 请求执行 CheckPoint。
(3)NameNode 滚动正在写的 Edits 日志。
(4)将滚动前的编辑日志和镜像文件拷贝到 Secondary NameNode。
(5)Secondary NameNode 加载编辑日志和镜像文件到内存,并合并。
(6)生成新的镜像文件 fsimage.chkpoint。
(7)拷贝 fsimage.chkpoint 到 NameNode。
(8)NameNode 将 fsimage.chkpoint 重新命名成 fsimage
2.Secondary NameNode辅助恢复NameNode流程,恢复NameNode环写之前的数据
第一步:杀死namenode进程
第二步:删除namenode的fsimage与edits文件
第三步:拷贝secondaryNamenode的fsimage与edits文件到namenode的fsimage与edits文件夹下面去
第四步:启动namenode
3.Secondary NameNode 不能恢复 NameNode 的全部数据,那如何 保证 NameNode 数据存储安全?
这个问题就要说 NameNode 的高可用了,即 NameNode HA
一个 NameNode 有单点故障的问题,那就配置双 NameNode,配置有两个关键点,
一是必须要保证这两个 NN 的元数据信息必须要同步的,二是一个 NN 挂掉之后
另一个要立马补上。
2.2.6 HDFS组成架构及主要作用
1)NameNode(nn):就是Master,它
是一个主管、管理者。
(1)管理HDFS的名称空间;
(2)配置副本策略;
(3)管理数据块(Block)映射信息;
(4)处理客户端读写请求。
2)DataNode:就是Slave。NameNode
下达命令,DataNode执行实际的操作。
(1)存储实际的数据块;
(2)执行数据块的读/写操作。
3)Client:就是客户端。
(1)文件切分。文件上传HDFS的时候,Client将文件切分成一个一个的Block,然后进行上传;
(2)与NameNode交互,获取文件的位置信息;
(3)与DataNode交互,读取或者写入数据;
(4)Client提供一些命令来管理HDFS,比如NameNode格式化;
(5)Client可以通过一些命令来访问HDFS,比如对HDFS增删查改操作;
4)Secondary NameNode:并非NameNode的热备。当NameNode挂掉的时候,它并不
能马上替换NameNode并提供服务。
(1)辅助NameNode,分担其工作量,比如定期合并Fsimage和Edits,并推送给NameNode ;
(2)在紧急情况下,可辅助恢复NameNode。
2.2.7 Hadoop集群启动时要启动哪些进程?作用?
1.NameNode它是hadoop中的主服务器,管理文件系统名称空间和对集群中存储的文件的访问,保存有metadate。
2.SecondaryNameNode它不是namenode的冗余守护进程,而是提供周期检查点和清理任务。帮助NN合并editslog,减少NN启动时间。
3.DataNode它负责管理连接到节点的存储(一个集群中可以有多个节点)。每个存储数据的节点运行一个datanode守护进程。
4.ResourceManager(JobTracker)JobTracker负责调度DataNode上的工作。每个DataNode有一个TaskTracker,它们执行实际工作。
5.NodeManager(TaskTracker)执行任务
6.DFSZKFailoverController高可用时它负责监控NN的状态,并及时的把状态信息写入ZK。它通过一个独立线程周期性的调用NN上的一个特定接口来获取NN的健康状态。FC也有选择谁作为Active NN的权利,因为最多只有两个节点,目前选择策略还比较简单(先到先得,轮换)。
7.JournalNode 高可用情况下存放namenode的editlog文件.
2.2.8 MapReduce工作原理
Map task:
程序会根据InputFormat将输入文件分割成splits,每个split会作为一个map task的输入,每个map task会有一个内存缓冲区,输入数据经过map阶段处理后的中间结果会写入内存缓冲区,并且决定数据写入到哪个partitioner,当写入的数据到达内存缓冲区的的阀值(默认是0.8),会启动一个线程将内存中的数据溢写入磁盘,同时不影响map中间结果继续写入缓冲区。在溢写过程中,MapReduce框架会对key进行排序,如果中间结果比较大,会形成多个溢写文件,最后的缓冲区数据也会全部溢写入磁盘形成一个溢写文件(最少有一个溢写文件),如果是多个溢写文件,则最后合并所有的溢写文件为一个文件。
Reduce task:
当所有的map task完成后,每个map task会形成一个最终文件,并且该文件按区划分。reduce任务启动之前,一个map task完成后,
就会启动线程来拉取map结果数据到相应的reduce task,不断地合并数据,为reduce的数据输入做准备,当所有的map tesk完成后,
数据也拉取合并完毕后,reduce task 启动,最终将输出输出结果存入HDFS上。
2.2.9 MapReduce中shuffer机制
shuffle 阶段分为四个步骤:依次为:分区,排序,规约,分组,其中前三个步骤
在 map 阶段完成,最后一个步骤在 reduce 阶段完成
shuffle 是 Mapreduce 的核心,它分布在 Mapreduce 的 map 阶段和 reduce
阶段。一般把从 Map 产生输出开始到 Reduce 取得数据作为输入之前的过程称
作 shuffle。
1. Collect 阶段:将 MapTask 的结果输出到默认大小为 100M 的环形缓冲区,保存的
是 key/value,Partition 分区信息等。
2. Spill 阶段:当内存中的数据量达到一定的阀值的时候,就会将数据写入本地磁盘,
在将数据写入磁盘之前需要对数据进行一次排序的操作,如果配置了 combiner,还会将有
相同分区号和 key 的数据进行排序。
3. Merge 阶段:把所有溢出的临时文件进行一次合并操作,以确保一个 MapTask 最终
只产生一个中间数据文件
4.** Copy 阶段**:ReduceTask 启动 Fetcher 线程到已经完成 MapTask 的节点上复制一份
属于自己的数据,这些数据默认会保存在内存的缓冲区中,当内存的缓冲区达到一定的阀值
的时候,就会将数据写到磁盘之上
4. Merge 阶段:在 ReduceTask 远程复制数据的同时,会在后台开启两个线程对内存到
本地的数据文件进行合并操作
5. Sort 阶段:在对数据进行合并的同时,会进行排序操作,由于 MapTask 阶段已经对
数据进行了局部的排序,ReduceTask 只需保证 Copy 的数据的最终整体有效性即可。
Shuffle 中的缓冲区大小会影响到 mapreduce 程序的执行效率,原则上说,缓冲区越大,
磁盘 io 的次数越少,执行速度就越快
缓冲区的大小可以通过参数调整, 参数:mapreduce.task.io.sort.mb 默认 100M
2.2.10 MapReduce中切片机制
1.MapReduce中FileInputFormat 切片机制
- 简单地按照文件的内容长度进行切片
- 切片大小,默认等于Block大小
- 切片时不考虑数据集整体,而是逐个针对每一个文件单独切片
2.MapReduce中CombineTextInputFormat 切片机制
框架默认的 TextInputFormat 切片机制是对任务按文件规划切片,不管文件多小,都会
是一个单独的切片,都会交给一个 MapTask,这样如果有大量小文件,就会产生大量的
MapTask,处理效率极其低下。