출처 : http://www.dbguide.net/knowledge.db?cmd=view&boardUid=166753&boardConfigUid=20&boardStep=&categoryUid=209


스케일 아웃 측면에서 살펴본 MySQL의 특성

최근 인터넷 서비스들은 글로벌을 지향하고 소셜 네트워크 기능들을 추가하다 보니 데이터의 양과 트래픽의 양이 급속히 증가하고 있다. 또한 가용성 확보 목적으로 RDBMS도 이젠 스케일아웃(Scale-Out)에 자유롭지 못한 상황에 놓이게 되었다. RDBMS가 여러 측면에서 최상의 조합 기능을 제공하지만, 개별 영역의 장점을 추구하는 솔루션들보다 좋은 성능을 낼 수 없는 건 당연하다. 스케일아웃 관점에 맞는 솔루션을 찾을 필요가 있어 MySQL의 스케일아웃 측면에서 어떤 솔루션들이 있는지 살펴보고자 한다. 

[필자] 하호진 | KTH에서 포털 서비스 및 플랫폼(Identity/Payment) 개발 업무를 수행했으며, 현재 와이즈에코에서 이사로 일하고 있다. 개인 블로그 mimul.com/pebble/default를 운영한다.


1. MySQL Partitioning

1) 개요

파티셔닝은 대규모 테이블을 여러 개의 작은 파티션으로 분할해 성능을 높이는 기술이다. 각 행에 대해 각각의 파티션에 분할하며, MySQL에서는 5.1버전부터 지원한다. 파티셔닝은 주로 데이터 웨어하우스와 같은 거대한 테이블을 사용하는 경우에 위력을 발휘한다. 일반적으로 B 트리 인덱스가 커지면서 검색 및 삽입 속도가 저하된다(계산 순서는 O(log m N)). 하지만, 테이블을 파티션으로 나누는 것으로, B 트리 인덱스의 오버헤드를 줄일 수 있다.


 
그림 1 파티션된 테이블

파티션 테이블은 데이터의 분류 조건에 의해 여러 개의 작은 파티션으로 나뉘어 저장된다. 

+ 제약 사항
- 파티셔닝된 테이블은 스토리지 엔진이 같아야 한다. 
-외부키 제약은 사용할 수 없다.
-FULLTEXT 인덱스를 사용할 수 없다. 
-GIS 컬럼을 사용할 수 없다.
-임시 테이블, MERGE 스토리지 엔진, CSV 스토리지 엔진은 파티셔닝할 수 없다.


2) 방식

+ RANGE 
파티션마다 칼럼의 값이 취할 범위를 지정하는 방식이다.

 


 + LIST

파티션 마다 칼럼의 값을 직접 지정하는 방식이다.

 

+ HASH
HASH 값을 갖고 파티션을 할당하고, 할당이 사용자에 의해 정해지는 것이 아니라 MySQL에 맡기는 방식이다.

 

파티션 방식의 수식을 좀 더 이해하기 쉽게 설명하면, 내부적으로‘2012-05-15’라는 입력 값이 들어간다면 birthday가 아래와 같이 처리되어 파티션 1에 저장된다.


+ KEY

HASH와 비슷하나 분할 결정 값은 Primary Key(혹은 Unique Key)에 대해 서버 측의 결정 알고리즘(MySQL 클러스터:MD5, 다른 스토리지 엔진:PASSWORD())에 의해 결정되는 방식이다.
- PRIMARY/UNIQUE 키가 없으면 사용 불가
- UNIQUE 키가 NOT NULL이 아니면 불가(NULL 값은 MD5, PASSWORD 함수 적용 불가)

 

+ 서브 파티셔닝 RANGE와 LIST일 때 각 파티션을 더 분할할 수가 있다. 이것을 서브파티션이라고 한다.



  


3) 장단점

+ 장점
- 대량의 데이터 저장
- 테이블을 분할할 수 있기 때문에 많은 양의 데이터를 저장할 수 있다.

- 부하 경감
- 테이블의 데이터를 분할할 수 있어서 쿼리에 검색되는 데이터가 줄어든다.
- 해당 디스크에 남아있는 분할 데이터를 받을 확률이 높기 때문에 캐시 히트율도 높아진다.
- 집계 함수(SUM/COUNT)가 병렬 처리가 가능해 속도 향상을 가져 온다.

+ 단점
- 분할 방법의 정의, 관리, 그것을 취급하는 애플리케이션 측의 구현, 조사 비용 등이 증가한다.


4) 고려사항

+ 장점
 -테이블 설계 시 PK는 파티셔닝키와 연관돼야 하고 PK를 제외한 추가 제약 조건은 불가능하만, 테이블 특성에 맞는 것들만 파티셔닝 테이블로 설계해야 한다. 그리고 파티셔닝 키가 모든 조회 조건에 들어가야 한다는 점도 유의해야 한다. ? 
그 외는 1) 개요의 제약 사항을 참고하기 바란다.



2. MySQL Cluster

1) 개요

MySQL Cluster는 공유 디스크를 사용하지 않는 Active-Active 형태의 데이터베이스 클러스터에서 트랜잭션을 지원하고 MySQL의 SQL 문장을 사용할 수 있는 관계형 데이터베이스이다. 단일 장애 지점을 없애기 위하여 99.999%의 가용성(연간 5분 정도의 정지시간)을 달성하기 위한 설계가 반영돼 있다. 데이터를 여러 서버에 분산함으로써 동시 다발적으로 대량으로 발생하는 데이터 업데이트를 신속하게 처리하고, 확장성을 높인 접근이다. 온라인 백업뿐만 아니라 클러스터에 서버 추가와 업데이트도 온라인 상태에서 할 수 있기 때문에 클러스터를 중단 없이 운용할 수 있다. MySQL Cluster의 시발점은 통신장비 업체 에릭슨 휴대 통신망의 가입자 데이터베이스용으로 개발된 Ericsson Network DataBase(NDB)라고 한다. 2003년부터 MySQL 서버의 기능과 통합해 제품화하고, 현재 MySQL 서버와 별도의 제품으로 개발?판매가 진행되고 있다. 

+아키텍처
MySQL Cluster에서 공유 디스크를 사용하지 않는 대신 여러 서버에 데이터를 분산 배치하고, 항상 여러 서버가 동일한 데이터 사본을 갖고 있게 한 접근이다. 각 노드의 특성은 다음 <표 1>과 같다.



 

각 테이블의 기본 키 또는 고유 키의 해시를 계산해 파티션을 내부적으로 만들고, 해시 값과 데이터 노드의 수에 따라 각 파티션의 데이터를 데이터 노드에 분산한다. 분산된 데이터는 같은 그룹 데이터 노드의 복제본에 중복 저장된다. 파티션의 데이터가 변경되면 동일한 파티션을 가진 데이터 노드에 동기적으로 변경 사항이 반영되기 때문에 각 데이터 노드의 데이터는 항상 동일하게 유지된다.



 
그림 2 Cluster

클러스터에 있는 데이터 노드? 비트 패킷을 보내 모니터링하고 데이터 노드가 중지된 경우 클러스터에서 자동으로 분리된다. 또한 재해 복구 데이터 노드는 같은 그룹의 데이터 노드에서 최신 변경사항까지 차이를 취득해 데이터를 자동으로 반영하고 데이터를 동기화할 때 클러스터에 다시 참여한다.


+ 특징
- 자동 파티셔닝
- 분산 프라그먼트
- 동기화 방식
- 자동으로 이뤄지는 고속 데이터 노드

+ 페일오버
- 자동 재동기화
-트랜잭션 지원

+ 제약 사항
- 인메모리 인덱스
- 크로스 테이블 조인, 레인지 스캔 등을 지원 안 함
- 포린키 지원 안 함
- 롱 트랜젝션 지원 안 함
- 네트워크 지연 시 치명적
- 모든 클러스터의 기종은 동일해야 함. 기종에 따른 비트 저장방식이 다른 경우에 문제 발생



2) 방식

+ Shared-Nothing



 
그림 3 Shared-Nothing

각 데이터 노드별 독립적인 스토리지를 연결하고 스토리지 공유를 하지 않기 때문에 오라클 RAC와는 달라 스토리지 장애 발생 가능성을 차단하는 구조이다.


+Data Partitioning(데이터 분산 구조)
 
그림 4 Data Partitioning

테이블 Row 단위의 여러 노드에 분산해 쓰기 성능 확장이 가능하고 하나의 노드 그룹 시스템에 동일한 복제본으로 이중화 구성을 했다.


3) 장단점


+ 장점
  -고성능?고가용성
  - 어플리케이션에서 샤딩 기능이 필요 없어 개발 및 유지보수 비용 절감
  - Join 실행 가능
  - 샤드(Shard) 간 ACID 보장
  - 네트워크 홉이 크게 줄어 높은 처리 성능과 짧은 대기 시간 제공
  - 즉각적인 페일오버 및 복구 지원

+ 단점
  - MySQL Cluster 7.2에서 많은 개선이 있었지만 테이블 조인 성능이 떨어짐
  - 클러스터 격리 수준이 READ-COMMITTED



4) 고려사항

+ Distribution Awareness 고려한 설계 MySQL Cluster 내에서 데이터의 분산은 이른바 Sharding과 같은 원리로 이뤄지고 있다. 그래서 Distribution Awareness가 제대로 고려되지 않은, 데이터 노드 수가 증가하면 네트워크 병목현상이 일어나 성능 저하를 유발한다. 이를 위해서는 Sharding 방식으로 테이블을 정의하고 응용 프로그램에서 사용하는 쿼리도 조정한다면 효율을 높일 수 있다. 예를 들어 아래와 같이 Distribution Awareness를 이용하기 위해서는 테이블 정의와 쿼리를 조정해야 한다.


 

그리고 Distribution Awareness가 효과가 있는지 확인하려면 'EXPLAIN PARTITIONS SELECT ...'를 이용해 파티션이 하나만 선택됐는지 확인한다.

+ 키 설계도 중요하다.
MySQL Cluster는 Hash 인덱스 및 Ordered 인덱스라는 두 유형의 인덱스가 있다. Ordered 인덱스는 한 테이블에서 여러 개를 만들 수 있지만, 해시 인덱스는 테이블마다 하나만 만들 수 있다. 즉, 해시 인덱스로 구성되는 기본 키뿐이다. 한편, UNIQUE KEY 제약 조건을 이용하는 경우에는 해시 인덱스가 될 수 있다. 하지만 MySQL Cluster에서는 UNIQUE 키를 정의하면 내부적으로 지원 테이블이라는 다른 테이블이 생성된다. 지원 테이블만큼 테이블에 대한 참조가 증가하므로 UNIQUE KEY 제약 조건을 이용하는 키는 성능이 떨어짐을 알아야 한다.



3. MySQL Replication

1) 개요

MySQL은 마스터/슬레이브 복제 기능을 제공한다. MySQL에서 지원하는 것은 비동기식 복제로 마스터 서버에서 실행되는 SQL 문을 슬레이브 서버로 전송하고 슬레이브로 다시 실행해 데이터를 일관되게 유지하는 기법을 사용하고 있다. 이것은 스테이트먼트 기반 리플리케이션(SBR, Statement Based Replication)이라고 한다. SBR는 그 구조에 근본적인 문제가 있다. 예를 들어 UUID() 함수를 사용할 경우 마스터와 슬레이브에서 각각 UUID()를 실행하면, 각기 다른 결과로 나타난다. 그 결과, 마스터와 슬레이브는 데이터가 불일치하게 된다. 이 문제를 해결하려면 슬레이브로 전달되는 정보를 스테이트먼트 대신 실제로 테이블에 기록된 내용 또는 행 자체를 복제한다. 그것을 구현하는 것이 로우 기반 리플리케이션(RBR, Row Based Replication)이다. 

MySQL 5.1에서 UUID()을 복제하지 못할 스테이트먼트를 포함할 때만 자동으로 SBR에서 RBR로 전환 MIXED 모드가 기본값(binlog_format)으로 돼 있다. 

+아키텍처

 
그림 5 Replication

MySQL Replication은 READ 관련 스케일아웃만 가능할 뿐, WRITE 관련 스케일아웃은 불가하다. 만약 Replication 운영 시 마스터 트래픽이 과도하게 발생하면, 마스터와 슬레이브 간 데이터 동기화 지연 현상이 발생하기도 한다는 점을 염두에 둬야 한다. 동작의 흐름을 살펴본다면 아래와 같다.

① Slave I/O 스레드가 Master에 접속
② Master가 Slave를 인증하고 Slave와의 세션 개시
③ Slave I/O 스레드가 바이너리 로그파일(파일명, 위치)을 요구
④ Master(binlog dump 스레드)가 요구된 지점으로부터 이벤트를 바이너리 로그에서 읽어 들여 Slave에 전송
⑤ Slave I/O 스레드는 받아 낸 이벤트를 relay-log에 기록
⑥ Slave SQL 스레드가 relay-log 내용을 읽어 들여 SQL문을 실행
⑦ Master에 새로운 이벤트가 있으면 Master가 Slave에 송신



2) 방식

+ Linux Heartbeat + MySQL Replication

 
그림 6 Heartbeat + MySQL replication

Heartbeat 프로토콜을 사용해 노드 간 생존 확인 메시지를 송수신해 장애 여부를 인지한다. 두 서버 사이에는 가상(Virtual) IP가 위치해 장애 시 가상 IP는 살아있는 서버로 송수신해 장애를 피한다.


+ L/B + MySQL Replication

 
그림 7 L/B + MySQL Replication

여러 대의 슬레이브를 앞에 두고 부하 분산을 목표로 하며??서 마스터에서 장애가 발생하면 L/B는 자동 IP를 슬레이브로 향하게 해 서비스가 중단 없이 가능하게 된다.


+Linux Heartbeat + DRBD + MySQL Replication

 
그림 8 Heartbeat + DRBD + MySQL Replication

디스크 미러링 소프트웨어(DRBD; 단방향 복제, 동기 복제, 오픈소스)를 활용해 HA를 구성하는 방식이다. 이는 동기 방식으로 데이터 복제가 이뤄져 데이터 불일치가 없는 장점을 갖고 있다.

3) 장단점

+ 장점
  - MySQL 서버의 부하 분산 가능
  - 실시간 백업 가능


+ 단점
  - 장애가 발생시 슬레이브에 반영이 안 될 가능성 존재
  - Master와 Slave 간 데이터 동기화 지연 발생 가능성 존재
  - 장애 복구가 수동으로 이뤄짐



4) 고려 사항

+ MySQL 5.6.3에서는 slave multithread를 지원하지만, 이전 버전의 경우 Slave는 하나의 스레드로만 SQL을 실행하기 때문에 서버 간 동기화 지연 현상이 발생한다. 따라서 replicate_do_db 혹은 replicate_do_table 옵션을 사용해 실제로 적용할 객체들만 선별적으로 동기화하는 것이다. 이는 서비스 단위로 기능을 나눌 수도 있고, 역할별로 기능을 나눌 수 있게 할 수 있다. 그 외에 롱 트렌젝션을 제거하고, Slave 개수를 잘 조절하고, 작업 집합이 InnoDB 버퍼 풀보다 훨씬 큰 경우는 Slave pre-fetching 기술도 활용해 볼 만하다.

+ MySQL Replication에서 5.5버전부터 Semi-syncronous 기능이 추가됐다. 부하량이 적은 환경에서 마스터와 슬레이브 간의 데이터 정합성을 강화시키는 방법이므로 필요 시 활용하면 좋다.



4. MySQL Sharding

샤딩은 물리적으로 다른 데이터베이스에 데이터를 수평 분할 방식으로 분산 저장하고 조회하는 방법을 말한다. 여러 데이터베이스를 대상으로 작업해야 하기 때문에 경우에 따라서는 기능에 제약이 있을 수 있고(JOIN 연산 등) 일관성(consistency)과 복제(replication) 등에서 불리한 점이 많다. 과거의 샤딩은 애플리케이션 서버 레벨에서 구현하는 경우가 많았는데 최근에는 이를 플랫폼 차원에서 제공하려는 시도가 많다. 그중 미들티어에 샤딩 플랫폼을 둔 Gizzard, Spider, Spock Proxy에 대해 알아본다.


1) Gizzard


+ 개요
트위터(Twitter)에서 자체 개발한 데이터를 분산 환경에 쉽게 구성?관리하고, 장애 발생에 유연하게 대처할 수 있는 오픈소스이면서 미들웨어다. Gizzard 의 핵심이 되는 것은 샤딩(Sharding)이라는 기술이다. 트위터에 따르면, 샤딩은 파티션과 복제라는 두 기술로 구성됐다. 파티션은 하나의 데이터베이스를 해시 등을 사용해 여러 부분으로 나눔으로써 여러 데이터베이스에 분산하는 것을 말하고, 복제는 한 데이터 복제를 다른 서버에 만드는 것이다. 데이터를 복제해 전체 탄력성이 증가함과 동시에 대량의 액세스에 대해 복수의 서버가 동시에 응답할 수 있기 때문에 성능 향상을 기대할 수 있다. 

+ 아키텍처



 
그림 9 Replication

Gizzard는 데이터 저장소와 클라이언트 애플리케이션 사이에 위치해 모든 질의는 Gizzard를 통해 이뤄지고 있어 Gizzard가 분할?복제 키를 쥐고 있다.

 
그림 10 Gizzard Partition

① Gizzard 는 데이터 매핑 선행 테이블에서 데이터 조각을 관리한다. 키에 해당하는 값이 어디에 저장됐는지 샤드 정보를 갖고 있다. 특정 데이터에 관한 키 값을 해시 함수로 돌리고 결과값을 Gizzard에 전달하면, Gizzard는 해당 데이터가 어떤 구역에 속할지 숫자 정보를 생성한다. 이러한 함수는 프로그래밍 가능하기 때문에 사용자 성향에 맞춰 지역성 혹은 균형성 면에서 최적화할 수 있다.



 
그림 11 Gizzard Replication

② Gizzard는 'Replication Tree'로 복제 데이터를 관리한다. 매핑 테이블이 지칭하는 각 데이터 조각들은 물리적 또는 논리적인 형태로 구현될 수 있다. 즉, 물리적인 형태는 특정 데이터 저장소를 의미하고, 논리적인 형태는 데이터 조각에 관한 트리를 의미한다. 트리 안의 각 브랜치들은 데이터의 논리적인 변형을 나타내고, 각 노드들은 데이터 저장소를 의미한다.

③ Gizzard는 장애 상황에도 강한 시스템이다. 특정 파티션 내에 있는 복제 데이터가 유실됐을 지라도, Gizzard는 남은 다른 정상적인 복제 데이터 시스템에 읽기/쓰기를 전환 요청한다. 대응 시나리오는 데이터 조각 안의 특정 복제 데이터 불능이 발생하면 Gizzard는 최대한 빠르게 다른 정상적인 복제 데이터에 읽기/쓰기 작업을 시도해서 정상적인 응답을 주고, Gizzard 내부에서도 문제가 발생했던 복제 데이터가 정상으로 돌아오면, 변경 이력을 다시 적용해 동기화한다.



 
그림 12 Gizzard Migrations

④ Gizzard는 데이터 이전 방안을 제시할 수 있다. 데이터 노드가 A에서 B로 이전한다고 가정할 때 Replicate 샤드가 A와 B 사이에 위치하고 Writeonly는 B 앞에 위치해서 A의 데이터를 B로 복제하게 된다. Writeonly 샤드는 B가 사용 가능한 시점까지 유지되다가 B가 사용 가능한 시점이 되면 WriteOnly는 빠지고 Replicate가 동시에 A와 B에 데이터를 복제하며 동기화해 준다.

 + 고려사항 Gizzard는 동일 데이터를 동시에 변경하려면 데이터 충돌(Confliction)이 발생한다. 그래서 Gizzard는 데이터가 적용 순서를 보장하지 않기 때문에 모델링 시 반드시 이러한 점을 염두에 둬야 한다.



2) SPIDER for MySQL

+ 개요
SPIDER는 Kentoku SHIBA가 개발한 스토리지 엔진이다. MySQL의 파티셔닝 기능을 사용해 파티션마다 다른 서버로 데이터를 저장할 수 있게 한 구조이다. Sharding 기능이 가능한 스토리지 엔진이라고 할 수 있다. 물론 데이터가 저장된 서버가 다른 경우에도 조인할 수 있는 장점이 있다. 이러한 구조를 구현할 수 있었던 배경은 MySQL의 유연한 스토리지 엔진구조가 있었기 때문이다. 

+ 아키텍처

 
그림 13 Spider for MySQL

Spider 는 위 그림처럼 테이블 링크를 통해 로컬의 MySQL 서버처럼 활용할 수 있는 구조이다. 내부적으로는 클러스터의 약점인 애플리케이션에서 구현하던 분산 환경에서의 조인과 트렌잭션 문제를 Spider가 해결해 준다. 더불어 Spider는 XA 트렌잭션과 테이블 파티셔닝을 지원한다. GPL 라이선스 정책을 갖고 있다. 여기에 병BR>+ 고려사항
① SPIDER 테이블을 드롭해도 데이터 노드의 데이터는 사라지지 않는다. SPIDER은 FEDERATED 스토리지 엔진과 마찬가지를 생성하는 스토리지 엔진으로 테이블 DROP 때는 링크만 제거된다. 더불어 TRUNCATE 명령문은 원격 MySQL Server의 데이터를 모두 클리어해 버리므로 주의하자.
② MySQL Cluster처럼 Spider도 파티션을 전제로 한 스토리지 엔진이기 때문에 Distribution Awareness를 고려한 설계를 해줘야 한다.
③ 전체 텍스트 검색과 R-Tree 인덱스를 지원하지 못한다.



3) Spock Proxy

+ 개요
Spock Proxy는 MySQL Proxy를 바탕으로 제작된 샤딩 플랫폼이다. 데이터베이스들을 수평적 분할해 여러 샤드(shard)로 나눠줘 응용 프로그램들이 직면한 중요한 문제들을 해결해 줬고, 이로써 데이터베이스는 성능과 확장성을 쉽게 높일 수 있다. 주요 역할은 Proxy가 클라이언트로부터 전송되는 쿼리를 가로채 데이터가 분할된 기법에 따라 적절한 MySQL 서버에 쿼리를 전송한다. 이후 각 MySQL 서버로부터의 응답을 모아 일반 MySQL 결과인 것처럼 클라이언트로 다시 전송한다.

+ 아키텍처


 
그림 14 Spock Proxy

Spock proxy는 MySQL DB의 Table(universal_db)에 샤딩 규칙을 저장한다. 그래서 애플리케이션 서버로부터 전달받은 SQL을 파싱해, 이 SQL에 shard key가 있는지 파악한다. 만약 shard key가 있다면 universal_db에 기록된 기준에 따라 MySQL 인스턴스를 찾아 SQL을 전달한다. 이런 방식을 사용할 경우 SQL에 shard key와 관련한 정보를 기술할 필요가 없는 장점으로 인해 기존 애플리케이션을 그대로 이용할 수 있다. 

+ MySQL Proxy와 다른 점
Spock Proxy는 MySQL Proxy에서 갈라진 것이다. 코드의 많은 부분이 변경되지 않았지만 기반 아키텍처가 다르다.

① MySQL Proxy는 최적화를 위해 Lua 스크립트 언어를 지원하지만, Spock Proxy는 그렇지 않다. 성능상의 이유로 C/C++를 활용했다.
② MySQL Proxy는 각 클라이언트가 개별 데이터베이스에 직접 인증하는 것을 허용한다. 이는 클라이언트가 proxy 작업에 앞서 최소 연결을 해야 하기 때문에 문제가 있는 방법이다. Spock Proxy는 클라이언트로부터 독립된 서버 연결을 하도록 설계됐다.
③ Spock Proxy는 클라이언트와 서버 연결을 분리해, 관리할 최소/최대 연결 크기를 허용한다. 시작 시에 proxy는 최소 연결 개 수만큼을 미리 연결해 놓는다.
④ 다중 서버 Send/Recv가 가능하다. 그래서 다수의 서버에 요청을 보내고, 이 결과들을 합치는 것 또한 가능하다. 

+ 고려사항
Spock Proxy의 제약사항을 보면 쉽게 구현 단계에서 고려 사항들이 도출될 것이다 
① 데이터베이스들간의 조인이 불가능하다.
② 저장 프로시저와 트랜잭션 지원은 제한적이다.
③ 중첩 질의는 불가능하다.
④ SELECT에서 2개 테이블의 JOIN은 지원하지만, GROUP BY는 지원하지 않는다.
⑤ INSERT에서 칼럼명은 항상 표현돼야 한다.
⑥ MySQL 함수는 데이터들이 여러 파티션에 걸쳐 있는 경우 MAX, MIN, SUM, AVERAGE만 지원한다.
⑦ Spock Proxy는 read only (slave)와 read/write (master)를 구분하지 못한다.
⑧ auto_increment 값이 다르다.



5. 결론

MySQL은 다양한 방식의 스케일아웃을 지원하는 솔루션들이 있고, 지속적으로 개발?보완되고 있다. 중요한 건 우리가 용도에 적합한 솔루션들을 선택할 수 있는 혜안을 갖고 판단할 필요가 있다는 것이다. 비즈니스에 어느 정도 제약성도 있다는 점을 기획자들이 인지할 수 있게 지속적으로 커뮤니케이션 하는 활동도 필요하다. 거기에 DBA나 프로그래머들은 제약 사항 및 고려 사항들을 숙지하고 있어야 하며, 운용하면서 발생될 수 있는 문제점을 애플리케이션이든, 자체 미들웨어를 갖추든 보완하는 자세도 필요해 보인다. 트위터나 페이스북 등에서 행해지는 MySQL을 보완해 주는 미들웨어들을 유심히 살펴본다면 힌트를 얻을 수 있을 것이다.





출처 : 한국데이터베이스진흥원

제공 : DB포탈사이트 DBguide.net


'IT > dbms' 카테고리의 다른 글

[MySQL] 1.MySQL as a NoSQL  (1) 2013.02.12

[MySQL] 1.MySQL as a NoSQL

IT/dbms 2013. 2. 12. 11:23

출처 : http://www.dbguide.net/knowledge.db?cmd=view&boardUid=166138&boardConfigUid=20&boardStep=&categoryUid=209

DBGuide net에 연재된 내용으로 요새 관심있는 Mysql에 관하여 잘 정리가 되어 있어 스크랩해왔습니다.

MySQL as a NoSQL



NoSQL 데이터베이스로서 MySQL

[저자] 하호진 | KTH에서 포털 서비스 및 플랫폼(Identity/Payment) 개발 업무를 수행했으며, 현재 와이즈에코에서 이사로 일하고 있다. 개인 블로그 mimul.com/pebble/default를 운영한다.

제 1회 NoSQL 데이터베이스로서 MySQL 제 2회 스케일 아웃 측면에서 살펴본 MySQL의 특성 제 3회 NoSQL 데이터 모델링 


최근 NoSQL이 데이터베이스 영역에 한 축으로 자리잡고 있지만, 기존 관계형 데이터베이스(RDB) 사용자들에게 NoSQL은 아직 낯설기만 하다. 이런 상황을 반영해 데이터 정합성이 중시되는 서비스에서 RDB의 장점을 활용하면서 NoSQL 특징을 결합하려는 시도들이 이어지고 있다. NoSQL의 특징들을 추가하면서 RDB 기능을 보완하는 방법과 이왕 NoSQL을 사용하려면 제대로 한번 해보는 차원에서 모델링까지 살펴보기로 했다.

첫 번째 연재에서는 'MySQL as a NoSQL'이라는 제목으로 MySQL의 장점에 HandlerSocket Plugin이나 Memcached Plugin을 활용해 NoSQL의 특성을 가미하는 방법과 성능에 대해 알아본다. 2회차 연재에서는 'MySQL의 스케일 아웃(Scale Out)'에 대해 알아본다. MySQL의 Scale Out 기능의 약점을 보완하는 차원에서 대안적 스케일 아웃 방법들에 대해 살펴볼 계획이다. 3회에서는 'NoSQL 데이터 모델일'이라는 주제로 MySQL을 본격적인 NoSQL로 DB로 사용하기 위한 모델링 방법 대해 소개할 계획이다. 



IT 환경의 변화


데이터베이스 분야는 최근 클라우드 컴퓨팅과 소셜 네트워크 서비스의 등장, 스마트 기기의 확산 등 컴퓨팅 환경 변화에 대처하고 내부적으로 데이터의 폭증과 원활한 서비스 지원을 위해 다음과 같은 과제를 해결해야 하는 환경에 놓여있다. 

<span style="font-family: Gulim, 굴림, AppleGothic, sans-serif; font-size: 10pt; color: rgb(0, 0, 0);"> ◆ 중저가 PC급으로 읽기/쓰기를 할 수 있으면서 데이터베이스 확장성(Scalability) 보장 ◆ 중단 없는 서비스와 높은 가용성 보장(Auto-failover) ◆ 빅데이터 환경을 고성능(High Performance)과 무결성(Integrity) 있게 지원 ◆ 비즈니스에 적합한 데이터베이스 스키마의 신속한 확장 ◆ 데이터베이스 설계와 액세스 패턴 등의 사용의 편이성(Usability) 제공 </span>

이렇듯 기존의 RDB의 장점인 데이터 무결성, 습관화된 사용 편이성과 NoSQL의 장점인 빅데이터를 수용하는 구조, 짧은 대기 시간을 통해 높은 성능 보장, 심플한 액세스 패턴을 결합하는 사례들이 늘어나고 있다. 이에 따라 필자는 MySQL을 NoSQL로 쓰는 여러 방법을 성능과 확장성 등 여러 관점에서 고찰해 업무에 적용하고자 하는 DB 엔지니어에게 도움을 드리고자 한다. 

1. MySQL에 NoSQL 엔진을 올릴 수 있었던 배경


MySQL에서 쿼리를 던져서 결과를 가져오는 데까지 가장 많은 비용을 차지하는 곳이 SQL Layer의 구문 분석 단계이다. <그림 1>을 보면서 간략히 설명한다.


[그림 1] 쿼리 프로세스

MySQL 데이터베이스 서버에 SQL이 들어오면 SQL Layer는 SQL 구문을 분석, 해당 테이블에 오픈과 락을 걸고 쿼리 실행 계획을 분석한다. 이어서 테이블 락을 해제하고 닫는 처리 과정을 진행하게 된다. 이 과정은 MySQL의 성능에 많은 오버헤드를 안겨준다.

이러한 SQL Layer의 오버헤드를 어떻게 하면 줄일 수 있을까? 하는 생각과 더불어 MySQL 아키텍처가 SQL 처리 레이어와 실제 데이터베이스 스토리지 엔진이 분리된 점에서 MySQL에 NoSQL 엔진을 올려 성능 향상을 꾀할 여지가 생긴 것이다.

MySQL 스토리지 엔진에 직접 API를 호출함으로써 고성능을 보장할 수 있는 것이다. 즉, 기존 관계형 데이터베이스의 장점을 그대로 유지하면서 단순한 key/value의 연산 비용만 소비돼 고성능 처리가 되는 것이다. 

MySQL을 NoSQL처럼 사용한 예로는 HandlerSocket Plug-in, Memcached Plug-in 등의 사례가 있다. 기존에는 별도의 캐시 서버(memcached 등)와 MySQL 데이터베이스를 사용하는 아키텍처에서 데이터의 일관성 유지 차원에서 애플리케이션 측에서 개발자가 직접 개발?보장해야 하는 어려움이 있었다. MySQL에 NoSQL 요소를 플러그인해 이 부분의 개선을 가져온 것도 중요한 장점이다.

본 연재에서는 MySQL 인프라 위에서 NoSQL 특징 가운데 하나인 성능 확보를 위해 접근한 HandlerSocket Plug-in, 아직 출시되지 않았지만 MySQL에서 준비중인 Memcached Plug-in에 대해 살펴본다. 

2. HandlerSocket Plug-in for MySQL


HandlerSocket은 Percona(MySQL의 브랜치 버전, 성능이 좀 더 낫다고 볼 수 있음)와 MySQL에 각각 플러그인해 사용하는 방법이 있다. 그리고 Percona Server 5.1.52-12.3 부터 HandlerScoket이 기본 플러그인돼 있지만, 여기서는 가장 많이 사용되는 MySQL에 플러그인하는 측면에서 접근했다.



1) 아키텍처 개요


[ 그림 2] HandlerSocket Plug-in 아키텍처

HandlerSocket Plug-in 모듈이 MySQL의 SQL Layer 역할(SQL 파싱, Query Optimizing)을 대신함으로써 데이터 무결성을 보장하고 성능을 개선한 사례이다.

2) 장점

- 다양한 쿼리 패턴을 구사할 수 있다. PK/unique lookups, non-unique index lookups, range scan, LIMIT, INSERT/UPDATE/DELETE.

- 적은 메모리 사용하고 안정적이다. 다수의 동시 커넥션을 수용할 수 있다.

- 조회 시 고성능을 보장한다(750,000 QPS가 가능하다고 함).

- MySQL을 사용함으로써 영속성(persistent), 충돌 제거(crash-safe), ACID를 준수할 수 있다.

- MySQL과 독립적으로 사용돼 MySQL에 장애 발생 우려가 낮다.

3) 단점

- 분산 처리는 가능하지만 스케일 아웃이 보장되지 않는다.

- 보안 대책이 없다. 

4) 지원 클라이언트

- PHP
- 자바
- 파이썬
- Ruby
- JavaScript
- Scala
- Haskell

5) MySQL 설치

<span style="font-family: Gulim, 굴림, AppleGothic, sans-serif; font-size: 10pt; color: rgb(0, 0, 0);"> &amp;gt; yum install -y libevent libevent-devl &amp;gt; vi /etc/security/limits.conf mysql soft nproc 8192 mysql hard nproc 16384 mysql soft nofile 8192 mysql hard nofile 65536 &amp;gt; wget ftp://mirror.services.wisc.edu/mirrors/mysql/Downloads/MySQL-5.5/ mysql-5.5.23.tar.gz &amp;gt; cmake -DCMAKE_INSTALL_PREFIX=/database/server/mysql-5.5.23 \ -DDEFAULT_CHARSET=utf8 -DDEFAULT_COLLATION=utf8_general_ci \ -DWITH_EXTRA_CHARSETS=all \ -DMYSQL_DATADIR=/database/data2 \ -DMYSQL_UNIX_ADDR=/tmp/mysql.sock \ -DMYSQL_TCP_PORT=3306 -DENABLED_LOCAL_INFILE=1 \ -DWITH_INNOBASE_STORAGE_ENGINE=1 \ -DWITH_BLACKHOLE_STORAGE_ENGINE=1 \ -DWITH_PERFSCHEMA_STORAGE_ENGINE=1 \ -DWITH_PARTITION_STORAGE_ENGINE=1 &amp;gt; mkdir /database/data2 &amp;gt; chown -R mysql:mysql /database/data2 &amp;gt; cp support-files/my-innodb-heavy-4G.cnf /etc/mysql-5.5.23/my.cnf &amp;gt; scripts/mysql_install_db --defaults-file=/etc/mysql-5.5.23/my.cnf --basedir=/database/server/mysql-5.5.23 --datadir=/database/data2 --user=mysql --pid-file=/etc/mysql-5.5.23/mysql.pid --port=3308 --socket=/etc/mysql-5.5.23/mysql.sock &amp;gt; bin/mysqld_safe --defaults-file=/etc/mysql-5.5.23/my.cnf --datadir=/database/data2 --user=mysql &amp;amp; &amp;gt; bin/mysqladmin -u root password 'new-password' </span>





6) HandlerSocket 설치

<span style="font-family: Gulim, 굴림, AppleGothic, sans-serif; font-size: 10pt; color: rgb(0, 0, 0);"> &amp;gt; tar xvfz ahiguti-HandlerSocket-Plugin-for-MySQL-1.1.0-2-g395fa55.tar.gz &amp;gt; cd ahiguti-HandlerSocket-Plugin-for-MySQL-395fa55 &amp;gt;./autogen.sh ./configure --with-mysql-source=/database/src/mysql-5.5.23 --with-mysql-bindir=/database/ server/mysql-5.5.23/bin --with-mysql-plugindir=/database/server/mysql-5.5.23/lib/plugin # --with-mysql-source : MySQL의 소스 코드 디렉토리. # --with-mysql-bindir : 설치된 MySQL의 mysql_config 커맨드가 존재하는 디렉토리 # --with-mysql-plugindir : MySQL의 plugin 디렉토리 &amp;gt; tar xvfz ahiguti-HandlerSocket-Plugin-for-MySQL-1.1.0-2-g395fa55.tar.gz &amp;gt; cd ahiguti-HandlerSocket-Plugin-for-MySQL-395fa55 &amp;gt;./autogen.sh ./configure --with-mysql-source=/database/src/mysql-5.5.23 --with-mysql-bindir=/database/ server/mysql-5.5.23/bin --with-mysql-plugindir=/database/server/mysql-5.5.23/lib/plugin # --with-mysql-source : MySQL의 소스 코드 디렉토리. # --with-mysql-bindir : 설치된 MySQL의 mysql_config 커맨드가 존재하는 디렉토리 # --with-mysql-plugindir : MySQL의 plugin 디렉토리 &amp;gt; make;sudo make install &amp;gt; vi /etc/mysql-5.5.23/my.cnf [mysqld] innodb_flush_log_at_trx_commit = 2 innodb_flush_method = O_DIRECT max_connections=500 loose_handlersocket_port = 9998 loose_handlersocket_port_wr = 9999 loose_handlersocket_threads = 16 loose_handlersocket_threads_wr = 1 [mysqld_safe] open-files-limit = 65535 &amp;gt; mysql -uroot -p mysql&amp;gt;install plugin handlersocket soname 'handlersocket.so'; mysql&amp;gt; show plugins; +--------------+--------+---------+----------------+---------+ | Name | Status | Type | Library | License | +--------------+--------+---------+----------------+---------+ .............. | handlersocket| ACTIVE | DAEMON |handlersocket.so| BSD | +--------------+--------+---------+----------------+---------+ </span>



7) 테스트 테이블 확인

<span style="font-family: Gulim, 굴림, AppleGothic, sans-serif; font-size: 10pt; color: rgb(0, 0, 0);"> # 테스트를 위한 테이블 생성 &amp;gt; mysql -uroot -p mysql&amp;gt;use test; mysql&amp;gt; CREATE TABLE user( -&amp;gt; `id` bigint(20) NOT NULL AUTO_INCREMENT, -&amp;gt; `last_name` varchar(256) DEFAULT NULL, -&amp;gt; `first_name` varchar(256) DEFAULT NULL, -&amp;gt; `duty` varchar(256) DEFAULT NULL, -&amp;gt; `cellphone` varchar(256) DEFAULT NULL, -&amp;gt; `housephone` varchar(256) DEFAULT NULL, -&amp;gt; `telephone` varchar(256) DEFAULT NULL, -&amp;gt; `office_fax` varchar(256) DEFAULT NULL, -&amp;gt; `home_address` varchar(256) DEFAULT NULL, -&amp;gt; `office_address` varchar(256) DEFAULT NULL, -&amp;gt; `remark` text, -&amp;gt; PRIMARY KEY (`id`), -&amp;gt; KEY `NAME_INDEX` (`first_name`,`last_name`) -&amp;gt; )ENGINE=InnoDB DEFAULT CHARSET=utf8; mysql&amp;gt; desc user; +----------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------------+--------------+------+-----+---------+----------------+ | id | bigint(20) | NO | PRI | NULL | auto_increment | | last_name | varchar(256) | YES | | NULL | | | first_name | varchar(256) | YES | MUL | NULL | | | duty | varchar(256) | YES | | NULL | | | cellphone | varchar(256) | YES | | NULL | | | housephone | varchar(256) | YES | | NULL | | | telephone | varchar(256) | YES | | NULL | | | office_fax | varchar(256) | YES | | NULL | | | home_address | varchar(256) | YES | | NULL | | | office_address | varchar(256) | YES | | NULL | | | remark | text | YES | | NULL | | +----------------+--------------+------+-----+---------+----------------+ </span>





3. Memcached Plug-in for MySQL


Memcached는 5.6.2-labs-innodb-memcached-log 버전을 설치하며, MySQL도 5.6버전부터는 Memcached가 디폴트 플러그인 된다.



1) 아키텍처 개요


[그림 3] Memcached Plug-in 아키텍처 


HandlerSocket과 유사하게 SQL Layer에서 처리하던 SQL 파싱(parsing)과 Query 최적화 같은 연산이 제거되고, 직접 MySQL Storage Engine에 접근해 읽기/쓰기를 해 더 많은 서버 자원(CPU, 메모리 및 I/O)이 스토리지 엔진 자체 내 쿼리를 지원하는 데 쓰여 성능이 향상되는 구조다. 데이터 연동 방식은 cache-only, innodb-only, caching(cache + innodb) 등 세 가지 중 하나를 설정 가능하며, daemon_memcached_option 옵션을 설정함으로써 기존 사용하는 memcache 관련 추가적 설정이 가능하다.



2) 장점

- 기존 Memcached 를 사용하고 있다면 클라이언트 소스 변경 없이 재사용이 가능하다.

- Memcached의 비 영속적 데이터를 영속적으로 유지할 수 있게 됐다.

- MySQL을 사용함으로써 영속성(persistent), 충돌 제거(crash-safe), ACID 준수가 보장된다.

- 캐시 및 데이터베이스 간 데이터 중복을 제거함으로써 메모리 공간을 절약할 수 있다.

- 고성능 조회가 가능하다.

- Memcached를 독립적으로 운영했을 때와 비교했을 경우 데이터 동기화, 데이터 일관성 검사 작업을 제거함으로써 운영 비용이 감소된다.

3) 단점

- 현재 연구 개발 버전으로 단 한 개의 테이블만 memcache와 연동할 수 있다..

- 성능을 올리기 위해 daemon_memcached_w_batch_size를 통해 커밋 시기를 결정할 수 있는데, 이때 상호 다른 세션에서 데이터 확인이 안 되기 때문에 이를 해소하려면 isolation-level을 read uncommitted로 설정해야 데이터가 보인다.

- Character Set을 설정할 수 없다. 현재 Latin1만 지정할 수 있다.

- 보안에 대한 대응책이 없다. 

4) 지원 클라이언트

- C/C++
- PHP
- 자바
- 파이썬
- Ruby
- Perl
- 닷넷/C#
- Erlang
- Lua

5) MySQL 설치

<span style="font-family: Gulim, 굴림, AppleGothic, sans-serif; font-size: 10pt; color: rgb(0, 0, 0);"> &amp;gt; yum install -y libevent libevent-devl &amp;gt; vi /etc/security/limits.conf mysql soft nproc 8192 mysql hard nproc 16384 mysql soft nofile 8192 mysql hard nofile 65536 &amp;gt; wget http://downloads.mysql.com/snapshots/pb/mysql-5.6-labs-innodb-memcached/ mysql-5.6.2-labs-innodb-memcached.tar.gz &amp;gt; tar -xzvf mysql-5.6.2-labs-innodb-memcached.tar.gz;cd mysql-5.6.2-labs-innodb-memcached &amp;gt; cmake . -DCMAKE_INSTALL_PREFIX=/database/server/mysql-5.6.2 &amp;gt; make; sudo make install &amp;gt; mkdir /database/data2 &amp;gt; chown -R mysql:mysql /database/data2 &amp;gt; cp support-files/my-innodb-heavy-4G.cnf /etc/mysql-5.6.2/my.cnf vi /etc/mysql-5.6.2/my.cnf [mysqld] innodb_flush_log_at_trx_commit = 2 innodb_flush_method = O_DIRECT max_connections=500 [mysqld_safe] open-files-limit = 65535 ./scripts/mysql_install_db --defaults-file=/etc/mysql-5.6.2/my.cnf --basedir=/database/server/ mysql-5.6.2 --datadir=/database/data2 --user=mysql --pid-file=/etc/mysql-5.6.2/mysql.pid --port=3308 --socket=/etc/mysql-5.6.2/mysql.sock &amp;gt; bin/mysqld_safe --defaults-file=/etc/mysql-5.6.2/my.cnf --datadir=/database/data2 --user=mysql &amp;amp; &amp;gt; bin/mysqladmin -u root password 'new-password' </span>



6) Memcached 설치

<span style="font-family: Gulim, 굴림, AppleGothic, sans-serif; font-size: 10pt; color: rgb(0, 0, 0);"> &amp;gt; cd /database/server/mysql-5.6.2 mysql -u root &amp;lt; scripts/innodb_memcached_config.sql mysql -uroot -p mysql&amp;gt; install plugin daemon_memcached soname "libmemcached.so"; mysql&amp;gt; show variables like '%memcached%'; +----------------------------------+-----------------+ | Variable_name | Value | +----------------------------------+-----------------+ | daemon_memcached_engine_lib_name | innodb_engine.so| | daemon_memcached_engine_lib_path | | | daemon_memcached_option | |#'-P 11222' 포트 변경 가능. | daemon_memcached_r_batch_size | 1048576 |# 읽기 작업 일괄 처리 크기가 임계값 | daemon_memcached_w_batch_size | 32 |# 일괄 처리 커밋 크기 임계값 +----------------------------------+-----------------+ mysql&amp;gt; use innodb_memcache; mysql&amp;gt; show tables; +---------------------------+ | Tables_in_innodb_memcache | +---------------------------+ | cache_policies | | config_options | | containers | # memcached 연동 데이터베이스 및 테이블 정보 기술됨 +---------------------------+ </span>



7) 테스트 테이블 확인

<span style="font-family: Gulim, 굴림, AppleGothic, sans-serif; font-size: 10pt; color: rgb(0, 0, 0);">mysql -uroot ?p mysql&amp;gt; use innodb_memcache; mysql&amp;gt; use test mysql&amp;gt; select * from demo_test; # 테스트 테이블 +----+--------------+------+------+------+ | c1 | c2 | c3 | c4 | C5 | +----+--------------+------+------+------+ | AA | HELLO, HELLO | 8 | 0 | 0 | +----+--------------+------+------+------+ mysql&amp;gt; desc demo_test; +-------+---------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+---------------------+------+-----+---------+-------+ | c1 | varchar(32) | NO | PRI | | | | c2 | varchar(1024) | YES | | NULL | | | c3 | int(11) | YES | | NULL | | | c4 | bigint(20) unsigned | YES | | NULL | | | C5 | int(11) | YES | | NULL | | +-------+---------------------+------+-----+---------+-------+ </span>



4. 성능 비교


1) 클라이언트/서버 시스템 사양 및 소프트웨어 설정 값

 

1)2) Write 성능

Write(Insert)는 MySQL과 HandlerSocket은 user 테이블에 id 값을 유니크하게 보장하고, 한 레코드의 사이즈는 1024byte로 구성했다. 클라는 10,000을 설정하고 테스트를 진행했다. Memcached는 수행 방식은 HandlerSocket 방식과 같으나 테이블은 기 생성된 demo_test 테이블에 key/values 형태로 Memcached 프로토콜을 통해 테스트를 진행한 결과이다. 

 

HandlerSocket>Memcached>MySQL 순으로 Insert 성능이 진단됐고, MySQL 기준으로 볼 때 HandlerSocket은 1.6배, Memcached는 1.4배 정도의 성능 개선을 보였다. Insert 성능은 InnoDB에서 데이터를 받아 처리해야 하는 구조이기 ?문에 Insert 시 발생하는 I/O에 영향을 많이 받아 기존 MySQL과 성능 차가 그리 많이 나지는 않았다. 성능 테스트 기간에 데이터 정합성 불일치 건은 없었다. 

1)3) Read 성능

Read 테스트는 Write와 진행 방법은 같다. 조회 키로는 HahdlerSocket과 MySQL은 user 테이블의 id를 조회 조건으로 걸고 유니크하게 조회했으며, Memcached도 마찬가지로 demo_test 테이블의 c1 필드(키)를 유니크하게 바꿔가면서 테스트를 진행한 결과이다. 

 

HandlerSocket>Memcached>MySQL 순으로 조회 성능이 진단됐고 MySQL 기준으로 볼 때 평균적으로는 HandlerSocket은 3.4배, Memcached는 2.8배 정도의 성능 개선을 보였고, Thread 500개일 경우 HandlerSocket은 8.2배, Memcached는 7.5배의 성능 향상을 보였다. Read 성능은 확실히 MySQL보다는 많이 개선된 결과를 볼 수 있었다. 

5. 결론


Write의 성능은 MySQL의 InnoDB 쓰기 성능에 영향을 받기 때문에 HandlerSocket, Memcached 가 각각 1.6배와 1.4배의 큰 성능 개선을 보여주지 못했다. NoSQL 기능으로서 MySQL의 데이터 정합성에 만족해야 했다. 하지만, Read 성능은 DeNA의 개발자가 테스트한 750,000 QPS 수준은 아니지만 최대 HandlerSocket은 8.2배, Memcached는 7.5배 정도의 성능 개선을 보여줬다. 

이 같은 결과로 유추해 볼 때 하드웨어, 디스크, 메모리 DB, MySQL을 튜닝한다면 성능 개선 효과가 기대되며, 조회가 많은 서비스에서 활용하면 더 좋은 결과가 나올 것으로 판단된다. 

HandlerSocket은 MySQL의 테이블 그대로 데이터 활용이 가능한 반면, Memcached는 key/value의 행태로 데이터가 관리돼야 하는 차이는 있다. Memcached는 아직 연구 버전 단계이나 HandlerSocket은 DeNA에서 상용 환경에서 사용한 사례가 있다는 것 등으로 볼 때 필자는 HandlerSocket을 활용하는 방안이 더 매력적으로 보인다. 하지만, MySQL 서버에 영향이 적더라도 실제 수많은 테스트 케이스를 통해 안정성을 확인하고 Plugin의 내부 소스를 파악해 운영 중에 발생할 수 있는 예외 상황을 즉시 제거할 수 있는 준비가 필요하다는 점을 강조하고 싶다. 다음 연재에서는 스케이일 아웃 측면에서 NoSQL로서 MySQL의 특성을 살펴보겠다.







출처 : 한국데이터베이스진흥원

제공 : DB포탈사이트 DBguide.net

'IT > dbms' 카테고리의 다른 글

[Mysql] 2. 스케일 아웃 측면에서 살펴본 MySQL의 특성  (0) 2013.02.12

유용한 vi, vim 명령어 정리

IT/etc 2013. 2. 6. 09:53

유용한 vi, vim 명령어 정리


 기본 기능

:w                  파일 저장하기

:q                   종료하기

h, j, k, l           커서 이동

x, dd, J           삭제

yy                   복사

p                    붙이기

u                    명령 취소

v                    범위 지정


● 터미널 단축키

Ctrl + i : 탭

Ctrl + c : 현재 작업 강제 종료

Ctrl + q : 현재 작업 강제 종료 (디버깅용)

Ctrl + s : 스크롤 잠금

Ctrl + z : 현재 작업을 백그라운드로 보냄


● 입력 모드 전환 키

a append, 현재 커서 위치에서 한칸 뒤로 이동한 후 입력 모드

A      현재 행의 끝으로 이동한 후 입력 모드로 전환

i insert,     입력모드로 전환

I        현재 행의 맨 앞으로 이동한 후 입력 모드로 전환

o Open line, 현재 행 아래에 새로운 행을 만든 뒤 입력모드로 전환

O          현재 행 위에 새로운 행을 만든 뒤 입력모드로 전환

R Replace, 모든 글자를 덧씌움


● 저장과 종료

:w         write, 현재 파일을 저장

:q         quit, vi를 종료

:wq         저장하고 종료

:w filename      다른이름으로 저장

:q!         저장 안하고 나가기

:w! filename filename에 해당하는 파일을 덮어쓴다.


● 커서 이동 키

[#]h 좌, #칸 이동

[#]l

[#]j 아래

[#]k

^ 행의 맨앞으로

$ 행의 맨끝으로

Ctrl + b page up

Ctrl + f page down

Ctrl + u page up (1/2)

Ctrl + d page down (1/2)

w,e 단어 단위 이동(앞으로)

b 단어 단위 이동(뒤로)



● 특정 위치로 이동 명령

[#]gg #행으로 이동. #생략되면 첫번째행

[#]G #행으로 이동. #생략되면 마지막행

:#         #행으로 이동

Ctrl + g         현재 문서 위치 정보를 하단에 표시


● 옵션

:set         현재 옵션 설정 확인

:set all         모든 옵션 설정 확인

:set name! on/off

:set nu 화면에 행 번호 표시

:set ai 자동 들여쓰기


● syntax 명령어

:syntax enable 문법 표시 사용 (컬러분류)

:syntax clear 문법 표시 종료


● 문자열 검색

/word word를 검색

n         다음 검색 결과로

N         반대 방향의 검색 결과로

*         커서 위치의 단어 검색

:set nohls         하이라이트 제거


● 문자열 교체

:1,$s/man/boy/g 1~$(처음부터 끝)까지 man을 boy로 교체 (g: 안물어봄)

:1,$s/man/boy/i 대소문자 무시

:1,$s/man/boy/c 교체 전 확인 (/를 escape하기 위해선 \/로 처리)

:%s/$/ <BR>/g         각 행의 끝에 <br> 넣기


● 파일관련

:edit         파일 열기 (:e)

Ctrl + 6         이전 파일 열기

:e #         #번째 파일로 이동

:w filename 파일을 저장

:sav filename 현 파일을 다른 이름으로 저장

:sp         수평으로 창 분할 (Ctrl+W, s)

:sp + filename 수평으로 다른 파일과 창 분할

Ctrl+W 분할 된 창들 사이에서 이동

:vs         수직으로 분할 (Ctrl+W, v)

:tabedit filename 탭으로 다른 파일 열기

:tabn[ext]         탭 이동 (Ctrl+PageUp,Down)

:tabc[lose] 탭 닫기

:set fenc         현재 파일의 인코딩형식

:set fenc=euc-kr,utf-8 인코딩 변경


기타 정규식은 pass (-ㅅ-);;

위 내용은 "손에 잡히는 vim"의 내용에서 필요한 부분만 발췌하였습니다.



2012년 12월 마소의 "2012 IT 이슈 TOP 5" 가운데 클라우드 관련 글이 있어

필요한 부분만 간단히 정리해 보았다.


클라우드를 지탱하는 기술 (2012.12 마소)


<기반기술>

클라우드 컴퓨팅과 관련된 가장 먼저 떠오르는 기반 기술은 가상화다. 클라우드라는 개념을 논하는 초기에는 클라우드와 가상화 기술을 동일시 한 설명이 많았지만 이제 클라우드는 가상화 기술뿐 아니라 하드웨어 장비가 구축된 데이터 센터와 이를 운용하는 기술, 멀티 테넌트 모델, 서비스 프로비저닝 기능, 자원의 유연하고 즉각적인 관리 등이 요구되고 있다.


<오픈소스 기술>

  • IDG (www.itworld.co.kr)
  • 오픈소스 PaaS : Cloud Foundry, OpenShift
  • 오픈소스 RDBMS : Mysql, PostgreSQL
  • 공개 언어와 런타임 : PHP, 루비, 자바스크립트 등
  • 하이퍼바이저/가상화 : KVM
  • 오픈소스 IaaS : 클라우드스택


<참고자료>

※ 나중에 직접 찾아서 링크 걸 것

  1. 가트너 : Gartner Says Worldwide Cloud Services Market to Surpass $109 Billion in 2012
  2. 전자신문 : 하반기 IT서비스 클라우드 대전 막 올라
  3. 한국정보화진흥원 : CIO리포트 17호 클라우드 컴퓨팅 활성화 전략
  4. IDG : 클라우드를 가능케 한 10가지 오픈 소스 프로젝트
  5. IDG : 클라우드 건너편의 IT직업. "기회와 과제 공존"
  6. IDG : 클라우드 분야에서 각광받는 직업 10선
  7. 정보통신산업진흥원 : 2013년 IT산업 10대 이슈
  8. 한국인터넷진흥원 : 가트너, 개인용 클라우드 서비스의 부상으로 PC입지 약화 가능성 제기
  9. 디지털데일리 : 일본의 클라우드 대란에서 얻는 교훈
  10. 지식경제부 : 클라우드 컴퓨터 산업 발전 위한 기술 간담회



'IT > bigdata' 카테고리의 다른 글

하둡 시작하기: 평가부터 첫 생산 클러스터까지  (0) 2013.01.29

번역 원문 : http://www.hanb.co.kr/network/view.html?bi_id=1813

하둡 시작하기: 평가부터 첫 생산 클러스터까지

제공 : 한빛 네트워크
저자 : Brett Sheppard(@zettaforce)
역자 : 임혜연
원문 : Get started with Hadoop: From evaluation to your first production cluster 

하둡 평가와 첫 클러스터 셋업에 대한 모범 사례 

하둡은 성장 중이다. 아파치 소프트웨어 재단(ASF)의 하둡 및 연관된 프로젝트들과 부프로젝트들은 거대한 크기의 다양한 준구조적, 비구조적, 미가공 데이터를 저장, 처리, 분석하기 위한 느슨하게 결합된 통합된 스택의 형태로 성숙했다. 

하둡은 비교적 짧은 시간동안 크게 진보했다. 구글 파일 시스템(GFS)과 맵리듀스에 대한 구글의 논문은 데이터 스토리지와 전산 처리 작업을 클러스터에 퍼진 각각의 노드에 같이 배치하는 작업에 대한 영감을 주었다. 그리고, 2006년 초 Doug Cutting은 야후에 입사한 후 아파치 Nutch 검색엔진 프로젝트의 일부였던 분산 컴퓨팅 플랫폼을 적용한 노드 300개로 이루어진 연구용 클러스터를 설치했다. 

이제, 가장 큰 생산 클러스터들은 클러스터마다 15페타바이트 스토리지를 가진 4,000개의 노드로 되어 있다. 예를 들어, 야후는 200페타바이트 이상의 데이터를 저장하는 42,000개 이상의 하둡 노드를 운영한다. Hadoop World 2011의 Hortonworks 발표에 따르면, 차세대 맵리듀스 (YARN)가 적용된 하둡 클러스터들은 100,000개 이상의 병렬 태스크와 10,000개 이상의 병렬 잡을 수행할 수 있는 6,000에서 10,000개 사이의 노드까지 늘어날 수 있다. 

이 신생 (소프트웨어) 스택 소개글을 쓴 2011년 8월로부터 시간이 지나면서 하둡 설치, 설정, 하둡을 사용한 프로그램 작성은 더 쉬워졌다. 신생 기술에겐 당연하게도, 여전히 할 일은 남아있다. Tom White가 저서 하둡 완벽 가이드: 2판에 언급한 대로,

하둡이 더 널리 적용되기 위해서는 하둡을 한층 더 사용하기 쉽게 만들어야 한다. 이것은 더 많은 도구의 작성, 더 많은 시스템과의 통합, 새롭고 발전된 API의 작성을 수반한다.
이 글은 하둡을 평가하고 첫 클러스터를 배치하려는 조직을 위한 팁과 모범 사례, 주의사항을 제공한다. 이 글은 하둡 분산 파일 시스템(HDFS)과 맵리듀스에 초점을 두었다. 만약 Hive, Pig 혹은 연관 프로젝트와 도구에 대한 상세사항을 찾는다면, 바로 이 글에는 실망하겠지만 더 많은 정보를 찾을 수 있는 링크를 제공하겠다. Cloudera 교육 서비스 부서 임원 Sarah Sproehnle의 Introduction to Apache Hadoop 발표자료를 포함하여, 2012년 2월 28일에 시작한 O'Reilly Strata: Making Data Work의 발표자료들 또한 참조할 수 있다. 

독립 실행 혹은 의사 분산 모드로 무료 평가를 시작하라 

아직 해보지 않았다면, 무료 하둡 배포판 중 하나를 다운로드받아 설치하여 하둡 평가를 시작할 수 있다. 

아파치 하둡 웹사이트에서는 릴리스 0.22 문서에서보다 더욱 자세히 기술된 하둡 릴리스 0.23 싱글 노드 설치 가이드 (역주:실제 링크는 여기인 듯)를 제공한다. 하둡 커뮤니티는 반영되지 않은 몇몇 이전 업데이트가 있지만, 업데이트들을 하둡 버전 1.0으로 묶었다. 예를 들어, 차세대 맵리듀스(프로젝트 이름 YARN)와 HDFS 연합체(엄청나게 많은 수의 파일을 사용하는 클러스터를 지원하기 위해 HDfS 이름공간을 여러 개의 네임노드에 나누는)는 하둡 버전 0.23에는 포함되었으나 하둡 버전 1.0에는 포함되어 있지 않다. 그러니 하둡 버전간 버전 관리를 의식하라. 

단일 장비에서의 지역 단독 실행 혹은 의사 분산 모드 실행으로 첫 평가를 시작할 수 있다. 선호하는 리눅스 종류를 고르면 된다. 

리눅스나 솔라리스의 대안으로, HDFS와 맵리듀스를 Microsoft Windows 에서 실행하는 선택지가 있다. Microsoft는 Dryad 프로젝트를 중단했고, Sqoop 확장으로하둡에서 SQL Server로의 직접 커넥터를 지원하고, Windows Azure를 위한 하둡 기반 서비스에 착수했고, Hortonworks와 협력 관계를 맺었고, 하둡 지원을 Microsoft SQL Server 2012 버전에 포함하겠다는 계획을 발표했다. 

독립 실행 모드에서는 데몬이 실행되지 않는다. 모든 것은 표준 파일 시스템을 사용하는 스토리지를 가지고 하나의 자바 가상 머신(JVM)에서 실행된다. 의사 분산 모드에서는 각각의 데몬은 자기 자신의 JVM에서 실행되지만, 여전히 하나의 장비에서 기본으로 HDFS를 사용하는 스토리지를 가지고 돌아간다. 예를 들어, 나는 하둡 가상 머신을 인텔 프로세서를 탑재한 맥북에서 VMWare Fusion을 통해 Ubuntu 리눅스를 띄우고 거기에 아파치 하둡이 포함된 Cloudera의 배포판(CDH)을 의사 분산 모드로 실행시킨다. 

만약 미리 설정되어 있지 않다면, HDFS 복제(replication) 설정값을 기본값 3에서 1로 바꾸는 것을 잊지 말라. 그러면 HDFS의 대안 데이터 노드로 블록을 복제하지 못하기 때문에 발생하는 에러 메시지가 계속해서 나타나지 않을 것이다. 설정 파일들은 "conf" 디렉터리에 있고, XML 형식이다. 복제 파라미터는 dfs.replication이다. 주의: 몇몇 접두사는 하둡 버전 0.22와 0.23 사이에 변경되었다. (그러나 아직 하둡 버전 1.0에 반영되지 않았다). HDFS 접두 이름 변화 설명을 보라. 

의사 분산 모드의 기본 평가로도 하둡 데몬에 따라오는, 50030과 50070 포트에서 동작하는 것 같은 웹 인터페이스들을 사용해볼 수 있다. 웹 인터페이스들로 네임노드와 잡트래커 상태를 볼 수 있다. 아래의 스크린샷 예제는 네임노드 웹 인터페이스를 보여준다. 더욱 상세한 리포팅을 위해 하둡은 내장된 Ganglia 연결을 포함한다. 알림 일정을 잡는 데 Nagios를 사용할 수 있다. 

배포판을 고르라 

임대된 혹은 정해진 하드웨어상의 멀티노드 클러스터 시험으로 넘어가려 한다면, 하둡 배포판을 골라야 한다. 아파치 하둡은 Common, HDFS, 맵리듀스로 구성된다. 하둡 Common은 하둡 부 프로젝트들을 지원하기 위한 유틸리티 모음이다. 이 유틸리티에는 파일 시스템, 원격 프로시저 호출(RPC), 직렬화 라이브러리가 포함된다. 추가적인 아파치 프로젝트 및 부 프로젝트들은 아파치로부터 제각각 구하거나, 혹은 하둡 소프트웨어 배포판을 패키지하는 Cloudera나 EMS Greenplum, Hortonworks 같은 벤더들로부터 소프트웨어 묶음으로 함께 구할 수 있다. 

하둡은 아파치 하둡 커뮤니티에 의해 매우 혁신적으로 진행중인 작업이다. 2011년과 2012년에 추가된 기능에는 차세대 맵리듀스, 네임노드 고가용성에 대한 작업, 클러스터 자원 관리와 맵리듀스 잡 스케줄링의 분리, 모든 하둡 요소의 Avro 데이터 파일 포맷 지원, 메타데이터 관리를 위한 HCatalog가 있다. 

상용 배포판을 선택하면 상업적 지원 서비스를 받을 수 있다는 것과 거기 더해 벤더가 연관된 아파치 프로젝트 및 부 프로젝트 내 모든 움직이는 부분 사이의 버전 호환성을 테스트해 준다는 이점이 있다. 이것은 상업적 지원이 있는 Red Hat Linux나 Canonical Ubuntu Linux 간의 선택과 비슷하지만, 확신하건대 하둡이 비교적 최근에 등장했고 많은 숫자의 느슨하게 연결된 프로젝트나 부 프로젝트들이 제공된다는 것을 고려해볼 때 훨씬 중요하다. 

지금까지, 아파치 하둡을 포함한 Cloudera 배포판이 가장 완결되고 통합된 배포판이다. 그것은 아파치 하둡, 아파치 Hive, 아파치 Pig, 아파치 HBase, 아파치 Zookeeper, 아파치 Whirr(하둡을 클라우드에서 실행하기 위한 라이브러리), Flume, Oozie, Sqoop을 포함한다. CDH3은 아마존 EC2, Rackspace, Softlayer clouds를 지원한다. Cloudera 엔터프라이즈는 CDH3에 더해 운영 도구 모음과 생산 지원 서비스를 추가로 제공한다. 

Yahoo와 Benchmark Capital은 아파치 하둡 소프트웨어, 하둡 훈련 및 컨설팅 서비스를 제공하는 Hortonworks에 공동투자하기로 했다. Hortonworks 데이터 플랫폼(HDP) 버전 2는 하둡 0.23에 기반하고, 차세대 맵리듀스 및 HDFS 연합체(federation)를 포함한다. 지금까지, 모든 Hortonworks 배포판은 Hortonworks의 Ambari 관리 콘솔까지 포함하여 오픈 소스이다. 2012년 2월과 3월에 Hortonworks는 두 경영진의 역할을 바꾸었고(Rob Bearden은 CEO가 되었고 Eric Baldeschwieler가 CTO가 되었음), 마케팅 부사장으로 John Kreisa를 고용했다(Cloudera에서도 전에 같은 직위에 있었던). 그리고 아파치 하둡 0.23.1과 HDFS 네임노드 고가용성의 출시를 발표했고, Microsoft, Talend, Teradata와의 새롭거나 확장된 협력 관계를 논의했고, Hortonworks의 하둡 배포판을 100% 오픈 소스로 지원하겠다는 약속을 재확인했다.

2011년 6월, Cloudera의 Tom White와 Patrick Hunt는 아파치 Incubator에 Bigtop이란 이름의 새 프로젝트를 제안했다. 그들의 Bigtop 제안서 를 인용하면: "Bigtop은 하둡 생태계의 패키징 개발 및 테스트를 위한 프로젝트이다. 프로젝트의 목적은 다양한 공동체가 개발한 레벨의 결과물을 각각의 프로젝트보다는 시스템 전체에 초점을 맞추어(패키징, 플랫폼, 실행시간, 업그레이드 등) 테스트해보는 것이다." Bigtop은 아파치 Incubator 단계에 이르렀고, 설치용 바이너리 패키지(RPM과 데비안 패키지)를 제공한다. 

EMC Greenplum HD Community Edition 은 HDFS, 맵리듀스, Zookeeper, Hive, HBase를 포함한다. 또한 EMC는 MapR과의 OEM을 발표했으나, 스토리지 벤더 Isilon 인수합병에 따라 MapR과의 협력관계를 경시할지도 모른다. 

MapR은 HDFS를 고유 독자 소프트웨어로 대체했다. Hadoop Summit 2011에서, MapR은 comScore와 Narus로부터의 고객 레퍼런스 및 CX, Karmasphere, Think BIg Analytics로부터의 파트너 레퍼런스와 함께 M3 및 M5 Edition의 안정화 버전(general availability, GA)을 발표했다. MapR에 따르면, MapR의 배포판은 HBase, Pig, Hive, Cascading, 아파치 Mahout 기계학습 라이브러리, Nagios 통합, Ganglia 통합을 포함한다. HDFS 대체에 더해, MapR은 맵리듀스 연산 고속화 작업을 했고, 고가용성 옵션을 네임노드와 잡트래커에 추가했다. MapR CEO이자 공동 설립자인 John Schroeder, 마케팅 부사장 Jack Norris와 Hadoop Summit에서 나눈 대화에 따르면 MapR은 네트워크 파일 시스템(NFS)과 NFS 로그 컬렉션, HDFS API를 통한 아파치-표준 HDFS와의 데이터 상호 운용성을 제공한다. 

무료 M3 데이션은 MapR 포럼을 통해 이용 가능한 기술 질의응답과 함께 연구용 및 제한 없이 생산용으로 이용 가능하다. 요금 기반 M5 Edition은 상업적 지원 서비스와 함께 미러링, 스냅샷, NFS HA, 데이터 배치 제어 기능을 추가했다. MapR과 Informatica는 2012년 3월 MapR 하둡 배포판에 Informatica 파서를 지원한다고 발표했다. 아파치 하둡의 IBM 배포판(IDAH)은 아파치 하둡, Java 6 SR 8용 32-bit 리눅스 버전 IBM SDK, 하둡용 인스톨러와 설정 도구를 포함한다.Hadoop Summit 2011의 IBM의 Anant Jhingran의 강연 후 Q&A 세션에서, 나는 Jhingran 박사에게 IBM 배포판의 미래에 대해 물었다. 그는 청중들에게 IBM의 배포판은 기술과 시장이 성숙할 때까지의 임시적인 과정이며, 장기적으로는 하둡의 별도 IBM 배포판을 계속해서 발표하려는 계획은 없다고 설명했다. 

IBM은 자신들이 하둡 위에서 동작하는 소프트웨어 패키지들을 만들어냄으로써 하둡을 빅데이터 전략의 초석으로 보고 있음을 시사했다. IBM InfoSphere BigInsights는 데이터 관리, 보안, 개발자 도구, 기업용 통합을 위한 기능들과 함께 구조화되지 않은 텍스트 해석과 인덱싱을 지원한다. IBM은 무료로 다운로드할 수 있는 Biginsights Basic Edition을 제공한다. IBM 고객들은 IBM InfoSphere Streams로부터 나오는 스트리밍 데이터를 분석하도록 BigInsights를 확장할 수 있다. Jeopardy 게임 쇼 경쟁에서, IBM Watson은 하둡을 자연어 해석 지원이 들어있는 정보 가공 작업량을 분산하는 데 사용했다. 

Amazon Elastic 맵리듀스 (EMR) 은 아마존 웹 서비스에서 동작하는 데 최적화된 아파치 하둡, Hive, Pig의 독자적인 버전을 개발한다. Amazon EMR은 Amazon Elastic Compute Cloud(EC2)나 SImple Storage Servie(S3)의 웹 규모의 기반 시스템에서 동작하는 임대용(hosted) 하둡 프레임워크를 제공한다. 

HStreaming의 배포판은 표준 맵리듀스 배치 처리에 더해 스트리밍 프로세싱 및 실시간 분석 기능을 지원하는 하둡의 독자 버전이다. 

하둡 트레이닝을 고려하라 

교육 강좌는 하둡 시작과 새 직원 훈련에 도움이 될 수 있다. 필자는 Cloudera의 시니어 강사인 Glynn Durham이 가르치는 이틀짜리 하둡 시스템 관리자 강좌를 들을 기회가 있었다. 그 강좌는 시스템 관리자들과 기업 IT 설계자들에게 추천할 만 했다. Hortonworks는 지원 서비스 가입과 트레이닝을 제공한다. 하둡 트레이닝과 그 외 지원 서비스를 제공하는 다른 조직을 찾으려면 아파치 하둡 위키 지원 페이지를 방문하라. 

Cloudera가 가르치는 하둡 시스템 관리자 강좌를 들으려면 하둡에 대한 선행 지식이 필요하지는 않지만 최소한 기본적 리눅스 명령어를 이해하는 능력은 필요하다. 또한 각각의 하둡 데몬이 자바 프로세스로 동작하기 때문에 약간의 Java 지식도 유익하다. 강좌를 수료한 다음, Cloudera 공인 하둡 관리자가 되기 위한 1시간짜리 시험을 볼 수 있다. 시스템 관리자 수업과 시험은 하둡 클러스터 동작, 계획, 관리, 잡 스케줄링, 모니터링, 로깅에 걸친 범위를 다룬다. 

하둡 아키텍처를 설계하라 

바로 사용 가능한 클러스터에 일단 몇십 개 이상의 노드를 두기 시작했다면, 각각이 다음의 가장 중요한 데몬에 해당되는 분리된 3대의 엔터프라이즈급 서버에 투자하고 싶을 것이다.
  • 네임노드 

  • 세컨더리 네임노드 (체크포인트 노드) 

  • 맵리듀스 자원 관리자
이 엔터프라이즈급 서버들은 램 메모리가 많아야 하지만, 자기 자신의 디스크 저장소 용량은 크지 않아도 된다 - 저장소 용량은 데이터노드의 역할이다. 네임노드 메모리는, 충분한 램 용량의 기본선으로 파일당 250바이트에 더해 블록당 250바이트로 생각하라. 블록에 대해, 대다수의 조직들은 기본 블록 크기를 64MB에서 128MB로 바꾸고 싶어하는 데 주의하라. dfs.block.size를 변경하여 블록 크기를 변경할 수 있다. 

여러 네임노드 사이에서 이름 공간을 공유하기 위한 HDFS 연합체 옵션은 하둡 0.23 버전부터 시작되었으나, 하둡 버전 1에는 아직 포함되지 않았다. 만약 아주 작은 파일을 굉장히 많이 저장해야만 한다면, HDFS 연합체 사용을 고려하라. 각각의 파일, 디렉토리, 블록은 네임노드 메모리를 150바이트가량 차지하기 때문에 HDFS 연합체를 사용하지 않고는 몇십억개의 파일을 저장할 수 없다. 

큰 클러스터에 대해, 네임노드에는 32GB 메모리로 충분하다. 50GB를 훌쩍 넘는 메모리는 네임노드에서 동작하는 자바 가상 머신에서 지나치게 길고 동작에 지장을 주는 시간을 가비지 컬렉션에 사용함으로써 오히려 생산성을 저하시킬 수 있다. 

가비지 컬렉션은 JVM이 사용하지 않는 램을 재활용하는 과정을 가리킨다. 시스템 관리자가 통제할 수 있는 옵션이 아주 적으며, 아무 때나 시작될 수 있고, 거의 임의의 시간동안 동작한다. Eric Bruno가 Dr.Dobb's Report에서 언급한 것처럼, 자바용 실시간 규격(Real-Time specification for Java, RTSJ)은 JVM이 다른 실시간 애플리케이션을 지원하기 좋게 하기까지 하면서 가비지 컬렉션 문제를 해결할 수 있을지도 모른다. Oracle Java Real-Time System, IBM WepSphere Real-Time VM, Timesys RTSJ 레퍼런스 구현이 RTSJ를 지원하지만, 표준으로서는, 특히 리눅스 구현에서는 아직 시험 단계에 머물러 있다. 

만약 네임노드가 사라지고 백업이 없다면 HDFS는 쓸 수 없다. HDFS는 데이터 캐싱이 없는 GFS에 기반한다. 네임노드로부터 NFS에 마운트된 디스크 기반 이미지뿐 아니라 적어도 1~2개의 동기화된 복사본을 저장하도록 설계해야 한다. Yahoo와 Facebook에서는 네임노드가 쓰는 실제 데이터를 보유하기 위해 두 개의 NetApp 필터를 사용한다. 이 아키텍처에서는, 두 개의 NetApp 필터는 비휘발성 RAM(NVRAM) 복사를 이용한 HA 모드로 동작한다. HDFS는 이제 네임노드에 고가용성(HA) 즉각적인 장애 복구를 위한 대기(Standby) 네임노드 옵션을 지원한다. 네임노드 HA 브랜치는 HDFS trunk에 병합되었다. 이전 하둡 버전(0.23.1 혹은 그 이전)을 사용하는 조직은 HDFS-1623을 통해 코드를 사용할 수 있다. 

잘못 명명된 세컨더리 네임노드(체크포인트 노드로 재명명되고 있는)는 즉각적 장애 복구를 위한 것이 아니고, 네임노드의 네임노드의 재시작 시간을 늘리고 끝내 네임노드의 가용 메모리를 소진시킬 수도 있는 로그가 커지는 것을 방지하기 위한 서버이다. 시작할 때 네임노드는 기본 이미지 파일을 적재하고, 로그 파일에 기록된 최근 변경사항을 적용한다. 세컨더리 네임노드는 네임노드에 대한 주기적인 체크포인트를 수행한다. 그것은 로그 파일의 내용을 이미지 파일에 적용하고, 새 이미지를 생성한다. 체크포인트를 사용하더라도, 클러스터의 재시작은 대형 클러스터에서는 90분 이상이 걸리는데, 네임노드가 시스템을 사용 가능하게 만들기 전 데이터노드 각각의 스토리지 보고를 필요로 하기 때문이다. 

하둡 버전 0.21과 그 이후 버전에 백업 네임노드를 사용하는 옵션이 있다. 그러나 MapR 공동 설립자이자 CTO인 M.C.Srivas가 블로그 질의응답에서 설명한 것처럼, 백업 네임노드를 사용하더라도 네임노드가 실패하면 클러스터는 몇 시간이 걸릴 수도 있는 완전한 재시작을 해야 한다. 원래 네임노드를 동기화되었거나 NFS에 마운트된 복사본으로 다시 살리는 것이 백업 네임노드를 사용하는 것보다 나을지도 모른다. 

HDFS의 이후 버전들에는 네임노드 고가용성을 얻기 위한 활성-대기(active-standby) 설정으로 묶인 한 쌍의 네임노드(네임노드와 스탠드바이 네임노드) 혹은 Zookeeper 위에 구현된 BookKeeper-기반 시스템과 같은 더 많은 옵션이 있을 것이다. 만약 완전 분산 애플리케이션을 지원해야 한다면, 아파치 ZooKeeper를 고려하라. 

YARN(차세대 맵리듀스)부터, 맵리듀스 잡 트래킹은 다음 구성요소 및 부 구성요소를 사용하기 시작했다. 

출처: Brett Sheppard가 아파치 하둡 YARN 릴리스 문서에서 따온 그래픽 

(1) 자원 관리자(Resource Manager) 

1a. 스케줄러: 계층적 큐를 사용하거나, Capacity 스케줄러, 공정(Fair) 스케줄러, 또는 Azkaban이나 Oozie와 같은 작업흐름 도구를 끼워넣을 수 있다. 

1b. 애플리케이션 관리자(Applications Manager): 애플리케이션 관리자는 잡 제출 승인, 애플리케이션 마스터를 실행하는 첫 컨테이너 협상, 애플리케이션 마스터 컨테이너 실패시 재시작을 책임진다. 

1c. 자원 추적자(Resource Tracker): Application Master 최대 재시도 횟수, 컨테이너 생존 확인 빈도, 노드 관리자(Node Manager)를 죽은 것으로 판단할 때까지 얼마나 기다릴지 등의 설정이 들어 있다. 

(2) 하드웨어 노드는 각각 자원 "컨테이너들"(CPU, 메모리, 디스크, 네트워크)을 자원 관리자/스케줄러에게 관리, 모니터, 보고하는 책임이 있는 노드 관리자(Node Manager) 에이전트를 갖는다. 이 컨테이너들은 이전 버전 맵리듀스의 고정 Map과 Reduce 슬롯을 대체한다. 

(3) 애플리케이션별, 패러다임-특수적 애플리케이션 마스터(App Mstr)는 애플리케이션 태스크들을 스케줄링하고 실행한다. 만약 클러스터가 맵리듀스와 MPI 같이 여러 패러다임을 사용한다면, 각각은 맵리듀스 애플리케이션 마스터와 MPI 애플리케이션 마스터와 같은 자기 고유의 애플리케이션 마스터를 갖는다. 

이름공간(namespace)과 같은 용어처럼, 이 YARN 구성요소들은 ResourceManager, NodeManager, ApplicationMaster로 종종 표기된다. 애플리케이션 마스터가 하나 이상의 하드웨어 노드와 통신할 수 있기 때문에, 모든 노드에 애플리케이션 마스터를 복제할 필요가 없다. 이 차트에서 보여주는 것처럼, 몇몇 노드는 애플리케이션 마스터를 인근 노드(예를 들면 랙 감지를 통해 같은 랙에 있는 노드)에 두고 컨테이너만 가지고 있을 수 있다. 

차세대 맵리듀스에 대한 더 많은 정보는 YARN 출시 노트를 참고하라. 

지금 세대의 하둡은 IPv6을 지원하지 않는다. IPV6을 사용하는 조직에서는, 개별 노드에 이름을 붙일 때 IP 주소 대신 DNS 서버를 통해 사용되는 장비의 이름을 조사해야 한다. 중국과 같이 빠르게 성장하는 시장에 있는 조직들이 IPv4 주소의 역사적 분배 때문에 IPv6의 조기 수용자가 되는 동안, IPv6은 북미와 다른 지역에서도 더 많은 관심을 갖기 시작했다. 

데이터노드는 실패한다고 예상하라. HDFS를 사용하면, 데이터노드가 고장나도 클러스터는 중단되지 않지만 성능은 여전히 동작하는 데이터노드의 여유가 줄어드는 것처럼 유실된 저장공간의 양과 프로세싱 용량에 비례하여 저하된다. 일반적으로, 데이터노드에 RAID를 사용하지 말고, 리눅스 논리 볼륨 마스터(LVM)을 하둡과 사용하는 것을 피하라. HDFS는 여러 노드에 걸쳐 블록을 복제하여 내장된 중복성을 제공한다. 

Facebook은 HDFS RAID에 공을 들여왔다. NetApp은 데이터노드에 대한 RAID 사용을 옹호하는 조직이다. 2011년 6월 26일의 NetApp 전략기획 최고 책임자인 Val Bercovici와의 이메일 교환에 의하면: "NetApp의 E-시리즈 하둡 사용자들은 잡과 질의의 완료로부터 데이터 보호를 분리하는 데이터노드에 고도의 공학적인 HDFS RAID 설정을 사용한다. 우리는 대부분의 하둡 ETL 태스크에서, 과거에는 가능하지 않았던 가공(transformation)을 위한 맵리듀스 파이프라이닝을 가능하게 함으로써 향상된 추출과 적재 성능을 목격하고 있다. 롱테일 HDFS 데이터는 또한 훨씬 뛰어난 장기적 HDFS 저장소 효율을 위해서 복제 설정값을 1로 사용하고 RAID로 보호되는 데이터노드로 안전하게 이식될 수 있다." 

데이터노드당 스토리지 용량은 증가하고 있기는 하지만 12테라바이트가 일반적이다. Hadoop World 2011의 Hortonworks 발표자료에 의하면, 각각의 데이터노드는 16개 혹은 그 이상의 코어와 48G/96G의 램, 그리고 24TB/36TB 디스크를 갖는다고 한다. 

파일 스토리지에 더해, 데이터노드는 30퍼센트 정도의 디스크 용량을 맵리듀스 프로세싱 중간에 생성되는 임시 파일을 위한 빈 공간으로 확보해 두어야 한다. 메모리에 대해서는, 이전 경험법칙은 데이터노드마다 Map이나 Reduce 태스크 슬롯에 1~2GB 메모리를 잡아두는 것이었다. 고정 Map과 Reduce 슬롯을 가상 컨테이너로 대체할 차세대 맵리듀스 / YARN 이 이것을 바꾸었다. 

하둡 은 지정한 코덱으로 데이터를 압축하는 옵션을 제공한다. 예를 들어, 페이스북은 대부분의 데이터셋에 대해 압축 인자를 6에서 7 사이로 설정한 gzip 코덱에 의존한다. (2010년 6월 SIGMOD '10 발표자료, "Facebook의 데이터 웨어하우징과 분석 인프라스트럭처") 

되도록 데이터노드의 하드웨어 설정을 표준화하라. 여러 종류의 하드웨어에서 실행할 수 있지만, 권한 설정과 조작을 복잡하게 한다. 다른 종류의 하드웨어를 사용하는 노드들이 있다면, 아키텍처는 클러스터보다는 그리드에 가까워진다. 

또한, 가상화 사용을 기대하지 말라 - 중대한 성능상 문제가 있다. 하둡은 데이터노드가 자신의 디스크 전체를 사용할 수 있을 때 가장 잘 동작한다. 하둡은 고확장성 기술이지, 고성능 기술이 아니다. HDFS의 특성에 따르면, 데이터 블록과 같이 배치한 프로세싱이 수십, 수백, 수천 개의 독립적인 노드에 퍼지는 것이 낫다. 만약 가상화를 사용해야 할 필요가 있다면, 각 데이터노드 하드웨어 장치에 하나의 VM을 할당하는 것을 고려하라. 이것은 자동화된 권한 설정과 소프트웨어 업데이트와 같은 가상화의 장점을 취하면서 성능 저하를 가능한 한 적게 유지한다. 

시스템 관리자를 위한 몇 가지 운영 팁:
  • 큰 파일을 지향하라: 너무 많은 작은 크기 파일을 저장하려 하지 말라. 파일당 네임노드 메모리 비용이 발생한다. 몇 개의 작은 파일은 괜찮다 - 수백에서 수천까지도 - 그러나 100메가바이트, 몇 기가바이트, 혹은 그 이상까지 이르는 많은 수의 파일은 사용하지 말아야 한다. 

  • 설정 파일의 쉼표로 구분된 리스트에는 공백이 없어야 한다: 공백은 에러를 일으킬 수 있다. 

  • 부하 분산(Load balance): 과부하 상황이거나 부하가 지나치게 낮은 노드를 갱신하기 위해 부하 분산자(load balancer)를 주기적으로 실행시켜라. 재분산 작업은 맵리듀스 잡에 지장을 주지 않는다. 

  • 랙 감지를 도입하라: HDFS가 가장 가까운 노드를 인식할 수 있게, 랙 감지를 지원하도록 랙 설정을 정의하고 갱신하라. 이것은 랙 감지를 지원하지 않는 Amazon Elastic Compute Cloud에는 적용되지 않음에 주의하라. 

  • HDFS의 손상을 검사하기 위해 비서비스 시간에 fsck를 매일 실행하라. 

  • 노드들의 시각을 동기화하라. (기본이지만 잊기 쉬운 과정이다.)
Facebook으로부터, 애플리케이션 운용 엔지니어 Andrew Ryan은 2011년 2월 Yahoo Sunnyvale campus에서 열린 Bay 지역 하둡 사용자 그룹 모임에서 자신이 얻은 교훈을 하둡 클러스터 관리자를 위해 공유했다. 

그의 멋진 강연에서 나온 몇 가지 제안사항:
  • 클러스터들, 노드들, 그리고 클러스터에서의 각 노드의 역할에 대한 서비스와 자산 관리 플랫폼과 통합된 중앙 레지스트리를 유지하라. 

  • 망가졌던/망가진 하드웨어는 가장 큰 적이다 - 'excludes' 파일은 친구이다. 

  • 하둡이 하라고 하기 전까지는 ext3 데이터 드라이브에 fsck를 실행시키지 말라. 

  • 다른 부류의 사용자를 적절한 서비스 수준과 용량을 갖도록 다른 클러스터로 분리하라.
클러스터로는 당연한 말 같지만, 하둡이 여러 개의 데이터 센터로 확장된 클러스터를 구동하는 데 아직 잘 맞지 않기 때문에 위의 교훈은 여전히 상기할 필요가 있다. 야후조차, 최대 비공개영역 하둡 생산 클러스터를 기동할 때 하둡 파일 시스템이나 맵리듀스 잡을 여러 데이터 센터로 분할하지 않았다. Facebook과 같은 조직은 여러 데이터센터에 걸쳐 하둡 클러스터를 연합할 방법을 고려하고 있으나, 그것은 시간 제한 및 일반 규모의 데이터 부하에 도전을 일으킨다. 아키텍처와 엔지니어링 부서 고위 임원인 Mr.Eddie Satterly의 O'Reilly Strata 2012의 Expedia 발표에 따르면, Expedia는 하나 이상의 데이터센터로 확장된 하둡 클러스터를 가동하고 있다. 

HDFS로 데이터를 불러오라 

클러스터에 저장하려는 데이터의 출처와 관계없이, 입력은 HDFS API를 거친다. 예를 들어, 당신은 로그 데이터 파일을아파치 Chukwa, Cloudera가 개발한 Flume, Facebook이 개발한 Scribe에 모으고 그 파일들을 HDFS API를 가지고 HDFS 블록 스토리지로 나뉜 클러스터에 넣을 수 있다. 로그 파일과 같은 스트리밍 데이터에 대한 접근법 중 하나는 데이터가 오는 대로 모으는 임시 발판(staging) 서버를 사용한 다음, 데이터를 배치 적재로 HDFS에 넣는 것이다. 

Sqoop은 관계형 데이터베이스로부터 데이터를 불러오는 용도로 설계되었다. Sqoop은 데이터베이스 테이블을 불러오고, 테이블로부터 로우들을 뽑아내기 위한 맵리듀스 잡을 실행하고, 결과 레코드를 HDFS에 쓴다. 데이터 손상으로부터 분리하기 위해 임시 테이블을 사용할 수 있다. 빈 내보내기 테이블로 시작하고 가져오기와 내보내기에 대해 같은 테이블을 사용하지 않는 것이 좋다. SQL 데이터베이스로부터 Hive 데이터 웨어하우스나 HBase 테이블로 데이터를 내보낼 수 있다. Sqoop과 함께 Oozie를 태스크 가져오기와 내보내기 일정을 계획하기 위해 사용할 수 있다. Sqoop은 아파치Sqoop 프로젝트 페이지로부터 직접 다운로드하거나 Cloudera 것 같은 하둡 배포판의 일부로 다운로드받을 수 있다. 

JDBC나 ODBC를 사용한 관계형 데이터베이스와 하둡간 데이터 전송이 느리기 때문에, 많은 벤더들은 고유 도구를 지원하는 빠른 직접 커넥터를 종종 Sqoop 확장을 통해 제공한다. 그 중에서도 직접 커넥터를 제공하는 벤더는 EMC Greenplum, IBM Netezza, Microsoft SQL Server, Microsoft Parallel Data Warehouse (PDW), Oracle and Teradata Aster Data를 포함한다. Quest는 Oracle용 커넥터를 개발했다(Sqoop 프리웨어 플러그인으로 사용 가능한). 더 최근에, Oracle은 Cloudera와 하둡 배포판과 Oracle Big Data Appliance 지원을 제공받는 협력 관계를 맺었다. 

잡(job)을 관리하고 질의에 답하라 

몇몇 맵리듀스용 잡 스케줄러를 고를 수 있다. Facebook이 개발한 Fair Scheduler는 작은 잡에 대해 빠른 응답 시간을 제공하고, 생산 잡에 대해 서비스 품질을 보장한다. 그것은 하둡 맵리듀스의 기본값으로 설정된 선입선출(FIFO) 스케줄러의 업그레이드이다. Fair Scheduler를 사용하면, 잡들은 풀로 묶이고, 최저한도의 맵 슬롯과 리듀스 슬롯, 그리고 실행되는 잡 개수의 제한을 풀에 배정할 수 있다. 맵 슬롯과 리듀스 슬롯의 최대 할당량을 제한할 수 있는 방법은 없다. (예를 들어 제대로 작성되지 않은 잡이 너무 많은 클러스터 용량을 차지하는 것이 걱정된다면) 그러나 이를 우회할 수 있는 하나의 방법은 각각의 풀에 통제할 수 없는 잡의 연쇄를 일으키지 않을 정도로 충분히 보장된 최소 할당량을 제공하는 것이다. 

Yahoo가 개발한 Capacity Scheduler는 큐에 제출된 잡에 우선순위 수준을 배정할 수 있다. 큐 안에서는, 자원을 쓸 수 있게 되면 가장 높은 우선순위를 가진 잡에 배정한다. 잡이 실행되면 이미 배정된 자원 할당량을 되돌리기 위한 끼어들기는 일어나지 않는다. 

Yahoo는 작업흐름(workflow) 관리를 위해 Oozie를 개발했다. Oozie는 HDFS, Pig, 맵리듀스등 하둡에서 실행되는 잡 사이의 의존관계를 조정하는 기능적 확장성이 있고, 규모 확장이 가능하고, 데이터 인식이 가능한 서비스이다. 

Azkaban은 하둡 잡이나 다른 오프라인 프로세스를 생성하고 실행시키는 배치 스케줄러를 제공한다. LinkedIn에서는 하루 1조 이상의 관계들의 대용량 데이터 처리 및 저-지연 사이트 제공을 가능하게 하기 위해 대규모 배치 작업을 처리하는 하둡과 NoSQL 키/값 스토리지 엔진에 대한 프로젝트 Voldemort와 Azkaban 오픈소스 작업흐름 시스템을 결합해서 사용한다. LinkedIn은 Azkaban을 오픈 소스 프로젝트로 후원하고 있고, Azkaban github에 코드를 제공하고 있다. 

Eclipse를 통합 개발 환경으로 사용하는 조직은 Eclipse IDE 아래 하둡 개발 환경을 설치할 수 있다. 하둡 Eclipse 플러그인으로 Mapper, Reducer, Driver 클래스를 생성할 수 있고, 잡 실행을 모니터링할 수 있다. 

Karmasphere Studio는 맵리듀스 잡을 개발, 디버그, 배치, 최적화할 수 있는 그래피컬 작업 환경을 제공한다. Karmasphere는 무료 커뮤니티 에디션과 라이센스 기반 프로페셔널 에디션을 지원한다. 

아파치 Pig를 사용하거나 R과 하둡 통합 프로세싱 환경(RHIPE)에서 R을 사용하여 큰 데이터 셋을 쿼리할 수 있다. 아파치 Hive를 통해 RCFile을 사용한 컬럼식 스토리지 레이아웃뿐만 아니라 큰 데이터 셋에서도 SQL같은 쿼리를 가능하게 할 수 있다. 

Tableau와 Cloudera는 Tableau Desktop 버전 7부터 사용 가능한 SQL에서 하둡으로의 인터페이스를 제공하는 Tableau-to-HDFS 직접 커넥터에 대해 제휴했다. 그것은 HDFS에 저장된 XML 오브젝트 지원을 포함한다. Tableau Desktop 안에서, 맵리듀스 잡에 대한 워크로드 파라미터를 설정하도록 커넥터들을 조정할 수 있다. 또한 Tableau의 인-메모리 데이터 엔진을 사용한 빠른 분석이 필요할 때는 데이터를 HDFS에서 Tableau로 가져올 수 있다. 

MicroStrategy 9 플랫폼은 이미 구성된 하둡 클러스터나 Amazon Elastic MapReduce와 같은 클라우드 제공 서비스를 위해 애플리케이션 개발자와 데이터 분석가가 HiveQL을 사용하여 쿼리를 제출하고 MicroStrategy 대시보드에서 하둡 데이터를 볼 수 있게 한다. Groupon은 MicroStrategy를 고객 행동에 대한 심도있는 이해 및 광고 효과 평가를 위해 Groupon의 일일 거래를 분석하려고 채택했다. Groupon 직원은 MicroStrategy 기반 리포트와 대시보드를 하둡과 HP Vertica에서 데이터를 분석하기 위해 사용할 수 있다. 

SAS는 2012년 2월에 HDFS 지원 계획을 발표했는데, 여기에는 메모리 내 분석을 위해 대용량 메모리가 설치된 블레이드 서버들에서 돌아가도록 설계된, 하드웨어 준비가 된 소프트웨어 패키지가 들어 있다. 

Jaspersoft는 하둡에 있는 데이터에 접근하기 위한 3가지 기본 모드를 제공한다. 먼저 Hive를 통해 직접 HiveQL을 통한 SQL-비슷한 질의를 받아들이는 것이다. 이 방식은 배치화된 리포트를 얻고 싶은 IT 직원이나 개발자에게 적합하지만, 현재의 Hive는 꽤 느린 인터페이스기 때문에 빠른 반응시간 응답이 필요한 경우에는 적절하지 않다. 

둘째, Jaspersoft는 HBase로의 직접 연결을 제공한다. Jaspersoft는 데이터를 HBase 커넥터를 통해 자신의 인-메모리 엔진에 집어넣는다. 이 방식은 맵리듀스 태스크를 작성하지 않고 하둡에 저장된 데이터를 분석하려는 비즈니스 분석가에게 잘 동작한다. 

HBase는 고유 질의 언어가 없기 때문에, 필터링 언어가 없으나 필터링 API는 있다. Jaspersoft의 HBase 커넥터는 StartRow나 EndRow처럼 간단한 것부터 RowFilter, FamilyFilter, ValueFilter, SkipValueFilter와 같이 복잡한 것까지 다양한 하둡 필터를 지원한다. Jaspersoft HBase 질의는 반환되는 ColumnFamily 와/또는 Qualifier를 지정할 수 있다. 몇몇 HBase 사용자들은 굉장히 넓은 테이블을 가지고 있기 때문에, 이 지정은 성능과 사용성을 위해 중요할 수 있다. Jaspersoft HBase 커넥터는 HBase의 쉘을 통해 들어온 데이터나 자바의 기본 직렬화가 사용된 데이터를 위한 역직렬화 엔진(SerDe) 프레임워크와 같이 출하된다. 사용자는 자신이 가진 역직렬 .jars를 플러그인하여 커넥터가 자동으로 HBase의 미가공된 바이트들을 의미있는 데이터 타입으로 변환하도록 할 수 있다. 

셋째, Informatica나 다른 ETL 제공자를 통해 Jaspersoft 소프트웨어에서 가능한 관계형 데이터베이스로의 데이터통합 프로세스를 사용할 수 있다. 그리고는 직접 리포트하거나 Jaspersoft의 메모리 데이터베이스 또는 OLAP 엔진을 통해 분석을 수행할 수 있다. 

클러스터 밖의 애플리케이션이 파일 시스템에 접근할 수 있게 하려고 한다면, 자바 프로그램의 경우는 자바 API를 사용하면 잘 된다. 예를 들어, 스트림을 열기 위해 java.net.url 객체를 사용할 수 있다. C++, Perl, PHP, Python, Ruby나 그 외의 프로그래밍 언어로 작성된 프로그램에서 파일 시스템에 접근하기 위해서 Thrift API를 사용할 수 있다. 

보안을 강화하라 

암호없는 Secure Shell(SSH)는 사용 편의상 장점이 있다. - 예를 들어 모든 클러스터 노드를 간단한 명령어로 시작시키고 중지시킬 수 있다 - 그러나 당신의 조직은 암호없는 SSH의 사용을 막는 보안 정책을 가질 수도 있다. 일반적으로, start-all.sh 와 stop-all.sh 명령어는 하둡 평가 혹은 시험 클러스터 가동에는 유용하나, 생산 클러스터에 대해서는 불필요해지거나 사용하지 않고 싶을 것이다. 

HDFS의 예전 버전들은 사용자 인증을 위한 견고한 보안을 제공하지 않았다. 올바른 패스워드가 있는 사용자는 클러스터에 접근할 수 있었다. 패스워드를 넘으면, 사용자가 자신이 주장하는 바로 그 사용자인지 검증할 수 있는 인증이 없었다. HDFS에 사용자 인증을 활성화하려면, Kerberos 네트워크 인증 프로토콜을 사용하면 된다. 이것은 Generic Services Application Program Interface(GSS-API)를 통해 Simple Authentication and Security Layer(SASL)을 제공한다. 이 셋업은 위임(Delegation), 잡(Job), 블록 접근(Block Access)을 위한 토큰이 있는 원격 프로시저 호출(RPC) 다이제스트 방식을 사용한다. 이 토큰들 각각은 구조가 비슷하고 HMAC-SHA1에 기반한다. Yahoo는 하둡 Kerberos 인증을 위한 Oozie 작업흐름 관리자 설정 방법을 제공한다. 

3단계 Kerberos 티켓 교환 이후, 하둡은 매번 Kerberos 키 배포 센터(KDC)에 접근하지 않고 계속해서 인증된 접근을 허용하기 위해 위임(delegation) 토큰을 사용한다. Kerberos 인증은 환영할 만한 추가 기능이지만, 그 자체로는 하둡이 엔터프라이즈급 보안에 도달하지 못한다. Andrew Bechere가 BlackHat USA 2010 보안 컨퍼런스에서 발표자료와 백서 "하둡 보안 설계: 그냥 Kerberos를 추가하라고? 정말?"에서 언급했듯 다음과 같은 보안 약점이 남는다:
  • 대칭형 암호 키가 널리 배포된다. 

  • 잡 트래커, 태스크 트래커, 노드와 Oozie를 위한 몇몇 웹 도구들은 정적 사용자 인증으로 접근 가능한 웹 사용자 인터페이스(UI) 에 의존한다. SPNEGO-기반 웹 인증 플러그인을 더하는 패치 가능한 HADOOP-7119 jira 이슈가 있다. 

  • 몇몇 구현은 HDFS를 위한 HTTP 프론트엔드를 제공함으로써 대량 데이터 전송에 접근 권한을 주기 위해 프록시 IP 주소와 역할 데이터베이스를 사용한다.
하둡 자체의 제한된 보안을 고려해볼 때, 당신의 하둡 클러스터가 엔터프라이즈 방화벽 뒤에서 근거리 혹은 광역 네트워크에서 운용될 것이라고 해도, 클러스터에 속한 비공개 데이터를 더욱 완벽히 보호하기 위해 클러스터-특정의 방화벽을 고려하고 싶을 수 있다. 이 배치 모델에서, 하둡 클러스터를 IT 인프라 안의 섬으로 생각하라 - 이 섬으로의 모든 연결지점(bridge)을 보안을 위한 모서리(edge) 노드로 고려해야 한다. 

클러스터를 둘러싼 네트워크 방화벽에 더해, 데이터베이스 방화벽이나 데이터베이스 활동 감시 제품을 고려할 수 있다. 이런 제품에는 AppSec DbProtect, Imperva SecureSphere and Oracle Database Firewall이 있다. 데이터베이스 방화벽은 데이터베이스로의 접근을 통과, 로그, 경고, 차단, 치환할 것인지에 대한 규칙 기반 결정을 가능하게 한다. 데이터베이스 방화벽은 데이터베이스 감시 제품이라는 더 넓은 소프트웨어 카테고리의 부분집합이다. 대부분의 데이터베이스 방화벽과 활동 감시 제품은 아직 바로 사용할 수 있는 하둡 지원기능이 없다. 데이터베이스 방화벽 벤더나 시스템 통합자의 도움이 필요할 수 있다. 

클러스터 밖에서 클러스터를 접근할 수 있도록 인증되고 권한을 부여받은 어플리케이션을 보호하기 위해 다른 보안 조치 또한 필요할 수 있다. 예를 들어, Oozie 작업흐름 관리자를 사용하기로 했다면, Oozie는 모든 하둡 사용자를 대표하여 동작을 수행할 수 있는 승인된 "슈퍼유저" 가 된다. 그래서, 만약 Oozie를 도입하기로 했다면, Oozie와 같이 사용할 추가적인 인증 메커니즘을 고려해야 한다. 

어쩌면 위의 몇몇 보안 우려는 Cloudera Enterprise 혹은 Karmasphere Studio처럼, 하둡 데몬에 붙어있는 웹 사용자 인터페이스를 대신해 관리 애플리케이션을 사용하는 기능을 지원한다든가 하는 유료 소프트웨어를 사용하는 것으로 다룰 수 있을지도 모른다. 예를 들어, Cloudera Enterprise 3.5는 현재 버전의 하둡에서 사용 가능한 보안 기능의 설정을 단순화해주는 몇몇 도구를 포함한다. Zettaset(이전 GOTO Metrics)는 사용자-레벨 보안과 감사 트래킹 및 HDFS로의 암호화 옵션 추가 계획을 포함한 보안 향상을 하둡 조정자(Orchestrator)에 묶었다. 

하둡 도구 상자에 추가하라 

Mike Loukids의 "데이터 과학이란 무엇인가?"에 언급되었듯이, "만약 무언가 한 곳에서 정보를 모두 처리할 수 있는 플랫폼(one-stop information platform)이라 부를 수 있는 게 있다면, 하둡일 것이다.". 넓은 하둡 생태계는 아파치 프로젝트 및 부프로젝트들, 다른 오픈 소스 도구들, 그리고 독자적 소프트웨어 제공물 등을 통해 툴과 역량에서 다양한 선택을 제공한다. 이는 아래와 같은 것들을 포함한다.
  • 직렬화에 대해, 아파치 Avro는 자바 외의 다른 언어로 작성된 네이티브 HDFS 클라이언트를 사용 가능하도록 설계되었다. 다른 가능한 직렬화 옵션에는 구글 Protocol Buffer와 Binary JSON이 있다. 

  • Cascading은 Concurrent로부터 상업적 지원을 받을 수 있는, 맵리듀스 위에 구현된 오픈소스 데이터 프로세싱 API이다. Cascading은 잡과 작업흐름(workflow) 관리를 지원한다. Concurrent 창립자이자 CTO인 Chris Wensel에 따르면, 모든 XML과 텍스트 문법 없이 단일 라이브러리를 통해 Pig/Hive/Oozie 기능이 제공된다. Nathan Marz는 HDFS로의 가져오기/내보내기를 위한 Cascading 기반 JDBC 도구인 db-migrate를 작성했다. BackType과 그 예전에는 Rapleaf에서, Nathan은 또한 Clojure에서 지원되는 하둡/Cascading 기반 질의 언어인 Cascalog를 작성했다. Multitool은 명령행에서 HDFS나 Amazon S3에 위치한 큰 데이터셋을 "grep", "sed", 조인 가능하게 한다. 

  • Hadoop User Experience (HUE) 는 브라우저를 통한 "데스크탑-같은" 접근을 제공한다. HUE로, 파일 시스템을 열람하고, 사용자 계정을 생성하고 관리하고, 클러스터 상황을 감시하고, 맵리듀스 잡을 생성하고, Beeswax라는 Hive 프론트엔드를 활성화할 수 있다. Beeswax는 Hive 테이블 생성, 데이터 적재, Hive 질의 실행 및 관리, 결과를 엑셀 형식으로 다운로드 받는 것을 도와주는 마법사를 제공한다. Cloudera는 HUE를 오픈 소스 프로젝트로 공헌했다. 

  • Pervasive TurboRush for Hive는 Hive가 맵리듀스 대안으로써 데이터흐름(dataflow) 그래프를 사용하여 실행 계획을 생성하도록 허용한다. 그러고 이 그래프들을 클러스터의 장비들에 분산된 Pervasive DataRush를 사용하여 실행한다. 

  • Pentaho는 데이터 통합, 추출-가공-적재(extract transform load, ETL), 리포트 설계, 분석을 위한 비주얼 디자인 환경과 HDFS, 맵리듀스, Hive, HBase, 더해서 아파치 Cassandra, MongoDB와 통합되는 대시보드를 제공한다. Pentaho는 Kettle ETL 프로젝트를 아파치 버전 2.0 라이센스로 오픈소스화했다. 

  • Karmasphere Analyst는 하둡 데이터에 Tableau 혹은 Microsoft Excel로의 시각화를 지원하는 Visual SQL 접근을 제공한다. 두번째 제품, Karmasphere Studio는 맵리듀스 잡을 개발, 디버그, 배치, 최적화하기 위한 그래픽 환경을 제공하고, 무료 커뮤니티 에디션 혹은 라이센스-기반 프로페셔널 에디션을 통해 사용 가능하다. Karmasphere는 SSH 터널과 SOCKS 프록시를 통하여 방화벽 뒤의 바로 사용 가능한 하둡 구현을 지원하는데 더해, Amazon Elastic MapReduce와 통합되었고, 연간 사용 계약 대신 EMR-친화적인 선불 옵션을 제공한다. 

  • Datameer는 그들의 Datameer Analytics 솔루션의 일부분으로 하둡 데이터로 작업하는 분석가를 위한 "스프레드시트 같은" 인터페이스를 제공한다. 추가 기능은 큰 데이터 셋을 적재하고 변환하는 마법사 도구와 analytic workbooks 기반으로 데이터를 시각화하는 대시보드 위젯, 고정밀도 통계를 위한 소수점 이하 32자리까지의 지원, 사용자 집단을 인증하기 위한 외부 LDAP과 액티브 디렉터리와의 통합을 포함한다. 

  • Google BigTable을 본떠 만든 아파치 Hbase는 HDFS 위에 만들어진 분산 컬럼-지향 데이터베이스이다. HBase로, 큰 데이터 셋에 실시간 읽기와 쓰기 임의 접근을 실행할 수 있다. HBase를 구체화된 뷰들의 백엔드로 사용할 수 있다; Facebook에 따르면, 이것은 실시간 분석을 지원한다. 

  • HCatalog는 Hive metastore 위에 만들어진 하둡용 메타데이터 도구이다. 이것은 데이터 정의를 위한 명령행 인터페이스와 함께 Pig와 맵리듀스를 위한 읽기와 쓰기 인터페이스를 제공한다. HCatalog는 Pig, Hive, 맵리듀스를 위한 공유 스키마와 데이터 모델을 제공한다. HCatalog는 아파치 프로젝트로 승격되었다. 

  • Hadoop Online Prototype(HOP)는 데이터가 태스크 간에 그리고 잡 간에 파이프라인되는 것을 허용하는 하둡 맵리듀스의 수정된 버전이다. 이것은 더 나은 클러스터 활용과 병렬성 증가를 가능하게 한다. 그리고 다음과 같은 새 기능을 허용한다: 온라인 집합 연산(aggregation) (잡이 실행될 때 해답 근사치), 스트림 프로세싱(연속으로 실행되는 맵리듀스 잡, 새 데이터가 오자마자 처리). HOP는 현 단계에서는 완제품 상태가 아닌 개발 프로토타입이라는 점에 주의하라. 

  • VMware는 2012년 2월에 그들의 Spring 개발 프레임워크(SpringSource 합병으로 얻은)를, Spring 컨테이너를 통한 맵리듀스, Streaming, Hive, Pig, Cascading 잡 지원과 함께 "Spring Hadoop" 으로 확장했다.
하둡의 느슨하게 결합된 아키텍처의 장점 중 하나라면 HDFS나 맵리듀스와 같은 구성요소를 대체할 수 있다는 것이다. 느슨하게 결합된 데이터-중심 아키텍처로서, 하둡은 조립식 구성요소를 지원한다. 2011년 3월 InformationWeek 기사에 Rajive Joshi가 언급한 것처럼, "데이터-중심 설계의 핵심은 데이터와 동작을 분리하는 것이다. 그러면 데이터와 데이터 전송 구조가 주된 조직화 구조가 된다." 이것은 하둡 구성요소간 통합 작업 없이 완벽한 플러그 앤 플레이가 된다는 이야기가 아니다. (제안된 아파치 Bigtop 프로젝트가 이 분야에 도움이 될지도 모른다), 모든 조직이 똑같은 하나로 된 소프트웨어 스택을 사용할 필요가 없다는 것이다. 

하둡 스택 구성요소를 다른 방식으로 대체하는 제품을 내놓은 몇몇 신생 기업들이 최근 급부상했다. 다음과 같은 것들이 있다:
  • DataStax Brisk 는 HDFS 대신 Cassandra 위에서 동작하는 아파치 하둡 맵리듀스와 아파치 Hive의 변경된 버전을 개발했다. 

  • Appistry CloudIQ Storage Hadoop Ediiton은 HDFS를 CloudIQ Storage로 대체했다. 

  • Hadapt는 적응형 질의 엔진과 HBase 및 Hive의 대체물을 더했다.
하둡의 시장 점유 증가 추세로 보자면, 더 많은 하둡의 대안이나 경쟁자의 등장이 눈에 띄기 시작하는 것은 놀랍지 않다. 여기에는 Spark와 LexisNexis HPCC 등이 있다. 

Spark는 UC Berkeley AMP 랩에서 개발되었고, 스팸 필터링, 자연어 처리, 도로 통행량 예측을 위한 버클리의 몇몇 연구 그룹에 의해 사용되었다. AMP Lab은 기계학습 반복적 알고리즘과 상호작용형 데이터 마이닝을 위해 Spark를 개발했다. 온라인 영상 분석 서비스 제공업체 Conviva는 Spark를 사용한다. Spark는 BSD 라이센스의 오픈 소스이다. Spark는 하둡 응용 프로그램 또한 실행할 수 있는 Mesos 클러스터 관리자 위에서 실행된다. Mesos의 사용자에는 Conviva, Twitter, UC Berkeley 등이 있다. Mesos는 2011년 1월 아파치 Incubator에 합류했다. 

2011년 6월, LexisNexis는 하둡 대안으로 고성능 컴퓨팅 클러스터를 발표했다. HPCC Systems는 지원, 교육, 컨설팅을 받을 수 있는 엔터프라이즈 에디션과 함께 무료 커뮤니티 버전을 위한 계획을 발표했다. Sandia National Laboratories는 페타바이트 단위의 데이터를 정렬하고 상관 관계를 찾고 가설을 세우기 위해 데이터 분석 슈퍼컴퓨터 플랫폼이라는 HPCC의 선도 기술을 사용한다. LexisNexis에 따르면, HPCC Systems 설정은 하둡 클러스터와 같은 처리 성능을 제공할 때 더 적은 노드로 가능하고, 몇몇 성능 시험 테스트에서 더 빠르다. 

그러나, 어떤 타입의 준구조적, 비구조적, 미가공 데이터 분석이 LexisNexis/HPCC System에서 더 빠르게 수행되거나 더 적은 노드로 수행되는지는 불분명하다. LexisNexis는 회사들과 공헌자들의 생태계가 아파치 하둡 커뮤니티가 이루어낸 것 같은 활기를 가지기 위해 애써야 할 것이다. 그리고 그들의 HPCC 기술은 LexisNexis 밖에서 널리 쓰이지 않고, 정부나 학계에서만 가끔 쓰이는 ECL 프로그래밍 언어를 사용한다. 

정리하면서 

하둡은 이질적 소스로부터의 거대하고 다양한 준구조적, 비구조적, 미가공 데이터 볼륨을 저장, 처리, 분석하기 위한 정보 플랫폼으로 성숙하고 있다. 하둡을 시작하려면:
  • 무료 배포판 중 하나를 독립 실행이나 의사 분산 모드로 평가하라. 

  • Tom White의 "Hadoop: The Definitive Guide, Second Edition"을 참고하고, Cloudera, Hortonworks 혹은 아파치 하둡 위키의 지원 페이지에 있는 다른 서비스 제공자로부터 하나 이상의 강좌 수강을 고려하라. 

  • 구성된 클러스터에서는, 네임노드, 세컨더리 네임노드, 맵리듀스 자원 관리자에 대해서 별도의 엔터프라이즈급 서버를 사용하라. . 

  • 랙 감지, 파일 시스템 검사, 로드 밸런싱에 대한 운영 팁을 기억하라. 

  • 사용자 인증, edge 노드 보안 방화벽, 다른 보안 정책으로 보안을 강화하라.
자신의 하둡 경험에 기반해 어떤 배치 팁, 주의, 혹은 모범 사례를 더하거나 지적하겠는가? 

Val Bercovici, Michele Chambers, Julianna DeLua, Glynn Durham, Jeff Hammerbacher, Sarah Sproehnle, M.C. Srivas, and Chris K. Wensel 에게, 원고 초안을 평해준 것에 감사한다.

'IT > bigdata' 카테고리의 다른 글

클라우드를 지탱하는 기술 (2012.12 마소)  (0) 2013.01.29

원문: http://www.lug.or.kr/docs/LINUX/others/12-2.htm

쉘스크립트 (Shell Script) - (III)

임종균 / 서울대학교 컴퓨터공학과 리눅스 프로그래머
(hermes44@secsm.org)


디버깅

    이전 기사를 통해 우리는 간단한 정도의 쉘 스크립트는 작성할 수 있게 되었다. 이제는 다음 단계로 작성한 쉘 스크립트를 디버깅하는 방법에 대해서 다루도록 하겠다. 프로그램을 한 번에 에러없이 작성할 수 있는 천재 프로그래머가 아닌 이상 디버깅이란 코드의 안정성과 완벽함을 높이는 필수적인 작업이다. 또한 대부분의 경우, 코드를 작성하는 것보다도 더 많은 시간이 걸리는 일이 디버깅이다. 보통 리눅스 개발 환경에서 C로 프로그램을 작성하였다면 디버깅 도구로 gdb를 사용할 것이다. 하지만 gdb이전에 가장 좋은 디버깅 방법은 코드 곳곳에 printf를 추가하여 실행 결과를 보고 문제점을 파악하는 것일 것이다. 쉘 스크립트에도 별다른 디버거가 존재하지 않기 때문에 echo를 사용하여 디버깅하는 것이 일반적이다. 하지만 다음에서는 그 방법 이외에 사용할 수 있는 방법을 알아보도록 하겠다.

     

쉘 옵션 기능

    쉘 자체적으로 디버깅을 위해 사용되는 명령행 옵션이 있다. -v는 쉘이 스크립트를 수행하기 위해서 읽은 부분을 화면에 출력해준다. -x는 읽어들인 부분 중에서 실제 실행을 한 부분을 보여준다. 이 결과는 stderr로 출력이 되면 다음의 세 가지 방법 중 하나로 사용할 수 있다.

    ·쉘 스크립트의 첫 줄에 다음과 같이 옵션을 지정한다. 
    #!/bin/sh -xv

    ·소스를 수정하지 않고 한 번만 실행하려면 다음과 같이 스크립트를 실행한다. 
    $ sh -xv [스크립트이름]

    ·스크립트의 전체가 아닌 일부분에서만 이 기능을 사용하려면 사용하려고 하는 부분 앞에 
      다음을 추가한다. 
    set -xv

    ·이 기능을 없애기 위해서 필요한 부분 이후에 다음을 추가한다. 
    set +xv

    첫 번 기사에서 다루었던 예제를 다시 보면서 사용법을 설명하도록 하겠다.

    보면 쉽게 알 수 있듯이  prarg 스크립트는 세 인자를 입력받아서 출력하는 매우 간단한 스크립트이다. 두번째 방법을 이용하여서 실행해 보자.

     

      $ cat ./prarg 
      #!/bin/sh 
      # 
      # prarg: 인자를 출력하다. 
      #

      prog=`basename $0`

      if [ $# -eq 3 ] 
      then 
      echo “Script $prog path: $0” 
      echo “Arg1: $1” 
      echo “Arg2: $2” 
      shift 
      echo “Arg3: $2” 
      else 
      echo “Usage: $ $prog arg1 arg2 arg3” 
      exit 1 
      fi 
      $ ./prarg 1 2 3 
      Script prarg path: ./prarg 
      Arg1: 1 
      Arg2: 2 
      Arg3: 3 
      $ sh -x ./prarg 1 2 3 
      ++ basename ./prarg 
      + prog=prarg 
      + [ 3 -eq 3 ] 
      + echo Script prarg path: ./prarg 
      Script prarg path: ./prarg 
      + echo Arg1: 1 
      Arg1: 1 
      + echo Arg2: 2 
      Arg2: 2 
      + shift 
      + echo Arg3: 3 
      Arg3: 3 
      $ sh -xv ./prarg 1 2 3 
      #!/bin/sh 
      # 
      # prarg: 인자를 출력하다. 
      #

      prog=`basename $0` 
      basename $0 
      ++ basename ./prarg 
      + prog=prarg

      if [ $# -eq 3 ] 
      then 
      echo “Script $prog path: $0” 
      echo “Arg1: $1” 
      echo “Arg2: $2” 
      shift 
      echo “Arg3: $2” 
      else 
      echo “Usage: $ $prog arg1 arg2 arg3” 
      exit 1 
      fi 
      + [ 3 -eq 3 ] 
      + echo Script prarg path: ./prarg 
      Script prarg path: ./prarg 
      + echo Arg1: 1 
      Arg1: 1 
      + echo Arg2: 2 
      Arg2: 2 
      + shift 
      + echo Arg3: 3 
      Arg3: 3

     

    -x 옵션만으로 실행을 할 경우에는 스크립트에서 실행하는 부분만을 보여준다. + 은 쉘이 실행하는 부분, ++는 다른 외부 프로그램이 (이 외부 프로그램은 쉘이 실행한다.) 실행하는 부분을 의미한다. -v 옵션과 같이 실행하면 스크립트를 읽은 부분을 보여준다. if, for, while, case 등의 블럭들은 한 번에 블럭 전체를 읽어서 수행하기 때문에 위의 예제에서와 같은 결과가 나온다. 출력시에는 스크립트의 실행 결과와 디버깅을 위한 출력이 같은 화면으로 보이는 듯하지만 전자는 stdout으로, 후자는 stderr로 표시되는 것이다. 따라서 이 결과를 파일로 리다이렉션하기 위해서는 다음과 같이 실행해야 한다.

      $ sh -xv [스크립트이름]  >[파일명] 2>&1

    2>&1은 stderr(2)의 결과를 stdout(1)과 같은 곳으로 리다이렉션하는 것이다.

    또한 실행문의 결과를 검사하기 위한  -e 옵션이 있다.  -e는 -x에 의해 출력되는 실행문들의 실행 결과가  0이 아닌 값 즉, 실패를 리턴하였을 경우 쉘 스크립트를 종료한다. 하지만 while, until, if문에서 사용하는 조건식이나 &&, ||, !이 포함되있는 실행문에서는  -e가 효과 없다. 
    사용법은  -x, -v를 사용할 때와 같다.

     

      $ cat ./stdio3 
      #!/bin/sh 
      # 
      # stdio3: 표준 입력을 받아 표준 출력으로 표시한다. 
      #

      filename=`line`

      if [ -e $filename ] 
      then 
      echo $filename exists. 
      else 
      echo $filename doesn\’t exist. 
      fi 
      $ ./stdio3 
      ./stdio3: line: command not found 
      exists. 
      $ sh -x ./stdio3 
      ++ line 
      ./stdio3: line: command not found 
      + filename= 
      + [ -e ] 
      + echo exists. 
      exists. 
      $ sh -ev ./stdio3 
      ++ line 
      ./stdio3: line: command not found 
      + filename=

     

    -e 옵션을 주고 실행한 경우 if 이전의 실행문이 실패를 하여 if 가 실행되기 전에 종료함을 알 수 있다.

     

조건식

    조건식을 일반적인 컴파일 언어에서와 비슷하게 사용할 경우 생각지도 않는 에러가 발생하는 경우가 있다.

    수식 검사 조건식에서 검사하려는 변수가 존재하지 않거나 값이 설정되지 않았을 경우 에러가 발생한다. 즉, 다음과 같은 조건식에서

      if [ “$count” -eq 3 ]

    count 변수가 존재하지 않거나 값이 설정되어 있지 않으면 다음과 같이 해석이 되어

      if [ “” -eq 3 ]

    아래와 같은 에러가 발생한다. 

      [: integer expression expected before -eq

    이를 방지하기 위해서는 위의 수식을 다음과 같이 바꾼다.

      if  [ “0$count” -eq 3 ]

    이 때는 위와 같은 에러 상황일 때 0을 리턴하게 되고 count 변수값이 3일 경우에는  03을 리턴하게 되어 에러없이  조건식이 수행이 된다.

    문자열 검사 조건식에서는 검사하려는 문자열이 조건식에서 사용하는 키워드일 경우 에러가 발생한다. 즉, 그 문자열이 -eq, -ne, -gt, -r, -w, -z, -f등의 것들일 때이다. 이 경우에는 비교하려는 문자열 앞에 적당한 문자를 추가하여 앞에서와 같은 것들이 조건식에서 나오지 않도록 한다.

      if  [ “$op” = -gt ]

    를 다음과 같이 변경을 한다.

      if  [ “Z$op” = Z-gt ]

    앞의 -e 옵션을 설명할 때 보았던 것과 같이 쉘 스크립트에서 실행문이 실패한다고 해서 스크립트가 중단되지는 않는다. (중단시키려면 -e 옵션을 주어야 한다.) 하지만 중단이 된다는 잘못된 착각을 하여 스크립트를 작성하는 경우가 있다. 다음의 경우에는 그것이 치명적인 결과를 나을 수 있다.

     

      $ cat clean 
      #!/bin/sh

      tempdir=’/tmp /usr/tmp /var/tmp’

      for dir in $tempdir 
      do 
      cd $dir 
      rm -rf * 
      done

      echo “Cleanup done !”

     

    ‘cd $dir’이 실패할 경우에도 다음 실행문인 ‘rm -rf *’은 실행이 된다. cd가 실패를 한다면 생각지도 않는 디렉토리의 내용을 다 지워버리는 결과를 나을 수 있다. 이런 문제를 방지하기 위해 이와같이 다음에 치명적인 실행문이 올 경우 이전의 실행문이 실패하면 실행하지 않도록 한다. || 조건을 이용 cd 실행문을 바꾼다.

      cd $dir || exit

    이 경우 || 앞의 cd가 실패할 경우 exit가 실행되어 더 이상 진행되지 않도록 한다. cd가 성공한 경우에는 || 조건식은 항상 참이 되기 때문에 || 우측의 exit는 실행되지 않는다. 위의 예제에서는 exit 대신 continue를 써도 무방하다.

 

변수값 확인하기

    쉘 스크립트에 대화식으로 변수값을 확인할 수 있는 방법이 있다. 그런 기능을 하는 코드를 쉘 스크립트 중간에 삽입하는 방법이다.

      while echo -n “Enter a variable name you want to know; \
      just ENTER to quit: “ 
      read var 
      do 
      case “$var” in 
      “”) break ;; 
      *) eval echo \$$var ;; 
      esac 
      done

    이 트레이스(trace) 코드 이전에 사용된 변수의 값을 확인해 볼 수가 있다.

     

    $ cat trace 
    #!/bin/sh 
    # 
    # trace: 변수값을 보여주는 트레이스 코드를 사용해 본다. 
    #

    dir=`dirname $0` 
    file=`basename $0`

    count=0

    for arg in $* 
    do 
    count=`expr $count + 1`

    # Trace code 
    while echo -n “Enter a variable name you want to know; just ENTER to quit: “ 
    read var 
    do 
    case “$var” in 
    “”) break ;; 
    *) eval echo \$$var ;; 
    esac 
    done 
    done 
    $ ./trace a b cde fg h 
    Enter a variable name you want to know; just ENTER to quit: dir 
    . 
    Enter a variable name you want to know; just ENTER to quit: file 
    trace 
    Enter a variable name you want to know; just ENTER to quit: count 
    1 
    Enter a variable name you want to know; just ENTER to quit: arg 
    a 
    Enter a variable name you want to know; just ENTER to quit: [ENTER] 
    Enter a variable name you want to know; just ENTER to quit: count 
    2 
    Enter a variable name you want to know; just ENTER to quit: arg 
    b 
    Enter a variable name you want to know; just ENTER to quit: [ENTER] 
    Enter a variable name you want to know; just ENTER to quit: count 
    3 
    Enter a variable name you want to know; just ENTER to quit: arg 
    cde 
    Enter a variable name you want to know; just ENTER to quit: [ENTER] 
    Enter a variable name you want to know; just ENTER to quit: count 
    4 
    Enter a variable name you want to know; just ENTER to quit: arg 
    fg 
    Enter a variable name you want to know; just ENTER to quit: [ENTER] 
    Enter a variable name you want to know; just ENTER to quit: count 
    5 
    Enter a variable name you want to know; just ENTER to quit: arg 
    h 
    Enter a variable name you want to know; just ENTER to quit: [ENTER]

    ([ENTER]은 ENTER를 눌렀음을 의미한다.)

     

결론

    이제까지 쉘 스크립트의 작성과 디버깅에 관한 사항을 알아보았다. 물론 지금까지 다룬 내용이 쉘 스크립트의 전부는 아니다. 자잘하고 미묘한 부분들 하지만 중요한 부분들은 다루지 못했으며, 현재 많이 사용하는 bash나 tcsh의 확장 기능도 남아 있다. 이제 그 부분은 독자들에게 남겨진 몫이며 이 기사를 통해 그 시작을 할 수 있기를 바란다. 일단은 다른 사람들이 만들어 놓은 스크립트를 보고 이해하면서 코드를 수정해보고 필요한 스크립트를 하나씩 만들어 가면서 익히면 될 것이다. 그리고 작성중에 막히는 부분은 매뉴얼 페이지가 큰 도움이 될 것이다.  man bash ! 
    참고자료

    UNIX POWER TOOLS, 2ed. Jerry Peek, Tim O’Reilly, Mike Loukides. O’Reilly 
    bash 매뉴얼 페이지

'IT > language' 카테고리의 다른 글

쉘스크립트 (Shell Script) - (II)  (0) 2013.01.28
쉘스크립트 (Shell Script) - (I)  (0) 2013.01.28

원문 : http://www.lug.or.kr/docs/LINUX/others/11-3.htm

쉘스크립트 (Shell Script) - (II)

임종균 / 서울대학교 컴퓨터공학과 리눅스 프로그래머
(hermes44@secsm.org)


표준 입출력

    이전 기사에서 표준 출력(stdout)으로 출력을 하기 위해서 echo 명령을 - 외부 프로그램으로 같은 역할을 하는 echo가 있지만 여기서의 echo는 쉘의 내장(built-in)명령이다. - 사용하였다. 그렇다면 표준 입력(stdin)으로 사용자 입력을 받을 수 있는 방법은? 표준 입력을 받아 변수에 저장을 해주는 read 명령이 있다.
     

    $ cat ./stdio
    #!/bin/sh
    #
    # stdio: 표준 입력을 받아 표준 출력으로 표시한다.
    #

    echo -n “Type the filename: “
    read filename

    if [ -e $filename ] 
    then
    echo $filename exists.
    else
    echo $filename doesn\’t exist.  
    fi
    $ ./stdio
    Type the filename: /dev/fd0
    /dev/fd0 exists.
    $ ./stdio
    Type the filename: /dev/fd0 ./stdio
    ./stdio: [: /dev/fd0: binary operator expected
    /dev/fd0 ./stdio doesn’t exist.

 

    stdio 예제에서 처럼 read는 표준 입력의 한 줄을 모두 filename이라는 변수에 넣는다. (한 줄은 엔터를 입력함으로서 끝난다.) 하지만 위와 같이 할 경우, 입력값이 여러 개라면 문제가 생길 수 있다. 두 개의 파일명을 공백으로 구분하여 입력할 경우 각각이 따로 저장되는 것이 아니라 하나의 filename 변수에 들어가기 때문에 if 조건식에서 실패를 한다. 이런 경우 가장 처음에 입력된 파일명만을 받아 처리하고 나머지는 무시하려면? read 다음에 변수를 여러 개를 명시하면 된다. 표준 입력은 공백 문자로 - 스페이스와 탭 - 구분이 되고 구분된 각각의 값들은 read 다음에 명시된 변수에 차례로 채워진다. 가장 마지막 변수에는 나머지 남아있는 입력값들이 모두 다 들어간다.
     

    $ cat ./stdio2
    #!/bin/sh
    #
    # stdio2: 표준 입력을 받아 표준 출력으로 표시한다.
    #

    echo -n “Type the filename: “
    read filename1 filename2 dummy

    for fn in $filename1 $filename2
    do
    if [ -e $fn ]
    then
    echo $fn exists.
    else
    echo $fn doesn\’t exist.
    fi
    done

    echo Ignore $dummy
    $ ./stdio2
    Type the filename: /dev/hda1 /etc/bashrc /bin/sh /bin/ls
    /dev/hda1 exists.
    /etc/bashrc exists.
    Ignore /bin/sh /bin/ls

 

    즉, stdio2의 예에서 공백으로 구분된 입력 /dev/hda1은 filename1에, /etc/bashrc는 filenam2에 /bin/sh /bin/ls는 dummy에 들어가게 되는 것이다.
    암호를 입력받을 경우와 같이 잠시 키보드 입력이 화면에 표시되지 - 이렇게 입력이 화면에 출력되는 것을 echo라고 말한다. - 않게 하려면 stty 프로그램을 이용하여 echo를 없애면 된다. 후에 다시 복원을 해야한다. 스크립트가 echo를 다시 복원하지 못하고 비정상적으로 종료할 경우를 대비하여 반드시 trap 구문을 두어야 한다.
     

    $ cat pswd
    #!/bin/sh
    #
    # pswd: 암호를 입력받는다.
    #

    trap ‘stty echo; exit’ 0 1 2 3 15

    echo -n “Enter password: “
    stty -echo
    read password
    stty echo
    echo

    echo “Your password is $password”

 

리다이렉션 (Redirection)

    우리는 쉘 상에서 <, >, >>를 이용하여 표준 입출력을 리다이렉션(redirection)할 수 있다.
    쉘 스크립트 상에서도 그와 같은 일이 가능하다. exec를 이용하는 것이다.
     

    $ cat redirect
    #!/bin/sh
    # 
    # redirect: 표준 입력을 파일로 리다이렉션한다.
    #

    temp=/tmp/delme$$
    # $$는 현재 프로세스의 id값을 넘겨준다.
    echo “This is line1.
    This is line2.
    This is line3.” > $temp
    exec < $temp
    read line; echo $line
    read line; echo $line
    read line; echo $line
    $ ./redirect
    This is line1.
    This is line2.
    This is line3.

 

    redirect 예제에서 exec 명령에 의해서 표준 입력이 /tmp/delme$$ 파일로 리다이렉션되어 read 명령은 그 파일에서 한 줄씩 입력을 받게 된다. 본 쉘의 리다이렉션에서 각 표준 입력, 표준 출력, 표준 에러는 파일 디스크립터 0, 1, 2에 해당한다. 그 외에 3~9까지 디스크립터를 사용할 수 있다.
     

    $ cat fredirect
    #!/bin/sh
    #
    # fredirct: 동적인 리다이렉션 변경
    #

    outfile=fredirect.out

    exec 3<&1
    # 표준 출력과 3번 파일 디스크립터를 일치시킨다. 
    # 표준 출력을 3번 파일 디스크립터에 저장해두는 역할

    /bin/rm -f $outfile

    while 
    echo -n “Enter command or CTRL-D to quit: “
    read cmd
    do
    exec >> $outfile
    # 표준 출력을 fredirect.out 파일로 리다이렉션
    echo $cmd
    exec >&3
    # 파일로 변환된 것은 다시 표준 출력으로 복원
    done
    $ ./fredirect
    Enter command or CTRL-D to quit: 21
    Enter command or CTRL-D to quit: 234
    Enter command or CTRL-D to quit: 2
    Enter command or CTRL-D to quit: sjf
    Enter command or CTRL-D to quit: sd
    Enter command or CTRL-D to quit: kd
    Enter command or CTRL-D to quit: 
    $ cat fredirect.out 
    21
    234
    2
    sjf
    sd
    kd

 

    while, until, for, if, case 구문에서 가장 마지막 줄에 - done, fi, esac 뒤에 - 리다이렉션을 지정하여 그 구문 내에서의 입출력만을 변경할 수 있다. 그 구문을 빠져나올 때에는 원래대로 복원이 된다.
     

    $ cat bredirect
    #!/bin/sh
    #
    # bredirct: 특정 구문에서만 리다이렉션을 한다.
    #

    for arg
    do
    echo $arg
    done > bredirect.out 2> /tmp/bredirect.err

    # 에러를 표준 에러로 출력하고 임시 에러 파일을 지운다.
    if [ -s bredirect.err ]
    then
    /bin/cat /tmp/bredirect.err 1>&2
    fi
    /bin/rm -f /tmp/bredirect.err
    $ ./bredirect 1 2 3 45
    $ cat ./bredirect.out
    1
    2
    3
    45

 

경로명

    쉘 스크립트를 이용하여서 파일을 다루다보면 경로명을 조작해야할 필요가 있다. 보통 경로명은 ‘디렉토리명/파일명’ 형식으로 되어 있다. 이렇게 사용자의 입력이나 환경 변수 등을 통해서 얻어진 경로명에서 디렉토리명와 파일명을 분리해주는 basename과 dirname이라는 프로그램이 있다.

      basename <경로명>

    은 경로명에서 파일명만을 넘겨준다. 이 때 파일이 실제로 존재할 필요는 없다.

      basename <경로명> <확장자>

    은 파일명에서 지정한 확장자 부분을 없앤다.

      dirname <경로명>

    은 경로명에서 디렉토리 부분만을 넘겨준다.
     

    $ basename /home/httpd/index.html
    index.html
    $ basename /home/httpd/index.html .html
    index
    $ dirname /home/httpd/index.html
    /home/httpd

     

수식 계산 : expr

    스크립트에서는 기본적인 모든 값들을 문자열로 처리하기 때문에 숫자값을 이용한 수식 계산을 하기 위해서는 expr 프로그램을 이용해야 한다.

      expr 인자1 연산자 인자2 [연산자 인자3 ...]

    인자는 숫자값이나 문자열이 될 수 있고, 연산자는 수식 연산자, 관계 연산자, 논리 연산자 세 가지 종류가 있다. 인자와 연산자 사이에는 반드시 공백으로 구분되어야만 한다. expr의 결과값이 0이 아니거나 null이 아니면 종료 상태값은 0이다. 0이나 null일 경우에는 1이고 수식이 유효하지 않을 경우는 2이다.

    지원하는 수식 연산자는 +, -, *, /, %가 있고, 연산 순위는 일반적인 순위를 따른다. 연산 순위 변경을 위한 괄호 또한 사용할 수 있다. *, (, )는 쉘에서 특별히 사용되기 때문에 수식에서 사용하려면 \와 함께 쓰여야 한다. 수식 연산자가 올 때의 인자는 정수값이 되어야만 한다. 수식 계산의 결과값이 출력된다.
     

    $ expr 3 + 5 \* 2
    13
    $ expr \( 3 + 5 \) \* 2
    16
    $ echo $1
    1
    $ expr $i + 1
    2

 

    지원하는 관계 연산자는 =, !=, >, >=, <, <= 이 있고, >와 <는 \과 함께 사용되어야 한다. 비교한 결과가 참이면 1을 출력하고, 거짓이면 0을 출력하다. 이 때 인자는 정수, 실수, 문자열이 모두 다 올 수 있다.
     

    $ echo $USER
    hermes44
    $ expr $USER = hermes44
    1
    $ expr 3 \> 5
    0
    $ expr 4.5 \<= 4.5
    1

 

    논리 연산자는 3가지가 있다. |, &, :이다. 각 OR, AND, 정규식 검색을 나타내며 |와 &는 \와 함께 사용되어야 한다.

    ·|는 OR이다. 인자1과 인자2가 둘 다 0이 아니면 인자1을 출력하고 그렇지 않으면 0을 
       출력한다. 
    ·&는 AND이다. 인자 1이 0이 아니면 인자 1을 출력하고, 그렇지 않으면 인자 2를 출력한다.
    ·:는 정규식(regular expression) 검색이다. 인자1에는 어떤 문자열이 오고, 인자2에는 정규식
       이 온다. 인자1에서 인자2로 주어진 정규식에 해당하는 패턴을 찾는다.인자2를 \(와 \)로
       괄호를 씌우면 패턴에 해당하는 인자1의 부분을 출력하고 괄호가 없을 때에는 패턴이 일치
       하는 회수를 출력한다.(정규식의 형식에 대한 사항은 이 기사의 범위를 넘어가기 때문에 
       생략한다).
     

    $ echo $1
    1
    $ expr $i \> 5 \| $i + 1
    2
    $ expr $i \< 5 \& $i + 1
    1
    $ export d=`date`; echo $d
    Mon Oct 10 00:53:04 KST 1999
    $ expr “$d” : ‘.*’
    28
    $ expr “$d” : ‘\(.*\)’
    Mon Oct 18 00:53:04 KST 1999
    $ expr “$d” : ‘[a-zA-Z]*’
    3
    $ expr “$d” : ‘\([a-zA-Z]*\)’
    Mon

 

여러 프로그램을 하나의 스크립트로

    많은 스크립트를 작성을 하다 보면 다음과 같은 경우가 발생할 수 있다.

    ·같은 동작을 하는 다른 이름의 프로그램들. 예를 들어 문서 편집기인 ex, vi, view는 이름은
      다르지만 다 같은 프로그램이다. 하지만 어떤 이름으로 실행하느냐에 따라 동작이 조금씩 
      다르다. ex는 줄 편집기 모드로 시작하고, vi는 화면 편집기 모드로 시작한다. view는 읽기 
      전용 모드로 파일을 연다.
    ·다른 프로그램이지만 공통되는 부분이 많다. 예를 들어 jdk패키지의 들어있는 java, javac,
      javadoc, jar, jdb, appletview 등은 모두 .javawrapper 스크립트에 링크되어 있다.
      .javawrapper는 자바 환경을 설정을 하고 해당하는 프로그램을 실행시켜 준다.

    이와 같은 경우에 공통되는 부분을 하나로 묶어 주게 된다면 디스크 공간을 절약할 수 있을 뿐만 아니라, 코딩에 드는 노력도 줄여줄 수 있고, 각 공통되는 부분에 대한 일관성을 유지할 수가 있다. 쉘 스크립트에서는 공통되는 부분을 처리하고 실행한 프로그램의 이름을 살펴보아 각각에 해당하는 처리를 한다.

    공통 부분에 대한 핵심 스크립트를 만든다. 각각의 프로그램은 핵심 스크립트에 대한 링크로 만든다. 그 스크립트에서는 공통된 부분을 처리하고 프로그램의 이름, $0를 보고서 각 프로그램에 대한 작업을 수행한다.
     

    $ cat sc_core
    #!/bin/sh
    #
    # sc_core: 공통되는 부분을 처리하는 핵심부분
    #

    echo Setup the Environments and Flags

    case “$0” in
    *sc1)
    echo Excute sc1 ;;
    *sc2)
    echo Excute sc2 ;;
    *)
    echo Invalid commnad !
    exit 1 ;;
    esac
    $ ln -s sc_core sc1
    $ ln -s sc_core sc2
    $ ./sc1
    Setup the Environments and Flags
    Excute sc1
    $ ./sc2
    Setup the Environments and Flags
    Excute sc2

 

    실행한 파일이름을 찾을 때 sc_core 예제에서와 같이 ‘*파일명’ 패턴을 이용하는 방법도 있고 basename 프로그램을 사용할 수도 있다.
     

    $ cat jc_core
    #!/bin/sh
    #
    # jc_core: basename을 이용한 또 다른 방법
    #

    jcpath=’/usr/local/bin’
    jcprogram=`basename $0`

    echo Setup the Environments and Flags

    case “$jcprogram” in
    jcc)
    echo Excute jcc ;;
    jdb)
    echo Excute jdb ;;
    *)
    echo “$jcpath/$jcprogram” ;;
    esac
    $ ln -s jc_core jcc
    $ ln -s jc_core jdb
    $ ln -s jc_core jzip

    $ ./jcc
    Setup the Environments and Flags
    Excute jcc
    $ ./jdb
    Setup the Environments and Flags
    Excute jdb
    $ ./jzip
    Setup the Environments and Flags
    /usr/local/bin/jzip

 

결론

    스크립트를 작성하는 일이 다 끝이 났다면 이제 마지막으로 남은 것은 스크립트의 이름을 정하는 것이다. 어떤 이름을 짓던지 상관은 없지만 한 가지 주의할 것은 이미 있는 프로그램의 이름을 사용해서는 안 된다는 것이다. 우리가 정한 이름이 이미 존재하는 지는 다음과 같은 방법으로 찾아보면 된다.

      man 1  <스크립트 이름>
      which   <스크립트 이름>
      whereis <스크립트 이름> 
      alias     <스크립트 이름>
      type     <스크립트 이름>

    모든 가능성을 검사해 보고 없는 이름으로 정한다.

    이렇게 스크립트의 작성이 끝이 났다. 이제는 반복적인 일을 간단히 처리해주는 나름대로의 스크립트는 작성할 수 있을 것이다. 부족한 부분이 있기는 하지만 그런 부분들은 많은 시도를 통해서 채득할 수 있을 것이라 생각한다. 또한 쉘 스크립트를 작성하기 위해서는 사용하는 쉘에 대한 이해도 필요하다. 다음 기사에서는 작성한 스크립트를 디버깅하는 방법을 알아보자.

     

·참·고·자·료·

·UNIX POWER TOOLS, 2ed. Jerry Peek, Tim O’Reilly, Mike Loukides. O’Reilly
·bash 매뉴얼 페이지

'IT > language' 카테고리의 다른 글

쉘스크립트 (Shell Script) - (III)  (0) 2013.01.28
쉘스크립트 (Shell Script) - (I)  (0) 2013.01.28


원문 : http://www.lug.or.kr/docs/LINUX/others/10-4.htm

쉘스크립트 (Shell Script) - (I)

임종균 / 서울대학교 컴퓨터공학과 리눅스 프로그래머
(hermes44@secsm.org)


들어가며

    쉘 스크립트란 쉘에서 사용할 수 있는 명령어들의 조합을 모아서 만든 배치(batch) 파일이다. 리눅스에서는 여러 명령어들을 파이프(pipe), 리다이렉션(redirection), 필터(filter) 등으로 연결하여 원하는 결과를 얻어 낼 수 있다. 이런 방식으로 묶여진 명령어 조합이 반복적으로 사용된다면 이를 쉘 스크립트로, 즉 단일 명령으로 만들어 쉽게 사용할 수 있다.

    스크립트라고 하는 것은 인터프리터(interpreter)에 의해 해석/실행되는 프로그램을 말한다. 어떤 종류의 인터프리터를 사용하는 가에 따라서 어떤 스크립트인가에 대한 이름이 정해진다. 쉘 스크립트, 펄(Perl) 스크립트, Tcl/Tk 스크립트 등의 이름에서 사용하는 인터프리터를 알 수 있다. 쉘 스크립트는 인터프리터로 쉘을 사용하는 스크립트를 가르킨다. 또한 어떠한 쉘을 사용하는 가에 따라서 본(bourne) 쉘 스크립트, C 쉘 스크립트, 콘(Korn) 쉘 스크립트, TC 쉘 스크립트 등으로 나뉜다.

    이 연재에서는 쉘 스크립트 중의 기본이 되는 본 쉘 스크립트에 대해서 살펴볼 것이다. 본 쉘 스크립트에서 사용하는 기능과 문법은 다른 쉘에서도 지원이 된다. 따라서 실제 사용할 때는 다른 쉘을 사용할 수도 있을 것이다. 필자는 bash 1.14.7을 사용하여 설명을 할 것이다.

     

어떤 것이 쉘 스크립트?

    우리는 알게 모르게 많은 쉘 스크립트을 사용한다. 그렇다면 어떤 것이 쉘스크립트인가? 확인을 해보는 방법은 file와 grep명령을 사용해서 찾아보는 것이다. 필자의 시스템에서의 결과는 다음과 같다.

     

      $ (cd /bin ; file * |grep “shell script”)
      false :                   Bourne shell script text
      igawk :                  Bourne shell script text
      remadmin :            Bourne shell script text
      true :                    Bourne shell script text
      $ (cd /usr/bin ; file * |grep “shell script”)
      anytopnm :           Bourne shell script text
      apropos :             Bourne shell script text
      audiocompose :    C shell script text
      audiosend :          C shell script text
      autoconf :            Bourne shell script text
      autoheader :         Bourne shell script text
      autoreconf :         Bourne shell script text
      autoupdate :         Bourne shell script text
      bash2bug :           Bourne shell script text
      bashbug :             Bourne shell script text
      batch :                Bourne shell script text
      bdftops :             Bourne shell script text
      bzless :                Bourne shell script text
      ......
      whatis :               Bourne shell script text
      wv-incconfig :      Bourne shell script text
      wv-libconfig :      Bourne shell script text
      xbm2ikon :           Bourne shell script text
      xbmcut48 :          Bourne shell script text
      xbmsize48 :         Bourne shell script text
      zcmp :                Bourne shell script text
      zdiff :                  Bourne shell script text
      zforce :               Bourne shell script text
      zgrep :                Bourne shell script text
      zipgrep :             Bourne shell script text
      zless :                 Bourne shell script text
      zmore :               Bourne shell script text
      znew :                Bourne shell script text

     

    위의 명령으로 확인을 해보면 false, true, apropos, netscape, nohup, pdf2ps, ps2pdf, whatis, zgrep, zless 등 많은 쉘 스크립트가 있음을 알 수 있다.

     

쉘 스크립트 작성하기

    스크립트의 특징 중의 하나는 그 내용이 텍스트 형식이기 때문에 일반 편집기로 볼 수 있다는 것이다. 위에서 찾는 스크립트 중 아무 것이나 cat, vi, emacs 등으로 보아라. 여러 명령들과 스크립트 문법의 조합으로 되어 있는 것을 확인할 수 있다.

    스크립트의 가장 첫줄은 항상 #!로 시작한다. #! 다음에는 이 스크립트를 실행할 인터프리터와 그 실행 옵션을 지정한다. 쉘 스크립트에서는 #!/bin/sh, #!/bin/csh, #!/bin/bash, #!/bin/ksh, #!/bin/tcsh와 같이 쉘의 절대 경로를 써준다. 전통적인 관습에 의하여 #!만 써줄 경우에는 #!/bin/sh로 인식을 한다.
    따라서 본 쉘 스크립트 작성시에는 첫 줄은 #!/bin/sh나 #!로 하면 된다.

    이제 앞의 예제를 바탕으로 간단한 ‘findscript’ 쉘 스크립트를 작성하여 보자. 이 스크립트는 /bin, /usr/bin에서 쉘 스크립트를 찾아 보여준다.

     

      $ cat findscript
      #!/bin/sh#
      # findscript: /bin, /usr/bin에 있는 쉘 스크립트를
      찾는다.
      #

      (cd /bin; file * | grep “shell script”)
      (cd /usr/bin; file * | grep “shell script”)
      $ chmod +x findscript.sh
      $ ./findscript.sh

 

    cat 또는 다른 편집기를 이용하여 위에서 처럼 작성을 하고, 실행 가능하도록 퍼미션을 준다. 그리고서 다른 프로그램 처럼 실행을 하면 된다. 위에서 본 것과 같이 기본적으로 쉘 스크립트는 쉘에서 사용할 수 있는 명령들의 집합이다. 여기에 덧붙여 쉘에서는 쉘 스크립트에서 사용할 수 있는 나름의 문법을 제공한다.

     

종료 상태 (Exit status)

    각 명령들은 실행을 올바로 마치고 정상적인 종료(성공/참)하거나, 실행 오류 또는 인터럽트에 의한 중단과 같은 이유로 비정상적으로 종료(실패/거짓)할 수 있다. 이 성공과 실패는 명령의 종료 상태값으로 알 수 있다. 보통 0은 성공을 나타내며, 0이 아닌 값은 실패를 나타낸다. 쉘에서는 이전에 실행한 명령이 성공을 하였는지 실패를 하였는지를 ? 변수값에 저장을 한다.

     

      $ who | grep root
      $ echo $?
      1
      $ who | grep hermes44
      hermes44 : 0       Sep 16 11:34
      hermes44 pts/0    Sep 16 11:36
      hermes44 pts/1    Sep 16 14:07
      $ echo $?
      0
      $ false; echo $?
      1
      $ true; echo $?
      0

     

    false 명령은 항상 1, 실패의 종료 상태를 반환하고 true 명령은 항상 0, 성공의 종료 상태를 반환한다.

    쉘 스크립트에서는 exit를 이용하여 스크립트를 종료하면서 종료 상태를 반환할 수 있다. exit만을 사용하면 쉘 스크립트를 종료하고 가장 마지막에 실행한 명령의 종료 상태를 반환하고, exit <숫자>를 사용하면 종료하고 <숫자> 값을 쉘에 반환한다.

     

      $ cat return_exit
      #!/bin/sh
      #
      #return_exit: <인자>의 값을 종료 상태로
      #반환한다.
      #

      if [ $# -eq 0 ]
      then
            exit
      else
            exit $1
      fi
      $ ./return_exit; echo $?
      0
      $ ./return_exit 8; echo $?
      8

     

      if 구문은 조건식에 따라서 분기를 한다.
         형식은 다음과 같다.

      if 조건식
      then
              명령들
      [ elif 조건식
         then
              명령들 ]
      [ else
              명령들 ]
      fi

    if의 조건식이 참이면, 즉 0을 반환하면 then 다음의 명령들을 수행하고, 거짓이면, 즉 0이 아닌 값을 반환하면 (대개 1이다) else 다음의 명령을 수행한다. elif는 if의 조건식이 거짓이 될 경우에 분기되어 다시 새로운 조건식을 검사한다. elif나 else 구문은 생략이 가능하다. fi는 if 구문의 끝은 나타낸다. (fi는 if를 거꾸로 쓴 것이다. :-))

    위의 예제 스크립트에서 if 조건문의 [ $# -eq 0 ]는 스크립트의 인자의 갯수($#)가 0과 같은지(-eq)를 검사하는 것이다. 인자가 없다면 exit를 수행하고 마지막으로 수행한 명령인 조건식의 종료 상태값 0을 반환하다. 인자가 있다면 else 구문에서 첫번째 인자 값을($1)을 종료 상태로 반환한다.

    쉘 스크립트가 수행도중에 인터럽트를 받아서 비정상적으로 종료할 수도 있다. 이런 경우에는 임시로 사용한 파일을 삭제하는 것과 같은 정리 작업을 수행할 수 없게된다. 이를 방지하기 위한 trap 구문이 있다. 형식은 다음과 같다.

      trap ‘명령들’ [시그널 번호들]

    인터럽트에 해당하는 시그널 번호를 써준다. 이 번호는 kill -l을 하면 알 수 있다.시그널 번호를 0을 쓸 경우는 쉘 스크립트가 정상적인 종료를 할 경우를 나타낸다.

    아래의 쉘 스크립트를 수행하면 loop 라는 글씨가 화면에 계속 출력될 것이다. 여기서 사용된 while은 무한 루프를 돌게 된다. 루프에 대해서는 뒤에서 보겠다. 종료를 하기 위해서 Ctrl+C(SIGINT,2)를 누르더라도 이는 첫번째 trap 구문에 의해서 메세지만을 출력한다. 
    Ctrl+\(SINQUIT,3)를 누르면 스크립트는 종료를 하게된다.

     

     $ kill -1

    1) SIGHUP

    2) SIGINT

    3) SIGQUIT

    4) SIGILL

    5) SIGTRAP

    6) SIGIOT

    7) SIGBUS

    8) SIGFPE

    9) SIGKILL

    10) SIGUSR1

    11) SIGSEGV

    12) SIGUSR2

    13) SIGPIPE

    14) SIGALRM

    15) SIGTERM

    16) SIGCHLD

    17) SIGCONT

    18) SIGSTOP

    19) SIGTSTP

    20) SIGTTIN

    21) SIGTTOU

    22) SIGURG

    23) SIGXCPU

    24) SIGXFSZ

    25) SIGVTALRM

    26) SIGPROF

    27) SIGWINCH

    28) SIGIO

    29) SIGPWR

     

     

     

    $ cat trap_exit
    #!/bin/sh
    #
    #trap_exit: trap 테스트
    #

    trap ‘echo basename $0: signal catch’ 1 2 15
    trap ‘echo script exit; exit’ 3

    while :
    do
            echo loop
    done
    $ ./trap_exit

     

명령행 인자 (Command-line argument)

    쉘 스크립트에서는 최대 9개의 명령행 인자를 받을 수 있다. 그 값은 $1~$9에 저장된다. (최신 쉘에서는 그 이상의 인자를 받을 수도 있다. ${10}과 같은 형식이다.) $0에는 실행한 쉘 스크립트의 경로가 저장된다. 또한 위에서 잠깐 보았듯이 $#에는 인자의 개수가 저장이 된다.

    스크립트 중에 shift를 사용하였음을 주목하라. shift는 $1 인자를 없애고 각 인자번호를 1씩 줄인다. 즉 $2는 $1, $3은 $2, $4은 $3과 같은 식으로 된다.

     

      #!/bin/sh
      #
      # prarg: 세 개의 인자를 출력하다.
      #

      prog= basename $0

      if [$# -eq 3 ]
      then
            echo “Script $prog path: $0”
            echo “Arg1: $1”
            echo “Arg2: $2”
            shift
            echo “Arg3: $2”
      else
            echo “Usage: $ $prog arg1 arg2 arg3”
            exit
      fi
      $ ./prog es 34
      Usage: $ prarg arg1 arg2 arg3
      $ ./prog 28 ksl 9
      Script prarg path: ./prarg
      Arg1: 28
      Arg2: ksl
      Arg3: 9

     

    그래서 shift한 이후에는 세번째 인자가 $2가 되는 것이다. 이때 $# 값도 1준다.

    모든 인자는 “$@”, $*에 저장이 된다. “$@”는 명령행에서 사용한 따옴표가 그래도 적용되지만, $*에서는 그 따옴표가 적용되지 않는다. 따옴표에 유무에 따라서 쉘에서 사용하는 특수문자들 - 공백, 탭, \, ‘, “, ` 등 - 해석할 것인지의 여부가 결정이 된다. 이는 쉘을 사용하는 것에 관한 문제이기 때문에 더이상 자세히는 다루지 않겠다.

    $$에는 현재 쉘 스크립트의 프로세스 ID가 저장이 된다. 이는 명령행 인자는 아니지만 임시 파일을 만들 때와 같은 경우에 유융하게 사용된다.

 

루프 (Loop)

    쉘 스크립트에서 사용할 수 있는 루프는 세 가지가 있다.

      while  조건식
      do
                명령들
      done

    while 루프는 조건식이 참인 동안 do~done 사이의 명령을 수행한다.

     

      $ cat arg-while
      #!/bin/sh
      #
      # arg-while: 모든 인자를 출력한다.
      #

      echo Argument number: $#
      while [ $# -gt 0 ]
      do
            echo $1
            shift
      done
      $ ./arg-whilel 1 2 3 4
      Argument number: 4
      1
      2
      3
      4

     

      until   조건식
      do
                명령들
      done

    until 루프는 조건식이 참이 될 때까지 do~done 사이의 명령을 수행한다.

     

      $ cat arg-until
      #!/bin/sh
      #
      # arg-until: 모든 인자를 출력한다.
      #

      echo Argument number: $#
      until [ $# -eq 0 ]
      do
            echo $1
            shift
      done
      $ ./arg-until 1 2 3 4
      Argument number: 4
      1
      2
      3
      4

     

      for 변수 in [문자열 목록]
      do
            명령들
      done

     

      $ cat arg-for
      #
      !/bin/sh
      #
      # arg-for: @ 인자앞의 인자를 출력한다.
      #
      echo Argument number: $#
      for arg
      do
      if [ $arg = @ ]
      then
      break
      fi
      echo $arg
      done
      $ ./arg-for 1 2 @ 3 2 4 6
      Argument number: 7
      1
      2

     

    for 루프는 문자열 목록의 값들이 for 변수에 지정되어 do~done 사이의 명령을 수행한다. in 부분을 생략하면 명령행 인자가 사용된다. break를 사용하면 루프를 빠져나온다.

    루프는 아닌지만 C에서의 switch와 비슷한 역할을 하는 case구문이 있다.
    case의 형식은 다음과 같다.

      case 변수 in
      패턴1) 명령들 ;;
      패턴2) 명령들 ;;
      *) 명령들 ;;
      esac

    변수값을 패턴1부터 비교해가면서 해당하는 패턴이 있으면 그에 해당하는 명령들을 수행한다. ;;은 패턴에 해당하는 명령의 끝을 나타내고 esac은 (case를 거꾸로 쓴 것이다.) case 구문의 끝을 나타낸다. 해당되는 패턴이 없다면 * 패턴의 명령을 수행하게 된다. 패턴에는 쉘에서 사용할 수 있는 와일드 카드(*,?), 정규표현식, 문자열, 변수가 올 수 있다.

     

      $ cat check-flag
      #!/bin/sh
      #
      # check_flag: 인자를 검사하여 flag를 켠다.
      #

      aflag=0
      bflag=0

      for arg
      do
                case $arg in
                 -a) aflag=1 ;;
                 -b) bflag=1 ;;
             *) echo “Usage: `basename $0` [-a] [-b]” 1>&2
                exit 1 ;;
             esac
      done

      echo aflag=$aflag bflag=$bflag
      $ ./check-flag
      aflag=0 bflag=0
      $ ./check-flag -a
      aflag=1 bflag=0
      $ ./check-flag -a -b
      aflag=1 bflag=1 

     

     조건식

    if, while, until 구문에서는 조건식이 사용된다. 조건식은 참과 거짓의 결과를 내는 구문이다. 참일 경우 조건식은 0을 반환하고, 거짓일 경우에는 1을 반환한다. 조건식의 형식은 다음과 같다.

    test 식
    [ 식 ]
    :

    식은 파일식, 문자열식, 수식의 세 종류로 크게 나눌 수 있다. :는 항상 참임을 나타낸다. while, until에서 무한 루프를 만들기 위해 사용된다.

    파일식은 어떤 파일의 속성을 검사하는 것으로 다음과 같은 종류가 있다.

    -b 파일 : 파일이 블럭 장치 파일이면 참
    -c 파일 : 파일이 문자 장치 파일이면 참
    -d 파일 : 파일이 디렉토리이면 참
    -e 파일 : 파일이 존재하면 참
    -f 파일 : 파일이 정규 파일이면 참
    -L 파일 : 파일이 심볼릭 링크이면 참
    -p 파일 : 파일이 네임드(named) 파이프이면 참
    -S 파일 : 파일이 소켓이면 참
    -r 파일 : 파일이 읽기 가능이면 참
    -s 파일 : 파일의 크기가 0보다 크면 참
    -w 파일 : 파일이 쓰기 가능이면 참
    -x 파일 : 파일이 실행 가능이면 참
    파일1 -nt 파일2 : 파일1이 파일2보다 새로운 파일이면 참
    파일1 -ot 파일2 : 파일1이 파일2보다 오래된 파일이면 참
    파일1 -ef 파일2 : 파일1과 파일2가 같은 파일이면 참

    문자열식은 문자열에 대한 비교를 한다.

    -z 문자열 : 문자열의 길이가 0이면 참
    -n 문자열 : 문자일의 길이가 0이 아니면 참
    문자열1 = 문자열2 : 문자열1과 문자열2가 같으면 참
    문자열1 != 문자열2 : 문자열1과 문자열2가 다르면 참

    수식은 숫자값을 비교한다. 양의 정수, 음의 정수, 0, 변수값이 올 수 있다.

    값1 -eq 값2 : 값1 = 값2
    값1 -ne 값2 : 값1 != 값2
    값1 -lt 값2 : 값1 < 값2
    값1 -le 값2 : 값1 <= 값2
    값1 -gt 값2 : 값1 > 값2
    값1 -ge 값2 : 값1 >= 값2

    이외에도 다음과 같이 식 전체에 대한 연산이 가능하다.

    ! 식 : 식에 대한 부정(not)
    식1 -a 식2 : 식1과 식2에 대한 논리곱(and)
    식1 -o 식2 : 식1과 식2에 대한 논리합(or)

 

결론

    이번 기사에서는 쉘 스크립트에 대한 기본적인 사항들을 살펴보았다. 작성, 실행 방법과 기본적인 문법만으로도 간단히 개인적으로 유용하게 사용할 수 있는 스크립트를 작성할 수 있을 것이다. 다음 기사에는 각 세부 사항에 대한 자세한 설명과 기법에 대해서 알아도록 하자.

    <참고자료>
    ·UNIX POWER TOOLS, 2ed. Jerry Peek,
        Tim O’Reilly, Mike Loukides. O’Reilly
    ·bash 매뉴얼 페이지

'IT > language' 카테고리의 다른 글

쉘스크립트 (Shell Script) - (III)  (0) 2013.01.28
쉘스크립트 (Shell Script) - (II)  (0) 2013.01.28