年始早々、Dataflowのエラーでかなりハマりました。
エラー自体は些細なことだったのですが、全然原因わからずに1日中悩んでしましました。
備忘も兼ねて、対応メモ書いておきます。
エラーの事象と対応
事象
開発中のジョブで、データ量的に数分で終わる、またはすぐにエラーで落ちるはずのジョブがあったのですが、実行中のまま動かず。そのままにしたら1時間実行中で何もないままタイムアウトしてしまいました。
根本原因調査
最初はどこか自分の書いた処理でループしたり、ハングしているのかと思ったのですが、よくよくStackdriverのログを見てみると、どうも環境構築ができずにループしているようでした。
いくつかエラーや警告が出ていたので調べていたのですが、一番気になったのはこれです。Shuffleに使うライブラリが無いって、結構コア部分だと思うのでそもそもおかしい。
Failed to install packages: failed to copy shuffle client: open /usr/local/lib/python3.6/site-packages/dataflow_worker/shuffle_client.so: no such file or directory
設定やコード変えては実行して、ログを見てを続けていたのですが、わからないなと思っていたら、以下のログを発見。
Checking docker image integrity of gcr.io/cloud-dataflow/v1beta3/python36:2.16.0
これ、Dockerイメージの中身を見れば何かわかるのでは?と docker pull
してみる。
中身を見てみると以下にコアっぽいtarファイルを発見。
# ls /opt/google/dataflow/
boot dataflow_python_worker.tar
展開してみた。
# ls
LICENSE dataflow_worker setup.py
気になる setup.py
の中身を抜粋見てみると、以下のようになっている。 上記のShuffleのファイルは cythonize
で作られているよう。ってことはこれがうまく動いていない・・
setuptools.setup( name='dataflow-worker', version=get_version(), description='Google Cloud Dataflow for Python Worker', long_description='', url='https://cloud.google.com/dataflow/', author='Google, Inc.', packages=setuptools.find_packages(), ext_modules=cythonize([ 'dataflow_worker/native_operations.py', 'dataflow_worker/shuffle_operations.py', 'dataflow_worker/stacktrace.pyx', ]),
そこから30分格闘して原因判明しました。
自分のDataflowジョブのsetup.pyファイル。
setuptools.setup(
name='dataflow worker'
Dataflow Workerのsetup.pyファイル。
setuptools.setup(
name='dataflow-worker',
そうです。空白とハイフンが違うものの名前が被っていたので、自分のジョブ用のファイルが、wokerのファイルを上書きしてしまっているのが原因でした。。。
くだらない内容ですが、わかった時特有の気持ちよさは感じました。
Dataflowのトラブルシュート方法
こんな変なハマり方久しぶりだったので、教訓を書いておきます。
ログはStackdriverで確認する
Dataflowのフロー図の画面からもログは確認できるので、普段使いはこれで良いと思います。ただ、トラブルシュート時にはStackdriverを使うことを強くオススメします。
特にこのフェーズ毎のログが役立ちました。あとは検索、絞り込みによりループしていることがわかったり。Dataflowに限ったことでは無いですが、サーバーレス系のサービスはログを意識して注意深く読むべきだと改めて感じました。
Dataflowのworkerの中身はDockerで確認できる
上記でも書いたDockerで見れるじゃん!という情報もStackdriverのログから見つけました。
Checking docker image integrity of gcr.io/cloud-dataflow/v1beta3/python36:2.16.0
そのままだとEntrypointが動いてしまってログオンできないので、以下のようにEntrypoint上書きすると入ることができます。これで中をみたり、setup.py等でコマンドを打った挙動を想定できるようになります。
$ docker run --entrypoint /bin/bash -it gcr.io/cloud-dataflow/v1beta3/python36:2.16.0
Dataflow WorkerによるStagingのマウント場所
通常、--staging_location
のオプションで指定されたGCSのディレクトリに、Pythonモジュール等が配置されます。
DataflowのWorkerから見ると、このGCSの配置場所は /var/opt/google/dataflow/
としてマウントされています。これを知っていると結構便利です。
困ったらGithubのコードを読む
WEB上の情報がJavaの方が圧倒的に多いので、特にPython SDKを使って開発している方は、Githubを読む機会が多くなると思います。
※以下のリンクは、v2.16のタグでリンク作っているので、適切なタグに変更してみてください。
特にポイントとなるコードとして、以下の pipeline_options.py
のコードがあります。コメントも豊富なので、Dataflowにどんなオプションがあるのかを知るには一番のドキュメントだったりします。
beam/pipeline_options.py at v2.16.0 · apache/beam · GitHub
実際に処理を書く時には、transformsとioのモジュール周りが参考になります。
beam/sdks/python/apache_beam/transforms at v2.16.0 · apache/beam · GitHub beam/sdks/python/apache_beam/io at v2.16.0 · apache/beam · GitHub
あとはExampleが置いてあるので、ここも参考になります。
beam/sdks/python/apache_beam/examples at v2.16.0 · apache/beam · GitHub