관계형 데이터베이스에 갇힌 데이터 분석가를 위한 HDFS 자습서
게시 됨: 2022-03-11소개
지금쯤이면 HDFS(Hadoop Distributed File System)에 대해 들어보았을 것입니다. 특히 데이터 분석가이거나 한 시스템에서 다른 시스템으로 데이터를 이동하는 일을 담당하는 사람이라면 더욱 그렇습니다. 그러나 HDFS가 관계형 데이터베이스에 비해 갖는 이점은 무엇입니까?
HDFS는 대용량 데이터를 저장하고 처리하기 위한 확장 가능한 오픈 소스 솔루션입니다. HDFS는 많은 최신 데이터 센터에서 안정적이고 효율적인 것으로 입증되었습니다.
HDFS는 오픈 소스 소프트웨어와 함께 상용 하드웨어를 활용하여 스토리지의 바이트당 전체 비용을 줄입니다.
내장된 복제 및 디스크 장애에 대한 복원력을 갖춘 HDFS는 분석을 위한 데이터 저장 및 처리에 이상적인 시스템입니다. 기존 관계형 데이터베이스 시스템에 필요한 트랜잭션 원자성, 일관성, 격리 및 내구성(ACID)을 지원하기 위한 토대와 오버헤드가 필요하지 않습니다.
또한 Oracle과 같은 엔터프라이즈 및 상용 데이터베이스와 비교할 때 Hadoop을 분석 플랫폼으로 활용하면 추가 라이선스 비용을 피할 수 있습니다.
HDFS에 대해 처음 배울 때 많은 사람들이 묻는 질문 중 하나는 다음과 같습니다. 기존 데이터를 HDFS로 가져오려면 어떻게 해야 합니까?
이 기사에서는 PostgreSQL 데이터베이스에서 HDFS로 데이터를 가져오는 방법을 살펴보겠습니다. 현재 가장 효율적인 오픈 소스 솔루션인 Apache Sqoop을 사용하여 HDFS와 관계형 데이터베이스 시스템 간에 데이터를 전송합니다. Apache Sqoop은 관계형 데이터베이스에서 HDFS로 데이터를 대량 로드(가져오기)하고 HDFS에서 관계형 데이터베이스로 데이터를 대량 쓰기(내보내기)하도록 설계되었습니다.
이 자습서의 단계는 SQL 쿼리 실행에 대한 기본 지식과 HDFS 명령에 대한 기본 지식이 있는 사람을 위해 작성되었습니다.
사용된 데이터베이스 시스템은 Windows용 PostgreSQL 9.5이고 HDFS 버전은 Centos 6.4 Linux 가상 머신의 Cloudera Hadoop 2.5.0-cdh5.2.0입니다.
Apache Sqoop은 관계형 데이터베이스 공급업체 및 데이터베이스 버전에 특정한 JDBC 드라이버 JAR 파일에 의존합니다.
이 기사에 표시된 단계를 실행하려면 사용자는 PostgreSQL 데이터베이스에 원격으로 연결할 수 있는 권한, 관계형 데이터베이스에 대한 SELECT
권한, HDFS에 대한 쓰기 권한, Sqoop 실행 파일에 대한 실행 권한이 필요합니다.
이 자습서의 목적을 위해 Toptal 이라는 PostgreSQL 데이터베이스를 만들고 포트 5432를 통해 액세스할 수 있도록 했습니다.
PostgreSQL 데이터 소스
시작하기 위해 PostgreSQL Toptal
데이터베이스에서 sales
라는 테스트 데이터 테이블을 생성합니다. OpenSSL 인증서와 개인 키 파일이 이미 PostgreSQL 서버에 있다고 가정합니다.
Server [localhost]: Database [postgres]: Toptal Port [5432]: Username [postgres]: Password for user postgres: psql (9.5.3) Toptal=# create table sales Toptal-# ( Toptal(# pkSales integer constraint salesKey primary key, Toptal(# saleDate date, Toptal(# saleAmount money, Toptal(# orderID int not null, Toptal(# itemID int not null Toptal(# ); CREATE TABLE
다음으로 테이블에 20개의 행을 삽입합니다.
Toptal=# insert into sales values (1, '2016-09-27', 1.23, 1, 1); INSERT 0 1 Toptal=# insert into sales values (2, '2016-09-27', 2.34, 1, 2); INSERT 0 1 Toptal=# insert into sales values (3, '2016-09-27', 1.23, 2, 1); INSERT 0 1 Toptal=# insert into sales values (4, '2016-09-27', 2.34, 2, 2); INSERT 0 1 Toptal=# insert into sales values (5, '2016-09-27', 3.45, 2, 3); INSERT 0 1 Toptal=# insert into sales values (6, '2016-09-28', 3.45, 3, 3); INSERT 0 1 Toptal=# insert into sales values (7, '2016-09-28', 4.56, 3, 4); INSERT 0 1 Toptal=# insert into sales values (8, '2016-09-28', 5.67, 3, 5); INSERT 0 1 Toptal=# insert into sales values (9, '2016-09-28', 1.23, 4, 1); INSERT 0 1 Toptal=# insert into sales values (10, '2016-09-28', 1.23, 5, 1); INSERT 0 1 Toptal=# insert into sales values (11, '2016-09-28', 1.23, 6, 1); INSERT 0 1 Toptal=# insert into sales values (12, '2016-09-29', 1.23, 7, 1); INSERT 0 1 Toptal=# insert into sales values (13, '2016-09-29', 2.34, 7, 2); INSERT 0 1 Toptal=# insert into sales values (14, '2016-09-29', 3.45, 7, 3); INSERT 0 1 Toptal=# insert into sales values (15, '2016-09-29', 4.56, 7, 4); INSERT 0 1 Toptal=# insert into sales values (16, '2016-09-29', 5.67, 7, 5); INSERT 0 1 Toptal=# insert into sales values (17, '2016-09-29', 6.78, 7, 6); INSERT 0 1 Toptal=# insert into sales values (18, '2016-09-29', 7.89, 7, 7); INSERT 0 1 Toptal=# insert into sales values (19, '2016-09-29', 7.89, 8, 7); INSERT 0 1 Toptal=# insert into sales values (20, '2016-09-30', 1.23, 9, 1); INSERT 0 1
데이터를 선택하여 데이터가 올바른지 확인하겠습니다.
Toptal=# select * from sales; pksales | saledate | saleamount | orderid | itemid ---------+------------+------------+---------+-------- 1 | 2016-09-27 | $1.23 | 1 | 1 2 | 2016-09-27 | $2.34 | 1 | 2 3 | 2016-09-27 | $1.23 | 2 | 1 4 | 2016-09-27 | $2.34 | 2 | 2 5 | 2016-09-27 | $3.45 | 2 | 3 6 | 2016-09-28 | $3.45 | 3 | 3 7 | 2016-09-28 | $4.56 | 3 | 4 8 | 2016-09-28 | $5.67 | 3 | 5 9 | 2016-09-28 | $1.23 | 4 | 1 10 | 2016-09-28 | $1.23 | 5 | 1 11 | 2016-09-28 | $1.23 | 6 | 1 12 | 2016-09-29 | $1.23 | 7 | 1 13 | 2016-09-29 | $2.34 | 7 | 2 14 | 2016-09-29 | $3.45 | 7 | 3 15 | 2016-09-29 | $4.56 | 7 | 4 16 | 2016-09-29 | $5.67 | 7 | 5 17 | 2016-09-29 | $6.78 | 7 | 6 18 | 2016-09-29 | $7.89 | 7 | 7 19 | 2016-09-29 | $7.89 | 8 | 7 20 | 2016-09-30 | $1.23 | 9 | 1 (20 rows)
데이터가 좋아 보이므로 계속 진행해 보겠습니다.
Sqoop을 사용하여 HDFS로 가져오기
데이터 소스가 정의되었으므로 이제 데이터를 HDFS로 가져올 준비가 되었습니다. 우리가 검토할 sqoop
명령은 아래에 나열되어 있으며 다음 글머리 기호에서 각 인수를 분해할 것입니다. 명령은 하나의 완전한 줄에 있어야 하거나 아래 표시된 것처럼 마지막 줄을 제외한 각 줄 끝에 백슬래시(Linux 명령줄 연속 문자)가 있어야 합니다.
sqoop import --connect 'jdbc:postgresql://aaa.bbb.ccc.ddd:5432/Toptal?ssl=true&sslfactory=org.postgresql.ssl.NonValidatingFactory' \ --username 'postgres' -P \ --table 'sales' \ --target-dir 'sales' \ --split-by 'pksales'
-
sqoop import
- 실행 파일의 이름은sqoop
이며 테이블이나 뷰의 데이터를 데이터베이스에서 HDFS로 가져오도록 지시합니다. -
--connect
---connect
인수를 사용하여 PostgreSQL용 JDBC 연결 문자열을 전달합니다. 이 경우 IP 주소, 포트 번호 및 데이터베이스 이름을 사용합니다. 또한 SSL이 사용 중이고 사용할SSLSocketFactory
클래스를 제공해야 함을 지정해야 합니다. -
--username
- 이 예에서 사용자 이름은 Windows 로그인이 아닌 PostgreSQL 로그인입니다. 사용자는 지정된 데이터베이스에 연결하고 지정된 테이블에서 선택할 수 있는 권한이 있어야 합니다. -
-P
- 명령줄 사용자에게 암호를 묻는 메시지가 표시됩니다. Sqoop이 거의 실행되지 않는다면 이것은 좋은 선택이 될 수 있습니다. 암호를 명령에 자동으로 전달하는 다른 방법이 여러 가지 있지만 이 기사에서는 간단하게 유지하려고 합니다. -
--table
- PostgreSQL 테이블의 이름을 전달하는 곳입니다. -
--target-dir
- 이 인수는 데이터가 저장될 HDFS 디렉토리를 지정합니다. -
--split-by
- 작업 부하를 분산하는 데 도움이 되도록 Sqoop에 고유 식별자를 제공해야 합니다. 나중에 작업 출력에서 Sqoop이 분할 경계를 설정하는 데 도움이 되는 최소값과 최대값을 선택하는 위치를 볼 수 있습니다.
아래와 같이 반복성과 편집을 위해 스크립트에 명령을 넣는 것이 좋습니다.
[hdfs@localhost:/sqoop]$ cat sqoopCommand.sh sqoop import --connect 'jdbc:postgresql://aaa.bbb.ccc.ddd:5432/toptal?ssl=true&sslfactory=org.postgresql.ssl.NonValidatingFactory' \ --username 'postgres' -P \ --table 'sales' \ --target-dir 'sales' \ --split-by 'pksales' [hdfs@localhost:/sqoop]$
이제 위의 Sqoop 명령 스크립트를 실행할 차례입니다. Sqoop 명령의 출력은 다음과 같습니다.
[hdfs@localhost:/sqoop]$ ./sqoopCommand.sh 16/10/02 18:58:34 INFO sqoop.Sqoop: Running Sqoop version: 1.4.5-cdh5.2.0 Enter password: 16/10/02 18:58:40 INFO manager.SqlManager: Using default fetchSize of 1000 16/10/02 18:58:40 INFO tool.CodeGenTool: Beginning code generation 16/10/02 18:58:41 INFO manager.SqlManager: Executing SQL statement: SELECT t.* FROM "sales" AS t LIMIT 1 16/10/02 18:58:41 INFO orm.CompilationManager: HADOOP_MAPRED_HOME is /usr/lib/hadoop-0.20-mapreduce Note: /tmp/sqoop-training/compile/77f9452788024792770d52da72ae871f/sales.java uses or overrides a deprecated API. Note: Recompile with -Xlint:deprecation for details. 16/10/02 18:58:43 INFO orm.CompilationManager: Writing jar file: /tmp/sqoop-training/compile/77f9452788024792770d52da72ae871f/sales.jar 16/10/02 18:58:43 WARN manager.PostgresqlManager: It looks like you are importing from postgresql. 16/10/02 18:58:43 WARN manager.PostgresqlManager: This transfer can be faster! Use the --direct 16/10/02 18:58:43 WARN manager.PostgresqlManager: option to exercise a postgresql-specific fast path. 16/10/02 18:58:43 INFO mapreduce.ImportJobBase: Beginning import of sales 16/10/02 18:58:45 WARN mapred.JobClient: Use GenericOptionsParser for parsing the arguments. Applications should implement Tool for the same. 16/10/02 18:58:46 INFO db.DBInputFormat: Using read commited transaction isolation 16/10/02 18:58:46 INFO db.DataDrivenDBInputFormat: BoundingValsQuery: SELECT MIN("pksales"), MAX("pksales") FROM "sales" 16/10/02 18:58:47 INFO mapred.JobClient: Running job: job_201609280401_0005 16/10/02 18:58:48 INFO mapred.JobClient: map 0% reduce 0% 16/10/02 18:59:04 INFO mapred.JobClient: map 50% reduce 0% 16/10/02 18:59:14 INFO mapred.JobClient: map 75% reduce 0% 16/10/02 18:59:15 INFO mapred.JobClient: map 100% reduce 0% 16/10/02 18:59:18 INFO mapred.JobClient: Job complete: job_201609280401_0005 16/10/02 18:59:18 INFO mapred.JobClient: Counters: 23 16/10/02 18:59:18 INFO mapred.JobClient: File System Counters 16/10/02 18:59:18 INFO mapred.JobClient: FILE: Number of bytes read=0 16/10/02 18:59:18 INFO mapred.JobClient: FILE: Number of bytes written=1190344 16/10/02 18:59:18 INFO mapred.JobClient: FILE: Number of read operations=0 16/10/02 18:59:18 INFO mapred.JobClient: FILE: Number of large read operations=0 16/10/02 18:59:18 INFO mapred.JobClient: FILE: Number of write operations=0 16/10/02 18:59:18 INFO mapred.JobClient: HDFS: Number of bytes read=438 16/10/02 18:59:18 INFO mapred.JobClient: HDFS: Number of bytes written=451 16/10/02 18:59:18 INFO mapred.JobClient: HDFS: Number of read operations=4 16/10/02 18:59:18 INFO mapred.JobClient: HDFS: Number of large read operations=0 16/10/02 18:59:18 INFO mapred.JobClient: HDFS: Number of write operations=4 16/10/02 18:59:18 INFO mapred.JobClient: Job Counters 16/10/02 18:59:18 INFO mapred.JobClient: Launched map tasks=4 16/10/02 18:59:18 INFO mapred.JobClient: Total time spent by all maps in occupied slots (ms)=48877 16/10/02 18:59:18 INFO mapred.JobClient: Total time spent by all reduces in occupied slots (ms)=0 16/10/02 18:59:18 INFO mapred.JobClient: Total time spent by all maps waiting after reserving slots (ms)=0 16/10/02 18:59:18 INFO mapred.JobClient: Total time spent by all reduces waiting after reserving slots (ms)=0 16/10/02 18:59:18 INFO mapred.JobClient: Map-Reduce Framework 16/10/02 18:59:18 INFO mapred.JobClient: Map input records=20 16/10/02 18:59:18 INFO mapred.JobClient: Map output records=20 16/10/02 18:59:18 INFO mapred.JobClient: Input split bytes=438 16/10/02 18:59:18 INFO mapred.JobClient: Spilled Records=0 16/10/02 18:59:18 INFO mapred.JobClient: CPU time spent (ms)=3980 16/10/02 18:59:18 INFO mapred.JobClient: Physical memory (bytes) snapshot=481574912 16/10/02 18:59:18 INFO mapred.JobClient: Virtual memory (bytes) snapshot=2949685248 16/10/02 18:59:18 INFO mapred.JobClient: Total committed heap usage (bytes)=127401984 16/10/02 18:59:18 INFO mapreduce.ImportJobBase: Transferred 451 bytes in 33.7555 seconds (13.3608 bytes/sec) 16/10/02 18:59:18 INFO mapreduce.ImportJobBase: Retrieved 20 records. [hdfs@localhost:/sqoop]$
위 출력의 마지막 줄은 20개의 레코드가 검색되었음을 보여주며, 이는 PostgreSQL 데이터베이스의 테이블에 있는 20개의 레코드에 해당합니다.

Sqoop 명령을 실행한 후 hdfs dfs -ls
명령을 실행하여 기본적으로 HDFS에 테이블 이름으로 생성된 디렉토리를 볼 수 있습니다.
[hdfs@localhost:/sqoop]$ hdfs dfs -ls Found 1 items drwxrwxrwx - toptal data 0 2016-10-02 18:59 sales [hdfs@localhost:/sqoop]$
hdfs dfs -ls
명령을 다시 사용하여 sales
디렉토리의 내용을 나열할 수 있습니다. HDFS를 보면 데이터가 기본적으로 하나의 파일에 포함되지 않고 4개의 파일에 분할되어 분산되어 있음을 알 수 있습니다.
[hdfs@localhost:/sqoop]$ hdfs dfs -ls sales Found 6 items -rw-rw-rw- 1 toptal data 0 2016-10-02 18:59 sales/_SUCCESS drwxrwxrwx - toptal data 0 2016-10-02 18:58 sales/_logs -rw-rw-rw- 1 toptal data 110 2016-10-02 18:59 sales/part-m-00000 -rw-rw-rw- 1 toptal data 111 2016-10-02 18:59 sales/part-m-00001 -rw-rw-rw- 1 toptal data 115 2016-10-02 18:59 sales/part-m-00002 -rw-rw-rw- 1 toptal data 115 2016-10-02 18:59 sales/part-m-00003 [hdfs@localhost:/sqoop]$
hdfs dfs -cat
명령은 HDFS에 있는 판매 데이터의 첫 번째 파티션에 있는 모든 레코드를 표시합니다.
[hdfs@localhost:/sqoop]$ hdfs dfs -cat sales/part-m-00000 1,2016-09-27,1.23,1,1 2,2016-09-27,2.34,1,2 3,2016-09-27,1.23,2,1 4,2016-09-27,2.34,2,2 5,2016-09-27,3.45,2,3 [hdfs@localhost:/sqoop]$
기본 파일 구분 기호는 쉼표입니다. 또한 소스의 20개 행이 4개의 파티션에 균등하게 분산되었기 때문에 각 파티션에는 5개의 행만 있다는 점에 유의하십시오.
화면에 출력되는 행 수를 제한하기 위해 cat
명령의 출력을 아래와 같이 head
명령으로 파이프하여 다른 세 파티션의 내용을 확인할 수 있습니다.
head
명령에 대한 -n 5
인수는 화면 출력을 처음 5개 행으로 제한합니다.
(우리의 경우 처음에는 각 파티션에 5개의 행만 있기 때문에 이것은 불필요합니다. 그러나 실제로는 각 파티션에 이보다 더 많은 행이 있을 것이며 처음 몇 개만 확인하고 싶을 것입니다. 올바르게 보이는지 확인하십시오. 이렇게 하는 방법을 보여줍니다.)
[hdfs@localhost:/sqoop]$ hdfs dfs -cat sales/part-m-00001 |head -n 5 6,2016-09-28,3.45,3,3 7,2016-09-28,4.56,3,4 8,2016-09-28,5.67,3,5 9,2016-09-28,1.23,4,1 10,2016-09-28,1.23,5,1 [hdfs@localhost:/sqoop]$ hdfs dfs -cat sales/part-m-00002 |head -n 5 11,2016-09-28,1.23,6,1 12,2016-09-29,1.23,7,1 13,2016-09-29,2.34,7,2 14,2016-09-29,3.45,7,3 15,2016-09-29,4.56,7,4 [hdfs@localhost:/sqoop]$ hdfs dfs -cat sales/part-m-00003 |head -n 5 16,2016-09-29,5.67,7,5 17,2016-09-29,6.78,7,6 18,2016-09-29,7.89,7,7 19,2016-09-29,7.89,8,7 20,2016-09-30,1.23,9,1 [hdfs@localhost:/sqoop]$
PostgreSQL 데이터베이스의 여러 테이블에서 데이터를 추출하기 위해 쿼리를 실행해야 하는 경우 다음 명령을 사용하여 수행할 수 있습니다.
[hdfs@localhost:/sqoop]$ cat sqoopCommand.sh sqoop import --connect 'jdbc:postgresql://aaa.bbb.ccc.ddd:5432/toptal?ssl=true&sslfactory=org.postgresql.ssl.NonValidatingFactory' \ --username 'postgres' -P \ --target-dir 'creditCardOrders' \ --split-by 'pksales' \ --query "select s.pksales, s.saledate, s.saleamount, o.shippingtype, o.methodofpayment from sales s inner join orders o on s.orderid=o.orderid where o.methodofpayment='credit card' and \$CONDITIONS" [hdfs@localhost:/sqoop]$
위의 명령에서 Sqoop 명령에 대해 동일한 인수 중 일부를 사용하지만 SQL 명령과 함께 사용할 때 중요도가 다릅니다.
-
--target-dir
- 대상 디렉토리는 선택한 데이터를 저장할 HDFS의 디렉토리를 Sqoop에 알려줍니다. 이 인수는 자유 형식 쿼리를 사용할 때 Sqoop에서 필요합니다. -
--split-by
- 판매 테이블의 기본 키를 선택하더라도 작업 부하를 분산하는 데 도움이 되도록 Sqoop에 고유 식별자를 제공해야 합니다. -
--query
- 이것은 우리가 SQL 쿼리를 제공하는 인수입니다. 위의 쿼리는 큰따옴표로 묶여 있습니다. 쿼리를 포함하는 여러 줄에는 백슬래시(줄 연속 문자)가 없습니다 . 또한WHERE
절 끝에 있는and \$CONDITIONS
에 유의하십시오. 이것은 Sqoop이$CONDITIONS
토큰을 고유한 표현식으로 자동으로 대체하기 때문에 Sqoop에 필요합니다.
문제 또는 문제 없음: HDFS를 고려해야 합니다.
HDFS는 관계형 데이터베이스에 비해 많은 장점이 있습니다. 데이터 분석을 하고 있다면 지금 데이터를 HDFS로 마이그레이션하는 것을 고려해야 합니다.
여기에서 배운 기술을 사용하여 관계형 데이터베이스 시스템에서 HDFS로 데이터를 가져오는 것은 단일 명령으로 수행할 수 있는 간단하고 간단한 프로세스입니다. 이러한 예에는 행 수가 적지만 PostgreSQL 데이터베이스 테이블에서 HDFS로 대용량 데이터를 가져오는 메커니즘은 동일하게 유지됩니다.
큰 테이블을 가져오고 다양한 저장소 구분 기호를 실험해 볼 수도 있습니다. Apache Sqoop을 사용하는 것은 데이터베이스 데이터를 파일로 내보내고 데이터베이스 서버에서 HDFS로 파일을 전송한 다음 HDFS로 파일을 로드하는 것보다 더 효율적입니다.