TIME_WAITに関する話

6,301 views

Published on

TIME_WAIT のお話です。

Published in: Technology
2 Comments
9 Likes
Statistics
Notes
  • @Elder Darkover すみません。通知が来なかったので、気づくのが遅れました。ご意見ありがとうございます。 TimeStamp Option を使ったPAWSですが、こちら、https://tools.ietf.org/html/rfc7323#section-5.4 にあります通り、 "It is important to understand that the PAWS algorithm does not require clock synchronization between the sender and receiver." で、時刻同期を必要としません。wikipedia からの引用で恐縮ですが、送信される timestamp(TSVal)は https://ja.wikipedia.org/wiki/Transmission_Control_Protocol#TCP.E3.82.BF.E3.82.A4.E3.83.A0.E3.82.B9.E3.82.BF.E3.83.B3.E3.83.97 "TCPタイムスタンプはシステムクロックに合わせているわけではなく、無作為な値から開始する。" となります。 PAWSは、送信側が送った値を受信側が見て、送信側が送信したパケットの順番がわかればよいのです。また、 tcp_tw_recycle がNATなどと相性が悪いのはご指摘のとおりかと思います。ただ、本資料では tcp_tw_recycle ではなく tcp_tw_reuse という別の機能についての解説となりますので、 tcp_tw_recycle を利用するものではありません。以上、よろしくお願いいたします。
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • 興味深いお話で参考になりましたが、TaimeStampsに関しては送り側と受け側で時刻同期が正常に行われる前提かと思いますが、Windowsなどの仕様ではADのケルベロス認証に必要な精度(誤差5分以内が仕様)とかになり、かなりアバウトになると思います。また、tcp_tw_recyle利用は、ロードバランサやNATと相性が悪いので與検討かと思われます。
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total views
6,301
On SlideShare
0
From Embeds
0
Number of Embeds
3,027
Actions
Shares
0
Downloads
12
Comments
2
Likes
9
Embeds 0
No embeds

No notes for slide

TIME_WAITに関する話

  1. 1. TIME_WAIT に関する話 sejima
  2. 2. 免責事項 - 本資料において示される見解は、私自身の見 解であって、私が所属する組織の見解を必ずし も反映したものではありません。ご了承くださ い。
  3. 3. 自己紹介 - まぁまぁ MySQL でご飯食べてます - 一時期は Resource Monitoring や KVS にも 力入れてました - ネットワーク的には素人です - Linuxとハードウェアは嗜む程度 - disk I/O にはむかしから興味あります - その他 slideshare はこちら - http://www.slideshare.net/takanorisejima/
  4. 4. 本日のお題 - kernel 新しくしたりすると、TCP的に意識したほ うが良い変化が見つかるので - 今日は、Webアプリケーションサーバの観点か ら、 connect(2) する際に気になる TIME_WAIT について、書いてみようかと思います - 有識者からのマサカリを、強く歓迎いたします
  5. 5. 最初に参考資料 - この二つの記事を読んでいただけば、それで概 ね良いと思うんですが - Linuxカーネルの「TCP_TIMEWAIT_LEN」変更は無意味? - Coping with the TCP TIME-WAIT state on busy Linux servers - これらの記事をなぞりつつ、もうちょっと込み 入った話をしてみようと思います。
  6. 6. 対象とする環境 - Ubuntu 14.04 LTS - kernel 3.13 or 4.4 - 余談ですが、 EC2 で一番使われてるOSは、 Ubuntu らしいですね。 - Amazon EC2でもっとも人気のあるOSはUbuntu - なので Ubuntu を対象にするのは無難かなと思 います。また、16.04 LTS の GA kernel は 4.4 なので、応用効くと思います。
  7. 7. そもそも、 TIME_WAIT 溜まると 何が起こるのか?
  8. 8. 困ったときは
  9. 9. ソースコードを 読んでみよう
  10. 10. kernel 3.13 だとここらへん - tcp_v4_connect() から読んでくと - net/ipv4/tcp_ipv4.c#L223 - inet_hash_connect() - __inet_hash_connect() で inet_get_local_port_range() で connect(2) 時に割り当てできる Ephemeral port の range をとって、ひたすら for ループ回して、 空いてる port 見つからなかったら
  11. 11. return -EADDRNOTAVAIL; - ここに来るはず - inet_get_local_port_range() は net.ipv4.ip_local_port_range の min/max を返す関数 で、connect(2) したとき ip_local_port_range で指定し た範囲で port 割り当てられなかったらエラー。 - ESTABLISHED や TIME_WAIT で socket 大 量に開いてて Ephemeral port 割り当てできな いと、Linux 的には EADDRNOTAVAIL 返 す。
  12. 12. TCP 的になぜ TIME_WAIT はあるのか - 理由は二つあって、一つは a. FIN 受けた側(Passive Close)側が 、 FIN 送った (Active Close)側に FIN+ACK を返して、 LAST_ACK に遷移した後 b. Active Close 側が FIN+ACK への ACK を Passive Close 側に返したんだけど、 packet 落ちても c. Active Close 側が TIME_WAIT で待ってれば、 Passive Close 側が FIN+ACK 再送すれば、Active Close 側がACK再送できる(ACK来たら LAST_ACK から、 直ちに CLOSED に遷移できる)
  13. 13. 図に描くとこう
  14. 14. TCP 的になぜ TIME_WAIT はあるのか - もう一つは a. Active Close 側が送信した packet を、Passive Close 側が、(packet 落ちるかなんかして)受信できてない状 態になって b. その後すぐまた connect(2)し、同じ送信元 {ip,port} と 送信先 {ip,port} のセットで通信がはじまって c. a. で受信できてなかった packet がたまたま遅れてやっ てきて、それが TCP の sequence number 的にかぶっ てて packet が受けられてしまうと不味い
  15. 15. ただ、これらの問題は - RFC 7323 で定義されてる TCP Time Stamp Option と PAWS で回避できます。 - tcp header に timestamp つけることで、sequence number が一周しても、 timestamp を比較することに よって、受信側は古い packet かどうか判断できます。 - ただ Option なので、無効化されている環境もありえま す。 - ややこしい話なので後述します。
  16. 16. というわけで - これら二つの TCP 的な目的から TIME_WAIT という状態が必要で - TIME_WAIT で待ち続けている socket が多い 状態で connect(2) すると、 Linux は EADDRNOTAVAIL を返す可能性がある。 - そうであるならば、これら二つの TCP 的な目的 を満たしつつ、 EADDRNOTAVAIL が発生しな い状況にすればよい。
  17. 17. では、 アプリケーションを なるべく変更せずに EADDRNOTAVAIL を 回避するためには
  18. 18. はじめに大前提 - TCP 的に port が 2byte のデータなら、パブリッ ククラウド使ってるなら、インスタンスをスケール ダウンして数並べれば良いんじゃないかと思い ます。 - EC2 の c4.large でも c4.8xlarge でも、 TCP 的に使え る port が 0-65535 なのは変わらないわけです。 - あるいは、コネクションプーリングできるなら、そ れでも良いと思います。
  19. 19. ただそれでも - スケールアップして集約できることに、メリットが ある場合もあります。 - EC2 の c4.8xlarge は、使える vCPU が多いとか - 使っているインスタンス or サーバの数が少ないと、監視 などの面で楽だとか。 - というわけで、高性能なサーバを上手く使おうと するとき、 TIME_WAIT とどう付き合うか、とい うのを考えたいわけです。
  20. 20. ではどうするか 1. 先ずは Monitoring する。 a. kernel 4.4 にして、 Monitoring の精度を上げる。 b. Ephemeral port の使用状況をざっくり Monitoring す る。 2. ip_local_port_range を変更する。 a. (必要であれば)ip_local_reserved_ports を指定 3. net.ipv4.tcp_tw_reuse = 1 にする。 4. 接続先の MySQL や KVS を集約して、 tcp_tw_reuse で TIME_WAIT の socket を再利用しやすくする。
  21. 21. 1. 先ずは Monitoring する - (個人的に)継続的な Monitoring は、すべての 基本だと思うんで、先ずは Monitoring - TIME_WAIT の数をざっくり調べるには - /proc/net/sockstat の tw - なぜざっくりかというと、(少なくとも Ubuntu の) kernel 3.13 だと、 TIME_WAIT の socket が、 60sec (TIME_WAIT_LEN)経っても回収 されるとは限らないからです
  22. 22. netstat -o あるいは --timers - netstat には -o というオプションがあります - Include information related to networking timers. - kernel 3.13 で TIME_WAIT 多いサーバで次の コマンドを打つと、 timewait (0.00/0/0) がけっこ う残ってることがあるのですが - $ netstat -nato | egrep -c 'timewait.*(0.00' - これは TIME_WAIT を回収できるまでの残り時 間で、 60sec 以上経ってるから 0です
  23. 23. なぜ kernel 4.4 にすると良いのか? - kernel 4.4 の場合、 60sec 経つと、速やかに TIME_WAIT 回収されるようです。 - ただ、なんでこのあたりの修正が効くのかは、い まの私にはわかりませんでした。 - kernel4.1 で入ったこの patch で性能改善した 結果なんでしょうか?
  24. 24. お客様の中に LinuxのTCPプロトコルスタックに 詳しい方が いらっしゃいましたら、 教えていただけると幸いです
  25. 25. Ephemeral port をざっくり数える - Webサーバの場合、DBなどに接続するだけで なく、 Reverse Proxy とか ELB から接続され たりするので、それらをWebサーバから close(2) すると TIME_WAIT になりますが、こ うやって数えることができます - $ netstat -nat | grep -v '127.0.0.1' | egrep -c ' 1[0-9]+.[0-9]+.[0-9]+.[0-9]+:80 +[0-9]+.[0-9]+.[0-9]+.[0-9]+:[0-9]+ .*TIME_WAIT'
  26. 26. TCP:80 の TIME_WAIT を上手く除外 - connect(2) するときに EADDRNOTAVAIL 返 るのが困るなら - Web サーバが LISTEN してる TCP:80 で残っ てる TIME_WAIT(Reverse Proxy や ELB な どに対して close(2) して残った TIME_WAIT) を除外すると - connect(2) に影響する、Ephemeral port の TIME_WAIT を数えやすくなるわけです
  27. 27. 2. ip_local_port_range を変更する - LISTEN してる port と被らないなら、 ip_local_port_range を変更するのは確実 - kernel 3.13 では 32768 - 61000、 kernel 4.4 では 32768 - 60999 が default - 例えば、下限を 32768 から 24225 にするだけ で、使える Ephemeral port が約30%増加 - よく使われてる fluentd は default で tcp:24224 を使う ので、被らないように 24225。
  28. 28. net.ipv4.ip_local_reserved_ports - fluentd で tcp:24224 を LISTEN してるんだけ ど、net.ipv4.ip_local_port_range もっと下の range まで指定したいときは、 ip_local_reserved_ports に、 LISTEN したい port を列挙しておけば良いです。 - __inet_hash_connect() の中で予約された port を使わ ないように見てる ので
  29. 29. 3. net.ipv4.tcp_tw_reuse = 1 にする - ようやく出てきました tcp_tw_reuse - これについては Coping with the TCP TIME-WAIT state on busy Linux servers が最 高に良い資料で、ほとんどここに書いてあると 思いますが - いちおう触れておきます
  30. 30. tcp_tw_reuse が使える条件は? - TCP Time Stamps Option 有効な接続 - net.ipv4.tcp_timestamps = 1(default) で、client も server も TCP Time Stamps Option 有効 なとき - かつ、 source の ip と port、 destination の ip と port が一致してるとき - __inet_check_established() が INET_MATCH() でみ てる
  31. 31. ざっくり仕組みを書くと - source と destination の ip と port が一致した ら、TIME_WAIT の socket が使ってる Ephemeral port の再利用を試みるのだが - tcp_tw_reuse は「TIME_WAIT になって一秒 以上経過した socket」を再利用する - 何と比較して一秒と判断するかというと、 Active Close側がFIN+ACK受け取ったときの時間を見 てる
  32. 32. TCP的に問題ない範囲でTW切り上げる - Active Close 側が送信した最後の ACK が受 信できていた場合 - Passive Close 側に socket 残ってないので、 TIME_WAIT を一秒で切り上げてもOK
  33. 33. - Active Close 側が送信した最後の ACK が受 信できてなかった場合 - Passive Close 側は LAST_ACK で待っているが、(雑 にいうと) TCP Timestamps が効いて(PAWSが効い て)、SYN 再送しつつ connection 張れる
  34. 34. 雑に描くとこう SEQ = Sequence number TS = Time stamp ecr = Time stamp echo reply timestamp や sequence number はざっくりしたイメージ です。 実際のものと、ずらす値や桁数 は異なります。 例えば、tcp_tw_reuse で sequence number ずらすとき、 実際のソースコードでは +65535+2 されてます。
  35. 35. - PAWSというものが RFC7323 で定義されてい る。(雑にいうと)高速な回線では、 sequence number だけでは不充分。そこで TCP TimeStamps Option で TCP header につけら れた timestamp を見て、受信側は packet を破 棄したりできる。timestamp は 1msec ~ 1sec 間隔で更新されるのが RFC で良いとされるて いるので tw_reuse が一秒を基準にするのは
  36. 36. - TIME_WAIT に遷移してから 1sec 後に再利用 すれば、TCP header の timestamp が必ず更 新されており、遅延してやってきた (TIME_WAITなsocketを再利用する前の) packet があったとしても、遅延してきた packet は timestamp 古いから、受信側が破棄でき るってことではないかなぁ。たぶん
  37. 37. Time Stamp Option に守られてないと - LAST_ACK で待ってる Passive Close 側に SYN 送ると、 RST が返ってくる。 SYN_SENT で RST 受けると、 ECONNREFUSED になっ てしまう。 - TimeStamp Option が有効だと、 ACK の確認 して RST する前に、 PAWS で再送されるか ら、それで助かるって設計のようだ。
  38. 38. 4. 接続先の MySQL や(略) - tcp_tw_reuse は有効な手段だけど、 INET_MATCH() でマッチしないと使えないので - WEBサーバから見たとき、 接続先の DB や KVS が多いと、マッチしない可能性がある - よって、 tcp_tw_reuse を活用したいなら、接続 先の DB や KVS などの ip と port の組み合わ せは、少ないほうが望ましい
  39. 39. ただ、そもそもの話として
  40. 40. クライアントライブラリが、 そのソフトウェアで 定義されたプロトコルを 活用できてない可能性があります
  41. 41. COM_QUIT や quit - MySQL のプロトコルには COM_QUIT、 memcached には quit というコマンドがありま す - これらをクライアントから送ると、サーバ側から close(2) してくれるので、本来、 TIME_WAIT は mysqld や memcached 側にしか残らない のが正しいはずです
  42. 42. だがしかし
  43. 43. ここで MySQL の クライアントライブラリの ソースコードを 読んでみましょう
  44. 44. MySQL 5.7.18 では - mysql_close() では、 COM_QUIT 送ってから end_server() 呼んでるのだが、 COM_QUIT 送るところで skip_check flag 立ってるので、 recv(2) などされず に、最終的に shutdown(2) & close(2) されている。 - ということは、タイミング次第で RFC793の P.39 の Simultaneous Close Sequence になる可能 性がある。 recv(2) して欲しいなぁ
  45. 45. 残念ながら - COM_QUIT を送ってる client にも mysqld 側 にも、 TIME_WAIT が残ってしまう可能性があ る - じっさいこれ見たことあります。 Simultaneous Close Sequence に入っちゃってるのでしょう。
  46. 46. なので - Feature request を出してみました - https://bugs.mysql.com/bug.php?id=8635 6 - 直して欲しい方は、お手数ですが Impact on me: のところで Affects Me を押して頂けると助 かります。ボタン押すのに Oracle アカウントが 必要なんですが、無料でとれます。
  47. 47. といったところなんですが
  48. 48. 基本的に - DB や KVS に接続しまくるWEBサーバは、 tcp_tw_reuse 有効にすれば、 TIME_WAIT が 溜まっててもだいたい動くと思うけど - 次のような条件は環境によって異なるので、ど れくらい reuse できるかは環境依存 - WEBサーバが同時に connect(2) する数 - すなわち、 (thread や process の数) * (一回の requestで接続されるDBやKVS)
  49. 49. いろいろMonitoringしても難しい - /proc で TIME_WAIT は数えられるけど、 tcp_tw_reuse で再利用できる TIME_WAITの 数を数えるのは難しいので - まずは次の式を満たす範囲で運用して - (ip_local_port_range の 上限 - 下限) >= TIME_WAIT の総数 - どれくらい reuse されるかは、徐々に試せば良 いのでは
  50. 50. まとめ - TIME_WAIT の数が気になるなら、先ずはイン スタンスの数を並べてみては? - それでもスケールアップしたいなら、できれば kernel4.4 以降にして、 Monitoring しつつ、次 の設定を変えてみては - net.ipv4.ip_local_port_range - net.ipv4.ip_local_port_reserved_ports - net.ipv4.tcp_tw_reuse
  51. 51. おわり

×
Save this presentationTap To Close