005 Kudu | Impala

Kudu可以完美的和Impala結合在一起使用,充分利用Impala提供的Insert,Update,Delete等語句。當然使用原生的Kudu API也是可以,只不過結果Impala標準SQL規(guī)范,可以利用JDBC等框架實現(xiàn)無縫的Kudu數(shù)據(jù)管理。

Kudu和Impala的打通,方式1)可以在Impala的服務配置文件加入--kudu_master_hosts=<master1>[:port],<master2>[:port],<master3>[:port],方式2)如果方式1不采用,可以通過創(chuàng)建impala創(chuàng)建kudu表的sql語句的TBLPROPERTIES 中加入,kudu_master_addresses property。

xx  PARTITION BY HASH (user_id) PARTITIONS 3                                                                                          |
 STORED AS KUDU                                                                                                                 
 TBLPROPERTIES ('kudu.table_name'='test', 'kudu.master_addresses'='localhost', 'kudu.num_tablet_replicas'='3')

Using Impala Shell

使用impala-shell命令,即可啟動shell,默認連接本機的21000端口,使用 -i host:port可以連接遠端的impala server, 使用-d <database> 可以指定連接后,打開的database。

Impala的內(nèi)部和外部表

顧名思義,內(nèi)部表,數(shù)據(jù)有impala管理,當通過impala刪除數(shù)據(jù)時候,數(shù)據(jù)就刪除了;而外部表impala不負責管理,刪除的時候,不會刪除數(shù)據(jù)真正存放的位置,而是簡單刪除impala和外部存儲源之間的映射關系,外部表通過create external xxx來創(chuàng)建

CREATE EXTERNAL TABLE my_mapping_table
STORED AS KUDU
TBLPROPERTIES (
  'kudu.table_name' = 'my_kudu_table'
);

kudu中通過kudu api或者spark等創(chuàng)建的表,無法直接被impala使用,需通過如上的語句完成impala和kudu表之間的映射。

從Impala創(chuàng)建Kudu表

和創(chuàng)建Kudu外部表類似,只不過你親自需要指定表的schema和分區(qū)信息,例如,

CREATE TABLE my_first_table
(
  id BIGINT,
  name STRING,
  PRIMARY KEY(id)
)
PARTITION BY HASH PARTITIONS 16
STORED AS KUDU;

主要以下幾點:

  1. store as kudu
  2. primary key的列放在第一位置,入id
  3. 被生成為primary key的列,潛在默認為not null

當create一個表的時候,你需要指定分區(qū)的方案,具體分區(qū)的知識點見下問,上述語句在主鍵id上分成了16個分區(qū)信息。

默認每個分區(qū)的副本數(shù)為3,可以通過create table語句中加入TBLPROPERTIES 描述來設定不同的副本數(shù),

TBLPROPERTIES ('kudu.num_tablet_replicas' = 'n')

其中n表示副本factor的個數(shù),且n必須為odd number,注意,在alter table中修改TBLPROPERTIES ('kudu.num_tablet_replicas' = 'n')目前無效

通過create table as select方式創(chuàng)建表,

CREATE TABLE new_table
PRIMARY KEY (ts, name)
PARTITION BY HASH(name) PARTITIONS 8
STORED AS KUDU
AS SELECT ts, name, value FROM old_table;

new_table的列自動推斷于select后面跟著的列,從old_table表中抽取數(shù)據(jù),生成新的表new_table并存儲于kudu中。

表的分區(qū)

Kudu中的table是分成多個tablet的,這些tablet,目前為止,kudu不支持自動以及手動的將已經(jīng)存在的tablet分割成多個tablet(Hbase可以實現(xiàn)region的自動分割),所以我們需要在創(chuàng)建表的時候,指定好分區(qū),那么數(shù)據(jù)在入庫的時候就會按照分區(qū)規(guī)則自動歸入到某個tablet中。

當create表時候,設置分區(qū)信息,需要根據(jù)primary key來設定分區(qū)的規(guī)則,primary key的hash方式,或者primary key的range方式。

CREATE TABLE cust_behavior (
  _id BIGINT PRIMARY KEY,
  salary STRING,
  edu_level INT,
  usergender STRING,
  `group` STRING,
  city STRING,
  postcode STRING,
  last_purchase_price FLOAT,
  last_purchase_date BIGINT,
  category STRING,
  sku STRING,
  rating INT,
  fulfilled_date BIGINT
)
PARTITION BY RANGE (_id)
(
    PARTITION VALUES < 1439560049342,
    PARTITION 1439560049342 <= VALUES < 1439566253755,
    PARTITION 1439566253755 <= VALUES < 1439572458168,
    PARTITION 1439572458168 <= VALUES < 1439578662581,
    PARTITION 1439578662581 <= VALUES < 1439584866994,
    PARTITION 1439584866994 <= VALUES < 1439591071407,
    PARTITION 1439591071407 <= VALUES
)
STORED AS KUDU;

Database

Kudu表默認在default數(shù)據(jù)庫中,在create表的時候,可以修改默認database,使用表的時候,需要加上database的前綴訪問數(shù)據(jù)庫,如,my_database::table_name

Kudu table不支持的Impala關鍵詞

  • PARTITIONED
  • LOCATION
  • ROWFORMAT

表分區(qū)

根據(jù)primary key來設置表的分區(qū),每個分區(qū)形成叫做tablet,每個tablet被一個或者多個tablet server管理,這些tablet均衡分布在多個tablet server中,形成負載支持訪問,具體的分區(qū)方案,需要根據(jù)數(shù)據(jù)類型和業(yè)務特點決定,兩種分區(qū)方案Hash和Range。

range分區(qū)

分區(qū)方案可以包含0個或者多個hash方式,后面跟著一個可選的range方案。range方案可以涉及1個或者多個primary key列。

CREATE TABLE customers (
  state STRING,
  name STRING,
  purchase_count int,
  PRIMARY KEY (state, name)
)
PARTITION BY RANGE (state)
(
  PARTITION VALUE = 'al',
  PARTITION VALUE = 'ak',
  PARTITION VALUE = 'ar',
  -- ... etc ...
  PARTITION VALUE = 'wv',
  PARTITION VALUE = 'wy'
)
STORED AS KUDU;

以上0個hash,后面跟著range
這里需要注意,當單調(diào)遞增的主鍵增長情況,如果使用range分區(qū)的方式,會出現(xiàn)一直只往一個tablet寫入的情況,限制了寫入的速率,即熱點寫問題,此時考慮使用hash的分區(qū),可以隨機的往不同的tablet寫入。

hash分區(qū)

替換range分區(qū)或者結合range分區(qū),hash分區(qū)可以通過指定筒的個數(shù),借助hash的方式,實現(xiàn)數(shù)據(jù)分筒。可以指定使用哪個primary key,以及分成多少個筒,數(shù)據(jù)會按照primary key的hash值分到不同的筒中。

可以使用多個hash分區(qū)策略,及時是復合的primary keys,但是,一個列,不能同時出現(xiàn)在多個hash分區(qū)規(guī)則中,例如,兩個列a,b,則,hash(a), hash(b)對,hash(a,b)對,hash(a),hash(a,b)錯,

如果hash方案沒有指定列,PARTITION BY HASH,則表明使用所有的primary keys作為hash方案,

Hash方案適合列的值在范圍內(nèi)分布均勻,或者很明顯不會出現(xiàn)數(shù)據(jù)傾斜,比如, timestamps or serial IDs。

下面的例子是通過未指定列的方式,實現(xiàn)16分區(qū),

CREATE TABLE cust_behavior (
  id BIGINT,
  sku STRING,
  salary STRING,
  edu_level INT,
  usergender STRING,
  `group` STRING,
  city STRING,
  postcode STRING,
  last_purchase_price FLOAT,
  last_purchase_date BIGINT,
  category STRING,
  rating INT,
  fulfilled_date BIGINT,
  PRIMARY KEY (id, sku)
)
PARTITION BY HASH PARTITIONS 16
STORED AS KUDU;

這個列子不是最好的方案,因為sku的range查詢會導致16個tablet都要參與查詢,以為分區(qū)是id和sku的混合。

高級的分區(qū)方案

結合hash和range,0個或者多個hash,構面跟著0個或者多個range。

hash和range結合方案

考慮上面那個不成熟的列子,我們可以結合hash和range方式,來優(yōu)化sku的范圍查找(假設我們經(jīng)常進行sku的范圍查找),

CREATE TABLE cust_behavior (
  id BIGINT,
  sku STRING,
  salary STRING,
  edu_level INT,
  usergender STRING,
  `group` STRING,
  city STRING,
  postcode STRING,
  last_purchase_price FLOAT,
  last_purchase_date BIGINT,
  category STRING,
  rating INT,
  fulfilled_date BIGINT,
  PRIMARY KEY (id, sku)
)
PARTITION BY HASH (id) PARTITIONS 4,
RANGE (sku)
(
  PARTITION VALUES < 'g',
  PARTITION 'g' <= VALUES < 'o',
  PARTITION 'o' <= VALUES < 'u',
  PARTITION 'u' <= VALUES
)
STORED AS KUDU;

上述代碼,通過id實現(xiàn)4個buckets,每個bucket根據(jù)sku的范圍又分成了4個部分,總共,也是16個tablet。二次sku分區(qū)的時候,其實可以理解為單獨的sku分區(qū),只不過事先按照id分成了四份而已,因為sku的分區(qū)相當于獨立一樣,故而范圍查找有優(yōu)勢,比hash(id,sku)同時分區(qū)打亂sku范圍好很多。寫入的時候,根據(jù)id的hash定位一次,然后按照sku的范圍寫入,使用id的hash方式,因為id值的特點,使用hash合適,可以保證data spread整個tablet中,避免數(shù)據(jù)傾斜;讀取的時候,畢竟sku是單獨分區(qū)的,所以16個tablet,在sku上每個tablet的sku有一定的范圍,故而,有機會縮小tablet查找數(shù)量(如果沒有給定id,則可以繞過id直接進行sku分區(qū),如果給定id,則直接定位1/4個bucket,再進行范圍sku查找)

hash和hash方式

如果對于sku的搜索模式無法預測,又想保證數(shù)據(jù)spread到整個tablet,可以采用多個hash方式在每個primary key上。

CREATE TABLE cust_behavior (
  id BIGINT,
  sku STRING,
  salary STRING,
  edu_level INT,
  usergender STRING,
  `group` STRING,
  city STRING,
  postcode STRING,
  last_purchase_price FLOAT,
  last_purchase_date BIGINT,
  category STRING,
  rating INT,
  fulfilled_date BIGINT,
  PRIMARY KEY (id, sku)
)
PARTITION BY HASH (id) PARTITIONS 4,
             HASH (sku) PARTITIONS 4
STORED AS KUDU;

未覆蓋的范圍分區(qū)

Kudu1.0或者更高支持未覆蓋的范圍分區(qū),此種情況一般發(fā)生在

  1. 時間序列或者持續(xù)遞增的primary key
  2. 產(chǎn)品類型等等,事先不知道具體的類型。

當我們讀取一個不存在的分區(qū),kudu會reject,提示,

CREATE TABLE sales_by_year (
  year INT, sale_id INT, amount INT,
  PRIMARY KEY (sale_id, year)
)
PARTITION BY RANGE (year) (
  PARTITION VALUE = 2012,
  PARTITION VALUE = 2013,
  PARTITION VALUE = 2014,
  PARTITION VALUE = 2015,
  PARTITION VALUE = 2016
)
STORED AS KUDU;

當我們,查詢2017的數(shù)據(jù)發(fā)現(xiàn)沒有,kudu會reject,此時,我們應該通過語句add新的分區(qū),

ALTER TABLE sales_by_year ADD RANGE PARTITION VALUE = 2017;

當然,每個range范圍不需要了,也可以刪除

ALTER TABLE sales_by_year DROP RANGE PARTITION VALUE = 2012;

Insert Data

標準的SQL語句方式

Insert Single Values

插入一條數(shù)據(jù)

INSERT INTO my_first_table VALUES (99, "sarah");

在同一個語句中插入多行數(shù)據(jù)

INSERT INTO my_first_table VALUES (1, "john"), (2, "jane"), (3, "jim");

Insert In Bulk

有幾種方式,各有好壞

  1. Multiple single INSERT statements:多個insert sql語句放在一起執(zhí)行,顯然會影響系統(tǒng)吞吐率
  2. Single INSERT statement with multiple VALUES:一條語句中加入多個value,當我們累加到1024個value list后,impala會將1024個value list組織到一起,請求kudu,顯然比方案1號。并且通過更改當前impala shell session對應的batch_size來改變1024這個默認值,增大batch的size大小。
  3. Batch Insert:借助insert語句,如下語句,第一步,如果數(shù)據(jù)不在impala或者kudu中,通過文件的形式映射成一張表,第二步,創(chuàng)建新的表,注意primary key非空對應原始文件中的數(shù)據(jù)不能為空,第三步,執(zhí)行語句如下。
INSERT INTO my_kudu_table
  SELECT * FROM legacy_data_import_table;
  1. Ingest using the C++ or Java API

插入主鍵重復數(shù)據(jù)

不會報錯,但是會報警,后面的語句繼續(xù)被執(zhí)行。

Upsert

如果數(shù)據(jù)不存在則插入,否則為更新,可以使用upsrt語句

INSERT INTO my_first_table VALUES (99, "sarah");
UPSERT INTO my_first_table VALUES (99, "zoe");
-- the current value of the row is 'zoe'

Update/Delete/Drop table

ignore

SQL Failed

insert,update,delete等語句,不支持事物,batch語句,由于沒有事物控制,當中間出錯,前面的失效了,后面的忽略了。

修改表的屬性

修改表名

ALTER TABLE my_table RENAME TO my_new_table;

修改Impala內(nèi)部表對應的底層kudu表

ALTER TABLE my_internal_table
SET TBLPROPERTIES('kudu.table_name' = 'new_name')

修改Impala外部表映射到不同的kudu表

ALTER TABLE my_external_table_
SET TBLPROPERTIES('kudu.table_name' = 'some_other_kudu_table')

修改表的kudu master地址

ALTER TABLE my_table
SET TBLPROPERTIES('kudu.master_addresses' = 'kudu-new-master.example.com:7051');

內(nèi)部表改為外部表

ALTER TABLE my_table SET TBLPROPERTIES('EXTERNAL' = 'TRUE');
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容