今乗っている路線をなめらかに表示させる

作ったもの

Near Station

ソース

GitHub - Goryudyuma/location2

動機

前に同じようなの作ってて、でも満足はしてなくて、その後某駅○モにも前作と似たような実装で表示されるようなやつができたとの話を聞いたので、じゃあ僕はもっとなめらかなすごいやつ作ってやるぞ!ってなって今作を作った。(たぶんn番煎じ)

使った技術

ubuntu+さくらVPS+NGINX+PHP7+MySQL5.7+React.js+bootstrap

ubuntu

雑魚なのでまともに触れるのubuntuだけ・・・

さくらVPS

前に使ってたVPSより性能高くて反応もよくて非常に満足。ただし高い。

NGINX

配信用。Let's Encryptも使ってHTTPSとHTTP2の対応。ついでにIPv6も対応させた。

letsencrypt.org

qiita.com

PHP7

APIスクリプト。適当に書くだけで動くから好き。PHP5でもたぶん動くけどPHP7にしたのは趣味。

MySQL5.7

位置情報とか駅情報などを入れてるDB。MySQL5.6から導入されたgeolocation型や、MySQL5.7から導入されたJSON関数などを使用している。

React.js

JSの先生に勧められるがまま勉強したフレームワーク。時々詰まることもあったけど、日本語資料が多く調べやすかった(たまに英語資料だがわかりやすい)。画面更新処理などがとても書きやすい(、けどJSのフレームワークこれくらいしかしらないので、もっと書きやすいやつは探せばあるのかも?)。日本語チュートリアルや、koba04氏の一人React.js Advent Calendarがとても参考になった。

qiita.com

bootstrap

Viewを整えるやつ。React-Bootstrapを使った。

React-Bootstrap

データ

国土交通省国土政策局国土情報課国土数値情報ダウンロードサービスの国土数値情報鉄道時系列データから取ってきた。国交省(と気象庁)は手軽にデータ数が増えないそこそこ多めのデータが手に入り、データベースの勉強に最適だと思う。(Twitterなどはリアルタイムにデータが変わるので、初学者にはつらい可能性?)

国土数値情報 鉄道時系列データの詳細

今後

気が向いたらPHPAPIを書き直すかもしれません。(現状の実装がとても汚いことは自覚している・・・)

あと、もっと機能付け加えた方がいいのかな。シンプルイズベストで、今の感じが結構気に入ってるけど、やる気が起きてアイデア浮かべば実装するかも。

感想

ひとりISUCON、つらいけど楽しかったです() ISUCON6も決勝頑張っていきたいと思います!

謝辞

協力してくれたものづくりサークルkstmのメンバー達、様々な情報を提供している先人達、データを公開している国交省の人達、その他何かしらで関わってる人達、感謝です!

供養

この作品は前作の全面改修でもあります。もう使われることは無いと思うので、ここに残しときます。

前作ったやつ

位置情報から路線を取得するテスト。

それのソース

GitHub - Goryudyuma/location

ひどさ

JSがわからなくて、PHPでJSのコード生成してたりする。と聞くだけで想像する方法とはたぶん違う方の生成。どうしても詳細が知りたかったらソースみて。うんコードが大量にある。見ない方が幸せ。

動機

電車に乗っているときに、今乗っている路線の情報とか取得できたらおもしろそうって思った。ただしこの前作では、新幹線など駅間が長いところに乗っていると、横の在来線に乗っている判定がされることが多々ある。(今どの路線に乗っているかの判定が再近隣駅から判定しているため。)

さらば

まともに書いた初めてのwebアプリよ、さらば。

ISUCON参戦記

うまです。

ISUCON参戦したので、参戦記を書きます。

チーム名はkstmで、学生枠での参加です。インフラ周りのふぉのと、司令塔のあーちゃん、お荷物枠の僕の三人で参加しました。全員ものづくりサークルkstmのメンバーです。チームの団結力は高いほうかと思いますが、共通言語がないのが問題点です。

 

まずは予選から。

githubに一応ログを残しています。

github.com

様々な事情から、予選の練習を開始したのが前日の夕方頃からで、練習不足感甚だしいしかも寝不足の状態での予選でした。少し触ってみて決めたことは、ISUCONで使える言語の内、ふぉのはPerlRubyがある程度読めますが、インフラ周りを見ることに徹するのでその2つはボツ、あーちゃんはJavascript大好きなのでNode.JSが使え、PHPもかけます。僕はPHPGolangがスコシヨメルですが、たいして書けません。しかしPHPはバリバリにフレームワークが使ってあり、その知識もないと見るのは厳しそうだと判断し、優先度を下げました。よって担当割当はnginxなどをふぉの、サーバープログラムをNode.JSであーちゃん、SQLを僕が担当することを事前に決めました。

少し仮眠を取り、サークル部屋に集合。本番開始直前に開始の一時間の遅れとNode.JSの実装がないこと、さらにPHPがエラーでうまくいかない可能性があること、付け加えてGolangも点数が出ない事が判明、大慌てで言語の変更を迫られました。とりあえず過去問を見たところ、GolangならSQLクエリも読みやすく使えそうだとの判断で、僕はSQLを読むのをGolang実装で読むことにし、サーバープログラムはとりあえずGolangでやってみて無理そうならその時考える方針で開始しました。

とりあえずインスタンス起動して初enqueue、たいして性能でずGolangに変更してenqueue、0点を記録してからの滑り出しでした。僕とあーちゃんはちょっと長めのコードだったのでひたすらコメントを付けて回りました。その間にふぉのさんが改善してくれて600点ちょいを出せるようになりました。このあとはひたすらこの時に書いたコメントに従ってコードの改善をしていくことになります。なにしてるかよくわからなければコメント書いとけばなんとかなる・・・こともある・・・。僕は頭があまり回っておらず、構造把握は殆どできてない状態でしたが、あーちゃんに言われるがままやっていました。まともに改善したのはN+1問題のクエリ一つだけと、SQL担当とはとても思えない結果でした(お荷物枠の力発動!)。それからGolangを一年ほど前に少し書いただけというあーちゃんにGolangの仕様を聞かれたら答え、わからなければggって答えと、そんなことをずっとしていました。apt-get upgradeの罠をたまたま回避できたり(誰かしてるだろと思って僕はしなかった)、謎のタマキさんには出会わなかったり、最後どうしても時間内に改善できなかったLIMIT 1000を100に変えたりキャッシュつけたりいろいろした(主に僕以外のメンバーの頑張りの)結果5000点以上上がったり、再起動後のジャッジの点数ではなく最終ジャッジの点数が取られたことなど(再起動試験は行っていたが、不安要素満載だった。failしてても文句言えない・・・)と、大変運にも恵まれていました。最終スコアは7898と学生枠3位での通過となりました。この本戦通過の通知は、サークルバーベキュー大会が終わって直後のサプライズになったことを記しときます。

 

そして、昨日の本戦。もちろん練習時間は験を担いで(?)ほぼ一日、これまた練習不足での本戦でした(反省しろよ!!)。朝の長野駅集合で新幹線で東京は渋谷ヒカリエまで。北陸新幹線かがやきはとても速くて快適ですね!堪能して山手線で渋谷まで。開場40分前に集合場所についてリラックスしていました。開場し、かっこいい参加者を示すカードが貰えてLINEオフィスまで。カードにはtwitterアイコンをそのまま提出したのですが、もっとまともなアイコンを使えばよかったと少し反省。会場に到着して、最初は景色のいい窓際のソファ席をチョイスしたのですが、机が低く狭く、あまりやりやすい環境ではなさそうだったので机席に移動。長机も1つ借りてとても良い環境でコードを読むことができました。周りに強い人がたくさんいる中での緊張感を味わえてよかったです。

さて、本戦ですが、結果から言うとfailの0点でした。いくら時間がなくとも慌てていようとも天地がひっくり返ろうとも、再起動試験だけは絶対にするべきことだということをまず書いておきます。ただ、半数以上のチームがfailで落ちていました。もう一度書きます。再起動試験は絶対にやるべきです。

内容はAPIをいかに効率的に叩くか(まとめすぎ?詳細はggってください)というやつでした。予選と同じ体制で、Golangを選びました。とりあえずubuntu14.04の3コアCPU4GBメモリ*3という構成だったので、ubuntu14.04のapt-getで標準で入るGolang1.3(←今は違うかも?)でapp.goがコンパイルされている可能性があったので、Golang1.5に上げてくださいと提案。インフラ周りの改善とGolang1.5によるコンパイルで10000点を少し超える点数を出し上位陣の仲間入り。司令塔のあーちゃんから「dataが明らかに遅いです」ともらったので、そのあたりを読みました。何が遅いかすぐには気づけなかったのですが、よくよく読んでみると何回もAPIを叩いていることが判明。ここでの改善案として、1,Golangお得意の並列化をする、2,redisにクエリ結果をキャッシュするの二点を考えました。並列化を実装してみたのですが、なぜかエラーで落ちる。クエリ結果をキャッシュする方も、キャッシュしていいやつとしてはダメな奴があり、途中で気付いて分けていたりしたのですがなぜかfail連発でダメ。ブラウザから見ると正常に動いているように見えるのですけどね。そこそこのコードを書いたり消したりしましたが、結局コードとしては余り貢献できませんでした。並列化もしていいやつとダメな奴、クエリ結果のキャッシュもやっていいやつとダメな奴があったっぽいです。もっとちゃんとAPIの仕様を調べておけば回避できたかもしれませんが、考察できたかどうかは未知数です。並列化してはいけない奴、キャッシュしてはいけない奴に気づけなかったので、どこかコードが間違っているんだろうといろいろ書きなおしたりしてたのですが、点数はfailになるか下がるかのどちらかで、大した改善はできませんでした。もっと自分の書いたコードに自信を持つことはもちろんのこと、APIは並列で一斉に叩けばよいわけではないことを学びました。

本戦終わっての結果発表、今年は学生賞は該当なしでした。学生枠全チーム再起動試験で落ちたっぽいです。過去の自分に伝えることができるなら、「本戦始まったら一切PCに触れるな。そしたら学生賞は取れるぞ」と教えてあげたい・・・。一位のfuziwara組には脱帽です。どうやったらあんなにすごい改善が実装できるのか。すごすぎです。

 

ISUCON参戦記は以上です。お荷物枠になってしまいましたが、来年はちゃんと活躍して本戦に行けるように、一年間精進します。

@Goryudyuma