Linuxで使う時間と文字コードとプロセスとメモリとファイルシステムについて調べて見た👀

# はじめに
Linuxの時間と文字コードとプロセスについて調べてみた

# 時間
地球上では地球の片方に太陽の光があたり昼になり、もう片方は夜になります。太陽の光が当たっている地域はどんどん西へ移動していくので、日本から西へ向かうと早いほうへ時刻が戻っていきます。このように地球上では地域によって必ず`時差`が生じる。キリバスが最も時刻が早く進んでいる国でアメリカ領サモアとニウエ島が最も遅い地域

自宅にあるパソコンといえど、インターネットを介して世界中のサーバやパソコンとの通信が可能です。こうなると世界中のパソコンが同じ基準の時刻情報を使う必要性が生じ、UTC(Universal Time Coordinated)と呼ばれる協定世界時をコンピュータの世界における標準時とするようになりました。

## GMT(グリニッジ標準時)
* UTC以前の初期の国際的な基準
* GMTを継承して数種類の世界時が定義された

## UTC(協定世界時)
* GMTに代わって世界各地の標準時を決めるときの**基準となる時間**のこと
* 原子時計で1秒を刻みつつ、自転に基づきUT(世界時)との差が0.9秒を超えないようにうるう秒(自転速度のふらつきを埋める仕組み)を導入


## 標準時 ローカルタイム 
* 各国・各地域で、`標準として定められている時刻`。地理的、社会的に近い地域では共通の時刻を使う。**UTCを基準に各国・各地域で標準時を決めている**
* 日本の標準時は**JST**

## タイムゾーン
* 同じ`標準時`を使う地域。
* タイムゾーンの境界の多くは国境や国内の政治境界に準じる


## 時差
UTCからの差で表現。日本はUTC+9,UTC+09:00、+09:00

# VMware
# Vmware EsxiはUTC
https://go-journey.club/archives/3887

https://communities.vmware.com/thread/499346
→ESXiのdataコマンド等の時刻表示はUTCで、ESXiのログファイルもUTCで記録されます。

```
ただ、BIOSでの設定というわけではなく、ESXi自身がUTC設定となっているのでUTCになります。

仮にBIOSでUTCとしなかった場合も、UTCになります。

NTPで時刻同期していても、ESXiではUTCになります。

→ESXiで起きたアラート、タスク、イベント等の情報はJSTで表示しますが、

ログファイルは基本的にUTCの時間のままです。

※ログブラウザだと、UTCの時間文字列に「+0900」という文字列(JSTだと+9時間ということ)を付けて表示されます。
```

```
仮にBIOSの設定でJSTにしていたとしても、ESXiがNTPサーバを参照するようになっていれば、

お構いなしにUTC時刻で時間の記録を行う、ということでしょうか？

(BIOSの時刻のゾーン設定はESXiにとって、ある種無意味、ということでしょうか)

はい。結局はそうなると思われます。

ESXiは、起動時にBIOSの時間（ハードウェアクロック）を見ても、

NTPで時刻同期する場合はUTCの時間（JST-9h）で時刻同期されて

date コマンドの結果や、ログファイルの記録もUTCになります。
```

https://note.com/xochop/n/nca742a6db05e

https://note.com/xochop/n/nca742a6db05e

# VMware 仮想マシンでの時間
https://tech-mmmm.blogspot.com/2015/01/vmware.html
https://note.com/xochop/n/n3b5a5e87601e

物理サーバーの時間はメーカが設定する。
だいたいJSTで設定している？？
この場合EsxiはUTCとして認識するのでUTC=JSTとなってしまう

仮想環境では以下のような4階層構造となる。

https://note.com/xochop/n/n5d9e4bdfda7e

[a. VM：システムクロック]　←仮想マシンのOSが持つ時間
[b. VM：ハードウェアクロック]　←仮想マシンのBIOSが持つ時間
//------------------------------//
[c. ESX：システムクロック]　←ESXのハイパーバイザーが持つ時間
[d. ESX：ハードウェアクロック]　←ハードウェアが持つ時間(通常は内蔵電池で時間を維持)

## 同期タイミング
同期タイミングは以下の通り。

[a. VM：システムクロック]　←VM起動時にb→aに同期、VM停止時にa→bに同期
[b. VM：ハードウェアクロック]　←VM起動時にc→bに同期
//------------------------------//
[c. ESX：システムクロック]　←ESX起動時にd→cに同期、ESX停止時にc→dに同期
[d. ESX：ハードウェアクロック]　←通常は内蔵電池で時間を維持

注目すべきは、以下の点。

VMにおけるハードウェアクロックは仮想BIOSが持つ時間
VM停止後のハードウェアクロック情報はBIOSは保持せず消失
VM起動時にESXのシステムクロックをVMのハードウェアクロックとして同期する


## 参考
https://www.kodomonokagaku.com/hatena/?223f02da3a998eae8fce53600dcf9d40
https://www.724685.com/word/wd140611.htm

# 時間まとめ
世界で共通の時間を(UTC)を決めてUTCをもとに各地域や国で標準時を使用することで、世界で共通の時間認識のもとで人々がコミュニケーションを取ることができるようになる

# OSの時間
http://park12.wakwak.com/~eslab/pcmemo/clock/clock2.html

起動されたOSは直ちにハードウェア クロックを読み出して、そのデータを基にシステム クロックの設定を行います。

## 参考
https://qiita.com/tabimoba/items/f9c4f9024f7c3ff65360

## Unixタイム
Linuxの内部での時間の表現。UTCにおける1970年1月1日0時0分0秒からの経過秒数で示す

## システムクロック
* OSが認識する現在時刻。ハードウェアクロックから現愛時刻を読み出してシステムクロックを設定する
* **NTPでシステムクロックもntpの値に同期される**
* ハードウェアクロックの進み方は正確ではないことが多いのであくまで起動時の時刻設定のみで起動後は独自にカウントアップする。OS停止後にシステムクロックの値をハードウェアクロックに設定する

## ハードウェアクロック リアルタイムクロック(RTC)
  - 内蔵電池で稼働する時計機能
  - RTC(Real Time Clock)あるいはCMOSクロックとも呼ばれる

## Linuxのシステムクロック
* Linuxのシステムクロック=Unixタイム


## CentOSインストール時のSystem clock uses UTC
* チェックをつけようがつけまいがシステムクロックは正しく設定される
* Windowsとの互換性のために用意された

## Linuxでの時間設定
https://anqou.net/poc/2018/04/17/post-1521/

timedatectlでシステムクロック、ハードウェアクロックを確認できて、設定もできる

```bash

#timedatectl
      Local time: 木 2020-03-05 13:46:35 JST
  Universal time: 木 2020-03-05 04:46:35 UTC
        RTC time: 木 2020-03-05 04:46:35
       Time zone: Asia/Tokyo (JST, +0900)
     NTP enabled: yes
NTP synchronized: yes
 RTC in local TZ: yes
      DST active: n/a
```

**前提として
Windows では日本標準時を、Linux では協定世界時がハードウエア時刻に設定されている、と想定している。**

よってLinux環境ではRTCをUTCをハードウェアクロックに設定する



# windowsとLinuxの時間
http://park12.wakwak.com/~eslab/pcmemo/clock/clock2.html

　ハードウェア クロックが参照されるのはOS起動時の一度だけで、その後はシステム クロックのみが唯一の時刻情報源となります。また両クロック間での同期調整は行われないので、両者の時刻情報には必然的にズレが生じ時間の経過と共にズレは大きくなります。
　「ハードウェア クロックはあまり正確ではない」と言われているくらいですから、このままでは再起動やシャットダウンのたびに、時刻合わせに苦労することになります。

　ただ、システム クロックについては、人手あるいは自動実行されるNTP(インターネット時刻との同期)によって、その時々に修正が行われるのが普通です。
　そこで Linux や Windows では、システム クロックをハードウェア クロックに反映する方法が採られています。

## Linux
シャットダウンや再起動の時に、システム クロックの値をハードウェア クロックへ書き込み(同期し)ます。

## windows
　Windows は時刻情報(システム クロック)が修正されると、直ちにハードウェア クロックに書き込みが行われるようです。


## マルチブート環境
windows はハードウェア クロックのタイムゾーンを、暗黙裡にローカル タイムであると認識します。 Linux のようにタイムゾーンを選択(UTC or ローカルタイム)できる機能はありません。

　そのため windows を含むマルチ ブート環境では、ハードウェア クロックのタイムゾーンをUTCとすることは不可能(ローカルタイム固定)で、**他のOSが windows の作法に合わせる必要があります。**

# 文字コードについて
## 文字集合、文字セット
* コンピューター上で扱う対象となる文字を集めたもの
* 表現する文字の一覧
* 日本語、英語など

## 符号化文字集合、文字コード
* 文字集合の文字に対して数値を割り当てたもの
* 現在では標準的な文字コードはUTF-8
* Shift_JISとかEUC-JPとかISO-2022-JPとかUNicodeなど

## エンコード(エンコーディング)、符号化方式とは
* 符号化文字集合として定められている符号とは異なる表現でメモリやファイルなどのストリーム上にデータを保持したいときの表現ルール
  - たぶん`符号化文字集合`をコンピューター上で扱いやすくするように？数値変換している
  - **単純に文字と数字をマッピングする「方式」として覚えれば良い**

```
「Unicode」という「文字集合」に対して「UTF-8」「UTF-16」などの「エンコード」方式がある、
同様に、
「JIS X 0208」という「文字集合」に対して「ISO-2022-JP」「EUC-JP」「Shift_JIS」などの「エンコード」方式がある、
という対応付けになるようです。
```

## Charset
「文字集合」と「エンコード」の両方を含んだもの


## 文字コード参考
https://cero-t.hatenadiary.jp/entry/20110614/1308063484

# プロセスについて
CentOS6.10で手元のMACから一般ユーザでsshdを使ってサーバーにリモートログインしてpsコマンドをgrepするプロセスを確認してみた

```bash

# ps auxf | grep sshd
root      1527  0.0  0.0  66288   516 ?        Ss    2018   0:00 /usr/sbin/sshd
root     31336  0.2  0.1 102132  4056 ?        Ss   08:02   0:00  \_ sshd: ユーザー [priv]
ユーザー   31340  0.0  0.0 102132  1868 ?        S    08:02   0:00      \_ sshd: ユーザー@pts/0
ユーザー   31341  0.8  0.0 110352  3924 pts/0    Ss   08:02   0:00          \_ -bash
ユーザー   31374  1.0  0.0 110356  1208 pts/0    R+   08:02   0:00              \_ ps auxf
```
この場合sshdプロセスは３つ起動している。

* sshd(root:1527)
  - sshd(1527)は接続要求を受ける
  - フォークしてsshd(root:28028)を生成
  - フォーク後は次のssh接続要求を待つ
* sshd(root:31336)
  - ユーザー認証を担当して一般ユーザ権限のsshd(一般ユーザ:28034)をフォークする
* sshd(一般ユーザ:31340)
  - フォーク&execしてbashコマンドを実行してシェルを起動。さらにそのシェルからpsコマンドのプロセスを起動
  - ユーザーからのコマンド入力を中継してコマンドを実行する

## なぜsshdが3個起動？
セキュリティが理由で３つ目のsshｄは**ユーザー権限で起動**。sshdに脆弱性が存在して特定の文字を入力するとsshdからシャットダウンするコマンドが誤って実行される場合に(もしもの場合)、コマンド入力を中継するsshdがroot権限で動いていたら誰でもシャットダウンできてしまうので。

## httpdのプロセス

```
root     24852  0.0  0.7 435348 27972 ?        Ss   May16   9:29 /usr/sbin/httpd
apache   22048  0.0  1.0 453472 40580 ?        S    03:46   0:09  \_ /usr/sbin/httpd
apache   22049  0.0  0.9 458040 38604 ?        S    03:46   0:08  \_ /usr/sbin/httpd
apache   22050  0.0  0.8 445704 34328 ?        S    03:46   0:09  \_ /usr/sbin/httpd
apache   22053  0.0  0.9 450268 37104 ?        S    03:46   0:08  \_ /usr/sbin/httpd
apache   22054  0.0  0.8 447180 33556 ?        S    03:46   0:08  \_ /usr/sbin/httpd
apache   22055  0.0  1.1 465172 43944 ?        S    03:46   0:08  \_ /usr/sbin/httpd
apache   22056  0.0  0.8 447272 34288 ?        S    03:46   0:06  \_ /usr/sbin/httpd
```

* 24852がアクセスを受け取り、返送は子プロセスに依頼する。
* 事前にいくつかの子プロセスを起動している。プリフォークという。数はhttpdの設定に依存
* 子プロセスが足りなくなると増やす、逆にアクセスがなくなると最初の数に戻る

## プロセス生成
### プロセス生成の２つの目的
Linuxにおいてはプロセス生成は2つの目的がある

* 1, 同じプログラムの処理を複数のプロセスに分けて処理する(webサーバによる複数リクエストの受付)
* 2, 全く別のプログラムを生成する(例:bashから各種プログラムの新規生成)

fork() execve() という２つの関数ある
内部的にclone(),execve()システムコールを呼び出している

## fork()関数
1の場合fork()関数を使って親プログラムをコピーして、子プロセス側でも同じプログラムを実行する。fork()関数から復帰すると親はもとのプログラム、子はコピーした親と同じプログラムを実行する。

## execve()関数
全く別のプロセスを生成する場合はfork()関数発行後に子プロセスでexecve()関数を読んで全く別のプロセスに生まれ変わる。fork and exec 

親になるプログラムにfork()の後の条件分岐で子プロセス用、親プロセス用のプログラムが書かれている

```c


ret=fork();

if(ret==0){
//子供
//例えばhttpdだと返送処理するプログラムが書かれている
//コマンドの実行する場合は全く別のプロセスを生成するのでexecve()

}else{
//親
//例えばhttpdだと接続要求待機
}
```


## psコマンド
### オプションのスタイル
-ではじまるPOSIXスタイル
-をつけないBSDスタイル


### すべてのプロセスを表示する
wwで画面の幅で切らずにすべてを表示する

* POSIXスタイル
  - ps -efww
* BSDスタイル
  - ps auxfww

### プロセスのCPU使用時間と経過時間(プロセスが開始してからの時間)
* ps -eo pid,comm,time,etime
  - time(CPU使用時間)、etime(経過時間)

```bash

$ ps -eo pid,comm,time,etime
  PID COMMAND             TIME     ELAPSED
    1 init            00:00:18 287-13:24:11
```
TIME 18秒
ETIME 287日13時間24分11秒

## プロセススケジューラ
マルチコアCPUはLinuxから一つのコアが一つの論理CPUとして認識される。またハイパースレッドが有効だとそれぞれのハイパーコアスレッドが論理CPUとして認識される。

* プロセス終了までの経過時間はプロセス数に比例して増加する
* 各プロセスはおおよそ等しい長さのタイムスライスを持つ
* 論理cpu上では複数プロセスｇあプロセスを順番に動かして、1周したらまた一番目のプロセスから動かすラウンドロビン方式で動作している
+ プロセスがいかなるコードを実行中であろうとｍ、タイムスライスが切れると容赦なくコンテキストスイッチが発生する
  - 特定のプロセスに優先度をつけることで優先度の高いプロセスは通常より多くCPU時間を得られる

## コンテキストスイッチ
プロセスがいかなるコードを実行中であろうとも、タイムスライスが切れるとコンテキストスイッチが容赦なく発生する

## プロセスの状態
* 実行状態(R)
  - CPUを使っている
* 実行可能状態(R)
  - CPU時間が割り当てられるのを待っている
* スリープ状態(sまたはD)
  - 何らかのイベントが発生するのを待っている状態(S)
  - デバイスへの読み書き待ち(D)
  - ネットワーク送受信待ち(S)
 
D状態にあるプロセスは通常、数ミリ秒程度で別の状態に遷移するらしい。長時間この状態にある場合は次の原因がある

* ストレージIOが終了しない状態になっている
* カーネル内で何らかの問題が発生

# メモリについて
## freeコマンド

```bash

             total       used       free     shared    buffers     cached
Mem:          3.7G       3.2G       579M       596K       196M       979M
-/+ buffers/cache:       2.0G       1.7G
Swap:         2.0G       315M       1.7G
```

* 2行目の1.7G= 1行目のfree項目 + 開放できるbuffers/cacheの容量
* **どれくらい余裕があるかは2行目のfree項目を見ればよい**

## OOM Killer
メモリが増え続けて容量が足りなくなると適当なプロセスを選んで強制終了する

## 仮想記憶
* プロセスから物理アドレスに直接アクセスする方法はない
* 仮想アドレスから物理アドレスへの変換はページテーブルで行う

## ページテーブル
* すべてのメモリを**ページ**という単位で区切って管理。x86_64だと4kバイト
* 各ページには物理アドレスが存在するかのフラグあり

### ページフォールト
* 仮想空間に物理アドレスが紐付いていない状態でアクセスされると発生。ページフォルトハンドラで物理アドレスに紐付けられる
* ハンドラ内でプロセスによるメモリアクセスが不正なものかをチェック

## デマンドページング
* メモリを獲得してから当分、あるいはプロセス終了まで使わない領域が存在する。そこでデマンドページングという仕組みを使ってメモリをプロセスに割り当てる
* **物理メモリは当該ページにアクセスしたときにページフォールトハンドラで初めて割り当てる**

## コピーオンライト
* fork()システムコールのときの子プロセス生成を高速化する仕組み
* 親プロセスをすべてコピーするのではなく、**親プロセスのページテーブルのみをコピー**
* ページテーブルエントリでは書き込み権限フィールドを無効化する
* 実際に書き込みが発生したときにページフォールト発生させハンドラの中で子プロセスの物理アドレスを初めて確保する(デマンドページング)

## スワップ
* ストレージデバイスのいち部を一時的にメモリの代わりとして使用する仕組み
* 既存の使用中の物理メモリの一部をストレージデバイスに退避する、このときの退避する領域を**スワップ領域**と呼ぶ

### スワップアウト、ページアウト
メモリの内容をスワップ領域に退避すること

###　スワップイン、ページイン
スワップ領域から退避していたデータをメモリに戻す

### スワッピング
スワップアウト、スワップイン、またはLinuxではページング

### スラッシング
スワップイン、スワップアウトが頻繁に繰り返される状態

# メモリ(いろんなキャッシュ)
## キャッシュメモリ
* **レジスタとメインメモリのアクセス速度差**を埋めるのがキャッシュメモリ
* メモリに反映さていないデータはフラグ設定(ダーティ)されて所定のタイミングでメモリに反映される
* さらにキャッシュメモリの中でもL1、L2、L3とレベルがある
* 多くの場合プログラムは参照の局所性があるので狭い範囲がキャッシュメモリに収まり高速になりやすい
* TLB
  - CPUには仮想アドレスから物理アドレスい変換する表を保持することでこうせ奥にアクセス可能な領域

## ページキャッシュ
* **CPUからストレージデバイス**への速度差を埋めるため
* ページアウトはページキャッシュからストレージデバイスに書き込む
* ページインはストレージデバイスからページキャッシュに読み込む
* sar -B のpgpgin/s pgpgout/sは**スワッピングのときも値が表示**、**ページキャッシュイン、アウトのときにも値が表示される**

# ファイルシステム
* ext4、XFS、Btrfsなどあるがユーザーからはopen()、write()、read()など統一したインターフェースでアクセスできる。内部でカーネルが各ファイルシステムの関数を紐付けしている。
* データの読み書きするときは**デバイスドライバ**に処理を依頼する

## ファイルシステムの不整合を防ぐ技術
### ジャーナリング
* ext4とXFS
* ジャーナルという特殊な領域を用意。ここにアトミックな処理の一覧(ファイルの移動だったり)をいったん書き出す。この一覧をジャーナルログと呼ぶ
* ジャーナルログの処理一覧を書き出す途中で電源停止
  - ジャーナルログを捨てて最初から始める
* ジャーナルログの処理一覧を実行中に電源停止
  - ジャーナルログを最初から実行
* **処理前か処理後の状態に必ずなる**

### コピーオンライト
* Btfsの場合。割愛

## それでも不整合になった場合
* **バックアップをとった状態に戻すのが最善策**
* 復旧用コマンドfsck(どのファイルシステムにも存在)を使う
  - **しかしおすすめはしない**。修復に長い時間がかかる。数テラバイトで数時間、数日。結局失敗になることがおい
  - **さらに不整合が起きているデータやメタデータを容赦なく削除する**

# 参考
[[試して理解]Linuxのしくみ ~実験と図解で学ぶOSとハードウェアの基礎知識](https://www.amazon.co.jp/%E8%A9%A6%E3%81%97%E3%81%A6%E7%90%86%E8%A7%A3-Linux%E3%81%AE%E3%81%97%E3%81%8F%E3%81%BF-%E5%AE%9F%E9%A8%93%E3%81%A8%E5%9B%B3%E8%A7%A3%E3%81%A7%E5%AD%A6%E3%81%B6OS%E3%81%A8%E3%83%8F%E3%83%BC%E3%83%89%E3%82%A6%E3%82%A7%E3%82%A2%E3%81%AE%E5%9F%BA%E7%A4%8E%E7%9F%A5%E8%AD%98-%E6%AD%A6%E5%86%85-%E8%A6%9A/dp/477419607X/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&keywords=linux%E3%81%AE%E4%BB%95%E7%B5%84%E3%81%BF&qid=1566887113&s=gateway&sr=8-1)

[「独習Linux専科」サーバ構築/運用/管理](https://www.amazon.co.jp/%E3%80%8C%E7%8B%AC%E7%BF%92Linux%E5%B0%82%E7%A7%91%E3%80%8D%E3%82%B5%E3%83%BC%E3%83%90%E6%A7%8B%E7%AF%89-%E2%80%95%E2%80%95%E3%81%82%E3%81%AA%E3%81%9F%E3%81%AB%E4%BC%9D%E3%81%88%E3%81%9F%E3%81%84%E6%8A%80%E3%81%A8%E7%9F%A5%E6%81%B5%E3%81%A8%E9%89%84%E5%89%87-Software-Design-plus/dp/4774159379/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&keywords=linux+%E5%B0%82%E7%A7%91&qid=1566878082&s=gateway&sr=8-1)