Wednesday, February 26, 2020

7 Simple Steps Mongodb sharding

HI There,

Simple steps to configure and test mongo db sharding on same server. I have configured config server, mongos, shards on same server. There i will separate them with port.

1. Configure Config servers

pwd
mkdir configsrv
cd configsrv/
mkdir config1 config2
cd
mongod --configsvr --dbpath /home/mongod/configsrv/config1 --port 20000 --replSet RS_CONFIGSRV --logpath /home/mongod/configsrv/config1/config1.log --fork
mongod --configsvr --dbpath /home/mongod/configsrv/config2 --port 20001 --replSet RS_CONFIGSRV --logpath /home/mongod/configsrv/config2/config2.log --fork
mongo --port 20000
rs.initiate()
rs.add("localhost:20001")


2. Start mongos with config servers

mongos --configdb RS_CONFIGSRV/localhost:20000,localhost:20001 logpath /home/mongod/mongos.log --fork


3. Configure your first shard server

mkdir -p shard1/server1
mkdir -p shard1/server2
mongod --shardsvr --dbpath /home/mongod/shard1/server1 --port 30001 --replSet r1 --logpath /home/mongod/shard1/server1/mongod.log --fork
mongod --shardsvr --dbpath /home/mongod/shard1/server2 --port 30002 --replSet r1 --logpath /home/mongod/shard1/server2/mongod.log --fork
mongo --port 30001
rs.initiate()
rs.add("localhost:30002")


4. Configure your Second shard server

mkdir -p shard2/server1
mkdir -p shard2/server2
mongod --shardsvr --dbpath /home/mongod/shard2/server1 --port 40001 --replSet r2 --logpath /home/mongod/shard2/server1/mongod.log --fork
mongod --shardsvr --dbpath /home/mongod/shard2/server2 --port 40002 --replSet r2 --logpath /home/mongod/shard2/server2/mongod.log --fork
mongo --port 40001
rs.initiate()
rs.add("localhost:40002")

5. Create a database in primary shard you want to keep the collection

mongo --port 30001
use test_db
db.test_collection.ensureIndex( { _id : "hashed" } )

6. Add shards to mongos

mongo
sh.addShard("r1/localhost:30001,localhost:30002")
sh.addShard("r2/localhost:40001,localhost:40002")
sh.status()

7. Enable sharding. add collection and insert dummy data

sh.enableSharding("test_db")
sh.shardCollection("test_db.test_collection", { "_id": "hashed" } )
use test_db
for (var i = 1; i <= 5000; i++) db.test_collection.insert( { x : i } )


8. Result:

mongos> sh.status()
--- Sharding Status ---
  sharding version: {
        "_id" : 1,
        "minCompatibleVersion" : 5,
        "currentVersion" : 6,
        "clusterId" : ObjectId("5e56411ab72635cd8d291541")
  }
  shards:
        {  "_id" : "r1",  "host" : "r1/localhost:30001,localhost:30002",  "state" : 1 }
        {  "_id" : "r2",  "host" : "r2/localhost:40001,localhost:40002",  "state" : 1 }
  active mongoses:
        "4.0.16" : 1
  autosplit:
        Currently enabled: yes
  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" : "config",  "primary" : "config",  "partitioned" : true }
                config.system.sessions
                        shard key: { "_id" : 1 }
                        unique: false
                        balancing: true
                        chunks:
                                r1      1
                        { "_id" : { "$minKey" : 1 } } -->> { "_id" : { "$maxKey" : 1 } } on : r1 Timestamp(1, 0)
        {  "_id" : "test_db",  "primary" : "r1",  "partitioned" : true,  "version" : {  "uuid" : UUID("ab3ca1c4-de9b-4273-b787-f61193b6b614"),  "lastMod" : 1 } }
                test_db.test_collection
                        shard key: { "_id" : "hashed" }
                        unique: false
                        balancing: true
                        chunks:
                                r1      2
                                r2      2
                        { "_id" : { "$minKey" : 1 } } -->> { "_id" : NumberLong("-4611686018427387902") } on : r1 Timestamp(1, 0)
                        { "_id" : NumberLong("-4611686018427387902") } -->> { "_id" : NumberLong(0) } on : r1 Timestamp(1, 1)
                        { "_id" : NumberLong(0) } -->> { "_id" : NumberLong("4611686018427387902") } on : r2 Timestamp(1, 2)
                        { "_id" : NumberLong("4611686018427387902") } -->> { "_id" : { "$maxKey" : 1 } } on : r2 Timestamp(1, 3)

mongos>

Tuesday, February 18, 2020

How to see current connections to mongodb

Use below 2 commands to total count of connections:


testRepl:PRIMARY> var status=db.serverStatus()
testRepl:PRIMARY> status.connections
{ "current" : 9, "available" : 51191, "totalCreated" : 29 }

OR


testRepl:PRIMARY> db.serverStatus().connections
{ "current" : 9, "available" : 51191, "totalCreated" : 29 }
testRepl:PRIMARY> 


 To get connection per client you can 


db.currentOp(true).inprog.reduce(
  (accumulator, connection) => {
    ipaddress = connection.client ? connection.client.split(":")[0] : "Internal";
    accumulator[ipaddress] = (accumulator[ipaddress] || 0) + 1;
    accumulator["TOTAL_CONNECTION_COUNT"]++;
    return accumulator;
  },
  { TOTAL_CONNECTION_COUNT: 0 }
)
OUTPUT:
testRepl:PRIMARY> db.currentOp(true).inprog.reduce(
...   (accumulator, connection) => {
...     ipaddress = connection.client ? connection.client.split(":")[0] : "Internal";
...     accumulator[ipaddress] = (accumulator[ipaddress] || 0) + 1;
...     accumulator["TOTAL_CONNECTION_COUNT"]++;
...     return accumulator;
...   },
...   { TOTAL_CONNECTION_COUNT: 0 }
... )
{
        "TOTAL_CONNECTION_COUNT" : 59,
        "172.31.30.18" : 5,
        "172.31.16.25" : 3,
        "172.31.31.40" : 1,
        "Internal" : 50
}
testRepl:PRIMARY> 
You can see internal as 50. These are all mongodb internal connections, If you wish to
see those, use below commands.
db.currentOp(true).inprog.filter(connection => !connection.client).map(connection => connection.desc);
OUTPUT:testRepl:PRIMARY> db.currentOp(true).inprog.filter(connection => !connection.client).map(connection => connection.desc);[ "NoopWriter", "replication-3", "replexec-15", "replexec-14", "repl writer worker 14", "repl writer worker 13", "repl writer worker 10", "repl writer worker 9", "repl writer worker 7", "repl writer worker 6", "repl writer worker 5", "WT RecordStoreThread: local.oplog.rs", "repl writer worker 5", "WTOplogJournalThread", "repl writer worker 12", "SessionKiller", "repl writer worker 8", "ReplBatcher", "repl writer worker 4", "WTCheckpointThread", "monitoring keys for HMAC", "WTIdleSessionSweeper", "TTLMonitor", "repl writer worker 0", "WTJournalFlusher", "clientcursormon", "rsBackgroundSync", "repl writer worker 4", "rsSync", "ftdc", "repl writer worker 2", "repl writer worker 6", "repl writer worker 10", "repl writer worker 11", "repl writer worker 7", "SyncSourceFeedback", "initandlisten", "LogicalSessionCacheRefresh", "repl writer worker 3", "repl writer worker 3", "repl writer worker 11", "repl writer worker 12", "repl writer worker 8", "repl writer worker 1", "LogicalSessionCacheReap", "repl writer worker 15", "repl writer worker 9", "ApplyBatchFinalizerForJournal", "repl writer worker 0", "repl writer worker 2"]testRepl:PRIMARY>



Saturday, September 14, 2019

MongoDB: Security


db.system.users.find()

db.system.users.find({},{credentials:0}).pretty()

to list all users.




Friday, September 13, 2019

MOngoDB : Monitoring

1.) Logfile:  /var/log/mongod/mongo.log or you can also the logs remotly from below commands.

r1:PRIMARY> show logs
global
rs
startupWarnings
r1:PRIMARY> show logs startupWarnings
global
rs
startupWarnings
r1:PRIMARY> show log startupWarnings
2019-09-10T08:53:54.730+0000 I CONTROL  [initandlisten]
2019-09-10T08:53:54.730+0000 I CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.
2019-09-10T08:53:54.730+0000 I CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.
2019-09-10T08:53:54.730+0000 I CONTROL  [initandlisten]
2019-09-10T08:53:54.730+0000 I CONTROL  [initandlisten] ** WARNING: This server is bound to localhost.
2019-09-10T08:53:54.730+0000 I CONTROL  [initandlisten] **          Remote systems will be unable to connect to this server.
2019-09-10T08:53:54.730+0000 I CONTROL  [initandlisten] **          Start the server with --bind_ip <address> to specify which IP
2019-09-10T08:53:54.730+0000 I CONTROL  [initandlisten] **          addresses it should serve responses from, or with --bind_ip_all to
2019-09-10T08:53:54.730+0000 I CONTROL  [initandlisten] **          bind to all interfaces. If this behavior is desired, start the
2019-09-10T08:53:54.730+0000 I CONTROL  [initandlisten] **          server with --bind_ip 127.0.0.1 to disable this warning.
2019-09-10T08:53:54.730+0000 I CONTROL  [initandlisten]
2019-09-10T08:53:54.730+0000 I CONTROL  [initandlisten]
2019-09-10T08:53:54.730+0000 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
2019-09-10T08:53:54.730+0000 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2019-09-10T08:53:54.730+0000 I CONTROL  [initandlisten]
2019-09-10T08:53:54.730+0000 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2019-09-10T08:53:54.730+0000 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2019-09-10T08:53:54.730+0000 I CONTROL  [initandlisten]
r1:PRIMARY>

2.) verbosity: if you wna tto see details logs you can set the level of verbosity.
Verbosity level numberic 0-5
Level Description
F Fatal
E Error
W Warning
I Informational, for Verbosity Level of 0
D[1-5] Debug, for All Verbosity Levels > 0


you can also set the verbosity of specific topic instead of everything
(accesscontrol, command, control, geo, index, network,query,replication,storage, journal, write)


example:  Syntax:  db.setLogLevel(0,'query')
                               db.setLogLevel(0,'index') OR db.setLogLevel(0,'replication')

note: if you dont supply a topic, by default it will enable logging for everything.

Lets see the verbosity 4 for query component.

r1:PRIMARY> db.setLogLevel(4,'query')
{
        "was" : {
                "verbosity" : 0,   ---- this was before
                "accessControl" : {
                        "verbosity" : -1
                },
                "command" : {
                        "verbosity" : -1
                },
                "control" : {
                        "verbosity" : -1
                },
                "executor" : {
                        "verbosity" : -1
                },
                "geo" : {
                        "verbosity" : -1
                },
                "index" : {
                        "verbosity" : -1
                },
                "network" : {
                        "verbosity" : -1,
                        "asio" : {
                                "verbosity" : -1
                        },
                        "bridge" : {
                                "verbosity" : -1
                        }
                },
                "query" : {
                        "verbosity" : -1
                },
                "replication" : {
                        "verbosity" : -1,
                        "heartbeats" : {
                                "verbosity" : -1
                        },
                        "rollback" : {
                                "verbosity" : -1
                        }
                },
                "sharding" : {
                        "verbosity" : -1,
                        "shardingCatalogRefresh" : {
                                "verbosity" : -1
                        }
                },
                "storage" : {
                        "verbosity" : -1,
                        "journal" : {
                                "verbosity" : -1
                        }
                },
                "write" : {
                        "verbosity" : -1
                },
                "ftdc" : {
                        "verbosity" : -1
                },
                "tracking" : {
                        "verbosity" : -1
                }
        },
        "ok" : 1,
        "operationTime" : Timestamp(1568112427, 1),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1568112427, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}
r1:PRIMARY>


It should have changed of the verbosity of query, lets check

r1:PRIMARY> db.getLogComponents()
{
        "verbosity" : 0,
        "accessControl" : {
                "verbosity" : -1
        },
        "command" : {
                "verbosity" : -1
        },
        "control" : {
                "verbosity" : -1
        },
        "executor" : {
                "verbosity" : -1
        },
        "geo" : {
                "verbosity" : -1
        },
        "index" : {
                "verbosity" : -1
        },
        "network" : {
                "verbosity" : -1,
                "asio" : {
                        "verbosity" : -1
                },
                "bridge" : {
                        "verbosity" : -1
                }
        },
        "query" : {
                "verbosity" : 4  --- query verbosity changed to 4
        },
        "replication" : {
                "verbosity" : -1,
                "heartbeats" : {
                        "verbosity" : -1
                },
                "rollback" : {
                        "verbosity" : -1
                }
        },
        "sharding" : {
                "verbosity" : -1,
                "shardingCatalogRefresh" : {
                        "verbosity" : -1
                }
        },
        "storage" : {
                "verbosity" : -1,
                "journal" : {
                        "verbosity" : -1
                }
        },
        "write" : {
                "verbosity" : -1
        },
        "ftdc" : {
                "verbosity" : -1
        },
        "tracking" : {
                "verbosity" : -1
        }


Lets see of log is created


r1:PRIMARY> use demo
switched to db demo
r1:PRIMARY> db.testData.count()
100000
r1:PRIMARY> show logs
global
rs
startupWarnings
r1:PRIMARY> show log global

2019-09-10T10:47:08.497+0000 I COMMAND  [conn21] successfully set parameter logComponentVerbosity to { query: { verbosity: 4.0 } } (was { verbosity: 0, accessControl: { verbosity: -1 }, command: { verbosity: -1 }, control: { verbosity: -1 }, executor: { verbosity: -1 }, geo: { verbosity: -1 }, index: { verbosity: -1 }, network: { verbosity: -1, asio: { verbosity: -1 }, bridge: { verbosity: -1 } }, query: { verbosity: -1 }, replication: { verbosity: -1, heartbeats: { verbosity: -1 }, rollback: { verbosity:
2019-09-10T10:48:54.741+0000 D QUERY    [LogicalSessionCacheRefresh] Using idhack: { _id: { id: UUID("b943e79b-fb79-477f-a5b7-2057ac5447c1"), uid: BinData(0, E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855) } }
2019-09-10T10:48:54.746+0000 D QUERY    [LogicalSessionCacheReap] Only one plan is available; it will be run but will not be cached. query: { lastWriteDate: { $lt: new Date(1568110734741) } } sort: { _id: 1 } projection: { _id: 1 }, planSummary: IXSCAN { _id: 1 }
2019-09-10T10:53:54.741+0000 D QUERY    [LogicalSessionCacheRefresh] Using idhack: { _id: { id: UUID("b943e79b-fb79-477f-a5b7-2057ac5447c1"), uid: BinData(0, E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855) } }
2019-09-10T10:53:54.746+0000 D QUERY    [LogicalSessionCacheReap] Only one plan is available; it will be run but will not be cached. query: { lastWriteDate: { $lt: new Date(1568111034741) } } sort: { _id: 1 } projection: { _id: 1 }, planSummary: IXSCAN { _id: 1 }
r1:PRIMARY>

See this, some extra information is written about query execution.

to unset this, u need set the verbosity to -1.

db.setLogLevel(-1,'query')
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

you can also verbosity in config file, if you want to set that it should be there after a reboot.

Say i want to set verbosity level 2 for command topic.

it needs to added under

systemLog:
       component:
           command:
                 verbosity: 2

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

3: Query Profiler: it can capture slow query so you can erview later

Mongo has 3 profiling levels, 0,1 & 2

0 is default. it means no profiling data is collected at all, 
1 only slow operations are logged
2 all operations are logged regardless of  their speed.

In level 1, you can supply a threshold in milliseconds, operations that take longer than that threshold are logged, faster operations are not.

lets enbale profiling for any operations running more than 2 millisencons

r1:PRIMARY> show profile
db.system.profile is empty
Use db.setProfilingLevel(2) will enable profiling
Use db.system.profile.find() to show raw profile entries
r1:PRIMARY> db.setProfilingLevel(1,2)
{
        "was" : 0,
        "slowms" : 100,
        "sampleRate" : 1,
        "ok" : 1,
        "operationTime" : Timestamp(1568113657, 1),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1568113657, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
db.system.profile:
from lot of profiling data, you can look for query specific to your collections
operation type: "Query"
namespace: is the collections name



+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

4. Mongostat: lets you see metrics on several key things. Mongostat is part of the

[mongod@sikki4u2c ~]$ mongostat --port 30001
insert query update delete getmore command dirty used flushes vsize   res qrw arw net_in net_out conn set repl                time
    *0    *0     *0     *0       2     4|0  0.0% 0.0%       0 1.41G 79.0M 0|0 1|0  2.20k   65.1k   14  r1  PRI Sep 13 08:53:55.349
    *0    *0     *0     *0       0     2|0  0.0% 0.0%       0 1.41G 79.0M 0|0 1|0   416b   63.1k   14  r1  PRI Sep 13 08:53:56.350
    *0    *0     *0     *0       0     1|0  0.0% 0.0%       0 1.41G 79.0M 0|0 1|0   157b   62.5k   14  r1  PRI Sep 13 08:53:57.351
    *0    *0     *0     *0       0     4|0  0.0% 0.0%       0 1.41G 79.0M 0|0 1|0   697b   63.9k   14  r1  PRI Sep 13 08:53:58.349
    *0    *0     *0     *0       0     1|0  0.0% 0.0%       0 1.41G 79.0M 0|0 1|0   157b   62.5k   14  r1  PRI Sep 13 08:53:59.349
    *0    *0     *0     *0       0     3|0  0.0% 0.0%       0 1.41G 79.0M 0|0 1|0  1.43k   64.0k   14  r1  PRI Sep 13 08:54:00.350

^C2019-09-13T08:54:01.253+0000  signal 'interrupt' received; forcefully terminating


insert update delete :  Each one is the no of operations per second from the client. our is very quite system. nothing running. so they are all zero.

getmore  : when there is a cursor and the client asks for more data on an open cursor. 

query : it could be lower than the "getmore" in case you have not so many queries but each query is returning many many documents. wen there is too many documetns and thewy  dont just fit in the fisrt batch of the cursor then the applicatio will be issuing another "getmore" and another "getmore" for the same query, there fore the query number might be lower than the "getmore's"

flush: is the no of  disk flushes per second. "flush" relates to I/O, high flush rates means more I/O pressure.

res: is the no of megabytes of resident memore, roughly this is how much memory the mongod process consumes. this number can grow over time and can  approach the avaialbel ram, this is expected, after all mongo uses available memory to speed up operations, another reson to tun mongo on its own server.

mapped: is megabytes of data that is mapped from memory mapped files , this is relevant with the "mmapv1" the classic memory mapped file storage engine. this number can far exceed your availabel RAM size which is fine, this indications tells you how much of the data on disk was loaded at some point by mongo.

vsize: is the amount of virtual memory the mongod process is using. f

faults: IS the no of page faults per second, when data is required and is not in memory yet, it has to be brought in to the disk, while we do expect that mongo needs data from disk, high spikes here or large ramp up should be investigated. this number can go up due to no of factors, if your system starts to get bugged down by I/O this number can often be an early warning

idx miss:  refers to the percentage of attempts to load an index part that is not in memory, causing a page fault. we would like this no to be low. if the parts of the index needed overtime dont fit in memory, this number can grow. same concerns as page faults. In general IO is the slowest part, whatever you can do to minimize IO you should.

qrw arw : are the no of queued reads and writes. mongo only runs certain no of total reads and writes in given time. if more are requested by clients , those requests are queued untill current read and write complete. high queuing means high demand, if mongo cant keep up then the no of queued operations will spike.

ar aw: are the no of active reads and wrties, these are the non queued ones. looking at these and queued ones help u see if capacity is appropriate. if u see a high no of queued operations u might need to scale out or up. the no of active ops gives u a sense of how many ur server can handle because if it could handle more , the no of actives would be higher and the no of queued will lower.

net in net out :  is the bytes on th network. gives us a sense of overall traffic on the wire.

conn: this number includes all connections from other mongo replica member, application connection and etc. Connections needs to controlled, a very high no of connections would result in high memory usage.

set: shows the replica set name

repl: shows the role of member being monitored.

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5.) MongoTop : gives overall engine stats. It shows where mongo spends most of its time. it shows time spent doing reads and writes in the most active collections

[mongod@sikki4u2c ~]$ mongotop --port 30001
2019-09-13T16:20:55.590+0000    connected to: 127.0.0.1:30001

                    ns    total    read    write    2019-09-13T16:20:56Z
     admin.system.keys      0ms     0ms      0ms
    admin.system.roles      0ms     0ms      0ms
  admin.system.version      0ms     0ms      0ms
config.system.sessions      0ms     0ms      0ms
   config.transactions      0ms     0ms      0ms
         demo.testData      0ms     0ms      0ms
       demo.testData_1      0ms     0ms      0ms
              local.me      0ms     0ms      0ms
        local.oplog.rs      0ms     0ms      0ms
local.replset.election      0ms     0ms

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

db.stats() : using this fucntion we can get the disk and memory usage estimates.

connect to any database:

r1:PRIMARY> use demo
switched to db demo
r1:PRIMARY> db.stats()
{
        "db" : "demo",
        "collections" : 2,
        "views" : 0,
        "objects" : 100020,
        "avgObjSize" : 33,
        "dataSize" : 3300660,   --- in bytes
        "storageSize" : 1691648,
        "numExtents" : 0,
        "indexes" : 2,
        "indexSize" : 954368,
        "fsUsedSize" : 10444038144,
        "fsTotalSize" : 21463281664,
        "ok" : 1,
        "operationTime" : Timestamp(1568391949, 1),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1568391949, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}

to see in megabye

db.stats(1000000)


++++++++++++++++++++++++++++++++++++++++++



This picture is what we studied: see the flow here:

1. using mongotop we found where mongo was spending lot of time,
2 using db.stats() on the collection in question  we found some fishy index that may  be not so usefull. removing this index reduced the size of indx on disk , reduces the work mongo has  to do when writing to the collection and conserve resource.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6.) db.serverStatus() : gather the mix of runtime statistics  and resource usgae. Mongo give statistics  and numbers resource usage, locks, timings,  =memory, data size, flush intervals, etc.

https://docs.mongodb.com/manual/reference/command/serverStatus/

entire output of db.serverStatus() can be too much, you can use specific component command
db.serverStatus().dur   --durability info
db.serverStatus().mem  -- memory statistcis
db.serverStatus().network --gives network statistics
db.serverStatus().metrics.cursor -- related to queries -- cursor gives indication of open cursor
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++




 mongostat --port 30001 --rowcount 3

 tell mongo just to print 3 rows n then exit.



Tuesday, September 10, 2019

MongoDB: Sharding Concepts

Sharding Topology:

Applications will always talk to Mongos server, Mongos server is aware of the data distribution and  fetches the information from config servers.

And accordingly route the session to respective shard.



Lets do the setup:


1.) Config server setup,

[mongod@sikki4u2c sharding]$ pwd
/home/mongod/sharding
[mongod@sikki4u2c sharding]$ mkdir -p ConfigShard1/config1_srv_1
                                                     mkdir -p ConfigShard1/config1_srv_2
                                                     mkdir -p ConfigShard1/config1_srv_3
[mongod@sikki4u2c sharding]$ ll
total 0
drwxrwxr-x. 2 mongod mongod 6 Sep  9 05:49 config1
[mongod@sikki4u2c sharding]$   mongod --configsvr --dbpath /home/mongod/sharding/ConfigShard1/config1_srv_1 --replSet replSetConfig01 --logpath /home/mongod/sharding/ConfigShard1/config_srv_1.log --fork
about to fork child process, waiting until server is ready for connections.
forked process: 2541
child process started successfully, parent exiting
[mongod@sikki4u2c sharding]$

[mongod@sikki4u2c ConfigShard1]$ mongod --configsvr --dbpath /home/mongod/sharding/ConfigShard1/config1_srv_2 --port 20002 --replSet replSetConfig01 --logpath /home/mongod/sharding/ConfigShard1/config_srv_2.log --fork
about to fork child process, waiting until server is ready for connections.
forked process: 3172
child process started successfully, parent exiting
[mongod@sikki4u2c ConfigShard1]$ mongod --configsvr --dbpath /home/mongod/sharding/ConfigShard1/config1_srv_1 --port 20001 --replSet replSetConfig01 --logpath /home/mongod/sharding/ConfigShard1/config_srv_1.log --fork
about to fork child process, waiting until server is ready for connections.
forked process: 3208
child process started successfully, parent exiting
[mongod@sikki4u2c ConfigShard1]$ mongod --configsvr --dbpath /home/mongod/sharding/ConfigShard1/config1_srv_3 --port 20003 --replSet replSetConfig01 --logpath /home/mongod/sharding/ConfigShard1/config_srv_3.log --fork
about to fork child process, waiting until server is ready for connections.
forked process: 3297
child process started successfully, parent exiting
[mongod@sikki4u2c ConfigShard1]$

Add them to replicaset.


2.) Now lets start Mongos our sharding router process.

This process needs to know one thing , i,e. where is the config server.

mongos --configdb replSetConfig01/localhost:20001,localhost:20002,localhost:20003 --logpath /home/mongod/sharding/ConfigShard1/shard_01.log --fork
about to fork child process, waiting until server is ready for connections.
forked process: 3719
child process started successfully, parent exiting
[mongod@sikki4u2c ConfigShard1]$

3.) Lets configure the mongod server with actual data.

Lets configure replica set 1

mongod --dbpath /home/mongod/sharding/ConfigShard1/mongod_data_01 --port 30001 --replSet r1 --logpath /home/mongod/sharding/ConfigShard1/mongod_data_01/mongod_m1.log --fork
mongod --dbpath /home/mongod/sharding/ConfigShard1/mongod_data_02 --port 30002 --replSet r1 --logpath /home/mongod/sharding/ConfigShard1/mongod_data_02/mongod_m2.log --fork


Lets setup another replica set 

mongod --dbpath /home/mongod/sharding/ConfigShard1/Shard_RS2/mongo_svr1_rs2 --port 30003 --replSet r2 --logpath /home/mongod/sharding/ConfigShard1/Shard_RS2/mongo_svr1_rs2/mongod.log --fork
mongod --dbpath /home/mongod/sharding/ConfigShard1/Shard_RS2/mongo_svr2_rs2 --port 30004 --replSet r2 --logpath /home/mongod/sharding/ConfigShard1/Shard_RS2/mongo_svr2_rs2/mongod.log --fork

Done:

Till now we have configured 

a config server replica set,
a shard server
and 2 mongod replicaset with actual data

mongod    3172     1  0 06:09 ?        00:00:05 mongod --configsvr --dbpath /home/mongod/sharding/ConfigShard1/config1_srv_2 --port 20002 --replSet replSetConfig01 --logpath /home/mongod/sharding/ConfigShard1/config_srv_2.log --fork
mongod    3208     1  0 06:10 ?        00:00:05 mongod --configsvr --dbpath /home/mongod/sharding/ConfigShard1/config1_srv_1 --port 20001 --replSet replSetConfig01 --logpath /home/mongod/sharding/ConfigShard1/config_srv_1.log --fork
mongod    3297     1  0 06:10 ?        00:00:05 mongod --configsvr --dbpath /home/mongod/sharding/ConfigShard1/config1_srv_3 --port 20003 --replSet replSetConfig01 --logpath /home/mongod/sharding/ConfigShard1/config_srv_3.log --fork
mongod    3719     1  0 06:17 ?        00:00:00 mongos --configdb replSetConfig01/localhost:20001,localhost:20002,localhost:20003 --logpath /home/mongod/sharding/ConfigShard1/shard_01.log --fork
mongod    3820     1  0 06:21 ?        00:00:02 mongod --dbpath /home/mongod/sharding/ConfigShard1/mongod_data_01 --port 30001 --replSet r1 --logpath /home/mongod/sharding/ConfigShard1/mongod_data_01/mongod_m1.log --fork
mongod    3884     1  0 06:22 ?        00:00:02 mongod --dbpath /home/mongod/sharding/ConfigShard1/mongod_data_02 --port 30002 --replSet r1 --logpath /home/mongod/sharding/ConfigShard1/mongod_data_02/mongod_m2.log --fork
mongod    4153     1  0 06:26 ?        00:00:00 mongod --dbpath /home/mongod/sharding/ConfigShard1/Shard_RS2/mongo_svr1_rs2 --port 30003 --replSet r2 --logpath /home/mongod/sharding/ConfigShard1/Shard_RS2/mongo_svr1_rs2/mongod.log --fork
mongod    4183     1  0 06:26 ?        00:00:00 mongod --dbpath /home/mongod/sharding/ConfigShard1/Shard_RS2/mongo_svr2_rs2 --port 30004 --replSet r2 --logpath /home/mongod/sharding/ConfigShard1/Shard_RS2/mongo_svr2_rs2/mongod.log --fork
mongod    4378  2336  0 06:28 pts/0    00:00:00 ps -ef


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

In sharded env, anything / mostly you do will be done through sharded server. (mongos), as it is the one that knows

For us mongos is running on default port 27017, so we connec to mongos

mongo
mongos> sh.addShard('r1/localhost:30001,localhost:30002')
{
        "shardAdded" : "r1",
        "ok" : 1,
        "operationTime" : Timestamp(1568052737, 4),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1568052737, 4),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}
mongos>

mongos> sh.addShard('r2/localhost:30003,localhost:30004')
{
        "shardAdded" : "r2",
        "ok" : 1,
        "operationTime" : Timestamp(1568052808, 2),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1568052808, 2),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}
mongos>

No i will use below code to create demo data

for (var i = 1; i <= 100000; i++) {
   db.testData.insert( { x : i } )
}

Then i need to enable sharding on database, my collection testData is in Demo database.

mongos> sh.enableSharding('demo');
{
        "ok" : 1,
        "operationTime" : Timestamp(1568053819, 1),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1568053819, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}

Lets check the cluster status

mongos> sh.status()
--- Sharding Status ---
  sharding version: {
        "_id" : 1,
        "minCompatibleVersion" : 5,
        "currentVersion" : 6,
        "clusterId" : ObjectId("5d75ed206988427493d216bc")
  }
  shards:
        {  "_id" : "r1",  "host" : "r1/localhost:30001,localhost:30002",  "state" : 1 }
        {  "_id" : "r2",  "host" : "r2/localhost:30003,localhost:30004",  "state" : 1 }
  active mongoses:
        "3.6.14" : 1
  autosplit:
        Currently enabled: yes
  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" : "config",  "primary" : "config",  "partitioned" : true }
                config.system.sessions
                        shard key: { "_id" : 1 }
                        unique: false
                        balancing: true
                        chunks:
                                r1      1
                        { "_id" : { "$minKey" : 1 } } -->> { "_id" : { "$maxKey" : 1 } } on : r1 Timestamp(1, 0)
        {  "_id" : "demo",  "primary" : "r2",  "partitioned" : true }

mongos>

Notice the line in bold.

Now lets shard our collection, on "x" field

mongos> sh.shardCollection('demo.testData', {'x':1})
{
        "collectionsharded" : "demo.testData",
        "collectionUUID" : UUID("ff66a1f3-6384-416c-9b11-bb74b1b9a30a"),
        "ok" : 1,
        "operationTime" : Timestamp(1568054173, 13),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1568054173, 13),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}

mongos> show dbs
admin   0.000GB
config  0.001GB
demo    0.002GB
mongos> use demo
switched to db demo
mongos> show collections
testData
mongos>

i did not created a database "demo" in mongos, i added to shard, so we can see the db in mongos now


mongos> use config
switched to db config
mongos>
mongos> db.chunks.find().pretty()
{
        "_id" : "config.system.sessions-_id_MinKey",
        "ns" : "config.system.sessions",
        "min" : {
                "_id" : { "$minKey" : 1 }
        },
        "max" : {
                "_id" : { "$maxKey" : 1 }
        },
        "shard" : "r1",
        "lastmod" : Timestamp(1, 0),
        "lastmodEpoch" : ObjectId("5d76964ec058b369d1d2e6f0")
} --- this chunk associate itself with ReplicaSet "r1" and it has the min and max key
{
        "_id" : "demo.testData-x_MinKey",
        "ns" : "demo.testData",
        "min" : {
                "x" : { "$minKey" : 1 }
        },
        "max" : {
                "x" : { "$maxKey" : 1 }
        },
        "shard" : "r2",
        "lastmod" : Timestamp(1, 0),
        "lastmodEpoch" : ObjectId("5d769b9dc058b369d1d300fc")
}--- this chunk associate itself with ReplicaSet "r2" and it has the min and max key
mongos>






MOngoDb : Sharding Keys

Always pick the field with High Cardinality as shard key, so that the data is distributed well among all shard servers.

Sharding can be based on Chunks defines keys  and tags defines keys.

Chunks defines keys  :
the shard key you pick should be such that it provides a god variety over all documents. Ideally we should always be able to take a chunk , a range of keys and split them futhur as more documetns are added. Mongo will automatically split the chunks in smaller chunk when it feels a chunk is too large.

                                             



Pic1: Large chunk: Minkey 1 Max key 4                       Pic 2: Chunk split into 2 chunk, 1-2,2-4


Tags defines keys:
lets you designate a shard for a range of keys . Lets consider where we have one shard in a DataCenter in Amstermdam, other shard in NewZEaland. The latency will be increased. If would be cool so say mongo, if you see a phone prefix from any european country, those should be spread among the shard in Amsterdam DC.


Say the phone number data, all country with european phone prefix goes to Europe,  and American phone prefix in american shard.

Lets say if below exmaple, the applications send a data, mongo inspects the shard key value in that documetns. It finds a tag range defination that covers that shard key value. Using the tag name it will locate a chunk that lives on one of the shards that is marked with the tag. If a chunk dosent exists, it will create one on of the shards that has a specified tag.




Example:


mongos> sh.status()
--- Sharding Status ---
  sharding version: {
        "_id" : 1,
        "minCompatibleVersion" : 5,
        "currentVersion" : 6,
        "clusterId" : ObjectId("5d75ed206988427493d216bc")
  }
  shards:
        {  "_id" : "r1",  "host" : "r1/localhost:30001,localhost:30002",  "state" : 1 }
        {  "_id" : "r2",  "host" : "r2/localhost:30003,localhost:30004",  "state" : 1 }
  active mongoses:
        "3.6.14" : 1

Lets tag them 

mongos> sh.addShardTag('r1','europe')
{
        "ok" : 1,
        "operationTime" : Timestamp(1568108258, 1),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1568108258, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}
mongos> sh.addShardTag('r2','america')
{
        "ok" : 1,
        "operationTime" : Timestamp(1568108273, 2),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1568108273, 2),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}
mongos>

mongos> sh.status()
--- Sharding Status ---
  sharding version: {
        "_id" : 1,
        "minCompatibleVersion" : 5,
        "currentVersion" : 6,
        "clusterId" : ObjectId("5d75ed206988427493d216bc")
  }
  shards:
        {  "_id" : "r1",  "host" : "r1/localhost:30001,localhost:30002",  "state" : 1,  "tags" : [ "europe" ] }
        {  "_id" : "r2",  "host" : "r2/localhost:30003,localhost:30004",  "state" : 1,  "tags" : [ "america" ] }
  active mongoses:
        "3.6.14" : 1


Creating a tag range: it defines a range that is assigned to a tag, helps balancer to automatically assign chunks to desired shards.

I below exmaple, in messages collections, i want my country prefix '1' and '2' to live in the shard america. SO lower bound is 1 and upper bound is country prefix 2.
Note: Lower bound in inclusice, upper bound is exclusive. So upper bound will not fall in this range that is 2. Same logic, 2,3, 4 go to europe. 5,6 again to america. and 6.9 to austratila.

And best is from 9 to infinity.  Any prefix from 9 to anythong will go to europe.



Now will enable sharding and shared messges collection



We see 1 chunk already created.



Once you enable sharding , you would like to move the chunks to there repective shards. and that would the right direction.
I will ask mongo to move the chunk with prefix 0 to america shard. ALso prefix to move to america and so on for europe chunks.


Lets see sh.status, see chunks moved as per the tags






Chunks has the min key and max key.