Wie skaliert man eine Azure SQL Datenbank on Demand und vollautomatisch

Hallo @all,

traditionell wird in der IT die Infrastruktur nach dem maximalen Peak geplant . D.h. die Umgebung wird oftmals überdimensioniert umgesetzt, für den Fall der Fälle. In Azure wird Hardware zum Service. Ich nennen es mal Hardware as a Service, d.h. Hardware ist nur noch eine Quota, die man einfach aufdreht und wieder zudreht, wie einen Wasserhahn. D.h. auf dieser Basis plant man Cloud-Architekturen. Also nicht mehr nach dem maximalen Peak sondern nach dem Skalierungsverhalten und das Anfangsziel ist immer die Unterdimensionierung und minimale Hardwareanforderung.

Ja Ihr habt richtig gehört/gelesen, Unterdimensionierung. Am Anfang unterdimensioniert man jede Umgebung, denn damit definiert man die immer anfallenden Fix-Kosten. Ähnlich wie beim Wasserhahn. Wenn dieser zu 10% geöffnet ist, fließt ständig ein wenig Wasser und das kostet Geld.

Derzeit (Stand: 30.4.2015) werden die Azure Datenbankstufen auf stündlicher Basis gemessen und ein ändern des Performance-Levels ist pro Tag, 4 mal möglich. D.h. unter dem Strich, Wasserhahn voll aufdrehen => mehr Wasserkosten/Hardwarekosten, Wasserhahn zudrehen => weniger Hardwarekosten. Bei Azure SQL Datenbanken gibt es folgende Stufen bei der Wahl des richtigen PerformanceLevels/Hardwarestufen:

  • Basis
  • Standard S0
  • Standard S1
  • Standard S2
  • (Standard S3 – in Preview)
  • Premium P1
  • Premium P2
  • Premium P3

image
Notiz: Die Tabelle hilft, doch in der Praxis ist das Messen der Datenbankauslastung in der Performance-Stufe entscheidend.

Wie implementiert man diese Verhalten?

Insgesamt mit 3 Schritten:

  1. Messen der aktuellen Lastsituation & Hardwareauslastung, pro Datenbank
  2. Eine Entscheidungslogik definieren wann man skalieren möchte.
  3. Skalierung durchführen

In dem Blogpost gebe ich euch die Schritte 1 und 3. Wie ihr am besten eure Applikation skaliert, d.h. in welche Stufe ihr springen wollt, das könnt ihr einfach austesten mit den beiden Schritten.

Punkt 1: Messen der Performancelast & Hardwareauslastung:
Der Hardware-Verbrauch wird in Azure SQL Datenbanken durch Performance-Stufen beschrieben. Jede Stufe hat eine Anzahl an CPU (DTU in Azure genannt), RAM, IO-Verhalten, etc.  Unter dem Strich kann man mit einer einzigen SQL Query die aktuelle Auslastung der Performance-Stufe abrufen:

image

-- aktuelle SQL Auslastung ausgeben
select top 1 * from sys.dm_db_resource_stats order by end_time desc

Die Query ist so intelligent, dass man das Ergebnis prozentual zur aktuell laufenden Performance-Stufe erhält. Also kein Wildes ausrechnen von Max. und Min.-Werten für die jeweilige Stufe.

Ich lasse es in der Regel via Powershell ausführen:

$mypassword = "..."
$user = "sqladmin"
$dbserver = "akskdfjasldkfa"
$dbname = "myDb"

function Invoke-SQL {
    param(
        [string] $sqlCommand = $(throw "Please specify a query.")
      )

    $connectionString = "Server=tcp:$dbserver.database.windows.net,1433;Database=$dbname;User ID=$user@$dbserver;Password=$mypassword;Trusted_Connection=False;Encrypt=True;Connection Timeout=30;"

    $connection = new-object system.data.SqlClient.SQLConnection($connectionString)
    $command = new-object system.data.sqlclient.sqlcommand($sqlCommand,$connection)
    $connection.Open()

    $adapter = New-Object System.Data.sqlclient.sqlDataAdapter $command
    $dataset = New-Object System.Data.DataSet
    $adapter.Fill($dataSet) | Out-Null

    $connection.Close()
    $dataSet.Tables | ft -AutoSize

}

for ($x = 0; $x -lt 10000; $x++)
{
    Write-Host "run $x"
     Invoke-SQL -sqlCommand "select top 1 * from sys.dm_db_resource_stats order by end_time desc"
   
    # sys.dm_db_resource_stats
    # sys.resource_stats
    Start-Sleep -Seconds 1
}

Das Ergebnis sieht dann so aus:

image

Punkt 2: Entscheiden wann der Performance-Hahn aufgedreht wird und wann dieser wieder zugedreht werden soll.

Bevor man einfach blind entscheidet muss man kurz ein paar Dinge wissen, damit man richtig und optimal entscheiden kann.

Azure SQL Datenbanken werden Stundengenau in der Performance-Stufe berechnet. Auf Basis dieser Information sollte man die Frequenz zum Skalieren von mind. größer als 1 Stunde wählen.

Pro Tag kann man eine Datenbank 4 mal skalieren. D.h. man muss mit dem skalieren sparsam und gleichzeitig bewusst umgehen.

weitere Details hierzu: https://azure.microsoft.com/de-de/pricing/details/sql-database/

Eine einfache Businessentscheidung:

2 Zeiten definieren und das unerwartete:
1. die Non-Business-Phase
2. die Business-Phase
3. die unerwartete Phase

ein Beispiel:  
Non-Buisness-Phase – 22:00 – 06:00 => S0
Business-Phase – 6:00 – 22:00 => S2
unerwartete Phase – S3, P1, P2, P3

In Summe benötigt man über den Tag 2 Wechsel und man hat noch 2 Wechsel der Performance-Stufe in Reserve, für den Fall, das etwas unerwartetes passiert.

Punkt 3: Automatisiert den Performance-Hahn regeln lassen

Das setzen der neuen Performance-Stufe passiert bspw. über PowerShell.

# get all sql azure db server listed
Get-AzureSqlDatabaseServer

Write-Host
$dbserver = Read-Host "Choose your DB-Server"
$sqlServerContext = New-AzureSqlDatabaseServerContext -ServerName $dbserver -UseSubscription

Start-Sleep -Seconds 1

# get all DBs from Server
Get-AzureSqlDatabase $sqlServerContext | select Name,Edition, ServiceObjectiveName,ServiceObjectiveAssignmentStateDescription, MaxSizeGB| ft -AutoSize

Write-Host
$database = Read-Host "Choose your Database on"

$db = Get-AzureSqlDatabase $sqlServerContext -DatabaseName $database
# Name                                       : testdb1
# CollationName                              : SQL_Latin1_General_CP1_CI_AS
# Edition                                    : Premium
# MaxSizeGB                                  : 500
# MaxSizeBytes                               : 536870912000
# ServiceObjectiveName                       : P1
# ServiceObjectiveAssignmentStateDescription : Complete
# CreationDate                               : 12.01.2015 15:14:09
# RecoveryPeriodStartDate                    : 12.01.2015 15:44:10

$perflevel = Read-Host "Choose your new Database Performance Level: (Basic, S0, S1, S2, P1, P2, P3)"

# define a Premium performance level for the Database
$performanceLevel = Get-AzureSqlDatabaseServiceObjective $sqlServerContext -ServiceObjectiveName $perflevel  # set value to "P1 or P2 or P3"

# set the db performance Level to current db
switch -wildcard ($performanceLevel.Description)
    {
        "*Basic*"    { Set-AzureSqlDatabase $sqlServerContext –Database $db –ServiceObjective $performanceLevel –Edition Basic -Force
                      Write-Output "setup to basic"
                    }
        "*Standard*" { Set-AzureSqlDatabase $sqlServerContext –Database $db –ServiceObjective $performanceLevel –Edition Standard -Force
                      Write-Output "setup to standard"
                    }
        "*Premium*"  { Set-AzureSqlDatabase $sqlServerContext –Database $db –ServiceObjective $performanceLevel –Edition Premium -Force
                      Write-Output "setup to premium"
                    }
    }

Write-Host
Write-Host "new performance level"
$status = Get-AzureSqlDatabase $sqlServerContext -DatabaseName $database

write-host "operation status is " $status.ServiceObjectiveAssignmentStateDescription.ToString()

while ($status.ServiceObjectiveAssignmentStateDescription -eq 'Pending')
{
    $status = Get-AzureSqlDatabase $sqlServerContext -DatabaseName $database
    $time = get-date

    write-host "operation status is: " $status.ServiceObjectiveAssignmentStateDescription.ToString() " - " $time.ToLongTimeString()
   
}
Get-AzureSqlDatabase $sqlServerContext -DatabaseName $database | select Name,Edition, ServiceObjectiveName,ServiceObjectiveAssignmentStateDescription, MaxSizeGB| ft -AutoSize

Zu guter Letzt benötigt Ihr noch etwas Traffic im System und dann kann das IT-Regel-System einmal durchgetestet werden.

Meine Erfahrungen mit dem Verhalten in Projekten ist bisher nur positiv.

Viel Spaß damit und Liebe Grüße

Patrick