【1~2章】「Webエンジニアが知っておきたいインフラの基本」私的まとめ

# 課題図書のアウトプット
2019卒で面白法人カヤックに入社するKoyoです！
カヤックでの入社課題としてリーダブルコードを提示されましたが、何度か読んだことあったため、代わりに[「Webエンジニアが知っておきたいインフラの基本」](https://www.amazon.co.jp/dp/B00SY2UKHY/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)を提示されました
アプリケーション周りはインターンなどでそれなりに経験できたかなと思いますが、実際の運用（インフラや監視）に関わる知識が乏しいと実感していたため大変参考になりました

一通り読み終わったので、備忘録がてら自分なりにアウトプットすることでより深めていきたいと思います！
※自分が知っていることは基本的に省略するので、気になる方は本を買ってみてくださいね

本稿では全8章のうち**1~2章**をまとめます！
残りの章は機会があれば・・・

# 1章 Webサービスにおけるインフラの役割
一般的なWebシステムの階層構造は以下です（コロケーション知らなかった笑）
本書では主に**「ミドルウェア～コロケーション」**を扱っています

|階層|内容|
|:--:|:--:|
|アプリケーション|独自開発 or 製品 or オープンソース|
|アプリケーション実行環境|プログラミング言語選定、実行環境、フレームワーク|
|ミドルウェア|Apache、nginx、MySQLなど|
|OS|Linux、Windows|
|ハードウェア|サーバ・ネットワーク機器|
|ネットワーク|インターネット接続回線などのネットワーク環境|
|コロケーション|データセンター、空調、ラック、電源などの物理的格納場所|

また工程としては以下を扱っています
**要件定義→設計→調達→構築→運用**
ちなみに「調達」の工程がアプリケーションの構築と異なる部分です
調達には「リードタイム」を意識しないといけない点に注意が必要です

インフラはミドルウェアから下だけでも

* OS
* サーバ機器
* ストレージ
* データセンター
* ドメイン取得
* DNS
* ネットワーク機器
* ネットワーク技術
* SSL証明書

など様々な要素の組み合わせから成ります

### インフラ設計時の注意点
インフラ設計とは要件を実装に落とし込む工程です
インフラ要件には以下の2種類あります

* 非機能要件
    * 「1年間10分以上サービス停止させない」など
    * 非機能要件の例
        * 可用性（稼働率・目標復旧時間・災害対策）
        * 性能・拡張性
        * 運用・保守性（運用時間・バックアップ・監視保守）
        * 移行性（移行方式の規定、移行スケジュール）
        * セキュリティ
        * システム環境・エコロジー（適合規格・機器設置規格など）
    * まじめにやると再現がないのでリスクと現実の折り合いをつける
* 機能要件
    * 機能要件を具体化したもの
    * 「ロードバランサは以下にWebサーバ4台設置する」「ネットワークは完全二重化する」など

### RAS
RASとはシステムの信頼性を総合的に考える指標です

* RAS
    * Reliability 信頼性
    * Availability 可用性
    * Serviceability 保守性

※上記に加え、データの一貫性を表すIntegrity（完全性）とSecurity（安全性）を加えた指標を**RASIS**と言います

ちなみに似たような概念として情報セキュリティではCAIという指標があります

* CIA
    * Confidentiality 機密性
    * Integrity 完全性
    * Availability 可用性 
    
#### 具体的な検討方法
RASを検討する際には以下を用います

* 稼働率
    * MTBF/(MTBF+MTTR)
    * 計画メンテナンスは含めないことも
    * レアケースをどの程度対処するかがとても重要
* 障害発生間隔（Mean Time Between Failures = **MTBF**）
    * 累積使用時間/故障回数
* 平均復旧時間（Mean Time To Repair = **MTTR**）
    * 累積修理時間/故障回数

稼働率を高めるには「冗長化によりMTBFを長くMTTRを短く」するのが重要です
特に「単一障害点（SPOF）を無くすか、残る場合はMTBFを長くMTTRを短くする」のが重要になります
具体的には以下の3つあります

1. 要素単体の稼働率を高くする
  * サーバ専用パーツを利用する
     * データセンターに置くなども
  * パーツを二重化する
     * ディスクRAID
     * 無停電電源装置（UPS）を使った電源の二重化
  * 要素ごとの稼働率を確認する
     * 稼働率は必要な要素のうち一番低い部分の稼働率で決まる
     * クラウドなどはTierで表現されるSLA(Service Level Agreement)を参照する
         * Tier3は99.982%
  * ※一定以上のレベルを求めると途端にコストが上がる
2. 要素を組み合わせて全体の稼働率を高くする
  * **コストの低い要素を組み合わせるため、よく使われる**
  * 冗長化構成は以下の２つ
     *  Active-Standby = 冗長化した片方は利用不能
         * Hot Standby = スタンバイ側は普段起動しすぐ利用可能
         * Warm Standby = スタンバイ側は普段起動しているが利用可能にするためにデータリストアなど必要（時間を要する）
         * Cold Standby = スタンバイ側は普段停止
     *  Active-Active = 冗長化した両方が利用可能
         * 最も稼働率が高い
         * ステートレスであれば簡単だが、そうでなければ難しい  
3. 適切なプロビジョニングで負荷問題を回避する
  * プロビジョニングとは「負荷を予測しリソースを適切に準備すること」
  * 代表的なのはスケールアップとスケールアウト
     * スケールアップは個々の要素の性能向上させる方法
         * ある程度までは効率的だが、一定範囲を超えるとコストパフォーマンスが急激に悪化 
     * スケールアウトは個々の要素の数を増やす方法
         * スケーリングは一瞬では終わらない 
         * クラウドではオートスケールがある
         * サービス提供に最低限必要な台数をNとすると通常はN+1必要（**N+1構成**と呼ぶ）
             * 予算があればN+2にすることもある 
             * 「障害対応」とは N+1->N の状態を N->N+1 にすること 

稼働率を高めるには他に「故障時の対応」「大規模災害時の対応」も重要みたいです
詳しくは本を読んでみてください！

# 2章 インフラ技術の基礎知識
この章ではインフラに関する基本技術に関して述べられています

### IPアドレス
グローバルIPとローカルIPに分かれます
自由に使えるローカルIPは以下の種類があります

`10.0.0.0 ~ 10.255.255.255`
`172.16.0.0 ~ 172.31.255.255`
`192.168.0.0 ~ 192.168.255.255`

ちなみに
`127.0.0.1 ~ 127.255.255.254` をローカルループバックアドレス
`169.254.0.0 ~ 169.254.255.255` をリンクローカルアドレス
という特殊な名前で呼びます

### ドメイン
* IPアドレスはドメインによって紐づけされる
  * DNSと呼ばれる世界的な分散型データベースシステムによって行われる
* 一番右側の.comや.jpをトップレベルドメイン（TLD）と呼ぶ
* ドメイン全体をFQDN（Fully Qualified Domain Name）と呼ぶ
  * `サブドメイン（wwwなど）.名称.属性（coなど）.TLD`の形
  * ドメイン→IPアドレスは多対多の関係
  * ドメイン→IPアドレスに変換することを**正引き**と呼び、ドメインの管理者が設定する
      * １つのドメインに複数のIPアドレスが対応することもある 
  * IPアドレス→ドメインに変換することを**逆引き**と呼び、IPアドレスの管理者が設定する
      * 必ず1対1で紐づく 
* DNSの主なレコードとその意味は以下
  * A
      * アドレス情報（IPアドレス）を設定
  * PTR
      * ポインタ情報（ドメイン名に対するIPアドレス）を設定
  * NS
      * ネームサーバーを設定 
  * CNAME
      * Canonical NAME（正式名称）を設定（エイリアスのようなもの）
  * TXT
      * ドメインに紐づくテキスト情報を設定 
  * MX
      * ドメインのメールサーバ情報を設定

### ルーティング
グローバルIPアドレスは不足してきており、その対応としてプライベートIPを活用するNAT(Network Address Translation)が利用されている
詳しい図はp43参照

### URL
URL/URIの記述は以下
`<PROT>://[<USER>[:<PASS>]@]<FQDN>[:<PORT>]<PATH>`

* PROT
  * プロトコル（ HTTP,FTPなど）
* USER
  * 認証がある場合のユーザ名（省略可）
* PASS
  * 認証がある場合のパスワード（省略可） 
* FQDN
* PORT
  * IANA(Internet Assigned Numbers Authority)が管理するポート番号0~1023は省略可
* PATH

### ネットワークとセキュリティ
* ネットワーク内でのセキュリティはファイアウォールを用いる
  * ファイアウォールは内部ネットワークとインターネット間の通信内容を制御し、意図しない通信が発生しないように接続要求を遮断できます
  * 接続元IP、接続先IP、ポート、通信量の制限を行うことが出来る
  * 通信内容まで踏み込んで管理するものをUTM(Unified Thread Management)と呼ぶ
  * HTTPやHTTPSの中身まで踏み込んで検査するものをWAF(Web Application Firewall)と呼ぶ
      * SQLインジェクションへの対応はこちらを用いる
* 通信の暗号にはSSL（Secure Sockets Layer）を用いる 

### インフラ要素のスペックの読み方と選び方
* CPU
  * 基準は複数あるが（p53の表）、特にキャッシュメモリサイズが重要 
* ディスク
  * 容量/接続規格(SAS 6Gbps, SATA 6Gbpsなど)/回転数(1500rpmなど）/サイズ(2.5inchなど) 
  * RAIDはソフトウェアでも可能だが、ハードウェアRAIDを第一優先にすべき
  * RAID
    * RAID 0（ストライピング）
        * ディスク複数台全体を保存領域
        * アクセス速度とディスク容量の向上
        * ディスク1本でも壊れるとアウト
    * RAID 1（ミラーリング）
        * ディスク1台にデータを保存しペアを用意する
        * アクセス速度とディスク容量は1台の時と変わらない
        * ディスク1台壊れても大丈夫
    * RAID 5
        * 訂正符号とデータを複数ディスクに分散（注：最低3台あればいい「達人に学ぶDB設計指南書」より）
        * アクセス速度とディスク容量の向上（ディスク本数に比例）
        * ディスク1台壊れても大丈夫
    * RAID 6
        * 訂正符号を2重に生成
        * アクセス速度とディスク容量の向上（ディスク本数に比例）
        * ディスク2台壊れても大丈夫 
    * RAID 10, 50, 60
        * それぞれRAID 0 と RAID 1,5,6を組み合わせたもの
  * PCL expressはSSDに比べて圧倒的に性能が優れているので、性能に困った時は有用
* ネットワークのスペックと選び方
    * ファイアウォール
        * メーカーは情報が多いものを選ぶならCisco
        * NATを利用する場合は後から変更が難しいNATセッション数を検討
        * スループットはネットワーク帯域以上出るように
        * カタログスペックの7~8割を目安に読む
    * スイッチ
        * 接続規格はネットワークの帯域以上出るものを選ぶ
        * VLAN方式を使えば物理配線をスッキリさせたまま複雑な論理構成が可能
        * インテリジェント機能があればSSHなどで遠隔から監視・管理できる

### 性能とデータに関する基礎知識
* ACIDを意識
    * Atomicity 原子性
        * 一連の処理A,Bが「どちらも実行される」または「どちらも実行されない」
    * Consistency 一貫性
        * 操作の完了に関わらずデータの整合性が保たれる（一部だけ書き込みがない）
    * Isolation 独立性
        * 一連の処理A,Bの順番が保たれ、他の操作から途中状態が見えない（複数の操作を行っても単独で行った場合と一致する必要）
    * Durability 永続性
        * 処理が完了したにも関わらずデータが保存されないことがない
* ACIDを満たしつつ性能を上げる方法
    * ロックと排他処理
        * データの整合性を取るのに重要
    * バッファ
        * 処理を効率化しボトルネックを緩和する
        * 負荷の高いI/Oを一気に行う
    * キャッシュ
        * ボトルネック緩和
        * 結果を使いまわす
    * キューイング
        * ボトルネックに引きずられて全体のキャパシティを落とさないために使う
        * 「処理キュー」にボトルネック処理に渡す処理を置いて「結果キュー」にボトルネック処理が行った結果を出して、他の処理は定期的に確認を行う

### 冗長化
* データの整合性を取るための方法
    * Shared Disk
        * 高価な専用ストレージを用いてデータを共有
        * 共有ストレージ自体を冗長化する必要がある
    * Shared Nothing
        * 送信元の「マスター」と受信側の「スレーブ」に分けて、レプリケーションを行う
        * 同期型や非同期型など
        * 最近のRDBMSは非同期レプリケーションをサポートしている
* フェイルオーバー
    * StandbyがActiveに昇格する一連の動作
    * 自動化する際はLinux-HAが提供する「Heartbeat」や「Pacemaker」などのソフトウェアを使うことが多い
    * 他にVirtual Router Redundancy Protocol（VRRP）など
    * 上記を使うことでダウンタイムを数秒以内にできる
    * これと組み合わせてDistributed Replicated Block Device（DRBD）というストレージシステムを使うことが多い
    * これを使うとShared Nothing のものをShared Diskのように扱える
    * 誤検知によりプライマリ（マスター）が生きているのにセカンダリ（スレーブ）と入れ替わることがあり、これをSplit Brainと呼ぶ
    * これを避けるためセカンダリが昇格する際にプライマリを強制停止するSTONITHを利用する

### 暗号化とハッシュ化
* 外部から読み取られてはいけない情報の可読性を下げる方法
    * パスワードは暗号化（可逆）ではなくハッシュ（不可逆）で保持
    * ハッシュ方式にかかわらずハッシュ化する際は長めのsaltを用いる
    * ハッシュ化の際に元の文字列の文字種類を増やす
* 暗号化方式
    * 共通鍵暗号方式
        * パスワードをかける
    * 公開鍵暗号
        * 暗号化と複合化に別の鍵（暗号化手順）を用意し、暗号化の方の鍵を公開する方法
* ハッシュ
    * ハッシュ元が同じであれば同じ値になる
    * ハッシュ化方式によっては衝突が発生
    * SHA256など
* 暗号化を破る方法
    * 総当たりなど
    * 暗号化したものが流出しても漏洩と判断される
    * ハッシュの場合は短い文字列の場合、ハッシュ化方式がばれると解読される可能性がある
    * そのためsaltという短い文字列を入れてハッシュ化する
    * そもそも価値の大きいものはなるべく持たないことが肝要