Re: Understanding the UnavailableException
Consistency and availability are two different things: Consistency means getting the same stuff that you
wrote. Availability means getting *anything*.
Say you write first row = "Markus", column = "emailaddress", value =
"foo@..." with CL=ONE, Cassandra will return once at least one node which
would handle this row responds that it has stored the data. If your RF is 1, then there's exactly one node
that would receive this data. If you have RF=3, a response of any of these three nodes would work. (CL=ZERO
means that Cassandra won't wait for anyone, so the write might fail or not.)
Then you write immediately row = "Markus", column = "emailaddress", value = "newaddress@...".
Then you read row = "Markus", column = "emailaddress".
If your data is available, you'll get the value "foo@..." or
"newaddress@...", depending on your CL settings and whether the data has
replicated across replicas and so on. Consistency means that you would get
newaddress@..., because that's what you wrote last. By increasing your CL
you increase the chances of actually getting the latest data.
If all the nodes that handle "Markus" are down, then you will receive an error and the data is not available.
If you get an UnavailableException, your data is not available. It might be consistent, but you can't get to
it, because there aren't enough nodes for the CL you chose to respond.
Writes and reads can be sent to *any* node, but Cassandra will internally reroute the request to the node
which actually should contain the data. So if you write with CL=ZERO, a node will buffer up the write, but if
actual recipient node is down, the write may never go on the disk. Hence it's a good idea to write at least
with CL=ONE to be sure that at least one node was able to store the data. Writing with CL=QUORUM then means
that at least (RF/2+1) nodes acknowledged storing the data.
(Also, writing a lot of data with CL=ZERO is a great way to eat up all memory :-P)
/Janne
On Oct 1, 2010, at 18:31 , Markus Kramer wrote:
> Thanks a lot for the clarification!
>
> It makes sense to me that reads might fail if I'm using RF=1.
> So if I don't care at all about the consistency of my reads I'll have
> to catch and ignore the UnavailableException?
>
> However, some writes also fail. Since I'm writing with a
> ConsistencyLevel of ZERO, I thought cassandra's hinted handoffs
> feature would allow me to write to any node regardless of where the
> data actually belongs to (even if that node doesn't keep a replica)?
>
> Cheers, Markus
>
>
> On Oct 1, 3:20 pm, Janne Jalkanen <jalka...@...> wrote:
>> RF=1 means that only one node will hold your data. If that's the node which happens to be down, then you
won't get the data...
>>
>> Cassandra divides the keyspace and distributes them according to the RF. So, for example, if you have
three servers, each of them gets allotted (roughly) one third of the keyspace. If you have RF=1, each of the
servers then holds that one third, but no more. If you specify RF=2, then each server grabs *another*
third, so each of them holds their own third, and a third from some other server. If you specify RF=3, then
each of the servers holds its own third + the thirds from the two other servers, which essentially means
that every single server has a full copy of the entire
>> keyspace.
>>
>> So you need to increase your RF, so that when one node is down, other nodes which still hold the data, can
step in.
>>
>> CL then means a different thing: whenever you are reading, CL=ONE means that Cassandra will think a value
from any of the servers is ok. It might be stale, or it might not be. Cassandra does not care. CL=QUORUM means
that Cassandra will ask a vote from all the machines that hold the particular key, and then sends you the
data which has over one half of the votes. For example, if RF=3, at least two nodes need to agree what a value
is before it sends it back to the requester.
>>
>> Note that if you do stuff like have RF=2, and then read with CL=QUORUM, you will get into trouble, because
when one node goes down, then the other node cannot get a quorum (2/1 = 1, and for quorum you need *over* half
of the votes). So RF=3 is the first RF which protects you against one node going down if you are doing
CL=QUORUM reads. If you read *always* with CL=1, then RF=2 is enough.
>>
>> Hope this helps,
>>
>> /Janne
>>
>> On 1 Oct 2010, at 14:48, Markus Kramer wrote:
>>
>>> Hi,
>>> I know questions about the UnavailableException have been asked in
>>> here before, but I still got problems.
>>
>>> I'm using a simple and fresh three node cluster for testing. Writing
>>> some entries works nicely. However, if I disable one node I get an
>>> UnavailableException. Shouldn't Hector/Cassandra failover to the two
>>> remaining nodes?
>>> I'm using RF=1 and (hopefully corretly) set CL to weakest possible
>>> consistency (reads=one, writes=zero).
>>
>>> I'm using Cassandra 0.6.5 and Hector 0.6.0-17.
>>> This is my test code:
>>
>>> --------------------------------------------
>>> <at> Test
>>> public void testFailover() {
>>> Cluster cluster = HFactory.getOrCreateCluster("MyCluster", "moabit:
>>> 9160,bramstedt:9160,moers:9160");
>>> this.keyspace = HFactory.createKeyspace(this.keyspaceId, cluster,
>>> zeroConsistencyLevel);
>>
>>> String username;
>>> String city;
>>
>>> System.out.println("\n\nStarting a fresh cluster with 3 nodes");
>>
>>> for (int i = 0; i < 5; i++) {
>>> System.out.println("\n\n");
>>> username = "User1_" + i;
>>> city = "Berlin";
>>> setCity(username, city);
>>> Assert.assertEquals(city, getCity(username));
>>> }
>>
>>> System.out.println("\n\nManually disable node 'moers'");
>>
>>> for (int i = 0; i < 5; i++) {
>>> System.out.println("\n\n");
>>> username = "User2_" + i;
>>> city = "New York";
>>> setCity(username, city);
>>> Assert.assertEquals(city, getCity(username));
>>> }
>>> }
>>
>>> private void setCity(String key, String value) {
>>> Mutator m = HFactory.createMutator(this.keyspace);
>>> m.insert(key, this.columnFamily,
>>> HFactory.createColumn(this.columnId, value, this.ss, this.ss));
>>> }
>>
>>> private String getCity(String key) {
>>> ColumnQuery<String, String> q =
>>> HFactory.createColumnQuery(keyspace, ss, ss);
>>> QueryResult<HColumn<String, String>> r =
>>> q.setKey(key).setName(columnId).setColumnFamily(
>>> columnFamily).execute();
>>
>>> HColumn<String, String> c = r.get();
>>> return c.getValue();
>>> }
>>> --------------------------------------------
>>
>>> After I've disable one node I immediately get the
>>> UnavailableException.
>>> Regards, Markus