うなすけとあれこれ

2018年02月04日

落ちていたitamaeのintegration specを直しました

itamae readme

master build failed

itamaeの名前を久々に聞いたのは、昨年11月に行なわれた福岡Ruby会議02でのことでした。前夜祭でのまなてぃさんの発表でitamaeを使っているとの話を聞き、また、懇親会でまなてぃさんがPullRequsetを出したがテストが通らずmergeもしてもらえないという話を聞き、それからずっとitamaeのことがどこか頭の片隅にありました。

その後、転職記事でも触れましたが、業務でpuppetを置き替えることになったときに、ここはitamaeを使ってみようと考えました。そこでitamae-kitchen/itamaeを見に行くと、そもそもmaster branchのでのCIが(2017年3月から)failedになっていることに気づきました。

cookpadでの採用実績や、gihyoでの解説記事、バージョンも1.9を迎えるなどそれなりに成熟しているOSSと言って差し支えないでしょうが、masterのCIが失敗しているプロダクトにあまりいい印象はないでしょう。そこで、業務でitamae recipeを書きつつ、その合間と個人的な時間でitamaeのCIを直すことに挑戦しました。

fix CI

まずは手元で実行できるように

さて、では作業にとりかかろうとforkし、cloneしてbundle installを実行しましたが、まずこれが失敗します。原因としては、net-ssh gemが、itamaeが依存しているspecinfraで要求しているバージョンとvagrantが要求しているバージョンとで衝突しているせいでした。

itamaeが要求しているvagrantですが、ryot_a_raiさんがforkしたものであり、またその意図もよくわからなかったので、gem update vagrantをしてしまえと思いました。

なるほど。そもそもなんでforkしていたか忘れてしまった

— Ryota Arai (@ryot_a_rai) 2017年12月7日

しかしvagrantはある時点からrubygemでの配布をやめ、公式サイトからパッケージをインストールする方式になっていたので、そもそもvagrantへの依存自体を削除することにしました。

test-unitで落ちるspec

さて、落ちるspecを見てみます。

https://app.wercker.com/buildstep/58bf89e2ae336e01005e1487

ERROR :         Command `gem install -v 3.2.0 test-unit` failed. (exit status: 1)
ERROR :   gem_package[test-unit] Failed.

というわけで、test-unit gemのあたりでなにやら失敗しているようです。このrecipeを見ると、以下のようになっています。

gem_package 'test-unit' do
  version '3.2.0'
end

何の変哲もないgem_packageですが、何故失敗するのでしょうか。

test-unit gemは、power_assert gemに依存しています。power_assert gemの内部で、%i を使用しているコードがあるのですが、integration specで使用しているubuntu trustyのRubyが1.9.3でまだこのリテラルに対応していないために、power_assert gemのインストール(RDocの生成)に失敗してしまいます。

https://github.com/k-tsj/power_assert/blob/180b0c0fe619f4619d91e25b1d09b30f3df2f14c/lib/power_assert/parser.rb#L61

itamaeのintegration specでは、trustyにbuilt inのRuby(1.9.3)を使うんだけど、Ruby 1.9.3には %i がまだ実装されてないからpower_assert gem v1.1.1のinstallで落ちるんだ……

— うなすけ (@yu_suke1994) 2017年12月10日

まあそれはそうなんですがEOLなRubyのためにアレコレするのはちょっとどうかなーと思っているので、普通にRuby 2.2以上を入れたい気持ちです。

— うなすけ (@yu_suke1994) 2017年12月10日

なので、ubuntuをtrusty(14.04 LTS)ではなくxenial(16.04 LTS)にアップグレードしてしまいました。

パッケージがインストールできなくなる

ある程度覚悟していましたが、ubuntuをアップグレードした結果、バージョンを指定していたパッケージのインストールに失敗するようになってしまいました。 これは、単純にバージョンを有効なものに変更するだけで済みます。これでslのバージョンが上がり(?)ました。

 package 'sl' do
-  version '3.03-17'
+  version '3.03-17build1'
 end

rcスクリプトを参照するrecipeが存在する

とりあえず、以下のrepiceを見てください。

service "nginx" do
  action [:enable, :start]
end

execute "test -f /etc/rc3.d/S20nginx" # test
execute "test $(ps h -C nginx | wc -l) -gt 0" # test

service "nginx" do
  action [:disable, :stop]
end

execute "test ! -f /etc/rc3.d/S20nginx" # test
execute "test $(ps h -C nginx | wc -l) -eq 0" # test

https://github.com/itamae-kitchen/itamae/blob/2c57ecc2f085643a47a7d509040685dbecde8bc7/spec/integration/recipes/default.rb#L246

見てわかるように、rcスクリプトを参照しているrecipeがあります。しかし、ubuntu xenialにアップグレードしたことによって、initがUpstartからsystemdへと変化しました。その結果、rcスクリプトは利用できなくなってしまい、このrecipeは適用できません。(この辺ちゃんとした理解ができてないです)

ただ、rcスクリプトを使用したコマンドの内容自体は、続く行で実行している ps にて担保できているとみなせます。なので、rcスクリプトを使用しているrecipeを削除することで対応しました。

複数回実行したときに落ちる場所が変わるspec

新規に起動したVMに対してspecを実行する場合と、それが失敗して、もう一度そのVMに対してspecを実行する場合とで、落ちるspecが異なることに気付きました。

原因調査のためにvagrant sshなどでVMに入り調べたところ、以下のspecでその問題が発生していました。

execute "mkdir /tmp/link-force-no-dereference1"
link "link-force-no-dereference" do
  cwd "/tmp"
  to "link-force-no-dereference1"
  force true
end

execute "mkdir /tmp/link-force-no-dereference2"
link "link-force-no-dereference" do
  cwd "/tmp"
  to "link-force-no-dereference2"
  force true
end

このmkdirを実行している部分です。mkdirは、既に存在しているディレクトリを対象にして実行するとエラーを返します。一度目の実行で作成されたディレクトリが残ったまま、もう一度recipeを適用すると、作成対象のディレクトリは既に存在しているためにエラーになってしまいます。

なので、このexecuteに対してnot_if制約を追加することにより、エラーが発生しないようにしました。

これについては、一度作成したVMに対して複数回specを流す場合に発生する問題で、CI上では都度インスタンスを作成するために問題になりません。 また、mkdir-pを追加することでも回避できるでしょう。

mkdir -p でうまくいったりしないの #wakate2018w

— why/橘和板 (@whywaita) 2018年2月3日

解消できなかったsticky bit問題

とあるrecipeの実行で、net-scp gemが例外を吐いて落ちる、という問題が発生しました。

file '/tmp/file_edit_with_suid' do
  action :edit
  owner 'itamae2'
  group 'itamae2'
  mode '4755'
end

これについては、エラーの内容、backtraceが深いこと、recipeの実行そのものには成功していることなどから、深追いするのは諦めました。実力不足とも言えます。

なぜか以下のような変更をすることによって回避できるので、workaroundである旨をcommit message書いておきました。

 file '/tmp/file_edit_with_suid' do
-  action :edit
   owner 'itamae2'
   group 'itamae2'
   mode '4755'
end

Rakeが複数インストールされている

実はこれまでに挙げた問題というのは、specを実行する前段階であるrecipeの適用段階で発生していた問題でした。integration specでは、まずVMに対してitamae repiceを適用してから、そのrepcipeが正しく適用されているかの確認のためにserverspecを実行しています。

という訳で、やっとserverspecが落ちているところまで辿りつきました。次のようなspecです。

describe command('gem list') do
  its(:stdout) { should include('rake (11.1.0)') }
end

内容としては、rake gemのversion 11.1.0が入っていることを期待するもので、repcipeにも同様の記述が存在しています。

しかし、同様にrepcipeでのインストール指定を行なっているbundler 1.16では、rakeのversion 10系をdependencyとしています。 そのために、gem listの実行では複数versionのrakeがインストールされている事実が返ってくるので、文字列 'rake (11.1.0)' のmatchに失敗します。

これについては、文字列の末尾の閉じカッコを削除し、複数versionのrake gemがインストールされている状態でも通るようにしました。(あまり筋がいいとは思えませんが……)

test-unit gemが存在してしまう

test-unit gem、2回目の登場です。

以下のrepcipeにより、test-unit gemは削除されているはずなのですが、実際にはtest-unit gemは削除されておらず、specが落ちてしまいます。

gem_package 'test-unit' do
  version '3.2.0'
end

gem_package 'test-unit' do
  version '3.1.9'
end

gem_package 'test-unit' do
  action :uninstall
end

これは、ubuntuがxenialにアップグレードされたことに関係しています。 xenialでは、Ruby 2.3.1がaptからインストールされますが、Ruby 2.3.1では、test-unit gemをdefault gemとして扱っています。

そのために、test-unit gemをuninstallすることができず、specは落ちる、ということでした。

これについては、このspecを削除することで対応しました。

wercker.ymlの書き直し

さて、これでローカル環境でspecが通るようになったので、CIであるwerckerで実行できるようにしなければなりません。

しかし、Vagrantのインストール方法を変更したので、wercker.ymlの内容を変更する必要があります。

まずは愚直に、Ruby officialのdocker imageをboxに指定してみましたが、Vagrantの起動に失敗します。エラーの内容を見ると、modinfoが存在していない、というものでした。

しかし、色々調べてみたところ、docker container内でmodinfoをインストールすることはできないようです。

(数ヶ月前のことなのでどこを参照してその結論に至ったかは覚えてないのですが、今ruby:2.3.1のimageに対してapt install kmodを実行すると、インストールできるので、この認識が間違っている可能性は大いにあります。 しかし、modinfoの実行自体も、様々なmoduleに対して実行してもエラーが返ってくるので、やはり一筋縄ではいかないようです)

よくわからんなー状態になっていたのですが、そういえばsue445さんがitamae pluginをCIすることに一家言ある方だったことを思い出し、そのwercker.ymlを参考にすることにしました。

34歳になった&itamaeプラグインを本気でCIする #omotesandorb - くりにっき

そして紆余曲折あり、drecom-ruby imageを使用してVagrantのインストールと実行に成功するようになりました。

sue445さんのアドバイス in itamae.slack #random

Pull Requestの作成

これでなんとかようやくCIがpassするようになったので、pull requestを作成しました。

Fix failing integration spec (including workaround) by unasuke · Pull Request #253 · itamae-kitchen/itamae

#253

これに取り組み始めたのが12月の頭、PullReqの作成が1月の末であることから、まるまる2ヶ月の間、格闘していたことになります。実作業時間は恐らく1週間とちょっとくらいだと思いますが……

12月のESMさんでのOSSパッチ会でもくもくしていたのが遠い昔のように思えます(その時はmkdir問題に取り組んでいました)。

このPullReq自体も、wercker pipelineの編集が必要なためにCIは落ちているのですが、仕方ないですね。

情報科学若手の会冬の陣2018での発表

情報科学若手の会冬の陣2018 #wakate2018w - connpass

また、これに関して、情報科学若手の会冬の陣2018で発表してきました。以下が資料となります。

unasuke/wakate2018w_talk

Tweet
2018年02月04日
2018年02月01日

株式会社バンクで働きはじめました

bank

TLDR

from 株式会社spice life (2015-04-01 〜 2018-01-31) to 株式会社バンク (2018-02-01 〜)

Bank, Inc - 株式会社バンク

転職活動でお世話になった方々には本当に感謝しています。ありがとうございました。

退職直前にやったこと

退職直前に負債を出来る限り返済するの、気持ちよく退職できるのでおすすめです。

フラー株式会社を退職し、合同会社ヘマタイトに入社しました - Allajah’s Reservoir

誰?

うなすけです。

Tweet
2018年02月01日
2018年01月31日

Windows 10に開発環境を構築する in 2018年1月

Powershell on ConEmu

Windowsネイティブな開発環境があるとよさそうという気持ちになったので、構築してみることにした記録です。

前提条件

という条件のもと、Windows 10上にRubyおよびGolangの開発環境を構築しました。

PowerShell

なるべくネイティブ環境を目指すので、cmd.exeもしくはPowerShellを用いることになります。なので、PowerShellを使用しました。ただ、powershell.exeをそのまま使うのはちょっとつらいので、ターミナルエミュレーターからPowerShellを使用します。ConEmuやcmderなどがありますが、今回はConEmuを使うことにしました。

ConEmuの設定

ConEmuでは、colorschemeとしてSolarized Darkを、PowerShellの起動オプションとして-executionpolicy remotesignedを追加しました。

ConEmu PowerShell 起動オプション ConEmu PowerShell colorscheme

参考

Windows 10の開発環境を整えた - YAMAGUCHI::weblog

Chocolatey

LinuxでのaptやDNF、macOSでのhomebrewのようなパッケージマネージャーは開発には欠かせません。 Windowsで使用できるパッケージマネージャーといえばChocolateyなので、インストールしました。インストールにあたって、WMF経由ではなく、Chocolatey公式サイトの手順に従いました。

参考

とりあえずインストールしたパッケージ

Rubyのインストール

Rubyは、RubyInstallerを用いてインストールしました。場所はデフォルトのC直下にしています。

RubyInstaller for Windows

uru

Rubyのバージョンを切り替えて使いたいとなっても、rbenvやrvmはPowerShellでは動作しません。なので、uruを使用してRubyのバージョンを切り替えることにします。

インストール

  1. jonforums / uru / wiki / Downloads — Bitbucket よりnupkgをダウンロードする
  2. PowerShellでnupkgをダウンロードしたディレクトリに移動する
  3. choco install uru.0.8.4.nupkg を実行する

インストールが終了したあとは、uru admin add C:\Ruby25-x64\bin --tag 2.5.0 などでuruにRubyを追加し、 .ruby-version のあるディレクトリで uru auto を実行するとRubyのversionが切り替わります。

参考

Golang

Golangも、Rubyと同様にインストーラ(msi)を用いてインストールしました。

Downloads - The Go Programming Language

環境変数

また、環境変数として、以下の値を登録しました。

参考

Docker for Windowsのインストール

公式のインストーラを使用することで、PowerShellからdockerを使用することができるようになりました。

Docker Community Edition for Windows - Docker Store

Windows Subsystem for Linuxのインストール

ChocolateyやDockerの環境を構築しても、どうしてもLinux環境がないとどうにもならないことがあるので、WSLのインストールも行ないます。

ちなみに、このブログを書くためのmiddlemanはWSL環境でしか動作しませんでした。

これに関しては、必要になったタイミングで使うという方針なので、あまり環境構築に手間をかけないことにしました。

参考

参考サイト一覧

当初はMSYS2でいくつもりだった

最初はMSYS2でやっていくつもりだったのですが、Docker for Windowsを入れたタイミングでdockerコマンドがMSYS2で入れたzshから使用できなかった(PATHが通ってなかっただけ?)のでエイヤでPowerShellに切り替えました。

MSYS2の環境構築で参考にしたサイト一覧

Tweet
2018年01月31日
2018年01月19日

Nikon D3300の入手と撮影画像の管理について

nikon D3300

始めての一眼レフ

my new gear…… (thank you @Do_Su_0805 !) pic.twitter.com/bvmlkGC22j

— うなすけ (@yu_suke1994) 2017年12月26日

お金に余裕ができたら一眼レフが欲しいと思っていたところに、 @Do_Su_0805 が一眼レフを安価で譲ってくれるとのことで、待ってましたとばかりにお願いしました。

最近はちょっとしたイベントの度に持って行き、パシャパシャするのがとても楽しいです。

おいしかったやつ1

撮影した写真の管理について

RAW現像のすゝめ 2018 - 良いあそなすちゃん

(このエントリに触発されて書いているというのもあります)

撮影時のフォーマット

RAW+JPEGで撮影しています。SDカードが64GBなので、最高画質で大体1300枚ほど撮影できます。

撮影画像の取り込み

一眼レフを手に入れて、勢いでやっていきになってAdobe Creative Cloudフォトプランを購入しました。取り込みについてはLightroom(Classic)に全部任せています。(撮影日付ごとにフォルダが切られ、その中にオリジナルのファイル名で保存される。ClassicでないとRAW+JPEGでの管理ができなかった)

イベントごとに日付を先頭に含むコレクションを作成して、そこに全部を突っ込んでいます。

現像

まずはコレクションの写真をざっと見て、現像しないものに「除外」フラグをつけていきます。

採用する写真に対しては、とりあえず思考停止「自動補正」をして、その上で明るすぎるのを暗くしたり、ノイズ除去などをやっています。その辺をアレコレする知識が無いのと、Adobeへの信頼です。

共有

現像まで終わった写真は、Google Photoにアルバムを作成してアップロードしています。そこから、イベントに応じた共有をしています。Google Photoのアルバムの共有リンクを発行することもあれば、Dropboxにも保存して共有リンクを発行したりもします。

これからどうなっていくか

まだ自分のユースケースだと、その場で現像とかは不要かなーという感じなのでFlashAirを買うことはないなと思いますが、時間次第な気もします。

それよりも、屋内の暗い場面での撮影でノイズが結構気になるので、撮影技術の向上や、F値の低いレンズの購入のほうが先になるのかなと思います(今はキットレンズ)

強い意思で沼に深く嵌らないようにしたいです。

おいしかったやつ2

Tweet
2018年01月19日
2017年12月25日

ハコクラでDJをしてきました

ハコクラ stage pass

高専DJ部 Advent Calendar 2017

高専DJ部 Advent Calendar 2017 - Adventar

25日目です。

セトリ

  1. すてきなホリデイ - 竹内まりや
  2. ベィスドロップ・フリークス - かめりあ Feat. ななひら
  3. in the Sky - Ryu☆
  4. Ragga Bomb - Skrillex
  5. Fury - Feint
  6. Go Berzerk (Gammer Remix) - Pegboard Nerds & Quiet Disorder
  7. Honey Trap - ななひら
  8. Like A Bitch (Extended Mix) - Zomboy
  9. Alien Cookies - Dirty Audio
  10. Scary Monsters & Nice Sprites - Skrillex
  11. ショコラ・ティアラ - 三村かな子 (大坪由佳)
  12. さよならトリップ - Dormir
  13. Rave After Rave (Original Mix) - W&W
  14. Sushi Of God (Original Mix) - Nom De Strip, Nezzo
  15. Sexy Beast - Stereotronique
  16. クリスマスキャロルの頃には - 稲垣潤一

高専DJ部以外では初のDJでした。出演させていただきありがとうございました。とても楽しかったです。

Skrillexでもベタベタなのを流すチャラすけ #ハコクラ pic.twitter.com/1VhfcW0tC2

— DJ Futoshi@12/24ハコクラ (@dj_futoshi) 2017年12月24日

チャラい?知らない概念ですね……

Tweet
2017年12月25日
2017年12月17日

高専DJ部 #16 でした

kosendj-bu #16 みかん

Advent Calendars

17日目です。

セトリ

  1. Saving Light (feat. HALIENE) - Gareth Emery & Standerwick
  2. Shelter - Porter Robinson & Madeon
  3. Bass Drop - Zero Hero
  4. Go Berzerk (Gammer Remix) - Pegboard Nerds & Quiet Disorder
  5. Outbreak (feat. MYLK) - Feint
  6. Superhuman (Gammer Remix) [feat. Eric Leva] - Slander
  7. Burn (Original Mix) - DallasK, KSHMR
  8. Insanity (Extended Mix) - Alan Crown, Alicia Madison, Rooverb
  9. Kill EVERYBODY - Skrillex
  10. Sexy Beast - Stereotronique
  11. Stickup (feat. Juliette Lewis) - Karma Fields & MORTEN
  12. Saving Light (INTERCOM Remix) [feat. HALIENE] - Gareth Emery & Standerwick

まあ脱チャラと言えるのではないでしょうか。

チャラい #kosendj pic.twitter.com/5DFoaXuxAh

— あそなす (@asonas) 2017年12月16日

ついでに #15

前回のDJ部、#15の再現Mixも録っておいたので貼っておきます。

高専DJ部 #15 でした | うなすけとあれこれ

Tweet
2017年12月17日
2017年12月14日

kosen10sにpaymoを導入して

paymo アプリ画面

kosen10s Advent Calendar 2017

#kosen10s Advent Calendar 2017 - Adventar

13日目です。

始まりは秋吉会

8月22日の秋吉会、直前に旅行をしてきたこともあり、僕は現金が枯渇していました。 具体的には、秋吉会での割り勘で確実に足りる、という額は財布に無く、かといって数万円を口座から引き落とすとカードの請求額が払えなくなる、というカツカツっぷりでした。

このような状況だと、一旦僕がカードで払って、他のみんなには人数頭で割った金額を渡してもらう、という割り勘手法になるかと思います。

割り勘面倒問題

でも、そもそも割り勘って面倒ではないですか?人数で割り切れない金額になることもありますし、割り切れたとして、金額をその額面丁度で支払えることなんて稀です。 ざっくり千円単位に丸めて、貸し借りの概念が発生するのもどうかなーと思います。これは気分の問題ですが。

割り勘アプリ

さてその時、ちょうど割り勘アプリがいくつか出てきていました。その時検討対象だったのは、PaymoとKyashでした。

Paymoはレシートの撮影が必要という手間は必要ですが、そのおかげで収納代行業者として機能するので、割り勘した金額をあとから銀行に振り込むことができます。

参考 ユーザー体験から紐解く「個人間送金」アプリの仕組みと歴史(日本編) | hajipion.com

なので、Paymoを使うことにしました。

秋吉会以降

秋吉会で、さく、どくぴー、でなり、puhitakuにPaymoを使ってもらいました。その時の体験が良かったので、以降のkosen10sのイベントで割り勘が必要になったときも、Paymoが使われるようになりました。

僕が記憶しているうちで、Paymoによる割り勘が行われたkosen10sのイベントは以下の3つです。

まとめ

現金レス割り勘、超便利です。

訂正

2017-12-17 kosen10s Advent Calendar 2017 へのリンクを追加

Tweet
2017年12月14日
2017年12月10日

高専DJ部 #14 とtumblr酒場in東京 #3 の再現Mixをアップロードしました

tumblr sakaba #3 看板

高専DJ部 Advent Calendar 9日目

高専DJ部 Advent Calendar 2017 - Adventar

そういうことなので、録り直しました。左右に別れているささやきの音声とかがちゃんとなってると思います。

いや〜長いMixだった。

Tweet
2017年12月10日
2017年11月28日

福岡Ruby会議02 前夜祭でLTをしてきました

やればできる

前夜祭

もともとCFPとして応募していたのですが落選してしまい、どうしようとなっていたところ、pixivさん主催で前夜祭が開催されることになり、その中でLT大会が催されるということなので早速応募しました。

発表資料

https://github.com/unasuke/fukuoka_ruby_kaigi_02_lt

最初は5分枠で応募していたのですが、10分枠で話してみて「5分とか無理だな」ってなりました。

Tweet
2017年11月28日
2017年10月22日

ISUCON 7 やまのほすけ 提出スコア 11,204

落ち着くこと

メンバー

やったこと(順不同)

僕らが高速化したのはRuby実装です。

MySQLのチューニング by のほ

まずはslow query logの有効化、それからinnodb_buffer_pool_sizeを1Gにしました。

deploy scriptの作成 by うなすけ

今回はサーバーが複数台あるので、手元で叩いて各サーバーにssh経由でgit pullsudo systemctl restartをさせようと思ったのですがなかなかうまくいかず、結局サーバーにsshした上で実行するscriptになってしまいました。

このscriptはちょこちょこ書き替えが発生していました。

user.nameにindexを張る by うなすけ

CREATE TABLE user (
  id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
  name VARCHAR(191) UNIQUE,
  salt VARCHAR(20),
  password VARCHAR(40),
  display_name TEXT,
  avatar_icon TEXT,
  created_at DATETIME NOT NULL,
  INDEX(name)
) Engine=InnoDB DEFAULT CHARSET=utf8mb4;

ただ、このQueryを実際に流すのを忘れていて、終了10分前とかに気づいてIndexを張ったというポカミスがあります。

RACK_ENVをdeploymentに by うなすけ

定石というか、なんというか。あわせてAPP_ENV(Sinatra)もproductionにしています。

静的ファイルをnginxから返すように by やまま

これも定石。しかし、nginxから返すようにしてから数十件の静的ファイルへのリクエストがタイムアウトするようになってしまいました。はじめはnginxが詰まったのだろうか……と考えていましたが、その後Discordでeth0で頻繁にネットワーク遅延が発生していると報告がなされました。もしやと思って僕からnginxへのリクエストがタイムアウトする旨を使えたところ、報告された方も同様の症状だったそうで、「これはインスタンスガチャか……?」となりました。

しかし競技終了後、Cache-control publiclast-modifiedEtagの値などは考慮していないことに気付き、やはり自分達に原因があったのでは……となりました。(このへん詳細ちょっと不明です)

/loginと/registerへのGETを静的に返す by うなすけ

これは最初、アプリのコードを読むと静的やんけ〜〜となったので雑にpublic以下にhtmlを生成して置いたところ、ステータスコードでひっかかってダメでした。nginxで返すときにステータスコードも強制的に302に書き替えたりもしてみましたが、Locationヘッダーも必要でアーそうですねとなって一旦撤退しました。

しかしその後、「一度File.openとかで変数に格納して、それを返すようにすればいいのでは?」と気付きを得てそのようにしたところ、有意なスコアの上昇が見られてよかったです。もっと早く気付くべきですね。

N+1となるクエリをjoinで解消 by うなすけ

/message/history/:channel_idへのGETは、その内部で実行しているSQLにN+1問題があることがわかります。なので、これをjoinして解決することにしました。

 statement = db.prepare(
   'SELECT message.id, message.created_at, message.content, message.user_id, user.name as user_name, user.display_name as display_name, user.avatar_icon as avatar_icon FROM message INNER JOIN user ON user.id = message.user_id WHERE message.channel_id = ? ORDER BY message.id DESC LIMIT ? OFFSET ?'
 )
 rows = statement.execute(@channel_id, n, (@page - 1) * n).to_a
 statement.close
 @messages = []
 rows.each do |row|
   r = {}
   r['id'] = row['id']
   statement = db.prepare('SELECT name, display_name, avatar_icon FROM user WHERE id = ?')
   r['user'] = statement.execute(row['user_id']).first
   r['user'] = { display_name: row['display_name'], avatar_icon: row['avatar_icon'], name: row['user_name'] }
   r['date'] = row['created_at'].strftime("%Y/%m/%d %H:%M:%S")
   r['content'] = row['content']
   @messages << r
 end

hashにぶち込んでレスポンスを返すところ、特にuserの情報の部分では、/history/:channel_idではerbから参照しているのでhashのkeyがSymbolになっているとベンチマークでエラーが出るのにはちょっとハマりました。

あと競技終了後のDiscordで、statement.closeの漏れがけっこうあることを指摘されていて、この辺の知識がなくstatement.closeの有無がどう影響してくるのか不明で放置してしまっていました。

/fetchでのsleepを5秒にした(けどやめた) by うなすけ

レギュレーションには/fetchへのアクセスは採点対象ではないことが書いてあり、/fetchへのアクセス回数を減らせられればその分リクエストの処理が可能なのではないかと思い5秒までのばしてみましたが、ベンチで有意なスコア上昇が見られなかったことと、pumaのスレッド使い尽したらリクエスト受けられないのでは?と思いrevertしました。短くしようかとも思いましたが時間が足りず挑戦していません。

Varnishを用いたリクエストの分散 by やまま

もともとサーバーそのものは3台提供されていましたが、リクエストはapp1台とdb1台で処理していました。

これをVarnishにより、まずリクエストはapp1で受け、/profileへのPOSTと静的ファイルへのリクエストはapp2のnginx + pumaで、それ以外はapp1のpumaで受け、裏のdb1にデータを取りに行くという構成にしました。

多分今回のなかで一番大仕事かつ成果のあった作業だと思います。(これでベストスコアが出た)

よくわからなかったところ

pumaが重くなっていく

長時間サーバーを起動しっぱなしにしていると、/initializeが規定時間内に終わらなくなってしまいました。これは、isubata.ruby.serviceの再起動で解消されるので、ベンチマーク実行前にserviceの再起動をかけるようにして凌いでました。

感想

去年の提出スコアが0だったことを考えると、スコアが11204というのはもう去年の何倍というスケールには収まらない成長っぷり(?)でめちゃくちゃ嬉しいです。が、もっとやれることあっただろ、というところでもあります。

あと予習とか訓練が足りなかったかなーと思います。(2週間前にisucon4の予選問題でリハーサルをしただけ)

行動ログ

分単位で記入していますが曖昧です。

時刻 行動
9:05 うなすけ 会場準備
11:41 うなすけ ラブライブ サンシャイン 1期完走
13:00 競技開始、みんなで予選当日マニュアルのgistを読む
13:10 うなすけ Ruby実装を使うようsystemctlで設定、初期実装でのスコアを見るため先頭2台をenqueue (6173)
13:19 うなすけ アプリのコードをローカルにscp
13:24 うなすけ private git repositoryを用意
13:30 以降 うなすけ → deploy script、のほ → MySQL、やまま → アプリ理解 に分担
14:32 のほ slowquerylog など有効化
14:34 うなすけ deploy scriptの大枠が完成
15:00 ごろ やまま インスタンス内からbundler消失疑惑がありあたふた
15:26 やまま systemdの設定とnginxの設定をrepository管理下に
15:37 うなすけ RACK_ENVをdeploymentに
15:43 のほ innodbbufferpool_sizeを1GBに
15:45 うなすけ user.nameにINDEXを張る(コード上のみで実際には張らず)
15:48:40 スコア 6227を記録
16:03 うなすけ SQLのJoin化に着手
16:07:40 スコア 6403を記録
17:00 ごろ やまま 静的ファイルをnginxから配信するように悪戦苦闘中
17:23 うなすけ SQLをJoinするように
17:44:30 スコア 5698を記録
17:45 やまま pumaとnginxの間をunix domain socketで繋ぐ
17:46:46 スコア 8540を記録
18:08 うなすけ /login と /registerのGETをnginxから返すようにする
18:48 うなすけ /login と /registerのGETをnginxから返すようにするのをやめる
18:54:47 スコア 10852を記録
18:56:27 スコア 8248を記録
18:57 やまま Varnishの導入に着手
18:59:24 スコア 3016を記録
19:04:44 /initializeがTimeoutし始める
19:17 うなすけ /fetchで5秒sleepするようにしてみる
19:27:48 スコア 5678を記録
19:39 やまま Varnishを使ったrequestの分散に着手
19:51:22 スコア 4032を記録
19:57 うなすけ /fetchで5秒sleepするコードをrevert
20:00 やまま Varnishを使ったrequestの分散を完了
20:00ごろ みんなで他になにかできるか確認
20:31 うなすけ /loginと/registerを変数から返すようにする
20:31:26 スコア 11246を記録
20:35ごろ あまり覚えてないけど再起動試験とかしてたはず
20:40 user.nameにINDEXが張られる
20:42:42 スコア 12033を記録(ベストスコア)
20:51:28 スコア 11204を記録(提出スコア)

追記

2017-10-23 0:14

誤字の修正とメンバー紹介を追加しました。 (ykztsさんありがとうございます 🙏 )

Tweet
2017年10月22日
新しい投稿
古い投稿