見出し画像

aws Aurora on terraform

以前プロジェクトでauroraを構築したので忘れない内に備忘録を残しておこうと思います。

Auroraとは

AuroraとはRDSを用いた完全マネージドRDBサービスです。高可用性があり低レイテンシーな特徴があります。

標準的な MySQL データベースと比べて最大で 5 倍、標準的な PostgreSQL データベースと比べて最大で 3 倍高速です。

素晴らしいスループットだ!

Aurora には、高性能のストレージサブシステムが含まれています。MySQL と PostgreSQL との互換性のあるデータベースエンジンは、その高速分散ストレージを利用するようにカスタマイズされています。基本ストレージは、必要に応じて自動的に拡張されます。Aurora クラスターは、最大サイズの 128 tebibytes (TiB) まで拡張できます。
継続的にS3に増分バックアップします。

自動的にスケーリングするストレージで最大128TBだと!デカすぎる!

auroraのアーキテクトは後説明しますが、カスタムエンドポイントを作成できる点も負荷を分散する点では優れてます。例えば、バッチ処理のインスタンを作成し、そのエンドポイント経由で読み込みを行うことも可能です!

Auroraのアーキテクト

ここまでざっくりとしたAuroraの話しはしましたが、実際アーキテクチャーはどうなってんの?っとなっていると思いますので説明をしていきます

下記がAuroraのアーキテクチャ図です。
aurora clusterを形成、そこにマスターとレプリカインスタンス、ストレージクラスタを形成します。これが一つのパッケージっていうイメージ。
特徴的なのはストレージ、ストレージは1AZに2つずつの計6つ配置されます。

画像1

Aurora claster

Aurora clusterを形成してインスタンを管理します。インスタンスはマルチAZで作成します。クラスターにはmasterとreplicaを形成して、書き込み、読み込みを分けることができます。インスタンス自体を増やすことも可能です。例えば、何かの処理用のread replicaを作成したりと柔軟に対応ができ、それ用のカスタムエンドポイントを作成することもできます。

replica

1つのクラスタで最大15個まで増やすことが出来る読み取り専用のインスタンスです。リードレプリカの追加/削除はダウンタイム無く行うことができます。
プライマリDBと参照するクラスタボリュームは同じであるため、レプリカ遅延も低いです。(通常10ms未満)
データベースに対して書き込みや更新より読み取り処理が多いアプリケーションでは、リードレプリカ側に負荷が偏る場合があります。そういったケースに対してリードレプリカの台数を増やすことで負荷を分散することが可能です。

Auto scaling機能

replicaにはEC2のようにauto scaling機能があります。
スケーリング対象のメトリクスはCPU使用率replicaの接続数です。
キャパシティの最小、最大数を選択選択します。(replicaの数)

例として、事前定義された平均 CPU 使用率メトリクスを使用するスケーリングポリシーを挙げましょう。そのようなポリシーは、40 パーセントなどの指定された使用率に、またはそれに近い割合に CPU 使用率を維持できます。

スケーリングのクールダウン
auto scalingの設定でクールダウンという機能があります。これはスケールイン、スケールアウトした後の待機時間です。いくらメトリクスに掛かったからといってすぐにスケールインやスケールアウトするのではなく、一旦待機時間を設けてスケールイン、スケールアウト行う為に用いられます。
defaultでは300秒が待機時間になります。

エンドポイント

エンドポイントはインスタンの接続先のことです。
エンドポイントには3つ概念があります

クラスターエンドポイント

クラスタのプライマリDBインスタンス(master)に接続するエンドポイントになります。
仮にプライマリDBインスタンスで障害が発生して、リードレプリカが昇格した場合もエンドポイントの向き先は自動的に昇格後のプライマリDBインスタンスに向き、接続リクエストに継続して応答するためサービスの中断は最小限に抑えることが出来ます。
プライマリDBインスタンスに接続出来る唯一のエンドポイントになるため、書き込み等のオペレーションではこちらのエンドポイントを使用します

読み取りエンドポイント

クラスター内に存在するリードレプリカに接続するエンドポイントになります。
接続対象はクラスター内に存在する全てのリードレプリカになるため、読み取りのオペレーションの負荷分散ができます。
クラスター内にリードレプリカが存在しない場合はプライマリDBインスタンスに接続を行います

カスタムエンドポイント

任意のDBインスタントを接続対象としてグループ設定が出来るエンドポイントになります。
クラスターエンドポイント、読み取りエンドポイントとは異なり、プライマリDBインスタンスとリードレプリカの両方を接続対象として指定することができます。

フェイルオーバーについて

プライマリーインスタンに障害があった時にreplicaが自動的にゲールオーバーしてくれます。フェールオーバーの優先順位を指定することもできます。
リードレプリカ毎にフェイルオーバの優先度を最も高い値の0から、最も低い値の15の範囲で設定できます。

障害イベントによって短い中断が発生し、その間例外によって読み取りと書き込みオペレーションが失敗します。ただし、一般的なサービスの復元時間は 120 秒未満であり、多くの場合 60 秒未満で復元されます。

レプリカを立ててなかったら
障害イベントの発生時にプライマリインスタンスが再作成されます。障害イベントによって中断が発生し、その間例外によって読み取りと書き込みオペレーションが失敗します。新しいプライマリインスタンスが再作成されると、サービスが回復します。これは、通常は 10 分未満で行われます。Aurora レプリカのプライマリインスタンスへの昇格は、新しいプライマリインスタンスの作成よりもはるかに短時間で実行されます。

ストレージクラスターについて

Auroraでは3A Zにまたがって2つずつ計6つのストレージを保持しています。しかもこれらはデータベースのデータ量が増えるほど、自動的に容量を増やしてくれます。最大で128TB!
また書き込みが行われたストレージを読み取りストレージに自動的に更新してくれます。ストレージと考えるとI/O処理が結構時間かかるんじゃないのと考えるかもしれませんが、これらのコピーは並列で行われる為、コピーへのオーバーヘッドを短縮しています。

ちなみにdefaultでは一つのストレージボリュームは10GB(nodeという概念)からの仕様になっていてそこからよしなにスケールアウトしてくれます。

1az x 2つnode x 10GB x 3 = 60GB

画像2

基礎的な内容はここまでで、次はterraformでクラスターを表現していきます!

クラスターの構築

事前にネットワーク周りのcomponetを作成が必要です。

#============================ #aurora  cluster
#============================
resource "aws_rds_cluster" "aurora_cluster" {
 cluster_identifier              = "${var.env}-${var.project}-cluster"
 engine                          = "aurora-mysql"
 engine_version                  = "5.7.mysql_aurora.2.07.2"
 database_name                   = var.project
 master_username                 = var.project
 master_password                 = var.rds_password
 backup_retention_period         = 7
 preferred_backup_window         = "18:00-18:30"
 preferred_maintenance_window    = "sun:18:30-sun:19:00"
 db_subnet_group_name            = aws_db_subnet_group.main.id
 vpc_security_group_ids          = [aws_security_group.aurora.id]
 db_cluster_parameter_group_name = aws_rds_cluster_parameter_group.main.id
 final_snapshot_identifier       = "${var.project}-${var.env}-aurora-cluster"
 enabled_cloudwatch_logs_exports = ["error", "slowquery"]
 deletion_protection             = true
}

ざっとコード読んでもらったらわかると思いますが、クラスで用いいるマシン、データベース名、username、password、サブネットグループなどを設定しています。
バックアップの時間はUTCなので時間を合わせて設定しています。(preferred_backup_window)
バックアップ保存期間は7日(backup_retention_period )

クラスターの設定は以上です

subnet groupの作成

#=================================== #aurora  cluster subnet group
#===================================
resource "aws_db_subnet_group" "main" {
 name        = "${var.env}-${var.project}"
 description = "${var.env}-subnet grupe"
 subnet_ids = [
   for subnet in aws_subnet.app_env_private :
   subnet.id
 ]

 tags = {
   Name = "${var.env} DB subnet group"
 }
}

サブネットグループの作成です。このサブネットグループがクラスターのとことで指定されています。

パラメーターグループの作成

#========================

#cluster parameter group
#========================
resource "aws_rds_cluster_parameter_group" "main" {
 name        = "${var.env}-${var.project}-aurora-pg"
 family      = "aurora-mysql5.7"
 description = "RDS parameter group for ${var.project}"

 parameter {
   name  = "character_set_server"
   value = "utf8mb4"
 }

 parameter {
   name  = "character_set_client"
   value = "utf8mb4"
 }

 parameter {
   name  = "character_set_database"
   value = "utf8mb4"
 }

 parameter {
   name  = "character_set_connection"
   value = "utf8mb4"
 }

 lifecycle {
   ignore_changes = [parameter]
 }
}

#===================
#db parameter group
#===================
resource "aws_db_parameter_group" "main" {
 name        = "${var.env}-${var.project}-pg"
 family      = "aurora-mysql5.7"
 description = "RDS parameter group for ${var.env}"

 parameter {
   name  = "max_connections"
   value = "512"
 }

 parameter {
   name         = "slow_query_log"
   value        = 1
   apply_method = "pending-reboot"
 }

 parameter {
   name         = "long_query_time"
   value        = 0.1
   apply_method = "pending-reboot"
 }

 parameter {
   name         = "log_output"
   value        = "file"
   apply_method = "pending-reboot"
 }

 parameter {
   name         = "query_cache_type"
   value        = 1
   apply_method = "pending-reboot"
 }

 parameter {
   name         = "general_log"
   value        = 1
   apply_method = "pending-reboot"
 }
}

こいつは文字コード等をコネクション数を設定しています。
一部のエンジンは再起動しないと一部のパラメーターを適用できないため、ここで「pending-reboot」を指定する必要があります。

インスタンスの作成

#==============================
 #aws  aurora instance master
#==============================
resource "aws_rds_cluster_instance" "aurora_cluster_instance" {
 count                   = 1
 cluster_identifier      = aws_rds_cluster.aurora_cluster.id
 identifier              = "${var.env}-${var.project}-aurora-instance-${count.index + 1}"
 engine                  = "aurora-mysql"
 instance_class          = "db.t3.medium"
 db_parameter_group_name = aws_db_parameter_group.main.name
 db_subnet_group_name    = aws_db_subnet_group.main.name
 publicly_accessible     = false

 tags = {
   Name        = "${var.env}-${var.project}-${count.index}"
   Group       = var.project
   ManagedBy   = "terraform"
   Environment = var.env
 }

 lifecycle {
   create_before_destroy = true
   ignore_changes        = [instance_class]
 }
}

#==============================
 #aws  aurora instance replica
#==============================
resource "aws_rds_cluster_instance" "aurora_cluster_instance_reader" {
 count                   = 1
 cluster_identifier      = aws_rds_cluster.aurora_cluster.id
 identifier              = "${var.env}-${var.project}-aurora-instance-${count.index + 1}-reader"
 engine                  = "aurora-mysql"
 instance_class          = "db.t3.medium"
 db_parameter_group_name = aws_db_parameter_group.main.name
 db_subnet_group_name    = aws_db_subnet_group.main.name
 publicly_accessible     = false
 depends_on              = [aws_rds_cluster_instance.aurora_cluster_instance]


 tags = {
   Name        = "${var.env}-${var.project}-${count.index}"
   Group       = var.project
   ManagedBy   = "terraform"
   Environment = var.env
 }

 lifecycle {
   create_before_destroy = true
   ignore_changes        = [instance_class]
 }
}

master と   replicaで分けて作成してます。identifierはインスタンの識別子となります。この識別子を元にendpointの作成がされます。

カスタムエンドポイントの作り方は以下です

resource "aws_rds_cluster" "db" {
 中略
}
resource "aws_rds_cluster_instance" "analysis" {
 中略
}
//カスタムエンドポイントの設定
resource "aws_rds_cluster_endpoint" "analysis" {
 cluster_identifier          = aws_rds_cluster.db.id
 cluster_endpoint_identifier = "${var.name}-${var.env}-${var.service}-analysis"
 custom_endpoint_type        = "READER"
 static_members = [
   aws_rds_cluster_instance.analysis.id,
 ]
}

customo_entdpoint_typeはREADER, ANYの2種類になります。
REDERは読み取り専用。
ANYはWriter/Reader両方をカスタムエンドポイントに設定できます。タイプがANYの場合WriterとReaderを区別せず同確率で負荷分散し書き込み可能か事前に判断できないため、読み込み専用として使用してください。

以上でAuroraの作成は終了です! ありがとうございました!


この記事が気に入ったらサポートをしてみませんか?