Skip to content
kiddingbaby edited this page Dec 6, 2017 · 126 revisions

项目依赖

  • hadoop(2.7.3)
  • mysql(5.5+)
  • hive(1.2.1): 提交 hive 任务需要用到
  • spark(1.6.3): 提交 spark 任务需要用到
  • storm(1.1.0): 提交 storm 任务需要用到
  • baifendian-datax: 导入导出任务需要使用
  • livy: 采用 spark 引擎执行 SQL 需要使用, 当前可以不安装

编译

git clone https://github.com/baifendian/swordfish.git
    
cd  {swordfish_source_code_home}
mvn -U clean package assembly:assembly -Dmaven.test.skip=true

注意,跑单元测试需要配置好:$HADOOP_HOME,不然会报错。

正常编译完后,会在当前目录生成 target/swordfish-all-{version}.

查看该目录, 如下:

.
bin/
conf/
lib/
script/
sql/

初始化

数据库初始化

注意 mysqld 配置为:

[client]
default-character-set = utf8mb4

[mysql]
default-character-set = utf8mb4

[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
  • 创建 db 和 账号
mysql -h {hostname} -u {admin-user} -p{password}

mysql> CREATE DATABASE {db-name} DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;
mysql> GRANT ALL PRIVILEGES ON {db-name}.* TO '{db-user}'@'%' IDENTIFIED BY '{password}';
mysql> GRANT ALL PRIVILEGES ON {db-name}.* TO '{db-user}'@'localhost' IDENTIFIED BY '{password}';
mysql> flush privileges;
  • 创建表

说明:sql 为 {swordfish_source_code_home}/sql/create-table.sql

mysql -h {hostname} -u {db-user} -p{password} -D {db-name} < {swordfish_source_code_home}/sql/create-table.sql

创建quartz相关表,sql为 {swordfish_source_code_home/sql/CreateQuartTables.sql

mysql -h {hostname} -u {db-user} -p{password} -D {db-name} < {swordfish_source_code_home}/sql/CreateQuartTables.sql

部署账号权限

由于 exec-server 通过 sudo 方式来实现作业由指定用户执行,所有部署的账号需要具备 sudo 权限,且是免秘钥的方式。

vi /etc/sudoers (最好用 visudo 命令)

# 这里假定我们部署采用的是 swordfish 账号
swordfish  ALL=(ALL)       NOPASSWD: NOPASSWD: ALL

# 并且需要注释掉 Default requiretty 一行
#Default requiretty

服务配置

注意:部署 swordfish 的各个服务器之间,应进行时钟的同步。

方案一

说明:配置文件位于 {swordfish_source_code_home}/target/swordfish-all-{version}/conf 下面。

  • 1.配置 application.properties
# api 应用启动的端口,默认为 12345
server.port=
  • 2.配置 common
common/
├── base_config.properties
├── hadoop
│   └── hadoop.properties
├── hive
│   └── hive.properties
├── mail.properties
├── search.properties
└── storm.properties
└── phoenix.properties

base_config.properties 中的重要配置:

注意:下面的相关目录,运行时会自动创建,用户也可以自己创建,确保采用部署用户来创建即可。

# 表示禁用用户列表,即任务不能以这些账号进行执行,一般列出具备 root 权限的用户
prohibit.user.list=

# 本地文件缓存目录
local.data.basepath=/tmp/swordfish/filecache

# 下载时使用的本地缓存目录
local.download.basepath=/tmp/swordfish/downloadcache

# 执行目录
local.exec.basepath=/tmp/swordfish/exec

# hdfs 存储数据的目录
hdfs.data.basepath=/tmp/swordfish/filecache

# 本地的 jar 包目录,udf 文件放在这里面
hdfs.udfjar.basepath=/tmp/swordfish/hiveJars

# 导入导出使用的 hdfs 临时目录,有个特别要说明的是,这个目录需要是 0777 权限,它的上级需要是 755 即可
hdfs.impexp.basepath=/tmp/swordfish/impexp

# 执行任务的环境变量文件,由于各工作流的执行用户是不一样的,这里配置全局的环境变量信息,如 
# HADOOP_HOME,PATH 等。
# 另注意该文件存放路径需保证各执行用户有访问权限,且需要是绝对路径,该文件需要用户手动创建。
sf.env.file=/home/swordfish/.sf_env.sh

# 是否是开发模式,true 表示在开发模式下,系统会保留临时文件,生产环境不建议开启
develop.mode=false

注意:若有其他组件配置了环境变量,如Tez,这里必须保证sf.env.file文件中包含该环境变量。

具体 sf.env.file 文件的示例(该文件需要具备 0755 权限,上一级目录需要是 0755,比如 chmod -R 0755 /home/swordfish/.sf_env.sh):

export HADOOP_HOME=/home/bfd_hz/hadoop
export HADOOP_CONF_DIR=/home/bfd_hz/hadoop/etc/hadoop/

export SPARK_HOME=/home/bfd_hz/spark

export STORM_HOME=/home/bfd_hz/storm

export PYTHON_HOME=/opt/Python-2.7
export JAVA_HOME=/opt/java

export HIVE_HOME=/home/bfd_hz/hive

export PATH=$HIVE_HOME/bin:$HADOOP_HOME/bin:$SPARK_HOME/bin:$JAVA_HOME/bin:$PYTHON_HOME/bin/:$STORM_HOME/bin:$PATH

hadoop/hadoop.properties 配置说明:需要将相关的 hadoop 访问地址改为正确的地址。

mail.properties 配置说明:邮件配置,修改相应的配置即可。

search.properties 配置说明:

# es 连接地址,注意这里是 es 的 node 连接地址,一般端口为 9300
es.address =

# es 集群的名称
es.cluster.name =

hive/hive.properties 重要配置说明:

# hive metastore 地址,使用 metastore server 时配置
hive.metastore.uris=

# hive thrift 地址 
hive.thrift.uris=

storm.properties重要配置说明:

# storm rest api
storm.rest.url=

# storm status api
storm.rest.topology=/topology.html?id=

phoenix.properties重要配置说明:

# phoenix host
phoenix.host = 

# phoenix port
phoenix.port = 

  • 3.配置 dao
.
└── dao
    └── data_source.properties

dao/data_source.properties 配置说明(注意下面的配置需要和上面数据库初始化中的 {db-name}, {db-user}, {password} 保存一致):

# mysql 的连接信息,需要修改的
spring.datasource.url=

# mysql 连接账号
spring.datasource.username=

# mysql 连接密码
spring.datasource.password=
  • 4.配置 master.properties
# master 请求 worker 第一次失败后的,默认的重试次数(0 表示不重试)
masterToWorker.failRetry.count=

# master 请求 worker 的工作流队列大小的最大值
masterToWorker.executionFlow.queueSize=

# master 心跳检查间隔
master.heartbeat.check.interval=

# master 心跳超时间隔
master.heartbeat.timeout.interval=

# master 启动端口
master.port=12000

# 流任务的检测状态周期,单位:秒
streaming.check.interval=

# 流任务提交后,没有进入接受、运行状态的超时时间,单位:秒
streaming.timeout.threshold=

quartz.properties 重要配置说明:

# quartz jdbc 连接 url
org.quartz.dataSource.myDS.URL=

# quartz jdbc 用户
org.quartz.dataSource.myDS.user=

# quartz jdbc 连接密码
org.quartz.dataSource.myDS.password=
  • 5.配置 worker.properties
# worker 端口
executor.port=12001

# worker 的心跳汇报间隔
executor.heartbeat.interval=

# 即席查询运行线程池大小
executor.adhocrunner.threads=

# 工作量运行线程池大小
executor.flowrunner.threads=

# 结点运行线程池大小
executor.noderunner.threads=

# 流任务运行运行线程大小
executor.streaming.threads=

# 编译的dataX所在的目录,非dataX源码目录。一般在编译后的源码包target/datax/datax内。
executor.datax.home=

方案二

按照方案一配置好 sf.env.file=/home/swordfish/.sf_env.sh,采用 install.sh 脚本,修改其中的变量信息,替换为正确的值。然后运行 install.sh:

# 其中 -r true 表示会执行配置文件的变量替换,-r false 表示不会执行替换,-m module 表示部署具体的模块,其中 all 表示所有模块
./install.sh -r <true|false> -m <all|web-server|master-server|exec-server>

# 需要注意的是,这种方案不仅会完成配置,还会启停服务,缺点是该脚本只提供了部分的配置项替换。

配置注意项

有一个设置超时的配置,必须满足一个条件,如下所示:

{executor.heartbeat.interval} + {master.executor.maxallow.ticket.interval} + 18 <= {master.heartbeat.timeout.interval}

启停

  • 1.启停 API
cd {swordfish_source_code_home}/target/swordfish-all-{version}/
./bin/swordfish-daemon.sh start web-server
./bin/swordfish-daemon.sh stop web-server
  • 2.启停 Master
cd {swordfish_source_code_home}/target/swordfish-all-{version}/
./bin/swordfish-daemon.sh start master-server
./bin/swordfish-daemon.sh stop master-server
  • 3.启停 Worker

说明:启动 Worker 的用户,必须具有 sudo 权限,且是免密码方式。

cd {swordfish_source_code_home}/target/swordfish-all-{version}/
./bin/swordfish-daemon.sh start exec-server
./bin/swordfish-daemon.sh stop exec-server

上面操作,注意启动之后查看进程是否存在,停止之后进程是否关闭。

日志收集

日志收集,采用的是 ELK 框架,即 elasticsearch,logstash,kibana,另外还有 filebeat 组件。其中 filebeat 用于扫描日志文件,将日志发送到 logstash 服务,logstash 服务则完成将日志切分,发送到 elasticsearch 服务。

  • filebeat(日志 -> logstash)
# 配置文件如下(swordfish-filebeat.yml):

filebeat.prospectors:
- input_type: log
  multiline.timeout: 1s
  paths:
    - {swordfish_source_code_home}/target/swordfish-all-{version}/logs/exec-server*.log
  multiline:
    pattern: '^\['
    negate: true
    match: after
#  exclude_lines: ["^\\[DEBUG\\]"]

output.logstash:
  hosts: ["{logstash-ip}:{logstash-port}"]

启动方式为:

./filebeat -e -c swordfish-filebeat.yml -d publish &
  • logstash(logstash -> elasticsearch)
# 配置文件如下(swordfish-pipeline.conf):

input {
  beats {
    port => "{logstash-port}"
  }
}
# The filter part of this file is commented out to indicate that it is
# optional.
# filter {
#
# }
#

filter {
  grok {
    match => { "message" => ["%{LOGLEVEL:logLevel}\]\[%{NUMBER:nanoTime:integer}\](?<V1>.*)\[jobId=(?<jobId>[\w\d\-_]+)\](?<V2>.*)", "%{LOGLEVEL:logLevel}\]\[%{NUMBER:nanoTime:integer}\](?<V1>.)(?<V2>.*)"] }
    add_field => { "nest_msg" => "[%{logLevel}]%{V1}%{V2}" }
    remove_field => [ "message", "V1", "V2" ]
  }

  if ![jobId] {
  drop {}
}

mutate {
  convert => { "nanoTime" => "integer" }
}
}

output {
  stdout {
    codec => json
  }
  elasticsearch {
    hosts => [ "{es-ip}:{es-port}", "{es-ip}:{es-port}", "{es-ip}:{es-port}" ]
    codec => json
    index => "swordfish-logstash-%{+YYYY.MM.dd}"
  }
}

启动方式为:

bin/logstash -f swordfish-pipeline.conf &

部署测试

参考使用 python client

FAQ

  1. 服务启动失败
    可能是端口重复导致,请检测一下端口是否被占用。

  2. master-server 启动失败
    检查一下数据库中的表 master_server,看是否具有记录,如果记录中的 ip:port 和当前启动的 master_server 不一致,则需要删除数据库中的记录,或者修改为一致的。

  3. 数据库的配置需要注意什么
    数据库的配置一定要注意编码,编码不要用 utf-8,而是 utf8mb4,实际上 utf8mb4 是 utf8 的超集,不会对业务系统产生影响,它的出现是为了兼容四字节的 unicode。

  4. 提交的工作流,在执行的时候会以什么账号运行
    代理账号执行,也就是 API 中的 proxyUser 字段。

  5. 部署账号为什么需要 sudo 免秘钥的权限
    因为系统运行的时候,是采用代理用户执行的,如果代理用户不存在,则会创建用户,系统切换到代理账号执行,是需要具有 sudo 免秘钥权限的。

  6. 禁用用户列表的配置 prohibit.user.list 有什么作用
    因为系统是以代理账号运行,但是我们希望在执行工作流的时候,能保证系统安全,所以有一个禁用用户列表,比如,我们不希望能够代理 root 账号执行,就需要配置 prohibit.user.list=root,如果还需要加上其它用户,可以以逗号分隔多个用户,比如 root,swordfish

  7. 系统用到的本地和 hdfs 目录都有什么作用,需要什么权限
    系统在运行过程中,会生成一个本地执行目录,另外,在上传、下载 API 中,会用到本地和 hdfs 的目录,以及生成 udf 函数,执行工作流的导入导出等,都需要具有相应的目录权限,除了导入导出需要 0777 权限,其它的操作是以部署账号执行的,所以部署系统的用户需要对这些目录具备读、写权限。

  8. 系统如何支持容灾和负载均衡的
    系统分为 web-server,master-server,exec-server,其中 web-server,exec-server 是可以多台部署,支持高可用,但是 master-server 在当前设计中存在单点故障,exec-server 是实际执行任务的服务,多个 exec-server 的负载均衡采用的是随机策略,也就是说一个任务(工作流、流任务、即席任务等)的执行会随机发送到一个 exec-server 中去。

  9. 工作流日志是怎么收集的
    通过 ELK 技术栈,日志保存在 ElasticSearch 中。

  10. 工作流支持哪些类型
    具体请参见 任务类型描述

  11. 流任务支持哪些类型
    具体请参见 任务类型描述

  12. 系统为什么会依赖 DataX
    实际上,在 IMPEXP 任务类型中,采用了 DataX,但是如果用户不创建该任务类型,是可以不安装 DataX 的。如果用到了 DataX,需要配置 worker.properties 文件中的 executor.datax.home 参数。

  13. 构建工作流的时候,结点可以是流任务类型吗
    不可以,流任务的运行机制和普通的工作流不一样,所以构建工作流的 DAG 的时候,结点类型不可以是 流任务类型。