-
Vertica 임포트 및 익스포트의 이해VERTICA/99.Best Practices 2017. 11. 28. 15:53
Vertica는 Vertica 클러스터끼리 데이터를 이동시킬 수 있는 임포트 및 익스포트 기능을 지원합니다. 클러스터 사이에서 데이터를 가져오거나 내보내면 STDIN을 통해 데이터를 스트리밍하거나 vsql 연결을 사용하는 것보다 속도가 더 빠른데, 이번 문서에서 그 이유를 살펴보겠습니다.
임포트 및 익스포트: 개요
임포트 및 익스포트 프로세스는 미러 이미지로 실행됩니다. 데이터를 익스포트하는 클러스터는 SELECT 문에 해당하는 쿼리를 실행합니다. 그리고 데이터를 임포트하는 클러스터는 COPY 문에 해당하는 쿼리를 실행합니다. 임포트/익스포트 작업의 메커니즘은 INSERT... SELECT ... 쿼리와 비슷합니다.
본 문서에서는 데이터를 익스포트하는 클러스터를 소스 클러스터로, 그리고 데이터를 임포트하는 클러스터를 대상 클러스터로 표현합니다. 데이터는 소스 클러스터의 테이블에서 대상 클러스터의 유사 테이블로 이동합니다. 이러한 클러스터와 테이블은 토폴로지가 다양해서 다음과 같은 특성이 서로 다를 수 있습니다.
- 노드 수
- 데이터베이스 버전
- 프로젝션 수
- 컬럼 데이터 타입
- 세그먼트화(segmentation)
- 사용자
- 구성 설정
본 문서의 예제에서는 임포트와 익스포트의 실행 방식을 설명할 목적으로 두 가지 Vertica 클러스터를 사용합니다.
- 소스 클러스터: 노드 3개(10.100.0.55, 10.100.0.66, 10.100.0.77)
- 대상 클러스터: 노드 2개(10.100.0.88, 10.100.0.99)
익스포트의 실행 방식
소스 클러스터에서 익스포트 작업은 일반적으로 다음 명령을 통해 실행됩니다. 먼저 소스 데이터베이스가 타깃 데이터베이스에 연결됩니다. 그런 다음 소스에서 EXPORT TO VERTICA 쿼리가 실행되고, 여기에서 SELECT 문을 지정하여 대상으로 익스포트할 데이터를 찾습니다
source=> CONNECT TO VERTICA VerticaDBTarget USER dbadmin PASSWORD '' ON '10.100.0.88',5433;
source=> EXPORT TO VERTICA VerticaDBTarget.tgt_table (n,a,b) AS SELECT n AS col1, a as col2 , b as col3 from src_table;
소스가 위의 EXPORT 문에서 SELECT 문을 실행하여 익스포트할 데이터를 찾습니다. 타깃은 COPY 문을 작성하여 소스에 연결한 후 SELECT 문의 출력을 수신합니다.
이 COPY 문에는 대상 클러스터가 소스 클러스터에 연결하여 데이터를 스트리밍하는 데 필요한 정보가 입력됩니다. IP 주소, 포트 번호, 데이터 타입, 컬럼 이름, 인코딩 및 압축 정보가 여기에 포함됩니다.
COPY 문은 소스에서 실행되는 SELECT 문의 출력을 복사하여 해당 데이터를 타깃에 저장합니다.
다음은 EXPORT 프로세스를 설명한 이미지입니다.
대상 데이터베이스에서 실행되는 정확한 COPY 문을 보려면 SESSIONS 시스템 테이블에 대한 쿼리를 실행합니다. 이 COPY 문은 다수의 TCP 스트림이 동시에 데이터를 로드하기 때문에 vsql을 사용하거나 STDIN에서 데이터를 복사하는 것보다 실행 속도가 빠릅니다.
target=> SELECT user_name, node_name, current_statement FROM sessions;
user_name | node_name |
-----------+----------------------------+----------------------------------------------------
dbadmin | v_VerticaDBTarget_node0001 | COPY tgt FROM EXPORT ':SendExport explainBits:0 ...
(1 rows)
처음에는 소스 노드 IPs:5434에 연결되었다가 소스 측 임시 포트로 전환됩니다.다음 예제에서,
- v_VerticaDBTarget_node0001은 10.100.0.55(소스 노드 1)와 10.100.0.77(소스 노드 3)에서 데이터를 수신합니다.
- v_VerticaDBTarget_node0002는 10.100.0.66(소스 노드 2)에서 데이터를 수신합니다.
v_VerticaDBTarget_node0001은 v_VerticaDBTarget_node0002보다 작업량이 2배 더 많습니다. 임포트/익스포트 작업은 소스 및 타깃 노드가 서로 균등하게 일치하지 않으면 시간이 더 걸릴 수 있습니다.
COPY tgt ( n, a, b )
FROM EXPORT
':SendExport explainBits:0 planNumber:45035996273709640 tag:1000 status:
:DataPort ip_source:2 oid:45035996273704982
name:v_VerticaDBTarget_node0001 ip:10.100.0.55 address_family:0 port:5434 .
ports: { :DataPort ip_source:2 oid:45035996273704982
name:v_VerticaDBTarget_node0001 ip:10.100.0.55 address_family:0 port:5434 .
:DataPort ip_source:2 oid:45035996273721216
name:v_VerticaDBTarget_node0002 ip:10.100.0.66 address_family:0 port:5434 .
:DataPort ip_source:2 oid:45035996273721220
name:v_VerticaDBTarget_node0003 ip:10.100.0.77 address_family:0 port:5434 . }
db:VerticaDBSource
table:tgt colnames: { :string _:n . :string _:a . :string _:b . }
columns: { :DataType oid:9 type:6 len:3 typmod:7 .
:DataType oid:9 type:6 len:4997 typmod:5001 .
:DataType oid:9 type:6 len:4997 typmod:5001 . }
rle: { :vbool _:0 . :vbool _:0 . :vbool _:0 . }
isCompressed:0 . '
netstat 명령은 타깃 시스템 10.100.0.88 및 10.100.0.99의 수신 대기열이 활발하게 데이터를 수신하고 있는 모습을 출력합니다. 10.100.0.88은 10.100.0.55과 10.100.0.77에서, 그리고 10.100.0.99는 10.100.0.66에서 데이터를 수신합니다.
[ dbadmin@ip-10-100-0-88 ~]$ netstat -tna -p $(pgrep vertica) | grep ESTABLISHED | grep ":5434"
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 476767 0 10.100.0.88:5434 10.100.0.55:46756 ESTABLISHED 6834/vertica
tcp 457636 0 10.100.0.88:5434 10.100.0.77:59568 ESTABLISHED 6834/vertica
[ dbadmin@ip-10-100-0-99 ~]$ netstat -tna -p $(pgrep vertica) | grep ESTABLISHED | grep ":5434"
tcp 480539 0 10.100.0.99:5434 10.100.0.66:59074 ESTABLISHED 6359/vertica
소스 클러스터와 대상 클러스터의 노드 수가 동일한 것을 권장합니다. 그러면 로드 밸런싱에 도움이 되어 어떠한 노드에서도 익스포트 작업이 지체되는 일이 없기 때문입니다. 또한 데이터 전송 속도를 높이는 데도 효과적입니다.
소스 및 대상 클러스터의 노드 수가 다를 경우에는 다수의 소스가 대상 하나에게 데이터를 전송하거나, 혹은 하나의 소스가 다수의 대상에게 데이터를 전송하는 일이 벌어질 수도 있습니다.
대상 클러스터에서 임포트 작업은 일반적으로 다음 명령을 통해 실행됩니다.
target=> CONNECT TO VERTICA VerticaDBSource USER dbadmin PASSWORD '' ON '10.100.0.55',5433;
CONNECT
target=> COPY tgt(n,a,b) FROM VERTICA VerticaDBSource.src(n,a,b) DIRECT;
CONNECT 명령을 실행하여 대상 클러스터를 소스 클러스터에 연결합니다. COPY 명령이 임포트할 데이터를 지정합니다.
다음은 이러한 프로세스를 설명한 이미지입니다.
소스 데이터베이스에서 실행되는 EXPORT 문을 보려면 SESSIONS 시스템 테이블에 대한 쿼리를 실행합니다.
source=> SELECT node_name, current_statement, last_statement FROM sessions;
node_name | current_statement | last_statement
----------------------+-----------------------------------------+----------------
v_verticadb_node0001 | export to STDOUT FROM src ( n , a , b )
네트워크 데이터 압축
일반적으로 임포트 또는 익스포트 작업을 실행할 때 네트워크에서 병목 현상이 일어나지는 않습니다. 하지만 일부 느리거나 낮은 대역폭의 네트워크에서는 소스 및 타깃 클러스터 모두에서 네트워크 데이터 압축을 사용하여 소스 클러스터와 타깃 클러스터 사이의 데이터 전송 속도를 높일 수 있습니다.
네트워크 설정이 동일하지 않은 경우에는 다음과 같은 오류 메시지가 표시됩니다.
target=> COPY tgt(n,a,b) FROM VERTICA verticadb.src(n,a,b) DIRECT;
ERROR 5520: verticadb compresses network traffic. verticadb2
does NOT compress network traffic. Please change the configuration
to be consistent
HINT: Configuration can be changed using set_config_parameter() function
소스 노드와 대상 노드 모두에서 네트워크 데이터 압축 사용할 것을 권장합니다. 그러기 위해서는 다음과 같이 CompressNetworkData 구성 매개 변수를 1로 설정합니다.
=> SELECT SET_CONFIG_PARAMETER('CompressNetworkData',1);
SET_CONFIG_PARAMETER
----------------------------
Parameter set successfully
(1 row)
임포트 및 익스포트 작업의 진행 상황 모니터링
임포트/익스포트 작업의 진행 상황은 대상에서 LOAD_STREAMS 시스템 테이블을 사용하여 모니터링할 수 있습니다. parse_complete_percent 필드는 비어 있습니다. 따라서 대상 클러스터에서는 데이터의 구문 분석이 필요하지 않습니다.
target=> SELECT read_bytes,parse_complete_percent,unsorted_row_count,sorted_row_count
FROM load_streams WHERE is_executing;
read_bytes | parse_complete_percent | unsorted_row_count | sorted_row_count
------------+------------------------+--------------------+------------------
0 | | 39645696 | 19559826
(1 row)
COPY 문을 사용하여 CSV 파일을 로드할 때는 파일 구문 분석이 필요하지만 IMPORT 작업은 COPY를 내포하기 때문에 Vertica에서는 대상 클러스터에서 구문을 분석할 필요가 없습니다. 소스는 데이터를 튜플 형태로 대상에 스트리밍합니다.
다음과 같이 대상에서 rows received 카운터를 보면서 진행 상황을 명확하게 모니터링합니다.
target=> SELECT node_name, counter_name, counter_value, operator_name
from execution_engine_profiles WHERE is_executing='t'
AND counter_name IN ('rows received') AND Operator_name IN ('Import');
node_name | counter_name | counter_value | operator_name
----------------------------+---------------+---------------+---------------
v_VerticaDBTarget_node0001 | rows received | 124257398 | Import
v_VerticaDBTarget_node0001 | rows received | 123197558 | Import
v_VerticaDBTarget_node0002 | rows received | 237063416 | Import
(3 rows)
소스에서 진행되는 프로세스를 모니터링하려면 다음과 같이 rows sent 카운터를 살펴봅니다.
source=> SELECT node_name, counter_name, counter_value,operator_name
FROM execution_engine_profiles WHERE is_executing='t' a
AND counter_name in ('rows sent') AND Operator_name IN ('Export');
node_name | counter_name | counter_value | operator_name
----------------------------+--------------+---------------+---------------
v_VerticaDBSource_node0001 | rows sent | 78890185 | Export
v_VerticaDBSource_node0002 | rows sent | 126071726 | Export
v_VerticaDBSource_node0003 | rows sent | 78889767 | Export
(3 rows)
증분 익스포트
데이터를 소스 클러스터의 테이블에 계속해서 추가하면서 타깃 클러스터의 테이블로 데이터를 복사하고 싶을 때는 증분 익스포트를 실행할 수 있습니다. 증분 익스포트에서는 에포크(epoch) 조건절, 또는 날짜 조건절 같은 다른 조건절과 함께 쿼리를 사용하여 최근에 추가된 데이터를 타깃으로 보냅니다.
다음 예제에서 39는 마지막으로 익스포트기를 실행했을 때의 에포크입니다. 아래 예제에서 EXPORT 문은 에포크 39 이후에 소스로 로드된 데이터만 내보냅니다. 임포트 작업에서는 이와 유사한 구문을 지원하지 않습니다.
source=> COPY cluster1_table1 FROM STDIN DIRECT;
Enter data to be copied followed by a newline.
End with a backslash and a period on a line by itself.
>> 100
>> 101
>> 102
>> 103
>> \.
source=> SELECT epoch, * FROM cluster1_table1;
epoch | i
-------+-----
39 | 2
39 | 3
39 | 5
40 | 101
40 | 102
39 | 1
39 | 4
40 | 100
40 | 103
(9 rows)
source=> CONNECT TO VERTICA VerticaDBTarget USER dbadmin PASSWORD '' ON '10.100.0.88',5433;
CONNECT
source=> EXPORT TO VERTICA VerticaDBTarget.cluster2_table2 AS SELECT * FROM public.cluster1_table1
WHERE epoch > 39;
Rows Exported
---------------
4
(1 row)
병렬 익스포트
내보낼 데이터의 용량이 많을 경우에는 다수의 익스포트를 병렬 실행하여 익스포트기 작업 속도를 높일 수 있습니다.
=> EXPORT TO VERTICA VerticaDBTarget.tgt (n,a,b) AS
SELECT n as col1, a as col2 , b as col3 FROM src
WHERE epoch > 0 AND epoch <= 1;
=> EXPORT TO VERTICA VerticaDBTarget.tgt (n,a,b) AS
SELECT n as col1, a as col2 , b as col3 FROM src
WHERE epoch > 1 AND epoch <= 2;
=> EXPORT TO VERTICA VerticaDBTarget.tgt (n,a,b) AS
SELECT n as col1, a as col2 , b as col3 FROM src
WHERE epoch > 2 AND epoch <= 3;
=> EXPORT TO VERTICA VerticaDBTarget.tgt (n,a,b) AS
SELECT n as col1, a as col2 , b as col3 FROM src
WHERE epoch > 3 AND epoch <= 4;
행의 수가 데이터 크기에 대략적으로 맞을 수 있도록 에포크 범위(또는 날짜 조건절 등의 기타 조건절)를 선택합니다.
Vertica는 전용 네트워크상에서 EXPORT TO VERTICA 문과 COPY FROM VERTICA 문을 사용하여 Vertica 클러스터끼리 데이터를 내보내거나 가져옵니다. 기본적으로 클러스터는 데이터를 익스포트하거나 임포트할 때 전용 네트워크를 사용합니다.
공용 네트워크를 사용하려면 익스포트 주소를 변경하여 시스템을 구성해야 합니다. 네트워크 구성은 각 서버마다 한 가지만 허용됩니다. 공용 네트워크 사용을 위한 시스템 구성은 다음과 같습니다.
- 공용 네트워크에서 노드 또는 클러스트의 IP 주소를 확인합니다.
- 데이터베이스 또는 개별 노드를 임포트/익스포트에 맞게 구성합니다.
익스포트 작업은 데이터 입력작업과 비슷합니다. 하지만 데이터를 소스에서 직접 익스포트하는 경우 Vertica는 타깃의 시퀀스와 컬럼 기본값에 대해 자동 생성(generation)하지 않습니다.
예를 들어 test_seq라는 이름의 테이블에서 다음과 같은 시퀀스를 가정하겠습니다.
source=> CREATE SEQUENCE seqinc START 101 MAXVALUE 1000 CACHE 7 CYCLE;
source=> CREATE TABLE test_seq (col_seq INT DEFAULT NEXTVAL('seqinc'),data VARCHAR(100)) ;
source=> COPY test_seq (data) FROM STDIN;
Enter data to be copied followed by a newline.
End with a backslash and a period on a line by itself.
>> AAAA
>> BBB
>> CCCC
>> AAAAA
>> BBBBB
>> CCCCC
>> DDDDD
>> EEEEE
>> FFFFF
>> \.
source=> SELECT * FROM source;
col_seq | data
---------+-------
101 | AAAA
102 | BBB
103 | CCCC
104 | AAAAA
105 | BBBBB
106 | CCCCC
107 | DDDDD
108 | EEEEE
109 | FFFFF
(9 rows)
이 데이터를 타깃으로 내보내려면 타깃에서 다음 명령을 실행합니다.
target=> CREATE SEQUENCE seqinc START 10000 MAXVALUE 100000 CACHE 9 CYCLE;
target=> CREATE TABLE tgt(col_seq INT DEFAULT NEXTVAL('seqinc'), data VARCHAR(100)) ;
소스의 데이터를 가져오려면 소스에서 다음 명령을 실행합니다.
source=> CONNECT TO VERTICA targetdb USER dbadmin
PASSWORD '' ON '10.100.0.77',5433;
source=> EXPORT TO VERTICA targetdb.tgt AS SELECT * from test_seq;
Rows Exported
---------------
9
(1 row)
SELECT *를 지정했기 때문에 타깃은 소스에서 생성된 시퀀스 값을 가져옵니다.
target=> SELECT * FROM tgt;
col_seq | data
---------+-------
101 | AAAA
102 | BBB
103 | CCCC
104 | AAAAA
105 | BBBBB
106 | CCCCC
107 | DDDDD
108 | EEEEE
109 | FFFFF
(9 rows)
타깃 테이블에 기본값(시퀀스, ID 포함)을 적용하려면 data 컬럼의 값만 선택하도록 익스포트를 작성해야 합니다. 시퀀스 컬럼을 생략하면 타깃이 시퀀스와 ID 값을 작성합니다.
source=> CONNECT TO VERTICA targetdb USER dbadmin
PASSWORD '' ON '10.100.0.77',5433;
source=> EXPORT TO VERTICA test1.tgt(data) AS
SELECT data FROM test_seq;
Rows Exported
---------------
9
(1 row)
이제 타깃의 시퀀스가 항상 소스의 시퀀스 순서를 따르지 않는다는 것을 알 수 있습니다.
target=> SELECT * FROM tgt;
col_seq | data
---------+-------
10012 | BBBBB
10013 | CCCCC
10015 | EEEEE
10000 | AAAA
10009 | BBB
10010 | CCCC
10011 | AAAAA
10014 | DDDDD
10016 | FFFFF
(9 rows)
이러한 접근 방식에 따라 시퀀스 및 ID 값을 소스에서 타깃으로 내보낼 수 있습니다. 또는 EXPORT/IMPORT 문에서 컬럼을 생략하여 시퀀스 및 ID 컬럼이 타깃에 자동 생성되도록 할 수도 있습니다.
Vertica 7.2.x는 새로운 오브젝트 레벨 백업/복원 기능을 지원합니다. 이 기능을 사용하여 전체 백업을 복원할 필요 없이 해당 오브젝트가 저장된 백업에서 테이블 또는 스키마를 개별적으로 복원할 수 있습니다.
소스와 대상의 노드 수가 일치하고 Vertica 서버 버전이 동일할 경우에는 오브젝트 레벨 백업/복원이 임포트/익스포트 작업보다 더 빠릅니다. 하지만 소스 노드의 수가 타깃 노드의 수와 일치하지 않을 때는 vbr.py 스크립트를 사용할 수 없습니다.
따라서 소스 및 타깃 노드의 수가 일치할 때는 오브젝트 레벨 백업/복원 사용을 권장합니다.
'VERTICA > 99.Best Practices' 카테고리의 다른 글
Spread 디버깅 (0) 2017.05.10 Tuple Mover 모범 사례 (0) 2017.04.04 댓글