cassandra基础之数据模型和模式(Schema)的配置检查

1 数据模型检查


本节列出了客户咨询团队在分析现有数据模型时执行的一组常规检查。(您也可以用于开发中的数据模型。)他们从由OpsCenter产生的诊断性压缩文件(tarball)中获取现有的schema,或从诊断收集脚本中获取。您可以通过在一个集群节点上执行cqlsh -e ‘describe schema;’ 然后将结果输出到例如schema.cql的文件中。我们会在在本文中都使用该名称。

在诊断性压缩文件中,它是位于节点的driver/schema里。 除了有关schema的信息之外,您还可以使用nodetool命令,这些nodetool命令是在集群的节点上执行的(或从诊断性压缩文件中提取),因为在某些情况下只有某些节点会受到影响。

在分析数据模型时,请考虑与CQL相关的Cassandra和DSE(取决于版本)中的硬性限制,以及本文中的建议。


2 Keyspace复制设置


检查所有Keyspace,确保它们都具有正确的复制设置。注意以下内容:

2.1 错误的复制策略

当您的集群具有多个数据中心时,请使用NetworkTopologyStrategy而非SimpleStrategy。如果使用SimpleStrategy,副本可能无法保证被放置在正确的数据中心位置。

提示:即使您只有一个数据中心,也最好使用NetworkTopologyStrategy,因为如果以后您决定添加数据中心,这样的设置会使问题简单化。

2.2 Keyspace在数据中心内部复制不足或未复制到所有数据中心

这对于系统Keyspaces(例如system_auth)尤其重要。 例如,如果丢失了来自system_auth的数据副本,则您或您的应用程序可能会失去登录集群的能力。

2.3 Keyspace的过度复制

有时在大型集群中,某些Keyspace的复制因子比通常设置(“3”)要高得多。在某些情况下,它是一个有效数字,例如“5”。更高的值通常会增加读写操作的延迟,尤其是在使用一致性级别时,例如QUORUM或LOCAL_QURUM。如果要进一步保护数据并确保集群可用性,请考虑添加新的数据中心和备份等。

2.4 偶数用于复制因子(RF)

通常,在诸如QUORUM或LOCAL_QURUM之类的一致性级别上,偶数作为副本数不能很好地发挥作用,因为这会使集群对故障的适应性降低。QUORUM计算为N / 2 + 1,其中N是集群的副本数。LOCAL_QUORUM使用相同的数字计算,但N是特定数据中心中的副本数。

例如,对于RF = 2,QUARUM的副本数等于2,因此当一个节点发生故障时,操作将失败。 如果将RF增加到3,则不会发生这种情况,因为QUORUM的副本数仍为2。这意味着,如果一个节点出现故障,将不会影响操作,如下表所示:

复制因子在不丧失集群一致性级别QUORUM或在一个数据中心实现LOCAL_QUORUM能力的情况下可关闭的节点数
20
31
41
52
62
73

要解决复制问题,您可以手动执行ALTER KEYSPACE命令,或者使用Adjust-keyspaces.sh脚本或类似的命令自动执行这些操作。使用LocalStrategy或EverywhereStrategy的系统 keyspaces必须保持不变。


3 表数


Cassandra中表的数目可以直接影响集群的性能。通常,一个集群中建议最多只能有200个活跃使用的表。即使集群正常工作,拥有500个活跃使用的表也会被视为故障级别,因为很可能效率低下,也容易发生故障。

问题出在,每个表都需要大约1 MB的内存用于元数据。对每个正在使用的表,系统都分配给一个内存表(memtable)。具有大量数据的表还会为Bloom筛选器和其他辅助数据结构存储更多数据,这也增加了对内存的压力。而且,每个keyspace还会给JVM内存带来额外负担。所有这些共同影响了Cassandra的性能。以下基准显示,表的数目增加导致吞吐量的显著下降:

要检查集群中有多少个表和keyspaces可以用:


$ grep 'CREATE TABLE' schema.cql |wc -l


4 检查表的结构


在表的定义中应该做以下几个检查,它们可能会影响集群的操作性能。

4.1 检查主键(primary key)和分区键(partition key)的结构

主键(尤其是分区键)的结构可能会对集群的性能和稳定性产生重大影响。分析表的结构时,请考虑以下因素:

  • 当主键仅由分区键组成时,行的大小可能会太小。由于与分区关联的元数据可能大于行的本身大小,因此在访问或存储数据时可能导致效率低下。

  • 当表是由一列组成时,请检查分区键的数据类型。某些数据类型(根据定义)具有低基数(cardinality),例如boolean或tinyint,这可能导致节点之间的数据分布不均。例如,如果使用boolean类型定义列,则表中将只有2个分区。当分区中有很多行时,您可能还会得到较大的分区。

用日期类型作为分区键列可能会引起另一个潜在的问题。在许多情况下,如果人们使用日期类型作分区键并按“天”来组织写入数据,应用程序会为某一天在一个分区写入/读取大量数据(每秒数百和数千个请求),这样就容易导致热点的产生。

4.2 检查表的列数

我们不建议为单个表定义数百或数千列,因为:

  • 容易超过通常建议的每个分区的最大单元数(number of cells)(每行太多列)。 请参阅下面的每个分区的单元数。

  • 存储单个值的负荷:每个单元都有与其相关的时间戳,这至少增加了8个字节。如果存在TTL,则会增加更多负荷。

  • 它可能会影响范围扫描的性能。

如果表中的列过多,请首先分析数据访问模式。 解决方案包括:

  • 如果几个列是经常一起读取的,可以把这些列组合成一个冻结的用户定义类型(UDT),其中UDT中的所有数据都作为一个单元写入。

  • 在应用程序内部执行数据的序列化和反序列化。

  • 将数据存储为Blob。

4.3 检查数据使用类型的适用性

Cassandra提供了丰富的数据类型,可用于表的数列。由于数据类型太多,导致用户经常使用不正确的数据类型。例如,使用文本类型存储时间戳,使用不当的数值类型(其数值范围比所需的范围大得多,例如,本来用int就足够了的列却使用long type类型)。 这种不当使用会导致以下问题:

  • 不必要地使用磁盘空间。例如,把时间戳标为ISO-8601编码类的文本类型要占用28个字节,而时间戳类型仅使用8个字节。同样,对于数字类型,long type类型占用8个字节,而int仅使用4个字节。使用十进制和varint类型时,情况更糟,因为它们的大小不固定,大小取决于实际值。

  • 如果使用DSE Search,您可能无法正确搜索数据。例如,如果使用文本数据类型来存储数字或时间戳,您可能无法执行范围查询。

  • 当数据编码不正确时,您可能无法执行正确的数据排序。

4.4 检查集合类型的使用

Cassandra提供了几种数据类型,可在单个列中存储多个值:列表,集合和映射。 每种类型都要求在建表时就定义好集合中元素的类型。集合类型为:

冻结的

集合的全部内容被序列化并存储为一个值。这种类型解决了下面描述的一些问题,但不允许更新集合的单个元素。

非冻结的

该集合作为一组单独元素存储在单独的单元格中。

集合类型便于开发。使用时请考虑以下因素:

  • 使用非冻结集合时用于保留单个元素的元数据的额外负荷。这包括写时间戳和可选的TTL。对于列表类型,使用UUID的元素索引(每个元素16个字节)要求额外的负荷来存储。

  • 当发生非冻结集合的插入或完全更新时,例如用一个值来取代列的另一个值时(如UPDATE table SET field = new_value…),Cassandra会插入一个墓碑标记,以防止与以前的数据发生重叠,即使这个数据以前没有存在过。大量的墓碑会严重影响读取性能。

  • 集合中元素的数量有一个上限。对于Cassandra 3.0.1 / 3.1及更高版本:20亿。对于早期版本:65,535。元素数量过多可能会在访问非冻结集合中的数据或使用冻结集合时超出最大写入值大小限制, 从而导致性能问题。另外,在读取具有集合类型的数列时,其全部内容将被返回,如此大量数据的传输可能会损害性能。

  • 对于非冻结集合,其中的单个元素在被插入和更新之后,由于数据可能散布在多个SSTable之间,在被读取以后需要重建实际列值,因此可能导致性能下降。

  • 由于读取修复不会传播墓碑,有删除元素的集合的内容可能会受到影响。发生这种情况是因为作为删除标记的自定义墓碑得不到传播。

遵循以下几个规则可以缓解上面列出的问题:

  • 使用冻结的集合,直到有必要更新单个元素为止。

  • 将所有集合类型中的元素数量保持在几十个的数量级,最大数量为数百个。集合列的内容是整体读取的,因此,如果元素太多,会出现读取问题,因为该页面的最大可能大小为256 MB。

注意:当查询返回许多行时,将它们作为单个响应消息返回是效率很低的。相反,驱动程序将结果分成若干页面,这些页面将根据需要返回。应用程序可以控制单个页面中包含多少行,但是页面最大值是由原生协议来定义的。

  • 如果您知道以前不存在任何数据,为了防止创建墓碑,在将数据插入到集合或映射中(或执行集合或映射的完整更新)时,您可以对列使用追加操作。 例如:

CREATETABLE test.m1 (



id int PRIMARY KEY,



m map<int, text>



);

不是使用:


INSERT INTO test.m1(id, m) VALUES (1, {1:'t1', 2:'t2'});


UPDATE test.m1 SET m = {1:'t1', 2:'t2'} WHERE id = 1;

那样会生成墓碑,执行:


UPDATE test.m1 SET m = m + {1:'t1', 2:'t2'} WHERE id = 1;

这样的话,结果相同,但没有墓碑生成。

如果表中只有一列具有集合类型,您则可以将其建模为其他集群列。 例如:


CREATETABLE test.m1 (



    id int PRIMARY KEY,



       m map<int, text>



       );

可以在没有映射列的情况下创建此表(对集合和列表使用相同的方法):


CREATETABLE test.m1 (



id int,



m_key int,



m_value text,



PRIMARY KEY(id, m_key)



);

您可以通过省略m_key的条件来为特定分区选择所有值,或者通过提供完整的主键来仅仅选择特定元素。相比于会被整体返回的集合类型的列,这是一个更大的优势。

4.5 检查清单类型的使用

上节中描述的所有内容也适用于列表类型。但是,列表类型还有其他限制:

  • 按位置设置和删除元素,以及删除特定值的出现,会导致内部先读后写 (read-before-write)。

  • 前置或追加操作不是幂等的(idempotent)。

万一失败,您不能简单地重试该操作,因为不知道该操作是否完成。重试会导致重复的元素;不重试则可能会丢失数据。有关更多信息,请参见列表字段(List fields)文档。

如果您不需要按特定顺序排列元素,也不必让元素具有重复的值,请使用集合类型而不是列表类型。 如果您仍然需要使用列表类型的列,请考虑使用其冻结版本。

4.6 检查用户定义类型的使用

Cassandra允许创建用户定义类型(UDT)。您可以使用UDT类型将相关信息分组在一起,把每个组合作为单个实体来使用。从数据模型分析的角度来看,您可以应用与集合相同的规则:

  • 尽可能使用冻结的UDT。

  • 对于非冻结的UDT,请不要指定太多字段。

但是,UDT仍然存在与UDT的序列化/反序列化有关的问题。从模式(schema)演变的角度来看,另一个问题是:虽然可以向UDT添加字段,但却无法删除它们。这意味着UDT仅应在非常必要的有限情况下使用。否则,最好将此数据定义为表的常规列。另一种选择是在应用程序内部执行UDT数据的序列化和反序列化,并将数据存储为Blob。

4.7 检查深度嵌套的UDT和UDT集合的使用

尽管UDT可以嵌套在其他UDT中或作为集合中的元素,您必须非常小心。如果集合中存在太多元素或嵌套的UDT太多,则将达到最大的写入值上限,导致操作失败。

4.8 检查元组类型的使用

CQL提供了元组数据类型,可以将不同数据类型的多个元素分组为一个实体。此类型的局限性是:

  • 它的值总是冻结的,这意味着每次更新都会重写该列。

  • 您必须按位置访问元素,这使得开发代码更加困难,因为您需要记住在哪个位置使用了哪种类型以及该位置的含义。

由于这些限制,DataStax建议不要使用此数据类型,而应使用UDT。

4.9 检查计数器数据类型的使用

计数器数据类型允许您执行递增和递减操作,这对某些应用程序很有用。从Cassandra 2.1开始,计数器的执行更加鲁棒,但仍存在局限性:

  • 当节点发生故障,写入丢失、或类似情况时,计数器的值可能并不精确,因为计数器操作不是幂等的,并且无法重试:重试可能会导致计数过多;不重试,则可能计数不足。

  • 表可能只包含针对计数器类型的常规列;不可能与其他数据类型混合使用。

4.10 检查Blob数据类型的使用

Cassandra通过提供blob类型来支持将二进制数据存储在数据库中。使用blob时,请确保您没有在Cassandra中存储大于几百KB的对象,否则从数据库中获取数据时可能会发生问题。例如,当获取的页面大小大于原生协议设置的限制(256MB)时,查询可能会失败。

4.11 定义集群列的排序顺序

定义表时,可以定义集群列的排序方向。执行查询时应用程序可以颠倒定义的排序方向,但效率不如相同排序(在表级别上定义的)方向上读取数据。DataStax建议在建表时定义正确的排序方向。同样,如果查询时排序颠倒了,它会影响到所有列,而不仅是一列,导致Cassandra沿着反方向读取数据。


5 每个分区的单元数


Cassandra文档经常使用术语“单元‘(cell)来描述常规列(非主键列)的存储值。除了实际值之外,每个单元还具有关联的元数据,例如时间戳,可选的TTL和复杂单元的其他数据。集合和用户定义的类型会更加复杂。

Cassandra每个分区的硬限制为20亿个单元。为了确保读取操作具有可预测性,DataStax建议限制分区中的单元数,以使分区小于100 MB。

您可以使用nodetool tablehistograms命令(旧版Cassandra中的cfhistograms)检查每个分区的单元数。较新版本的Cassandra和DSE可以输出系统中所有表的数据,而较旧版本则需要给出具体的keyspace和表名。

查看输出的“单元计数”列,并检查99%百分位和“最大”行中的值。如果您的值大于100,000,请考虑更改数据模型;这可能表明存在大的分区(在下一节中介绍),列过多,或在非冻结集合中的元素过多。


$ nodetool tablehistograms test widerows

test/widerows histograms

Percentile     SSTables     Write Latency     Read Latency     Partition Size     Cell Count

                            (micros)          (micros)         (bytes)

50%           1.00          0.00              1310.72          545791             103

75%           1.00          0.00              1310.72          545791             124

95%           1.00          0.00              1310.72          545791             124

98%           1.00          0.00              1310.72          545791             124

99%           1.00          0.00              1310.72          545791             124

Min           1.00          0.00              1310.72          454827             87

Max           1.00          0.00              1572.86          545791             124


6 大分区


对于Cassandra,我们建议将分区大小保持在100MB以下。大分区的存在现象表明数据模型有错误,通常是由以下因素触发的:

  • 分区键的基数低。 ——分区键的可能值太少。

  • 分区之间的数据分布不均匀。

例如,如果用客户ID作分区键,则大客户的应用程序将比小客户写入更多的数据。结果导致,某些节点可能比其他节点拥有更多的数据。更多的数据会增加这些节点的负载,因为它们要处理更多的请求,需要更多的压实操作等。

  • 表中的列和行太多,尤其是当每一行包含所有或大多数列的数据时。

  • 在表中存储大blobs或长文本(long texts)。

  • 大分区会对Cassandra造成额外的负担,例如分配额外的内存来保存分区索引。注意:在Cassandra 3.6版之前,读取大分区会对Java heap施加更大的压力,并经常导致节点崩溃。

  • 当某些节点处理请求比其他节点多时,节点之间的数据分配不均会导致热点。

  • 在读取整个分区时,大分区之间需要传输更多的数据。

  • Cassandra分区的大小会影响外部系统,例如Spark,因为Cassandra的分区是映射到Spark分区的最小对象。任何Cassandra中的不平衡都可能导致Spark处理数据时的不平衡。

6.1 查找有关分区的信息

使用以下工具查找分区的大小:

  • 使用nodetool tablehistograms命令(旧版Cassandra中的cfhistograms)查找75、95、99和100%百分位数的分区大小。如果看到这些值之间有很大差异,则可能是分区键值的分布不均匀。用sstablepartitions命令也可以获得类似信息。

  • 有关最大分区大小的信息可通过nodetool tablestats(旧版Cassandra中的cfstats)获得。检查“Compacted partition maximum bytes”行中的值是否大于建议的100 MB。

总结

至此,文章终于到了尾声。总结一下,我们谈论了简历制作过程中需要注意的以下三个部分,并分别给出了一些建议:

  1. 技术能力:先写岗位所需能力,再写加分能力,不要写无关能力;
  2. 项目经历:只写明星项目,描述遵循 STAR 法则;
  3. 简历印象:简历遵循三大原则:清晰,简短,必要,要有的放矢,不要海投;

以及最后为大家准备的福利时间:简历模板+Java面试题+热门技术系列教程视频

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

ra中的cfhistograms)查找75、95、99和100%百分位数的分区大小。如果看到这些值之间有很大差异,则可能是分区键值的分布不均匀。用sstablepartitions命令也可以获得类似信息。

  • 有关最大分区大小的信息可通过nodetool tablestats(旧版Cassandra中的cfstats)获得。检查“Compacted partition maximum bytes”行中的值是否大于建议的100 MB。

总结

至此,文章终于到了尾声。总结一下,我们谈论了简历制作过程中需要注意的以下三个部分,并分别给出了一些建议:

  1. 技术能力:先写岗位所需能力,再写加分能力,不要写无关能力;
  2. 项目经历:只写明星项目,描述遵循 STAR 法则;
  3. 简历印象:简历遵循三大原则:清晰,简短,必要,要有的放矢,不要海投;

以及最后为大家准备的福利时间:简历模板+Java面试题+热门技术系列教程视频

[外链图片转存中…(img-h8E62M1w-1714280376749)]

[外链图片转存中…(img-IWtLyEAt-1714280376751)]

[外链图片转存中…(img-1LzEVEWa-1714280376751)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值