コード例 #1
0
        public static HyperScaleTier GetServiceObjective(HyperScaleTier currentSLO, SearchDirection direction)
        {
            var targetSLO     = currentSLO;
            var availableSlos = HyperscaleSLOs[currentSLO.Generation];
            var index         = availableSlos.IndexOf(currentSLO.ToString());

            if (direction == SearchDirection.Next && index < availableSlos.Count)
            {
                targetSLO = HyperScaleTier.Parse(availableSlos[index + 1]);
            }

            if (direction == SearchDirection.Previous && index > 0)
            {
                targetSLO = HyperScaleTier.Parse(availableSlos[index - 1]);
            }

            return(targetSLO);
        }
コード例 #2
0
        public static void Run([TimerTrigger("*/5 * * * * *")] TimerInfo timer, ILogger log)
        {
            var autoscalerConfig = new AutoScalerConfiguration();

            string connectionString = Environment.GetEnvironmentVariable("AzureSQLConnection");
            string databaseName     = (new SqlConnectionStringBuilder(connectionString)).InitialCatalog;

            using (var conn = new SqlConnection(connectionString))
            {
                // Get usage data
                var followingRows = autoscalerConfig.RequiredDataPoints - 1;
                var usageInfo     = conn.QuerySingleOrDefault <UsageInfo>($@"
                    select top (1)
                        [end_time] as [TimeStamp], 
                        databasepropertyex(db_name(), 'ServiceObjective') as ServiceObjective,
                        [avg_cpu_percent] as AvgCpuPercent, 
                        avg([avg_cpu_percent]) over (order by end_time desc rows between current row and {followingRows} following) as MovingAvgCpuPercent,
                        count(*) over (order by end_time desc rows between current row and {followingRows} following) as DataPoints
                    from 
                        sys.dm_db_resource_stats
                    order by 
                        end_time desc 
                ");

                // If SLO is happening result could be null
                if (usageInfo == null)
                {
                    log.LogInformation("No information received from server.");
                    return;
                }

                // Decode current SLO
                var currentSlo = HyperScaleTier.Parse(usageInfo.ServiceObjective);
                var targetSlo  = currentSlo;

                // At least one minute of historical data is needed
                if (usageInfo.DataPoints < autoscalerConfig.RequiredDataPoints)
                {
                    log.LogInformation("Not enough data points.");
                    WriteMetrics(log, usageInfo, currentSlo, targetSlo);
                    conn.Execute("INSERT INTO [dbo].[AutoscalerMonitor] (RequestedSLO, UsageInfo) VALUES (NULL, @UsageInfo)", new { UsageInfo = JsonConvert.SerializeObject(usageInfo) });
                    return;
                }

                // Scale Up
                if (usageInfo.MovingAvgCpuPercent > autoscalerConfig.HighThreshold)
                {
                    targetSlo = GetServiceObjective(currentSlo, SearchDirection.Next);
                    if (targetSlo != null && currentSlo.Cores < autoscalerConfig.vCoreMax && currentSlo != targetSlo)
                    {
                        log.LogInformation($"HIGH threshold reached: scaling up to {targetSlo}");
                        conn.Execute($"alter database [{databaseName}] modify (service_objective = '{targetSlo}')");
                    }
                }

                // Scale Down
                if (usageInfo.MovingAvgCpuPercent < autoscalerConfig.LowThreshold)
                {
                    targetSlo = GetServiceObjective(currentSlo, SearchDirection.Previous);
                    if (targetSlo != null && currentSlo.Cores > autoscalerConfig.vCoreMin && currentSlo != targetSlo)
                    {
                        log.LogInformation($"LOW threshold reached: scaling down to {targetSlo}");
                        conn.Execute($"alter database [{databaseName}] modify (service_objective = '{targetSlo}')");
                    }
                }

                // Write current SLO to monitor table
                WriteMetrics(log, usageInfo, currentSlo, targetSlo);
                conn.Execute("INSERT INTO [dbo].[AutoscalerMonitor] (RequestedSLO, UsageInfo) VALUES (@RequestedSLO, @UsageInfo)", new { @RequestedSLO = targetSlo.ToString().ToUpper(), UsageInfo = JsonConvert.SerializeObject(usageInfo) });
            }
        }