Applicazioni con database: i backup

Prima di entrare nel vivo credo sia necessaria una precisazione: il termine cantinaro ha una derivazione più informatica di quella che credevo, come indica la Treccani. A quanti per propria cultura personale vogliono capire meglio l’etimologia del termine, possono trovare maggiori informazioni sul sito dell’enciclopedia stessa.

Come ho già risposto a mr. Antonio TDJ nel suo commento al mio post precedente, la questione di “a chi tocchi fare un backup” non ha una risposta. Molto dipende dai rapporti di affari che si intrattengono con i diversi attori con cui si collabora, ed anche dalla natura degli attori stessi. Il mio “target” sono PMI con un investimento informatico annuo che varia dai 1.000 ai 30.000. Si tratta quindi di aziende neanche troppo piccole in cui però posso avere o non avere una persona che gestisce la rete, o che vi lavora part time, oppure mi viene richiesto di essere io in prima persona ad occuparmi di tutto.

Mi preme far notare che in questi casi preferisco rinunciare a parte degli introiti subappaltando o collaborando con terzi competenti: ho chi mi gestisce le reti, ho chi mi segue la parte di hosting e soprattutto ho chi mi segue la parte hardware, ovvero chi vende, ripara e sostituisce i PC. Questo perché da un lato non ho una struttura adeguata per questo tipo di gestioni né posso caricarmi il magazzino di pezzi di ricambio o mettermi a tirare il CAT5, dall’altro la mia “mission” è quella di fare del software, non quella di gestire migliaia di cose diverse, e mentre vado avanti ed indietro, da già che ci sono, pulire anche il pavimento.

Una cosa che personalmente trovo odiosa riguarda il fatto che i programmatori, soprattutto i cantinari, hanno una notevole capacità di stupirsi e di compiacersi. Ad esempio si stupiscono e si compiacciono quando il programma che hanno scritto funziona. Per inciso, la cosa ha lo stesso senso di un chirurgo che si stupisce e si compiace ogni volta che un suo paziente non gli crepa sotto i ferri, o ancora di un operaio che si compiace e si stupisce che l’automobile appena prodotta funziona. Ogni tanto, parlando con colleghi programmatori, ho l’impressione che gli unici che non danno per certo il funzionamento di un programma sono quelli che li scrivono.

Dotare il programma di un sistema di backup dei dati, o meglio, di un sistema che permetta di caricare e scaricare i dati rappresenta una di quelle caratteristiche cogenti che pur essendo praticamente indispensabili, ne senti la mancanza solo quando ti servono. I clienti danno per scontato, visto che pagano, che il sistema che andiamo a vendere o produrre sia sufficientemente FAULT TOLERANT da supportare la terza guerra mondiale ed un’epidemia di ebola nello stesso tempo. Deve essere compito di chi intrattiene i rapporti commerciali con il cliente lo specificare (per iscritto, ovviamente) tutti quelli che sono i compiti dei vari attori, e che questi siano spiegati in maniera chiara, magari con doppia firma. Ed è compito del programmatore prevedere questo sistema. Il cantinaro non si pone il problema, tanto i dischi si inchiodano mica tutti i momenti, e poi è compito del cliente, tante scuse per non fare degnamente il proprio lavoro. Il programmatore serio si premunisce. Sempre.

Oltre a prevenire disastri al cliente, cosa per la quale nessuno ringrazierà mai (perché la robustezza viene data per scontata, lo ripeto di nuovo), l’avere un sistema di gestione dei backup è una comodità anche nei confronti del programmatore, soprattutto in due momenti.

  • Nell’installazione: mi evito di installarmi un management per il motore in questione, di dovermi creare degli script e poi eseguirli.
  • Nella risoluzione di eventuali errori: mi riproduco sul pc di lavoro esattamente la stessa situazione che ho in remoto.

Che poi la gestione dei backup possa, anzi debba essere demandata al cliente o ad un suo incaricato è pacifico. Anzi, certi tecnici di rete si arrabbiano se gli porti via il lavoro, quindi guai a non lasciagli fare le cose a modo loro. Quello che mi preoccupa, che sia chiaro, non è quando c’è un’organizzazione strutturata in cui ognuno fa il suo compito e tutte le persone sono competenti (il che mi capita veramente di rado, ma questo è un altro problema). Il problema è quando hai a che fare con persone che si credono competenti, oppure quando non si sa bene chi debba fare che cosa. Le cose vanno sempre e comunque quantomeno preventivate e discusse. Personalmente adatto le soluzioni al caso specifico, per cui ho massima flessibilità. L’unica cosa chiara è che se i backup non vengono effettuati a tempo ed ora io BLOCCO TUTTO.

Capito il perché, vediamo di analizzare il come. E qui cominciano le differenze sostanziali perché il come dipende fortemente da quello che è il motore sul quale lavoriamo, e qui ragioniamo diversamente a seconda che il motore sia File Based oppure meno.

Nel caso il motore sia File Based, ovvero basato su file, e quindi, per chi non l’avesse capito, stiamo parlando di programmi che usano Access, SQL Compact, SQLite, VistaDB o quant’altro, un backup e/o un restore può essere fatto in maniera molto semplice copiando una serie di file.

Nel caso invece il motore sia un motore vero, invece, in qualche maniera allora è previsto un sistema di backup e restore. Ad esempio, in SQLServer è possibile fare un backup di un database con un semplice comando chiamato, ad esempio, dal management.

Backup Database NomeDB to Disk='NomeFileBackup.bak'

Se si usa una versione di SQLServer superiore alla express, allora sarà possibile schedulare il JOB di backup, in maniera semplice. Se invece si usa proprio quella? Si può prendere spunto da una soluzione “precotta”, magari adattandola alle proprie esigenze (io consiglio di studiarsi questa soluzione scritta da Danilo Corallo).

Concepito così il sistema non è difficile da realizzare (e questo è un bene), e con certe premesse funziona (e questo è un molto bene), ma implica il pensare ad alcuni problemi (male) ed ha anche grossi limiti (molto male).

Vediamo di analizzare i problemi ed i limiti.

Il problema principale è quello che con molti motori (sia file based che engine based) il database può essere “backuppato” solo se non ci sono connessioni attive. Quindi bisogna indagare se ci sono connessioni attive, bloccare l’accesso al database durante le operazioni di backup, fare le operazioni necessarie, quindi liberare il tutto. Sui motori file based è raccomandato, prima di effettuare il backup, di eseguire una compattazione del database stesso, così da spurgare quest’ultimo delle righe cancellate (che richiede tempo, e quindi ulteriore tempo di fermo per manutenzione del programma stesso). Ora, se il programma è monoutente questo può non essere un problema, diverso invece quando gli utenti sono più di uno.

Un ulteriore problema è rappresentato dal fatto che se ti “parte” una tabella o il database, allora non è detto che quanto ti salvi sia una copia questa possa poi essere ripristinata senza problemi.  Mica da ridere.

Credo che ognuno, quando pensa al problema, se la canti e se la suoni un po’ come vuole, tamponando il problema ognuno alla sua maniera, in mille modi diversi. Per quanto uno ci pensi l’affidabilità del sistema è garantita al 99,9%, che è meglio di niente, ma è ben lontana dal 100%.

Il limite più grande di un sistema del genere è che presuppone di avere tutti i diritti e tutti gli accessi sull’eventuale server (questo vale soprattutto per i database engine based, magari piazzati su server remoto ovvero ad esempio su server web), cosa che con molti host non è assolutamente vera. Provare per credere. Io l’ho scoperto a mie spese adesso che devo trasferire un DB da un server ad un altro (a proposito, grazie Stefano per la tua disponibilità e pazienza).

Un altro limite (per me) è nel fatto che in un sistema del genere si finisce per backuppare tutto il database, comprese tabelle magari grosse e che non vengono aggiornate tutti i momenti o magari non vengono aggiornate mai, o ancora tabelle che vengono aggiornate periodicamente ma non dagli utenti stessi.

Tanto per essere chiari, si pensi alle tabelle dei comuni, delle regioni e delle provincie, oppure alle tabelle degli ABI e CAB come quelle pubblicate dall’ottimo Bastianello su questi schermi.

Il mio metodi alternativo.

Dopo questo mega-pistolozzo introduttivo alquanto noioso, mi permetto di suggerire un metodo alternativo che consente di eseguire backup e restore anche parziali, richiede solo un qualsiasi accesso al database (ovvero senza particolari permessi), è adattabile “virtualmente” ad ogni tipo di database anche file based, e non richiede nessun permesso sulla macchina server. Inoltre, se analizzato in sede di creazione delle tabelle stesse, può essere adattato anche a backup parziali sulla singola tabella. Infine normalmente non bisogna bloccare l’accesso al database stesso. I difetti sono di una inefficienza sostanziale (traduzione: è sicuramente molto più lento di un Backup Database) e nella quantità di dati che viaggiano sulla rete stessa, che è decisamente più grande che in caso di backup. Chiaramente la soluzione è perfettibile, ha i suoi drawback, alcuni dei quali sono chiaramente evidenziati, e sicuramente molti ci hanno pensato prima di me ed hanno realizzato una soluzione migliore.

Alla noia, ripeto che quanto segue è UNA soluzione possibile, quella che io nella mia becera ignoranza adotto per la MIA comodità nelle MIE applicazioni. Ognuno credo che debba ragionare e scegliere quella che per le proprie esigenze ritiene più opportuna.

Detto questo, il tutto si risolve in maniera banale facendo queste semplici operazioni:

  1. Leggi dal Database l’elenco delle tabelle.
  2. Per ogni tabella guarda se devi esportare o meno dei dati
  3. Se devi esportare dei dati, carica la tabella in memoria e poi salva i dati in un file XML

Difficile? 50 righe di codice (scritte maluccio, a dire la verità) per la versione “interattiva”, ovvero una form che ti richiede quali tabelle vuoi salvare, quantità simile di codice per la versione “schedulata”, senza interfaccia utente, che fa l’operazione inversa.

Imports System.Data.Sql
Imports System.Data.SqlClient
Public Class frmEsportazioneDatiTabelle

    Private Sub frmEsportazioneDatiTabelle_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Dim Conn As New SqlConnection(My.Application.CSB)
        Dim CMDNomiTabelle As SqlCommand
        Dim CMDRecordTabelle As SqlCommand
        Dim NomeTabella As String
        Dim RecordTabelle As Nullable(Of Integer)
        Dim RigaTabelle As dsTabelle.tbTabelleRow
        Try
            Conn.Open()
            'Mi trovo le tabelle
            CMDNomiTabelle = New SqlCommand("select * from INFORMATION_SCHEMA.TABLES where TABLE_TYPE = 'BASE TABLE'", Conn)
            Using reader As SqlDataReader = CMDNomiTabelle.ExecuteReader
                While reader.Read
                    NomeTabella = reader("TABLE_NAME").ToString
                    Me.DsTabelle.tbTabelle.AddtbTabelleRow(NomeTabella, True, 0, False, 0)
                End While
            End Using
            'Mi trovo quanti record per ogni tabella
            For Each RigaTabelle In Me.DsTabelle.tbTabelle
                CMDRecordTabelle = New SqlCommand("select count(*) from [" & RigaTabelle.NOME & "]", Conn)
                RecordTabelle = CMDRecordTabelle.ExecuteScalar()
                If RecordTabelle.HasValue Then
                    RigaTabelle.Righe = RecordTabelle.Value
                End If
            Next
            Conn.Close()
        Catch ex As Exception

        End Try
    End Sub

    Private Sub btnEsporta_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEsporta.Click
        Dim RigaTabelle As dsTabelle.tbTabelleRow
        Using connection As New SqlConnection(My.Application.CSB)
            For Each RigaTabelle In Me.DsTabelle.tbTabelle
                If RigaTabelle.Check = True Then
                    Dim Adapter As New SqlDataAdapter()
                    Dim DataSet As New DataSet
                    Adapter.SelectCommand = New SqlCommand("select * from [" & RigaTabelle.NOME & "]", connection)
                    Adapter.Fill(DataSet)
                    DataSet.WriteXml(My.MyApplication.PATH & RigaTabelle.NOME & ".xml", XmlWriteMode.WriteSchema)
                End If
            Next
        End Using
        MsgBox("Esportazione dati completata correttamente")
    End Sub
End Class

Per i più pigri sto preparando un programma già pronto che distribuirò in sorgente (e che comprende anche il restore, nonchè il backup della struttura del database, che qui non viene salvata.) Come già detto in questi mesi sono mio malgrado limitato da alcuni problemi “di cuore”, per cui ci vuole ancora un attimo di pazienza. La mia speranza è comunque non tanto di fornire soluzioni già pronte, quanto piuttosto spunti di riflessione. Alla prossima.

posted @ lunedì 22 ottobre 2012 12:58

Print

Comments on this entry:

# re: Applicazioni con database: i backup

Left by Antonio "tdj" Catucci at 22/10/2012 13:44
Gravatar
Continuo a rimanere dell'idea che il backup va fatto con strumenti idonei e da persone che sappiano cosa fare.
Personalmente non sono un esperto in materia (ed è per questo che nemmeno mi sogno di realizzare un'applicazione di backup fatta in casa) ma esistono diverse soluzione a pagamento che gestiscono backup di database anche in situazione non convenzionali.
E comunque, personalmente, credo che un buon sistema di backup funziona, quando funziona anche il ripristino :) Ma noto che spesso si pianificano piani di backup e mai nessuno fa un mai test di ripristino in situazioni critiche...

Ovviamente tutto questo, poi, va contestualizzato con la criticità delle applicazioni e con le esigenze del cliente.

Your comment:



 (will not be displayed)


 
 
 
Please add 6 and 5 and type the answer here:
 

Live Comment Preview: