简单介绍

​ Cassandra是一个高可靠的大规模分布式存储系统。高度可伸缩的、一致的、分布式的结构化key-value存储方案,集Google BigTable的数据模型与Amazon Dynamo的完全分布式的架构于一身。Cassandra使用了Google BigTable的数据模型,与面向行的传统的关系型数据库不同,这是一种面向列的数据库,列被组织成为列族(Column Family),在数据库中增加一列非常方便。Cassandra的系统架构与Dynamo一脉相承,是基于O(1)DHT(分布式哈希表)的完全P2P架构,与传统的基于Sharding的数据库集群相比,Cassandra可以无缝地加入或删除节点,非常适于对于节点规模变化比较快的应用场景。
​ Cassandra的数据会写入多个节点,来保证数据的可靠性,在一致性、可用性和网络分区耐受能力(CAP)的折衷问题上,Cassandra比较灵活,用户在读取时可以指定要求所有副本一致(高一致性)、读到一个副本即可(高可用性)或是通过选举来确认多数副本一致即可(折衷)。这样,Cassandra可以适用于有节点、网络失效,以及多数据中心的场景。Cassandra是一套开源分布式NoSQL数据库系统,设计思想采用了google的BigTable的数据模型和Amazon的Dynamo的完全分布式架构,因而它具有很好的扩展性且不存在单点故障。

数据模型

​ Cassandra将数据存储在表中,每个表由行和列组成。CQL用户查询存储在表中的数据。Cassandra数据模型基于查询针对查询进行了优化。Cassandra不支持用户关系数据库的关系数据建模。

### 查询驱动建模

​ 数据建模是识别实体及其关系的过程。

​ 在关系型数据库中,数据被放置在规范化表中,外检用于引用其他表中的相关数据。应用程序进行的查询由表的结构驱动,相关数据作为表连接进行查询。

​ 在cassandra中,数据建模是查询驱动的,数据访问模式和应用程序查询决定了数据的结构和组织,然后用于设计数据库表。数据围绕特定查询建模,查询最好设计为访问单个表,这意味着查询中设计的所有实体必须在同一个表中,才能非常快速的访问数据,数据被建模以最合适一个查询或一组查询,一张表以有一个或多个最适合查询的实体。由于实体之间通常确实存在关系,并且查询可能涉及实体之间存在关系,因此单个实体可能包含在多个表中。

目标

​ 主键和分区键的选择对于在集群中均匀分布数据很重要,将查询读取的分区数量保持在最低水平也很重要,因为不同的分区可能位于不同的节点上,并且协调器需要向每个节点发送请求,这会增加请求开销和延迟,即使查询中涉及的不同分区在同一个节点上,更少的分区也能提高查询效率。

分区

​ Cassandra 是一个分布式数据库,用于跨节点集群存储数据。分区键用于在节点之间对数据进行分区,Cassandra使用一致性散列的变体来对存储节点上的数据进行分区以进行数据分发。散列是一种用于映射给定键的数据的技术,散列函数生成存储在散列表中的散列值。分区键是从主键的第一个字段生成的。使用分区键将数据分区到哈希表中以实现快速查找。用于查询的分区越少,查询的响应时间就越快。

作为划分的一个例子,考虑表t中id是在主键的唯一字段。

CREATE TABLE t (id int,k int,v text,PRIMARY KEY (id)
);

分区键是从主键生成的,id用于跨集群中的节点分发数据。

考虑一个表的变体,t它具有构成主键的两个字段以构成复合或复合主键。

CREATE TABLE t (id int,c text,k int,v text,PRIMARY KEY (id,c)
);

对于t具有复合主键的表,第一个字段id用于生成分区键,第二个字段c是用于在分区内排序的集群键。使用聚类键对数据进行排序可以更有效地检索相邻数据。

通常,主键的第一个字段或其它主键被散列以生成分区键,其余字段或其它主键是用于对分区内的数据进行排序的集群建。对数据进行分区,提高了读写效率。其它非主键字段可能会被单独索引以进一步提高查询性能。

如果将多个字段分组为主键的第一个主键,则可以从多个字段生成分区键,作为table的另一个变体t,请考虑一个表,其中主键的第一个主键由使用括号分组的两个字段组成。

CREATE TABLE t (id1 int,id2 int,c1 text,c2 textk int,v text,PRIMARY KEY ((id1,id2),c1,c2)
);

对于前面的表 t 构成的主键的第一个主键字段id1和id2用于生成分区键和其余字段c1和c2是用于在分区内排序聚类主键。

与关系型数据库比较

​ 关系型数据库将数据存储在使用外键和其他表有关系的表中,关系型数据库的数据建模方法是以表为中心的。查询必须使用表连接从多个表中获取数据,这些表之间存在关系。Cassandra没有外键或关系完整性的概念。Cassandra的数据模型是基于设计高效查询;不涉及多个表的查询,关系数据库规范化数据以避免重复。相比之下,Cassandra通过以查询为中心的数据模型在多个表中复制数据来反规范化数据。如果Cassandra数据模型不能完全集成特定查询的不同实体之间关系的复杂性,则可以使用应用程序代码中处理。

数据建模示例

例如,一个magazine 数据集由具有杂志 ID 、杂志名称、出版频率、出版日期和出版商等属性的杂志数据组成。杂志数据的基本查询 (Q1) 是列出所有杂志名称,包括其出版频率。由于并非Q1需要所有数据属性,因此数据模型仅包含id(用于分区键)、杂志名称和出版频率,如下所示

另一个查询(Q2) 是按照出版商列出所有杂志名称。对于Q2,数据模型将由publisher 分区键的附件属性组成。该id会成为一个分区内排序聚集键。如下所示

Schema 设计

在创建数据模型之后,可为查询设计schema,Q1 schema 设计如下

CREATE TABLE magazine_name (id int PRIMARY KEY, name text, publicationFrequency text)

对于Q2,schema定义包含用于排序的聚类键

CREATE TABLE magazine_publisher (publisher text,id int,name text, publicationFrequency text,
PRIMARY KEY (publisher, id)) WITH CLUSTERING ORDER BY (id DESC)

CQL(Cassandra Query Language)

CQL提供一套类似sql的查询驱动

数据类型

Data type

ddl

Data Definition

数据操作

SELECT

select_statement ::=  SELECT [ JSON | DISTINCT ] ( select_clause | '*' )FROM table_name[ WHERE where_clause ][ GROUP BY group_by_clause ][ ORDER BY ordering_clause ][ PER PARTITION LIMIT (integer | bind_marker) ][ LIMIT (integer | bind_marker) ][ ALLOW FILTERING ]
select_clause    ::=  selector [ AS identifier ] ( ',' selector [ AS identifier ] )
selector         ::=  column_name| term| CAST '(' selector AS cql_type ')'| function_name '(' [ selector ( ',' selector )* ] ')'| COUNT '(' '*' ')'
where_clause     ::=  relation ( AND relation )*
relation         ::=  column_name operator term'(' column_name ( ',' column_name )* ')' operator tuple_literalTOKEN '(' column_name ( ',' column_name )* ')' operator term
operator         ::=  '=' | '<' | '>' | '<=' | '>=' | '!=' | IN | CONTAINS | CONTAINS KEY
group_by_clause  ::=  column_name ( ',' column_name )*
ordering_clause  ::=  column_name [ ASC | DESC ] ( ',' column_name [ ASC | DESC ] )*

例:

SELECT name, occupation FROM users WHERE userid IN (199, 200, 207);
SELECT JSON name, occupation FROM users WHERE userid = 199;
SELECT name AS user_name, occupation AS user_occupation FROM users;SELECT time, value
FROM events
WHERE event_type = 'myEvent'AND time > '2011-02-03'AND time <= '2012-01-01'SELECT COUNT (*) AS user_count FROM users;
  1. select_clause :定义返回的列,可由selectors 定义或者是 * 通配符返回所有的列

  2. selector (选择器) :

    • 表的列名
    • 强制转换,允许将嵌套选择器转换为(兼容)类型
    • 一个函数调用,其中参数是选择器本身
    • COUNT(*)对COUNT 函数的特殊调用,它计算所有非空结果
  3. where_clause

    1. where条件的列必须是primary key 或者是定义了二级索引的字段

      注意:查询是不是所有的满足上述条件的都支持。例如:

      CREATE TABLE posts (userid text,blog_title text,posted_at timestamp,entry_title text,content text,category int,PRIMARY KEY (userid, blog_title, posted_at)
      )
      

      上面userid是分区主键,blog_title和posted_at是聚类主键

      下面的查询是允许的 where 后面id是按照顺序来的:

      SELECT entry_title, content FROM postsWHERE userid = 'john doe'AND blog_title='John''s Blog'AND posted_at >= '2012-01-01' AND posted_at < '2012-01-31'
      

      但是下面的sql不允许,因为它没有选择一组连续的行 (假设blog_title没有创建二级索引)

      // Needs a blog_title to be set to select ranges of posted_at
      SELECT entry_title, content FROM postsWHERE userid = 'john doe'AND posted_at >= '2012-01-01' AND posted_at < '2012-01-31'
      
  4. Group_by_clause

    group by 字段只能是partition key 或者聚类主键

  5. Allowing filtering

    默认情况下,我们所有的查询条件都是主键,也是no filtering的;当非主键使用allow filtering查询时,查询结果和性能是不可预测的,请谨慎使用!

    例如:如下birth_year字段带有二级索引

    CREATE TABLE users (username text PRIMARY KEY,firstname text,lastname text,birth_year int,country text
    )CREATE INDEX ON users(birth_year);
    

    那么如下查询是有效的:

    SELECT * FROM users;
    SELECT * FROM users WHERE birth_year = 1981;
    

    这两个查询语句,Cassandra都保证性能和返回的数据量成正比。

    但是,如下查询将被拒绝

    SELECT * FROM users WHERE birth_year = 1981 AND country = 'FR';
    

    因为Cassandra不能保证即使这些查询的结果很小也不会扫描大量数据。通常,它会扫描birth_year=1981所有索引条目,即使实际上只有少数country=‘FR’。但是如果你知道“know what you are doing”,可以强制使用 ALLOW FILTERING ,以下语句是合法的

    SELECT * FROM users WHERE birth_year = 1981 AND country = 'FR' ALLOW FILTERING;
    
  6. 总结

    查询条件尽量使用主键(分区主键和者聚类主键),表设计时充分考虑查询需求;少用二级索引(测试过数据量千万级,二级索引效率明显降低,查询慢);不用 ALLOW FILTERING

INSERT

insert_statement ::= INSERT INTO table_name( names_values| json_clause) [ IF NOT EXISTS ] [ USING update_parameter( AND update_parameter)* ]names_values     ::=   namesVALUES json_clause      ::= JSON [ DEFAULT ( NULL | UNSET ) ]names            ::= '(' ( ',' )* ')'
tuple_literal
stringcolumn_namecolumn_name

例如:

INSERT INTO NerdMovies (movie, director, main_actor, year)VALUES ('Serenity', 'Joss Whedon', 'Nathan Fillion', 2005)USING TTL 86400;INSERT INTO NerdMovies JSON '{"movie": "Serenity","director": "Joss Whedon","year": 2005}';

总结:与 SQL 不同,INSERT默认情况下不检查该行的先前存在:如果之前不存在该行,则创建该行,否则更新该行

UPDATE

update_statement ::= UPDATE table_name[ USING update_parameter( AND update_parameter)* ] SET assignment( ',' assignment)* WHERE where_clause[ IF ( EXISTS | condition( AND condition)*) ]update_parameter ::= ( TIMESTAMP | TTL ) ( integer| bind_marker)assignment       ::=   simple_selection'=' term| column_name'=' column_name( '+' | '-' ) term| column_name'=' list_literal'+' simple_selection ::=   | '[' ']' | '.' `字段名称
column_name
column_namecolumn_nametermcolumn_name条件       ::=  simple_selection operator term

例如

UPDATE NerdMovies USING TTL 400SET director   = 'Joss Whedon',main_actor = 'Nathan Fillion',year       = 2005WHERE movie = 'Serenity';UPDATE UserActionsSET total = total + 2WHERE user = B70DE1D0-9908-4AE3-BE34-5573E5B09F14AND action = 'click';

总结:更新条件字段必须是primary key;UPDATE默认情况下不检查该行的先前存在(除了使用IF):如果之前不存在该行,则创建该行,否则进行更新。此外,无法知道是否发生了创建或更新。

DELETE 和 Tombstone

delete_statement ::=  DELETE [ simple_selection ( ',' simple_selection ) ]FROM table_name[ USING update_parameter ( AND update_parameter )* ]WHERE where_clause[ IF ( EXISTS | condition ( AND condition )*) ]

例如:

DELETE FROM NerdMovies USING TIMESTAMP 1240003134WHERE movie = 'Serenity';DELETE phone FROM UsersWHERE userid IN (C73DE1D3-AF08-40F3-B124-3FF3E5109F22, B70DE1D0-9908-4AE3-BE34-5573E5B09F14);

tombstone(墓碑问题):

​ cassandra是分布式的,数据删除相比较关系型数据库要复杂的多;当删除一条数据时,会被写入一个被称作墓碑(tombstone)的标记,用于记录一个删除操作,表示之前的值被删除了;等到执行合并(compact,gc_grace_seconds默认864000秒,即10天)时,就利用这些墓碑数据删除SSTable中对应的数据。

问题点:Cassandra会将同一份数据存放到多个副本不同的节点上,如果某个节点A收到了删除指令,删除了本地的记录,并尝试将删除逻辑传递给包含该记录副本的其他节点B,如果对应节点B并没有进行相应,即该节点无法将数据立即删除,且该节点上仍然拥有删除前的数据。如果在节点B重新恢复到集群中之前,其他节点上的该数据已经被清除,则节点B上的该数据会被认为是新的记录,进行同步。就会导致删除操作并不能生效,这种记录被称为僵尸(zombie)。

总结

  • 删除可以是一行,也可以是某一列
  • 尽量使用id删除
  • 避免大量数据删除,可通过删表重建的方式

BATCH

batch_statement        ::= BEGIN [未记录| COUNTER ] BATCH [ USING update_parameter( AND update_parameter)* ]modification_statement( ';' modification_statement)* APPLY BATCH modify_statement ::=   | |
insert_statementupdate_statementdelete_statement

例如:

BEGIN BATCHINSERT INTO users (userid, password, name) VALUES ('user2', 'ch@ngem3b', 'second user');UPDATE users SET password = 'ps22dhds' WHERE userid = 'user3';INSERT INTO users (userid, password) VALUES ('user4', 'ch@ngem3c');DELETE name FROM users WHERE userid = 'user1';
APPLY BATCH;

总结:

  • 在批处理多个更新时,它可以节省客户端和服务器之间(有时是服务器协调器和副本之间)的网络往返
  • BATCH语句只能包含UPDATE,INSERT和DELETE语句
  • 默认情况下,批处理中的所有操作都按记录执行,以确保所有更改最终完成(或不会完成)

Cassandra Tools

cassandra提供了很多工具,比如CQL shell、Nodetool、SSTable Tools,这里简单介绍下使用Nodetool备份还原数据,其它工具可参考官网介绍

Nodetool 备份还原数据

Cassandra Tools

备份:./bin/nodetool snapshot -t 备份文件夹名 备份的keyspacecassandra数据存储目录查看cassandra.ymal文件的hints_directory配置
scylladb数据存储目录查看scylla.ymal文件的hints_directory配置备份完成后数据会存在数据目录
bak_dir(../data/keyspacename/tablename-uuid/snapshots/备份文件夹名/时间戳-tablename/)还原
将备份的表数据bak_dir里文件直接拷贝至目标table目录下
../data/keyspacename/tablename-uuid/执行./bin/nodetool refresh -- keyspacename tablename

java集成

java集成有很多方式,可以直接使用cassandra提供的驱动,也可以使用spring-data-cassandra,下面介绍下使用spring-data-cassandra方式集成

引入依赖(maven方式)

        <dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-cassandra</artifactId></dependency><dependency><groupId>com.datastax.cassandra</groupId><artifactId>cassandra-driver-core</artifactId><version>3.9.0</version></dependency>

配置

在spring配置文件中添加一下配置

spring.data.cassandra.contact-points=10.192.77.203
spring.data.cassandra.port=9042
spring.data.cassandra.cluster-name=Test Cluster

使用(查询和删除)

下面使用的CassandraTemplate实现查询和删除

@Repository
@Slf4j
public class Demo {@Autowiredprivate CassandraTemplate cassandraTemplate;/*** 查询* @return*/public List<Map> select(){String sql = "select * from demo where id = '1794871'";List<Map> maps = cassandraTemplate.select(sql, Map.class);if(CollectionUtils.isEmpty(maps)){return null;}return maps;}/*** 删除* @return*/public boolean delete(){String sql = "DELETE FROM demo WHERE id='127198' ";boolean execute = cassandraTemplate.getCqlOperations().execute(sql);return execute;}
}

CassandraTemplate类包含较全的CQL相关方法,基本能满足使用,如果没有想要的方法,可以使用cassandraTemplate.getCqlOperations().execute 执行自定义cql。

参考资料

cassandra官方文档

Cassandra使用总结相关推荐

  1. Cassandra 1.2 发布,NoSQL 数据库

    NoSQL 数据库 Cassandra 发布 1.2 正式版,该版本包含 CQL3,这是在 2012年4月发布的 1.1 版本中引入的.CQL 是一个 Cassandra 的建模和查询语言,类似关系数 ...

  2. Cassandra安装测试

     说明,本人成功安装过程记录   只要看解压目录的readme.txt即可,其他网上教程由于版本不对会执行报错,例如遇到编码问题 #wget  http://www.apache.org/dyn/cl ...

  3. cassandra命令

    压力测试:cassandra-stress [command] -node [nodes] -mode thrift user=[user] password=[password] example: ...

  4. 在eclipse中通过基于spring data的easyrest风格的maven项目操纵cassandra和lucene

    一.项目前提步骤 1>.创建键空间 CREATE KEYSPACE mykeyspace WITH REPLICATION = { 'class' : 'SimpleStrategy', 're ...

  5. Cassandra数据模型设计最佳实践

    2019独角兽企业重金招聘Python工程师标准>>> 本文是Cassandra数据模型设计第一篇(全两篇),该系列文章包含了eBay使用Cassandra数据模型设计的一些实践.其 ...

  6. Cassandra 可视化工具

    2019独角兽企业重金招聘Python工程师标准>>> 最近开始接触Cassandra,这些天在cassandra的wiki发现了一些可视化工具的推荐.现在也把这个链接推荐给大家:h ...

  7. Cassandra读写性能测试

    1. 测试目的 测试Cassandra集群读写TPS的极值,确定Cassandra读写性能. 2. 测试环境 2.1 硬件信息 CPU 8核 Intel(R) Xeon(R) CPU E5-2650 ...

  8. 读过本文才算真正了解Cassandra数据库

    来自:DBAplus社群 作者介绍 宇文湛泉,现任金融行业核心业务系统DBA,主要涉及Oracle.DB2.Cassandra等数据库开发工作. Cassandra数据库,值得介绍的技术细节其实挺多的 ...

  9. 利用Kafka和Cassandra构建实时异常检测实验

    导言 异常检测是一种跨行业的方法,用于发现事件流中的异常事件 - 它适用于物联网传感器,财务欺诈检测,安全性,威胁检测,数字广告欺诈以及许多其他应用程序.此类系统检查流数据以检查异常或不规则,并在检测 ...

  10. cassandra mysql_cassandra命令行操作

    查看cqlsh命令帮助 root@sitewhere-cassandra-0:/# cqlsh --help Usage: cqlsh.py [options] [host [port]] CQL S ...

最新文章

  1. 解析腾讯行政区划API接口数据
  2. IE兼容问题IE6,IE7,IE8,IE9,IE10
  3. MongoDB实战(4)MapReduce
  4. C语言十六进制数转八进制(十进制作为中介)(附完整源码)
  5. 支持回调处理 php函数,PHP支持回调的函数有哪些?
  6. 计算机并行处理专业,分布式计算机并行处理技术(论文).doc
  7. 吴恩达机器学习【第六天】神经网络模型
  8. HDFS写入HBase
  9. ProcessOn画图
  10. CH579 以太网转串口 串口服务器代码!需要自己编程提升能力的非常值得参考的代码
  11. 【恩智浦杯(飞思卡尔)全国大学生智能汽车竞赛】解读部分北科技术报告图像处理内容(点到为止)
  12. c 抓取百度页面html,搜索引擎百度蜘蛛详解,百度蜘蛛IP分析
  13. python 贝塞尔曲线对图像进行扭曲_Python3 OpenCV3图像处理-图像扭曲
  14. 单幅图像去雾java_一种基于深度学习的单幅图像去雾方法与流程
  15. 俞敏洪致青春三“想”:理想、梦想和思想(转载)
  16. OpenCV定位二维码的三个定位点
  17. [嵌入式框架][nrf51822][SDK12.3] BLE分层设计 NUS 透传数据队列发送,提升带宽利用率
  18. html5 swf在线播放,html5怎样播放swf格式的视频
  19. 职中计算机一级证,职中计算机等级一级考证教学网站的设计
  20. 学术届职称与凡人修仙传等级对应关系

热门文章

  1. 国家开放大学 计算机网络形式测试二
  2. NE555芯片常用产生的频率计算方法
  3. ForeSpider数据采集系统
  4. IFS Applications权限架构
  5. Project 2010 概述
  6. MySQL 数据库平滑扩容的6 种方案剖析
  7. linux centos设置定时重启,Linux CentOS使用crontab设置定时重启的方法
  8. PHP获取当前文件的绝对路径
  9. 十大在线网上冲印站点介绍
  10. IP数据报的分片和组装过程