Ekspresowa instalacja Hadoop + Hive + Pig

Przedstawię Wam dzisiaj jak może wyglądać ekspresowa instalacja Hadoop na potrzeby rozpoznania/testów/zabawy. Wykorzystam do tego oprogramowanie do automatyzacji procesów administracyjnych Chef.

Instalacja Ubuntu

W pierwszym kroku musimy przygotować sobie instalację Ubuntu Linux 14.04.1 w wersji Server 64bit. Wykonamy możliwie najprostszy wariant, oszczędzając dzięki temu czas oraz przestrzeń dyskową, skupiając się jedynie na istotnym dla nas oprogramowaniu.

Swój przykład opieram na lokalnej maszynie wirtualnej utworzonej pod Oracle VirtualBox. Parametry maszyny:

  • 2x CPU
  • 2GB RAM
  • 20GB HDD

Proces instalacji udokumentowałem na YouTube. Pod filmem wrzucam kolejne kroki wykonane w ramach instalacji. Cały proces zajmuje poniżej 8 minut.

Wybrane kolejno parametry:

  1. Język instalacji – English (domyślna wartość)
  2. Install Ubuntu Server (domyślna wartość)
  3. Język systemu – English (domyślna wartość)
  4. Lokalizacja – other
  5. Lokalizacja – Europe
  6. Lokalizacja – Poland
  7. Locale – en_US.UTF-8 (domyślna wartosć)
  8. Detect Keyboard Layout – No (domyślny wybór)
  9. Keyboard layout – Polish (domyślny wybór)
  10. Keyboard layout – Polish (domyślny wybór)
  11. Hostname – hadoop
  12. Full Name – Maciej Stopa
  13. User Name – administrator
  14. Password – xxx
  15. Re-enter Password – xxx
  16. Encrypt Home Directory – No (domyślny wybór)
  17. Timezone Europe/Warsaw – Yes (domyślny wybór)
  18. Guided – use entire disk and set up LVM (domyślny wybór)
  19. SCSI – 21,5GB (domyślna wartość)
  20. Write changes and configure LVM – Yes
  21. Amount of volume group to use – 21.2GB (domyślna wartość)
  22. Write changes to disk – Yes
  23. Http Proxy – u mnie brak – pusto
  24. How do you want to manage upgrades – No automatic (domyślny wybór)
  25. Choose software – OpenSSH Server
  26. Install GRUB to master boot record – Yes (domyślny wybór)
  27. Finish the installation – Continue (domyślny wybrór)

Założenia środowiska

  • nazwa hosta to hadoop
  • nazwa użytkownika z uprawnieniami administratora to administrator
  • wykorzystana dystrybucja Ubuntu Server 14.04.1 LTS

Instalacja Chef

Logujemy się na użytkownika administrator i rozpoczynamy od utworzenia struktury katalogów w których nasz kucharz (Chef) będzie trzymać receptury oraz role do instalacji. Poniższe komendy nie wymagają uprawnień super użytkownika.

mkdir -p /home/administrator/chef-solo
mkdir -p /home/administrator/chef-repo/.chef
mkdir -p /home/administrator/chef-repo/cookbooks
mkdir -p /home/administrator/chef-repo/roles

Następnie potrzebujemy zainstalować naszego Kucharza czyli oprogramowanie Chef które zrobi za nas 99% trudnej pracy przy konfiguracji.
Startujemy od zaktualizowania listy dostępnych w Ubuntu pakietów (komenda apt-get update), opierając się na najnowszych dla danej dystrubucji. Potrzebujemy do tego uprawnień superużytkownika (komenda sudo -s).

sudo -s
apt-get update

Ze spraw kosmetycznych specyficznych dla Ubuntu, musimy wyłączyć czyszczenie katalogu /tmp po restarcie – ponieważ nasz Hadoop sporo rzeczy będzie tam przechowywał. Dla uproszczenia środowiska nie modyfikujemy tego zachowania, a jedynie wyłączamy czyszczenie /tmp. Edytujemy plik /etc/default/rcS i dopisujemy poniższą linię:

TMPTIME=-1

Instalację Chef’a wykona za nas automatyczny skrypt, kolejny raz upraszczając cały proces. Wykonujemy poniższą komendę już z uprawnieniami administratora przyznanymi przez sudo

curl -L https://www.opscode.com/chef/install.sh | bash

W tym momencie mamy zainstalowane oprogramowanie do automatyzowania naszej instalacji.

Konfiguracja Chef’a

Tworzymy katalog z konfiguracją Chef’a oraz edytujemy plik /etc/chef/solo.rb przy pomocy ulubionego edytora (u mnie vi)

mkdir /etc/chef
vi /etc/chef/solo.rb

Zawartość pliku /etc/chef/solo.rb

file_cache_path "/home/administrator/chef-solo"
repo = '/home/administrator/chef-repo'

cookbook_path repo + '/cookbooks'
data_bag_path repo + '/data_bags'
role_path repo + '/roles'

log_location STDOUT

Potrzebujemy jeszcze tylko skonfigurować automagiczny menedżer receptur Knife, który pobierze dla nas to co będzie dalej wymagane, czyli receptury dla apt, yum, java oraz hadoop. Przechodzimy do katalogu repozytorium Chef’a i edytujemy plik /home/administrator/chef-repo/.chef/knife.rb

cd /home/administrator/chef-repo
vi /home/administrator/chef-repo/.chef/knife.rb

Zawartość pliku /home/administrator/chef-repo/.chef/knife.rb

cookbook_path [ '/root/chef-repo/cookbooks' ]

Przygotowanie receptur

Powoli pozwalamy magii działać, czyli pobieramy nasze receptury dla środowiska narzędziem Knife, pozostając w katalogu /home/administrator/chef-repo

knife cookbook site download apt
knife cookbook site download yum
knife cookbook site download java
knife cookbook site download hadoop
knife cookbook site download selinux
knife cookbook site download sysctl
knife cookbook site download ohai
knife cookbook site download ulimit

Wchodzimy do katalogu z recepturami (cookbooks) aby je rozpakować

cd /home/administrator/chef-repo/cookbooks
find .. -name "*.gz" -exec tar zxvf "{}" \;

Pozostaje nam przygotować role dla Chef’a czyli wybrać wersje oprogramowania które mają zostać zainstalowane – dostawcę Java (Oracle, OpenJDK) oraz dostawcę stacka Hadoop. Edytujemy kolejno pliki /home/administrator/chef-repo/roles/java.rb oraz /home/administrator/chef-repo/roles/hadoop.rb

Zawartość pliku /home/administrator/chef-repo/roles/java.rb

name "java"
description "Install Oracle Java"
default_attributes(
  "java" => {
    "install_flavor" => "oracle",
    "jdk_version" => "7",
    "set_etc_environment" => true,
    "oracle" => {
      "accept_oracle_download_terms" => true
    }
  }
)
run_list(
  "recipe[ java]"
)

Zawartość pliku /home/administrator/chef-repo/roles/hadoop.rb

name "hadoop"
description "set Hadoop attributes"
default_attributes(
  "hadoop" => {
    "distribution" => "bigtop",
    "core_site" => {
      "fs.defaultFS" => "hdfs://hadoop"
    },
    "yarn_site" => {
      "yarn.resourcemanager.hostname" => "hadoop"
    }
  }
)
run_list(
  "recipe[hadoop]"
)

Gdy konfiguracja Chef’a jest gotowa, wskazujemy które role oraz receptury mają zostać wykonane w celu przygotowania naszego środowiska Hadoop. W tym celu przygotowujemy ostatni plik, niejako naszą recepturę instalacji komponentów. Edytujemy plik vi /home/administrator/chef-repo/hadoop.json.

Zawartość pliku vi /home/administrator/chef-repo/hadoop.json

{
  "run_list": [
     "role[ java]",
     "recipe[ java]",
     "role[hadoop]",
     "recipe[hadoop::hadoop_hdfs_namenode]",
     "recipe[hadoop::hadoop_yarn_nodemanager]",
     "recipe[hadoop::hadoop_yarn_resourcemanager]",
     "recipe[hadoop::hadoop_hdfs_datanode]",
     "recipe[hadoop::hbase]",
     "recipe[hadoop::hive]",
     "recipe[hadoop::hive_metastore]",
     "recipe[hadoop::oozie]",
     "recipe[hadoop::pig]",
     "recipe[hadoop::zookeeper]"  ]
}

Siła szefa kuchni

Pozostając w katalogu /home/administrator/chef-repo i posiadając nadal uprawnienia administratora, pozwalamy na przygotowanie naszego środowiska. Chef zajmie się wszystkim od pobrania pakietów, przez ich konfigurację, integrację ze sobą, utworzenie i uruchomienie niezbędnych serwisów. MAGIC!

chef-solo -c /etc/chef/solo.rb -j hadoop.json

Należy teraz zainicjalizować naszego Hadoop NameNode

su -l hdfs
hadoop namenode -format
exit

Uruchamiamy NameNode oraz DataNode

service hadoop-hdfs-namenode start
service hadoop-hdfs-datanode start

Formatujemy HDFS i przygotowujemy katalogi dla usług

/usr/lib/hadoop/libexec/init-hdfs.sh

Uruchamiamy Hive Metastore

service hive-metastore start

Jeżeli nie pomyliliśmy się i wszystkie komendy i wklejki zostały wykonane poprawnie, po kilku minutach otrzymujemy w pełni skonfigurowane środowisko z dostępnymi Hadoop, Hive, Pig, YARN, Oozie i Zookeeper.

Testy

Na potrzeby testów wykorzystam przykład z HDP polegający na pobraniu archiwów meczy baseball’owych, wrzuceniu ich na HDFS, import do Hive i wykorzystanie MapReduce do wykonania kilku Select’ów.

Z uprawnieniami superużytkownika doinstalowujemy unzip i tworzymy katalog dla danych /home/administrator/data następnie przechodząc do niego.

apt-get install unzip
mkdir /home/administrator/data
cd /home/administrator/data

Pobieramy plik z danymi i rozpakowujemy go

wget http://seanlahman.com/files/database/lahman591-csv.zip
unzip lahman591-csv.zip

Umieszczamy kopię pliku na HDFS, tak aby węzły (w naszym przypadku jeden) miały dostęp do tych danych, jednocześnie udostępniając je dla usług np Hive.

hdfs dfs -copyFromLocal Batting.csv /user/root/

Uruchamiamy Hive, który pozwoli na potraktowanie danych CSV prostymi zapytaniami SQL wykorzystując mechanizmy Hadoop i MapReduce. Jeżeli wszystko jest dobrze skonfigurowane, powinniśmy zostać przywitani promptem Hive czyli hive>.

root@hadoop:~/data# hive
Logging initialized using configuration in jar:file:/usr/lib/hive/lib/hive-common-0.13.0.jar!/hive-log4j.properties
hive>

Kolejne komendy wpisujemy w prompcie Hive. Tworzymy tabelę tymczasową temp_batting do której przypisujemy nasz plik z HDFS /user/root/Batting.csv. Na jego podstawie utworzymy docelową tabelę z danymi batting które zostaną wyodrębnione przy pomocy Regexp’ów. Nie przejmuj się komunikatami Warning – mówią one o tym że działamy na pojedynczym węźle i pewne zmienne dotyczące podziału zadań pomiędzy większą ilość węzłów poprostu nie są skonfigurowane, w naszych przykładach nie jest to żadnym problemem.

CREATE TABLE temp_batting (col_value STRING);

LOAD DATA INPATH '/user/root/Batting.csv' OVERWRITE INTO TABLE temp_batting;

CREATE TABLE batting (player_id STRING, year INT, runs INT);

INSERT OVERWRITE TABLE batting  
SELECT  
  regexp_extract(col_value, '^(?:([^,]*)\,?){1}', 1) player_id,  
  regexp_extract(col_value, '^(?:([^,]*)\,?){2}', 1) year,  
  regexp_extract(col_value, '^(?:([^,]*)\,?){9}', 1) run  
FROM temp_batting;

Efekt powyższych komend powinien wyglądać mniej więcej tak:

hive> CREATE TABLE temp_batting (col_value STRING);
OK
Time taken: 0.215 seconds

hive> LOAD DATA INPATH '/user/root/Batting.csv' OVERWRITE INTO TABLE temp_batting;
Loading data to table default.temp_batting
Table default.temp_batting stats: [numFiles=1, numRows=0, totalSize=6398990, rawDataSize=0]
OK
Time taken: 1.017 seconds

hive> INSERT OVERWRITE TABLE batting
    > SELECT
    >   regexp_extract(col_value, '^(?:([^,]*)\,?){1}', 1) player_id,
    >   regexp_extract(col_value, '^(?:([^,]*)\,?){2}', 1) year,
    >   regexp_extract(col_value, '^(?:([^,]*)\,?){9}', 1) run
    > FROM temp_batting;
Total jobs = 3
Launching Job 1 out of 3
Number of reduce tasks is set to 0 since theres no reduce operator
Execution log at: /tmp/root/root_20150219105353_aa0aabfe-3589-48d7-a047-6b0987fe20c3.log
Job running in-process (local Hadoop)
Hadoop job information for null: number of mappers: 0; number of reducers: 0
2015-02-19 10:53:04,269 null map = 0%,  reduce = 0%
2015-02-19 10:53:05,287 null map = 100%,  reduce = 0%
Ended Job = job_local592960733_0001
Execution completed successfully
MapredLocal task succeeded
Stage-4 is selected by condition resolver.
Stage-3 is filtered out by condition resolver.
Stage-5 is filtered out by condition resolver.
Moving data to: hdfs://hadoop/tmp/hive-root/hive_2015-02-19_10-53-00_203_7795567368711574116-1/-ext-10000
Loading data to table default.batting
rmr: DEPRECATED: Please use 'rm -r' instead.
Deleted hdfs://hadoop/user/hive/warehouse/batting
Table default.batting stats: [numFiles=1, numRows=95196, totalSize=1653324, rawDataSize=1558128]
OK
Time taken: 5.89 seconds

Tak przygotowane tabele zawierają już dane które mogą nas zainteresować. Możemy teraz wyszukiwać zapytaniami SQL szczegółowe informacje.

hive> SELECT year, max(runs) FROM batting GROUP BY year;
Total jobs = 1
Launching Job 1 out of 1
Number of reduce tasks not specified. Estimated from input data size: 1
Execution log at: /tmp/root/root_20150219105454_01e4848f-b71c-4e12-88c3-ed4e9360ace6.log
Job running in-process (local Hadoop)
Hadoop job information for null: number of mappers: 0; number of reducers: 0
2015-02-19 10:54:09,113 null map = 100%,  reduce = 100%
Ended Job = job_local2006606267_0001
Execution completed successfully
MapredLocal task succeeded
OK
NULL    NULL
1871    66
1872    94
...
2010    115
2011    136
Time taken: 4.689 seconds, Fetched: 142 row(s)
hive> SELECT a.year, a.player_id, a.runs from batting a
    > JOIN (SELECT year, max(runs) runs FROM batting GROUP BY year ) b
    > ON (a.year = b.year AND a.runs = b.runs) ;
Total jobs = 2
Launching Job 1 out of 2
Number of reduce tasks not specified. Estimated from input data size: 1
Execution log at: /tmp/root/root_20150219105555_a44780bc-4cbc-4d07-b65e-775f58325789.log
Job running in-process (local Hadoop)
Hadoop job information for null: number of mappers: 0; number of reducers: 0
2015-02-19 10:55:41,842 null map = 100%,  reduce = 100%
Ended Job = job_local1016279659_0001
Execution completed successfully
MapredLocal task succeeded
Execution log at: /tmp/root/root_20150219105555_a44780bc-4cbc-4d07-b65e-775f58325789.log
2015-02-19 10:55:44     Starting to launch local task to process map join;     maximum memory = 932184064
2015-02-19 10:55:45     Dump the side-table into file: file:/tmp/root/hive_2015-02-19_10-55-37_776_592556185375942408-1/-local-10004/HashTable-Stage-4/MapJoin-mapfile00--.hashtable
2015-02-19 10:55:45     Uploaded 1 File to: file:/tmp/root/hive_2015-02-19_10-55-37_776_592556185375942408-1/-local-10004/HashTable-Stage-4/MapJoin-mapfile00--.hashtable (2033677 bytes)
2015-02-19 10:55:45     End of local task; Time Taken: 0.93 sec.
Execution completed successfully
MapredLocal task succeeded
Launching Job 2 out of 2
Number of reduce tasks is set to 0 since there's no reduce operator
Execution log at: /tmp/root/root_20150219105555_a44780bc-4cbc-4d07-b65e-775f58325789.log
Job running in-process (local Hadoop)
Hadoop job information for null: number of mappers: 0; number of reducers: 0
2015-02-19 10:55:50,002 null map = 100%,  reduce = 0%
Ended Job = job_local1075503958_0001
Execution completed successfully
MapredLocal task succeeded
OK
1871    barnero01       66
1872    eggleda01       94
...
2010    pujolal01       115
2011    grandcu01       136
Time taken: 12.746 seconds, Fetched: 151 row(s)

Proste prawda? Pomyśl teraz jak wiele różnych danych mógłbyś w ten sposób przetwarzać. Jest to tylko bardzo mały wycinek tego co możemy uzyskać dzięki zestawom aplikacji Hadoop. Zachęcam do wrzucenia swoich zestawów danych i eksperymentowania.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *