文章目錄
表的優化
- 在表的優化中, 當數據量較大的時候常用的手段就是拆分表, 大表拆小表, 分區表, 臨時表, 外部表
- 小表和大表的join, 要把數據量小的表放在join的左邊, 先進行緩存, 這樣會減少表join的時候內存的消耗量
數據傾斜
數據傾斜產生的原因爲分區之後某一個reduce運算的數據量比較小, 而某一個reduce運行的數據量比較大, 造成兩個reduce處理數據不平等
合理設置map數量
可以影響map的數量的因素
在input文件夾中, 每一個文件就是一個map. input文件的數量, input文件的大小都會影響map的數量, 在mapreduce任務中, 一個切片就是一個map任務, 在Driver中設置如下:
FileInputFormat.setMaxInputSplitSize(job, size);
FileInputFormat.setMinInputSplitSize(job, size);
合理設置reduce數量
設置reduce個數:
hive (default)> set mapreduce.job.reduces;
mapreduce.job.reduces=-1
//默認爲-1, 就是不設置reduce的個數
根據業務自定分區規則
並行執行
並行執行與java多線程的異步和同步概念差不多, 在MR運行任務中, 存在很多的MR任務可以進行執行, 有些MR任務和下一個MR任務存在依賴關係, 但是有些MR任務沒有依賴關係. 例如: 存在依賴關係的MR, 一個MR任務的輸出就是下一個MR任務的輸入. 對於沒有依賴關係的MR任務可以使用並行執行, 在同一時間運行多個MR任務, 這樣在運行的過程中效率就會得到提升.
可以通過以下參數來設置
- 開啓並行任務
hive (default)> set hive.exec.parallel;
hive.exec.parallel=false
---------------------------------------
set hive.exec.parallel=true;
- 設置多少個任務可以同時運行
hive (default)> set hive.exec.parallel.thread.number;
hive.exec.parallel.thread.number=8
//默認值爲8個任務可以同時執行
嚴格模式
hive中提供有嚴格模式, 爲了防止一些查詢出現不好的影響, 例如笛卡爾積, 在嚴格模式下是不能運行的.
默認的嚴格模式設置:
<property>
<name>hive.mapred.mode</name>
<value>nonstrict</value>
<description>
The mode in which the Hive operations are being performed.
In strict mode, some risky queries are not allowed to run. They include:
Cartesian Product.
No partition being picked up for a query.
Comparing bigints and strings.
Comparing bigints and doubles.
Orderby without limit.
</description>
</property>
//默認值爲非嚴格模式 : nonstrict
開啓嚴格模式 : strict
開啓了嚴格模式會對查詢語句進行一些限制:
- 對於分區表: 必須存在where語句對分區表中的分區字段進行條件過濾, 否則不允許執行該查詢.
- 對於使用order by: 當使用orderby語句時, 必須使用limit進行限定, 由於orderby之後所有的數據都會被分到一個reduce中, 這樣reduce操作的數據量太大, 可能時間過長, 導致卡死, 所以爲了防止出現這種情況, 在orderby的時候必須給定limit限制, 減少reduce處理的數據量
- 笛卡爾積查詢: 在多表join中會出現笛卡爾積, 笛卡爾積灰造成內存的加大消耗, 爲了防止這種情況, 禁止使用笛卡爾積查詢, 同時防止誤操作
JVM重用
在hive執行計算任務的時候, 會把執行計劃上傳到YARN集羣中進行提交, 運行MR任務, 每次進行任務的運行的時候都會開啓一個JVM進程運行MR任務, 如果提交任務頻繁過多, 就會造成JVM頻繁的開啓和關閉, 在JVM的開啓和關閉的過程中會造成大量的資源浪費.
在處理小文件的時候, 由於map任務較多, 所以JVM或頻繁的開啓和關閉, 所以對於小文件的處理優化, 主要減少JVM開啓的次數
在mapred-default.xml配置文件中有如下參數:
<property>
<name>mapreduce.job.jvm.numtasks</name>
<value>10</value>
<description>How many tasks to run per jvm. If set to -1, there is
no limit.
</description>
</property>
在hive中臨時設置JVM重用任務的數量
hive (default)> set mapreduce.job.jvm.numtasks;
mapreduce.job.jvm.numtasks=1
推測執行
由於集羣中的資源分配不均等, 或者說每個集羣中節點硬件性能會導致某個任務運行的時間快, 或者某個任務運行時間慢, 或者某個任務運行時直接卡死.
爲了防止某些任務在運行過程中拖慢了整個MR任務的進度, 在運行慢的任務節點上, 開啓相同的任務, 如果時間比原來的任務運行的快, 則直接輸出推測的任務.
注意 : 推測執行分爲map端的推測執行以及reduce端的推測執行
map端
設置開啓map端推測執行的參數:
<property>
<name>mapreduce.map.speculative</name>
<value>true</value>
<description>If true, then multiple instances of some map tasks
may be executed in parallel.</description>
</property>
在hadoop中默認開啓推測執行, 推測執行不是說一卡死就開啓推測任務, 而是必須要運行到5%以上纔開啓推測執行
在hive中通過set設置
hive (default)> set mapreduce.map.speculative;
mapreduce.map.speculative=true
reduce端
設置開啓reduce端推測執行的參數:
<property>
<name>mapreduce.reduce.speculative</name>
<value>true</value>
<description>If true, then multiple instances of some reduce tasks
may be executed in parallel.</description>
</property>
在hive中通過set設置
hive (default)> set mapreduce.reduce.speculative;
mapreduce.reduce.speculative=true
執行計劃—查看SQL語句的執行過程
hive中提供可以查看hql語句的執行計劃 , 在執行計劃中會生成抽象語法樹, 在語法樹中會顯示hql語句之間的以來關係以及執行過程. 通過這些執行的過程和以來關係可以對hql語句進行優化
explain + 執行語句
------------------------------------------------
hive (default)> explain select * from emp;
OK
Explain
STAGE DEPENDENCIES:
Stage-0 is a root stage
STAGE PLANS:
Stage: Stage-0
Fetch Operator
limit: -1
Processor Tree:
TableScan
alias: emp
Statistics: Num rows: 2 Data size: 653 Basic stats: COMPLETE Column stats: NONE
Select Operator
expressions: empno (type: int), ename (type: string), job (type: string), mgr (type: int), edate (type: string), sal (type: double), deptno (type: int)
outputColumnNames: _col0, _col1, _col2, _col3, _col4, _col5, _col6
Statistics: Num rows: 2 Data size: 653 Basic stats: COMPLETE Column stats: NONE
ListSink
Time taken: 0.127 seconds, Fetched: 17 row(s)
一般來說都會把複雜語句簡單化處理, 例如多表的join
虛擬列
虛擬列本身是一個不存在的列, 在數據查詢的時候, 可以通過虛擬列查詢數據的路徑, 以及數據的偏移量, 這兩個都是hive中爲用戶提供的虛擬列進行的查詢
INPUT__FILE__NAME : 數據文件的保存路徑
通過查詢得到文件的保存路徑
select ename, INPUT__FILE__NAME from emp;
SMITH hdfs://ns1/user/hive/warehouse/emp/emp.txt
ALLEN hdfs://ns1/user/hive/warehouse/emp/emp.txt
WARD hdfs://ns1/user/hive/warehouse/emp/emp.txt
JONES hdfs://ns1/user/hive/warehouse/emp/emp.txt
MARTIN hdfs://ns1/user/hive/warehouse/emp/emp.txt
BLAKE hdfs://ns1/user/hive/warehouse/emp/emp.txt
CLARK hdfs://ns1/user/hive/warehouse/emp/emp.txt
SCOTT hdfs://ns1/user/hive/warehouse/emp/emp.txt
KING hdfs://ns1/user/hive/warehouse/emp/emp.txt
TURNER hdfs://ns1/user/hive/warehouse/emp/emp.txt
ADAMS hdfs://ns1/user/hive/warehouse/emp/emp.txt
JAMES hdfs://ns1/user/hive/warehouse/emp/emp.txt
FORD hdfs://ns1/user/hive/warehouse/emp/emp.txt
MILLER hdfs://ns1/user/hive/warehouse/emp/emp.txt
BLOCK__OFFSET__INSIDE__FILE : 得到數據文件的偏移量信息
通過虛擬裏得到數據的偏移量
select ename ,BLOCK__OFFSET__INSIDE__FILE from emp;
ename block__offset__inside__file
SMITH 0
ALLEN 44
WARD 97
JONES 149
MARTIN 194
BLAKE 249
CLARK 294
SCOTT 339
KING 385
TURNER 429
ADAMS 480
JAMES 524
FORD 567
MILLER 612
安裝配置mysql
由於hive中默認的元數據保存在derby中只能單用戶訪問hive , 則另一用戶無法訪問, 會出現以下錯誤信息:
Caused by: ERROR XSDB6: Another instance of Derby may have already booted the database /opt/app/apache-hive-1.2.1-bin/metastore_db.
爲了解決以上的問題, 可以把hive的元數據保存在mysql中.
mysql的安裝步驟
- 在Linux系統中,可能存在mysql的安裝包, 所以第一步先檢查是否安裝過mysql
[hadoop@hadoop apache-hive-1.2.1-bin]$ rpm -qa | grep -i mysql
mysql-libs-5.1.73-5.el6_6.x86_64
執行該命令可以查看是否安裝mysql
- 卸載已有的mysql安裝包
[hadoop@hadoop apache-hive-1.2.1-bin]$ sudo rpm -e --nodeps mysql-libs-5.1.73-5.el6_6.x86_64
[sudo] password for hadoop:
- 查看是否卸載成功
[hadoop@hadoop apache-hive-1.2.1-bin]$ rpm -qa | grep -i mysql
[hadoop@hadoop apache-hive-1.2.1-bin]$
- mysql分爲server端和client端
MySQL-client-5.5.47-1.linux2.6.x86_64.rpm
MySQL-server-5.5.47-1.linux2.6.x86_64.rpm
-
安裝mysql軟件
通過rpm安裝server
sudo rpm -ivh MySQL-server-5.5.47-1.linux2.6.x86_64.rpm
通過rpm安裝client
sudo rpm -ivh MySQL-client-5.5.47-1.linux2.6.x86_64.rpm
- 查看mysql的運行狀態
sudo service mysql status
- 啓動mysql服務
[root@hadoop mysql]# service mysql start
Starting MySQL.. SUCCESS!
- 再次查看mysql運行狀態
SUCCESS! MySQL running (5094)
設置密碼,遠程授權
設置密碼
- mysql安裝好之後進入mysql
mysql -uroot
- 查詢數據庫
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
+--------------------+
4 rows in set (0.01 sec)
- 切換mysql數據庫
mysql> use mysql;
Database changed
- 查看user, host, passWord信息
mysql> select user,host,password from user;
+------+-----------+----------+
| user | host | password |
+------+-----------+----------+
| root | localhost | |
| root | hadoop | |
| root | 127.0.0.1 | |
| root | ::1 | |
| | localhost | |
| | hadoop | |
+------+-----------+----------+
6 rows in set (0.00 sec)
- 設置mysql密碼
mysql> update user set password=PASSWORD('root') where user='root';
Query OK, 4 rows affected (0.00 sec)
Rows matched: 4 Changed: 4 Warnings: 0
- 修改密碼之後, 查詢user表內容如下,說明在本地已經成功設置好了密碼
mysql> select user,host,password from user;
+------+-----------+-------------------------------------------+
| user | host | password |
+------+-----------+-------------------------------------------+
| root | localhost | *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B |
| root | hadoop | *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B |
| root | 127.0.0.1 | *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B |
| root | ::1 | *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B |
| | localhost | |
| | hadoop | |
+------+-----------+-------------------------------------------+
6 rows in set (0.00 sec)
設置遠程授權
- 通過新設置的密碼登錄mysql, 發現遇到如下問題, 說明用戶名或密碼不正確
[root@hadoop mysql]# mysql -uroot -proot
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
在user表中存在字段host , 該字段表示可以訪問mysql的路徑地址, 從哪個節點可以訪問, 有這個字段來決定
- 所以要授權遠程登錄, 則需要修改host字段, 增加一條信息, 表示任意節點都可以訪問mysql, 用%來表示任意
mysql> update user set host='%' where user='root' and host='127.0.0.1';
- 完成以上語句後, 需要對修改的user進行刷新來生效語句操作
mysql> flush privileges;
- 完成以上操作之後驗證mysql用戶登錄,可以登錄成功
[root@hadoop mysql]# mysql -uroot -proot
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 6
Server version: 5.5.47 MySQL Community Server (GPL)
Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
配置hive元數據保存在mysql
需要在hive-site.xml配置文件總進行配置
- 設置hive鏈接mysql
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://192.168.91.100:3306/metastore?createDatabaseIfNotExist=true</value>
<description>JDBC connect string for a JDBC metastore</description>
</property>
metastore: 默認保存hive中的元數據, 是一個數據庫的名字
- 設置jdbc的驅動類
<property>
<name>javax.jdo.option.ConnectionDriverName</name>
<value>com.mysql.jdbc.Driver</value>
<description>Driver class name for a JDBC metastore</description>
</property>
- 設置mysql的用戶名
<property>
<name>javax.jdo.option.ConnectionUserName</name>
<value>root</value>
<description>Username to use against metastore database</description>
</property>
- 設置mysql的密碼
<property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>root</value>
<description>password to use against metastore database</description>
</property>
- 完成以上的配置之後, 需要在hive/lib下邊存放jdbc的驅動包, 上傳好驅動包之後最好修改權限
sudo chown -R hadoop:hadoop mysql-connector-java-5.1.31.jar
- 將驅動包拷貝到hive目錄下的lib文件夾
cp mysql-connector-java-5.1.31.jar /opt/app/apache-hive-1.2.1-bin/lib/
-
到hive的lib下檢查是否拷貝成功
-
配置完成, 退出hive重新進入, 檢查mysql中是否創建了metastore數據庫, 如果創建成功, 則說明配置成功
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| metastore |
| mysql |
| performance_schema |
| test |
+--------------------+
hiveserver2
1. beeline方式的連接
相當於在hive中啓動一個服務器端, 客戶端可以遠程連接該hive, hiveserver2不用安裝, 直接在hive/bin目錄下啓動
bin/hiveserver2
hiveserver2的服務啓動之後, 可以通過bin/beeline客戶端進行連接
官方實例:
!connect jdbc:hive2://localhost:10000 scott tiger
按照官方提供實例, 連接hiveserver2 測試能否連接成功
!connect jdbc:hive2://hadoop:10000 hadoop 123456
2. jdbc的方式連接
package org.hive.server;
import java.sql.SQLException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.DriverManager;
public class HiveJdbcClient {
private static String driverName = ""org.apache.hive.jdbc.HiveDriver"";
/**
* @param args
* @throws SQLException
*/
public static void main(String[] args) throws SQLException {
try {
Class.forName(driverName);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.exit(1);
}
//replace ""hive"" here with the name of the user the queries should run as
Connection con = DriverManager.getConnection(""jdbc:hive2://10.0.152.235:10000/default"", ""hive"", """");
Statement stmt = con.createStatement();
String sql = ""show tables"";
System.out.println(""Running: "" + sql);
ResultSet res = stmt.executeQuery(sql);
if (res.next()) {
System.out.println(res.getString(1));
}
}
}