前言
极光从某种意义上讲,是一家数据公司。在整个公司的技术运营体系中,需要存储大量的KV数据。根据数据量、KV结构特点、数据更新频率、数据冷热、读写请求量和比例等因素,在极光逐步形成了CouchBase、Redis和Pika三种不同的KV解决方案。
以下我们主要是从大规模数据量/请求量场景下碰到的运维难题,以及服务的性能、可扩容性、数据备份与安全、运维保障工具等方面介绍一下极光在使用以上KV组件的实践经验。
一、CouchBase实践
极光 CouchBase 规模
CouchBase 当前总使用量大约在 6.5T 左右;单个集群最大25台(16核128G内存)。
CouchBase是一个非关系型数据库,它实际上是由couchdb+membase组成,所以它既能像couchdb那样存储json文档,也能像membase那样高速存储键值对。
在极光我们主要用它做KV存储,主要有以下几个特点:
速度快
由于是放在内存中的数据库,所有的读写操作都是直接操作内存,因此速度非常快。极光数据量最大的集群规模约25台机器(16核128G),可以提供1.5TB的可用内存。读写压力最大的集群,大概是8台机器,但是需要抗住100万的QPS,单机可以抗住10万以上的QPS,性能相当强悍了。
与官网宣称的性能与节点数的线性关系不同,实际使用中发现,超过40个节点的集群,在扩缩容、故障节点替换、集群稳定性方面存在明显的问题,在扩缩容、替换节点的时候,集群容易进入假死的状态,在控制台上没有任何反应,客户端断断续续出现超时或者错误的返回结果。这个过程无法快速自动恢复,在极光类似的故障最长的一次持续了3个多小时,最终我们是停掉了业务才修复的。
另外有一次故障,发现主要原因CouchBase 内存占用只增不减,导致机器内存爆满,最终被 oom。最终通过进行集群拆分暂时解决了问题,新集群也同步使用更新的版本。
高可用
主要有两个方面的高可用:一个是它自带集群方案,支持多副本模式,我们一般是选择2副本模式,类似一主一备的方案,这样可以确保没有单点故障的问题;
另一个是它自带持久化方案,可以设置定时把数据异步写到文件系统上,所以在一般情况下单一节点的宕机,对集群的可用性和性能影响有限,但是一次性故障超过2个节点,就有出现数据丢失的可能性了。
配置使用方便
CouchBase安装后自带web管理台,可以在管理台上对集群、桶、索引、搜索等进行管理和操作,大大简化运维的工作。这也是一般开源软件所普遍不具备的能力,商业化的产品对于用户体验确实做得很好。
当然,CouchBase也有一些明显的缺点:
1、只能提供简单KV存储模型,不支持复杂数据结构(value 支持json 格式)
2、为了提升查询效率,KV中的Key全部都缓存在内存,需要消耗大量内存,特别是每一对KV所附加的MetaData(一个KV存储至少消耗56Bytes的MetaData)同样缓存在内存中。在极光的实践过程中,经常碰到MetaData超过50%内存占用的情况,对内存容量提出高要求,也导致成本较高。
3、本身是闭源产品,文档较少,出现异常故障处理手段有限,存在一定的风险;我们碰到过好几次的集群节点假死,还有数据量大的集群无法进行备份的情况,没有找到任何有效的方案。那么对于核心、关键数据,放在CouchBase上进行存储是不可靠的,这块是需要根据业务场景来判断的,目前极光使用CouchBase的数据都是中间层数据,一旦发生数据丢失,都可以从其他渠道恢复回来。
数据备份问题:
对于数据量达到一定规模,使用 CouchBase 自带的备份工具进行备份时就会出现备份失败的情况。与 CouchBase 官方沟通也没有回复。
针对CouchBase大规模集群下的rebalance会存在假死的问题,后面我们把大集群拆解成了数个小集群,实现了压力的分散和运维管理的分散,不过需要在业务侧做数据的分片处理,需要业务介入,对业务方存在一定的侵入。
监控和告警生态相对比较成熟,通过对应的Exporter获取数据上传到Prometheus,整体比较简单方便
我们设置了以下的主要告警规则,便于及时发现问题:
1、bucket内存使用超过85%
2、CouchBase集群节点CPU使用超过90%
3、xdcr同步失败
4、CouchBase 节点发生异常/重启
二、Redis实践
Redis是知名的开源KV存储,在业界使用极为广泛,极光也在大量使用Redis。
极光Redis规模
当前极光 Redis 资源使用量大约在 30TB 左右,实例总数大概在 7K
生态丰富
Redis因本身的知名度,实践案例非常多,网上的文章和教程十分丰富,有一个很好的生态,运维和研发人员也非常熟悉。这块对比CouchBase和Pika来说,真的非常重要,不但可以节省大量的沟通成本,还可以直接复用很多的成熟解决方案,排查故障和优化工作也更加简便。
在选择基础组件这块,成熟、通用、生态丰富真的非常重要。
高性能
同样因为全内存操作,Redis表现出相当高的性能,我们实际使用中单Redis实例峰值性能可以到达5万QPS(这是公司的峰值标准,达到该值我们就认为已经达到瓶颈了,但实际性能测试要高于此),如果按照单机8个实例,理论上可以达到40万QPS,这个数据相当惊人了。当然,由于redis的单进程+阻塞模型,碰到慢指令就会导致延迟整体上涨,这块我们在应用架构设计和运维方面需要特别考虑,比如在业务低峰期再进行一些高延迟的操作。
redis 性能测试:
主从模式下,我们一般都使用哨兵模式,这个一般来讲不会有什么问题;但是有一次我们怀着提高可用性的目的,把一套哨兵从3节点扩容到5节点,之后发现该哨兵监管的redis实例出现大量的延迟告警,后来排查发现和扩容到5节点密切相关,进一步排查slowlog发现是哨兵发送的INFO指令导致redis实例响应延迟增加。在这块,要特别注意哨兵的探活导致的资源消耗,在高QPS压力下,任何一点新增的压力都十分敏感。
自带集群模式
Redis自带了Redis-Cluster架构,在一定程度上解决了超大规模数据集的存储问题。
Redis cluster 性能测试:
不过,由于其无中心的架构模型,在大规模集群下运维和数据迁移较为困难。在极光,我们当前最大的Redis-Cluster集群达到244个主从节点,总共超过800G的数据量,峰值QPS可以达到8M(八百万QPS),压力相当大,带来的运维压力也是相当大。
首先:扩容比较困难,扩容导致的slot迁移在大QPS压力下,导致客户端收到大量MOVED返回,最终导致业务端大量报错;
其次:扩容时间非常长,从244个节点扩容到272个节点,花费了我们一个星期时间,浪费了我们很多人力资源。
逐渐地我们形成了一套Redis-Cluster的应用最佳实践
首先、严格控制Redis-Cluster集群规模,主节点不超过100个。
其次、前期我们通过在业务端做数据切割,将数据分布到不同的Redis-Cluster集群;逐渐地公司通过自研JCache组件实现宏集群,将多个原生的Redis-Cluster组合成一个宏集群;在JCache做基于Key规则的hash,相当于多了一层代理。当然,这样也带来一些新的问题需要解决,比如后端Redis-Cluster的分裂和数据重新分片的问题,也增加了JCache的复杂度。
JCache 宏集群方案:
监控同样是使用Exporter收集数据到Prometheus,这块生态十分完善,直接复用现成的方案即可。
我们针对Redis设置了如下的告警规则:
1、内存使用率告警(每个 redis 应用自定义,默认 90%)
2、客户端连接数告警(默认 2000)
3、redis 实例 down 告警
4、哨兵发生主从切换告警
5、应用整体 qps 阈值告警
6、特定 redis key 监控
性能优化:
1、关闭 THP
2、高危命令屏蔽(keys/flushall/flushdb 等)
3、部分数据频繁过期的 Redis 应用,通过调整 hz 参数,加快过期 key 清理,尽快回收内存,有一些从默认每秒清理10次提高到100次,但是在大QPS请求下,会有性能影响
4、对部分内存需求高,性能要求稍低的 Redis 应用,通过调整数据的底层存储结构,来节省内存,如调整hash-max-ziplist-entries/hash-max-ziplist-value
三、Pika实践
Pika是国内开源的一套兼容Redis协议的KV存储,底层基于RocksDB存储引擎,支持多线程,属于磁盘KV存储系统,比较适用于数据量特别大(例如TB级别)但是QPS要求不是特别高的场景。
极光 Pika 规模
Pika 当前数据量大约在 160T 左右。
性能较高
从我们使用NVMe SSD作为存储介质实测下来,单机(8核32G)峰值达到18W QPS是没有问题的,实际使用场景下峰值QPS可以达到10W而不影响业务。
当前公司自建 IDC 使用 NVMe SSD 最大的 ops 在 7.6W 左右
生态不算成熟
国内开源软件,受众不算大,软件不是特别成熟,功能迭代变化较快,从2.X版本快速迭代到3.X版本,根据社区反馈而做了很多改进,目前我们基本稳定使用3.2.X的版本。
注:新应用基本都是基于 3.2.x 版本,还有部分遗留的历史应用由于数据比较重要,暂时没有升级
最近一年因为项目变更,Pika似乎捐献给了国内某个开源基金会,不再由360公司继续负责维护,从QQ群的反馈来看,核心开发人员似乎越来越少,项目前景有一点暗淡。这也是很多小众开源软件的常见问题,软件本身很容易因为公司政策或者某些核心人员的变动而受到较大影响。
Pika最近一次发版本还是在 2020年 12 月,已经快过去一年时间了。
代理层
因为Pika只有主从模式,而我们的数据量动不动就好几个T,QPS 数十万,所以我们在实际使用时需要在前面加了一层代理层来做hash分片工作。目前单个实例最大达到了2T,实际QPS达到10万,读写实例比例1:3,满足写少读多的场景。
标配SSD
无论从官方建议还是实际使用,Pika的磁盘我们都标配NVMe SSD磁盘,相比普通SSD磁盘,提供更高的IOPS和吞吐能力,更低的读写延迟。Pika生产环境,NVMe SSD我们峰值IOPS可以达到5万,而普通的SAS SSD磁盘也就1万,性能提升还是很明显的,对比价格的区别,性能提升非常多,更不用说相比内存了。
串联主从问题
Redis可以支持和实现主-从-从的串联关系,我们在使用Pika的时候也做过类似的部署,结果出现了严重问题,导致我们丢失了数据。Pika在串联主从这种模式下对于数据同步状态的管理十分简单粗暴,只能看到slave和master已建立连接,但是数据是否同步完毕、是否有数据缺失都需要应用层去处理。这也是后面我们研究代码得出来的,一方面是文档的缺失,另一方面也说明了在使用开源软件时不要理所当然地认为是怎么样,而是要经过严格的确认和测试,否则带来的代价是非常大的。
注:Pika从 3.2.X 版本后就不再支持串联主从的设置了,所有Slave都必须从Master同步数据,会对Master节点造成一定的读压力。
监控和告警
监控信息还是可以通过Exporter搜集并上传到Prometheus,比较简单清晰
Pika的告警规则设置如下:
1、Pika 实例进程告警
2、Pika 连接数告警
3、哨兵主从切换告警
4、JCache 慢查询告警
5、Pika master 写数据失败告警
性能参数:
1、auto-compact 自动压缩参数,针对存在大量过期数据的应用
2、root-connection-num 保证客户端把连接数占满后仍然能通过 pika 本地连接上
3、压缩算法改为 lz4,性能好,压缩比高
四、后续规划
极光目前的KV存储经历了这么多年的演进,满足当前需求是足够的,但是仍然存在扩容不方便、不平滑,大规模集群性能瓶颈、性价比等问题;未来将重点投入在对业务的赋能上,将KV存储做成一套适应性更强、更灵活的存储服务,可能考虑引入类似存算分离、冷热分层等技术,在扩缩容、性能优化、性价比等维度上更上一层楼。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。