Tutti gli articoli di Marco

Le origini dei RDBMS

Se dovessi scegliere una tecnologia comune a tutti i programmatori forse sarebbe quella dei database relazionali. Anche se naturalmente non esiste niente che metta d’accordo proprio tutti, posso affermare che la stragrande maggioranza di essi, nel corso della loro carriera, hanno scritto almeno una volta un breve pezzo di codice che abbia a che fare con un database, di qualunque dimensione e tipo.

Del resto possiamo scindere il software nei suoi componenti di base: i dati e il funzionamento. Come impariamo i linguaggi di programmazione per esprimere il funzionamento di un programma, così impariamo a registrare e a rendere permanenti i nostri preziosi dati.

Quando si mettono i dati in una qualunque forma organizzata, ecco che abbiamo una sorta di database. Quando poi li organizziamo sotto forma di relazione, ecco che abbiamo un database relazionale. A questo punto quando aggiungiamo funzionalità per gestire e ottimizzare l’accesso ai dati, ecco che abbiamo un sistema per la gestione di basi di dati relazionali, altrimenti detto relational database management system o RDBMS.

Sicuramente molte persone hanno una certa dimestichezza con questi sistemi. Esistono prodotti considerati dei veri pilastri del settore come Oracle, Microsoft SQL Server, PostgreSQL e MySQL.
In effetti, si fondono così perfettamente nelle attività più disparate che si potrebbero dare facilmente per scontato. Ma da dove vengono e perché? E come si sono evoluti nel corso degli anni? Oggi, diamo uno sguardo indietro alle origini dei RDBMS.

I primi database

Potrebbe sorprendervi sapere che il concetto di database è in realtà antecedente al computing moderno. Potreste leggere questo articolo per i dettagli, ma basti dire che è possibile rintracciare le radici di questo concetto fino al censimento del 1880 negli Stati Uniti. Gli innovatori di quell’epoca inventarono “macchine per la tabulazione” che praticavano dei buchi nelle cosiddette “schede perforate”. Queste carte, insieme ai metodi per la loro memorizzazione, diventarono le prime vere “basi di dati” (o database).

Nei primi anni ’60, un uomo di nome Charles Bachman automatizzò questo concetto. In seguito ricevette un premio Turing per i suoi sforzi nella creazione di un qualcosa chiamato “Integrated Data Store” o IDS. Utilizzando infatti i concetti presi dai database delle schede perforate, come “file”, “campo” e “chiave”, creò un sistema che disaccoppiava la logica dell’applicazione dall’archiviazione dei dati in file. Anche adesso, dopo più di 50 anni, lo riconosceremmo comunque come un database.

Traendo spunto da Bachman, negli anni ’60 sono emersi due tipi di database: i database di rete e i database gerarchici. In breve, il modello gerarchico struttura i dati in alberi, mentre il modello di rete usa una struttura più libera che permette la modellazione diretta delle relazioni “molti a molti”.

La rivoluzione relazionale

Edgar F. Codd (1923 – 2003), un informatico britannico e una delle figure informatiche più di spicco del secolo scorso, ha concepito il modello di database relazionale che usiamo oggi. E’ possibile leggere su di lui anche sul il sito di IBM dal momento che ha lavorato lì.
Quando Codd pubblicò il suo articolo sulle basi di dati relazionali nel 1970, il mondo aveva già sperimentato modelli di database esistenti, abbastanza a lungo da comprendere sia i loro benefici che le loro carenze. Il principale tra questi difetti era la difficoltà causata dall’accoppiamento tra i dati e la conservazione fisica di tali dati. In altre parole, i record stessi dicevano ai ricercatori dove cercare quelli successivi.

All’epoca, sia la potenza di elaborazione che lo spazio di archiviazione avevano un costo molto alto. Questi sistemi andavano bene all’inizio quando i dati venivano memorizzavano, ma i nuovi processi di elaborazione e la necessità di nuove query di ricerca richiedevano una rielaborazione costosa e dispendiosa in termini di tempo.

Codd cambiò tutto questo: il suo modello relazionale ha disaccoppiato la forma dei dati dall’archiviazione fisica di quegli stessi dati. Solo questo fu sufficiente per portare miglioramenti significativi. Ma le “12 regole di Codd” (in realtà 13 perché le indicizzava a zero) sarebbero arrivate più tardi. Queste regole richiedono l’eliminazione di qualsiasi duplicazione dei dati, ottimizzando efficacemente anche il costo dello storage.

L’ascesa di SQL

Occorre fare ancora un po’ di strada prima di arrivare ai database moderni, anche se cominciamo a intravederne la forma.

Chi ha frequentato un corso universitario sui database, avrà sicuramente sentito parlare della Forma Normale di Boyes-Codd (BCNF). Quel Codd è lo stesso Edgar F. Codd che ha generato il modello relazionale.

Il suo complice, un certo Raymond Boyce, lavorava con Codd e un altro signore di nome Donald Chamberline presso IBM. Tutti e tre hanno svolto un lavoro significativo nel campo dei database. Boyce e Chamberlin crearono insieme un modo standard per richiedere le informazioni da questi “database relazionali”. Lo chiamavano “Structured English Query Language” o più brevemente “SEQUEL”. In seguito divenne ancora più breve: “Structure Query Language” o “SQL”.

Sebbene non fosse l’unico modo per creare le query di ricerca, divenne ben presto il più utilizzato. Molti fattori contribuirono al suo successo, in particolare una caratteristica: la natura dichiarativa di SQL. I programmatori delle applicazioni devono solo dichiarare quali record desiderano senza specificare come recuperarli. Il “come” diventa un dettaglio di implementazione del RDBMS.

L’esplosione di Internet

L’origine del modello relazionale ebbe luogo presso IBM negli anni ’70, così come il concepimento di SQL. Ma la sua crescita esponenziale ebbe luogo negli anni ’80, così come l’ascesa di vari fornitori commerciali di RDBMS. Durante quegli anni, quando tutti si adeguarono attorno allo standard SQL, emersero molti prodotti e fornitori di database RDBMS, registrando un grande successo commerciale tra le imprese.

Tuttavia questi piccoli RDBMS durarono poco: attraverso un processo di accrescimento, i concorrenti più grandi assorbirono quelli più piccoli facendo così emergere e maturare quelli che conosciamo oggi.

Tutto questo successe proprio nel momento in cui Internet appariva sulla scena. Se l’esplosione che seguì SQL negli anni ’80 fu qualcosa, nessuno era preparato a ciò che sarebbe accaduto dopo. Man mano che i siti web diventavano applicazioni web, i dati diventavano importanti per le comunicazioni in modi senza precedenti. All’improvviso, quasi tutti gli sviluppatori sulla Terra sembravano aver bisogno dell’accesso client-server a un RDBMS.

Questa continua richiesta ha spinto i fornitori a ottimizzare e a  espandere le funzionalità e più in generale a soddisfare gli sviluppatori di applicazioni. I venditori si sono così buttati su ogni tipo di offerta e hanno incoraggiato una situazione tale che il RDBMS occupava il ruolo di “centro dell’universo”.

La competizione rivista

Quando Codd elaborò il suo modello relazionale, ha cercato di affrontare i costosi colli di bottiglia dell’epoca: lo spazio su disco e la potenza di elaborazione. I modelli relazionali hanno permesso di economizzare intensamente lo spazio ma, a volte, a scapito di un’intensa complessità per determinati tipi di dati. In altre parole, non tutto si presta bene allo storage relazionale e alla normalizzazione. I registri di log di grandi dimensioni, ad esempio, non traggono alcun vantaggio dalla normalizzazione.

Non appena il concetto di “larga scala del web” è cresciuto nella nostra coscienza collettiva, alcuni hanno iniziato a rivedere l’assunto onnipresente di RDBMS per ogni applicazione scegliendo approcci diversi come i database documentali che memorizzano ed elaborano i dati in modi meno “tradizionali”, riscuotendo anche un certo consenso fino ad emergere una linea di pensiero anti-SQL.

È con questo adeguato senso di simmetria che arriviamo al presente: prima che l’RDBMS acquisisse la sua importanza nel mondo dell’informatica, c’erano pochi concorrenti. Ora, circa 40 anni dopo, ancora una volta ci sono pochi concorrenti. Poche cose hanno inciso tanto quanto l’RDBMS ma la storia scritta tra altri 40 anni forse la vedrà solo come una delle tante opzioni per l’età della “larga scala del web”.

Fonte: A Look at the History of RDBMS di Erik Dietrich

Migrare da KVM/QEMU a VMware ESXi

Una volta che il nostro server con installato VMware ESXi è pronto possiamo iniziare a creare le macchine virtuali.

Nel mio caso ne ho alcune che finora giravano su KVM/QEMU e che vorrei tentare di migrare invece di reinstallarle daccapo. Inizio con quella su cui gira Ubuntu Linux Server 14.04 64 bit.

Copia del disco virtuale

Il mio server KVM (Debian 8.0) utilizza LVM come datastore. Quindi per prima cosa creo uno snapshot (2 GB saranno più che sufficienti per il tempo necessario alla copia dei dati) del disco virtuale vmdisk1 che dovrò poi convertire nel formato VMware.

$ sudo lvcreate --size 2GB --snapshot --name snapdisk1 /dev/kvmstore/vmdisk1
$ sudo qemu-img convert /dev/kvmstore/snapdisk1 -O vmdk /tmp/vmdisk1.tmp.vmdk
$ sudo lvremove -f /dev/kvmstore/snapdisk1

A questo punto trasferire il file provvisorio vmdisk1.tmp.vmdk sul nuovo server (tramite NFS o ssh).

Creazione della macchina virtuale su ESXi

Utilizzare la procedura guidata via web per creare la nuova macchina virtuale, con le impostazioni hardware simili a quelle che avevamo nel nostro vecchio server. La procedura creerà un disco virtuale predefinito che andremo poi a sostituire.

Conversione

Il file così trasferito richiede un’ulteriore conversione prima di poter essere utilizzato dalla macchina virtuale. Se lo facessimo infatti l’avvio della vm fallirebbe restituendo un bel messaggio di errore.

Occorre quindi accedere via shell SSH al server e effettuare la conversione del file temporaneo in quello definitivo:

[root@dellpet440:~] vmkfstools -i vmdisk1.tmp.vmdk -d thin vmdisk1.vmdk
Destination disk format: VMFS thin-provisioned
Cloning disk 'vmdisk1.tmp.vmdk'...
Clone: 100% done.

Possiamo quindi spostare il file definitivo vmdisk1.vmdk nella directory della macchina virtuale, ad esempio /vmfs/volumes/datastore1/mynewvm.

Riconfigurazione e avvio della VM

Non ci resta quindi che tornare nella configurazione della VM, eliminare il disco virtuale che il wizard aveva creato e aggiungere un  disco virtuale esistente: andare su Edit > Add Hard Disk > Existing Hard Disk e selezionare il file convertito.

Salvare il tutto, avviare la macchina virtuale e incrociare le dita!

Modificare le regole del firewall in ESXi

Dopo una certa esperienza maturata nell’ambito della virtualizzazione con Linux e KVM/QEMU, ho voluto iniziare a cimentarmi con VMware ESXi 6.7. In realtà non è proprio una novità in quanto già diversi anni fa avevo fatto uso di VMware versioni Workstation (su piattaforma Windows) e Server (su piattaforma Linux).

Come quasi sempre accade quando si affrontano nuovi sistemi, dobbiamo innanzitutto impararne le peculiarità e scontrarsi con i suoi limiti. In questo articolo mi voglio soffermare proprio su uno di questi, ovvero quella della persistenza delle modifiche. Infatti, quelle effettuate tramite shell a basso livello sui file di configurazione, vengono perse ad ogni riavvio del sistema. Ciò è dovuto alla particolare struttura di ESXi ove il file-system viene caricato su RAM e solo una parte di essa viene manutenuta sul disco di boot.

Così succede che per aggiungere una banale regola del firewall come quella di aprire in uscita la porta SMTP (TCP 25) occorre lavorare manualmente sulla configurazione in quanto l’interfaccia web non te lo permette di fare (puoi solo modificare quelle esistenti). In rete ho trovato diverse guide ma non abbastanza chiare in quanto la soluzione cambia da una versione all’altra. Io sono riuscito a rendere persistente la modifica sul mio ESXi 6.7 seguendo questi passaggi. Accetto suggerimenti se esistono soluzioni più eleganti.

Creazione della regola

Per prima cosa occorre creare la regola. Quelle predefinite si trovano nel file /etc/vmware/firewall/services.xml. Alcuni ti suggeriscono di aggungere le tue modifiche in questo file. Io ho preferito adottare una strada leggermente diversa che consiste nell’aggiungere un nuovo file che definisce la regola.

Ho creato così il file /etc/vmware/firewall/smtp.xml:

<ConfigRoot>
  <service id="1000">
    <id>SMTP_Outbound</id>
    <rule>
      <direction>outbound</direction>
      <protocol>tcp</protocol>
      <porttype>dst</porttype>
      <port>25</port>
    </rule>
    <enabled>true</enabled>
    <required>false</required>
  </service>
</ConfigRoot>

Ho riavviato il firewall, sempre da riga di comando:

[root@dellpet440:~] esxcli network firewall refresh

Quindi ho verificato sull’interfaccia web la mia regola appena creata:

Come rendere le modifiche persistenti

Senza entrare troppo nel merito di come funziona ESXi (lo devo ancora capire meglio anch’io) per rendere questa modifica persistente, occorre creare un archivio compresso, contenente il nostro file, che verrà scompattato automaticamente dal sistema ad ogni avvio.

Così ho creato l’archivio compresso smtpfw.tgz contenente il file smtp.xml e l’ho registrato nella cache di boot con l’apposito comando:

[root@dellpet440:~] tar -czvf smtpfw.tgz /etc/vmware/firewall/state.xml
[root@dellpet440:~] BootModuleConfig.sh --add=smtpfw.tgz

Possiamo verificare se l’archivio è stato copiato correttamente nella cache:

[root@dellpet440:~] ls -la /bootbank/smtpfw.tgz
-rwx------ 1 root root 1887 Mar 28 08:54 /bootbank/smtpfw.tgz

Possiamo anche verificare se l’archivio verrà correttamente scompattato all’avvio:

[root@dellpet440:~] cat /bootbank/boot.cfg 
bootstate=0
title=
timeout=5
prefix=
kernel=b.b00
kernelopt=installerDiskDumpSlotSize=2560
modules=jumpstrt.gz --- useropts.gz --- features.gz --- k.b00 --- chardevs.b00 --- user.b00 --- procfs.b00 --- uc_intel.b00 --- uc_amd.b00 --- vmx.v00 --- vim.v00 --- sb.v00 --- s.v00 --- ata_liba.v00 --- ata_pata.v00 --- ata_pata.v01 --- ata_pata.v02 --- ata_pata.v03 --- ata_pata.v04 --- ata_pata.v05 --- ata_pata.v06 --- ata_pata.v07 --- block_cc.v00 --- bnxtnet.v00 --- brcmfcoe.v00 --- char_ran.v00 --- ehci_ehc.v00 --- elxiscsi.v00 --- elxnet.v00 --- hid_hid.v00 --- i40en.v00 --- iavmd.v00 --- igbn.v00 --- ima_qla4.v00 --- ipmi_ipm.v00 --- ipmi_ipm.v01 --- ipmi_ipm.v02 --- iser.v00 --- ixgben.v00 --- lpfc.v00 --- lpnic.v00 --- lsi_mr3.v00 --- lsi_msgp.v00 --- lsi_msgp.v01 --- lsi_msgp.v02 --- misc_cni.v00 --- misc_dri.v00 --- mtip32xx.v00 --- ne1000.v00 --- nenic.v00 --- net_bnx2.v00 --- net_bnx2.v01 --- net_cdc_.v00 --- net_cnic.v00 --- net_e100.v00 --- net_e100.v01 --- net_enic.v00 --- net_fcoe.v00 --- net_forc.v00 --- net_igb.v00 --- net_ixgb.v00 --- net_libf.v00 --- net_mlx4.v00 --- net_mlx4.v01 --- net_nx_n.v00 --- net_tg3.v00 --- net_usbn.v00 --- net_vmxn.v00 --- nhpsa.v00 --- nmlx4_co.v00 --- nmlx4_en.v00 --- nmlx4_rd.v00 --- nmlx5_co.v00 --- nmlx5_rd.v00 --- ntg3.v00 --- nvme.v00 --- nvmxnet3.v00 --- nvmxnet3.v01 --- ohci_usb.v00 --- pvscsi.v00 --- qcnic.v00 --- qedentv.v00 --- qfle3.v00 --- qfle3f.v00 --- qfle3i.v00 --- qflge.v00 --- sata_ahc.v00 --- sata_ata.v00 --- sata_sat.v00 --- sata_sat.v01 --- sata_sat.v02 --- sata_sat.v03 --- sata_sat.v04 --- scsi_aac.v00 --- scsi_adp.v00 --- scsi_aic.v00 --- scsi_bnx.v00 --- scsi_bnx.v01 --- scsi_fni.v00 --- scsi_hps.v00 --- scsi_ips.v00 --- scsi_isc.v00 --- scsi_lib.v00 --- scsi_meg.v00 --- scsi_meg.v01 --- scsi_meg.v02 --- scsi_mpt.v00 --- scsi_mpt.v01 --- scsi_mpt.v02 --- scsi_qla.v00 --- shim_isc.v00 --- shim_isc.v01 --- shim_lib.v00 --- shim_lib.v01 --- shim_lib.v02 --- shim_lib.v03 --- shim_lib.v04 --- shim_lib.v05 --- shim_vmk.v00 --- shim_vmk.v01 --- shim_vmk.v02 --- smartpqi.v00 --- uhci_usb.v00 --- usb_stor.v00 --- usbcore_.v00 --- vmkata.v00 --- vmkfcoe.v00 --- vmkplexe.v00 --- vmkusb.v00 --- vmw_ahci.v00 --- xhci_xhc.v00 --- elx_esx_.v00 --- btldr.t00 --- weaselin.t00 --- esx_dvfi.v00 --- esx_ui.v00 --- lsu_hp_h.v00 --- lsu_lsi_.v00 --- lsu_lsi_.v01 --- lsu_lsi_.v02 --- lsu_lsi_.v03 --- native_m.v00 --- qlnative.v00 --- rste.v00 --- vmware_e.v00 --- vsan.v00 --- vsanheal.v00 --- vsanmgmt.v00 --- payload1.v00 --- xorg.v00 --- imgdb.tgz --- state.tgz --- smtpfw.tgz
build=6.7.0-0.0.8169922
updated=4

Da adesso in poi, ogni volta che riavvieremo il nostro server, il sistema scompatterà il nostro file nella giusta posizione, il resto lo farà il firewall che aggiungerà così la regola.

Come tornare indietro

Sarò sufficiente rimuovere la nostra modifica dalla cache di avvio:

[root@dellpet440:~] BootModuleConfig.sh --remove=smtpfw.tgz

e poi riavviare.

Considerazioni finali

Come già detto, questa è stata l’unica soluzione che mi ha permesso di rendere persistente la mia modifica; non credo sia l’unica e neanche la più elegante. Ho anche il dubbio che venga mantenuta in caso di aggiornamento del sistema.

Un’altra possibilità poteva essere quella di modificare direttamente il file services.xml. Per chi desidera procedere in questo modo deve prima prima modificare i permessi così:

[root@dellpet440:~] chmod 644 /etc/vmware/firewall/services.xml
[root@dellpet440:~] chmod +t /etc/vmware/firewall/services.xml

Se il primo comando risulta quasi ovvio, il secondo merita una spiegazione a parte: secondo quanto trovato in rete, i file di configurazione in ESXi sono tutti in sola lettura e se tentate di modificarne uno senza prima abilitare lo sticky bit il sistema vi negherà il salvataggio delle modifiche anche con i permessi in scrittura. Questo perché il sistema salva automaticamente una copia del file originale che verrà poi confrontata con la versione modificata, al fine di creare un file diff che verrà poi applicato in fase di reboot. A me sinceramente non ha funzionato, non sono sicuro se per un qualche mio errore oppure se nella versione 6.7 è stato cambiato qualcosa. Purtroppo quello che si trova in rete è abbastanza datato e fa riferimento alle versioni 4.x o 5.x.

Login remoto via SSH senza password

Per effettuare il login da remoto su un sistema Linux senza digitare ogni volta la password bastano i comandi ssh-keygen e ssh-copy-id e seguire le istruzioni descritte in questo articolo.

ssh-keygen permette di creare le chiavi pubbliche e private, mentre ssh-copy-id copia la chiave publica del client nella lista degli host autorizzati sul server remoto.

1° passo: creare le chiavi pubbliche e private sul client

Per prima cosa creiamo le nostre chiavi pubbliche e private sulla macchina client. Apriamo la console a riga di comando e digitiamo il comando ssh-keygen:

mark@local-host$ [Nota: qui siete nella console del client]
mark@local-host$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/mark/.ssh/id_rsa):[Premere il tasto Enter]
Enter passphrase (empty for no passphrase): [Premere il tasto Enter]
Enter same passphrase again: [Premere il tasto Enter]
Your identification has been saved in /home/mark/.ssh/id_rsa.
Your public key has been saved in /home/mark/.ssh/id_rsa.pub.
The key fingerprint is:
33:b3:fe:af:95:95:18:11:31:d5:de:96:2f:f2:35:f9
mark@local-host

2° passo: copiare la cave pubblica sul server remoto

A questo punto copiamo la chiave pubblica appena creata sul server remoto tramite il comando ssh-copy-id:

mark@local-host$ ssh-copy-id -i ~/.ssh/id_rsa.pub remote-host
mark@remote-host's password: [Inserisci la password del server remoto seguito dal tasto Enter]
Now try logging into the machine, with "ssh 'remote-host'", and check in:
.ssh/authorized_keys
to make sure we haven't added extra keys that you weren't expecting.

3° passo: login sul server remoto

Non ci resta che effettuare il login sul server remoto senza che ci venga richiesta la password di accesso:

mark@local-host$ ssh remote-host
Last login: Sun Nov 16 17:22:33 2008 from 192.168.1.2
[Nota: SSH non richiederà di inserire la password.]
mark@remote-host$ [Nota: adesso sei nel prompt del server remoto]