2017年に趣味とかでやったこと
RCC OBOG Advent Calendar 2017 - Adventar の7日目の記事です.昨日はgol19さんの趣味のこととか作ったものとかです。
2017年に大学を卒業して社会人になったabcangです。ぱちお世代です。 書くネタがないなーと思いつつ登録して、結局書くネタが思いつかなかったので、
とあるように近況を書く、とと言うより今年を雑に振り返ってみよう思います。
アニメ
大学のときから継続してアニメを見ています。だいたい趣味の時間の大半はアニメに使っていると思います。(たぶん) 昔は見たアニメをGoogleスプレッドシートに記録していましたが、去年ぐらいからAnnictに移行して、それからはAnnict上で記録しています。
見返してみると、去年放送のアニメは15〜20ぐらい見てたのに対して、今年放送のアニメは10前後とあまり見てないですね。世の中には放送されているアニメをほぼ全部見ている人もいるらしいのでにわかですね。
去年までは単純に見た作品と見たい作品を記録していただけですが、今年の冬頃に大規模なアップデートがあってGitHubの芝のような機能が実装されたので、 2017の春からは話数ごとに記録して芝を生やすようにしてみました。
Twitter連携をしているので見たアニメはどんどん流れていると思います。特定のアプリからのツイートをMastodonにも流すツールを作ったので、それを使ってAnnictの記録をPawooにも流しています。フォローワーさんがアニメの視聴記録を見て、「このアニメのタイトルをよく目にするけど面白いのだろうか」と興味を持つきっかけになってくれればと思って共有しています。邪魔だったらごめんね。
Annictは個人で開発・運用しているということなので応援していきたいです。
作ったもの
今年作ったプログラムとかを紹介したいと思います。
特定のアプリからのツイートをMastodonにも流すツール
上で紹介したツールです。自分のサーバなどで常時起動しておく必要がありますが、ターゲットのアプリを複数指定できるので便利です。
今はAnnictとはてなブックマークとSwarmをPawooにも流すようにしています。需要があるならWebサービスにするのもいいのかもしれません。
ただ、ユーザーの数だけストリーミングAPIを実行したくないですし、かと言ってポーリングにすると投稿されるまでに時間がかかったりして使いづらくなりそうでうーんと悩んでたりします。とりあえず自分も使いたいと思った人は声をかけてください。考えます。
PCの電源に連動してテレビが付くプログラム
自分は通常のディスプレイは持っておらず、PCをテレビに繋いで使ってます。通常のディスプレイはPCの電源が入ると自動的にディスプレイも付きますよね。テレビでそれを実現しようとしたものです。
これを使うにはRaspberry Piが必要で、テレビのCECを制御できるcec-clientを使っています。Raspberry Piから定期的にPCにpingを送って、返ってきたらテレビを付けて返ってこなくなったらテレビを消すという非常にシンプルな作りになってます。
そのため、実現しようとしたものと表現したように、使い勝手が悪いです。経験したもので一番多かったのが、テレビの入力をNintendo switchに切り替えてスプラトゥーンをやっていると、勝手にPCがスリープ状態に入ってテレビの電源が切れるというパターンです。
正直、リモコンを使ってテレビをつけるのがだるいだけなので、PCの起動に合わせなくても声で「テレビつけて」って言ったら電源が入ってくれるだけでも個人的にはいいんですよね。
そこでGoogle Homeを検討してみたんですが、どうやらいろいろやるにはIFTTTを経由する必要があるらしく、直接ローカルのマシンに対して通信できないのかーと買うのを迷ってます。
リクエストごとにSQLの実行ログを書き出すgem
Qiitaに書いているのでぜひ見てください。
ニコニコアニメスペシャルbot
ニコニコアニメスペシャルbotは今年作ったものではないですが、今年はずいぶんとフォロー数が伸びて1年で450ぐらい増えました。
このグラフはSocialDogというサービスで表示したもので、フォロー管理やグラフの表示ができて便利です。以前はCheetahというサービス名ですが、使っているうちにいつの間にか変わってました。
ちなみにフォローワー数のグラフで段になっているところは、このゆゆ式の一挙放送のツイートが伸びたときです。ゆゆ式すごい、ゆゆ式を見ましょう。
【2週間後(10/22 19:00)】 「ゆゆ式」全12話一挙放送 / きららファンタジア 事前登録記念 https://t.co/dt1PW5Uii1 pic.twitter.com/HBTXDXs184
— ニコニコアニメスペシャルbot (@NicoAnimeSPBot) 2017年10月3日
Mastodon
今年はずっとMastodonを触ってました。ずっと前からOSS活動に憧れていましたが、Mastodonでその願いを叶えることができました*1。今ではコラボレーターになって(あまりレビューとかできてないですが)、コントリビュート数も40を超えて上から10番目になりました*2。
最近は自分でも検証用のMastodonインスタンスを立てて、Mastodonで発生するエラーを収集したり、SQLの実行ログを取得したり、プロファイラを仕込んだりしてコントリビュートできることを探しています。その話はまたMastodon Advent Calendar 2017で書きたいと思います。
終わりに
今年はMastodonばっかりやってて他のことはあまりできなかったなーと今では思います。あとはアニメやニコ動を見るばっかりであまり生産的なことができてなかった気がします。
大学生のときは面白そうなことに取り組んだりしていた気がする(思い込みじゃないはず)ので、来年はやっていきたいなーと思ったりしてます。
あとは、今年は去年までに比べて全然絵を描けてなかったので来年は頑張ってみようかなと思いながら、iPadを買ったら本当に自分はお絵描きするのか?と自問自答しています。
明日は irgalyさんです。よろしくお願いします。
ISUCON7 本戦で惨敗しました
チーム新卒としてISUCON7 本戦に参加し、見事に惨敗しました。
本戦の問題
本戦の問題は、ルームを作って複数人で協力できるクッキークリッカーみたいなゲーム「Chair Constructor Online」でした。 通信はWebSocketを使用していて、アクションが厳密に同期される非常に複雑なアプリケーションでした。 また、計算が複雑ということでテストが用意されていたのには驚きました。テストは非常に役に立ったのでありがたかったです。
自分が主にやったこと
序盤
WebSocketが使われていたのでどの言語で進めるか悩みましたが、WebSocketがボトルネックになる問題ようなではないだろうと予想して、当初の予定通りRubyで進めることにしました。
最初はプロファイラを仕込んで時間がかかっているところなどを調べていました。 今回はN+1や遅いクエリが全然なく、ほとんどが計算の部分だったのでstackprofが非常に役に立ちました。
あとは、DBのコネクションを使いまわすようにしました。(あとでもとに戻した)
中盤
get_powerやget_priceはcountに対して計算結果はいつも同じなので、計算結果をキャッシュするようにしました。 今思えばredisに入れておけば他のサーバでも使えて、再起動後でも利用できて更に効果があったかも。
あとは1000ミリ秒後の未来をシミュレートする処理が遅かったので最適化しました。
addingとbuyingで一致する時間と、もともとのループで使用していた最初の時間(current_time + 1)と最後の時間(current_time + 1000)だけをループで使用するようにしました(9行目)。 今思えばcurrent_time + 1の方は必要なかった気がします。 また、total_milli_isuは線形増加するので、間の時間をtotal_powerに掛けた値を足すように変更しました(11行目)。
そして、アイテムの購入可能判定では、item_on_saleにその時間を入れるのではなく、一つ前のループの時間から1ミリ秒づつチェックするように変更しました(23-33行目)。 一つ前のループから現在のループまでの線形増加によるtmp_total_milli_isuの値がしきい値を超えていなかった場合、buyingによってtotal_milli_isuが増えていることになるのでそのループ時の時間をitem_on_saleに入れています(32行目)。
終盤
使用されるサーバが偏っていたので、WebSocketの接続先を返すサーバを一つにして、ベンチ対象もその1台にしようとチームメイトに提案しました。 それまではそれぞれのサーバがラウンドロビンで接続先のサーバのホストを返していました。 WebSocketの接続先を返す専用のサーバを1プロセスだけ立てて、すべての接続先の管理を1プロセスに任せることで、より均等に接続先を振り分けることができました。
あと、DBでtoo many connectionsが出ていると言われたので、DBのコネクションを使いまわすのをやめました。 今回はプロセス数とスレッド数、サーバ数も多く、WebSocketで接続されっぱなしになっていたから起きたのだろうと思います。 なんでもかんでも使い回せばいいわけじゃないということがわかって勉強になりました。
チームメイトが主にやったこと
- motさん
- mitemをDBから読まないように
- ミドルウェア周りの調整
- 全サーバーの使用状況などの監視
- syusuiくん
- ある時点での椅子合計数とパワーの合計を保存
反省と感想
今回は、ある時点の計算結果をDBに保存する部分でDBがボトルネックになってしまい、そこからredisに変えようとしたけどうまく動かずにタイムアップという感じでした。最初からオンメモリは危険だろうと思っていたので、最初からオンメモリで考えれていたらもう少し点数が伸びていたのかもしれないです。
いつものISUCONではN+1の解消やDBのindexの改善ばっかりをやっていたので、今回はあまり貢献できなかった気がします。 ただ今回は去年とは違い、初期実装よりも点数が上がり、なんとか10000点も超えることができたのでよかったです。
最後に、運営の皆様ありがとうございました!
ISUCON7の予選を突破しました!
ISUCON6からはや一年…
今年も去年と同じメンバー(@mot, @syusui)で「チーム新卒」という名前で参加して、めでたく予選を突破できました!! この記事では自分が主にやったことを書こうと思います。 ちなみに、ソースコードはgitlabにあげてます。 gitlab.com
全体の流れについては@motさんの記事を見てください。 programmermot.hatenablog.com
始まった直後
今回もチームメンバー全員が使い慣れているrubyを使うことにして、まずはstackprofとリクエストごとにSQLのログを取れるお手製ツールを仕込んでボトルネックを探しました。
出力結果を見てみると/fetchや/messageにN+1があったり、画像をDBから取得する処理が遅いことに気が付きました。 画像周りは@syusuiくんに任せて、自分は/fetchや/messageのN+1を改善していきました。
アプリケーション側の改善
/fetchのN+1は、チャンネルごとの既読情報の取得と未読メッセージ数をカウントするというものでした。 プロファイラを見たところ、既読情報の取得と、既読情報が一つもない場合の未読メッセージ数(そのチャンネルのメッセージの総数)のカウントが多く呼ばれていました。なのでとりあえず既読情報がある場合の未読メッセージ数のカウントはN+1を残したまま、ほかの部分のN+1を改善しました。
あと、謎のsleep 1.0
を見て「なんだこのsleepは!?」となりましたが、レギュレーションを読んでいなかった自分は深く考えもせず消してしまいました。(レギュレーションはちゃんと読みましょう)
その後にMySQLでtoo many connectionsが出ると@motさんに言われたので調べていました。 今までの問題をやっててこんなことはなかったよなーと去年の予選の問題と見比べてみたところ、去年の問題ではThread.currentを使用してスレッド内でDBのコネクションを共有していましたが、今年の問題ではリクエストごとにコネクションを張るようになっていたことに気が付きました。過去問大事ですね。
/messageのN+1は単純だったのでサクッと直しました。 また、ベンチ回してると/historyも遅いと表示されたので見てみると、似たようなN+1があったので直してました。
DBの最適化
@syusuiくんが画像をローカルに保存する変更を加えたり、@motさんがnginxの設定を追えて10万点を超えたあたりで、改めてプロファイリングやDBのスロークエリを見ました。 プロファイリングの結果を見ると明らかにクエリの実行に時間がかかっていて、スロークエリの箇所と一致していました。
スロークエリはmessageのテーブルで発生していて、EXPLAINを実行してみるとindexが効いていませんでした。 クエリではchannel_idとidを使っていましたが、idにしかindexがなかったのでchannel_idとidの複合indexを作成しました。 これで20万点近くまで点数が上がりました。
もう一度スロークエリを見てみると、チャンネルのメッセージの総数のカウントに時間がかかっていることに気が付きました。 メッセージはどんどん増えていくので、総数のカウントにかかる時間もどんどん増えていきます。
だいぶ時間も迫っていてredisを入れたくなかったので、カウンターキャッシュを実装することにしました。 新しくmessage_countというテーブルを作成して、メッセージの追加のたびにチャンネルごとにメッセージ数をインクリメントするように変更しました。 また、何度ベンチマークを回しても大丈夫なように/initializeが呼ばれたときにリセットする機能も実装しました。 これで25万点を超え、最終的には268,588点で1日目の2位になることができました!
感想
今回のISUCONの予選の問題が複数台構成だったのでびっくりしましたが、手も足も出なかったISUCON 6本戦での複数台構成のリベンジができてよかったです。 アプリケーション側のボトルネックは事前に練習していたpixiv社内ISUCONと似ていたので、だいぶスムーズに進めれた気がします。
今回は全然レギュレーションを読んでいなくて、あとから/fetchや/messageの得点について知ったので、ちゃんとレギュレーションは読まないとダメだということを再認識しました。もしちゃんと読んでてsleepを残すという考えがあればもう少し点数が伸びていたのかも?
今回のISUCONの個人的な目標は一般枠で予選通過して本戦に出ることだったので、目標が達成できて本当によかったです! 本戦に出たからには何かしらの功績を残せるように頑張りたいです!
マスコットアプリ文化祭でこのはちゃんとあんずちゃんのアプリを作った話
この記事は、ConoHa Advent Calender 2016の16日目の記事です。
技術的な内容メインじゃないのでQiitaじゃなくてこっちに書きます。 ConoHaにはCoreOSをインストールしていて、DockerでWebアプリをデプロイしてたりします。
マスコットアプリ文化祭とは
企業や団体のイメージキャラクターを使った作品のコンテストです。 作品はアプリに限らず、イラストや動画でもOKな感じになっています。
mascot-apps-contest.azurewebsites.net
このマスコットアプリ文化祭で2014年と2016年はConoHaがスポンサーをしていたため、このはちゃんやあんずちゃんのアプリを作りました。
もちろんどちらのアプリもConoHaで動かしています!
それにしてもいつもこのはちゃん負けてますね
続きを読む
Tekkaが提供している機能について少し紹介してみます
この記事はTekka Advent Calendar 2016の14日目の記事です。
いつもTekkaを見ています。 というのは言い過ぎで全部は見れてないですが、それでも頻繁には見てます。 ROMっている事が多くて、あまり書き込みはしてないです。 その割にはオフライン進捗会(カラオケ会)にそこそこ顔を出している気がします。
さて、今回はTekkaが提供している機能について少しだけ書いてみようと思います。
Tekkaが提供している機能
TekkaはWebブラウザで見ることができます。また、モバイル向けの表示にも対応しています。 現状ではチャンネルがいくつかあり、そこで発言することができます。 ファイルを添付して発言する機能や、手書きで文字や絵を描く機能などがあります。 また、Web Notificationsや棒読みちゃんに対応しているなど、いち早く更新に気付けるようになっています。
Tekkaの目玉機能は、「作品やで」機能でしょうか。 「作品やで」と書かれたチェックボタンにチェックを入れて発言すると、なんと発言の枠が金色(?)に変わり、豪華になります。 創作応援SNSならではの投稿した作品を目立たせる機能ですね。
Tekkaを開発しているゆーひさんによると、まだ未実装機能がたくさんあるようなので、 一般公開される頃にはもう少し機能が増えているかも?
スマホアプリは?
先程モバイル向けの表示にも対応していると言いましたが、 残念ながらスマホアプリは今のところありません。 でも安心してください。 TekkaはAPIを公開しているので、あなたが頑張ればスマホアプリを作ることができるのです!
…はい、本当は自分が作ろうと思ってたのですが、 他の優先度が高いタスクをしてたらもう12月でした。 一応、react nativeを使ってiOSとAndroid向けに作って、 reactとelectronでMacやWindows向けにクライアントアプリを作りたいなーとざっくりとは考えていました。 なので、いろいろ落ち着いたら作っていきたいと思います。
おわりに
思ったより短い記事になってしまいました。 これはTekkaの機能が少ないのではなく、自分の文章能力がないだけです。
Tekkaにはいろんな物を作っている人たちが集まります。 一般公開されたら、創作が好きな人はぜひのぞいてみてください。 そして、自分のようにROMるのではなく発言していきましょう。
ISUCON本戦に行ってきた
チーム卒業の阿部(ABCanG)です。 めでたく予選を勝ち抜いたのでISUCON本戦に行ってきました。
全体のお話はmot先輩のエントリを見てください。
時系列で何をしたかとかはsyusuiくんのエントリを見てください。
syusui.tumblr.comこのエントリでは、僕がやったこととか、感想とかを書こうと思います。
当日までにやったこと
画像とか扱う系のが出るのかなーと勝手に予想してて、ISUCON4の本戦の記事とかを眺めたり、 nginxのproxy cacheの設定方法とか軽く見てました。 あまり何もしてないです。
当日
最初、ReactやらDockerやらと言う話を聞いて、マジかってなりました。 日頃からReactとかDockerは軽くは触っていたので、それほど焦りはしませんでしたが、 Docker周りの操作で結構時間を取ってしまいました。
ReactやDockerとはあまり関係のないところで、二つの大きなミスをしてしまいました。 一つは、計測を怠ってしまったことです。 最初のベンチを回した後、計測をしてボトルネックを探すことをせず、 そのまま5台のサーバをどう使うかと話し合ってしまいました。
今思えば、どう分けたら効率がいいかなんて分かるはずもなく、 なんで計測をしなかったのだろうと結構後悔してます。 そんな感じで僕らのチームはReactのサーバを1台とAppのサーバを3台で構築し、 初期実装のスコアより少し低い点で終わってしまいました。 「Appがたくさん呼ばれそうだから多めに配置するほうがいいのでは?」なんて僕が言わなければ運命は変わっていたかもしれない。
もう一つのミスは、5台のサーバを使うタイミングが早すぎたことです。 お昼頃には5台に分散させてましたが、他のチームの話を聞く感じだと終了から3時間前とかにやってる感じでした。 1台でとりあえず高速化して、ボトルネックになる部分を別のサーバに切り分けていくというのが普通なのかーなるほどーって思いました。
自分がやったこと
最初はコードを読んで、アプリの把握をしてました。 Reactのサーバが全部のリクエストを受け取って、APIはそこからプロキシさせてるしマジかってなりました。 アプリの挙動を見ながら、「あー数年前こんな感じの絵チャット作ったなー。でも適当に作ってしまったからあまり活かせる部分なさそうだなー」とか思ってました。
アプリの把握が終わった後は、主にアプリ側をやってました。 アプリにはちらほらN+1問題が仕込まれていたので、 それをせっせと直してました。 Server Sent Eventについてはメンバーのsyusuiくんにやってもらってて、僕はそれ以外の部分という感じです。
N+1問題ですが、先人の方が作ってくださったライブラリを元に自分好みに拡張したものを使って探してました。 このライブラリは、mysql2にモンキーパッチを当てて実行されるSQLと実行時間をログとして出力してくれます。
当時はこのライブラリはqueryメソッドにしか対応してなくて、本戦のコードではプリペアドステートメントが使われてたので、 しばらくの間なんで何も出力されないんだ?と悩んでました。 原因に気づいてサクッとプリペアドステートメントに(SQL出力部分のみ)対応させて利用しました。 今はプリペアドステートメントが使われている場合も実行時間を取得できるようになってます。
あとはstack-profで遅そうな部分を探したりとかもしてました。
App部分の開発はDockerを使わず、直接手元でRackサーバを立ててやってました。 その方がいろいろ楽だろうと思ってそうしてましたが、後でハマりました。 直接APIを叩いてAPIの動作確認をしていましたが、CSRFトークン付きのリクエストがうまく発行できずに苦しんで結局放置するということをしてしまいました。
N+1問題は減らしたけどスコア上がらないなーって言ってたら終了時間になってました。
まとめと感想
本戦とにかく難しいという印象を持ちました。 特に複数台構成のWebアプリを作ったことがなくて、どうしていけばいいかわかりませんでした。
あとはちゃんと計測しようということですかね、憶測で進めるのはよくないというのが実感できました。 実際、マシンがどれくらいCPU食っているか、もしくは食っていないかを把握できてなくて、 非常によくありませんでした。
スコアを伸ばせなかった原因は、計測を怠って不適切なマシン構成にしてしまったことだと思うので、 今度本戦に出る時はこれを避けれるようになりたいです。
ISUCONをすることで非常に多くのことが学べたので、その点はとても良かったです。 特に、今回の本戦の問題のおかげで複数台構成のコツを少し知れたような気がします。
今後
今年卒業するチーム卒業は、来年はチーム新卒としてリベンジしたいです。 しかしながら、来年は社会人ということで本戦出場のハードルがぐっと上がるので、 本戦に出れるように力をつけていきたいです。
最後に
運営のみなさま本当にありがとうございました!! 非常にいいイベントなので、長く続いてほしいです!