auto-sharding 无用论:auto-sharding vs. manual-sharding

本文深入探讨了MongoDB的Auto-Sharding功能在实际应用中遇到的问题,包括数据分配不均、迁移代价大及碎片化现象,并对比了手动分片的优势。同时分析了冷数据对存储规划的影响,指出Auto-Sharding可能导致的老结点资源浪费,并提出通过手动分片进行冷数据管理的建议。

原文连接已经无法打开

一、美好的蓝图

刚接触MongoDB的时候,看到它的auto-sharding功能图,配合上replica sets简直有一种一统世界的感觉。既下图:

mongodb auto-sharding

图中路由机mongos可以有多台,config机器可以多台配置成主从或者replica sets,sharding的每个结点是三台mongod组成的replica sets。高可用性,无限扩展性尽在眼前。看似宏伟壮观。

然而当我真的打算要用auto-sharding功能的时候,才发现此设计根本不适用,下面谈一点我个人的看法。

Sharding一词的翻译是分片,在这里的意思是将数据进行水平切分。最简单的例子就是我们在数据库设计中的分库分表,在Memcached缓存中的多结点hash存储。而MongoDB的auto-sharding功能重在一个auto(自动化分片)。官方称,使用这一功能,你只需要指定数据分片依赖的某个字段值,既可在不关心具体结点数量的情况下存储你的数据,数据会自动平均分配到后端结点,在增加结点时,数据又会自动的进行迁移,对整个系统进行负载平衡。相比我们传统的分库分表,它是auto(自动)的,而传统方法是manual(手动)的。

二、Foursquare宕机事件

看罢上面的描述,好像没有任何可以挑剔的理由,但事实并不如描绘的那样美好,从Foursquare长达11小时的宕机事件分析中,我们可以看到如下一些问题:

  1. auto-sharding算法导致数据分配不均:事实上数据并不会那么平均的在各个机器间平均分配,由此而造成的短板效应是无法忍受的。
  2. 数据迁移代价过大:在增加新的sharding结点时,数据确实会自动的进行迁移,而这种迁移对于原来线上服务的结点,服务上是有影响的。所以我们最好在存储瓶颈到来很早之前就开始做这个迁移,而这样做,和我们手动进行分片,预先估算好数据量相比,优势不再明显。
  3. 数据迁移造成碎片:同样是Foursquare的失败经验,在数据迁移时,我们需要迁移的数据通常并不会在磁盘上进行连续存储(除非你的hash条件是天然的insert时间戳)。而我们又知道MongoDB采用的是磁盘空间预分配的机制,于是在数据迁移时,可能并不会减小磁盘占用空间,反而会使得磁盘碎片化。更甚的是由于MongoDB在是采用mmap提速数据访问,磁盘空洞并不会减小mmap的大小,反而导致内存也碎片化。

而以上一些问题,在我们预先规划好存储量的manual-sharding上,是不存在的。

三、冷数据不冷

我认为在存储规划上,可以简单的从两方面来评估,一是磁盘占用,也就是总数据量,二是内存占用,也就是热数据量。热数据在全部数据的中所占的比例,通常会越来越小。造成这一原因的是老数据的访问量下降。我们考虑这样一种情况,如果你的应用用户量和每日新增数据量已经相当稳定,我们以最近三天的数据为热数据进行评估,那么总数据量会随着时间的增长而增长,而热数据量永远是三天的量。我们这里举的是一个极端的例子,可能你的用户量会每天增长,但是热数据量在全部数据中占的比例,通常是越来越少的,这个事实不容反驳。

上面说了这么多,下面我们来看我们的问题。

  1. auto-sharding数据量变化情况:和我们上面说的情况一样,auto-sharding机群会通过增加结点数来扩展集群的存储能力。结点数和数据量成线性的正比关系。
  2. auto-sharding的热数据比例:auto-sharding一旦一个结点配置完成,那么这些机器的内存与磁盘空间比就定了。于是整个集群的热数据比例占所有数据的比例也是一定的。

而对比我们上面的说法,热数据占比例在所有数据中是会越来越小的。于是我们可以认为,auto-sharding中的老结点浪费掉了大量的内存和CPU资源。

而如果我们是人为手动进行分片,我们完全可以自己控制数据的存储,自行设定自己的LRU或者TTL机制,将老数据,冷数据进行存储转移,不再占用高性能机器的各项机能。从而让我们公司花大钱买来的机器能够物尽其用。

好了,就说这一些,理解不一定正确,欢迎探讨,拍砖。



这个是我的配置信息有没有需要修改的 spring: redis: host: 10.224.206.16 port: 6379 password: Siq2025redisZS datasource: type: com.zaxxer.hikari.HikariDataSource kafka: bootstrap-servers: 10.224.206.16:9092 listener: type: batch producer: acks: 1 batch-size: 16384 retries: 0 buffer-memory: 33554432 key-serializer: org.apache.kafka.common.serialization.StringSerializer value-serializer: org.apache.kafka.common.serialization.StringSerializer consumer: group-id: myGroup enable-auto-commit: true auto-commit-interval: 100 key-deserializer: org.apache.kafka.common.serialization.StringDeserializer value-deserializer: org.apache.kafka.common.serialization.StringDeserializer shardingsphere: mode: type: Memory repository: type: JDBC overwrite: false datasource: names: enterprise-info,tag,app enterprise-info: type: com.zaxxer.hikari.HikariDataSource driver-class-name: dm.jdbc.driver.DmDriver jdbc-url: jdbc:dm://10.224.206.78:5236/DAMENG?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true username: SYSDBA password: Dm123456 minimum-idle: 5 idle-timeout: 180000 maximum-pool-size: 300 max-lifetime: 0 connection-timeout: 30000 connection-test-query: select 1 connection-init-sql: SET SCHEMA ENTERPRISE_INFO tag: type: com.zaxxer.hikari.HikariDataSource driver-class-name: dm.jdbc.driver.DmDriver jdbc-url: jdbc:dm://10.224.206.78:5236/DAMENG?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true username: SYSDBA password: Dm123456 minimum-idle: 5 idle-timeout: 180000 maximum-pool-size: 300 max-lifetime: 0 connection-timeout: 30000 connection-test-query: select 1 connection-init-sql: SET SCHEMA TAG app: type: com.zaxxer.hikari.HikariDataSource driver-class-name: dm.jdbc.driver.DmDriver jdbc-url: jdbc:dm://10.224.206.78:5236/DAMENG?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true username: SYSDBA password: Dm123456 minimum-idle: 5 idle-timeout: 180000 maximum-pool-size: 300 max-lifetime: 0 connection-timeout: 30000 connection-test-query: select 1 connection-init-sql: SET SCHEMA APP rules: - type: SHARDING tables: enterprise_factdata_daily: actualDataNodes: enterprise-info.enterprise_factdata_daily$->{0..31} tableStrategy: standard: shardingColumn: social_creditcode shardingAlgorithmName: table-sharding-algorithm shardingAlgorithms: table-sharding-algorithm: type: CLASS_BASED props: strategy: standard algorithmClassName: com.tencent.egb.job.configuration.TableShardingAlgorithm props: # 关键配置:禁用数据库元数据检查 check-database-metadata-enabled: false check-table-metadata-enabled: false sql-show: false query-with-cipher-column: true check-duplicate-table-enabled: false proxy-frontend-flush-threshold: 128 sql-comment-parse-enabled: false jpa: database-platform: org.hibernate.dialect.DmDialect show-sql: true hibernate: ddl-auto: validate naming: physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl properties: hibernate: default_schema: ENTERPRISE_INFO dialect: org.hibernate.dialect.DmDialect hibernate.dialect.storage_engine: dm globally_quoted_identifiers: true globally_quoted_identifiers_skip_column_definitions: true jdbc.batch_size: 50 jdbc.fetch_size: 100 jdbc.time_zone: Asia/Shanghai temp.use_jdbc_metadata_defaults: false hibernate.length_force_inline: true hibernate.varchar.maxlength: 8188 format_sql: true use_sql_comments: true
最新发布
08-28
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值