Hadoop/Spark 太重,esProc SPL 很轻

随着大数据时代的来临,数据量不断增长,传统小机上跑数据库的模式扩容困难且成本高昂,难以支撑业务发展。很多用户开始转向分布式计算路线,用多台廉价的 PC 服务器组成集群来完成大数据计算任务。Hadoop/Spark 就是其中重要的软件技术,由于开源免费而广受欢迎。经过多年的应用和发展,Hadoop 已经被广泛接受,不仅直接应用于数据计算,还发展出很多基于它的新数据库,比如 Hive、Impala 等。

Hadoop/Spark 之重

Hadoop 的设计目标是成百上千台节点的集群,为此,开发者实现了很多复杂、沉重的功能模块。但是,除了一些互联网巨头企业、国家级通信运营商和大型银行外,大多数场景的数据量并没有那么巨大。结果,经常能看到只有几个到十几个节点的 Hadoop 集群。由于目标和现实的错位,对很多用户来讲,Hadoop 成了一个在技术、应用和成本上都很沉重的产品。

技术之重

如果真的有几千台计算机组成的集群,是不可能依靠手工个性化管理的。试想,将这些计算机罗列出来,运维人员看都看不过来,更别说管理和分配任务了。再说,这么多机器,难免会不断出现各种故障,怎么保证计算任务顺利执行?Hadoop/Spark 的开发者为了解决这些问题,编写了大量代码,用于实现自动化节点管理、任务分配和强容错功能。

但是,这些功能本身就要占用很多计算资源(CPU、内存和硬盘等),如果用到几台到十几台节点的集群上,就太过沉重了。集群本来就不大,Hadoop 还要占用相当一部分的资源,非常不划算。

不仅如此,Hadoop 产品线很长,要把这些模块都放在一个平台上运行,还要梳理好各个产品之间的相互依赖性,就不得不实现一个包罗万象的复杂架构。虽然大多数场景只用其中一两个产品,也必须接受这个复杂、沉重的平台。

后来出现的 Spark 弥补了 Hadoop 对内存利用的不足,技术上是不是可以变轻呢?很遗憾,Spark 走向了另一个极端,从理论模型上就只考虑内存计算了。特别是 Spark 中的 RDD 采用了 immutable 机制,在每个计算步骤后都会复制出新的 RDD,造成内存和 CPU 的大量占用和浪费,离开大内存甚至无法运行,所以技术上还是很重。

使用之重

Hadoop 技术上太过复杂,也就意味着安装和运维会很麻烦。集群只有几台计算机时,却不得不使用为几千台节点集群设计的节点管理、任务分配和容错功能。可想而知,安装、配置、调试都很困难,日常运行的维护、管理工作也不容易。

即使克服这些困难让 Hadoop 运行起来了,编写大数据计算代码时还会面临更大的麻烦。Hadoop 编程的核心框架是 MapReduce,程序员要编写并行程序,只要写 Map 和 Reduce 动作即可,用来解决求和、计数等简单问题也确实有效。但是,遇到复杂一些的业务逻辑,用 MapReduce 编程就会变得非常困难。例如,业务计算中很常见的 JOIN 计算,就很难用 MapReduce 实现。再比如,很多和次序有关的运算实现起来也很困难。

Spark 的 Scala 语言具备一定的结构化数据计算能力,是不是能简单一些呢?很可惜,Scala 使用难度很大,难学更难精。遇到复杂一些的运算逻辑,Scala 也很难写出来。

MapReduce、Scala 都这么难,所以 Hadoop/Spark 计算语法开始回归 SQL 语言。Hive 可以将 SQL 转化为 MapReduce 所以很受欢迎,Spark SQL 的应用也比 Scala 广泛的多。但是,用 SQL 做一些常规查询还算简单,用于处理多步骤过程计算或次序相关运算还是非常麻烦,要写很复杂的 UDF。而且,许多计算场景虽然勉强能用 SQL 实现,但是计算速度却很不理想,也很难进行性能调优。

成本之重

虽然 Hadoop 软件本身开源免费,但它技术复杂、使用困难,会带来高昂的综合成本。

前面说过,Hadoop 自身会占用过多的 CPU、内存和硬盘,而 Spark 需要大内存支撑才能正常运行。所以不得不为 Hadoop/Spark 采购更高配置的服务器,要增加硬件支出。

Hadoop/Spark 使用困难,就需要投入更多的人力去完成安装、运维,保证 Hadoop/Spark 的正常运转;还要投入更多的开发人员,编程实现各种复杂的业务计算,要增加人力资源成本。

由于使用过于困难,很多用户不得不采购商业公司的收费版本 Hadoop/Spark,价格相当可观,会大幅增加软件采购成本。

既然 Hadoop 如此沉重,为什么还有很多用户会选择它呢?答案很简单:暂时找不到别的选择,也只有 Hadoop 勉强可用,好歹知名度高一些。

如此一来,用户就只能安装、配置 Hadoop 的重型应用,并忍受 Hadoop 本身对计算资源的大量消耗。小规模集群的服务器数量本来就不多,Hadoop 又浪费了不少,小马拉大车,最后运行的效果可想而知。花了大价钱采购、费事费力的使用 Hadoop,实际计算的性能却不理想。

就没有别的选择了?

轻量级的选择

开源的 esProc SPL 是轻量级大数据计算引擎,采用了全新的实现技术,可以做到技术轻、使用简单、成本低。

技术轻

本文开头说过,越来越大的数据量让传统数据库撑不住,所以用户只能转向分布式计算技术。而数据库之所以撑不住,是因为 SQL 难以实现高速算法,大数据运算性能只能指望数据库的优化引擎,遇到复杂计算时,优化引擎又常常无能为力。

所以,我们应该想办法设计更高效的算法,而不是一味地追求分布式计算。按照这个思路,SPL 提供了众多高性能算法(有许多是业界首创)以及高效的存储方案,同等硬件环境下可以获得远超过数据库的运算性能。安装在单机上的 SPL 就可以完成很多大数据计算任务,架构比集群简单很多,从技术上自然就轻的多了。

SPL 的高性能算法有下面这些:

..

对于数据量更大的情况,SPL 实现了轻量级集群计算功能。这一功能的设计目标是几台到十几台节点的集群,采用了与 Hadoop 完全不同的实现方法。

SPL 集群不提供复杂沉重的自动化管理功能,而是允许对每个节点进行个性化配置。程序员可以根据数据特征和计算目标来决定各节点存储什么样的数据,完成哪些计算。这样做,不仅大大降低了架构复杂度,也是提升性能的重要手段。

以订单分析为例,订单表很大,要通过产品号字段与较小的产品表主键做关联,再按照产品供应商分组汇总订单金额。SPL 集群可以很容易的将订单表分段存放在各个节点的硬盘上,再将较小的产品表读入每个节点的内存中。计算时,每个节点仅对本机上的订单分段和产品数据做关联、分组汇总,可以缩短总计算时间;再将结果传输到一个节点上做二次汇总。由于传输的是第一次汇总的结果,数据量小、网络传输时间较短。总体来说,这个方案可以获得最佳性能,虽然程序员需要做一些更细致的工作,但对于小规模集群来说,增加的工作量并不大。

SPL 也不提供超强的容错能力,不会像 Hadoop 那样,在有节点故障的情况下,还要保证任何一个任务都会执行成功。实际上,大多数计算任务的执行时间都在几个小时以内,而几台、十几台机器的集群一般都能做到较长时间正常运行,不会这么频繁的出故障。即使偶尔出现节点故障导致任务执行失败,再重新计算一遍也可以接受,毕竟这种情况不会经常发生。所以,SPL 的容错能力只是保证有少数节点故障的时候,整个集群还能继续工作并接受新任务(包括重算的任务),这就大大降低了 SPL 集群的复杂度。

在内存计算方面,SPL 没有使用 Spark RDD 的 immutable 机制,而是采用了指针式复用机制,利用地址(指针)访问内存,在数据结构没有改变的情况下,直接用原数据的地址形成结果集,不必每个计算都将数据复制一遍,仅仅多保存一个地址(指针),可以同时减少 CPU 和内存的消耗,运行起来要比 Spark 轻很多了。并且,SPL 改进了当前的外存计算算法体系,降低了复杂度并扩大了适应范围,可以做到内外存计算结合,充分提升计算性能的同时,还不像 Spark 那样依赖大内存。

使用简单

SPL 采用轻量级技术,自然更容易安装、配置和运行维护。SPL 不仅可以作为独立服务器使用,还很容易集成到需要高性能计算的应用中,比如即时查询系统,只要引入几个 jar 包即可。Hadoop 则很难集成,只能在边上作为一个数据源运行。有些临时性数据需要随时进行处理,则可使用 SPL 的桌面集成开发环境可视化地计算,快速得到结果。如果要安装部署 Hadoop,那么等环境搭建好时临时数据任务已经过期了。

前面展示的众多 SPL 高性能算法,也能让大数据计算编程变得简单。程序员可以在较短时间内掌握这些算法函数,学习成本相对较低。而且,使用这些现成的函数很容易实现各种复杂的计算需求,不仅比 MapReduce/Scala 简单,比 SQL 也简单很多。

比如,以电商网站常见的漏斗分析为例,用 SQL 实现三步漏斗的代码大致如下:

with e1 as (
	select gid,1 as step1,min(etime) as t1
	from T
	where etime>= to_date('2021-01-10', 'yyyy-MM-dd') and etime<to_date('2021-01-25', 'yyyy-MM-dd')
		and eventtype='eventtype1' and …
	group by 1
),
with e2 as (
	select gid,1 as step2,min(e1.t1) as t1,min(e2.etime) as t2
	from T as e2
	inner join e1 on e2.gid = e1.gid
	where e2.etime>= to_date('2021-01-10', 'yyyy-MM-dd') and e2.etime<to_date('2021-01-25', 'yyyy-MM-dd') 
and e2.etime > t1
		and e2.etime < t1 + 7
		and eventtype='eventtype2' and …
	group by 1
),
with e3 as (
	select gid,1 as step3,min(e2.t1) as t1,min(e3.etime) as t3
	from T as e3
	inner join e2 on e3.gid = e2.gid
	where e3.etime>= to_date('2021-01-10', 'yyyy-MM-dd') and e3.etime<to_date('2021-01-25', 'yyyy-MM-dd') 
and e3.etime > t2
		and e3.etime < t1 + 7
		and eventtype='eventtype3' and …
	group by 1
)
select
  sum(step1) as step1,
  sum(step2) as step2,
  sum(step3) as step3
from
  e1
  left join e2 on e1.gid = e2.gid
  left join e3 on e2.gid = e3.gid

SQL 写出来要三十多行,理解起来有相当的难度。如果用 MapReduce/Scala 来写,会更加困难。即使是用 SQL 实现,写出来的这段代码和漏斗的步骤数量相关,每增加一步就要再增加一段子查询。

相比之下,SPL 就简单得多,处理任意步骤数都是下面这样简洁的代码:


A

B

1

=["etype1","etype2","etype3"]

=file("event.ctx").open()

2

=B1.cursor(id,etime,etype;etime>=date("2021-01-10") && etime

3

=A2.group(id).(~.sort(etime))

=A3.new(~.select@1(etype==A1(1)):first,~:all).select(first)

4

=B3.(A1.(t=if(#==1,t1=first.etime,if(t,all.select@1(etype==A1.~ && etime>t && etime

5

=A4.groups(;count(~(1)):STEP1,count(~(2)):STEP2,count(~(3)):STEP3)

SPL 集群计算的代码也非常简单,比如前面提到的订单分析计算,具体要求是:大订单表分段存储在 4 个节点上,小产品表则加载到每个节点的内存中,两表关联之后要按照产品供应商分组汇总订单金额。用 SPL 写出来大致是下面这样:


A

B

1

["192.168.0.101:8281","192.168.0.102:8281",…, "192.168.0.104:8281"]

2

fork to(4);A1

=file("product.ctx").open().import()

3


>env(PRODUCT,B2)

4

=memory(A1,PRODUCT)

5

=file("orders.ctx":to(4),A1).open().cursor(p_id,quantity)

6

=A5.switch(p_id,A4)

7

=A7.groups(p_id.vendor;sum(p_id.price*quantity))

这段代码执行时,任务管理(内存加载、任务拆分、合并等)所需要的计算资源,远远小于关联和分组汇总计算的消耗。如此轻便的任务管理功能,可以在任意节点、甚至是集成开发环境 IDE 上执行。

成本低

与 Hadoop 相同,SPL 也是开源软件,不同的是 SPL 不仅软件免费,综合成本也非常低。

SPL 安装、配置、运维很容易,可以大大降低支持人员的人力资源成本。同时,由于 SPL 降低了大数据计算编程的难度,程序员很容易实现各种复杂的计算,开发效率显著提高,也就节省了程序员的人力资源成本。

而且,由于 SPL 技术体系非常轻,平台自身占用的 CPU、内存和硬盘很少,可以让更多的资源用于业务计算,能大幅提高硬件利用率。SPL 也不像 Spark 那样依赖大内存,总体来说,大大减少了硬件采购成本。

SPL 既轻且快

SPL 技术轻、自身消耗小,而且还提供了众多高性能算法,所以,在几个到几十个节点的集群,甚至单机的情况下,比 Hadoop/Spark 有更好的性能表现。

案例 1:某电商漏斗分析计算。

Spark:6 节点,每节点 4CPU 核,平均计算时间:25 秒。

SPL:单机,8 线程计算,平均计算时间可达 10 秒。代码量仅有 Spark Scala 的一半。

案例 2:某大型银行用户画像分析。

Hadoop 上某 OLAP 服务器:虚拟机 100CPU 核,计算时间:120 秒。

SPL:虚拟机 12CPU 核,计算时间:仅 4 秒。性能提高 250 倍。

案例 3:某商业银行的手机银行 APP,活期明细查询,数据量大且高并发。

基于 Hadoop 的某商用数据仓库:高并发时无法达到秒级的响应速度,只好换用 6 台 ES 集群。

SPL 单机:达到 6 台 ES 集群同样的并发和响应能力。

总结来说,Hadoop/Spark 是源自头部互联网企业的重型解决方案,适合需要有超大规模集群的巨大企业。很多场景的数据虽然也不少,但小集群甚至无集群就足够处理,远没多到这些巨大企业的规模,也没有那么多的硬件设备和维护人员。这种情况下,轻量级的大数据计算引擎 SPL 是首选,投入很低的成本,就可以做到技术轻、使用简便,而且还能提高开发效率、达到更高的性能。


GitHub: https://github.com/SPLWare/esProc