본문 바로가기
개발/Hadoop eco-system

CDH6 HBase2 X Impala2 쿼리 튜닝

by 달사쿠 2021. 11. 11.
반응형

Cloudera 공식 문서의 impala_hbase 를 번역했습니다.

 

Using Impala to Query HBase Tables | 6.3.x | Cloudera Documentation

The Impala INSERT statement works for HBase tables. The INSERT ... VALUES syntax is ideally suited to HBase tables, because inserting a single row is an efficient operation for an HBase table. (For regular Impala tables, with data files in HDFS, the tiny d

docs.cloudera.com

 


HBase 열에 지원되는 데이터 유형

HBase 테이블에 대한 Impala 쿼리의 최상의 성능을 위해, 대부분의 쿼리는 HBase row key에 해당하는 column에 대해 WHERE 절에서 비교를 수행합니다. Hive shell을 통해 테이블을 생성할 때, HBase row key에 해당하는 column은 STRING 데이터 유형을 사용합니다. Impala는 이 열에 대한 조건자를 (=, < 및 BETWEEN과 같은 연산자를 통해) HBase의 빠른 조회로 변환할 수 있지만 이 최적화("predicate pushdown")는 해당 열이 STRING으로 정의된 경우에만 작동합니다.


Impala-HBase 통합을 위한 성능 고려 사항

HBase에 저장된 데이터에 대한 SQL 쿼리의 성능 특성을 이해하려면, 먼저 HBase가 SQL 지향 시스템과 상호 작용하는 방법에 대한 배경 지식이 있어야 합니다. Impala는 Hive와 동일한 메타스토어 데이터베이스를 공유하기 때문에 Hive 테이블의 열을 HBase 테이블로 매핑하는 정보는 일반적으로 Impala에도 적용됩니다. Impala는 JNI(Java Native Interface)를 통해 HBase 클라이언트 API를 사용하여 HBase에 저장된 데이터를 쿼리합니다. 이 쿼리는 HFiles를 직접 읽지 않습니다. 추가 통신 오버헤드로 인해 HBase 또는 HDFS에 저장할 데이터를 선택하고 HBase 데이터를 효율적으로 검색할 수 있는 효율적인 쿼리를 구성하는 것이 중요합니다.

  • single row 또는 작은 범위의 rows을 반환하는 쿼리에 HBase 테이블을 사용하십시오. 전체 테이블의 전체 테이블 scan을 수행하는 쿼리에서는 사용하지 마세요.  (쿼리에 HBase 테이블이 있고 해당 테이블을 참조하는 WHERE 절이 없는 경우, 이는 HBase 테이블에 대한 비효율적인 쿼리라는 강력한 지표입니다.)
  • HBase는 모든 쿼리에 대해 전체 테이블 sacn을 실행하는 것이 충분히 효율적일 만큼 테이블이 작은 경우, 작은 dimension table을 저장하는 데 적합한 성능을 제공할 수 있습니다. 그러나 Kudu는 dimension table을 저장하는 우수한 대안입니다. HDFS table은 업데이트 쿼리, 쿼리 삭제 또는 행 수가 적은 삽입 쿼리를 지원할 필요가 없는 dimension table에도 적합합니다.

쿼리 조건자는 row key에 start 및 stop key로 적용되어 특정 조회의 범위를 제한합니다. rowkey가 string columns에 매핑되지 않으면, 일반적으로 순서가 잘못되고 비교 작업이 작동하지 않습니다. 예를 들어 row key가 string column에 매핑되지 않은 경우 초과(>) 또는 미만(<) evaluation을 완료할 수 없습니다.

 

non-key columns에 대한 predicate(술어)는 HBase로 보내서 SingleColumnValueFilters로 스캔하여 일부 성능 향상을 제공할 수 있습니다. 이러한 경우, HBase는 Impala를 사용하여 동일한 predicate를 적용한 경우보다 더 적은 rows을 리턴합니다. 몇 가지 개선 사항이 있지만 start/stop row을 사용할 때는 그다지 좋지 않습니다. HBase가 검사해야 하는 행의 수는 start/stop row을 사용할 때와 같이 제한이 없기 때문입니다. row key 술어가 단일 행에만 적용되는 한 HBase는 해당 row을 찾아 반환합니다. 반대로 non-key 술어가 사용되면, 단일 row에만 적용되더라도 HBase는 올바른 결과를 찾기 위해 전체 테이블을 계속 scan해야 합니다.

 

 


HBase 쿼리에 대한 EXPLAIN 출력 해석

다음은 HBase 테이블에 매핑된 다음 Impala 테이블에 대한 몇 가지 쿼리입니다.

예제는 EXPLAIN 문의 출력에서 ​​발췌한 내용을 보여주며 HBase 테이블에 대해 효율적이거나 비효율적인 쿼리를 나타내기 위해 무엇을 찾아야 하는지 보여줍니다. 첫 번째 column(cust_id)이 CREATE EXTERNAL TABLE 문에서 row key로 지정되었습니다. 성능을 위해 이 column을 STRING으로 선언하는 것이 중요합니다. BIRTH_YEARNEVER_LOGGED_ON과 같은 다른 column도 Impala가 HBase 테이블에서 이러한 type을 보다 효과적으로 최적화할 수 있기 때문에, INT나 BOOLEAN이 더 자연스러울 수 있지만, STRING으로 선언합니다. 비교를 위해 YEAR_REGISTERED column 하나를 INT로 남겨 이 column에 대한 필터링이 비효율적임을 보여주겠습니다.

describe hbase_table;
Query: describe hbase_table
+-----------------------+--------+---------+
| name                  | type   | comment |
+-----------------------+--------+---------+
| cust_id               | string |         |
| birth_year            | string |         |
| never_logged_on       | string |         |
| private_email_address | string |         |
| year_registered       | int    |         |
+-----------------------+--------+---------+

 

성능을 위한 최상의 경우는 row key로 정의된 column에 대한 equality comparison(동등 비교)를 사용하는 단일 row 조회입니다.

explain select count(*) from hbase_table where cust_id = 'some_user@example.com';
+------------------------------------------------------------------------------------+
| Explain String                                                                     |
+------------------------------------------------------------------------------------+
| Estimated Per-Host Requirements: Memory=1.01GB VCores=1                            |
| WARNING: The following tables are missing relevant table and/or column statistics. |
| hbase.hbase_table                                                                  |
|                                                                                    |
| 03:AGGREGATE [MERGE FINALIZE]                                                      |
| |  output: sum(count(*))                                                           |
| |                                                                                  |
| 02:EXCHANGE [PARTITION=UNPARTITIONED]                                              |
| |                                                                                  |
| 01:AGGREGATE                                                                       |
| |  output: count(*)                                                                |
| |                                                                                  |
| 00:SCAN HBASE [hbase.hbase_table]                                                  |
|    start key: some_user@example.com                                                |
|    stop key: some_user@example.com\0                                               |
+------------------------------------------------------------------------------------+

 

반응형

다른 유형의 효율적인 쿼리는 크거나(같음), 작거나(같음) 또는 BETWEEN과 같은 SQL 연산자를 사용하여 row key column에 대한 범위 조회를 포함합니다. 이 예제에는 key가 아닌 column에 대한 동등성 테스트도 포함됩니다. 해당 열이 STRING이기 때문에 Impala는 HBase가 EXPLAIN 출력의 hbase filters: 행으로 표시된 해당 테스트를 수행하도록 할 수 있습니다. HBase 내에서 필터링을 수행하는 것은 모든 데이터를 Impala로 전송하고 Impala 측에서 필터링을 수행하는 것보다 더 효율적입니다.

explain select count(*) from hbase_table where cust_id between 'a' and 'b'
  and never_logged_on = 'true';
+------------------------------------------------------------------------------------+
| Explain String                                                                     |
+------------------------------------------------------------------------------------+
...

| 01:AGGREGATE                                                                       |
| |  output: count(*)                                                                |
| |                                                                                  |
| 00:SCAN HBASE [hbase.hbase_table]                                                  |
|    start key: a                                                                    |
|    stop key: b\0                                                                   |
|    hbase filters: cols:never_logged_on EQUAL 'true'                                |
+------------------------------------------------------------------------------------+

 

Impala는 전체 HBase 테이블을 scan해야 하기 때문에, Impala가 술어를 평가해야 하는 경우 쿼리가 덜 효율적입니다. Impala는 STRING으로 선언된 column에 대해서만 술어를 HBase로 push down할 수 있습니다. 이 예는 INT로 선언된 열을 테스트하고 EXPLAIN 출력의 predicates: 은 데이터가 Impala로 전송된 후 테스트가 수행되었음을 나타냅니다.

explain select count(*) from hbase_table where year_registered = 2010;
+------------------------------------------------------------------------------------+
| Explain String                                                                     |
+------------------------------------------------------------------------------------+
...

| 01:AGGREGATE                                                                       |
| |  output: count(*)                                                                |
| |                                                                                  |
| 00:SCAN HBASE [hbase.hbase_table]                                                  |
|    predicates: year_registered = 2010                                              |
+------------------------------------------------------------------------------------+

 

key column이 상수가 아닌 값과 비교되는 경우에도 동일한 비효율성이 적용됩니다. 여기서 key column이 STRING이고 등호 연산자를 사용하여 테스트되더라도, key column은 상수가 아닌 다른 column 값과 비교되기 때문에 Impala는 전체 HBase 테이블을 스캔해야 합니다.

explain select count(*) from hbase_table where cust_id = private_email_address;
+------------------------------------------------------------------------------------+
| Explain String                                                                     |
+------------------------------------------------------------------------------------+
...

| 01:AGGREGATE                                                                       |
| |  output: count(*)                                                                |
| |                                                                                  |
| 00:SCAN HBASE [hbase.hbase_table]                                                  |
|    predicates: cust_id = private_email_address                                    |
+------------------------------------------------------------------------------------+

 

현재 OR 또는 IN 절을 사용하는 row key에 대한 테스트도 직접 조회에 최적화되어 있지 않습니다. 이러한 제한은 나중에 개선될 수 있으므로 항상 EXPLAIN 출력을 확인하여 특정 SQL 구성이 HBase 테이블에 대해 효율적인 쿼리를 생성하는지 여부를 확인하십시오.

explain select count(*) from hbase_table where
  cust_id = 'some_user@example.com' or cust_id = 'other_user@example.com';
+----------------------------------------------------------------------------------------+
| Explain String                                                                         |
+----------------------------------------------------------------------------------------+
...

| 01:AGGREGATE                                                                           |
| |  output: count(*)                                                                    |
| |                                                                                      |
| 00:SCAN HBASE [hbase.hbase_table]                                                      |
|    predicates: cust_id = 'some_user@example.com' OR cust_id = 'other_user@example.com' |
+----------------------------------------------------------------------------------------+

explain select count(*) from hbase_table where
  cust_id in ('some_user@example.com', 'other_user@example.com');
+------------------------------------------------------------------------------------+
| Explain String                                                                     |
+------------------------------------------------------------------------------------+
...

| 01:AGGREGATE                                                                       |
| |  output: count(*)                                                                |
| |                                                                                  |
| 00:SCAN HBASE [hbase.hbase_table]                                                  |
|    predicates: cust_id IN ('some_user@example.com', 'other_user@example.com')      |
+------------------------------------------------------------------------------------+

 

각 값에 대해 별도의 쿼리로 다시 작성하고 애플리케이션에서 결과를 결합하거나 UNION ALL을 사용하여 단일 행 쿼리를 결합합니다.

select count(*) from hbase_table where cust_id = 'some_user@example.com';
union all
select count(*) from hbase_table where cust_id = 'other_user@example.com';

explain
  select count(*) from hbase_table where cust_id = 'some_user@example.com'
  union all
  select count(*) from hbase_table where cust_id = 'other_user@example.com';
+------------------------------------------------------------------------------------+
| Explain String                                                                     |
+------------------------------------------------------------------------------------+
...

| |  04:AGGREGATE                                                                    |
| |  |  output: count(*)                                                             |
| |  |                                                                               |
| |  03:SCAN HBASE [hbase.hbase_table]                                               |
| |     start key: other_user@example.com                                            |
| |     stop key: other_user@example.com\0                                           |
| |                                                                                  |
| 10:MERGE                                                                           |
...

| 02:AGGREGATE                                                                       |
| |  output: count(*)                                                                |
| |                                                                                  |
| 01:SCAN HBASE [hbase.hbase_table]                                                  |
|    start key: some_user@example.com                                                |
|    stop key: some_user@example.com\0                                               |
+------------------------------------------------------------------------------------+

 


Java HBase 애플리케이션에 대한 구성 옵션

org.apache.hadoop.hbase.client.Scan 클래스의 setCacheBlocks 또는 setCaching 메소드를 호출하는 HBase Java 애플리케이션이 있는 경우, Impala 쿼리 옵션을 통해 이와 동일한 캐싱 동작을 설정하여 HBase RegionServer의 memory pressure을 제어할 수 있습니다.

예를 들어, HBase에서 쿼리를 수행하여 전체 테이블 scan(기본적으로 HBase에 비효율적임)을 수행할 때 HBASE_CACHE_BLOCKS 설정을 끄고, HBASE_CACHING 설정에 큰 수를 지정하여 메모리 사용량을 줄이고 쿼리 속도를 높일 수 있습니다.

 

이러한 옵션을 설정하려면 impala-shell에서 다음과 같은 명령을 실행하세요.

-- Same as calling setCacheBlocks(true) or setCacheBlocks(false).
set hbase_cache_blocks=true;
set hbase_cache_blocks=false;

-- Same as calling setCaching(rows).
set hbase_caching=1000;

또는 임팔라 기본 파일 /etc/default/impala를 업데이트하고 IMPALA_SERVER_ARGS에 대한 -default_query_options 설정에 HBASE_CACHE_BLOCKS 및/또는 HBASE_CACHING에 대한 설정을 포함합니다. 자세한 내용은 Impala 시작 옵션 수정을 참조하십시오.


Impala를 통한 HBase 쿼리 사용 사례

  • HBase를 사용하여 웹 페이지를 본 횟수 또는 소셜 네트워크에서 사용자의 연결 수 또는 게시물이 받은 투표 수와 같이 빠르게 증가하는 카운터를 저장합니다. HBase는 변경 가능한 데이터를 캡처하는 데 효율적입니다. 추가 전용 저장 메커니즘은 각 변경 사항을 디스크에 기록하는 데 효율적이고 쿼리는 항상 최신 값을 반환합니다. 애플리케이션은 HBase에서 이와 같은 특정 합계를 쿼리하고 결과를 Impala에서 쿼리한 광범위한 데이터 세트와 결합할 수 있습니다.
  • HBase에 매우 넓은 테이블을 저장합니다. 넓은 테이블에는 일반적으로 온라인 서비스 사용자와 같은 중요한 주제에 대한 많은 속성을 기록하는 많은 열, 아마도 수천이 있습니다. 이러한 테이블은 종종 희소합니다. 즉, 대부분의 열 값은 NULL, 0, false, 빈 문자열 또는 기타 빈 또는 자리 표시자 값입니다. (예를 들어, 특정 웹 사이트 사용자는 프로필의 특정 필드를 채우고, 사이트의 특정 부분을 방문하는 등의 사이트 기능을 한 번도 사용하지 않았을 수 있습니다.) 이러한 종류의 테이블에 대한 일반적인 쿼리는 일반적인 Impala 관리 테이블에서처럼 수백만 개의 행을 합산, 평균화 또는 필터링하는 대신 단일 행을 위로 올려 특정 주제에 대한 모든 정보를 검색합니다.

 


HBase 테이블에 데이터 load

Impala INSERT 문은 HBase 테이블에서 작동합니다. INSERT ... VALUES 구문은 HBase 테이블에 이상적으로 적합합니다. 단일 row을 삽입하는 것이 HBase 테이블에 대한 효율적인 작업이기 때문입니다. (HDFS에 데이터 파일이 있는 일반 Impala 테이블의 경우 INSERT ... VALUES에 의해 생성된 작은 데이터 파일은 매우 비효율적이므로 중요한 데이터 볼륨이 포함된 테이블에는 이 기술을 사용하지 않습니다.) INSERT ... SELECT 구문을 사용할 때 HBase 테이블의 결과는 예상보다 적은 수의 행이 될 수 있습니다. HBase는 각 고유 행 키의 최신 버전만 저장하므로 INSERT ... SELECT 문이 키 열에 대해 동일한 값을 포함하는 여러 행에 복사하는 경우 후속 쿼리는 각 키 열 값이 있는 하나의 행만 반환합니다. Impala에는 UPDATE 문이 없지만 매번 키 열에 대해 동일한 값을 사용하여 연속적인 INSERT 문을 수행하여 동일한 효과를 얻을 수 있습니다.

 


Impala 및 HBase 통합의 제한 사항과 제약 사항

HBase와의 Impala 통합에는 다음과 같은 제한 사항이 있으며, 일부는 HBase와 Hive 간의 통합에서 상속되고 일부는 Impala에 고유합니다.

  • HBase 테이블에 매핑된 내부(Impala 관리) 테이블에 대해 DROP TABLE을 발행하면 기본 테이블이 HBase에서 제거되지 않습니다. Hive DROP TABLE 문은 이 경우에도 HBase 테이블을 제거합니다.
  • INSERT OVERWRITE 문은 HBase 테이블에 사용할 수 없습니다. 새 데이터를 삽입하거나 키 값이 동일한 새 행을 삽입하여 기존 행을 수정할 수 있지만 테이블의 전체 내용을 바꿀 수는 없습니다. 이 기능이 필요한 경우 Hive에서 INSERT OVERWRITE를 수행할 수 있습니다.
  • HBase 테이블에 매핑된 테이블에 대해 CREATE TABLE LIKE 문을 실행하면 새 테이블도 HBase 테이블이지만 원본과 동일한 기본 HBase 테이블 이름을 상속합니다. 새 테이블은 동일한 열 구조를 가진 새 테이블이 아니라 사실상 이전 테이블의 별칭입니다. 혼동을 피하기 위해 HBase 테이블에 CREATE TABLE LIKE를 사용하지 마십시오.
  • Impala INSERT ... SELECT 구문을 사용하여 HBase 테이블에 데이터를 복사하면 쿼리 결과 집합에 있는 것보다 적은 수의 새 행이 생성될 수 있습니다. 결과 집합에 키 열에 대해 동일한 값이 있는 여러 행이 포함된 경우 각 행은 동일한 키 값을 가진 이전 행을 대체합니다. 삽입된 행의 순서를 예측할 수 없기 때문에 이 기술을 사용하여 특정 키 값의 "최신" 버전을 유지할 수 없습니다.
  • CDH 5.5 / Impala 2.3 이상에서 사용 가능한 복합 데이터 유형(ARRAY, STRUCT 및 MAP)은 현재 Parquet 테이블에서만 지원되기 때문에 Impala를 통해 쿼리되는 HBase 테이블에서는 이러한 유형을 사용할 수 없습니다.
  • LOAD DATA 문은 HBase 테이블과 함께 사용할 수 없습니다.
  • SELECT 문의 TABLESAMPLE 절은 뷰, 하위 쿼리 또는 실제 기본 테이블이 아닌 다른 항목에서 파생된 테이블 참조에 적용되지 않습니다. 이 절은 HDFS 또는 HDFS와 같은 데이터 파일이 지원하는 테이블에만 적용되므로 Kudu 또는 HBase 테이블에는 적용되지 않습니다.
반응형

댓글