ゆるく分かる　クラウドインフラのデザインパターン

## はじめに

この記事は『[Amazon Web Services クラウドデザインパターン設計ガイド](https://www.amazon.co.jp/dp/4822277372)』という本の読書メモです。
自分はgcpを触ることの方が多いので、抽象的でも一旦はawsでもgcpでも応用できるようにクラウドインフラのよくあるユースケースをまとめられたらと思います。


## 基本

#### SnapShot
ボタンorコマンド一つでサーバ中身のバックアップが取れる。

#### Stamp
インスタンスの作成時の設定(サーバのスペック、OS、セキュリティのルールなど)をテンプレ化させ、同じインスタンスを量産できる。

#### Scale Up
cpuやメモリなどのスペックを上げ下げできる。作った後からでも変えられる。

#### Ondemand Disk
ディスクの容量も増減させられる。
aws:EBS(仮想ディスクサービス)
gcp:Google Compute Engine > ディスク

## 負荷に耐えるインフラを構築する

#### Multi Server, Multi Datacenter
インスタンスを複数用意し、ロードバランサーで処理を振り分ける構成。ロードバランサーは定期的に各インスタンスに対してヘルスチェックを行っている。故に1台インスタンスが死んだとしても、生きているサーバにだけ処理が振り分けられるためユーザ側に影響が出ないようになっている。システムが稼働し続けられる。

またインスタンスが構築される物理サーバは、世界各地のデータセンターを選べるようになっている。
仮にシンガポールリージョンで災害があってDC自体が機能しなくなったとしても、台湾リージョンにもインスタンスを置いていれば、残ったインスタンスでサービスは稼働し続けられる。

#### Floating IP
障害やメンテナンスでサーバを止める時、代わりに予備のサーバで稼働させるようなケースがある。そういったときは本番用のipを予備サーバに割り当てるか、DNSなどで向き先を変えてあげるように設定し直さなければならない。クラウドではIPアドレスの設定のサービスも提供されているため、数秒程度の時間で従来よりも簡単に付け替えが行える。
aws: Elastic IP Address
gcp: VPCネットワーキング > 外部IPアドレス

#### Deep Health Check
lvsのヘルスチェックのやり方は様々だが、従来だとlvsは自身にひもづくwebサーバの死活監視は行えても、webサーバの後ろにあるproxyサーバやdbサーバの状態まではわからなかった。
クラウドのlvsサービスの機能では、phpやjavaServletなどプログラムのチェックも行えるので、システム全体の稼働をチェックできる。

#### Scale Out
lvsで管理しているサービスに対して、あらかじめ決められた閾値を超えるような負荷が発生したら、自動でサーバを増加or減少させる設定ができる。

#### Clone Server
あらかじめscale outを想定していない既存サービスに対して、scale outのような負荷分散を行わせるシステムにする。
あらかじめマスターサーバからcloneを作成し、負荷に応じてcloneインスタンスを起動。マスターからディスクを同期してサービスインさせる。
(scale out, clone serverのような負荷分散系に関しては、注意点がありすぎてとても2,3行では語り切れない...)

#### NFS Sharing
scaleout, clone serverのような負荷分散時のコンテンツ同期方法について。
共有コンテンツを管理するNFSサーバを用意し、各インスタンスはNFSサーバを参照する形を取るようにする。

#### NFS Replica
アクセスが集中するNFSサーバも負荷分散対応を行う時。
lvsにぶら下がっている各webサーバは、nfsサーバを定期的に(マウントしてコピーしたような)rsyncなどで複製したものを持つようにする。参照する時は自身がもつレプリカから参照する。

#### State Sharing
lvs構成時に一つのサーバが壊れたとする。そのサーバが独自に持っていた情報(そこにアクセスしていたユーザ情報など)が消失されてしまうのを防ぎたい時。
管理したいステート情報は耐久性の高いサーバ内で共有させる。各webサーバはそこからステート情報を参照するようにする。
aws: Elastic Cache(インメモリーキャッシュ), DynamoDB(kvs)
gcp: cloud Datastore(kvs)
　※執筆時点だとgcpのインメモリキャッシュサービスはなかった。app engineにはmemcacheが使えるようになっている

#### URL Rewriting
webサービスのアクセスの大半は、htmlや画像など静的なコンテンツへのリクエストだったりする。静的コンテンツへのアクセスをうまく分散させれば、オートスケールで稼働させるインスタンスの量を減らせたりするため。(料金の節約にもつながる)
そういった時は、クラウドサービスの提供しているインターネットストレージを利用する。
対象のコンテンツをストレージにアップして、参照先をストレージのurlにすることで、webサーバへのアクセス数を減らせる。
aws: S3
gcp: Google Cloud Storage
この方法は全世界にコンテンツを配信する時の場所が原因の遅延を防ぐことにもつながる。(最寄りのサーバから参照させるようにできるため)

#### Rewrite Proxy
元々はwebサーバ上にあった静的コンテンツをストレージサービスに移動させる時、urlの置き換えといった既存システムに手を加える必要がある。
既存システムに手を加えずに参照先を変更するために、既存システムの前にproxy serverを立てる。プロキシサーバにコンテンツ内のurl書き換えルールを適用させる。またproxy serverがspofにならないように、冗長化させる。

#### Cache Proxy
普通のwebサーバの前にVarnishなどのキャッシュサーバソフトをインストールしたサーバを配置する。配信期限が切れるまでは、配信パフォーマンスの高いサーバでコンテンツ配信を行うことで、高負荷対策が行える。これもまたキャッシュサーバがspofにならないように冗長化させる。

#### Schedule Scale Out
高負荷な時間帯がわかっていれば、その時間帯だけスケールアウトするようにする。

## 静的コンテンツを配信する

#### Web Storage
動画などの容量の大きいファイルを配信させたいときは、webサーバからではなく S3などのストレージに配置して行うようにする。そうすることでwebサーバのネットワーク負荷とディスクの容量の問題を解決する。

#### Direct Hosting
上記のようなストレージをサーバ代わりにして、htmlやcss、jsなどもホスティングさせる。

#### Private Distribution
特定のユーザのみに配信したい時。
制限付きurl発行機能でユーザごとにurlを発行してアクセスさせる。この機能はストレージサービスが提供する。有効期限やIPアドレスで制限をかけられる。(cloudStorageも同じく。)

#### Cache Distribution
複数箇所にコンテンツを配信するキャッシュサーバを立てる。ユーザになるべく近い距離にあるサーバからコンテンツを配信できるようにすることで、ユーザエクスペリエンスを向上させる。変更の反映が遅れることがある。

#### Rename Distribution
コンテンツの変更がキャッシュに反映されるのに時間がかかる問題への対応策。
更新したい内容のファイル名を自体を変えて、url自体が変更されるようにする。そうすると取得先が変更されているため、キャッシュを返すのではなくオリジンサーバまで取得しに行くから、内容がすぐに反映されるようになる。

#### Private Cache Distribution
世界規模のサービスで、特定のユーザーにのみコンテンツを配信したい場合。
CDNで提供される「署名付きurl認証機能」を利用することで、アクセス元ipやアクセス元地域などの細かい条件でのurlを発行することができる。
ユーザ認証はストレージ上ではなく自システム上で行うことになるが、コンテンツの配信はCDN上から行われる。

## データをアップロードする

#### Write Proxy
インターネットストレージは読み込みに対するデータのキャパシティやデータの耐久性は高いが、複数サーバにバックアップを取っていることもあり、大量データに対する書き込みには弱い。
大量データの書き込みの対策として、クライアント側からストレージに直接アップするのではなく、間に仮想サーバを噛ませるとよい。仮想サーバとストレージ間ではhttp/https以外の高速なプロトコルが使えたり、また専用回線で通信ができるようになっているため。

#### Storage Index
インターネットストレージは高度な検索機能は用意されていなかったりする。そのため特定のユーザや日付のデータを取得したいときは、kvsサーバを用意し、データ格納時にメタ情報をinsertするようにする。
ストレージのデータを検索して取得したいときは、そのkvsサーバで検索を行い、取得されたurlにアクセスできるようにする。

#### Direct Object Upload
多数のユーザから写真や動画がアップロードされる写真/画像共有サイトの場合だと、webサーバのアップロードの負荷対策が困難。
そういったケースでは、Write Proxyのパターンとは逆に、アップロードの処理をストレージに任せた方が良い。ストレージに上げたあとストレージからwebサーバに完了通知を出せば、インスタンス間で画像の共有も容易になる。

## RDBを使う

#### DB Replication
クラウドでは地理ロケーションをまたいでDBのレプリケーションの設定を容易に行える。

#### Read Replication
読み込みが多いサービスでは、読み込みはそれ専用のレプリカで行うようにさせる。
読み込みを分散させることで、書き込みや更新などを行なっているマスターサーバの負担を減らすことができ、システム全体のパフォーマンス向上につながる。

#### Inmemory DB cache
DBの読み込みパフォーマンスを向上させたい場合、頻繁に読み込まれるデータをメモリーにキャッシュしておく方法がある。
aws: Elastic Cache
gcp: State Sharingのところでも書いたが、おそらくapp engineでないとgcpでの実装はできないと思われる。
キャッシュするデータのよくある例としては、取得に時間のかかるクエリーの結果や複雑な計算の結果など。

#### Sharding Write
複数のデータベースで書き込みパフォーマンスを上げたいとき、シャーディングという方法が上げられる。これは同じ構造のデータベースを複数用意して、適切なテーブルのカラムをキーにして分割し書き込みを行う。
クラウドサービスを利用すれば、より可用性と運用効率の良いシャーディングを行わせることもできる。
aws: Spiderストレージエンジンを組み込んだmysqlサーバなどのシャーディングソフトウェアをec2にインストールする
gcp: cloud Spanner

## バッチ処理を行う

#### Queuting Chain
連鎖する処理は疎結合に行う。例えば「画像アップロード -> 保存 -> encoding -> サムネイル作成」のような。処理を各インスタンス間で行い、その間のデータの受け渡しをキューサービスを使う。
非同期処理にすることで、すぐにレスポンスを返すことができる。
aws: SQS
gcp: cloud pub/sub

#### Priority Queue
多くの優先順位があるバッチジョブの場合(例えば無料会員より有料会員の方が速く動画が見れたりするなど)、キューを優先順位の数だけ用意する。処理を行う性能は優先順位に合わせて設定する。

#### Job Observer
バッチサーバを負荷分散するとき、リクエスト量をモニタリングしてその量に合わせて仮想サーバを増減するようにする。

#### Schedule Autoscaling
バッチ処理を行う時間は特定の短時間だったりするので、クラウドのスケジューリングの仕組みを使って、その時間帯だけサーバを起動させたり増減させたりする。

## 運用保守を行う

#### Bootstrap
Stampパターンの適用に対して、どのくらいの頻度でマシンイメージを取得するかが課題になる。ミドルウェアからアプリケーションまで全て設定済みの段階だと、イメージを取得して起動すればそのまま立ち上がるが、ミドルウェアを一つバージョンアップしたりするとマシンイメージを作り直しになってしまうことも有り得る。
クラウドのマシンは起動時にパラメータを渡すことができる。起動時にサーバ自らが設定を取得して、そこからインストール、設定、起動を行うようにすれば、イメージの作り直しのような事態は避けられる。

#### Cloud DI
多数のサーバを構築するとき、例えばscale outやauto scaleパターンの時などは、bootstrapパターンが有効だが、外出ししておきたい情報(接続先のdbのipやサーバ名など)が多数ある場合はcloudDIパターンを利用するとより柔軟にサーバの初期化が行える。
bootstrapパターンのような汎用的なイメージに対して固有の設定を行える。

#### Stack Deployment
インスタンス単体ではなく、システムを構成するサーバ群の立ち上げもテンプレート化できる。
構築したい環境で、必要なクラウドコンポーネントをテンプレートに記載しておき、それに従い環境構築を行う。
aws: cloud formation。cloud formerを使えば既存システムからテンプレートを作ることも可能になる。
gcp: computeEngine > インスタンス テンプレート

#### Server Swapping
障害が起きた時、仮想サーバのディスクを別のサーバに付け替えることで対応を行うこと。

#### Monitoring Integration
仮想サーバはクラウドのモニタリングツールで監視し、OS以上の層は自前の仕組みで監視し、クラウドのモニタリングツールのapiを利用することで監視を一元化するようにする。監視の複雑化を解消できる。

#### Web Storage Archive
ログやバックアップなどの大量データの保存先には、クラウドストレージが向いている。ディスク拡張のメンテナンスや事前のキャパシティプランニングが必要ないためお得。

#### Weight Transition
システムを止める事なく移行させたいとき、クラウドのdnsサービスで重み付けラウンドロビンの機能が使える。
名前解決の時点でアクセスの10%を既存から新システムへ行かせるようにし、問題がなければ徐々に割合を増やすことで最小限のdns運用でシステムを移行させられる。

## ネットワークを構築する

#### On Demand NAT
OSのアップデート時など、普段インターネット接続させていないサーバを一時的にnatできるようにしたい時。
NATを仮想サーバで実現して、必要な時だけ起動し、他の対象サーバのサブネットをnatサーバに向けるように設定。立てている間だけnatの課金が行われるためコスパも良い。

#### Backnet
webサービスの管理システムなど、より高いセキュリティを施すために、公開するwebサービスに一般用と管理者用二つのネットワークインターフェースを設定し、sshやログはプライベートなネットワークからでしか行えないようにする。

#### Function Firewall
クラウドのfirewallはルールをグループ化できるので、webサーバやDBサーバなど機能単位で設定をまとめたりサーバへの適用が行える。

#### Operational Firewall
クラウドのfirewallはルールをグループ化できるので、開発やインブラなど組織単位で設定をまとめると、組織に関するアクセス制限を一元化できる。

#### Multi Load Balancer
webアプリをマルチデバイスに対応させたい時、それぞれのデバイスに対する設定を施したlvsを複数立てる。

#### WAF Proxy
WAF: Web Application Firewall。webサービスの前に導入して通信を解析・検査して、脆弱性を突いて不正ログインをしようとするアクセスから守ってくれる。クレカ情報などを扱うサイトがセキュリティを高めるために導入する。
これがクラウドだとスケールアウトなどによってライセンス数が必要になるため導入が困難になりがち。
上流にproxyサーバを置いてWAFをインストールすることで効率的に運用できる。

#### Cloud Hub

VPNの接続方法に関して。フルメッシュ型にすると拠点が増えるごとにメンテナンスが大変になる。
それに引き換えスター型はメンテナンスは楽になるが、hubが落ちると前拠点でvpnが使えなくなるといった可用性が課題だった。
クラウドのvpnのhubは構築も簡単で、その上従量課金制のためコスト効率も良いので従来の課題を解決する。