インフラエンジニアの教科書2 まとめ ~Part1~

今後アウトプットのために、技術書を簡単にまとめることにした。
今回は「インフラエンジニアの教科書2」をまとめてみました。
とりあえず2章までですが、質問や指摘等あれば遠慮なく！！


## 1章 プロトコル

インターネットに関するプロトコルとして、「TCP/IP参照モデル」と「OSI参照モデル」が簡単に紹介されていた。個人的には、この章の理解度が一番低いように思われる。
TCP/IP参照モデルの、TCP/UDP、IPについては個別の説明が書かれていた。(少しだけ)

#### トランスポート層

- TCP
    - TCPはデータが相手に届いたかどうかを確認する
    - パケットを送る際に、都度シーケンスナンバーを発行。受取手も常に、受信確認パケットを返す。
    - データが相手に届かない or エラーが発生した時は、データの再送をする
    - シーケンス番号があるので、パケットの順番が異なった時に並び替える。また重複した時は、除去を行う
        - コネクション開始
        - 3ウェイハンドシェイク
            - SYN(クライアント→サーバ)
            - ACK+SYN(サーバ→クライアント)
            - ACK(クライアント→サーバ)
        - コネクション終了
            - FIN+ACK(クライアント→サーバ)
            - ACK(サーバ→クライアント)
            - FIN+ACK（サーバ→クライアント)
            - ACK(クライアント→サーバ)
        - SYN,ACK,FINなどは、TCPヘッダー内にある制御ビッドに含まれる。
- UDP
    - 送信元は、受信先にコネクションを張らずに、いきなり一方的に送りつける。データは、送信先に届く保証はなく、また正常に届いても送信先から返答があるわけではない。
    - 低品質で高速なプロトコルと言われる。DNSやNTPといった早い応答が重要なサービスや、一部の情報がかけても問題のないアプリケーションなどで用いられる。

#### インターネット層

- IP
    - IPアドレスについて
        - ネットワーク部とホスト部に分けられる
        - ネットワーク部は、各ネットワークに対して固有に割り振られる
        - ホスト部は各組織で自由に割り振ることが可能


## 2章 OS
結構長かった。OSについての基礎知識が書かれていたので、つらつらとまとめる。

#### プロセスとスレッド

- プロセス
    - OSでの処理の最小実行単位
    - プロセスに含まれる要素
        - PID
        - 実行コード
        - 変数
        - ファイル記述子
        - コンテキスト(CPUの持つレジスタ情報、物理メモリのアドレッシング等)
        - (スレッド)
- ファイル記述子
    - プロセスから開かれているファイルを識別するために割り当てられる0以上の整数値のこと
    - 0~2は、標準入力、標準出力、標準エラー出力としてデフォルトで割り当てられている
- プロセスの親子関係と新しいプロセスの生成
    - 新しいプロセスを生成する場合は、すでにあるプロセスをコピーすることで生成する
    - この時、コピー元を親プロセス、新規作成されるプロセスを子プロセス呼ぶ
    - Linux系OSの場合、OS起動時に生成されるプロセスはinitプロセスであり、全てのプロセスはinitプロセスの子孫である
    - プロセスのコピーはfork()
    - プログラムの実行はexec()
    - 例えば、bashからlsを実行する時は、
    - 1.bashプロセスがforkされる2.子プロセスがlsをexecする3.親プロセスは子プロセスの実行を待つ(子プロセスは実行終了と同時になくなる)
        - このリンクが参考になった: http://x68000.q-e-d.net/~68user/unix/pickup?exec
        - 例えば、bashから `exec ls`を打つと、プログラム実行終了後にプロセスはなくなる
- プロセス間通信
    - いわゆるパイプといわれるものでデータを受け渡す
    - `cat hoge | grep text` の `|` 
- プロセスの状態遷移
    - 様々な状態がある
        - 実行中
        - 実行待ち(実行待ちキューに登録して、CPUリソースが割り当てられるのを待っている状態)
        - 休止中
- シグナル
    - ユーザーはシグナルを送ることでプロセスをコントロールできる
    - シグナルを受け取ったプロセスは現在実行中の処理を中断し、シグナルに応じた処理を実行する。
    - kill コマンドは、指定したシグナルを指定したプロセスまたはプロセスグループへ送る。 シグナルが指定されない場合、TERMシグナルを送る。
    - シグナルの例(https://tech.nikkeibp.co.jp/it/article/COLUMN/20060227/230806/)
        - SIGHUP(終了して再起動)
        - SIGINT(割り込み)
- プロセスの終了
    - プロセスが終了すると、ゾンビプロセスになる
    - 親プロセスがwait()システムコールを呼ぶと、ゾンビプロセスが消滅する
- スレッド
    - 並列処理を目的にして、プロセス内に作られるタスクの実行単位
    - スレッドは同じプロセス内にある各スレッドがメモリ空間を共有できる

#### OSによるプロセス処理の仕組み

- タイムスライス
    - OSは実行待ちのプロセスに順次CPUリソースを割り当てていく
- コンテキストスイッチ
    - CPUがあるプロセスから別のプロセスに割当先を変える時に発生する
    - プロセスに割り当てられた時間を使い切る or I/O待ちなどで、自発的にCPUを手放す際に発生する
    - CPUの各種レジスタ、プログラムカウント、スタックポイントがスタック領域に退避される
    - コンテキストスイッチはOSにとって、負荷の高い処理
    - 実行待ち状態のプロセスを減らすことが大切→コンテキストスイッチの数が減る
        - CPUのコア数を増やす
        - サーバを増加させて、プロセスを分散されるなど
    - Copy on Write(CoW)
        - 子プロセスを生成する時に、親プロセスをコピーするのは負荷が大きい
        - よって、生成された時点では、親プロセスへの参照リンクだけを貼る
        - 実際にプロセスに変更があった時に初めて、親プロセスをコピーしてくる
    - アフィニティ
        - プロセスごとに割り当て可能なCPUコアのグループを指定することができる
        - `taskset` コマンドというものがあるらしい

#### プロセス管理に当たって気をつけること

- コンテキストスイッチの発生を抑える
    - 頻繁にコンテキストスイッチが発生する環境では応答速度が落ちる
    - 実行待ちのプロセスを減らすことで、コンテキストスイッチの発生を抑えることが好ましい

#### メモリ管理

- 簡単まとめ
    - プロセスがメモリアクセスを行う場合は仮想メモリを通して。物理メモリに直接アクセスしない。
    - メモリの割り当てと解放を繰り返すと、メモリ空間内が徐々に断片化されていく
    - 空き物理メモリが不足していると、スワップアウトが発生する
    - 物理メモリが不足していなくても、断片化によってまとまった物理メモリ領域を確保できない場合もスワップアウトが発生する場合がある
    - 複数のCPUソケットを扱うサーバの場合、NUMAという仕組みでメモリを扱う
        - 同一NUMAノード内の物理メモリには高速でアクセスが可能
- 物理メモリと仮想メモリ
    - プロセスがOSに対してメモリ割り当てを要求。OSは仮想メモリのアドレスを返す
    - 仮想メモリ取得時に、物理メモリと仮想メモリとがマッピングされる
        - 物理メモリの領域が確保できないときは、スワップ領域からマッピングされる。
        - 物理メモリと仮想メモリのマッピングはCPUに組み込まれたMMU(Memory Management Unit)によって行われる
        - アドレスマッピングのテーブルは物理メモリ上に置かれる
- スワップ
    - スワップアウト
        - 確保しようとする仮想メモリと対応した物理メモリが確保できない場合、OSはすでに割り当てられている物理メモリをスワップ領域に追い出して、物理メモリを確保する。
    - スワップイン
        - 逆に、追い出したデータが必要になり、スワップ領域から物理メモリにデータが戻されること
- ページング
    - ページと呼ばれる固定サイズでメモリ空間を分割する単位
    - 物理メモリとディスクデバイスとの間でページの出し入れが行われることをページングと呼ぶ
    - 一般的には4KB
    - ページアウト、メモリ領域を確保するために使われる
    - ページイン、直ちに使われるデータがディスクから物理メモリに呼ばれている(時間かかる)
- NUMA(非対称メモリアクセス)
    - NUMA(Non-Uniform Memory Access)
    - 複数のCPUソケットを搭載したサーバは、NUMAノードと呼ばれるCPUとメモリが組み合わさったグループが構成される
    - 同一ノード内のメモリにアクセスするときは高速にアクセスできる。(アプリケーションがNUMAノード内に搭載されている物理メモリ量より大きなメモリを使うときは、別のNUMAノードのメモリを使わざるを得ず、性能が低下する)

#### OSによるメモリ処理の仕組み
- ページキャッシュ
    - ディスクから読み込んだデータを捨てずに、メモリにキャッシュするOSの機能
    - OSはメモリをページ単位でキャッシュするため、ページキャッシュと呼ばれる
    - ページキャッシュが増えることで、ディスクI/Oがへり、一般的にはサーバのパフォーマンスは向上する
- 空き物理メモリが足りなく見える
    - 物理メモリ量が数値上はパツパツに見えても、物理メモリのほとんどがキャッシュとして使われている場合もある
    - キャッシュは空きメモリとしてみなせる
    - キャッシュ
        - ページキャッシュ(ファイルのページ単位でのキャッシュ)
        - バッファキャッシュ(ディスクのブロック単位のキャッシュ)

```
$ free
             total       used       free     shared    buffers     cached
Mem:        713444     649936      63508      12320      36096     331528
-/+ buffers/cache:     282312     431132
Swap:       735228        120     735108
```

`-/+ buffers/cache` の欄が、実質的に考えて良いメモリ(usedが使われている、freeは空きメモリ)

#### ファイル管理

- ファイルのメタデータ
    - OSでファイルを扱うためには各ファイルに対応したメタデータが必要
    - Linuxではinodeテーブルに保存される
    - メタデータ(一部)
        - ファイルサイズ
        - ファイルの種類
        - 保存先
        - 作成者
        - グループ
        - パーミッション情報
    - Linuxにおいては、inodeテーブルにはファイル名は保存されない
        - ディレクトリエントリの中に、ファイル名が記載される
- ファイルシステム
    - ファイルシステムとはOS内でディスク管理を行う機能
        - ext4、NTFSなどのさまざまな種類が存在
    - 分散ファイルシステム
        - ファイルシステムはネットワーク経由でも利用できる
        - 他のサーバやストレージ上に構築されているファイルシステムをネットワーク越しに利用できるようにしたものを分散ファイルシステムという
        - 分散ファイルシステムはNFS(UNIX/Linux)プロトコルでマウントして使う

#### Linux/UNIXのファイル管理

- ファイルのメタデータ
    - LinuxやUNIXではinodeと呼ばれるメタデータを用いる
    - statなどで、メタデータ確認可能

```
$ stat temp
  File: `temp'
  Size: 6         	Blocks: 8          IO Block: 4096   通常ファイル
Device: 801h/2049d	Inode: 1579860     Links: 1
Access: (0644/-rw-r--r--)  Uid: (  501/  hoge)   Gid: (  502/  hoge)
Access: 2019-08-11 16:04:35.534875269 +0900
Modify: 2019-08-11 16:03:57.240834953 +0900
Change: 2019-08-11 16:03:57.240834953 +0900
```

- ディレクトリエントリ
    - inodeにはファイル名やディレクトリ名の情報が含まれない
    - ファイル名やディレクトリ名の情報はディレクトリエントリに含まれる
    - ディレクトリエントリとはディレクトリを作成した時に、ディレクトリ自体に書かれる情報
    - ディレクトリエントリは、inode番号とファイル名かディレクトリ名が含まれている
    - ls -iで確認可能

```
$ ls -i
1579879 a  1579980 b  1587159 c  1587165 d
```

- 使用中ファイルの削除
    - ファイル削除
        - 1.ディレクトリエントリからの削除
        - 2.inodeテーブルからの削除
    - Linuxはファイルがプロセスからオープンされている状態であってもファイル削除の操作はできる
    - ただし、その場合1のみが行われる
    - 2は、全てのプロセスからファイルがクローズされた後に行われる
    - プロセスがファイルOPENするときは、inode番号で識別する
- シンボリックリンクとハードリンク
    - シンボリックリンク
        - ファイル名でリンクを貼る
        - 元のファイル名やディレクトリ名が削除されると、シンボリックリンクは残るがリンク切れの状態になる
        - オリジナルファイルとシンボリックリンクでは異なるinode番号が付与される
    - ハードリンク
        - ファイルにのみ、ハードリンクが可能
        - オリジナルファイルとハードリンクでは同じinode番号が付与される

実際の挙動の違い

```
$ echo "hoge" > origin

$ ln -s origin symlink

$ ln origin hardlink

$ ls -i
1587166 hardlink  1587166 origin  1587167 symlink

$ stat symlink
File: `symlink' -> `origin'
Size: 6         	Blocks: 0          IO Block: 4096   シンボリックリンク
Device: 801h/2049d	Inode: 1587167     Links: 1
Access: (0777/lrwxrwxrwx)  Uid: (  501/  hoge)   Gid: (  502/   hoge)
Access: 2019-08-11 16:23:18.115096895 +0900
Modify: 2019-08-11 16:23:06.499174475 +0900
Change: 2019-08-11 16:23:06.499174475 +0900

$ stat origin
File: `origin'
Size: 5         	Blocks: 8          IO Block: 4096   通常ファイル
Device: 801h/2049d	Inode: 1587166     Links: 2
Access: (0664/-rw-rw-r--)  Uid: (  501/  hoge)   Gid: (  502/   hoge)
Access: 2019-08-11 16:22:54.311206857 +0900
Modify: 2019-08-11 16:22:54.311206857 +0900
Change: 2019-08-11 16:23:14.281792721 +0900

#ハードリンクは通常ファイルとして扱われる
$ stat hardlink
File: `hardlink'
Size: 5         	Blocks: 8          IO Block: 4096   通常ファイル
Device: 801h/2049d	Inode: 1587166     Links: 1
Access: (0664/-rw-rw-r--)  Uid: (  501/  hoge)   Gid: (  502/   hoge)
Access: 2019-08-11 16:22:54.311206857 +0900
Modify: 2019-08-11 16:22:54.311206857 +0900
Change: 2019-08-11 16:24:43.229857105 +0900

$ rm origin

#ハードリンクは参照可能(つまり、inodeはファイルなり、プロセスなり、参照されている場合は、inode tableから削除されないということ)
$ cat hardlink
hoge

$ cat symlink
cat: symlink: そのようなファイルやディレクトリはありません

$ ln hardlink origin

$ ls -i
1587166 hardlink  1587166 origin  1587167 symlink

#シンボリックリンクはファイル名でリンクしている
$ cat symlink
hoge

$ cat > hardlink
changed

$ cat origin
changed

$ cat symlink
changed
```

- バインドマウント
    - Linuxではバインドマウントにより、ディレクトリのマウントが可能(細かいことはちょっとわかってない)

```
$ sudo mount --bind origin copy

$ touch origin/hoge

$ ls copy
hoge
```

- ファイルシステムのマウント
    - ハードディスクやDVD-ROMなどの記録媒体へは、ファイルシステムとしてマウントすることでアクセスが可能になる

- その他
    - ファイルを消しても空き容量が増えない
        - ファイルをopenしているプロセスがあるのかも
        - ファイルをopenしているプロセスIDを特定したい場合は、lsofコマンドを使う


```
$ sudo lsof temp
COMMAND   PID  USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
tail    22105 hoge    3r   REG    8,1        6 1579860 temp
```
- ディスク容量に空きがあるのにファイルを生成できない
    - inodeの枯渇が原因かも

ディスクについての情報

```
$ df
Filesystem     1K-blocks     Used Available Use% Mounted on
/dev/sda1       51473368 21692624  27159952  45% /
```

ディスクのinodeについての情報

```
$ df -i
Filesystem      Inodes  IUsed   IFree IUse% Mounted on
/dev/sda1      3276800 410726 2866074   13% /
```

- ログ出力でディスク容量を使い果たした
    - ログ出力をしているプロセスを停止してから、ログファイルを削除
    - 他の大きいパーティションにログファイルを移動してから、シンボリックリンクを貼る
    - プロセスを停止できない場合、既存のログファイルをコピーした後、 `/dev/nill` をログファイルにコピーしてログファイルをの中身をからにする方法もある
    - よくある失敗
        - ログファイルをmvで他のパーティションに退避した後に、同じファイル名でログファイルを作成すること
            - プロセスがオープンしているログファイルのinode番号と新しく生成したファイルのinodeが異なるので、プロセスは新しいファイルに書き込まない
            - また、古いファイルは解放されていないので、空きデスク量は増えない


- 想定よりハードディスクの空き容量が少ない
    - ext3/4などのファイルシステムでは、リザーブ領域と呼ばれるrootしか使えない専用領域がデフォルトで5%確保されている
    - tune2fsコマンドでリザーブ領域を0%にすると、全ての領域が使えるようになる