吴太银:华为消费者云服务Cassandra使用场景与最佳实践

你们好,我是华为消费者云的吴太银。node

 

我今天分享的主要是华为消费者云服务使用Cassandra的应用场景和最佳实践。我这个可能跟其余嘉宾分享的不太同样,由于前几个嘉宾讲的实际上对Cassandra原生的代码有必定的修改,而咱们当前使用的是纯粹的、原生的Cassandra,咱们没有作任何的修改。因此这个分享能够给一些想大量使用原生的Cassandra的朋友有比较好的借鉴意义。算法


我今天会大概从这三个方面来给你们介绍一下:第一个就是咱们用Cassandra的一些使用历程,经验和教训,以及咱们当前的规模;第二个就是咱们现网遇到的典型问题,我以前跟组织者交流,由于咱们当前的规模比较大,他主要是想看咱们在用到典型的ToC场景下,在用到大规模,大数据量的状况下,在现网有哪些典型的问题,这个对你们应该有必定的启示做用(哪些是Cassandra的雷区,是不能碰的,若是你把这些避免掉,就不会出大问题);第三个就是咱们使用Cassandra总结出来的最佳实践,由于咱们如今全部的终端业务,基本上都会用到Cassandra,咱们的业务场景很是的复杂,必须有些设计上的,包括表结构的设计上的约束,不能随便用,由于随便用它必定会有问题。这个在前面的各位演讲嘉宾也常常提到:咱们要顺着它来用。数据库


咱们如今先看一下为何选Cassandra。你们可能都比较清楚了,我就简单的说一下:一个是去中心化的部署,不但简单,并且扩展性很好,能够轻松应对业务发展带来的数据容量和性能上的要求;第三个是它自然支持多DC的部署,咱们当前是一主一备,再加容灾,三个数据中心,它自然的支持(这种部署),内部自动同步;第四个是它的监控指标和监控接口很是完善,经过nodetool和JMX能够很是容易监控到Cassandra原生的各个指标,这个在咱们后面的幻灯片里会看到,这一块是很是重要的,在现网,特别是你在集群规模变大了以后,你须要快速恢复一些故障的时候,没有这些东西,你是作不到的;第五个是它的这个开源社区确实很活跃,包括稳定的版本演进,可让咱们不停的选择它。缓存


这个(幻灯片)是咱们的使用历程,给你们看一下。咱们其实是从2010年开始就使用了。Cassandra是差很少2008年开始在Apache孵化,咱们差很少是跟孵化同时的时间开始接触,一开始是0.7版本。Cassandra在咱们这边用大概分两个阶段:前一个阶段,多是一个相对来讲比较失败的一个经历,由于这个阶段咱们仍是主要用于ToB的场景。当时咱们的华为手机还没彻底(流行)起来。这个场景在这个阶段咱们面对都是电信级的应用。安全

 

在这个时间段,其实NoSQL尚未彻底流行起来。咱们找的应用都是电信级的应用。可是电信级的应用你们都习惯用SQL的方式去作,第一个当时KV的方式你们也不太习惯,第二个当时Cassandra的接口不像如今这么好。当时是纯的Thrift接口,如今支持CQL,还有不少CQL的驱动。因此说当时是咱们找业务,因此咱们要按照它的使用方式,提供了一堆的定制化的东西,好比说咱们在Thrfit的基础上,定制了一个类JDBC的接口,让它像SQL同样用Cassandra。这一块当时咱们也是深刻的修改,咱们写了一整套SQL解析的模块(DDL,DML所有都重写了,而后转换成原生的mutation对象)。序列化和反序列化咱们所有都改了。包括咱们作得比较前沿的东西(由于当时0.7的版本尚未堆外内存),由于它的GC比较严重,咱们把memtable, index summary, bloom filter, row cache, key cache这些常驻内存的一大部分所有都放到了堆外。网络

 

另外,咱们还作了存储过程、二级索引、触发器等。其实当时咱们就是对标的关系型数据库去作。可是实际上咱们你们也知道原本Cassandra原生的是列数据库,咱们强制按照行的方式来改造,实际上有很大的问题。再加上电信级的业务场景,这个对可靠性和数据的准确性的要求是很是高的。因此说咱们当时虽然作到了SQL的形状,可是实际上没有SQL的实质。这个只是在小范围使用,也没有彻底用起来。这个基本上算是一个失败的尝试。架构


而后这个过程对咱们有什么好处呢?这个让咱们深刻的看到了一些Cassandra架构,以及它的处理方式,还有它的源码。由于在后续的发展过程当中,Cassandra的代码虽然重写了好多版(不停的重构),可是它的整个框架,整个处理流程是没有变化的。这些知识对咱们后面这个阶段是有很好的指导意义的。虽然咱们把Cassandra应用在电信场景没有很成功,可是后来华为的手机慢慢流行起来了。2014年开始,终端开始起来了。框架

 

以后,咱们面临互联网ToC的场景,实际上是很是适合Cassandra的,咱们就慢慢的找到了Cassandra存在的一些价值,而且不停的在往下走。这一阶段咱们就没有修改任何源码了,彻底用原生的。由于根据咱们第一阶段的教训,改了源码以后,基本上就成为了孤版,很难向前演进。而后在终端状况下,咱们不停的找,它最佳的使用场景。第二个由于ToC终端用户对实时性和可靠性要求都很是高,因此咱们基于Cassandra的天生的多DC方式,实现故障切换。tcp

 

这里仔细讲一下:咱们当前的业务通常是1+1+1,一主一备一容灾,每一个DC都是3副本。正常的状况下咱们只会向一个DC写,若是出现故障,咱们经过这个咱们重写的驱动,把它切到另外一个DC去,保证任何DC里的两个节点出现故障,对终端业务的请求来讲是无损的,客户端会自动切换数据中心。另外,Cassandra原来是有OpsCenter来进行管理的,可是由于咱们公司的安全规范,没有用它。咱们如今是构建了一套华为本身的集群部署管理,包括监控系统。第三,咱们不断跟进社区的新版本。第四,Cassandra在华为的使用场景很是多。能够这样说,凡是华为终端,包括手机,包括穿戴式,包括IoT的全部华为终端应用的背后,你看得见看不见的背后,都有咱们Cassandra的身影。好比举个简单的例子,运动健康,你们跑步的时候,就是这些数据都基本上存在咱们Cassandra里去。华为手机上的应用,只要你看获得的,基本上后面都有Cassandra的身影。因此Cassandra伴随了咱们消费者云,伴随了咱们华为终端,六年的快速发展。性能


而后咱们能够看一下咱们当前的规模。咱们当前的规模仍是比较庞大的,基本上咱们这里存的全是用户数据。Cassandra咱们全球的节点大概有三万多台,咱们的数据规模大概有20PB。咱们的集群数量可能有500多。咱们最大的集群的节点数有600多节点。咱们如今全网每秒有一千万每秒的访问吞吐量。咱们的平均延迟是4毫秒。咱们当前最大的一张表,单表达到三千亿条记录。像咱们这个量,在原生的没有改动Cassandra源码的状况,可以达到这个规模,也是比较值得让人骄傲的一件事情。这些数据从另外一个角度证实,Cassandra原生的稳定性,使得它足以在ToC的这种线上场景,能够有很好的一个应用。

咱们下面再看一下,虽然咱们规模有这么大,可是不表明Cassandra是万能的,也不表明Cassandra它什么问题都能解决。咱们要避开这些问题。


咱们当前面临的挑战,首先是华为终端,包括中国区和海外不停的业务发展带来的庞大数据量形成的稳定性的问题。如今华为终端卖得很是好,并且用的人是愈来愈多,这个对咱们数据库的压力很大,也带来数据一致性的问题。当前咱们有些数据是没有上云的。咱们自建了机房,自建机房一块块的盘,是不稳定的,会遇到一些坏盘的问题,坏盘会带来一致性,包括僵尸的问题。第三个是基础设施的问题,好比JDK的问题,网络的问题,磁盘的问题,咱们都所有遇到过。第四个是故障的快速定位、定界,以及恢复。由于咱们如今面临的都是OLTP的场景,全是ToC的。ToC的场景,基本上就是华为终端用户的场景。我举个例子:假如你用到的华为手表,故障的时间一长,你的业务终端用户就不能用,人家是很着急的。因此说咱们如今对于业务的体验,包括故障的恢复的要求也很是高。咱们必须在半个小时以内把全部的故障必须恢复,你能够定位不出来问题,可是你必须把它恢复掉。


我这里有一个分类,把咱们现网里遇到的典型问题列了一下。咱们现网遇到的问题比这多得多,多是这个的好几倍,可是我总结了一下这些典型的问题,但愿对你们,或者是即将使用原生Cassandra来构建本身的核心业务的朋友作一个提醒,你必定要注意这些方面的问题。这里都是咱们在业务发展过程当中遇到的典型问题。我后面会针对每个问题,包括它的现象,包括从监控里面的反应,包括堆栈,都会介绍一下,结合咱们的业务场景,给你们讲讲。


你们能够看一下,这里是咱们的监控系统,我把一些IP抹掉了,这是咱们的业务成功率,这是咱们现网节点的CPU、IO等系统指标。你们能够看到案例的描述:有一次,现网扩容,可是扩着扩着就发现,到必定程度的时候,全部节点的CPU和IO都所有很是高,这个对咱们的业务影响你们能够在右边的图里看到,原本成功率百分之百,突然一降低了这么多。对应的时间点内CPU、IO所有都飙升。为何,这个就是集群规模过大形成的影响。咱们能够先看一下为何会这样。


根本缘由是:第一是咱们的集群很是大,几百个节点,第二个是咱们的Token数有256个,这样算起来, 咱们最多能够有十几万个Token范围。新节点加入集群过程当中,Token信息须要更新。同时,Cassandra读写流程里面,也须要获取Token信息用于路由。两个流程使用读写锁获取一个对象。当集群规模达到必定的程度时,Token数量过大,会致使Token信息更新缓慢,若是此时恰好业务高峰,请求会由于拿不到锁而阻塞,从而致使业务请求大量超时失败。这里咱们给出的解决方案是,控制单集群规模,主要是虚拟Token数量,尽可能不要超过十万。集群过大的时候,须要考虑拆分,不要让一个集群无限膨胀。咱们如今ToC的集群为了稳定性,咱们的集群节点数不超过两百。超过两百个节点咱们建议业务去拆分。


第二个是,单节点数据量过大的时候,会有什么问题。咱们当时每一个节点数据量达到了5TB,集群变得很是不稳定。表如今单节点数据量大时,bloomfilter、index summary等须要的常驻内存量会很大,致使频繁full GC甚至OOM;另外,咱们默认使用的压实算法是Leveled Compaction Strategy,若是使用LCS并且数据量过大,磁盘空间可能不够,由于L0常常须要使用STCS来作压实操做。解决的方法是避免单节点数据量超过1.5TB,另外在扩容过程当中临时增大磁盘空间或者设置disable_tscs_in_l0=true。注意,这个参数只能在紧急时候使用,扩容完成后,务必记得恢复成默认值。


第三个问题是节点压实操做(Compaction)堆积严重。大量的压实堆积说明压实跟不上,会产生大量小文件,影响读性能。后面这两张图里能够明显看到在LCS的小文件太多的时候,读延迟大大增高。咱们找出的解决办法,一个是调整compaction的速度,一个是调整两个系统参数:sstable_preemptive_open_interval_in_mb,以及-Dcassandra.never_purge_tombstones。经过jstack查看线程的调用栈能够判断须要调整那个参数。另外注意,never_purge_tombstones也仅限紧急状况下使用,压实的堆积消除之后必须恢复原有的默认配置。


第四个问题是大Key的问题。前面的几位嘉宾也提到单个partition太大的时候对性能和稳定性的影响。这个在Cassandra日志里会出现告警信息。解决的办法是在业务里改变表结构和使用方法。好比一个文件删除记录表,对于我的文件来讲,某个文件下面的删除记录不会很大,可是对于公共文件,好比华为手机上的锁屏图片,就会出现大Key问题,解决的办法就是在业务里增长判断,若是是热门文件,在删除次数达到某个阈值后就再也不新增删除记录。再好比,若是记录一个热门电影的预定用户,使用电影的resourceID做为分区键,预定用户的UserID做为聚类键,当预定的用户数达到千万甚至上亿级别,就必定会出现大Key问题。解决办法就是使用额外的hash串将resourceID继续离散,避免单个resourceID下的分区太大。


第五个问题是热点Key问题。表如今短期内对同一个Key频繁操做,会致使该节点的CPU和Load太高,影响其余的请求,致使业务成功率降低。这个从右边监控系统的截图能够看到,部分节点的CPU和负载都很是高。应急处理的方法,通常是经过toppartitions找到访问量最大的partition key,在业务侧加黑名单屏蔽这种热Key。最终的解决方案是利用缓存来减少热Key对数据库的冲击。


第六个是墓碑问题,这个我就不花太多时间说了。这方面必定要避免的就是短时间内若是有频繁的删除而且还有频繁的读操做的话,可能Cassandra并不适合这种场景。另外,做为应急方案,能够临时减小gc_grace_seconds,以加速墓碑的物理清理回收时间。


第七个是坏盘致使的僵尸数据,这个你们能够直接看一下图示和源码,由于个人时间有限。咱们的解决方案是若是你用的是自建的IDC机房,出现坏盘了,必须在gc_grace_seconds的周期内完成数据修复,或者直接replace掉出了坏盘的节点;固然,若是你的业务有条件上云的话,这种坏盘发生的可能性要低不少。


第八个是基础设施方面的网络丢包问题。咱们现网当时出现的症状是忽然时延大幅度增长,Cassandra驱动侧出现大量的慢日志信息。排查了集群的资源利用和线程池都没发现问题,可是咱们用getendpoints把慢查询日志涉及的分区键对应的副本节点打出来,发现都涉及到一个*.*.23.20的节点。后来果真发现这个节点的网卡出现了丢包的故障。修复了丢包故障后,业务时延恢复正常。


第九个是集群节点规格不一致致使的节点负载不均。这个其实涉及Cassandra的一个优化,可是优化用得很差,也会带来问题。由于Cassandra的Gossip交换的信息里,会包含每一个副本节点的负载,负载越小,收到的请求就越多。若是你的节点的物理配置不均,会致使请求集中在高配的几个节点上。这个对自建IDC的影响比较大。在云上,你们的节点配置比较一致,会较少遇到这个问题。


第十个是操做系统的网络调参。咱们这里只列举了一个。网络参数不合理的症状是数据迁移不会出错,可是会卡死。在集群扩容时,200GB的数据不是卡死,就是长达一两天。在公有云上咱们发现把net.ipv4.tcp_sack (Selective ACK) 开启,以后咱们200GB的数据迁移20分钟就完成了。这个参数可以减少报文重传的几率,在网络拥塞或者乱序的状况下会有很好的效果。


最后一个是JDK的STW (Stop The World)的问题。这个问题咱们到如今都尚未复现,咱们是经过把业务切到备用的DC,而后重启故障DC的全部节点解决的。咱们是怎么发现这个问题呢,当时业务的平均时延增高到3秒,可是系统CPU、IO、负载都正常,咱们也排查了集群节点系统的各个核心参数,均没有发现问题,可是注意到Hint大量出现,这说明数据在写入过程当中,出现了大量的业务节点被短暂识别为宕机状态,引发Hint被记录下来。经过查看Jstack和GC日志,发现线程卡顿和STW常常长达10秒。

最后,咱们再来看看咱们总结出来的Cassandra最佳实践。我这里总结了几点。


首先,须要管控业务使用场景,增强业务表结构的评审。无论你是用云上的,仍是用自建IDC的,这个对你们都是有必定的借鉴意义的。咱们如今整个业务大概有几百个利用Cassandra数据库。咱们这个组如今负责在业务上线以前,对业务场景和表结构进行评审。咱们基于这样一些方面的规范(咱们也叫“军规”):主键设计合不合理,Schema约束,数据老化机制,单条数据频繁更新/删除,单条记录过大,大面积数据删除引起墓碑问题,集群规模。咱们如今为何会作到这么大的量,是由于咱们管控了使用的场景,让它必须按照咱们要求的来作。


而后,是构建完善的Cassandra集群监控系统。咱们有不少方面的监控:第一个是主机级别的监控,包括CPU/IO/磁盘/内存;第二个是读写请求的监控,这个是从业务的角度来看请求量是多少;第三个是Cassandra内部核心线程监控,这个是Cassandra内部的一些显微镜级别的监控手段,必须可视化出来,不然的话现网几万台机器,出了问题的话,你是没有任何办法能够快速恢复的;第四个是集群规模的监控,包括节点数和集群统计量,告警,自动化部署相关的指标。


另外一个最佳实践,就是使用Cassandra,必定要多看源码,多熟练掌握nodetool各类命令和使用场景。Nodetool命令其实很是好用,这个只是列了一些咱们用得最多的,包括cleanup, compactionstats, getendpoints, netstats, rebuild, repair, toppartitions, tpstats, cfstats,我不在这里一一说明,你们能够看这个表。若是你在大规模应用中,须要快速的恢复,这些命令对于故障排查和恢复会很是有帮助。

相关文章
相关标签/搜索