採集方式彙集(sqoop、spark、flume、logstash、filebeat)

前文:

           數據倉庫中ods層一般使用外部表,一般默認採用 \001 作爲分隔符,但textfile格式在遇到文本數據就會有分隔符及換行符問題,所以採用parquet作爲存儲格式,但也會引進數據類型轉換的問題。

            對於日誌數據,kafka中經常存放不同來源的日誌數據,可通過Flume的正則匹配將數據發送到不同的hdfs文件夾。

            對於部分mysql百萬級進行模糊查詢將會產生慢查詢,一般我們用可以存放在es中。

一、Mysql導數據導Hive

1.1 建表

create external table if not exists ods.ods_stu( 
`id` int comment '主鍵Id', 
`name` string comment '名稱',
`addtime` string commint '添加時間'
)comment '姓名錶'
partitioned by (dt string)
stored as parquet
location '/user/hive/warehouse/ods.db/ods_stu';

備註:parquet存儲格式查詢效率高

1.2 使用sqoop導數據

sqoop import \
--connect jdbc:mysql://localhost:3306/ods_stu\
--username root\
--password 123456\
--null-string 'NULL'  \
--null-non-string 'NULL' \
--query '
select * 
from stu
where $CONDITIONS' \
--target-dir /user/hive/warehouse/ods.db/ods_stu/dt=2020-06-04 \
--map-column-java addtime=String \
--map-column-hive addtime=String 
--append \
--split-by id \
--num-mappers 2 \
--as-parquetfile \

存在問題:sqoop直接從mysql導入parquet格式的hive表有一個數據類型異常

Failed with exception java.io.IOException:org.apache.hadoop.hive.ql.metadata.HiveException: java.lang.ClassCastException: org.apache.hadoop.io.LongWritable cannot be cast to org.apache.hadoop.hive.serde2.io.TimestampWritabl

解決方式:採用 --map-column-java 和 --map-column-hive 把mysql中時間類型之間轉換爲string類型存儲hive中

load data inpath '/user/hive/warehouse/ods.db/ods_stu/dt=2020-06-04' into table ods.ods_minisns_systemtag partition (dt = '2020-06-04');

1.3 使用spark導數據

    /**
     * 通過拉取mysql數據,創建臨時表寫入hive中
     */
    val df: DataFrame = spark.read.format("jdbc")
      .options(mysqlParam)
      //增量:單線程
      .option("query", query_mysql)
      .load()
    df.createOrReplaceTempView(tmp_tablename)
    spark.sql(insert_hive);

備註:spark可以直接寫入parquet格式的hive表,並且可以直接數據清洗。但spark連接查詢mysql會有一個散列id排序的問題,並且使用query自定義sql查詢的話只有1個線程拉數據。而sqoop可以完美的解決這兩個問題,使用方式簡單。

1.4sqoop與spark導數據的比較

  sqoop spark
textfile格式外部表 不支持複雜分隔符,需要編譯 無需關心分隔符
paquet格式 需處理數據類型轉換 無需關心數據類型問題
散列id同步 存在傾斜問題

存在傾斜問題

並行度 完美處理 query自定義查詢只有單線程查詢mysql
直接清洗 僅在mysql查詢時清洗,性能較差 拉取數據後直接清洗
使用難度 簡單配置 寫個工具類傳參也可,但較複雜

二、Flume採集Kafka數據

 

2.1kafka數據到hive外部表

a1.sources = r1
a1.channels = c1
a1.sinks = k1

#————————————————————  sources  ————————————————————#

a1.sources.r1.type = org.apache.flume.source.kafka.KafkaSource
a1.sources.r1.batchSize = 5000
a1.sources.r1.batchDurationMillis = 2000
a1.sources.r1.kafka.bootstrap.servers = bigdata-test:9092
a1.sources.r1.kafka.topics = test_0603
a1.sources.r1.kafka.consumer.group.id = custom.g.id
a1.sources.r1.kafka.consumer.auto.offset.reset=earliest



#————————————————————  interceptors  ————————————————————#

a1.sources.r1.interceptors = i1
a1.sources.r1.interceptors.i1.type = regex_extractor

# 正則獲取捕獲組並命名,用於sink文件夾路徑設置

a1.sources.r1.interceptors.i1.regex = (\\d{4}\\-\\d{2}\\-\\d{2})
a1.sources.r1.interceptors.i1.serializers = s1
a1.sources.r1.interceptors.i1.serializers.s1.name = eventTime



#————————————————————  channels  ————————————————————#

a1.channels.c1.type = memory
a1.channels.c1.capacity = 10000
a1.channels.c1.transactionCapacity = 10000
a1.channels.c1.byteCapacityBufferPercentage = 20
a1.channels.c1.byteCapacity = 800000



#————————————————————  sinks  ————————————————————#

a1.sinks.k1.type = hdfs
a1.sinks.k1.hdfs.path = /tmp/flume_test_0603/%{eventTime}

# 使用當地時間(而不是從事件的時間戳頭)而取代轉義序列。
a1.sinks.k1.hdfs.useLocalTimeStamp = true

# DataStream不會壓縮輸出文件
a1.sinks.k1.hdfs.fileType = DataStream	

# 默認爲1024,觸發滾動的文件大小,以字節爲單位(0:從不基於文件大小滾動)
a1.sinks.k1.hdfs.rollSize = 104857600  

# 默認爲30,滾動當前文件之前要等待的秒數(0 =根據時間間隔從不滾動)
#a1.sinks.k1.hdfs.rollInterval = 7200   

# 默認爲10,滾動之前寫入文件的事件數(0 =基於事件數從不滾動)
a1.sinks.k1.hdfs.rollCount = 0     

a1.sinks.k1.hdfs.filePrefix = %Y%m%d_
a1.sinks.k1.hdfs.fileSuffix = .log

#————————————————————  綁定  ————————————————————#

a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1

備註:通過正則匹配kafka日誌中的數據,將數據發送到不同的文件夾下,但是正在寫入時文件格式爲tmp類型,hive不能識別出文件,所以可以按2小時形成一個正式文件。當沒有數據寫入時,就不會生成tmp文件。

2.2flume切割文件相關參數


#————————————————————  滾動切換:控制寫文件的切換規則  ————————————————————#
# 按文件體積(字節)來切
ag1.sinks.sink1.hdfs.rollSize = 512000
# 按event條數切
ag1.sinks.sink1.hdfs.rollCount = 1000000 
# 按時間間隔切換文件,創建文件多久後
ag1.sinks.sink1.hdfs.rollInterval = 60 



#————————————————————  時間切換:控制生成目錄的規則  ————————————————————#

ag1.sinks.sink1.hdfs.path =hdfs://hadoop04:9000/flume/%y/%m/%d/%H

ag1.sinks.sink1.hdfs.round = true
ag1.sinks.sink1.hdfs.roundValue = 10
ag1.sinks.sink1.hdfs.roundUnit = minute
ag1.sinks.sink1.hdfs.useLocalTimeStamp = true

三、Es數據採集

3.1採集mysql數據到Es

stu.conf文件

input {
  jdbc{
    # mysql 數據庫鏈接
    jdbc_connection_string => "jdbc:mysql://localhost:3306/minisns?useUnicode=true&characterEncoding=utf-8&useSSL=false"
    # 用戶名和密碼
    jdbc_user => "123456"
    jdbc_password => "123456"
    #驅動
    jdbc_driver_library => "/opt/mysql/mysql-connector-java.jar"
    # 驅動類名
    jdbc_driver_class => "com.mysql.jdbc.Driver"
    jdbc_paging_enabled => "true"
    #jdbc_page_size => "5000"
    jdbc_page_size => "50000"
    jdbc_default_timezone =>"Asia/Shanghai"
    # mysql文件, 也可以直接寫SQL語句在此處,如下:
    statement_filepath => "/opt/logstash/config/jdbc_sql/stu.sql"
    # 這裏類似crontab,可以定製定時操作,比如每分鐘執行一次同步(分 時 天 月 年)
    schedule => "*/5 * * * *"
    #type => "jdbc"
    # 是否記錄上次執行結果, 如果爲真,將會把上次執行到的 tracking_column 字段的值記錄下來,保存到 last_run_metadata_path 指定的文件中
    record_last_run => true

    # 是否需要記錄某個column 的值,如果record_last_run爲真,可以自定義我們需要 track 的 column 名稱,此時該參數就要爲 true. 否則默認 track 的是 timestamp 的值.
    use_column_value => true
    # 如果 use_column_value 爲真,需配置此參數. track 的數據庫 column 名,該 column 必須是遞增的. 一般是mysql主鍵
    tracking_column => "addtime"
    tracking_column_type => "datatime"
    last_run_metadata_path => "/opt/logstash/config/track_value/stu"
    # 是否清除 last_run_metadata_path 的記錄,如果爲真那麼每次都相當於從頭開始查詢所有的數據庫記錄
    clean_run => false
    # 是否將 字段(column) 名稱轉小寫
    lowercase_column_names => false
  }
}
          
output { 
  elasticsearch {
    hosts => ["http://es-01:9200","http://es-02:9200","http://es-03:9200"]
    index => "stu_v1"
    document_id => "%{Id}"
    user => "elastic"
    password => "123456"
  } 
} 

stu.sql文件

select
Id
,name
,date_format(addtime, '%Y-%m-%d %H:%i:%s') as addtime
from student
where addtime >= date_add(:sql_last_value, interval -8 hour)

3.2採集Kafka數據到Es


#=========================== Filebeat inputs =============================

filebeat.inputs:

# Each - is an input. Most options can be set at the input level, so
# you can use different inputs for various configurations.
# Below are the input specific configurations.

- type: kafka
  hosts:
    - kafka-01:9092
    - kafka-02:9092
    - kafka-03:9092
  topics: ["stu"]
  group_id: "test_group"
  # Change to true to enable this input configuration.
  #enabled: false
  
  
#==================== Elasticsearch template setting ==========================

setup.template.settings:
  index.number_of_shards: 3
  index.number_of_replicas: 1
  #index.codec: best_compression
  #_source.enabled: false
  
  
#================================ Outputs =====================================

# Configure what output to use when sending the data collected by the beat.

#-------------------------- Elasticsearch output ------------------------------
output.elasticsearch:
  hosts: ["es-01:9200","es-02:9200","es-03:9200"]
  username: "elastic"
  password: "123456"
  index: "student_%{+yyyyMM}"

setup.template.name: "student_"
setup.template.pattern: "student_*"
setup.ilm.enabled: false


#================================ Processors =====================================

# Configure processors to enhance or manipulate events generated by the beat.

# This allows to enable 6.7 migration aliases
#migration.6_to_7.enabled: true
processors:
  - drop_fields:
        fields: ['host','agent','ecs','kafka']
  - decode_json_fields:
        fields: ["message"]
        process_array: true
        max_depth: 1
        target: ""
        overwrite_keys: false
        add_error_key: true

3.3Logstash與FileBeat的對比

  logstash filebeat
語言 Jruby golang
應用場景 採集kafka數據後過濾分析發送到es 採集日誌,然後發送到消息隊列
優勢 豐富的input|filter|output插件 輕量級

 

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章