P2Pニコ動キャッシュ共有プロキシ実装案

このエントリでは、P2Pニコ動キャッシュ共有プロキシ実験結果(http://d.hatena.ne.jp/kanbayashi/20080101/p1)を読んだことを前提として話を進めます。


まずNico Cacheのおおまかな処理内容を書きますと

  • 1:ユーザがニコ動の動画ページにアクセス
  • 2:Nico Cacheがニコ動サーバとブラウザの通信に割って入る
  • 3:Nico Cacheがローカルの指定されたディレクトリ内にキャッシュされたflvファイルがないか探す
  • 4a:あればその内容をブラウザ内のFlash製動画プレーヤに送信
  • 4b:なければブラウザ内のFlash製動画プレーヤのストリームをニコ動サーバとつなげる


というようになっています。
で、私の作ったキャッシュ共有版では上記の4bの処理を以下のように変更したわけです。

  • 4b.1: 用意されたディレクトリサーバに尋ねて、対象動画のflvファイルを持っているノードを教えてもらう
  • 4b.2: 教えてもらったノードから、P2PSocketによって実現された通信路をつかってデータもらう
  • 4b.3: 受信したデータをファイルに保存
  • 4b.4: 元々の手順の3に戻る -> ダウンロードしたflvがあるはずなでそれがブラウザに返されることになる


私のとった方法はこのようになりましたが、結局のところ、欲しいflvファイルを対象ディレクトリに特定の規則に従ったファイル名で置いておけるようにさえすれば、実現方法は何だってよいのです。


そこで以下に挙げる実装案を考えてみました。
#考えただけ

DHTライブラリを使って真面目にやる

DHTとはDistributed Hash Tableの略称で、ネットワークで接続された複数ノードが連携して、効率的に一つのハッシュテーブルを構成する手法です。
#JXTA,Bittorrent,Limewireなども最近では採用しています


詳細は自分で調べていただくとして、簡単な説明をしますと、例えば、ノードAがキー"hoge"に対して値"bar"をputしたとすると、ノードBがキー"hoge"でgetすると値"bar"が手に入れられるという寸法です。


同様のことを今回の目的に合わせて行うと、あるノードが動画"sm11111"の部分ピース1を"sm11111-1"というキー、実際のデータを値として登録すれば、他のどのノードからもそのデータが、キー"sm11111-1"を与えることで入手できるようになるわけです。これができれば、上記の元手順の4bを置き換えるのは簡単ですね。


国内ではOverlay Weaver(http://overlayweaver.sourceforge.net/index-j.html)がよく出来ていて使えそうな感じです。
サンプルはMLでのやり取り(http://groups.yahoo.co.jp/group/overlayweaver/messagesearch?query=DHTTest)を読めばすぐ動かせるはずです。

Bittorrent*1を取り込む

上のDHTを用いる方法は真面目でよいですが、ピース単位でのダウンロード・アップロードを行う処理や、またそのスケジューリング処理を自分で書かなくてはいけないので、実装コストがそれなりに高いです。
しかし、それは面倒なので、こちらの方法ではそういった処理を既存のソフトウェア(Bittorrent)で済ませてしまう方法を考えます。


まずBittorrentですが、効率的なデータ配布手法の一つであるというのはご存知の通りですね。
こちらも詳細説明は省きますが、要は各プロキシがBittorrentでキャッシュのflvファイルをアップロード・ダウンロードしようということです。


これについては、コマンドライン

    • torrentファイルの生成
    • torrentファイルのトラッカーへのアップロード
    • torrentファイルを元にデータをダウンロード

ができるようなクライアント(未発見・・・)と

    • 非手動によるtorrentファイルのアップロードを受け付けるトラッカー*2

があれば、それらをプロキシから叩いてやるだけで簡単に実装できるはずです。
また、ライブラリがあればさらにスマートにできるでしょう。
普通のクライアント(AzureusとかBitcomet)を同時に使うようにして、プロキシからキック(torrentファイルを関連付けに従ってオープンするとか)してあげるという方法もありかもしれません(torrentファイルの生成とアップロードをどうするかが問題ですが)。


処理手順に従って説明しますと

    • 0:動画をニコ動サーバからダウンロードし終わったノードが、ローカルのflvファイルに対応するtorrentファイルを生成、トラッカー(誰かがグローバルIPを持つものを一つだけ用意しておく)にそれをアップロード
    • 1:動画を見たいノードは、トラッカーに欲しいファイルに対応するtorrentファイルがあるか問い合せる*3
    • 2:手に入れたtorrentファイルを使ってflvファイルをダウンロード
    • 3:ダウンロードしたflvファイルの内容をブラウザに返す

といった手順になります。


余談ですが、最近のクライアントでは、クライアント独自*4のDHTネットワークを持っていて、トラッカー無しでも動作させることが可能だそうです。それを使うとアーキテクチャ的に非集中になってさらに良い感じかもしれません。

UPNPを使う

実は、ユーザにルータのポートを開けさせることがOKなのであれば、今のものを実際に使えるレベルにすることは難しくありません。
一日もあればできるでしょう。
ただ、ブラウザで動画を見るだけなのにわざわざルータのセッティングをさせるなんてことは許容できないと考え、その方法は断念しました。


ですが、今のルータにはUPNPという機構がついていて、ソフトウェアで自動的に必要なポートを開けさせることができたりします。そして都合の良い事に、Javaで使えるライブラリ(http://www.sbbi.net/site/upnp/docs/natmappings.html)もあります。
これを使って実装するというのは悪くないかもしれません。
#IPがバレバレなのがちょっと難点ですが

キャッシュ用ディレクトリをWinnyのダウンロード・アップロードフォルダに設定する

2chのスレ(http://pc11.2ch.net/test/read.cgi/software/1192196662/)で提案されていました。
Winnyではルールベースでの自動ダウンロード(アップロードはどうせ勝手にやられたはず)ができるので確かに可能ですね。
#Winny自体のセキュリティの問題や、偽ファイルを流される問題などは解決しないとですかね
#使っているところを見られたらアレな感じだとか。。

Power Folderを使う

Power Folder*5というソフトウェアで、指定したディレクトリを複数人で同期させることができます。
そこで、それを使ってキャッシュディレクトリを同期させてしまいましょう。


しかし、そのままだとキャッシュディレクトリが大量の動画で溢れ返ってしまうので、再生数とアップされた日にちから、どれだけ見る確率があるかを求める評価関数を作って、プロキシから定期的に削除をかけてあげるとかしないと駄目ですね。


あと、部分キャッシュファイルはキャッシュ用ディレクトリと別のところで管理するようにしないと、それらも同期がとられてしまってまずいことになりそう。


懸念事項としては、Winnyの場合と同じように、変なファイルを対象ディレクトリに置かれると、それが他のユーザのディレクトリにもコピーされてしまったり、偽のファイルを掴まされたりする可能性があることでしょうか。
#正しいファイルを何人かが持っている状況で、同じ名前の違うファイルを持つユーザが現れたらどういう風に同期がとられるのでしょうね。


[PowerFolder 日本語 Wiki]
http://powerfolder.qp.land.to/


まとめ

実装案は出したので誰かやって下さい。
以上。

*1:http://ja.wikipedia.org/wiki/BitTorrent

*2:普通のトラッカーにPOSTするようなプログラムを書けばいい?

*3:そういったWebサーバもどきを自分で作らないといけないかもしれない

*4:各クライアントが勝手に実装してしまっているようですが。。

*5:bittorrentを内部で利用しているらしく、効率は良いのではないかと予想されます