はじめに
この記事はisucon本の9章の内容をまとめたものになります。要点を抑えている(つもり)なので是非ご覧ください
Linuxとは
LinuxとはOSの一種でありオープンソースのOSです。それゆえに様々なユースケースで用いられています。Linuxではカーネルパラメータというパラメータがあります。これによってコードを書き換えずともカーネルの挙動を変えることができます。
Linux Kernel
Linuxは、OSとしてのコア機能をLinux Kernelと呼ばれるソフトウェアが担っています。OS上で動作するアプリケーションはシステムコールと呼ばれる命令を用いてLinux Kernelの機能を利用しています。
以下はアプリケーションからシステムコールする際の図です。
レイヤー | 説明 |
---|---|
ユーザー空間(ユーザーランド) | アプリケーションが動作する領域のこと。ユーザーが直接操作するソフトウェアやプログラムが実行される |
システムコールインターフェース | アプリケーションとOSのカーネル部分の間に設けられたインターフェース。 |
カーネル空間(カーネルランド) | Linuxカーネルが動作する領域。ハードウェアリソースの管理や制御を行い、ユーザー空間からのリクエストを処理します。 |
アプリケーションからLinuxを操作する場合にはシステムコールインターフェスを介して操作します。そのため、ハードやソフトの事情に引っ張られずにシステムコールができます。
Linuxのプロセス管理
プロセスとスレッド
ユーザー空間で操作されるアプリケーションは全てプロセスとして扱われます。プロセスはpsコマンドをで出力できます。以下の例ではpsコマンドに-efオプションでプロセスとその親子関係を出力させた例です。
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 Nov30 ? 00:00:05 /sbin/init
root 58 1 0 Nov30 ? 00:00:01 /usr/lib/systemd/systemd-journald
root 75 1 0 Nov30 ? 00:00:00 /usr/lib/systemd/systemd-udevd
root 101 1 0 Nov30 ? 00:00:00 /usr/lib/systemd/systemd-logind
root 150 1 0 Nov30 ? 00:00:00 /usr/sbin/cron
root 210 101 0 Nov30 ? 00:00:00 /bin/bash
プロセスにはIDが振られます。PIDがそのIDです。Linuxでは最初にinitというプロセスが呼び出され、initが子プロセスを生成します。プロセスには親子関係があり、PPIDが親のプロセスIDになります。この場合は以下のような親子関係があります。
プロセスを生成するとプロセスごとにマシンのリソースが確保されます。このとき基本的に他プロセスのリソースにアクセスすることができません。一方プロセスにはスレッドという概念もあります。スレッドはプロセスの中で並行実行できるタスクの概念です。一プロセスには一つ以上のスレッドがあります。スレッド間ではリソースを共有できます。スレッドが複数あることをマルチスレッドといいます。
Linuxのネットワーク
例としてhttpリクエストを受け取る場合について説明します。
説明 | |
---|---|
NIC | ネットワークからのパケットを受信し、OS(カーネル)に渡す。 |
Linuxカーネル | 受信したパケットを処理し、Webサーバーに渡す。OSの中心的役割を果たす。 |
Webサーバー | パケットのデータをもとにHTTPリクエストを解析し、応答を生成する。 |
httpリクエストをNICが受け取るとNICはLinuxCarnelにパケットを送信します。このとき、あくまでhttpリクエストとしてではなくパケット単位で送信し、カーネルを通じてwebサーバに届きます。
スループットとレイテンシ
ネットワークの計測において大事な二つのメトリクスを紹介します。
メトリクス | 説明 |
---|---|
スループット | 一定時間で処理できるパケットの量を示します。 |
レイテンシ | 通信を開始してから終了するまでの所要時間を指します。 |
この二つのメトリクスはどちらも重要なメトリクスです。スループットが大きくてもレイテンシが高いと通信に時間がかかるのは変わりません。逆にレイテンシが低くてもスループットが小さいということは処理が非効率であることを示します。
スループットとレイテンシはこのような判断ができる重要なメトリクスです。
CPU利用率
cpuの利用率を確認するにはtopコマンドを使用します。
topコマンドの見方
top - 12:34:56 up 3 days, 5:45, 2 users, load average: 0.12, 0.08, 0.10
Tasks: 162 total, 1 running, 161 sleeping, 0 stopped, 0 zombie
%Cpu(s): 5.5 us, 2.3 sy, 0.0 ni, 91.5 id, 0.7 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 7982.6 total, 1024.0 free, 4096.0 used, 2862.6 buff/cache
MiB Swap: 2048.0 total, 2048.0 free, 0.0 used. 3586.5 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1234 myuser 20 0 123456 65432 5432 S 5.0 0.8 0:12.34 myapp
5678 root 20 0 65432 12345 4321 S 2.0 0.4 0:01.23 systemd-jou
9101 myuser 20 0 43210 12340 3210 S 1.0 0.2 0:00.98 sshd
指標 | 説明 |
---|---|
us - User | ユーザ空間におけるCPU利用率。実装されたWebアプリケーションが多くのCPUを利用している場合に上昇。 |
sy - System | カーネル空間におけるCPU利用率。forkやコンテキストスイッチが多い環境で上昇。WebアプリケーションやミドルウェアがCPU支援処理を利用する際にも上昇することがある。 |
ni - Nice | nice値(-20~19)で優先度が変更されたプロセスのCPU利用率。低い値ほど優先度が高い。大きなI/O処理ではionice(1)で優先度を下げる運用を行うことがある。 |
id - Idle | 利用されていないCPU。100からidの値を引いた値が他の指標の合計値。 |
wa - Wait | I/O処理を待っているプロセスのCPU利用率。ディスク読み書きを減らす設計変更が必要になる場合がある。 |
hi - Hardware Interrupt | ハードウェア割り込みプロセスのCPU利用率。 |
si - Soft Interrupt | ソフト割り込みプロセスのCPU利用率。 |
st - Steal | ハイパーバイザによって利用されているCPU利用率。パブリッククラウドなど仮想化環境でLinuxが使用しているCPU利用率。 |
Linuxにおける効率的なシステム設定
ulimit
ulimit(User limit) は、プロセスが利用できるリソースの制限を設定する概念です。
各プロセスはどのリソースをどのぐらい利用できるのかについて、制限がかけられており、プロセス単位で設定されています。
この設定を引き上げておくことによってアクセス過多による障害を防ぐことができます。アクセスが多くなった際に突然デーモンが落ちてしまい障害が発生することもあります。ミドルウェアの多くは効率的に処理を行うためファイルの読み書きを行う場合があり、特にパケットを多くやりとりする環境ではコネクションも多く生成されるため、同時に利用するファイルの数も増える傾向にあるので注意が必要です。
Linuxカーネルパラメータ
Linuxカーネルパラメータはsysctlコマンドで確認できます。以下の出力例ではgrepしてパフォーマンスチューニングに重要なパラメータを抽出しています。
$ sysctl -a | grep -E 'net.core.somaxconn|net.ipv4.ip_local_port_range'
net.core.somaxconn = 128
net.ipv4.ip_local_port_range = 32768 60999
net.core.somaxconn
net.core.somaxconn はパケット通信における「接続要求のキュー」である backlog がどのぐらい受け入れられるかを表すパラメータです。listen(2)プロセスでソケットへの接続要求を待ち、accept(2)で接続要求のキューから取り出します。漏れてしまった場合にはパケットを破棄します。
net.ipv4.ip_local_port_range
net.ipv4.ip_local_port_range は Ephemeral Portsの範囲を設定するパラメータです。Ephemeral Portsは」クライアント側で開けるポート番号のことで、逆にサーバー側で用いるHTTPなら80、HTTPSなら443番といったポート番号はシステムポートと呼ばれています。これらを含め、ポートは以下のように定義されています。
ポートの種類 | 範囲 | 説明 |
---|---|---|
System Ports | 0~1023番 | サーバー側で使用。例: HTTP (80番), HTTPS (443番)。 |
User Ports | 1024~49151番 | ユーザー定義のサービスやアプリケーションで利用されるポート番号。 |
Ephemeral Ports | 32768~60999番 | クライアント側で一時的に使用されるポート番号。 |
Dynamic/Private Ports | 49152~65535番 | 一時的、またはプライベート用途のポート番号。主に動的に割り当てられる。 |
ちなみにnet.ipv4.ip_local_port_rangeという名前ですが、Ephemeral Portsの設定はIPv6環境でも有効です。
具体的な利用例
- アプリケーションサーバーが、MySQLなどのデータベースや外部システムに接続する際、クライアント側のポートとしてEphemeral Portsを使用します。
- クライアント接続数が多い環境では、Ephemeral Portsを使い切る可能性があり、ポート範囲の拡張が必要になる場合があります。
同一ホスト内での通信
-
UNIXドメインソケットを利用することで、同一ホスト内のプロセス間通信が可能です。
-
主な特徴:
- サーバーのポート番号を使用せずに通信が行える。
- 同一ホスト内でのみ利用可能(例: Webサーバーとそのバックエンドアプリケーションの通信)。
- ポートの管理(例: 「どのポートが空いているか」)が不要になる。
- パフォーマンスが向上するケースが多い。
-
使用例:
- Webサーバーから同一サーバー上のアプリケーションやデータベースに接続する際に利用。
-
主な特徴:
パフォーマンスと設計上の注意
アプリケーションサーバーが、MySQLなどのデータベースや外部システムに接続する際、クライアント側のポートとしてEphemeral Portsを使用します。 クライアント接続数が多い環境では、Ephemeral Portsを使い切る可能性があり、ポート範囲の拡張が必要になる場合があります。
同一ホスト内での通信
違うホスト同士ではポートを拡張する必要がありますが、同一ホスト内での通信ではUNIXドメインソケットを利用することで、ポートを拡張せずともこの問題に対処することができます。
これにより、ポートの管理(例: 「どのポートが空いているか」)が不要になります。また、パフォーマンスが向上するケースが多いです。
MTU(Maximum Transmission Unit)
MTU とはそのネットワークインターフェースから送信できる最大サイズです。設定した値よりも大きなパケットを送信する際には、MTUのサイズまで分割して送信します。また、TCPにおいてもMSS(Maximum Segment Size)という技術でMTUに近い形での分割送信を行っています。
Webサービスを提供する上でMTU/MSSの設定はあまり大きな効果を得ることができません。というのもネットワークの様々な経路で設定されているためです。多くの場合においては、MTUの設定はOSの定めるデフォルト設定を利用するべきです。
まとめ
以上がisucon本9章まとめです。チューニングに必須な項目を要約したので是非ご活用ください!
その他の章の記事はこちらから
ISUCON本の内容をまとめてみた DB編
ISUCON本の内容をまとめてみた リバースプロキシ nginx編
ISUCON本の内容をまとめてみた キャッシュ編
ISUCON本の内容をまとめてみた 高速化に必要なその他技術編
ISUCON本の内容をまとめてみた OS Linux編