// Compute expected utility as a weighted average over all of the SLAs used by all clients private float ExpectedUtilityForClients(ReplicaConfiguration config, Dictionary <string, ClientUsageData> clientData) { float avgExpectedUtility = 0; int totalReads = clientData.Values.Sum(client => client.NumberOfReads); float totalUtility = 0; foreach (string clientName in clientData.Keys) { float totalClientUtility = 0; foreach (ServiceLevelAgreement sla in clientData[clientName].SLAs) { float slaUtility = ExpectedUtilityForSla(config, sla, clientData[clientName].ServerRTTs); totalClientUtility += slaUtility; } float avgClientUtility = 0; if (totalClientUtility > 0) { avgClientUtility = totalClientUtility / clientData[clientName].SLAs.Count; } totalUtility += avgClientUtility * clientData[clientName].NumberOfReads; } if (totalReads != 0) { avgExpectedUtility = totalUtility / totalReads; } return(avgExpectedUtility); }
/// <summary> /// Read the configuration blob from Azure storage and update the local configuration. /// </summary> internal bool DownloadConfiguration() { try { using (MemoryStream stream = new MemoryStream()) { configurationBlob.DownloadToStream(stream); stream.Seek(0, 0); BinaryFormatter formatter = new BinaryFormatter(); ReplicaConfiguration cloudConfig = (ReplicaConfiguration)formatter.Deserialize(stream); if (!configurationBlob.Metadata.ContainsKey(ConstPool.EPOCH_NUMBER)) { Console.WriteLine("No Epoch in configuration metadata!"); // this should not happen return(false); // stay with current configuration for now } int currentEpoch = Convert.ToInt32(configurationBlob.Metadata[ConstPool.EPOCH_NUMBER]); if (currentEpoch > config.Epoch) { config.PrimaryServers = cloudConfig.PrimaryServers; config.PrimaryServers.Sort(); config.SecondaryServers = cloudConfig.SecondaryServers ?? new List <string>(); config.WriteOnlyPrimaryServers = cloudConfig.WriteOnlyPrimaryServers ?? new List <string>(); foreach (string server in config.SecondaryServers) { config.SetSyncPeriod(server, cloudConfig.GetSyncPeriod(server)); } config.Epoch = currentEpoch; if (configurationBlob.Metadata[ConstPool.EPOCH_MODIFIED_TIME] != null) { config.EpochModifiedTime = DateTimeOffset.Parse(configurationBlob.Metadata[ConstPool.EPOCH_MODIFIED_TIME]); } else { config.EpochModifiedTime = DateTimeOffset.MinValue; } } } } catch (StorageException se) { Console.WriteLine(se.ToString()); Console.WriteLine(se.StackTrace); throw se; } catch (Exception ex) { Console.WriteLine(ex.ToString()); Console.WriteLine(ex.StackTrace); throw ex; } return(true); }
/// <summary> /// Returns the <see cref="ReplicaConfiguration"/> for a named container. /// If the configuration has not yet been cached locally, it is read from Azure's configuration container. /// </summary> /// <param name="containerName">Name of the container</param> /// <param name="cloudBacked">Whether the configuration should be fetched from Azure</param> /// <param name="autoRefresh">If true, the configuration will automatically refresh by reading its state from the azure storage. Hence, all new configurations will be reflected here automatically.</param> /// <returns></returns> public static ReplicaConfiguration GetConfiguration(string containerName, bool cloudBacked = true, bool autoRefresh = true) { if (!configurations.ContainsKey(containerName)) { configurations[containerName] = new ReplicaConfiguration(containerName); if (cloudBacked) { configurations[containerName].SyncWithCloud(configurationAccount, autoRefresh); } } return(configurations[containerName]); }
/// <summary> /// Periodically uploads SLAs and SessionStates. /// SLAs and SessionStates are stored in two Azure tables called. /// </summary> public void StartUploadConfigurationTask(string containerName, List <ConsistencySLAEngine> engines, SessionState sessionState, ServerMonitor monitor) { activeUploaders[containerName] = true; int sleepDuration = 0; int epoch; DateTimeOffset lastModified; ReplicaConfiguration configuration = ClientRegistry.GetConfiguration(containerName, false); if (configuration == null) { activeUploaders[containerName] = false; } while (activeUploaders[containerName]) { try { configuration.SyncWithCloud(ClientRegistry.GetConfigurationAccount()); while (!configuration.IsInFastMode()) { lock (configuration) Monitor.Wait(configuration, 1000); } epoch = configuration.Epoch; Console.WriteLine("Uploading SLA and SessionState with Epoch: " + epoch); lastModified = configuration.EpochModifiedTime; // |====a====|-conf in progress-|====b====| //Clients upload their configurations between the middle of a configuration period, and before a configuration epoch is finished. //I.e., after for example a, and before the first next bar, or after b, and before the next upcomming bar. if (DateTimeOffset.Now.Subtract(lastModified).TotalMilliseconds > ConstPool.CONFIGURATION_UPLOAD_INTERVAL / 2) { UploadClientData(containerName, epoch, engines, sessionState, monitor); //Console.WriteLine("Uploaded the configuration to the azure storage. ..."); sleepDuration = ConstPool.CONFIGURATION_UPLOAD_INTERVAL; } else { //we try to push the upload to some time after the middle of an epoch duration. sleepDuration = (ConstPool.CONFIGURATION_UPLOAD_INTERVAL / 2) - DateTimeOffset.Now.Subtract(lastModified).Milliseconds; } Thread.Sleep(sleepDuration); } catch (Exception ex) { Console.WriteLine(ex.StackTrace); throw ex; } } }
private float ComputeUtilityGain(ReplicaConfiguration config, List <ConfigurationAction> actions, Dictionary <string, ClientUsageData> clientData) { ReplicaConfiguration newConfig = config; foreach (ConfigurationAction action in actions) { newConfig = action.IfApply(newConfig); } float gain = ExpectedUtilityForClients(newConfig, clientData) - DeliveredUtilityForClients(config, clientData); return(gain); }
private float ExpectedUtilityForSla(ReplicaConfiguration config, ServiceLevelAgreement sla, Dictionary <string, LatencyDistribution> serverRTTs) { float utility = 0; float cumulativeProb = 0; float prob = 0; List <string> allServers = config.GetServers(true, true, false); foreach (SubSLA sub in sla) { foreach (string server in allServers) { prob = allServers.Max(s => serverRTTs[s].ProbabilityOfFindingValueLessThanGiven(sub.Latency) * ProbabilityOfServerConsistency(config, s, sub.Consistency, sub.Bound)); } float subUtility = (1 - cumulativeProb) * prob * sub.Utility; utility += subUtility; cumulativeProb += (1 - cumulativeProb) * prob; } return(utility); }
/// <summary> /// Constructor for ConfigurationCloudStore /// </summary> /// <param name="account">the Azure account where configuration data is stored</param> public ConfigurationCloudStore(CloudStorageAccount account, ReplicaConfiguration configuration) { config = configuration; try { configurationCloudBlobClient = account.CreateCloudBlobClient(); configurationContainer = configurationCloudBlobClient.GetContainerReference(ConstPool.CONFIGURATION_CONTAINER_PREFIX + config.Name); configurationContainer.CreateIfNotExists(); configurationBlob = configurationContainer.GetBlockBlobReference(ConstPool.CURRENT_CONFIGURATION_BLOB_NAME); if (!configurationBlob.Exists()) { CreateConfiguration(false); } } catch (StorageException ex) { Console.WriteLine(ex.ToString()); throw ex; } }
public Replicator(string capCloudBlobContainerName) { configuration = ClientRegistry.GetConfiguration(capCloudBlobContainerName, true); name = configuration.Name; }
public static void RemoveConfiguration(ReplicaConfiguration Configuration) { configurations.Remove(Configuration.Name); }
public static void AddConfiguration(ReplicaConfiguration Configuration) { configurations[Configuration.Name] = Configuration; }
private List <ConfigurationAction> ChooseReconfigActions(Dictionary <string, ClientUsageData> clientData, List <ConfigurationConstraint> constraints, ReplicaConfiguration config) { Dictionary <string, ConfigurationAction> actions = new Dictionary <string, ConfigurationAction>(); // build sorted list of all SLAs SortedSet <ServiceLevelAgreement> SLAs = new SortedSet <ServiceLevelAgreement>(new ServiceLevelAgreementComparer()); foreach (ClientUsageData client in clientData.Values) { SLAs.UnionWith(client.SLAs); } AppendToLogger("Start Computing Actions"); foreach (string clientName in clientData.Keys) { foreach (ServiceLevelAgreement sla in clientData[clientName].SLAs) { Dictionary <string, ConfigurationAction> tmp = ActionSelector.ComputeActions(this.containerName, config, sla, clientData[clientName]); foreach (string id in tmp.Keys) { if (!actions.ContainsKey(id)) { actions[id] = tmp[id]; } else { actions[id].Merge(tmp[id]); } //We keep track of clients. We will use this list in the checking phase (below) actions[id].Clients.Add(clientName); AppendToLogger(tmp[id].ToString()); } } } AppendToLogger("Start Checking Actions"); foreach (string clientName in clientData.Keys) { foreach (ServiceLevelAgreement sla in clientData[clientName].SLAs) { foreach (ConfigurationAction action in actions.Values) { if (!action.OriginatingSLAs.Contains(sla.Id) || !action.Clients.Contains(clientName)) { ActionSelector.CheckAction(action, sla, clientData[clientName], config); } } } } foreach (ConfigurationAction action in actions.Values) { AppendToLogger(action.ToString()); } List <ConfigurationAction> pickedAction = new List <ConfigurationAction>(); List <ConfigurationAction> sortedActions = actions.Values.ToList(); //we do not even consider actions with negative gained utility. sortedActions.RemoveAll(e => e.GainedUtility < 0); sortedActions.Sort(new ConfigurationActionComparer()); // we sort constraints based on their priority. constraints.Sort(new ConfigurationConstraintComparer()); bool foundAction = false; for (int i = sortedActions.Count - 1; i >= 0; i--) { pickedAction.Clear(); pickedAction.Add(sortedActions[i]); if (constraints.Count() == 0) { foundAction = true; break; } //Remove actions that are not satisfying constraints. foreach (ConfigurationConstraint c in constraints) { c.Apply(pickedAction, constraints, SLAs, clientData); if (pickedAction.All(e => e.Source == ConfigurationActionSource.Constraint)) { //the action is removed because of conflict with other constraints. foundAction = false; break; } else { foundAction = true; } } if (foundAction) { break; } } if (!foundAction) { //no action is applicable with all constraints. so, we just try to apply constraints. //hence, no non-constraint action will be executed to improve utility. pickedAction.Clear(); foreach (ConfigurationConstraint c in constraints) { c.Apply(pickedAction, constraints, SLAs, clientData); } } return(pickedAction); }
public List <ConfigurationAction> PickNewConfiguration(CloudStorageAccount account, int currentConfigurationEpoch, ReplicaConfiguration config, List <ConfigurationConstraint> constraints) { // Read client's data Dictionary <string, ClientUsageData> clientData; ClientUsageCloudStore store = new ClientUsageCloudStore(account, "configurator"); clientData = store.ReadClientData(containerName, currentConfigurationEpoch); // Choose actions to produce a better configuration return(ChooseReconfigActions(clientData, constraints, config)); }
/// <summary> /// Picks a new configuration given a single SLA and single client's session state /// </summary> /// <param name="sla">The SLA for which the new configuration should be tailored</param> /// <param name="ss">The session state</param> /// <param name="constraints">The constraints</param> /// <returns>a set of reconfiguration actions</returns> public List <ConfigurationAction> PickNewConfiguration(string containerName, ServiceLevelAgreement sla, SessionState ss, ServerMonitor monitor, ReplicaConfiguration config, List <ConfigurationConstraint> constraints) { Dictionary <string, ClientUsageData> clientData = new Dictionary <string, ClientUsageData>(); ClientUsageData usage = new ClientUsageData("local"); // Convert args into client data usage.SLAs.Add(sla); usage.NumberOfReads = ss.GetNumberOfReadsPerMonth(); usage.NumberOfWrites = ss.GetNumberOfWritesPerMonth(); usage.ServerRTTs = new Dictionary <string, LatencyDistribution>(); foreach (ServerState server in monitor.GetAllServersState()) { usage.ServerRTTs.Add(server.Name, server.RTTs); } // Use client data for a single user clientData.Add(usage.ClientName, usage); // Choose actions to produce a better configuration return(ChooseReconfigActions(clientData, constraints, config)); }
// Returns the likelihood that a given server is sufficiently up-to-date to meet the given consistency // For many consistencies, this is hard to predict, and better predicitve models are possible. public float ProbabilityOfServerConsistency(ReplicaConfiguration config, string server, Consistency consistency, int bound) { float prob = 0; switch (consistency) { case Consistency.Strong: if (config.PrimaryServers.Contains(server) && !config.WriteOnlyPrimaryServers.Contains(server)) { prob = 1.0F; } break; case Consistency.ReadMyWrites: case Consistency.Session: // could possibly compute probability based on past performance and read/write ratio // for now, arbitrarily return 0.5 prob = 0.5F; break; case Consistency.MonotonicReads: // almost always will read from the closest server prob = 1.0F; break; case Consistency.Causal: // could possibly compute probability based on past performance and read/write ratio // for now, arbitrarily return 0.25 prob = 0.25F; break; case Consistency.Bounded: case Consistency.BoundedMonotonicReads: // depends on the sync frequency if (bound >= config.GetSyncPeriod(server)) { prob = 1.0F; } else { prob = bound / config.GetSyncPeriod(server); } break; case Consistency.BoundedReadMyWrites: case Consistency.BoundedSession: // depends on the sync frequency if (bound >= config.GetSyncPeriod(server)) { prob = 0.5F; } else { prob = bound / config.GetSyncPeriod(server); } break; case Consistency.Eventual: if (config.PrimaryServers.Contains(server) || config.SecondaryServers.Contains(server)) { prob = 1.0F; } break; default: prob = 0; break; } return(prob); }
public void Configure(CloudStorageAccount account, int currentConfigurationEpoch, ReplicaConfiguration currentConfig, List <ConfigurationConstraint> constraints) { List <ConfigurationAction> pickedAction = PickNewConfiguration(account, currentConfigurationEpoch, currentConfig, constraints); InstallNewConfiguration(pickedAction); }
/// <summary> /// Picks a new configuration given a single SLA and single client's session state /// </summary> /// <param name="sla">The SLA for which the new configuration should be tailored</param> /// <param name="ss">The session state</param> /// <param name="constraints">The constraints</param> /// <returns>a set of reconfiguration actions</returns> public float ComputeUtilityGainFromNewConfiguration(string containerName, ServiceLevelAgreement sla, SessionState ss, ServerMonitor monitor, ReplicaConfiguration config, List <ConfigurationAction> actions) { Dictionary <string, ClientUsageData> clientData = new Dictionary <string, ClientUsageData>(); ClientUsageData usage = new ClientUsageData("local"); // Convert args into client data usage.SLAs.Add(sla); usage.NumberOfReads = ss.GetNumberOfReadsPerMonth(); usage.NumberOfWrites = ss.GetNumberOfWritesPerMonth(); usage.ServerRTTs = new Dictionary <string, LatencyDistribution>(); foreach (ServerState server in monitor.GetAllServersState()) { usage.ServerRTTs.Add(server.Name, server.RTTs); } // Use client data for a single user clientData.Add(usage.ClientName, usage); return(ComputeUtilityGain(config, actions, clientData)); }