欢迎投稿

今日深度:

关于cassandra集群的数据一致性问题,cassandra集群

关于cassandra集群的数据一致性问题,cassandra集群


cassandra集群要求严格的时间同步,有一点同步就会发生这样那样的问题,这个事情我已经在cassandra集群要求严格的时间同步里说明了,所以时间同步是cassandra集群的前提。

cassandra使用的是最后一致性模型,也就是说一开始的并发更新的数据可能是不一致的,但是经过这段不一致的时间之后,系统会达到最终的一致性。让每个客户端看到的结果是一样的。

这个最终一致性的强度,在cassandra中是有你所选的一致性模型决定的。通常使用cassandra,我们选择QUORUM级别,表示有半数副本收到请求的时候,返回客户端响应,这样保证插入的数据,可以肯定被查询到。然而这里存在一个问题,关于并发性,假设客户端对同一条记录进行更新,cassandra是根据什么判断请求的先后呢?只有时间,cassandra会根据请求到达服务器的先后时间。例如:

QueryOptions options = new QueryOptions();
options.setConsistencyLevel(ConsistencyLevel.QUORUM);
 
Cluster cluster = Cluster.builder()
.addContactPoint("192.168.1.101")
.withCredentials("cassandra", "cassandra")
.withQueryOptions(options)
.build();
 
Session session = cluster.connect();
RegularStatement update10 = QueryBuilder.update("myKeysapce","tableName")
.with(QueryBuilder.set("col2", 10))
.where(QueryBuilder.eq("key1", 1));
session.execute(update10);
 
RegularStatement update20 = QueryBuilder.update("myKeysapce","tableName")
.with(QueryBuilder.set("col2", 20))
.where(QueryBuilder.eq("key1", 1));
session.execute(update20);

 但是cassandra集群有多台机器,客户端发到服务器的不同机器上呢?糟了,数据乱掉了。是的,当你使用datastax的驱动程序的时候,你会发现快速对同一条记录进行两次更新,最终的结果有时候并不是第二个请求更新的结果,就像上面的例子,每次更新结果可能是20,也可能是10。即便你的一致性级别选择的ALL,也有可能发生这样的情况。因为两次请求的时间间隔实在很短,而集群的所有机器又不能完全时间同步,即便是使用了ntp同步,时间差也会在ms级别,两次请求发到不同的机器上,就会发生这样的问题。

怎么办呢?当我们换用另外一个cassandra客户端Astyana的时候,我们发现并不会发生上面描述的情况,这是为什么呢?难道客户端有问题,经过调查发现,Astyanax客户端发的两次请求都是发到了集群的同一个节点,而datastax官方驱动客户端,却是发向了不同的节点。

原来Astyanax客户端有一个请求策略的概念,它有三种策略(TOKEN_AWARE,ROUND_ROBIN和BAG),其中TOKEN_AWARE就是根据主键token请求到相同的客户端。
那原生的datastax客户端有没有这样的概念呢?调查后发现也是有的,它叫做LoadBalancingPolicy,可以通过 Cluster.builder().withLoadBalancingPolicy(policy)指定,它也有三个策略,分别是:

DCAwareRoundRobinPolicy
RoundRobinPolicy
TokenAwarePolicy

其中TokenAwarePolicy就是根据token把对同一条记录的请求,发到同一个节点,看代码我们发现datastax默认使用的策略就是TokenAwarePolicy,那为什么没有和Astyana一样的效果呢?

通过阅读它的代码,原因找到了,那就是在更新的时候,要给它指定表的tablemetadata,否则datastatx无法知道哪些字段是主键,额,貌似这个客户端也太傻了。。。
上面的例子改成下面这样,就万事大吉了。

TableMetadata metaData = cluster.getMetadata().getKeyspace("myKeyspace").getTable("tableName");
RegularStatement update10 = QueryBuilder.update(metaData)
.with(QueryBuilder.set("col2", 10))
.where(QueryBuilder.eq("key1", 1));

 

www.htsjk.Com true http://www.htsjk.com/cassandra/35267.html NewsArticle 关于cassandra集群的数据一致性问题,cassandra集群 cassandra集群要求严格的时间同步,有一点同步就会发生这样那样的问题,这个事情我已经在cassandra集群要求严格的时间同步里说明了,所...
相关文章
    暂无相关文章
评论暂时关闭