EMR上でPython3系でpysparkする


概要

  • 機械学習・データサイエンスといえばpython(numpy/iPython/scikit-learn)なのでpythonで書いていきたい。
  • しかし、仕事柄大規模なデータを扱うことになるので、分散できるsparkのAPIで取り扱いたい。

  • ということで(EMR)クラスタ上でpysparkを動かしてみます。

  • 今からpython学ぶなら3系だろうということで3系(Anaconda3-4.0)で動かします。

  • 不安だったので確認したけど、sparkは1,4からpython3系に対応してますね。


手順

基本的にこちらの記事を参考にしました。丁寧に書かれていて素晴らしいです。

Spark + IPython環境をAmazon EMR上で構築し、簡単なData解析を動かして見る (第1回:環境構築編)

  • スクリプト準備
  • EMRクラスタ立ち上げ
  • iPython Notebook起動
  • 動作確認

スクリプト準備

以下の2つのshellを用意します。

  • EMRのbootstrap時に全ノードにanaconda3を入れるためのスクリプト
anaconda3-bootstrap.sh
#Environments
ANACONDA_VERSION=3-4.0.0

PYENV=~/.pyenv
PYENV_BIN=$PYENV/bin


##Install git and Anaconda
sudo yum -y install git
git clone https://github.com/yyuu/pyenv.git $PYENV

echo -e "\nexport PYENV_ROOT=$PYENV" | tee -a ~/.bash_profile  >> /dev/null
echo -e "\nexport PATH=$PYENV_BIN:$PATH" | tee -a ~/.bash_profile  >> /dev/null
echo -e "\neval '$($PYENV_BIN/pyenv init -)'" | tee -a ~/.bash_profile  >> /dev/null
source ~/.bash_profile

pyenv install anaconda$ANACONDA_VERSION
pyenv rehash
pyenv global anaconda$ANACONDA_VERSION

echo -e "\nexport PATH='$PYENV/versions/anaconda$ANACONDA_VERSION/bin/:$PATH'" | tee -a ~/.bash_profile  >> /dev/null
source ~/.bash_profile
conda update --yes conda

##Install addtional python libraries
conda install --yes seaborn
  • MasterNodeでiPyhtonの設定を行うスクリプト
setup-iPython.sh
#Environments
SPARK_PACKAGES=com.databricks:spark-avro_2.10:2.0.1,com.databricks:spark-csv_2.10:1.4.0
ANACONDA_VERSION=3-4.0.0
JUPYTER_LOG=/home/hadoop/.jupyter/jupyter.log

PYENV=~/.pyenv
PYENV_BIN=$PYENV/bin

##Configure Jupyter
jupyter notebook --generate-config

JUPYTER_NOTEBOOK_CONFIG=/home/hadoop/.jupyter/jupyter_notebook_config.py
sed -i -e "3a c.NotebookApp.ip = '*'" $JUPYTER_NOTEBOOK_CONFIG
sed -i -e "3a c.NotebookApp.open_browser =False" $JUPYTER_NOTEBOOK_CONFIG
sed -i -e "3a c.NotebookApp.port = 8080" $JUPYTER_NOTEBOOK_CONFIG
sed -i -e "3a c = get_config()" $JUPYTER_NOTEBOOK_CONFIG

IPYTHON_KERNEL_CONFIG=/home/hadoop/.ipython/profile_default/ipython_kernel_config.py
ipython profile create
sed -i -e "3a c.InteractiveShellApp.matplotlib = 'inline'" $IPYTHON_KERNEL_CONFIG


##Launch Jupyter by executing "pyspark"
JUPYTER_PYSPARK_BIN=/home/hadoop/.jupyter/start-jupyter-pyspark.sh

cat << EOF > $JUPYTER_PYSPARK_BIN
export SPARK_HOME=/usr/lib/spark/
export PYSPARK_PYTHON=$PYENV/versions/anaconda$ANACONDA_VERSION/bin/python
export PYSPARK_DRIVER_PYTHON=ipython
export PYSPARK_DRIVER_PYTHON_OPTS='notebook'
export SPARK_PACKAGES=$SPARK_PACKAGES
nohup pyspark --packages $SPARK_PACKAGES > $JUPYTER_LOG 2>&1 &
EOF

chmod +x $JUPYTER_PYSPARK_BIN

EMRクラスタ立ち上げ

基本は上記参考記事のままなのですが、

  • BootStrapActionで上記のanaconda3-bootstrap.shを読ませる。
  • とりあえず使うときはSpot Instanceを使うと安いよ。
  • Security-Groupは、とりあえず自分のマシンからMasterNodeにsshログインさえできればOK。
    • 実運用ではEMRを外に晒したくないので踏み台とか経由すると思います
    • が、ちょいと面倒なので、とりあえずKeyがないとsshできなくて、他のportが空いてなければいいかなと。
    • CoreNodeはとりあえずEmrManagedSlaveSecurityGroupを使っとけば大丈夫。

設定例の全体はこんな感じ。

aws emr create-cluster --applications Name=Hadoop Name=Spark Name=Ganglia --bootstrap-actions '[{"Path":"s3://<bucket>/anaconda3-bootstrap.sh","Name":"Custom action"}]' --ec2-attributes '{"KeyName":"","AdditionalSlaveSecurityGroups":[],"InstanceProfile":"EMR_EC2_DefaultRole","SubnetId":"","EmrManagedSlaveSecurityGroup":"","EmrManagedMasterSecurityGroup":""}' --service-role EMR_DefaultRole --enable-debugging --release-label emr-4.7.2 --log-uri '' --name 'jupyter pyspark' --instance-groups '[{"InstanceCount":1,"BidPrice":"0.1","EbsConfiguration":{"EbsBlockDeviceConfigs":[{"VolumeSpecification":{"SizeInGB":32,"VolumeType":"gp2"},"VolumesPerInstance":1}]},"InstanceGroupType":"MASTER","InstanceType":"m4.large","Name":"Master instance group - 1"},{"InstanceCount":2,"BidPrice":"0.1","EbsConfiguration":{"EbsBlockDeviceConfigs":[{"VolumeSpecification":{"SizeInGB":32,"VolumeType":"gp2"},"VolumesPerInstance":1}]},"InstanceGroupType":"CORE","InstanceType":"m4.large","Name":"Core instance group - 2"}]' --configurations '[{"Classification":"spark","Properties":{"maximizeResourceAllocation":"true"},"Configurations":[]}]' --region ap-northeast-1


iPython Notebook起動

立ち上げた後、MasterNodeにSSHして、上記のsetup-iPython.shを流し、

$JUPYTER_PYSPARK_BINを実行すればiPython notebookが立ち上がります。

後は自分のマシンから
ssh -i ~/.ssh/my.pem -ND 8157 [email protected]のようにsshトンネリングを行い、ブラウザにproxyを立てればOK(やり方はEMRに書いてある)

ブラウザからhttp://ec2-XXXX.com:8080に繋げたら設定完了。


動作確認

こんな感じになりました。試しにKMeansをscikit-learnと比較してみました。


まとめ

  • EMR使うとクラスタ上でのpyspark環境が楽に用意できますよ。
  • ただ、sparkContext張りっぱなしなので一度に複数のNOTEBOOKは操作できないかも。
  • iPyhtonで試して、上手く行ったらそれをそのままScalaに直して実運用!とかできそう。
  • MasterNodeにもWorkerNodeにもPython3系が必要です
    • もしバージョンが合ってないと実行時に怒られます。