基于SnappyData构建实时数据仓库

SnappyData是一个基于内存的数据库,和redis不同的是SnappyData以数据分析为主,可以处理一定的并发量,但不建议太高,100%支持hive sql,但执行速度比hive快数百上甚至千倍,自带spark(指定的spark版本)。

背景

随着易企秀业务的发展,大量的分析需求&报表需求接踵而至,产品和运营同学对数据分析的要求越来越高、对数据分析延迟越来越低,之前通过由数据产品梳理业务指定分析指标,再由研发进行完成计算的方式已不能胜任,需要重新重视数据仓库的重要性。

介绍

这里采用的优化方案是SnappyData + CBoard,通过jdbc连接SnappyData进行业务数据实时交互分析。其中CBoard是一个开源的自助分析BI系统,简单的分组排序需求,产品和运营同学可以在上面托拉拽实现,从此研发同学不用加班加点疲于完成各种定制化报表了、大量释放了研发同学的宝贵时间;SnappyData是一个开源的内存型OLAP分析数据库,支持列式与行式存储,目前我们绝大部分数据分析业务都能秒出,支持adhoc, 100%兼容spark算子与sql操作,可通过spark 任务快速实现HDFS或者hive中的数据导入到SnappyData。

常见OLAP对比

数据库 响应时间 并发能力 社区 处理能力 分析能力 缺点
Impala 适中 支持的数据规模大 支持标准SQL以及多表join和窗口函数 性能差、不实时
Kylin 活跃 支持的数据规模大 性能高,支持标准SQL 需要预计算、不支持多表关联
Druid 活跃 支持的数据规模大 性能高,但SQL支持弱 不支持adhoc、吃内存
ES 活跃 支持的数据规模小 性能高,但SQL支持弱 仅支持单表的分组聚合排序
ClickHouse 不活跃 支持的数据规模一般 性能中,但SQL支持弱 扩展性弱、不支持adhoc
Doris 适中 支持的数据规模大 支持标准SQL 还在孵化阶段、不兼容hadoop生态
SnappyData 不活跃 支持的数据规模中等 完全兼容spark sql,支持update与delete操作 稳定性差、存在OOM的风险

虽然snappydata的社区并不活跃,但个人觉得官网提供的一手资料已经足够了,即便snappydata稳定性稍差但易用性和性能做的真是太诱人了

应用

这里以一个简单例子讲解SnappyData的使用:将现有日志数据导入到SnappyData,实现用户多维度自助分析。

  • 安装
1、官网下载最新的SnappyData文件 ,

2、分发在20台hadoop nodemanager节点上

3、
启动 locator(任意两台):
./sbin/snappy-locator.sh start -peer-discovery-address=hadoop011 -peer-discovery-port=8888  -dir=/data/work/snappydata-1.1.0-bin/data/locator_1 -heap-size=1024m  -locators=hadoop010:8888

启动 lead(任意两台):
./sbin/snappy-lead.sh start -dir=/data/work/snappydata-1.1.0-bin/data/lead_1 -heap-size=4096m -spark.ui.port=2480 -locators=hadoop011:8888,hadoop010:8888 -spark.executor.cores=20

启动 server(所有节点):
./sbin/snappy-server.sh start -dir=/data/work/snappydata-1.1.0-bin/data/server_1  -heap-size=8096m -locators=hadoop010:8888,hadoop011:8888

4、监控
浏览器输入如下地址
 http://hadoop010.eqxiu.com:2480/dashboard/ 

  • 导入日志数据
    因为我们的按天日志数据都在hdfs上,以parquet格式压缩存储,这里我们使用spark脚本进行ETL数据迁移,命令如下:
val snappy = new org.apache.spark.sql.SnappySession(spark.sparkContext)

val df = spark.read.parquet("/data/merge/tracker_view/page_view/201906/01")

val sn = snappy.createDataFrame(df.rdd, df.schema)

#第一次执行saveAsTable 会自动在SnappyData中创建对应的表
sn.write.format("column").saveAsTable("tracker_view")

#之后每天增量执行
sn.write.format("column").insertInto("tracker_view")

也可以手动先创建表 ,然后再导入数据

CREATE TABLE CUSTOMER ( 
    C_1     INTEGER NOT NULL,
    ...
    ...
 )
 USING COLUMN OPTIONS (BUCKETS '10', PARTITION_BY 'C_1')

其它参数说明

1、COLOCATE_WITH:COLOCATE_WITH {exist_table}语法的含义是对于新建的表,与exist_table具有相同的分区键,且相同键存储在同一个节点上,即数据存储本地化。这样做的好处是当2个表发生基于key的join时,那些非常耗资源的hash join就不用跨节点进行数据传输(广播),而是在本地进行join。这个设计思路非常像关系型数据库Oracle中的cluster存储。这种数据存储本地化的特点,也是SnappyData在做join时比Spark快很多的原因之一。

2、PARTITION_BY:PARTITION_BY {COLUMN}语法的含义是按某列进行分区,当然也可以指定多个列作为组合。行表如果没有指定分区键,那么将是一张全局复制表;列表如果没有指定,那么内部也会有个默认的分区。列表中的分区遵循Spark Catalyst的hash分区,使得join时最小化shuffle。

3、BUCKETS:分区的个数。默认是128个,最小的数据存储单元。本地存储,这个值可以设置为集群core数量的2倍。

4、REDUNDANCY:分区的副本数,如果设置为0,表示没有副本;如果设置大于0,则会为partition创建对应的副本数,以防止member失败,达到数据的高可用性的目的。

5、EVICTION_BY:驱逐,很像Flink window中的eviction设置。列表上默认的参数值是LRUHEAPPERCENT,根据LRU算法达到阀值时,开始将内存中的较“冷”的数据溢出到本地磁盘:SnappyStore存储。

6、PERSISTENCE:持久化。默认是允许持久化的,数据会从内存中持久化到本地SnappyStore存储中,当重启memeber时,SnappyData会自动从本地的SnappyStore存储中恢复数据。

7、OVERFLOW:溢出,默认是true,即允许溢出。如果没有指定PERSISTENCE,且将OVERFLOW设置为false,那么当失败时,内存中的数据将被丢失。

8、DISKSTORE:为持久化的数据或溢出的数据提供持久化目录。可以通过CREATE DISKSTORE为表提前创建出本地文件目录,可以指定文件、配置数据收缩、配置数据异步到磁盘的频率等等.

9、EXPIRE:过期时间。为了提高内存使用率,对于很老的历史数据,可以通过设置过期时间使得超过阀值的行数据过期。但是过期参数只适合行表。

10、COLUMN_BATCH_SIZE:刚才提到了,delta row buffer的batch大小,默认24MB。超过阀值就会写到列表。

11、COLUMN_MAX_DELTA_ROWS:delta row buffer的最大行数,默认10000行。超过阀值会写到列表。

  • 测试
    下面分组聚合在亿级别数据量上1-2秒完成
select pro,count(distinct c_i) cn from tracker_view group by pro order by cn desc limit 11

小结

在做SnappyData搭建过程中也遇到了不少坑,这里就不一一列举了,因为这不是一篇填坑的文章,大家使用过程中有遇到问题也欢迎留言。
经测试,我们最大的两张业务表 作品(上亿)+用户(千万) 关联分析,可秒出;使用过程中发现灵活性足够了,但稳定性稍差一些,建议在一些对稳定性要求不高、时效性要求很高的内部分析场景中使用。

猜你喜欢

转载自blog.csdn.net/weixin_34293246/article/details/91001387