动态数据源@四种实现方案对比

简单描述需求,当前咱们的分析型数据都是不可变的,且每次的分析都是要将总体数据都加载到计算节点进行分析计算,因此基础的存储和缓存都是面向文件的,并不支持对某一行的修改,若是须要Update某些行或者插入新的记录,须要将增量修改与原数据源联合进行复杂的合并操做,对于常常须要修改的数据源尤为是更新某些行的属性值不那么方便,若是只是Append还好,而且还有对这个数据源的实时查询需求,用户但愿可以在页面上进行交互式查询,要求响应速度亚秒级别。git

看起来这个需求很像是一个数据库所擅长的,可是从另外的角度看,这并非典型的数据库的应用场景,咱们平时使用数据库都是做为某个成熟的业务场景的数据保存,这个数据通常是提早定义好的结构,数量能够很大可是数一个或者一组数据库实例服务组合在一块儿的这个集群,其中的表格种类通常是有限的几十最多几百个,而在咱们的产品中,这种可变数据源不属于产品的结构化数据,而是用户所自定义的我的数据,属于数据里边的数据,格式多种多样,做为一个个独立的数据源,且使用的频率很是低,有可能存在很大量的这种数据源,每一个的结构彻底不一样且属于不一样的用户,有可能一天也用不上一次,使用数据库来管理这种低频数据对资源有些浪费,大概能够采用的方案有如下三种:github

  1. 分布式数据库:
    也就是上边提到的,数据再也不以文件的形式存在于分布式存储中,而是直接写入到支持索引和复杂查询的数据库中,这个数据库能够支持各类存储结构,文档、图、key-value最好都支持,最好是支持很方便横向的扩展,可以无限制的新建不少的数据库和表,而且能够控制将表加载到内存以及释放内存,以减小资源的占用。从NOSQL Databases这个网站看了比较了不少的数据库,目前看来支持以上要求的数据库有RethinkDB和ArangoDB (Find ArangoDB on Github),Mongodb因为有明确的命名空间数量限制,因此建立表有数量限制,暂时不考虑,RethinkDB理念不错且支持对表的加载释放,API和文档很是友好,然而这家公司已经被收购,产品将来前景不明朗,而ArangoDB相对来讲很小众,支持的数据模型和索引种类不少,使用起来也相对比较灵活,运行效率也不错,能够做为首选考虑。
    * 优点就是使用起来简单,数据采用传统的数据库增删改语句写入到数据库中,查询也就直接使用索引,执行效率较高,使用数据库的引擎能够避免咱们本身去处理各类原始数据和增量数据的合并,以Write-Ahead-Log(WAL)系统为例,其实全部的修改操做都是直接写入日志,由数据库引擎去寻找对应的数据同步或者异步的将操做反应到底层的数据库存储中,多是某种自定义的文件结构,也多是某种更小巧的嵌入式数据库。最终数据的存在形式通常是一个方便插入的树型结构,常见的有B+树,LSM树。
    * 缺点也比较明显,一是资源的占用,用户的数据做为低频使用数据使用数据库来作托管相对比较昂贵,若是支持从内存中释放还能够减小数据库自身的缓存处理压力,若是表的数据很大数量不少则压力会更大,二是写入速度受限于数据库集群的处理能力,好比有大量的插入时须要路由节点的运行效率足够高,与Alluxio这种直接写本地缓存的速度有较大的差距,另外插入的过程当中须要创建大量的链接,不然单链接的循环写入速度会很是慢,三是跟Spark等分布式处理框架的结合,目前数据的输入输出都是类Hadoop文件的,若是直接读取或者写入数据库,须要本身开发,目前这方便比较少见,你们的分析型数据要么是直接从某系统导出要么就是直接生成的日志,不多直接使用分布式计算引擎去读取已经结构化的带索引的数据库,这样也会加大当前支持业务产品服务的数据库的压力。四是分析型数据的使用,假如这个数据源也会常常的跟其余数据联合或者独立的进行复杂的统计分析,这时典型的场景会经过Spark将数据都加载到内存中,至关于一次将数据库全表导出的过程,比直接读一个几百M的文件要慢不少。sql

  2. 采用嵌入式数据库
    嵌入式数据库相对分布式数据库更灵活,只须要在数据须要进行读写的时候启动一个实例供调用,不用的时候数据以文件的形式存在于系统中,对资源的消耗低,同时具备数据库读写的各类优点。缺点是文件只能存在于本地,若是咱们须要以统一的存储来做为嵌入式数据的来源,每次修改都须要去远程分布式文件系统去比较数据是否有更新,若是有须要加锁并下载数据到本地,启动实例进行读写,若是这时候有其余用户想修改则只能等待这个写操做释放,若是是读操做则不影响直接下载使用。在修改完成以后将数据写入分布式存储某地址,并标记新数据的地址为该数据源地址,控制起来比较复杂,因为没有统一的服务实例地址,本地操做之间互不知晓,因此不支持并行写入。一样也有分布式数据库的问题,须要本身开发Spark到嵌入式数据结构的转换代码,若是有直接支持远程分布式存储的嵌入式数据库就比较完美了,固然这种定义自己就比较矛盾,不是嵌入式数据库的使用场景。有个比较有趣的数据库是CouchBase,他家的嵌入式数据库能够在联网的时候将修改同步到远程数据库,适合网络环境不稳定的移动端,若是要在咱们的产品中使用也存在数据同步问题,由于数据不是在固定的某个“移动端”,随着计算资源分配的不一样,用户的可变数据源多是在任意一台机器的任意的一个容器。另外就是嵌入式数据库支持的数据量广泛规模较小。数据库

  3. 采用文件存储+OLAP解决方案
    Parquet+Druid解决方案,目前咱们采用Alluxio做为文件还存,HDFS或者S3做为底层的文件存储,具体的存储格式采用了利于分析的Parquet格式,且通过了压缩。可是不论是Alluxio仍是Partqut,都不支持对原来数据的修改,只适合于不可变的分析型数据源,假如须要对原来的数据进行修改,须要在Spark内部进行数据的联合,以后写入新的数据源,这个操做消耗较大,读写成本高。并且直接使用SparkSQL作数据分析实时性较差,即便对DataSet作了Cache也难以在秒内返回结果,因此须要借助于额外的索引服务,这里考虑了Druid,Pinot,Kylin这三种OLAP方案,其中麒麟纯粹的以绝对的空间换取时间,创建索引的时间也很长,使用不灵活,不考虑,前二者区别不大,成熟度上Druid更高,LinkIn 所开发的Pinot对非BitMap索引支持的较好,可能将来会比Druid好,但暂时不考虑。
    Druid作的事情比较简单,就是根据预先定义的数据格式(包括timestamp, dimension, metric 列的属性)将批量的和实时的数据通过一个Indexing service来生成目标的segment数据,生成的数据通过了压缩,针对不一样的统计列和分析列来生成对应的segment数据,以本身开发的列式存储的形式将这些中间索引数据保存下来,用户提交的查询通过broker节点会根据预先保存在metadata server里边的数据找到对应的historical节点或者realtime节点去进行索引数据的二次查询分析,不须要查询的节点不会收到请求,最终结果汇总到broker返回给客户端。做为一个额外的索引服务,其数据来源能够是Hadoop文件系统或者兼容的协议,索引数据也能够保存到他所定义的deep storage里边,也就是hdfs或者s3,保证数据也是分布式存储的,这个额外的服务除了占用系统计算资源不对如今的存储结构形成大的影响,也能够方便的迁移或者替换,若是咱们采用了数据库,这样若是要切换一种数据库,所须要的迁移工做是巨大的。
  4. ElasticSearch解决方案,原始数据依然经过文件备份,同时发送给ES作索引服务,支持增量更新以及一些简单的聚合运算,优点在于查询速度快,对于须要小规模结果返回的查询来讲优点很大,索引同时携带原始数据,能够做为数据库使用,但其核心引擎又是列式存储,利用率很高。ES还能够跟Spark直接链接,读取或者写入都有成熟的connector可用,结合ES的索引能力和Spark的分析能力,能够知足大部分的需求。

目前看来,选择哪一种方案仍是看具体的需求,能知足产品的设计。缓存

  1. 是否须要提供用户交互界面修改数据,或者每次批量的更新规模很是小,这种状况适合经过数据库来托管关系型数据源
  2. 是否常常须要从新分析这个数据源,仍是只是用来作实时查询展现用,若是须要分析,就会涉及倒全量数据的读取,适合采用文件
相关文章
相关标签/搜索