domenica 28 febbraio 2016

Mongodb shard test (versione 3.0.7)

In questo esempio creiamo un ambiente con:
  • 3 config server;
  • 2 shard;
  • 2 router(mongos)
Per prima cosa mi sono creato una directory shardTest con all'interno le seguenti directory:
  • configServ;
  • configServ2;
  • configServ3;
  • shard1;
  • shard2

Quindiho fatto partire da shell prima i config server poi i router e poi gli shard


mongod --configsvr --port 30000 --dbpath /home/csciandrone//eserciziMongo/shardTest/configServ --logpath /home/csciandrone/eserciziMongo/shardTest/configServ/log.txt --fork



mongod --configsvr --port 30001 --dbpath /home/csciandrone//eserciziMongo/shardTest/configServ2 --logpath /home/csciandrone/eserciziMongo/shardTest/configServ2/log.txt --fork



mongod --configsvr --port 30002 --dbpath /home/csciandrone//eserciziMongo/shardTest/configServ3 --logpath /home/csciandrone/eserciziMongo/shardTest/configServ3/log.txt --fork


Di seguito i comandi per attivare i mongos:

mongos --port 27018 --configdb 127.0.0.1:30000,127.0.0.1:30001,127.0.0.1:30002
mongos --port 27019 --configdb 127.0.0.1:30000,127.0.0.1:30001,127.0.0.1:30002



Ora facciamo partire i 2 mongod (i 2 shard):

mongod --port 27020 --dbpath /home/csciandrone/eserciziMongo/shardTest/shard1 --logpath /home/csciandrone/eserciziMongo/shardTest/shard1/log.txt --fork
mongod --port 27021 --dbpath /home/csciandrone/eserciziMongo/shardTest/shard2 --logpath /home/csciandrone/eserciziMongo/shardTest/shard2/log.txt --fork


Ora possiamo connetterci ad uno dei due mongos e aggiungere i 2 shard appena creati:

mongo --port 27018
MongoDB shell version: 3.0.9
connecting to: 127.0.0.1:27018/test
mongos> sh.addShard("127.0.0.1:27020")
{ "shardAdded" : "shard0000", "ok" : 1 }
mongos> sh.addShard("127.0.0.1:27021")
{ "shardAdded" : "shard0001", "ok" : 1 }



A questo punto il nostro sharding cluster è configurato correttamente.
Occorre quindi operare nel seguente modo:
1) scegliere un db e creare la collection (es db test collection randomNumbers);
2) abilitare lo sharding per il db;
3) scegliere chiave di sharding per la collection;
4) creare la shard key

Quindi supponiamo di inserire un record in una collection:

db.randomNumbers.insert({a:1,b:2,c:3}) 

Creaiamo un indice sulla chiave a:
db.randomNumbers.createIndex({a:1})

Quindi abilitiamo lo shard:

sh.enableSharding("test")

Ora effettuiamo lo shard della collection sulla chiave a:

sh.shardCollection("test.randomNumbers",{a:1})
Con il comando sh.status() possiamo vedere lo stato del cluster:

sh.status()
--- Sharding Status --- 
  sharding version: {
 "_id" : 1,
 "minCompatibleVersion" : 5,
 "currentVersion" : 6,
 "clusterId" : ObjectId("56d305ccad2dda9a7c735322")
}
  shards:
 {  "_id" : "shard0000",  "host" : "127.0.0.1:27020" }
 {  "_id" : "shard0001",  "host" : "127.0.0.1:27021" }
  balancer:
 Currently enabled:  yes
 Currently running:  no
 Failed balancer rounds in last 5 attempts:  0
 Migration Results for the last 24 hours: 
  No recent migrations
  databases:
 {  "_id" : "admin",  "partitioned" : false,  "primary" : "config" }
 {  "_id" : "test",  "partitioned" : true,  "primary" : "shard0000" }
  test.randomNumbers
   shard key: { "a" : 1 }
   chunks:
    shard0000 1
   { "a" : { "$minKey" : 1 } } -->> { "a" : { "$maxKey" : 1 } } on : shard0000 Timestamp(1, 0)

Ora proviamo ad inserire un pò di record nella collection:

for(var i=0;i<100000;i++){db.randomNumbers.insert({a:Math.floor(Math.random()*100),b:Math.floor(Math.random()*100),c:Math.floor(Math.random()*100)})}

Ora possiamo rieseguire il comando sh.status() e vediamo che il balancer è entrato in azione:

sh.status(true)
--- Sharding Status --- 
  sharding version: {
 "_id" : 1,
 "minCompatibleVersion" : 5,
 "currentVersion" : 6,
 "clusterId" : ObjectId("56d305ccad2dda9a7c735322")
}
  shards:
 {  "_id" : "shard0000",  "host" : "127.0.0.1:27020" }
 {  "_id" : "shard0001",  "host" : "127.0.0.1:27021" }
  balancer:
 Currently enabled:  yes
 Currently running:  no
 Failed balancer rounds in last 5 attempts:  0
 Migration Results for the last 24 hours: 
  1 : Success
  1 : Failed with error 'could not acquire collection lock for test.randomNumbers to migrate chunk [{ : MinKey },{ : MaxKey }) :: caused by :: Lock for migrating chunk [{ : MinKey }, { : MaxKey }) in test.randomNumbers is taken.', from shard0000 to shard0001
  databases:
 {  "_id" : "admin",  "partitioned" : false,  "primary" : "config" }
 {  "_id" : "test",  "partitioned" : true,  "primary" : "shard0000" }
  test.randomNumbers
   shard key: { "a" : 1 }
   chunks:
    shard0000 2
    shard0001 1
   { "a" : { "$minKey" : 1 } } -->> { "a" : 9 } on : shard0000 Timestamp(2, 1) 
   { "a" : 9 } -->> { "a" : 81 } on : shard0000 Timestamp(1, 2) 
   { "a" : 81 } -->> { "a" : { "$maxKey" : 1 } } on : shard0001 Timestamp(2, 0)

lunedì 22 febbraio 2016

MongoDb 3.0 Security

Su MongoDb di default le impostazioni di sicurezza sono disabilitate, per abilitarle occorre far partire il server con l'opzione --auth.
Tutti i dati degli utenti sono salvati nella collection db.system.users nel db admin.
Obiettivo del post è creare un utente root in grado di creare utenti e che abbia un ruolo da amministratore generale su ogni db.
Quindi creare un db di prova e abilitare due utenti uno in sola lettura e uno in lettura e scrittura al db.

RUOLI BUILT-IN

Mongodb fornisce la possibilità di inserire i ruoli scegliendo in un ventaglio di ruoli predefiniti.

A livello di singolo database abbiamo:
  • read, può leggere su tutte le collection non di tipo system , eccezion fatta per system.indexes,system.js e system.namespaces
  • readWrite legge e modifica tutte le collection non system più la system.js

A livello di amministrazione di singolo database abbiamo:
  • dbAdmin consente di effettuare operazione amministrative, indicizzazione e raccolta di statistiche, non consente di gestire le utenze;
  • dbOwner consente di effettuare tutto sul singolo db, unisce i privilegi di readWrite a quelli di userAdmin e di dbOwner
  • userAdmin crea e modifica ruoli sul db
 A livello di amministrazione globale dei database abbiamo invece:
  • readAnyDatabase
  • readWriteAnyDatabase
  • userAdminAnyDatabase
  • dbAdminAnyDatabase
A livello di amministrazione di cluster abbiamo invece:

  • clusterAdmin
  • clusterManager
  • clusterMonitor
  • hostManager 
A livello di superuser abbiamo root che combina le abilitazioni di:
  • readWriteAnyDatabase
  • dbAdminAnyDatabase
  • userAdminAnyDatabase
  • clusterAdmin

ESEMPIO CREAZIONE SUPER USER


Facciamo partire il server senza impostazioni di sicurezza

sudo mongod --dbpath /data/dbTest --port 27018 --logpath /data/dbTest/dbInfo.log  --fork

Ora colleghiamoci al db:

mongo --port 27018

Quindi scegliamo il db admin e creaiamo l'utente con role root

> use admin
switched to db admin
> db.createUser({user:"superAdmin",pwd:"root",roles:["root"]})
Successfully added user: { "user" : "superAdmin", "roles" : [ "root" ] }


Quindi possiamo vedere interrogando la collection db.system.users l'utente attualmente inserito:


> db.system.users.find().pretty()
{
 "_id" : "admin.superAdmin",
 "user" : "superAdmin",
 "db" : "admin",
 "credentials" : {
  "SCRAM-SHA-1" : {
   "iterationCount" : 10000,
   "salt" : "HL4Hdem/yHeYZdPzC/1rFA==",
   "storedKey" : "3XGxaW4FtZEc+O+Xk+D/Zq7w3K0=",
   "serverKey" : "cOFlFork/KU//07ZZeNTp/vQ6AM="
  }
 },
 "roles" : [
  {
   "role" : "root",
   "db" : "admin"
  }
 ]
}


Quindi buttiamo giù il servizio di mongod e facciamo ripartire il server con lo stesso script di prima + l'opzione --auth. Con l'utenza appena creata possiamo riloggarci al db admin:

mongo 127.0.0.1:27018/admin -u superAdmin -p

Verrà chiesta al prompt la password.

Iniziamo a creare 4 utenti su un db denominato provaUser, uno con profilo read, uno write e uno dbOwner. Infine creiamo un utente denominato utentepowerdb con ruolo dbAdminAnyDatabase.

Per fare questa operazione dobbiamo specificare prima il db su cui opereremo , quindi dobbiamo digitare il comando use provaUser.

Prima di creare invece l'utente con ruolo dbAdminAnyDatabase


> db.createUser({user:"utentebase",pwd:"utentebase",roles:[{role:"read",db:"provaUser"}]})
Successfully added user: {
 "user" : "utentebase",
 "roles" : [
  {
   "role" : "read",
   "db" : "provaUser"
  }
 ]
}
> db.createUser({user:"utentewrite",pwd:"utentewrite",roles:[{role:"readWrite",db:"provaUser"}]})
Successfully added user: {
 "user" : "utentewrite",
 "roles" : [
  {
   "role" : "readWrite",
   "db" : "provaUser"
  }
 ]
}
> db.createUser({user:"utenteowner",pwd:"utenteowner",roles:[{role:"dbOwner",db:"provaUser"}]})
Successfully added user: {
 "user" : "utenteowner",
 "roles" : [
  {
   "role" : "dbOwner",
   "db" : "provaUser"
  }
 ]
}
db.createUser({user:"utentepowerdb",pwd:"utentepowerdb",roles:["dbAdminAnyDatabase"]}) 

Quindi proviamo a riloggarci con utentebase e verifichiamo che possiamo leggere dalla collection presente sul db provaUser ma non scrivere:


mongo 127.0.0.1:27018/provaUser -u utentebase -p 
MongoDB shell version: 3.0.9
Enter password: 
connecting to: 127.0.0.1:27018/provaUser
> show collections
randomData
system.indexes
> db.randomData.find()
{ "_id" : ObjectId("56cb814e7c51ef2d6cf2fdd1"), "a" : 60 }
> db.randomData.insert({a:Math.floor(Math.random()*100)})
WriteResult({
 "writeError" : {
  "code" : 13,
  "errmsg" : "not authorized on provaUser to execute command { insert: \"randomData\", documents: [ { _id: ObjectId('56cb8c0928a311bd5a49faa5'), a: 18.0 } ], ordered: true }"
 }
})




Con l'utentewrite invece l'inserimento sarà possibile ma non si potranno ad esempio creare nuovi utenti; tale operazione sarà invece consentita al nostro utente con ruolo dbOwner.


mongo 127.0.0.1:27018/provaUser -u utentewrite -p 
MongoDB shell version: 3.0.9
Enter password: 
connecting to: 127.0.0.1:27018/provaUser
> db.randomData.insert({a:Math.floor(Math.random()*100)})
WriteResult({ "nInserted" : 1 })
> db.randomData.createIndex({a:1})
{
 "createdCollectionAutomatically" : false,
 "numIndexesBefore" : 1,
 "numIndexesAfter" : 2,
 "ok" : 1
}
> db.createUser({user:"test",pwd:"test",roles:[{role:"read",db:"provaUser"}]})
2016-02-22T23:36:39.962+0100 E QUERY    Error: couldn't add user: not authorized on provaUser to execute command { createUser: "test", pwd: "xxx", roles: [ { role: "read", db: "provaUser" } ], digestPassword: false, writeConcern: { w: "majority", wtimeout: 30000.0 } }
    at Error ()
    at DB.createUser (src/mongo/shell/db.js:1101:11)
    at (shell):1:4 at src/mongo/shell/db.js:1101
> ^C
bye
xxxxxx@xxxxxx-HP-Pavilion-Notebook:/data$ mongo 127.0.0.1:27018/provaUser -u utenteowner -p 
MongoDB shell version: 3.0.9
Enter password: 
connecting to: 127.0.0.1:27018/provaUser
> db.createUser({user:"test",pwd:"test",roles:[{role:"read",db:"provaUser"}]})
Successfully added user: {
 "user" : "test",
 "roles" : [
  {
   "role" : "read",
   "db" : "provaUser"
  }
 ]
}




sabato 20 febbraio 2016

Mongostat e Mongotop

Tra i tool nativi di monitoraggio performance di MongoDb quelli  principalmente usati sono due:

1) mongostat -> fornisce dati real time sul processo mongod o mongos in esame, in particolare ci indica il numero di insert /update/delete etc

2) mongotop -> fornisce dati sul processo mongod o mongos separati per namespace (quindi per database e nome collection)indicando tempo totale di esecuzione e poi tempo impiegato per lettura e per scrittura

Entrambi i comandi agiscono ogni secondo e si bloccano premendo CTRL+C.

Esempio output mongostat

insert query update delete getmore command flushes mapped   vsize    res faults qr|qw ar|aw netIn netOut conn     time
  4413    *0     *0     *0       0     1|0       0 400.0M 1000.0M 131.0M      0   0|0   0|0  600k   257k    2 16:40:29
  4176    *0     *0     *0       0     1|0       0 400.0M 1000.0M 132.0M      0   0|0   0|0  568k   244k    2 16:40:30
  4376    *0     *0     *0       0     1|0       0 400.0M 1000.0M 132.0M      0   0|0   0|0  595k   255k    2 16:40:31
  4122    *0     *0     *0       0     1|0       0 400.0M 1000.0M 133.0M      0   0|0   0|0  561k   241k    2 16:40:32

Da questo output si deduce che sono in  corso delle insert sul db.

Esempio output mongotop sullo stesso db a batch in corso

2016-02-20T16:44:26.936+0100    connected to: 127.0.0.1

                                 ns    total    read    write    2016-02-20T16:44:27+01:00
                        test.awards     63ms     0ms     63ms                            
                 admin.system.roles      0ms     0ms      0ms                            
               admin.system.version      0ms     0ms      0ms                            
             certificationTest.crud      0ms     0ms      0ms                            
       certificationTest.log_events      0ms     0ms      0ms                            
            certificationTest.ninni      0ms     0ms      0ms                            
        certificationTest.sliceTest      0ms     0ms      0ms                            
   certificationTest.system.indexes      0ms     0ms      0ms                            
certificationTest.system.namespaces      0ms     0ms      0ms                            
                     prova.persona      0ms     0ms      0ms                            

                                 ns    total    read    write    2016-02-20T16:44:28+01:00
                        test.awards     51ms     0ms     51ms                            
                 admin.system.roles      0ms     0ms      0ms                            
               admin.system.version      0ms     0ms      0ms                            
             certificationTest.crud      0ms     0ms      0ms                            
       certificationTest.log_events      0ms     0ms      0ms                            
            certificationTest.ninni      0ms     0ms      0ms                            
        certificationTest.sliceTest      0ms     0ms      0ms                            
   certificationTest.system.indexes      0ms     0ms      0ms                            
certificationTest.system.namespaces      0ms     0ms      0ms                            
                   prova.persona      0ms     0ms      0ms                            


 Dal mongotop vediamo sempre che sono in corso operazioni di write e in più abbiamo l'evidenza del fatto che il namespace interessato è test.awards (quindi db test e collection awards)