yigarashiのブログ

学んだことや考えていることを書きます

embulk-input-mysqlでCommunications link failureになる時の原因と解決方法

最近Embulkを使ってMySQLのデータをBigQueryに転送する仕事をよくやっています。データに基づく意思決定を促進するための大事な仕事です。これをやっている時にたまに以下のようなエラーに出会います。

org.embulk.exec.PartialExecutionException: java.lang.RuntimeException: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
 
 The last packet successfully received from the server was 5,024 milliseconds ago.  The last packet sent successfully to the server was 5,020 milliseconds ago.

この記事ではこのエラーの原因と解決方法を紹介します。

原因

結論から言うとMySQL Connector/JのsocketTimeoutオプション1によるタイムアウトが原因です。socketTimeoutは、このオプションで指定された秒数を超えてサーバーからのデータ送信が確認されない場合にタイムアウトにするものです。以下のようなEmbulkの設定で簡単に再現することができます。この例ではsocketTimeoutを5秒に指定してMySQL側で10秒sleepしています。

in:
  type: mysql
  host: ...
  user: ...
  database: ...
  table: ...
  select: sleep(10)
  socket_timeout: 5

out:
  type: stdout

この場合はMySQLからのレスポンスが遅いためにタイムアウトが発生しています。Embulkで実際にデータを転送する際には、クライアント(つまりEmbulk)側の処理が遅いために次のfetchを実行できず、結果としてデータ送信が発生せずにタイムアウトする場合もあります。

とはいえ、デフォルトのタイムアウトは30分とかなり長めに設定されているので、このエラーが発生するのは極めてスペックの低い環境で実行している場合に限られそうです。また、今回紹介した原因とは別にCommunications link failureが起こるケースも様々あるようなのですが、今回はそちらについては触れません。

解決方法

原因が分かってしまえば解決するのは簡単です。socketTimeoutよりも短い間隔でMySQLからデータが送信されるようにしてやれば良いのです。以下のように様々な方法が考えられます。

(1) socketTimeoutを伸ばす

embulk-input-mysqlのデフォルトのsocketTimeoutは1800秒です2。当然これを伸ばせばタイムアウトしづらくなります。さらに0を指定するとそもそもタイムアウトしなくなります。とはいえ、TCPコネクションが確立されたあとにサーバーがダウンしたケースもsocketTimeoutでカバーされるという意見もある3ので、バッチ処理を適切に失敗させるために適度なタイムアウトを設定するのが無難かと思います。Fargateで実行して気づかずに永遠に実行していたといった事故が起こりかねないと予想されます(他にも失敗させる機構はあるかもしれませんが)。

(2) fetch_rowsを小さくする

MySQL Connector/Jでは一回の通信で何件のレコードをfetchするかを指定することができます。embulk-input-mysqlにもfetch_rowsというオプションがあり指定することができます(デフォルトは10,000) 。これを小さくすると、一回のfetchにかかる時間や、embulk側でfetchしたレコードを処理して次のfetchを行うまでの時間が短くなるので、タイムアウトしづらくなります。当然サーバークライアント間の往復数は増えるのでオーバーヘッドは増加します。

(3) Embulk実行環境のスペックを上げる

Emulk側で処理して次のfetchを行うまでに時間がかかっている場合に有効です。ECSで実行しているならContainer Insightsを見てリソースが100%に当たっていないかを確認すると良いでしょう。何件か実行した感覚としては、Embulkを実行するときはCPUリソースが足りなくなりがちです。

(4) Embulkの並列数を下げる

Embulkを実行する際は、Digdagのようなワークフローエンジンと組み合わせて並列に実行することも多いように思います。このとき、並列数が多すぎるとCPUを食い潰してタイムアウトが発生することがあるようです。ワークフローエンジンの設定で並列数を調整してみましょう。

(5) データベースの当たり前のポイントを確認する

インデックスが効かない異常なクエリを投げたりロックが取られていたり、DB側のリソースが圧迫されてデータを返せなかったりすると当然タイムアウトする可能性があります。データベースからデータを読み出す際の一般的な注意点は踏襲しましょう。

最後に

デフォルトのタイムアウトが30分とかなり長めなので、調べながらホントに起こってたのか?という気持ちにはなったのですが、ひとまず手元で実験した結果や一般的に言えそうなことをまとめてみました。基本的にはEmbulkというよりJDBCMySQLの知識といった様子でしたが、大規模データを転送する場面では特に起こりやすいエラーではあるでしょう。ちなみに、一番オススメの解決策は(3)で、クラウドで実行しているならインフラ費用で殴って解決しましょう。実行時間も短くなってお得です。

『ふりかえりガイドブック』に学ぶワンランク上のふりかえりのポイント

ここ1年ほど仕事でふりかえりを主導する機会が多く、自分としてもふりかえりが重要だという気持ちが日に日に高まっています。しかし、ふりかえりをやればやるほどその難しさを実感しているのもまた事実です。ファシリテーションが負担であるとか、具体的なアクションに繋がらないとか、全員に話してもらえないとか、色々な課題を発見しては試行錯誤を繰り返しています。幸いなことに最近は手応えを感じ始めており、その知見をチーム外に展開していく運動を始めつつあります。自分の中に蓄積した経験的な知識を再構成して発信する上で、なんらかのよりどころが欲しいと思い、弊社の先輩がおすすめしていたアジャイルなチームをつくる ふりかえりガイドブックを読んでみました。

書籍全体の感想

端的にいうとかなりの良書です。ふりかえり初心者〜中級者に役立つ知識がぎっしり詰まっています。理論と実践のバランスがよく、まずは形からスタートして本質に立ち戻りながら改善を進めるというステップを1冊で完結できます。ふりかえりで直面しがちな様々な悩みに随所で言及しており、ふりかえりで悩んでいる人は心強く感じると思います。ふりかえりやチームカイゼンマインドセットについても厚く言及されているので、ふりかえりに深く関わっていない人が読んでも学びがあるでしょう。読みやすい文体と豊富なイラストですらすら読めるのも良いポイントです。ふりかえりの書籍ではアジャイルレトロスペクティブズも有名ですが、こちらは手法に寄った話題が多く中級者向けな印象が強かったので、よりチームメンバーにオススメしやすいふりかえりの書籍として重宝しそうです。

特に印象に残ったポイント

最近の自分の気付きと重なって特に印象に残ったポイントを2つ紹介します。書籍中でも何度も言及されているポイントで、効果が大きく、しかし自分で思いつくのが難しいと感じるワンランク上のポイントです。

ひとつは「小さく具体的なアクションから始めること」です。「ふりかえりの成果を感じられない」「〜を意識する系のアクションがワークしない」といった悩みに対するアンサーとして何度も言及されているポイントです。小さい変化はすぐに成果を実感しやすく上手くいかなかった場合も切り戻しが簡単なので、ふりかえりを続けやすくなります。また、SMART(Specific、Measurable、Achievable、Relevant、Timely/Time-bounded)なアクションを立てることで何をすべきかが具体化され、メンバーの行動につながりやすくなります。試行錯誤を細かく刻んで進めるのはまさにアジャイル開発のやり方で、チームカイゼンにおいてもアジャイルが有効だというのは重要な視点だと思います。

もうひとつは「メタなふりかえりを重視すること」です。ふりかえりが対象にするのはふりかえり以外のチームの活動だけと思いがちですが、そこだけを見て同じやり方を続けてしまうと、チームが変化せずふりかえりもマンネリ化して徐々に影が薄くなってしまいます。まずふりかえりで決めたアクションの実施状況や成果をふりかえりことが大事です。ふりかえりが具体的なチームの変化や成果に結びついているかを毎回検査することで、ふりかえりの価値を維持・向上することができます。さらに、ふりかえりのアクティビティ自体もふりかえることで、チームに合った形に変化させながら続けていくことができます。反復によって学習を積み重ね成長するのはスクラム開発の考え方でもあります。ふりかえり自体にもこの考え方を適用し、意識的にフィードバックループを作りだすことで成果を増幅していくことができるでしょう。

自分のように、ふりかえりをやっているけど悩みが尽きないというレベルにある人は、この2点が特に効くのではないかと感じました。もちろん本書では他の様々な観点についても丁寧に説明されており、その人のレベルによって学びを感じる部分は異なってくることでしょう。ふりかえりに興味がある方もない方もぜひ読んでみてください。

上手にカイゼンタスクを依頼してチームの自己組織化をアジャイルに進める

上手にタスクを依頼する

1月末の評価で「自分の挑戦はできているので、次は人が勝手に挑戦する仕組みづくりを」とフィードバックをいただきました。チーム内で果たせる役割が増え、自分だけではやりたいことを達成できない場面が増えたこともあり、最近はこのフィードバックに素直に従って周囲を巻き込むことを意識しています。

人を巻き込む典型的なパターンは、大きなタスクを分割してサブタスクを依頼するやり方かと思います。最近はこのパターンによく遭遇します。そうした状況でどのようにタスクを依頼するかは非常に難しい問題だと感じます。依頼した結果、依頼した側は手を動かさずに目的を達し、依頼された側はそのタスクを通して成長し成果を主張できるのが理想です。まだまだできていないことも多いですが、この理想の状態に至るために次の2点を意識しようとしています。

ひとつは期待を具体的に伝えることです。どんな目的でやっていて、依頼したタスクでどんな成果を得たいかということを、なるべく具体的にわかりやすく伝えるのです。よくわからないが形式的にやってみた、という結果を2人で見て直していくのが一番大変なので、とにかくそこを回避するように気を回します。場合によっては、タスクの目的を言語化するところからお願いすることもあります。

もうひとつは方針案を伝えすぎないことです。タスクを依頼する側は、良かれと思って方針案を並べて詳細に書いてしまうことがよくあると思います。しかし実際に進めてもらったら全然違ったということも、またよくあるように思います。これは、分業しないと進まない程度には難しいタスクについて、やる前に正しい方針を言い当てるのは難しいという、ごく一般的な事実を示唆しています。間違った方針案でお互いに時間を浪費するのは非常にもったいないので、手を動かした者がそのタスクに一番詳しくなることを信じて、検索キーワードや参考リンクといった形で足掛かりを作れないか考えるようにしています(ちなみにこれは不確実性・創造性の高いタスクを想定した話で、新卒向けの導入などはまた別の議論があると思います)。

チームの自己組織化に応用する

以上2点によって達成しようとしているのは「目的を共有して自律的な行動を促す」ことです。これは小規模な自己組織化に他なりません。依頼する側の目的に対して、依頼される側が自律的に行動し達成するという図式は、スクラムマスターがチーム単位で起こしたい現象によく似ています。最近はこの「他人に上手にタスクを依頼すると自己組織化が起こる」という現象を、チーム改善における自己組織化に積極的に利用する実験を試みています。

スクラムチームは、スクラムマスターがチーム改善に対して最も自己組織化された状態からスタートします。ここから自律的なチーム改善を広げていきたいわけですが、これまで自分が持っていた方法論は、チームの目的を啓蒙するであったり、ふりかえりを強化するであったり、教科書的には正しいもののメンバーひとりひとりの行動の変化からは距離があるものばかりで、難しさを感じていました。しかしよく考えてみると、モチベーションに差がある何人ものメンバーに対して一度に自己組織化を広げようとするのは、やり方としてはウォーターフォール的で、これが大変なことはアジャイルを志向する人々なら想像に難くないかと思います。ここから、自己組織化の浸透もアジャイルに進めてみようという発想が生まれます。

まずは、チーム内でチーム改善に対してモチベーションが高い人を1人〜2人仲間にします。そして、そのメンバーに大きめのチーム改善タスクや、スクラムイベントの一部を任せます。その際には、上に述べたような自律的な行動を促す依頼を意識します。これによって、スクラムのエッセンスを自分ごととして取り込んで行動してもらえるようになることが期待されます。チームをシャンパンタワーのようなモデルだと思って、中心からじわじわ考え方を広げていくようなイメージです。これによって、今まで漠然とチーム全体を対象に議論して足踏みしていた自己組織化が、段階を分けて議論できるようになると考えています。

今は1ホップ目を開始したところで、このエントリを書いている途中でも目的の共有が甘いなと思い直す部分が多々あるなど、前途多難ではありますがやっていこうと思います。

ふりかえりは必ずポジティブなコーナーから始める

ふりかえりは少なからず自分たちの悪いところを明らかにするプロセスを含むので、痛みを伴います。そして、チームが真面目で向上心があるほど、その痛みに立ち向かって改善を推し進めようとします。しかし痛みは痛みです。大小あれどストレスを感じて落ち込む人もいるでしょう。私は、そうした状況ではふりかえりの価値は低いと感じます。ふりかえりは単にフィードバックループができれば良いのではなく、ふりかえりの結果、次も頑張るぞとやる気が湧いてくるべきものだと思います。プロセスが改善されて、そのプロセスを回すメンバーのモチベーションが下がっては意味がありません。スプリントレトロスペクティブのような定期的なふりかえりでは、意欲的に参加し続けてもらうために、次のふりかえりも楽しみだなと感じてもらえることも重要です。

こうした考えから、ふりかえりをポジティブなコーナーから始めることを大事にしています。メンタリング等でよく言われる「まずは褒めよ」と同じ発想ですね。とにかく良かったことや成果に関する話題からスタートして、チームはよくやっているという気持ちを共有した上で、次に向けて直せるポイントがあれば議論しましょうとするわけです。最初にポジティブな空気を作ることで、そのあとの議論のトーンも変わっていくことが期待できます。少なくとも問題を追及するだけの地獄のふりかえりは避けられます。個人的には、これだけで100点中60点くらいは保証されると思っていて、ふりかえりを主導する立場からするとこんなに心強いことはありません。

自分のチームのスプリントレトロスペクティブでは、KPTにGoodのGを加えたGKPTを採用しています。Goodは自分のことでも他人のことでもチームのことでもなんでもよく、めでたいことや良い仕事を褒め合いましょうとしています。そうして書いてもらったGは最初のコーナーで全て取り上げます。この「全て」が大事で、投票して上位だけ取りあげるような形になると、下の方に触れられない自画自賛が残ったりして気まずくなるので要注意です。Goodコーナーでは、書いた人に次々読んでもらって、司会から「良いですね」と声をかけてみたり、他の人にコメントをもらったりします。それが一通り終わったあと、G以外の項目で投票を行って通常のKPTに入っていきます。この形式は「ミニ成果発表会のようで良い」とチームからも好評です。

それ以外の単発のふりかえりに呼ばれることもありますが、その場合も必ずポジティブなコーナーを作るようにしています。GKPTのようなフレームワークに載せられない場合は、アイスブレークと称して冒頭に時間を取って、「このプロジェクトで作ったものを見せてください」「チームやユーザーからポジティブなフィードバックがあったら教えてください」といった問いを投げたりしています。

もちろん、何もかも失敗していてどうしようもない場合もありますが、別に悪いプロジェクトじゃなかったのに何故かふりかえりがつらかった、というような落とし穴にはまらないためのセーフティーネットとして「ポジティブなコーナーから始める」は心強いプラクティスです。ぜひお試しください。

プルリクエストが大きくなると判断が歪むことに気付いた

僕の個人的な話で、一般の話ではありません。もし心当たりがあれば一緒に気付きましょう。

とある日、大きめの実装タスクがアサインされました。大きめというのは実営業日で1週間ちょっとかかるイメージです。内容はそこまで難しくなく、なんとなく書いて大きめのプルリクで済ませてもシュッと進みそうな印象でした。ということで、+500行くらいのプルリクと+400行くらいのプルリクに分けて実装を進めたわけですが、その中で一部のテストをどのくらい丁寧に書くか迷いました。レガシー寄りのシステムで堅牢さはそこまで要求されていないが、自分が安心できるくらいのテストは書きたい、しかし丁寧にテストするにはちょっとしたヘルパメソッドを用意する必要があるだろう、という状況でした。僕の最初の判断は次の通りです。

まず丁寧なテストはスキップすることにしました。代わりにヘルパメソッドを実装しなくて済むようモックを使った簡易的なテストを行うことにしました。手元のブランチには既にdiffが積み上がっており、さらにdiffを大きくする変更は、得られる安心に対して割に合わないように思ったからです。

出来上がったプルリクをレビューしてもらって、特に問題はありませんでした。ただ、修正の必要はない程度のコメントとして、件のテストの箇所に「ここはモックするんですね(意訳)」というコメントをもらいました。まさしくそこは迷ったし、他の部分との一貫性もないので、至極真っ当な疑問だと思いました。このコメントを受けた僕の判断は次の通りです。

やはり丁寧なテストをすることにしました。ヘルパメソッドを実装して、モックを使っていたテストを置き換えました。実装してみたらたかだか数十行で、動作確認を含めても10分で終わりました。追加のコミットを見てもらうだけなので何も躊躇することはありません。

ここまできて、自分の判断がプルリクエストの大きさによって歪んでいたことに気がつきました。個別に見たら簡単に取り組めるはずの事柄が、大きいプルリクエストに含まれることによって阻まれてしまっていたのです。原因はdiffの大きさというパラメータがコストパフォーマンスの判断に入り込んでしまったことでしょう。

この気付きを受けてなんらか改善を試みます。とはいえ、一番困るのはこうした誤認が起こりうることに気づかずに方針を縮退させてしまうことで、気づいた今となっては恐るるに足りません。一番良いのは、上手にタスクを分割してそもそもこういう誤認が起こりづらい状況を作ることです。当たり前ですね。とはいえ、それが過剰であったり面倒であったりするのが現実なわけです。落穂拾いなどと称してわざわざ別のプルリクエストにするほどの重要度はないが、その場でやっておけると世界が少し良くなるような事柄が無数にあります。そこでどうするか。diffの大きさを気にしすぎないというのはひとつの手だと思います。実際、もともと大きめのプルリクエストに数十行のコミットが足されたところで、レビュワーの負担はほとんど変わりません。diffが大きいのは悪というプラクティスに引っ張られて良い行いをやめるくらいなら、開き直って実装するほうが前向きではあります。

じゃあ200行も300行も足して良いかというとそうではないので、いつもの通り要はバランスという結論になるのですが、とにかく、diffの大きさに自分の判断が振り回されていないか考えてみてはいかがでしょうかという話でした。