Exponential Backoff とは何か
Exponential Backoff という言葉を最近覚えたので、まとめておきます。
これはなにか
ネットワークを通してサーバーと通信失敗時にリトライ間隔をクライアント側で調節する手法です。 Exponential という名前の通り、リトライするときに失敗回数に応じて待ち時間を指数関数的に増やします。 1, 2, 4, 8秒・・・みたいな感じでどんどん次のリクエストを送るまでの時間が伸びていくわけですね。
ロードバランサを経由したリクエストを受けたけど、その先のWeb APIサーバーがダウンしてしまっている。。。みたいなときに有効です。
AWSの橋本さんの記事 にも実例が書かれています。
ジッターはリクエストの集中を防ぐ
システム内にクライアントが複数ある場合は、このまま特定のタイミングにリクエストが集中してしまう可能性があります。 そこで、ランダムに少しだけ時刻をずらすジッター(ゆらぎ)を加えることでリクエストの集中を防ぐのが定石です。
アルゴリズム例
Google Cloud Storage の Truncate Exponential backoff を参考に説明すると、
- リクエストを送る
- 失敗したら、1秒 + ジッター秒分だけずらす
- 失敗したら、2秒 + ジッター秒分だけずらす
- 失敗したら、4秒 + ジッター秒分だけずらす
- 待ち時間の上限を超えるまで増やし続ける
- リトライ上限回数を超えるまでリトライする(※ただし、待ち時間はこれ以上増やさない)
という風になります。
実装例
Go
Go も色々な実装があります。shogo82148さんのgo-retryはcontextがサポートされており、Goっぽい実装です。
package main import ( "context" "errors" "fmt" "time" "github.com/shogo82148/go-retry" ) type Result int func DoSomething(ctx context.Context) (Result, error) { // do something here that should to do exponential backoff https://en.wikipedia.org/wiki/Exponential_backoff return 0, errors.New("fails") } var policy = retry.Policy{ MinDelay: 100 * time.Millisecond, MaxDelay: time.Second, MaxCount: 10, } func DoSomethingWithRetry(ctx context.Context) (Result, error) { retrier := policy.Start(ctx) for retrier.Continue() { if res, err := DoSomething(ctx); err == nil { return res, nil } } return 0, errors.New("tried very hard, but no luck") } func main() { fmt.Println(DoSomethingWithRetry(context.Background())) }
Python
invlさんのretryはPython実装でデコレーターを使うAPIになっていて、Pythonicな実装だなーと思いました。
@retry() def make_trouble(): '''Retry until succeed''
参考
社会人2年目になった
社会人2年生になった
以下は昨年度を通してできるようになったことです
やったこと / できるようになったこと
Python3 たくさん書いた
スクリプト/CLIなら人並みにかけるようになりました。 FlaskなどのWebアプリケーション用途では使ってないので、そちらには明るくないです。 Python3 に関しては大体CTOから全部教わりました。
タスクの依存関係が複雑なバッチ処理をメンテナンスした
これが昨年度の自分の主な仕事でした。 怪しい臭いがするところにロギングを仕込んだりするとかはまだまだ自分はきちんとできないので、これからの課題です。 マネージドサービスに頼り切ってしまっていたので、インフラの知識が足りなさを痛感しています。
VS Code Meetup で登壇した
勢いで応募しました。自分はそんなに人前で話したりするタイプじゃないので、度胸試しみたいな気持ちで応募しました。 勢いで弊社SlackにもVS Codeユーザが集まるチャンネルを作ったりしました。
メリット/デメリット考えながらライブラリの選定とかできるようになった
運用時の制約やOSSのメンテナンス具合を考慮してライブラリの選定をできるようになりました。 直近だとPythonの仮想環境&パッケージ管理ツールであるPipenvのメンテナンスが滞ってしまい、Poetryへの移行を検討したりしました。 このような意思決定は運用を経験しないと身につかないスキルだと思います。
一次情報に触れるようになった
ビビらずに公式ドキュメントを読むようになりました。 必要に応じてGitHubのissueを開いたりできるようになりました。 あとは、Google翻訳に頼らずに早く英語を読み書きできるようになることが今後の課題です。
おわりに
\( ‘ω’)/ウオオオオアアーーーッッ!!!
GDG DevFest Tokyo 2019 参加レポート
※この記事はフラー Advent Calendar 2019 の24日目の記事です。23日は@RyotaMurohoshi さんの TypeScriptでnoImplicitAnyを導入するために、妥協してsuppressImplicitAnyIndexErrorsを導入する でした。
先日、GDG Tokyo が開催する DevFest2019 に参加した。
自分は業務で使っていないが、弊社で他のメンバーが使っている技術スタックのセッションがそれなりにあったので、興味本位で参加してみた。
聴講したセッション
岩尾 エマ はるか / 円周率世界記録への道
彼女自身がどのようにエンジニアのキャリアを形成し、円周率の世界記録を更新したかについての話だった。
彼女が中学生の頃に書いたオセロゲームのコードの変数名が適切でなかったエピソードなども面白かった。
(当時、英単語がわからなかったので、オセロの枠の変数名を border
などではなく、waku
で宣言していたようだ。)
Life with open mind これは彼女のブログであるが、Linux Kernel に強い興味を示しており、彼女自身の技術に対する探究心が伺える。
彼女に関する情報は以下にわかりやすくまとまっている。
太田 満久 / TensorFlow の使い方 〜 TF2.x とエコシステム 〜
自分はTensorFlowに関しては一度も今まで使ったことなかったが、それでも大まかな雰囲気をキャッチアップできるぐらいには非常にまとまっている良いプレゼンテーションだった。
近年では、TensorFlow.js や TensorFlow Lite などクライアントでMLをするために必要なものが割と整備されてきた印象がある。 クライアントMLのモチベーションとして * ネットワークのない環境でも利用できる * ネットワークの遅延を気にする必要がなくなる * サーバーサイドにデータを送らないため、プライバシーの問題が発生しない 等が挙げられるらしい。
デモでは、GAされたばかりのCloud Run でML用のAPIを作り、披露していた。
TensorFlowの使い方 DevFest 2019 - Google スライド
今はアノテーションツールとかいうのも充実してるらしく、これはデータに対して正解ラベルを付与するものである。
山口 能迪 / Goの10年の道のりとその変遷
10周年を迎えたGoの今までとこれからについてのセッションだった。
ALGOLからCやPASCALなどの言語が生まれ、それらのエンジニアたちが作り上げた言語がGoであること。C++が言語として大きく、ビルドが遅くなってしまったことがGoを作るモチベーションになっていることが説明されていた。
今より初学者フレンドリーにするためにgo.devが開設されたらしく、ここではA Tour of Goと違い体系的にGoに関する一次情報を得ることができるようだ。
柴田芳樹 / マイクロサービスの開発とテストファースト/テスト駆動開発
メルペイでBackendエンジニアとしてGoを書いている柴田さんのセッション。
www.slideshare.net
自身の経験から組み込みとWeb開発の違いや時代によるソフトウェアテストの変化について触れている。
柴田さんのブログの人気記事である初心者レベルの言い訳をしないではソフトウェアエンジニアだけでなく、教育者としての一面も強く現れている。
柴田さんは技術書の翻訳なども積極的に携わっており、その中の著名な本として プログラミング言語Go や Effective Java がある。
Katie Hockman / Go Modules made Safer and More Reliable
Google の Go Team で働く Katie Hockman さんによる公演。
Go Modules の checksum database や proxy についての話だったが、自分はまだGoについての知識が浅いのと英語のリスニング力が欠落しているので3割ぐらいしか理解できなかった。
かなしい。でも、Go の中の人が目の前で公演していることはすごく自分にとって貴重でいい刺激になった。
※Katie さんは来日をとても楽しんでいたようです。
Japan is gorgeous y'all pic.twitter.com/Qzl5R15KEM
— Katie Hockman (@katie_hockman) December 16, 2019
まとめ
純粋に参加者として楽しめました。
運営の方々、スピーカーの皆様、ありがとうございました。
Web APIにおけるデータフォーマットの指定方法
Web API The Good Partsを読んだ。
メモを少し書いておきます。
データフォーマットの指定方法
APIのフォーマットはJSONがデファクトスタンダードであるが、XMLもサポートしたい場合などは クライアントにどのように取得したい形式を指定させるべきか考える。
一般的に以下の方法が使われている。
- クエリパラメータを使う方法
- 拡張子を使う方法
- リクエストヘッダでメディアタイプを指定する方法
1つ目のクエリパラメータを使う方法は以下のようにして、json
やxml
といったデータ形式を指定する方法である。
https://api.example.com/v1/users?format=xml
2つ目は拡張子を使う方法で、ファイルに拡張子をつけるのと同じようにURIの最後に.json
や.xml
をつけてデータ形式を指定するものである。
https://api.example.com/v1/users.json
3つ目はAccept
というリクエストヘッダを使う方法である。Accept
は受け取りたいメディアタイプを指定するための
HTTPヘッダで、データ形式を指定することで「この形式でデータを受け取りたい」ということをサーバに対して伝えることができる。
どれを使えば良いのか
HTTPの仕様を最大限に活用する場合はリクエストヘッダで指定する場合が理想的であるが、やや敷居が高いという問題がある。 多くのサービスはクエリパラメータで取得することが多い。 本書でもクエリパラメータで取得することを推奨している。
macOSにhomebrew経由でJDKをインストールする
はじめに
TL;DR
こちらに関しては以下のリンクが参考になる。 【Mac】HomebrewでJavaをインストールする - Reasonable Code homebrew-versionsはその名の通り、バージョンを指定してインストールする拡張機能である。
$ brew tap caskroom/versions
その後、以下をjavaをsearchしてみる。
$ brew search java ==> Formulae app-engine-java google-java-format javarepl jslint4java libreadline-java ==> Casks charles-applejava java ✔ java6 oracle-jdk-javadoc charles-applejava java ✔ java8 oracle-jdk-javadoc eclipse-java java-beta java8 yourkit-java-profiler eclipse-java java-beta netbeans-java-ee yourkit-java-profiler eclipse-javascript java11 netbeans-java-ee eclipse-javascript java11 netbeans-java-se font-noto-sans-javanese java6 netbeans-java-se
※ここでtapした拡張機能は /usr/local/Homebrew/Library/Taps
に存在する。
❯ ls /usr/local/Homebrew/Library/Taps caskroom homebrew sachaos yusukehosonuma heroku rcmdnk sanemat
/usr/libexec
caskでJDKをインストールした後はインストールされた場所を調べる。
/usr/libexec/java_home -V Matching Java Virtual Machines (2): 11.0.1, x86_64: "OpenJDK 11.0.1" /Library/Java/JavaVirtualMachines/openjdk-11.0.1.jdk/Contents/Home 1.8.0_202-zulu-8.36.0.1, x86_64: "Zulu 8" /Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home /Library/Java/JavaVirtualMachines/openjdk-11.0.1.jdk/Contents/Home
いきなり現れた /usr/libexec
は /usr/bin/
や /usr/sbin/
の内部でcallされる補助的なコマンドである。
補助コマンドは /usr/libexec に - ソフトウェアエンジニア現役続行
ちなみにオプションである -V
をなしで実行するとインストール済みの最新のJDKが1つ表示される。
あとは、シェルの環境変数としてパスを通せば良い。
フラーに入社しました
フラーに入社しました。
入社の決めてはオフィスで楽しそうに働いている自分が容易に想像できたことです。
職種はソフトウェアエンジニアです。
おわりに
やっていくぞという気持ちです。 どうぞよろしくお願いします。