php-doc-en/reference/mongo/writeconcerns.xml

411 lines
14 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<chapter xml:id="mongo.writeconcerns" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Write Concerns</title>
<para>
MongoDB provides several different ways of selecting how durable a write to
the database should be. These ways are called <literal>Write
Concerns</literal> and span everything from completely ignoring all errors,
to specifically targetting which servers are required to confirm the write
before returning the operation.
</para>
<para>
When a write (such as with <methodname>MongoCollection::insert</methodname>,
<methodname>MongoCollection::update</methodname>, and
<methodname>MongoCollection::remove</methodname>) is given a Write Concern
option (<literal>"w"</literal>) the driver will send the query to MongoDB
and piggy back a <literal>getLastError</literal> command
(<acronym>GLE</acronym>) with the Write Concern option at the same time.
The server only returns when the Write Concern condition is verified to be
fullfilled, or the query times out (controlled with the
<literal>"wtimeout"</literal> option, <literal>10000</literal> milliseconds
is the default).
</para>
<warning>
<para>
Even though a <literal>getLastError</literal> command times out the data
will most likely have been written to the primary server and will be
replicated to all the secondaries once they have cought up.
</para>
<para>
The typical reasons for a timeout to happen is if you specify a Write
Concern which requires confirmation from more servers then you currently
have available.
</para>
</warning>
<para>
When using acknowledged writes and the replica set has failed over, the driver
will automatically disconnect from the primary, throw an exception, and
attempt to find a new primary on the next operation (your application must
decide whether or not to retry the operation on the new primary).
</para>
<para>
When using unacknowledged writes (w=0) and the replica set has failed over,
there will be no way for the driver to know about the change so it will
continue and silently fail to write.
</para>
<para>
The default Write Concern for the <classname>MongoClient</classname> is
<literal>1</literal>: acknowledge write operations.
</para>
<para>
<table xml:id="mongo.writeconcerns.options">
<title>Available Write Concerns</title>
<tgroup cols="3">
<thead>
<row>
<entry>Write Concern</entry>
<entry>Meaning</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<!--
<row>
<entry>w=-1</entry>
<entry>Errors ignored</entry>
<entry>No errors, including network errors, will be checked at all</entry>
</row>
-->
<row>
<entry>w=0</entry>
<entry>Unacknowledged</entry>
<entry>A write will not be followed up with a <acronym>GLE</acronym> call, and therefore not checked ("fire and forget")</entry>
</row>
<row>
<entry>w=1</entry>
<entry>Acknowledged</entry>
<entry>The write will be acknowledged by the server (the primary on replica set configuration)</entry>
</row>
<row>
<entry>w=N</entry>
<entry>Replica Set Acknowledged</entry>
<entry>The write will be acknowledged by the primary server, and
replicated to <literal>N-1</literal> secondaries.</entry>
</row>
<row>
<entry>w=majority</entry>
<entry>Majority Acknowledged</entry>
<entry>The write will be acknowledged by the majority of the replica set (including the primary). This is a special reserved string.</entry>
</row>
<row>
<entry>w=&lt;tag set&gt;</entry>
<entry>Replica Set Tag Set Acknowledged</entry>
<entry>The write will be acknowledged by members of the entire tag set</entry>
</row>
<row>
<entry>j=true</entry>
<entry>Journaled</entry>
<entry>The write will be acknowledged by primary and the journal flushed to disk</entry>
</row>
</tbody>
</tgroup>
</table>
</para>
<simplesect xml:id="mongo.writeconcerns.setting">
<title>Using WriteConcerns</title>
<para>
Each of the methods that causes writes
(<methodname>MongoCollection::insert</methodname>,
<methodname>MongoCollection::update</methodname>,
<methodname>MongoCollection::remove</methodname>, and
<methodname>MongoCollection::batchInsert</methodname>) allow an optional
argument to send a set of options to the MongoDB server. With this option
array you can set the WriteConcern as the following example illustrates:
</para>
<example>
<title>Passing a WriteConcern to a write operation</title>
<programlisting role="php">
<![CDATA[
<?php
// Setting w=0 for insert:
$collection->insert($someDoc, array("w" => 0));
// Setting w=majority for update:
$collection->update($someDoc, $someUpdates, array("w" => "majority"));
// Setting w=5 and j=true for remove:
$collection->update($someDoc, array("w" => 5, "j" => true));
// Setting w="AllDCs" for batchInsert:
$collection->update(array($someDoc1, $someDoc2), array("w" => "AllDCs"));
?>
]]>
</programlisting>
</example>
<para>
Besides setting WriteConcerns per operation as an option argument, it is
also possible to set a default WriteConcern in different ways.
</para>
<para>
The first way is through the <link
linkend="mongo.mongoclient.construct.parameters">connection
string</link>. The connection string accepts the
<literal>journal</literal>, <literal>w</literal>, and
<literal>wTimeoutMS</literal> options:
</para>
<example>
<title>Connection string WriteConcerns</title>
<programlisting role="php">
<![CDATA[
<?php
$m = new MongoClient("mongodb://localhost/?journal=true&w=majority&wTimeoutMS=20000");
?>
]]>
</programlisting>
</example>
<para>
Since driver version 1.5 it is also possible to call
<methodname>MongoDB::setWriteConcern</methodname> and
<methodname>MongoCollection::setWriteConcern</methodname> to set a default
WriteConcern for all operations created from that specific
<classname>MongoDB</classname> or <classname>MongoCollection</classname>
object:
</para>
<example>
<title>MongoDB::setWriteConcern and MongoCollection::setWriteConcern</title>
<programlisting role="php">
<![CDATA[
<?php
$m = new MongoClient("mongodb://localhost/");
$d = $m->demoDb;
$c = $d->demoCollection;
// Set w=3 on the database object with a timeout of 25000ms
$d->setWriteConcern(3, 25000);
// Set w=majority on the collection object without changing the timeout
$c->setWriteConcern("majority");
?>
]]>
</programlisting>
</example>
</simplesect>
<simplesect xml:id="mongo.writeconcerns.unacknowledged">
<title>Unacknowledged Writes</title>
<para>
By not requiring the server to acknowledge writes the writes can be performed
extremely quickly, but you don't know whether or not they actually succeeded.
Writes can fail for a number of reasons: if there are network problems, if a
database server goes down, or if the write was simply invalid (e.g., writing
to a system collection; or duplicate key errors).
</para>
<para>
While developing, you should always use acknowledged writes (to protect against
inadvertent mistakes, such as syntax errors, invalid operators, duplicate key errors and so on). In
production, unacknowledged writes can be used for "unimportant" data. Unimportant
data varies on application, but it's generally automatically (instead of user
generated) data, such as click tracking or GPS locations, where you can get
thousands of records per second.
</para>
<para>
It is strongly recommended that you do an acknowledged write at the end of
series of unacknowledged writes. Doing so will not incur in a too large
performance penalty, but still allow you to catch any errors that may have
occurred.
</para>
<example xml:id="mongo.writeconcerns.unacknowledged-example">
<title>Unacknowledged WriteConcern, followed with Acknowledged Write</title>
<programlisting role="php">
<![CDATA[
<?php
$collection->insert($someDoc, array("w" => 0));
$collection->update($criteria, $newObj, array("w" => 0));
$collection->insert($somethingElse, array("w" => 0));
try {
$collection->remove($something, array("w" => 1));
} catch(MongoCursorException $e) {
/* Handle the exception.. */
/* Here we should issue find() queries on the IDs generated for
$somethingElse and $someDoc to verify they got written to the database and
attempt to figureout where in the chain something happened. */
}
?>
]]>
</programlisting>
<para>
If the last write throws an exception, you know that there's a problem
with your database.
</para>
</example>
</simplesect>
<simplesect xml:id="mongo.writeconcerns.acknowledged">
<title>Acknowledged Writes</title>
<para>
These type of write operations will make sure that the database has
accepted the write operation before returning success. If the write failed,
it will throw a <classname>MongoCursorException</classname> with an
explanation of the failure. The <classname>MongoClient</classname> default
behaviour is to acknowledge the write (w=1).
</para>
<para>
It is possible to specify how many members of an replica set have to
acknowledge the write (i.e. have it replicated) before the write is deemed
acknowledged and the operation returns.
<example xml:id="mongo.writeconcerns.acknowledged-example">
<title>Acknowledged Writes</title>
<programlisting role="php">
<![CDATA[
<?php
// Force acknowledgement from the primary only
$collection->insert($doc, array("w" => 1));
// Force acknowledgement from the primary, and one other member of the
// replica set
$collection->insert($doc, array("w" => 2));
// Force acknowledgement from the primary, and six other members of the
// replica set (you probably never should do this):
$collection->insert($doc, array("w" => 7));
]]>
</programlisting>
<para>
Keep in mind to select your Write Concern carefully. If you have a
replica set with 5 members, and you select Write Concern of
<literal>4</literal> you will risk the write blocking forever when one
member of the replica set goes down for maintenance or a temporary network
outage happens.
</para>
</example>
</para>
<warning>
<para>
Passing in a string value for Write Concern has a specific meaning
(Replica Set Tag Set Acknowledged). Please be careful of
<emphasis>NOT</emphasis> using string values for numbers (i.e.
<literal>array("w" => "1")</literal>) as it will be treated as a tag set
name.
</para>
</warning>
</simplesect>
<simplesect xml:id="mongo.writeconcerns.majority.acknowledged">
<title>Majority Acknowledged Writes</title>
<para>
Using the special <literal>majority</literal> Write Concern option is the
recommended way for writes that are required to survive the apocalypse, as
it will ensure the majority of your replica set will have the write and will
therefore be guaranteed to survive all usual suspect outage scenarios.
</para>
<example xml:id="mongo.writeconcerns.majority.acknowledged-example">
<title>Majority Acknowledged Write</title>
<programlisting role="php">
<![CDATA[
<?php
$collection->insert($someDoc, array("w" => "majority"));
?>
]]>
</programlisting>
</example>
</simplesect>
<!-- FIXME
<simplesect xml:id="mongo.writeconcerns.tagset">
<title>ReplicaSet TagSet Acknowledged</title>
</simplesect>
-->
<simplesect xml:id="mongo.writeconcerns.journal">
<title>Journaled Writes</title>
<para>
When connecting to a replica set the default Write Concern is only to have
the primary server acknowledge the write. There is however a 100ms window
until the write gets journaled and flushed to disk. It is possible to force
the write to be journaled before acknowledging the write by setting the
<literal>j</literal> option:
<example xml:id="mongo.writeconcerns.journalled">
<title>Acknowledged and Journaled Write</title>
<para>Forcing journal flush</para>
<programlisting role="php">
<![CDATA[
<?php
$options = array(
"w" => 1,
"j" => true,
);
try {
$collection->insert($document, $options);
} catch(MongoCursorException $e) {
/* handle the exception */
}
]]>
</programlisting>
</example>
</para>
</simplesect>
<simplesect role="seealso">
&reftitle.seealso;
<simplelist>
<member>
<link xlink:href="&url.mongodb.docs;applications/replication/#replica-set-write-concern">MongoDB WriteConcern docs</link>
</member>
</simplelist>
</simplesect>
<simplesect role="changelog">
&reftitle.changelog;
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>&Version;</entry>
<entry>&Description;</entry>
</row>
</thead>
<tbody>
<row>
<entry>1.3.0</entry>
<entry>
<classname>MongoClient</classname> was introduced and defaults to
<link linkend="mongo.writeconcerns.acknowledged">acknowledged</link> writes.
The deprecated <classname>Mongo</classname> defaults to unacknowledged
writes.
</entry>
</row>
<row>
<entry>1.3.0</entry>
<entry>
The <literal>"safe"</literal> write option has been deprecated and is
not available with the new <classname>MongoClient</classname> class.
Use the <literal>"w"</literal> option instead.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</simplesect>
</chapter>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->