많이 사용되는 쉘(shell)은 대표적으로 아래와 같다.


Stephen Bourne이 개발 한 오래된 Bourne 쉘, David Korn이 개발한 Korn 셸, 주로 리눅스 시스템에서 사용되는 Bash 쉘, Bill Joy가 개발한 C 쉘, 최근에 유행하는 각 쉘의 장점을 이용한 zsh이 있다. 




오늘 처음 안 내용이 있었는데, 내가 그렇게 좋아하는 쉘인 bash의 원 단어를 알았다!


bash shell이 Bourne again shell의 약자였다니!! 



bash 위키에 다음처럼 적혀 있다!!


배시 (Bash, Bourne-again shell, 본 어게인 셸)은 본 셸을 대체하는 자유 소프트웨어로서 GNU 프로젝트를 위해 브라이언 폭스(Brian Fox)가 작성한 유닉스 셸이다.[2][3] 1989년 발표되어 GNU 운영 체제와 리눅스맥 OS X 그리고 다윈 등 운영 체제의 기본 셸로 탑재되어 광범위하게 배포 되었다. 또한 DJGPP와 노벨 넷웨어에 의해 도스로 이식되었고 시그윈과 MinGW의 배포로 마이크로소프트 윈도로 이식되었다.






Posted by '김용환'
,

[공부] Hbase compaction

hbase 2016. 12. 16. 20:23


발로 번역해서 공부한 내용이다.

Hbase compaction을 공부하기 위해 여러 군데 흩어져 있는 내용을 짬뽕한 내용이다. 



hbase에 데이터가 바뀌면 commit log로 저장되는데, WAL(Write-Ahead Log)에 존재한다. 데이터는 이후 메모리 상의 Memstore에 저장된다. 메모리 상의 데이터가 설정된 최대값을 넘어서면 디스크에 HFile로 저장된다. 

이를 compaction(컴팩션)이라고 한다. 읽는 관점도 동일하게, 읽기 쉽게 저장되는 형태이기도 하다.



또한, 데이터가 변경/삭제되면서 이미 저장된 HFile에 필요 없는 데이터가 삭제 마킹(tombstone marking)이 되면서 지울 것은 지우고 합칠 것은 합치는 작업(compaction)을 진행한다.  하나의 리전(region)에서 한 저장소에서 HFile을 모아 병합한다. 


참고로, compaction은 두 가지 종류가 있다. 

- minor compaction : 작고 많은 HFile을 소수의 큰 HFile로 결합한다. compaction할 HFile 개수와 빈도를 제어할 수 있다. 특정 로우를 읽다가 디스크 읽기를 많이 하다가 전반적인 성능이 저하될 수 있기 때문이다...

- major compaction  : Region의 모든 Store 파일을 읽고 하나의 Store 파일에 저장한다.



CDH 4/HBase 0.96 이전의 기본 정책은 HFile의 목록을 살펴보고 전체 파일 수에 hbase.store.compaction.ratio를 곱한 값보다 작은 크기를 가진 파 중 첫 번째를 찾으려 한다. 만약 해당 파일을 찾으면 HFile과 그보다 작은 id를 가진 모든 파일이 컴팩션되도록 선택된다. 기본 정책은 RatioBasedCompactionPolicy이다(사실 이거 하나였다). 오래된 HFiles부터 시작된다. 하지만, 파일의 age와 size를 기반한 일부 가정이 잘못되었다.



CDH 5/HBase 0.96에서 https://issues.apache.org/jira/browse/HBASE-7516를 통해 사용자가 원하는 compaction(ExploringCompactionPolicy)을 진행할 수 있게 되었다. 모든 파일이 지정된 compaction 비율내에 있음을 보장한다. 그리고 compaction 비율 내에서 첫 번째 파일 집합만 선택하지 않고, 규칙을 위반하지 않은채 가장 IO가 적을 것 같은 것만 선택한다. compaction할 파일을 찾은 후 크기가 작은 파일이 대상이 된다. 그래서 IO 부하를 최소화하는 전략으로 변경했다. 벌크 로딩이 필요한 작업에서는 엄청난 성능 향상이 있다고 한다. 


ExploringCompactionPolicy을 사용하면 minor compaction이 효율적이라서 major compaction이 덜 발생해서 성능이 좋다고 한다. 그래서 기본 compaction 정책으로 사용되어 지금까지 쓰고 있다고 한다. 




ExploringCompactionPolicy에 대한 소스는 https://github.com/apache/hbase/blob/master/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/compactions/ExploringCompactionPolicy.java에 있으니 참고할 수 있다. 


ExploringCompactionPolicy이 확장되어 Stripe compaction(https://issues.apache.org/jira/browse/HBASE-7667)이 0.98, 0.99에 추가되었다. 또한 tiered-based compaction(https://issues.apache.org/jira/browse/HBASE-7055)은 개발 중이지만,2015년에 쓴 댓글이 마지막이라서 나올지 의문이다.



다음은 compaction 관련으로 Hortonworks에서 발표한 내용이다(동영상은 https://vimeo.com/69989292을 참조한다).


HBaseCon 2013: Compaction Improvements in Apache HBase from Cloudera, Inc.



참고로 https://hbase.apache.org/book.html#compaction을 참조하면, 

0.94의 RatioBasedCompactionPolicy 동작 순서와 0.96의 ExploringCompactionPolicy 동작 순서를 잘 알 수 있을 것이다. 그리고, hbase compaction property를 참조하면 hbase의 compaction를 더욱 이해할 수 있을 것 같다. 





참조 


https://hbase.apache.org/book.html#compaction


http://blog.cloudera.com/blog/2012/06/hbase-write-path/


http://blog.cloudera.com/blog/2013/12/what-are-hbase-compactions/


https://www.linkedin.com/pulse/hbase-minor-major-compaction-explained-jeetendra-gangele


http://engineering.vcnc.co.kr/2013/04/hbase-configuration/




참고


cassandra의 compaction 전략은 다음을 참조한다. hbase의 compaction은 전체 클러스터의 설정이라면, cassandra의 compaction설정은 테이블 단위이다.


http://knight76.tistory.com/entry/cassadra-compaction-%EC%A0%84%EB%9E%B5

Posted by '김용환'
,



bash에서 사용할 수 있는 간단한 스칼라 커맨드 유틸리티를 소개한다. 



scala REPL을 그대로 사용하고 간단하게 사용할 수 있다. 



#!/bin/sh


exec scala "$0" "$@"

!#


print("given parameter : " )

args.foreach(arg => print(arg + " "))

println

println("given parameter number : " + args.length)


if (args.length >= 2 || args.length < 1) {

  println("wrong parameter, only 1 parametr")

  sys.exit

}


println("Hello " + args(0) + "!")



실행한 코드는 다음과 같다. 


 ./scalahello world

given parameter : world

given parameter number : 1

Hello world!




가장 실수한 부분은 sys.exit였다. scala 실행할 때 종료하면 sys.exit하듯이 스크립트에서도 사용하면 된다. 



[~/temp] scala

Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_101).

Type in expressions for evaluation. Or try :help.


scala> sys.exit

[~/temp]





REPL은 좀 제약이 많아서 될 수 있으면 코드베이스가 더 나은 것 같긴 하지만, 필요하다면 스크립트도 괜찮은 방법일 수 있다. 


Posted by '김용환'
,


hbase 0.94에서 hbase shell을 사용해서 테이블 추가/삭제를 진행하는 예시이다.




$ hbase shell


16/12/16 14:20:08 WARN conf.Configuration: hadoop.native.lib is deprecated. Instead, use io.native.lib.available

HBase Shell; enter 'help<RETURN>' for list of supported commands.

Type "exit<RETURN>" to leave the HBase Shell

Version 0.94.15-cdh4.7.1, rUnknown, Tue Nov 18 08:51:37 PST 2014



table1을 생성한다.


> create 'table1', 'columnfamily1'

=> Hbase::Table - table1




생성된 테이블이 존재하는지 확인한다. 


> list 'table1'

TABLE

table1



table1 테이블을 삭제하기 위해 drop를 사용하려면 먼저 disable을 먼저 사용하라고 알린다. 


> drop 'table1'


ERROR: Table table1 is enabled. Disable it first.'


Here is some help for this command:

Drop the named table. Table must first be disabled: e.g. "hbase> drop 't1'"




table1 테이블을 삭제하기 위해 disable과 drop을 실행한다.



> disable 'table1'

0 row(s) in 1.1150 seconds


> drop 'table1'

0 row(s) in 1.0580 seconds


> list 'table1'

TABLE

0 row(s) in 0.0230 seconds





데이터를 테이블에 저장하는 예시를 진행한다.



먼저 간단한 google 테이블을 생성한다. 테이블의 이름은 google이고, 컬럼패밀리는 vi 이다. 



> create 'google', 'vi'

0 row(s) in 1.0600 seconds

=> Hbase::Table - google



테이블에 row를 추가하기 위해 put을 사용한다. 



> put 'google', 'row1', 'vi:make', '1'

0 row(s) in 0.0360 seconds


> put 'google', 'row2', 'vi:make', '2'

0 row(s) in 0.0060 seconds


> put 'google', 'row3', 'vi:make', '3'

0 row(s) in 0.0050 seconds


> put 'google', 'row1', 'vi:get', '1'

0 row(s) in 0.0030 seconds


> put 'google', 'row2', 'vi:get', '2'

0 row(s) in 0.0030 seconds


> put 'google', 'row3', 'vi:get', '3'

0 row(s) in 0.0030 seconds





저장한 데이터가 존재하는지 scan으로 확인한다. 



> scan 'google'

ROW                              COLUMN+CELL

 row1                            column=vi:get, timestamp=1481865972730, value=1

 row1                            column=vi:make, timestamp=1481865868177, value=1

 row2                            column=vi:get, timestamp=1481865976807, value=2

 row2                            column=vi:make, timestamp=1481865882636, value=2

 row3                            column=vi:get, timestamp=1481865981007, value=3

 row3                            column=vi:make, timestamp=1481865891477, value=3

3 row(s) in 0.0410 seconds



특정 컬럼 패밀리만 보고 싶다면, scan에 COLUMNS를 추가한다. 


> scan 'google', {COLUMNS => ['vi:make']}

ROW                              COLUMN+CELL

 row1                            column=vi:make, timestamp=1481865868177, value=1

 row2                            column=vi:make, timestamp=1481865882636, value=2

 row3                            column=vi:make, timestamp=1481865891477, value=3

3 row(s) in 0.0850 seconds



해당 커맨드에 LIMIT을 이용해 개수를 지정해서 볼 수 있다.



> scan 'google', {COLUMNS => ['vi:make'], LIMIT => 100}

ROW                              COLUMN+CELL

 row1                            column=vi:make, timestamp=1481865868177, value=1

 row2                            column=vi:make, timestamp=1481865882636, value=2

 row3                            column=vi:make, timestamp=1481865891477, value=3

3 row(s) in 0.0170 seconds


> scan 'google', {COLUMNS => ['vi:make'], LIMIT => 2}

ROW                              COLUMN+CELL

 row1                            column=vi:make, timestamp=1481865868177, value=1

 row2                            column=vi:make, timestamp=1481865882636, value=2

2 row(s) in 0.0090 seconds


> scan 'google', {COLUMNS => ['vi:make'], LIMIT => 1}

ROW                              COLUMN+CELL

 row1                            column=vi:make, timestamp=1481865868177, value=1

1 row(s) in 0.0050 seconds




데이터를 얻으려면 get을 사용하는데, 테이블과 로우 키가 중요하다. 테이블과 컬럼패밀리로 검색하면 값을 얻을 수 없다.


> get 'google', 'vi:make'

COLUMN                           CELL

0 row(s) in 0.0110 seconds



테이블과 로우 키로 데이터를 검색한다. 테이블-로우키로 검색 가능하고, 테이블-로우키-컬럼패밀리로 검색할 수 있다.



> get 'google', 'row1'

COLUMN                                        CELL

 vi:get                                       timestamp=1481865972730, value=1

 vi:make                                      timestamp=1481865868177, value=1

2 row(s) in 0.0340 seconds


> get 'google', 'row1', 'vi:get'

COLUMN                                        CELL

 vi:get                                       timestamp=1481865972730, value=1

1 row(s) in 0.0080 seconds




scan 처럼 get도 COLUMN 단위로 검색할 수 있다. (FILTER, TIMERANGE로도 검색할 수 있다)



> get 'google', 'row1', {COLUMN => [ 'vi:make', 'vi:get' ] }

COLUMN                                        CELL

 vi:get                                       timestamp=1481865972730, value=1

 vi:make                                      timestamp=1481865868177, value=1

2 row(s) in 0.0120 seconds


> get 'google', 'row1', {COLUMN => [ 'vi:get' ] }

COLUMN                                        CELL

 vi:get                                       timestamp=1481865972730, value=1

1 row(s) in 0.0050 seconds





삭제하려면 delete를 사용한다.



> scan 'google'

ROW                              COLUMN+CELL

 row1                            column=vi:get, timestamp=1481865972730, value=1

 row1                            column=vi:make, timestamp=1481865868177, value=1

 row2                            column=vi:get, timestamp=1481865976807, value=2

 row2                            column=vi:make, timestamp=1481865882636, value=2

 row3                            column=vi:get, timestamp=1481865981007, value=3

 row3                            column=vi:make, timestamp=1481865891477, value=3




> delete 'google', 'row1', 'vi:make'

0 row(s) in 0.0120 seconds



scan 해보면 데이터가 삭제된 것을 확인할 수 있다. 



> scan 'google'

ROW                          COLUMN+CELL

 row1                        column=vi:get, timestamp=1481865972730, value=1

 row2                        column=vi:get, timestamp=1481865976807, value=2

 row2                        column=vi:make, timestamp=1481865882636, value=2

 row3                        column=vi:get, timestamp=1481865981007, value=3

 row3                        column=vi:make, timestamp=1481865891477, value=3

3 row(s) in 0.0350 seconds




delete할 때는 테이블-로우키-컬럼패밀리에 맞춰 지워야 한다. delete 테이블-로우키, delete 테이블을 실행시 에러가 발생한다.


> delete 'google', 'row2'

//에러 

> delete 'google'

// 에러





데이터 변경(update)는 put을 그대로 사용한다. 



> get 'google', 'row1'

COLUMN                       CELL

 vi:get                      timestamp=1481865972730, value=1

1 row(s) in 0.0080 seconds



> put 'google', 'row1', 'vi:get', 3

0 row(s) in 0.0120 seconds



> get 'google', 'row1'

COLUMN                       CELL

 vi:get                      timestamp=1481868410482, value=3

1 row(s) in 0.0040 seconds




테이블 삭제하려면, disable -> drop 테이블 과정을 거친다.


여기서는 disable과 enable 테이블을 시도해본 후 drop 테이블을 실행한다.



hbase(main):023:0> disable 'google'

0 row(s) in 1.1310 seconds


disable했기 때문에 scan이나 get하면 DoNotRetryIOException 예외가 발생한다. 


hbase(main):024:0> scan 'google'

ROW                          COLUMN+CELL

ERROR: org.apache.hadoop.hbase.DoNotRetryIOException: google is disabled.

hbase(main):025:0> get 'google', 'row1'
COLUMN                       CELL

ERROR: org.apache.hadoop.hbase.DoNotRetryIOException: google is disabled.


하지만, exists를 실행하면 아직 존재하는지 알 수 있다. 기타 list, decribe를 사용시 제대로 동작 중인지 확인할 수 있다. 


> exists 'google'

Table google does exist

0 row(s) in 0.0250 seconds



> describe 'google'

DESCRIPTION                                                             ENABLED

 'google', {NAME => 'vi', DATA_BLOCK_ENCODING => 'NONE', BLOOMFILTER => false

  'NONE', REPLICATION_SCOPE => '0', VERSIONS => '3', COMPRESSION => 'NO

 NE', MIN_VERSIONS => '0', TTL => '2147483647', KEEP_DELETED_CELLS => '

 false', BLOCKSIZE => '65536', IN_MEMORY => 'false', ENCODE_ON_DISK =>

 'true', BLOCKCACHE => 'true'}

1 row(s) in 0.0460 seconds



> list 'google'

TABLE

google

1 row(s) in 0.0230 seconds



disable 했던 테이블을 다시 사용하려면 enable을 호출한다. 


> enable 'google'

0 row(s) in 1.1450 seconds



> scan 'google'

ROW                          COLUMN+CELL

 row1                        column=vi:get, timestamp=1481868410482, value=3

 row2                        column=vi:get, timestamp=1481865976807, value=2

 row2                        column=vi:make, timestamp=1481865882636, value=2

 row3                        column=vi:get, timestamp=1481865981007, value=3

 row3                        column=vi:make, timestamp=1481865891477, value=3

3 row(s) in 0.0210 seconds




google 테이블을 삭제한다. 



> disable 'google'

0 row(s) in 1.1450 seconds


> drop 'google'

0 row(s) in 1.0570 seconds


Posted by '김용환'
,