














官页 - https://cassandra.apache.org/_/index.html
官中文档- https://cassandra.apache.ac.cn/doc/latest/cassandra/getting-started/index.html
Wiki(Cassandra) - https://zh.wikipedia.org/zh-cn/Cassandra
Apache Cassandra is an open source NoSQL distributed database trusted by thousands of companies for scalability and high availability without compromising performance. Linear scalability and proven fault-tolerance on commodity hardware or cloud infrastructure make it the perfect platform for mission-critical data.
Apache Cassandra 是一种开源的 NoSQL 分布式数据库,被数千家公司信赖,其可扩展性和高可用性性能得到了验证。即使在普通硬件或云基础设施上,它也能实现线性扩展,并且具有出色的容错能力,因此它是处理关键数据的理想选择。
https://db-engines.com/en/ranking
Cassandra 它最初由Meta开发,用于改善电子邮件系统的搜索性能的简单格式数据,集Google BigTable的数据模型与Amazon Dynamo的完全分布式架构于一身。Facebook于2008将 Cassandra 开源。
Cassandra 被设计为分布式数据库管理系统 (DBMS),依赖于点对点架构。Cassandra 集群中的每个节点或存储部分数据的单个服务器都是平等的,数据分布在各个对等节点,而非集中存储,从而消除了单点故障(单一故障可能会迅速引发连锁反应)。通过这种设计,系统即使在计划内停机或突发变化期间,也能实现无缝复制、高效数据分发并保持持续服务。
注意: 它也不支持传统 ACID 事务
大规模、高写入、低延迟、可扩展、高可用。适合的场景如:IoT 数据、设备遥测、用户行为日志、订单流水、消息存储
RDBMS 和 Cassandra 之间的设计差异 - https://cassandra.apache.ac.cn/doc/latest/cassandra/developing/data-modeling/data-modeling_rdbms.html
下表列出了区分 Cassandra 的数据模型和 RDBMS 的数据模型的对比。
| RDBMS | Cassandra |
|---|---|
| RDBMS 处理结构化数据。 | Cassandra 处理非结构化数据。 |
| 它具有固定的模式。 | Cassandra 具有灵活的架构。 |
| 在 RDBMS 中,表是一个数组的数组。 (ROW x COLUMN) | 在 Cassandra 中,表是“嵌套的键值对”的列表。 (ROW x COLUMN 键 x COLUMN 值) |
| 数据库是包含与应用程序对应的数据的最外层容器。 | Keyspace 是包含与应用程序对应的数据的最外层容器。 |
| 表是数据库的实体。 | 表或列族是键空间的实体。 |
| Row 是 RDBMS 中的单个记录。 | Row 是 Cassandra 中的一个复制单元。 |
| 列表示关系的属性。 | Column 是 Cassandra 中的存储单元。 |
| RDBMS 支持外键的概念,连接。 | 关系是使用集合表示。 |
从 Cassandra 3.0 开始,CQL 全面普及后:在 CQL 中用 CREATE TABLE 创建的东西,底层就是列族同一个东西。 |
Cassandra 的核心数据层次可以理解为:
集群(Cluster)
│
├── 数据中心(Datacenter)
│
├── 节点(Node)
│
└── Keyspace
│
├── Table
│ │
│ ├── Row
│ │ └── Column
│ │
│ └── Row
│
└── Table
Cassandra数据库是为跨越多条主机共同工作,对用户呈现为一个整体的分布式系统设计的。Cassandra最外层容器被称为群集。Cassandra将集群中的节点组织成一个环(ring),然后把数据分配到集群中的节点(Node)上。
Cassandra 集群中的每个节点或存储部分数据的单个服务器都是平等的, 集群中的所有节点都是一样的
https://www.w3cschool.cn/cassandra/cassandra_data_model.html
Keyspace 是 Cassandra 中数据的最外层逻辑容器。它有点类似于关系型数据库中的:Database / Schema
创建键空间的语法
CREATE KEYSPACE Keyspace name
WITH replication = {'class': 'SimpleStrategy', 'replication_factor' : 3};
如:
CREATE KEYSPACE store
WITH replication = {
'class': 'SimpleStrategy',
'replication_factor': 3
};
Keyspace 本身并不直接存储业务数据,而是用来管理一组 Table,并定义这些数据在 Cassandra 集群中的复制策略。
Keyspace 最重要的配置:
它是集群中将接收相同数据副本的计算机数。
它只是把副本放在介质中的策略。有简单策略(机架感知策略),网络拓扑策略(数据中心共享策略)等策略。
常见策略:
| 策略名 | 中文名 | 描述 |
|---|---|---|
| SimpleStrategy | 简单策略 | 适用于只有一个数据中心。为集群指定简单的副本因子(有几个副本) |
| NetworkTopologyStrategy | 网络拓扑策略 | 推荐方式,因为可以扩展到多数据中心,可以单独为每个数据中心设置 Replication Factor |
相当于关系数据库的表(Table) 以前叫 Column Family
| 关系表 | Cassandra Table |
|---|---|
| 关系模型中的模式是固定的。 一旦为表定义了某些列,在插入数据时,在每一行中,所有列必须至少填充一个空值。 | 在 Cassandra 中,虽然定义了列族,但列不是。 您可以随时向任何列族自由添加任何列。 |
| 关系表只定义列,用户用值填充表。 | 在 Cassandra 中,表包含列,或者可以定义为超级列族。 |
https://cassandra.apache.ac.cn/doc/latest/cassandra/reference/cql-commands/create-table.html
可以理解类似 Java 的Map<String,Map<byte[],Column>> 结构存储, 下为表中的数据示例
![[Pasted image 20260826214432.png]]
Cassandra Table 中的每一行都用 Row Key 来标识,这个相当于关系数据库表中的主键,并且总是被索引的。
主键
PRIMARY KEY 由表中定义的一个或多个列组成。主键定义中列的顺序定义了分区键和聚簇列。
CQL 主键由两部分组成
CREATE TABLE t (k text PRIMARY KEY);
这些列是主键定义中分区键后面的列。这些列的顺序定义了_聚簇顺序_。
PRIMARY KEY (a):a 是单个分区键,没有聚簇列
PRIMARY KEY (a, b, c):a 是单个分区键,b 和 c 是聚簇列
PRIMARY KEY ((a, b), c):a 和 b 组成_复合_分区键,c 是聚簇列
列是 Cassandra 的基本数据结构,是最小的存储单元, 具有三个值: 列名 + 列值 + 时间戳
| 名称 | 值 | 时间戳 |
|---|---|---|
| name:byte[] | value:byte[] | clock:byte[] |
注意这里的时间戳是 Cassandra 列的内部元数据,由系统自动管理,不体现在表结构中,可以通过 writetime() 函数查询。
-- 查看某列的写入时间戳(返回微秒级整数)
SELECT name, writetime(name) FROM users WHERE id = 1;
-- 同时查看多列的时间戳
SELECT name, age, writetime(name), writetime(age) FROM users WHERE id = 1;
writetime() 不能用于主键列,否则会报错Cassandra 的一切操作(增、改、删)本质上都是"带时间戳的写入",读取时按时间戳合并取最新版本,过期的数据由后台 Compaction 清理。
Row Key 是逻辑概念(标识一行数据),Primary Key 是物理概念(决定数据分布和排序)。当 Primary Key 只有一个字段时,它既是 Partition Key 也是 Row Key。
CREATE TABLE orders (
user_id INT,
created_at TIMESTAMP,
amount DECIMAL,
PRIMARY KEY (user_id, created_at)
);
-- =========================================================
-- PRIMARY KEY 属性说明
-- =========================================================
-- PRIMARY KEY ((partition_key), clustering_column)
-- 第一部分:
-- Partition Key
-- 决定数据存储在哪个节点
--
-- 第二部分:
-- Clustering Column
-- 决定同一个 Partition 内的数据排序方式
user_id(决定数据在哪个节点)created_at(决定分区内排序)(user_id, created_at)(全局唯一)user_id(定位到分区,分区内再用 created_at 区分不同行)**Cassandra会对Partition key 列计算出一个哈希值,该哈希值定义了分区位置。再例如:
CREATE TABLE t (
a int,
b int,
c int,
d int,
PRIMARY KEY ((a, b), c, d)
);
INSERT INTO t (a, b, c, d) VALUES (0,0,0,0);
INSERT INTO t (a, b, c, d) VALUES (0,0,1,1);
INSERT INTO t (a, b, c, d) VALUES (0,1,2,2);
INSERT INTO t (a, b, c, d) VALUES (0,1,3,3);
INSERT INTO t (a, b, c, d) VALUES (1,1,4,4);
SELECT * FROM t;
a | b | c | d
---+---+---+---
0 | 0 | 0 | 0
0 | 0 | 1 | 1
0 | 1 | 2 | 2
0 | 1 | 3 | 3
1 | 1 | 4 | 4
(5 rows)
| 数据说明 |
|---|
行 1 和 2 在同一分区中,因为列 a 和 b 都为零。 |
行 3 和 4 在同一分区中,但分区不同,因为列 a 为零,列 b 在两行中都为 1。 |
行 5 独自在一个第三个分区中,因为列 a 和 b 都为 1。 |
https://cassandra.apache.org/doc/latest/cassandra/getting-started/index.html
Apache Cassandra can be installed on a number of Linux distributions:
Install the latest version of Java 11 or Java 17, from one of the following locations
$ tar xzvf apache-cassandra-4.0.0-bin.tar.gz
The files will be extracted to the apache-cassandra-4.0.0/ directory. This is the tarball installation location.
Located in the tarball installation location are the directories for the scripts, binaries, utilities, configuration, data and log files:
<tarball_installation>/
bin/ 1
conf/ 2
data/ 3
doc/
interface/
javadoc/
lib/
logs/ 4
pylib/
tools/ 5
https://cassandra.apache.org/doc/latest/cassandra/getting-started/configuring.html
The Cassandra configuration files location varies, depending on the type of installation:
/etc/cassandra directoryconf directory within the tarball install location/etc/cassandra directoryCassandra’s default configuration file, cassandra.yaml, is sufficient to explore a simple single-node cluster.
cassandra.yaml:Cassandra的主要配置文件,其中包含敏感设置,因此不应被不可信任的用户访问或修改。cassandra-env.sh:可以设置环境变量文件。cassandra-rackdc.properties 或 cassandra-topology.properties:设置集群的机架和数据中心信息。logback.xml:日志配置文件,包含日志级别设置。jvm-*:多个JVM配置文件,用于服务器和客户端的行为设置。commitlog_archiving.properties:设置commitlog的归档参数。cqlshrc.sample:如何配置 CQL shell 工具 cqlshConfiguring Cassandra is done by setting yaml properties in the cassandra.yaml file. At a minimum you should consider setting the following properties:
cluster_name: Set the name of your cluster.seeds: A comma separated list of the IP addresses of your cluster seed nodes.storage_port: Check that you don’t have the default port of 7000 blocked by a firewall.listen_address: The listen address is the IP address of a node that allows it to communicate with other nodes in the cluster. Set to localhost by default. Alternatively, you can set listen_interface to tell Cassandra which interface to use, and consecutively which address to use. Set one property, not both.native_transport_port: Check that you don’t have the default port of 9042 blocked by a firewall, so that clients like cqlsh can communicate with Cassandra on this port.Cassandra 的持久化数据主要涉及 SSTable 数据、Commit Log 和 Hints 三类,其存储位置均可通过 cassandra.yaml 进行配置。此外,Cassandra 还可以通过 saved_caches_directory 配置缓存文件的存储位置。
# 1. SSTable
data_file_directories:
- /var/lib/cassandra/data
# 2. CommitLog
commitlog_directory: /var/lib/cassandra/commitlog
# 3. Hints
hints_directory: /var/lib/cassandra/hints
# 4. Cache
saved_caches_directory: /var/lib/cassandra/saved_caches
| 配置 | 存储内容 | 核心作用 |
|---|---|---|
data_file_directories |
SSTable | 存储真正的数据 |
commitlog_directory |
Commit Log | 写入日志、故障恢复 |
hints_directory |
Hints | 节点不可用时的数据补偿 |
saved_caches_directory |
Cache | 保存缓存、提高性能 |
data_file_directoriesdata_file_directories 用于存储 Cassandra 真正的数据文件,主要是 SSTable。Cassandra 会按照 Keyspace 和 Table 对数据进行组织,每个 Keyspace 通常对应数据目录下的一个目录,例如 ks1、ks2。同时还会存在 system、system_schema、system_auth 等 Cassandra 内部使用的系统 Keyspace。
该配置支持指定多个目录,例如将不同目录放在不同磁盘上。这样 Cassandra 可以利用多个磁盘的存储空间和 I/O 能力,提高整体存储容量和性能。
commitlog_directorycommitlog_directory 用于存储 Commit Log(提交日志)。Cassandra 在处理写请求时,会先将写操作记录到 Commit Log,然后写入 MemTable,之后 MemTable 再 Flush 成 SSTable。Commit Log 主要用于 Cassandra 节点发生故障后的数据恢复。
如果服务器有多个磁盘,可以将 Commit Log 放在与 data_file_directories 不同的磁盘上,从而减少 Commit Log 与 SSTable 数据文件之间的 I/O 竞争。不过是否需要独立磁盘,应根据实际硬件和负载情况决定。
hints_directoryhints_directory 用于存储 Hints。在 Cassandra 集群中,如果某个负责数据副本的节点暂时不可用,其他节点可以保存针对该节点的 Hint,等目标节点恢复后,再将 Hint 中记录的数据发送给它,从而帮助恢复数据副本的一致性。
Hints 是 Cassandra 分布式数据复制机制中的一种辅助数据,并不是业务数据的最终存储位置。它与 Commit Log 不同:Commit Log 主要用于本节点故障后的写入恢复,而 Hint 主要用于其他副本节点暂时不可用时的数据补偿。
saved_caches_directorysaved_caches_directory 用于存储 Cassandra 保存到磁盘中的缓存数据。这些缓存主要用于提高 Cassandra 启动和运行过程中的性能,例如保存部分已经建立的缓存信息,避免每次启动都完全重新建立。
缓存并不是业务数据的最终存储位置,因此即使缓存文件丢失,Cassandra 仍然可以重新建立缓存,不会像删除 SSTable 那样直接导致业务数据丢失。它属于性能优化相关的存储目录。
**in short: SSTable 存数据,Commit Log 保恢复,Hints 保副本,Cache 保性能。
cassandra.yaml 找到:
authenticator: AllowAllAuthenticator
修改为:
authenticator: PasswordAuthenticator
| 配置 | 作用 |
|---|---|
PasswordAuthenticator |
强制客户端提供用户名/密码 |
CassandraAuthorizer |
控制用户能访问哪些 Keyspace、Table |
AllowAllAuthenticator |
不进行用户名密码认证 |
AllowAllAuthorizer |
不进行权限控制 |
如果是AllowAllAuthenticator: 则不需要用户名密码 直接 $ bin/cqlsh 可以裸奔登录。 |
使用默认超级用户登录
开启认证后,Cassandra 会自动创建默认超级用户 cassandra,密码也是 cassandra:
cqlsh -u cassandra -p cassandra
**修改 cassandra 用户密码
ALTER ROLE cassandra WITH PASSWORD = '新的强密码';
# ============================================================
# Cassandra 网络、端口、Listen Address 配置
# ============================================================
# ============================================================
# Listen Address
# ============================================================
#
# Cassandra 用哪个本机 IP 地址作为**节点间通信地址** 主要用于 Cassandra 节点之间的通信
# 注意这个改了, seed_provider.parameters.seeds: "192.168.1.101:7000" 也需要修改!!
#
listen_address: 192.168.1.101
# ============================================================
# RPC Address
# ============================================================
# 客户端连接 Cassandra 时使用的地址
#
#
rpc_address: 0.0.0.0
# ============================================================
# Native Transport
# ============================================================
# CQL 原生协议端口
#
# cqlsh、Java Driver、Python Driver 等客户端使用
native_transport_port: 9042
# 是否启用 Native Transport
native_transport: true
# Native Transport SSL 端口
#
# 启用客户端 SSL 后使用
native_transport_port_ssl: 9142
# ============================================================
# Storage Port
# ============================================================
# Cassandra 节点之间普通通信端口
# Gossip、数据传输等内部通信使用
storage_port: 7000
# 节点之间 SSL 加密通信
ssl_storage_port: 7001
# ============================================================
# JMX Port
# ============================================================
# nodetool 默认通过 JMX 管理 Cassandra
#
# 默认:
jmx_port: 7199
启动它会占用N个端口
| 端口 | 用途 | 通信方向 | 配置文件 |
|---|---|---|---|
| 7000 | 节点间通信(Gossip、数据流、副本同步) | 节点 ↔ 节点 | cassandra.yaml |
| 7001 | 节点间通信(SSL 加密) | 节点 ↔ 节点 | cassandra.yaml |
| 9042 | 客户端连接(CQL Native Protocol) | 客户端 → 节点 | cassandra.yaml |
| 9142 | 客户端连接(SSL 加密) | 客户端 → 节点 | cassandra.yaml |
| 7199 | JMX 监控管理(nodetool 等工具使用) | 管理工具 → 节点 | cassandra-env.sh |
只能去改它的启动脚本 /opt/apache-cassandra-5.0.9/bin/cassandra
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
export PATH="$JAVA_HOME/bin:$PATH"
bin/cassandra
./bin/nodetool stopdaemon
tail -f logs/system.log
bin/nodetool status
./bin/cqlsh 127.0.0.1 9042 -u cassandra
# 修改密码
ALTER ROLE cassandra WITH PASSWORD = 'BibYOlBIFshAWdCz';
https://cassandra.apache.org/doc/4.1/cassandra/cql/types.html
The following table gives additional informations on the native data types, and on which kind of constants each type supports:
| Type | Constants supported | Description |
|---|---|---|
ascii |
string |
ASCII character string |
bigint |
integer |
64-bit signed long |
blob |
blob |
Arbitrary bytes (no validation) |
boolean |
boolean |
Either true or false |
counter |
integer |
Counter column (64-bit signed value). See counters for details. |
date |
integer, string |
A date (with no corresponding time value). See dates below for details. |
decimal |
integer, float |
Variable-precision decimal |
double |
integer float |
64-bit IEEE-754 floating point |
duration |
duration, |
A duration with nanosecond precision. See durations below for details. |
float |
integer, float |
32-bit IEEE-754 floating point |
inet |
string |
An IP address, either IPv4 (4 bytes long) or IPv6 (16 bytes long). Note that there is no inet constant, IP address should be input as strings. |
int |
integer |
32-bit signed int |
smallint |
integer |
16-bit signed int |
text |
string |
UTF8 encoded string |
time |
integer, string |
A time (with no corresponding date value) with nanosecond precision. See times below for details. |
timestamp |
integer, string |
A timestamp (date and time) with millisecond precision. See timestamps below for details. |
timeuuid |
uuid |
Version 1 UUID, generally used as a “conflict-free” timestamp. Also see timeuuid-functions. |
tinyint |
integer |
8-bit signed int |
uuid |
uuid |
A UUID (of any version) |
varchar |
string |
UTF8 encoded string |
varint |
integer |
Arbitrary-precision integer |
A map is a (sorted) set of key-value pairs, where keys are unique and the map is sorted by its keys. You can define and insert a map with:
CREATE TABLE users (
id text PRIMARY KEY,
name text,
favs map<text, text> // A map of text keys, and text values
);
INSERT INTO users (id, name, favs)
VALUES ('jsmith', 'John Smith', { 'fruit' : 'Apple', 'band' : 'Beatles' });
// Replace the existing map entirely.
UPDATE users SET favs = { 'fruit' : 'Banana' } WHERE id = 'jsmith';
A set is a (sorted) collection of unique values. You can define and insert a map with:
CREATE TABLE images (
name text PRIMARY KEY,
owner text,
tags set<text> // A set of text values
);
INSERT INTO images (name, owner, tags)
VALUES ('cat.jpg', 'jsmith', { 'pet', 'cute' });
// Replace the existing set entirely
UPDATE images SET tags = { 'kitten', 'cat', 'lol' } WHERE name = 'cat.jpg';
A list is a (sorted) collection of non-unique values where elements are ordered by there position in the list. You can define and insert a list with:
CREATE TABLE plays (
id text PRIMARY KEY,
game text,
players int,
scores list<int> // A list of integers
)
INSERT INTO plays (id, game, players, scores)
VALUES ('123-afde', 'quake', 3, [17, 4, 2]);
// Replace the existing list entirely
UPDATE plays SET scores = [ 3, 9, 4] WHERE id = '123-afde';
Values of the
timestamptype are encoded as 64-bit signed integers representing a number of milliseconds since the standard base time known as the epoch: January 1 1970 at 00:00:00 GMT.
Timestamps can be input in CQL either using their value as an
integer, or using astringthat represents an ISO 8601 date. For instance, all of the values below are validtimestampvalues for Mar 2, 2011, at 04:05:00 AM, GMT:
1299038700000'2011-02-03 04:05+0000''2011-02-03 04:05:00+0000''2011-02-03 04:05:00.000+0000''2011-02-03T04:05+0000''2011-02-03T04:05:00+0000''2011-02-03T04:05:00.000+0000'**Date type
a date can be input either as an
integeror using a datestring. In the later case, the format should beyyyy-mm-dd(so'2011-02-03'for instance).
**Time
Values of the
timetype are encoded as 64-bit signed integers representing the number of nanoseconds since midnight.
a time can be input either as an
integeror using astringrepresenting the time. In the later case, the format should behh:mm:ss[.fffffffff](where the sub-second precision is optional and if provided, can be less than the nanosecond). So for instance, the following are valid inputs for a time:
'08:12:54''08:12:54.123''08:12:54.123456''08:12:54.123456789'https://cassandra.apache.ac.cn/doc/5.0/cassandra/developing/cql/json.html
Cassandra 2.2 在 SELECT <select-statement> 和 INSERT <insert-statement> 语句中引入了 JSON 支持。此支持不会从根本上改变 CQL API。它只是提供了一种方便的方式来处理 JSON 文档。
对于 SELECT 语句,JSON 关键字用于将每行返回为单个 JSON 编码的映射。SELECT 语句行为的其余部分保持不变。
结果映射键与普通结果集中的列名匹配。例如,类似于 SELECT JSON a, ttl(b) FROM … 的语句将生成一个具有键 "a" 和 "ttl(b)" 的映射。但是,有一个值得注意的例外:为了与 INSERT JSON 行为对称,区分大小写的列名(包含大写字母)将用双引号括起来。例如,SELECT JSON myColumn FROM … 将生成一个具有转义引号的映射键 "\"myColumn\""。
对于 INSERT 语句,新的 JSON 关键字可用于启用将 JSON 编码的映射作为单行插入。JSON 映射的格式通常应与在同一表上执行 SELECT JSON 语句返回的格式匹配。特别是,区分大小写的列名应使用双引号括起来。
下表描述了 Cassandra 在 INSERT JSON 值(和 from_json() 参数)中将接受的编码以及 Cassandra 在返回 SELECT JSON 语句(和 from_json())的数据时将使用的格式
| 类型 | 接受的格式 | 返回格式 | 说明 |
|---|---|---|---|
ascii |
字符串 | 字符串 | 使用 JSON 的 \u 字符转义 |
bigint |
整数、字符串 | 整数 | 字符串必须是有效的 64 位整数 |
blob |
字符串 | 字符串 | 字符串应为 0x 后跟偶数个十六进制数字 |
boolean |
布尔值、字符串 | boolean | 字符串必须是 "true" 或 "false" |
date |
字符串 | 字符串 | 格式为 YYYY-MM-DD 的日期,时区为 UTC |
decimal |
整数、浮点数、字符串 | 浮点数 | 可能超过客户端解码器中的 32 位或 64 位 IEEE-754 浮点数精度 |
double |
整数、浮点数、字符串 | 浮点数 | 字符串必须是有效的整数或浮点数 |
浮点数 |
整数、浮点数、字符串 | 浮点数 | 字符串必须是有效的整数或浮点数 |
inet |
字符串 | 字符串 | IPv4 或 IPv6 地址 |
int |
整数、字符串 | 整数 | 字符串必须是有效的 32 位整数 |
list |
列表、字符串 | list | 使用 JSON 的本机列表表示形式 |
map |
映射、字符串 | map | 使用 JSON 的本机映射表示形式 |
smallint |
整数、字符串 | 整数 | 字符串必须是有效的 16 位整数 |
set |
列表、字符串 | list | 使用 JSON 的本机列表表示形式 |
text |
字符串 | 字符串 | 使用 JSON 的 \u 字符转义 |
time |
字符串 | 字符串 | 格式为 HH-MM-SS[.fffffffff] 的一天中的时间 |
timestamp |
整数、字符串 | 字符串 | 时间戳。字符串常量允许输入 timestamps as dates <timestamps>。格式为 YYYY-MM-DD HH:MM:SS.SSS 的日期戳将被返回。 |
timeuuid |
字符串 | 字符串 | 类型 1 UUID。有关 UUID 格式,请参见 constant |
tinyint |
整数、字符串 | 整数 | 字符串必须是有效的 8 位整数 |
tuple |
列表、字符串 | list | 使用 JSON 的本机列表表示形式 |
UDT |
映射、字符串 | map | 使用 JSON 的本机映射表示形式,字段名称作为键 |
uuid |
字符串 | 字符串 | 有关 UUID 格式,请参见 constant |
varchar |
字符串 | 字符串 | 使用 JSON 的 \u 字符转义 |
varint |
整数、字符串 | 整数 | 可变长度;可能在客户端解码器中溢出 32 位或 64 位整数 |
from_json() 函数
from_json() 函数的使用方式类似于 INSERT JSON,但用于单个列值。它只能在 INSERT 语句的 VALUES 子句中使用,或者作为 UPDATE、DELETE 或 SELECT 语句中的列值之一使用。例如,它不能在 SELECT 语句的选择子句中使用。
to_json() 函数
to_json() 函数的使用方式类似于 SELECT JSON,但用于单个列值。它只能在 SELECT 语句的选择子句中使用。
// 修改system_auth 避免单点故障
ALTER KEYSPACE system_auth WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 3 };
// 创建带有超级权限的用户
CREATE ROLE cassandra_dba WITH SUPERUSER = true AND LOGIN = true AND PASSWORD = 'BibYOlBIFshAWdCz';
// 禁用默认账号
ALTER ROLE cassandra WITH SUPERUSER = false AND LOGIN = false;
-- 创建超级用户
CREATE USER admin
WITH PASSWORD 'Admin@123456'
SUPERUSER;
-- 创建普通用户
CREATE USER app
WITH PASSWORD 'App@123456'
NOSUPERUSER;
-- 创建只读用户
CREATE USER readonly
WITH PASSWORD 'ReadOnly@123456'
NOSUPERUSER;
-- =========================================================
-- 用户管理
-- =========================================================
-- 修改密码
ALTER USER app
WITH PASSWORD 'NewPassword@123456';
-- 设置为超级用户
ALTER USER app SUPERUSER;
-- 取消超级用户
ALTER USER app NOSUPERUSER;
-- 查看所有用户
LIST USERS;
-- 删除用户
DROP USER readonly;
-- =========================================================
-- 创建 Role
-- =========================================================
-- 创建业务 Role
CREATE ROLE app_role;
-- 创建只读 Role
CREATE ROLE readonly_role;
-- =========================================================
-- 授权
-- =========================================================
-- app_role:允许查询和修改 myapp
GRANT SELECT, MODIFY
ON KEYSPACE myapp
TO app_role;
-- readonly_role:只允许查询 myapp
GRANT SELECT
ON KEYSPACE myapp
TO readonly_role;
-- 将 Role 授予用户
GRANT app_role
TO app;
GRANT readonly_role
TO readonly;
-- =========================================================
-- Table 级别授权
-- =========================================================
-- 只允许访问指定 Table
GRANT SELECT, MODIFY
ON TABLE myapp.user
TO app;
GRANT SELECT
ON TABLE myapp.user
TO readonly;
-- =========================================================
-- 查看权限
-- =========================================================
-- 查看用户拥有的所有权限
LIST ALL PERMISSIONS OF app;
-- 查看 Role 权限
LIST ALL PERMISSIONS OF app_role;
-- 查看用户拥有的 Role
LIST ROLES OF app;
-- =========================================================
-- 撤销权限
-- =========================================================
REVOKE MODIFY
ON KEYSPACE myapp
FROM app_role;
REVOKE SELECT
ON KEYSPACE myapp
FROM readonly_role;
-- =========================================================
-- 删除 Role
-- =========================================================
DROP ROLE readonly_role;
https://cassandra.apache.ac.cn/doc/5.0/cassandra/developing/cql/index.html
-- Describe cluster 提供有关集群的信息
Describe cluster
-- 显示当前Cassandra里的所有键空间
Describe Keyspaces
-- 列出键空间的所有表
Describe tables;
--切换到 键空间 和 mysql 一样
USE system_trace;
键空间和表名应仅包含字母数字字符,不能为空,大小限制为 48 个字符(此限制主要用于避免文件名(可能包含键空间和表名)超过某些文件系统的限制)。默认情况下,键空间和表名不区分大小写(myTable 等同于 mytable),但可以使用双引号强制区分大小写("myTable" 与 mytable 不同)。
此外,表始终是键空间的一部分,表名可以通过其所属的键空间进行完全限定。如果未进行完全限定,则假定该表位于_当前_键空间中
| 指令 | 描述 |
|---|---|
| CREATE KEYSPACE | 在Cassandra中创建KeySpace |
| USE | 连接到已创建的KeySpace |
| ALTER KEYSPACE | 更改KeySpace的属性 |
| DROP KEYSPACE | 删除KeySpace |
| CREATE TABLE | 在KeySpace中创建表 |
-- =========================================================
-- 1. Keyspace
-- =========================================================
-- 创建 Keyspace
CREATE KEYSPACE myapp
WITH replication = {
'class': 'NetworkTopologyStrategy',
'datacenter1': 3
};
-- 单机测试
CREATE KEYSPACE test
WITH replication = {
'class': 'SimpleStrategy',
'replication_factor': 1
};
-- 查看 Keyspace
DESCRIBE KEYSPACE myapp;
-- 删除 Keyspace
DROP KEYSPACE myapp;
-- 修改 Keyspace 属性
ALTER KEYSPACE myapp
WITH replication = {
'class': 'NetworkTopologyStrategy',
'datacenter1': 3
};
-- =========================================================
-- Keyspace 常见属性
-- =========================================================
-- replication
-- 副本配置
--
-- class
-- SimpleStrategy
-- 单机/简单测试使用
--
-- NetworkTopologyStrategy
-- 生产环境推荐
--
-- replication_factor
-- SimpleStrategy 使用
--
-- datacenter1: 3
-- 表示 datacenter1 保存 3 个副本
--
-- durable_writes
-- 是否启用 CommitLog
--
-- 默认:true
--
-- 例如:
CREATE KEYSPACE demo
WITH replication = {
'class': 'NetworkTopologyStrategy',
'datacenter1': 3
}
AND durable_writes = true;
-- =========================================================
-- 查看 Schema
-- =========================================================
-- 查看所有 Keyspace
DESCRIBE KEYSPACES;
-- 查看当前 Keyspace
DESCRIBE KEYSPACE myapp;
-- 查看所有 Table
DESCRIBE TABLES;
-- 查看指定 Table
DESCRIBE TABLE myapp.user;
-- 查看完整 Schema
DESCRIBE SCHEMA;
| ALTER TABLE | 修改表的列属性 |
|---|---|
| DROP TABLE | 删除表 |
| TRUNCATE | 从表中删除所有数据 |
| CREATE INDEX | 在表的单个列上定义新索引 |
| DROP INDEX | 删除命名索引 |
-- =========================================================
-- 2. Table
-- =========================================================
-- 创建基本 Table
CREATE TABLE myapp.user (
id uuid PRIMARY KEY,
username text,
age int,
email text
);
create table book(
id int,
name varchar,
type varchar,
no int,
PRIMARY KEY(id)
);
-- 创建复合主键
CREATE TABLE myapp.device (
device_id text,
create_time timestamp,
name text,
status int,
PRIMARY KEY (device_id, create_time)
);
-- 创建复合 Partition Key
CREATE TABLE myapp.device_data (
device_id text,
device_type text,
create_time timestamp,
value double,
PRIMARY KEY ((device_id, device_type), create_time)
);
-- =========================================================
-- Table 常见操作
-- =========================================================
-- 查看表结构
DESCRIBE TABLE myapp.user;
-- 删除 Table
DROP TABLE myapp.user;
-- 修改 Table
ALTER TABLE myapp.user
ADD phone text;
-- 修改列类型
ALTER TABLE myapp.user
ALTER age TYPE bigint;
-- 删除列
ALTER TABLE myapp.user
DROP phone;
-- =========================================================
-- Table 常见 WITH 属性
-- =========================================================
CREATE TABLE myapp.data (
id uuid PRIMARY KEY,
value text
)
WITH comment = '业务数据表';
-- 压缩配置
CREATE TABLE myapp.data_compress (
id uuid PRIMARY KEY,
value text
)
WITH compression = {
'class': 'ZstdCompressor'
};
-- TTL 默认值
CREATE TABLE myapp.data_ttl (
id uuid PRIMARY KEY,
value text
)
WITH default_time_to_live = 86400;
-- GC Grace
CREATE TABLE myapp.data_gc (
id uuid PRIMARY KEY,
value text
)
WITH gc_grace_seconds = 864000;
-- Bloom Filter
CREATE TABLE myapp.data_bloom (
id uuid PRIMARY KEY,
value text
)
WITH bloom_filter_fp_chance = 0.01;
-- =========================================================
-- 修改 Table 属性
-- =========================================================
ALTER TABLE myapp.data
WITH comment = '修改后的描述';
ALTER TABLE myapp.data
WITH default_time_to_live = 86400;
ALTER TABLE myapp.data
WITH gc_grace_seconds = 864000;
-- =========================================================
-- 常见集合类型
-- =========================================================
CREATE TABLE myapp.collection_demo (
id uuid PRIMARY KEY,
-- List:有序、允许重复
tags list<text>,
-- Set:无序、不允许重复
roles set<text>,
-- Map:Key -> Value
attributes map<text, text>
);
-- =========================================================
-- Frozen
-- =========================================================
-- 将集合/UDT 作为一个整体存储
CREATE TABLE myapp.frozen_demo (
id uuid PRIMARY KEY,
address frozen<map<text, text>>
);
-- =========================================================
-- 静态列 Static Column
-- =========================================================
CREATE TABLE myapp.device_info (
device_id text,
create_time timestamp,
device_name text STATIC,
device_type text STATIC,
value double,
PRIMARY KEY (device_id, create_time)
);
-- =========================================================
-- PRIMARY KEY
-- =========================================================
-- Partition Key
CREATE TABLE myapp.user1 (
id text PRIMARY KEY,
name text
);
-- 等价于:
CREATE TABLE myapp.user2 (
id text,
name text,
PRIMARY KEY (id)
);
-- Partition Key + Clustering Column
CREATE TABLE myapp.user_log (
user_id text,
create_time timestamp,
message text,
PRIMARY KEY (user_id, create_time)
);
-- 多个 Partition Key
CREATE TABLE myapp.device_data2 (
device_id text,
device_type text,
create_time timestamp,
value double,
PRIMARY KEY ((device_id, device_type), create_time)
);
-- =========================================================
-- Column 添加 / 删除 / 修改
-- =========================================================
-- 添加列
ALTER TABLE myapp.user
ADD phone text;
-- 添加多个列
ALTER TABLE myapp.user
ADD address text;
ALTER TABLE myapp.user
ADD birthday date;
-- 修改列类型
ALTER TABLE myapp.user
ALTER age TYPE bigint;
-- 删除列
ALTER TABLE myapp.user
DROP phone;
Cassandra之中的索引的实现相对MySQL的索引来说就要简单粗暴很多了。Cassandra自动新创建了一张表格,同时将原始表格之中的索引字段作为新索引表的Primary Key!并且存储的值为原始数据的Primary Key
-- 创建索引
CREATE INDEX user_email_idx
ON myapp.user (email);
-- 删除索引
DROP INDEX myapp.user_email_idx;
-- =========================================================
-- Materialized View
-- =========================================================
-- 语法
create_materialized_view_statement::= CREATE MATERIALIZED VIEW [ IF NOT EXISTS ] view_name AS select_statement PRIMARY KEY '(' primary_key')' WITH table_options
-- 创建物化视图
CREATE MATERIALIZED VIEW myapp.user_by_email AS
SELECT *
FROM myapp.user
WHERE email IS NOT NULL
AND id IS NOT NULL
PRIMARY KEY (email, id);
-- 删除物化视图
DROP MATERIALIZED VIEW myapp.user_by_email;
-- =========================================================
-- User Defined Type(UDT)
-- =========================================================
-- 创建 UDT
CREATE TYPE myapp.address (
province text,
city text,
detail text
);
-- 使用 UDT
CREATE TABLE myapp.customer (
id uuid PRIMARY KEY,
name text,
address frozen<address>
);
-- 删除 UDT
DROP TYPE myapp.address;
-- =========================================================
-- Table Options 常见属性总结
-- =========================================================
-- comment
-- Table 描述
-- default_time_to_live
-- 默认 TTL,单位:秒
-- 0 表示不设置默认 TTL
-- gc_grace_seconds
-- Tombstone 保留时间
-- 与 Repair / Compaction 密切相关
-- compression
-- SSTable 压缩方式
--
-- Cassandra 5.x 常见:
-- ZstdCompressor
-- LZ4Compressor
--
-- bloom_filter_fp_chance
-- Bloom Filter 的误判概率
-- caching
-- Cache 配置
-- compaction
-- Compaction 策略
-- memtable
-- MemTable 相关配置
因为是集群, 列式 存储的原理, 所有它有一些特殊的限制
Cassandra 查询使用索引的核心要求是:Partition Key 仅支持等值查询,Clustering Key 支持范围查询但必须连续且依赖前置键,二级索引仅支持等值查询且需全节点扫描,非索引列过滤必须显式加 ALLOW FILTERING。
| 列类型 | 支持的操作符 |
|---|---|
| Partition Key(第一主键) | 仅 = 和 IN |
| Clustering Key(第二主键) | = > < >= <= |
| 索引列(二级索引) | 仅 = |
| 普通列(无索引) | 需配合 ALLOW FILTERING |
主键(Primary Key)查询规则
Cassandra 的查询必须严格遵循主键的设计顺序,主键由分区键(Partition Key)和聚簇键(Clustering Key)**组成。
(A, B, C, D),如果要在 WHERE 中使用 C,则必须同时提供 B 的条件。>, <, >=, <=)只能出现在聚簇键条件链的最后一个位置。一旦使用了范围查询,其后的聚簇键就不能再作为过滤条件。=)和 IN 查询;聚簇键支持等值查询和范围查询。=),但不支持对二级索引列进行范围查询(>, <)。ALLOW FILTERING 才能强制执行。
ALLOW FILTERING 会导致 Cassandra 扫描整个集群或分区内的数据,查询时间不再与结果集大小成正比,而是与总数据量成正比。在生产环境中应极力避免。LIKE 模糊查询。如果必须使用,需要创建 SASI(SSTable Attached Secondary Index)自定义索引。在 Cassandra 中按列分组统计性能极差,属于典型的反模式;原因在于数据按 Partition Key 分散存储且不支持跨分区聚合。
但是: 如果是指定 Partition Key + 单列聚合",单节点顺序扫描,性能是极好的
CREATE TABLE orders (
user_id INT,
created_at TIMESTAMP,
amount DECIMAL,
PRIMARY KEY (user_id, created_at)
);
其中 user_id 是 Partition Key,created_at 是 Clustering Key。
SELECT SUM(amount) FROM orders
WHERE user_id = 1001
AND created_at >= '2026-08-01'
AND created_at < '2026-08-27';
整个过程:单节点 + 分区内顺序扫描 + 无跨分区通信。
Cassandra 的数据包括在内存中的和磁盘中的数据
这些数据主要分为三种:
CommitLog:主要记录客户端提交过来的数据以及操作。这种数据被持久化到磁盘中,方便数据没有被持久化到磁盘时可以用来恢复。
Memtable:用户写的数据在内存中的形式。
SSTable:数据被持久化到磁盘,又分为 Data、Index 和 Filter 三种数据格式。
https://cassandra.apache.ac.cn/doc/5.0/cassandra/architecture/storage-engine.html
写入 = 先顺序写 CommitLog 保证可靠性,再写 Memtable 保证速度;Memtable 满了刷成只读 SSTable;后台 Compaction
负责真正删除数据、合并文件、并生成 MerkleTree 供节点间数据修复。整个链路没有任何随机磁盘写,这是 Cassandra
高写入性能的根源。
SSTable 的本质
SSTable(Sorted String Table)是 Memtable flush 到磁盘后形成的不可变(Immutable)**文件,数据按 partition key
排序存储。"只读"意味着:
SSTable 的文件组成
一个 SSTable 在磁盘上不是单个文件,而是一组同前缀的文件:
| 文件 | 作用 |
|---|---|
| Data.db | 真正的数据文件,按 key 排序存储各行数据 |
| Index.db | 分区索引,记录 partition key 到 Data.db 中偏移量的映射 |
| Filter.db | Bloom Filter 的持久化文件,判断 key 是否"可能存在"于本 SSTable |
| Summary.db | 索引的抽样(索引的索引),常驻内存,加速在 Index.db 中的定位 |
| Statistics.db | 统计信息:时间戳范围、墓碑数量、行数等,供 compaction 和读优化使用 |
| CompressionInfo.db | 压缩块的偏移量元数据(数据文件默认分块压缩) |
| TOC.txt | 记录本 SSTable 包含哪些组件文件 |
| Digest.crc32 | 数据文件的校验和,用于检测损坏 |
读取一个 key 时 SSTable 内部的查找路径
https://cassandra.apache.ac.cn/doc/5.0/cassandra/managing/operating/compaction/tombstones.html
Cassandra 将删除视为插入,并插入一个带时间戳的删除标记,称为墓碑。墓碑会经过 Cassandra 的写入路径,并写入一个或多个节点上的 SSTable。墓碑的主要特征区别在于它具有内置的过期日期/时间。在过期时间段(宽限期)结束时,墓碑将在 Cassandra 的正常压缩过程中被删除。
墓碑必须保留一段时间(gc_grace_seconds,默认 10 天)才能在 compaction中真正清除,目的是留出时间让宕机恢复的副本节点同步到这个删除,否则已删数据会"复活"。
在多节点集群中,Cassandra 可能会在两个或多个节点上存储相同数据的副本。这有助于防止数据丢失,但也使删除过程变得复杂。如果一个节点收到对其本地存储数据的删除命令,该节点会将指定对象标记为墓碑,并尝试将墓碑传递给包含该对象副本的其他节点。但如果其中一个副本节点此时无响应,它不会立即收到墓碑,因此它仍然包含该对象的删除前版本。如果在该节点恢复之前,墓碑对象已从集群的其余部分删除,Cassandra 会将恢复节点上的对象视为新数据,并将其传播到集群的其余部分。这种已删除但仍然存在的对象称为 僵尸。
为了防止僵尸重新出现,Cassandra 为每个墓碑设置了一个宽限期。墓碑的宽限期由表属性 WITH gc_grace_seconds 设置。其默认值为 864000 秒(十天),之后墓碑会过期,并在压缩期间被删除。在宽限期结束之前,Cassandra 会通过压缩事件保留墓碑。每个表都可以为此属性设置自己的值。
Compaction 策略
| 策略 | 适用场景 | 思路 |
|---|---|---|
| STCS(Size Tiered) | 写多读少,默认策略 | 把大小相近的 SSTable 分组合并,写放大小但空间放大和读放大较大 |
| LCS(Leveled) | 读多写少、读延迟敏感 | 按层级组织,每层内 SSTable 的 key 范围互不重叠,一个 key 每层最多查一个文件,读放大小但写放大大 |
| TWCS(Time Window) | 时序数据、带 TTL 的数据 | 按时间窗口分组合并,整窗过期后可直接整文件删除 |
https://cassandra.apache.ac.cn/doc/5.0/cassandra/architecture/dynamo.html
Cassandra 使用一种称为 一致性哈希 的特殊形式的哈希,将数据分区到存储节点上。在简单的哈希中,通常通过对键进行哈希并对桶的数量取模来将键分配到桶中。例如,如果您想使用简单的哈希将数据分布到 100 个节点,您可能会将每个节点分配到 0 到 100 之间的桶中,对输入键进行哈希并对 100 取模,并将数据存储在关联的桶中。但是,在这种简单的方案中,添加单个节点可能会使几乎所有映射失效。
Cassandra 而是将每个节点映射到令牌环上的一个或多个令牌,并通过对键进行哈希并沿着环“行走”来定义所有权,类似于 Chord 算法。一致性哈希与简单哈希的主要区别在于,当要哈希到的节点(桶)数量发生变化时,一致性哈希只需要移动一小部分键。
例如,如果我们有一个八节点集群,令牌均匀分布,复制因子 (RF) 为 3,那么要找到某个键的所有者节点,我们首先对该键进行哈希以生成令牌(这只是键的哈希值),然后我们沿着环顺时针“行走”,直到遇到三个不同的节点,此时我们找到了该键的所有副本。这个八节点集群的示例,gRF=3,可以可视化为如下

您可以看到,在类似 Dynamo 的系统中,键的范围,也称为 令牌范围,映射到相同的物理节点集。在这个示例中,所有落在令牌范围内的键,不包括令牌 1,包括令牌 2 (grange(t1, t2]),都存储在节点 2、3 和 4 上。
普通取模哈希(hash(key) % N)的问题:节点数 N 一变,几乎所有 key 的归属都要重算,扩缩容时会引发全量数据迁移。一致性哈希把哈希空间组织成一个首尾相接的环,节点增减只影响环上相邻的一小段数据,迁移量从"全部"降为"约 1/N"。
-2^63 ~ 2^63-1。**in short : 环 = 表盘;token = 表盘上的刻度;Token Range = 相邻刻度之间的扇区
假设 4 个节点均分环(简化为 0~100 的哈希空间):
| 节点 | Token | 负责范围 |
|---|---|---|
| A | 25 | (0, 25] |
| B | 50 | (25, 50] |
| C | 75 | (50, 75] |
| D | 100 | (75, 100] 及 (100, 0] 回绕段 |
某 key 哈希后 token = 62,落在 (50, 75],由节点 C 负责;若副本因子为 3,则副本继续放在顺时针的 D 和 A 上。
flowchart LR subgraph before[加入前] B1[B: 负责 25~50] end subgraph after[新节点 E 加入 token=40] E1[E: 接管 25~40] B2[B: 只剩 40~50] end before --> after
只给每个物理节点一个 token 有两个问题:数据分布不均匀;新节点加入时只有一个邻居为它传数据,压力集中。
Cassandra 的解决方案是虚拟节点:每个物理节点在环上持有多个 token(num_tokens,新版本默认 16,早期默认 256),即把环切成大量小段,随机散布到各物理节点。
| 对比项 | 单 Token | Vnodes |
|---|---|---|
| 数据均匀性 | 依赖人工精心分配 token | 大量随机小段,天然趋于均匀 |
| 扩容数据来源 | 仅相邻一个节点 | 从集群中多个节点并行流入,更快 |
| 节点故障恢复 | 由少数邻居承担重建 | 重建压力分摊到全集群 |
| 异构机器 | 难以支持 | 性能强的机器可配更多 vnode 多担数据 |
token 只决定第一副本的位置,其余副本由副本策略决定:
| 策略 | 放置规则 | 适用 |
|---|---|---|
| SimpleStrategy | 从第一副本开始,沿环顺时针依次放在后续节点上,不感知机架和数据中心 | 单数据中心、测试环境 |
| NetworkTopologyStrategy | 可为每个数据中心单独指定副本数;同一数据中心内尽量将副本放在不同机架上 | 生产环境标准选择 |
Cassandra 用一致性哈希把数据按 partition key 的 token 映射到首尾相接的环上,节点各自认领环上的区段;vnodes 让分布更均匀、扩缩容更平滑;副本沿环顺时针并结合机架/数据中心拓扑放置。任何节点都能据此直接算出数据位置,无需中心节点,这是其线性扩展能力的核心。
生成环境建议 - https://cassandra.apache.ac.cn/doc/5.0/cassandra/getting-started/production.html#tokens
Nodetool工具 - https://cassandra.apache.ac.cn/doc/5.0/cassandra/managing/tools/nodetool/nodetool.html
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。