投稿

So-net フレッツ回線を IPv6 + DS-Lite に変更して劇的に速度改善しました

イメージ
最近、毎晩8時~12時くらいの時間帯で、So-net フレッツ光マンションタイプのインターネット回線のダウンロード速度が非常に遅くなる (0.1~1Mbps程度) 現象に見舞われており、大変困っていました。 具体的には、YouTube の 1080p や、AbemaTV の最高画質はダウンロードが追い付かず、低ビットレートのモヤモヤした画面を見させられ、アプリの更新やデータダウンロードでもやたら時間がかかるという感じで、この回線に繋がる Wi-Fi よりも、ドコモ Xi の 4G+ の方がずっと速いという、いったい何にお金払っているんだろうかという状況でした。 切り分け用に NTT 東日本の用意してくれている フレッツ速度測定 では、十分に高速 (90Mbps 以上) な速度になっているので、おそらくボトルネックは So-net 用の PPPoE 部分にあるようで、先駆者のブログでの改善報告も参考にして、以下のページより IPv6 接続オプションを申し込みました。 「IPv6」ご利用のご案内 | 会員サポート | So-net 申し込み数時間後、手続きが完了したようで、ルーター広告 (RA) でグローバル IPv6 アドレスが降ってきて IPv6 で通信できるようになり、Google, Facebook, YouTube, Netflix など、IPv6 接続性のあるサイトの速度が改善しました。 この調子で IPv4 の速度も改善するため、So-net での IPv4 over IPv6 トンネリング (IPv6 ネットワーク上で IPv4 の通信を行う技術) のために必要な DS-Lite に対応した無線LANルーター WXR-1751DHP2 を導入してみました。セットアップ自体は PPPoE の設定すら必要なく、有線で繋いで電源を入れるだけで、あとは IPv6 と IPv4 (DS-Lite) の接続性が得られました。 速度測定結果は以下のように、混み合っていた時間帯でも安定してダウンロード 60Mbps 以上は出るようになって、非常に快適になりました。 プロバイダを So-net に変えてから、遅延がひどくてやらなくなっていた、FPS も試しにやってみたところ、ちゃんと敵の居場所が反映されるようになって、レイテンシーも安定し...

[adtech] 行動ターゲティング広告を最大限強化するには

イメージ
インターネット広告について、もし広告ブロッカーなどは使わず、広告を受け入れるポリシーなのであれば、完全に最適化してもらうのも面白いと思います。行動ターゲティング広告という仕組みはご存知であっても、具体的に最適化を強化するには何をすれば良いかは、各社気持ち悪がられることを恐れてか、あまり明確な説明をしていないように思います。そこで、広告の最適化をより進め、広告の配信が楽しみになるアイディアをご紹介します。 まず、Google, Facebook, Twitter, Yahoo! JAPAN など、広告配信に直結したアカウントで、モバイルを含む普段使うすべてのブラウザにログインしましょう。クッキーを受け入れていれば、すでにブラウザごとに履歴が蓄積しているのですが、アカウント経由で全ての行動履歴が統合されることでより正確なプロフィールが仕上がります。 Safari のデフォルトの設定は広告最適化上よろしくないものがあるので、サードパーティークッキーは受け入れる、サイト越えトラッキングも防がない設定に変更すると良いです。 次に、所持しているモバイル端末全てに、各社のモバイルアプリをインストールし、ログインしましょう。これにより、デバイス単位で存在する IDFA (iOS), AdID (Android) の広告用識別子と、ユーザープロフィールが統合され、モバイルアプリ内の広告も最適化が完了します。追加で、位置情報も定期送信しておくと良いです。 これらのユーザーごとに広告配信を最適化する仕組みは、必ずしもリアルタイムではなく、日次~週次ほどのバッチ処理で随時更新されるような雰囲気です。すぐに面白い広告が出なくともしばらく放置してみると良いと思います。 以上の対応により、例えば、 Google 広告設定 を見てみると、以下のように収集された興味関心が一覧で表示されると思います。 現状の分析 現状どれくらい正確なユーザーの情報を得られているかについて、Google は Google Chrome により、SDK の埋め込みがなくても、全ての閲覧履歴を収集する仕組みを持っているので、格段に優位な状況にあると思います。 Facebook のモバイルアプリも、標準ブラウザでログイン済みかどうかを定期的に確認し、ログインさせる機能を有しているので、広告...

[isucon] ISUCON7 本選17位でした

イメージ
2017年11月25日、LINE の新宿ミライナタワーの会場にて、 ISUCON7 本選にチーム 円山町(hidekiy, kotaroy, k_enoki) として参加してきました。成績は ISUCON6 本選と比べて若干の進歩はしたのですが、まだまだ上位層との壁を感じました。 当日やったことを書いておきます。 10:00~ SSH 鍵ログイン設定、Mackerel Agent 設定、Go 実装に変更、アプリの動作確認、Go の CPU プロファイル取得 (pprof) 12:00~ 分析の結果、初期状態のボトルネックは、DB と API のどちらの CPU, 各種 IO も使い切っていると言えないので、ロック競合か何かかと思ったが、煮え切らないまま深く考えなかった (これが致命的にまずかった) CPU プロファイル的には、多倍長整数演算が遅かったのと、コード上明らかにおかしな1000回ループ、テストコード付属という親切設計を見て、このループを最初に修理することにした。 16:00~ 初めて使う Go の多倍長整数演算ライブラリで、苦労の末1000回ループの除去に成功、それでも相変わらずボトルネックはDBのロックにあるように見え、これを何とか小細工しようとするが、特に有効な手を打てないまま時間切れとなった。 感想 速やかに、オンメモリー方式に作り替え、ロックを部屋別に分散させる決定をする必要があった。 Go の多倍長演算には結構苦しんだ。 糖を消費したせいか、ISUCON ケーキが美味しかった。 総括 素晴らしいイベントを企画、運営いただいた、LINE、KLab、さくらインターネット様には大変お世話になりました。ありがとうございます。

[isucon] ISUCON7 予選通過しました

ISUCON7 にチーム名 円山町 (@hidekiy, @kotaroy, @k_enoki) として出場し、去年に引き続き予選通過しました。当日について、記憶が定かな内にメモしておきます。 今回の予選問題について isubata という名前で、これは ISUCON 参加者になじみの深い idobata というチャットサービスを参考に作られているようでした。 用意したもの GitLab のプライベートリポジトリと権限設定 専用の Slack チャンネル Mackerel オーガニゼーションと公式プラグイン (inode, linux, mysql, nginx, proc-fd, uptime) の設定 ngxtop の使い方 2017/10/22 13:00 無事全員そろって開始 当日用マニュアル熟読 (@hidekiy, @kotaroy) 公開鍵ログイン設定と ssh config 作成 (@k_enoki) アプリのソースコードを GitLab へアップロード (@k_enoki) アプリを Go 実装へ切り替えと自動起動設定の修正 (@k_enoki) isubata アプリの動作確認 (@hidekiy, @kotaroy) インフラ構成と、nginx, MySQL の動作状況の確認 (@k_enoki) トラブルシュート用の mackerel-agent を全台に設定 (@hidekiy) 14:00 ローカル開発環境構築 (@hidekiy, @kotaroy) make deploy で全台にアプリがデプロイ (ローカルで GOOS=linux でクロスコンパイル後、scp して rename して systemctl restart) されるように設定 (@hidekiy) 静的ファイルの nginx 配信化と事前圧縮設定 (@k_enoki) DB のネットワーク上りがあんまりな状態だったので、一旦 image のオンメモリキャッシュを実装 (@hidekiy) /icon にインチキ Etag + If-None-Match 実装を試すが、全く 304 を返せず挫折 (@hidekiy) /profile の画像アップロード機能で、DB に二重に書き込まないように修正、ついでに...

[golang] crypto/rand で疑似乱数生成器を初期化する

Go 言語で疑似乱数 math/rand を使うとき、実行ごとに別の乱数列を選択するための方法として、rand.Seed(time.Now().UnixNano()) とするのが人気があるようなのですが、より予測困難さを追加するためには以下のコードのようにすると良いです。 今日では、Perl, Ruby, Python などで、明示的な seed をせずに rand を使った場合に、内部的に行われる自動的な seed では、OS の乱数生成器由来の値が使われるようになっているので、Go でも同じ感じで良いと思います。 package main import ( cryptorand "crypto/rand" "encoding/binary" "math/rand" ) func main() { randSeed() println("rand int:", rand.Int()) } func randSeed() { var seed int64 err := binary.Read(cryptorand.Reader, binary.LittleEndian, &seed) if err != nil { panic(err) } rand.Seed(seed) } LittleEndian は BigEndian でも良いです。crypto/rand には big.Int のインターフェースもありますが、こちらの方式の方が簡潔に書けると思います。 蛇足ですが、暗号化用の鍵や、何とかトークンのような、長さ分のエントロピーを持つ乱雑な文字列を作りたい場合は、math/rand ではなく、 crypto/rand をそのまま使う必要があります。 リンク math/rand: Deterministic random by default is dangerous #11871

ISUCON6 本戦敗退しました #isucon

22日土曜は第6回の ISUCON に参加しました。当日は無事起床は成功したのですが、完全に打ちのめされました。チーム名は円山町です。参加メンバーは会社の同期 @k_enoki, @ymz_kotaro です。今後のため当日やったことをメモしておきます。 10時~12時 4コア * 5台の構成が Azure のデフォルトのコア数制限にひっかかってデプロイ失敗、運営で2コア * 5台に変更していただき、この構成で競技することになる。 デプロイ後なぜかログインできないと思ったらユーザー名が自分の名前で入ろうとしていた。isucon@ としてログインに成功する。 バックエンド側アプリを Go 実装に変更後、何もいじらずにベンチ流してみるが、フロント側アプリの Node.js でアクセスログが出ていないのでアクセス状況は良く分からず。 12時~14時 Go のアプリのプロファイルを取得するためにアプリを改造する。Node.js 部分は @ymz_kotaro に依頼する。 @k_enoki が Node.js の前に nginx を立ててアクセスログを解析する。 isu05 に MySQL と Redis を立ててもらうのを @k_enoki に依頼する。 本番環境では別ノードの MySQL を使いたいが、ちゃんとした設定が良く分からないのでひとまずホストネットワーク設定とする。 docker-compose の扱い方でローカル環境構築に手こずったが、Docker for Mac ではホストネットワークが使えない問題があることが分かったので本番でのみ使うこととする。 14時~16時 docker-compose build していなくてイメージがリビルドされずコードの変更が反映されない問題を解決する。 Go のプロファイル上最も時間を費やしていた、あるルームの全情報を取得する API を Redis でキャッシュする機能を作成する。 ポーリングで沢山無駄にクエリを発行している、SSE で部屋の更新情報を通知してくれる API を Redis の Pub Sub を使って改造することを計画する。 16時~18時 Redis のキャッシュ機構はバグ修正を git pull してようやく機能するようになる。 更新情報通知用の Pub S...

[isucon] ISUCON6 予選通過しました

今回はついに予選通過しました。チーム名は円山町です。17日土曜日の予選当日にやったことをメモしておきます。 予選当日のタイムライン 10時 出社 (会社のオフィスから参加させてもらいました。大変感謝) 前の日の晩に作った無料試用アカウントでデプロイ Go 実装に変更、動作確認 記事を削除したら /initialize しても復活しなくて、初期データを壊してしまったので復旧方法を調査 /var/log/cloud-init-output.log を見て展開イメージの tar.gz を発見したので、中に入っている SQL ダンプでデータを復元 11時 Go 実装に切り替えたところ、スターが付かない不具合があったので、コードを検査、ngrep で調査して原因を特定 ローカルでコードいじるためにホームディレクトリで git init、必要そうなものを add/commit して push ローカルの MySQL にデータを入れて似たような環境を構築、バグ修正、動作確認 正常に動作するが、キーワードの置換処理があるページが遅くてベンチどころじゃないので、アプリに net/http/pprof を仕込んで、キーワード個別ページを叩いた時の CPU プロファイルを取得 htmlify の正規表現コンパイルと正規表現マッチングが遅いことが分かったので、何とかする方法を検討 12時 昼食、修正方針の検討 13時 htmlify で行っているキーワードの発見部分は、元上司の okzk さんが活用しているのを見たり、他プロジェクトのコードで見たことがあったトライ木で何とかするのが良さそうと判断、触ったことのあった github.com/armon/go-radix を使わせていただいて試作してみたところ、特に問題なく動き、動作はだいぶ速くなった。 ベンチを流しながらプロファイルを取ったところ、トライ木の構築に時間がかかっていたので構築済みのトライ木をキャッシュする (キーワードリストが変わったら破棄) ように修正 14時 isutar のスター追加処理でキーワードの存在チェックにキーワード個別ページを叩いていて迷惑なので MySQL から存在情報を取るように修正 isuda のスター取得部分で HTTP API を使う必要はないと思...