在“监控平台MongoDB实践”上,千寻位置的技术专家肖应军发表了一场关于MongoDB实践演讲,他的演讲内容主要分为四个方面:
1.使用MongoDB的原因及MongoDB的现状2.MongoDB的使用场景有哪些?
3.监控平台MongoDB实践中有哪些经验值得参考?
4.MongoDB接下来的研究方向侧重哪些方面?
以下是根据现场演讲和PPT的整理内容。
一、为什么使用MongoDB以及MongoDB的现状又如何呢?
MongoDB早在11,12年时便首次提出,当时QA数据库刚开始流行起来,有人评论MongoDB数据库是最倾向于QA数据库的数据库,关于这个说法有两点说明,首先,MongoDB倾向于关系型数据库是因为其速度快,无论写或读,都会最大可能的使用内存。关系数据库最明显的特征之一是有各种各样复杂的事务隔离级别,保证高频发情况下数据的一次性,而在写多读少且没有事务的场景下,则恰好利用了MongoDB这个特点。其次,MongoDB虽倾向于关系型数据库但并不是强调它的关系型,也就是说MongoDB在关系型上有别于QA数据库。第一个不同之处在于MongoDB有行有列,这是区别于QA数据库的最明显的特征,第二个不同点是MongoDB的数据不固定,为什么呢?首先,阿里云是一个通信公司,其次,监控系统本身数据来源很广,有技术监控以及运营监控和应用监控,且应用监控的变化最大,所以数据结构不稳定成为了一个非常明显的特征,而MongoDB没有固定的数据结构,这恰好成为它本身的独到优势,当需要把监控数据做成列表以及曲线图、饼图和散点图等各种各样可视化的方式时,MongoDB非固定的数据结构便完美的配合了可视化的需求,这是选用MongoDB作为主要存储工具的原因。
目前,MongoDB的现状是每天大约存储十亿条数据,平均为每秒钟存储一万条,每日增量达到了20G+之多,并用到了四套复制集用以实现云加工。
二、MongoDB的使用场景
MongoDB的使用场景有三:监控数据、业务数据和报表计算。随着业务量的增长业务数据逐渐庞大进而成为最频繁的使用场景,下面具体探讨各种使用场景下的数据特点同时对比不同场景下数据的异同点。
1.监控数据
监控数据最为明显的场景是数据没有写入高峰,并且采样平稳,只会根据机器和应用的场景多少来增加量,本身不会随着用户的增长而增长,所以监控数据特点一是数据量不会呈现出爆发式的增长,而是线性增长的趋势。特点二,由于做报表或数据可视化时经常会长区间的拉数据,使得返回数据量很大,但是读取的并发率却很低,再一次说明MongoDB对于写多读少的场景十分适用。特点三,随着时间的积累,监控数据会越来越多,此时常需要用到TTL索引——时间过激索引,TTL索引是MongoDB特别引进的,目前只为MongoDB所独有,其他数据库并不具备。特点四,抽稀算法。在监控数据时常用RRD数据库存储数据,主要原因在于它具有很强的抽稀能力,所以目前若想使用MongoDB,则需要自身去实现这个算法。
那么,抽稀算法的重要之处到底在哪里呢?例如,正常情况下,看一两天的数据趋势可能会把数据一分钟一分钟的拉出来,但是如果连续看一个月那么一分钟一分钟的展示是不可能实现的,这时候抽稀算法的重要性凸显出来,目前MongoDB已成功实现了一套抽稀算法。
2.业务数据
业务数据跟监控数据差别很大,第一点,随着用户的增长,用户的行为会导致业务数据瞬间峰值非常高,所以业务数据具有数据峰值;第二,业务数据的定期查询也会增加。做报表时很多的定时任务会使业务数据的查询频次骤增,针对这个问题需要一系列解决方案,例如:队列削峰,而队列削峰又是通过什么实现的呢?最初的途径是使用JAVA本地的Q实现队列削峰,而现在则是利用统一写入层实现削峰。第三,监控数据与业务数据在模型上也有所差异,监控数据通过Agent—Service—MongoReplset模型进行存储,而业务数据则是利用Queue收数据,其主要目的也是实现队列削峰。
3.报表计算
监控数据和业务数据主要是两个存储场景,而报表计算则是对数据加以利用,随着业务量的逐步增长,报表计算的发展经历了两个阶段,第一个阶段时数据量不是很大,单次报表源数据在百万级以下,这种情况下一套简单的架构便可以实现,例如Mongo自带的AGM功能,这种场景对硬件资源较少、没有大规模集成框架的创业初期或数据量不是很大时更为简单灵活,能够快速实现需求、快速响应。这些功能基本上都是由JAVA实现的,属于Mongo的自身功能,所以并发性等问题可以巧妙地避免。然而,使用这种方式时也有一些事项值得注意,Mongo目前利用AGM这三个软件架构实现聚合功能,Aggregate是轻量级的聚合功能,适用于单列或者简单的聚合且速度非常快,例如,求最大值、最小值和平均值等简单运算,只需要一个socket语句就可以实现。当需要完成复杂逻辑时,Aggregate显然不能胜任,此时就要用到Groupby和Mapreduce,由于Mapreduce和AMI模型是一样的,所以两者相比,Mapreduce的功能更强大,但当前场景下,主要是用Groupby架构来实现聚合功能,这是为什么呢?问题就在于Mapreduce只支持sharding,而Groupby则是把查询的数据及结果一行一行地传给函数,函数逐一处理,所以Groupby虽功能不如Mapreduce强大,但大部分情况下是可以满足数据聚合的功能。同时,Groupby的使用也有注意事项,Mongo数据的结构是bson,且最终返回的值同样通过bson形式返回,而bson的要求之一是当一个返还的结构体超过64k时便无法实现,总之,要根据实际的情况选择合适的方法来完美地实现功能。
以上是报表一期使用的一整套架构方案,总结来说,报表一期适用于数据在百万级以下的情况,若超过百万,整个复制集就会出现不稳定因素,此时就需要监控报警,更复杂情况下甚至需要修改方案。随着业务的增长,业务数据量越来越大,出现了亿级、十亿级甚至百亿级,繁多的业务报表随之出现,统计周期发生变化变化,从小时报到天报到周报再到月报,而统计频次逐渐升高,从小时报到分钟报甚至是秒报。显而易见前面的一套方案已经不再适合了,亟待设计一套新的架构方案来应对愈加庞大的数据量和业务报表,报表二期应运而生。
第二阶段的方案架构分为四部分:
第一部分以Service直接写入。
第二部分是阿里云的SLS服务,SLS的速度非常快,即使是千万级的数据也仅仅需要秒级的延迟,一般情况下不会出现问题。在SLS服务下,第三方应用只需要把日志打入本地磁盘,阿里云收集后把数据分发到Mongo或ODPS里即可,这是目前的采集模型,除增加了SLS模型外与第一阶段并无太大变化。
第三部分由MetricMongoReplset和ReportMongoReplset两个复制集构成,MetricMongoReplset是一套存储原始数据的Mongo复制集,而ReportMongoReplset则是用来存储报表的结果数据,两者不同之处在于,MetricMongoReplset中会有大量数据的写入,导致TTL索引应用较为频繁,而ReportMongoReplset则是查询操作占主要部分。
第四部分是两个大规模集成框架——EMR和ODPS,先来说ODPS,这里既用到它的大数据集成框架也用到它的存储功能,所以在要求原始数据的场景的情况下一般会存储到ODPS里,如果只是用来快速查询且保护时间不需要太久的话,一般会把它存放在Mongo,这也是把Mongo和ODPS放到同一层级的原因,ODPS本身具有的大数据计算功能使得有些报表同样可以利用ODPS计算。再来说EMR,到了目前阶段特别是需要做秒级报表时,ODPS的缺陷便显现出来了,而EMR更为强大的功能则能适时填补ODPS的缺陷。在报表计算第二阶段的架构下,同样有一些注意事项,例如,EMR如何跟Mongo驱动呢?这里就用到了connector来实现这一功能,Mongo-spark-connector是Mongo官方推荐的一套connector,在使用Mongo-spark-connector时会用到两个partitioner,这里简单介绍MongoSamplePartitioner和MongoShardedPartitioner两种。
前文介绍过,利用JAVA方式查报表的方式是单行层拉数据,所以若使用多线程就会涉及到各种各样分区的概念和问题,而Mongo-spark-connector恰好解决了这个问题,即Mongo-spark-connector会在读取数据时根据spark模型的数量直接分区,一般来说分区有很多种,但在Mongo做数据源的场景下,按照Mongo文档的概念来分区更为易于人们使用,例如,按分页来分区,每页十个。所以Mongo分段的特性提供了一系列的Partitioner,复制集中用到了简单的MongoSamplePartitioner,当然还可以根据实际场景选择其他的Partitioner。
三、实践经验
一主二从
复制集在一般情况下一主一从便足够,但是复制集承受较大压力时,最好还是一主二从,从而避免各种问题的发生。
慢查询导致锁库
当习惯用关系型数据库时,慢查询可能会导致锁库就成为了一个极易容易忽略的问题,在关系型数据库中模型搜素语句变慢会导致锁表,高级的数据库会锁行,但是Mongo可能会直接锁库,特别是在慢查询情况下,要注意防止锁库现象的发生。
写入压力大导致整个库响应慢
新增索引{backgroud:true}
利用新增索引{backgroud:true}在后台进行索引不会导致前台数据库写入变化而使索引变化,以避免锁库。
监控工具grafana
grafana是一个开源的监控工具,布好后,读入写入以及文档更新等监控指标就会显示出来,是一个成本很低的监控方案。
写Mongo批处理脚本时,避免使用lord命令,推荐使用mongo--shella.js写批处理脚本。
TTL索引必须使用Date类型字段
在不特别注意的情况下,写入Mongo里的数据是longer类型字段,而TTL索引必须使用Date类型字段,解决方法是可以针对Date类型自己写一个序列化的方法。
连接驱动WriteConcern,推荐W1
使用复制集情况下通常会遇到一个主从问题,即“主”写入而“从“还未同步的情况,Mongo官方推荐的WriteConcern可以解决这个问题,其中W1类型是”从“写入即认为全部写入,适用于多数场景。
基于ECS自建MongoReplset的IOPS上限
普通云盘:3000,SSD:10000
当用户数据量或业务数据量达到一秒十万、百万时就会出现各种各样的问题,推荐使用阿里云的产品,因为自己运维成本较高,其中最主要的问题体现在数据的存储上,目前是使用虚拟机,之后要采用实体机乃至SSD高效磁盘来解决数据存储上存在的问题,由于CPU、内存等可能都要应用实体机完成,所以部分问题仍能够得以解决的。
四、Mongo进一步的开发计划
Mongo未来的研究方向:
首先,针对位置数据主要探索一些技术相关的搜索引擎,即未知数据相关引擎-GIS。其次是与监控特性相关的时序数据库相关引擎-TSDB,一些最基本的技术监控会随着时间的推移而产生数据的变化,此时便经常会用到时序数据库来存储这一类的数据。然后,目前的单台复制集数据量最快能达到一秒一万,当达到一秒十万时,无论如何分工、分表、分业务,能达到的数据量都是有限的、无法满足需求的,此时Sharding的应用便显得至关重要了。最后是跨机房与异地双活,目前阿里云已经实现了这些功能,使用方便。