テーブル 天板と脚

天板

こうやって穴を開けて f:id:tompng:20171121001156j:plain f:id:tompng:20171121140032j:plain ダボで繋いだら天板完成 写真は、反らないように、隙間があかないように固定してボンド乾燥中 f:id:tompng:20171126205123j:plain

脚の部品

f:id:tompng:20171113031231j:plain f:id:tompng:20171121141037j:plain 右用と左用 片方はかなりうまくいったけどもう片方は隙間があいてしまった

脚の組み立て

ドリルで穴を開けて f:id:tompng:20171130230750j:plain 3本の棒で繋げるように。とりあえず仮組み f:id:tompng:20171130234451j:plain 1本だけ、木材がもともとすごく捻れているせいで穴が合わなかった 仕方がないから穴の大きさを広げて、ぐらつき強度に影響なさそうな真ん中に使う予定

残りの工程

  • 脚の角を削る
  • 脚をボンドでくっつけて組み立てる
  • 天板の継ぎ目の段差と角を削る
  • ヤスリがけ
  • 塗装
  • 天板と脚の固定(乗せるだけでもいいかなぁ)

テーブル作る

テーブル設計

https://tompng.github.io/ghtable/

木材購入&カット

ホームセンターで購入&カットしてもらう
あの高さ3mくらいあるカッティングマシーン欲しい(パネルソーって言うらしい)
幅広い板が天板になる予定
f:id:tompng:20171109020119j:plain

穴あけ

とりあえず穴あける位置に印をつけた。ボール盤で穴あけてく
写真に写ってる透明なプラは印つける道具
f:id:tompng:20171109020259j:plain 穴あけ進捗: 24/200

sinatraのredirectとrailsのredirect_to

railsと違って、sinatraだとredirectメソッドを呼ぶとそれ以降が実行されない (って話をちらっとtwitterで見かけた)

get '/' do
  puts 'get sinatra index'
  redirect '/aaa'
  puts 'got index' # 呼ばれない
end

def index
  puts 'get rails index'
  redirect_to '/aaa'
  puts 'got index' # 呼ばれる
  render plain: 'hello' # エラー出る
end

どうやってるのかなと思ったらthrowしてた

def redirect(uri, *args)
  ...
  halt(*args)
end

def halt(*response)
  ...
  throw :halt, response
end

def invoke
  res = catch(:halt) { yield }
  ...
end

そんな感じの書き方いくつか

# raise-rescue
def hoge1
  puts '呼ばれる'
  stop1
  puts '呼ばれない'
end

def stop1
  raise :stop1
end

hoge1 rescue nil
# throw-catch sinatraはこれ
def hoge2
  puts '呼ばれる'
  stop2
  puts '呼ばれない'
end

def stop2; throw :stop2; end

catch(:stop2) { hoge2 }
# return
def hoge3
  puts '呼ばれる'
  stop3
  puts '呼ばれない'
end

def stop3; @return_from_lamba.call; end

lambda do
  @return_from_lamba = proc { return }
  hoge3
end.call
# Fiber.yield
def hoge4
  puts '呼ばれる'
  stop4
  puts '呼ばれない'
end

def stop4; Fiber.yield; end

Fiber.new { hoge4 }.resume

他にあるかな

isucon7予選参加して惨敗しました

isucon7予選参加して惨敗しました

10/21(土)のisucon7予選にチームokinawa.rb(@saboyutaka, @_simanman, @tompng)で参加して惨敗しました。

nginxがなぜかタイムアウトしたり(帯域制限に引っかかってた)
mysql接続が切れて500頻発したり(statement.close忘れ)
最後までその原因を特定できずにズルズルと時間が過ぎて絶望のまま終わってしまいました。

最終的には再起動試験にもfailしてて完全敗北です。

一応気合い入れて準備してきたしapp側は結構がっつりチューニングできたつもりだからダメだったなりに何やったかまとめとこうと思って...
突破エントリ書きたかった...

コードはこちら https://github.com/siman-man/isucon7-qualify/blob/master/ruby/ (感想戦として終了後もいくつかcommitしてます)

構成(途中でappを減らしたり増やしたり)

  • 1台目: nginx app
  • 2台目: nginx app
  • 3台目: nginx app db

オンメモリキャッシュする時のためにappサーバ同士をTCPSocketで直結(するために事前準備でgem作ったり)
(redis使うくらいなら直接他のappサーバにデータ渡せばいいじゃん、って発想)

やったこと一覧(だいたい時系列)

15:00~16:40 画像のファイル書き出し

  • 画像をDBに入れてたので初期データをファイルに書き出し(git add)
  • プロフィール変更で追加される画像は即座に3台にコピー(app2に/icons/aaa.jpgが追加されたよ通知を他のappサーバにbroadcastして)

この変更を本番に入れるもなぜかスコア変わらず(原因は参照実装pythonのままベンチ走らせてたから?)
そのあとでバグ取りとかして2万点くらいになって、画像は解決したつもりになっていた。
last_modified合わせるとか必要だったらしいけどそんなこと知らない。

15:00~15:15くらいにだいたいのコードは書いたけど最終的にバグ潰せたのが16:40くらいで、時間かけすぎた

15:45 /fetchのlong polling化

新着メッセージが来たら即座に返すようにしてみたけどあんまり効果なかったので保留

18:40 オンメモリキャッシュして/fetchのN+1を消す

  • channel
  • channelごとのmessage_idの配列(Array#bsearch_indexを使っての既読数計算に利用)
  • channel_id, user_id毎の既読メッセージ数(メッセージ数から引けば未読数になる)

を全部メモリに載せた。
これで/fetchは3クエリだけで返せるように(新しいchannel, message, 更新されたhavereadをそれぞれ読み込むSQL)
あとは /fetch が速くなったからsleep時間を色々と調整してみたり

19:00 /message /history のN+1を消すために、userをオンメモリに

オンメモリにしたあとでuserのupdate対策できてないことに気づいたけど、他の問題がでかくて直すどころじゃなかった
(オンメモリやめてjoinに直すか、updateされたら全appサーバに通知するべき 10行くらいの追加で直るからやっておけばよかった)

19:00〜 先延ばしにしてたnginxとmysql試行錯誤

途中から悩まされてたnginxのタイムアウト(画像の帯域制限)とmysqlの接続切れの対処をそろそろやらなきゃと、この頃から意味のない変更加えて試行錯誤してた。
def dbをThread.current使うように書き換えたせいかなと元のダメそうな実装に戻したりetc
再起動チェックは終了2時間前くらいにやる予定だったけど、nginxとmysqlの問題解決を優先してスキップ
終了1時間前くらいからはひたすら絶望してて、結局最後までどうにもならず、(post /loginですら出る)500エラーとタイムアウトエラーまみれ
スコアは2万台~4万台の間を上下するだけのまま終了(再起動試験fail 参考値34,580)

nginx知らない... CDN知らない... 速度勝負の土俵に上がりたかった...

まとめ

isuconは冷静になれる心の余裕が必要だなって思った。nginxとかCDNあたりは知らなかったとして、mysqlはなんでclose忘れ疑わなかったんだろう
最初のうちは楽しかったけど途中からは絶望で苦しかった。 終わった後もしばらくもやもやしてたけど、練習段階からやりたかったほぼ全部オンメモリキャッシュも後日書いてみたし、最後にこの記事で僕のisucon7は一区切りついたかなー
それでスコアどこまで行くのか、ちょっと気になるけど、検証も大変だし、終わり。