Apache Cassandra性能调优-混合工作负载压缩

2024-06-02 16:48

本文主要是介绍Apache Cassandra性能调优-混合工作负载压缩,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 

这是我们关于使用Apache Cassandra进行性能调整的系列文章中的第三篇。在我们的第一篇文章中,我们讨论了如何使用火焰图直观地诊断性能问题。在第二篇文章中,我们讨论了JVM调优,以及不同的JVM设置如何影响不同的工作负载。

在本文中,我们将深入探讨通常被忽略的表级设置:压缩。可以在创建或更改表时指定压缩选项,如果未指定,则默认启用。当处理写入繁重的工作负载时,默认值很棒,但是对于读取繁重的混合工作负载可能会成为问题。

在进行优化之前,让我们退后一步来了解Cassandra中的压缩基础。建立知识基础后,我们将了解如何将其应用于现实世界的工作负载。

怎么运行的

当我们在Cassandra中创建表时,除了字段外,我们还可以指定各种表选项。除了诸如将TWCS用于我们的压缩策略,指定gc宽限秒数和缓存选项之类的选项外,我们还可以告诉Cassandra我们希望它如何压缩数据。如果未指定压缩选项,则将使用LZ4Compressor,以其出色的性能和压缩率而闻名。除了算法之外,我们还可以指定chunk_length_in_kb,这是写入数据之前将数据写入其中的未压缩缓冲区的大小。这是一个使用LZ4Compressor的表的示例,该表的块长为64KB:

<span style="color:#2e3a33"><span style="color:#2e3a33"><code class="language-plaintext">create table sensor_data ( id text primary key, data text) 
WITH compression = {'sstable_compression': 'LZ4Compressor', 'chunk_length_kb': 64};
</code></span></span>

我们可以通过检查tablestats以下内容来检查压缩在表级别的工作情况:

<span style="color:#2e3a33"><span style="color:#2e3a33"><code class="language-plaintext">$ bin/nodetool tablestats tlp_stressKeyspace : tlp_stressRead Count: 89766Read Latency: 0.18743983245326737 msWrite Count: 8880859Write Latency: 0.009023213069816781 msPending Flushes: 0Table: sensor_dataSSTable count: 5Old SSTable count: 0Space used (live): 864131294Space used (total): 864131294Off heap memory used (total): 2472433SSTable Compression Ratio: 0.8964684393508305Compression metadata off heap memory used: 140544
</code></span></span>

SSTable Compression Ratio上面的行告诉我们有效的压缩方式。压缩率的计算公式如下:

<span style="color:#2e3a33"><span style="color:#2e3a33"><code class="language-plaintext">compressionRatio = (double) compressed/uncompressed;
</code></span></span>

表示数字越小,压缩效果越好。在上面的示例中,我们的压缩数据几乎占据了原始数据的90%,并不是特别好。

数据如何写入

我发现深入研究代码库,进行概要分析以及与调试器一起使用是学习软件工作原理的最有效方法。

当数据被写入SSTables或从SSTables读取数据时,我们不处理方便的类型化对象,而是处理字节流。我们的压缩数据写在CompressedSequentialWriter该类中,该类可以扩展BufferedDataOutputStreamPlus。作者使用一个临时缓冲区。当数据写到磁盘时,缓冲区将被压缩,有关它的一些元数据将记录到CompressionInfo文件中。如果缓冲区中的数据多于可用空间,则将缓冲区写入缓冲区并刷新,然后重新开始重新写入缓冲区(并可能再次刷新)。您可以在中看到此内容org/apache/cassandra/io/util/BufferedDataOutputStreamPlus.java

<span style="color:#2e3a33"><span style="color:#2e3a33"><code class="language-plaintext">@Override
public void write(byte[] b, int off, int len) throws IOException
{if (b == null)throw new NullPointerException();// avoid int overflowif (off < 0 || off > b.length || len < 0|| len > b.length - off)throw new IndexOutOfBoundsException();if (len == 0)return;int copied = 0;while (copied < len){if (buffer.hasRemaining()){int toCopy = Math.min(len - copied, buffer.remaining());buffer.put(b, off + copied, toCopy);copied += toCopy;}else{doFlush(len - copied);}}
}
</code></span></span>

此缓冲区的大小由确定chunk_length_in_kb

如何读取数据

Cassandra中的读取路径(或多或少)与写入路径相反。我们从SSTables中取出大块,对其进行解压缩,然后将其返回给客户端。完整的路径要复杂一些- 我们要经历一个aa ChunkCache(由咖啡因管理),但这超出了本文的范围。

在读取路径期间,必须读取并解压缩整个块。我们无法选择性地仅读取所需的字节。这样做的影响是,如果我们使用4K块,则仅读取磁盘4K就可以摆脱困境。如果使用256KB的块,则必须读取整个256K。这对于少数几个请求可能很好,但是当试图最大化吞吐量时,我们需要考虑当每秒有数千个请求时发生的情况。如果我们必须每秒读取256KB磁盘以处理一万个请求,那么我们将需要每秒读取2.5GB磁盘,而无论使用什么硬件,这都是一个问题。

那页面缓存呢?

Linux将自动利用应用程序未使用的任何RAM来将最近访问的文件系统块保留在内存中。通过使用该free工具,我们可以看到正在使用多少页面缓存:

<span style="color:#2e3a33"><span style="color:#2e3a33"><code class="language-plaintext">$ free -mhwtotal        used        free      shared     buffers       cache   available
Mem:            62G        823M         48G        1.7M        261M         13G         61G
Swap:          8.0G          0B        8.0G
</code></span></span>

如果您有适合内存使用的工作数据集,那么页面缓存可以带来巨大的好处。对于较小的数据集,这非常有用,但是Cassandra旨在解决大数据问题。通常,这意味着拥有比可用RAM更多的数据。如果我们在每个节点上的工作数据集为2 TB,而我们只有20-30 GB的可用RAM,则很有可能我们几乎不会在缓存外处理任何请求。kes。

最终,我们需要确保使用的块长度可以使I / O最小化。较大的块可以更好地压缩,从而为我们提供较小的磁盘空间,但是最终需要更多的硬件,因此对于某些工作负载而言,节省空间变得毫无意义。没有完美的设置可应用于所有工作负载。通常,您执行的读取次数最多,块大小较小。即使这也不是统一适用的。较大的请求将命中更多的块,并将受益于更大的块大小。

基准测试

好吧-足够的细节!我们将运行一个简单的基准测试,以测试Cassandra在具有简单键值数据模型的混合读写记录中的性能。我们将使用压力工具tlp-stress(提交40cb2d28fde)进行此操作。我们将在以后的文章中详细介绍这个压力工具-现在我们需要讨论的是它包含了一个现成的关键价值工作负载,我们可以在这里利用。

对于此测试,我按照cassandra.apache.org上的说明在运行Ubuntu 16.04的AWS c5d.4xlarge实例上安装了Apache Cassandra 3.11.3,并使用来更新了所有系统软件包apt-get upgrade。我在这里只使用一个节点,以隔离压缩设置,而不从运行整个群集的网络开销中引入噪音。

临时NVMe磁盘正在使用XFS并将其安装在/var/lib/cassandra。我使用设置了预读,blockdev --setra 0 /dev/nvme1n1因此我们可以看到压缩对磁盘请求的影响,而不是将其隐藏在页面缓存中。

对于每个工作负载,我将以下命令放入外壳脚本中,并从单独的c5d.4xlarge实例运行tlp-stress(将块大小作为第一个参数传递):

<span style="color:#2e3a33"><span style="color:#2e3a33"><code class="language-plaintext">$ bin/tlp-stress run KeyValue -i 10B -p 10M --populate -t 4 \--replication "{'class':'SimpleStrategy', 'replication_factor':1}" \--field.keyvalue.value='book(100,200)' -r .5  \--compression "{'chunk_length_in_kb': '$1', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor'}" \--host 172.31.42.30
</code></span></span>

这将在1000万个分区(-p 10M)上运行键值工作负载,预先填充数据(--populate),其中50%的读取(-r .5),从压力工具(--field.keyvalue.value='book(100,200)')中包含的一本书中选出100-200个单词。我们可以使用指定压缩策略--compression

在测试中,我使用了经过稍微修改的Cassandra配置文件,以通过增加总堆(12GB)和新一代(6GB)来减少GC暂停的影响。我花了很少的时间,因为没有必要对其进行完美的优化。我还将压缩吞吐量设置为160

在测试中,我使用Swiss Java Knife(sjk-plus)以及dstat对磁盘/网络/ cpu的使用情况监控了JVM的分配率。

默认64KB块大小

第一个测试使用默认的64KB块长度。我开始发出压力命令,然后走开和我的狗玩了一段时间。当我回来时,我遇到了大约3500万个请求:

 

您可以在上面的屏幕截图中看到我们的5分钟速率大约是22K次写入/秒和22K次读取/秒。查看这时dstat的输出,可以看到我们正在每秒读取500到600MB之间的数据:

DStat 64KB

内存分配有所波动,但徘徊在1GB / s左右:

sjk 4kb

不是世界上最惊人的结果。在磁盘读取中,某些吞吐量可以归因于压缩,而在现实世界中我们总是必须面对这种压缩。上限为160MB / s,剩下约400MB / s的读取速度。考虑到我们在网络上仅发送25MB,这很多。这意味着我们要做的磁盘I / O超过网络I / O的15倍。在此工作负载中,我们的磁盘空间很大。

4KB块大小

让我们看看4KB块大小是否更好。在测试之前,我关闭了Cassandra,清除了数据目录,然后开始备份。我使用上面的shell脚本在上面进行了相同的压力测试,将4作为块大小传递。我再次和我的狗玩了一段时间,然后在与之前的测试大约相同的时间回来。

从压力输出来看,显而易见的是,有了很大的改进:

 

在指标库报告的几乎每个指标中,具有4KB的测试都优于64KB的测试。我们的吞吐量更好(在1分钟内速率为62K ops /秒与44K ops /秒),而我们的p99读取更好(13ms vs 24ms)。

如果我们在每个请求上执行的I / O减少,这将如何影响我们的磁盘和网络I / O总数?

dstat 4kb

如您在上面看到的,有了很大的改进。磁盘I / O减少了对磁盘的较小(但更多)的请求,而响应更多的请求,网络I / O显着提高。

 

最初看到增加的堆分配率(因为我们正在将WAY的数据读入内存的数量减少)而感到意外,但这仅仅是执行更多请求的结果。为了满足请求而创建了许多对象。远远超过从磁盘读取数据而创建的数量。请求越多,分配就越高。我们要确保在进行JVM调整时这些对象不会进入OldGen。

堆外内存使用情况

最后要考虑的是堆外内存使用情况。在每个压缩的SSTable旁边是压缩元数据。压缩文件的名称类似于na-9-big-CompressionInfo.db。压缩元数据存储在Cassandra堆之外的内存中。堆使用量的大小与所用块的数量成正比。更多的块=使用更多的空间。当使用较小的块大小时,将使用更多的块,因此,将使用更多的堆外内存来存储每个块的元数据。了解这种权衡很重要。使用4KB块的表将使用的内存是使用64KB块的表的16倍。

在我上面使用的示例中,内存使用情况可以看到如下:

<span style="color:#2e3a33"><span style="color:#2e3a33"><code class="language-plaintext">Compression metadata off heap memory used: 140544 
</code></span></span>

更改现有表

既然您已经看到较小的块大小如何使读取繁重的混合工作负载受益,现在该尝试一下。如果您有要更改其压缩设置的表,则可以在cqlsh shell上执行以下操作:

<span style="color:#2e3a33"><span style="color:#2e3a33"><code class="language-plaintext">cqlsh:tlp_stress> alter table keyvalue with compression = {'sstable_compression': 'LZ4Compressor', 'chunk_length_kb': 4};
</code></span></span>

应用此更改后写入的新SSTables将使用此设置,但现有的SSTables不会自动重写。因此,应用此设置后,您不应指望立即出现性能差异。如果要立即重写每个SSTable,则需要执行以下操作:

<span style="color:#2e3a33"><span style="color:#2e3a33"><code class="language-plaintext">nodetool upgradesstables -a tlp_stress keyvalue
</code></span></span>

结论

上面是一个测试,展示了调整压缩设置如何显着影响Cassandra性能。在读取繁重的工作负载或混合工作负载时使用开箱即用的压缩设置几乎可以肯定会对磁盘造成不必要的负担,同时又会损害读取性能。我强烈建议您花一些时间了解您的工作负载,并分析系统资源以了解瓶颈所在,因为没有绝对正确的设置可用于每个工作负载。

还要记住在内存和块大小之间进行权衡。当在内存受限的环境中工作时,似乎很想在任何地方使用4KB块,但重要的是要了解它将使用更多的内存。在这些情况下,从读取最多的较小表开始是个好主意。

这篇关于Apache Cassandra性能调优-混合工作负载压缩的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1024530

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

hdu1565(状态压缩)

本人第一道ac的状态压缩dp,这题的数据非常水,很容易过 题意:在n*n的矩阵中选数字使得不存在任意两个数字相邻,求最大值 解题思路: 一、因为在1<<20中有很多状态是无效的,所以第一步是选择有效状态,存到cnt[]数组中 二、dp[i][j]表示到第i行的状态cnt[j]所能得到的最大值,状态转移方程dp[i][j] = max(dp[i][j],dp[i-1][k]) ,其中k满足c

黑神话,XSKY 星飞全闪单卷性能突破310万

当下,云计算仍然是企业主要的基础架构,随着关键业务的逐步虚拟化和云化,对于块存储的性能要求也日益提高。企业对于低延迟、高稳定性的存储解决方案的需求日益迫切。为了满足这些日益增长的 IO 密集型应用场景,众多云服务提供商正在不断推陈出新,推出具有更低时延和更高 IOPS 性能的云硬盘产品。 8 月 22 日 2024 DTCC 大会上(第十五届中国数据库技术大会),XSKY星辰天合正式公布了基于星

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

工作常用指令与快捷键

Git提交代码 git fetch  git add .  git commit -m “desc”  git pull  git push Git查看当前分支 git symbolic-ref --short -q HEAD Git创建新的分支并切换 git checkout -b XXXXXXXXXXXXXX git push origin XXXXXXXXXXXXXX

嵌入式方向的毕业生,找工作很迷茫

一个应届硕士生的问题: 虽然我明白想成为技术大牛需要日积月累的磨练,但我总感觉自己学习方法或者哪些方面有问题,时间一天天过去,自己也每天不停学习,但总感觉自己没有想象中那样进步,总感觉找不到一个很清晰的学习规划……眼看 9 月份就要参加秋招了,我想毕业了去大城市磨练几年,涨涨见识,拓开眼界多学点东西。但是感觉自己的实力还是很不够,内心慌得不行,总怕浪费了这人生唯一的校招机会,当然我也明白,毕业