十、CASSANDRA集群从云主机迁移物理机

背景

我们的cassandra集群是2019年4月份上的生产,压缩策略采用的是TWCS,数据保存10天,数据在8T左右,使用的是8台16C32G的云主机,当时日流量是30亿+,每台主机的CPU在50%左右,看起来一切都很正常,但是到19年8月份的时候,日流量达到了50亿,从这时候开始,偶尔有主机实例宕机的情况出现,观察发现有几台主机的CPU飙高(80%),剩下的其它主机CPU却很低(50%),同时集群所有节点的数据流入量却非常均衡。经过多天的观察对比发现,top命令的ST指标飙高,早高峰时可以达到30%。
ST:反映的是云主机等待底层物理机分配资源的等待时间,ST越大资源争抢越严重,ST是反应云主机稳定性质量的重要指标。问题定位之后就开始寻求解决方案,我们最开始找云平台同事帮忙解决这个问题,对方的答复是一台宿主物理机的CPU核按1:5比例虚拟出5台云主机,CPU无法隔离无法固定分配比例,如果是计算密集性应用,这种争抢是无法避免的。很明显,云主机无法提供稳定的性能(实际上,cassandra官网有AWS解决方案,不清楚AWS云主机是否也有资源争抢的问题,他们是这么解决的),因此我们决定购买物理机替换云主机。

方案及验证

由于涉及到从8台云主机切换到至少4台物理机,涉及到10T+数据的迁移,同时数据迁移过程不能影响业务正常使用,我们制定了在线切换方案及实施步骤:
一、扩容(原集群3节点)
1、准备新增实例XX.XX.XX.255
2、限制所有节点数据迁移流量
nodetool setstreamthroughput 32
3、启动新增节点 :cassandra -R
4、nodetool status,新增节点状态为UJ
二、修改集群种子节点
1、在第一步数据同步完成支行,将新增节点调整为种子节点
修改配置配置文件cassandra.yaml, 将seeds配置为:XX.XX.XX.255
2、重启实例
nodetool flush;
nodetool stopdaemon;
cassandra -R
3、依次修改其它节点的配置文件cassandra.yaml,将seeds配置为XX.XX.XX.255,然后依次重启(一台实例重启完成后再重启下一台)
三、修改应用(我们的是一个监控系统)的配置文件,调整种子节点配置,然后重启。
四、删除节点XX.XX.XX.66(验证生产环境云主机下线流程)
1、所有节点限流
nodetool setstreamthroughput 32
2、在被删除节点执行命令
nodetool decommission
3、查看集群状态
nodetool status 删除之前状态为UL
五、扩容异常情况验证
1、步骤同第一步
2、数据未迁移完成前, KILL cassandra进程
3、测试上层应用是否受影响
4、重启cassandra,验证数据是否续传、数据是否有丢失
六、删除节点异常情况验证
1、步骤同第四步
2、数据未迁移完成之前,KILL cassandra进程
3、测试上层应用是否受影响
4、重启cassandra,验证数据是否续传,数据是否有丢失
七、数据负载验证(物理机性能好,并行期间,物理机要多分担流量)
1、准备一个新实例
2、修改配置文件cassandra.yaml的配置项num_tokens: 384
3、新节点加入集群完成后,看各节点数据是否按 云:物=1:1.5比例分布。
八、重点关注点
1、新增/删除节点过程中对上层应用的影响
2、新增/删除节点过程中cassandra实例的CPU、内存、磁盘的变化情况,评估是否支撑正常业务
3、迁移速率、评估新增/删除一个节点需要限多大的流,迁移需要多长才能完成,以便评估生产环境夜间迁移是否能够完成。

为保证上述方案在生产环境顺利实施,我们在测试环境我们对以上步骤及场景一一做了验证,测试情况如下:
场景一:正常扩容:往集群中增加实例,中间无异常间断;实例启动以及数据迁移过程中,构造数据向cassandra集群推送数据.
测试结果:以配置的流量限制迁入数据正常;上层应用访问cassandra正常;推送的数据无丢失;CPU、内存、入流量、出流量与测试场景符合
现象:新增节点的入流量18MB/s,集群节点的出流量6MB/s,新节点CPU50%以上,原集群节点的CPU基本无变化,说明数据迁出对CPU影响小。

     场景二:修改种子节点:将新增节点调整为种子节点,重启种子节点;种子节点修改、重启以及数据迁移过程中,构造数据向cassandra集群推送数据
     测试结果:上层应用访问cassandra集群正常,推送的数据无丢失;CPU、内存、入流量、出流量与测试场景符合

	场景三:正常场景删除节点:从集群中删除某台实例,中间无异常间断;节点移除过程中,构造数据向cassandra集群推送
	测试结果:以配置的流量限制迁出数据正常;上层应用访问CASSANDRA集群正常,推送的数据无丢失;CPU、内存、入流量、出流量与测试场景符合
	      现象:出流量节点,CPU基本无变化:维持15%;入流节点,CPU有增长:从20% 增至 60%
	      
	场景四:异常场景扩容:往集群中增加实例,数据迁入过程中终止进程,而后重启新增的实例;终止及重启过程中,构造数据向cassandra集群推送
	测试结果:整个过程上层应用使用正常,推送数据无丢失;重启实例后,数据续传(无需重新执行命令);CPU、内存、入流量、出流量与测试场景符合

	场景五:异常删除节点:从集群中删除某台实例,数据迁出过程中终止进程,而后重启新增的实例;终止及重启过程中,构造数据向cassandra集群推送
	测试结果:整个过程上层应用访问cassandra集群正常,推送数据无丢失;重启实例后,按原数据重新迁出(状态变为UN,需要重新执行删除节点命令才会重新迁出数据);CPU、内存、入流量、出流量与测试场景符合

   场景六:数据负载验证:在扩容时,配置新增实例num_tokens为不同的值,测试该实例是否有不同的数据负载效果;实例启动以及数据迁移过程中,构造数据向cassandra推送
   测试结果:整个过程上层应用访问cassandra集群正常,推送数据无丢失;数据迁移完成后,该实例负载的数据与num_tokens值的配置相符;CPU、内存、入流量、出流量与测试场景符合
   现象:XX.XX.XX.77加入节点完成后,CPU一直维持50%,分析原因是因为短时间内流入大量数据,compact不及时有很多SSTABLE引起的,过几个小时后CPU下降

测试结果:数据迁移过程无异常,测试环境配置流量限制为20MB/s,正常迁移160G的数据约耗时3h,均速约50G/h
测试建议:生产环境可参考此数据迁移方案进行数据迁移,但由于生产环境数据量过大,仍需随时关注迁移情况以及上层应用的使用情况。

物理机选型及优化处理

公司的物理机型号有限,可选择面比较小,我们选择了成本最低又能满足性能要求的一个物理机配置:
CPU :24C
内存 :384G
磁盘 :2600G(SAS2.5,12G,10K) + 124T(SATA3.5,6G,7.2K)
LINUX:CentOS-7.4

本节所指优化方面主要涉及到LINUX操作系统层面的系统优化、磁盘raid选型、cassandra集群配置优化等。
一、系统调优、cassandra集群配置优化
相关内容在前面章节已详细介绍,在此不做过多说明。
重点两点:
1、JVM堆内存最大不要超过32G:
超过32G内存后,Java8的JVM启用UseCompressedOops,也就是不会启用压缩对象指针,jvm在内存小于32G的时候会采用一个内存对象指针压缩技术。
在java中,所有的对象都分配在堆上,然后有一个指针引用它。指向这些对象的指针大小通常是CPU的字长的大小,不是32bit就是64bit,这取决于你的处理器,指针指向了你的值的精确位置。
对于32位系统,你的内存最大可使用4G。对于64系统可以使用更大的内存。但是64位的指针意味着更大的浪费,因为你的指针本身大了。浪费内存不算,更糟糕的是,更大的指针在主内存和缓存器(例如LLC, L1等)之间移动数据的时候,会占用更多的带宽。
Java 使用一个叫内存指针压缩的技术来解决这个问题。它的指针不再表示对象在内存中的精确位置,而是表示偏移量。这意味着32位的指针可以引用40亿个对象,而不是40亿个字节。最终,也就是说堆内存长到32G的物理内存,也可以用32bit的指针表示。
一旦你越过那个神奇的32G的边界,指针就会切回普通对象的指针,每个对象的指针都变长了,就会使用更多的CPU内存带宽,也就是说你实际上失去了更多的内存。事实上当内存到达40-50GB的时候,有效内存才相当于使用内存对象指针压缩技术时候的32G内存。
2、针对物理机内核几个关键调优
kernel.msgmnb = 65536
以字节为单位,规定了一个消息队列的最大值;
默认值为:65536,即64k;
kernel.msgmax = 65536
进程间的通信需要依靠内核来进行管理;是通过消息列队来 传递消息;以字节为单位,规定消息的单大值;默认为65536,即64k;此值不能超过kernel.msgmnb的值,msgmnb限定了消息队列的最大值;
kernel.shmmax = 68719476736
定义单个共享内存段的最大值,我们的内存是384G,此值还可以设置得更大;
是核心参数中最重要的参数之一,用于定义单个共享内存段的最大值,shmmax 设置应该足够大,设置的过低可能会导致需要创建多个共享内存段,64位linux系统:可取的最大值为物理内存值-1byte,建议值为多于物理内存的一半,一般取值大于SGA_MAX_SIZE即可,可以取物理内存-1byte。例如,如果为64GB物理内存,可取6410241024*1024-1=68719476735
kernel.shmall = 4294967296
为单位,控制共享内存总量;Linux一个内存页大小为4kb,共享内存段的大小都是共享内存页大小的整数倍。一个共享内存段的最大大小是 16G,那么需要共享内存页数是16GB/4KB=16777216KB /4KB=4194304(页),也就是64Bit系统下16GB物理内存,设置kernel.shmall = 4194304才符合要求(几乎是原来设置2097152的两倍)

二、磁盘规划
cassandra有三种数据需要存储,分别是:commitlog、hints、data,其中commitlog、data都是高频的IO操作,在生产环境,这两种数据必须使用独立的磁盘,hints数据考虑到只有在特殊情况下才使用,我们是把它和data放一起,如果条件允许,可以单独盘存放。
先看下各种数据对磁盘的性能要求及磁盘大小要求
commitlog:高频的顺序写,对磁盘性IO性能要求较高、100G以下足够
hints:只有在集群中某台实例宕机时才会用到,也是顺序写,IOqps要求较低,磁盘要求较大,磁盘大小 > (小时入流量 / (n-1))  * 可容忍宕机时间(小时),一般500G以上。
data:数据文件,一个节点2T左右比较合适(网络、数据迁移等),考虑到物理机性能,我们一个节点规划了4T的容量。

以下是对常用RAID配置对比:
参考:https://www.cnblogs.com/qiumingcheng/p/11226058.html
          https://blog.csdn.net/ensp1/article/details/81318135
          https://blog.csdn.net/leo0805/article/details/79231853

(以下结论都是在没有cache或cache命中不高的情况下的raid阵列本身的性能对比,现在很多磁盘都有cache,在cache全部命中的情况下,性能相差都不会很大)
raid0:有最高的存储性能
磁盘空间使用率:100%,故成本最低。
读性能:N单块磁盘的读性能
写性能:N
单块磁盘的写性能
冗余:无,任何一块磁盘损坏都将导致数据不可用。
raid1:性能较差
磁盘空间使用率:50%,故成本最高。
读性能:只能在一个磁盘上读取,取决于磁盘中较快的那块盘
写性能:两块磁盘都要写入,虽然是并行写入,但因为要比对,故性能单块磁盘慢。
冗余:只要系统中任何一对镜像盘中有一块磁盘可以使用,甚至可以在一半数量的硬盘出现问题时系统都可以正常运行。
raid5:正常情况下的读性能仅次于raid0
磁盘空间利用率:(N-1)/N,即只浪费一块磁盘用于奇偶校验。
读性能:(n-1)单块磁盘的读性能,接近RAID0的读性能。
写性能:比单块磁盘的写性能要差
冗余:只允许一块磁盘损坏。
raid10:
磁盘空间利用率:50%。
读性能:N/2
单块硬盘的读性能
写性能:N/2*单块硬盘的写性能
冗余:只要一对镜像盘中有一块磁盘可以使用就没问题。

以下是我们对2 * SATA RAID1 顺序写性能测试数据如下,因为我们的BMS产品的服务器都是有阵列卡(数据先写cache再写磁盘)进行加速的,测试数据如下:
顺序写:
数据块 8K bw=1012MB/s
数据块 16K bw=1845MB/s
数据块 32K bw=2253MB/s

综上我们各个盘的配置如下:
系统盘:2 * SAS RAID1 (安全)
回滚盘:2 * SATA RAID1 (磁盘不用太大,性能满足要求,与数据盘相互独立)
数据盘:10 * SATA RAID10 (磁盘容量大、性能高高、安全:顺坏一块磁盘的时候不影响性能)

有些同学一定会问数据盘为什么不选择raid0、raid5?
1、磁盘容量充足,用raid10都有20T的空间使用;
2、性能上完全满足要求,raid1性能已足够好,raid10性能只会更好,没有必要选择raid0, 而raid5写的性能不如raid10。
3、若选择raid0,磁盘损坏后需要替换磁盘,然后要数据同步(3-4T),影响整个集群性能;而如果是raid5的磁盘损坏,替换损坏磁盘重建数据时, RAID5 的性能会受到较大的影响。

查看阵列情况:
#  fdisk -l | grep sd
Disk /dev/sda: 599.0 GB, 598999040000 bytes, 1169920000 sectors
Disk /dev/sdb: 4000  GB, 3999999721472 bytes, 7812499456 sectors
Disk /dev/sdc:  20000 GB, 19999998607360 bytes, 39062497280 sectors

查看挂载情况:
# lsblk

生产实施及问题

物理机准备就绪后,生产环境九按照之前制定的迁移方案去实施的,每周增加一台物理机,等物理机都加入集群后,云主机再一台台的删除,整个过程持续了3个月。
期间也遇到一些问题,都一一解决了

问题1:CPU使用不高,但一直有压缩任务积压,原因是没控制好限流,短时间内接受大量的数据,却来不及压缩造成的。
	查看积压任务:nodetool compactionstats -H
	解决方案:调整压缩线程配置:concurrent_compactors 默认2个,调整为3个。
		
问题2:不管是扩容还是删除节点,数据都会重新流动分布,造成每个节点数据会全量进行SSTABLE压缩(TWCS),迁移完成后,每个节点都会有大量sstable压缩任务,从我们的经验看,数据迁移一般10h内完成,但压缩任务一般会持续24h甚至更多,因此我们扩容或删除操作一般选择周五晚上进行。

问题3:云:物流量分配评估不足,造成云主机下线到最后2台的时候,云主机的负载相比性能来说太高了,云主机的CPU消耗在80%以上,还经常有宕机的情况出现,SSTABLE也有大量积压,不能及时完成压缩。
	解决方案:物理机的num_tokens可以再调大点,分担更多的流量。
		
问题4:问题3中由于云主机性能达到极限,很多SSTABLE来不及压缩,造成很多SSTABLE小文件(所谓小文件就是这些SSTABLE都是几十KB大小),这些小文件有几万个,恶性循环,性能越来越差,压缩的效率也很慢,基本不可能自愈,而且更严重的是,如果这时候进行集群扩容或缩容,这些小文件会扩散到集群中的每一个节点,造成每个节点都有很多压缩任务,压缩效率也非常缓慢,CPU也飙高。
	解决方案:1,扩缩容之前先坚持每个节点是否有小文件,如有先清理小文件,然后再进行扩缩容操作;
             2,若小文件已经扩容了,需要人工介入删除数据,根据数据有效期决定下个节点删除数据的间隔;数据备份数决定一次可以删除多少个节点的数据。
               删除小数据方案:
                 		a.  刷新缓存落盘:nodetool flush
                 		b.  停实例:nodetool stopdaemon
                 		c.  删除数据:
                 			cd /cassandra/data/mytestdb/mytable-0432ewljldssldfldsf323fsds/
                 			rm -rf mc*;
                 		d.  重启实例:cassandra -R
                 	    e.  间隔一个数据有效期后删除下个节点的小文件数据。
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值