本文整理自DTCC2016主题演讲内容,录音整理及文字编辑IT168@ZYY@老鱼。如需转载,请先联系本公众号获取授权!

演讲嘉宾

孙玄

58同城技术委员会

架构组主任

58同城高级系统架构师,技术委员会架构组主任,产品技术学院优秀讲师,58同城即时通讯、C2C技术负责人,代表58同城多次参与QCon、SDCC、DTCC、Top100等业界大会嘉宾演讲,并为《程序员》杂志两次撰稿。前百度高级工程师,参与基础系统的设计与实现。毕业于浙江大学。

分享内容

大家好,我是来自58的孙玄,今天分享的主题是《MongoDB在58同城的应用实践》,主要内容如下所示:

首先介绍一下MongoDB在58的使用情况,从2011年到2014年,58基本使用了三年MongoDB,三年中,整个公司的业务线都在大规模使用MongoDB。在2014年,由于技术选型的改变,58配合业务特点做了一些调整。14年和15年,58基本很少使用MongoDB,但随着赶集和英才对MongoDB的频繁使用,58于今年又开始大规模使用MongoDB。

就我个人而言,从15年开始真正使用MongoDB,主要应用在业务线上,所以分享的内容主要针对15年之前MongoDB在58的应用案例和实践。随着MongoDB社区的发展,特别是3.0的崛起,可能会略有不足。以上便是此次分享的背景,接下来切入主题。

基本上在2014年底,58比较核心的业务线都在使用MongoDB,包括IM,交友,招聘,信息质量,测试以及赶集和英才。现在最核心的数据存储也是采用MongoDB在做,后期由于技术选型以及业务调整,使用量有所下降。

接下来讲一下选用MongoDB的原因,作为一款NoSQL产品,选择的同时我们会考虑到它的特性,主要有如下几方面:

一是扩展性,MongoDB提供了两种扩展性,一种是Master—Slave,基于主从复制机制,现在58用的比较多的是Replic Set,实际上就是副本集结构。我们会针对不同的业务项进行垂直拆分。

二是高性能,MongoDB在3.0之前,整个的存储引擎依赖于MMAP。MMAP是整个的写内存,就是写磁盘。数据写入内存之后,要通过操作系统的MMAP机制,特别做数据层的,如果数据存多份的话,就可能会造成数据不一致的问题。MongoDB在提供高性能的同时,数据只存一份。这种情况下,设计提供高性能的同时,可以很好地解决数据一致性问题。

除此之外,MongoDB也有其他一些特性,包括丰富的查询,full index支持和Auto-Sharding。另外,做任何选择一定要结合业务逻辑。58原来是分类信息网站,主要的业务特征是并发量比较大,但58和电商的自主交易不同,对事务没那么高要求。在这种场景下,选择MongoDB作为核心存储机制,是非常不错的选择。

MongoDB不像关系型数据库,必须定义Schema,MongoDB比较个性化,对Schema的支持也没有那么严格,可以在表里随意更改结构。但free schema是否真的free吗?比如原来的关系型数据库,需要定义每一列的名称和类型,存储时只需存储真正的数据就可以了,schema本身不需要存储。由于MongoDB没有schema的概念,存储的自由度大了,但整个存储空间会带来一些额外开销,毕竟要存储字段名,value值无法改变,但可以减少字段名的长度,比如age可以考虑用A表示。这时可能会出现可读性问题,我们在业务层做了映射,用A代表age。同时,减小整个数据的字段名,通过上层映射解决可读性问题。

另外我们还做了数据压缩,其实我们有很多文本数据,文本数据的压缩率还是比较高的,我们对部分业务也采取了数据压缩的方式。在Auto-sharding方面,我们采用库级sharding,collection sharding采用手动sharding。当整个表的行数量比较大时,会进行拆分,把一些比较大的文档切分成小文档,包括这些文档的嵌套存储,都是MongoDB相对于其他关系型数据库而言比较优秀的地方。

自动生成_id其实就相当于主键的概念,默认的字段长度是12个字节,整个存储空间的占用比较大,我们尽可能根据业务特征,在业务层把该字段填充成我们自己的字段。如果存储用户信息,该字段可以填成UID,因为UID最大是八个字节。一方面可以减小整个存储空间,另一方面,虽说_id可以在MongoDB服务端生成,但我们尽可能把_id生成工作放在业务层或应用层,可以减少MongoDB在服务端生成_id的开销,写入压力比较大时,整个性能的节省非常明显。

接下来是部署层面,每一个分片上是Replica Set,同时开启Sharding功能,基本结构如上图右边所示,每个分片做一个Sharding,在Sharding上有Replica Set的概念。通过这个架构,所有configs直接通过mongos到shards。增加sharding或者在sharding上做增减,实际上对整个应用是比较透明的。这样部署一方面可以很好的满足业务需求,另一方面可以很好地满足内部扩展和故障转移。

另一个比较隐蔽的话题就是sharding操作,大家可能都比较关心,Auto-Sharding到底靠不靠谱。就我个人理解而言,既然要用Auto-sharding,就要解决sharding key的问题。如果选用单一递增的sharding key,可能会造成写数据全部在最后一片上,最后一片的写压力增大,数据量增大,会造成数据迁移到前面的分区。如果选用随机key,的确可以避免写问题,但如果写随机,读就会出现问题,可能会出现大量随机IO,对一些传统磁盘而言影响是致命的。那如何选取合适的sharding-key呢?先要保证该key在整个大范围内单调递增,这样随机选择时,可以保证相对均匀,不会引发其他问题。

此外,我们在测试中发现,数据迁移过程中经常会出现一些问题。一旦发生数据迁移,比如从A迁到B片,数据可能同时存在于两片数据上,直至迁移完成,整个数据才会全部存在于B片上。58的业务特点属于中午访问的人很少,这时MongoDB集群的负载比较低,系统会认为此适合进行数据迁移,将会开启Auto-sharding。午饭时间结束之后,访问量就开始逐渐增加。此时,整个迁移尚未完成,不会立即停止,集群的OPS会瞬间从几千掉到几十,这对业务的影响非常大。这时,我们会指定整个sharding的迁移时间,比如从凌晨两点到早上六点这段时间属于业务低峰期,这段时间可以允许sharding进行业务迁移,同时开启数据库级别的分片。这样可以避免Auto-sharding数据迁移带来的问题。

另外,做整个设计特别是业务设计时,一定要了解业务发展场景,比如半年或一年内,大概可以增长到什么样的规模,需要提前做预期。根据业务发展情况,就知道大概需要开多少分片,每一片放多少数据量合适。

做整个规划时,也需要考虑容量性能。至少要保证Index数据和Hot Data全部加载到内存中,这样才可以保证MongoDB的高性能,否则性能压力还是蛮大的。2011年开始使用MongoDB时,数据库内存是32g,后来一路上升至196g,其实随着业务的发展,整个硬件投入成本也是蛮高的。实际上如果内存足够大,整个性能情况还是比较令人满意的。

另外,MongoDB整个数据库是按照文件来存储的,如果有大量表需要删除的话,建议将这些表放到统一的数据库里,将会减少碎片,提高性能。单库单表绝对不是最好的选择,表越多,映射文件越多,从MongoDB的内存管理方式来看,浪费越多;同时,表越多,回写和读取时,无法合并IO资源,大量的随机IO对传统磁盘是致命的;单表数据量大,索引占用高,更新和读取速度慢。

另外一个是Local库,Local主要存放oplog,oplog到底设多少合适呢?根据58的经验来看,如果更新比较频繁而且存在延时从库,可以将oplog的值设置的稍微大一点,比如20G到50G,如果不存在延时从库,则可以适当放小oplog值。

针对业务场景设计库和表,因为MongoDB实际上是带有嵌入式功能的,比如以人为例,一个人有姓名,性别,年龄和地址,地址本身又是一个复杂的结构,在关系型数据库里,可能需要设置两张表。但在MongoDB里非常简单,把地址做成嵌套文档就可以了。

表设计无非这几种,一对一,一对多和多对多的关系,一对一关系比如用户信息表,实际上就是明显的一对一关系,类似于关系型数据的设计,用uid替换_id,做一个主键就ok了。

一对多的关系比如用户在线消息表,一个人其实可以收到很多消息,这是明显的一对多关系,可以按照关系型数据库来设计,按行扩展;也可以采用MongoDB嵌套方式来做,把收到的消息存在一个文档里,同时MongoDB对一个文档上的每一行会有限制,如果超过16兆,可能会出现更新不成功的情况。

多对多关系如上图示例,整个包括Team表,User表,还有两者之间的关系表。在关系型数据库里,这是三张表,一张表是整个Team表的元数据,另一张表是User表的元数据,同时还有关系表,表示二者的包含关系。在MongoDB里,可以借助嵌套关系来完成这件事。

每次通过Team表中的teammates反查询得到teamid,Teammates需要建立索引,具体设计可以参照上图。当整个表比较大的时候,可以做手工分表,这点与关系型数据库类似。

当数据库中一个表的数量超过了千万量级时,我们会按照单个id进行拆分,比如用户信息表,我们会按照uid进行拆分。比如一些商品表,既可以按照用户来查询,又可以按照整个人来查询,这时候怎么办呢?

首先对整个表进行分表操作,infoid包含uid的信息,对infoid进行水平拆分,既可以按照uid查询,又可以按照infoid查询,可以很好地满足商品信息表的需求,整体思路还是按照水平拆分的方式。

起初,我们做了IM离线消息集合结构,也就是说,当某人不在线时,我可以把消息先存起来,待他上线时,再把整个消息拉过去。在这个过程中考虑到发生物理删除时,更新压力会比较大,我们采用逻辑更新,在表中设置flag字段,flag为0,表示消息未读,flag为1表示消息已读。批量删除已经读取的离线消息,可以直接采用MongoDB的删除命令,非常简单。但当数据量比较大时,比如达到5KW条时,就没那么简单了,因为flag没有索引,我们晚上20点开始部署删除,一直到凌晨依然没有删除完毕,整个过程报警不断,集群的服务质量大幅下降。

原因很简单,因为你要进行删除,实际上就是做了一个全表扫描,扫描以后会把大量冷数据交换到内存,造成内存里全都是冷数据。当数据高峰期上来以后,一定会造成服务能力急剧下降。怎么解决呢?

首先把正在进行的opid kill掉,至少先让它恢复正常,另外可以在业务方面做优化,最好在用户读完以后,直接把整个逻辑删除掉就OK了。其次,对删除脚本进行优化,以前我们用flag删除时,既没有主键也没有索引,我们每天定期从从库把需要删除的数据导出来,转换成对应的主键来做删除,并且通过脚本控制整个删除速度,整个删除就比较可控了。

另外我们发现,一旦大量删除数据,MongoDB会存在大量的数据空间,这些空洞数据同时也会加载到内存中,导致内存有效负荷低,数据不断swap,导致MongoDB数据库性能并没有明显的提升。

这时的解决方案其实很容易想到,MongoDB数据空间的分配以DB为单位,本身提供了在线收缩功能,不以Collection为单位,整个收缩效率并不是很好,因为是online收缩,又会对在线服务造成影响,这时可以采取线下的解决方案。

方案二,收缩数据库,把已有的空洞数据remove掉,重新生成一份空洞数据。先预热从库,把预热从库提升为主库,把之前主库的数据全部删除,重新同步数据,同步完成后,预热此库,把此库提升为主库,完全没有碎片,收缩率达到100%。但这种方式持续时间长,投入维护成本高,如果只有2个副本的情况下, 收缩过程单点存在一定风险。

这时在线上做对比,我们发现,收缩前大概是85G的数据量,收缩之后是30G,大概节省了50G的存储量,整个收缩效果还是蛮好的,通过这种方式来做还是比较好的。

另外讲一下MongoDB的监控,MongoDB提供了很多监控工具,包括mongosniff,mongostat,mongotop,以及命令行监控,还有第三方监控。我们自己怎么做呢?

我们针对MongoDB本身的性能情况,用的比较多的是mongostat,可以反映出整个服务的负载情况,比如insert,query,update以及delete,通过这些数据可以反映出MongoDB的整体性能情况。

这其中有些字段比较重要,locked表示加锁时间占操作时间的百分比,faults表示缺页中断数量,miss代表索引miss的数量,还包括客户端查询排队长度,当前连接数,活跃客户端数量,以及当前时间,都可以通过字段反映出来。

根据经验来说,locked、faults、miss、qr/qw,这些字段的值越小越好,最好都为0,locked最好不要超过10%,faults和miss的原因可能是因为内存不够,内冷数据或索引设置不合理,qr|qw堆积会造成数据库处理慢。

Web自带的控制台监控和MongoDB服务一同开启,可以监控当前MongoDB所有的连接数,各个数据库和collection的访问统计,包括Reads,Writes,Queries等,写锁的状态以及最新的几百行日志文件。

官方2011年发布了MMS监控,MMS属于云监控服务,可视化图形监控。在MMS服务器上配置需要监控的MongoDB信息(ip/port/user/passwd等),在一台能够访问你的MongoDB服务的内网机器上运行其提供的Agent脚本,Agent脚本从MMS服务器获取到你配置的MongoDB信息,Agent脚本连接到相应的MongoDB获取必要的监控数据,Agent脚本将监控数据上传到MMS的服务器,登录MMS网站查看整理过后的监控数据图表。

除此之外,还有第三方监控,因为MongoDB的开源爱好者对它的支持比较多,所以会在常用监控框架上做一些扩展。

以上是MongoDB在58同城的使用情况,包括使用MongoDB的原因,以及针对不同的业务场景如何设计库和表,数据量增大和业务并发时遇到的典型问题及解决方案。

今天的分享到此结束,谢谢大家!

关于DTCC

中国数据库技术大会(DTCC)是目前国内数据库与大数据领域最大规模的技术盛宴,于每年春季召开,迄今已成功举办了七届。大会云集了国内外顶尖专家,共同探讨MySQL、NoSQL、Oracle、缓存技术、云端数据库、智能数据平台、大数据安全、数据治理、大数据和开源、大数据创业、大数据深度学习等领域的前瞻性热点话题与技术,吸引IT人士参会5000余名,为数据库人群、大数据从业人员、广大互联网人士及行业相关人士提供了极具价值的交流平台。

【技术分享】孙玄:MongoDB在58同城的应用实践相关推荐

  1. MongoDB在58同城的应用实践

    58同城作为中国最大的生活服务平台,涵盖了房产.招聘.二手.二手车.黄页等核心业务.58同城发展之初,大规模使用关系型数据库(SQL Server.MySQL等),随着业务扩展速度增加,数据量和并发量 ...

  2. MongoDB在58同城百亿量级数据下的应用实践

    58同城作为中国最大的生活服务平台,涵盖了房产.招聘.二手.二手车.黄页等核心业务.58同城发展之初,大规模使用关系型数据库(SQL Server.MySQL等),随着业务扩展速度增加,数据量和并发量 ...

  3. 爱奇艺技术分享:爱奇艺Android客户端启动速度优化实践总结

    本文由爱奇艺技术团队原创分享,原题<爱奇艺Android客户端启动优化与分析>. 1.引言 互联网领域里有个八秒定律,如果网页打开时间超过8秒,便会有超过70%的用户放弃等待,对Andro ...

  4. 基于 React Native 的 58 同城 App 开发实践

    作者简介: 彭飞,58 同城 iOS 客户端架构师.专注于新技术的研发,主要负责 App 端组件化架构以及性能优化,并已推广 React Native 在 58 同城 App 中业务场景的应用.在 M ...

  5. 技术分享 | 混合云模式下SaaS端前端最佳实践

    导读:集成开放平台采用的是混合云部署架构,包含两个大的组件,管理控制台和引擎.管理控制台是SaaS的,部署在公有云,按租户隔离.引擎部署在客户私有云.一套SaaS版的管理控制台如何适配不同客户的引擎, ...

  6. 技术分享:浅谈Service Mesh在瓜子的实践

    作者 | zeyaries 过去三年,微服务成为业界的技术热点,大量互联网公司都在做微服务架构落地,新一代微服务开发技术悄然兴起,Service Mesh 便是其中之一,该技术起初由 Linkerd ...

  7. 【百度技术分享】San介绍以及在百度APP的实践

    导读:San是百度自研的高性能MVVM框架,它是一个快速.轻量.灵活的JavaScript组件框架,体积小巧,兼容性好,性能卓越,目前已落地百度APP包括搜索.feed.小程序等核心业务,服务于亿级用 ...

  8. 【SDCC讲师专访】58同城孙玄:一切抛开业务的架构设计都是耍流氓

    本期我们采访的讲师是来自58同城高级系统架构师&技术负责人孙玄,他是58的技术委员会架构组主任,产品技术学院优秀讲师,代表58同城参与多次对外演讲. 58同城高级系统架构师,技术委员会架构组主 ...

  9. 【IT名人堂】一个神奇的网站:58同城背后的数据库设计实践

    大家好,我是主持人皮皮,欢迎大家做客第116期名人堂.58同城,一个被贴上"神奇"标签的网站,海量信息背后到底支撑的数据库是什么?当并发访问量相当密集的时候,这些数据库系统都会采取 ...

  10. 58同城离线计算平台设计与实践

    分享嘉宾:余意 58同城 高级架构师 编辑整理:史士博 内容来源:58大数据系列直播 出品平台:DataFun 导读:58离线计算平台基于 Hadoop 生态体系打造,单集群4000+台服务器,数百 ...

最新文章

  1. uni-app与Vue的区别
  2. struts2加入自定义的actionValidatorManager实现类
  3. java pdf表单域实现_Java 创建PDF表单域 - 文本框、复选框、列表框、组合框、按钮等...
  4. 7-10 先序序列创建二叉树,输出先序序列、中序序列、后序序列并输出叶子结点数 (10 分)
  5. 云图说|云数据库MySQL内核小版本升级全攻略
  6. Oracle 基础知识
  7. 使用即时通讯(IM)SDK心得体验
  8. 今年一个偶然的创业,就改变了我的人生
  9. java多线程基础_java线程基础
  10. apache poi教程_Apache POI教程
  11. 新鲜出炉的2012年8月桌面日历壁纸免费下载
  12. 虚拟机上安装linux版QQ并卸载
  13. 6. 中学生心理辅导
  14. 傻子,疯子,一根筋的人才能创业成功!
  15. Aggressive cows-疯牛POJ(2456)-详解
  16. linux关闭后台所有jinch,Centos查看端口占用情况和开启端口命令
  17. 什么是好的BIM轻量化引擎
  18. 物联网技术 android,基于Android技术的物联网应用开发
  19. 客户案例 | 斯歌K2携手中国金茂,用匠心筑就城市运营_K2 BPM
  20. MMoE论文中Synthetic Data生成代码(控制多任务学习中任务之间的相关性)

热门文章

  1. C语言经典面试题100道(附完整答案)
  2. 苹果手机以旧换新价格表_苹果支持安卓手机以旧换新;索尼公司将更名;百度网盘推出“防误删”文件恢复服务...
  3. minist数据集的获取方法
  4. 开源C++/C代码检查工具
  5. 单元三:阻抗匹配(电容电感,变压器,传输线变压器,附带硬件电路)
  6. Maven打包时指定配置文件
  7. 结合插件实现【IDM+百度网盘】高速下载
  8. java web 读取txt文件_java读取TXT文件
  9. FIT2CLOUD飞致云正式启用CloudExplorer多云管理平台产品品牌
  10. C++实现16进制和字符串的转换