ISUCON9予選参加した

反省会。

チームについて

@kadokusei , @watiko と3人で sisisinと愉快な仲間たち チームとして参加。
kadokusei がインフラ、 watiko・自分がアプリとかボトルネック調査を担当

自分の覚えてる範囲でやったこととか書き残しておきます

最終的に出来たこと

  • /users/transaction.json の外部API呼び出しのキャッシュ
    • redisに /status の結果をキャッシュしておいてそこから引く処理を入れた
    • /initialize 時に初期データから取得できるステータスを全てキャッシュに突っ込んだ
  • DBインスタンスを分けた・DBインスタンスにredisを載せた
  • categories テーブルのデータをメモリにキャッシュ
    • 最初から全部乗せるのはテーブル構造が地味に複雑だったので諦めて、結果をメモ化するにとどめた
  • items,transaction_evidences,shippingsに適当にインデックスをはった

やろうとしたけどダメだったこと

  • appの複数台構成
    • 画像をwebdavで一台にまとめて置く、などを試すも、アプリからwebdavにファイルを置くのが上手く行かず断念
  • /users/transaction.json の外部API呼び出しの並列化
    • こんなに言語によって難易度差出るやつは想定解法じゃないんじゃ?って疑問に思ってドキュメント見たらキャッシュできそうだったので方針切り替えた

調べて気付いたこと

  • datadog APM使って各種エンドポイントとそのどこに時間がかかっているかの調査
    • /users/transaction.json , /items/:item_id.json , /new_items.json 辺りが重い
  • DB全然時間かかってなさそう
  • /users/transaction.json はN+1に目がいったけど実際はAPI呼び出しがめっちゃ時間食っている
  • categoriesusers テーブルの呼び出し回数がやたら多い(が、時間はかかってない)

つらかったこと

  • 初手アリババクラウドから身分証明書提出を求められるダイアログが出てしまって運営の対応待ち。
    • 10:30ぐらいまで何もすることがなかったのでマニュアルを読んでいた。
    • せめて /docs だけでも最初に配布しておいてもらえればまだ良かったんだけど・・・

  • デプロイ周り整えるのに時間食いすぎた

よかったこと

  • 準備してたところはちゃんと出来た
    • redis用意、datadog apm用意、初期のconfig作成など
  • ローカル環境整えたのは便利に活用できた人もいた(自分は /users/transaction.json の動かし方がわからなかったのであまり活用できず。。)

感想

最終的に目の付け所は悪くなかったと思ってるんだけど、自分の地力不足を感じた
たかがインデックス貼るスクリプト書くのに30分とかかけてて雑魚乙って感じになってしまった、もっと上手くなりたい・・・

あとデプロイ周りは書いて終わりじゃなくてデプロイしてベンチするところまでちゃんとやりたいとか、ボトルネック調査もっと上手くやりたいとか色々ありつつ

初参加だったけど手応えはあった気もする
ただちょっと微妙な点として、普段こんなに生のインスタンス触らないから練習負荷が高いのがなんともなあという気持ちがちょっとだけあったりも。

結構悔しいので来年もまた頑張りたい所存

Aurora ServerlessとECS Fargateで動くRailsアプリのクエリチューニングをした

tl; dr

  • Aurora Serverlessの場合はスロークエリログ有効化設定がAWS上にある
  • DataAPIを有効化すればクエリ叩き放題で最高
  • チューニングのためのはじめの一歩として、パフォーマンス計測のための環境整備をインフラやアプリに合わせて適宜構築するのが大事

結果としてやったことはただ単純にslow query logを有効化して該当のクエリをexplainして直しただけ

前提

アプリケーションサーバ

DB

  • Aurora Serverless
  • MySQL 5.6

インフラの構成管理にはAWS CDK経由でCloudFormationを利用

準備

まずスロークエリログを見たい or APMでアプリのボトルネックを見たい、というところからスタート
スロークエリログ有効化の方が手っ取り早いし多分クエリが遅いはずだと思ってたのでひとまずスロークエリログから着手した

スロークエリログ有効化

Aurora Serverlessを利用している関係で直接MySQLのログを見ることは出来ない
CloudWatchLogsに吐かせる設定がコンソールやCFnなどから出来るのでその設定をした

参考:

Aurora ServerlessでログをCloudWatch Logsへ出力可能になりました | DevelopersIO

*aws-cdk@0.20.0 を利用(古いのはご愛嬌)

const dbParameterGroup = new rds.ClusterParameterGroup(this, 'DBParameterGroup', {
      family: 'aurora5.6',
      description: `Parameter Groups`,
      parameters: {
        slow_query_log: 1,
      },
    });
    const cluster = new rds.cloudformation.DBClusterResource(this, 'Database', {
      dbClusterParameterGroupName: dbParameterGroup.parameterGroupName,
      // 中略
    });

スロークエリログで何度も叩かれてそうな上に遅いクエリを見つけたのでとりあえずそいつをexplainしたいということになったので今度はその準備をすることに。

DBインスタンスにクエリを実行する

結論としては、Aurora ServerlessのDataAPIを有効化してAWSコンソールから直接クエリできるQueryEditorを利用した
参考: Amazon Aurora ServerlessでManagement Consoleからクエリが実行可能になりました | DevelopersIO

他の選択肢はこんな感じだった

  • ecs-cliのrunコマンド経由でrails runnerを利用してモデルのクエリをexplainする
    • ECSタスクを毎回立ち上げてクエリしてその結果をCloudWatchLogsで確認、という流れなので死ぬほど面倒
  • gatewayサーバー立ててssh
    • EC2立てるだけっちゃだけだけど、その辺手慣れてるメンバーがチームにいないので微妙に腰が重かったしお金もかかる
  • ALBで一時的にVPCトンネルをつくる・・・?
    • 風のうわさでそういうことが出来ると聞いたけどよくわからなかった

結果

ここまででスロークエリを探してexplain出来るようになったので、該当のクエリを見てみたらwhereされてないサブクエリの結果セットが80万行とかになっていたのが原因ということが判明
適当にモデルのクエリを調整していい感じに速くなった。めでたしめでたし。

APMについて

チューニングしたときには活用しなかったけどちょろっと調べたり動かしたりしたので一応メモ

あがった選択肢

  • NewRelic
    • gem入れるだけで動かせてお手軽
    • ECSの料金体系についてドキュメントがなく、問い合わせて見積もりもらわないとわからないので会社員的に地味に辛め
      • *そのぐらいポンッと使わせてくれない会社が悪いという説もある
  • AWS X-Ray
    • ECSの場合エージェント用のタスクを立ち上げる必要があるのでNewRelicに比べると導入めんどい
    • ドキュメントにもRailsのサンプルがなく、多少試行錯誤しそうだったので動かして見るところまではまだやってない
  • DataDog APM
    • NewRelicよりは安そうだった
    • あまりちゃんと調べてない

感想

Aurora Serverlessが便利だった(こなみかん)


実はこのクエリチューニングはチームで1日時間をとってISUCON大会と称して合宿したときの成果で、それはそれで良かったという話もあったり。
スロークエリを探しつつAPMをアプリ得意な人が準備したり、explainするときに何見ればいいのかとか横からアドバイスもらったりしながらワイワイやれて楽しかった。

うちのチームは様々な事情でバックエンドエンジニア不足のためにこの手のタスクの進みが悪いので、こうやってISUCON大会してガッと進められたのはめっちゃよかった

6月の新刊が多すぎるのでメモる

amzn.to amzn.to amzn.to amzn.to amzn.to うちの娘の為ならば、俺はもしかしたら魔王も倒せるかもしれない。 5
トニカクカワイイ(6)
私に天使が舞い降りた!6
君に愛されて痛かった(3)
ブルーピリオド(5)
舞妓さんちのまかないさん (10)
ダーウィンズゲーム(18)
初恋ゾンビ (17)

scansnapでスキャンした画像を自前で用意したプログラムで処理する

tl;dr

  • 連携するアプリケーションという設定 で、1回の取り込みが終わったタイミングで呼び出すexeファイルを指定できる
  • exeファイルは読み込んだファイルのファイルパスをコマンドライン引数で一括で渡してくれる
  • なので、コマンドライン引数を処理するプログラムをexeファイルとして固めることができれば自前のプログラムで自由に触ることができる

ということをやるプログラムを書いた

github.com

やったこと

  • nodeのプログラムをexeに固めるビルド環境の整備
  • Macでの開発環境作った
  • Windows環境のexeファイル呼び出しあれこれを調整

nodeのプログラムをexeに固めるビルド環境の整備

  • nexe をつかうだけ
  • Windows環境下で使う場合、Windowsでnexeを実行すれば何も考えずにexeファイルが作れる

Macでの開発環境作った

Windows環境でnode書くのいろいろしんどい(Macキーバインド違う、win周り疎いのでターミナル環境でハマる(素でnpx使えないのビビった))ので、Macで開発できるようにした

  • nexeの引数でwindows向けビルドを出来るように
    • -t win32-x86-10.13.0 で動いた
    • が、 win32-x86-10.13.0が何を指すのか全くわかってなくて辛い
  • バイナリをDropboxに吐き出すように調整
  • 基本的な動作確認はエントリポイントのファイルを nodeで叩けば良いので特に考える必要がない

Windows環境のexeファイル呼び出しあれこれを調整

  • PATH設定して再起動
  • exeファイル呼び出しで何もしないと実行が終わり次第ターミナルが落ちるので、readline.createInterfaceで待ち受けるようにしたり、ログをファイルに落とせるようにしたり

Macの環境作るのに一番ハマったので、我慢してwin環境で書けばよかったかも。。
やること自体はただのファイルコピーみたいなもんだし

やろうと思ってやらなかったこと

  • バイナリ公開
    • 誰得感あったのでやめた
    • cloneしてビルドコマンド叩いてもらえれば使えるしまあええやろみたいな気分
  • 対話インターフェース作って保存先調整したりしよう
    • 取り込み作業がめんどくなるのでやらんでいいかなと言う気持ちに
  • テスト・CI
    • travisがwin環境提供し始めたらしいし、exeビルドしてe2eテストとか書くと安心感あるかなと思ったけどめんどくさくて未着手
    • readline で待ち受けるところとかがね・・・
    • 気が向いたらやるかも?

SlackをTwitterのタイムラインライクに閲覧できるクライアントを作った

予定だったけどちゃんと作れた。やったぜ。
感想っぽい内容なのでQiitaではなくブログにしといた
というわけで簡単に振り返り

続きを読む

Reactで管理画面を作る際のComopnentライブラリ選定メモ

考えをまとめるためにメモ。

目指すところ

  • 手早く・楽して作る

アプローチ

  • 全部自分で作る
  • CSSフレームワークを自前でラップし、その他は単目的ライブラリを探して使う
  • Bootstrap/Material Designなどを実装したライブラリをベースにしてその他を自分で作ったり単目的ライブラリを探して使う
  • 全部入り(管理画面用コンポーネントライブラリ)を使う

全部自分で作る

文字通り、デザインもCSS書くのも動きをつけるJSを実装するのも全て自前でやる

メリット

  • 全て自分で制御できるので、ライブラリ使っててよくある「これが出来ないの困るんだけど」みたいなことにならない
  • ライブラリ探しとか考えなくていい

デメリット

  • UIデザインが出来ないと話にならない
  • とにかく実装に時間がかかる
  • クオリティ担保が大変

CSSフレームワークを自前でラップし、その他は単目的ライブラリを探して使う

BootstrapなどのライブラリのCSSを自前で作ったComponentに記述して使う

メリット

  • JSの世界については全て自分で制御できるので、ベースになるCSSフレームワークの制御をかなり自由に実装できる
  • CSSフレームワークの恩恵(Gridレイアウトを簡単に使える、ちょっと洒落たデザインをすぐ実装できる)を得られる
  • マイナーなCSSフレームワークで、React実装がないものでも自分で実装するので関係なく活用できるので選択肢の幅が広い

デメリット

  • 全て自前実装に比べてマシだけどやっぱり実装が大変
  • 大抵の場合jQueryとの共存を考える必要がある
  • ライブラリくささが出る(Bootstrap感を隠せない感じ)

Bootstrap/Material Designなどを実装したライブラリをベースにしてその他を自分で作ったり単目的ライブラリを探して使う

reactstrapなどを使う

メリット

  • Gridなどを簡単に実装できる
  • 最低限作るのに道具が揃ってるのである程度手早く実装できる

デメリット

  • ライブラリくささが出る
  • bs,mdのComponentライブラリの細かいデザイン調整は案外手間がかかるっぽい(あんまり詳しくないけど)

全部入り(管理画面用コンポーネントライブラリ)を使う

CoreUIなどを使う

メリット

  • 提供されているものの範疇で実装するなら一番手軽
  • 定番のUIライブラリとちょっと違ったデザインを利用できるのでただBootstrapを使ったものと差別化できる

デメリット

  • 有償のものが多い
    • =利用者が多くないので、利用方法の模索が大変そう・バグを踏んだときが不安
  • React Componentが提供されている物が少ない

上から順に自由度が下がっていく感じ。

今までは手なりで「Bootstrap/Material Designなどを実装したライブラリをベースにして〜」でやってきたけど今回はどうしようかなあ

最近覚えたりやったりしたことを列挙

こんなことやったなぁを書いておこうと思った。

Scala

型クラス

ぶっちゃけプロダクトでどう使えばいいのか全然ピンとこなかったのでもう忘れた...
型クラスがあることによってどんなことを型で表現するからメリットになるのか?の例が知りたい

scalikejdbcとscalikejdbc-bigquery触った

この辺

github.com

ついでにtypesafe-configとかも。
当初の目的としてはscalikejdbc-bigqueryをゴニョるために触った感じ。
普段のプロジェクトではいろいろなライブラリを使ってる関係で生scalikejdbcを触る機会が全然ないので適当に触って、クエリを発行できるようになるまでどんな手順でやればいいのかとかを適当に触った

=:=

型の同一性チェックができる(雑)

mockitoのeqをscalaで使う

Scalaには eq が存在してるのでインポート時に別名でインポートしないと使えない(ハマった

ScalaからCLIツール(具体的には gsutil コマンド)を叩く実装を書いた

要件として、

  • コマンドはなるべく複数並列で叩きたいし、並列数も制御したい
  • コマンドが応答しなくなったら並列で実行中のプロセスをkillしてからScalaのプロセスもちゃんと落としたい

というのがあって、Futureで並列度を制御しつつ、プロセスをkill出来るような実装を頭悩ませて実装したりした
jsでもCLIのラッパー書いたことあるけどキツかったので、CLIのラッパーはどの言語でやってもきついのかもしれない・・・

infra系

Ansible少々触った

  • task,role,inventoryあたりの概念多少知った
  • ユーザー定義の関数を作れるらしいと知った(作ったことはない)
  • スクランナー化したAnsibleは地獄だと知った(弊プロダクトのインフラはそうなってしまっている)
  • 変数の出処を探すのが大変なのでシンプルに保とうという気分になった
  • あと宣言的になるように、とかね。。。

CloudFormation少々触った

  • スタック・変更セット・アウトプット・userdataあたりの概念を知った
  • 順当に運用するのが普通に難しいということがわかった
  • Ansibleに比べて変更の頻度が少ないし、作り直しみたいなことも普通はしないので、「冪等性を保つ」のが意識されにくい
    • 最新のテンプレートだけを反映すればOKという状態になっていない不具合が起きてしまっていた
    • 作って壊してを頻繁に実施するような運用にしたほうがいいのかもしれない
    • インフラ系は触り始めて日が浅いので、ベストプラクティス・・・というかうちの事情を踏まえた上でどうすれば改善できるのか?というのがあまりわからない
  • GCPのDeploymentManagerも多分似た話があるんだけど、こっちは今いるプロダクトだとCFnよりさらにめったに触らないので逆に問題が起きにくい感じがある

Storage Transfer Serviceを毎時集計に使うようにした

EMRでサマった結果をBQでロードするためにS3→GCSへ移動するのに利用。
どうやらこのTransfer ServiceはGCP上の共通のリソースを使っているらしくて、他のProjectがTransferのリソースを使いまくってるときにこちらもアオリを食らうということがあったりしてひどい目にあった
アレ本番運用で定常的に使ってる人がいたらどうしてるのか聞きたい・・・

なおうちはgsutil rsyncコマンドで対処できるように、という対応をしました

CircleCI

この辺↓のことをやった

qiita.com

qiita.com