search
HomeDatabaseMysql Tutorial[Practical Cassandra]CH2

当为开始为你的keyspace创建数据模型的时候,首要事情就是忘记你知道的关于关系型数据建模的一切。关系型数据模型是被设计为用来高效存储,关系型查找,以及联系起关注点的。而Cassandra是被设计作为高性能和存储海量数据的。 与关系型数据库不同的是,Cassa


  当为开始为你的keyspace创建数据模型的时候,首要事情就是忘记你知道的关于关系型数据建模的一切。关系型数据模型是被设计为用来高效存储,关系型查找,以及联系起关注点的。而Cassandra是被设计作为高性能和存储海量数据的。

  与关系型数据库不同的是,Cassandra环境下的数据模型是建立在应用要求的查询模式上的。这意味着你在数据建模之前必须了解应用的读/写模式。这一点对于索引同样适用,Cassandra中建立索引是基于特定类型的查询要求的,而不像关系型数据库中那样作为性能优化功能的。

  本章中,我们会指出创建关系型数据建模方式与Cassandra数据建模方式的关键不同。我们将用一个存储时间序列数据的例子来进行讲解。

Cassandra数据模型

  为了了解如何在Cassandra环境下对应用建模,你需要先明白Cassandra数据模型是如何工作的。Cassandra的数据分布方式来源于Amazon的Dynamo,而其数据表示则来源于Google的BigTable。

  当使用CQL建表时,你不仅要告诉Cassandra你的数据的名称和类型,还要告知如何存储和分布你的数据。这是通过PRIMARY KEY操作符实现的。PRIMARY KEY告诉Cassandra存储系统基于这个键来分布数据,这通常被称作partition key。当PRIMARY KEY包含多个字段时(类似组合键),第一个字段作为partition key(决定数据如何分布),其余字段作为聚集键(clustering key,决定数据如何存储在磁盘)。聚集键允许你预先通过key中的字段group你的数据。使用组合键的行在Cassandra中称宽行(wide rows),但这里的宽行说的是Cassandra存储在磁盘上的行,而不是你查询是展示给你的行。



Listing3.1 示例使用单一字段PRIMARY KEY时数据如何存储

————————————————————————————————————— 

CREATE TABLE animals (

 name TEXT PRIMARY KEY,

 species TEXT,

 subspecies TEXT,

 genus TEXT,

 family TEXT

);

SELECT * FROM animals;

  name |family | genus | species | subspecies

_ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ _  __ _ _ __ _ _ 

dog | Canidae | Canis | C. lupus | C. l. familiaris

cat | Felidae | Felis | F. catus | null

duck | Anatidae | Anas | A. platyrhynchos | null

wolf | Canidae | Canis | C. lupus | null

_ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ _



Listing 3.2 示例当使用组合键时数据如何存储

————————————————————————————————————— 

CREATE TABLE animals (

 name TEXT,

 species TEXT,

 subspecies TEXT,

 genus TEXT,

 family TEXT,

 PRIMARY KEY(family, genus)

);

SELECT * FROM animals;

  name | family | genus | species | subspecies

_ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ _

dog | Canidae | Canis | C. lupus | C. l. familiaris

wolf | Canidae | Canis | C. lupus | null

cat | Felidae | Felis | F. catus | null

duck | Anatidae | Anas | A. platyrhynchos | null

————————————————————————————————————— 

从图3.2可以看出,当使用组合键时,wolf和dog的数据存储在相同的服务器上。这是因为我们设置了利用“family”字段partition和用“genus”字段聚集。这意味着相同family的数据会存储在相同副本集合,并通过genus排序或聚集。 这样使得可以通过已知的family和genus值快速查找数据。


模型查询———并非数据查询

使用Cassandra,当创建数据模型时首先要考虑的是查询的性能。在Cassandra中,行不会被切分到多个接点。也就是说如果一行存在于某个节点上,那整行都会存于节点。如果你对某个key频繁读写,就产生了热点。热点在频繁查询某key(row)导致服务器Spike时产生。某个机器上的高负载会导致集群范围的混乱,因为信道会back up。行的大小也要引起注意,一行应该在磁盘存储能力内,如果一行有数十亿列,那或许会超过所在节点可用磁盘空间的大小。

  列表3.3中,我们可以看到关系型数据库存储event logs的典型方式。自增的ID字段,event时间,事件类型对应的ID,以及一些该事件的信息。尽管你可以在Cassandra中模拟这个模型,但这并不是一种高效的做法,因为它需要两次查询(一次查这一事件行,一次通过事件类型ID查事件类型),因为Cassandra不支持join操作。

Listing 3.3 示例关系型数据模型作Log存储

————————————————————————————————————— 

CREATE TABLE events (

 id INT PRIMARY KEY,

 time TIME,

 event_type INT references event_types(id),

 data text

);

SELECT * FROM events;

  id | time | event_type | data

_ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ _  __ _ _ __ _ _ 

1 | 16:41:33.90814 | 4 | some event data

2 | 16:59:48.9131 | 2 | some event data

3 | 17:12:12.12758 | 4 | some event data

4 | 17:32:17.83765 | 1 | some event data

5 | 17:48:57.10934 | 0 | some event data

————————————————————————————————————— 

为了解决没有join操作的问题,我们只要每次都将event_type的值存在一列中即可。这样反范式化数据对Cassandra来说显然不frowned upon。Cassandra中的数据建模应该遵循“磁盘空间很廉价,所以复制数据(甚至多次)也不是问题”这个看法。事实上,范式化数据对于Cassandra来说反而是反模式的。Cassandra模型可能很相似,但是几点关键的不同导致了性能和可用性上的巨大差别。

  列表3.4展示了上述关系型版本的Cassandra复制版,但存储的是时间类型本身而不是其ID。值得注意的是这个模型的每行存储一个单一事件,这导致了查询某个时间或某个事件类型的事件数据变得困难。你需要知道事件对应的ID来获取事件的数据,但不需要遍历查找整个列族(ColumnFamily)。

Listing 3.4 示例Cassandra作Log存储的数据模型(复制RDBMS的)

————————————————————————————————————— 

CREATE TABLE events (

 id UUID PRIMARY KEY,

 time TIMESTAMP, 

 event_type TEXT,

 data text

);

————————————————————————————————————— 

我们可以通过索引解决其中的一些问题,但代码中却没有想象中那么高效。比如说你要获取某个小时里的所有事件,我们可以在time字段上加上索引,但这回 导致过高负载,因为这些事件需要从分散在集群中各节点中的行中获取。

  为了补偿这一点,鉴于我们事先知道获取的小时值,我们可以将小时变成key,利用Cassandra的动态表(dynamic tables)我们可以确保某个小时内的所有事件物理上都存储在一行中。当你使用组合键时,Cassandra将key off 第一个字段,而随后的字段作为列名的一部分。列表3.5中,我们调整代码,以一种便于快速查找小时对应所有事件的方式组织表中的数据存储。

Listing 3.5 示例Cassandra作Log存储的数据模型(低负载)。

————————————————————————————————————— 

CREATE TABLE events (

 hour TIMESTAMP,

 id UUID,

 time TIMESTAMP,

 event_type TEXT,

 data text

 PRIMARY KEY(hour, id)

);

————————————————————————————————————— 

  通过这个新模型,我们可以很方便地查找小时中所有事件,因为我们将同个小时中的数据物理地存储在磁盘上的一行中。这对于一个低流量的应用来说非常合适。然而,如果你的应用存在大量读写,你可能就要将一行切分为多行,因为小时内的事件都存放在一行会变得难以查询,而且会导致热点(因为所有的读写都在磁盘上同个文件中进行)。我们可以将一行切分为多行来解决问题,只要我们有多个可供查询的字段的信息。在这个例子中,就是event_type。我们还能通过确保数据按照event_time排序(而不是ID)来进一步提高性能。这样做还是得我们能够基于事件的时间来做区间查询(rang queries)。在列表3.6中,我们用到组合键以及聚集排序(clustering order)来解决热点问题,同时根据事件时间进行了倒序排序。

Listing 3.6 示例Cassandra作Log存储(优化后的)

————————————————————————————————————— 

CREATE TABLE events (

 hour TIMESTAMP,

 id TIMEUUID,

 time TIMESTAMP,

 event_type TEXT,

 data text,

 PRIMARY KEY((hour, event_type), time)

) WITH CLUSTERING ORDER BY (time DESC);

SELECT * FROM events;

hour | event_type | time | data | id

_ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ _  __ _ _ __ _ _ 

2013-06-13 11:00:00 | click | 2013-06-13 11:00:00 | some data | 3...

2013-06-13 11:00:00 | page_view | 2013-06-13 11:00:01 | some data | 2...

2013-06-13 11:00:00 | error | 2013-06-13 11:00:05 | some data | 0...

2013-06-13 11:00:00 | redirect | 2013-06-13 11:00:09 | some data | 1...

————————————————————————————————————— 

  既然我们有了一个存储我们的events数据的机制,我们可能还想跟踪事件上的度量(metrics)。Cassandra不支持以一种ad hoc的方式创建聚合度量(aggregate metrics)。为了跟踪特定的聚合信息,我们首先要清楚我们要跟踪何种聚合度量。在这个例子中,我们将通过跟踪小时内某event types的发生次数。这类跟踪的一种好候选方式是Cassandra Counter 列。

列表3.7展示为一个counter列族建表的做法。

Listing 3.7 示例带Counter列的建表

————————————————————————————————————— 

CREATE TABLE event_metrics (

 hour TIMESTAMP,

 event_type TEXT,

 count COUNTER,

 PRIMARY KEY(hour, event_type)

);

CREATE TABLE url_metrics (

  hour TIMESTAMP,

  url TEXT,

  count COUNTER,

  PRIMARY KEY(hour, url)

);

————————————————————————————————————— 

既然我们为我们的event_metrics创建了带有counters的表,我们已经能通过使用BATCH声明来在同一时间更新我们的counters。列表3.8展示了如何在一个原子的批处理中插入事件数据的同时更新我们的counters。

Listing 3.8 示例用Atomic Counter Batch插入和更新数据。

————————————————————————————————————— 

INSERT INTO events (hour, id, time, event_type, data)

     VALUES ('2013-06-13 11:00:00', NOW(), '2013-06-13 11:43:23',

     'click', '{"url":"http://example.com"}')

BEGIN COUNTER BATCH

     UPDATE event_metrics SET count _ count _ 1

          WHERE hour _ '2013-06-13 11:00:00'

          AND event_type _ 'click'

     UPDATE url_metrics SET count _ count _ 1

          WHERE hour _ '2013-06-13 11:00:00'

          AND url _ 'http://example.com'

APPLY BATCH;


集合类(Collections)

Cassandra将集合类作为数据模型的一部分。这些类被用来提供灵活的查询方式。

Sets

Cassandra sets 提供了一种无须先读后写(read-before-write)的维护唯一项集(a unique set of items)的方式。这以为着你可以轻松解决如跟踪唯一e-mail地址或唯一IP地址这样的问题。集合中的数据按照元素类型自然顺序排好。Listing 3.9展示了如何创建一个带有set类型的表,以及如何查询。

Listing 3.9 使用Set的例子

————————————————————————————————————— 

CREATE TABLE users (

 email TEXT PRIMARY KEY,

 portfolios SET@UUID:,

 tickers SET@TEXT:

);

UPDATE users set 

        portfolios = portfolios + {756716f7-2e54-4715-9f00-91dcbea6cf50},

        tickers = tickers + {'AMZN'}

WHERE email = 'foo@bar.com';

UPDATE users set

             portfolios = portfolios + {756716f7-2e54-4715-9f00-91dcbea6cf50},

       tickers = tickers + {'GOOD'}

WHERE email = 'foo@bar.com';

email | portfolios | tickers

_ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ _  __ _ _ __ _ _ 

foo@bar.com | {756716f7-2e54-4715-9f00-91dcbea6cf50} | {'AMZN', 'GOOG'}


UPDATE users SET

      tickers = tickers - {'AMZN'}

WHERE email = 'foo@bar.com';


email | portfolios | tickers

_ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ _  __ _ _ __ _ _ 

foo@bar.com | {756716f7-2e54-4715-9f00-91dcbea6cf50} | {'GOOG'}


DELETE tickers FROM users

  WHERE email = 'foo@bar.com';


email | portfolios | tickers

_ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ _  __ _ _ __ _ _ 

foo@bar.com | {756716f7-2e54-4715-9f00-91dcbea6cf50} | null

       

Lists

当不需要唯一性时而需要维护顺序时,Cassandra lists很好用。比如前面的例子,现在我们要为我们的用户指定top 5 tickers。列表3.10展示了使用lists的一个例子。

Listing 3.10 使用Lists的例子

————————————————————————————————————— 

ALTER TABLE users ADD top_tickers list;

UPDATE users

    set top_tickers = ['GOOD']

WHERE email = 'foo@bar.com';

UPDATE users

    set top_tickers = top_tickers + ['AMZN']

WHERE email = 'foo@bar.com';


email | portfolios | tickers | top_tickers

_ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ _  __ _ _ __ _ _ 

foo@bar.com | {756716f7-2e54... } | null | ['GOOG', 'AMZN']


Listing 3.10 使用Lists的例子

————————————————————————————————————— 

UPDATE users

    SET top_tickers[1] = 'FB'

WHERE email = 'foo@bar.com';

email | portfolios | tickers | top_tickers

_ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ _  __ _ _ __ _ _ 

foo@bar.com | {756716f7-2e54...} | null | ['GOOG', 'FB']


UPDATE users

    SET top_tickers = top_tickers - ['FB']

WHERE email = 'foo@bar.com';


email | portfolios | tickers | top_tickers

_ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ _  __ _ _ __ _ _ 

foo@bar.com | {756716f7-2e54...} | null | ['GOOG']

————————————————————————————————————— 


Maps

Cassandra maps 提供了字典的风格。当你需要在一行中存储表格式的数据时很有用。它可以减轻没有join操作的不适,或者避免在一列中存储JSON数据。列表3.22展示了使用maps的例子。

Listing 3.11 使用maps的例子

————————————————————————————————————— 

ALTER TABLE users ADD ticker_updates map;

UPDATE users 

  SET ticker_updates = {'AMZN':'2013-06-13 11:42:12' }

WHERE email 'foo@bar.com';

email | portfolios | ticker_updates

_ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ _  __ _ _ __ _ _ 

foo@bar.com | {756716f7...} | {'AMZN': '2013-06-13 11:42:12-0400'}


UPDATE users

  SET ticker_update['GOOD'] = '2013-06-13 12:51:31'

WHERE email = 'foo@bar.com';

email | portfolios | ticker_updates

_ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ _  __ _ _ __ _ _ 

foo@bar.com | {756716f7... } | {'AMZN': '2013-06-13 11:42:12-0400',

                                'GOOG': '2013-06-13 12:51:31-0400'}


DELETE ticker_updates['AMZN']

    FROM user

WHERE emial = 'foo@bar.com';

email | portfolios | ticker_updates

_ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ __ _ _ _  __ _ _ __ _ _ 

foo@bar.com | {756716f7...} | {'GOOG': '2013-06-13 12:51:31-0400'}


总结

  Cassandra中的数据建模方式在有的习惯使用关系型数据库的人看来可能不适应。这是为了在海量数据的情况下获得高负载作出的妥协。本章可以看出关系型数据库建模技术那一套在Cassandra的世界里不再使用;对查询建模,而不是数据;反范式化和复制数据并不是坏事--事实上,它们还是被推荐干的。另外,牢记任何时候将你的数据范式化都是不推荐的做法。Collections已经很强大,尽管但数据结构中的数据量非常大的时候会影响性能。



Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
PHP与Cassandra的集成PHP与Cassandra的集成May 15, 2023 pm 06:51 PM

随着大数据时代的到来以及数据增长量的不断增加,Cassandra已经成为了一种流行的分布式数据库技术。而PHP语言作为最流行的Web编程语言之一,则是Web开发领域的主流技术之一,如何让PHP和Cassandra进行无缝的集成呢?安装Cassandra在开始使用Cassandra之前,需要先安装Cassandra。Cassandra可以在官网上下载到最新的版

如何在Workerman中使用Cassandra进行数据存储如何在Workerman中使用Cassandra进行数据存储Nov 08, 2023 pm 08:30 PM

如何在Workerman中使用Cassandra进行数据存储在当今的软件开发中,不同的数据存储方式和引擎得到了广泛的应用。Cassandra作为一种高可用性、分布式的NoSQL数据库,在大数据领域中具有重要作用。本文将介绍如何在Workerman中使用Cassandra进行数据存储,并提供相关的代码示例。安装CassandraPHP扩展在开始使用Cassa

使用PHP操作Cassandra数据库使用PHP操作Cassandra数据库May 16, 2023 pm 03:51 PM

Cassandra是一个基于NoSQL的分布式数据库管理系统,可以支持处理大量数据。PHP作为一种流行的服务器端编程语言,可以用于操作Cassandra数据库。本篇文章将介绍如何使用PHP驱动程序和CQL来连接和操作Cassandra数据库。在开始之前,请确保已经按照以下步骤安装了Cassandra数据库和PHP驱动程序:1.安装Cassandra数据库2

从零开始理解Golang泛型从零开始理解Golang泛型Mar 18, 2024 pm 05:21 PM

Golang是一种开源的编程语言,由Google设计开发,并于2009年首次发布。作为一门现代化的语言,Golang一直以其简洁、高效的特点受到开发者的喜爱。然而,直到最近,Golang一直被人诟病缺乏泛型支持。泛型是一种编程语言的特性,能够编写出具有通用性的代码,以便于支持不同类型的数据。在Golang社区中,对于Golang何时会实现泛型功能一直存在争议

如何使用Java开发一个基于Cassandra的时序数据库应用如何使用Java开发一个基于Cassandra的时序数据库应用Sep 21, 2023 am 10:22 AM

如何使用Java开发一个基于Cassandra的时序数据库应用时序数据是指随时间推移而产生的有序数据,如传感器数据、日志数据等。随着物联网和大数据的发展,对时序数据的存储和分析需求也越来越高。Cassandra是一个高度可扩展的分布式数据库系统,具有高性能和高可用性的特点,因此非常适合存储时序数据。本文将介绍如何使用Java开发一个基于Cassandra的时

如何使用Java开发一个基于Cassandra的分布式数据库应用如何使用Java开发一个基于Cassandra的分布式数据库应用Sep 21, 2023 pm 03:19 PM

如何使用Java开发一个基于Cassandra的分布式数据库应用概述:Cassandra是一个开源的分布式NoSQL数据库系统,它具备高可扩展性、高可用性以及强大的数据分发能力。本文将介绍如何使用Java语言开发一个基于Cassandra的分布式数据库应用,包括连接Cassandra、创建数据库表、插入和查询数据等。步骤一:引入CassandraJava驱

如何使用PDO连接到Cassandra数据库如何使用PDO连接到Cassandra数据库Jul 28, 2023 pm 03:04 PM

如何使用PDO连接到Cassandra数据库Cassandra是一个高度可扩展的分布式数据库,广泛应用于大数据处理和分析领域。与传统关系型数据库相比,Cassandra有着更好的水平扩展性和高性能。为了方便在PHP程序中连接和操作Cassandra数据库,我们可以使用PDO扩展库。本文将介绍如何使用PDO连接到Cassandra

了解 Cassandra 缓存技术了解 Cassandra 缓存技术Jun 20, 2023 am 08:25 AM

Cassandra是一款高性能、分布式的NoSQL数据库,被广泛应用于大规模的数据管理领域。Cassandra的缓存技术是其高性能的关键之一。本文将介绍Cassandra缓存技术的基本原理、缓存类型和优化方法等内容。一、Cassandra缓存技术原理Cassandra的缓存是将经常访问的数据存储在内存中,以提高读取性能的一种技术。Cassan

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
2 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
Repo: How To Revive Teammates
1 months agoBy尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: How To Get Giant Seeds
4 weeks agoBy尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser is a secure browser environment for taking online exams securely. This software turns any computer into a secure workstation. It controls access to any utility and prevents students from using unauthorized resources.

SublimeText3 Linux new version

SublimeText3 Linux new version

SublimeText3 Linux latest version

VSCode Windows 64-bit Download

VSCode Windows 64-bit Download

A free and powerful IDE editor launched by Microsoft

Atom editor mac version download

Atom editor mac version download

The most popular open source editor

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)