サーバ/インフラを支える技術を読んだ
総括
読んでよかった。主に負荷分散やフェールオーバーの仕組みについて体系立てて理解できた。
10 年以上前の本なので、5 章以降のツールの話は読まなくていいと思う。
1 章. サーバ/インフラ構築入門
ハードウェアは壊れるので、冗長化が必要。
本章では、すごく原始的な冗長化から始まって、
順を追って冗長化の仕組みについて解説してくれている。
コールドスタンバイ
更新が少ない、データを持たない、などのサーバは適してる
ホットスタンバイ
フェイルオーバー
ヘルスチェックをして、VIP を切り替えるスクリプトなどで運用するのが昔ながらの方法?
Web サーバなどはスタンバイ機のリソースが無駄になるので、できれば負荷分散をしたい。
負荷分散
DNS ラウンドロビン
サーバの数だけグローバル IP が必要
通信元の DNS キャッシュによって、均等に分散されない。
バックエンドが死んでても気づけない
ロードバランサー
通信元から見えるのはロードバランサーだけ。こいつがリクエストを受ける。
そのためグローバル IP を割り当てるのも LB だけで良い。
LB がバックエンドの死活監視を行う。
負荷分散アルゴリズムが複数あり柔軟に負荷分散できる。
Linux の負荷分散ソフトウェア
IPVS(IP Virtual Server)という。
ipvsadm, keepalived などがある。
L4 と L7 ロードバランサーの違い
L4 は TCP ヘッダなどを見て分散先を決める。
L7 はアプリケーション層の中身まで見て分散先を決める。
L4 では通信元とバックエンドサーバを直接結ぶ(分散先を紹介するだけのイメージ)
L7 では通信元 ⇄L7LB,L7LB⇄ バックエンド、の2つの TCP セッションが張られる(常に通信を仲介するイメージ)
パフォーマンスは L4 の方が良いが、L7 の方が柔軟な分散ができる
L7のロードバランサーを使うと、画像ファイルはWebサーバではなく、
画像ファイルサーバを直接見に行くなどの設定ができそう。(AWSの事例で見たことあるかも)
また、同じセッションIDの通信は同じサーバに振り分けるなどもできる。
2 章.ワンランク上のサーバ/インフラ構築
リバースプロキシ
L4 ロードバランサは分散先を決めるだけなので、
その後の通信はクライアントと Web サーバが直接行う。
ここで、間にリバースプロキシを挟むことでさらに柔軟な負荷分散ができる。
L4 ではできなかった、パスベースのルーティングを行うことができる!
よく言うプロキシサーバはLAN→WANへ出るときに間を仲介して代理で通信してくれるサーバのこと。
逆に、WAN→LANヘリクエストが来るときに間を仲介してくれるので、「リバースプロキシ」と呼ぶ。
リバースプロキシでできることの例
IP アドレスによる制御。特定の IP からしかリクエストを受付けない等。
パスによる制御。画像ファイルなど静的ファイルは S3、動的ファイルは AP(アプリケーション)サーバへ。
URL の書き換え。リクエスト元に見える見た目上のパスと、サーバ側のパスを変えたい場合。
UserAgent による制御。
AP サーバの動き
基本的に 1 ユーザ(1 リクエスト)を、1 プロセス(1 スレッド)で処理する。
これによって、リソースの競合を防ぐことができるので、アプリケーション実装者が楽になる。
modperl,mod php,tomcat,gunicorn などがこれにあたる認識・・・。
動的リクエストの動き
まず、動的コンテンツへのリクエストによって HTML が生成され返される。
その後、HTML に記載された画像ファイル、JavaScript、css などのリクエストが送られる。
1 動的リクエスト+30 静的リクエスト のようになる。
よくある構成として
上でも書いているように、リクエストのパスによって、静的なファイルは Web サーバ、動的ファイルは AP サーバが返すようにする。
リバースプロキシ自身も Web サーバなので、自分自身が返すことが多い。(nginx とか使ってるとよくわかる)
HTTP の Keepalive
ユーザが Web ページを表示するのに 1 動的リクエスト+30 静的リクエストかかるとする。
31 回コネクションを張ることはせず、Web サーバ側の keepalive の設定時間はコネクションを再利用する。
Keepalive のおかげでコネクションのオーバーヘッドが減る。
keepaliveTimeout=15 なら 15 秒で切れる。一般的に 1 リクエスト 15 秒もかからないのでもっと下げても良い。
リバースプロキシを使う性能面のメリット
リバースプロキシが無いと AP サーバが直接セッションを維持することになるのでリソースを多く食う
リバースプロキシ(Web サーバ)は AP サーバに比べてリソース使用が小さいので数百〜数千プロセス保持されても大丈夫。
Web サーバ ⇄AP サーバ間は Keepalive をオフしておけば良い。
リバースプロキシを使う機能面のメリット
HTTP リクエストの前処理/後処理ができる
mod_deflate...レスポンスを gzip 圧縮して通信量を下げる(gzip はブラウザ側で解凍可能)
mod_dosdetector...DDoS 対策のモジュール(急激なアクセス負荷から守る)
リバースプロキシについてその他ノウハウ
プロセスが大量に増えるので worker モデルが適している。
prefork は 1 クライアント 1 プロセス、worker は 1 クライアント 1 スレッド。
httpd.conf の設定で最大プロセス数(MaxCLients)と、プロセスあたりの最大スレッド数()ThreadsPerChild を設定。
ServerLimit,ThredLimit も注意。これらのデフォルト値を超えそうな場合は調整しよう。
ただしメモリがスワップしない程度を上限としてチューニングすること。
キャッシュサーバ
MySQL のレプリケーション
MySQL の非同期レプリケーションの概要
シングルマスタ、マルチスレーブの構成が主
レプリケーションの遅延を減らすため、スレーブには、IO スレッド、SQL スレッドに別れている。
IO スレッド...マスタ側が出力した更新情報(バイナリログ)を読み取り、リレーログに書き込む。
SQL スレッド...リレーログを読み取りスレーブに SQL を発行する。
スレーブは「どこまで同期したか」を示す「ポジション情報」を持っている。
スレーブを読み取り専用として活用する
リアルタイムバックアップとしてだけでなく、負荷分散のために使うことを考える。
更新処理はマスターに、参照はスレーブに送ることで負荷分散させる方法が一般的。
さらに、スレーブをスケールアウトすることで、読み取りの負荷分散が可能。
一般的に RDBMS は SELECT 操作が大部分を閉めるのでこの方法は理にかなっている。
更新 or 参照の割り振りは AP サーバ側で行う。
スレーブの負荷分散には内部ロードバランサーを使う。
高速で軽量なストレージサーバの選択
今の現場だと、オンプレ環境でも Amazon S3 を s3fs でマウントするとかできるので、
よほどキツイ要件じゃなければ勉強する必要性が低そうなので飛ばす。
3 章.止まらないインフラを目指す
DNS サーバの冗長化
resolv.conf に複数 DNS サーバを記載しておくことはできるが、1 台目のタイムアウト待ち時間は深刻な問題になることがある。
DNS サーバ自体の冗長化 VRRP(keepAlive など)を使った冗長化が可能(VIP を付け替えることによる Active/Backup 構成)
IPVS と KeepAlive などでロードバランサーによる冗長化が可能(Active/Active 構成)
ストレージサーバの冗長化
割愛
ネットワークの冗長化
L1/l2 の冗長化
LAN ケーブルや NIC などの故障(リンク故障)
→ サーバとスイッチ間を冗長化する。ボンディングによって複数の物理 NIC を1つの論理 NIC として扱う
ネットワークスイッチなどスイッチ間接続の故障
→NIC を冗長化しても接続先のスイッチが単一だったら意味がない。
さらなる冗長化について書かれているが、自分の業務とは遠いので割愛・・
このへんは基礎用語が分かってればいいかな・・・
VLAN の冗長化
VLAN のメリット
構成変更の柔軟性が上がる
スイッチの有効活用ができる...上位ルーター、下位ルーターの別セグメントをまとめて管理できる
サーバの追加や置き換え、故障の復旧を物理的なつなぎ直しなしで行える。
Q. もしVLANを使わず同じスイッチで別セグメントで利用すると?
A. マルチキャスト/ブロードキャストフレームや、
まだスイッチが学習できていない宛先不明なユニキャストフレームなどは、
関係のないセグメントへも転送されてしまう。
無駄な帯域を消費するうえ、セキュリティ的にもよくない!
VLAN の種類
スタティック VLAN...ポート単位にグループわけをする。変更も手動。
ダイナミック VLAN...ルールに基づいてグループわけをする。
ポート VLAN
ポートごとに VLANID を割り当て、グループごとに同じ ID を割り当てる。
設定はシンプルだが、複数スイッチ間でグルーピングできない。
タグ VLAN
端末やスイッチから Ethernet フレームが送られる時に VLAN ID を挿入する。
複数スイッチ OK だが、フレームが流れる機器が全て VLAN タグに対応してないといけない。
4 章.性能チューニング
「負荷を知るということは、OSを知るということ」
「推測するな。計測せよ。」
Webアプリケーションの負荷分散は、多くの場合ディスクIOの分散と軽減。
OSはIOを軽減するために、キャッシュの仕組みを持つ。
キャッシュが最も効くようにすることがIO分散のコツ。
ボトルネック見極めの流れ
プロセスとスレッド
スレッドの方が、メモリ空間を共有する分リソースを食わない
スレッドの方が、コンテキストスイッチが発生しない分コストが低い
ただし、カーネルから見ればスレッドも 1 つずつのプロセスのように見えている(LWP...Light Wight Process)
ps -L でマルチスレッドのスレッドも一覧で表示される。
sarコマンドのオプション
sar -u...CPU(cpU)
sar -r...メモリ(memoRy)
sar -q...LoadAverage(キュー)
各項目の意味
usr...ユーザモードでCPUが消費された割合
nice...niceで優先度を変更していたプロセスがユーザモードでCPUを消費した時間の割合
system...システムモードでCPUが消費された時間の割合
iowait...CPUがディスクのIO待ちのためにアイドル状態で消費した時間の割合
steal...OS仮装化の場合に、他の仮装CPUの計算で待たされた時間
idle...待たされることなくアイドル状態で消費した時間の割合
チューニング
チューニングは、そのハードウェア、ミドルウェアが本来持つ性能を十分発揮できるようにすること。
限界以上の性能が出るわけではない。
遅くなった原因が明確になれば、対応方法を実施するだけ。
ボトルネックが発生したときに原因を特定するための知識が必要
チューニングのアプローチ
頭が痛いから頭痛薬を飲もう!みたいな対処療法はやめよう
根本原因を突き止めて根本解決を。(肩凝りからの頭痛かもしれない)
システムチューニングの場合は、推測ではなく計測をすること!!!
システムの性能限界以上の性能は出ない。ボトルネックが無いならサーバのスペックを上げるしかない
計測するためのツールの使い方と、OS やミドルウェアの仕組み・内部構造を理解しておくこと
Web サーバ(Apache)
並行処理の実装モデル
MPM(multi processing module)
prefork...あらかじめ複数プロセスを生成する
worker...マルチプロセスとマルチスレッドの複合技。大規模やスケーラビリティを求めるとこちら
プログラミングの観点から見た違い
マルチプロセスの方が、メモリ空間が分割されているので安全
マルチスレッドの方がリソースの競合を考慮しないといけないので実装が難しい。
結局、1クライアントあたりのレイテンシに違いはない。
大量のコンテキストスイッチがある場合をのぞいて大きな性能差は無い。
DB サーバ(MySQL)
チューニングの観点としては「いかに高速にデータの入出力を行うか」
サーバサイド
ディスク IO のカーネルパラメータの設定
ファイルシステムの選択とマウントオプション
パーティショニング
サーバサイド以外