# hadoop
https://hackmd.io/@QI-AN/rk4cq0M5q
資訊科技 (Infomation Technology)

* 「Business Intelligence」商業智慧:就是為了要做出決策報告。
* Business Intelligence世界第一品牌 teradata。
* 現在的公司使用資料庫就是為了能夠分析出有效、有價值的決策報告,但是teradata天睿這家公司出版的Teradata資料庫,不只軟體價格變高,還要求使用指定的硬體設備,讓很多公司受不了。
* OLTP的資料會抓去OTAP做備份
* binlog:他會儲存備份資料
* CDC:他會一直去抓binlog的資料
* Data Warehouse:把已經備份好的資料再給他很多種的model做出資料庫,主要是為了Business Intelligence。

* 因為teradata太貴了,所以另一個替代方案就是使用Hadoop。
* 另外一個替代方案以Hadoop搭配Hive,就可以做出企業所需要的Business Intelligence。
* Hadoop 儲存資料的單位以T來計算,他本身不提供修改功能。
* Hive架在hadoop之上,hive主要就是來做商業智慧的分析,所以他不是用來資訊的管理(新增刪除)。
* Spark (machine learning):主要是做資料深度分析,用來預測開發。
* HBase:用來處理iot,他是架在hadoop之上,有新增刪除修改的功能。
* 五顆寶石(資料來源):
1. 拇指圖案(OLAP):把企業的資料丟到hadoop。
2. 星星圖案(opendate):政府資料開放平台。
3. 放大鏡圖案(爬蟲程式):利用程式去抓程式,但是爬蟲回來的資料可用度不高。
4. 計算機圖案:要取得某個工廠的資料,需要取得法規的許可,並且人際關係要夠好,雖然都是同個公司,但是資料並不互通。
5. intel圖案(黑暗面):就是買資料。
## hadoop架構

* Hadoop Distributed File System (HDFS™),分散式檔案系統,這套檔案系統在運作一定要多台電腦
> windows的檔案系統為:NTFS
* YARN,運算系統,專門來跑程式的,就是分析儲存的資料,可以平行處理,意思就是說可以在多台電腦同時讓Mapreduce和Spark跑程式分析資料
> Hadoop算不算一個資料型的作業系統?
> 是,因為它具備資料儲存、運算能力
> windows裡,執行程式的平台叫做. net,其中有一個msSQ
* MapReduce,內建資料處理引擎,用來做資料分析
Spark,(可加裝)也是資料處理引擎
Hive,會使用MapReduce做出來的分析
Hadoop Common: The common utilities that support the other Hadoop modules.
代表Hadoop的管理命令和應用命令

* hadoop一定是多台電腦用java程式做出來的。
* hadoop有六台電腦,dta1做管理主機,dtm1:namenode,dtm2:resource manager (yarn主要的管理程式),dtw1,dtw2,dtw3:datanode。
* dtm1:上有NameNode,還有Secondary NameNode,他們就是java程式。
* dtw1 dtw2 stw3:data node,工作機。
* dtm2:resource manager,也都是jave程式。
## HDFS 分散檔案系統 - 寫入檔案

* client就是代表dta1,操作這台電腦的人就是資料管理師,他會上網去下載 `wget http://a.b.c/File.txt`再把檔案丟到hdfs檔案系統`hdfs dfs -put File.txt mydataset`,他會把file.txt切成三個區塊blk(block)
* 只要檔案要丟到hdfs,他在本機一定要先做切割。
* 切割的方法,每128m為單位
> 問題:一個檔案128m,那三個檔案檔案總共多大?
> 答:檔案的大小一定不會剛好,他會是一個範圍,因此有三個block,第三個block的大小我們不確定因此範圍是256m<x<=384m
dta1 把資料做切割後,會問name node要把block放在哪裡,因為現在有三個block,所以會放在三台電腦。
* 只要檔案往hdfs檔案系統丟,檔案一定會被切成很多個block,除非那個檔案很小;之後client會去找name node(HDFS),name node會安排每一個block要存在哪三台datanode機器裡面(一個block要存在三台不同的datanode主機)。
- 切割方法:128mb為單位(hadoop內定預設值),只要超過一個byte就會被多切一個block出來。
- 一個block內定一定存在三台不同的data node主機。
- 如果存1g大小的檔案,在hdfs檔案系統就等於存3g的檔案大小
* data node 1(dtw1) 收到blk a後,dtw1資料存到64k後就會開始把資料傳給dtw5(dtw1會持續把資料收完),一樣dtw5資料收到64k後會開始把檔案傳給dtw6,雖然檔案沒收完就傳給下一台主機,但檔案最終一定都會收完(同步的概念)。
- 如果一台data node掛了,我們還是可以讀到File.txt檔案,hdfs有容錯的能力。
## HDFS 分散檔案系統 - 讀取檔案

* client想要看檔案,name node會告訴他這三個blk分別放在哪,他會列出一個清單,並且取第一順位的blk,例如:
* blk A = 1、5、6
* blk B = 8、1、2
* blk C = 5、8、9
* (他會取1、8、5這三個data node)告訴dta1,知道位置後這三個blk會同時傳給dta1,然後再把三個blk合成一個我們要看檔案。
- name node列出的清單順序,如果同時有不同的人來讀同一個檔案,那每個人name node列出的清單(data node會不同)都會不一樣,這就是round robin(循環制)。
「HDFS好處」
1. 檔案切塊分散三台機器儲存,可容錯
2. 分散儲存檔案要讀取時由三台機器提供各自儲存的檔案,讀取效率高
3. 多人共用時會有round robin 的概念,輪流由不同組合機器提供檔案
> 問題:如果hadoop一個檔案是100t,那client可以讀到檔案嗎?
> 答:因為client的電腦設備一定不是機房的規格,硬碟不夠大,那client一定讀不進來。
> 問題:承上題,那要如何處理這個問題?
> 答:由後端的那些電腦(dtw1,dtw2...)來做資料分析,就是MapReduce,這是hadoop內建的資料處理引擎。
## HDFS 系統資訊
```
##可以看到hdfs架構的駐點資訊
$ hdfs dfsadmin -report
Configured Capacity: 1582106935296 (1.44 TB) ##多少空間可以使用
Present Capacity: 1465391128576 (1.33 TB)
DFS Remaining: 1465384878080 (1.33 TB)
DFS Used: 6250496 (5.96 MB)
DFS Used%: 0.00%
Replicated Blocks:
Under replicated blocks: 0
Blocks with corrupt replicas: 0
Missing blocks: 0
Missing blocks (with replication factor 1): 0
Pending deletion blocks: 0
Erasure Coded Block Groups:
Low redundancy block groups: 0
Block groups with corrupt internal blocks: 0
Missing block groups: 0
Pending deletion blocks: 0
-------------------------------------------------
Live datanodes (3): ##活者的datanode有幾台
Name: 192.168.61.6:9866 (dtw1)
Hostname: dtw1
Decommission Status : Normal
Configured Capacity: 526185201664 (490.05 GB) ##dtw1可用的空間
DFS Used: 84848640 (80.92 MB)
Non DFS Used: 6600155136 (6.15 GB)
DFS Remaining: 492696236032 (458.86 GB)
............
............
```
* 檔案的名字、檔案的資訊、屬性,都會存在name node這支java的程式裡,也就是dtm1主機。
* mate data :File name(名稱),File attributes(屬性)
* 檔案的資料是分散在不同的 data node 主機
## Name Node 目錄內容
```
##namenode這個java程式負責存hdfs的matedata
##nn這個目錄會存hdfs的mate data
##這裡會紀錄hdfs的檔案系統目錄,還有檔案屬性(檔案名稱,檔案的權限)
## edites 存放hadoop下達過的指令: hdfs dfs -put -cat...
## fsimage 紀錄檔案系統(檔案,目錄的資訊)
## 所以其實HDFS檔案系統是以Linux為基礎建設出來的
##dtm1負責儲存檔案存放的位置
$ ssh dtm1 tree nn
nn
├── current
│ ├── VERSION
│ ├── edits_0000000000000000001-0000000000000000009
│ ├── edits_0000000000000000010-0000000000000000011
│ ├── edits_inprogress_0000000000000000012
│ ├── fsimage_0000000000000000000 ##hdfs檔案系統的mate data
│ ├── fsimage_0000000000000000000.md5 ##mate data身分證號碼,防止mate data被竄改
│ └── seen_txid
└── in_use.lock
1 directory, 10 files
$ ssh dtm1 cat nn/current/VERSION
#Thu Nov 08 02:31:28 GMT 2018
namespaceID=1539483458
clusterID=cute
cTime=1541644288235
storageType=NAME_NODE
blockpoolID=BP-564818905-172.30.0.10-1541644288235 ##name node跟data node靠這個id做溝通
layoutVersion=-64
```
## Data Node 目錄內容
```
## dn就是linux的目錄,所以data node也是用linux的檔案系統來做他要處理的資料
##blk就是放在這個dn目錄區
$ ssh dtw1 tree dn
dn
├── current
│ ├── BP-1785240759-192.168.61.4-1645624914539 ## name node的識別代號,目前這個data node為這個name node服務
│ │ ├── current
│ │ │ ├── dfsUsed
│ │ │ ├── finalized
│ │ │ │ └── subdir0
│ │ │ │ └── subdir0 ##各種blk
│ │ │ │ ├── blk_1073741829
│ │ │ │ ├── blk_1073741829_1009.meta
│ │ │ │ ├── blk_1073741830
│ │ │ │ ├── blk_1073741830_1010.meta
│ │ │ │ ├── blk_1073741831
│ │ │ │ └── blk_1073741831_1011.meta
│ │ │ ├── rbw
│ │ │ └── VERSION
│ │ ├── scanner.cursor
│ │ └── tmp
│ └── VERSION
└── in_use.lock
```
## 檢視 NameNode MetaData
立即更新 fsimage
```
## 換成安全模式,只能讀目錄和讀檔案,不能新增和刪除檔案
$ hdfs dfsadmin -safemode enter
Safe mode is ON
##他會更新fsimage
##他會把新的metadata存在這裡
$ hdfs dfsadmin -saveNamespace
Save namespace successful
[註] 會立即將記憶體中的資料寫入一個新的 fsimage 檔中
$ ssh dtm1 tree -sh nn
..........
│ ├── edits_inprogress_0000000000000000012
│ ├── fsimage_0000000000000000000
│ ├── fsimage_0000000000000000000.md5
│ ├── fsimage_0000000000000000011
│ ├── fsimage_0000000000000000011.md5
..........
##關閉安全模式
$ hdfs dfsadmin -safemode leave
Safe mode is OFF
```
取出 fsimage 檔, 並將之轉換成 csv 格式檔
```
## 在dtm1拷貝到/tmp目錄裡
##-fetchImage 抓剛剛最新的metadata檔案
$ hdfs dfsadmin -fetchImage /tmp/
$ dir /tmp/fsimage*
-rw-rw-r-- 1 bigred bigred 320 7月 15 20:21 /tmp/fsimage_0000000000000000020
HDFS Offline Image Viewer
## 把fsimage這個matedata檔案換成csv格式
$ hdfs oiv -i /tmp/fsimage_0000000000000000020 -o /tmp/fsimage.csv -p Delimited -delimiter ","
```
```
##可以看到整個metadata資訊,使用者,檔案權限目錄,創建時間,資料都寫在這裡
$ cat /tmp/fsimage.csv
Path,Replication,ModificationTime,AccessTime,PreferredBlockSize,BlocksCount,FileSize,NSQUOTA,DSQUOTA,Permission,UserName,GroupName
/,0,2022-02-23 22:02,1970-01-01 08:00,0,0,0,9223372036854775807,-1,drwxr-xr-x,bigred,bigboss
/tmp,0,2022-02-23 22:02,1970-01-01 08:00,0,0,0,-1,-1,drwxrwx---,bigred,bigboss
/tmp/hadoop-yarn,0,2022-02-23 22:02,1970-01-01 08:00,0,0,0,-1,-1,drwxrwx---,bigred,bigboss
/tmp/hadoop-yarn/staging,0,2022-02-23 22:02,1970-01-01 08:00,0,0,0,-1,-1,drwxrwx---,bigred,bigboss
/tmp/hadoop-yarn/staging/history,0,2022-02-23 22:02,1970-01-01 08:00,0,0,0,-1,-1,drwxrwx---,bigred,bigboss
/tmp/hadoop-yarn/staging/history/done,0,2022-02-23 22:02,1970-01-01 08:00,0,0,0,-1,-1,drwxrwx---,bigred,bigboss
/tmp/hadoop-yarn/staging/history/done_intermediate,0,2022-02-23 22:02,1970-01-01 08:00,0,0,0,-1,-1,drwxrwxrwt,bigred,bigboss
```
[註] NameNode MetaData 只存放 目錄與檔案 資訊, 沒有 Transaction 資訊, Transaction 資訊分存在 edits_xxxxx 這類檔中
## HDFS 容錯處理 - 遺失資料區塊
```
##把我們linux的帳號檔案丟到hdfs裡面
$ hdfs dfs -put /etc/passwd /tmp/
##這個檔案只有1.5k,所以只有一個block
$ ls -lh /etc/passwd
-rw-r--r-- 1 root root 1.5K Sep 13 12:05 /etc/passwd
##找這個BLK在哪裡
##blk_1073741845_1021 blk名稱
##192.168.61.6、192.168.61.7 這個blk存在這兩個data node(這邊只有兩個是因為老師設定的)
bigred@dtm1:~$ hdfs fsck /tmp/passwd -files -blocks -locations
Connecting to namenode via http://dtm1:9870/fsck?ugi=bigred&files=1&blocks=1&locations=1&path=%2Ftmp%2Fpasswd
FSCK started by bigred (auth:SIMPLE) from /192.168.61.4 for path /tmp/passwd at Tue Jul 26 14:52:46 CST 2022
/tmp/passwd 1426 bytes, replicated: replication=2, 1 block(s): OK
0. BP-727742586-192.168.61.4-1658817601466:blk_1073741845_1021 len=1426 Live_repl=2 [DatanodeInfoWithStorage[192.168.61.6:9866,DS-1248c60c-51da-451a-9252-a8245868d702,DISK], DatanodeInfoWithStorage[192.168.61.7:9866,DS-0639480e-2155-4377-983b-667fdff6061f,DISK]]
```
```
##刪除blk
$ rm dn/current/BP-727742586-192.168.61.4-1658817601466/current/finalized/subdir0/subdir0/blk_1073741845*
```
```
還是可以看得到檔案
$ hdfs dfs -cat /tmp/passwd
root:x:0:0:root:/root:/bin/ash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
.......
```
```
## 同一個blk又回復了
$ tree dn
dn
├── current
│ ├── BP-727742586-192.168.61.4-1658817601466
│ │ ├── current
│ │ │ ├── VERSION
│ │ │ ├── finalized
│ │ │ │ └── subdir0
│ │ │ │ └── subdir0
│ │ │ │ ├── blk_1073741836
│ │ │ │ ├── blk_1073741836_1012.meta
│ │ │ │ ├── blk_1073741837
│ │ │ │ ├── blk_1073741837_1013.meta
│ │ │ │ ├── blk_1073741844
│ │ │ │ ├── blk_1073741844_1020.meta
│ │ │ │ ├── blk_1073741845
│ │ │ │ └── blk_1073741845_1021.meta
```
> 結論:把blk刪除,在下hdfs dfs -cat,還是可以看得到檔案,資料還原了
* 如果把其中一個data node的blk刪除,這時候如果cat沒有到沒有被刪除的blk,那他就還不會被修復,所以這時候去tree dn(被刪掉blk的機器),他的檔案還是沒復原,解法:多cat幾次,讓系統讀到那個blk。
> 問題:為什麼我把全部的blk都刪除了,我還是看的到檔案名稱?
> 答:因為檔案名稱是mate data,他是存在name node,他的檔案是放在dtm1。
## HDFS 設定檔
```
$ tree $HADOOP_HOME/etc/hadoop
/opt/hadoop-3.3.3/etc/hadoop
::
├── core-site.xml
├── hadoop-env.sh ##hadoop要建起來要設定環境變數
├── hdfs.allow (內定只允許 5 部工作主機)
├── hdfs-site.xml
::
├── mapred-site.xml
::
├── yarn-env.sh
└── yarn-site.xml
```
在dta1一定要有這個java程式,才能跑hadoop,因為我們環境變數有設定java所以我們可以直接跑這個程式
```
$ java -version
openjdk version "1.8.0-332"
OpenJDK Runtime Environment (build 1.8.0-332-b09)
OpenJDK 64-Bit Server VM (build 25.71-b09, mixed mode)
```
但是hadoop其實是靠這個設定檔找到java的程式,並不是在PATH找到的
```
$ sudo nano $HADOOP_HOME/etc/hadoop/hadoop-env.sh
.......
export JAVA_HOME=/opt/openjdk-8u332-linux-x64
.......
export HADOOP_HEAPSIZE=512 ##hadoop所有程式能跑的記憶體大小
........
export HADOOP_LOG_DIR=/tmp ##如果那些java程式有bug,都會丟到/tmp這個目錄
hadoop java 程式:
NameNode
DataNode
SecondaryNameNode
JobHistoryServer
ResourceManager
NodeManager
[註] Java 7 was end-of-lifed in April 2015, meaning Oracle would no longer publicly support it with security fixes.
```
* 設定hdfs
> xml 主要是用來做系統設定的格式,html主要是做顯示,雖然他們的格式有點像,但他們功能差很多
```
$ sudo nano $HADOOP_HOME/etc/hadoop/hdfs-site.xml
<?xml version="1.0" encoding="UTF-8"?>
.........
<configuration>
<property>
<name>dfs.replication</name>
<value>3</value> ##這邊3代表每一個blk存3分,如果沒有特定去調整內定都是3
</property>
<property>
<name>dfs.namenode.name.dir</name>
<value>file:/home/bigred/nn</value> ##設定matedata存在nn目錄
</property>
<property>
<name>dfs.datanode.data.dir</name>
<value>file:/home/bigred/dn</value> ##datanode存blk是在dn這個目錄區
</property>
<property>
<name>dfs.permissions.superusergroup</name>
<value>bigboss</value> ##管理者群組名稱
</property>
...........
</configuration>
```
[註] 在 client 端 (dta1) 修改 dfs.replication 數值後, 不需重新啟動 HDFS 分散檔案系統, 設定值直接生效
* hadoop核心設定
```
$ sudo nano $HADOOP_HOME/etc/hadoop/core-site.xml
<?xml version="1.0" encoding="UTF-8"?>
........
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://dtm1:8020</value> ##hadoop namenode要在哪裡執行,namenode port國際標準8020
</property>
<property>
<name>fs.default.name</name>
<value>hdfs://dtm1:8020</value> ##可以連到舊的名稱
</property>
<property>
<name>io.compression.codecs</name>
<value>org.apache.hadoop.io.compress.BZip2Codec,org.apache.hadoop.io.compress.GzipCodec,org.apache.hadoop.io.compress.SnappyCodec</value>
</property> ##hadoop用到的壓縮技術是BZip
<property>
<name>hadoop.user.group.static.mapping.overrides</name>
<value>rbean=soup;gbean=soup,rice;ybean=rice</value>
</property>
</configuration>
```
## YARN 分散運算系統(負責跑程式)

* Linux -> java(物件導向程式設計) -> JVM(process 程序),一定要有 JVM 來 run java,程序只要一起來就一定會霸佔記憶體空間。
* jvm會被載入到記憶體,記憶體裡面有分三個區域,static,stack,heap。
* 我們寫的程式,副檔名是(*.class),他會load到記憶體static區塊,變成一個表格叫blueprint(藍圖),最後做出object(物件)。
* java是由jvm去執行。
* 我們寫的java程式一定要有jvm,然後把她載入到記憶體,設計出藍圖,最後做出物件。
> windows -> C# -> .NET(他只會跑C#)
> 也是一樣會把C#網記憶體裡面丟,然後去執行
> 結論:java大約等於C#,這倆個程式一定要有人去幫他執行(跟go還有c語言不一樣,這兩個是編譯完後作業系統就可以直接去執行他)
* YARN跑的是mapreduce的java程式,還有Spark RDD的java程式,這類的資料引擎處理程式,其他的他不會。
### 設定 YARN 總量運算資源

* dtm2 中的 resource manager 認定一台機器有多少資源(CPU,記憶體)可以使用,是透過 dtw(1,2,3) 的 Node manager 告知 resource manager ,讓他知道現在這台工作機有多少硬體資源可以使用。
* 檢視 YARN 總量運算資源
```
在 dta1 執行以下命令
##dtm2跑的是resource manager,問他有多少記憶體,CPU可以使用
$ curl -s http://dtm2:8088/ws/v1/cluster/metrics | jq | grep -E "totalMB|totalVirtualCores"
"totalMB": 6144,
"totalVirtualCores": 6,
[重點] YARN 系統內定每部 Node Manager 的記憶體為 8G, CPU 為 8 Core
```
* 設定 YARN 總量運算資源
```
##設定 yarn ,記憶體修改3072,CPU改3
$ nano ~/vmalpdt/hdp33/conf/hadoop/yarn-site.xml
......
<property>
<name>yarn.nodemanager.resource.memory-mb</name>
<value>3072</value>
</property>
<property>
<name>yarn.nodemanager.resource.cpu-vcores</name>
<value>3</value>
</property>
.......
```
因為設定檔有改過,所以要在run這個命令把設定檔派送dtw1,dtw2,dtw3
`$ dtconf 33 `
* 3072*3因為有三台dtw1,dtw2,dtw3所以總量是9216
* 3*3因為有三台dtw1,dtw2,dtw3所以總量是9
```
$ curl -s http://dtm2:8088/ws/v1/cluster/metrics | jq | grep -E "totalMB|totalVirtualCores"
"totalMB": 9216,
"totalVirtualCores": 9
```
## 設定 Container 可用運算資源

1. dtm1,dtm2裡面可以執行container。
2. node manager , resource manager,都是用 java 寫的,java 一定要有 jvm 去執行,他一定霸佔記憶體空間,在10幾年前又稱為 container,container 指的就是 JVM,因為 JVM 裡面裝 object,所以稱為容器。
* 一個container的運算資源設定
```
##記憶體要使用多少就要去問resource manager
##記憶體最少使用384,做多使用896
##cpu只能使用一個核心
$ cat ~/vmalpdt/hdp33/conf/hadoop/yarn-site.xml
........
<property>
<name>yarn.scheduler.minimum-allocation-mb</name>
<value>384</value>
</property>
<property>
<name>yarn.scheduler.maximum-allocation-mb</name>
<value>896</value>
</property>
<property>
<name>yarn.scheduler.minimum-allocation-vcores</name>
<value>1</value>
</property>
<property>
<name>yarn.scheduler.maximum-allocation-vcores</name>
<value>1</value>
</property>
..........
```
> 問題:在這個(記憶體:9216,CPU:9c)的資源下我們總共可以跑多少個container?
> 答:9 個,cpu 和記憶體要一起考量,一個 container 最少要用 1 core,雖然記憶體不會用滿,但 cpu 已經用滿了,因此最多 9 個。
> 總共有三個 node manager ,因此一台 node manager 跑3個container
## 測試 YARN Container 最大的總執行量
```
在 dta1 終端機執行以下命令
$ startmaxctn
##15代表拿16個container來計算pi值
$ hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-${HADOOP_HOME##*-}.jar pi 15 300000
Number of Maps = 12
Samples per Map = 300000
Wrote input for Map #0
Wrote input for Map #1
............
Wrote input for Map #8
Wrote input for Map #9
Wrote input for Map #10
Wrote input for Map #11
Starting Job
Job Finished in 86.116 seconds
Estimated value of Pi is 3.14163444444444444444
```
## 取得 YARN Container 最大的總執行量
* 因為我們是讓16個container一次去跑,他會有順序的去跑,同時最大量一定只有9個container
```
##每一台機器在同一個時間點最多只有3個container,所以總共最多就是9個container
$ stopmaxctn
[dtw1]
10:19:19 -> Y:2 M:0
10:19:19 -> Y:3 M:0
10:19:27 -> Y:1 M:0
10:19:28 -> Y:1 M:0
10:19:29 -> Y:3 M:0
10:19:34 -> Y:2 M:0
10:19:35 -> Y:1 M:0
[dtw2]
10:19:08 -> Y:0 M:1
10:19:17 -> Y:1 M:1
10:19:18 -> Y:2 M:1
10:19:23 -> Y:1 M:1
10:19:25 -> Y:2 M:1
10:19:28 -> Y:1 M:1
10:19:29 -> Y:0 M:1
[dtw3]
10:19:19 -> Y:2 M:0
10:19:19 -> Y:3 M:0
10:19:27 -> Y:2 M:0
10:19:27 -> Y:1 M:0
10:19:28 -> Y:2 M:0
10:19:29 -> Y:3 M:0
10:19:34 -> Y:2 M:0
10:19:35 -> Y:1 M:0
```
## MapReduce 資料處理引擎
* YARN 分散運算系統運作圖

* client 就是 dta1,他會寫 MapReduce(Java) 程式。
* Hive -> MapReduce(Java),hive 會幫忙寫 MapReduce 這支 java 程式。
* 寫好的程式會丟給 resource manager ,那他要去 run 程式,resource manager 會去找 node manager,請他啟動 container,container 裡面的程式叫做 app master 。
* app master 這隻程式的功能會決定要有多少個 Map 程式,還有幾個 Reduce 程式,他會去跟 resource manager 要求。
* 之後 resource manager 會再去找 node manager , 誰去執行 map 程式,誰去執行 reduce 程式。
* 資料的分析還有處理都會跟 app master 做報告。
* MAP 擷取、過濾。
* REDUCE 分析、把資料儲存到HDFS。
## 檢視 MapReduce Job 的運算資源
在 dta1 終端機執行以下命令
```
$ startjps
# 2 代表現在要啟動三個 container
# 啟動兩個 map 程式和一個 reduce 程式
$ yarn jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-${HADOOP_HOME##*-}.jar pi 2 100000
Number of Maps = 2
Samples per Map = 100000
Wrote input for Map #0
Wrote input for Map #1
Starting Job
Job Finished in 25.829 seconds
Estimated value of Pi is 3.14280000000000000000
```
[註] map 及 樣本數 越大, PI 值越精準
### 檢視 MapReduce Job 的運算資源
```
# 要稱為大數據就是要能夠在多台電腦同時處理分析資料
# 第一個跑的一定是 app master
# 總共有兩個 map ,一個 reduce
# 一定會先啟動完 map ,再啟動 reduce
# reduce 的記憶體大小是 384m
$ stopjps
[dtw1]
[dtw2]
11:15:30
51020 YarnChild 256m # 51020 就是 pid ,他跑的是 map 程式
[dtw3]
11:15:23
50291 MRAppMaster 256m # 在 dtw3 第一個執行的 java 程式
11:15:30
50291 MRAppMaster 256m # 同一個 app master
51174 YarnChild 256m # 他就是 container 裡面跑的就是 map
11:15:33
50291 MRAppMaster 256m
11:15:36
50291 MRAppMaster 256m
51978 YarnChild 384m # 他跑的是 reduce
11:15:39
50291 MRAppMaster 256m
```
## Mapreduce 運作架構圖

* 土黃色的方塊:就是一個 block。
* block 存在的機器會啟動一個程式,map(也就是yarnchild)。
* map 可以同時在不同的機器同時執行,效能一定好,因為 hdfs 會把一個檔案切成很多 block。
* map:擷取與過濾資料。針對同一個檔案的不同 block。
* 每一個 map 都會產生小白區塊。
* shuffle 會把每一個小白區快 merged 成大白區塊,然後交給 reduce。
* merged:會把資料做分類跟排序。之後就產生大白資料。
* reduce:程式分析資料。分析好資料後會把檔案丟回 hdfs。
* 以上就是 MapReduce 資料處理引擎。
* 一個檔案切成多 block 好處:
- 因為大數據資料檔案一定很大,因此切成多區塊,在讀資料的時候會同時讀所有的 block 多台電腦同時共同作業(分散運算),因此速度一定快。
- 平衡附載。
* 一個檔案同一個 block 存成三份的好處:
- 可以有資料的容錯,並且有資料修復的功能,如果只有其中一個 block 被刪除,那這個 block 還可以被復原。
### 設定 MapReduce Job 的運算資源
```=!
$ cat $HADOOP_HOME/etc/hadoop/mapred-site.xml
..........
<property>
<name>mapreduce.reduce.memory.mb</name>
<value>512</value> # reduce 整個程式使用 512 記憶體大小,這個大小包含處理資料的記憶體大小
</property>
<property>
<name>mapreduce.reduce.java.opts</name>
<value>-Xmx384m</value> # reduce 處理資料用的記憶體大小
</property>
<property>
<name>mapreduce.map.memory.mb</name>
<value>384</value> # map 整個程式記憶體,這個大小包含處理資料的記憶體大小
</property>
<property>
<name>mapreduce.map.java.opts</name>
<value>-Xmx256m</value> # map 處理資料的記憶體大小
</property>
........
```
[註] 一般 reduce 設定為 map 的兩倍。Just make sure you set java.opts to 20-25% less than memory.mb
> 問題:為什麼 reduce 的記憶體空間比較大, map 比較小?
> 答:因為 map 要處理的 block 最大也只有 128m ,而 reduce 要做的是整個檔案的資料分析,因此一定比較大
### 設定 MapReduce Job 運算資源
設定 reduce 記憶體需求, 只需修改 dta1 主機的 mapred-site.xml 設定檔
```
$ sudo nano $HADOOP_HOME/etc/hadoop/mapred-site.xml
........
<property>
<name>mapreduce.reduce.memory.mb</name>
<value>1024</value> # 修改為 1024
</property>
<property>
<name>mapreduce.reduce.java.opts</name>
<value>-Xmx896m</value> # 修改為 896
</property>
........
```
### 設定 MapReduce Job 運算資源
```!
# 測試
$ yarn jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-${HADOOP_HOME##*-}.jar pi 2 100000
............
...... reduceResourceRequest: <memory:1024, vCores:1> maxContainerCapability:<memory:896, vCores:1>
Job received Kill while in RUNNING state.
```
* [註] 因 YARN 的 YARNChild 最大記憶體為 896M, 無法滿足 reduce 的要求, 使用 hadoop jar 命令執行上述運算, 如執行失敗, 不會出現錯誤訊息
```
$ sudo nano $HADOOP_HOME/etc/hadoop/mapred-site.xml
........
<property>
<name>mapreduce.reduce.memory.mb</name>
<value>512</value>
</property>
<property>
<name>mapreduce.reduce.java.opts</name>
<value>-Xmx384m</value>
</property>
........
```

* Node Manager 會把自己有多少硬體資源告訴 Resource Manager
> 問題:請問現在 yarn 總運算資源有多少?
> 答:實體主機也會需要cpu,記憶體,因此也要資源分配,記憶體打八折。CPU 可以多個程式使用同一個 core
> 記憶體:64*0.8=51.2 取整數 51
> CPU:12*2=24c


> 問題:現在系統規定一個 container 記憶體範圍定在 1024m~2048m,但是程式設計師他的程式規劃 map 和 reduce ,記憶體大小 384m 和 512m ,這樣這之程式一定不會過,如果是你請問會怎麼做?
> 答:直接把 map 和 reduce 的記憶體都改成 1024m。因為只有我們會知道mapred-site.XML這個檔案。
## bzip2

* 因為zip不能在切開的狀態下作解壓縮,所以必須把block 合起來才能做unzip 解壓縮。
* 因為Hadoop 是分散式處理,所以要先把block檔get 出linux ,才能作解壓縮動作

* BZIP2在壓縮時會以每100K為一個單位儲存
* Bzip2演算法於壓縮時,便會先以切割區塊(100K)的形式建立壓縮檔,後續使用hdfs dfs -put上傳 HDSF後,會被切成 blocks 分散儲存,其特性讓map可以直接處裡block的解壓縮 (能以區塊去解壓縮) 並記錄在shuffle,再 merge 成完整檔案交由 reduce 分析運算存回hdfs
### MapReduce 處理 bzip2 檔案 (一)
```!
$ hadoop fs -mkdir -p mydataset/sales
$ wget http://eforexcel.com/wp/wp-content/uploads/2017/07/1000000%20Sales%20Records.zip
$ unzip '1000000 Sales Records.zip'
$ dir '1000000 Sales Records.csv'
-rw-r--r-- 1 bigred bigred 120M 7月 29 2017 '1000000 Sales Records.csv'
$ head -n 3 1000000\ Sales\ Records.csv
Region,Country,Item Type,Sales Channel,Order Priority,Order Date,Order ID,Ship Date,Units Sold,Unit Price,Unit Cost,Total Revenue,Total Cost,Total Profit
Sub-Saharan Africa,South Africa,Fruits,Offline,M,7/27/2012,443368995,7/28/2012,1593,9.33,6.92,14862.69,11023.56,3839.13
Middle East and North Africa,Morocco,Clothes,Online,M,9/14/2013,667593514,10/19/2013,4611,109.28,35.84,503890.08,165258.24,338631.84
$ cat 1000000\ Sales\ Records.csv | grep Taiwan | wc -l
5483
```
### MapReduce 處理 bzip2 檔案 (二)
```
# 把 csv 檔壓縮成 bz2
# -k 壓縮完後原本的檔案還要存在
# -1 壓縮後的檔案每個要 100k
$ bzip2 -1 -kz '1000000 Sales Records.csv' -c > sales.bz2
-z --compress force compression
-k --keep keep (don't delete) input files
-1 .. -9 set block size to 100k .. 900k
$ dir sales.bz2
-rw-r--r-- 1 bigred bigred 30M 7月 28 09:14 sales.bz2
# -put 丟到 hdfs
# dfs.block.size=16m 對這個檔案每個 block 16m
# 這個檔案大小 30m 每個 block 存 16m 因此會存兩個 block
$ hadoop fs -D dfs.block.size=16m -put sales.bz2 mydataset/sales/
# 檢查這個檔案是否存兩個 block
$ hdfs fsck mydataset/sales/sales.bz2
......
Total blocks (validated): 2 (avg. block size 15386158 B) # 兩個 block
........
```
* bzip2 可 spiltable, 所以會用二個 Map Process 處理 bzip2 檔案內容, 因它有 2 個 Block
```!
$ yarn jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.3.jar grep mydataset/sales/ tmp/sales/ 'Taiwan'
$ hdfs dfs -ls tmp/sales/
Found 2 items
-rw-r--r-- 2 bigred bigboss 0 2020-07-08 04:48 /tmp/sales/_SUCCESS
-rw-r--r-- 2 bigred bigboss 12 2020-07-08 04:48 /tmp/sales/part-r-00000
$ hdfs dfs -cat tmp/sales/part-r-00000
5483 Taiwan
```
> 問題:一個檔案存到 hdfs ,那硬碟的需求會如何?
> 答:一個檔案存到 hdfs ,hdfs 會存三份,因此 1g 的資料存到 hdfs 就變成 3g。
> 問題:承上題,那要如何解決?
> 答:透過 bzip2 我先把原本 1t 的檔案做壓縮,變成大約 250g ,在丟到 hdfs ,因此在 hdfs 檔案大小才 750g ,並且最重要的是這個壓縮檔可以被 map 分析處理。
###### tags: `資料科技`