Showing posts with label MongoDB. Show all posts
Showing posts with label MongoDB. Show all posts
Sunday, March 9, 2014
Tuesday, February 19, 2013
mongoDB design tips(3)
1.
UTF-8 support.
a.MongoDB
regex queries support UTF-8 in the regex string.
b.Currently, sort() on a string uses strcmp: sort order will be
reasonable but not fully international correct.
Future
versions of MongoDB may support full UTF-8 sort ordering.
2.don’t support
Sequence Numbers, but you can use following method(careful using on sharding):
function counter(name) {
var ret =
db.counters.findAndModify({query:{_id:name}, update:{$inc : {next:1}},
"new":true,
upsert:true});
// ret == { "_id"
: "users", "next" : 1 }
return ret.next;
}
db.users.insert({_id:counter("users"),
name:"Sarah C."}) // _id : 1
db.users.insert({_id:counter("users"),
name:"Bob D."}) // _id : 2
//repeat
3. Collections
number limitation.
By default
MongoDB has a limit of approximately 24,000 namespaces per database. Each
namespace is 628 bytes, the .ns file is 16MB by default. If
more collections are required, run mongod with the --nssize parameter
specified. This will make the <database>.ns file larger and support more
collections. Note that --nssize sets the size used for newly created .ns files
-- if you have an existing database and wish to resize, after running the db
with --nssize, run the db.repairDatabase() command from the shell to adjust the
size.
Maximum .ns file
size is 2GB.
Be aware that
there is a certain minimum overhead per collection -- a few KB. Further, any
index will require at least 8KB of data space as the b-tree page size is 8KB.
Certain operations can get slow if there are a lot of collections and the meta
data gets paged out.
4.Keys Too
Large To Index
Index entries
have a limitation on their maximum size (the sum of the values), currently 1024
bytes (prior to v2.0 the maximum size was 819bytes). Documents whose fields
have values (key size in index terminology) greater than this size cannot be
indexed.
5.Index
limitation:
Object
has a Index(a,b,c)
a. The sort column must be
the last column used in the index.
Good:
find(a=1).sort(a)
find(a=1).sort(b)
find(a=1, b=2).sort(c)
Bad:
find(a=1).sort(c)
even though c is the last
column used in the index, a is that last column used, so you can only sort on a
or b.
b. The range query must
also be the last column in an index. This is an axiom of 1 above.
Good:
find(a=1,b>2)
find(a>1
and a<10)
find(a>1
and a<10).sort(a)
Bad:
find(a>1,
b=2)
c. Only use a range query
or sort on one column.
Good:
find(a=1,b=2).sort(c)
find(a=1,b>2)
find(a=1,b>2 and b<4)
find(a=1,b>2).sort(b)
Bad:
find(a>1,b>2)
find(a=1,b>2).sort(c)
d. Conserve indexes by
re-ordering columns used on equality (non-range) queries.
Imagine you
have the following two queries:
find(a=1,b=1,d=1)
find(a=1,b=1,c=1,d=1)
A single index defined on
a, b, c, and d can be used for both queries.
If, however, you need to
sort on the final value, you might need two indexes
e. MongoDB's $ne or $nin
operator's aren't efficient with indexes.
When excluding just a few
documents, it's better to retrieve extra rows from MongoDB and do the exclusion
on the client side.
6.Pay
attention to the read/write ratio of your application.
This is
important because, whenever you add an index, you add overhead to all insert,
update, and delete operations on the given collection. If your application is
read-heavy, as are most web applications, the additional indexes are usually a
good thing. But if your application is write-heavy, then be careful when
creating new indexes, since each additional index with impose a small
write-performance penalty.
In general,
don't be cavalier about adding indexes. Indexes should be added to complement
your queries. Always have a good reason for adding a new index, and make sure
you've benchmarked alternative strategies.
7.
Key names limitation
a. The '$' character must not be the first character in the
key name.
b. The '.' character must
not appear anywhere in the key name.
8.
Schema design Summary of Best Practices
a."First class"
objects, that are at top level, typically have their own collection.
b. Line item detail objects
typically are embedded.
c. Objects which follow an
object modelling "contains" relationship should generally be
embedded.
d. Many to many
relationships are generally done by linking.
e.
Collections with only a few objects may safely exist as separate collections,
as the whole collection is quickly cached in application server memory.
f. Embedded objects are a
bit harder to link to than "top level" objects in collections.
g.
It is more difficult to get a system-level view for embedded objects. When
needed an operation of this sort is performed by using MongoDB's map/reduce
facility.
h. If the amount of data to
embed is huge (many megabytes), you may reach the limit on size of a single
object.
I. If performance is an
issue, embed.
When
you Write the java program for mongo ,please notice it as following.
9.
use requestStart and requestDone.
In
turns the read operation may not see the data just written since replication is
asynchronous. If you want to ensure complete consistency in a
"session" (maybe an http request), you would want the driver to use
the same socket, which you can achieve by using a "consistent
request". Call requestStart() before your operations and requestDone() to
release the connection back to the pool.
example
codes:
DB
db...;
db.requestStart();
db.requestEnsureConnection();
code....
db.requestDone();
10.
WriteConcern option for single
write operation
Since by
default a connection is given back to the pool after each request, you may
wonder how calling getLastError() works after a write. You
should
actually use a write concern like WriteConcern.SAFE instead of calling
getLastError() manually. The driver will then call getLastError()
before
putting the connection back in the pool.
WriteConcern.NONE
: No exceptions thrown.
WriteConcern.NORMAL
: Exceptions are only thrown when the primary node is unreachable for a read,
or the full replica set is unreachable.
WriteConcern.SAFE
: Same as the above, but exceptions thrown when there is a server error on
writes or reads. Calls getLastError().
WriteConcern.REPLICAS_SAFE
: Tries to write to two separate nodes. Same as the above, but will throw an
exception if two writes are not possible.
WriteConcern.FSYNC_SAFE
: Same as WriteConcern.SAFE, but also waits for write to be written to disk.
example
codes:
DBCollection coll...;
coll.insert(..., WriteConcern.SAFE);
// is equivalent to
DB db...;
DBCollection coll...;
db.requestStart();
coll.insert(...);
DBObject err = db.getLastError();
db.requestDone();
11.
Saving Objects Using DBObject
The
Java driver provides a DBObject interface to save custom objects to the
database.
Example
codes:
public
class Tweet implements DBObject {
/*
... */
}
Then
you can:
Tweet
myTweet = new Tweet();
myTweet.put("user",
userId);
myTweet.put("message",
msg);
myTweet.put("date",
new Date());
collection.insert(myTweet);
When a document is retrieved from the database, it is automatically converted
to a DBObject. To convert it to an instance of your class, use
DBCollection.setObjectClass():
collection.setObjectClass(Tweet.class);
Tweet
myTweet = (Tweet)collection.findOne();
If for
some reason you wanted to change the message you can simply take that tweet and
save it back after updating the field.
Tweet myTweet = (Tweet)collection.findOne();
myTweet.put("message",
newMsg);
collection.save(myTweet);
12.
How to insert embedded document.
BasicDBObject
doc = new BasicDBObject();
doc.put("name", "MongoDB");
doc.put("type", "database");
doc.put("count", 1);
BasicDBObject
info = new BasicDBObject();
info.put("x", 203);
info.put("y", 102);
doc.put("info", info);
coll.insert(doc);
13.
How to insert array?
{
"x"
:
[
1,
2,
{"foo" : "bar"},
4
]
}
ArrayList x = new ArrayList();
x.add(1);
x.add(2);
x.add(new BasicDBObject("foo", "bar"));
x.add(4);
BasicDBObject doc = new BasicDBObject("x", x);
14.
Adding Multiple Documents
{
"i"
: value
}
and
we can do this fairly efficiently in a loop
for (int i=0; i < 100; i++) {
coll.insert(new
BasicDBObject().append("i", i));
}
15.
Regular Expressions
Pattern
john = Pattern.compile("joh?n", CASE_INSENSITIVE);
BasicDBObject
query = new BasicDBObject("name", john);
//
finds all people with "name" matching /joh?n/i
DBCursor
cursor = collection.find(query);
mongoDB design tips(2)
1.
Optimizing Object IDs(using mongodb
ObjectId() method, BSON ObjectId's begin with a timestamp)
The _id
field in a MongoDB document is very important and is always indexed for normal
collections. This page lists some recommendations.
Note
that it is common to use the BSON ObjectID datatype for _id's, but the values
of an _id field can be of any type.Use the collections 'natural primary key' in
the _id field._id's can be any type, so if your objects have a natural unique
identifier, consider using that in _id to both save space and avoid an
additional index.When possible, use _id values that are roughly in ascending
order. If the _id's are in a somewhat well defined order, on inserts the entire
b-tree for the _id index need not be loaded. BSON ObjectIds have this property.
Store Binary GUIDs as BinData, rather than as hex encoded strings
BSON
includes a binary data datatype for storing byte arrays. Using this will make
the id values, and their respective keys in the _id index, twice as small.
Note
that unlike the BSON Object ID type (see above), most UUIDs do not have a rough
ascending order, which creates additional caching needs for their index.
2.
Optimizing Storage.
a.
Using the _id Field Explicitly
Mongo
automatically adds an object ID to each document and sets it to a unique value.
Additionally this field in indexed. For tiny objects this takes up significant
space.
The
best way to optimize for this is to use _id explicitly. Take one of your fields
which is unique for the collection and store its values in _id. By doing so,
you have explicitly provided IDs. This will effectively eliminate the creation
of a separate _id field. If your previously separate field was
indexed,
this eliminates an extra index too.
b.
Using Small Field Names
Consider
a record
{
last_name : "Smith", best_score: 3.9 }
The
strings "last_name" and "best_score" will be stored in each
object's BSON. Using shorter strings would save space:
{
lname : "Smith", score : 3.9 }
Field names are not stored in indexes as indexes have a
predefined structure. Thus, shortening field names will not help the size of
indexes. In
general it is not necessary to use short field names.
3.
Querying and nulls
> db.foo.insert( {
x : 1, y : 1 } )
> db.foo.insert( {
x : 2, y : "string" } )
> db.foo.insert( {
x : 3, y : null } )
> db.foo.insert( {
x : 4 } )
//
Query #1
> db.foo.find( {
"y" : null } )
{ "_id" :
ObjectId("4dc1975312c677fc83b5629f"), "x" : 3,
"y" : null }
{ "_id" :
ObjectId("4dc1975a12c677fc83b562a0"), "x" : 4 }
//
Query #2
> db.foo.find( {
"y" : { $type : 10 } } )
{ "_id" :
ObjectId("4dc1975312c677fc83b5629f"), "x" : 3,
"y" : null }
//
Query #3
> db.foo.find( {
"y" : { $exists : false } } )
{ "_id" :
ObjectId("4dc1975a12c677fc83b562a0"), "x" : 4 }
To summarize the
three queries:
documents where y has
the value null or where y does not exist
documents where y has
the value null
documents where y
does not exist
4.
Field Negation
// get
all posts about 'tennis' but without the comments field
db.posts.find(
{ tags : 'tennis' }, { comments : 0 } );
5.
Covered Indexes
Mongod will
automatically use covered index when it can. But be sure that:
a. you provide list
of fields to return, so that it can determine that it can be covered by index
b. you must
explicitly exclude the _id field by using {_id: 0} (unless the index includes
that)
c. as soon as you insert one array value for one of the
index keys, the index will immediately become a multikey index and this
disables covered index functionality
d. use Explain to determine if the covered index is used: the indexOnly field should be true
6.
Retrieving a Subrange of Array Elements
You can
use the $slice operator to retrieve a subrange of elements in an array.
db.posts.find({},
{comments:{$slice: 5}}) // first 5 comments
db.posts.find({}, {comments:{$slice: -5}}) // last 5 comments
db.posts.find({}, {comments:{$slice: [20, 10]}}) // skip 20, limit 10
db.posts.find({}, {comments:{$slice: [-20, 10]}}) // 20 from end, limit 10
Filtering
with $slice does not affect other fields inclusion/exclusion. It only applies
within the array being sliced.
db.posts.find({}, {_id:1, comments:{$slice: 5}}) // first 5 comments, and the
_id field only
7.
Sharding scales reads better than replication
Replication doesn't
scale writes at all, but it can add some scalability as different servers can
service queries. Use sharding to scale out. Sharding
scales
queries just as well as writes, and tends to make better use of the cluster's
total ram than replication would.
8.
When in doubt, query the primary only
Consider the diagram below as an example.
A client in the
primary data center could use slaveOk for reads, querying from both Svr1 and
Svr2. However there are several things to consider in this situation:
Are eventually
consistent reads ok when you hit Svr2?
Do you expect to be
able to continue to run in Data Center 1 if one of the (Svr1/Svr2) pair is
down? If so, and you need both for query load normally, won't you be
overcapacity if one box goes down? That is, there is not n+1 capacity in Data
Center 1. Likewise if two are needed in DC1, you probably need 2 for DR also.
One could counter that one server has sufficient and that using two is just
"a little faster" in terms of latency; however, it is then very hard
to notice if one server truly has enough capacity to handle the entire load.
Do
you have real time alerts if replication is lagging. Imagine a bad ethernet
cable on Svr2 and it is 2 hours behind realtime on its data. You probably do
not want to be querying it then.
One argument for
using slaveOk would be graceful degradation in failure scenarios. During
replica set failover, 20+ seconds could pass before a new primary is elected.
With slaveOk you can read during that period. In addition, if your system were
badly broken (two servers down) the third would be readable, but not be primary
as a majority is needed to elect a primary. One best practice is to run
querying primaries only but have built into your app a "read only
mode" you can enable in an emergency (such as a disaster) so that reads
are still possible; in that mode slaveOk would be used.
Good uses of slaveOk
slaveOk does have its
uses.
Secondaries are great for doing dumps and backups and running reports without
slowing down your front end app / production system.
Secondaries in remote data centers are useful for low latency local queries
9.
BSON type.
db.things.find( { a :
{ $type : 2 } } ); // matches if a is a string
db.things.find( { a :
{ $type : 16 } } ); // matches if a is an int
10.
Regular Expressions
i - Case insensitive.
Letters in the pattern match both upper and lower case letters.
m - Multiline. By
default, Mongo treats the subject string as consisting of a single line of
characters (even if it actually contains newlines).
The "start of
line" metacharacter (^) matches only at the start of the string, while the
"end of line" metacharacter ($) matches only at the
end
of the string, or before a terminating newline.When m it is set, the
"start of line" and "end of line" constructs match
immediately following or immediately before internal newlines in the
subject string,
respectively, as well as at the very start and end. If there are no newlines in
a subject string, or no occurrences of ^ or $ in
a pattern, setting m
has no effect.
x - Extended. If set,
whitespace data characters in the pattern are totally ignored except when
escaped or inside a character class.
Whitespace
does not include the VT character (code 11). In addition, characters between an
unescaped # outside a character class and
the next
newline, inclusive, are also ignored.
This
option makes it possible to include comments inside complicated patterns. Note,
however, that this applies only to data characters.
Whitespace
characters may never appear within special character sequences in a pattern,
for example within the sequence (?( which
introduces
a conditional subpattern.
s - Dot
all. New in 1.9.0. Allows the dot (.) to
11.
Mongo Meta query operators
Only
return the index key:
db.foo.find()._addSpecial("$returnKey" , true )
Show disk
location of results:
db.foo.find()._addSpecial("$showDiskLoc" , true)
Force
query to use the given index:
db.foo.find()._addSpecial("$hint", {_id : 1})
12.
Matching with $elemMatch
// Document 1
{ "foo" : [
{
"shape" :
"square",
"color" :
"purple",
"thick" :
false
},
{
"shape" :
"circle",
"color" :
"red",
"thick" :
true
}
] }
// Document 2
{ "foo" : [
{
"shape" :
"square",
"color" :
"red",
"thick" :
true
},
{
"shape" :
"circle",
"color" :
"purple",
"thick" :
false
}
You want to query for
a purple square, and so you write the following:
db.foo.find({"foo.shape": "square", "foo.color":
"purple"})
or
db.foo.find({foo: {"shape": "square", "color":
"purple"} } )
The problem with this query is that it will match the second in addition to
matching the first document. In other words, the standard query syntax
won't restrict itself
to a single document within the foo array. As mentioned above, subobjects have
to match exactly.
To match an entire
document within the foo array, you need to use $elemMatch. To properly query
for a purple square, you'd use $elemMatch like
so:
db.foo.find({foo:
{"$elemMatch": {shape: "square", color:
"purple"}}})
The query will return
the first document, which contains the purple square you're looking for.
13.
Atomic Operations
MongoDB supports
atomic operations on single documents. MongoDB does not support traditional
locking and complex transactions for a
number of reasons:
First, in sharded
environments, distributed locks could be expensive and slow. Mongo DB's goal is
to be lightweight and fast.
We dislike the
concept of deadlocks. We want the system to be simple and predictable without
these sort of surprises.
We want Mongo DB to
work well for realtime problems. If an operation may execute which locks large
amounts of data, it might stop
some small light
queries for an extended period of time. (We don't claim Mongo DB is perfect yet
in regards to being "real-time", but we
certainly think
locking would make it even harder.)
The Mongo DB update
command supports several modifiers, all of which atomically update an element
in a document. They include:
$set - set
a particular value
$unset -
delete a particular field (v1.3+)
$inc -
increment a particular value by a certain amount
$push -
append a value to an array
$pushAll -
append several values to an array
$pull -
remove a value(s) from an existing array
$pullAll -
remove several value(s) from an existing array
$bit -
bitwise operations
These modifiers are convenient
ways to perform certain operations atomically.
Another strategy for
atomic updates is "Update if Current".
This is what an OS
person would call Compare and Swap. For this we
1.Fetch the object.
2.Modify the object
locally.
3.Send an update
request that says "update the object to this new value if it still matches
its old value".
Should the operation
fail, we might then want to try again from step 1.
14.
The ABA Nuance
However, what if
since our read, object had been modified?
We would then
overwrite that change and lose it!
There are several
ways to avoid this problem ; it's mainly just a matter of being aware of the
nuance.
a. Use the
entire object in the update's query expression, instead of just the _id and qty
field.
b. Use $set
to set the field we care about. If other fields have changed, they won't be
affected.
c. Put a
version variable in the object, and increment it on each update.
d. When
possible, use a $ operator instead of an update-if-current sequence of
operations.
15.
Operations Lock Type
16.
How many times is data written to disk when
replication and journaling are both on?
In v1.8, for an
insert, four times. The object is written to the main collection, and also the
oplog collection (so that is twice). Both of those writes
are
journaled as a single mini-transaction in the journal file (the files in
/data/db/journal). Thus 4 times total.
There is an open item
in to reduce this by having the journal be compressed. This will reduce from 4x
to probably ~2.5x.
The above applies to
collection data and inserts which is the worst case scenario. Index updates are
written to the index and the journal, but not
the oplog, so they
should be 2X today not 4X. Likewise updates with things like $set, $addToSet,
$inc, etc. are compactly logged all around so
those are
generally small.
17.
Prealloc Files
mongod will create
prealloc files in the journal directory under some circumstances to minimize
journal write latency. On some filesystems,
appending to a file
and making it larger can be slower than writing to a file of a predefined size.
mongod checks this at startup and if it finds this to
be the case will use
preallocated journal files. If found to be helpful, a small pool of prealloc
files will be created in the journal directory before
startup begins. This
is a one time initiation and does not occur with future invocations.
Approximately 3GB of files will be preallocated (and truly
prewritten, not
sparse allocated) - thus in this situation, expect roughly a 3 minute delay on
the first startup to preallocate these files.
If you don't want to
wait three minutes on startup, you can preallocate the files using another
instance of mongod and then move them to your
normal dbpath before
starting with journaling.
mongoDB design tips(1)
1.
Linux File Systems
MongoDB uses large
files for storing data, and preallocates these. These filesystems seem to work
well:
ext4 ( kernel version
>= 2.6.23 )
xfs ( kernel version
>= 2.6.25 )
In addition to the
file systems above you might also want to (explicitly) disable file/directory
modification times by using these mount options:
noatime (also enables
nodiratime)
We have found ext3 to
be very slow in allocating files (or removing them) as well as access within
large files is also poor.
2.
What Hardware?
MongoDB tends to run
well on virtually all hardware. In fact it was designed specifically with
commodity hardware in mind (to facilitate cloud
computing); that said
it works well on very large servers too. That said if you are about to buy
hardware here are a few suggestions:
1.Fast CPU clock
speed is helpful.
2.Many cores helps
but does not provide a high level of marginal return, so don't spend money on
them. (This is both a consequence of the
design of
the program and also that memory bandwidth can be a limiter; there isn't
necessarily a lot of computation happening inside a
database).
3.NUMA is not very
helpful as memory access is not very localized in a database. Thus non-NUMA is
recommended; or configure NUMA
as
detailed elsewhere in this document.
4.RAM is good.
5.SSD is good. We
have had good results and have seen good price/performance with SATA SSDs; the
(typically) more upscale PCI SSDs
work fine
too.
6.Commodity (SATA)
spinning drives are often a good option as the speed increase for random I/O
for more expensive drives is not that
dramatic (only on the
order of 2x) – spending that money on SSDs or RAM may be more effective.
3.
PCI vs. SATA
SSD is available both
as PCI cards and SATA drives. PCI is oriented towards the high end of products
on the market.
Some SATA SSD drives
now support 6Gbps sata transfer rates, yet at the time of this writing many
controllers shipped with servers are 3Gbps.
For random IO
oriented applications this is likely sufficient, but worth considering
regardless.
4.
RAM vs. SSD
Even though SSDs are
fast, RAM is still faster. Thus for the highest performance possible, having
enough RAM to contain the working set of data
from the database is
optimal. However, it is common to have a request rate that is easily met by the
speed of random IO's with SSDs, and SSD
cost per byte is
lower than RAM (and persistent too).
A system with less
RAM and SSDs will likely outperform a system with more RAM and spinning disks.
For example a system with SSD drives and
64GB RAM will often
outperform a system with 128GB RAM and spinning disks. (Results will vary by
use case of course.)
One helpful
characteristic of SSDs is they can facilitate fast "preheat" of RAM
on a hardware restart. On a restart a system's RAM file system
cache must be
repopulated. On a box with 64GB RAM or more, this can take a considerable
amount of time – for example six minutes at
100MB/sec, and much
longer when the requests are random IO to spinning disks.
5.
FlashCache
FlashCache is a write
back block cache for Linux. It was created by Facebook. Installation is a bit
of work as you have to build and install a kernel
module. Sep2011: If
you use this please report results in the mongo forum as it's new and everyone
will be curious how well it works.
6.
OS scheduler
One user reports good
results with the noop IO scheduler under certain configurations of their
system. As always caution is recommended on
nonstandard
configurations as such configurations never get as much testing...
7.
Virtualization
Generally MongoDB
works very well in virtualized environments, with the exception of OpenVZ.
8.
Replication
Two forms
of replication are available, Replica Sets and Master-Slave. Use Replica Sets –
replica sets are a functional superset of master/slave and are handled by much
newer, more robust code.
9.
Replica Set Design Concepts
majority
of the set is not up or reachable, no member will be elected primary.
There is
no way to tell (from the set's point of view) the difference between a network
partition and nodes going down, so members left in a
minority
will not attempt to become master (to prevent a set from ending up with masters
on either side of a partition).
This means
that, if there is no majority on either side of a network partition, the set
will be read only (thus, we suggest an odd number of servers:
e.g., two
servers in one data center and one in another). The upshot of this strategy is
that data is consistent: there are no multi-master conflicts
to
resolve.
There are
several important concepts concerning data integrity with replica sets that you
should be aware of:
1. A write
is (cluster-wide) committed once it has replicated to a majority of members of
the set.
For
important writes, the client should request acknowledgement of this with a
getLastError({w:...}) call. (If you do not call getLastError,
the
servers do exactly the same thing; the getlasterror call is simply to get
confirmation that committing is finished.)
For
important writes, use the getLastError to
ensure cluster-wide commits of critical writes.
2. Queries
in MongoDB and replica sets have "READ UNCOMMITTED" semantics.
Writes
which are committed at the primary of the set may be visible before the
cluster-wide commit completes.
The read
uncommitted semantics (an option on many databases) are more relaxed and make
theoretically achievable performance and
availability
higher (for example we never have an object locked in the server where the
locking is dependent on network performance).
3. On a
failover, if there are writes which have not replicated from the primary, the
writes are rolled back. Thus we use getlasterror as in #1
above when
we need to confirm a cluster-wide commit.
The data
is backed up to files in the rollback directory, although the assumption is
that in most cases this data is never recovered as that would
require
operator intervention. However, it is not "lost," it can be manually
applied at any time with mongorestore.
Rationale
Merging
back old operations later, after another node has accepted writes, is a hard
problem. One then has multi-master replication, with potential
for
conflicting writes. Typically that is handled in other products by manual
version reconciliation code by developers. We think that is too much
work : we
want MongoDB usage to be less developer work, not more. Multi-master also can
make atomic operation semantics problematic.
It is
possible (as mentioned above) to manually recover these events, via manual DBA
effort, but we believe in large system with many, many
nodes that
such efforts become impractical.
Comments
Some
drivers support 'safe' write modes for critical writes. For example via
setWriteConcern in the Java driver.
Additionally,
defaults for { w : ... } parameter to getLastError can be set in the replica
set's configuration.
Note a
call to getLastError will cause the client to have to wait for a response from
the server. This can slow the client's throughput on writes if
large
numbers are made because of the client/server network turnaround times. Thus
for "non-critical" writes it often makes sense to make no
getLastError
check at all, or only a single check after many writes.
10.
Replica Set Commands
11.
Forcing a Member to be Primary
In v2.0+,For
example, if we had members A, B, and C and A is the current primary and we want
B to be primary, we could give B a higher priority like so:
> config =
rs.conf()
{
"_id" :
"foo",
"version" :
1,
"members" :
[
{
"_id" : 0,
"host" :
"A",
},
{
"_id" : 1,
"host" :
"B",
},
{
"_id" : 2,
"host" :
"C",
}
]
}
> config.version++
> // the default
priority is 1
>
config.members[1].priority = 2
>
rs.reconfig(config)
Assuming
B is synced to within 10 seconds of A, A will step down, B (and C) will catch
up to where A is, and B will be elected primary.
If
B is far behind A, A will not step down until B is within 10 seconds of its
optime. This minimizes the amount of time there will be no primary on
failover.
If you do not care about how long the set is primary-less, you can force A to
step down by running:
db.adminCommand({replSetStepDown:1000000,
force:1})
12.
Changing
Config Servers
Best
Practices
A.Use
three config servers.
B.Give
them logical (DNS) names. Do not refer to them (on the mongos ocmmand line) by
IP address.
C.The DNS
name should be logical (e.g. "mycluster_config2") not a name that is
VM-specific.
Use a
short DNS TTL (20 seconds or example).
D.Act
slowly when replacing a config server – your system should be fine with one
down. Better to not have an operational typo and to let
one be
down for a while. If one is down, take some time and read this page, consider
opening a support ticket, etc., before taking action.
The
metadata for the cluster is very important.
E.When
replacing a config server, make sure the old process/machine is truly down
before starting up the new one. There may be legacy
sockets
open to the old config server process otherwise, and that would be bad.
13.
Simple
Initial Sharding Architecture
Goal
Two datacenters
(East=primary, West=backup/DR)
Data Tier
(MongoDB)
3 shards
3 nodes per shard
9 hosts total
Application Tier
4 application servers
Machines Locations
e1-e6 are in 1
datacenter (East)
w1-w3 are in another datacenter (West)
Datacenter Roles
We'll use
datacenter East as the primary, and data center West as disaster recovery.
14.
Licensing
Database:
Free Software Foundation's
GNU AGPL v3.0.
Commercial licenses
are also available from 10gen, including free evaluation licenses.
Drivers:
mongodb.org supported
drivers: Apache License v2.0.
Third parties have
created drivers too; licenses will vary there.
Subscribe to:
Posts (Atom)