大家在使用Cassandra的时候,往往容易忽视Cassandra本身的限制。
在Wiki中,我们可以看到Cassandra的限制:CassandraLimitations
Cassandra的设计限制
这一类限制是在当前的体系架构中无法改变的。
每一个key对应的value不能超过磁盘本身的容量限制。
这是因为Cassandra是将每一个key对应的value存储在本地磁盘上面的,所以当某一个key对应的vaule的大小超过了本地磁盘的容量上限,那么当Cassandra记录commitlog的时候就会失败,写入到SSTable中同样会失败。
这一点与Hadoop中的DFS不同,DFS是将本机分块存储的,所以无所谓文件的最大上限。
Cassandra当前的版本限制
这一类限制是在可以通过修改代码和版本升级改变的。
key的长度大小限制在65535之内
这个限制是由于Cassandra内部在将key写入到磁盘的时候,采用的是java.io.DataOutputStream.writeUTF(String, DataOutput),这个方法内部对key的大小有一个65535的限制。
在Cassandra中,所有的添加和修改操作会经过一个org.apache.cassandra.thrift.ThriftValidation.validateKey(String)进行判断,如果key的长度超过65535将抛出异常。不过这个方法也不能保证不会出现问题:因为Cassandra最终写入磁盘时候的key是一个被包装后的key,会添加token的信息,所以即使key本身的长度没有超过65535,被包装后的key的长度也有可能超过65535。
不过这个不是一个大问题,即使是,也可以容易修改掉:)
执行SSTable压缩操作的时消耗大量内存
在Cassandra执行将多个SSTable合并为一个SSTable时候,会将需要合并的key对应的所有value合并到。
如果某一个key对应的value非常大,那么就需要大量的内存来保持value。同时在写入的时候,我们需要记录value的大小。如果value的长度超过了Integer的限制,也会出现问题。
我们在Cassandra的配置文件storage-conf.xml中可以看到这么一个配置选项:RowWarningThresholdInMB,它的作用就是设置一个阀值,当压缩时某一个key对应的value大小超过这个阀值的时候,在日志中记录一条WARN信息。
这个问题将会在0.7的版本中修复。
SupperColumn下的Column无索引
现在的SSTable格式由包括3种文件组成:data,index和filter。其中filter文件用于判断需要寻找的key是否在data中,index文件用于快速定位每一个key在data文件中的位置,data文件中不仅保持了key和该key对应的value(这些value就是一系列Column),同时还有对应value的filter和index。
同理,data文件中的filter用于判断某一个Column是否存在(根据Column的Name),index用于快速定位这个key下面的这个Column在文件中的位置。
但是这里存在一个问题:data文件中的index只有一级索引,即如果都是Column,那么可以很快定位到所有的Column的位置。但如果是SupperColumn,那么只能定位到某一个SupperColumn的位置,而无法定位到SupperColumn下面的某一个Column的位置。
这种SSTable的设计就造成了一个很严重的问题:如果我们读取某一个key下的SupperColumn下的某一个Column的数据,那么Cassandra会将该SupperColumn下的所有数据都读取出来,然后找到我们需要的Column数据。
这也就造成了如果某一个SupperColumn数据量非常大,那么读取的时间也会非常长的现象。
要解决这个问题,需要一种新的SSTable的格式。
这个问题暂时还没有指定修复的版本。
Client端一次性从Cassandra中无法获取大量的数据
由于Cassandra是使用Thrift提供外部接口,所以Client端和Cassandra交互的时候,所有的数据传输都要先放到机器的内存中,再进行传输。假设我们使用multiget接口(关于Cassandra的编程接口,可以参考:谈谈Cassandra的客户端)获取一些列key的值,并且这些key的值都比较大,超过了内存的限制,那么这种交互将永远不会成功。
所以我们应该做的就是避免出现这个大量的请求操作。如果交互的数据量非常大,可以考虑压缩或者是拆分的策略。
这个问题暂时还没有指定修复的版本。
Client端如果发送不符合要求的数据,会导致Cassandra运行出错
我们使用Cassandra的时候,都是使用Cassandra提供的一系列Thrift API来调用的,包括Java,PHP,Python等等。但是我们要是通过这些Thrift发送一些不符合要求的数据,就会导致Cassandra运行出错。这个问题是由于Thrift本身的原因造成的。
但是这个问题不是一个大问题:只要我们不要暴露Cassandra的Thrift端口给外部直接使用即可。
这个问题将会在0.7的版本中修复。