小计--------flume 自定义kafka source 案例

自定义source
自定义的消息有两种类型的Source,PollableSource (轮训拉取)与EventDrivenSource (事件驱动),两者的区别在于PollableSource是通过线程不断去调用process方法,主动拉取消息,而EventDrivenSource是需要触发一个调用机制,即被动等待。在利用PollableSource实现自定义Source时还需要实现Configurable接口,以便在项目中初始化某些配置用的,定义的Source如下:
 
  1 /**
  2 * EVM告警信息表数据采集
  3 * PollableSource 轮询拉取数据
  4 * 通过线程不断调用process方法,主动拉取消息
  5 */
  6 public class Ev_alarm_Source extends AbstractSource implements Configurable, PollableSource {
  7  
  8  
  9     private static String topic = "";
 10     private static String groupId = "";
 11     private KafkaConsumer<String, String> consumer = null;
 12     private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 13     @Override
 14     public void configure(Context context) {
 15     }
 16  
 17  
 18     /**
 19      * 该方法会由PollableSource线程去不断调用执行
 20      * 执行完后通过getChannelProcess的processEvent方法将kafka数据转换为flume的Event发送到channel
 21      * @return
 22      * @throws EventDeliveryException
 23      */
 24     @Override
 25     public Status process() throws EventDeliveryException {
 26         try{
 27             ConsumerRecords<String, String> records = consumer.poll(100);
 28             for (ConsumerRecord<String, String> record : records){
 29  
 30  
 31                 try {
 32                     // 存放解析好后的字符串
 33                     HashMap<String, String> header = new HashMap<String, String>();
 34                     //解析
 35                     String value = record.value();
 36                     // 通过ali的fastJson解析kafka中的json串
 37                     JSONObject jsonObject = JSONObject.parseObject(value);
 38  
 39  
 40                     String msgid = jsonObject.getString("msgid");
 41                     String vin = jsonObject.getString("vin");
 42                     Long tm_c = jsonObject.getString("tm_c") == null ? System.currentTimeMillis()/1000:jsonObject.getLong("tm_c");
 43                     Long tm_u = jsonObject.getString("tm_u") == null ? System.currentTimeMillis()/1000:jsonObject.getLong("tm_u");
 44                     String t_flg = jsonObject.getString("t_flg");
 45                     String ha_level = jsonObject.getString("ha_level");
 46                     String ca_flg = jsonObject.getString("ca_flg");
 47                     String sef_va = jsonObject.getString("sef_va");
 48                     String dmf_va = jsonObject.getString("dmf_va");
 49                     String egf_va = jsonObject.getString("egf_va");
 50                     String of_va = jsonObject.getString("of_va");
 51                     String lng = jsonObject.getString("lng");
 52                     String lat = jsonObject.getString("lat");
 53  
 54  
 55                     // 拼接字段用#号进行连接不同字段
 56                     StringBuilder sb = new StringBuilder("");
 57                     sb.append(msgid);
 58                     sb.append("#");
 59                     sb.append(vin);
 60                     sb.append("#");
 61                     sb.append(sdf.format(new Date(tm_c*1000)));
 62                     sb.append("#");
 63                     sb.append(sdf.format(new Date(tm_u*1000)));
 64                     sb.append("#");
 65                     sb.append(t_flg);
 66                     sb.append("#");
 67                     sb.append(ha_level);
 68                     sb.append("#");
 69                     sb.append(ca_flg);
 70                     sb.append("#");
 71                     sb.append(sef_va);
 72                     sb.append("#");
 73                     sb.append(dmf_va);
 74                     sb.append("#");
 75                     sb.append(egf_va);
 76                     sb.append("#");
 77                     sb.append(of_va);
 78                     sb.append("#");
 79                     sb.append(lng);
 80                     sb.append("#");
 81                     sb.append(lat);
 82  
 83  
 84                     // 封装到hashmap
 85                     header.put("timestamp", String.valueOf(tm_c * 1000));
 86                     //将hashMap转换成flume的event发送到channel
 87                     this.getChannelProcessor().processEvent(EventBuilder.withBody(sb.toString(), Charset.forName("UTF-8"), header));
 88                 } catch (Exception e) {
 89                     e.printStackTrace();
 90                 }
 91  
 92  
 93             }
 94         }catch (Exception e){
 95             e.printStackTrace();
 96         }
 97         // 返回Event的状态
 98         return Status.READY;
 99     }
100  
101  
102     public long getBackOffSleepIncrement() {
103         return 0;
104     }
105  
106  
107     public long getMaxBackOffSleepInterval() {
108         return 0;
109     }
110  
111  
112     /**
113      * 释放资源或清空字段
114      */
115     @Override
116     public synchronized void stop() {
117         if(consumer != null ){
118             consumer.close();//释放资源
119         }
120     }
121  
122  
123     /**
124      * 在执行process() 方法执行会首先执行一次start()
125      * 进行初始化配置
126      */
127     @Override
128     public synchronized void start() {
129         try{
130             // 设置kafka topic
131             this.topic = PropertiesUtils.getProperty(Conf.EVM_ALARM_TOPIC);
132             // 设置kafka groupID
133             this.groupId = PropertiesUtils.getProperty(Conf.EVM_ALARM_GROUPID);
134             // 设置kafka broker
135             String kafka_broker_list = PropertiesUtils.getProperty(Conf.KAFKA_BROKER_LIST);
136             if(consumer == null ){
137                 this.consumer = new KafkaConsumer<String, String>(KafkaUtils.getKafkaProp(kafka_broker_list,this.groupId));
138                 this.consumer.subscribe(Arrays.asList(topic));
139             }
140         }catch (Exception e){
141             e.printStackTrace();
142         }
143     }
144  
145  
146     public static void main(String[] args){
147  
148  
149     }
150 }

 

配置flume.conf 文件
 1 #登出
 2 a1.sources = r1
 3 a1.sinks = k1
 4 a1.channels = c1
 5  
 6 # 指定Flume source(要监听的路径)自定义kafka生产者
 7 a1.sources.r1.type = com.sz.ly.bdp.dc.evm.etl.ev_alarm.Ev_alarm_Source
 8  
 9 # 指定Flume sink
10 a1.sinks.k1.type = hdfs
11 a1.sinks.k1.channel = c1
12 # 输出hdfs路径
13 a1.sinks.k1.hdfs.path = hdfs://nameservice1:8020/flume/evm/alarm/%Y%m%d
14 # 文本格式
15 a1.sinks.k1.hdfs.writeFormat = Text
16 # 输出文件后缀
17 a1.sinks.k1.hdfs.fileSuffix = .txt
18 # DataStream文件不压缩,不需要设置hdfs.codeC
19 a1.sinks.k1.hdfs.fileType = DataStream
20 # 每个批次刷新到hdfs上events数量
21 a1.sinks.k1.hdfs.batchSize = 100
22 # hdfs sink启动的操作HDFS的线程数
23 a1.sinks.k1.hdfs.threadsPoolSize = 10
24 # 默认值为0,当目前被打开的临时文件在该参数指定的时间(秒)内,没有任何数据写入,则将该临时文件关闭并重命名成目标文件
25 a1.sinks.k1.hdfs.idleTimeout = 0
26 # 默认值 1024 , 当临时文件达到多少(单位:bytes)时,滚动成目标文件;如果设置成0,则表示不根据临时文件大小来滚动文件
27 a1.sinks.k1.hdfs.rollSize = 268435456
28 # 默认值:10,当events 数据达到该数量时候,将临时文件滚动成目标文件;如果设置成0 , 则表示不根据events数据来滚动文件
29 a1.sinks.k1.hdfs.rollCount = 0
30 # 临时文件 间隔60分钟滚动成最终文件; 单位: s
31 a1.sinks.k1.hdfs.rollInterval = 3600
32 # 默认值:HDFS副本数,写入hdfs文件块的最小副本数。该参数会影响文件的滚动配置,一般将该参数配置成1,才可以按照配置正确滚动文件
33 a1.sinks.k1.hdfs.minBlockReplicas=1
34 a1.sinks.k1.hdfs.connect-timeout=80000
35 # 默认值: 10000 , 执行HDFS操作的超时时间(单位:毫秒)
36 a1.sinks.k1.hdfs.callTimeout=120000
37 # 使用本机时间 %Y%m%d , 在替换转义序列时使用本地时间
38 a1.sinks.k1.hdfs.useLocalTimeStamp=true
39  
40  
41 # 指定Flume channel
42 a1.channels.c1.type = memory
43 a1.channels.c1.capacity = 200000
44 a1.channels.c1.transactionCapacity = 20000
45 a1.channels.c1.byteCapacityBufferPercentage = 20
46 a1.channels.c1.byteCapacity = 536870912
47  
48 # 绑定source和sink到channel上
49 a1.sources.r1.channels = c1
50 a1.sinks.k1.channel = c1

 

 
 
 
部署集群步骤:
1.首先将程序打包、并把jar包放在集群flume-ng下的lib下。
 
2.将conf文件放到一个固定位置,在执行flume-ng命令的时候指定conf文件路径
 
3.执行flume-ng命令
#因为在环境变量中配置了flume环境,故不需要绝对路径
flume-ng agent -c conf -f /root/yzq/bdp-dc-flume/alarm.conf -n a1 -Dflume.root.logger=INFO,console 1 > /root/yzq/bdp-dc-flume/alarm.log 2>&1 &
 
4.启动kafka生产者进行模拟生产数据,查看hdfs是否有输出文件
kafka-console-producer --broker-list ip:端口 —topic 主题名
 
 
posted @ 2020-06-16 00:34  二黑诶  阅读(883)  评论(0编辑  收藏  举报