読者です 読者をやめる 読者になる 読者になる

ES2015強化月間

特にそういうつもりはなかったのだが、6月はめちゃくちゃ ES2015 書いてた。

作ったやつ

細かいものを作っては壊してを繰り返してた中でそれなりに満足したやつを出す

Chromeプラグイン

50分くらいでさくっと書いた、URLに紐づけてノートが書けるやつ。
ブコメみたいに使えるし保存はローカルだから他人には見えない。

f:id:Dolpen:20160622122411p:plain

リポジトリはこれ。

github.com

babel + React で書いてて、 EventEmitter を必要最低限にラップした Store を作って、Store からコンポーネントツリーに直接全 state を流し込むようにしたオレオレ flux にした。これにより

  • コンポーネントは state の書き戻し操作に関与せず、与えられた state / props から VDOM を吐く map 操作となる
  • 上記に関連して、 state の書き換え処理を一ヶ所に集約できる
  • そもそもの構造として、完成品の state をプッシュし続けるだけで良くなる

みたいな点が良さそうだった。

スペクトラムアナライザのデモ

https://dolpen.net/labs/sa/

6時間くらいかかった。これも babel + React +Rx 。モチベーションは、

  • 音源を Observable ベースのローダーを作って読み込みたかった
  • 画面更新の tick 処理も Observable から定期的に実行したかった
  • Web Audio API のラッパー作りたかった
  • React で SVG レンダリングしてみたかった

という感じだ。おおむね満足している。 SVG上のクリック座標の取得が、(おそらく)グローバル座標系からの差分計算になったりしてコンポーネントのモジュラリティを破壊しかけたり、Web Audio APIFFT の結果を返すとき、周波数を均等割して返すため、一般的に良くあるスペクトラムアナライザのように表示するために対数ベースに変換するなどのドメイン知識の部分で苦労したりでもう二度とやりたくない感じだった。

ES以外

  • Knife Solo → Knife Zero (できることできないことがわかってきてやっと実用できそうになった)
  • Capistrano2 → Capistrano3 (できることできないことがわかってきてやっと実用できそうになった)
  • netty4 でwebsocket のサーバー実装する ( WebRTC のシグナリングに使いたかった)

みたいな感じで、レガシーになりかけてた環境の刷新に向けて動けそうなところまで来た。

この先

まず痩せる。あと右手首が壊れたっぽい(曲げに加えて引っぱりに対して痛みが出るので靭帯の可能性がある)ので適切な対処をする。必然的にイカとかFPSの頻度を下げざるを得ないかもしれない。

激安クソVPSとプロビジョニングツール

クソVPSの話

少し前まではいろいろな怪しい VPS サービスに突っ込んで、サービス改悪や閉鎖などの地雷を踏みまくってるクソ VPS ハンターだったのだが、 CloudAtCost という激安 VPS サービスがあり、半年ほど使い続けている。

この VPS サービスは、基本的に異常に安いという特徴を持っている。1コア0.5Gのメモリで35ドル、CPUとメモリ増やすごとにほぼ比例して料金が上がるのだが、これは月額ではなく払いきりである。一度料金を支払えばサービスか自分が死ぬまでは無限に使えるのだ。さらに言うと、表示されている価格に対して、ほぼ常時4割引のセールを行っており、たまに6-10割引のクーポンを Twitter やサイト上で配っている。

なぜこんなに安いかという疑問はある。FAQ - How can you do this for this price?にある程度説明があって

  • ネットワークは国営インフラと提携
  • 電気代が安い
  • データセンターの用地やハードウェアを既に調達済み

らしい。日本とはだいぶ事情が違うらしいが、良くわからない。

購入するのはインスタンスではなくサーバープランであることも大きな特徴だ。契約したプランの範囲内で、自由にインスタンスを立ち上げることができる。たとえば、4コアのプランを2つ契約すれば

  • 8コア x 1
  • 2コア + 6コア
  • 2コア x 4

などの分配が可能だ。メモリやストレージについても、同様に分配可能である。

ここまでだと非常に良い印象だが、そこまで旨い話はやはりないのだ。

良くないところとして

  • CPU がしょぼい(6年くらい前のやつ)
  • CPU / 回線帯域の継続的な使いすぎで無断停止する可能性がある
  • 初期設定だと7日で止まる罠がある
  • インスタンスの生成が遅い、失敗する可能性がある
  • インスタンスに IP がアタッチされても、外からアクセス可能になるまでが遅い
  • 遅いだけなら良いがいつまでもネットワークからアクセスできない場合もある
  • IP を静的にアタッチする( AWS だと EIP みたいな)機能がない
  • ping が遅い(RTT が 160-200ms 程度)

という点が挙がる。インスタンスが正常にセットアップされ、ネットワークに繋がるという当たり前のことに、低くはない一定の確率で失敗し、その後も常に突然死し得るという要素は、クラウドサービスを標榜するものとして大変なマイナスである。そして何よりまずいのは、

  • 月末セールなどで盛り上がる度に、インスタンスの生成が24時間以上もペンディングする
  • アタッチされたはずのIPが他と競合していて使えない

というところである。極めて厳しい。

さて、この「RTT が長くレスポンスが悪い、いつ吹っ飛ぶか分からない」というサービスをいかに使っていくかというところで、サーバーのプロビジョニングツールの出番となる。

プロビジョニングツールの話

chef などのプロビジョニングツールの良いところは

  • あるべき状態を記述すれば自動的にパッチを当ててその状態にする
  • 羃等性の担保(いつでも何回でも同じ作業を繰り返すことができる)

ということで、これはサーバー内の state (ログとか保存の必要性があるファイル)さえ管理しておけば、いつでもそのサーバーを使い捨てにできる (disposable) という事である。逆に言えば、state なんて捨ててもいいという使い方に限定すれば、人間がやることはどうあるべきか、という完成形を記述して push するだけでよいのである。 ssh でログインしてミドルの設定ファイルを手で弄ったりする作業を jQuery 的と例えるならば、プロビジョニングツールのアプローチは仮想 DOM に近いものだろう。

クソ VPS サービスの歩き方

というわけで、いつ dispose されるか分からないクソ VPS では

  • state を捨てても良い使い方しかしない (サーバーを disposable にする)
  • そのための手段がプロビジョニングツール

というのが今の自分の考え方だ。実際、本当にどうでも良いインスタンスを除く、webやゲームサーバーのホストなどは chef のレシピを書いて管理している。コンテンツに付いても、消えたら困るものに付いては github で管理しつつ、それを使うサーバーが fetch するようにしている。

回線が細かったり CPU がしょぼかったりするので、おすすめの使い方は

  • 時間かかっても良いような定期ジョブやCIを回す
  • クローラ(通信遅くても別に良い)
  • Webサーバーにするけど無料のCDNで高速化する
  • ゲームサーバーとかならCPUをたくさん割り当てて、CPUバウンドな処理でも使用率が上がらないようにする

くらいだろうか。どのみちあまり信用していないので、復旧可能にできない、かつクリティカルな用途には使わない方が良い。仕事で使うとかありえない。

React勉強会1(2016-05-25)

発端

やりたいと言ったら @mizchi がやってくれることになった。

今回の目標

weapons.json · GitHub

メインクエスト : この json を使って、Splatoon のブキを一覧表示する機能を作る
サブクエスト : 絞り込み機能を付ける
サブクエスト : 検索フォームと一覧部分をサブコンポーネントに分けて、それらを管理するルートコンポーネントstate の更新内容を書き戻す

進捗

割と実践的で、構築しながら説明と言う感じだった。実際 GitHub - dolpen/react-tutorial のコミットログを見た方が何をしたかは分かりやすいのではないかと思うので大胆に割愛。

コンポーネントは何を与えられるべきか

React 自体は data => view を担当するのが主機能なので、view を出力するコンポーネントの構築に、この data に当たるもの以外が依存として入ってはいけないと感じた。具体的には stateprops で、render() に必要な情報が全て賄われるべきだと思った。

種類 何が入るべきか
state そのコンポーネントが管理する状態
props コンポーネントから渡される情報

仮想DOMと再描画

React を使うとき、そこには3つのDOMツリーがあると考えた方が良い。

  • 実DOM。ブラウザがレンダリングに使うもの。
  • 仮想DOM(A)。実DOMと同じであるものとして React 内部で保持されているもの
  • 仮想DOM(B)。state が更新されたときに生成されるもの。

React が state の変更を受けて実DOMを更新するとき、以下のステップを踏む

  • 新たな state を受けて、仮想DOM(B)が丸ごと生成される
  • 仮想DOM(A) と 仮想DOM(B) が比較され、仮想DOM(A)にどのような操作をすれば、仮想DOM(B)相当になるかの差分をコマンド化する
  • 実DOMに差分コマンドを適用し、実DOMが新たな state を反映したものになる
  • 仮想DOM(A) が 仮想DOM(B) で上書きされる

実際に実DOMに対して実行されるコマンドは

el.textContent = "piyo";
el.style.color = '#ff0011';

といった感じでおなじみの本当にネイティブな命令だが、React の価値は、

  • 変更を最低限にするための差分検知の仕組みがあることによって、実DOMの必要以上の更新が起こることがなく高速。
  • その差分が、常に stateprops に依存するために、普通に使っていれば状態と表示がズレることもない。

ということだ。

なぜjQueryが俺の魂を震えさせていたのか分からなくなった

上記からjQueryのそもそもの筋の良くなさに対して、さらに理解が深まった。

出来上がった実DOMに対してセレクタで走査して、アクセサで表示やイベントを手動で付け替えるというjQueryで当たり前に行われていたことを、サーバーサイドプログラミングで言うとこんな感じになる。

  • jspやテンプレートエンジンを用いてHTMLを生成する
  • DOMパーサーにHTMLを突っ込む
  • cssセレクタでエレメントを取得する
  • プロパティや内部のコンテントを書き換える
  • 書き換えたDOMからHTMLを再生成してレスポンスにする

それが筋のいいことではないという事は一目見ても分かるし「最初からテンプレートの定義で表示を出し分けようよ」となるのは必至であるはずなのに、何となくjQuery使っている時は、それが不思議とは思わなかった。

なぜ仮想DOMという概念が俺の魂を震えさせるのか

しかし今翻って React のコンポーネントを見てみると、そこにはデータ定義とテンプレートがあり、それらがツリーになっているという、自分の目からはサーバーサイドでよく見た光景に映った。なぜ今までこうなっていなかったのだろうとさえ思った。何も新しい事ではなかったのである。

SPAや巨大で複雑なアプリケーションに使えることも利点なのかもしれないが、 かつて我々がサーバーからHTMLを出力していた時代と同じようなパラダイムがフロントエンドに来て、

  • 階層化、モジュール化ができる奇麗で高速な設計
  • それをもれなく view に反映できる奇麗で高速な仕組み

が我々の魂に響くのではないかと思った。

付録

奇麗な世界の汚い話

コンポーネントshouldComponentUpdate というメソッドを生やす事で、stateprops の差分から

  • 新たな state を受けて、仮想DOM(B)が丸ごと生成される
  • 仮想DOM(A) と 仮想DOM(B) が比較され、仮想DOM(A)にどのような操作をすれば、仮想DOM(B)相当になるかの差分をコマンド化する

のステップを実行すべきか、すべきでないかを通知する事ができる。これは、stateprops が更新されても差分コマンドがゼロ(変更無し)になるパターンで探索をスキップできるのでパフォーマンスが上がる。しかしコードの可読性や保守性が下がったり、メンテナンス時に思わぬ罠になったりするというのは明らかだろう。。。

奇麗な世界の汚い話2

差分コマンドが最小限になるとは言っても document.createElement とか el.appendChild などのツリー構造の変更というのは相対的にコストが高く、表示/非表示を切り替えるのにエレメントの付け替えを行うより、差分が el.style.display = "block" or "none" で解決される形にしたほうが実DOM更新が高速化するなどの泥の紹介があった。こうなってくるとコードやテンプレートに意味がつき始めて闇が生成される。。。

無線LAN環境を更新した

無線遅い問題

無線 LAN のスループットが安定せず、動画など巨大なデータのダウンロードでも定期的に引っかかりが起こることに気づいた。チェックツールで確認すると周囲には無線 LAN の電波が無秩序に飛び交っていた。自宅は都心に極めて近い住宅密集地。周囲の家からあまりよく設定されていないアクセスポイントの電波が睨み合うように電波のチャンネルを切り替え合い、その度に無線電波の干渉具合が変わり、パケットロス、ひいては TCP のウインドウサイズのリセットなどが起こったのだろう。

現状

これが現状のネットワーク構成である。

f:id:Dolpen:20160526124424p:plain

2010年に BUFFALO Air Station WHR-G301N を購入し長らく使ってきたが、ギガビット非対応でただでさえ自宅内のボトルネックになっていた上に、複数端末接続時のスイッチングコスト(遅い端末が繋がると全部遅くなる)やアクセスポイント自体の負荷が無視できないという状況だった。

設備買い替え

そこで、次のような効果を狙って無線 LAN アクセスポイントの買い替えを行った。

  • 無線のギガビット化。801.11ac を使えるようにしてボトルネックにならないようにする
  • アンテナの強化により、周囲の無線電波に負けないような電波強度を得る

購入したのは以下の無線 LAN ルーターである。 ルーターではあるものの、アクセスポイント(無線ハブ)として使うのが目的だ。

更新後の構成である。

f:id:Dolpen:20160526125750p:plain

当然アクセスポイント自体への接続も GbE となる。 図の赤い部分が主に変更される部分だが、電波環境の改善により他の無線端末にも恩恵はあるだろう。

結果

電波強度は非常に高い。法律の範囲内ではあるものの過剰なレベルなので、多少は出力を抑えても良いかもしれない。

端末 G301N Archer C7
Androidスマホ(11n) 40-50Mbps 100-130Mbps
Kindle(11n) 40-50Mbps 100-120Mbps
ThinkPad(11n->11ac) 50Mbps 240-300Mbps

ざっくり計測でこんな感じになった。 11n / 11ac ともに理論値の3割程度出ているので、実効速度としては申し分ない。

ハマりポイントとこれからの課題

WAN側ポートが使えない問題

Archer C7 を無線 LAN ルーターとして使う分には、WAN 側を上位ネットワークに接続し、LAN 側のポートと無線を下位のネットワークとして分離するのが常識的な構成のため、普通に設定可能だ。しかし、アクセスポイント(ハブ)として使おうとしたときに、設定画面からでは WAN 側 と LAN 側のそれぞれのポートを、同じネットワークセグメントにあるものとして扱うことができない(エラーとなる) そこで、LAN 側を既存のネットワークに繋ぎ、WAN 側が存在しない状態で、既存のネットワークを無線へと拡張する必要がある。そしてその方法は添付の書類や公式サイトには全く書かれていない。方法について、以下のエントリが大変参考になった。

awesometoast.com

開幕「添付書類を完全無視しろ」と書いてあって大変味わい深い。

電波どうするか問題

Archer C7 は 3x3 MIMO 対応なので、例えばチャンネルを固定してバンド幅増やしてみたいなことをするともうちょっと改善できる(今は自動設定)と思うが、まだその部分を煮詰められていない。

ファームウェアどうするか問題

openwrt / dd-wrt の両方存在する。

https://wiki.openwrt.org/toh/tp-link/tl-wdr7500

TP Link Archer C7 - DD-WRT Wiki

さすがに買った直後に博打するのはどうかと思うので、しばらく使って満足したらここら辺に挑戦してみたい。

Angular2 における Injector の話

ちょっと機会があってみんなで Angular2 + TypeScript TUTORIAL: TOUR OF HEROES を少しずつ読んで行く勉強会をやっているのだが、コンポーネントの依存性解決に関してかなり独特な世界観があったのでちょっとまとめる。

Dependency Injection (依存性の注入)って何?

依存性とは

あるクラスに特定の変数や定数、インスタンスが入ってしまっている状態。

class Car {
    engine:Engine = new HondaEngine();
    tire:Tire = new BridgestoneTire();
}

こんな例だと「この車はHONDAのエンジンとブリヂストンのタイヤに依存している」と言える。

これだと何が問題になるか

Car クラスの動き(特定のメソッド)をテストすることを考える。

  • HONDAのエンジンとブリヂストンのタイヤを用意しなければならない。
  • もしHONDAのエンジンを用意するのに10分かかると、このテストをする度に10分待たなければならない
  • テストする度にタイヤが摩耗して減ってお金がかかる場合、タイヤ回す目的でないテストにお金がかかることになる。

などいろいろ不都合がある。
実際の開発だと「ソシャゲの課金部分を実際にお金払う仕組みに依存したらテストが有料化した」みたいなことになりかねない。

注入ってなに

メソッドの引数で、クラスや変数などを外から受け取れるようにする

class Car {
    engine:Engine;
    tire:Tire;
    constructor(_engine: Engine, _tire: Tire) {
        this.engine = _engine;
        this.tire = _tire;
    }
}

こうすると、エンジンをTOYOTAにしようが、タイヤをピレリにしようが、それをコンストラクタの引数に指定することで車が組み立てられる。この過程が注入と呼ばれる。
こうして、この車が特定の部品に依存することなく走り出すことが出来るようになる。 テストする時も、理想的なエンジンのフリをする偽エンジンと理想的なタイヤのフリをする偽タイヤを用意することで、本当に Car クラスだけの挙動を見ることができる。
そのとき、もしも不具合が起こっても「エンジンやタイヤが悪いのかも」という心配をしなくて良くなる。

Angular の Dependency Injection

さて、次は Angular2 における Dependency Injection だが、実のところ チュートリアル ではいくつかある機能のうち1個しか使っていない。
まず使ってるものに関して説明する。

@Injectable() と Angular 内部のコンテナ

まず Angular の内部にはコンテナがあり、他のコンポーネント注入 するものを入れておくことができる。
前述の Car クラスだと、エンジンやタイヤのことで、チュートリアルだと HeroService が当てはまる。
@Injectable() でデコレートしたものを、Angularが内部コンテナに取り込んでくれる。

provider プロパティと Angular 内部のコンテナからの注入

@Component({
    ...
    providers: [HeroService],
    ...
}
export class AppComponent {
    constructor(_heroService: HeroService) { }
}

こんなコードで HeroService を Angular 内部のコンテナから取り出して AppComponent に注入したと思う。
これは実は下記のシンタックスシュガー(糖衣構文。ざっくり言うと省略記法のこと)である。

@Component({
    ...
    providers: [
        new Provider(HeroService, {useClass: HeroService})
    ],
    ...
}
export class AppComponent {
    constructor(@Inject(HeroService) _heroService: HeroService) { }
}

Provider とは何ぞ?

このクラスは、指定された何か(ここではHeroService)をコンテナからコンポーネント(AppComponent) に「どうやって注入するか」を管理するクラスだ。

new Provider(A, {useClass: B}) という形で説明すると

  • A: この Providerインスタンスに付ける名前(DIトークンと呼ばれる)
  • B: 注入するクラス名

になる。useClass の部分はいろいろ変えることができて、よく使うのは下記の3個くらいだと思う。
これらのうち、どれを指定するかによって、最終的に注入されるものや方法が変わる。

  • useClass:クラス名 指定したクラスからインスタンスを作って(new)注入してくれ
  • useValue:インスタンスやオブジェクト 指定したインスタンスやオブジェクトを注入してくれ
  • useFactory:関数 指定した関数から返される値を注入してくれ

ここで、useClass 意外のものを指定してるプロパティがクラス名でないということに注目してほしい。
実は、インスタンスじゃなくて変数や定数も注入できるし、関数を指定してその結果を注入するなんてこともできる。 ここで、同じProviderからは同じインスタンスやオブジェクトが必ず返されることを覚えておくといい。 useClass を使ったプロバイダを親コンポーネントと子コンポーネントから参照しても二度 new されることはなく、 Provider 内部にキャッシュされたものを参照する。
コンポーネントProvider がなければ、親コンポーネントProvider を参照するので、子コンポーネントに同じインスタンスを注入できる、ということだ。

@Inject とは何ぞ?

@Inject(HeroService) デコレータは、上で指定したDIトークンを指定して、 どの Provider から注入してもらうかを指定するものだ。

なんで省略できたの

  • Provider : そういう決まりだから。基本的に providers にクラス名だけ書いたら、DIトークンがクラス名と同じで、かつ useClass:クラス名 を指定したことになる。
  • @Inject(HeroService) : こっちには世界観というより的確な理由がある。DIトークンが引数のクラス名と同じである場合に省略できる。

やってみるといいこと

チュートリアル に関して、以下のようなことをして動きを確認すると良い。

  • 省略記法を Provider@Inject を使った書き方に変えてみる
  • DIトークンを変えてみて、正しく動くことを確認してみる
  • HeroServiceuseValue プロパティを使った書き方に変えてみる

寿司のスポンサーになりました

何言ってんのお前

Unicode コンソーシアムには里親( Adoptation )制度があり、スポンサーになると文字を一つ選択することで里親になることができる。選択した文字は Unicode コンソーシアムのサイト上 に自分の名前とセットで掲載してもらえるのだ。そこで僕は🍣を選び、1年間の期限付きではあるが🍣の里親、ブロンズスポンサーとなったのである。

どうして

"はじめに言葉ありき"というように、人間はそれを指し示す言葉がなければそれを認識できない。ただそれを認識したときに人がどうそれを受け入れるかというのはかなり怪しいもので、Unicode という統一を目指す文字コード体系は最終的に言語以上に文化の壁に当たるのではないかと思っている。実際、人アイコンの肌色で揉めたりとかは事実それなりに起きているし、今「犬を食べる」という絵文字や「鯨を捕まえて食べる」みたいな絵文字が入るとしたら、それを見たあらゆる人がそれを穏やかに受け入れてくれるなんて楽観的な考え方にはなれそうにない。Unicode コンソーシアムの仕事とは、言語の壁、文字の壁、そして文化の壁を世界中から取り払うことそのものであり、到底簡単なものではない。そしてそんな中🍣という文字があることにより、🍣の存在が世界から認知され、受け入れられ、長く存在できるということに対して何らかの貢献がしたかったとかそういうことはあまり考えていなくて、認定アイコンに🍣が乗ったら回転寿司の皿っぽくて面白いな、と思ったからだ。

スポンサー認定までの流れ

登録と支払い

  • Unicode コンソーシアムの Adopt ページ にアクセスする。
  • スポンサーになりたい文字を1個だけ選択して書き込む。文字そのものでもいいし、コードを書いてもよい。
  • 自分の名前を書く。ここに書いた名前をサイト上に掲載してもらえる。
    • ここに Twitter のスクリーン名を含めると、 @unicode がスポンサー告知ツイートをするときにリプライになるため便利である。いくつかそうしている人がいて大変賢いと思った。
  • スポンサードするレベルを決めます。
    • ブロンズ($100 - 無制限枠) : 希望すれば紙の感謝状が貰える
    • シルバー($1000 - 1字につき5枠) : ブロンズ特典に加え、希望すれば記念品がもらえる
    • ゴールド($5000 - 1字につき1枠) : シルバー特典に加え、メールで連絡すればサイト上の名前にリンク付けることができる
  • 希望するオプションを埋めたら Adopt ボタンを押して、メールアドレスやクレジットカード情報を入力する。

そのあと

  • 支払い直後にレシートメールが来る
  • 1営業日でサイト上に追加される
  • 2営業日で告知ツイートされる
  • と同時にコンソーシアムからお礼のメールが届く
    • そこにはブロンズ🍣スポンサーの透過pngアイコン(上記告知の画像と同じもの)が添付されている
  • 多分しばらくすると紙の感謝状が届く

まとめ

🍣だけにネタになるので、今のうちに乗っかっておくと面白いのではないかと思う。その際はぜひ🍣のスポンサーになって、届いた認定証画像をTwitterのアイコンに設定して、TLを回転寿司にしていきましょう。

イカとインターネット

これは何

イカをきっかけにかなり回線周辺を強化したので、それらについてちゃんとまとめます。

家の外のネットワーク

図1:概略図 f:id:Dolpen:20160229172646p:plain

どんなISPを選んでも大体こんな感じです。上から順に話をします。

まずIXって何よ

ISP が加入する上位の ISP みたいなものです。この IX も国内外にたくさんあり、それらが相互に接続してインターネットはできています。ISP ごとに契約も違って、IX と ISP を繋ぐ回線帯域も異なっています。ほとんどの場合、インターネットへのアクセスは IX を通して行われるので、この IX と ISP を繋ぐ回線帯域が細いと、 ISP の利用者が多い場合混雑しやすい、というのはなんとなくわかると思います。そういう ISP をクソとかしょぼいとか言うわけです。

日本だと JPIX とかがメジャーです

JPIX - 加入者一覧:お申し込み順

上記 JPIX への加入業者一覧を見ても分かるように、Google とかの巨大インターネットメガコーポは、自社データセンターなどのインフラを ISP を通すことなく、この IX と直接契約してインターネットにサーバーを接続しています。

回線業者の選定

というわけで、我々はしょぼくない ISP を選ぶ必要があります。改めて整理するとこんな感じです。

  • ISP 同士を繋ぐバックボーン(図1-1)が太いか(別 ISP のクライアントや国外との通信に影響、ISP によって契約帯域が違う)
  • ISP 自体の基幹ネットワーク(図1-2)が太いか(同 ISP 内のクライアント間の通信に影響)

とは言っても、回線をとっかえひっかえして個別に試すことは出来ないので
BNR統計情報 2015/10/01 - 2016/03/01
などの統計情報から当たりを付けておきましょう。

他にも、

  • 昼間は良いけど休日や夜間は遅くなる(家庭用のユーザーが多く、帰宅時間帯になると基幹ネットワークがパンクしやすい)
  • 回線障害が多かったり、サポートが雑

などのサービス品質に関する評判も調べておいた方が良いです。

良い場所に住む

現代科学ではどんな回線でも光の速さを越えることはできないので、そもそも情報を移動させる距離(図1-1〜3)を短くする、というアプローチは有効です。
ISP が決まったら、その ISP が接続している IX の拠点を調べておきましょう。東京都内であれば大手町や日本橋周辺、および品川などが多いと思います。
特定のホストに ping や traceroute などの問い合わせを送信し、その結果が帰ってくるまでの時間を RTT (ラウンドトリップタイム) と呼びますが、23区内など、なるべく IX に近い回線収容拠点に接続出来る場所に住むことで、 RTT が 5ms を切って 3〜4ms まで改善することが期待できます。多分ここら辺が物理限界です。

家の中のネットワーク

図1-4 以降の話です。

ブロードバンドルーターの選定

回線契約時によく送りつけられるブロードバンドルーターは結構な割合でゴミがあって、回線自体は 500Mbps くらい出るのに機器が 100MbE までしか対応してなくて遅い、みたいなことがあるので、ちゃんとしたのを買いましょう。
適切な GbE 対応のルーターを買って、回線契約時の書類に書かれた PPPoE の設定をしてしまえばよいです。ヤマハでもシスコでもバッファローでもかまわないです。

端末接続

次に端末接続ですが、無線はあまり考えないで、1000BASE-T 対応の物( NIC とか アダプタ とか ケーブル)をなるべく用意してください。なるべくとは言っても、WiiUの有線アダプタなどは 100Mbps が限界なので買いようが無いです。。。
そこそこちゃんとしているルーターであれば、どの規格でルーターと端末が接続しているかを見てくれるものもありますが、各機器はそこまで高くないはずなので、分からなければ買っちゃうのも手です。
ケーブルであれば cat5e 以上であれば GbE にも対応するので問題ないです。

ネットワーク設定

少なくとも有線機器は固定IPにしましょう。DHCP で IP アドレスを振られるがままにしてしまうと、

  • なにか障害があったときに調べづらい
  • DHCP には IP アドレスのリース(割り当て)期間があり、期間を過ぎると再割り当ての間ネットワークが瞬断する

など問題が起こります。

あと大事なのが MTU の設定です。 MTU というのは、パケットを送受信するバイト数の単位で、これをネットワークに接続する全機器で同じにしておくのは、パフォーマンスの改善に繋がります。WiiU は 1500 バイトずつパケットを送受信して、一方でルーターの送受信単位が 1400 バイトであるような不一致があると、ルーター側でパケットの分割展開、再分割などの無駄な作業が発生し、ネットワークのスループットが遅くなることがあります。

まとめと付録

通信系路上の一番性能の低いものに合わせて全体の性能が決まってしまうので、見直すポイントも多く、ネットワークが安定して繋がるのってかなりシビアで難しい物なんだなぁと痛感しました。ただ、ピュアオーディオみたいな質の幻想でなくて、光の速さという物理限界がある分幾分マシかなぁ。

最後に、家の中のネットワーク図です

f:id:Dolpen:20160226155738p:plain

青は光回線、緑は 1Gbps でリンク、オレンジは 100Mbps でリンクしています。回線業者はソフトバンクBBで、フレッツ網使ってるので先述の説明と構造が若干違うのですが、それでも IX まで ping が 4ms くらいです。
無線の親機はハブとして動かしていて、無線向けの DHCP や経路制御は RTX1200 側に一任することで、ダブルルータを回避しています。無線親機が GbE 非対応で 11ac もない古いものなので、近いうちにリプレースする気がします。