"possible SYN Flooding"その後の右往左往

"possible SYN Flooding"というログをみかけてからの迷走と調査の記録と結果について自分のための備忘録を失礼します。

## 迷走表(効果あるのは上の２つだけであとは焼け石に水）

|番号|対応概要|変更前|変更後|効果のほど|参考リンク|
|:--|:-----|:--------|:-------|:-----|:-----|
|1|fluentdのforwardのbacklogとOSのbacklog(tcp_max_syn_backlogとsomaxconn)を最大値まで広げた|fluentd:1024,os:8192|`65535`|変えた日は劇的改善するもELB側が再度パケットを握りつぶし始めた|[link](http://d.hatena.ne.jp/nyant/20111216/1324043063)|
|2|ELBをやめて直接配送|内部ELBをかましていた|直接配送|ELBのサージキュー上限とか気にせず再送してくれるようになった(まだ試験環境だけ)||
|3|tcp_syncookiesをやめてみた|1|0|焼け石にみずで大差なかった|[link](http://d.hatena.ne.jp/nyant/20111216/1324043063)|
|4|tcp_syn_retriesとtcp_synack_retries削減|5|3|再送が増えた（たぶん悪化な気がしている）|[link](http://serverfault.com/questions/294209/possible-syn-flooding-in-log-despite-low-number-of-syn-recv-connections)|
|5|tcp_fin_timeoutを短くしてみる|10|2|きもちnetstat -sのoverflowedの増加速度が鈍化||
||tcp_abort_on_overflow有効化|0|1|むしろ能動的RSTがふえるメリットが微妙そうで怖くて試せず試験環境でためしたところ大差なかった|[link](https://www.npa.go.jp/cyberpolice/server/rd_env/pdf/DDoS_Inspection_2.pdf)|
||ELBを作り直してみた|-|-|作り直すと直るという情報があって試したけどサーバ側の問題だったので効果なくむしろヘルスチェックの負荷が2倍になってやばそうだったのですぐ戻した|[link](http://blog.wacul.co.jp/blog/2014/07/24/elb/)|
||ip_local_port_rangeを広げる|||公式情報に従って広げて意味はあったつもりでいるけど特に状況の改善はしてない|[link](http://docs.fluentd.org/articles/before-install)|
||tcp_tw_reuse有効化|0|1|公式情報に従って設定してみたが大差はなかった(たぶん既にtcp_fin_timeoutが2だったせい)|[link](http://docs.fluentd.org/articles/before-install)|
||netdev_max_backlog|1024|65535|backlogつながりで増やしてはみたけどむしろTIME_WAITが増えた(synじゃなく全体を増やしたら余計な通信が増えてリソースの枯渇に拍車を？）||
||OS再起動してみる|||お察しのとおり付け焼刃的に直後だけ改善してすぐ元に戻った(昔定期リブートってあったな。。)||
||ELBの設定を大丈夫なtd-agent1側のELBにあわせて変える|||実はtd-agent2側がだめだったんです。Cross-Zone Load Balancingとかを無効化したものの意味がなかった||
とりあえずこのくらいで。

1についてですが、
・実施当日は劇的な効果がありELBの保持するサージキューの頭打ち状態が改善しspiloverCountも0になり握りつぶされるパケットはなくなったんですが、
OS側のclose_waitが激増（20万ちかく）してまたしてもELB側の状況が悪化してパケットが握りつぶされるようになりました。
ただ、netstat -sでみたoverflowedがどんどん増加していく現象だけはピッタリ止んだままでそこは改善したかと。
close_waitが非常に多い状態が継続するとよくないように見えた。

結果として、
試験環境で負荷試験したらELB介さなければパケットが握りつぶされることがなくログが再配送されて届くことがわかったので、ログ配送するのに内部ELBつかうのやめようぜ！！という方向に。

なんでtd-agent1が大丈夫でtd-agent2がダメだったのかは謎のまま。
違うことといえば2側はSSL通信も若干うけてたこととバージョンくらいでむしろさばいてる通信量は2側のほうが圧倒的に少なかったけど2側のほうが詰まっていた。
http://www.slideshare.net/repeatedly/fluentd-v012-master-guide

**fluentdとELBのTCPリスナーの相性は負荷が高いとログロストして最悪という結論に。**



## tcpのキューの見方

`/proc/net/tcp`を`cat`するとみれます。netstat -antとかだとその瞬間のやつが見切れないぽかった。

```
$ cat /proc/net/tcp |awk '{print $4}'|sort|uniq -c|sort -r|grep -v st|sed -e 's/ 01/ established/g' -e 's/ 02/ syn_sent/g' -e 's/ 03/ syn_recv/g' -e 's/ 04/ fin_wait1/g' -e 's/ 05/ fin_wait2/g' -e 's/ 06/ time_wait/g' -e 's/ 07/ close/g' -e 's/ 08/ close_wait/g' -e 's/ 09/ last_ack/g' -e 's/ 0A/ listen/g' -e 's/ 0B/ closing/g'
```

muninのコードとかみると監視的なツボがわかりやすくて参考になります。
https://searchcode.com/codesearch/view/67882452/

zabbixは2.2.4から"net.tcp.listen が、内部的に [/proc/net/tcp] の完全なリストを読み取っていない"問題は解決されてる模様
http://www.zabbix.jp/node/2652

## OSのbacklogの限界値について

16ビッドだそうで65535が最大値。うっかり65536にすると0を意味するようになるとか恐ろしいですね。
http://blog.yuryu.jp/2014/01/somaxconn-is-16-bit.html

この記事に興味があってみるような人は`sysctl`的な反映の仕方にはきっと興味がないと思うのですが一応、
`/etc/sysctl.conf`にかいて`sysctl -p`するとOS再起動しても消えない設定になります。
一時的に変えたい場合は`sysctl -w`とか。

## fluentdのbacklogの増やし方
```td-agent.conf
<source>
  type forward
  port 24224
  bind 0.0.0.0
  backlog 2048 #これを追加
</source>
```
変更後td-agentをrestartします。OSのbacklog変更後もtd-agentをrestartしないと反映されないようでした。

## tcpまわりのカーネルパラメータの意味調べ

・manみる
`man 2 listen`とか`man 7 tcp`とか`man socket`とかするとみれます。
たまにman更新忘れがあってソースみた人からこれないけどと言われて調べると本当に漏れてただけだったり。

・ぐぐりまくる
はてブのマイページがだいぶtcpとfluentdにまみれた。
tcp系
https://github.com/hiboma/hiboma/blob/master/kernel/net/net-backlog.md
http://ele-craft.blogspot.jp/2011/11/syncookieslisten.html
http://docs.fluentd.org/articles/before-install

結局、
tcp_syncookiesは圧倒的に受けきれない状況だと1でも2でもあんまり変わらず。

fluentd系
http://blog.livedoor.jp/sonots/archives/44690980.html
https://github.com/sonots/fluentd-scr/blob/master/01_out_forward_heartbeat.md
http://qiita.com/tatsu-yam/items/bd7006e483f3b3c64309


もっと山ほどあるんすけど気が遠くなったのでたぶんそのうち追記します。

## パケットキャプチャしてみた

```
$ sudo tcpdump port 24224 -s0 -w 20160317_dump.pcap
```
・ほんとは丸どりして全体の傾向みるのがいいらしいけど問題あるポートはわかってたしファイルサイズが大変なことになるのでポート指定で10秒前後をdump。
・Wiresharkで左下の丸をぽちるとAnalize>ExpertInfo的なのがみれてエラーパケットがどのくらいとかの傾向がわかるのでべんり。あとは統計サマリとか。
・再送が半分くらいでRST(リセット)もそれなりに多発してた。
・push(ログデータ送信してるぽい量のでかいやつ)がとてもすくなくて秒間100いかないかんじでほとんどheartbeat通信じゃないか疑惑が明るみに。

http://rpapaweb.com/network-wireshark-d/
http://raven.air-nifty.com/night/2009/08/wireshark-af0f.html
http://d.hatena.ne.jp/EijiYoshida/20080625/1214342918


## ELBの現象について
SurgeキューはELBが保持するキュー。最大1000まで保持してくれるけどそれ以上は配送をあきらめてSpiloverCountが増える。
SpiloverCountというのはELBが握りつぶして送ることができなかったリクエスト数。つまりロスト。
http://docs.aws.amazon.com/ja_jp/ElasticLoadBalancing/latest/DeveloperGuide/elb-cloudwatch-metrics.html#loadbalancing-metrics

受けきれなくなるとELBから外れるというのを繰り返してましたOutOfServiceとInServiceを繰り返す現象がでてた。
外れてる間に詰まった処理が流れてはいた風。

## 試験環境でdummerで負荷テストしてみた

・dummerつかって送って受ける側でwcでロスト状況をカウント
http://qiita.com/sonots/items/750da77a18e62852a02f

→ELBあるなしでロストがあるかどうかをざっくり→backlogがデフォでELBだとロスト
　backlog最大値だとどっちもロストしなかったが継続的負荷ではなかった（本番環境のELBは実際パケットが握りつぶされてた。）
→一時的なテストではELBなしの場合heartbeat_intervalが1sでも再送がなかった
　ただしheartbeat_typeがUDPだとRSTが多くてほとんどおくれてなくてhard_timeoutとかphi_threshholdにすぐ到達してしまい、
　heartbeat_typeがTCPならちゃんと送れるのでタイムアウトに達することはほぼなし。そのためheartbeat_typeがUDPならclose_waitでなくなりそうではあるけどTCPのままでいいんじゃないかと話題に。
https://github.com/sonots/fluentd-scr/blob/master/01_out_forward_heartbeat.md

## backendが詰まってるならプロセスやスレッドをマルチ化できないか説
マルチプロセスはできそうだったけどだいぶ少なめなSSL通信と分けるくらいしかなさそうで運用の手間をかんがみて却下に。
http://qiita.com/tatsu-yam/items/1bcd0116005f9434cd87
http://tech.mercari.com/entry/2015/12/15/170117

num_threadsあげるのはいいんじゃないの説は私の中で話題に。
（バックエンドのElasticsearchとかに投げてるぶんの処理の並列化的な。）
http://qiita.com/tatsu-yam/items/bd7006e483f3b3c64309
ただし誰も使っていない説も2013年の記事であってちょっとよくわからない。
http://kazegusuri.hateblo.jp/entry/2013/09/28/202504

## クライアント側の設定調整しようぜ的な参考情報

heartbeat_intervalとかphi_threshholdとか色々。
https://github.com/sonots/fluentd-scr/blob/master/01_out_forward_heartbeat.md
http://blog.livedoor.jp/sonots/archives/36895001.html
http://bynatures.net/wordpress/3104/

require_ack_responseを使うといいんではと負荷試験したところ高負荷時NWが不安定になると重複するケースも。
onだと秒間150行30秒間とかで重複なしだけど60秒間になるとack未受信による再送hard_timeoutが発生し、パケットロスはないが多少の重複が発生。
http://ogibayashi.github.io/blog/2014/12/16/try-fluentd-v0-dot-12-at-least-once/

s3に置いてincludeしたらrestartだけでちょっと楽かも説。
http://memocra.blogspot.jp/2013/05/fluentd.html

とりあえずELBやめてheartbeat_intervalは1sじゃなくてとりあえず2sに、heartbeat_typeはTCPのまま、
phiとかhard_timeoutはデフォ、require_ack_response設定しない、という感じで様子をみる方向。

以上になります。