Inertia

git tips

git/github 모르면 간첩.

useful git config

.git/config

1
2
3
4
5
[alias]
push-for-gerrit = push origin HEAD:refs/for/master
unpushed = log --branches --not --remotes --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative
lg = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative
change-commits = "!f() { VAR=$1; OLD=$2; NEW=$3; shift 3; git filter-branch -f --env-filter \"if [[ \\\"$`echo $VAR`\\\" = '$OLD' ]]; then export $VAR='$NEW'; fi\" $@; }; f "

아래처럼 cli로 적용을 해도 된다.

git config –global alias.lg “log –color –graph –pretty=format:’%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset’ –abbrev-commit”

  • lg 는 git log를 informative하게 보여주고
  • unpushed는 push되지 않은 브랜치들을 보여준다.
  • change-commit은 이미 커밋한 메세지를 수정할때 사용할 수 있다. 아래처럼. 아래는 HEAD 전 2번째 커밋까지의 커밋 메세지 중에서 from@gmail.comto@gmail.com으로 수정한다.

    git change-commits GIT_AUTHOR_EMAIL “from@gmail.com“ “to@gmail.com“ HEAD~2..HEAD

make topic branch

포크한 repo에서 바로 작업을 하게 되면 나중에 apache/master를 rebase하기가 힘들어 진다. 그래서 토픽 브랜치를 만들어서 거기서 태스크를 위한 커밋을 하고, 준비가 되면 거기서 바로 pull request를 하고, 업스트림에 머지가 되면 그 토픽브랜치는 이제 더이상 필요가 없다. 그후 업스트림으로 부터 다시 리베이스를 하면 마스터 브랜치는 최신으로 유지가 가능하다.

1
2
3
4
5
6
7
8
9
# assume current branch is master
git checkout -b topic # make topic branch
...
git commit -m "..."
git push -u origin topic # push topic branch to origin
# 이 상태에서 github상에서 pull request를 요청하면 된다.

git checkout master
git merge --squash topic # merge to master ans make 1 commit

undoing commits

git reset 명령을 하게 되면 커밋은 돌려지고 HEAD의 체인지가 워킹 디렉토리에 반영이 되지만(그래서 원복을 할 기회가 있음.), –hard를 붙이면 워킹 디렉토리의 변경사항은 없다. 따라서 –hard옵션은 조심해서 쓸것.

1
2
3
git reset --hard <dest_commithash> # move head to the designated commit
git reset (--hard) HEAD^1 # reset last commit
# HEAD^1 : parent of head

pathspec

git에서 파일을 지칭하고 싶을때 매번 풀 패스를 써주면 길어서 번거러울때가 있다. 이럴때 pathspec을 이용해서 줄일 수 있다. 잘 사용하면 아주 유용하다. pathspec 참고.

1
2
3
4
5
6
7
8
# java파일만 리스트 업
git log -p -- **/*.java

#abc folder하위 모든 파일
git log -p -- abc/**

# find public static method from java files
git grep public.*static.*\{ **/*.java

upstream의 release branch tracking 하기

1
git checkout -b rel upstream/release

revision selection

  • HEAD^1 : parent of head
  • HEAD^2 : 2nd parent of head. only valid for merge commit
  • HEAD@{n} : nth prior head

cherrypick specific file from different branch

git cherry-pick은 커밋 단위로 가지고 오기때문에, 다른 파일의 변경사항도 같이 적용이 된다. 이럴때는 checkout file을 사용하면 된다.

1
git checkout <branch> -- <filename>

ssh key를 등록했음에도 아이디와 패스워드를 물어볼때

git clone을 하고 난후 ssh키를 등록을 했음에도 매번 아이디와 패스워드를 물어본다면 git clone을 https로 해서 그렇다. 그럴때는 이렇게 하면 된다.

1
git remote set-url origin git@github.com:username/repo.git

commit a file and ignore content changes

설정파일의 경우, gradle.propertes 라던가, 로컬에서 수정할 필요는 있으나, 변경사항을 업스트림으로 반영하면 안되는 경우가 있다. 이럴때는 .gitignore를 사용할 수도 없고 매번 수동으로 커밋되지 않게 했다가 커밋하고 나면 다시 수정을 해야 하니까 불편하다. 이럴때 아래 명령어를 사용하면 변경사항은 무시 된다.

from http://stackoverflow.com/questions/3319479/git-can-i-commit-a-file-and-ignore-the-content-changes

1
2
3
4
5
# <file> 변경사항 무시
git update-index --assume-unchanged <file>

# 원복할때
git update-index --no-assume-unchanged <file>

upstream 복구 하기

실수로 upstream git을 지워버렸고, 로컬에는 포크된 git이 존재한다. 그렇다면 이상황에서 어떻게 복원할 수 있을까?
우선 같은 이름의 upstream git을 생성한후에 아래 명령어를 실행해주면 아주 쉽게 복원 가능

1
git push <upstream> --mirror

checkout files in other branches

1
2
git checkout feature-branch -- src/js/some-file.js
git checkout feature-branch -- src/js/

Zeppelin

Zeppelin은 아파치 인큐베이팅 프로젝트로 spark-shell 을 웹에서 할 수 있게 옮겨 놓은 것 + ipython notebook + data visualization(with d3.js) + screen sharing with websocket 정도 되겠다. 게다가 스파크의 변수를 angular변수로 맵핑이 가능해서 동적인 화면을 구성할 수 있다.
실제 사용해 보면 유용하고 데이터 분석을 하기에 최적화 되어 있다. 분석과정을 보여줄 수 있어 유용하다. NFLab이라고 하는 한국 스타트업에서 만들었는데 작품인 것 같다. 스파크와 함께 요즘에 젤 눈에 띄는 프로젝트다.

interpreter를 통해서 백엔드랑 통신을 하고 그 결과를 노트북으로 가져와서 보여주는 컨셉. 현재 지원하는 것은 markdown, spark, shell, hive, Tajo 등이 있다. 로드맵상 가능한 분석툴들은 다 지원하려고 하는 것 같다.

설치 및 설정

  1. 아직 인큐베이팅 프로젝트라서 바이너리는 배포가 안되고 있어서 직접 빌드를 해야 한다. zeppelin github project 에 가면 빌드 방법이 가이드가 되어 있고 나의 경우는 아래처럼 빌드했다. mvn clean package -Pspark-1.3 -Dhadoop.version=2.3.0 -Phadoop-2.3 -DskipTests

  2. 빌드가 끝나면 bin/zeppelin-daemon.sh가 생성이 되는데 bin/zeppelin-daemon.sh start하면 실행이 된다.

  3. 그러면 localhost:8080으로 접속하면 web interface가 뜬다. 여기서 위의 Interpreter tab을 누르고 spark interperter의 master 주소를 설정하면 끝.
  4. 스파크 클러스트 중의 하나의 컴에 제플린 서버를 두는게 설정이 쉽다. 처음엔 외부에 서버를 띄우려고 했었는데 1차 시도는 실패했던 기억

Tips

  1. 특정 jar를 제플린에서 로드하고 싶으면 interpreter tab에서 args property에 다음 처럼 명시해주면 된다. –packages :: 이런 형식으로
    1
    --packages com.google.code.gson:gson:2.3.1

TroubleShooting

뭐가 잘 안될때 분산되어 동작하는 것 때문에 디버깅이 쉽지 않은데 /logs/ 폴더 하위의 로그들을 잘 보면 힌트가 있다.

serialization error

한가지 경험담을 공유하자면 위에서 빌드할때 -Pspark-1.3을 주면 기본적으로 1.3.1으로 빌드를 하는데, 나는 스파크 1.3.0 버전을 설치해서 스파크 클러스터와 제플린 간의 라이브러리 버전이 달라서 실패하는 경우가 있었다. 대부분의 커맨드는 괜찮은데 특정 상황에서 특정 클래스의 Serialize id 가 달라서 로그와 나온게 있었는데 그것으로 인해 추측해서 알게 되었다. 에러는 아래와 같았다.

1
Slf4jLogger.scala[apply$mcV$sp]:71) - Association with remote system [akka.tcp://sparkExecutor@sa-dev-server:57240] has failed, address is now gated for [5000] ms. Reason is: [org.apache.spark.TaskState$; local class incompatible: stream classdesc serialVersionUID = -2913614267616900700, local class serialVersionUID = 746799155515967470].

YARN support

Caused by: java.lang.ClassNotFoundException: org.apache.spark.deploy.yarn.YarnSparkHadoopUtil 이런 에러가 발생하면 -Pyarn 옵션을 줘서 빌드해 주면 됨.

Spark 설치 및 설정

환경

  • spark 1.3.0 버전 기준임.
  • hadoop 2.3.0 기준

Standalone vs YARN

deploy 방법에는 Standalone 과 YARN 모드가 있다. MESOS는 안해봐서 패스. YARN으로 복수개의 스파크 잡을 스케쥴링 하거나 동시에 실행할 수 있어 프러덕션환경에서는 YARN이 필수라고 볼 수 있겠고 테스트 용도라면 Standalone이 설정하기 쉽다.
예를 들면, Standalone은 실행중일때 다른 스파크 잡이 들어오면 무시되지만, YARN은 그 잡을 스케쥴링 해서 수행하고 있는 잡이 끝나면 실행해 준다. 스파크 클러스터의 사용자가 많아지고 잡이 많아지면 YARN은 필수 되겠다.

Standalone mode

  1. master가 될 컴퓨터에 spark 1.3.0 버전을 다운받아서 압축을 푼다
  2. conf/spark-env.sh 에
    1. SPARK_MASTER_IP 에 master ip 기입
    2. SPARK_LOCAL_IP 에 자신의 ip 기입. 이것은 spark-env.sh보다는 환경변수에 해주는 것이 좋다. IP는 노드마다 다를테니까.
  3. conf/slaves 에 slave ip 혹은 호스트 명을 기입 - 한줄에 하나씩
  4. spark 폴더 전체를 다른 slave에 복사. 앞서 설명한 bash script를 사용하면 쉽다.
  5. master에서 .sbin/start-all.sh 실행
  6. http://:8080/ 에 접속하면 spark web ui를 볼 수 있다.

YARN

yarn이 편한것은 굳이 spark를 hadoop cluster에 설치하지 않아도 되는 것이다. 그 이유는 yarn에 어플을 submit할때 피룡한 모든 jar를 던져 주기 때문.
해서, spark 다른 버전 여러개를 동시에 yarn 상에서 구동해 볼 수 도 있겠다.

  1. master가 될 컴퓨터에 spark 1.3.0 버전을 다운받아서 압축을 푼다.
  2. spark-submit을 사용할 컴에 스파크를 다운 받아 압축을 풀고
  3. HADOOP_CONF_DIR 환경변수 설정
  4. 이 작업을 모든 컴에서 반복.
  5. spark-submit 을 불러주면 된다.

spark-shell --master yarn-client을 실행해서 해보면 잘 동작하는지 확인 할 수 있다.
job submit은 spark-submit --class --master yarn-cluster xxxx.jar 이런식..

spark on EMR

cluster모드로 이용하면 exception이 발생했을때 디버깅이 여러모로 번거로운데 팁을 정리해 본다.

EMR log이용 해서 디버깅

EMR 상에서 spark job을 실행시키면 yarn의 arregation-log option이 default로 꺼져 있는데 그래서 log를 보기가 쉽지가 않다. 하지만, EMR의 하둡은 AWS상으로 로그를 남기는 기능이 있어서 더 쉽게 spark job의 로그를 확인할 수 있다. 단, EMR cluster를 실행할때 LogUri를 걸어주기만 하면 끝이다. 그러면 EMR 4.0 에서는 <bucket_path>/<cluster_id>/container/<application_id> 하위에 spark로그들이 쌓이므로 이것을 확인하면 디버깅이 가능하다.

j-3NJPE2Q3IR2T/containers/application_1450245879642_0002/container_1450245879642_0002_01_000001
위의 예는 의 클러스터에 2번째 스파크 잡의 로그는 위의 경로에 저장된다. driver가 000001의 아이디를 가지고 되나본데(?) 그래서 첫번째의 로그만 보면 보통 해결이 된다.
단점은, 로그가 s3로 싱크가 되려면 10분정도의 시간이 걸리기 때문에 불편하다. 그래서 아래에서 lynx 를 이용하는 부분을 추가했다.

EMR에서 lynx를 이용해서 디버깅

특정 스파크 잡이 실패하면 보통 아래 처럼 로그가 뜬다. 그러면 아래의 tracking url을 이용해서 shell 기반 브라우져인 lynx를 이용해서 들어가면 로그를 바로 확인할 수 있다. 1.5.0의 경우는 shell에서 lynx http://ip-xxx.us-west-2.compute.internal:20888/proxy/application_1450245879642_0004 들어간후 executors 링크를 타고 들어가 driver의 stderr로그를 보면 대부분 해결된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
07:12:27 INFO yarn.Client:
client token: N/A
diagnostics: N/A
ApplicationMaster RPC port: 0
queue: default
start time: 1450249874517
final status: FAILED
tracking URL: http://ip-000-00-00-00.us-west-2.compute.internal:20888/proxy/application_1450245879642_0004/history/application_1450245879642_0004/2
user: hadoop
Exception in thread "main" org.apache.spark.SparkException: Application application_1450245879642_0004 finished with failed status
at org.apache.spark.deploy.yarn.Client.run(Client.scala:920)
at org.apache.spark.deploy.yarn.Client$.main(Client.scala:966)
at org.apache.spark.deploy.yarn.Client.main(Client.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

enabling spark event log

conf/spark-defaults.conf 를 아래처럼.

1
2
spark.eventLog.enabled true
spark.eventLog.dir hdfs://xxxx/sparklogs

이렇게 하고 spark job을 실행하면 위에서 설정한 hdfs에 spark event log가 쌓이게 된다. 이 이벤트 로그는 spark의 history server를 통해서 볼 수 있다. sbin/start-history-server.sh 를 통해서 실행하면 되는데 그전에 로그 파일들이 어디에 있는지 지정을 해줘야 한다. 그것은 아래와 같은 환경 변수로 할 수 있다.

export SPARK_HISTORY_OPTS=" -Dspark.history.fs.logDirectory=hdfs://xxx/sparklog"

그후 histgory server를 실행하면, 실행한 컴의 http://:18080 으로 들어가면 web ui에서 각 잡의 logging을 볼 수 있다.

history

  • 15/8/18 fix wrong info about yarn cluster
  • 15/12/15 adding debugging tip on EMR spark

hadoop 설치 및 설정

소개

하둡은 hdfs + MapReduce + ResourceManager(YARN) 이라고 볼 수 있다. 하둡은 현재 사용되고 있는 모든 클라우드 기술의 근간이 되는 기술이다. 요즘 화제가 되고 있는 스파크(Spark)도 hdfs+MR 기술을 이용하여 만든 것이다.

  • hdfs : distributed file system, replication은 parallelism의 근간. 하나의 노드의 파일이 손상되어도 replication으로 보전하는 컨셉.
    • NameNode/SecondaryNameNode : file의 metadata를 기록하고 쿼리하면 리턴해주는 모듈.
  • MapReduce : MR 프로그램을 돌릴 수 있는 프레임웍. 그 유명한 Map Reduce. 물리적으로 하나의 컴퓨터에서 계산이 불가능한 것을 여러대의 컴으로 Map 해서 따로 계산후 Reduce로 취합하는 개념.
  • YARN : hadoop 2.x 버전 부터 Resource Manager가 독립이 되어 생긴 모듈. application scheduling 등을 하게 됨

설치 및 설정

hadoop 2.3 기준이고, 2.x 버전에서는 그대로 적용되는 내용일 것 같다. 우선 3대의 컴퓨터에 설치를 해보자. 각 컴퓨터의 이름과 용도를 맵핑 하면 아래처럼 된다.

1
2
3
dfs : hadoop master
dfs1 : data node
dfs2 : data node
  • 위 컴퓨터간에 ssh를 password없이 할 수 있게 서로 ssh key 등록
  • hadoop-2.3.x 버전을 master의 <HADOOP_INSTALL_DIR>에 untar
  • /etc/hosts에 컴퓨터 이름으로 찾아 갈 수 있게 dns 등록. 예> 0.0.0.0 dfs1 0.0.0.1 dfs2
  • /etc/hadoop/masters 에 master의 컴 이름인 dfs를 입력(한줄에 하나씩)

    1
    dfs
  • /etc/hadoop/salves 에 data node 를 실행시킬 컴 이름을 입력

    1
    2
    dfs1
    dfs2
  • /etc/hadoop/hadoop-env.sh 에 있는 JAVA_HOME, HADOOP_HOME 변수의 값을 채워준다. 각 JDK및 HADOOP이 설치되어 있는 path를 적어주면 된다.

  • master에 있는 hadoop 폴더를을 dfs1, dfs2에 카피. 아래 bash script를 사용하면 HADOOP_HOME 폴더를 싱크할 수 있어 무지 편하다.


1
2
3
4
for host in dfs1 dfs2
do
rsync -rv $HADOOP_CONF_DIR/ $host:$HADOOP_CONF_DIR/
done

hdfs 설정

etc/hadoop/hdfs-site.xml의 configuration 하위에 아래 property 추가

1
2
3
4
5
6
7
8
9
10
11
12
   <property>
<name>dfs.replication</name>
<value>2</value>
</property>
<property>
<name>dfs.name.dir</name>
<value>/home/spark/hadoop-2.3.0/hdfs/name</value>
</property>
<property>
<name>dfs.data.dir</name>
<value>/home/spark/hadoop-2.3.0/hdfs/data</value>
</property>

만약 하드 디스크가 여러개라면, dfs.data.dir에 마운트 된 경로를 추가해주면 된다. 경로1, 경로2 이런식으로..

YARN 설정

etc/hadoop/yarn-site.xml의 configuration 하위에 아래 property 추가. resource manager를 어느 컴에 둘지를 설정.

1
2
3
4
<property>
<name>yarn.resourcemanager.hostname</name>
<value>spark</value>
</property>

이 외에도 log aggregation 을 enable하려면 yarn-site.xml에 아래의 property를 추가해 주면 된다. 그럼 아래와 같은 식으로 log를 모아서 한번에 볼 수 있어서 분석시에 유용하다.
yarn logs -applicationId <app id>

1
2
3
4
<property>
<name>yarn.log-aggregation-enable</name>
<value>true</value>
</property>

실행

HDFS

  • master인 dfs 컴에서 .sbin/start-dfs.sh를 실행.
  • jps 실행시, 마스터에서는 NameNode,SecondaryNameNode가 그외 노드에서는 DataNode가 보이면 OK.
  • master:50070 으로 접속하면 hdfs web ui를 볼 수 있다.

stopping specific datanode

특정 datanode만 내리고 싶을때가 있는데 그때는 아래 명령어를 통해 특정ㅎ datanode를 kill 할 수 있다.

1
./bin/hadoop-daemon.sh --config ./etc/hadoop stop datanode

YARN

  • master인 dfs 컴에서 .sbin/start-yarn.sh을 실행
  • jps 실행시, master에서는 ResourceManager가, 그 외 노드에서는 NodeManager process가 보이면 제대로 뜬 것임.
  • master:8088 으로 접속하면 yarn web ui 를 볼 수 있다. nodes 메뉴에서 위에서 설정한 slaves들이 다 보이면 정상 동작하고 있는 것이다.

TroubleShooting

  • 우선 실행시 뜨는 콘솔의 에러내용을 보면 대락 실패원인을 알 수 있고
  • 특정 노드가 안뜬다던가 하면, 그 노드의 /logs 폴더에 있는 로그를 살펴 보면 힌트를 얻을 수 있다.

revision history

  • 2015/7/27 minor update

Jekyll + github = brand new blog

개발자들의 친구 github와 jekyll 이 만나니 이 홈페이지가 탄생했도다.
이를 기념하기 위한 포스트.

이제 알찬 컨텐츠를 넣는 일만 남았다.

여러가지 링크 예제

1
2
3
4
5
{% raw %}
[bash script]({% post_url 2015-06-11-hadoop-intro %})
![My helpful screenshot]({{ site.url }}/assets/screenshot.jpg)
{{ site.baseurl }}{% post_url 2010-07-21-name-of-post %}
{% endraw %}

gist 는 아래처럼 삽입할 수 있음.

1
2
3
{% raw %}
{% gist parkr/c08ee0f2726fd0e3909d %}
{% endraw %}

escape는 raw/endraw block으로 감싸주면 된다.

1
2
3
{{ "{% raw" }} %}

{{ "{% endraw"}} %}

References: