我是一个深资的函数式爱好者,研究得不深,但做过许多有趣的东西,应用在很多地方。。。
这些有趣的东西,就像成为魔术一样,让我变得自信快乐。。。
分享快乐会更加快乐,所以我很开心能够分享给大家。。。
很多人觉得函数式只是一个奇技淫巧,大多是用不上的,这里我想从心底告诉大家,函数式将无处不在!
下面开始我的表演:
- 极效开发环境REPL开发,尽情享受函数式
a. 简单开始REPL在线编程
b. 远程也能REPL在线编程
c. hadoop集群上REPL编程 - 大数据引擎,因函数式而生,因函数式而伟大
a. 定长之痛,第一代DataSet数据引擎COBOL/SAS的缺陷及思考
b. Report之痛,第二代OLTP数据引擎Mysql的缺陷及思考
c. 3NF之痛,第三代OLAP数据引擎Oracle/Postgres的缺陷及思考
d: Transform之痛,第四代半结构数据引擎Hive/SparkSQL的缺陷及思考
e: State之痛,第五代实时数据引擎storm的缺陷及思考
f: 传统函数式之痛, 第六代函数式引擎SQL与传统函数式融合之SparkSQL On lamdba的缺陷与思考
g: 非明细累计之痛,第七代半结构实时SQL引擎KSQL的缺陷及思考
h: 终级挑战: 函数式引擎SQL on transducer - SQL好兄弟transducer助力,一招打遍无敌手,函数式未来不再是梦
a. javascript上跑起来
b. java上跑起来
c. kafka上跑起来
d. spark上跑起来
e. ksql上跑起来 - 一切数据结构尽在KV,datalog/specs保驾护航
a. 索引查询即map, map结构及数据库rocksdb
b. 菜单层级即tree,tree结构及数据库zookeeper
c. 依赖关系即graph,graph 结构及数据库datomic/neo4j
d: tree与graph积极拥抱函数式
e: 终极挑战: tree与graph之争与转换,调度系统未来的思考 - 函数式终级无锁编程,这个世界突然清净了
a. STM
b. agent
c. core.async
d. zookeeper
e. avout
f. kafka - 函数式运维,将革命野火越烧越烈
a. 函数式编程语言nix
b. 函数式操作系统nixos
c. 函数式软件包nixpkg
e. 函数式构建nix-env
f. 函数式部署nix-store
g. 函数式隔离nixops - 函数即服务Faas,云上争霸天下
- 函数式区块链Cardano
一. 极效开发环境REPL开发,尽情享受函数式
相信大家对repl不陌生吧?
repl就是Read-eval-print-loop, 简单说就是边写边调,立即检查结果。。。
用过python/r/js/scala的朋友自然能感受到它的高效,现在java也抵抗不了诱惑加入了阵营。
1 单纯的repl的编辑功能比较弱,所以我们要高级一点,选择代码就运行!
2. 前面的功能确实不太过瘾。那我们在远程服务器上开个后门,悄悄连过去为所欲为如何?
a. 首先, 在服务器上拷贝安装后门REPL程序。
b. 紧接着,启动后门程序
c. 最后,我们可以对远程服务器为所欲为,为所欲为。。。
直接cider-connect连接到远程服务器:(如遇到ssh连接,请删除.ssh/know_host入口)
接着运行shell命令随意操纵远程服务器
3. 远程的操作权限于java跟clojure标准库,因为我们没有添加依赖的MAVEN库。。。没关系, maven库可以运行时添加! 事情开始变得有趣 了。。。
a. 首先在远程添加牛逼的动态maven解析库: [com.cemerick/pomegranate "1.0.0"]后启动repl后门
b. 连接到远程repl服务器,想要哪个MAVEN库就用哪个MAVENY库。。。
至此,基本告一段落了,现在已经可以随意运行各种SHELL命令,使用运行时加载各种MAVEN库为所欲为了。
4. 通过SSH开后门太简单了,我们应该把后门开到HADOOP集群上去!这么多机器其实可以拿来挖矿喽。。。
这里我们介绍一下hadoop, hadoop分为两部分: hdfs分布式文件存储 & yarn资源管理.
hdfs可以通过9000端口进行rpc接口调用。。。而yarn可以通过8032端口访问。。。
如果是HA的话,则可以通过ZOOKEEPER读取,这里不过多细诉。
正常 的HADOOP运行过程是:
- 本地上传JAR包及至HDFS
- 客户端通过向Yarn申请ApplicationMaster容器运行AM程序
- AM启动后向Yarn进行注册
- AM接着向Yarn申请executor, 得到driver的task后分配运行并监控
- AM根据所有executor运行的结果,返回给Yarn后退出。
那么我们怎么开后门呢?
- 编写我们的ApplicationMaster逻辑运行后门repl服务,打成jar包上传hdfs
- 通过repl启动注册服务,方便后门服务回连回来
- 通过repl连接至yarn,提交AM Repl后门程序,并传入监听注册中心服务地址
- AM repl后门程序被 yarn随机分配到集群上启动后,通过参数回连到repl进行服务注册。
- 我们本地的repl服务连接到回连注册的repl服务器上,发送代码对hadoop为所欲为...
代码示例如下:
a. 编写repl后台服务并打包上传至hdfs(参数包含了回连的注册服务器地址):
b. 通过repl启动注册服务供远程后门回连
c. 通过repl连接至yarn,提交并运行AM REPL后门程序
d. AM REPL后门回连至注册服务(属于a过程中代码)
e. 对回连注册的AM REPL后门,发送任意代码至远程服务器执行
由于时间关系,后续将会进一步对其进行代码整理,思路大致如此.
二. 大数据引擎,因函数式而生,因函数式而伟大
自从Hadoop的MR框架出现以后,大数据便以燎原之势迅速占领了数据处理的主战场。
随后storm流式框架以及spark批量引擎的出现,将函数式编程推向了至高点。
也许你要问,Hadoop跟函数式编程有啥关系?
如果你稍弱了解一下,将会知道map以及reduce是函数式最基本的功能。
map是单行处理数据,如果进行过滤,则产生了一对零操作filter,如果进行explode分解,则进行了一对多mapcat/flatmap操作。
如果需要跨行操作,则是需要进行reduce处理。
所以map + reduce,就是先逐行处理,然后进行跨行处理,单行处理不关心状态,多行处理往往伴随着状态。
跨行过程中,如果在分布式集群中,又涉及数据 的洗牌shffle或者 重分区repartition操作。
是不是感觉很熟悉?因为spark的基本API就是map, filter, flatmap, reduce操作...
如果熟悉storm trident机制,接口也是完全对等的。
除了数据处理操作之外,还有任务依赖的处理,那就属于图的概念了,后续将会详细介绍。
最近随着一股SQL On lambda之气,presto以及spark选手纷纷上场。
clojure更是推出通用复合性引擎transducer,一统所有模式。
实在不得不感叹到:
大数据处理,非函数式不破也!
本人从工作后一直从事数据搬运工工作,
玩过SAS/COBOL, MYSQL, Oracle/Teradata/SQL server/PostgreSQL, Hive/SparkSql, Storm, KSQL, Presto各种工具,
所以很清淅地看到了数据引擎发展的轨迹。也看懂了数据处理各阶段的难题。
当然每一代都在一起发展,所以这里的区分也不一定严格。
1. 最早的一代属于COBOL跟SAS。
也许你没听过COBOL,那你听过BUG这个词吧?那你听过JAVA吧?那你听过ATM取款机吧?
没错,BUG就是COBOL之母发明的,当时的COBOL就如当前的JAVA如此火爆,那怕是现在的银行核心系统以及ATM上的代码很多都是从COBOL诞用,延用直今。并且COBOL是完全面向人类习惯设计的语言,所有保贬不一,争议极大。
紧接着统计分析工作越来越显得重要,面向统计分析的SAS软件也面世,它的数据处理功能也是非常强大的。
那时候的数据格式都是长度固定的,所以处理性能极高。但是模式是不可改变的!
那时候的操作都是原生数据处理操作,所以开发效率极高,并且很灵活。
当然SAS通过内置一些基本的RPOC操作,加大了复用性,但是每一个功能都得自己做一步步来,一遍遍处理。
所以很多人写SAS不耐烦了,直接调用它的PROC SQL引擎以SQL方式处理也不为过了。
这一代的问题,是最基础的问题。
- 擅长处理定长文件,所以对模式扩展不友好,变长或者稀疏不太好搞。
- 开发效率过低,由于采用的原生的代码方式,对于多种操作的组合性不强,代码理解力极差。
比如要同时计算前十跟后十的计算,同比与环比的计算,移动平均值的计算。。。
要想一次处理所有逻辑,各种变量转移逻辑异常混乱
最终的结局:
数据模式及编程模式较为固定,故最终在特定领域发挥较大作用。
COBOL面向业务逻辑,SAS面向统计分析。
行业发展:
随着SQL时代的到来,通用性的引擎开始发光发热。
2. 第二代,关系型数据库Mysql开始登场
这时关系型数据库开始诞生,大部分用在OLTP事务处理上。
有了SQL引擎,不管怎么样,对于第一代有了明显的进步。
开始有了函数与聚合函数的概念,是不是跟map/reduce有点像?
函数及表达式 <=> map, where <=> filter, 多次insert<=>mapcat, group by <=> reduce。
所以简单看来基本的数据操作功能也算是有了,那么它到底还弱在那里呢?
- 分析功能太弱。比如我想算每个组排名前十的逻辑 ,需要自join才能处理好。自join随着数据量的增大带来了极大的性能开销。
- 数据量过大性能下降厉害,这个后期发展自然有分片机制发展,但是OLTP对于大数据处理,还是存在较大的问题。
- 灵活度差,相比于第一代系统一次遍历混乱搞定多个功能 来说,代码是清晰不少了,但是性能也下降了。这里组合功能不弱,而是只能对于标准模式进行组合,组合自由度下降了。比如同时比多个维度处理,分别计算每一级维度的汇总值。
最终的结局:
常用的事务支持非常优势,对于历史性数据分析,性能极差,甚至影响OLTP系统。
对于OLTP查看历史数据报表,甚至可以引起生产环境DOWN机的情况 发生。
这样,所有早期的系统会进行历史数据于当前数据区的划分,就是为减缓历史区对当前区所带来的负担。
发展:
ERP系统开始出现,DW+BI系统开始出现。新的OLAP引擎开始主载数据战场。OLTP+OLAP完成分离。
3. 第三代, 主要以Oracle/Teradata//PostgreSQL为代表。
应该是人们眼中传统的BI解析方案。SQL Server由于其经济性,在数据量不是很大的情况下,也是占领了一部分市场,影响力稍少。
这一代引擎的特点是,为分析而生。所以常用的分析强能80%以上都能轻松解决,哪剩下的呢,后面再说。
前面讲了多维度聚合的问题,它们有了grouping sets, cube, rollup去支持。
还有窗口状态自定义,它们有了leading, lag, row_number+partition by去支持
递归功能有了connect by, with recursive支持。
看起来接近完美 了。 真的是这样吗?
让我们一起来看一看它的弱点吧。
- 分析性能较差
传统的SQL出生于存储资源比较宝贵的年代。
所有的数据都是分离了,之间的关联则是通过主外键动态连接的,最终不断地加工直至产生所谓的"宽表" - 状态管理仍然不够灵活
虽然引入了窗口管理机制,可以引入不同层级的窗口进行跨行方面更细粒度的管理,但从本质上来说,并不能灵活定制。
仅仅只是实现了常用的环比,占比,排名之类的功能 。对于递归功能也是挺无奈,只是简单地进行关系关联。
但是分析功能的出现,在很大意义上提升了OLAP的实用性。 - UDF开发极其困难。
由于分析功能以及内部SQL引擎的复杂性,大部分并没有开放期UDAF接口,仅支持简单的非状态化的MAP逻辑。 - 反人类的三范式。
三范式一方面有了第一步所提到的数据分离问题,另一方面由于其原子性上的静态特征破坏了数据的结构性。
a. UV算法难题。
比如,一个用户,进行了多次的记录访问,从分析的本质上来说,其实都 是用户的访问分析,应该在同一条记录上。而在关系型数据库中,必须存成多份,这就产生了臭名昭著的”UV算法难题“。如果要计算一年的UV,那么要把所有的明细计算提取出来去重计算才行! 而不采用关系型存储形式,所有的用户记录通过函数提取访问记录结构体简单计算即可得出。
b. 历史拉链算法难题。
比如,一个用户,进行了多次状态的变更,从分析的本质上来说,其实都是用户的状态结构,应该在同一条记录上。而在关系型数据库中,甚至还需要闭链操作去处理跨行的状态管理 ,加上拉链修复难题,简单是惨不忍暏啊!这个本质上来写个函数提取一下状态数据结构就能解决的事情,但是它们做不到啊。
发展:
由于三范式引起的结构破坏,以及UDF开发困难,状态管理之难题等。新一代的半结构化数据开始逐渐登入舞台。
而真正的函数式技术由于其状态管理的高度自由,函数功能组合的高度自由 ,数据结构组合的高度自由 ,开始发光发热,呼风唤雨,天下大势,仅函数式是也!
第四代, 半结构化引擎HIVE为函数式之道义攻破关系型数据库的城门!
从传统OLAP发展得漫长岁月里,人们慢慢感觉到了它的局限性。
整个IT世界的,数据格式亦从最基本的CSV格式慢慢过渡到了JSON。
这说明了一个道理:数据之间的关系越来越紧密了。
所谓的数据关系,用专业角度来说,就是denormalize,反正则化。
一旦反正则化,好戏就要开始了,作为组合数据中,最基本的二种数据结构,MAP跟ARAAY登场了。
当然有人说还有STRUCT结构,STRUCT结构本质上等同于已知键模式的MAP,殊途同归。。。
这里已经能清楚看到了,MAP跟ARRAY是函数式的基本结构,可以不停地组合并多层级转换。
而函数式天生从骨子里就擅长干这个。
即然denormalize之后,数据组合在一起之后,多个表结构密集在一起了。
这个时候的数据模式,必定是多级的。HIVE在此种背景下应运而生。
为了支持模式的多样性,HIVE采用了SerDe来自定义数据的读取转换,对于数据的collect及explode操作
因此打开了半结构化世界的大门。
另一方面,由于模式的多样性,必然引入了复杂度。
所以当前主流的关结构化引擎都采取了自建门户的模式,比如HIVE采用ORC, SPARK采用parquet。
诸子百家,好不热闹,数据行业由于半结构化的到来,重新显示出了一片繁荣。
当然所有的核心结构依然是MAP跟ARRAY,互联网连接依然以浅模式JSON和深模式AVRO格式互连。
在新的半结构化世界里,表模式就是STRUCT结构,关系则以MAP结构组织,一对多则用ARRAY结构打包。
有了可自由组合以及自由扩展的数据结构,处理这些数据结构的逻辑也是非常急需的。
所以,慢慢的HIVE开始显示出不适应,而spark则以函数式为核心慢慢占领了主战场。
所以这一阶段处于先行军,所急需解决的问题也是不少。
- 最重要的一点,当然是对于数据结构的处理引擎。
hive这个引擎提供了UDAF(自定义聚合函数)的接口,可以说是打开了一个新世界。但是由于HIVE本身的类型系统不完善,最终致使HIVE这个功能非常难用。最终HIVE只能妥协,提供了collect的方法将跨行的状态累积起来编写UDF处理。这本身会消耗大量内存,但也是一种可以使用的临时解决方案。既然可以用UDAF COLLECT函数之后用UDF来处理,但是对于JAVA编程来说,处理半结构数据也是比较吃力的。
spark引擎在HIVE的基础上稍有增强,有RDD方法跟SQL方法 。Spark SQL方法本质上是传统OLAP的继承,采用窗口状态模型,所以对于半结构化数据也是非常无力的,直至最近的2.3 版本开始支持SQL on lambda,当然这是后面的话题了。当然, spark还是有退路的,spark提供了RDD提供底层接口供自由编程。Spark RDD是将函数式编程的方法分布式化,提供了核心的map, filter,mapcat/flatmap.reduce功能, 但是Spark RDD这种思路也是有问题,它的函数式组合能力太弱,因为reduce功能涉及状态管理,所有同时做sum与count处理就没有SQL那么强大,而sql on lambda就是将这些功能集成在sql上,一定程度上解决了这种问题。 - 数据引擎的统一性。
对于大数据处理,依然会有人使用HADOOP MR + HIVE UDF处理,新一点的则是Spark RDD + Spark SQL。这说明了两种模式的互补性。底层的函数式引擎能灵活处理各种问题,但是编码开发困难,复用性差。而上层的窗口状态模型依然存在传统OLAP所面监的问题,状态管理模式具有一定的局限性。随着hive把半结构化数据推上了OLAP上,传统OLAP引擎已显得苍白无力了。所以需要编写大量的UDAF来处理。UDAF状态管理模型与传统OLAP的冲突,最终导致了新的两代引擎诞生: 实时引擎 + SQL-on-lambda.
发展:
前面介绍了半结构数据的发展诞生了两个分支: 实时引擎以及SQL-on-lambda。也许有人不明白了,这两者有什么联系?
对于实时引擎来说,既然状态不好处理,那我们专心去处理状态。
而对于大量的OLAP来说,放弃窗口模型状态是不可能的!我们把函数式放在SQL上来用!
两者都是函数式原型的代表,第一种代表了函数式引擎 transducer的发展方向,第二种代表 了传统函数式的高阶函数操作。
从未来发展上来看,实时引擎的路更好走一些。
因为随着半结构化数据的成熟,所有的数据只需要遍历一次,管理 好状态就能得到结果。
现在的数据处理模式也在往这方面发展,达到”MapReduce边转换边聚合,Explode多维状态分解提取结果“。
接着,我们一一介绍。
第五代,实时引擎重新定义OLAP。
我们把实时引擎放在第五代,还不是SQL-on-lambda是有原因的。
在半结构化数据没有到来之前,就有实时引擎开始活跃。但是随着半结构化数据的到来,更加加剧了它的发展。
从技术上来说,主要有两个原因:
- 半结构化减 少了数据之间的分离,而实时处理对于表的join是很有局限性的,后期的KSQL很大程序上解决了这个问题
- 半结构化增加了状态复杂性,由于半结构化到来,传统的OLAP的状态管理不是特别适应,需要更灵活地解决方案。
从业务上来说,实时引擎有着极强的业务需要性。
对于传统的ETL流程,一天跑批对于急剧变化的商业世界也不再适应用。
所以大量的OLAP需求从1天转为1小时,接着10分钟,接着1分钟,最终形成了微批量!
微批量就是传统的OLAP模式,这种模式在很大程度上解决了很多问题,也在一定程度上限定了技术的发展。
微批量有很大的局限性,批量调度更复杂,作业间并行影响更复杂,编程模型更复杂。
商业上实时处理引擎最早出现的就是STORM引擎,它是由函数式编程语言clojure开发的。
如果读者读 到这里,应该不难承认,函数式已经占领了数据引擎战场。
实时处理引擎面临的问题也很多。
backpress回压技术,严格一次处理,tupl DAG依赖消息重发,状态管理。
上面提到的核心点,状态管理 。
对于严格一次来说,STORM处理得比较复杂,采用了微批量方式,按批次发送后补充发送完整,达到至少一次,接着将数据按照事务ID进行Persistent到外部存储,达到严格一次。在persistent过程中,引入了窗口状态管理机制。
所以,storm分为两派:
一派是单tuple执行自由状态管理,所有编程需要自己完成,可以通过数据间的依赖树进行消息重发
另一派相似于spark,通过外部管理状态实现窗口状态管理 ,失去了底层的灵活性。
所以,初期的storm模型的基础问题就在于以下几点:
- 状态管理要么太低级,要么太封闭。
如果采用最原生的tuple模型,需要大量的编码。而如果采用trident微批量形式,则状态管理其实是OLAP的这种微批量窗口模式。 - 状态管理需要外部系统侵入,低层接口与微批量接口的不一致严重损害系统的扩展能力。
前者状态比较自由,所以需要配合redis或者hbase进行状态持久化。后者状态比较封闭,则需要使用专用的接口去调用函数式接口编程。这两者的分离,加上外部状态管理 的耦合性,使流式计算扩展性大大削弱 - 流式系统的join操作
由于大部分平台的数据还处于3NF模式,所以不可避免存在JOIN的操作。即使denormalize之后,对于关联性不强的实体,依然是会有这种需求。所以呢,流式系统必然要实现join的操作 - 模式系统支持
由于早期的实时引擎需要管理状态,并且依赖于外部系统,所有的数据处理过程均采用编程模型完成,最终代码 没有模式支持,均靠API接口实现。
发展:
实时引擎发展越来越壮大,对于状态化管理 ,越来越多的方案出来了,并且实时引擎上面SQL平台也开始成熟起来。
随着函数式技术的进一步发展,可自由组合状态的transducer技术也开始横空出世,独领风骚,未来不可预期。。。
第六代,SQL与传统函数式融合之SQL On lamdba,持续发力中。。。
对于半结构化的到来,一方面函数式热不可挡,另一方面传统的函数式对于状态管理复合性过弱。比如,同时进行sum跟count操作。SQL引擎本身类似于流式引擎,是单条处理的,所以在固有的窗口状态模式下,是可以得合的,所以是可以同时进行SUM跟COUNTR的,这就是流式处理模式带来的好处,而传统的函数式采用的是映射式模式,对于状态复合还是理解不到味,以致于后面的transducer出世成功解决了这一点。
现在有了SQL,可以做基础的窗口状态管理 ,有了lamdba/reduce高阶函数,去处理半结构化数据进一步细化定制管理状态 。
一切看起来非常得完美 了。
然而呢,我们还需要往前走,往前看。
对于半结构化数据处理, map/reducel的lamdba转换只是函数式的基本功能!
前面已经论述过,lambda在一定程度上复合性太弱。哪种复合性?
首先你在SQL上能同时计算sum跟count了 ?可是如果lambda上面有这种需求呢?
当然你可以用SQL分别计算 之后通过lambda组合起来进行引擎的互补。
但是呢,函数式很多高级的操作,SQL是没有的。
比如我要计算半结构中上下级关系,lamdba复用性就跟不上了。
这么多年SparkSQL跟hive在半结构化进程中发展缓慢,很大一部分就是因为半结构化转换逻辑具复合实现难度太大!
当然有了SQL on lambda,我们的状态管理自由了,总体来说算是进步很大了。。。
所以,我们总结一下SQL on lambda的缺 陷.
- 数据处理逻辑 的复合性。
数据处理逻辑的复合很大程度上取决于状态的复合,在SQL一定的状态复合机制下,SQL on lambda会有较大成功的概率,因为一方面它吸收了OLAP模型,另一方面引入了半结构化与函数式处理机制,在一定程度上能很高效的解决问题 - SQL与映射函数式模型的不一致性
它的函数式功能还处于基础阶段,传统的函数式采用了sequence的映射机制,没有完善的状态复合功能。对于没有复合状态的传统函数式,想在半结构转换中组合状态,难度真不是一般的大啊! - SQL与函数式的融入性
对于函数式处理深层级结构的自由灵活编码方式,在SQL也不一定能成功地融入进去。当然非常值得人期待。
发展:
由于函数式在商业模式中仍处于起步阶段,这种风险小,效果显示的方式会被 大多数数据引擎所接受。
像很早之前presto查询引擎就率先加入了此阵列,不难想像,传统OLAP也会慢慢转移。
第七代,半结构实时SQL引擎KSQL,数据仓库革命者,实时数仓之领军者!
第七代引擎简单是厉害得不行,前面有Kafka流式队列的长久考验,再之后有Kafka Streams流式状态的技术突破,再加上samza流式引擎在商业应用上的广泛成熟。KSQL集一人之力,成功吸收之,并开创了第七代半结构实时SQL引擎。
它的伟大之处在于哪里呢?
- 模式化。传统的流式平台模式性很差,很大一部分状态由外部系统管理 。而KSQL在流式引擎存储底层就集成了模式。模式分为两种,一种是表Table,一种是流Stream,两者相辅相成,直接接成到了Kafka存储中去了!采用avro格式来实现半结构化数据结构的统一性,在整个引擎上达到了高度的简化与灵活性。
- 状态化。KSQL的状态处理模式非常帅气逼人。对于严格一次,KAFKA本身就有topic+offset来进行区分。对于状态的更新, kafka底层存储rocksdb直接 支持,就是那无敌的Table模式!状态还可以复合,表上再建表,开创了强大的undo机制!
- UDF/UDAF支持。KSQL的UDF/UDAF状态模型非常简单,成功吸收了HIVE的经验,但是又抛弃了很多复杂的机制。利用UDF/UDAF进行扩展,没难度!
- SQL支持。KSQL采用了熟悉的SQL模型,非常轻易地实现了窗口管理状态。
- 流式join处理。KSQL由于底层的Table与Stream模型,Stream-Streamg, Table-Table, Stream-Table都支持!
这样一来,KSQL要开创实时半结构数据的先行,太了不起了!
你可能要问,KSQL与SQL on lambda最大的优势在于哪里?
- KSQL采用了流式模型,能够很方便与函数式最新技术transducer结束,达到数据处理模式的高度一致性! transducer模型可以复合状态!当然SQL on transducer的批量引擎也是一个发展方向。
- KSQL对于非累计明细数据处理有着极大的优势。比如算UV,KSQL得计算所有明细数据,而KSQL的实时模型可以达到响应式效果。随着数据处理复杂度的提升,越来越多地非累计型计算会越来越多,以前OLAP解决不了的问题KSQL现在也可以处理了!
当然,实时引擎的发展不可避免有着它需要处理的问题。
- 流式状态处理的复杂度
前面所学的简单的流式状态已不再话下,自然也证明了KSQL的强大性。
但是新的变态需求还是不断显现的, 特别是对于非累计明细计算来说,UV是比较简单的概念 ,以此为例。
本人自创了一套明细-统计分离法,对于如何标准化得融入引擎,仍在大量尝试阶段
a. 非累计明细之任意时间段难题。(比如要计算任意时间段的UV访问数量)
对于每一条数据,都要更新所有的历史范围的数据。
比如从2018-01-01开始 ,接着2018-01-02,
在2018-01-03的时候,对于所有的日期{2018-01-01, 2018-01-02, 2018-01-03}的任意日期明细计算都要进行更新。
b. 非累计明细之维度组合难题。(比如要计算各种平台组合下的UV访问数据 )
比如有三个平台 [A,B,C], 我们对于不同的组合就要分别计算, [A, B], [A, C], [B, C], [A, B, C], A, B, C...
c. 非累计明细之度量值漂移。(比如对用户访问时长进行分组统计,用户的时长一直累计,有可能从一个组漂移到另一个组,当出现这种情况的时候则需要撤消先前维度的值,新增新维度的值)
例 子还有很多,后面会写文章专门讨论明细-统计分离法。在此不再多诉。 - 流式SQL引擎的灵活性
由于SQL在目录来看已经不属于关系型数据库,本质上来说是一种数据处理的语法表达,与XML有着相似的功能。
由于此种背景,SQL中的各种子循环,以及explode操作的结合性,以及未来模式的演化性,都具有极大的不确定性。
SQL作为一种数据表达语言,是否能真正适应未来的数据引擎需求,还是说更底层的transducer,或者 datalog之类的引擎日益发展壮大,成为新一代标准。这个自然是未来来经验了。当前,SQL还是无敌的。
发展:
按前面所描述的来说,流式引擎在实时数据仓库中会慢慢发挥具大的作用。
其中三点特别值得注意 ,一是半结构化SQL模式与复合性多层级函数式技术(lens, transducer)的深度结合,另一种是对于非累计明细的状态标准化,第三种是新型流式引擎的出现。。。
终级挑战: 新一代函数式引擎SQL on transducer
transducer是我非常喜欢的一个技术,也是应用非常广。当前也积极在研究SQL解析器,试图集成transducer功能。
如果能将SQL引擎在解析器上面集成transducer,那么它的威力是相互可怕的。
最近比较忙,这里对具体技术不做过多讲解,后续将会更新。
不经意间多次提到了transducer功能。那么我们下一步讲解的主题就是: