勉強会用: Linux OS設定

以前書いたものを転載します。内容は古い可能性があるほか、文体が不適切かもしれません。

#ネットワーク系sysctl
ネットワーク系パラメータは、受信に効果があるのか送信に効果があるのか区別しないとわかりづらい。
どのサーバのどこに効かせたいのか、TCPの状態遷移図を見ながら考えるとよい。
LBの存在も忘れずに。 

##TCP & socket 基本↓
送信元IP:送信元ポート:送信先IP:送信先ポート
このquadruplet（4つ子)が重複すると接続できずエラーになる。

###net.netfilter.nf_conntrack_tcp_timeout_time_wait
####目的
高負荷のリクエストを受けた時、パケットの取りこぼしを防止する。

####症状
高負荷のリクエストに耐え切れない。`/var/log/messages`に `nf_conntrack: table full, dropping packet`と出力される。
カウント数は`cat /proc/sys/net/netfilter/nf_conntrack_count`

####解説
iptablesではconntrackモジュールを利用している。iptablesは通信セッションの状態をテーブルで保持しているが、そこが満杯になるとエラーが発生する。
TIME_WAIT状態のtcp接続をテーブルで保持する秒数を短くすることで、テーブルの使用量を減らす。
なお満杯になるのを防ぐ目的でip_conntrack_maxパラメータによってテーブルの最大容量を上げることが多いが、
iptablesで複雑な処理をしないかぎり不要。 FWでアクセス制限を担保することでiptables切るという方法もある。

####デメリット
iptablesでTIME_WAIT絡みの処理をしていると影響があるかも。
カウントする時`cat /proc/net/nf_conntrack`だとロックかかるかも

###net.ipv4.ip_local_port_range
####目的
リクエストを送信する数を増やすため、リクエストに使えるポート数を増やす。

####症状
リクエスト送信時、ポートが割り当てられないというエラーがアプリケーションログに出力される。

####解説
リクエストを送るときには、送信用に適当なポートを割り当てる必要がある。
リクエストが多い時にはポートが不足することがあるので、送信に割り当てることができるポートを拡張する。
ちなみに送信先のIP/ポートが異なれば、送信元ポートはそうそう枯渇しない。
送信元IP:送信元ポート:送信先IP:送信先ポートが重複したのが原因なので、
送信先のIP/ポートが異なれば、送信元ポートは重複しても問題ないため。
以下で検証してみよう！

```bash
sysctl  'net.ipv4.ip_local_port_range' # 現在の値を確認 
sysctl -w 'net.ipv4.ip_local_port_range=60995    61000'
# ここからcurl連打 
```

####デメリット
新しくアプリで接続待ちしようとしたポートが、たまたま送信に割り当てられたポートと重複する可能性がある。

###net.core.somaxconn
####目的
ソケットのacceptキューを増やして、高負荷時にリクエストが受信できなくなることを防ぐ。

####症状
高負荷のリクエストに耐え切れない。`netstat -s`でxxx times the listen queue of a socket overflowedが増えていく。

####解説
established済みでまだacceptされてない接続を、listenごとに最大何個までためることができるかを表す(backlog)。
backlog数はOSかアプリ設定の少ないほうが採用される。

####デメリット
backlog分すら受け付け不能なスペックのサーバだと処理しきれないかも？

###net.ipv4.tcp_max_syn_backlog
####目的
ソケットのSYNキューを増やして、高負荷時にリクエストが受信できなくなることを防ぐ。

####症状
高負荷のリクエストに耐え切れない。`netstat -s`でxxx SYNs to LISTEN sockets droppedが増えていく。

####解説
SYNを受け取ってreceivedだがまだestablishedではない接続を、listenごとに最大何個までためることができるかを表す(syn backlog)。
BSDはsomaxconnとtcp_max_syn_backlogは1つにまとまっているらしい？ 
実際のキュー数や受取可能数は謎計算式なので注意。効かせるためにはsomaxconnも上げる必要がある。 
[ありがたい解説リンク](http://wiki.bit-hive.com/linuxkernelmemo/pg/listen%20backlog%20%A1%DA3.6%A1%DB)

####デメリット
backlog分すら受け付け不能なスペックのサーバだと処理しきれないかも？

###net.core.netdev_max_backlog
####目的
カーネルがNICから受け取ったパケットを処理するまでためておけるキュー数を増やす

####症状
高負荷のリクエストに耐え切れない。
`cat /proc/net/softnet_stat`の2列目が0以外(maxを超えた量をカウントしている)

####解説
CPUごとにキューを溜めている。CPU多い場合、意識しなくてもあまり超えないかも？

https://access.redhat.com/sites/default/files/attachments/20150325_network_performance_tuning.pdf

####デメリット
??

###net.ipv4.tcp_tw_reuse
####目的
TIME_WAITのコネクションを使い回すことで、新しいリクエストを送信できるようにする。

####症状
該当サーバから別のサーバAへのリクエストについて、TIME_WAITがやたら多い。
別のサーバAへのリクエストができない。 

####解説
新しいコネクションを作るときに(outgoing)、その接続と同じ接続元接続先がTIME_WAIT状態だとコネクションが作れない。
tw_reuseを1にすることで、その重複したTIME_WAITを上書きして新しくコネクションを作ることができる。
情報が錯綜しているので注意。

* [わりと信用できそうなTIME_WAIT解説](http://vincent.bernat.im/en/blog/2014-tcp-time-wait-state-linux.html)
* [reuseの実験](https://www.percona.com/blog/2014/12/08/what-happens-when-your-application-cannot-open-yet-another-connection-to-mysql/)

TIME_WAITにはtcp接続を切断した側(active close)がなる。
大体の場合リクエスト元がtcp切断しようとするのでTIME_WAITになる。 

####デメリット
tcpのtimestampが正しく入っていれば特にない。

###net.core.rmem_max / net.ipv4.tcp_rmem
####目的
受信ソケットの読み込みバッファを増やす

####症状
受信するサーバについて、`netstat -s`でxxx packets pruned from receive queue because of socket buffer overrunか
xxx packets collapsed in receive queue due to low socket buffer がでる。

解説
tcpの場合はnet.ipv4.tcp_rmemが優先。これらの値の使われ方はアプリケーション(ミドルウェア）の作りによる。

デメリット
増やしすぎると状況によってはbufferbloatによる輻輳が起きる可能性あり

##その他sysctl
###vm.swappiness
####目的
OSによるスワップ頻度を減らし、メモリをなるべくアプリケーションに割り当てるようにする。

####症状
急に重くなる。スワップがやたら多い。DBサーバでスワップが発生してしまった。

####解説
スワップ自体に必ずしも問題があるわけではない。
メモリにデータを大量にのせる必要があるアプリケーション(DBなど)は、スワップすると大きい影響があるので、
スワップ頻度を下げる必要がある。

####デメリット
`swappiness = 0` は最近のkernelでは、まずswapしないので、OOMでプロセスダウンの可能性が高まる。
`swappiness = 1` がよさげ。 

##limits.conf 90-nproc.conf
####nproc
```
cat /proc/`pgrep mysqld$`/limits | egrep "(processes|files)"
```

kernel 2.6.32からオンラインでプロセスの制限を変えられるみたいです

```
echo -n "Max processes=SOFT_LIMIT:HARD_LIMIT" > /proc/`pidof mysqld`/limits
```

#参考リンク

* [kernel設定読み解き](https://github.com/hiboma/hiboma/tree/master/kernel/net)
* [conntrackについて](https://gist.github.com/shtwave/5162614)
* [通信V字](http://ps-2.kev009.com/wisclibrary/aix51/usr/share/man/info/en_US/a_doc_lib/aixbman/prftungd/2365c91.htm)