http://www.jp.freebsd.org/QandA/HTML/1926.html

 Q. LAN 経由での Windows から FreeBSD へのデータ転送が、その逆に比べ  圧倒的に遅いです。Windows 同士だとこのような現象は起りません。

 A. 最大の理由は「Winsock2 は 2 packet 送信すると ack を待ってしまうから」です。

  Windows の TCP/IP 層はデフォルトでは 2 packet 送信する度にAck を待っ
  てしまいます。unix は TCP Window size にゆとりがある場合は「きっと
  向うはまだ送ってくるだろうから」と安心して piggy bag できる packet 
  がないか調べるために、10msec ほど沈黙します。当然一方向の通信 (RPC 
  とか) の場合 piggy bag などできるパケットが存在しませんので、この
  10msec の間、全くデータが転送されることがなくなります。

  Windows 同士の場合、受け側も「2packet 受け取ったら速攻で ack を返さ
  ねばならぬ」と思い込んでいるので、この「待ち」がほとんどありません。

  FreeBSD でこの問題を解決するには、sysctl で

  # sysctl -w net.inet.tcp.delayed_ack=0
   (デフォルトでは、net.inet.tcp.delayed_ack: 1)

  とすることです。こうすれば piggy bag できるかどうか悩むことなく、
  FreeBSD は ack を即座に返すようになります。

  ただし、この設定は「特定のコネクション相手」単位では設定できません。
  全体に有効になってしまいます。で、他の unix マシンと通信する場合、
  これは ack を投げすぎることになるので、逆にパフォーマンスを落す可能
  性が高いです。

  なお、この現象は [管理番号 1582] に似ていますが、異なる現象です。
  しかし、Winsock2 に起因するところは同じです。ただし、Windows 2000 
  (と多分 Windows Me) の Winsock2 では発生しないようです。

http://www.jp.freebsd.org/QandA/HTML/1582.html

Q. LAN 経由での FreeBSD から Windows へのデータ転送が、その逆に比べ圧倒的に遅いです。
Windows 同士だとこのような現象は起りません。
A. 一般的な解は、一般的な要因に依存するため、何とも判りませんが、次
  のような場合が Winsock2 の場合にあり得ることは判っています。

  一部の NIC では、NIC のせいなのか NIC Driver のせいなのかは不明で
  すが、Windows で使った場合に、時々 packet の取りこぼしが発生します。
  これは、NIC が用意している Recieve Buffer の大きさが、Winsock2 の
  Recieve Buffer よりも小さい場合、Winsock2 が NIC から packet を
  吸い出す前に NIC の Recieve Buffer が溢れてしまうために起るのでは
  ないか、と推測されます。

  Winsock2 の挙動を tcpdump などで見ると判るのですが、Windows 同士の
  通信において、Winsock は送信において次のようなルールに従っているよ
  うに見えます(これは、そう「見える」と言っているだけであって、そう
  「なっている」という意味で言っているのではありません。Winsock2 の
  実装がどうなっているのかは、そのソースコードを見ることができない以
  上、全く不明です)。

    I) 2つのマシン A,B があって、A->B というデータ転送しかない場合、
       A というマシンは
       Send, Send, Ack 待ち
       というパターンを忠実に守っているように見える。

   II) 2つのマシン A,B があって、双方向に転送すべきデータがある場合、
       A というマシンは

       Send(これには直前の Send に対する Ack を含んでいる),
       Data 待ち(これには直前の Send に対する Ack が含まれている)

       を繰り返す、というパターンを忠実に守っているように見える。

  III) I と II を切り替える際には 0.1 sec の wait が入る。


  もし、Windows 側の NIC のせいでこの現象が起っている場合は、
  Windows->FreeBSD 方向の通信には、この障害は出ていないはずです。
  (別の障害は出ているかも知れませんが :)


  さて、問題の解決方法ですが、ようするに上記の動きを FreeBSD 側で真
  似てやれば問題は解決します。具体的には TCP/IP の Send Buffer Size
  をどうにかして「IP Packet 2つ分」まで減らしてやれば、問題は解決す
  るはずなのです。そうすれば Winsock2 がそれを全て取り込み、Ack を返
  してくるまで先には進めません。

  「IP Packet 2つ分」が何バイトなのかを知るには、基本的には tcpdump
  を使うのが手だと思います。tcpdump は root であれば FreeBSD で使う
  ことができますし、
    WinDump <URL:http://windump.polito.it/>
  を使えば Windows 側で tcpdump を取ることもできます。これらを使って、
  mss の値を獲得します。これが「IP Packet 1つ分」の大きさだと思って
  ください。これを2倍すれば目的の値になります。

  あるいは、ethernet を使っている場合は、mss は大抵、536byte か 
  1460byte のどちらかです。ですので、その丁度2倍 1072byte かあるいは
  2920byte が「IP Packet 2つ分だ」という事ができます。ですので、
  2920 を使ってみて、駄目だったら 1072 を使ってみる、という手もあり
  ます。


  で、ここから先は FreeBSD の管理戦略にかなり依存します。


  1) システム全体を特定の Windows マシンに合わせる、という場合:

     この場合、 sysctl コマンドを使うと良いでしょう。root になって

       $ sysctl -w net.inet.tcp.sendspace=xxxx
       (#デフォルトは net.inet.tcp.sendspace: 32768)

     (xxxx は上記の「IP Packet 2つ分」の大きさ) を設定してみましょう。
     多分これでパフォーマンスは向上するはずです。

     ちなみに、
       $ sysctl -w net.inet.tcp.delayed_ack=0
     を設定すると Windows -> FreeBSD 方向の通信も改善される場合がある、
     という話があるそうです。


  2) Windows マシン毎に設定を変える場合:

     残念ながらマシン毎に FreeBSD の設定を変える場合、1 の場合のような
     汎用的戦略はありません。各アプリケーションが、それぞれ、自分が通信
     している相手を認識し、その適切な値をどこかのテーブルから lookup し
     なくてはいけませんが、そのようなサポートのないソフトもあるからです。

     もし、Samba に関して、というのであれば、smb.conf の中の
     [global] section の最後に

       include = /usr/local/etc/smb.conf.global.%m

     のような1行を加えておき、

       /usr/local/etc/smb.conf.global.<その問題の Windows マシン名>

     というファイル中で

       socket options = SO_SNDBUF=xxxx TCP_NODELAY
       (xxxx は上記の「IP Packet 2つ分」の大きさ) 

     を設定するとよいでしょう。上記の include 文は失敗しても smbd の
     起動に影響はありません。従って、特に特別な設定をする必要がない
     target に対しては

       /usr/local/etc/smb.conf.global.<その問題の Windows マシン名>

     というファイルを作成する必要はありません。このあたりは
       <URL:http://www.dd.iij4u.or.jp/~okuyamak/Documents/tuning.japanese.html>
     を参考にして下さい。

     この方法は Winsock2 についてしかチェックできていません。従って、
     Winsock1.1 の場合、あるいは将来できるであろう、Winsock2.1 (あるいは
     Winsock3) でうまく行くのかどうかは判りません。

     もし、現在すでにある程度パフォーマンスが良い場合、SO_SNDBUF の値を
     mss の整数倍にすることで、効率が向上する可能性があります。ですので、
     パフォーマンスを重視するマシンに対しては、そのマシン専用の

       /usr/local/etc/smb.conf.global.<その問題の Windows マシン名>

     ファイルを作った方がいいかも知れません。

     smb.conf には %a(Architecture) というオプションがあります。マルチ
     ブートマシンがある場合は smb.conf を

       include = /usr/local/etc/smb.conf.global.%m
       include = /usr/local/etc/smb.conf.global.%a.%M

     のように変更して、%a と %M で Client OS と Machine Name を指定して
     やると各 OS ごとの設定も可能になります。

トップ   編集 凍結解除 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2007-11-03 (土) 10:06:05