Azure SQL Databaseを使ったシステムの、高負荷試験を行った時に、最大同時リクエスト数の制限を超えてエラーになった為、各モデル・DTU毎のリソース制限値について調べててみた。
スポンサーリンク
リソース制限値
ちょうど、TechNetのブログにエントリーがあった為、記事書かれていた各モデル・DTU毎のリソース制限値について、以下にメモ。
(2015年6月時点の情報の為、若干古いかもしれません…)
Service Tier/Performance Level | DTU | MAX DB Size | Max Concurrent Requests | Max Concurrent Logins | Max Sessions | Benchmark Transaction Rate | Predictability |
---|---|---|---|---|---|---|---|
Basic | 5 | 2 GB | 30 | 30 | 300 | 16,600 transactions per hour | Good |
Standard/S0 | 10 | 250 GB | 60 | 60 | 600 | 521 transactions per minute | Better |
Standard/S1 | 20 | 250 GB | 90 | 90 | 900 | 934 transactions per minute | Better |
Standard/S2 | 50 | 250 GB | 120 | 120 | 1200 | 2,570 transactions per minute | Better |
Standard/S3 | 100 | 250 GB | 200 | 200 | 2400 | 5,100 transactions per minute | Better |
Premium/P1 | 125 | 500 GB | 200 | 200 | 2400 | 105 transactions per second | Best |
Premium/P2 | 250 | 500 GB | 400 | 400 | 4800 | 228 transactions per second | Best |
Premium/P3 | 1000 | 500 GB | 1600 | 1600 | 19200 | 735 transactions per second | Best |
対策
では、エラーにならない為の対策について考えます。
方法1) より上位のモデルにスケールアウトする
上に書いた表の通り、より上位のモデルを使用すれば同時リクエスト数の上限値が上がります。
※ 同時に価格も高くなりますが。。。
方法2) リトライ処理を組み込む
上位モデルに上げる事が出来ない場合は、同時リクエスト数の上限を超えた時に発生する、以下の例外メッセージをうまく使って、リトライ処理を実装します。
System.Data.SqlClient.SqlException (0x80131904): Resource ID : 1. The request limit for the database is 120 and has been reached.
C#で実際にサンプルコードを書いてみましたので、以下に紹介します。
まず、RetryExecute
というリトライ用の関数を作成します。
この関数では、SqlExceptionのメッセージに「request limit for the database」というキーワードがあれば、リクエスト数の上限を超えたと判断し、リトライを行なうようにします。
また、リトライまでのwait時間を一定にすると、また同じタイミングで大量リクエストが発生してエラーになる可能性がある為、wait時間を50〜150msの間でランダムにしています。
private static System.Random random = new System.Random (1000);
public static void RetryExecute(Action action) {
const int MAX_RETRY_CNT = 3;
for (int cnt = 1; cnt <= MAX_RETRY_CNT; cnt++) {
try {
action ();
break;
} catch (System.Data.SqlClient.SqlException sex) {
if (cnt == MAX_RETRY_CNT) {
throw sex;
}
if (sex.Message != null && sex.Message.IndexOf ("request limit for the database") >= 0) {
//最大同時リクエスト数を超えたエラーが発生した時、リトライを行う
int wtime = random.Next (50, 150);
System.Threading.Thread.Sleep (wtime);
} else {
throw sex;
}
}
}
}
次は、実際にSQLを発行する側の実装です。
まず(1)の所で、実行するSQLのSqlCommand
を作成します。
(2)で、RetryExecute
関数の引数に、SQLを実行する処理を関数で渡します。
こうする事で、RetryExecute
関数の中で、同時リクエスト数の上限を超えてエラーが発生しても、リトライが行われるようになります。
//(1)
var cmd = conn.CreateCommand ();
cmd.CommandText = "select user_name from users";
//(2)
RetryExecute (() => {
using(var reader = cmd.ExecuteReader ()) {
while (reader.NextResult ()) {
Console.WriteLine (reader.GetString (0));
}
}
});
スポンサーリンク
補足
2019年2月現在の、DBサイズ毎の、最大リクエスト数の上限値に関する資料が見つかったので、一応URLをメモしておきます。
https://docs.microsoft.com/ja-jp/azure/sql-database/sql-database-dtu-resource-limits-single-databases
0 件のコメント:
コメントを投稿