CDH+airflow

简介

本文档将展示如何部署数据仓库以及简单展示其使用场景和方式。

环境

软件 版本
Centos 7.2
CDH 5.15.0
Hadoop 2.6.0
Airflow 1.10.9
Python 2.7.5 (系统自带)3.7.0 (需要安装)
MySQL 5.7.28
Redis 4.0.14
Sqoop 1.4.6

模块安装

Airflow

Airflow是一个编排、调度和监控workflow的平台,由Airbnb开源,现在在Apache Software Foundation 孵化。airflow 将workflow编排为tasks组成的DAGs,调度器在一组workers上按照指定的依赖关系执行tasks。同时,airflow 提供了丰富的命令行工具和简单易用的用户界面以便用户查看和操作,并且airflow提供了监控和报警系统。

在生产中,airflow的集群并没有必要性,且airflow集群需要保持全部配置一致,增加了额外的操作和学习成本,因此本文只在CDH集群的主机上部署了airflow。

升级Python

编译环境

yum install gcc-c++ gcc make cmake zlib-devel bzip2-devel openssl-devel ncurse-devel libffi-devel -y复制代码

编译安装Python3

准备好Python-3.7.0.tar.xz

# 确认版本
python -V
# 解压
tar Jxvf Python-3.7.0.tar.xz
# 进入python3.7.0目录
cd Python-3.7.0
# 创建目录
mkdir -p /usr/local/python3
# 配置(指定安装目录)
./configure --prefix=/usr/local/python3 --enable-optimizations
make && make install复制代码

修改系统路径

#备份原有默认Python路径
mv /usr/bin/python /usr/bin/python.bak
#将 python 链接至 python3
ln -s /usr/local/python3/bin/python3.7 /usr/bin/python
ln -s /usr/local/python3/bin/pip3 /usr/bin/pip
# 升级pip
pip install --upgrade pip
#python如果链接的命令失败,可尝试使用下面这条命令
ln -sf /usr/local/python3/bin/python3.7 /usr/bin/python
# 确认版本
python -V
pip -V复制代码

修改yum路径

修改以下两个文件

vi /usr/bin/yum
vi /usr/libexec/urlgrabber-ext-down复制代码

将第一行的 “#! /usr/bin/python” 改为

#! /usr/bin/python2.7复制代码

Redis安装

安装

cd /tmp
tar zxvf redis-4.0.14.tar.gz
cd redis-4.0.14
make
make install PREFIX=/usr/local/redis
cd /usr/local/redis
mkdir /usr/local/redis/etc
cp /tmp/redis-4.0.14/redis.conf /usr/local/redis/etc/复制代码

配置

编辑配置文件/usr/local/redis/etc/redis.conf修改以下设置

bind 0.0.0.0
daemonize yes
protected-mode no
appendonly yes # 将持久化方案从rdb改为aof
# 如果下面的 'appendfilename "appendonly.aof"' 被注释了,那么就去掉注
# 以下按需修改-----
requirepass foobared
# 紧接着下面写一行 
requirepass your-password
# 如有需求也可以在此修改端口复制代码

启动

# 将redis加入到开机启动
vi /etc/rc.local
#添加内容
/usr/local/redis/bin/redis-server /usr/local/redis/etc/redis.conf
# 启动redis
/usr/local/redis/bin/redis-server /usr/local/redis/etc/redis.conf复制代码

检查

#端口和进程查找
netstat -tunpl | grep 6379
ps -aux | grep redis
#测试
redis-cli复制代码

Airflow安装

新建Linux用户

# 按需修改
adduser airflow
passwd airflow
#输入自定义密码
#修改该用户权限,使该用户在使用sudo时不需要密码
vi /etc/sudoers
root       ALL=(ALL)       ALL
airflow	ALL=(ALL) 	NOPASSWD:ALL 复制代码

修改配置

vi /etc/profile
export AIRFLOW_HOME=/home/airflow #根据需要修改
export PYTHON_HOME=/usr/local/python3 #根据实际情况修改
export SLUGIFY_USES_TEXT_UNIDECODE=yes #临时设定
export PATH=$PATH:$PYTHON_HOME/bin
source /etc/profile复制代码

安装

pip install --upgrade setuptools -i http://pypi.douban.com/simple/ --trusted-host=pypi.douban.com
cd /tmp
wget http://repo.mysql.com/mysql57-community-release-el7-8.noarch.rpm
rpm -ivh mysql57-community-release-el7-8.noarch.rpm


yum install mysql-deve


pip install apache-airflow -i http://pypi.douban.com/simple/ --trusted-host=pypi.douban.co复制代码

此时airflow会被安装到Python下的第三方包中,路径为${PYTHON_HOME}/lib/python3.7/site-packages/airflow

pip show apache-airflow复制代码

继续安装

pip install apache-airflow[mysql] -i http://pypi.douban.com/simple/ --trusted-host=pypi.douban.com
pip install apache-airflow[celery] -i http://pypi.douban.com/simple/ --trusted-host=pypi.douban.com
pip install apache-airflow[redis] -i http://pypi.douban.com/simple/ --trusted-host=pypi.douban.com


# 测试
airflow version复制代码

MySQL

默认在部署CDH时已经完成MySQL初期设置。

mysql -u root -p
# 针对airflow使用创建数据库,添加用户并授权
CREATE DATABASE airflow CHARACTER SET utf8 COLLATE utf8_unicode_ci;


# 修改密码强度
set global validate_password_policy=0; 
set global validate_password_length=4;


CREATE USER af@localhost IDENTIFIED BY 'xxxxx';
grant all privileges on airflow.* to 'af'@'%' identified by 'xxxxx' with grant option;
flush privileges;


# 开启timestamp ,数据更新时添加上当前时间(airflow推荐)
set @@global.explicit_defaults_for_timestamp=on;
exit
#重启服务器
service mysqld restart


# 账户测试
mysql -u af -p
show databas复制代码

Airflow配置

核心配置

# 编辑/home/airflow/airflow.cfg文件,修改以下内容,根据实际情况填写[ip和端口]:
sql_alchemy_conn = mysql://af:af123@10.0.10.xx:3306/airflow
# 格式mysql://帐号:密码@ip:port/db
executor = CeleryExecutor
#web_server_host = 10.0.10.xx
base_url = http://10.0.10.xx:8080


[celery] 
broker_url = redis://10.0.10.xx:6379/0
result_backend = db+mysql://af:xxxxx@10.0.10.xx:3306/airflow


# 进入 dag 详细页面时直接渲染依赖图
dag_default_view = graph


# 修改时区
default_timezone = Asia/Shangh复制代码

修改webUI的时间

修改以下文件,注意

${PYTHON_HOME}/lib/python3.7/site-packages/airflow复制代码

是airflow的安装路径。

/home/airflow/.local/lib/python3.7/site-packages/airflow/utils/timezone.py

img

img

/home/airflow/.local/lib/python3.7/site-packages/airflow/utils/sqlalchemy.py

img

/home/airflow/.local/lib/python3.7/site-packages/airflow/www/templates/admin/master.html

img

其他配置

# 不加载示例 dag
load_examples = False


# 以 airflow 用户运行 task
default_impersonation = airflow


# 对每个 dag,只运行最新达到周期条件的实例
catchup_by_default = False


# scheduler 的最大线程数
max_threads =复制代码

启动

初次使用或需要初始化数据库时

airflow initdb复制代码

使用操作系统的airflow用户登录,并运行

airflow webserver -D
airflow scheduler -D
airflow flower -D
airflow worker -D 复制代码

webUI

airflow host:8080
flower host:5555

测试

DAG脚本,如是集群,则需要在所有节点下配置DAG

mkdir /home/airflow/dags复制代码

在这个文件夹里存放这个hello_world.py文件。

# -*- coding: utf-8 -*-


import airflow
from airflow import DAG
from airflow.operators.bash_operator import BashOperator
from airflow.operators.python_operator import PythonOperator
from datetime import timedelta


#-------------------------------------------------------------------------------
# these args will get passed on to each operator
# you can override them on a per-task basis during operator initialization


default_args = {
    'owner': 'airflow',
    'depends_on_past': False,
    'start_date': airflow.utils.dates.days_ago(2),
    'email': ['langai818@qq.com'],
    'email_on_failure': False,
    'email_on_retry': False,
    'retries': 1,
    'retry_delay': timedelta(minutes=5),
}


#---------------------------------------------------------------------
# dag


dag = DAG(
    'hello_world_dag',
    default_args=default_args,
    description='test DAG',
    schedule_interval=timedelta(days=1))
    
def print_hello():
    return 'Hello world!'


#---------------------------------------------------------------------
# first operator


date_operator = BashOperator(
    task_id='date_task',
    bash_command='date',
    dag=dag)


#---------------------------------------------------------------------
# second operator


sleep_operator = BashOperator(
    task_id='sleep_task',
    depends_on_past=False,
    bash_command='sleep 5',
    dag=dag)


#---------------------------------------------------------------------
# third operator


hello_operator = PythonOperator(
    task_id='hello_task',
    python_callable=print_hello,
    dag=dag)


#---------------------------------------------------------------------
# dependencies


sleep_operator.set_upstream(date_operator)
hello_operator.set_upstream(da复制代码

Python代码验证

python hello_world.py复制代码

Airflow编译运行

airflow list_dags
airflow list_tasks dag_name 
airflow test dag_name task_name date
#清空任务实例
airflow clear dag_id 复制代码

Sqoop

测试环境配置

静态网关

为了方便测试,将本机(Windows)的网关设为静态。

img

img

关闭防火墙

img

img

img

img

MySQL设置

# 以下改动针对MySQL数据库,操作系统为Windows10
# 针对sqoop添加用户并授权
[mysql]
CREATE USER sqoop@localhost IDENTIFIED BY 'xxxxxx';
grant all privileges on *.* to 'sqoop'@'%' identified by 'xxxxxx' with grant option;
flush privileges;


# 重启服务器
exit
[bash]
service mysqld restart


# 账户测试
mysql -u af -p
show databases复制代码

测试

连接测试

sqoop list-databases --connect jdbc:mysql://10.0.11.99/ --username sqoop -P
sqoop list-tables --connect jdbc:mysql://10.0.11.xx/database_name--username sqoop -P
sqoop import --connect jdbc:mysql://10.0.11.xx/database_name --username sqoop -password xxxxxx-table table_name复制代码

MySQL等数据库,提供自己的传输方式,可以大大加速抽取的速度。

sqoop import --connect jdbc:mysql://10.0.11.xx/database_name-- username sqoop -password xxxxxx-table table_name --direct复制代码

脚本导入

create database if not exists shell_db comment "data import with script" location '/user/hive/warehouse/shell_db';复制代码

编写全量抽取覆盖脚本,hive和sqoop不区分表名和字段的大小写。

#!/bin/bash


local_db_address='10.0.11.xx'
db_name='shell_db'
tables=(cjd jgtzd rkd scjh scjld zcjh)


for table_name in ${tables[@]};
do
  sqoop import \
    --connect jdbc:mysql://$local_db_address/gnbz \
    --direct \
    --username sqoop \
    --password xxxxxx \
    --table $table_name \
    --m 2 \
    --hive-import \
    --hive-overwrite \
    --delete-target-dir \
    --hive-database $db_name;
don复制代码

定时任务

Note that if you run a DAG on a schedule_interval of one day, the run stamped 2016-01-01 will be trigger soon after 2016-01-01T23:59. In other words, the job instance is started once the period it covers has ended.

Airflow什么时候开始执行任务?实际上是从dag的start_date + schedule_interval开始的,如果schedule_interval设成@daily,那么会从start_date之后的一天开始。

整合

使用airflow完成每日对两个表的定时全量更新,然后将他们的部分字段组合成一个表。

用到的脚本一共有三个,使用一个Python文件作文DAG调度他们。

脚本

qw_import.sh

#!/bin/bash


db_address='192.168.200.xx'
db_name='dw1'
tables=(BIStoreFGReceive)


for table_name in ${tables[@]};
do
  sqoop import \
    --connect jdbc:mysql://$db_address/db_qw \
    --direct \
    --username ljw1 \
    --password xxx \
    --table $table_name \
    --m 1 \
    --hive-import \
    --hive-overwrite \
    --delete-target-dir \
    --hive-table $table_name \
    --hive-database $db_name;
don复制代码

kfq_import.sh

#!/bin/bash


db_address='192.168.200.xx4'
db_name='dw1'
tables=(RKD)


for table_name in ${tables[@]};
do
  sqoop import \
    --connect jdbc:mysql://$db_address/db_kaifaqu \
    --direct \
    --username ljw1 \
    --password xxxxxx \
    --table $table_name \
    --m 1 \
    --hive-import \
    --hive-overwrite \
    --delete-target-dir \
    --hive-table $table_name \
    --hive-database $db_name;
don复制代码

hive_comb.sql

-- 如果不存在则新建表
CREATE TABLE IF NOT EXISTS dw1.d_output(
storage_date timestamp,
unit_area DOUBLE,
storage_qty DOUBLE,
base_no INT)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';


-- 清空现有表中数据
truncate table dw1.d_output;


-- 插入老ERP数据
insert into dw1.d_output
select
cast(date_format(substr(ReceiveDate,1,10),'yyyy-MM-dd') as timestamp) as storage_date,
UnitArea as unit_area,
ReceiveQty as storage_qty,
6 as base_no
from dw1.bistorefgreceive;


-- 插入企望数据
insert into dw1.d_output
select
cast(date_format(substr(rkrq,1,10),'yyyy-MM-dd') as timestamp) as storage_date,
cpmj as unit_area,
rksl as storage_qty,
8 as base_no
from dw1.rk复制代码

DAG

# -*- coding: utf-8 -*-


import airflow
from airflow import DAG
from airflow.operators.bash_operator import BashOperator
from airflow.operators.python_operator import PythonOperator
from airflow.operators.email_operator import EmailOperator
from datetime import timedelta, datetime
from airflow.utils.trigger_rule import TriggerRule


default_args = {
    'owner': 'jin',
    'depends_on_past': False,
    'start_date': datetime(2020, 4, 12, 18),
    'email': ['jwli@aiit.org.cn'],
    'email_on_failure': False,
    'email_on_retry': False,
    'retries': 1,
    'retry_delay': timedelta(minutes=5),
}


dag_sqool_import = DAG(
    dag_id="daily_task",
    default_args=default_args,
    description='import and combine tasks',
    schedule_interval=timedelta(days=1))
# --------------------------------------------------------------------
kfq_script = "/home/script/kfq_import_all.sh"
qw_script = "/home/script/qw_import_all.sh"
#jd_script = "/home/script/jindie_import.sh"
hive_script = "/home/script/hive_comb.sql"


task_import_kfq = BashOperator(
    task_id='import_kfq',
    bash_command=". %s " % kfq_script,
    dag=dag_sqool_import)


task_import_qw = BashOperator(
    task_id='import_qw',
    bash_command=". %s " % qw_script,
    dag=dag_sqool_import)
    
task_combine = BashOperator(
    task_id='hive_combine',
    bash_command= "hive -f %s " % hive_script,
    dag=dag_sqool_import
)


[task_import_kfq, task_import_qw] >> task_co复制代码

运维

CDH

#主节点
/opt/cm-5.15.0/etc/init.d/cloudera-scm-server start
#所有节点
/opt/cm-5.15.0/etc/init.d/cloudera-scm-agent start
# 查询状态
/opt/cm-5.15.0/etc/init.d/cloudera-scm-agent status
/opt/cm-5.15.0/etc/init.d/cloudera-scm-server status
# 查询日志
tail -f /opt/cm-5.15.0/log/cloudera-scm-agent/cloudera-scm-agent.log
tail -f /opt/cm-5.15.0/log/cloudera-scm-agent/cloudera-scm-server.log
# 关闭
/opt/cm-5.15.0/etc/init.d/cloudera-scm-agent stop
/opt/cm-5.15.0/etc/init.d/cloudera-scm-server stop
# 退出安全模式
sudo -uhdfs hdfs dfsadmin -safemode leave
# Datanode健康状况
hdfs datanode
#清空回收站
hdfs dfs -expunge复制代码

airflow

cd /home/airflow/
rm -rf *.pid
# 删除所有pid,然后
airflow webserver -D
airflow scheduler -D
airflow worker -D
airflow flower -D复制代码

Linux

查找文件

find / -name file_name复制代码

Hive

查询表的最后修改时间

先找出表对应的transient_lastDdlTime

SHOW CREATE TABLE table_name;复制代码

或者

show TBLPROPERTIES table_name ('transient_lastDdlTime');复制代码

然后将该值代入以下query

SELECT CAST(from_unixtime(your_transient_lastDdlTime_value) AS timestamp);复制代码

或使用网页工具时间转换

错误排查

环境/配置

bash: airflow: command not found

需要添加airflow的系统路径

vi /etc/profile
# 末尾追加以下
export PATH=$PATH:$PYTHON_HOME/bin复制代码

mysql_config: command not found

在安装apache-airflow[mysql]时报错,是因为在安装MySQL时使用了编译安装,缺少了部分repo文件。

wget http://repo.mysql.com/mysql57-community-release-el7-8.noarch.rpm
rpm -ivh mysql57-community-release-el7-8.noarch.rpm
yum install mysql-devel复制代码

Global variable explicit_defaults_for_timestamp needs to be on (1) for mysql

vi /etc/my.cnf
# 在末尾追加
explicit_defaults_for_timestamp=1
# 重启MySQL
systemctl restart mysqld.service复制代码

或者

set @@global.explicit_defaults_for_timestamp=on;
# 重启MySQL
service mysqld restart复制代码

bash: netstat: command not found

yum install net-tools复制代码

登录用户出现‘-bash-4.2$’

原因:是在用useradd添加普通用户时,有时会丢失家目录下的环境变量文件,丢失文件如下:

  1. .bash_profile
  2. .bashrc

以上这些文件是每个用户都必备的文件。

方案:使用以下命令从主默认文件/etc/skel/下重新拷贝一份配置信息到此用户的家目录下。

cp /etc/skel/.bashrc  /home/airflow
cp /etc/skel/.bash_profile   /home/airflow复制代码

ssh: connect to host localhost port 22: Connection refused

yum install openssh-server复制代码

Airflow

Internal Server Error 500

原因:服务器没有正常启动。

方案:清空AIRFLOW_HOME下的所有out,err,log和pid文件,杀掉所有airflow相关的进程,然后重新启动airflow服务。

lockfile.AlreadyLocked: /home/airflow/airflow-webserver-monitor.pid is already locked 等类似问题

原因:进程ID被占用。

方案:清空AIRFLOW_HOME下的所有err和log文件,杀掉所有airflow相关的进程。

Sqoop

Hive

Job Submission failed with exception 'org.apache.hadoop.security.AccessControlException(Permission denied: user=root, access=WRITE, inode="/user":hdfs:supergroup:drwxr-xr-x

方案:创建root路径

# su - hdfs  
$ hdfs dfs -mkdir /user/root  
$ hdfs dfs -chown root:root /user/root复制代码

如果已经有了/user/root ,查看下文件的权限

[root@dn001 ~]# hdfs dfs -ls /user复制代码

改为root所有:

# hdfs dfs -chown root:root /user/root
hdfs dfs -chmod 777 /user/root复制代码

或:

img

然后重启HDFS服务器。

日志空间不足

修改配置

  1. CM管理控制台查看告警内容,很多都是日志空间不足。进入每个服务的配置页面,点击筛选“日志”,将每一个的最大日志文件备份从10改为2
  2. 在CM管理控制台,点击进去HDFS的配置页面,输入:dfs.replication,查看为3,改为2
  3. 登录集群的机器,输入命令hadoop fs -setrep -R 2 /,重启
  4. 重启完毕,查看主机存储,发现有些不平衡。故登录CM管理控制台的HDFS界面,点击操作,选择重新平衡。平衡完毕,各个主机的存储基本平衡。

修改的组件:

HDFS、YARN

查询HDFS存储情况

hadoop dfsadmin -report复制代码

img

清除tmp中的monitor文件

img

清理回收站

hadoop fs -expunge复制代码

参考资料

[Airflowv1.10]任务调度平台的安装教程

centos7安装mysql-devel出现包依赖问题

Command Line Interface Reference

Sqoop导入关系数据库到Hive

官网: Importing Data Into Hive

Sqoop User Guide (v1.4.6)

Hive Tutorial

How can I find last modified timestamp for a table in Hive?

CDH磁盘空间即将满之后的解决措施

posted @ 2021-06-24 21:00  叨叨勋  阅读(455)  评论(0编辑  收藏  举报