地方エンジニアの学習日記

興味ある技術の雑なメモだったりを書いてくブログ。たまに日記とガジェット紹介。

【Linux】net.core.(r|w)mem_maxあたりの話

概要

netstatの実行でたまに見るSendQとかRecvQの値の決定はどこで行っているかを確認した際のメモ

Send-Q/Recv-Qとは

Recv-Q
このソケットに接続されたユーザープログラムに渡されなかったデータのバイト数。  
Send-Q
リモートホストに受け入れられなかったデータのバイト数。  

manから抜粋。それぞれカーネルにデータはるけどアプリケーションで処理されていないデータ量を表している模様。send(2)の成功は相手への通信の成功じゃないみたいなイメージを持ってると意味はそれとなく理解しやすい。

Send-Q/Recv-Qの値はどこで決まるのか

答えとしてはソケットごとに設定するか設定せずにカーネルパラメータの値がそのまま入るパターンがある。setsockopt(2) の SO_RCVBUF, SO_SNDBUFなんかで設定すればその値が入るし設定しなければnet.core.(r|w)mem_defaultの値が設定される。

nxmnpg.lemoda.net

アプリケーションが適切にキューからデータを処理していれば問題になることはなくて高負荷状態でアプリケーションがいっぱいいっぱいのケースでこの値がmaxを超えるとパケットロストが発生する。

この値をいじることでデータをOSが保存しておく量が増えるがそもそもアプリケーションにボトルネックがあるのが明白ならこの値を買えるのではなくアプリケーションのチューニングが先になるはず。(インメモリなデータを大量にためたところでスケールアウトしづらくなるだけなので)

Send-Qについての注意

Send-Qの問題は、受信者が原因ではなく、送信者と受信者の間のルーティングの問題が原因である可能性がある。Send-Qに入ったが相手側が処理したAckを返してないのではなくAck自体がネットワーク設定によって帰ってないパターンの想定が必要。

また死ぬほど遅いクライアントが単純にデータのダウンロードが遅くAckを返せていないケースもある。(お昼の私のスマホなんかまさにそうかも。。。)。これ対策はアプリケーション側でするべきことでApacheなんかではSendTimeoutなんかいうパラーメータがあるらしい。

socketを設定するpythonサンプル

setsockoptはpythonでも触れるらしいことを知ったのでサンプル。(systemcallなのでcだけかと思ったがそんなことはないらしい。)

straceすれば当然だがsetsockoptをpythonから読んでいることを確認できる。(この程度のサンプルなら正直cで直接書いても良さそうな気はするけど。)

-bash-4.2# grep setsockopt  setsockopt
setsockopt(3, SOL_SOCKET, SO_SNDBUF, [1024], 4) = 0
setsockopt(3, SOL_SOCKET, SO_RCVBUF, [1024], 4) = 0
setsockopt(3, SOL_SOCKET, SO_SNDBUF, [4096], 4) = 0
setsockopt(3, SOL_SOCKET, SO_RCVBUF, [4096], 4) = 0
setsockopt(3, SOL_SOCKET, SO_SNDBUF, [1], 4) = 0
setsockopt(3, SOL_SOCKET, SO_RCVBUF, [1], 4) = 0
setsockopt(3, SOL_SOCKET, SO_SNDBUF, [1524280422], 4) = 0
setsockopt(3, SOL_SOCKET, SO_RCVBUF, [33554433], 4) = 0