-
First thing that i did was to create WordCountCombiner.java class that looks same as that of
WordCountReducer, but i did add oneSystem.Out.println()in it so that i would know when my combiner is called instead of reducer. -
Then i changed the driver class for my MapReduce framework class to add
job.setCombinerClass(WordCountCombiner.class);line in it.
How to create custom Combiner class with your MapReduce framework
The MapReduce framework passes control to your combiner class at the end of the map phase to combine different output files generated by Mappers, so that your combiner class combines/reduce the data generated by Mappers before it gets transferred to the Reducers. Sending data from Mapper to reducer requires that data to go over network from Mapper to Reducer.
I wanted to try creating custom combiner class, In order to keep things simple i decided to add combiner class in WordCount(HelloWorld) MapReduce program . Basically my combiner class does same thing as reducer, which is to take multiple [word, 1] tuples and combine them into something like [word1, 5], [word2, 6],,, etc. I followed these steps
Creating custom Partitioner class for your mapreduce program
The MapReduce framwork uses instance of
org.apache.hadoop.mapreduce.Partitioner class to figure our which mapreduce output key goes to which reducer. By default it uses org.apache.hadoop.mapreduce.lib.partition.HashPartitioner, this class calculates hash value for the key and divides it by number of Reducers in the program and uses remainder to figure out the reducer it goes to. This implementation is pretty good and as long as the keys generate hashCodes that gives uniform distribution it should be good.
But in some exceptional cases you might want to take control of how the output of Mapper gets distributed to Reducers. I just wanted to figure out how this works, so i decided to change my WordCount(HelloWorld) MapReduce program to add a custom Partitioner that sends upper and lower case alphabets two 2 different reducers. I followed these steps
- First i did create a WordCountPartitioner.java class like this First thing i am doing is checking if there are 2 reducers if yes i am using the first letter of the key to figure out if it starts with lower case letter (simply check it against 'a' letter, if yes send it to first reducer if not send it to second reducer
-
I had to make few changes in the Driver program to use my WordCountPartitioner
- job.setNumReduceTasks(2): This call is asking MapReduce framework to use 2 reducers
- job.setPartitionerClass(WordCountPartitioner.class); This call is setting my
WordCountPartitioneras the class for partitioner
Python client for publishing and consuming message from Apache Kafka
In the Java Client for publishing and consuming messages from Apache Kafka i talked about how to create a Java Client for publishing and consuming messages from Kafka. I wanted to try same thing using Python so i followed these steps
- Follow steps 1 through 4 of Java Client for publishing and consuming messages from Apache Kafka entry to start Zookeeper and Kafka server
- Follow these steps to install Kafka python client
git clone https://github.com/mumrah/kafka-python pip install ./kafka-python -
Next create a Producer.py python script to publish message to
pythontesttopic, the basic concept here is you connect to Kafka server onlocalhost:9092port and then publish a message to a particular topic -
Now create Consumer.py script that consumes messages from
pythontesttopic and writes them to console.
Java Client for publishing and consuming messages from Apache Kafka
I wanted to learn how to use Apache Kafka for publishing and consuming messages from Apache Kafka using Java client, so i followed these steps.
- Download the Kafka binaries from Kafka download page
-
Unzip the kafka tar file by executing
tar -xzf kafka_2.9.2-0.8.1.1.tgz. Then go to kafka directory by executingcd kafka_2.9.2-0.8.1.1 - Next start the Zookeeper server by executing following command
bin/zookeeper-server-start.sh config/zookeeper.properties - Start the Kafka server by executing following command
bin/kafka-server-start.sh config/server.properties - Now your Zookeeper and Kafka server are ready and you can download the source code for sample project from here
-
This is how a Java Client that publishes messages to Kafka looks like, execute it couple of times to publish couple of messages
First thing that you have to do while developing a producer is connect to the Kafka server, for that you will set value of
metadata.broker.listproperty to point to the port on which kafka server is listening (You can find value of port and host name from server.properties that you used in step 4. Once you haveProducerobject you can use it for publishing messages by creating object ofkafka.producer.KeyedMessage, you will have to pass name of the topic and message as argument -
This is how the Java client for consumer of messages from Kafka looks like, run it and it will start a thread that will keep listening to messages on topic and every time there is a message it will print it to console
The
HelloKafkaConsumerclass extends Thread class. In the constructor of this class first i am creating Properties class with value ofzookeeper.connectproperty equal to the port on which zookeeper server is listening on. In the constructor i am creating object ofkafka.javaapi.consumer.ConsumerConnector
Once the ConsumerConnector is ready in the run() method i am passing it name of the topic on which i want to listen (You can pass multiple topic names here). Everytime there is a new message i am reading it and printing it to console.
How MapReduce job in Yarn framework works
In case of Yarn MapReduce framework these are the main players involved in the process of running mapreduce application.
- Client The client submits the MapReduce job. Client is responsible for copying the map reduce related jars, configuration files and the distributed cache related files(jars, archives and files) into HDFS for distribution. It is also responsible for splitting the input into pieces and saving that information into HDFS for later use
- Application Master To manage lifecycle of application running on the cluster. When the map reduce framework starts application it creates application master on one of the worker nodes and the application master runs for the lifecycle of application/job
- Application master negotiates with the resource manager for cluster resources - described in terms of a number of containers, each with certain memory limit. Application master is also responsible for tracking the application progress such as status as well as counters across application.
- Resource Manager To manage the use of compute resources(Resources available for running map and reduce related tasks) across the cluster
- Node Manager node managers runs the application specific processes in the containers. The node manager ensures that the application does not use more resources than it has been allocated.
Creating Oozie workflow for mapreduce job that uses distributed cache
In the Using third part jars and files in your MapReduce application(Distributed cache) entry i blogged about how to create a MapReduce job that uses distributed cache for storing both required jar files and files for use in distributed cache. I wanted to figure out how to automate this mapreduce job using Apache Oozie so i followed these steps
- First i did create apachelog directory and in that i had to create job.properties file like this
-
Then i create workflow.xml file that looks like this, in this one thing to notice is
<file>GeoLite.mmdb#GeoLite2-City.mmdb</file>, so basically i have file GeoLite.mmdb on the disk but i want to refer to it asGeoLite2-City.mmdbin my program so that file element takes care of creating symlink - Then i copied all the required jar files in the lib folder and then this is how my directory structure looks like
- I used following command to copy the apachelog directory that has everything that my oozie job needs to the hdfs
hdfs dfs -put apachelog apachelog - Last step is to invoke the oozie job by executing following command
oozie job -oozie http://localhost:11000/oozie -config job.properties -run
Using Apache Oozie for automating streaming map-reduce job
In the
WordCount MapReduce program using Hadoop streaming and python i talked about how to create a Streaming map-reduce job using python. I wanted to figure out how to automate that program using Oozie workflow so i followed these steps
- First step was to create a folder called streaming on my local machine and copying of mapper.py, reducer.py into the streaming folder, i also create the place holder for job.properties and workflow.xml
- Next i did create a job.properties file like this
Now this job.properties is quite similar to the job.properties for java mapreduce job, only difference is you must set
oozie.use.system.libpath=true, by default the streaming related jars are not included in the classpath, so unless you set that value to true you will get following error2014-07-23 06:15:13,170 WARN org.apache.hadoop.mapred.Child: Error running child java.lang.RuntimeException: java.lang.RuntimeException: java.lang.ClassNotFoundException: Class org.apache.hadoop.streaming.Pi peMapRunner not found at org.apache.hadoop.conf.Configuration.getClass(Configuration.java:1649) at org.apache.hadoop.mapred.JobConf.getMapRunnerClass(JobConf.java:1010) at org.apache.hadoop.mapred.MapTask.runOldMapper(MapTask.java:413) at org.apache.hadoop.mapred.MapTask.run(MapTask.java:332) at org.apache.hadoop.mapred.Child$4.run(Child.java:268) at java.security.AccessController.doPrivileged(Native Method) at javax.security.auth.Subject.doAs(Subject.java:396) at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1408) at org.apache.hadoop.mapred.Child.main(Child.java:262) Caused by: java.lang.RuntimeException: java.lang.ClassNotFoundException: Class org.apache.hadoop.streaming.PipeMapRunner not f ound at org.apache.hadoop.conf.Configuration.getClass(Configuration.java:1617) at org.apache.hadoop.conf.Configuration.getClass(Configuration.java:1641) ... 8 more Caused by: java.lang.ClassNotFoundException: Class org.apache.hadoop.streaming.PipeMapRunner not found at org.apache.hadoop.conf.Configuration.getClassByName(Configuration.java:1523) at org.apache.hadoop.conf.Configuration.getClass(Configuration.java:1615) ... 9 more 2014-07-23 06:15:13,175 INFO org.apache.hadoop.mapred.Task: Runnning cleanup for the task -
Next step in the process is to create workflow.xml file like this, make sure to add
<file>mapper.py#mapper.py</file>element in the workflow.xml, which takes care of putting the mapper.py and reducer.py in the sharedlib and creating symbolic link to these two files. -
Upload the streaming folder with all your changes on hdfs by executing following command
hdfs dfs -put streaming streaming - You can trigger the oozie workflow by executing following command
oozie job -oozie http://localhost:11000/oozie -config streaming/job.properties -run
Using Apache Oozie to execute MapReduce jobs
I wanted to learn about how to automate MapReduce job using Oozie, so i decide to create Oozie workflow to invoke WordCount(HelloWorld) MapReduce program. I had to follow these steps
- FIrst thing that i did was to download the WordCount program source code by executing
This program does have maven script for building executable jar, so i usedgit clone https://github.com/sdpatil/HadoopWordCount3mvn clean packagecommand to build Hadoop jar. -
After that i tried executing the program manually by using following following command
hadoop jar target/HadoopWordCount.jar sorttest.txt output/wordcount - Now in order to use Oozie workflow you will have to create a particular folder structure on your machine
wordcount -- job.properties -- workflow.xml -- lib -- HadoopWordCount.jar -
In the workcount folder create job.properties file like this, This file lets you pass parameters to your oozie workflow. Value of
nameNodeandjobTrackerrepresent the name node and job tracker location. In my case i am using cloudera vm with single ndoe so both these properties point to localhost. The value ofoozie.wf.application.pathis equal to HDFS path where you uploaded the wordcount folder created in step 3 -
Next define your Apache oozie workflow.xml file like this. In my case the workflow has single step which is to execute mapreduce job. I am
- mapred.mapper.new-api & mapred.reducer.new-api: Set this property to true if your using the new MapReduce API based on
org.apache.hadoop.mapreduce.*classes - mapreduce.map.class: The fully qualified name of your mapper class
- mapreduce.reduce.class: The fully qualified name of your reducer class
- mapred.output.key.class: Fully qualified name of the output key class. This is same as parameter to
job.setOutputKeyClass()in your driver class - mapred.output.value.class: Fully qualified name of the output value class. This is same as parameter to
job.setOutputValueClass()in your driver class - mapred.input.dir: Location of your input file in my case i have sorttext.txt in hdfs://localhost/user/cloudera directory
- mapred.output.dir:Location of output file that will get generated. In my case i want output to go to hdfs://localhost/user/cloudera/output/wordcount directory
- mapred.mapper.new-api & mapred.reducer.new-api: Set this property to true if your using the new MapReduce API based on
-
Once your oozie workflow is ready upload the wordcount folder in HDFS by executing following command
hdfs dfs -put oozie wordcount -
If it runs successfully you should see output generated inNow run your oozie workflow by executing following command from your wordcount directory oozie job -oozie http://localhost:11000/oozie -config job.properties -runhdfs://localhost/user/cloudera/output/wordcountdirectory
Enabling Oozie console on Cloudera VM 4.4.0 and executing examples
I am trying to learn about Apache Oozie, so i wanted to figure out how to use it in Cloudera 4.4.0 VM. When you go to the Oozie web console it shows a message saying that the Console is disabled. In order to enable the console i had to follow these steps
- Go to your Cloudera Manager, in that i went to the oozie configuration screen and i did check the
Enable Oozie Server Web Consolescreen like this. As you can see in the description it says install ExtJS2.2 in/usr/lib/oozie/libext - Next i did go to
/usr/lib/oozie/libextdirectory and executed following command to download the ext-2.2.zip.
Since i am using CDH 4.4 i had to executewget 'http://extjs.com/deploy/ext-2.2.zip'unzip ext-2.2.zipto unzip the ext-2.2.zip - Last step was to restart the oozie service and now i could see the Oozie web console
- First thing for me was to find the
oozie-examples.tar.gzfile on my vm
I found it underfind / -name oozie-examples.tar.gz/usr/share/doc/oozie-3.3.2+92/directory. So i did untar it usingtar xvf oozie-examples.tar.gz -
Then i had to make change in the job.properties to change value of namenode and jobTracker from localhost to localhost.localdomain get rid of
Error: E0901 : E0901: Namenode [localhost:8020] not allowed, not in Oozies whitelisterror.nameNode=hdfs://localhost.localdomain:8020 jobTracker=localhost.localdomain:8021 queueName=default examplesRoot=examples oozie.wf.application.path=${nameNode}/user/${user.name}/${examplesRoot}/apps/map-reduce outputDir=map-reduce - After making changes in job.properties i did upload the examples folder to HDFS using following command
hdfs dfs -put examples examples - The last step in the process was to actually run the mapreduce job in oozie by executing following command
oozie job -oozie http://localhost:11000/oozie -config examples/apps/map-reduce/job.properties -run - Once the job was started i could see the progress using Oozie web console like this
Where are MapReduce logs when your using yarn framework
For last couple of months i have been using Yarn framework for running my mapreduce jobs. Normally using Yarn is transparent so i did not have to do any thing different but just change my mapred-site.xml file to set value of
mapreduce.framework.name to yarn like this.
But YARN affects how the logs and job history gets stored. For example if your using traditional map reduce framework you can go to http://localhost:50030 to look at the job and task history and also access the logs generated by mapreduce framework. In case of Yarn you will have to go to http://localhost:8088/cluster and it will take you to Resource Manager Home page like this, there you should see list of applications and then click on the name of the application and to get more details
When you try to look at the logs for application, it takes you the nodemanager home page like this
Since i am working on single node cluster i like to go to the hadoop log directory and there under userlogs directory i can see log folders for each application. The application folder is subdivided into container folder one for mapper task one for reducer task and one for driver task and each of the container folders has one file for stdout, stderr and syslog that contains more output. If you have any System.out.println() in your mapper or reducer class you should find the appropriate container folder and stdout file in that container should have output that you generated using System.out.println()
Subscribe to:
Posts (Atom)










