| 
									
										
										
										
											2016-07-25 14:44:02 -07:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Copyright 2015 LinkedIn Corp. All rights reserved.
 | 
					
						
							|  |  |  |  *
 | 
					
						
							|  |  |  |  * Licensed under the Apache License, Version 2.0 (the "License");
 | 
					
						
							|  |  |  |  * you may not use this file except in compliance with the License.
 | 
					
						
							|  |  |  |  * You may obtain a copy of the License at
 | 
					
						
							|  |  |  |  *
 | 
					
						
							|  |  |  |  * http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  |  *
 | 
					
						
							|  |  |  |  * Unless required by applicable law or agreed to in writing, software
 | 
					
						
							|  |  |  |  * distributed under the License is distributed on an "AS IS" BASIS,
 | 
					
						
							|  |  |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
					
						
							|  |  |  |  */
 | 
					
						
							|  |  |  | package actors;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import akka.actor.ActorRef;
 | 
					
						
							|  |  |  | import akka.actor.Props;
 | 
					
						
							|  |  |  | import akka.actor.UntypedActor;
 | 
					
						
							|  |  |  | import java.util.HashMap;
 | 
					
						
							|  |  |  | import java.util.List;
 | 
					
						
							|  |  |  | import java.util.Map;
 | 
					
						
							|  |  |  | import java.util.Properties;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import kafka.consumer.Consumer;
 | 
					
						
							|  |  |  | import kafka.consumer.ConsumerConfig;
 | 
					
						
							|  |  |  | import kafka.consumer.KafkaStream;
 | 
					
						
							|  |  |  | import kafka.javaapi.consumer.ConsumerConnector;
 | 
					
						
							| 
									
										
										
										
											2016-08-03 18:55:07 -07:00
										 |  |  | import metadata.etl.models.EtlJobName;
 | 
					
						
							|  |  |  | import models.daos.ClusterDao;
 | 
					
						
							|  |  |  | import models.daos.EtlJobDao;
 | 
					
						
							| 
									
										
										
										
											2016-07-25 14:44:02 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-11 11:26:36 -07:00
										 |  |  | import msgs.KafkaCommMsg;
 | 
					
						
							| 
									
										
										
										
											2016-07-25 14:44:02 -07:00
										 |  |  | import play.Logger;
 | 
					
						
							| 
									
										
										
										
											2016-08-03 18:55:07 -07:00
										 |  |  | import play.Play;
 | 
					
						
							| 
									
										
										
										
											2016-10-11 11:26:36 -07:00
										 |  |  | import models.kafka.KafkaConfig;
 | 
					
						
							|  |  |  | import models.kafka.KafkaConfig.Topic;
 | 
					
						
							| 
									
										
										
										
											2016-11-08 19:11:37 -08:00
										 |  |  | import play.db.DB;
 | 
					
						
							|  |  |  | import wherehows.common.PathAnalyzer;
 | 
					
						
							| 
									
										
										
										
											2016-07-25 14:44:02 -07:00
										 |  |  | import wherehows.common.kafka.schemaregistry.client.CachedSchemaRegistryClient;
 | 
					
						
							|  |  |  | import wherehows.common.kafka.schemaregistry.client.SchemaRegistryClient;
 | 
					
						
							| 
									
										
										
										
											2016-08-03 18:55:07 -07:00
										 |  |  | import wherehows.common.utils.ClusterUtil;
 | 
					
						
							| 
									
										
										
										
											2016-07-25 14:44:02 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2016-08-04 13:07:19 -07:00
										 |  |  |  * Akka actor responsible for managing Kafka workers
 | 
					
						
							| 
									
										
										
										
											2016-07-25 14:44:02 -07:00
										 |  |  |  */
 | 
					
						
							|  |  |  | public class KafkaConsumerMaster extends UntypedActor {
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-04 13:07:19 -07:00
										 |  |  |   // List of kafka job IDs
 | 
					
						
							| 
									
										
										
										
											2016-08-03 18:55:07 -07:00
										 |  |  |   private static List<Integer> _kafkaJobList;
 | 
					
						
							| 
									
										
										
										
											2016-08-04 13:07:19 -07:00
										 |  |  |   // map of kafka job id to configs
 | 
					
						
							|  |  |  |   private static Map<Integer, KafkaConfig> _kafkaConfigs = new HashMap<>();
 | 
					
						
							| 
									
										
										
										
											2016-07-25 14:44:02 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @Override
 | 
					
						
							| 
									
										
										
										
											2016-08-04 13:07:19 -07:00
										 |  |  |   public void preStart()
 | 
					
						
							|  |  |  |       throws Exception {
 | 
					
						
							|  |  |  |     _kafkaJobList = Play.application().configuration().getIntList("kafka.consumer.etl.jobid", null);
 | 
					
						
							| 
									
										
										
										
											2016-08-03 18:55:07 -07:00
										 |  |  |     if (_kafkaJobList == null || _kafkaJobList.size() == 0) {
 | 
					
						
							| 
									
										
										
										
											2016-08-04 13:07:19 -07:00
										 |  |  |       context().stop(getSelf());
 | 
					
						
							| 
									
										
										
										
											2016-08-03 18:55:07 -07:00
										 |  |  |       Logger.error("Kafka job id error, kafkaJobList: " + _kafkaJobList);
 | 
					
						
							| 
									
										
										
										
											2016-08-04 13:07:19 -07:00
										 |  |  |       return;
 | 
					
						
							| 
									
										
										
										
											2016-08-03 18:55:07 -07:00
										 |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2016-08-04 13:07:19 -07:00
										 |  |  |     Logger.info("Start KafkaConsumerMaster... Kafka job id list: " + _kafkaJobList);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (final int kafkaJobId : _kafkaJobList) {
 | 
					
						
							|  |  |  |       try {
 | 
					
						
							|  |  |  |         // handle 1 kafka connection
 | 
					
						
							|  |  |  |         Map<String, Object> kafkaEtlJob = EtlJobDao.getEtlJobById(kafkaJobId);
 | 
					
						
							|  |  |  |         final int kafkaJobRefId = Integer.parseInt(kafkaEtlJob.get("ref_id").toString());
 | 
					
						
							|  |  |  |         final String kafkaJobName = kafkaEtlJob.get("wh_etl_job_name").toString();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // get Kafka configurations from database
 | 
					
						
							|  |  |  |         final KafkaConfig kafkaConfig = new KafkaConfig();
 | 
					
						
							|  |  |  |         kafkaConfig.updateKafkaProperties(EtlJobName.valueOf(kafkaJobName), kafkaJobRefId);
 | 
					
						
							|  |  |  |         final Properties kafkaProps = kafkaConfig.getProperties();
 | 
					
						
							|  |  |  |         final Map<String, Topic> kafkaTopics = kafkaConfig.getTopics();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         kafkaConfig.updateTopicProcessor();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // create Kafka consumer connector
 | 
					
						
							|  |  |  |         Logger.info("Create Kafka Consumer with config: " + kafkaProps.toString());
 | 
					
						
							|  |  |  |         final SchemaRegistryClient schemaRegistryClient =
 | 
					
						
							|  |  |  |             new CachedSchemaRegistryClient((String) kafkaProps.get("schemaRegistryUrl"));
 | 
					
						
							|  |  |  |         final ConsumerConfig cfg = new ConsumerConfig(kafkaProps);
 | 
					
						
							|  |  |  |         ConsumerConnector consumerConnector = Consumer.createJavaConsumerConnector(cfg);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // create Kafka message streams
 | 
					
						
							|  |  |  |         final Map<String, Integer> topicCountMap = new HashMap<>();
 | 
					
						
							|  |  |  |         for (Topic topic : kafkaTopics.values()) {
 | 
					
						
							|  |  |  |           topicCountMap.put(topic.topic, topic.numOfWorkers);
 | 
					
						
							|  |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2016-07-25 14:44:02 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-04 13:07:19 -07:00
										 |  |  |         final Map<String, List<KafkaStream<byte[], byte[]>>> consumerMap =
 | 
					
						
							|  |  |  |             consumerConnector.createMessageStreams(topicCountMap);
 | 
					
						
							| 
									
										
										
										
											2016-08-03 18:55:07 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-04 13:07:19 -07:00
										 |  |  |         // add config to kafka config map
 | 
					
						
							|  |  |  |         kafkaConfig.setSchemaRegistryClient(schemaRegistryClient);
 | 
					
						
							|  |  |  |         kafkaConfig.setConsumer(consumerConnector);
 | 
					
						
							|  |  |  |         _kafkaConfigs.put(kafkaJobId, kafkaConfig);
 | 
					
						
							| 
									
										
										
										
											2016-07-25 14:44:02 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-04 13:07:19 -07:00
										 |  |  |         // create workers to handle each message stream
 | 
					
						
							|  |  |  |         for (String topic : kafkaTopics.keySet()) {
 | 
					
						
							|  |  |  |           final List<KafkaStream<byte[], byte[]>> streams = consumerMap.get(topic);
 | 
					
						
							| 
									
										
										
										
											2016-07-25 14:44:02 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-04 13:07:19 -07:00
										 |  |  |           int threadNumber = 0;
 | 
					
						
							|  |  |  |           for (final KafkaStream<byte[], byte[]> stream : streams) {
 | 
					
						
							|  |  |  |             ActorRef childActor = getContext().actorOf(
 | 
					
						
							|  |  |  |                 Props.create(KafkaConsumerWorker.class, topic, threadNumber, stream, schemaRegistryClient,
 | 
					
						
							| 
									
										
										
										
											2016-10-10 14:49:14 -07:00
										 |  |  |                     kafkaConfig.getProcessorClass(topic), kafkaConfig.getProcessorMethod(topic),
 | 
					
						
							|  |  |  |                     kafkaConfig.getDbWriter(topic)));
 | 
					
						
							| 
									
										
										
										
											2016-07-25 14:44:02 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-04 13:07:19 -07:00
										 |  |  |             childActor.tell("Start", getSelf());
 | 
					
						
							|  |  |  |             threadNumber++;
 | 
					
						
							|  |  |  |           }
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |         Logger.info("Initiate Kafka consumer job " + kafkaJobId + " with topics " + kafkaTopics.keySet());
 | 
					
						
							|  |  |  |       } catch (Exception e) {
 | 
					
						
							|  |  |  |         Logger.error("Initiating Kafka properties on startup fail, job id: " + kafkaJobId, e);
 | 
					
						
							|  |  |  |       }
 | 
					
						
							| 
									
										
										
										
											2016-07-25 14:44:02 -07:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-04 13:07:19 -07:00
										 |  |  |     try {
 | 
					
						
							|  |  |  |       // get list of cluster information from database and update ClusterUtil
 | 
					
						
							|  |  |  |       ClusterUtil.updateClusterInfo(ClusterDao.getClusterInfo());
 | 
					
						
							|  |  |  |     } catch (Exception e) {
 | 
					
						
							|  |  |  |       Logger.error("Fail to fetch cluster info from DB ", e);
 | 
					
						
							| 
									
										
										
										
											2016-07-25 14:44:02 -07:00
										 |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2016-11-08 19:11:37 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     try {
 | 
					
						
							|  |  |  |       // initialize PathAnalyzer
 | 
					
						
							|  |  |  |       PathAnalyzer.initialize(DB.getConnection("wherehows"));
 | 
					
						
							|  |  |  |     } catch (Exception e) {
 | 
					
						
							|  |  |  |       Logger.error("Fail to initialize PathAnalyzer from DB wherehows.", e);
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2016-07-25 14:44:02 -07:00
										 |  |  |   }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @Override
 | 
					
						
							| 
									
										
										
										
											2016-08-04 13:07:19 -07:00
										 |  |  |   public void onReceive(Object message)
 | 
					
						
							|  |  |  |       throws Exception {
 | 
					
						
							| 
									
										
										
										
											2016-10-11 11:26:36 -07:00
										 |  |  |     if (message instanceof KafkaCommMsg) {
 | 
					
						
							|  |  |  |       final KafkaCommMsg kafkaCommMsg = (KafkaCommMsg) message;
 | 
					
						
							|  |  |  |       Logger.debug(kafkaCommMsg.toString());
 | 
					
						
							| 
									
										
										
										
											2016-07-25 14:44:02 -07:00
										 |  |  |     } else {
 | 
					
						
							|  |  |  |       unhandled(message);
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |   }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @Override
 | 
					
						
							|  |  |  |   public void postStop() {
 | 
					
						
							| 
									
										
										
										
											2016-08-03 18:55:07 -07:00
										 |  |  |     Logger.info("Terminating KafkaConsumerMaster...");
 | 
					
						
							| 
									
										
										
										
											2016-08-04 13:07:19 -07:00
										 |  |  |     for (KafkaConfig config : _kafkaConfigs.values()) {
 | 
					
						
							|  |  |  |       config.close();
 | 
					
						
							| 
									
										
										
										
											2016-07-25 14:44:02 -07:00
										 |  |  |     }
 | 
					
						
							|  |  |  |   }
 | 
					
						
							| 
									
										
										
										
											2016-07-28 14:07:07 -07:00
										 |  |  | }
 |