Cassandra性能压测及调优实战|学习笔记

开发者学堂课程【Cassandra数据库入门与实战Cassandra性能压测及调优实战】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址https://developer.aliyun.com/learning/course/784


Cassandra性能压测及调优实战


内容简介:

一、性能压测

二、性能调优

场景一 写入稳定,读取的延迟在逐渐升高

场景二 写入少,读取多

场景三 写入量级特别大

场景四 读响应时间长

场景五读响应毛刺较高

三、性能调优总结

  

一、性能压测

  市面上有很多压测工具,ycsb也是其中之一,但是ycsb的使用较为简单,支持多种开源数据库,例如redis,mango,cassandra,hbase等,掌握ycsb就能够对多种数据库进行压测,并且ycsb方便在多个数据库之间做切换,对不同数据库做性能对比,选择出对应业务使用以上数据库的哪一种较为适合。ycsb支持对多种数据库进行压测,所以如果要下载其完整压缩包的话,会占用较大内存,以下是cassandra专用压缩包,可以较为快速的安装。

将其解压缩后可进入目录页面。

Cassandra目录结构主要有三种目录,分别是bin,lab,workloads。

bin主要是执行文件目录,lab主要依赖jar包,重点关注于workloads。

在这个目录里面可以看到预先存在一些定义完成的压测模型,可以根据其提供的默认压缩模型进行略微的修改,快速得到一个需要的压缩模型。一次正确的压测,首先需要定义压测模型,而如何定义压测模型主要和以下几个方面有关系。

首先需要定义初始的数据量,这个数据量最好是匹配实际的数据量。假设有1亿个数据,那么在压测的时候,就需要准备1亿个数据,如果只准备了10万或100万个数据,那么压测出来的性能和实际的性能会相差甚远。次数比那你在亚瑟的时候,你就需要准备1亿的数据,如果你只准备了1万或者10万的数据,那压出来的性能和你实际的性能会相差甚远。其次就是在压缩过程中需要执行的读写次数。  

除了这两个之外,还有一个比较重要的部分。以表的结构来举例,表是由很多行组成的,每一行有多个列,每列都有大小。所以需要定义字段数以及每个字段的长度。如此匹配你的实际业务模型,才能得到一个比较准确的压测。因为在大部分数据库对于每一行的大小都会有限制和要求,当这一行比较大时,其性能衰退往往比较明显的。

除了这几个字段以外还有readallfields,表示在压测的时候,是否需要读取所有的字段以及readproportion updateproportion可以定义读写比例。假设是纯读的场景,那么readproportion就设为一,如果是纯写的,insertproportion就设为一。

 

  压测模型定义完成后,要对数据库进行初始化。

ycsb这款压测工具默认的命名空间是ycsb,默认的压测表是usertable。通过这两条命令,可以直接创建出所需要的namespace和table表。需要注意的是在创建namespace的时,需要指定一个副本数。副本数也会影响整体的数据大小,同时会影响读写性能,所以在设置压测副本数的时候,和实际应用保持一致最佳。构造好表后,第一步需要构造测试数据,通过ycsbload加数据库类型指定一个现成数以及压测模板开始完成测试数据的构造。由于测试数据的构造是一个写入的过程,所以整个构造过程也可以理解为纯写入场景下数据库性能的表现。

构造完成后会反馈出共执行的操作次数,成功率,整个吞吐每秒所在量级,以及平均响应时长。所以ycsb这款工具在使用的时候较为方便,最后会形成一个报表的形式,告诉使用者整个过程中的性能表现情况。

压缩时要使用内网来进行压测,如果使用公网那么网络延迟会很大,导致压缩出来的结果不理想。其次是使用的压测ecs,例如虚拟器,其规格不宜太小,如果客户端规格太小,例如只有一盒两器,那么在压测的过程中,首先达到性能瓶颈的并不是数据库,而是客户端。压缩数据的时候,要确保数据量足够大,能够持续一段时间,因为任何一款数据库都存在周期运行的任务或后台的任务,如果持续的时间只有一分钟,那么这个后台的任务或者周期任务就可能没有执行,那么压缩出来的表现就并不是最真实的表现。

任何一个周期任务都会抢占cpu资源或磁盘的io资源会影响读写的性能。以读场景来举例,刚开始的时候,cassandra里面的缓存是空的,只有在持续一段时间之后,数据库的缓存命中率较为稳定了,测试出来的数据才真实。

二、性能调优

  以下为常见的压测场景以及对应的性能调优的思路

cassandra读写原理

  写请求就是在写请求进入之后,会首先进入log,也就是commit log或y log。

在记录完成之后,会将其插入到内存里对应的一个结构,一旦抄录完成,写请求就结束了。大部分产品如果正确的使用,写入,基本不会成为瓶颈。因为只涉及到一次磁盘写入和一次内存操作,而这一次磁盘写入,因为是写论文的形式,所以直接append,append磁盘写入的话,性能很高。以上就是如何完成一次写请求。

读请求,因为每一次写入,都写入到了内存的Memortable里,如果一直写入到内存中,memortable会越来越多,但内存却放不下。为了避免内存水位过高,cassandra会周期性的把内存里面的Memortable fresh到磁盘形成一个ss table文件。

ss table文件逐渐增多之后,文件数会过多,所以会有周期性的任务,叫做compaction,把多个ss table文件合并成一个大的ss table文件。所以在一条读请求进来之后,会对内存里面的memortable和磁盘剩的ss table做多路归并排序,然后找到所需要的数据再发回。在cassandra里面不存在落盘延迟或读延迟,在cassandra里,每一条写请求,只要成功了,立马就是可读的。因为在读的时候,会考虑内存里面的memmortable对象,所以每次写入成功,立马就可读,这就是cassandra的使用特性。

  做任何一次的性能调优,都需要有完善的监控。完善的监控是所有性能调优的出发地以及终点。一个完善的监控,需要具备cpu,内存,磁盘,网络等最基本的系统级别的监控,同时还需要能够看到一些Cassandra内部的应用的状态,例如读写的oops,命中率以及各线程承担的状态。

 

场景一的特点是写入稳定,但是读取的延迟在逐渐的升高,这是一个典型的案例。

如何处理一个读请求,读请求会对内存里面的table和s磁盘上的多个ss table做多路归并的排序。所以说如果ss table的数量越多,可能涉及到的io次数就会越多,IO是磁盘,当读取延迟在逐渐升高的时候,文件数在越来越多,compaction的过程被阻塞,导致文件数一直在增多。通过nodetool  compactionstarts可以看到叫Pending task的数据,通过这个数据可以定位是否是compaction任务太慢或卡住了,导致有太多堆积的compaction任务没有完成,如果是,可以通过调整Compaction的并发数或者升级拥有更赋予的cpu资源来完成compassion任务,起到优化的效果。

场景二

写入少,读取多,对响应延迟较为敏感。

Compaction是自然默认的compaction策略,默认的compaction策略叫做size tiered compaction,在这个Compaction实行很多次之后,磁盘上的ss table会形成根据大小进行分层的一种分布,也就是会出现一些相对较小的ss table或者大小比较中等的ss table以及大小比较大的ss table。这些ss table根据它的大小形成一个分层的一种设计。这个compassion策略作为默认的一种compaction设计,有好处,但是也有劣势。每一个table可能会存在重叠,所以在最坏的情况下,读取请求进来后,可能会需要对每一个ss table做一次sick操作,才能知道在当前ss table里,是否有对应需要的数据。文件数越多,设计的io就越长,延时就越长,这时可以考虑使用另一种Compaction策略,叫做leveled tiered compaction。会把磁盘上的ss table分成若干层,每一层里面的ss table相互之间没有重叠关系。有了这个保证,所以读取请求进来之后,在每一层里面,最多就只会有一个ss table会纳入到归并排序当中,所以层级次数会决定涉及这一次读取请求需要ss table的上限,从而更加可控。

但由于它需要保证每一个层级里面ss table之间相互不重叠,所以对于写的时候,会产生较大的放大和较多的Compaction任务的执行。比较适合于读较多,但是写入比较少的一种场景。

 

场景三

写入量级特别大。

类似于iot行业,物联网行业,或像滴滴轨迹记录行业,以上都很少有读,但是写入量级特别大,以下就是针对这个场景的优化思路。第一,需要知道的是网络延迟远远高于磁盘的写入延迟,所以在写入量级特别大的时候,可以考虑用批量写入的方式来使网络延迟减少客户端和服务端的交互次数,从而减少网络延迟的影响,Cassandra Batch不是为了批量写入这一个场景而设计的,它的功能强大,可以实现跨表级别的事物,但是在这样的使用方式下,它的性能损耗比较大。不太符合这个场景下的初衷,所以在实现一个批量写入的时候,需要注意的是,在做Batchinsert的时候,更适合对于同一个表做处理,不宜做跨表写入。需要unloged batch写入,而不是loged。使用unloged可以避免在实现事物的时候存在的巨大的性能损耗。

同时由于它并不是专门为了批量写入这个场景而设计的,所以每一个批量写入包含的写入数最好不超过十。

如果第一个场景不能满足写入的要求,大概率会遇到瓶颈,即commit log sync跟不上写入速度。

其原理就是在每十秒对Commit log做一次sync操作,sync操作就是把内存里面的commit log刷到磁盘里,这意味着每次审核都会产生一次磁盘写入峰值。这一次写入其实并真正的写入到磁盘的介质当中,而会写入到一个叫磁盘的page cache里,默认的磁盘的page cache会周期性的将需要持久化到磁盘介质里面的内容下刷到磁盘里面。每次写入磁盘都是一次大批量的写入,会产生一个较大的峰值,大概率会触发写入流量的限流策略,所以在这个情况下面,调节linux内核参数,例如dirty right back和dirty expire这两个参数,可以提高page cache下刷云盘的频率,从而导致每次刷下去的大小都会减小。不容易触发限流策略,导致io weight显著的降低,对于写的延迟会有一个质的提升。

Cassandra性能压测及调优实战|学习笔记

另一个cassandra写入的原理,由于默认每十秒做一次sync,再写入的量级特别大时,这十秒内会堆积大量的commit log,需要被sync到磁盘。commit log的sync操作是一个单线程的处理操作,可想而知,当sync速度跟不上写入的速度时,写入就需要被block住等待。以下代码根据上一次sync完成的时间点和当下期望的时间点,如果sync小于期望sync的时间点,证明sync的速率跟不上写入的速率。于是就会有等待的操作去降低写入的tps,能让sink追上。根据搭建一个完整的监控系统来看,cassandra的监控指标叫做waitoncommit,可以定位是否是由于这一个瓶颈导致的。

而在云Cassandra里面,由于每一个commit log都是一个单独的文件,在云Cassandra上,通过文件级别的并发,实现了sync环节的处理效率的提升,从而解决了这一个问题。

 

Cassandra性能压测及调优实战|学习笔记

如果对数据进行应用多副本,数据可靠性会更高,磁盘出现故障的时候,数据不会丢失,在多副本中的一条写入请求,会走到接收节点,往往接收节点自己会形成一个副本数,同时会像其他的节点去带领发送请求,从而满足设置的副本数。在cassandra里面,每一个节点和急需的其他的节点都会维护一个队列来保存节点和节点之间通信的消息。假设设置三副本,10万级别的写入量级,就会产生20万级别的内部消息的通信成本。副本数越多,内部消息通信的放大就越严重,但量级过高的时候,可随着默认的队列实现,会产生很严重的冲突,从而导致性能降低。

此时,可以通过降低副本数来达到减少内部通信的量子液去规避这个问题,或者增加节点数,节点数增加后,变相的节点之间的队列数就增加了,每一个队列的负载相对就会减少,从而也可以达到降低冲突的效果,但是这两个措施都需要业务改造,并且都有对应的成本,例如副本数降低,数据可靠性就降低了,或者集群节点数增加,其实增加的是运维的成本。而云Cassandra是通过去修改它的源码实现了一个高性能的无锁队列。

Cassandra性能压测及调优实战|学习笔记

 

场景四

读响应时间长,io重。

通用的使用误区就是在cassandra3的版本时,如果使用压缩,默认的大小是64kb。某种程度上是合理的,因为压缩需要针对指定的大小去进行压缩,才能达到比较理想的压缩率,磁盘的存储成本才能够降低,但是默认的64k依然很大,所以已经调整为16k。在4的版本里面默认的压缩的块大小就是16k,同时有比较理想的压缩率并且io会显著的降低。一个请求下来之后,需要落到对应的block下面做一个block,如果说是在磁盘里,需要把默认的64k全部读出来,做解压缩,然后才能找到对应的数据。

当block的大小设置得太大的时候,磁盘io会增加很多,通过alert表属性进行调整之后,还需要做major compaction才能使这个调整真正的生效。

Cassandra性能压测及调优实战|学习笔记

磁盘io重就是因为cache的命中没有命中到,才会走到磁盘,才会产生磁盘io。所以可以通过nodetool info这个工具看到对应的命中率。如果实力上有较富余的内存资源,可以调整chunkcache,key cache的大小,从而去提升cache的命中率。这样落到磁盘上的io就会显著减少,降低io,从而读响应时间会更加快。

如果场景是80%的读请求集中在20%的row上面,也可以考虑开启Row cache功能,这个功能默认关闭,因为会带来内存上的压力。

至于说key cache,row cache和chunk  cache三个cache的大小如何设置是没有一个最佳的比例的,可以根据的实际情况来调整三个cache的大小关系。调整往后以监控数据为准,监控数据实际效果好的就是最佳的大小比例。完善的监控不仅能够发现问题,还能去验证优化效果是否达到了预期,或优化措施是否有效果。Cassandra性能压测及调优实战|学习笔记

 

场景五

读响应毛刺较高。

如果毛刺较高,大概率是gc导致的。参考调参最佳时间,调整gc相关的参数能够实现gc的优化。还可以考虑使用cassandra自带的叫speculative的特性。speculative的工作原理就是客户端向服务端的节点发送了请求,根据设置的阈值,在超过这个阈值之后,如果请求还没有得到响应,就会选择第二个节点发送请求。

此时,针对一个请求发送了两次请求,到服务端这两次请求中任何一次请求优先返回之后,这一次请求都算成功。都算生效,所以集群里面会周期性的有一些慢节点,通过这个阈值来判断是否遇到了慢节点,如果是就可以通过一系列操作来规避这个慢节点导致请求一直被卡住。

如果阈值设置过小,会产生较多的额外请求,会增加整个集群的负载和压力,如果阈值设置得过大,就起不到应有的效果。于是,应该不断地调整阈值,去找到比较合适的一个点。

性能调优总结

一定要有监控,有监控才能分析,有监控才能评估优化效果,监控是性能优化的出发点和终点。

熟练掌握相关工具

要对原理有一定的理解

上一篇:基础设施助力双11(四):图片编码FPGA硬件优化


下一篇:持续九年,国际排名第一的宽表数据库概述|学习笔记