MongoDB线上实践指南-基础篇之支撑百亿级访问(二)

来源:互联网 发布:手机小夜灯软件 编辑:程序博客网 时间:2024/05/18 02:43

支撑百亿级访问的MongoDB线上实践指南

文档

文档中的key禁止使用任何_以外的特殊字符

尽量将同样类型的文档存放在一个集合中,将不同类型的文档分散在不同的集合中

相同类型的文档能够大幅度提高索引利用率,如果文档混杂存放则可能会出现查询经常需要全表扫描的情况

禁止使用_id,如:向_id中写入自定义内容

【案例3】某业务的MongoDB在放量后出现严重的写入性能问题,大致为:写入达到300/s的时候IO跑满,排查中发现,该业务在设计的时候为了方便, 而将_id中写入了无序的类似md5的数据。MongoDB的表与InnoDB相似,都是索引组织表,数据内容跟在主键后,而_id是MongoDB中的默认主键,一旦_id的值为非自增,当数据量达到一定程度之后,每一次写入都可能导致主键的二叉树大幅度调整,这将是一个代价极大的写入, 所以写入就会随着数据量的增大而下降,所以一定不要在_id中写入自定义的内容。
尽量不要让数组字段成为查询条件


【案例4】某业务在一个表的数组字段上创建了一个索引,创建完毕之后发现表体积增大了很多很多,排查发现是由于索引体积的大幅度增大导致在MongoDB中,如果为一个数组字段添加索引,那么MongoDB会主动为这个数组中的所有元素依次添加独立索引,例如: 为数组字段{a:[x,y,z]}添加索引{a:1},实际上添加的索引为:
{a:[x:1]}
{a:[y:1]}
{a:[z:1]}
该业务的数组字段中有11个元素,那么等于一次创建了11条索引,这是索引体积大幅度增大的根本原因。 另外,如果组合索引中存在数组字段,那么MongoDB会为每一个元素与其它字段的组合创建一个独立的索引,例如: 为数组字段{a:[x,y,z]}和{b:qqq}添加索引{a:1,b:1},实际上添加的索引为:
{a:[x:1],b:1}
{a:[y:1],b:1}
{a:[z:1],b:1}
如果一个组合索引中存在两个数组字段,那么索引的数量将是两个数组字段中元素的笛卡儿积,所以MongoDB不允许索引中存在一个以上的数组字段。

如果字段较大,应尽量压缩存放

【案例5】某业务上线后一直很正常,但在放量3倍之后发现MongoDB服务器的网卡流量报警,IO压力报警,排查中发现,该业务讲一个超长的文本字段存 放在MongoDB中,而这个字段的平均体积达到了7K。在并发为2000QPS的场景下,每次取出1~20条数据,导致这个MongoDB每秒钟要发送将 近100MB的数据,而对于数据库而言,读写均为随机IO,所以在如此大的数据吞吐场景中,IO达到了报警阈值。
由于文本是一个容易压缩的样本, 所以我们对该字段进行了压缩存放,使其平均体积降低到了2K,而解压在业务端进行处理,最终将吞吐降低到了20MB/S左右。

如果字段较大且会成为查询条件,例如一长串的url,尽量转成md5后存放

【案例6】某业务上线前进行压力测试,测试中发现某个场景下的查询性能不够理想,排查中发现该场景的查询条件类似:{url:xxxx},而url字段中的值大部分都很长很长,该字段的平均体积达到了0.5K,在这种情况下索引的体积会变得很大从而导致虽然请求虽然能够走索引但效率并不够理想,于是dba配合业务开发一起对该场景进行优化:
1.将该字段的存放的内容由真实的url改为url内容md5后的值,字段体积得到了大幅度缩小,固定在了32位
2.查询时,用户请求通过url查询,而此时程序会将该url进行md5,然后用得到的值进行查询,由于所以体积大幅度缩小,所以查询速度有了极大的提高,优化完毕后再次进行压力测试,性能达标,为之前的6倍。
由于MongoDB是大小写敏感的,如果字段无需大小写敏感,为了提高查询效率应尽量存放统一了大小写后的数据,如:全部小写或为该字段增加一个统一了大小写的辅助字段


【案例7】 某业务需要根据字段{a:XxX}来进行查询,在MongoDB中a的值是大小写敏感的,并且无法配置为忽略大小写,但该业务场景为了满足查询需求而需要忽略大小写,这个大小写敏感与否的矛盾导致业务需要使用正则来进行匹配:{a:/xxx/i},i参数在正则中表示忽略大小写,上线后发现, 查询性能非常低下,在一个拥有200万文档的集合中一次查询需要消耗2.8~7秒,并发达到50QPS的时候MongoDB实例所在服务器的CPU就跑到了973%。
MongoDB在查询条件中使用正则的时候,能够像普通精确匹配一样使用索引达到高效率的查询,但一旦使用了参数i来忽略大小写查询优化器就需要对每一个数据的大小写进行调整然后再进行匹配,此时这个请求就变成了全表扫描,这就是效率低下的根本原因。
对于这种场景可以采用新建一个统一了大小的字段,例如全部小写:假设原字段为:{a:aAbB},那么为其添加一个全部为小写的对应字段:{a_low:aabb}然后通过字段a_low进行查询就能达到精确匹配,按照该方案改进后,该场景的查询耗时降低到了2毫秒 虽然新增字段导致实例会变大一些,但对于换来性能的大幅度提升还是非常值得的。

不要存放太长的字符串,如果这个字段为查询条件,那么确保该字段的值不超过1KB

MongoDB的索引仅支持1K以内的字段,如果你存入的数据长度超过1K,那么它将无法被索引

0 0