Condividi tramite


Il presente articolo è stato tradotto automaticamente.

Previsioni: aria tira?

Bilanciamento del carico di endpoint privati in ruoli di lavoro

Joseph Fultz

Joseph FultzAll'inizio del mese di gennaio David Browne e ho lavorato su una soluzione per caricare i punti di servizio interno saldo sui ruoli di lavoro di Windows azzurro ghiaccio. In genere, gli endpoint del servizio nei ruoli di lavoro vengono pubblicati, in modo che il sistema di bilanciamento del carico può occuparsi di bilanciamento le chiamate tra le istanze. Tuttavia, il cliente con cui ci stavamo lavorando necessarie endpoint che non sono state pubblicamente indirizzabili. Inoltre, non è stato da eseguire sulla latenza di qualche tipo di operazione di Accodamento messaggi. Come si dovrebbe soddisfare questa esigenza?

Durante un evento interno destinato a noi esplorare le diverse tecnologie e soluzioni, David e sono inventati due diversi approcci per risolvere il problema. Per di mese questo si parlerà delle considerazioni sulla progettazione e i bit del codice utilizzato per il prototipo di uno di questi approcci.

Non desiderano creare colli di bottiglia inavvertitamente la soluzione finale, è permesso di escludere una soluzione di tipo proxy software. Invece, è stato scelto un meccanismo di software che fornisce un indirizzo IP valido per le chiamate di servizio e il nodo di chiamata memorizza nella cache l'endpoint per una durata determinata per ridurre il sovraccarico di risoluzione degli endpoint. Tre principali strategie che considerato sono:

• Static assignment: assign a service endpoint to each calling node

• Centralized control: one node tracks and controls assignment of each calling node

• Cooperative control: allow any given node to indicate if it’s available to service calls

Ognuna di queste scelte è accompagnata da una serie di vantaggi e una serie di svantaggi.

Assegnazione statica ha il vantaggio di essere semplice da implementare. Se il mapping delle unità di lavoro tra il chiamante e il processo di lavoro è uguale, ciò può costituire un approccio possibile per il bilanciamento perché la soluzione di bilanciamento del carico per il ruolo Web verrà dall'estensione di bilanciare le chiamate al ruolo di lavoro.

I due svantaggi principali sono che esso non si occupa di elevata disponibilità per il servizio, né affronta qualsiasi discrepanza nel carico tra il chiamante e il nodo di servizio. Se si tenta di deformazioni della soluzione di assegnazione statica per la risoluzione dei problemi, la soluzione avvia quasi assuredly per lo spostamento verso il controllo centralizzato o cooperativo.

Controllo centralizzato

Un sistema di bilanciamento del carico tipico che riceve informazioni sanitarie e di bilancia le richieste di servizio in base a tali informazioni utilizza il controllo centralizzato. Consente di raccogliere informazioni sui nodi, sa sulle assegnazioni che già effettuate e tutte le informazioni di heartbeat e dirige le richieste effettuate a virtuale IP (VIP) a un nodo.

In questo scenario il punto centrale farebbe per lo più le stesse ad eccezione del fatto che non avrebbe agito come un proxy per la richiesta, ma piuttosto il nodo chiamando chiederà il controllore centrale per ricevere un buon indirizzo per effettuare la chiamata e il controller assegnerà un indirizzo basato su che cosa sa (vedere Figura 1). Nodo di chiamata sarà memorizzare nella cache l'endpoint e utilizzarlo per un quantum predeterminato, che al momento della scadenza verrà ripetuto il processo di risoluzione.

Centralized Control

Figura 1 controllo centralizzato

Intelligenza in tutte le si trova all'interno del controller centrale e deve tenere traccia di tutte le informazioni necessarie per determinare quale nodo per assegnare le chiamate. Potrebbe essere semplice come il round robin o assumere sull'insieme completo dei dati e l'analisi di integrità. Potrebbe inoltre essere complicata da vari endpoint di servizio con diversi criteri per determinare la disponibilità, vale a dire che il controller centrale deve essere sapere tutto in tutte le implementazioni del servizio nel pool di lavoro.

La più grande detractor da questa implementazione è che, se il controller centrale verso il basso, quindi il sistema è inattivo. Ciò significa che è necessario implementare una soluzione completamente separata per un'elevata disponibilità del controller centrale è stato risolto.

In alcuni automatiche e sistemi di matrice, i nodi di lavoro verranno sceglie di un controller primario e, se l'heartbeat viene perso, si sceglie semplicemente una nuova. Pur essendo un buon progetto poiché combina il controllo centralizzato e il controllo cooperativa, aggiunge anche in modo significativo per l'implementazione del meccanismo di distribuzione del carico.

Controllo cooperativa

Qualsiasi utente che viene effettuato dirigenti per ottenere l'incarico a qualcuno che qualcosa SA può costituire un ostacolo reale per ottenere un utente per eseguire il lavoro. Che gli chiede direttamente se egli abbia il tempo per eseguire questa operazione risulta per essere molto più vantaggioso e dato del ha un buon giudice dello sforzo di, è il modo migliore per determinare se ha effettivamente tempo necessario per eseguire il lavoro. Tale è il modello che seguito.

L'idea è che ognuno dei nodi chiamante inizierà con l'endpoint del servizio attualmente assegnato e chiedere se è ancora disponibile (vedere Figura 2). Se non lo è, il nodo continuerà a round robin tramite il pool disponibile fino a quando uno risponde positivamente (vedere Figura 3). In seguito, lo stesso meccanismo di cache scadenza descritto in precedenza consente di ridurre il sovraccarico di risoluzione endpoint.

Cooperative Control

Figura 2 controllo cooperativo

Balancing to Another Node

Figura 3 bilanciamento su un altro nodo

Il vantaggio di questa struttura è che viene realizzata la disponibilità elevata per impostazione predefinita e deve essere alta fedeltà tra il nodo per determinare la disponibilità e il lavoro effettivamente la possibilità per i chiamanti del servizio. Tutti i nodi di servizio devono avere la mente che regolano l'implementazione che è a conoscenza di aspetti specifici del servizio che renderebbe disponibili o non. Si tratta di intelligence di là della CPU e così che si potrebbe essere, ad esempio la disponibilità di sistemi a valle in cui si accede dal nodo. In questo modo, se il nodo restituisce un valore negativo, un errore o un timeout, nodo di chiamata interroga il successivo nodo di servizio disponibili e, se disponibile, effettua le chiamate di servizio a tale endpoint.

Il grande detractor da questa soluzione è che richiede l'implementazione su entrambi i lati del recinto per fornire un servizio di disponibilità e un protocollo di chiamata tra il chiamante e gli endpoint per verificare la disponibilità di endpoint.

Il prototipo

L'esempio eseguirà le operazioni seguenti:

  • Un meccanismo standard per determinare la disponibilità di installazione
  • Il chiamante memorizza nella cache un nodo disponibile per un breve periodo
  • Sarà in grado di disattivare un nodo di un quantum set, che illustri come tutte le chiamate viene bilanciate a un singolo nodo
  • Una volta che il nodo è nuovamente disponibile, il chiamante deve essere in grado di restituire al nodo precedente

Alcune avvertenze: in primo luogo, non eseguirò alcun lavoro per determinare in modo intelligente la disponibilità, fornite sono semplicemente impostare il meccanismo di bilanciamento e non la possibilità che l'intelligenza dietro la decisione. Inoltre, non lo faccio errori e i timeout, ma quelli sarebbe gestite nello stesso modo come ottenere un risultato negativo della query di disponibilità. Infine, acquisisco semplicemente tutti i ruoli di lavoro per la distribuzione, ma in un'implementazione true un modo più intelligente per determinare tutti gli endpoint di servizio disponibili potrebbe essere desiderato, ad esempio un meccanismo del Registro di sistema o semplicemente tentando di colpire il servizio su ciascun endpoint e il contrassegno chiamate riuscite come possibili endpoint. Il codice di posizionarsi nella misura in cui come chiedere un privato specifico endpoint e se è diverso per ogni servizio, che può essere utilizzato come elemento di differenziazione.

La prima cosa da fare è eseguire get l'elenco degli indirizzi IP dai ruoli nella distribuzione del lavoro. Per raggiungere tale obiettivo è necessario configurare i ruoli. Per i ruoli di lavoratore apro la finestra di configurazione e aggiungere un endpoint di servizio interno, come illustrato nella Figura 4.

Adding an Internal Service Endpoint to the Worker Role

Figura 4 aggiungendo un Endpoint di servizio interno al ruolo del lavoratore

Inoltre ho etichettato i ruoli di lavoro di distribuzione come PrivateServices. Utilizzando l'API dell'oggetto RoleEnvironment e l'etichetta, è facile recuperare i nodi:

if (_CurrentUriString == null) {
  System.Collections.ObjectModel.ReadOnlyCollection<RoleInstance> 
    ServiceInstances = null;
  System.Collections.ObjectModel.ReadOnlyCollection<RoleInstance> 
    WebInstances = null;

  ServiceInstances = 
    RoleEnvironment.Roles["PrivateServices"].Instances;
  WebInstances = 
    RoleEnvironment.Roles["ServiceBalancingWeb"].Instances;

Verrà corrisponde al nodo di inizio per il controllo della disponibilità utilizzando il numero ordinale del nodo. Se sono presenti più ruoli di Web diverso i ruoli di lavoro, utilizzerò una funzione resto in modo che corrisponda un nodo di inizio. Con le istanze in mano e un nodo di partenza per verificare la disponibilità, posso iniziare a ciclo continuo e testare gli endpoint (vedere Figura 5).

Figura 5 test endpoint

while (!found && !Abort) {
  string testuri = 
    ServiceInstances[idxSvcInstance].InstanceEndpoints[
    "EndPointServices"].IPEndpoint.ToString();
  found = CheckAvailability(testuri);
  if (found) { 
    ServiceUriString = testuri; 
  }
  else {
    idxSvcInstance++;
    if (idxSvcInstance >= ServiceInstances.Count) { 
      idxSvcInstance = 0; 
    }
    loopCounter++;
    if (loopCounter == ServiceInstances.Count) { 
      Abort = true; 
    }
  }
}

Notare che c'è una chiamata a una funzione denominata CheckAvailability (vedere Figura 6). All'interno di tale funzione viene creata un'associazione con nessuna per la modalità di protezione perché l'endpoint è solo interno. I client del servizio di creare un'istanza e impostare un timeout accettabile e restituire il valore della chiamata.

Figura 6 CheckAvailability

static public bool CheckAvailability(string uri) {
  bool retval = true;
  Binding binding = new NetTcpBinding(SecurityMode.None);
  EndPointServicesRef.EndPointServicesClient endpointsvc = 
    new EndPointServicesRef.EndPointServicesClient(binding, 
    new EndpointAddress(@"net.tcp://" + uri));
  endpointsvc.InnerChannel.OperationTimeout = 
    new System.TimeSpan(0,0,0,0, 5000);

  try {
    retval = endpointsvc.IsAvailable();
  }
  catch (Exception ex) {
    // Todo: handle exception
    retval = false;
  }
  return retval;
}

Se si verifica un errore durante la chiamata, ho semplicemente restituire false e consentire il ciclo passare al nodo successivo e verificare la disponibilità. Si noti che per determinare il numero di istanza del ruolo Web attualmente in esecuzione il codice sotto ho analizzato l'ID dell'istanza. Per utilizzare questo affatto è stato necessario aprire un arbitrario interno (Impossibile superata esterno) dell'endpoint. Se non era, non sarebbe incrementare l'ID e l'analisi sarebbe inutile perché ogni nodo sarà simile a uno solo.

Un altro modo per creare un elenco di nodi sarebbe per scorrere tutti i nodi, che identifica la posizione ordinale del nodo corrente in esecuzione nell'elenco oppure per ordinarli solo per l'ultimo ottetto di IP. Uno dei due metodi quest'ultimi è un po' più complesso a prova, ma per questo particolare esempio appena utilizzate l'ID dell'istanza.

Ulteriori avvertimento va detto che la struttura dell'ID diverso per la distribuzione effettiva e all'infrastruttura di sviluppo, forzando me di gestirla nel codice di analisi, come nell'esempio seguente:

string[] IdArray = 
  RoleEnvironment.CurrentRoleInstance.Id.Split('.');
int idxWebInstance = 0;
if (!int.TryParse((IdArray[IdArray.Length - 1]), 
  out idxWebInstance)) {
  IdArray = RoleEnvironment.CurrentRoleInstance.Id.Split('_');
  idxWebInstance = int.Parse((IdArray[IdArray.Length - 1]));
}

Ciò dovrebbe restituire un indirizzo IP endpoint valido che è possibile memorizzare nella cache in una variabile statica. Viene quindi impostato un timer. Quando viene generato l'evento verrà configurata l'endpoint su null, causando il codice cercare nuovamente un endpoint di tipo valido da utilizzare per i servizi:

System.Timers.Timer invalidateTimer = 
  new System.Timers.Timer(5000);
invalidateTimer.Elapsed += (sender, e) => 
  _CurrentUriString = null;
invalidateTimer.Start();

Qui ho utilizzato una breve durata di 5 secondi per assicurare che nell'esecuzione di una breve test è possibile Rimbalzo almeno un ruolo Web a un altro endpoint dopo che è possibile disattivare uno dei nodi di servizio.

Esecuzione della dimostrazione

A questo punto, verrà per modificare la pagina predefinita e il code-behind soltanto per evidenziare il nodo a cui è stabilito un'affinità. Aggiungerò inoltre un pulsante per disattivare un nodo. Entrambe le parti di codice sono piuttosto semplici. Ad esempio, il pulsante Disattiva disattiverà l'endpoint del servizio associato alla pagina Web in cui la richiesta ottiene bilanciata. In questo modo, essa può causare un po' di un aspetto dell'interfaccia utente complessa per questo esempio di test.

Aggiungerò un'etichetta e un pulsante di comando per l'interfaccia utente. Nell'etichetta verrà stampa fuori l'ID dell'endpoint assegnato e il pulsante mi consentirà di disattivare un nodo ed è possibile visualizzare tutti i ruoli di Web associati a un endpoint singolo fino a quando il nodo ritorna in linea. All'interno del codice dietro aggiungo un piccolo codice sul caricamento della pagina per ottenere l'endpoint (vedere Figura 7).

Figura 7 Codice della pagina Demo

protected void Page_Load(object sender, EventArgs e) {
  string UriString = EndpointManager.GetEndPoint();
  LastUri=UriString;
            
  Binding binding = new NetTcpBinding(SecurityMode.None);
            
  EndPointServicesRef.EndPointServicesClient endpointsvc = 
    new EndPointServicesRef.EndPointServicesClient(binding, 
    new EndpointAddress(@"net.tcp://" + UriString));
  lblMessage.Text = "WebInstacne ID: " + 
    RoleEnvironment.CurrentRoleInstance.Id.ToString() + 
    " is Calling Service @ " + UriString + " & IsAvailable = " + 
    endpointsvc.IsAvailable().ToString();
  cmdDisable.Enabled=true;
}

Poiché sono in realtà solo tentando di illustrare il corretto bilanciamento cooperativa, che non ho implementato un altro metodo di servizio o un'interfaccia, in modo da riutilizzare semplicemente il metodo IsAvailable per chiarire la situazione.

Figura 8 mostra l'applicazione prototipo in azione. Innanzitutto è possibile visualizzare l'ID (tratta dal tessuto development), il periodo dell'inchiesta e se è disponibile. Aggiornare la pagina fa sì che la richiesta di saldo, pertanto l'endpoint inoltre visualizzato in modo diverso. Se si fa clic sul pulsante Disattiva, una piccola porzione di codice eseguito per impostare chiamare DisableNode per l'endpoint corrente:

protected void cmdDisable_Click(object sender, EventArgs e) {
  Binding binding = new NetTcpBinding(SecurityMode.None);
  EndPointServicesRef.EndPointServicesClient endpointsvc = 
    new EndPointServicesRef.EndPointServicesClient(binding, 
    new EndpointAddress(@"net.tcp://" + LastUri));
  endpointsvc.DisableNode();
}

Running the Demo

Figura 8 esegue la Demo

Il metodo DisableNode di impostare il valore booleano e quindi consente di impostare un timer per abilitare nuovamente. Il timer è impostato per essere un po' più lungo di scadenza per l'endpoint nella cache in modo da renderla più semplice illustrare questo concetto nell'esecuzione dei test:

public void DisableNode() {
  AvailabilityState.Enabled = false;
  AvailabilityState.Available = false;

  System.Timers.Timer invalidateTimer = 
    new System.Timers.Timer(20000);
  invalidateTimer.Elapsed += (sender, e) => EnableNode();
  invalidateTimer.Start();
}

Con il nodo è disabilitato, le richieste successive provenienti da diversi server Web devono tutti saldo allo stesso endpoint di lavoro.

Di là dell'esempio

Ovviamente si tratta di un semplice esempio per illustrare il punto, ma è opportuno evidenziare alcuni aspetti da considerare per un'implementazione effettiva. Inoltre, è necessario precisare l'implementazione del signor Carta per risolvere il problema, poiché ha indirizzato a un dominio di problemi che non ho.

Era il mio intento per questo esempio di nodo di chiamata verrebbe eseguito il codice di risoluzione endpoint come parte del processo di avvio di ruolo. Sarebbe memorizzare nella cache l'endpoint in un membro statico o in un aggiornamento della cache effettiva in base alla scadenza della cache. Tuttavia, che possono essere combinata come parte dell'implementazione del servizio, che consente di controllare in dettaglio e l'unità al livello IP e porta combinate. Seconda il reale problema da risolvere e la struttura del tessuto service, potrei scegliere uno stile rispetto a altra.

Per ottenere l'esecuzione in un ambiente di produzione, di seguito sono alcuni aspetti da prendere in considerazione e possibilmente risolvere:

  • Intelligenza per decidere la disponibilità. Ciò significa che non solo le cose che potrebbero essere esaminato (CPU, disco, lo stato della connessione back-end e così via), ma anche le soglie che devono essere utilizzate per invertire il bit tra la disponibilità o non.
  • Logica per gestire il caso tutto torna disponibile.
  • Decisioni sul quantum per memorizzare nella cache l'endpoint.
  • Alcuni metodi aggiuntivi in EndpointManager per modificare le impostazioni, rimuovere i nodi del pool e la manutenzione generale in fase di esecuzione.
  • Tutte le eccezioni più comuni e in genere inclusi nell'implementazione di un servizio di diagnostica.

Rendersi conto che le cose vanno probabilmente senza informare, ma mi piace di utilizzare un indirizzo di "Non Guessing".

Nel rapido riepilogo dell'approccio del signor Carta, egli impostare una matrice tra domini di errore e l'aggiornamento nel tentativo di garantire che la disponibilità del chiamante riscontro la disponibilità di endpoint preferendo endpoint nei domini stessi. Penso che questa è una buona idea. Combinazione con la propria implementazione che garantisca che il sito Web servito da un ruolo di lavoro seguendo la stessa service level agreement se possibile, ma nel caso non è disponibile, si avrà la possibilità di bilancio per qualsiasi altro nodo.

Considerazioni finali

Spero che la piattaforma azzurro ghiaccio Windows verrà sviluppata per consentire il bilanciamento del carico per gli endpoint privati come punto di configurazione. Fino ad allora, se è un elemento è necessario (socket raw quasi sempre necessario un livello di protezione per interni), quindi una soluzione di codice è probabilmente il modo più semplice per passare. Suddividere le chiamate di risoluzione endpoint allontana le chiamate di servizio effettivo e la messa a loro parte dei file di avvio, esso deve conservare il codice assegnati pulito e separato dal codice di base. In questo modo, quando diventa disponibile per configurare una funzionalità simile al seguente, i servizi devono continuare a lavorare e consente di disattivare il bilanciamento del codice.

Joseph Fultz è un architetto presso il Microsoft Technology Center di Dallas, dove lavora con i clienti aziendali e ISV progettazione e creazione di prototipi di soluzioni software per soddisfare le esigenze aziendali e mercato. Egli è intervenuto a eventi quali Tech ·Ed Viesturs e gli eventi di formazione interna simili.