AWS RDS勉強まとめ

・RDSの制限事項
バージョンが限定
キャパシティに上限
OSログインやファイルシステムへのアクセス不可
など

上記が許容できない場合はOn EC2かオンプレミスで構築

Multi-AZ
同期レプリケーションと自動フェイルオーバー
インスタンスやハードウェア障害時など

リードレプリカ
デフォルトで5台増設可能
マルチAZやクロスリージョン対応も可能
マスタと異なるタイプに設定可能
読み取り専用などに設定し、スループット向上

・スケールアップ、スケールダウン可能

・ストレージタイプ
汎用SSD
プロビジョンドIOPS
マグネティック

・バックアップ
自動スナップショット+トランザクションログをS3に保存
1日1回設定した時間に自動スナップショット取得、保存期間は0日~35日、手動スナップショットも可能

・リストア
スナップショットをもとにDBインスタンス作成
指定した時刻の状態にすることも可能(Point-in-Time)

・スナップショットはDBインスタンスのサイズと同サイズまでコスト無料
・自動スナップショットはDBインスタンス削除と同時に削除
※手動スナップショットは削除されないので、削除前に最終スナップショットをとること推奨
・スナップショット実行時にI/Oが停止するが、マルチAZの場合はスタンバイから取得するためアプリへの影響なし

リネーム
RDSに接続する際のエンドポイントを切り替える機能
旧本番インスタンスをリネーム→新本番インスタンス(スナップショットからリストア)をリネーム

・リネームの注意点
DNSはすぐに切り替わるわけでない
CloudWatchのMetricNameは引き継がない
マスターをリードレプリカの関係、タグ、スナップショットは引き継ぐ

・RDSにかかわる制限事項
RDSインスタンス数:40
1マスターあたりのリードレプリカ数:5
手動スナップショット数:100
DBインスタンスの合計ストレージ:100TB
必要に応じて上限緩和申請

・デフォルトではDBインスタンスに対するネットワークアクセスはオフ
→セキュリティグループで制御し、アクセス許可のポートなどを指定

・DBインスタンスとスナップショットの暗号化可能

オンデマンドDBインスタンスVSリザーブドインスタンス
リザーブドインスタンス:予約金を支払うことで価格割引

参考URL:https://www.slideshare.net/AmazonWebServicesJapan/20170510awsblackbeltrds

続きを読む

AWS再入門 Amazon EC2(Linux)編 | Developers.IO

はじめに AWSチームのすずきです。 Amazon RDS (MySQL, MariaDB)のリードレプリカ、Multi-AZ で利用可能となるアップデートがありました。 その設定を試す機会がありましたので、紹介させて頂きます。 Amazon RDSのリードレプリカがMulti-AZ配置をサポートしました 手順 AWSコンソール リードレプリカのMulti-AZ設定に … 続きを読む

AWSとAzureとGCPを比較してみる – DB編

DBについて、AWSとAzureとGCPを比較してみました。

1. 新世代DB

AWS Azure GCP
新世代DB Aurora Cosmos DB Cloud Spanner
DBの種類 MySQL,
Postgresql
SQL (document DB),
MongoDB (document DB),
Gremlin (graph DB),
Azure Table(KVS),
Cassandra
オリジナルのリレーショナルDB
サーバレスか否か サーバあり サーバレス サーバレス
高可用性構成 / 負荷分散 Auroraレプリカ,
クロスリージョンレプリカ(MySQLのみ)
リージョン間フェイルオーバー,
予約済みスループット
リージョン内レプリケーション,
マルチリージョンレプリケーション
地理的範囲 リージョン(MySQLは別リージョンにレプリケーション可) グローバル グローバル
マルチマスター シングルマスター,
マルチマスター*
マスターになるリージョンは1個 マルチマスター

*プレビュー

DBの種類ですが、Auroraは手堅くMySQLとPostgresql、Cosmos DBはバラエティーにとんでいてドキュメントDB・KVS・グラフDBとCassandra、Cloud SpannerはオリジナルのリレーショナルDBとなっています。
Cloud Spannerはクライアントライブラリが各言語(C#,GO,Java**, node.js**,PHP**, Python**, Ruby)に対し用意されていますが、ORMの対応が気になるところです。
**ベータ

Cosmos DBとCloud Spannerはサーバレスですが、Auroraはインスタンスタイプを指定してインスタンスを構築します。また、拡張機能というよりは別物として、サーバレスタイプのAurora serverless*がプレビュー中です。

高可用性構成と負荷分散ですが、Auroraはリージョン内ではリードレプリカが障害時にマスターに昇格することで対応しています。MySQL版はクロスリージョンレプリケーション構成を取ることができますが、リージョン間で自動フェイルオーバーする仕組みはありません。
また、Auroraはマルチマスター機能であるAurora Multi-Master*が現在プレビュー中ですが、リージョン間でも利用可能になる予定があるとアナウンスされています。リリースされればグローバルで高可用性と負荷分散が簡単に実現できそうです。
Cosmos DBは、1個の書き込みリージョンを持つリージョン間フェイルオーバー***の仕組みで高可用性を実現しています。
Cloud Spannerはリージョン内レプリケーションとマルチリージョンレプリケーションの仕組みで高可用性を実現しています。1つのリージョンで構築する場合は、3個のread-writeレプリカを保持します。複数リージョンで構築する場合は、2個のread-writeレプリカを保持する2個のread-writeリージョン(と場合によってread-onlyリージョン)で構成されます。

***Microsoftのドキュメントではregional failoverをリージョン内フェイルオーバーと訳していますが、意味合いはリージョン間フェイルオーバーなので、ここではそのように表記しています。

2. リレーショナルDB

AWS Azure GCP
MYSQL互換 MySQL
/ MariaDB
Azure Database for MySQL* Google Cloud SQL for MySQL
高可用性構成 Multi-AZ,
クロスリージョンリードレプリカ
フェイルオーバーレプリカ
負荷分散 リードレプリカ,
クロスリージョンリードレプリカ
リードレプリカ
Postgresql Postgresql Azure Database for PostgreSQL* Google Cloud SQL for PostgreSQL**
高可用性構成 Multi-AZ,
クロスリージョンリードレプリカ
リージョナルインスタンス**
負荷分散 リードレプリカ,
クロスリージョンリードレプリカ
リードレプリカ**
SQL Server SQL Server Azure SQL Database
高可用性構成 Multi-AZ アクティブgeoレプリケーション
負荷分散 アクティブgeoレプリケーション
Oracle Oracle
高可用性構成 Multi-AZ
負荷分散

*プレビュー
**ベータ

・各クラウド間での違い-その1

AWSのMulti-AZとGCPのリージョナルインスタンス(PostgreSQL)は、スタンバイ側はリードの機能がないので負荷分散には利用できませんが、GCPのフェイルオーバーレプリカ(MySQL)はリードの機能があるので負荷分散にも利用できます。

3. NOSQL

AWS Azure GCP
KVS・ドキュメント ElastiCache(Memcached, Redis),
DynamoDB
Redis Cache,
Cosmos DB(Azure Table, SQL, MongoDB)
Cloud Datastore,
Cloud Bigtable
グラフ Neptune* Cosmos DB(Gremlin)
Cosmos DB(Cassandra)

*プレビュー

Neptuneの現時点のプレビューのAWSマネジメントコンソール画面はAmazon RDSとよく似ています。また裏でAuroraと同じ仕組みを利用しているそうなので、ひょっとしたらCosmos DBみたいに、Auroraの一機能としてリリースされるかも知れません。

4. まとめ

現在は、MySQL・Postgresqlを利用したければAWSのAuroraかRDS、SQL Serverを利用したければAzureでしょうか。
ただ各クラウドのプレビュー・ベータ提供状況を見ていると、そのうち機能差は無くなるように思えます。

続きを読む

AWSとAzureとGCPを比較してみる – IaaS編

IaaSについて、AWSとAzureとGCPを比較してみました。

注)
Azureについては、リソースマネージャーモデルについて記載しています。
GCPについては、サブネットネットワークについて記載しています。

1. ネットワークの構成要素

AWS Azure GCP
1 リージョン リージョン リージョン
2 VPC 仮想ネットワーク VPCネットワーク
3 アベイラビリティゾーン(AZ) 可用性ゾーン* ゾーン
4 サブネット サブネット サブネット
5 EC2 仮想マシン Compute Engine
6 ネットワークインターフェイス 仮想NIC ネットワークインターフェイス
7 セキュリティーグループ ネットワークセキュリティグループ(NSG) ファイアウォールルール
8 ネットワークACL ネットワークセキュリティグループ(NSG) ファイアウォールルール

*プレビュー

2. リージョンとアベイラビリティゾーンとVPCとサブネット

IaaS比較vpc (1).png

リージョンは地理的に離れたロケーションことで、さらに1つのリージョンはデータセンターが設置される複数の独立したアベイラビリティゾーン(Azure:可用性ゾーン、GCP:ゾーン)から構成されます。
(*但しAzure:可用性ゾーンは未だプレビュー)

VPC(Azure:仮想ネットワーク)は、他と論理的に切り離された仮想ネットワークのことで、その中に1つまたは複数のサブネットを定義してEC2(Azure:仮想マシン、GCP:Compute Engine)を配置します。

複数のアベイラビリティゾーン(Azure:可用性ゾーン、GCP:ゾーン)にEC2等を配置し冗長構成をとることにより、可用性を高めることができます。(AWS用語でMulti-AZ)

Azureの可用性ゾーンは未だプレビューなので、現時点で冗長構成をとるためには可用性セットを構成します。
一方AWSは2017のre:InventでAzureの可用性セットと似た機能を提供するスプレッドプレイスメントグループをリリースしています。こちらは複数のアベイラビリティゾーンにまたがることが可能です。

・各クラウド間での違い-その1

AWSはアベイラビリティゾーンをまたがってサブネットを構成することができませんが、AzureとGCPは可用性ゾーン・ゾーンをまたがってサブネットを構成します。

・各クラウド間での違い-その2

AWSとAzureはVPC・仮想ネットワークに対しCIDR表記でIPアドレス空間を指定する必要があり、サブネットはVPCのIPアドレス空間の範囲に制限されますが、GCPはVPCに対しIPアドレス空間を指定せず、サブネットはRFC1918の範囲で自由に割り当てることができます。(例:192.168.0.0/24と10.0.1.0/24等)

3. セキュリティーグループとネットワークACL

IaaS比較sg.png

AWSはEC2のネットワークインターフェースに対しセキュリティグループを、サブネットに対しネットワークACLを関連づけることにより、INとOUTのネットワークトラフィックを制御します。
Azureは仮想マシンのNICやサブネットに対しネットワークセキュリティグループ(NSG)を関連づけることにより、INとOUTのネットワークトラフィックを制御します。
一方GCPはVPCネットワークに対しファイアウォールルールを設定することにより、INとOUTのネットワークトラフィックを制御します。設定がサブネット単位ではなくまた宛先をCIDRで指定できないため、サブネット単位で制御したい場合はタグを利用する場合もあります。

・各クラウド間での違い-その3

AWSのネットワークACLはセキュリティーグループと違いステートレスなので、明示的に戻りのトラフィックを許可する必要があります。

・各クラウド間での違い-その4

AWSのセキュリティーグループは、ネットワークACLやAzure・GCPと異なり許可のみ設定が可能です。

4.コスト

AWS Azure GCP
インスタンスの課金単位 秒単位(最小課金時間60秒) 分単位 秒単位(最小課金時間60秒)
長期利用割引の仕組み リザーブドインスタンス(1年または3年) Reserved VM Instances(1年または3年) 確約利用割引(1年または3年)・継続利用割引(自動適用)
短期利用割引の仕組み スポットインスタンス (Batch low-priority VM)* プリエンプティブインスタンス

*現在はAzure Batchのみ

秒単位の課金のAWSとGCPに比べ分単位の課金のAzureの方が不利に見えますが、下記ブログを信じる限り秒以下を切り捨てて課金するためAWSやGCPよりちょっとお買い得です。
 In Azure, we bill all virtual machines (VMs) running Linux and Windows on a per-minute basis, rounded down to the nearest minute.

・各クラウド間での違い-その5

AWSのスポットインスタンス、GCPのプリエンプティブインスタンスに相当するものがAzureにはありません。
ただ現在Azure Batchに限りlow-priority VMが利用できます。Azureのドキュメントに下記記述があるので、将来は仮想マシンでも利用できるようになるかもしれません。
 Low-priority VMs are currently available only for workloads running in Batch.

5. まとめ

AWS・Azure・GCP間でいくつか違いがあるものの、基本的な部分はそこまで大きな差はないようです。
他クラウドにあるがまだ無い機能がプレビュー提供中だったりと、どんどん違いが無くなって均質化していく感じがします。

続きを読む

【AWS】Aurora(MySQL)のCluster/Instanceを自動的に削除/リストアする【Aurora】

はじめに

Auroraがリリースされてから後、AWS上で稼働するサービスでAuroraを利用している諸兄諸姉が多いのではないかと思います。

RDS全般にまつわる悩み事ですが、開発環境の費用削減のため、RDSを利用しない間は停止したいと思っても、
RDSは容易に停止できない、削除することしかできないという制約があります。

そこで、Aurora Cluster/Instanceのsnapshotを作成して削除するスクリプトと、
削除時と同じ構成のAurora Cluster/Instanceをリストアするスクリプトを作ってみましたので、参考までに公開します。

このスクリプトを実際に利用したことにより発生した損害等には責任を負いません。
また、利用に関するサポートは致しません。
飽くまで参考程度にしてください。

基本的な考え方

Auroraはその構成上、単一インスタンス構成であろうとも、必ずClusterとして構成されます。

Auroraインスタンスの作成/削除時の流れは概ね下記のようになります。
簡単に言うと、Clusterというガワがまず存在して、ここにInstanceを追加/削除していく、というイメージになります。

  • インスタンス削除

    • メンバーInstanceを削除する
    • Instanceの削除完了を待つ(対象Instanceが存在しなくなる、ClusterのDBClusterMembersが存在しなくなる)
    • Clusterを削除する。併せて、snapshotを作成する。
    • Clusterの削除完了を待つ
  • インスタンス作成
    • Aurora Clusterを作成する
    • Clusterの作成完了を待つ(Statusがavailableになる)
    • 作成したClusterのメンバーとなるInstanceを作成する
    • Instanceの作成完了を待つ(Statusがavailableになる)

スクリプトの解説

前提条件

  • 既に存在しているAurora Cluster/Instanceを削除し、これを任意のタイミングでリストアする、という利用方法を想定しています。
  • このスクリプトはAWS CLIがインストールされたLinuxで動作します。
  • AWS CLIに環境ごとのprofileが設定されていることとします。
  • 対象はAurora(MySQL)エンジンのみとし、1Cluster・1Instance構成のみに対応しています。
  • Cluster名はInstance名に「-cluster」サフィックスが付与された名称とします。

2インスタンス以上のClusterは対象としていません。
こまめな削除・リストアを必要とするのは検証や開発で利用する環境のみであること、
それらの環境は通常はシングルインスタンスの最小構成であることから、このような前提となっています。

検証した環境

OS: CentOS Linux release 7.2.1511
Bash: GNU bash, version 4.2.46(1)-release (x86_64-redhat-linux-gnu)
AWS CLI: aws-cli/1.11.63 Python/2.7.5 Linux/3.10.0-327.22.2.el7.x86_64 botocore/1.5.26

Cluster/Instance削除

第1引数にAWS CLIのプロファイルを、第2引数には削除対象のAurora Instanceを改行(LFのみ)で羅列したファイルを指定します。
また、空行をスキップする処理は入れていないので、空行は含めないようにしてください。

具体的には、下記のようなファイルとなります。

rds-aurora-instance1
rds-aurora-instance2

Aurora Clusterは、Aurora Instance名に「-cluster」サフィックスが付与されたものと想定します。

これを実行すると、カレントディレクトリ配下に「result-delete-yyyymmdd」というディレクトリが作成され、ログ等が出力されます。
削除したCluster/Instanceに関する情報がJSONとして出力されますが、これはリストア時に必要となります。
# 上記JSONは、rds-describe-db-clusters及びrds-describe-db-instancesの実行結果となります。

RDS snapshotとして、「Instance名-yyyymmdd」と「Instance名-final」の2つが作成されます。
「Instance名-final」は次回削除時に手動で削除する必要があるため、誤操作に対する備えとして、「Instance名-yyyymmdd」を作成するようにしています。

#!/bin/sh


if [ $# -lt 2 ] ;then
    echo "usage: $0 <AWS CLI profile> <Listfile of RDS instances to be deleted>"
    exit 1;
fi


AWS_CLI_PROFILE=$1
RDS_LIST=$2

CURRENT_DATE=`TZ=Asia/Tokyo date +%Y%m%d`
CURRENT_DATETIME=`TZ=Asia/Tokyo date +%Y%m%d-%H%M%S`

OUTPUT_DIR="./result-delete-${CURRENT_DATE}"
LOG_STDOUT_FILE=${OUTPUT_DIR}/rds_delete_instance_${CURRENT_DATETIME}_stdout.log
LOG_STDERR_FILE=${OUTPUT_DIR}/rds_delete_instance_${CURRENT_DATETIME}_stderr.log
TMP_FILE=`mktemp`

alias aws="aws --profile ${AWS_CLI_PROFILE}"

mkdir -p ${OUTPUT_DIR}

#
# Utility Functions
#

function log_both () {
    echo "[`date +%Y-%m-%dT%H:%M:%S%z`] " $1 >> ${LOG_STDOUT_FILE}
    echo "[`date +%Y-%m-%dT%H:%M:%S%z`] " $1 >> ${LOG_STDERR_FILE}
    return
}

function log_std () {
    echo "[`date +%Y-%m-%dT%H:%M:%S%z`] " $1 >> ${LOG_STDOUT_FILE}
    return
}

function log_err () {
    echo "[`date +%Y-%m-%dT%H:%M:%S%z`] " $1 >> ${LOG_STDERR_FILE}
    return
}

function _describe_current_information (){
    local _rds_instance=$1
    local _rds_cluster=$2
    local _cmd

    # fetch current information of the RDS instance
    log_both "creating snapshots of \"${_rds_instance}\""
    _cmd="aws --profile ${AWS_CLI_PROFILE} rds describe-db-instances --filters Name=db-instance-id,Values=${_rds_instance}" >> ${LOG_STDOUT_FILE} 2>> ${LOG_STDERR_FILE}
    log_both "invoking an AWS API: \"${_cmd}\"."
    $_cmd > ${TMP_FILE} 2>> ${LOG_STDERR_FILE}
    cat ${TMP_FILE} >> ${LOG_STDOUT_FILE}
    cp ${TMP_FILE} ${OUTPUT_DIR}/${_rds_instance}_instance_information_${CURRENT_DATETIME}.json

    # fetch current information of the RDS cluster
    _cmd="aws --profile ${AWS_CLI_PROFILE} rds describe-db-clusters --filters Name=db-cluster-id,Values=${_rds_cluster}"
    log_both "invoking an AWS API: \"${_cmd}\"."
    $_cmd > ${TMP_FILE} 2>> ${LOG_STDERR_FILE}
    cat ${TMP_FILE} >> ${LOG_STDOUT_FILE}
    cp ${TMP_FILE} ${OUTPUT_DIR}/${_rds_instance}_cluster_information_${CURRENT_DATETIME}.json

}

function _create_snapshot (){
    local _rds_cluster=$1
    local _rds_snapshot=$2
    local _cmd

    # create an explicit snapshot
    _cmd="aws --profile ${AWS_CLI_PROFILE} rds create-db-cluster-snapshot --db-cluster-identifier ${_rds_cluster} --db-cluster-snapshot-identifier ${_rds_snapshot}"
    log_both "invoking an AWS API: \"${_cmd}\"."
    $_cmd >> ${LOG_STDOUT_FILE} 2>> ${LOG_STDERR_FILE}

}

function _delete_instance (){
    local _rds_instance=$1
    local _cmd
    local _instance_num

    _cmd="aws --profile ${AWS_CLI_PROFILE} rds delete-db-instance --db-instance-identifier ${_rds_instance}"
    log_both "invoking an AWS API: \"${_cmd}\"."
    $_cmd >> ${LOG_STDOUT_FILE} 2>> ${LOG_STDERR_FILE}

    _cmd="aws --profile ${AWS_CLI_PROFILE} rds describe-db-instances --filters Name=db-instance-id,Values=${_rds_instance}"
    log_both "invoking an AWS API: \"${_cmd}\"."
    $_cmd >> ${LOG_STDOUT_FILE} 2>> ${LOG_STDERR_FILE}


    # wait to finish deliting the RDS instance
    log_both "waiting to finish deleting the RDS instance \"${_rds_instance}\"."
    _cmd="aws --profile ${AWS_CLI_PROFILE} rds describe-db-instances --filters Name=db-instance-id,Values=${_rds_instance}"
    log_both "checking the RDS instance sutatus with the following AWS API: \"${_cmd}\"."

    while true
    do
        sleep 10

        _instance_num=`${_cmd} | jq '.DBInstances | length'`
        if [ ${_instance_num} -eq 1 ];then
            continue
        fi

        break
    done

    log_both "deleting the RDS instance \"${_rds_instance}\" has been finished."
}

function _delete_cluster (){
    local _rds_cluster=$1
    local _rds_snapshot=$2

    # wait until the members of its cluster is 0.
    log_both "waiting to change the members of the cluster \"${_rds_cluster}\" 0."
    _cmd="aws --profile ${AWS_CLI_PROFILE} rds describe-db-clusters --db-cluster-identifier ${_rds_cluster}"
    log_both "checking whether the members of the cluster is 0 with the following AWS API: \"${_cmd}\"."

    while true
    do
        sleep 5

        _instance_num=`${_cmd} | jq '.DBClusters[0].DBClusterMembers | length'`
        if [ ${_instance_num} -ne 0 ];then
            continue
        fi

        break
    done

    log_both "current cluster status: \"${_cmd}\"."
    $_cmd >> ${LOG_STDOUT_FILE} 2>> ${LOG_STDERR_FILE}

    # start deleting the cluster
    _cmd="aws --profile ${AWS_CLI_PROFILE} rds delete-db-cluster --db-cluster-identifier ${_rds_cluster} --final-db-snapshot-identifier ${_rds_snapshot}"
    log_both "invoking an AWS API: \"${_cmd}\"."
    $_cmd >> ${LOG_STDOUT_FILE} 2>> ${LOG_STDERR_FILE}

    _cmd="aws --profile ${AWS_CLI_PROFILE} rds describe-db-clusters --filters Name=db-cluster-id,Values=${_rds_cluster}"
    log_both "invoking an AWS API: \"${_cmd}\"."
    $_cmd >> ${LOG_STDOUT_FILE} 2>> ${LOG_STDERR_FILE}

}


#
# Main Function
#

    #
    # Description:
    #   This program deletes an Aurora RDS cluster and its instance and creates its snapshots automatically.
    #   It enables you to treat an RDS as if it can stop/start instances.
    #   It deal with each RDS instances one by one.
    #   It assumes that the cluster name is a combination with its instance name and a "-cluster" suffix.
    #
    # How it works in detail:
    #   1. Fetch current information. It will be saved into the ${OUTPUT_DIR} directory.
    #   2. Create its snapshot. it will be named what consists its instance name and a datetime suffix.
    #   3. Delete the RDS instance with creating a snapshot named what is the same as its instance name.
    #
    # License:
    #   Copyright (c) 2017 Taichi Miki
    #   Released under the MIT license
    #


    log_both "a temporary file is ${TMP_FILE}"

    for _rds_instance in `grep -v "^#.*$" ${RDS_LIST}`
    do

        _rds_cluster="${_rds_instance}-cluster"

        log_both "Start deleting the instance \"${_rds_instance}\", cluster \"${_rds_cluster}\" with creating snapshots."

        # fetch current information
        _describe_current_information ${_rds_instance} ${_rds_cluster}

        # create an explicit snapshot
        _create_snapshot ${_rds_cluster} "${_rds_instance}-${CURRENT_DATE}"

        # delete the RDS instance
        log_both "deleting the instance \"${_rds_instance}\""
        _delete_instance ${_rds_instance}


        # delete the RDS cluster with creating a snapshot
        log_both "deleting the cluster \"${_rds_cluster}\""
        _delete_cluster ${_rds_cluster} "${_rds_instance}-final"

        log_both "the deleting process for the instance \"${_rds_instance}\", cluster \"${_rds_cluster}\" has been finished."
    done

    log_both "delete the temporary file \"${TMP_FILE}\"."
    rm ${TMP_FILE}

    log_both "the deleting process for all instances has been finished."

Cluster/Instanceリストア

第1引数にAWS CLIのプロファイルを指定します。
第2引数には下記項目を「,」で区切って並べたファイルを指定します。項目の間には空白を含めないようにしてください。
空白を含めると確実に動かなくなります。

  • Aurora Instance名
  • リストアさせたいSnapshot名
  • 対象Aurora Clusterに対して、削除前に取得したrds-describe-db-clustersの実行結果(JSON形式)
  • 対象Aurora Instanceに対して、削除前に取得したrds-describe-db-instancesの実行結果(JSON形式)

Aurora Clusterは、Aurora Instance名に「-cluster」サフィックスが付与されたものと想定します。

上記項目のうち、3つ目と4つ目のファイルは、Cluster/Instance削除時に出力されたファイルを指定する想定です。
対象を複数指定する場合は、改行(LFのみ)で羅列したファイルを指定します。
また、空行をスキップする処理は入れていないので、空行は含めないようにしてください。

具体的には、下記のようなファイルとなります。

rds-aurora-instance1,rds-aurora-instance1-final,rds-aurora-instance1_cluster_information.json,rds-aurora-instance1_instance_information.json
rds-aurora-instance2,rds-aurora-instance2-final,rds-aurora-instance2_cluster_information.json,rds-aurora-instance2_instance_information.json

これを実行すると、カレントディレクトリ配下に「result-restore-yyyymmdd」というディレクトリが作成され、ログ等が出力されます。
VPCやDB Subnet Group, Security Groupなど、Aurora Cluster/Instance構築に必要な情報は、
削除前に実行したrds-describe-db-clusters/rds-describe-db-instancesの実行結果から取得します。

#!/bin/sh


if [ $# -lt 2 ] ;then
    echo "usage: $0 <AWS CLI profile> <List file consists an RDS restoration definition.>"
    echo "       The list file is like a CSV file consists 4 parameters those are"
    echo "       \"instance name\", \"snapshot name\", \"Information of the cluster\", \"Information of the instance\"."
    echo '       The 3rd and 4th parameters in the argument file are the result of AWS APIs "describe-db-cluster" and "describe-db-instances"'
    echo '       when the cluster and the instance were still alive.'
    exit 1;
fi


AWS_CLI_PROFILE=$1
RDS_LIST=$2

CURRENT_DATE=`TZ=Asia/Tokyo date +%Y%m%d`
CURRENT_DATETIME=`TZ=Asia/Tokyo date +%Y%m%d-%H%M%S`

OUTPUT_DIR="./result-restore-${CURRENT_DATE}"
LOG_STDOUT_FILE=${OUTPUT_DIR}/rds_delete_instance_${CURRENT_DATETIME}_stdout.log
LOG_STDERR_FILE=${OUTPUT_DIR}/rds_delete_instance_${CURRENT_DATETIME}_stderr.log
TMP_FILE=`mktemp`

alias aws="aws --profile ${AWS_CLI_PROFILE}"

mkdir -p ${OUTPUT_DIR}

#
# Utility Functions
#

function log_both () {
    echo "[`date +%Y-%m-%dT%H:%M:%S%z`] " $1 >> ${LOG_STDOUT_FILE}
    echo "[`date +%Y-%m-%dT%H:%M:%S%z`] " $1 >> ${LOG_STDERR_FILE}
    return
}

function log_std () {
    echo "[`date +%Y-%m-%dT%H:%M:%S%z`] " $1 >> ${LOG_STDOUT_FILE}
    return
}

function log_err () {
    echo "[`date +%Y-%m-%dT%H:%M:%S%z`] " $1 >> ${LOG_STDERR_FILE}
    return
}

function _describe_current_information (){
    local _rds_instance=$1
    local _rds_cluster=$2
    local _cmd

    # fetch current information of the RDS instance
    log_both "creating snapshots of \"${_rds_instance}\""
    _cmd="aws rds describe-db-instances --filters Name=db-instance-id,Values=${_rds_instance}" >> ${LOG_STDOUT_FILE} 2>> ${LOG_STDERR_FILE}
    log_both "invoking an AWS API: \"${_cmd}\"."
    $_cmd > ${TMP_FILE} 2>> ${LOG_STDERR_FILE}
    cat ${TMP_FILE} >> ${LOG_STDOUT_FILE}
    cp ${TMP_FILE} ${OUTPUT_DIR}/${_rds_instance}_instance_information_${CURRENT_DATETIME}.json

    # fetch current information of the RDS cluster
    _cmd="aws rds describe-db-clusters --filters Name=db-cluster-id,Values=${_rds_cluster}"
    log_both "invoking an AWS API: \"${_cmd}\"."
    $_cmd > ${TMP_FILE} 2>> ${LOG_STDERR_FILE}
    cat ${TMP_FILE} >> ${LOG_STDOUT_FILE}
    cp ${TMP_FILE} ${OUTPUT_DIR}/${_rds_instance}_cluster_information_${CURRENT_DATETIME}.json

}

function _create_cluster (){
    local _rds_cluster=$1
    local _snapshot=$2
    local _cluster_json_file=$3

    local _db_subnet_group_name=`cat ${_cluster_json_file} | jq -r '.DBClusters[0].DBSubnetGroup'`
    local _vpc_security_group_ids=`cat ${_cluster_json_file} | jq -r '.DBClusters[0].VpcSecurityGroups[0].VpcSecurityGroupId'`

    local _cmd


    _cmd="aws rds restore-db-cluster-from-snapshot --engine aurora --db-cluster-identifier ${_rds_cluster} --snapshot-identifier ${_snapshot} --db-subnet-group-name ${_db_subnet_group_name} --vpc-security-group-ids ${_vpc_security_group_ids}"
    log_both "invoking an AWS API: \"${_cmd}\"."

    $_cmd >> ${LOG_STDOUT_FILE} 2>> ${LOG_STDERR_FILE}


    _cmd="aws rds describe-db-clusters --filters Name=db-cluster-id,Values=${_rds_cluster}"
    log_both "invoking an AWS API: \"${_cmd}\"."
    $_cmd >> ${LOG_STDOUT_FILE} 2>> ${LOG_STDERR_FILE}

    # wait until the cluster's status changed into available.
    log_both "waiting to finish creating the RDS cluster \"${_rds_cluster}\"."

    while true
    do
        sleep 15

        _rds_status=`${_cmd} | jq -r '.DBClusters[0].Status'`
        if [ ${_rds_status} == "available" ];then
            break
        fi

    done
}

function _modify_cluster (){
    local _rds_cluster=$1
    local _cluster_json_file=$2

    local _db_cluster_parameter_group_name=`cat ${_cluster_json_file} | jq -r '.DBClusters[0].DBClusterParameterGroup'`

    local _cmd

    _cmd="aws rds modify-db-cluster --db-cluster-identifier ${_rds_cluster} --db-cluster-parameter-group-name ${_db_cluster_parameter_group_name}"
    log_both "invoking an AWS API: \"${_cmd}\"."
    $_cmd >> ${LOG_STDOUT_FILE} 2>> ${LOG_STDERR_FILE}

    _cmd="aws rds describe-db-clusters --filters Name=db-cluster-id,Values=${_rds_cluster}"
    log_both "invoking an AWS API: \"${_cmd}\"."
    $_cmd >> ${LOG_STDOUT_FILE} 2>> ${LOG_STDERR_FILE}

}


function _create_instance (){
    local _rds_instance=$1
    local _rds_cluster=$2
    local _instance_json_file=$3

    local _db_instance_class=`cat ${_instance_json_file} | jq -r '.DBInstances[0].DBInstanceClass'`
    local _db_parameter_group_name=`cat ${_instance_json_file} | jq -r '.DBInstances[0].DBParameterGroups[0].DBParameterGroupName'`

    local _cmd

    _cmd="aws rds create-db-instance --engine aurora --db-cluster-identifier ${_rds_cluster} --db-instance-identifier ${_rds_instance} --db-instance-class ${_db_instance_class} --db-parameter-group-name ${_db_parameter_group_name} --no-multi-az --no-publicly-accessible"
    log_both "invoking an AWS API: \"${_cmd}\"."
    $_cmd >> ${LOG_STDOUT_FILE} 2>> ${LOG_STDERR_FILE}

}


#
# Main Function
#

    #
    # Description:
    #   This program restores an Aurora(MySQL) cluster with one instance from a snapshot.
    #   It assumes that the cluster name is a combination with its instance name and a "-cluster" suffix.
    #
    #   The 3rd and 4th parameter in the argument file
    #   are the result of AWS APIs "describe-db-cluster" and "describe-db-instances"
    #   when the cluster and the instance are still alive.
    #
    # How it works in detail:
    #   1. read argument file and separate each line by one comma ",".
    #   2. get information of the cluster and instance to check they don't exist yet.
    #   3. create an Aurora(MySQL) cluster with parameters indicated by the information json file..
    #   4. modify the cluster's parameter group, because it cannot be set at creating.
    #   5. create an RDS instance as a member of the cluster.
    #
    # License:
    #   Copyright (c) 2017 Taichi Miki
    #   Released under the MIT license
    #

    log_both "a temporary file is ${TMP_FILE}"

    for _restore_definition in `grep -v "^#.*$" ${RDS_LIST}`
    do

        _rds_instance=`echo ${_restore_definition} | awk -F, '{print $1};'`
        _rds_cluster=${_rds_instance}-cluster
        _snapshot=`echo ${_restore_definition} | awk -F, '{print $2};'`
        _cluster_info_json=`echo ${_restore_definition} | awk -F, '{print $3};'`
        _instance_info_json=`echo ${_restore_definition} | awk -F, '{print $4};'`

        log_both "Start restoring the instance \"${_rds_instance}\", cluster \"${_rds_cluster}\" from the snapshot \"${_snapshot}\"."

        # fetch current information
        _describe_current_information ${_rds_instance} ${_rds_cluster}

        # create the RDS cluster
        log_both "creating a cluster \"${_rds_cluster}\""
        _create_cluster ${_rds_cluster} ${_snapshot} ${_cluster_info_json}

        # modify the cluster's parameter group
        log_both "modifying the cluster \"${_rds_cluster}\" to set its parameter group appropriately."
        _modify_cluster ${_rds_cluster} ${_cluster_info_json}

        # create an RDS instance
        log_both "creating an instance \"${_rds_instance}\" into the cluster \"${_rds_cluster}\"."
        _create_instance ${_rds_instance} ${_rds_cluster} ${_instance_info_json}


        log_both "the restoring process for the instance \"${_rds_instance}\", cluster \"${_rds_cluster}\" has been finished."
    done

    log_both "delete the temporary file \"${TMP_FILE}\"."
    rm ${TMP_FILE}

    log_both "the restoring process for all instances has been finished."

おわりに

Githubは準備中…

続きを読む

【01.リージョン / アベイラビリティゾーンとAWSサービスレベルについて】

はじめに

AWS認定ソリューションアーキテクト[アソシエイト]試験を受験するにあたり、
必要な基礎知識を #備忘録 も兼ねて記載していきます。

全体の流れにご興味がある方は、下記記事をご覧ください!
AWS認定ソリューションアーキテクト[アソシエイト] 合格までの奮闘記 (WIP)

1. リージョン (Region)

リージョン(Region) 自体は「範囲、領域」を持つ英単語 :point_up:
Amazon クラウドコンピューティングリソース世界各地の多くの場所でホストされており、
これらの世界各地の拠点リージョン(Region)と言います。

2017/10/12(木)時点で、世界中に16個ものリージョン(Region)が存在します。

(以下、「AWS公式サイト」より引用。)

image.png

初めてAWSサービスに触れられる方は、物理的に距離が近い、
アジアパシフィック [ 東京 (3) = ap-northeast-1 ] を選ばれることをお勧めいたします。

※今後、さらに5つのリージョンが追加される予定みたいです。( 2017 / 10 / 12 時点 )

・中国
・フランス
・香港
・スウェーデン
・米国 ( 2番目のAWS GovCloudリージョン )

[参考サイト]

2. アベイラビリティーゾーン (AZ : Availability Zone)

アベイラビリティーゾーンを物凄く分かりやすく、簡単に説明すると、

東京リージョン(物理的に離れた場所)= 「東京」という都市に、
地理的、電力的に独立した3つのデータセンター群 ( 拠点 ) が存在し、
この各々のデータセンター群のことを「 アベイラビリティーゾーン ( AZ ) 」と言います。

画像で表すと、下記のようなイメージです。

AWS.jpg

1つのリージョン内に2つ以上のアベイラビリティーゾーン(データセンター)が存在するので、
インフラ設計をする際は、複数のアベイラビリティーゾーン(Multi-AZ)を活用することにより、
構築するインフラ/アプリケーションの耐障害性を向上させることができます。

「リージョンとアベイラビリティゾーンに関する概念について」
各リージョンは完全に独立しています。各アベイラビリティーゾーンも独立していますが、
同じリージョン内のアベイラビリティーゾーン同士は低レイテンシーのリンクで接続されています。
http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/using-regions-availability-zones.html

AWSの3つのサービスレベルに関して


上記のように、世界各地にリージョンが存在するAWSですが、
サービスによって提供される場所が異なります。

  • リージョンごとに作成・管理される リージョンサービス
  • AZごとに作成・管理される AZ サービス
  • どこのリージョンからでも共通のサービスとして利用できる グローバルサービス

続きを読む

俺が結論づけたterraformベスト・プラクティスとworkspaceとmodule考え方(AWS Provider編)

俺です。
最強のテラフォーマーズなみなさんこんばんは。
久しぶりにterraformを弄っていて、かっこよくworkspaceとmodule使ってapplyキメたくなったので、どうつかったもんか、纏めたものです。

対応バージョン

  • 本体: terraform v0.11.1
  • provider: aws v1.5.0

terraform運用俺なりの結論

素terraformが一番ラク

それでも俺はWorkspaceやModuleを駆使するterraform新人類であり続けるぜ。むしろ既に触りすぎてて離れられない体だわはっはっはという俺な方は考え方読み飛ばしてどうぞ

考え方

  • 全部寺したいかたは寺どうぞ。
  • terraformは文学, CloudFormationは芸術, プルリクは人生, コードレビューは友情です。

環境構築

  • 設計思想やModule仕様をまとめたDocumentを常々更新するパワーがない
  • チームメンバーに伝達して一定品質保てるようなパワーがなければ素のterraformが楽です

運用

  • 全部寺でもいいけどLaunch/create/attach/destroyする、に留めるのがよいです
  • ルールの更新については俺達のCodenize.toolsで補えるものはこっちに寄せる方がRuby DSLによる表現力の高さや強力なDry-Runの恩恵を受けることができます。最高。
  • stateを持つコンポーネントであるRDSやElastiCache周りの構成変更はDestory判定から逃れられないものが多いのでCLIが安牌です

ex)ElastiCache Redisのreplication group memberの修正(Single-AZ->Multi-AZ化)

  • 1nodeのreplication group作成
  • number of nodeを1->2にするとDestroy -> Create判定になる

結局俺が選んだ最強のterraform設計is…?

  • Workspaceと異なり視覚効果に優れた方針を最強Opsの@shiruさんが公開してくれている。いきなりWorkspace/Moduleへ手を出す前に俺はコッチのほうをオススメしたい

それでもWorkspaceとModuleを使うんや!という方は次いってみましょー。

Workspaceについて

仮想的なディレクトリです。
terraform_workspace.png

resource内に ${terraform.env} を記述することでplan/apply時にcurrent workspace名が読み込まれ、冗長なコードを削減することができます。
上記図の例では、構築/運用対象の環境をworkspaceに収めることで、plan/apply実行時の構成変更対象を環境単位に実行することができます。

詳しくはssh絶対殺すマン@shogomuranushiさんのTerraform Best Practices in 2017を読むと良いです。

Workspaceの実装方法

ぼくはEC2原人なのでVPCを中心に実装方法を考えます。
今回の内容はregionについてはふれません。
マルチリージョンで構成される場合は他のWorkspaceの考え方がでてくるとも思います。

難易度 俺俺名称 VPCの状態 環境分離の方法
専用テナント型 環境ごとにVPCが分離されている場合 develop/stage/productionといった名称のVPCで環境が分離されている
共有テナント型 環境がVPCで分離されていない 1VPCとしてセキュリティグループレベルで環境が分離されている

専用テナント型

dedicated_workspace.png

全環境内に作るリソースを均一にできる場合はコレが最も楽です。
workspaceを切り替えてplan->applyでOKです。

terraform workspace new <環境名>
terraform workspace select <環境名>
module "ad" {
    source = "../../modules/provider/aws/ec2"
    ec2 = "${var.ad}"
    iam_instance_profile = "${data.terraform_remote_state.iam.activedirectory["name"]}"
    subnet_id = "${data.terraform_remote_state.network.vpc.${terraform.env}.protected-route-nat-a}"
    vpc_security_group_ids = ["${data.terraform_remote_state.network.common["id"]}",
                              "${data.terraform_remote_state.network.ad["id"]}"]
}

共有テナント型

shared_workspace.png

1VPCに複数の環境を作り、SGで分離する場合
これもworkspaceを切り替えてplan->applyでOKですが共有テナントを呼び出す時は${terraform.env}を書かないようにします。

terraform workspace new <環境名>
terraform workspace select <環境名>

★の箇所で${terraform.env}を指定せず、共有テナントが存在するworkspace名を直接指定する。

module "ad" {
    source = "../../modules/provider/aws/ec2"
    ec2 = "${var.ad}"
    iam_instance_profile = "${data.terraform_remote_state.iam.activedirectory["name"]}"
★    subnet_id = "${data.terraform_remote_state.network.vpc.prod.protected-route-nat-a}"
    vpc_security_group_ids = ["${data.terraform_remote_state.network.common["id"]}",
                              "${data.terraform_remote_state.network.ad["id"]}"]
}

Moduleについて

どこまでモジュール化するか。ちょっと悩みます。
なんでもモジュール化は良くないです。
モジュール化のレベルをキメておくのが良いです。
俺は2レベルでのモジュール化を推したいと思います。

public module

実体。俗に言うガワの定義
第三者に公開してもよい定義を表す。github.com などで公開してもよい。
リソース例:aws_vpc,aws_subnet,aws_instance,aws_eip等

private module

環境固有の情報が含れる属性を表す。
github.comのプライベートリポジトリやgithub enterprise上で管理する。
terraformにおいてガワと属性を分離して定義できないものもprivate moduleとして扱うのがよい。

リソース例:aws_security_group_rule, aws_elb等。ガワに対して中身をどうするかの定義。
SGの定義(企業のIPが入ってるもの)はPrivate moduleとして管理して使いまわせるとメンテが楽。
※aws_elbはELBとlistenerを分離して作成できないためprivate module化がよい。

やるな module

そもそもモジュール化してはならないモノ
実態と属性の関連付けを行うリソースはモジュールしないことが吉
リソース例: aws_elb_attachment,aws_eip_association等

Moduleの呼び出し例

  • 実体のvariable
variable "ad" {
    type = "map"
    default = {
        prod.ami = "ami-ec279c8a"  # Windows 2016
        prod.key_name = "XXXXXXXx"
        prod.public_key = "**********"
        prod.instance_type = "t2.medium"
        prod.iam_instance_profile = "ad"
        prod.source_dest_check = true
        prod.ebs_optimized = false
        prod.root_block_device = "gp2"
        prod.root_block_device_size = 64
        prod.ec2_count = 1
        prod.eip_count = 0
        prod.tag_name = "ad"
        prod.tag_role = "ad"
        prod.tag_amirotate = ""
    }
}
variable "ad_elb" {
    type = "map"
    default = {
        prod.name = "ad-elb"
        prod.instance_port = "3389"
        prod.availability_zones = ["ap-northeast-1a","ap-northeast-1c"]
        prod.access_logs_bucket = "XXXXXXXXXXX"
        prod.access_logs_bucket_prefix = ""
        prod.instance_protocol = "tcp"
        prod.lb_port = 3389
        prod.lb_protocol = "tcp"
        prod.lb_healthcheck_interval = 30
        prod.healthy_threshold = 2
        prod.unhealthy_threshold = 3
        prod.lb_target_timeout = 15
        prod.lb_healthcheck_interval = 5
        prod.cross_zone_load_balancing = true
        prod.idle_timeout = 60
        prod.connection_draining = 10
        prod.connection_draining_timeout = 15
    }
}
  • 実体の作成と関連付け
module "ad" {
    source = "../../modules/provider/aws/ec2"
    ec2 = "${var.ad}"
    iam_instance_profile = "${data.terraform_remote_state.iam.activedirectory["name"]}"
    subnet_id = "${data.terraform_remote_state.network.vpc.prod.protected-route-nat-a}"
    vpc_security_group_ids = ["${data.terraform_remote_state.network.common["id"]}",
                              "${data.terraform_remote_state.network.ad["id"]}"]
}

module "ad_elb" {
    source = "../../modules/provider/aws/loadbalancer/elb"
    elb = "${var.ad_elb}"
}

resource "aws_elb_attachment" "ad" {
  elb      = "${module.ad_elb.id}"
  instance = "${module.adelb.id}"
}

これで作り込みすぎないモジュール人生が送れると思います。

workspaceとmoduleの図解

2つを組み合わせるとこーんなかんじになります。
これの学習コストは高いか、低いかというと実装していて高いなって感じました。
workspace_and_module.png

terraformをこれから始めよう、とりあえず素terraformから卒業しようという方は、視認性の高いshiru式terraform設計で慣れてからworkspaceやmoduleへの取り組むステップを踏むと、workspaceとmoduleがよくわからないけどいいらしい。
から事故リスクを踏まえていい感じのterraform設計へつなげることができると思います。

それでは素晴らしいterraform生活を!

続きを読む

AWS Lambdaによるサーバーレス構成でのCacheとCashを考える

はじめに

Serverless Advent Calendar 2017の12日目の投稿です。

ここでは、AWSベースのサーバーレスアーキテクチャで、主にFaaS(Function-as-a-Service)の利用を前提としますが、データキャッシュ(Cache)が必要な場合にどのように実現するのか、その技術解とお金(Cash)の関係について整理してみました。

サーバーレスアーキテクチャにしたは良いけど

サーバーレスアーキテクチャをベースにすることで、処理数に応じてリソースの最適化を図れるので、スモールスタートしやすく、またマイクロサービス化しやすいので、積極的に検討するようにしています。

ただ、よく自社で課題になるのが、データキャッシュに関する処理。
例えば、何かしらのIDを持つイベントを受け取り、それに対して名称を付与するようなケース。AWS Lambdaでデータを処理して、DynamoDBにデータを保存するような場合に、どこで名称のデータを保持するかが問題になります。

lambda-cache.png

DynamoDBは、スループット課金のため、あまり高頻度なRead/Writeをするには向いていません。もちろん、それだけの投資が行えるサービスであれば良いのですが、ID->名称の変換だけで、それだけのコストが発生するとなると、なかなか費用帯効果が得にくいケースが多いのではないでしょうか?
しかも、DynamoDBのRead処理は、レイテンシがそこまで高速ではなく(といっても数十~数百msですが)、システムのパフォーマンスに制約が発生するので、あまりこのような用途には向かないでしょう。

ということで、普通はインメモリでのキャッシュを利用することに至りますよね。

キャッシュパターン

ここでは、以下を前提に考えます。

  • 料金は、東京リージョンでのオンデマンドとして計算する。

    • データ転送量は除く。
    • 1ドル=115円で計算する。

ElastiCache(Redis)

AWSにおけるキャッシュサービスといえば、まずはElastiCacheですよね。ElastiCacheのエンジンは、MemcachedとRedisがサポートされていますが、私はRedis派です。キャッシュとして保持できるデータもHash/List/Setなどの色々な型をサポートしており、対応できる幅が広く、レプリケーションにも対応しているためです。

ElastiCacheを利用する場合は、以下のような要件の場合に向きます。

  • 高頻度なWrite/高頻度なRead
  • Writeスルー1

ただ、コストはそれなりに高いです。

インスタンスタイプ スペック 単位時間コスト 1ヶ月のコスト
cache.t2.medium 2vCPU、3.22GiB $0.104/h $76.13(約8,800円)
cache.m4.xlarge 4vCPU、14.28GiB $0.452/h $330.87(約38,100円)

さらに注意が必要なのは、上記は 1ノード である、ということです。ElastiCache(Redis)は、Multi-AZでの冗長化構成に対応していますが、追加のノードはレプリカノードとなるので、利用する場合は単純に2倍のコストがかかります。加えて、非同期レプリケーションとなるので、データのロストを避けるために同一AZにもレプリカノードを配置するとなると3~4倍のコストがかかることになります。

DynamoDB Accelerator(DAX)

いつもElastiCacheを使うかどうかで悩むことが多かったのですが、2017年の4月にDAXが発表され、新たな選択肢ができました。
DAXを利用することで、DynamoDBにデータを保持しつつも、数ミリ秒~マイクロ秒での低レイテンシでの処理が実現可能になります。

DAXを利用する場合は、以下のような要件の場合に向きます。

  • 高頻度なRead
  • Writeスルー1

大事なポイントは、DAXのタイトルにあります。

Amazon DynamoDB Accelerator(DAX) – Read heavyなワークロード向けインメモリ型キャッシュクラスタ

そう、Read heavy であることです。DAXでは、DynamoDBに書き込んだデータを読み込む際にキャッシュされるので、2回目以降のアクセスなどが高速化されます。書き込み自体が高速化されるわけではないので、頻繁にキャッシュを更新するような場合には、書き込みスループットの設定値を上げる必要が出てきてしまいます。

DAXを利用する場合のコストですが、ElastiCache(Redis)よりは1GiBあたりのコストは低くなります。

インスタンスタイプ スペック 単位時間コスト 1ヶ月のコスト
dax.r3.large 2vCPU、15.25GiB $0.322/h $235.71(約27,100円)

DAXでも、可用性向上のためには、3ノード以上でのクラスタ構成での運用が推奨されています。
ただ、DAXの場合、データ自体はDynamoDBに保持されているので、DAXノードがダウンしても、データ自体はロストせずに済みます。

また、LambdaはPythonで実装派の自分としては残念なところなのですが、DAXはまだPythonには対応していません。そのため、DAXを利用する場合はJavaかNodeのSDKを利用する必要があります。

Lambda In-Memory

もうひとつは、適用条件は限られますが、Lambdaのインメモリを利用するパターンです。これは、Lambdaのインスタンスは再利用されるため、それを活用する方法です。
以下のような方法で実現しています。

  • キャッシュ対象のデータをLambda関数のグローバル変数に保持する。
  • インスタンスが新たに立ち上がった場合など、キャッシュがなければ、(DynamoDBやS3などから)データを取得する。
  • 一定時間を過ぎている場合、データを再取得する。

Lambdaのインスタンスの制御は、AWS任せなので、自分でコントロールはできません。
そのため、ゆるい一貫性(ある程度の時間を要して、書き込みしたデータがキャッシュに反映される)で問題が無い場合での利用に限定されますが、Lambdaの処理だけでシンプルに実現でき、コストも抑えられるので、条件が合えば強力な選択肢です。実際のプロジェクトで急遽DynamoDBへのアクセス負荷を減らすのに必要になった際に、役に立ちました。

Lambda In-Memory を利用する場合は、以下のような要件の場合に向きます。

  • 高頻度なRead
  • 呼び出し回数が少ない
  • ゆるい一貫性
  • キャッシュデータが大きくない

2017/11/30にLambdaの最大メモリ量が、3,008MB(=2.93GiB)に拡張されました(それ以前は、1,536MB)。そのため、2GiB程度までキャッシュが可能そうです(キャッシュを目的にして増えたわけではないでしょうが)。

キャッシュだけのコストを出すのは難しいですが、1回あたりのLambda処理が0.1秒として、1秒あたり10回の呼び出しを行う場合は、以下の程度のコストがかかります。

  • 合計コンピューティング(秒/日)= 10回/秒 x 0.1秒 x 86,400秒/日 = 86,400 秒/日
  • 合計コンピューティング(GB-秒/日)= 86,400 秒/日 × 1GB = 86,400 GB-秒/日
  • 1ヶ月のコンピューティング料金 = 86,400GB-秒/日 x 30.5日 × $0.00001667/秒 = $43.93(5,100円)

もちろん、呼び出し回数が多ければその分コストは大きくなりますが、元々Lambdaで処理する内容であり、呼び出し回数が少ない状況では都合が良さそうです。

おおよそのコードの内容ですが、以下のようにして、定期的にキャッシュが更新されるようにしています。

pytyon
import datetime
import json

_beacon_dict = {}
_updatetime = 0

def lambda_handler(event, context):
    update_beacon_dict()

    req_body = json.loads(event['body'])
    add_attributes(req_body)

    # データの保存
    ・・・

    return {}

def add_attributes(beacon_data):
    '''
    キャッシュデータを利用して、属性を付与します。
    '''
    global _beacon_dict

    beacon_id = beacon_data['beaconId']
    if beacon_id in _beacon_dict:
        # キャッシュからデータを取得してパラメータを追加
        beacon_data['name']  = _beacon_dict[beacon_id]

def update_beacon_dict():
    '''
    有効期限をチェックし、キャッシュデータの更新を行います。
    '''
    global _beacon_dict
    global _updatetime

    diff_time = 0
    if len(_beacon_dict) != 0:
        now = datetime.datetime.now()
        epoch_now = datetime.datetime_to_epoch(now)
        epoch_updatetime = datetime.datetime_to_epoch(_updatetime)
        diff_time = epoch_now - epoch_updatetime

    if len(_beacon_dict) == 0 or diff_time >= 5*60*1000:
        # キャッシュデータの更新
        ・・・
        _beacon_dict = new_dict
        _updatetime = datetime.datetime.now()

まとめ

キャッシュのパターンを整理すると、以下のようになります。
※費用は、あくまで目安です。インスタンスタイプやクラスタ構成などの条件で変わります。

方法 適用が向くケース 制限 1GiBキャッシュあたりのコスト
ElastiCache(Redis) ・高頻度なWrite
・高頻度なRead
Writeスルー
・可用性を上げるなら3ノード以上必要 1ノードの場合:
2,600~2,800円
3ノードクラスタの場合:
7,800~8,400円
DynamoDB Accelerator(DAX) ・高頻度なRead
・Writeスルー
・可用性を上げるなら3ノード以上必要 1ノードの場合:
1,800円
3ノードクラスタの場合:
5,400円
Lambda ・高頻度なRead
・呼び出し回数が少ない
・ゆるい一貫性
・キャッシュデータ2GiB以下(目安) 10回実行/秒
100ミリ秒/回
の場合:
5,100円

1GiBキャッシュあたりのコストで見ると、Lambdaでもそれなりの単価になりますね。上記はキャッシュする/しないに関わらず、Lambdaの実行にかかるコストのため単純な比較はできないですが、10回実行/秒以下の頻度の呼び出しであれば、メリットがありそうです。

キャッシュの更新や呼出をどう行うかによって、どの方法が良いかは変わりますが、処理の特性とコストを踏まえて、キャッシュの方式を選択できると良いと考えています。


  1. Writeスルー:キャッシュに書き込んだデータが、整合性を保って読み取り可能になる。 

続きを読む

[JAWS-UG CLI] RDS:#1 DBインスタンスの作成 (PostgreSQL: Public MultiAZ)

前提条件

RDSへの権限

RDSに対してフル権限があること。

EC2への権限

EC2への読み取り権限があること。

AWS CLI

以下のバージョンで動作確認済

  • AWS CLI 1.11.14
コマンド
aws --version
結果(例)
      aws-cli/1.11.14 Python/2.7.10 Darwin/15.6.0 botocore/1.4.71

バージョンが古い場合は最新版に更新しましょう。

コマンド
sudo -H pip install -U awscli

AWSアカウントの属性

AWSアカウントがEC2-Classicに対応していないこと。

コマンド
AWS_SUPPORT_PLATFORMS=$( 
               aws ec2 describe-account-attributes 
                 --query 'AccountAttributes[?AttributeName == `supported-platforms`].AttributeValues[].AttributeValue' 
                 --output text 
      ) && echo ${AWS_SUPPORT_PLATFORMS}
結果(例)
      VPC

‘VPC’の他に’EC2’が表示される場合、別のアカウントを作成もしくは利用してください。

デフォルトVPCの存在

デフォルトVPCが存在すること。

psqlコマンドの存在

コマンド
which psql
結果(存在する場合の例)
      /opt/local/bin/psql
結果(存在しない場合の例)
      psql: Command not found.

psqlコマンドのインストール: https://qiita.com/tcsh/items/be2f64904a3194f0a96b

0. 準備

0.1. リージョンの決定

変数の設定
export AWS_DEFAULT_REGION='ap-northeast-1'

0.2. 変数の確認

プロファイルが想定のものになっていることを確認します。

変数の確認
aws configure list
結果(例)
            Name                    Value             Type    Location
            ----                    -----             ----    --------
         profile       rdsFull-prjz-mbp13        env    AWS_DEFAULT_PROFILE
      access_key     ****************XXXX shared-credentials-file
      secret_key     ****************XXXX shared-credentials-file
          region        ap-northeast-1        env    AWS_DEFAULT_REGION

0.3. セキュリティーグループの指定

変数の設定
VPC_SG_NAME='postgresql-2017-11-20'

セキュリティーグループのIDを取得します。

コマンド
VPC_SG_ID=$( 
        aws ec2 describe-security-groups 
          --filter Name=group-name,Values=${VPC_SG_NAME} 
          --query 'SecurityGroups[].GroupId' 
          --output text 
) 
        && echo ${VPC_SG_ID}
結果(例)
      sg-xxxxxxxx

1. 事前作業

1.1. DBエンジンの決定

変数の設定
RDS_ENGINE_NAME='postgres'

1.2. License Model

PostgreSQLのライセンスモデルは1つのみです。

デフォルト値: postgresql-license

1.3. DB Instance Class

変数の設定
RDS_INSTANCE_CLASS='db.t2.micro'

1.4. Allocated Storage

データベース用に5GBのストレージを割り当てます。

変数の設定
RDS_STORAGE_SIZE='5'

1.5. DB Instance Identifier

DBインスタンス名を決定します。

選択したリージョン内で、自分のアカウントに対して一意であることが必要です。

変数の設定
RDS_INSTANCE_IDENT="postgre-handson-$(date +%Y%m%d)" 
        && echo ${RDS_INSTANCE_IDENT}

1.6. Master Username

DB インスタンスにログオンするためのマスターユーザー名を英数字で入力します。

変数の設定
RDS_USER_NAME='pgadmin'

1.6. Master Password

マスターパスワードとして 8~128 個の表示可能な ASCII 文字(/、”、@ 以外)を指定します。

変数の設定(例)
RDS_USER_PASS='#dbPass123'

1.7 データベース名の指定

データベースの名前を、英数字 63 文字以内で入力します。 (起動後に追加できない)

変数の設定
RDS_DB_NAME="handson$(date +%Y%m%d)" 
        && echo ${RDS_DB_NAME}

注釈: 名前を指定しない場合、DB インスタンスでデフォルトのデータベースは作成されません。

1.8 ポートの指定 (省略)

DBインスタンスを作成するとポートを変更できないため、デフォルトと異なるポートを利用する場合は、DBインスタンス作成時に指定する必要があります。

デフォルト値: 5432 (PostgreSQLの場合)

1.9. VPC IDの取得

コマンド
VPC_ID=$( 
        aws ec2 describe-vpcs 
          --filters Name=isDefault,Values=true 
          --query 'Vpcs[].VpcId' 
          --output text 
  ) 
          && echo ${VPC_ID}
結果(例)
      vpc-xxxxxxxx

1.10. セキュリティグループの配列への追加

変数の設定
ARRAY_SG_ID="${VPC_SG_ID} ${ARRAY_SG_ID}" 
        && echo ${ARRAY_SG_ID}

2. DBインスタンスの作成

2.1. 起動時刻の確認

変数の設定
DATETIME_UTC=$( date -u '+%Y-%m-%dT%H:%MZ' ) 
        && echo ${DATETIME_UTC}
結果(例)
      2016-11-13T01:23Z

2.2. DBインスタンスの起動

変数の確認
cat << ETX

        RDS_INSTANCE_IDENT: ${RDS_INSTANCE_IDENT}
        RDS_STORAGE_SIZE:   ${RDS_STORAGE_SIZE}
        RDS_INSTANCE_CLASS: ${RDS_INSTANCE_CLASS}
        RDS_ENGINE_NAME:    ${RDS_ENGINE_NAME}
        RDS_USER_NAME:      ${RDS_USER_NAME}
        RDS_USER_PASS:      ${RDS_USER_PASS}
        RDS_DB_NAME:        ${RDS_DB_NAME}
        ARRAY_SG_ID:        ${ARRAY_SG_ID}

ETX
コマンド
aws rds create-db-instance 
        --db-instance-identifier ${RDS_INSTANCE_IDENT} 
        --allocated-storage ${RDS_STORAGE_SIZE} 
        --db-instance-class ${RDS_INSTANCE_CLASS} 
        --engine ${RDS_ENGINE_NAME} 
        --master-username ${RDS_USER_NAME} 
        --master-user-password ${RDS_USER_PASS} 
        --db-name ${RDS_DB_NAME} 
        --vpc-security-group-ids ${ARRAY_SG_ID} 
        --publicly-accessible 
        --multi-az
結果(例)
      {
        "DBInstance": {
          "PubliclyAccessible": true,
          "MasterUsername": "pgadmin",
          "MonitoringInterval": 0,
          "LicenseModel": "postgresql-license",
          "VpcSecurityGroups": [
              {
                  "Status": "active",
                  "VpcSecurityGroupId": "sg-xxxxxxxx"
              }
          ],
          "CopyTagsToSnapshot": false,
          "OptionGroupMemberships": [
              {
                  "Status": "in-sync",
                  "OptionGroupName": "default:postgres-9-5"
              }
          ],
          "PendingModifiedValues": {
              "MasterUserPassword": "****"
          },
          "Engine": "postgres",
          "MultiAZ": false,
          "DBSecurityGroups": [],
          "DBParameterGroups": [
              {
                  "DBParameterGroupName": "default.postgres9.5",
                  "ParameterApplyStatus": "in-sync"
              }
          ],
          "AutoMinorVersionUpgrade": true,
          "PreferredBackupWindow": "14:30-15:00",
          "DBSubnetGroup": {
              "Subnets": [
                  {
                      "SubnetStatus": "Active",
                      "SubnetIdentifier": "subnet-xxxxxxxx",
                      "SubnetAvailabilityZone": {
                          "Name": "ap-northeast-1a"
                      }
                  },
                  {
                      "SubnetStatus": "Active",
                      "SubnetIdentifier": "subnet-xxxxxxxx",
                      "SubnetAvailabilityZone": {
                          "Name": "ap-northeast-1c"
                      }
                  }
              ],
              "DBSubnetGroupName": "default",
              "VpcId": "vpc-xxxxxxxx",
              "DBSubnetGroupDescription": "default",
              "SubnetGroupStatus": "Complete"
          },
          "ReadReplicaDBInstanceIdentifiers": [],
          "AllocatedStorage": 5,
          "DBInstanceArn": "arn:aws:rds:ap-northeast-1:XXXXXXXXXXXX:db:postgre-handson-20161114",
          "BackupRetentionPeriod": 1,
          "DBName": "handson20161114",
          "PreferredMaintenanceWindow": "sat:17:17-sat:17:47",
          "DBInstanceStatus": "creating",
          "EngineVersion": "9.5.4",
          "DomainMemberships": [],
          "StorageType": "standard",
          "DbiResourceId": "db-XXXXXXXXXXXXXXXXXXXXXXXXXX",
          "CACertificateIdentifier": "rds-ca-2015",
          "StorageEncrypted": false,
          "DBInstanceClass": "db.t2.micro",
          "DbInstancePort": 0,
          "DBInstanceIdentifier": "postgre-handson-20161114"
        }
      }

DBインスタンスの状態確認

変数の設定
RDS_INSTANCE_STATUS=$( 
        aws rds describe-db-instances 
          --db-instance-identifier ${RDS_INSTANCE_IDENT} 
          --query 'DBInstances[].DBInstanceStatus' 
          --output text 
) 
          && echo ${RDS_INSTANCE_STATUS}
結果(例)
      creating

availableになればデータベースを利用することができます。

注釈: t2でも起動に7分くらいかかるようです。

3. 事後確認

3.1. イベントの確認

変数の設定
RDS_EVENT_TYPE='db-instance'
RDS_EVENT_START=${DATETIME_UTC}
RDS_MAX_ITEMS='3'
コマンド
aws rds describe-events 
        --start-time ${RDS_EVENT_START} 
        --source-type ${RDS_EVENT_TYPE} 
        --max-items ${RDS_MAX_ITEMS}
結果(例)
      {
        "Events": [
          {
              "EventCategories": [
                  "creation"
              ],
              "SourceType": "db-instance",
              "SourceArn": "arn:aws:rds:ap-northeast-1:XXXXXXXXXXXX:db:postgre-handson-20161114",
              "Date": "2016-11-13T05:28:38.782Z",
              "Message": "DB instance created",
              "SourceIdentifier": "postgre-handson-20161114"
          },
          {
              "EventCategories": [
                  "backup"
              ],
              "SourceType": "db-instance",
              "SourceArn": "arn:aws:rds:ap-northeast-1:XXXXXXXXXXXX:db:postgre-handson-20161114",
              "Date": "2016-11-13T05:29:47.617Z",
              "Message": "Backing up DB instance",
              "SourceIdentifier": "postgre-handson-20161114"
          },
          {
              "EventCategories": [
                  "backup"
              ],
              "SourceType": "db-instance",
              "SourceArn": "arn:aws:rds:ap-northeast-1:XXXXXXXXXXXX:db:postgre-handson-20161114",
              "Date": "2016-11-13T05:32:17.561Z",
              "Message": "Finished DB Instance backup",
              "SourceIdentifier": "postgre-handson-20161114"
          }
        ]
      }

3.2. DBインスタンス情報の確認

コマンド
aws rds describe-db-instances 
        --db-instance-identifier ${RDS_INSTANCE_IDENT}
結果(例)
      {
        "DBInstances": [
          {
              "PubliclyAccessible": true,
              "MasterUsername": "pgadmin",
              "MonitoringInterval": 0,
              "LicenseModel": "postgresql-license",
              "VpcSecurityGroups": [
                  {
                      "Status": "active",
                      "VpcSecurityGroupId": "sg-xxxxxxxx"
                  }
              ],
              "InstanceCreateTime": "2016-11-13T05:28:38.651Z",
              "CopyTagsToSnapshot": false,
              "OptionGroupMemberships": [
                  {
                      "Status": "in-sync",
                      "OptionGroupName": "default:postgres-9-5"
                  }
              ],
              "PendingModifiedValues": {},
              "Engine": "postgres",
              "MultiAZ": false,
              "LatestRestorableTime": "2016-11-13T05:29:47.646Z",
              "DBSecurityGroups": [],
              "DBParameterGroups": [
                  {
                      "DBParameterGroupName": "default.postgres9.5",
                      "ParameterApplyStatus": "in-sync"
                  }
              ],
              "AutoMinorVersionUpgrade": true,
              "PreferredBackupWindow": "14:30-15:00",
              "DBSubnetGroup": {
                  "Subnets": [
                      {
                          "SubnetStatus": "Active",
                          "SubnetIdentifier": "subnet-xxxxxxxx",
                          "SubnetAvailabilityZone": {
                              "Name": "ap-northeast-1a"
                          }
                      },
                      {
                          "SubnetStatus": "Active",
                          "SubnetIdentifier": "subnet-xxxxxxxx",
                          "SubnetAvailabilityZone": {
                              "Name": "ap-northeast-1c"
                          }
                      }
                  ],
                  "DBSubnetGroupName": "default",
                  "VpcId": "vpc-xxxxxxxx",
                  "DBSubnetGroupDescription": "default",
                  "SubnetGroupStatus": "Complete"
              },
              "ReadReplicaDBInstanceIdentifiers": [],
              "AllocatedStorage": 5,
              "DBInstanceArn": "arn:aws:rds:ap-northeast-1:XXXXXXXXXXXX:db:postgre-handson-20161114",
              "BackupRetentionPeriod": 1,
              "DBName": "handson20161114",
              "PreferredMaintenanceWindow": "sat:17:17-sat:17:47",
              "Endpoint": {
                  "HostedZoneId": "Z24O6O9L7SGTNB",
                  "Port": 5432,
                  "Address": "postgre-handson-20161114.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com"
              },
              "DBInstanceStatus": "available",
              "EngineVersion": "9.5.4",
              "AvailabilityZone": "ap-northeast-1a",
              "DomainMemberships": [],
              "StorageType": "standard",
              "DbiResourceId": "db-XXXXXXXXXXXXXXXXXXXXXXXXXX",
              "CACertificateIdentifier": "rds-ca-2015",
              "StorageEncrypted": false,
              "DBInstanceClass": "db.t2.micro",
              "DbInstancePort": 0,
              "DBInstanceIdentifier": "postgre-handson-20161114"
          }
        ]
      }

3.3. エンドポイントの確認

変数の設定
RDS_INSTANCE_ENDPOINT=$( 
        aws rds describe-db-instances 
          --db-instance-identifier ${RDS_INSTANCE_IDENT} 
          --query 'DBInstances[].Endpoint.Address' 
          --output text 
) 
        && echo ${RDS_INSTANCE_ENDPOINT}
結果(例)
      postgre-handson-ap-northeast-1.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com

3.4. 接続情報設定ファイルの作成

変数の確認
cat << ETX

        RDS_INSTANCE_ENDPOINT: ${RDS_INSTANCE_ENDPOINT}
        VPC_SG_PORT:           ${VPC_SG_PORT}
        RDS_DB_NAME:           ${RDS_DB_NAME}
        RDS_USER_NAME:         ${RDS_USER_NAME}
        RDS_USER_PASS:         ${RDS_USER_PASS}

ETX
コマンド
echo "${RDS_INSTANCE_ENDPOINT}:${VPC_SG_PORT}:${RDS_DB_NAME}:${RDS_USER_NAME}:${RDS_USER_PASS}" >> ${HOME}/.pgpass 
        && chmod 600 ${HOME}/.pgpass 
        && cat ${HOME}/.pgpass

3.4. 接続

コマンド
psql 
        --host=${RDS_INSTANCE_ENDPOINT} 
        --username=${RDS_USER_NAME} 
        --dbname=${RDS_DB_NAME}
結果
      psql (9.5.5, server 9.5.4)
      SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
      Type "help" for help.

      handson20161114=>

DBコマンドのテスト実行をしてみます。

SQL
select version();
結果(例)
                                                       version
      ----------------------------------------------------------------------------------------------------------
        PostgreSQL 9.5.4 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.2 20140120 (Red Hat 4.8.2-16), 64-bit
       (1 row)

DBへの接続を切断します。

コマンド
q

3.5. 予定メンテナンスアクションの確認

コマンド
aws rds describe-pending-maintenance-actions 
        --filter Name=db-instance-id,Values=${RDS_INSTANCE_IDENT}
結果(例)
      {
          "PendingMaintenanceActions": []
      }

3.6. DBMSのログファイル確認

ログファイルの一覧を表示します。

コマンド
aws rds describe-db-log-files 
        --db-instance-identifier ${RDS_INSTANCE_IDENT}
結果(例)
      {
        "DescribeDBLogFiles": [
          {
              "LastWritten": 1479014886000,
              "LogFileName": "error/postgres.log",
              "Size": 307
          },
          {
              "LastWritten": 1479015287000,
              "LogFileName": "error/postgresql.log.2016-11-13-05",
              "Size": 1729
          }
        ]
      }

ログファイルをダウンロードします。

変数の設定
RDS_LOG_NAME=<ダウンロードするLogFileName>
コマンド
aws rds download-db-log-file-portion 
        --db-instance-identifier ${RDS_INSTANCE_IDENT} 
        --log-file-name ${RDS_LOG_NAME} 
        --query 'LogFileData' 
        --output text
結果(例)
      2016-11-13 05:28:06 UTC::@:[3317]:LOG:  MultiXact member wraparound protections are now enabled
      2016-11-13 05:28:06 UTC::@:[3315]:LOG:  database system is ready to accept connections
      2016-11-13 05:28:06 UTC::@:[3321]:LOG:  autovacuum launcher started
      2016-11-13 05:28:09 UTC::@:[3318]:LOG:  checkpoint starting: immediate force wait flush-all
      2016-11-13 05:28:09 UTC::@:[3318]:LOG:  checkpoint complete: wrote 21 buffers (0.1%); 0 transaction log file(s) added, 0 removed, 0 recycled; write=0.001 s, sync=0.008 s, total=0.031 s; sync files=19, longest=0.008 s, average=0.000 s; distance=17 kB, estimate=17 kB
      2016-11-13 05:28:10 UTC::@:[3318]:LOG:  checkpoint starting: immediate force wait
      2016-11-13 05:28:10 UTC::@:[3318]:LOG:  checkpoint complete: wrote 0 buffers (0.0%); 0 transaction log file(s) added, 0 removed, 0 recycled; write=0.000 s, sync=0.000 s, total=0.084 s; sync files=0, longest=0.000 s, average=0.000 s; distance=0 kB, estimate=15 kB
      2016-11-13 05:29:47 UTC::@:[3318]:LOG:  checkpoint starting: force wait
      2016-11-13 05:29:51 UTC::@:[3318]:LOG:  checkpoint complete: wrote 38 buffers (0.1%); 0 transaction log file(s) added, 0 removed, 0 recycled; write=3.736 s, sync=0.058 s, total=4.092 s; sync files=33, longest=0.058 s, average=0.001 s; distance=5516 kB, estimate=5516 kB
      2016-11-13 05:34:47 UTC::@:[3318]:LOG:  checkpoint starting: time
      2016-11-13 05:34:47 UTC::@:[3318]:LOG:  checkpoint complete: wrote 1 buffers (0.0%); 0 transaction log file(s) added, 0 removed, 0 recycled; write=0.000 s, sync=0.003 s, total=0.017 s; sync files=1, longest=0.003 s, average=0.003 s; distance=16384 kB, estimate=16384 kB
      2016-11-13 05:39:47 UTC::@:[3318]:LOG:  checkpoint starting: time
      2016-11-13 05:39:47 UTC::@:[3318]:LOG:  checkpoint complete: wrote 1 buffers (0.0%); 0 transaction log file(s) added, 0 removed, 0 recycled; write=0.000 s, sync=0.002 s, total=0.016 s; sync files=1, longest=0.002 s, average=0.002 s; distance=16384 kB, estimate=16384 kB

完了

続きを読む

AWSのウェブサイト構築チュートリアル解説を作ってみた はじめに

経緯

会社で勉強会でAWSをやることになり、教えてもらったチュートリアルを使って環境構築を行った。
分かりやすいチュートリアルだったが、作業の意味などが書かれていないので、その部分を忘れないように解説形式で残すことにした。

チュートリアルの前にすること

・アカウント作成
・アラート設定(課金が気にならない人はやらなくてもいい)
 ※アラートは通知が来るだけでサービスを停止したりはしない。
  上限を超えた通知が来たらAWSの請求コンソールで状況を確認し、必要に応じてインスタンスの停止などを行うこと

チュートリアル

https://aws.amazon.com/jp/getting-started/projects/scalable-wordpress-website/

※チュートリアルの環境構築あと、インスタンスなどが残っていると課金が続く。チュートリアル内の後片付けを確認し、不要なインスタンス等は削除すること。

チュートリアル全体の概要

以下の流れでAWSでWEBサービスの構築と拡張の基礎手順を学べる。
1.単一のwordpressインスタンスを作成
2.DBを別インスタンスに分離
3.WEBサーバの拡張しロードバランサーを設置
4.スレーブDBの追加

解説

フェーズ1: サーバー 1 台構成で WordPress 環境を構築
https://qiita.com/towtow/items/f17b30571a53ebf3ef9b

フェーズ2: 拡張性を向上しつつ、DB 運用負荷を軽減する構成を構築(作成中)

フェーズ3: ロードバランサーを使った負荷分散環境を構築(作成中)

フェーズ4 (オプション): フェーズ 3 の環境でスレーブ DB を追加(Amazon RDS を Multi-AZ 構成に変更)(作成中)

続きを読む