咨询热线
18580233332
![]() | ![]() | ![]() |
微信扫码 阿里云返佣 咨询 | 微信扫码 阿里云折扣 咨询 | 微信扫码 技术支持 |
电话:18580233332 QQ客服:32738651 | 电话:18623333330 QQ客服:2194888888 | 电话:18581111185 QQ客服:3388866681 |
Cassandra云数据库简介、Cassandra云数据库特性以及Q&A。
我们先了解一下Cassandra云数据库在阿里云上的部署和架构。首先这个架构主要反映了三个方向:
接下来我们深入了解一下单个DC和集群的情况。
除此之外,我们其它的架构和Apache Cassandra几乎是一样的。
接下来我们介绍一下Cassandra云数据库的特性:
即将上线的服务包括:
接下来,我们介绍一些我们在功能上做的优化。由于时间关系,我们只能重点介绍一部分功能优化。
第一点,我们做了一些自动化运维手段。
这个事情的背景是由于Cassandra是一个去中心化的数据库,社区建议用户做repair,目的主要是保证Cassandra三个或多个副本之间的一致性。Repair能够把副本上的数据做一个修复或者补齐,保证副本的数据是一致的。Repair是必须要做的,然而在我们的使用场景中,repair会引入一些问题:
在介绍我们的改进措施之前,我先来大概介绍一下repair的机制:在图中我们可以看到三个副本ABC,第一步repair会在三个副本上构建全量的Merkle Tree,第二步会比较ABC副本的Merkle Tree之间数据的差异,第三步再通过一个类似于Steaming的过程把数据补齐。
我们改进的目的是什么呢?
我们希望我们repair的过程是自动化的,不需要引入人工干预。这样当我们云上的集群越来越多或者用户扩容缩容的时候,我们不需要人工的干预,这样可以降低云上运维的复杂性,大大释放了人力资源。第二个目的是希望整个repair的过程是一个开销较小的过程,这样可以保证repair对线上服务的影响很小。
那么我们repair的大概原理是这样的:我们可以在图上看到ABC三个副本,每个副本节点上都会有一个primary range主范围。我们会把primary range切分成很小的组。每个node只会负责修复自己primary range的数据,它不会去管别的数据。比如说B这个节点,它有一个primary range是A到B,除此之外它也会有C到A的副本数据,但是这个部分节点B不管,它只管A到B的数据的修复。这样会降低我们修复的数据量。
节点B只管A到B的primary range,我们会把primary range切分成很小的段,这个部分是为了我们后面做断点续传。我们会针对每一个sub_range做修复。这个服务是在Cassandra的kernel里面,它是一个独立的修复模块。当Cassandra进程启动后,这个服务会首先会将primary range切分成sub_range。每一个sub_range会有一个自己的task,然后这些task会进行排列。这之后,我们会对所有的sub_ range从开头到结尾进行轮询scan。每次scan会把sub_range里的数据拿出来,现在我们设置的是每一次拿10条数据。我们独立实现的repair的module的读写链路和正常的读写链路是分开的,这样的好处是repair不会影响正常的读写链路。
除此之外,官方建议,一轮repair应该在gc_grace_seconds范围之内做完。那么我们可以通过流控控制每一个primary range修复的时间,也可以控制每一次服务对线上的影响。每一个sub-range做完之后,我们会在一个system表里面做记录。比如当我们修复到B节点的sub_range2时出现问题了,下一次B节点再启动时会通过system表断点续传到sub_range2,然后sub_range2继续完成任务。这样做的好处是很多过程可以完全自动化,独立的修复链路不会影响正常的读写链路,除此之外还可以降低对线上服务的影响以及有一个可控的修复时间。
接下来我们就性能增强方面选一个点进行详细介绍。
我们的性能增强基于我们阿里云的部署形态,我们的底层使用的是盘古提供的块存储设备。我们可以看到Cassandra原有的架构是上面是LSM,底下是我们现在用的Ext4文件系统,然后是一些操作系统的处理(比如Logical Volume和Volume Group),最终落到下面是有一个单独的disk放commitlog,其他的disk会放sstable。这样的部署模式会引入一些问题:
那么我们的优化方式就是把底层通过LVM条带,可以把下层的cloud disk1-4 bind起来。这样当从上层写入时,不论是sstable还是commitlog,都可以充分利用四块盘的资源,而不是只有disk 1写commitlog,其它disk 2、3、4写sstable。我们是把四块盘的并发能力全用起来。当写入一个commitlog,它不只是被写入disk 1。通过LVM条带,commitlog和sstable会被分成chunk,并发地写入disk 1、2、3、4。
这样的好处一是可以利用LVM的条带化和多盘的并行能力提高写入性能。现在我们的写入性能比之前提高了20%以上,这是一个平均数,比较极致的提高会更多。第二,我们的四块盘既可以提供commitlog也可以提供sstable,我们就不需要额外的一块盘放commitlog,这样的性价比是最高的。另外,假设我们四块盘加起来的容量是80个G,它们对应的IOPS和一块80个G盘的IOPS是一样的,但是前者的价格会比后者低。通过这个方式,我们可以把整个Cassandra产品的价格降低。第三,我们底层所用的盘古可以提供比较极致的数据可靠性(9个9)。我们可以利用盘古的数据可靠性和LVM的条带化保证数据节点的数据可靠性,因为如果单块盘的数据可靠性不高时,LVM条带化是用不起来的。
除此之外,我们做了一些功能性的增强。
第一,我们支持全量和增量的备份恢复。原有的Cassandra并没有一个机制可以把增量的备份恢复做到同一的系统里面。我们现在能做到的是,假设原集群是三个节点,我们可以恢复到对应的三个节点。我们现在在云上的宗旨是恢复到对等节点。
我们的备份和恢复分为两部分:全量的备份恢复和增量的备份恢复。
首先我们在图上有snapshot这个点,我们会对各个节点并发地做snapshot,做完snapshot我们会有一个全量的sstable。在打完snapshot这个时间点以后,我们会开始做增量的备份。增量的备份我们分两部分:一是incremental backup是社区已有的功能,我们在此基础上做了一个表级别的备份恢复的点。除此之外,我们还做了一个增量commitlog的数据备份恢复。
可能有的用户会问,增量的incremental backup和commitlog的数据其实是有重叠的,我们后面会对此做一些介绍,解释我们为什么这样做。
我们通过snapshot打完全量的快照以后,把每个节点的数据备份到阿里云的oss上面去。当用户选择恢复的时候,我们会对用户所有的sstable做对等拓扑的恢复,每个节点的token范围也是对等映射的。这样做的好处是可以不通过sstableloader的方式把sstable load进去,这样恢复的速度是最快的。我们只需要做一个对等拷贝,然后做一个单节点的nodetool refresh就可以了。
增量我们通过incremental backup及WAL log online archive来做。我们在云上做了这样的一个优化:每次从memtable flush下来的sstable会通过incremental backup产生hard link到对应的backups目录,同时扩容节点的时候,streaming生成的SSTable也会产生hard link。我们会把hard link对应的SSTable也备份。
除此之外,我们利用了Cassandra原有的archive功能,把每个节点写入的WAL log也做一个备份。当每个commitlog生成的时候,它都会把一个hard link到用户指定的地方。因为archive是需要重启集群和节点的,我们在这里做的一个优化使之无需重启。我们做了一个在线归档的功能,只要用户点击某个命令,开启incremental backup log的归档,我们会有对应的进程把log收到OSS上面去。因为我们的备份恢复是对等拓扑的,节点在恢复的时候都会对应到与它相关的token的节点上去。它恢复的时候可以做本节点的nodetool flush以及本节点的commitlog replay,并且这个replay是online replay。
这样的好处是备份恢复的时间是最短的。Incremental backup和commitlog的组合可以让恢复的时间是最短的,因为我们通过incremental backup的sstable筛选出需要恢复的WAL log/commitlog,然后做一个归档。这样的话可以避免log的replay的时间越来越多。
接下来我会介绍一下我们的数据迁移。
Cassandra原有的数据迁移分为COPY TO/FROM命令和文件级别的sstableloader两种。COPY TO/FROM是一个多线程读写key value的操作,当数据量比较大时,它的速度会比较慢。就sstableloader来说,O1、O2、O3节点上的数据都需要被load,load到新的集群时可能会有一些冗余。另外实时新增的数据可能处理得不会很融洽。
在这里,我们启动了阿里云的BDS服务。无论原集群和目标集群是对等或不对等拓扑,它们都可以通过BDS高效迁移。
原有的sstableloader方案中,原集群所有节点都需要进行一个类似于streaming的过程,并在目标集群进行一个拖数据的过程。原集群中节点o1的文件可能和目标集群中的节点n1、n2、n3都会有重叠。原集群o1中的文件复制到目标集群可能要有一个三副本的放大。当原集群有三个副本,目标集群也三个副本时,一份数据通过sstableloader可能会有九倍的放大。这会产生冗余。
当使用BDS,我们把原集群和目标集群做了数据范围的映射。原集群的primary range的数据我们只会迁移到目标集群的primary range,副本节点的数据会迁移到副本节点。我们的副本摆放策略默认使用SimpleStrategy,根据这个副本摆放策略我们做一个副本范围的一一映射。当某个sstable在目标集群上横跨了多个节点时,我们会对于这个sstable做一个切分,切分后需要把对应的数据复制到对应的节点上面去。这样可以避免数据的冗余。
除此之外,我们还做了文件级别的迁移,速度比较快。另外我们也支持增量数据的迁移,包括增量的commitlog和incremental backup。我们支持实时的增量数据的迁移需求,用户只需要通过我们的BDS服务,无需额外操作即可完成无缝迁移。
最后,我来介绍一下我们监控报警的大概模式。我们会分三个层面来介绍。
首先是OS操作系统层面。
因为Cassandra是share-nothing的架构,它是直接写本地的文件系统。对于本地的文件系统的error我们会做实时探测,对网络包package的异常处理我们也会做监控。在这里像file system error这样的相对比较重要的error,我们会通过unavailable这样的异常报给Ops服务。我们也会对Cassandra的daemon death进行实时监控,在Cassandra每一个进程的机制下面,我们都会有个单独的agent来发出system error,包括网络和内存的异常。另外Cassandra daemon的判活还有gc。关于gc,我们比较关注的是时间比较长的后续情况,超过500毫秒我们会通过发出unavailable异常报给Ops同学。
第二个层面是Logs层面异常的收集。
第一是slow cql,就是读的时候比较慢的cql,我们会收集。gc log是Cassandra自己的GCInspector的log,还有warn log比如large partition。这些我们会通过SLS收集,之后相关的报警也会告诉我们值班的同学,最上层是Cassandra自己的metric的信息。Metric信息我们会分两类进行处理。第一是展示给用户的Metric,比如容量、compaction等,是我们觉得用户会比较关心的,会通过CMS给用户。全量的80%的metric也会通过CMS链路报给我们自己的Ops同学。通过这种方式,我们可以对metric也设置一些报警。