2021年1月アーカイブ

Linux memo 2021/01/09(Fri) ネットワーク雑多編

● TCPが遅延する話
TCPではいわゆるショートパット問題による輻輳を防ぐためのNagleアルゴリズム(RFC 896)がある。が、適当にTCP送受信してしまうとこれが遅延悪化を起こしてしまうことがある。例えば下記の例など。
俺の MQTTブローカー がこんなに遅いわけがない - Qiita
https://qiita.com/ryskiwt/items/551f5ad60d8c4cd14588
理由は、Nagleアルゴリズムとdelayed acknowledgmentとの相性が最悪だから。詳細はこのへんに詳しい。
Nagleアルゴリズムと遅延ACK - それが僕には楽しかったんです。
https://rabbitfoot141.hatenablog.com/entry/2018/11/18/003606

● Nagleアルゴリズムの無効化
setsockopt()でTCP_NODELAYを有効にするとNagleアルゴリズムを無効にできる。無効にするとショートパケット問題が生じるが、これはアプリケーションプロトコルレベルで対処したほうが手っ取り早い。具体的にはwrite()やwritev()システムコールで一度にたくさん送信するようにすればよい。
ググると「/proc/sys/net/ipv4/tcp_low_latency でグローバルに設定できる」と記したページがいくつか見つかるが、man 7 tcpにある通り、Linux-4.14からこのパラメータは何の意味も持たなくなっている(Linuxのソースコードも確認済み)

● delayed acknowledgmentの無効化
setsockopt()でTCP_QUICKACKを有効にするとdelayed acknowledgmentを無効にできる。ただし、無効にした場合、ACKと応答パケットを同時に送ったり、受信ウィンドウを効率よく使ったりすることができなくなる。結局これも、アプリケーションプロトコルレベルで応答を必要とするケースを減らしたり、スループットを求めるコネクションは別ソケットにする、などの対策が必要になる。

● 遅延量を調整できないの?
Nagleアルゴリズムはそもそも遅延する時間という概念を持っていない。
networking - How to set nagle timeout in linux kernel? - Server Fault
https://serverfault.com/questions/836675/how-to-set-nagle-timeout-in-linux-kernel
delayed acknowledgmentの遅延時間はLinx kernelが動的に決める。linux/include/net/tcp.hの「TCP_DELACK_MAX」「TCP_DELACK_MIN」がそれに当たる。40msecから200msecでスケールする(今どきのcpu archだと HZ はほぼ100以上のため)

#define TCP_DELACK_MAX ((unsigned)(HZ/5)) /* maximal time to delay before sending an ACK */
#if HZ >= 100
#define TCP_DELACK_MIN ((unsigned)(HZ/25)) /* minimal time to delay before sending an ACK */
#define TCP_ATO_MIN ((unsigned)(HZ/25))
#else
#define TCP_DELACK_MIN 4U
#define TCP_ATO_MIN 4U
#endif
コードの方を見た感じ、スケールのさせ方にもいろいろ手が入っているようで、おいそれと簡単に変更できる実装にはなっていない。非常によくわかっている場合を除いてパラメータを変更するのはおすすめできない。

● 他のアプローチ
逆の、積極的に送信を遅延させるTCP_CORK(setsockopt()で設定)というオプションがある。TCP_NODELAYを有効にしたままTCP_CORKのON,OFFを切り替えることで、TCPを実際に送信するタイミングを調整することができる。もちろんMSSも意識しないといけない。ので、結局は、TCP_CORKなんて使わずに、ユーザランドでバッファリングしてwrite()システムコールで一度にたくさん書いたほうが手っ取り早いのかもしれない。

● TCPのタイムアウト
「SO_SNDTIMEO, SO_RCVTIMEOが使える」と書いたページも見つかるが、Linuxのコードを読む限り、これらはsocket全般に広く効くものの、ことTCPに関してはこれらは使われないように読めた。TCPは代わりにTCP_USER_TIMEOUTで設定するというように見える。でもごめんちょっと自信ない、誰か本当のとこ教えて。

● tcp keep alive
再送やらタイムアウトやらヘタに頑張ってほしくないと思いTCP_KEEPCNT, TCP_KEEPIDLE, TCP_KEEPINTVLを設定する例もたくさん見られる。が、やっぱりワナがあるようで、設定しといたほうがいいものの、過信はしないほうが良さげ。
TCPとタイムアウトと私 - Cybozu Inside Out | サイボウズエンジニアのブログ
https://blog.cybozu.io/entry/2015/11/26/170019
結局、アプリケーションプロトコルレベルでも検知して後始末する系をケアせざるを得ないようだ。

● ApacheのTCP_NODELAYの状況
Nagle algorythem / TCP_NODELAY をまとめる - Qiita
https://qiita.com/uturned0/items/3ab037d4d2d0500586f5
ではApacheがNagleアルゴリズムをどうしているのかわからないと記載されているが、コード見た感じ、問答無用でAPR_TCP_NODELAYを設定しているようですね。

● nginxのパフォーマンス
Apacheに比べて静的コンテツの配信に強いとされるnginx、その理由はApacheがpreforkなのに対してnginxはイベント駆動だ、とか書かれたページがいくつか見つかるものの、どうもそれだけじゃイマイチ納得できなかった。REUSEPORTとかが効いてんのかなと持って調べてみると、その程度の話ではなく、もはやcontext switchやCPU cache lineのレベルで性能差が出ているという話の模様。そのレベルまで性能引き出せているなら、確かに、無駄にプロセスやスレッドを増やしたりせず、CPUコア数に応じただけの数のworkerをぶん回らせた方が早そう。でもそれ、ネットワークやディスクがボトルネックじゃないという前提も必要よね。このへんに詳しかった。
linux - Is Nginx's approach to CPUs scalability (per process epoll event queue) optimal? - Stack Overflow
https://stackoverflow.com/questions/62234057/is-nginxs-approach-to-cpus-scalability-per-process-epoll-event-queue-optimal
Why does one NGINX worker take all the load?
https://blog.cloudflare.com/the-sad-state-of-linux-socket-balancing/

● その他(過去の記事)
Linux memo 2019/11/22
https://www.rarul.com/mt/log/2019/11/linux-memo-2019-8.html
TIME_WAIT関連のメモ
https://www.rarul.com/mt/log/2018/01/time-wait.html

● その他(ネットワークですらない雑記)
LD_BIND_NOWという環境変数が使える。man ld.so(8)とか、見たことないパラメータがいっぱいあるな...このうちどれが実用的なやつなのかも正直よくわからん。

Linux memo 2021/01/03 CentOS Stream 8 編

● 前置き
長い間塩漬け運用していたCentOS6がEOFになっちゃったので移行することにした。CentOS 8はプロジェクトを中止する予定だし、別のRHELクローン立ち上げはまだまだ時間かかるだろうし、ということで素直にCentOS Stream 8を移行先に選んだ。

● dnf
yum から dnf に変わった
オプション類がだいたい一緒なのでノリでそのまま使える。

● selinux
どうして人はみなselinuxを無効にしてしまうのだろうか(自戒を込めて)
/etc/selinux/config
SELINUX=disabled

● 公開鍵の暗号強度の確認
ssh-keygen -l -f ~/.ssh/authorized_keys
昔作ったのが RSA 1536 だったので、作り直すことにした。オプションなしに作ったら RSA 3072 になった
ちなみに、ssh-keygenで作ったときのファイルの id_rsaが秘密鍵、id_rsa.pubが公開鍵、「わからないから両方送ります」とかしないように

● firewalld
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --reload
firewall-cmd --permanent --new-zone=rarullocal
firewall-cmd --permanent --zone=rarullocal --set-target=ACCEPT
firewall-cmd --permanent --zone=rarullocal --add-source=192.168.0.0/16
firewall-cmd --permanent --zone=rarullocal --add-service=samba
firewall-cmd --reload
AllowZoneDriftingがどうとか怒られるので、マルチゾーンにならないようにした上で、
/etc/firewalld/firewalld.conf
AllowZoneDrifting=no

● sshd
/etc/ssh/sshd_config
Port [NewPort]
PasswordAuthentication no
パブリックサーバだと最近はつつくやつが非常に多いので、ポート番号変えた上でパスワード認証なしくらいにしとかないと怖い。

● dnsmasq
/etc/dnsmasq.conf
domain-needed
bogus-priv
local=/www.rarul.com/
/etc/hosts
192.168.123.234 www.rarul.com

● chronyd
#pool 2.centos.pool.ntp.org iburst
server YOURSERVER iburst
allow 192.168.0.0/16
port 123
(port 123 は、ntpdを内部公開したい場合に)

● Apache(httpd.conf)
あんま晒したくないので部分的に、、
 ※ 2021/02/02訂正、.gitはディレクトリなので、FilesでマッチさせるのではなくてFilesDirectorymatchでマッチさせる。
/etc/http/conf/httpd.conf
<FilesDirectorymatch "^/.*/\.git/">
Require all denied
<Files/Directorymatch>
#AddDefaultCharset UTF-8
ExpiresActive on
ExpiresDefault "access plus 3 minutes"
ExpiresByType image/gif "access plus 1 days"
ExpiresByType image/png "access plus 1 days"
ExpiresByType image/jpg "access plus 1 days"
ExpiresByType image/jpeg "access plus 1 days"
ExpiresByType image/ico "access plus 1 days"
ExpiresByType image/x-icon "access plus 1 days"
ExpiresByType image/vnd.microsoft.icon "access plus 1 days"
ExpiresByType text/css "access plus 1 days"
ExpiresByType text/javascript "access plus 1 days"
ExpiresByType application/x-javascript "access plus 1 days"
ExpiresByType application/javascript "access plus 1 days"
ExpiresByType audio/mp3 "access plus 1 days"
AddOutputFilterByType DEFLATE text/plain text/html text/css
AddOutputFilterByType DEFLATE text/xml application/xml application/xhtml+xml
AddOutputFilterByType DEFLATE application/rss+xml application/atom+xml application/rdf+xml
AddOutputFilterByType DEFLATE text/javascript application/x-javascript application/javascript

/etc/httpd/conf.d/ssl.conf
の SSLCertificateFile, SSLCertificateKeyFile を Let's Encryptに合わせて変更。
warningログがうざかったので使う予定ないモジュールをコメントアウト
/etc/httpd/conf.modules.d/00-proxy.conf
#LoadModule lbmethod_heartbeat_module modules/mod_lbmethod_heartbeat.so

● .htaccess
order deny,allowとかSatisfy AnyとかがApache-2.4から使えなくなったんでその置き換えで。
AuthUserFile /home/rarul/.htdigest
AuthGroupFile /dev/null
AuthName "for members only"
AuthType Digest
<RequireAny>
Require all denied
Require user [USERNAME]
Require ip 192.168. 127.0.0.1
</RequireAny>
Digest認証はmd5なのでそれほど強度強くない。HTTPS化が大前提として、本気で認証したいなら...なにがいいんだろ。HTTPSなら他のid/pass方式でも大差ない気がしてきた。

● MariaDB
vi /etc/my.cnf.d/client.cnf
[client-mariadb]
default-character-set = utf8mb4
データベース作るときに明示的にデフォルト文字コードを設定
create database YOURDB character set utf8mb4;
それでも、phpからアクセスするときに SET NAMES utf8mb4 しないと化けることがあったけど、正直良くわからんし、SET NAMES utf8mb4 すればよいから、もう原因追求諦めた。
utf8mb4じゃない文字コードで作ってしまったDBは、潔くutf8mb4じゃない文字コードのまま運用したほうが無難げ。(特にutf8とutf8mb4との違いには要注意) 文字コードをutf8mb4に変換したい場合は、移行作業とは別の機会を構えたほうがよいと思う。これでようやくSET NAMES binaryを卒業できた。
あとマジメにチューニングしてないけどRAM余り気味のサーバなので適当に盛っといた。
/etc/my.cnf.d/mariadb-server.cnf
[mysqld]
hread_cache_size=16
query_cache_size=128M
sort_buffer_size=8M
join_buffer_size=64M
read_buffer_size=1M
read_rnd_buffer_size=2M
myisam_max_sort_file_size=64M

● PHP
ereg -> preg_match
mysql_connect -> mysqli_connect
mysql_query -> mysqli_query
mysql_real_escape_string -> mysqli_real_escape_string
mysql_fetch_assoc -> mysqli_fetch_assoc
mysql_free_result -> mysqli_free_result
mysql_close -> mysqli_close
他にもあった気がするけど、まぁ似たようなノリでなんとかなるでしょ。

● Let's Encrypt
/etc/letsencrypt/を移行しておいた上で、certbot-autoをダウンロードして実行するだけ、あとは全部勝手にやってくれる。すごい。

● その他(省略したとこも含めて)
centos8stream.txtを見てね >未来のらるるさんへ

このアーカイブについて

このページには、2021年1月に書かれたブログ記事が新しい順に公開されています。

前のアーカイブは2020年12月です。

次のアーカイブは2021年3月です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

月別 アーカイブ

ウェブページ

Powered by Movable Type 7.5.0