Coursera 笔记

Module 03 · Introducing Apache Cassandra: An Open-Source NoSQL Database

Apache Cassandra Data Model: Part 2Apache Cassandra 数据模型(第二部分)

Coursera ↗

欢迎观看关于 Apache Cassandra 数据模型 的第二部分视频。在本视频中,您将能够:

  • 解释 聚类键(Clustering Keys)是什么,
  • 描述 动态表(Dynamic Tables),
  • 解释建模数据的基本准则。

 聚类键(Clustering Key)

聚类键的作用

在 Cassandra 中,聚类键 是主键的第二部分,用于决定数据在 分区 内的排序方式。分区键决定了数据的本地性,而聚类键则定义了数据在分区内部的排列顺序(升序或降序),并优化了在一个分区内检索相似值的数据。

  • 聚类键可以是单列或多列键。
  • 在本例中,聚类键由 username 列组成,这意味着数据将在每个分区内按用户名升序排列。

聚类键的优势

聚类键不仅提供了主键的唯一性,还能显著提升 读取查询 的性能。例如,当我们查询某个特定分组下年龄为 32 的用户时,数据将根据年龄分组,然后根据用户名排序,查询时将只读取符合条件的记录,避免了读取大量无关数据。

减少查询数据量的重要性

减少从分区读取的数据量对查询时间至关重要,特别是在大型分区中,Cassandra 可能需要读取数百兆字节的数据才能从几千字节的数据中提供答案。


 动态表(Dynamic Table)

动态表 是具有分区键和聚类键的表。这些表根据主键的定义动态增长,随着数据的增加,分区的大小会变化。

动态表的数据插入

当向动态表中插入数据时,Cassandra 会根据 分区键 确定数据存储的位置,并将新数据追加到现有分区中。如果分区中已有多个条目,新的条目将按聚类键的顺序存储。

  • 分区 是 Cassandra 存储的最小单位,每个分区的数据总是存储在同一节点上,并在其他节点上有副本。
  • 在实际操作中,插入或读取数据时,Cassandra 会通过哈希函数定位到具体的节点。

数据的分布和复制

在 Cassandra 中,数据分布到集群中的不同节点,并根据 复制因子 在多个节点上保持副本。例如,如果一个分区的复制因子为 3,则该分区的数据会有 3 个副本分布在集群中的不同节点上。


 建模数据的基本准则

在 Cassandra 中进行数据建模时,以下是几个关键的准则:

选择分区键

  1. 选择能够起始查询的分区键:分区键应能均匀地分布数据。例如,如果有多个 groupId,并且每个 groupId 的大小差不多,那么 groupId 可以是一个合适的分区键。
  2. 最小化查询时需要读取的分区数量:Cassandra 将数据分布到多个分区,如果查询需要读取多个分区,则可能需要访问多个节点,从而影响查询性能。理想情况下,我们应该设计主键以便能够仅读取一个分区来完成查询。

优化聚类键

聚类键的设计应根据查询需求,按顺序排列列,以便能最小化读取的数据量。通过合理设计聚类键,能显著提高查询效率。


 总结

通过本视频,您学习了:

  • 聚类键 用于定义分区内部数据的排序顺序,并可以优化读取性能。
  • 动态表 中的数据随着条目的增加而动态增长,分区的大小会随之变化。
  • 在 Cassandra 数据建模中,最重要的步骤是根据您的查询需求设计主键,确保尽可能只读取一个分区的数据,从而提高查询效率。
  • 构建主键时要考虑 分区键 的均匀分布和 聚类键 的顺序安排,以便最优化数据访问。

核心概念深度解析

1. 聚类键 (Clustering Key) 的威力

在Part 1中,我们知道了聚类键用于在分区内排序。Part 2则深入揭示了它的另一个强大功能:​​分区内的高效数据检索和过滤​​。

  • ​​工作机制:​​
    • 在一个分区内(即共享同一个分区键的所有数据),数据行​​按照聚类键的定义顺序物理存储在磁盘上​​。
    • 这个顺序可以是升序(ASC)或降序(DESC),可以在建表时定义。
    • 因为数据是有序的,Cassandra可以像在​​有序数组​​中一样进行高效的​​范围查询​​和​​等值查询​​,而无需扫描整个分区。
  • ​​视频中的例子解析:​​
    • ​​查询:​​ “给我组ID 12中所有年龄为32的用户。”
    • ​​设计方案:​​
      PRIMARY KEY ((groupid), age, username)
      • ​​分区键:​​ groupid-> 确保查询groupid=12的数据全都在一个节点上的一个分区内。
      • 聚类键: age, username-> 数据在分区内先按 age 排序,在 age 相同的情况下再按 username 排序。
    • ​​执行过程(架构师视角):​​
      1. 查询WHERE groupid=12 AND age=32。
      2. 系统定位到存储groupid=12这个分区的节点。
      3. 由于数据按age排序,它可以直接​​二分查找​​或快速定位到age=32的数据块。
      4. 它只需要读取这个特定age值对应的​​连续数据块​​(可能只有几KB),而​​无需读取整个可能包含各个年龄段用户的、巨大的分区​​(可能几百MB)。
      5. 这就是所谓的 ​​“减少分区内数据读取量”​​ ,是优化查询性能的关键。

2. 动态表 (Dynamic Table) 的再认识

  • ​​定义:​​ 主键包含聚类键的表。
  • ​​特点:​​ 每个分区(分区键相同)可以包含​​多行数据​​(由不同的聚类键值区分)。分区的大小会随着数据的插入而动态增长。
  • ​​架构师警示:​​ 必须警惕 ​​“超大分区(Large Partitions)”​​ 问题。如果一个分区的数据无限增长(例如,一个非常活跃的聊天群的所有消息都放在一个分区里),当这个分区的大小达到MB甚至GB级别时,会对读写性能、压缩和修复操作造成巨大压力。​​设计时必须估算一个分区的最大可能容量​​。

3. 数据建模的核心准则(黄金法则)

这部分是视频的精华,也是你作为架构师必须内化的设计原则。

  1. ​​准则一:分区键的选择 —— 均匀分布与查询入口​​
    • ​​必须支持查询:​​ 你的查询的WHERE子句​​必须包含分区键​​(等于或IN操作),这是铁律。
    • ​​必须避免热点:​​ 分区键的​​基数​​(不同取值的数量)要足够高,以确保数据能均匀分布到集群的所有节点上。例如,用user_id(高基数)比用country_code(低基数)做分区键要好得多,否则所有中国用户的数据都会堆在同一个节点上,形成热点。
  2. ​​准则二:最小化分区读取数量 —— “One Query, One Partition”​​
    • ​​理想目标:​​ ​​一个查询最好只从一个分区中读取数据​​。这意味着只需要访问集群中的一个节点(及其副本)就能得到答案,延迟最低,性能最高。
    • ​​反面模式:​​ 如果查询需要​​扫描多个分区​​(例如,WHERE age = 25,但age不是分区键),那么协调节点就需要向集群中​​所有节点​​(或大量节点)发起请求,收集结果后再聚合。这会产生极高的延迟和协调开销,在Cassandra中应​​极力避免​​。
  3. ​​准则三:利用聚类键优化分区内查询​​
    • 在满足“一个查询一个分区”的基础上,使用聚类键来​​进一步缩小需要扫描的数据范围​​。如上面的例子,通过age和username聚类,可以快速定位到分区内一个更小的、连续的数据片段。

总结给你(系统架构师备考者)

Cassandra的数据建模是一个 ​​“目的导向”​​ 的逆向过程,与你熟悉的RDBMS范式化设计截然不同。请牢记以下流程:

  1. ​​起点:​​ 从​​应用程序的查询需求​​出发。列出所有必须支持的查询语句。
  2. ​​设计:​​ ​​为每个查询设计最佳的表结构​​。这意味着通常会有大量的数据冗余,同一个数据可能会出现在多张不同的表中,以支持不同的查询模式。这是用​​空间换时间​​和​​扩展性​​的经典权衡。
  3. ​​实现:​​
    • 根据查询的WHERE条件确定​​分区键​​。确保它能直接定位到数据所在节点,且数据分布均匀。
    • 根据查询的排序(ORDER BY)和过滤(WHERE中对非分区键字段的条件)需求确定​​聚类键​​。利用它来组织分区内数据,实现高效检索。
  4. ​​校验:​​ 始终问自己:这个设计是否遵循了 ​​“一个查询,一个分区”​​ 的黄金法则?是否能避免超大分区?

掌握这些思想,你就能设计出真正高性能、可扩展的Cassandra数据模型,从而为大型分布式系统打下坚实的基础。这是系统架构师的核心技能之一。