ISUCON本の内容をまとめてみた OS Linux編

# はじめに
この記事は[isucon本](https://www.amazon.co.jp/%E9%81%94%E4%BA%BA%E3%81%8C%E6%95%99%E3%81%88%E3%82%8BWeb%E3%83%91%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%B3%E3%82%B9%E3%83%81%E3%83%A5%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0-%E3%80%9CISUCON%E3%81%8B%E3%82%89%E5%AD%A6%E3%81%B6%E9%AB%98%E9%80%9F%E5%8C%96%E3%81%AE%E5%AE%9F%E8%B7%B5-%E8%97%A4%E5%8E%9F-%E4%BF%8A%E4%B8%80%E9%83%8E-ebook/dp/B0B1Z9ZMY6/ref=sr_1_1?crid=3VFKVU9V3LQ4D&dib=eyJ2IjoiMSJ9.Fqg1BYtrQnEUkAI-Nz64Vlht-4b2gmnfCNzmBcYOOLrGjHj071QN20LucGBJIEps.ihawrCdi4UxmgZ_Xbpwz0kJimoBykcQ7nS9WIqRl40U&dib_tag=se&keywords=isucon&qid=1732981401&sprefix=isucon%2Caps%2C178&sr=8-1)の9章の内容をまとめたものになります。要点を抑えている(つもり)なので是非ご覧ください

# Linuxとは
LinuxとはOSの一種でありオープンソースのOSです。それゆえに様々なユースケースで用いられています。Linuxではカーネルパラメータというパラメータがあります。これによってコードを書き換えずともカーネルの挙動を変えることができます。

# Linux Kernel
Linuxは、OSとしてのコア機能をLinux Kernelと呼ばれるソフトウェアが担っています。OS上で動作するアプリケーションはシステムコールと呼ばれる命令を用いてLinux Kernelの機能を利用しています。
以下はアプリケーションからシステムコールする際の図です。

```mermaid
flowchart TB
    subgraph ユーザー空間
        direction TB
        Application[アプリケーション]
    end
    subgraph カーネル空間
        direction TB
        SystemCall[システムコールインターフェース]
        LinuxKernel[Linuxカーネル]
    end

     subgraph ハードウェア
        direction TB
        Hardware[ハードウェア]
    end
    
    Application --> SystemCall
    SystemCall --> LinuxKernel
    LinuxKernel --> Hardware

```
| **レイヤー**            | **説明**                                                                                                                                                            |
|-------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **ユーザー空間(ユーザーランド)**         | アプリケーションが動作する領域のこと。ユーザーが直接操作するソフトウェアやプログラムが実行される     |
| **システムコールインターフェース** | アプリケーションと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になります。この場合は以下のような親子関係があります。

```mermaid
graph TD
    A["init (PID 1)"] --> B["systemd-journald (PID 58)"]
    A --> C["systemd-udevd (PID 75)"]
    A --> D["systemd-logind (PID 101)"]
    A --> E["cron (PID 150)"]
    D --> F["bash (PID 210)"]
```

プロセスを生成するとプロセスごとにマシンのリソースが確保されます。このとき基本的に他プロセスのリソースにアクセスすることができません。一方プロセスにはスレッドという概念もあります。スレッドはプロセスの中で並行実行できるタスクの概念です。一プロセスには一つ以上のスレッドがあります。スレッド間ではリソースを共有できます。スレッドが複数あることをマルチスレッドといいます。

# Linuxのネットワーク
例としてhttpリクエストを受け取る場合について説明します。
```mermaid
flowchart LR
    Client[クライアント] -->|HTTPリクエスト| Network[ネットワーク]
    Network --> NIC[NIC]
    NIC -->|パケット| Kernel[Linux Kernel]
    Kernel -->|パケット| WebServer[Webサーバー]
    WebServer -->|パケット| Kernel
    Kernel -->|パケット| NIC
```

|         |説明                                   |
|-----------------------|-----------------------------------------------|
| NIC                  |ネットワークからのパケットを受信し、OS（カーネル）に渡す。| 
| Linuxカーネル         |受信したパケットを処理し、Webサーバーに渡す。OSの中心的役割を果たす。| 
| Webサーバー           |パケットのデータをもとにHTTPリクエストを解析し、応答を生成する。|


httpリクエストをNICが受け取るとNICはLinuxCarnelにパケットを送信します。このとき、あくまでhttpリクエストとしてではなくパケット単位で送信し、カーネルを通じてwebサーバに届きます。

## スループットとレイテンシ
ネットワークの計測において大事な二つのメトリクスを紹介します。
| メトリクス   | 説明                                                                 |
|--------------|----------------------------------------------------------------------|
| スループット | 一定時間で処理できるパケットの量を示します。                           |
| レイテンシ   | 通信を開始してから終了するまでの所要時間を指します。                   |

この二つのメトリクスはどちらも重要なメトリクスです。スループットが大きくてもレイテンシが高いと通信に時間がかかるのは変わりません。逆にレイテンシが低くてもスループットが小さいということは処理が非効率であることを示します。
スループットとレイテンシはこのような判断ができる重要なメトリクスです。

# CPU利用率
cpuの利用率を確認するにはtopコマンドを使用します。
## 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コマンドの出力例
$ 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)で接続要求のキューから取り出します。漏れてしまった場合にはパケットを破棄します。

```mermaid
flowchart TD
    HTTPRequest["HTTPリクエスト"] --> BacklogQueue["backlogキュー"]
    BacklogQueue -->|接続確立| AcceptProcess["accept(2): 接続済みソケットへ"]
    BacklogQueue -->|キュー不足| PacketDrop["パケット破棄"]

    subgraph サーバー
        BacklogQueue
        AcceptProcess
    end
```

## 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編](https://qiita.com/Atkiyama/items/e9429910a17fa749e243)
[ISUCON本の内容をまとめてみた リバースプロキシ nginx編](https://qiita.com/Atkiyama/items/2dcfa7a3147368da6cec)
[ISUCON本の内容をまとめてみた キャッシュ編](https://qiita.com/Atkiyama/items/91a1c2924f15f29264cc)
[ISUCON本の内容をまとめてみた 高速化に必要なその他技術編](https://qiita.com/Atkiyama/items/8de9f6e5db5c6a4384c4)
[ISUCON本の内容をまとめてみた OS Linux編](https://qiita.com/Atkiyama/items/32bdc11ea631fe1c1820)