Cassandra要解决的问题就是伸缩(web-scale)。没有中心节点(masterless),对应于CAP理论,Cassandra属于AP
几个概念
节点(node)
集群(cluster,ring)
数据中心
复制因数
Gossiper:节点之间相互通知自己状态。
Cassandra重要特性:
- 没有单点故障,数据在多个节点上有多个拷贝。
- 可以调节的一致性,允许多种粒度的读写控制。
- 数据中心可察觉,在不同地理位置建立多个数据中心,性能更好
- 线性伸缩,主要是负载。
- 基于JVM,可通过JMX监控
Primary Key = Partition Key + Clustering Key
Partition Key:用来决定数据在哪个节点读写。
Clustering Key:保证磁盘存储的顺序,以及数据模型的唯一性。
应用场景
- 非常适合用在时间序列的,基于日志的,事件驱动的数据。一次写入,从不更新的数据。
- 数据量大,持续增长。受益于Cassandra水平伸缩性。
- 查询模式固定的场景 。
Cassandra反模式
- 频繁更新数据。因为背后的数据文件是不可变的,频繁更新导致数据存储在多个SSTable文件上,数据读取需要检查每个SSTable文件,增加读取延迟。
- 频繁删除数据。删除其实是写一个墓碑,所以删除也是写操作。
- 把Cassandra当作队列使用。队列需要经常的插入删除。导致太多的废数据。
- 灵活的查询方式。根据查询模式设计表结构,来保证查询可以在一个节点执行。通常一个查询对应一个表。Cassandra不适合多种,动态的查询。
- 全表扫描。没有WHERE的SELECT。违背了Cassandra的初衷,一个查询应该由一个节点来服务。
- 不恰当的使用Batch。Cassandra支持在一个事务中包含多个写操作。Batch是用来同事更新几个不同的表,保证一致性。而不是像RDBMS一样,对一个表一次写入成千上万条数据,这样会导致节点崩溃。
- 使用ByteOrderedPartitioner。已经过期,应该使用默认的Murmur3Partitioner
- Cassandra集群前面加负载均衡器。不需要。Cassandra有自己的负载均衡策略。
- 直接使用DataStax,不要使用Spring Data Cassandra。Spring Data Cassandra会消耗更多资源,可能导致节点不稳定。
下载Cassandra:
http://www.apache.org/dyn/closer.lua/cassandra/3.11.2/apache-cassandra-3.11.2-bin.tar.gz
解压后运行
apache-cassandra-3.11.2\bin\cassandra.bat
通过nodetool查看:
D:\Tools\apache-cassandra-3.11.2\bin>nodetool status
Datacenter: datacenter1
========================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
-- Address Load Tokens Owns (effective) Host ID Rack
UN 127.0.0.1 103.77 KiB 256 100.0% 043457d9-c61b-49ff-a6a3-5e1c118a554d rack1
运行cqlsh
D:\Tools\apache-cassandra-3.11.2\bin>cqlsh
Connected to Test Cluster at 127.0.0.1:9042.
[cqlsh 5.0.1 | Cassandra 3.11.2 | CQL spec 3.4.4 | Native protocol v4]
Use HELP for help.
cqlsh>
创建Keyspace,注意这里是 datacenter1,需要和nodetool status查询的Datacenter名字相同。
CREATE KEYSPACE mykeyspace WITH replication = {'class':'NetworkTopologyStrategy', 'datacenter1':'1'}
添加表
CREATE TABLE mykeyspace.myTable (
name text, age int, group int,
PRIMARY KEY (group,name));
插入数据,查询:
cqlsh> INSERT INTO mykeyspace.myTable(name, age, group) VALUES('andy', 33, 1);
cqlsh> SELECT * FROM mykeyspace.myTable;
group | name | age
-------+------+-----
1 | andy | 33
Java API操作
添加dependency:
<dependency>
<groupId>com.datastax.cassandra</groupId>
<artifactId>cassandra-driver-core</artifactId>
<version>3.3.0</version>
</dependency>
添加Java类:
import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Session;
public class CassandraTest {
public static void main(String[] args) {
Cluster cluster = Cluster.builder().addContactPoint("127.0.0.1").build();
Session session = cluster.connect();
session.execute("INSERT INTO mykeyspace.myTable(name, age, group) VALUES('Test', 33, 2)");
ResultSet rs = session.execute("SELECT * FROM mykeyspace.myTable WHERE group=? AND name=?", 2, "Test");
System.out.println(rs.all());
session.close();
cluster.close();
}
}
运行结果:
[Row[2, Test, 33]]