RDSのストレージ費用を最適化したいと思ったことはありませんか?
特に、Eコマースサイトのセール期間や、SaaSアプリの月次予算更新後など、アクセス集中が予測できる場合、高性能なストレージを常時稼働させておくのはコスト的に無駄が多いですよね。
そこで今回は、予測可能なワークロードに対して、Amazon RDSのコストを最適化する方法をご紹介したいと思います。具体的には、Amazon RDSのIOPSとスループットを自動スケーリングして、月次や季節ごとのピークに合わせてスケールアップ・ダウンする方法を解説します。
ぜひこの記事を参考にして、無駄なコストを抑えつつ、必要な時に十分なパフォーマンスを発揮できるRDS環境を構築してください!
今回ご紹介するソリューションでは、AWS Lambda関数を使用して、RDSインスタンスのタグで定義されたスケジュールに従って、ストレージ設定をスケールアップ・ダウンします。
ワークフローは以下のステップと主要コンポーネントで構成されます。
以下の図は、ソリューションのアーキテクチャを示しています。
今回の例ではAmazon RDS for MariaDBインスタンスを使用していますが、RDS for PostgreSQL、RDS for MySQL、RDS for SQL Server、RDS for Oracle、RDS for Db2にも、このガイダンスを適用できます。ただし、Amazon Auroraは全く異なるストレージアーキテクチャを使用しているため、今回のソリューションの対象外となりますのでご注意ください。
Amazon RDSストレージ操作には、以下のような制限事項があります。
制限事項 | 補足 |
---|---|
IOPSとスループットの変更は6時間ごと、 またはストレージの最適化が完了するまでの 間隔のいずれか長い方で1回だけ許可 | 期間とパフォーマンスのパラメータは賢く選択する必要があります。 |
ディスクパフォーマンスがデータベースにとって重要な場合は、 Amazon EBS最適化インスタンスの使用を検討 | gp3ストレージで提供される以上のパフォーマンスと 耐久性が必要な場合は、io2 Block Expressの使用を検討してください。 io2 Block Expressは、最大256,000 IOPSを実現できます。 |
gp3ボリュームの場合、 プロビジョニングされたIOPSとスループットの変更 | Oracleの場合は200 GB以上、Db2、MariaDB、MySQL、PostgreSQLの場合は400 GB以上の ボリュームに対してのみ許可され、SQL Serverの場合はストレージ割り当て制限は設定されていません。 制限値未満の場合は、3,000 IOPS/125MiB/sの固定ベースラインが適用され、設定を変更することはできません。 ベースラインは価格に含まれており、容量を追加でプロビジョニングした場合にのみ追加料金が発生します。 |
上記の制限値を超えるgp3ストレージでは、 プロビジョニングされたIOPSを12,000~64,000、 スループットを500~4,000 MiB/sの範囲で設定可能。 | インスタンスクラスが設定されたIOPSとスループットの量をサポートしていることを確認する必要があります。 そうでない場合、インスタンスクラスがボトルネックになります。 |
io2 Block Expressの場合、 スループットはプロビジョニングされたIOPSごとに最大0.256 MiB/s、 最大4,000 MiB/sまで比例的にスケールアップ |
これらの制限事項の詳細については、Amazon RDS DBインスタンスのストレージの操作を参照してください。
以下の手順に従って、Lambda関数を作成します。簡略化のため、以下の例ではIOPSスケーリングを自動化する方法について説明していますが、スループットをスケーリングするようにコードを適応させることもできます。
【1】AWS Identity and Access Management(IAM)Lambda実行ロールを作成し、Lambda関数にRDSインスタンスのストレージパラメータを変更する権限を付与します。Amazon CloudWatchにメッセージをログに記録するために必要な権限を含む、以下の権限が必要です。
rds:DescribeDBInstances
rds:ListTagsForResource
rds:ModifyDBInstance
logs:CreateLogGroup
logs:CreateLogStream
logs:PutLogEvents
以下は、必要な権限を提供するIAMポリシーの例です。(例にあるアカウントIDは、ご自身のアカウントIDに変更する必要があります)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor",
"Effect": "Allow",
"Action": [
"rds:DescribeDBInstances",
"rds:ListTagsForResource",
"rds:ModifyDBInstance"
],
"Resource": "arn:aws:rds:*:{your_account_id}:db:*"
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:{your_account_id}:*"
}
]
}
【2】PythonでLambda関数を作成
前に作成したIAMロールをアタッチし、Lambda関数では以下のことを行います。
また、現在の日付を取得し、その日が需要が高い期間に該当するかどうかを確認し、需要が低い場合はmodify_db_instance()を呼び出して、IOPSをIOPSLowSettingの値に設定します。
タグ | 意味 |
---|---|
IOPSHighSetting | インスタンスの需要が高い場合(期間内)に設定されるIOPSの数 |
IOPSLowSetting | インスタンスの需要が低い場合(期間外)に設定されるIOPSの数 |
IOPSHighDayInterval | データベースの需要が高い日数の間隔 |
IOPSをスケーリングするためのソースコードは以下のとおりです。
import boto3
import os
import logging
logger = logging.getLogger()
logger.setLevel("INFO")
from datetime import datetime
rds = boto3.client('rds')
def lambda_handler(event, context):
logger.info('## ENVIRONMENT VARIABLES')
logger.info(os.environ['AWS_LAMBDA_LOG_GROUP_NAME'])
logger.info(os.environ['AWS_LAMBDA_LOG_STREAM_NAME'])
logger.info('## EVENT')
logger.info(event)
# Get current day of month
today = datetime.today().day
# Get list of RDS instances
response = rds.describe_db_instances()
for db in response['DBInstances']:
curr_Iops = int(db['Iops'])
arn = db['DBInstanceArn']
tags = rds.list_tags_for_resource(ResourceName=arn)
# Check if tags exist
tag_dict = {tag['Key']: tag['Value'] for tag in tags['TagList']}
logger.info('Processing database {0}'.format(arn))
if 'IOPSHighSetting' in tag_dict and 'IOPSLowSetting' in tag_dict and 'IOPSHighDayInterval' in tag_dict:
logger.info('IOPS tags found')
high_iops = int(tag_dict['IOPSHighSetting'])
low_iops = int(tag_dict['IOPSLowSetting'])
interval_str = tag_dict['IOPSHighDayInterval']
# Parse interval
interval_days = [int(x) for x in interval_str.split("-")]
interval_start = interval_days[0]
interval_end = interval_days[1]
# Check if current day is within interval
if interval_start <= today <= interval_end:
iops = high_iops
else:
iops = low_iops
if curr_Iops == iops:
logger.info('No change needed, databases IOPS already set to {0}'.format(str(iops)))
else:
logger.info('Changing databases IOPS from {0} to {1}'.format(curr_Iops,str(iops)))
# Modify IOPS
try:
rds.modify_db_instance(
DBInstanceIdentifier=db['DBInstanceIdentifier'],
AllocatedStorage=db['AllocatedStorage'],
Iops=iops,
ApplyImmediately=True
)
except Exception as error:
logger.error('Could not apply change to database {0}: {1}'.format(db['DBInstanceIdentifier'], error))
else:
logger.info('No IOPS tags found')
【3】Lambda関数を毎日午前0時に呼び出すには、スケジュール式cron(0 0 * * ? *)を使用して、EventBridge Schedulerルールを作成します。
これにより、Lambda関数が毎日UTC 00:00にトリガーされますが、より適切な変更時間を選択できます。運用中にダウンタイムは発生しません。
Lambda関数に、必要なアクションを完了するための十分なタイムアウトとメモリが割り当てられていることを確認してください。デフォルトの3秒と128 MBは、RDSインスタンスが1つのテスト環境では機能しますが、複数のインスタンスでは機能しない場合があります。
【1】3つのタグ(IOPSHighSetting、IOPSLowSetting、IOPSHighDayInterval)を設定して、RDSインスタンスを作成
前に説明したように、インスタンスとストレージタイプのIOPS設定の境界内に設定が収まっていることを確認するには、Amazon RDS DBインスタンスストレージを参照してください。
【2】Lambdaコンソールで、テスト環境を設定
提供されているコードの場合、テストイベントに変数を指定する必要はありません。
【3】Lambda関数をテスト
Lambda関数が期待どおりに機能している場合は、ログに次のようなメッセージが表示されます。
上記の例では、RDSインスタンスはすでに本日の予想されるIOPS設定で設定されていました。
【4】本日を高い需要間隔に含めるように、タグIOPSHighDayIntervalを変更してみましょう。
【5】Lambdaテストイベントを再度実行すると、インスタンスのIOPS設定が変更されていることがわかります。
インスタンスの状態は「変更中」に変わります。変更が完了するまでしばらく時間がかかる場合があります。「変更中」の後は、状態は「ストレージの最適化」に変わります。インスタンスがこれらのいずれかの状態にある間は、少なくとも6時間はストレージに新しい変更を加えることができず、間隔を再度変更してLambda関数を実行すると、次のエラーが発生します。ModifyDBInstance操作の呼び出し中にエラーが発生しました(InvalidParameterCombination):以前のストレージ変更が最適化されているため、現在このDBインスタンスのストレージを変更できません。
ストレージの最適化の詳細については、Amazon RDS DBインスタンスのストレージの操作を参照してください。
スケジューラータグに従ってストレージ設定を調整するには、Lambda関数を毎日実行する必要があります。これは、EventBridgeでスケジューラーイベントを作成することで実現できます。以下の手順を実行します。
【1】EventBridgeコンソールのナビゲーションペインの[スケジューラー]で、[スケジュール]を選択
【2】[スケジュールの作成]を選択します。
【3】ルール名、オプションの説明、イベントバスなどのルール詳細を入力
【4】[ルールタイプ]で、[スケジュール]を選択します。
【5】[スケジュールパターン]で、[スケジュール式]を選択します。
【6】[発生]で、[繰り返しスケジュール]を選択
【7】[スケジュールタイプ]で、[Cronベースのスケジュール]を選択
【8】[Cron式]に、cronパラメータを入力
この記事では、アクションを毎日午前0時に実行するようにスケジュールします。
【9】15分の柔軟な時間枠を選択し、[次へ]を選択
【10】[ターゲットの選択]で、[AWS Lambdaの呼び出し]を選択
【11】関数名で、前に作成したLambda関数を選択
【12】[設定]で、[すべてのリクエストで同じ設定を使用する]を選択
【13】[スケジュールの完了後のアクション]で、[なし]を選択
【14】[権限]セクションで、すでに作成済みの特定のロールがない限り、[スケジュールの新しいロールを作成する]を選択し、ロール名を入力
【15】[次へ]を選択
【16】すべてが想定どおりであることを確認し、[スケジュールの作成]を選択します。
Lambda関数はスケジュールどおりに実行されます。実行を監視するには、Amazon EventBridgeの監視を参照してください。
このガイドに従ってテスト環境を作成した場合は、継続的なコストが発生しないように、以下のリソースを削除する必要があります。
この記事では、RDSインスタンスタグで設定されたスケジューラーに基づいて、ストレージパフォーマンスパラメータを自動的に調整する方法について概説しました。このソリューションは、EventBridgeスケジューラーとPythonで記述されたLambda関数に基づいており、コストを削減し、データベースのパフォーマンスを向上させることができます。このソリューションは、要件に応じて、IOPSパラメータだけでなく、スループットもスケーリングできます。
この記事が、皆さんのRDS環境の最適化に役立てば幸いです。
AWSモダナイズ開発、データ分析基盤構築とデータ活用支援、基幹業務システムのUI.UX刷新はお気軽にお問い合わせください。
スモールスタート開発支援、サーバーレス・NoSQLのことなら
ラーゲイトまでご相談ください
低コスト、サーバーレスの
モダナイズ開発をご検討なら
下請け対応可能
Sler企業様からの依頼も歓迎