IndexR实现了一种可部署于分布式环境,可并行化处理,带索引的,列式的结构化数据格式。基于这种数据格式,IndexR构建了一个数据仓库系统(Data Warehouse),它基于Hadoop生态,可以对海量数据集做快速统计分析(OLAP),数据可实时导入并且对于查询零延迟。IndexR 为解决大数据场景下分析缓慢、数据延迟、系统复杂等问题而设计。本文描述了IndexR的设计思想,系统架构,以及核心的技术细节。
:
它最早是为了解决互联网广告业务产生的海量数据进行实时、在线分析而研发的分析型数据库,目前使用十几台一般配置服务器,支撑了舜飞科技包含多条业务线,每日近千亿数据的实时入库、在线多维分析系统。
IndexR开源至今,获得了国内外的许多团队的认可,从调研、测试到最后部署于生产环境,包括广告、电商、AI等领域的大型互联网公司和创业团队,以及政府,咨询,物流等有超大数据集,对数据质量有极高要求的行业。
开源地址:shunfei/indexr
<-----------------------------------------------
当前IndexR版本为-0.6.1, 从IndexR-0.6.0 开始,支持Spark 2.1.0+。您可以使用Spark以IndexR文件格式管理和查询表。IndexR文件格式支持所有Spark支持的操作,如Parquet。
由于Spark的运行架构,IndexR节点在Spark中不支持实时提取。
按照这里的说明在Spark中设置IndexR文件格式。
下面为建表格式。
IndexR模式:
{
"schema":{
"columns":
[
{"name": "date", "dataType": "int"},
{"name": "d1", "dataType": "string"},
{"name": "m1", "dataType": "int"},
{"name": "m2", "dataType": "bigint"},
{"name": "m3", "dataType": "float", "default": "-0.1"},
{"name": "m4", "dataType": "double"}
]
},
"location": "/indexr/segment/test",
"mode": "vlt",
"agg":{
"grouping": true,
"dims": [
"date",
"d1"
],
"metrics": [
{"name": "m1", "agg": "sum"},
{"name": "m2", "agg": "min"},
{"name": "m3", "agg": "max"},
{"name": "m4", "agg": "first"}
]
}
}
Hive模式:
CREATE EXTERNAL TABLE IF NOT EXISTS test (
`date` int,
`d1` string,
`m1` int,
`m2` bigint,
`m3` float,
`m4` double
)
PARTITIONED BY (`dt` string)
ROW FORMAT SERDE 'io.indexr.hive.IndexRSerde'
STORED AS INPUTFORMAT 'io.indexr.hive.IndexRInputFormat'
OUTPUTFORMAT 'io.indexr.hive.IndexROutputFormat'
LOCATION '/indexr/segment/test'
TBLPROPERTIES (
'indexr.segment.mode'='vlt',
'indexr.index.columns'='d1',
'indexr.agg.grouping'='true',
'indexr.agg.dims'='date,d1',
'indexr.agg.metrics'='m1:sum,m2:min,m3:max,m4:first'
)
;
Spark模式:
CREATE TABLE test_spark (
`date` int,
`d1` string,
`m1` int,
`m2` bigint,
`m3` float,
`m4` double,
`dt` string
)
USING org.apache.spark.sql.execution.datasources.indexr.IndexRFileFormat
OPTIONS (
'path'='/indexr/segment/test' ,
'indexr.segment.mode'='vlt',
'indexr.index.columns'='d1',
'indexr.agg.grouping'='true',
'indexr.agg.dims'='date,d1',
'indexr.agg.metrics'='m1:sum,m2:min,m3:max,m4:first'
)
PARTITIONED BY (dt)
;
> CREATE TABLE test_spark (
`date` int,
`d1` string,
`m1` int,
`m2` bigint,
`m3` float,
`m4` double,
`dt` string
)
USING org.apache.spark.sql.execution.datasources.indexr.IndexRFileFormat
OPTIONS (
'path'='/indexr/segment/test' ,
'indexr.segment.mode'='vlt',
'indexr.index.columns'='d1',
'indexr.agg.grouping'='true',
'indexr.agg.dims'='date,d1',
'indexr.agg.metrics'='m1:sum,m2:min,m3:max,m4:first'
)
PARTITIONED BY (dt)
;
> msck repair table test_spark;
> select * from test_spark limit 10;
> insert into table test_spark partition (dt=20160702) values(20160702,'mac',100,192444,1.55,-331.43555);
<-----------------------------------------------
IndexR可与Hadoop生态的各个系统互相配合,以下是一个典型系统的示意图。
存储格式自带索引。
IndexR包含三层索引,粗糙集索引(Rough Set Index),内索引(Inner Index)和可选的外索引(Outer Index)。
目前的On Hadoop存储格式如ORC,Parquet等都没有真正的索引,只有靠分区和利用一些简单的统计特征如最大最小值,可以大概满足离线分析的需求,但是在服务在线业务的时候就非常力不从心,需要从磁盘读取有大量无用数据。事实上并不是每次查询都需要获取全部数据,特别Ad-hoc类型的查询。IndexR通过多层索引设计,一方面极大的提高了IO效率,只读取有效数据,另一方面把索引的额外开销降到最低。
一般传统数据库系统的索引设计是通过索引直接命中具体的数据行,但是这样方式只适用于OLTP场景,即每次查询只获取少量数据。但是在OLAP场景下并不适合,每次查询可能要涉及上万甚至上亿行数据,这样的设计的索引开销极大(内存、IO、CPU),并且带来磁盘随机读的问题,很多时候还不如直接对原始数据扫描速度快。
IndexR的索引设计是分层的。打个比喻,如果要定位全国具体的某个街道,传统的方式是把“省市-街道”组成一个索引,而IndexR是通过把“街道”映射在相应的“省市”的集合(Pack)里,然后再在具体的集合了里做细致的索引。
具体查询的时候,IndexR先进行粗糙集索引过滤,再对剩下的数据集进行倒排索引过滤。然后把命中的Pack直接加载入内存,对其进行高效的细致查询。这种方式解决了分布式架构、海量数据场景下索引困难的问题,避免了随机读问题,不管是在需要大范围扫描还是少量数据查询,效率都很高。
两种存储模式,适应不同场景
支持流式导入,实时分析
目前的Hadoop生态对于实时的数据分析还是比较困难。比如Storm、Spark Streaming,这类型属于对数据进行预计算,在业务频繁改动,或者需要对原始数据进行启发式分析(Ad-hoc)的情况下没法满足需求。而Druid,Kudu等系统虽然支持实时写入,但是属于自成体系的,在我们的实际运用中遇到部署、整合甚至性能方面的问题。
IndexR支持实时数据写入,比如从Kafka导入,并且数据到达系统之后可以立刻被分析,它与Hadoop生态的无缝整合,使得对于业务设计非常灵活。目前IndexR单表单节点入库速度每秒超过3w条数据,入库速度随着节点数量线性增加,每个表使用一个单独的线程,互不影响。对于OLAP型多维分析场景,IndexR还支持实时、离线预聚合,让分析速度飞起!
速度超快
IndexR使用深度优化的编码方式,大大加快数据解析,甚至可以媲美一些内存数据库。它的数据组织形式根据向量化执行的特点定制,把全部数据存放于堆外内存,并且优化到个byte的组织方式,把JVM的GC和虚函数开销降到最低。
IndexR是基于Hadoop的数据格式,意味着文件存放于HDFS,这样可以非常方便的利用HDFS本身的高可用特性保证数据安全,并且可以方便的使用Hadoop生态上的所有分析工具。我们对基于HDFS的文件读取做了大量的优化工作,把计算尽量分发到离数据最近的本地节点,HDFS层的开销基本被剔除,与直接读取本地数据无异。
以下是使用TPC-H数据集,IndexR与Parquet格式在相同的Drill集群上做的一个性能对比。
最大表lineitem数据总量6亿,5个节点,节点配置 [Intel(R) Xeon(R) CPU E5-2620 v2 @ 2.10GHz] x 2, RAM 64G(实际使用约12G), HDD SATA with 7200RPM。
柱状图:
柱状图:
省资源
IndexR的数据结构经过精心设计,绝不多浪费任何内存空间。为了避免Java中对象和抽象的开销,IndexR的代码大量使用了Code C In Java的编程风格(调侃),通过内存结构而非接口进行解耦。紧凑的内存结构减少了寻址开销,且非常利于JVM的运行时优化。结果是IndexR保证了高性能、有效索引的同时非常省内存,与使用Parquet格式查询时的内存使用量差不多,不会出现CarbonData需要配置超大堆内存的情况。但是为什么不直接使用C或者C++呢?因为目前Hadoop生态最适合的开发语言还是基于JVM的语言,可与其他系统无缝集成,在工具链支持方面也是最全面的。
IndexR通过与Hadoop生态的深度整合,非常适合用来搭建海量数据场景下的数据仓库。
IndexR从开源至今,经过不同的团队实践,积累了很多使用案例,下面介绍我们了解到的IndexR在不同公司的几个常见使用方式。
替换Parquet,利用IndexR的强大性能和索引优势,可以加速整个查询系统。
替换Druid等,做实时入库,多维分析。IndexR可以实现Druid的所有功能,并且有完整的SQL支持,包括Join,子查询,多数据源等。它没有时间窗口概念,不会主动丢弃过期数据,运维更加简单,数据存放于HDFS,可以使用同一份数据进行离线分析。大部分查询性能比Druid要好,即使没有SSD硬盘也能获得很好的性能,并且非常的省内存。
将IndexR与其他开源工具结合,如Drill,搭建OLAP查询系统。利用IndexR支持实时入库的特性和查询速度优势,并且基于Hadoop生态的特点,很容易满足实时分析、海量数据、线性扩展、高可用、功能丰富、业务灵活等当前和未来对于OLAP系统的需求。不再有纯预计算所带来的局限性所困扰,且在线分析和离线分析可以使用同一份数据,提高率用率,降低成本。
作为数据仓库的存储格式,存放海量历史数据,并且支持都有海量实时的数据入库,数据使用方式包括明细查询,在原始数据上做分析查询,和定期的预处理脚本。
MySQL、Oracle等业务数据库,或者ES、Solr等搜索引擎,把它们统计分析工作移交到IndexR系统,通过模块分离,提高服务能力。
IndexR适合的经典场景:
目前业界典型选型:
IndexR项目由舜飞科技开源并快速推进,目前已经发布0.6.1版本。IndexR立志于成为Hadoop生态下快速分析查询的标准存储格式。希望它可以获得业界更多的关注和使用,和社区的更多积极参与。
大数据经过近些年的快速发展,完整的生态渐渐成熟,已经早已不是只有Hadoop跑MR任务的时代。人们在在满足了能够分析大量数据集的需求之后,渐渐的对时效性、易用性等方面提出了更高的要求,因而诞生了如Storm,Spark等新的工具。新的问题催生新的挑战,提供新的机遇。而传统的数据仓库产品,在面对大数据的冲击显得非常无力。IndexR为解决这种现状,提供了新的思路和方向。
IndexR是新一代数据仓库系统,为OLAP场景而设计,可以对超大量的结构化数据进行快速的分析,支持快速的实时入库。它功能强大,并简单可靠,支持大规模集群部署。它与Hadoop生态系统深度整合,可以充分发挥大数据工具的能力。
不用再为分析能力的瓶颈担忧,不用放弃经典的OLAP理论,不用降级你的服务,不用担心业务人员对大数据工具不熟悉,IndexR像Mysql一样好用,会SQL就好了。
IndexR在开源之后,我们已经看到有不少使用案例,包括国内外的不同团队。有意思的是,有些团队的使用方式比较特别,比如用于存放超大量(单表千亿级别)的复杂明细数据,做历史数据的明细查询。IndexR不仅可以用于多维分析,商业智能等OLAP经典领域,还可以用于物联网,舆情监控,人群行为分析等新兴方向。