ISUCON7に参加した
前回のISUCON6に出た時、結構楽しかったので今年も出ることに
(こんな雑なノリで出向先の会社で誘って集まったメンバーで参加しました)
メンバーは @chiastolite さん、 @hachi-eiji さんでした。
準備
大会の二週前に決まって週一くらいでざっくり戦略とか話しますかーって言ってたけど仕事周りで忙しく結局一回、1hくらい
- sshキーまとめとく
- 今回が初の人がいたので以前の傾向とか対策をざっくり話してた
- 解析はさくっとやるのにnew relic入れたいよねーでアカウント作ったりした
- さくらのクラウドの操作をざっくり見直してた
そもそも出るのも急に決めちゃったので前日に飲み会入ってる人が二人とか色々大丈夫か?って感じだった
大会前
時間が13時開始にずれてちょっとほっとしてた。雑談用チャンネルの🍺高度な情報戦🍶に圧倒されてた。ちなみにうちのチームは
テンション上げるにはなんのアニメがいいか検討した結果、キルミーベイベーが採用されてます pic.twitter.com/cJ4ykCpc4Q
— jacksmam (@jacksmam0) 2017年10月22日
序盤
SSH周りとか下手に触ると邪魔になるだけなので資料見てサーバーに入れるまでちょっと待ってた。
サーバーに入れるようになってからはコード見たり、ブラウザで見てみたりしてサービスの把握とかクソそうなapi探してた。何個か目をつけて
- fetchのapiは叩かれる回数が多い + レスポンスがおそすぎたのでやるべき
- get message とか history/:channel_id で n + 1がある
- get_channel_list_infoがほぼ全画面で呼ばれてたのでやると良さそう
ぐらいの当たりを付けてた。
中盤
今回は2台サーバーがあってそれぞれ負荷をかけれたので1台ずつ使ってベンチがよかったらmasterにマージして両方に適用、みたいな手法で進めた。
get fetch のAPI
チームの人がimage周りヤバそうって言って色々直してくれていたのでapi側に集中してfetch周り調整してた。
- 単純にjoinしてなんとかなる気がしなかった(ただの能力不足)
- 血迷ってunread_count的なカラムを追加して user_id, channel_idで紐付け、unread_countを増やしたりすれば n+1が解消できそうって考えて色々組んでた
- とはいえ初回の未読データとか作らないといけないことに気づき辛みを感じる
みたいな感じであんまり進まず、結局image側の対応が終わってfetch周りをお願いした。
get message と get history/:channel_id
次にget message と history/channel_id の n+1を直してた。
こっちはひねりなくuserテーブルのjoinで済んだのでさくっと出来た。ただ取ってきたデータをrubyのシンボルの文字列で返してしまっててちょっとハマった。
この辺でimage関連を入れずで6000点くらいだった気がする。
後半
キャッシュデータの検討
imageをファイル化は出来たけど複数サーバーだと困るってことでnginxでファイルアップロード・ダウンロードでは一台にアクセスが来るように調整してもらっていた。
その間何かしらキャッシュがいるよねーでmemcachedを入れてもらいつつキャッシュできそうなデータを検討してた。
結果、全画面で使ってるchannelデータをキャッシュすることに
- 全画面で毎回呼ばれるのでキャッシュで返せると良さそうだった
- channelはユーザーに紐付かないので全ユーザー共通で返せるのに気づいた
memcachedも爆速で入れてくれてとりあえず試したら点数が20000ぐらいまで跳ね上がってテンション上がる
地味な所を直す
チームの人がDBのインデックス再確認してたりnginxのキャッシュ周り見てくれてたが、自分にできそうなことがほぼなかった。ので邪魔にならない範囲で最適化できそうな所を調べてた。
見つけたのが
- get message時のhavereadの更新でそもそもmessageがないのにhavereadのレコード入れようしてた
- get history/:channel_idでmessageを20件取りに行った後にpageをチェックして400返したりしてた
のでそれぞれ無駄をなくそうとして調整してた。ベンチを走らせるも点数が下がったりしてあてが外れて萎えてた。でも後から考えるとガチャ引けてなかっただけな気もする
終盤
imageの周りも入ってベンチを回すと60000点ほどまで上がった。ここでテンション上がって皆でスクショを撮る
結局後は何も出来ずひたすらベンチガチャを回して良い点数でやめようって判断になった。結果的に81003点まで上がりラッキーって感じでベンチは打ち止めにした。
ラスト1時間ぐらいで再起動のチェックしてたらまさかの502が出て焦ってた。が何も出来ずpuma周りのネット記事探したりしたけど力になれず...
結局pumaの起動が遅いだけで1分くらいするとアクセスできることに気づいた。
流石に失格にはならんだろって判断でフィニッシュ
感想
- 改めてwebサーバーもDBも何も出来なさすぎて申し訳無さしかなかった。
- アプリ側も多分できてる箇所が少ないと思うので力不足がすごかった。
- fetchの周りとかJS直そうとか思ってたけどソレ系は対象外なので業務外しかないの難しい。
- ISUCONはやっぱ楽しい
- 急に誘ったのに参加してくれた二人にはほんと感謝🙏
CSSを組むときの考え方 ~レイアウト編~
cssを実装する時にcssのクラスに関しての設計はよく話に出てきますが、パラメータ側を考慮した良い設計という話はあまり見ないのでまとめてみました。
1 縦と横を意識する
Webページを作成する際、一番最初にすることは画面を縦、横を意識しつつ分割していく作業です。ここを意識して設計すると後々別の要素が追加されたり、逆に消す場合もバランスを保ちやすく扱いやすいhtml、cssになります。
それでは実際のwebページを見つつパースしてみましょう。参考に Yahoo! JAPANを使います。以下は上部を切り取って分割してみた図です。(一応ボカしてます)
赤線 縦方向の分割
青線 横方向の分割
分割するときの優先順位は
1 縦
2 横
の順番で分割します。今回の例だと最上部のヘッダのエリア、下のコンテンツのエリアで分割できます。(下のほうは実際はもっと下のコンテンツまでが範囲です)
さらに下のコンテンツは左、中、右の3つのコンテンツで分割でき、これが横並びで分割できます。このような作業を繰り返してレイアウトを縦、横で分割していきます。
2 inline要素とblock要素
レイアウトを分割してじゃあ実装だ!となるところですが、まずは要素の特性を知ってから組みましょう。要素には2つの特性があります。それぞれの特性を見ていきましょう。
・inline要素
inline要素はその名の通り並べると文字が並ぶようにインラインで連なるような要素です。基本的には横に並びますが、文字のように折り返します。また、ブロック要素の内部にテキストを記述した場合、そのテキストはinline要素の特徴を持ちます。
実際に配置してみたものが以下になります。2つ並びで指定すると横並びになりますね(見やすいように少しcssをかけてます)
・block要素
block要素はinlineとは逆に複数並べても横並びしません。基本的に親要素の幅いっぱいまで横に広がります。その為複数並べたときには縦に並びます。
こちらも実際に配置してみるとこうなります。
3 実際にレイアウトを組む
さて、ここからは実際にレイアウトを組んでみます。試しに1で分解したレイアウトを組んでみます。赤線で縦に分割した要素はblock要素、青線で横に分割した要素はinline要素で組みます。実際にレイアウトを組むとこうなります。
ざっくりとは形になりました。ただこれでは同じレイアウトとはいえなさそうです。
全体のサイズ感を整えてみます。spanはinline要素ですが、inline要素は色々と不便な所が多いのでinline-block要素にします。
まだ崩れていますが、なんとなく見える形にはなりましたね。
このように縦と横を分け、要素の特徴を使い分けるとより見やすく保守しやすいレイアウトが組めます。ただ実際にinlineとblockだけで実装するのは困難です。inlineとblockは大枠でさらに拡張した属性を使って組むことが多いです。さきほど利用したinline-blockもその一つです。詳細はdisplay - CSS | MDNにあります。
ざっくりとレイアウトを分割→組む作業までの流れを書いてみました。
次回は中のコンテンツ(モジュール)の作り方を書きたいと思います。
aureliaに関する調査
公式のGetStart
公式のチュートリアルを読みながら試してみた
AureliaのGet-startedを試してみる(1 - Qiita
公式の構成を最小にしたtypescriptチュートリアル
TypeScriptで書くAurelia 最小構成 - Qiita
おまけ
TypeScript クイックガイド
AndroidでOpenStreetMapを利用する
備忘録として
環境
Android Studio(IntelliJ) v0.8.14
Mac OSX 10.9.5
参考資料
OpenStreetMapをAndroidアプリに組み込む -でじうぃき
続きを読む
cocos2dのCCLayerのクラス名に関して
すごくどうでもいいところで時間を使ってしまった。
cocos2dの新しいCClayerを作成する際に
~Sceneというクラス名にしないと何故か自動入力とかクラス関係とかが一切反応しなくなりました・・・
こんな落とし穴があるとは・・・
何か他の条件でもあるのだろうか?
NSScannerの取り扱い
走査方法
(BOOL)isAtEnd
・文字列をすべて走査し終わったかの判定、whileとかで使うと便利
- (NSInteger)scanLocation
・現在の走査位置
・プロパティのように見えるがただのメソッドなので前の位置に戻ったりとかはできないみたい
- (BOOL)scanString:(NSString *)string intoString:(NSString **)stringValue
・scanLocationの位置からstringがあるかどうかを調べる
・なかったらNOを返す。あればYESを返し、scanLocationの位置をstringの次の文字の位置に移動させる。
・ちなみになかったらstringValueがnil、あればそこまでの文字が返ってくる
- (BOOL)scanUpToString:(NSString *)string intoString:(NSString **)stringValue
・scanLocationの位置から以降にstringがあるかどうかを調べる
・なければNO、あればYESを返し、scanLocationの位置をstringの先頭文字の位置まで移動させる。
・stringValueにはあればそれまでのscanLocationからstringの手前までの文字列が入り、なければscanLocationから最後の文字列までは入る
またscanなんたら系にはintegerやfloatもあるので数字しかないのがわかっている場合には利用してもいいかもしれない
でもparserとか色々いいものもあるしぶっちゃけ使わないだろうなぁ・・・
2chViewer作りたい
とりあえず取得情報を見てみると
view-source:http://menu.2ch.net/bbsmenu.html
の
大タイトル
<BR><BR>から取得
少タイトル
大タイトルの間にある<A HREF>にurlと少タイトル
スレ一覧
その先は<A HREF>から取得したurlに /subback.html にアクセス
<a href>にスレのurlとタイトルを取得
ただし/50で最新50件取得になるので外してすべてを取得
中が意外と厄介で
dlの間の要素が実際のレス
dt 要素がひとつのレスだけど囲ってないので処理に少し困る
見るとすれば<br><br>かなぁ、ただ普通のレスにも入れられるのでそれだけで見ていると痛い目を見そう
今日はこのくらい