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を見てね >未来のらるるさんへ

Linux memo 2020/12/29

● git cloneの高速化
$ git clone --branch --depth 1 --single-branch

● repoの場合
$ repo init --depth=1
$ repo sync -c
ブランチ切り替えたりgit diff, git logしたりする場合は、節約せずにちゃんとcloneしたほうがほとんどの場合は手っ取り早い。

● glibc-2.26のmallocのtcacheのメモリリーク
Bug 22111 - malloc: per thread cache is not returned when thread exits
https://sourceware.org/bugzilla/show_bug.cgi?id=22111
1スレッドあたり1回リークする。スレッドを何度も作る設計だとハマる。
glibcのmalloc()のメモリリークバグなのに世の中ではあんまり騒がれているように見えない。ユースケースがぶつからないから気にしないパターンが多いのかな。
修正は下記で。
https://sourceware.org/git/?p=glibc.git;a=commit;h=1e26d35193efbb29239c710a4c46a64708643320
(※元チケットでは「まだ直っていない」とコメントついているが(2020-10-10 07:23:03 UTCのコメ)、何度も繰り返さないと起こらないので、たいていはレアケースとして無視してもそれほど支障はない)

● NEON
NEONなにもわからずに奮闘していたのに、2020アドベントカレンダーでがんばって解説してくれる人がいた。
ひとりNEON Advent Calendar 2020
https://qiita.com/advent-calendar/2020/neon-only
もう少し早ければ(遅ければ?)よかったのに。

● ssh pass phrase自動化
- expect
- sshpass
- SSH_ASKPASS
- ssh-agent
まぁ、sshはセキュリティ上の穴になりがちなのでちゃんとしておくべきところになるため、パスフレーズなしにする(クローズドな環境)か、毎回手で打つか、ssh-agent使うか、かな。
パスワード認証?やさすがにそれは...
ちなみにsshレベルで圧縮する場合は、ssh -C, scp -C する。狭い帯域に大量にterminalログ流す場合やでかいファイル転送やの場合に役に立つ。

Linux memo 2020/11/15 (NEON)

NEONなんもわからん。

● ARM NEON 超入門
ARM Compiler toolchain Assembler Reference
https://developer.arm.com/documentation/dui0489/g/neon-and-vfp-programming/
ARM NEON Intrinsics - Using the GNU Compiler Collection (GCC)
https://gcc.gnu.org/onlinedocs/gcc-4.9.4/gcc/ARM-NEON-Intrinsics.html
SIMD Assembly Tutorial: ARM NEON (pdf注意)
http://download.xskernel.org/docs/processors/cortex-a53/neon_tutorial.pdf
ARM NEONの使い方 予告編 - おぺんcv
https://atkg.hatenablog.com/entry/2016/09/25/170031

● 超初心者のチート表
n: mov結果を半型にする
h: 計算後に2で割る
d: 計算後に2をかける
q: 桁あふれ時にオーバフローさせず上限張り付き
r: シフト結果を丸める
l: 計算結果の型を倍型にする
hn: 計算結果から上位半分取り出して半型にする
w: 計算元の片側が半型
q: 倍幅で計算

● 初心者の感想
- レジスタへのload, storeがめんどい。NEONフレンドリーなデータ構造・配列にしておかないと効率よくない
- 計算順は大事。積和(vmla)にしないと命令数増えて効率悪い
- 計算幅大事。64bitだとx2なので並列度が上がらない。オーバーフローをうまく処理して32bitのx4や16bitのx8にしないといけない
- パイプラインよくわからん。依存低い並びにしないと処理速度上がらないらしいが、その域はまだよくわかってない

Linux memo 2020/10/17

● CMAメモリ領域
CMA(contiguous memory allocator)は、DMAのように使えるメモリ領域を提供するが、そのメモリ領域を普段は通常の用途にも使えるように適合させたLinuxの汎用の仕組み。「MOVABLE」なメモリ割り当て要求のときに限りCMAメモリ領域を渡すようにしておくことで、いざ本当にCMA用途のメモリ割り当て要求が来たときでも、先に渡したメモリ割り当てをmigrateさせて「どかせる」ことで、CMA用途のメモリ割り当て要求にも応えることができるようにしている。
A reworked contiguous memory allocator [LWN.net]
https://lwn.net/Articles/447405/
A deep dive into CMA [LWN.net]
https://lwn.net/Articles/486301/
しかし、実際に使ってみると、そんな理想通りにはなかなかいかない。

● CMAの使いづらさ
Linux の CMA と THP その 1 - コグノスケ
http://www.katsuster.net/index.php?arg_act=cmd_show_diary&arg_date=20170929
より、まさにここで言及されているようなことが起こる。
- 1) THP に CMA 占領されちゃう問題
- 2) ユーザプロセスが CMA 全然使わない問題
それ以外にも、
- 3) cma開放時にpcpリストへ繋がれるためcma以外が空いててもCMAばかり使われ続けてしまう。
- 4) 大量のwriteでdirtyなページキャッシュがたくさんあるケースにて、いざCMAがほしいときにmigrateさせようとするとpage outでディスク書き込みが発生し長時間待たされてしまう
など。最近のLinuxでは改善が入っていたりしていて、1)にはCMA allocでTHPをmigrateさせる変更が、2)にはCMAが使われやすいくする変更が、3)にはpcp入りをやめる提案がされていて(これは結局採用されてない)、などがあるものの、どうも対応にアドホック感がある。ALLOC_CMAをなくす取り組みがrevertされてたりと、正直あるべき姿すらブレていて迷走している。
kswapd0とOOMの発動条件にも悪影響を与えているようで、正直CMAなんてやめて、昔からよくある専用メモリ領域を作って管理したほうが面倒事が少なくて済むように思えてならない。実は誰もCMAをマジメには使っていない?スマホがAndroiでION_HEAPとしてバリバリ使ってるって感じでもないのか?

● OOMの発生しづらさと発生時の予測不能なスラッシングやデッドロック
ケースごとに見ていけばいろいろとあるんだろうけど、下記でXFSにて起こる1例が提示されてる。
The OOM CTF
http://i-love.sakura.ne.jp/The_OOM_CTF.html
FilesystemやディスクI/Oが絡むと「成功してもらわないと困る」メモリアロケーションも多く、そことOOMに選ばれたプロセスへのSIGKILLが重なると、ライブロックや3者間ロックが容易に起こる。以前私がQiitaに書いたこの記事もそんな例の一つになる。
Linux+squashfs+swapなし環境でOOM時にハングする問題 - Qiita
https://qiita.com/rarul/items/843e05a7bc18278e3188
ちなみに、もとのCTF記事中にある「order が 3 以下のメモリ割り当て要求は成功するまで永遠にリトライする」は、PAGE_ALLOC_COSTLY_ORDERのことの模様。上記から言及されてるLWN.netの記事より、
The "too small to fail" memory-allocation rule [LWN.net]
https://lwn.net/Articles/627419/
LinuxのOOMやメモリ管理も、2.6.xやらのころと別物のように変わっているので、OOM発動条件すらが相当理解しにくい。スワップも複雑に絡む。下記の記事も参考に。
スワップの弁護:よくある誤解を解く
https://chrisdown.name/ja/2018/01/02/in-defence-of-swap.html

● ディスクによもsyncが必要な理由
ddコマンドではconv=fsyncなオプションが使えるが、of=がディスクの場合にもこれが必要なことがある。
最近のディスクはハードウェア的なwriteback機能を持っていて、それを積極的に利用するためdisk queueにも非同期で要求を突っ込めるようになっている。
CONFIG_BLK_WBT, QUEUE_FLAG_FUA, QUEUE_FLAG_WC, blk-wbt.c, あたりがキーワードか。

● zlib-ngなど
zlibとのバイナリコンパチと性能改善をうたうzlib-ngというライブラリがある。
https://github.com/zlib-ng/zlib-ng
プロジェクト自体は長く続いているので、適当に採用してもそこそこ使えるだろうと思って試していたら、なんてことはないアプリがクラッシュしやがる。仕方なくいろいろ調べると、arm64のchunkmemset_3()がバグっていることに気づく。報告でもしようかと詳細確認していると、ちょうど直前にchunkmemset_3()とchunkmemset_6()がバグってると削除されてた。プロジェクトがstableバージョンという概念を持ってないようだったので、結局採用するのはやめておいた。
ただまぁ、例えば画像でも、惰性でpngやjpegを使ったりせず、積極的に新しいものを試していかないといけないと思った。opting, zopflipng, brotli, webp, など。webpのlossyで十分だという理由からなのか知らないけど、JPEG 2000は今もほとんど聞かない。
libpng/libzのAPI互換を崩していい(フォーマット互換は維持)なら、minizとかlibspngとかもあるらしい。
https://libspng.org/
これまで何度も宣伝してきたけど、良記事なので、また宣伝しておく。
2016年のOSS圧縮ツール選択カタログ - Qiita
https://qiita.com/nishemon/items/818cc64dc2f8577edd87

Linux memo 2020/07/26

● ぼくのかんがえたさいきょうのmemcpy()
※ただしC言語に限る
https://github.com/rarul/algorithm_bench/blob/master/memcpy/common/memcpy.c
- 実用上は32bitか64bitの2か4のループアンローリングくらいで十分っぽい?
- gccの-O3だとヘタに自分で展開するより早かったりする、勝手にループアンローリングやってる?
- __int128のgcc拡張が使えるという知見を得た(gcc-4.4.7は使えなかった)
- alignment合ってなくてもCPUでなんとかしちゃうx86ずるい
- x86_64は、alignment乗ってると早いし、乗ってなくてもちゃんと動くし、alignmentチェックする価値がなさそう
- __int128は、x86_64でもalignmentエラーで落ちた
- 結局glibcのmemcpy()が一番早い、次点でgcc -O3
- asm使った最適化は猛者の総ツッコミが来そうなので語らないことにする

● その他
ネタはあったはずなのに最近やる気が出なくて作業が進まない...

Linux memo 2020/07/01

● ~(Tilde, チルダ)って何?
たぶんちゃんとしたUNIX規格とかあるんだろうけど、現状のLinuxとしては、
- 「~」(※\0含む)や「~/」はホームディレクトリを表す
- 「~strings/」は、/があるとこまでをユーザ名とみなして、そのユーザのホームディレクトリを表す
となる(bashのtilde.cあたり)
bashのいうホームディレクトリとは、
- 環境変数$HOMEのこと
- $HOMEが空のときは、getpwuid()とかで取れるやつ(==つまり/etc/passwdに書いてあるもの)
- bashはログインシェルとして振る舞うとき、起動時にgetpwuid()で取得したやつを$HOMEに設定する
となる。つまりすべてシェルのお仕事。
このため、自作プログラムとかにおもむろに「~rarul/memo.txt」とか書いても何もしてくれない。
あとこんなことができる
[rarul@tina bash-4.4.18]$ echo ~
/home/rarul
[rarul@tina bash-4.4.18]$ export HOME=hogehoge
[rarul@tina bash-4.4.18]$ echo ~
hogehoge

● ヌル島 (Null Island)
ヌル島 - Wikipedia
緯度0経度0はアフリカギニア湾の沖合いになるが、実装の都合上そこに何かがあったほうがいいということで設定された島。
ヌルオブジェクトパターンのようなイメージなのかな。
現在位置がここになっている技術者は世界中にたくさんいると思われる。

アイテム

月別 アーカイブ

ウェブページ

Powered by Movable Type 7.5.0