小计--------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 主题名
作者:于二黑
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。