積極的後進

後ろ向きに全力ダッシュ

Web開発者のための大規模サービス技術入門を読んだ

会社の本棚にあったものを読むことにした。

業務ではWebフロントに注力していて、触るとしてもnginxやCDNまわりなのでサービス負荷について考える基準が欲しかったことがモチベーション。

少し古い本なので多少内容が陳腐化している箇所もあったものの、今でも使える基本的な知識や考え方について解説されている。(やむを得ないが)書籍中に出てくるコードはほぼPerlなので読んでなんとなく内容を察する程度で精一杯だった。

OSキャッシュやスケーリングの考え方はあまり詳しく知らなかったところなので良かった。業務外でサーバーを立てる時もスペックは割と適当だったりするので、この辺りの考え方を体得できると業務にも役立てることが出来そう。OSキャッシュの辺りは特に、言われてみれば当たり前だが今までさほど気にしたこともなかった。普段はブラウザ全体のメモリ消費量をなんとなく気にする程度なのだが、アプリケーションのパフォーマンスの観点でもメモリ消費量を気にする癖をつけたい。モニタリングが手軽に出来れば良いのだろうか。

DBまわりも通り一遍というかクエリの書き方を知っている程度なので、サービスに落とし込む際にどういったことを考えるかを知れてよかった。マスタースレーブ構成のクラスタにおいて、マスター間の遅延について考えたこともなかったので新鮮だった。また、これも初歩的な話だがストレージエンジンについて今までほぼシカトしてきていたので知ることができてよかった。

また、アルゴリズムにも興味があった。学生時代に講義で触った記憶はあるものの、ほぼ忘れ去っているからだ。せめてクイックソートくらいは諳んじて書けるようにしたい。結果、書籍中では具体的なアルゴリズムに踏み込んではいなかったが、きっかけにはなった。実践するには競技プログラミングあたりに踏み込むことになるのだろうか。

領域外の知識を吸収する足がかりに出来そうなので、定期的に読み返しておきたい。

以下読書メモ。

オリエンテーション

  • スケールアウト時の課題
    • ロードバランシング
    • データの同期
    • ネットワークレイテンシ
  • 大規模データ量への対処
    • ディスク、メモリ、キャッシュメモリ、CPUの順で速度差がある
    • データが小さいうちは処理をメモリで行えるが、大規模になるとそうはいかない
    • いかにデータを小さく持つか、複数サーバーに分散させるか、必要なデータを最小限の回数で読み取るか

大規模データ処理入門

  • 大規模データとは何か
  • 大規模すぎてメモリで処理できない
    • メモリはディスクの105 ~ 106倍早い
  • SSDは高速だが、バスの性能差故にメモリほどではない
  • 負荷の種類
    • CPU負荷
    • I/O負荷
  • ボトルネックを調べるには
  • CPU負荷のスケーリングはサーバー台数を増やす
  • DBなどI/Oの場合は、データ同期の観点から分散が難しい

OSのキャッシュと分散

  • ページ: OSが物理メモリを確保/管理する単位、仮想メモリの最小単位
  • プロセスは仮想メモリにしかアクセスできず、ディスクに直接アクセス出来ない
  • そのプロセスがアクセス済みになったデータもメモリに残しておく、これがページキャッシュ
    • 一度ディスクにアクセスすると、その後のアクセスが早くなる
  • LRU: Least Recently Used、一番古いものを破棄して新しいものを残す
  • Linuxはメモリがあいていればディスクをキャッシュし続ける
  • メモリを増やす = I/O負荷軽減
  • キャッシュがI/O対策の基本
    • 小さければメモリに載せきれる
  • データをキャッシュしきれない規模になったら、複数サーバーでのスケールを考える
    • CPUリソース(APIサーバー)が必要な場合は単純に増やせる
    • DBの場合は局所性が絡んでくる
  • メモリの増設ポイント
    • キャッシュ容量と、アプリケーションが扱う有効なデータ量を比較する
  • 局所性対策
    • アクセスパターンを考慮して分散させて、キャッシュできない領域をなくす
    • パーティショニングで実現することが多い
  • 負荷分散の学習のためには、OSの動作原理を知ると良い

DBのスケールアウト戦略

  • インデックスを正しく運用する
  • カラムの型が何で、どれくらいのバイト数で、全体通すとどれくらいのサイズになるのか計算する
  • B+木
    • O(n) to O(log n)
  • MySQLでは、where, order by , group byに指定されたカラムに対してインデックスが使われる
  • 明示的に作用したインデックス、プライマリーキー、UNIQUE制約がインデックスとして作用する
  • MySQLにおいては、複数カラムがインデックス利用の対象になった場合には、複合インデックスを使う必要がある
    • 単一のインデックスの場合は、どちらかのインデックスのみが使われる
  • explainコマンドで、インデックスが効いているかどうか確認できる
  • レプリケーション
    • マスタースレーブ
      • マスターが更新系、スレーブが参照系
      • 参照系はスケールするが、更新系はスケールさせない
      • どうしても更新系をスケールさせる際は、テーブル分割でテーブルサイズを小さくする
        • もしくはKVSを使う、RDBMSではなくする
    • ポーリング
  • MySQLでは、異なるサーバーにあるテーブルをJOINできない
    • クエリを分割して対応する方が良い
    • テーブル同士が密結合であれば、同じサーバーにおいてしまう方が良い
  • パーティショニングのデメリット
    • 運用が複雑になる
    • 故障率が上がる
    • 冗長化を考えるとマスター1スレーブ3の4台1セットにすると良い
      • 故障時のデータコピーのことを考える
    • パーティショニングはあくまで切り札として扱う方が良い

大規模データ処理[実践]入門

  • 全文検索や類似文書系探索、データマイニングRDBMSだと限界が来る
    • バッチ処理でデータを抽出し、別途インデックスサーバーを作る
    • WebアプリケーションからはAPIでインデックスサーバーにアクセスする
    • 用途特化型の参照用サーバー

アルゴリズムの実用化

大規模データ処理を支えるサーバー/インフラ入門

スケーラビリティの確保に必要な考え方

  • 多くのサービスはサーバー一台で動く
    • 4core CPU 8GB: 100万PV/月
    • 4core CPU 32GB: 200万PV/月
  • 負荷を測るための項目
    • ロードアベレージ
      • それらのプロセスがいつでも動ける状態なのにCPUが未割り当てで、待ち状態にあるプロセスの平均値
    • メモリの割当状態
  • 用途ごとのチューニング
    • レスポンスタイム、処理数など何に注力するのか
  • 用途が増え、細分化すると管理や異常検知が大変
    • だからkubeが人気になったんだよなあ

冗長性の確保、システムの安定化

  • 単一故障点の除去
  • APサーバーは、台数を並べるのが基本
    • ロードバランサのフェイルオーバー、フェイルオーバー
      • ロードバランサによるAPサーバーのヘルスチェック
      • 落ちたら外して、復帰したら戻す
  • サーバーが止まる理由は様々
    • 人為的な理由
    • 物理的な故障
    • メモリ異常
  • DBサーバー
    • マスタースレーブ方式で、一台二台落ちても大丈夫にする
    • マスターの冗長化にはマルチマスタ方式を用いる
      • 双方が双方のスレーブである
      • 片方への更新が、もう片方にも伝搬する
      • ミリ秒単位の遅延は避けられない(割り切るか、どうか
  • マルチマスタ
    • active/standby方式
    • 通常はactiveにのみ書き込み
    • activeに異常が生じたらstandbyがactiveに昇格する
  • ストレージサーバー
    • MogileFS: 分散ストレージサーバー
  • システムの安定化
    • トレードオフが基本
      • リソースをギリギリまで使うチューニングは、突発的なリクエスト増加に耐えられない
    • システムの不安定要因
      • アプリケーション/サービスレベル → 負荷増大
        • 機能追加
        • メモリリーク
        • 地雷
          • 特定のURLで応答が返ってこないなど
          • 機能によるバグと思ってよさそう
        • ユーザーのアクセスパターン
          • 人気のあるリクエストにリンクが貼られるなど
        • データ量の追加
        • 外部連携の追加
      • ハードウェア → 能力低下
        • メモリ・ストレージ障害
        • NIC障害
    • 実際の安定化対策
      • 適切なバッファの維持
        • 限界の7割運用
      • 不安定要因の除去
        • SQL負荷対策
          • どうしても重くなるSQLは、DBサーバーごと隔離して実行
        • メモリリークをへらす
        • 異常動作時の自律制御

Webサービスとネットワーク

  • サービスの成長とネットワークの分岐点

いまどきのWebサービス構築に求められる実践技術

  • ジョブキューシステム
  • ストレージの選択
    • 適切なストレージを選択することは難しい
    • アプリケーションからストレージを参照する際のアクセスパターン
      • 平均サイズ
      • 最大サイズ
      • 新規追加頻度
      • 更新頻度
      • 削除頻度
      • 参照頻度
    • ストレージの種類
      • RDBMS
        • 2つの機能ブロックから成る
          • SQLを解釈し実行するブロック
          • 実際にデータを保管するブロック
            • ストレージエンジン
        • MyISAM v.s. InnoDB
      • 分散key-valueストア
        • memcached
          • メモリ上で動作
          • キャッシュとして使う
          • redisと比べて、パフォーマンスに大きく差があるわけではない
          • redisに出来て、memcachedに出来ないこと
  • キャッシュシステム
    • フォワードプロキシ
      • クライアントが外部のサーバー・ネットワークに接続する際に挟むプロキシ
    • リバースプロキシ
      • 外部のクライアントが内部のサーバー・ネットワークに接続する際に挟むプロキシ
    • これらのプロキシでは、リクエストをキャッシュしておくことが出来る
    • キャッシュサーバーのメリット
      • 平常時に、APサーバーへのリクエストを軽減することが出来る
        • サーバーの台数削減に繋がる
      • アクセス増加時には、負荷増大によるシステム全体のダウンを予防することが出来る
        • アクセスが集中しているコンテンツをキャッシュして返す
    • 分散、冗長化も効果的
    • 容量が大きいファイルなどをキャッシュする場合は、キャッシュサーバーを二重化すると良い
      • リクエストを受け付けるサーバーと、キャッシュ本体を受けもつサーバーのクラスタ
      • 特定のファイルキャッシュはこのサーバー、などすると、キャッシュサーバーの台数が増えても効率的なキャッシュが出来るようになる
    • サーバー起動時にはキャッシュが全然ないから注意
      • activeにする前に、ウォームアップをしてキャッシュを溜めておこう
    • Squid
      • リバースプロキシキャッシュサーバー
      • 結構歴史がある
      • 代替にはnginx, varnishなど。。。
    • Varnish
      • リバースプロキシキャッシュに特化
      • Squidより性能が高い
      • VCLの柔軟さが特にポイント
      • 再起動でキャッシュが全て失われる
        • 数台以上のクラスタで運用する方が良さそう
  • 計算クラスタ
    • Hadoop
    • Redshift
    • 最近のトレンドは。。。?
      • BiqQuery?