在线Excel存储方案

2022-08-25 13:57:13 浏览数 (1)

引言:设计数据存储方案时,Feed流、IM消息、订单等一些典型业务场景的,都有比较多的技术文章和教学课程;在线Excel场景下的文章却很匮乏,所以把自己近期对在线Excel存储选型的一些思考写下来,和大家一起交流。

文章主要有四部分:场景介绍、问题分析、方案设计、总结。

场景介绍

数据介绍

在线Excel场景下,主要有人、Excel文档两个实体。

人的主要属性有:用户ID、人员名称等,是典型的结构化数据,我们只需要根据数据量去选择合适的存储方案就可以,不是本文的重点,就不细说了。

我们重点分析Excel文档的存储。

Excel文档的数据主要包括:

字段

描述

特点

元数据

文件名、创建者、创建时间等

结构化

Sheet页

一个Excel可以有一个到多个Sheet页

表格整体配置

对某个sheet页生效的配置,比如背景色、字体、主题、冻结行列等

配置丰富,适合JSON格式,JSON嵌套深,易变

行、列

行、列高度宽度、列筛选、列排序

单元格数据

单元格展示的文本信息、数据类型(比如数值、字符串、时间等)、数据的样式

信息多,适合JSON格式,易变

单元格样式

单元格的宽高、背景色、左右对齐、自动换行

信息多,适合JSON格式,易变

函数

比如:求和、平均值等

信息多,适合JSON格式,易变,要和单元格关联

图表

柱状图、饼图、曲线图等图表数据

适合JSON格式,JSON嵌套深,易变,要和单元格关联

其他功能

比如数据透视表等,随着在线Excel功能的丰富,需要更多数据支持

不可控

用户行为

我们把用户在Excel系统中的操作,抽象到存储层,主要有:

  1. 对Excel元数据的实时读和写操作
  2. 对Excel文档内容的实时读和写操作

基于用户平常使用Office Excel的场景分析,Excel文档还有以下特点:

  1. 通常绝大多数Excel在1M之内。但是也有一些场景下Excel会有几十M甚至几百M
  2. 单元格数量众多
  3. 一个单元格的内容通常不会特别大(不排除极端场景)
  4. 用户读写Excel数据时,一次只能操作一个sheet页
  5. 有些Excel文件创建完之后读写频次并不高,比如:历史销售数据、几年前的财务报表。但是如果用户一旦打开查看就有可能产生实时的读写请求
  6. 对于Excel文档内容的读操作基本都是全量读,写操作是针对部分字段写
  7. 随着时间的积累Excel文档的数量会越来越多
  8. 有些使用场景下用户修改的单元格内容是不能丢失的,一旦丢失可能会给用户带来巨大损失,所以我们文档内容的写操作更倾向「CP模型」。 当然如果客户明确给出了Excel的使用场景,比如记录任务、填写OKR、统计学生人数等等不是特别重要的数据,AP模型也可以。(CAP模型见《分布式理论》)

问题分析

通过场景分析我们总结出一些比较关键的问题:

问题一:不管是元数据还是Excel文档数据都有「实时读写」的需求,所以我们需要低延迟的数据库

问题二:Excel文档内容的数据字段特别丰富,所以我们的数据库要支持非结构化数据存储。文档型数据库通常都支持非结构化存储。选择文档型数据库可以让我们更方便的设计Excel的JSON结构;也可以允许我们只「更新JSON中的某个Key对应的Value」值而不用更新整个JSON,而且在扩展一些功能时,不用像关系型数据库一样修改表结构。

问题三:单个文档既有小于1M的又有上百M的。小文档可以存在数据库的一个字段里,但是在如果大文件存在一个字段中,通常会面临诸多问题。比如MongoDB一行document最大支持15M;再比如用MySQL(InnoDB引擎)的Longtext类型存储很多上百M的数据时,对MySQL的查询性能也会有一定的影响。

问题四:能否把Excel的一个单元格存为数据库的一行?

  • 假设有1万用户,每人创建100个Excel,每个Excel有1个Sheet页,每个Sheet页有1000行*10列的数据。1万*100*1*1000*10 == 「100亿」
  • 「100亿」行数据,如果我们用MySQL分表的话,每个表控制在「1000万」行记录,需要一千个表。如果我们的业务量增长10倍就需要一万个表,这么庞大的分表数量显然是不太可取的。
  • 因为我们的每个单元格内容往往很少,单独占用数据库中的一行记录是很浪费资源的(因为绝大多数数据库每一行记录存储都是有额外开销的,比如分配唯一ID;一行记录也往往是数据库存储链表中的一个节点,多了会影响数据库性能),为了解决这个问题我们可以把Excel中的「一行记录」作为一个整体存入数据库中的一行,我们称这种存储方式为「行式存储」。基于我们上面的100亿数据,如果改成行式存储,100亿条记录立马变成了「10亿条」,少了一个数量级。
  • 再进一步思考,如果Excel中的10行记录存为数据库中的一条记录的话,我们的「10亿条」记录就变成了「1亿条」。1亿条记录对我们来说就手到擒来了。
  • 其实刚才的「10行」记录也可以是「15、20行」。具体的行数可以根据业务中实际的数据计算一个合理的数值。这样我们业务层的设计就为我们的存储极大的减轻了压力。当然业务上的牺牲就需要我们的业务逻辑里去解决Excel的行和数据库中行的匹配问题,不过这个也很简单,在Dao层做一下封装就可以了。
  • 既然能按行存,那能否按列存呢?答案是否定的。因为实际场景中很多Excel可以会存在上百万行。如果按Excel的一列为数据库的一行记录又会存在大字段的问题(大字段虽然也有解决方案,但是我们在做设计时要尽量避免)。

问题五:对于一些访问频繁的Excel文件我们可以认为是「热数据」,采用低延迟的数据库,而且需要创建好索引加快数据的查找。但是对于一些被打入冷宫的「冷数据」,和热数据放在一起,有一种站着茅坑不拉屎的感觉。所以我们可以把冷数据单独存储,当用户访问到这些冷数据时,再把它们读出来,和热数据存在一起。

方案设计

经过上面的分析我们对数据库的需求有:

需求

是否必须

低延迟

必须

支持CP模型

必须

支持非结构化数据存储

必须

有亿级数据的存储方案

必须

有成熟的扩容方案

必须

冷热数据

非必须

各类数据库对比

传统的关系型数据库(RDBMS)在访问延迟和CP模型支持上都很好,但是不支持非结构化数据,所以如果选择关系型数据库对我们进行Schema的设计会有很大的挑战,也会给业务开发带来很大工作量。

文档型数据库(MongoDB),对非结构化数据的存储支持友好,最典型的比如MongoDB。而且MongoDB对访问性能也高于很多传统关系型数据库。MongoDB也有类似MySQL的Write Ahead Log的方案,可以支持CP模型。

NewSQL数据库(TiDB,OceanBase):低延迟和CP模型基本都能支持,非结构化数据存储有的数据库支持有的数据库不支持。

对象存储(S3、HBase):低延迟和CP模型支持不太好,但是由于成本低廉和相对不错的访问速度比较适合存储冷数据。

最终选型

需求

MySQL

MongoDB

TiDB

S3

低延迟

支持CP模型

支持非结构化数据存储

有亿级数据的存储方案

✅ ✅

有成熟的扩容方案

冷热数据

MySQL是典型的传统关系型数据库,MongoDB是典型的文档型数据库,TiDB是典型的NewSQL数据库,S3是典型的对象存储数据库。近几年,随着互联网的发展新出的数据库类型和服务越来越多比如:阿里的OceanBase、腾讯的TDSQL、Cos等等。

选择数据库时,除了我们上面分析的问题,还需要考虑数据库的吞吐量、高可用架构、数据安全等问题。一般使用比较多的数据库如MySQL、MongoDB在这些方面都有成熟的方案。综上所述:采用「MongoDB」来存储元数据和Excel文档的热数据,采用「对象存储」来存放冷数据是一个比较不错的方案。

方案不止一种,主要是大家理解业务场景中的关键点然后做出对应的选择就可以了

前面我们主要考虑的都是开源数据库,其实还有云厂商的数据库可以选择,比如阿里云的表格存储。

总结

本文我们通过分析在线Exce场景,分析其中的关键问题,经过业务的设计让步之后,明确存储的必要需求,然后根据各种数据库的特点,最终选择合适的数据库。

在做存储选型时还要从实际出发,考虑当前数据规模、公司运维能力等其他因素;还要预留充足的buffer防止预估偏差,并给不可预估的业务增长留下足够的缓冲空间。

最后

前几天刚写了《如何实现多人协作的在线文档》,今天又来写Excel。后续还会产出几篇,目的就是把在线协作场景的各种问题和大家交流学习。

如果大家对在线协作或者类似的场景中有问题欢迎留言交流,有好更好的建议、更优雅的方案也请不吝赐教。

0 人点赞