Obiettivo: anzitutto creiamo una classe per mediare la connessione MySQL (con o senza cluster è indifferente) e testiamo il cluster MySQL creato nell’esercizio precedente
Per realizzare il nostro scopo avviamo un server apache sulla nostra macchina host, dove abbiamo già avviato 3 macchine virtuali che costituiscono il nostro MySQL Cluster.
Per avviare il server apache mi avvarrò di XAMPP.
Inoltre prima di procedere devo inoltrare la porta 3306 verso il MySQL Cluster Manager che ho configurato in precedenza. Per farlo mi è sufficiente spostarmi in File ⇒ Preferenze ⇒ Rete
Selezioniamo la nostra Rete NAT corrispondente al cluster che abbiamo realizzato e andiamo a configurare l’inoltro delle porte, per ottenere qualcosa di simile a questo:
A questo punto andiamo nel nostro PHP. Creiamo anzitutto un file /inc/MySQLDb.php contenente il seguente codice:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
class MySQLdb { private $mysql = NULL; function __construct($cfg = NULL) { if( $cfg != NULL ) { $this->config($cfg['dbname'],$cfg['dbhost'],$cfg['dbuser'],$cfg['dbport'],$cfg['dbpass']); $this->connect_db(); } } function __destruct() { $this->close_db(); } function config( $dbname, $dbhost, $dbuser, $dbport, $dbpass ) { $this->dbname = $dbname; $this->dbhost = $dbhost; $this->dbuser = $dbuser; $this->dbport = $dbport; $this->dbpass = $dbpass; } function select_db($dbname = NULL) { $this->mysql->select_db($dbname ? $dbname : $this->dbname); } function connect_db() { if( $this->mysql == NULL ) { $this->mysql = new mysqli($this->dbhost, $this->dbuser, $this->dbpass); $this->select_db(); $this->errorHandler(); } } function close_db() { if( $this->mysql != NULL ) { $this->mysql->close(); $this->mysql = NULL; } } function errorHandler() { if( $this->mysql->connect_errno ) { printf( "Connect failed: %s\n", $this->mysql->connect_error ); die(); } } function clean( $val ) { return $this->mysql->real_escape_string($val); } function in( $query ) { $status = $this->mysql->query( $query ); if( $this->mysql->insert_id ) return $this->mysql->insert_id; else return $status; } function out( $query , $autoReduce = true ) { $result = $this->mysql->query( $query ); if( !is_object($result) ) return array(); while ($linea = $result->fetch_assoc()) { $i = $i !== NULL ? $i + 1 : 0; foreach( $linea as $key => $value ) { $dati[$i][$key] = $value; } } $result->close(); if( count($dati) == 1 && $autoReduce ) return $dati[0]; return $dati; } } |
Andiamo adesso a creare il nostro file index.php:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<?php include("inc/MySQLDb.php"); $mysql = new MySQLdb(array( "dbname" => "cluster_test", "dbhost" => "192.168.56.1", "dbuser" => "root", "dbpass" => "password", "dbport" => 3306 )); $utenti = $mysql->out("SELECT * FROM cluster_test",false); print_r( $utenti ); ?> |
Eseguendo la pagina index.php è molto probabile incorrere nel seguente output di errori:
1 2 3 4 5 6 7 8 9 |
Warning: mysqli::__construct(): MySQL server has gone away in D:\xampp\htdocs\tests\mysqlcluster\inc\MySQLDb.php on line 45 Warning: mysqli::__construct(): Error while reading greeting packet. PID=2612 in D:\xampp\htdocs\tests\mysqlcluster\inc\MySQLDb.php on line 45 Warning: mysqli::__construct(): (HY000/2006): MySQL server has gone away in D:\xampp\htdocs\tests\mysqlcluster\inc\MySQLDb.php on line 45 Warning: mysqli::select_db(): Couldn't fetch mysqli in D:\xampp\htdocs\tests\mysqlcluster\inc\MySQLDb.php on line 37 Connect failed: MySQL server has gone away Warning: mysqli::close(): Couldn't fetch mysqli in D:\xampp\htdocs\tests\mysqlcluster\inc\MySQLDb.php on line 57 |
Questo tipo di errore può dipendere o dal fatto che stiamo richiedendo una query troppo grossa, oppure perché il nostro Server MySQL non è predisposto per accettare le connessioni dall’esterno.
Per risolvere il problema procediamo nel modo seguente.
Anzitutto creiamo un utente apposito con il quale ci collegheremo dall’esterno (nel mio caso gli garantirò tutti i permessi possibili su tutti i database, ovviamente andrebbe limitato ad uno specifico database).
Accediamo al mysql sul nostro cluster manager digitando:
1 |
mysql -u root -p |
Inseriamo la password di root e poi eseguiamo le seguenti due query per creare l’utente zelda:
1 2 |
GRANT ALL PRIVILEGES ON *.* TO 'zelda'@'192.168.56.1' IDENTIFIED BY 'password' WITH GRANT OPTION; FLUSH PRIVILEGES; |
Faccio notare che con ‘zelda’@’192.168.56.1′ garantiamo l’accesso all’utente zelda dall’indirizzo 192.168.56.1 che è l’indirizzo esterno della nostra rete NAT su Virtual Box.
Digitiamo exit per uscire e andiamo a modificare il file di configurazione del mysql:
1 |
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf |
Cerchiamo la voce bind-address e commentiamola in modo che risulti in questo modo:
1 2 3 4 5 6 7 8 9 |
[mysqld] pid-file = /var/run/mysqld/mysqld.pid socket = /var/run/mysqld/mysqld.sock datadir = /var/lib/mysql log-error = /var/log/mysql/error.log # By default we only accept connections from localhost #bind-address = 127.0.0.1 # Disabling symbolic-links is recommended to prevent assorted security risks symbolic-links=0 |
Infine modifichiamo anche il file /etc/mysql/my.cnf
1 |
sudo nano /etc/mysql/my.cnf |
Inseriamo in fondo max_allowed_packet=16M in modo tale che il file risulti così
1 2 3 |
[mysqld] ndbcluster max_allowed_packet=16M |
Quest’ultima modifica è di solito sufficiente per correggere il precedente errore, se dovesse ripresentarsi possiamo alzare ancora questo valore.
Fatto tutto questo riavviamo il servizio mysql digitando:
1 |
sudo service mysql restart |
Se abbiamo fatto tutto bene non ci saranno errori.
A questo punto modifichiamo il file index.php di sopra perché appaia in questo modo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<?php error_reporting(E_ALL & ~E_NOTICE); include("inc/MySQLDb.php"); $mysql = new MySQLdb(array( "dbname" => "cluster_test", "dbhost" => "192.168.56.1", "dbuser" => "zelda", "dbpass" => "password", "dbport" => 3306 )); $utenti = $mysql->out("SELECT * FROM cluster_test",false); print_r( $utenti ); ?> |
Eseguendo la pagina dovremmo vedere qualcosa di simile a questo:
Questo significa che è tutto andato correttamente. A questo punto divertiamoci ad inserire qualche altro utente e generare una tabella con HTML corretto. Modifichiamo il file PHP come segue:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
<?php error_reporting(E_ALL & ~E_NOTICE); include("inc/MySQLDb.php"); // connettiamoci al database $mysql = new MySQLdb(array( "dbname" => "cluster_test", "dbhost" => "192.168.56.1", "dbuser" => "zelda", "dbpass" => "password", "dbport" => 3306 )); // inseriamo un nuovo nominativo $mysql->in("INSERT INTO cluster_test (nome,cognome) VALUES('Luigi','Verdi')"); // leggiamo tutti gli utenti $utenti = $mysql->out("SELECT * FROM cluster_test",false); ?> <html> <head> <title>Esempio Cluster MySQL e PHP</title> </head> <body> <table border="1"> <thead> <tr> <th>Nome</th> <th>Cognome</th> </tr> </thead> <tbody> <?php foreach( $utenti as $k => $v ) { ?> <tr> <td><?php echo $v['nome'] ?></td> <td><?php echo $v['cognome'] ?></td> </tr> <? } ?> </tbody> </table> </body> </html> |
Il risultato, aggiornando la pagina, dovrebbe essere simile a questo:
Infine facciamo una prova per caricare di dati il nostro cluster.
Modifichiamo il file index.php alterando la parte dell’inserimento degli utenti come segue:
1 2 3 |
// inseriamo un nuovo nominativo for( $i = 0; $i < 10000; $i++ ) $mysql->in("INSERT INTO cluster_test (nome,cognome) VALUES('Luigi$i','Verdi$i')"); |
Prima di aggiornare la pagina andiamo nel nostro cluster manager e digitiamo:
1 |
ndb_mgm -e 'ALL REPORT MEMORYUSAGE' |
Quello che dovremmo vedere sarà un risultato simile a questo:
Inserendo 10.000 record, con il precedente script, dovremmo vedere questa “importante” differenza: