Al CAC viene spesso chiesto di esaminare i problemi con le code dei messaggi VOS. Qui ce ne sono un paio interessanti, insieme ad alcune soluzioni e raccomandazioni che mi piacerebbe condividere con voi.
Problema 1: Recentemente, un cliente è venuto da noi con un problema. Un richiedente non è stato in grado di aggiungere un messaggio ad una coda di messaggi, ricevendo il codice di errore e$max_file_exceeded. Stranamente, la coda era vuota, come mostra il comando list_messages.
Esaminando la coda, si è visto che il conteggio dei blocchi disco utilizzati per questa coda si avvicinava alla dimensione massima del file per un file non estratto.
nome: %s1#d01>AppData>queue.MQ
organizzazione dei file: file di coda dei messaggi
usato per l'ultima volta a: 11-08-16 14:45:13 edt
modificato l'ultima volta a: 11-08-16 14:45:13 edt
l'ultimo salvato a: 10-06-14 21:34:18 edt
tempo creato: 10-06-09 11:03:15 edt
file della transazione: sì
registro protetto: no
interruttore di sicurezza: no
revisione: no
Estensioni dinamiche: no
dimensione dell'estensione: 1
ultimo messaggio: 51689380
blocchi utilizzati: 520201
…
Perché questa coda era piena e vuota?
Ad un certo punto, in passato, i server responsabili del drenaggio dei messaggi dalla coda erano off-line. Questo ha portato ad un notevole arretrato di messaggi. Questi messaggi sono stati infine gestiti dai server e cancellati dalla coda. Quando i messaggi vengono cancellati da una coda, una chiave viene aggiunta all'indice _record_index della coda e il valore della chiave indica il numero di byte del messaggio o dei messaggi cancellati. Quando un nuovo messaggio viene aggiunto ad una coda di messaggi, il file system cercherà di trovare un messaggio precedentemente cancellato della dimensione esatta del nuovo messaggio. Se uno non è disponibile, il nuovo messaggio viene scritto nello spazio vergine alla fine della coda.
In questo caso, non c'era abbastanza spazio vergine nella coda per contenere il nuovo messaggio, e non c'era nessun messaggio cancellato preesistente della dimensione corretta.
La morale di questa storia è che è una buona idea limitare il numero di lunghezze di messaggi unici in una determinata coda. Piuttosto che far sì che ogni messaggio utilizzi il numero esatto di byte di cui ha bisogno, arrotondare il valore fino a qualche dimensione standard. Usando questa tecnica, si aumenta la possibilità che un nuovo messaggio possa riutilizzare lo spazio di un messaggio precedentemente cancellato.
Problema 2: Recentemente è emersa un'altra situazione relativa all'esecuzione delle code di messaggi. Un cliente ha dichiarato che il tempo di svuotare una coda di oltre 400.000 messaggi richiedeva un tempo eccessivo.
Recentemente hanno avuto un problema con i loro processi di server che non sono in grado di elaborare i messaggi in una coda di messaggi in modo tempestivo. Fortunatamente, i richiedenti sono stati mantenuti in funzione in modo da non perdere alcun dato. Quando il problema del server è stato risolto, sono passate molte ore prima che si fossero messi al passo con le richieste arretrate e potessero quindi avviare l'elaborazione delle transazioni recenti. Il cliente chiedeva il motivo per cui ciò si era verificato e come si poteva evitare o accelerare in situazioni future.
Quando un messaggio viene cancellato in una coda di messaggi, viene aggiunta una chiave all'indice _record_ di sistema, dove il valore della chiave è la lunghezza del messaggio. Se il messaggio che viene cancellato ha la stessa lunghezza di un messaggio precedentemente cancellato, la posizione dei dati non utilizzati viene salvata come voce duplicata sulla chiave contenente quella dimensione del messaggio alla fine della lista dei valori duplicati. Così, se ci sono centinaia di migliaia di messaggi cancellati, tutti della stessa dimensione (o l'insieme delle lunghezze dei messaggi cancellati è piccolo), la lista delle chiavi duplicate è molto lunga e il tempo per cancellare un singolo messaggio sale linearmente.
Al contrario, quando un messaggio viene aggiunto alla coda ed esiste una chiave _record_index per la lunghezza del messaggio, lo spazio occupato dal nuovo record cancellato viene riutilizzato per contenere i dati del nuovo messaggio. Questo valore deve poi essere cancellato dal valore della chiave che contiene la lunghezza del messaggio. In questo modo, il tempo per aggiungere un messaggio aumenta linearmente; più i messaggi cancellati sono numerosi, più tempo ci vuole per aggiungere un nuovo messaggio.
La morale di questa storia è che i dati di sistema mantenuti nelle code dei messaggi hanno memoria; le code ricordano le posizioni e le dimensioni di tutti i messaggi precedenti. Queste informazioni persistono anche dopo che la coda è stata svuotata. Cercate di evitare di far crescere le code dei messaggi fino a raggiungere dimensioni enormi (decine o centinaia di migliaia di blocchi di dischi). Altrimenti scoprirete che il costo dell'aggiunta e dell'eliminazione dei messaggi in una coda può crescere nel tempo.
Le soluzioni ad entrambe le situazioni sono le stesse.
Soluzione A: Una coda di messaggi può essere troncata mentre è aperta. A questo scopo si può usare la routine s$truncate_queue di s$truncate_queue. Tuttavia, ci sono 4 condizioni che devono essere soddisfatte:
1: non ci devono essere richiedenti che tengono aperta la coda dei messaggi
2: la coda dei messaggi deve essere svuotata di tutti i messaggi
3: questa routine deve essere chiamata da un server
4: la coda non può essere un file di transazione
Se le prime 3 condizioni non sono soddisfatte, s$truncate_queue restituirà e$no_truncate_queue. Se l'ultima condizione non è soddisfatta, s$truncate_queue restituirà e$invalid_io_operazione.
Soluzione B: se il design dell'applicazione permette di avere più server, è possibile rinominare periodicamente la coda di messaggi esistente, creare una nuova coda di messaggi con il nome corretto, avviare un nuovo set di server e far rimbalzare i richiedenti. Quando i server si avviano, iniziano l'elaborazione su una nuova coda di messaggi, ma vuota. Quando i richiedenti si avviano, aggiungeranno le loro richieste nella nuova coda di messaggi vuota. Il set originale di server può rimanere in esecuzione, elaborando il backlog delle richieste fino a quando la coda è vuota. Poi il vecchio set di server può essere fermato, e la vecchia coda di messaggi può essere cancellata.
Inoltre, una soluzione al problema 1 può essere quella di utilizzare una coda di messaggi basata sull'estensione. Questo permetterebbe di inserire messaggi aggiuntivi nella coda, in quanto la dimensione massima del file sarebbe maggiore di un fattore della dimensione dell'estensione. Tuttavia, utilizzando le code di messaggi in base all'estensione, le prestazioni saranno ancora peggiori del normale se o quando la coda di messaggi contiene un gran numero di messaggi in un qualsiasi momento.
Come già detto in precedenza, limitare il numero di lunghezze di messaggi unici in una determinata coda migliorerà la probabilità che un nuovo messaggio possa riutilizzare lo spazio rilasciato da un messaggio precedentemente cancellato. Questo aiuterà a risolvere entrambi i problemi menzionati in questo post.