2014년 10월 28일 화요일

Spark 사용기 1 - Hive vs Spark vs SAS : select count(*) performance 비교

오늘은 야간에 데이타센터 님께서 작업하시므로 새벽 대기를 해야하는 날이다.

오랫만에 철야 하는 기념으로 다가, 오늘은 드디어 Code 를 돌려 보도록 하겠다.

우선 master node 에서 아래 명령어를 수행하였다.
 ./spark-shell --master spark://master003.prod.moneymall.ssgbi.com:7077

아래처럼 멋쮠 Spark 텍스트 로고가 보인다.

우선 첫번째로 해보고 싶은 것은 Hive Table 의 Seclect Count(*) 와 Spark Engine 에서의 Line Count 의 성능 비교이다. 덤으로 SAS 에서 Hadoop Connector(내부적으로 HiveQL JDBC를 이용한다.)의 성능도 함께 비교해 보았다. 

간단한 수행이므로, Hive 는 Hive Shell Console 에서, 그리고 Spark 는 Spark의 Scala Console 에서 수행 해보았다. SAS 는 SAS 서버에서 직접 Base Programe Code로 수행하였다.

[1] Hive Console 에서 수행.

수행한 쿼리는 다음과 같다.

hive> select count(*) from search_keyword_result;

결과는 다음과 같이, 15.459초



[2] SCALA Console 에서 수행.

비교를 위해 선정한 위의 Table 은 Hive 의 External Table 로서, HDFS 입장에서는 Directory 이다. 해당 디렉토리에 일배치가 끝난 파일이 하루에 한개씩 파일이 생기는 구조이며, Hive Table 입장에서는 Row 가 일단위로 Append 되는 형태의 Table 이다.

그래서, 먼저 처음 수행한 코드는 아래와 같다.

 val hdfsFile = sc.textFile("hdfs://master001.prod.moneymall.ssgbi.com:9000/user/hive/warehouse/research_keyword_result/")

혹시나 디렉토리가 바로 로딩 되진 않을까 하는 기대여서 였지만....
역시나... 아래처럼 에러가 발생한다.


서칭을 좀 해보니, 디렉토리를 통채로 로딩할때는 아래처럼 하면 된다.

 val hdfsFile = sc.textFile("hdfs://master001.prod.moneymall.ssgbi.com:9000/user/hive/warehouse/research_keyword_result/*")

count 를 위한 아래와 같은 짧은 코드를 위 코드 뒤이어 수행해 보았다.

hdfsFile.count()

결과는 놀랄 말큼 빠르다.
0.38초....

결과도 Hive 와 동일하다.


[3] SAS 에서 Hive Connector 로 수행.

(1) 첫번째 시도. ( with SAS Dataset Binding )

SAS 에서 맨처음 해본것은 Data Step 에서 Hive Table 라이브러리를 임시 테이블로 Dataset 로딩 해보는 작업이었다. 그렇게만 하여도, Observation 관측치 값을 알려주기 때문이다. 그런데, 위에서 scala가 1초도 안걸리는 수행을 임시 테이블 바인딩 작업이 무려 21분이나 소요 되었다. (현재 12시가 넘어버린 시점이라 위 시점과 아래 스샷의 시점차에 의한 결과 값이 미묘하게 다르지만, 너무 오래걸려서 저걸 다시 수행하고 싶진 않다.)


뭘 해보기도 전에 21분씩이나 초기 로딩에 소요 되는 것은 대략 안습이다. 게다가 저게 얼마 주고 산건데.... 벤츠를 3대는 뽑았을 금액인데..

(2) 두번째 시도. ( with SAS Memory Iteration )

일단 SAS 도 포기하고 싶지 않아 몇가지 실험을 더 해보기로 하였다. 사실 Hive Table 을 SAS DataSet으로 바인딩 하는 것은 Hive Table 이 매우 클 수 있음을 감안하면, 좀 무식한 접근 일 수 있다. Data Download Time 및 serialize Time 을 고려하면, 위 첫번째 시도는 그럴만도 했다고 일단은 스스로 위안을 해보도록 하자.

그래서 아래처럼 메모리 상에서 루프 돌며 Count 를 구해 보았다. 결과는 일단, 드라마틱하게 개선....

21분 걸렸던게 무려 3분8초로 단축 되었다.


(3) 세번째 시도. ( With SAS SQL )

한가지만 더 실험해 보고 싶은 욕구가 생겼다... 흑, 조금있으면 출근해야 할 정도로 시간이 많이 지나 버렸긴 하지만....잠자기는 틀린것 같고..

SAS 영업께서는 늘 말씀 하셨다. SAS 의 Hadoop Connector는 Hadoop의 자원을 쓰기 때문에 Hadoop 과 공존하며, 상호 보완적 하이브리드 Analytics 환경을 제공해 준다고...

이 말을 꼭 검증해 보고 싶었다. 사실 위가 사실이 아니라면, 나는 오늘 부로 Hadoop 데이타를 SAS 를 이용해서 핸들링하는 시도를 아예 접을 생각이었다.

결과는 우선 영업의 말이 사실이다는 점. SAS SQL 은 일단 Hadoop에게 Query 수행을 일임해준듯 한 결과가 나왔다. 이로써 느려 터진 SAS 는 Hadoop과 공존 할때, Heavy 한 업무는 Hadoop 에게 맞기고, 좀더 스마트한 계산만 SAS 로 하면 된다는 존재 이유가 생겼다.

수행시간은 무려 57초. (처음 21분에 비하면 무지 개선 되었다. Hadoop 의 힘을 빌은 결과이긴 하지만... 왠지 Hive 대신 Shark 를 Spark 위에 올리고, HiveQL을 Shark에게 날리면, 57초가 20초대 미만으로 줄어들것도 같은 생각이 들긴 한다.)


[4] Hive vs Spark vs SAS 오늘의 결론!
 
(1) Hive vs Spark vs SAS(with HiveQL)
15.45 s : 0.38 s : 57.2 s

(2) Hive vs Spark vs SAS(only SAS)
15.45 s : 0.38 s : 3m 8s

Spark Perfect Win!!!!!!!!!!!!!!!!!!!

2014년 10월 22일 수요일

Spark 설치기 5 - Cluster Installation with Cluster Launch Scripts

이레 저레 벌써 새벽 0시 22분...

잠을 청하기에 앞서... 드디어... Cluster Launch Scripts 를 가지고 Cluster 위에 재대로 (운영 수준으로) 클러스터를 설치 해보기로 하겠다...

우선 선행적으로 필요한 것은 아래와 같다.

(1) password-less ssh 세팅...
- 이미 세팅 되어 있으므로 skip..

(2) SPARK_HOME 수정.
- 우리 cluster 는 spark 0.9.1 버전을 깔았었던 이력이 있으므로, .bashrc  안에 있는 잔해를 수정해주었다.
- 그러고 보니 spark 0.9.X 버전 대에는 sbt 로 패키지 설치를 했던 기억이....

SPARK_HOME=/data01/spark/spark-1.1.0-bin-hadoop1
export SPARK_HOME

(3) 이제 본격적으로 세팅.
(ㄱ) cd $SPARK_HOME/conf
(ㄴ) mv spark-env.sh.template spark-env.sh
(ㄷ) vi slaves  하고 각 WorkNode 의 호스트명 기입.
(ㄹ) vi spark-env.sh 하고 최 하단에 아래 기입. 인스턴스 갯수를 2개로 설정했기 때문에, 한 머신당 8g 메모리가 할당 되도록 세팅하였다. 적절한 메모리 세팅은 추후 운영상황을 보며 조정하여야 할 테지만, 우선은 매우 적게 보수적으로 세팅 하였다.

SPARK_MASTER_IP=master003.prod.moneymall.ssgbi.com
SPARK_WORKER_MEMORY=4g
SPARK_WORKER_INSTANCES=2
(ㅁ) 마지막으로 마스터 노드의 sbin 디렉토리에서 아래 script 수행.
./start-all.sh


에러 하나 없이 깔끔하게 설치 되었다.

오늘은 여기까쥐.... 자야겠다.

2014년 10월 21일 화요일

Spark 설치기 4 - Stand Alone on a Cluster 설치2

[약간의 부가적인 실험]

우선 Worker Node 한곳에서 ps 를 날려 보았다...


노드 관리 상황을 실험해 보기 위해 Kill 로 해당 프로세스를 죽여 보았다...

2개 노드를 Kill 로 죽이고 죽인 Node 중 한개를 다시 수동으로 구동하였다.


kill 로 죽인경우에도 Master Node 에서는 바로 DEAD 로 감지가 되었다.
그런데, 다시 프로세스를 띄우니, 기존 DEAD 노드가 ALIVE 로 바뀌진 않았고, ALIVE 노드가 새로 추가 되었다.

그리고 나서 몇분 후.....

다시 새로 고침을 해 보았다.

음... Dead 2개가 사라졌다...

일단, 간단한 실험이었지만, 매우 Reasonable 하게 장애 노드 감지 및 처리가 이루어지는 듯 하다.


2014년 10월 19일 일요일

Spark 설치기 3 - Stand Alone on a Cluster 설치

우선 클러스터 모드 설치에 앞서 이론 공부 부터...
https://spark.apache.org/docs/latest/cluster-overview.html

그리고 설치 가이드 문서 정독하기.
https://spark.apache.org/docs/latest/spark-standalone.html


(1) 복수개의 데이타 노드와 마스터 노드에 파일 다운로드
다운로드 경로는 skip. 설치기2에서 사용했던 file 을 그대로 사용하였다.

(2) 그리고 압축 풀기.. (모든 마스터노드와 데이타노드에서..)

tar xvzf spark-1.1.0-bin-hadoop1.tgz

(3) Master Node 에서 아래 명령어 수행하여 일단 Master Node 만 띄운다.


./sbin/start-master.sh

(4) 웹UI뜨는지 확인

(default port 는 8080 인데, 우리는 storm web ui 가 해당 port 를 이미 사용중이다.)
(에러 날 줄 알았는데, 수행해보니 에러가 나지 않길래 log를 상세하게 뒤져보니 warning 만 뜨고, 해당 port 가 사용중이라 8081 로 시도한다는 문구가 보인다.)
아래 이미지 처럼 아직은 worker node 가 모두 떠 있지 않은 상태임.


(5) 각 DataNode 로 가서 Worker 구동


cd /data01/spark
tar xvzf spark-1.1.0-bin-hadoop1.tgz
cd spark-1.1.0-bin-hadoop1

./bin/spark-class org.apache.spark.deploy.worker.Worker spark://master003.prod.moneymall.ssgbi.com:7077

ctrl+z
bg 
요부분은 메뉴얼에 없는 부분인데. 백그라운드 수행이 자동으로 되지 않고 있다. 수동으로 해주었지만, 사실, 운영시에는 요 방식이 아닌 뒤이어 실험할, Cluster Launch Scripts 방식으로 가야 할듯.

worker 노드 구동 확인

전체 노드에 대하여 위 작업 수행.

위 작업 이후 Master Node 에서 Worker 들이 모두 구동 되었는지 확인.

요기까진 아무런 막힘이 없었다. 우선 몸풀기 정도로 생각하고, 현재 세팅은 여기서 마무리...

일요일 오후... 다행히 내일이 휴가인지라... 오늘 저녁엔 저걸 다 내리고, 운영용으로 재 세팅을 할 예정이다.


2014년 10월 11일 토요일

Spark 설치기 2 - Stand Alone 설치

우선 나의 Portable 개발 환경인 CentOS 노트북에 먼저 Stand Alone 설치....

참고로 나의 CentOS 노트북에는 Hadoop 1.2.1 이 깔려 있다.

[1] 다운로드

https://spark.apache.org/downloads.html

[2] 다운로드 옵션

1.1.0
Pre-built for Hadoop1.x
Direct Download....

이렇게 옵션을 주고 spark-1.1.0-bin-hadoop1.tgz 를 받았다.

[3] pre-requiste...


Spark runs on Java 6+ and Python 2.6+. For the Scala API, Spark 1.1.0 uses Scala 2.10. You will need to use a compatible Scala version (2.10.x).

[4] 설치

설치는 걍... 압축 풀면 끝난다...

[5] 테스트 Scala 버전 M/R 실행.

spark top 폴더에서 아래 처럼 수행.
[spiccato@hoonnote spark-1.1.0-bin-hadoop1]$ ./bin/run-example SparkPi 10

결과는
Pi is roughly 3.142752

vi 로 run-example 파일을 열어보자 아래 같은 내용이 보인다.

if [[ ! $EXAMPLE_CLASS == org.apache.spark.examples* ]]; then
  EXAMPLE_CLASS="org.apache.spark.examples.$EXAMPLE_CLASS"
fi

"$FWDIR"/bin/spark-submit \
  --master $EXAMPLE_MASTER \
  --class $EXAMPLE_CLASS \
  "$SPARK_EXAMPLES_JAR" \
  "$@"

즉, 위 소스는 EXAMPLE_CLASS 안에 있는 듯 하다.

위 위치에서 SparkPi.scala 소스를 열어 보았다.

위 스칼라 소스를 수행하면 수행 시간은  0.620 초가 소요된다.

[6] 테스트 Python 버전 M/R 실행.

소스는 아래와 같다.

위 파이썬 소스를 수행하면 수행 시간이 scala 보다 2배정도 느린 1.270 초가 소요된다.
위 결과 만으로 절대 비교 하면, Python이 느린 것 처럼 보이긴 하지만,
만약 Python 코드를 Scala 코드로 Convert 하는 시간이 위 시간 만큼의 차이를 주고, 실제 계산 수행은 동일하다고 한다면, 대용량 데이타를 처리하는 시간은 동일하다고 할수도 있을 것이므로 이는 좀더 지켜보아야 할것 같다.

[7] 결론

로컬모드 설치는 압축만 풀면 된다...

2014년 10월 10일 금요일

Spark 설치기 1 - 잡담들.

[1] 설치에 앞서 잡담들...

사실 Spark 는 수도없이 깔아보았지만, 그동안은 익숙한 HiveQL을 함께 쓰기 위해 항상 Shark 와 함께 깔수 있는 0.9.X 버전만 깔아왔었다...(이참에는 1.1.0 을 깔것이다.)

그리고, 만났던 수많은 Heap Memory 관련 에러들....

한때, 메모리 Cache 부분을 조금더 효율적으로 사용하고자, Shark + Spark + Tachyon 조합으로 시스템을 재 구성하여 설치 시도도 해 보았었다.

결론은... 테스트로 한두개 돌리는 것은 꽤 좋은 성능을 보이고, 매우 고무적이었다. 그러나, 운영시스템에서 실제 운영용 배치로 스케줄에 걸어 여러 Job 과 함께 사용을 하면, 역쉬나 수많은 Memory 관련 에러로 유지 자체가 힘들 다는 것..


그래서 선택한 아키텍처는.... Shark 와 Tachyon 까지 없애고, 그냥... Spark 만 쓰는 것...

Simple is best 라는 말이 있듯이....기본이 불안한 경우는 기본을 불안하게 만드는 곁가지들을 모두 제거하는 것.

이제와서 Spark 를 포기하고 싶지는 않고, 그동안 Shark , Tachyon 와의 궁합때문에 어쩔수 없이 사용하지 못했던 최신 1.1.0 버전으로 다시한번 도전해 보기로 하였다.

물론 Shark 를 걷어 냈으므로, Scala 로 M/R 을 짤 예정이기도 하다.. 내가 이를 위해 정독 중인 Scala 서적...



그리고, 엊그제 Amazon 에서 구매한 Spark 서적. 따끈하다 못해 심지어 출판 예정일이 내년2월인 미출시 서적의 Early_released 버전 ebook 이다.



이놈의 기술 역마살 때문에.... 한권을 다 읽기도 전에 두번째 서적을 사서 읽기 시작하면서, 두권을 다 읽기도 전에 (운영모드 포함)설치를 동시에 착수하고 있다...

2014년 10월 5일 일요일

Spark 다시 보기...

Shark + Spark + Tachyon 의 조합에서 Hive 대비 수십배의 성능을 보고 흥분하던 순간이 있었지만, 그 흥분은 오래가지 못했다...
운영 M/R Batch 에 실적용하는 경우 Heap Memory 관련 에러가 너무 자주 발생하였고, 기타 여러가지 에러들로 인하여, 안정성이 매우 떨어 졌기 때문...

결국, 한동안 저 조합의 사용을 접고 있다가, 다시 Shark 와 Tachyon 의 콜라보레이션을 포기하고, 최신 버전의 Spark 에서 Scala 랭귀지로만 접근하여, Spark 엔진을 다시한번 우리 운영(Production) M/R Batch 에 적용 해 보기로 결심 하였다.

우선 찾은 유용한 아티클은 다음과 같다.

(1) Using Parquet and Scrooge with Spark
http://engineering.ooyala.com/blog/using-parquet-and-scrooge-spark

우리가 현재 Parquet 포맷을 쓰고 있기 때문에, 제일 먼저 검색 했던 것이, Parquet 와의 Compatibility Issue 였다. Shark에서의 Parquet Compatibility Issue 때문에 한두번 쓴맛을 본적이 있기 때문에, 아직 안심하긴 힘들지만, 어찌 되었든, 좋은 참고 모델이 생겨 안심이다.

(2) scrooge
https://twitter.github.io/scrooge/
https://github.com/twitter/scrooge
트위터는 이미 cascading 위에서 scala 기반으로 scalding 을 잘 쓰고 있어서이겠지만, 요런 유용한 scala 확장 응용모듈들을 많이 보유하고 있다. scala 로 spark 를 헨들링함에 있어, 다양한 우리쪽 다른 Data 원천과도 멀티소스 Join 이 필요할 것이므로,(예를 들어 HBase 나 MemCached 와...) scrooge 같은 thrift 제너레이터가 유용하게 쓰일 수 있을 듯 하다.