cyrus replication : master to replica and replica to master
Rob Mueller
robm at fastmail.fm
Thu Oct 22 20:35:25 EDT 2009
> Client A: upload message to Inbox, gets UID 100
> At the same time, Client B: upload message to Inbox, gets UID 100
>
> You can't have two messages with the same UID.
>
> There's 3 solutions I can see:
>
> 1. Mysql solves this by having interleving id's on separate servers (eg.
> auto-increment column on server A is odd numbers, on server B it's
> even numbers). I guess you could in theory do the same with IMAP
> (though I'd have to double check the spec), but it would create
> really annoying UID lists because you basically lose the ability to
> use things like 30:50. One other option would be to alternate in
> 100's or something like that (eg. 1-100 on s1, 101-200 on s2, etc)
I realised another potential problem with this.
The IMAP spec says UIDs must be incremental. So if you upload a message to
s1 and it gets UID 100, and upload on s2, and it gets UID 200, then when you
upload the next message on s1, it has to get UID 300. So you have to make
sure that if any UIDs are allocated in a "higher range", you have to jump to
the next range. This could cause you to run out of UIDs quite quickly in
pathalogical back and forth cases (eg 2 IMAP clients connected separately to
s1 & s2 both uploading a bunch of messages to the same folder).
> 3. Use some conflict resolution strategy. If some client uploads UID 100
> on s1, and another uploads UID 100 on s2, then when the conflict is
> noticed, both sides have to delete + expunge the message (because
> different IMAP clients might have different ideas on what message UID
> 100 is) and create new UIDs 101 and 102 with the two messages. This
> can be messy because if a POP client is connected, you can't alter
> the mailbox at all because the message list isn't allowed to change
> under the POP clients feet, so connected POP clients could cause
> nasty locking issues.
As an FYI, this is basically what we currently do with active/passive
replication if we have to do a "hard" failover, but we have to do it all by
hand.
In a controlled failover, we make sure all the sync logs are correctly
played before switching roles, so we know master/replica are in sync when we
change roles.
However if a server hard fails (eg kernel panic or some other OS lockup),
then we may have to switch roles, without knowing if the logs have been
cleanly played. When we get the dead server back online, it may be that a
message with the same UID exists on both ends.
In the current cyrus code, the master wins, and overwrites the message on
the replica. That's dangerous, and might end up destroying messages. We have
a patch for cyrus that checks for this case, and compares the GUID of the
messages (basically SHA1 of message content), and if they're different, it
refuses to overwrite the message, and instead just logs a message to syslog.
We have another script that notices those syslog messages, and emails us.
We then have yet another script, that lets us inspect the offending message
on both sides (eg master and replica), to see what the situation is. In most
cases, it's a message that was clearly delivered to one side, but not
replicated to the other before the machine crashed. We can then give a flag
to the script that makes it delete the UID on both sides, and then
re-appends both messages to the current master server, causing both messages
to get new UIDs.
Ideally, this whole process would be automated, and at some point we
probably will make our scripts do it automatically, but it would probably be
nice if this was eventually pushed down into the cyrus replication protocol
somehow. As Bron noted, there would still be lots of other things to make
active-active replication work properly (thinking about folder renames while
someone else has a folder selected on the other server really scares me),
but at least this would deal with the most common active-passive case where
a non-graceful failover occured.
Rob
More information about the Info-cyrus
mailing list