1.问题描述
软件版本:cassandra2.0.1,Hector-1.1-4
由于业务需要,需要使用Composite做rowkey,我使用的CQL创建的table,CQL脚本如下:
CREATE TABLE t_sim_gameinfo (
column1 text,
column2 text,
column3 text,
column4 text,
PRIMARY KEY (column1, column2)
);
按照上面create table的脚本,column1和column2组成一个composite row key,在Hector中我也是用这个composite row key建Mutator。但是Hector在插入数据时总是不能成功,调试期间会出现如下2个异常(第1个出现得最多):
Caused by: InvalidRequestException(why:Not enough bytes to read value of component 0)
at org.apache.cassandra.thrift.Cassandra$batch_mutate_result.read(Cassandra.java:20833)
at org.apache.thrift.TServiceClient.receiveBase(TServiceClient.java:78)
at org.apache.cassandra.thrift.Cassandra$Client.recv_batch_mutate(Cassandra.java:964)
at org.apache.cassandra.thrift.Cassandra$Client.batch_mutate(Cassandra.java:950)
at me.prettyprint.cassandra.model.MutatorImpl$3.execute(MutatorImpl.java:246)
at me.prettyprint.cassandra.model.MutatorImpl$3.execute(MutatorImpl.java:1)
at me.prettyprint.cassandra.service.Operation.executeAndSetResult(Operation.java:104)
at me.prettyprint.cassandra.connection.HConnectionManager.operateWithFailover(HConnectionManager.java:241)
... 3 more
InvalidRequestException(why:String didn't validate.)
2、发现问题
经查资料,另外Hector主要也是对columnfamily来操作的,于是通过cassandra-cli查看table(describe t_sim_gameinfo),出现如下信息:
ColumnFamily: t_sim_gameinfo
Key Validation Class: org.apache.cassandra.db.marshal.UTF8Type
Default column value validator: org.apache.cassandra.db.marshal.BytesType
Cells sorted by: org.apache.cassandra.db.marshal.CompositeType(org.apache.cassandra.db.marshal.UTF8Type,org.apache.cassandra.db.marshal.UTF8Type)
从上面可以看出,此create table的脚本对应的ColumnFamily的row key是UTF8Type,根本不是CompositeType,所以用Composite做row key来建Mutator后执行异常。
3、问题解决
2种行不通的解决方法
- 修改key_validation_class为CompositeType。我们可能会想到,既然key_validation_class是UTF8Type,那就把它改成CompositeType。那为什么不行。第1,Alter table根本就没有key_validation_class相关的参数。第2,如果通过修改ColumnFamily,例如:
会抛异常的哦。UPDATE COLUMN FAMILY t_sim_gameinfo WITH comparator =UTF8Type AND column_metadata =[{ name:null, keyvalidation_class:'CompositeType(UTF8Type, UTF8Type)'}];
- 把column1当key,PK中所有的column再组合成当Composite Column。但是这种方式也不行,会抛上面第一种异常的。
解决方法
- 修改cassandar-cli脚本
要使用Composite做rowkey,可以修改cassandar-cli脚本,如下:
create column family t_sim_gameinfo with comparator = 'UTF8Type'
and key_validation_class = 'CompositeType(UTF8Type, UTF8Type)'
AND default_validation_class = UTF8Type
and column_metadata=[
{column_name: column3, validation_class: UTF8Type},
{column_name: column4, validation_class: UTF8Type}
]
with read_repair_chance=0.1
and dclocal_read_repair_chance=0.5;
这时再通过cassandra-cli查看,相应的columnfamily信息是:
ColumnFamily: t_sim_gameinfo
Key Validation Class: org.apache.cassandra.db.marshal.CompositeType(org.apache.cassandra.db.marshal.UTF8Type,org.apache.cassandra.db.marshal.UTF8Type)
Default column value validator: org.apache.cassandra.db.marshal.BytesType
Cells sorted by: org.apache.cassandra.db.marshal.CompositeType(org.apache.cassandra.db.marshal.UTF8Type)
key_validation_class已经成CompositeType,默认会有key,key1当做联合主键,此时如果把key和key1组成CompositeType做为row key建Mutator就没有问题了。
- 修改cql脚本
另外,也可以修改cql脚本,如下。Insert数据没有问题,但只可以通过cassandra-cli查看数据,用cqlsh查不到数据。
CREATE TABLE t_sim_gameinfo (
column1 text,
column2 text,
column3 text,
column4 text,
PRIMARY KEY ((column1, column2))
)WITH COMPACT STORAGE;
参考:
cannot insert composite key,
Can't insert rows with composite key using Hector