首先简单回顾下大数据技术的发展,基于我个人的理解,将大数据的发展分了4个时期:
第一个时期: 2006 年到 2008 年。2008 年左右,Hadoop 成为了 Apache 顶级项目,并正式发布了 1.0 版本,它的基础主要是基于谷歌的三驾马车,GFS、MapReduce、BigTable 去定义的。
第二个时期: 2009 年到 2013 年阶段。雅虎、阿里、Facebook 等企业对大数据的应用越来越多。2013 年底 Hadoop 正式发布 2.0 版本。我有幸在 2012 年的时候开始接触大数据,用 Hadoop 1.0 加 Hive 的模式体验了下,当时感觉很神奇的,大数据用几台机器就可以快速解决原来用 SQL Server 或者 MySQL 解决不了的问题。
第三阶段:2014 年到 2019 年,这段时间发展的非常快,期间 Spark、Flink 都成为了 Apache 顶级项目。在这个快速爬升期的过程中,我们还尝试用过 Storm,后来 Storm 就被 Flink 所替代了。
第四阶段: 从 2020 年至今,2020 年 Hudi 从 Apache 毕业成为顶级项目之后,我个人理解数据湖进入到整个发展的成熟期,到了大数据的数据湖 2.0 阶段。数据湖主要三个特点,首先是统一、开放式的存储,其次是开放式的格式,以及丰富的计算引擎。
整体的发展过程中,大数据主要是有几个特点,就是大家常说的四个“V”:规模性(Volume)、高速性(Velocity)、多样性(Variety)、价值性(Value)。现在还有第五个“V”(Veracity),数据的准确性和可信赖度。数据的质量是一直被人诟病的,希望行业里能有一套标准把数据湖的质量去做提升,这个可能是数据湖 2.0 出现的标准,因为出现了 Hudi、Iceberg 这些项目,都是想把整个数据湖的管理做好。
个人觉得 Hadoop 是大数据的一个代名词,但是大数据并不只有 Hadoop。大数据是在发展过程中由多个组件整合之后形成的一套解决大量数据加工处理和使用的解决方案。这几年,大家基本上认为 Hadoop 是在走下坡路的,首先是 Hadoop 商业化公司 Cloudera 和 Hortonworks 的合并和退市,原来的商业模式无法延续;也面临着快速增长的云供应商在成本和易用性上的挑战,以及 Hadoop 本身生态系统的日益复杂。
在这个阶段,理想汽车的大数据平台如上图所示。理想汽车用了很多开源的组件。
大家通过大数据平台的现状可以发现一些特点:
最后,整个数据体系目前从文件层面看缺少一些有效的管理手段。 从建设至今,基本上还是以 HDFS 为主,有大量的无用数据存在,造成了资源的浪费,这是我们亟待解决的问题。
首先,先简单分享一下我个人理解的云原生:
第一,云原生是在云计算的基础上衍生出来的。现在大家用的如阿里云、 AWS、腾讯云、百度云等云厂商,最开始提供的都是 IaaS 层的技术服务,帮企业把存储、计算、网络这些这些最基础的东西封装好统一管理,企业只需要在上面申请服务器就可以了。申请了服务器之后,这些服务器还是由云厂商来管理的,也就是大家传统的上云操作。
云原生离不开云计算,笼统地说,云原生属于云计算的 PaaS 层服务,主要是面向开发者的一类应用。云原生必须在云上安装,是一种基于云计算的软件开发应用方式。云+原生,云即云计算,原生则是摒弃传统的运维开发框架,通过容器化、DevOps,还有微服务架构实现应用弹性伸缩和自动化部署,充分利用云计算资源实现在最少的空间里做最大的事。也能解决我们目前大数据系统的一些痛点,比如扩展性和维护性都比较差,需要大量人力与时间等。
上图简单列了一下云原生的几个时间点
接下来介绍一下理想汽车大数据平台在云原生化之后组件发生的变化:
总结一下,我个人觉得大数据未来的云原生基本上就是:
但是这样也给目前的数据平台产品带来挑战,就是如何设计具备 Serverless能力的产品来给用户使用。
第一点,存算分离,弹性伸缩。使用物理机部署 Hadoop 之后,如果需要扩容缩容还需要去联系运营商,并且可能会有很长的周期,存算分离很好地解决了这个问题。
其次是按需付费,不用购买闲置资源,目前我们整个的业务场景的数据是有波峰波谷的,波峰的时候需要准备机器,波谷的时候需要撤机器,但现在是做不到的。现在我们基本上是把所有的机器都堆到波峰,波峰的时候能满足需求,稳定不失败,但它在波谷的时候最少 12 个小时左右是闲置的,这种情况下资源也是要付费的。云原生之后我们就可以不用再为此买单了。
第二点,自动化部署和可运维性。Kubernetes 是支持 DevOps 集成化的部署方案的。这样我们的组件整体可以实现快速的部署(比如通过 Helm chart),把组件运维的能力下沉到云原生平台上,这样大数据就不需要考虑组件运维场景了。
第三点,对象存储。对象存储是云计算推出的最核心最主要的产品。对象存储的好处不言而喻了,易扩展,存储空间无上下限,单价比较低,而且对象存储还分为低频存储、归档存储等多种存储类型,进一步降低存储成本,数据就可以存更长时间。同时成本可控,高可靠,操作复杂性低也都是对象存储的优势。
第四点,安全和合规性。云原生之后可以实现专用命名空间,多租户隔离,远程认证。目前我们做到的基本上都是网络层面上的隔离,HDFS的文件管理大家公认的方案是Ranger。通过 Ranger 去管理 HDFS 的目录权限,也能管理如 Hive server、HBase、Kafka 的一些权限,但是相对而言这些权限都会偏弱一些。
还有一个方案是 Kerberos,整个大数据组件的安全性会提高很多,但是它有很多的成本,它任何一个请求都要去验证。这个方案目前我们没有使用过,和我们的集群环境和场景有关系,我们基本上都是内网的,并不对外提供服务。如果大家做的大数据项目需要对外网提供一些服务,还是需要有强认证,不然数据很容易泄露。
大数据云原生的难点同样也是存在的。
第一,大数据相关的组件是比较多的,同时 Kubernetes 的更新比较快,组件和组件之间交叉之后,兼容性、复杂性和扩展性,都会存在问题。
第二,资源的分配和再分配。Kubernetes 是通用的容器资源调度工具,很难满足不同大数据组件的资源使用场景。大数据场景下资源使用会比较大,请求频率高,每次启动的 pod 的数又会比较多,这种情况下,目前没有什么好的方案。目前我们正在看 Fluid 这个方案,Fluid 也实现了 JuiceFS 的 runtime,这个也是我们后边要去深入调研的,Fluid 目前宣称是可以支持大数据和 AI 的,并不是只有 AI 的场景,因为大数据和 AI 的场景是比较像的,都是数据密集型的操作,Fluid 在计算效率和数据抽象管理方面是有了一些突破性的进展。
第三点,对象存储也是有一些劣势的。对象存储的劣势是元数据操作性能低、和大数据组件兼容性差、最终一致性等问题。
最后一点,就是数据密集型应用。存算分离模式无法满足大数据、AI 等数据密集型应用在计算运行效率、数据抽象管理方面的需求。
在 JuiceFS 开源之前我们就已经关注并做了一些落地的测试,开源版上线之后,我们就马上上线使用了。上线的时候也遇到了一些权限的问题和几个小的 bug,社区非常给力,快速地帮我们都解决了。
要下线 HDFS 是因为它的扩展性差,同时我们的数据量比较大,HDFS 的存储成本比较高。在存储了几批数据后,物理机的空间就不够了,而且需要的计算非常多。当时我们的业务发展还在初期,为了尽可能从数据中获得价值,我们要保留尽可能多的数据。而且 HDFS 需要三副本,我们后来改成两副本,但是两副本还是有风险的。
在这个基础上,我们深度测试了 JuiceFS,测试完成之后,我们很快就把 JuiceFS 引到我们的线上环境。把一些比较大的表从 HDFS 迁移到 JuiceFS 里,缓解了我们的燃眉之急。
我们对 JuiceFS 比较看重的三点:
第一, JuiceFS 是多协议兼容。完全兼容 POSIX、HDFS 和 S3 协议 ,目前用下来都是百分百兼容的,没有遇到任何问题。
第二,跨云的能力。当企业有一定规模之后,为了避免系统性风险,都不会只使用一个云服务商。不会绑在一个云上,都会是多云操作的。这种情况下,JuiceFS 的跨云数据同步的能力就起到了作用。
第三,云原生的场景。JuiceFS 支持 CSI,目前 CSI 这个场景我们还没有用,我们基本上都是用 POSIX 去挂载的,但是使用 CSI 的方式会更简单更兼容,我们现在也正在往云原生上去发展,但整个的组件还没有真正上到 Kubernetes。
JuiceFS 开源之后,我们就开始尝试把 HDFS 上的数据同步到 JuiceFS。开始同步的时候是使用 DistCp,结合 JuiceFS 的 Hadoop SDK 同步非常方便,整体迁移比较顺利。之所以要把数据从 HDFS 迁移到 JuiceFS 上,是因为遇到了一些问题。
第一就是 HDFS 的存算耦合设计扩展性差 ,这个是没有办法解决的。我个人从一开始接触大数据的认知就是大数据是必须要部署在物理机上的,而不是在云主机。包括后来云厂商推出的各类 EMR 系统,其实是在对 Hadoop 进行封装,最近一两年这些 EMR 系统都在逐渐去 Hadoop 化。
第二是 HDFS 难以适配云原生化。现在的 HDFS 很难适配云原生,因为它比较重,虽然社区一直在着重发力去做云原生,但是我个人认为 Hadoop 的发展趋势在走下坡路,未来应该以对象存储为主。
第三,对象存储也有一些弊病,它不能很好的适配 HDFS API,由于网络等原因性能跟本地盘比也相差很多,另外 list 目录等元数据操作也很慢。我们通过 JuiceFS 做一些加速,测下来性能非常可观,在有缓存的情况下基本上可以媲美本地盘,基于此我们快速地将当前的场景直接切换到 JuiceFS 上。
第二个场景平台级别的文件共享。我们目前的整个调度系统、实时系统、开发平台的共享文件的数据全部都是存在 HDFS 上的,后续如果要是停止使用HDFS ,需要把这些数据迁移走。目前的方案是用 JuiceFS 对接对象存储,通过应用层的服务,全部以 POSIX 的方式挂载上去,大家就可以无感地去请求 JuiceFS 里的文件。
JuiceFS 在这个场景满足了我们大部分的应用需求,但还有些小场景存在问题。最初的设想是会把 Python 环境之类的都放进去,后来发现实操难度太大,因为 Python 环境里边有大量的小文件,加载的时候还是会有问题。类似 Python 环境这种包含大量碎文件的场景还是需要存储在本地盘来操作。后续我们准备挂一块块存储,专门来做这件事。
分享几个我们之前使用 HDFS 遇到的问题:
第一个,当 NameNode 压力大或 Full GC 时会有下载失败的情况,目前暂时没有一个完美的方案解决。我们的方案是尽量加内存,或者在下载包的时候加一些重试,避一避它的高峰期,但是这种情况下很难完全解决 HDFS 的问题,因为它终究是 Java 写的,GC 的场景是没有办法避免的。
第二个,在跨系统里面去使用 HDFS 的时候,比如我们有两个集群,现在要用一个集群去共享文件,基本上是不现实的,因为需要开通网络,来把两个集群之间打通或者应用上打通,这样安全性是没有办法保证的。目前我们基本上就是两个集群是独立各自维护自己的共享文件。现在实时平台(如 Flink 平台)已经切换到 JuiceFS 上了,目前还是非常顺利,没有遇到什么问题。
第三个,目前我们有大量的物理机部署,物理机部署都是单集群的,没有容灾的策略,如果哪天机房出了一些灾难性的问题,我们整个服务就不可用了。但是对象存储它本身是跨机房,是同一个 region 里面,应该都是有最少三个副本,云厂商帮我们做到了备份。后续,我们可能会发展多云,希望通过 JuiceFS 去共享一些高级别的文件、核心的数据库,包括一些核心的备份文件,在多云里面去做备份。这样就实现了多云、多 region、多地域,就可以解决现在单点容灾的问题。
另外一个场景,平台和平台之间全部都是通过 JuiceFS 去共享海量数据。我们这边的共享的数据中第一类是路试车的数据,路试车会有大量的视频语音图像数据上传,这些数据上传了之后会直接进到 JuiceFS 里,方便下游去做一些同步和共享,包括一些数据的筛查,再拿到 PFS 就是并行文件系统,其下面挂载的是 SSD。这样可以让 GPU 利用率更高一些,因为对象存储的能力是相对比较弱的,不然 GPU 的能力就会有大量浪费。
剩下的数据类型包括车辆上报的一些用于分析的日志,埋点数据,还有一些国家平台需要的车辆相关的信号数据,这些数据都会进到数仓里面去做一些分析。也会对这些数据做一些特征数据提取,给算法团队去做模型训练,或者做一些 NLP 的检索和其他的更多场景。
现在我们正在测的是另外一个场景是在对象存储层挂一个 Lustre 去给 JuiceFS 去做读缓存,通过 Lustre 的缓存来帮助 JuiceFS 来提高读取速度和缓存命中率。
这样可以有一个好处是我们现在用的都是物理机,它是有物理盘的,物理盘可以用来缓存数据。但是因为计算任务在多个节点执行,缓存的命中率不太高。这是因为社区版 JuiceFS 目前还不支持 P2P 的分布式缓存,只支持单节点的本地缓存,每一个节点可能会读很多数据。这种情况下也给计算节点造成了一些磁盘的压力,因为缓存会占用一定的磁盘空间。
目前我们的方案是通过 Lustre 来作为 JuiceFS 的读缓存。具体来说是根据需要缓存的数据大小,将一个容量大概是 20~30TB 的 Lustre 文件系统挂载到计算节点本地,然后将这个 Lustre 挂载点作为 JuiceFS 的缓存目录。这种情况下 JuiceFS 读完数据之后,可以异步缓存到 Lustre 里。这个方案可以有效解决缓存命中率不高的问题,大幅度提高读取性能。
如果我们在 Spark 场景往对象存储里直接写数据的时候,会有带宽和 QPS 的限制,如果写入得太慢,上游的任务可能会发生抖动,在这种情况下可以通过 JuiceFS 的写缓存功能把数据先写到 Lustre 里,再异步写到对象存储,这个方案在某些场景下是适用的。但是有一个问题是 Lustre 并不是一个云原生的方案,它对于用户来说是有感知的,用户在启动 pod 的时候需要显式写一个命令把它挂载上去。因此后面我们也希望对 JuiceFS 做一些改造,自动去识别对象存储和 Lustre,然后自动实现一些缓存的机制,这样就不需要用户来感知 Lustre 的存在。
目前这个方案的 PoC 已经完成,通过了基础测试,接下来我们会在生产环境做大量的压测,预计今年 Q3 应该可以正式上线覆盖一些边缘业务。
从整体方案的架构图可以看到,目前 JuiceFS 客户端提供的三种方式我们都有用到。
如上图左半部分所示,我们会有独立的 Spark、Flink 集群,我们通过 CSI Driver 的方式将 JuiceFS 直接挂载到整个集群上,这样用户启动 Spark 和 Flink 的时候,就完全感知不到 JuiceFS 到存在了,计算任务的读写都是通过对象存储来完成。
这部分目前有一个有关 shuffle 的问题。因为 Spark 任务在计算过程中的 shuffle 阶段需要大量的数据落盘,这其间产生的大量文件读写请求对于底层存储的性能要求较高。Flink 相对来说好一些,因为它是流式的,不需要大量的落盘。未来我们希望 JuiceFS 可以直接写到 Lustre 里,但是这样就需要在 JuiceFS 里做一些改造,通过客户端集成的方式,让 JuiceFS 直接读写 Lustre,这对于用户来说就无感知了,也能提升 shuffle 阶段的读写性能。
上图右半部分的应用有两个场景。一个是简单查询一下 JuiceFS 的数据,例如通过HiveJDBC来进行数据预览,这个场景可以通过 S3 网关访问 JuiceFS。
第二个是大数据平台和 AI 平台联动的场景。比方说 AI 平台的同事在日常工作中需要经常读取样本数据、特征数据等,而这些数据通常是由大数据平台上的 Spark 或者 Flink 任务产生的,并且已经存储到了 JuiceFS 里。为了不同的平台之间能够共享数据,在 AI 平台的 pod 启动时,会通过 FUSE 的方式将 JuiceFS 直接挂载到 pod 里,这样 AI 平台的同事就可以通过 Jupyter 直接访问 JuiceFS 里的数据做一些模型的训练,而不用像传统的架构那样在不同平台之间重复拷贝数据,提高了跨团队的协作效率。
因为 JuiceFS 使用 POSIX 标准的用户、用户组进行权限控制,同时容器启动默认是 root 用户,导致权限不好管控。因此我们对 JuiceFS 做了一个改造,通过一个认证 token 来挂载文件系统,这个 token 里面包含元数据引擎的连接信息和其他一些权限控制信息。
在某些需要同时访问多个 JuiceFS 文件系统的场景,我们使用 JuiceFS S3 网关并结合 IAM 策略做统一的权限管理。
第一点,基于用户和用户组的权限管理功能比较简单,在某些场景容器启动默认为 root 用户,权限不好管控。
第二点,关于 JuiceFS Hadoop SDK 的配置优化。目前我们对 JuiceFS Hadoop SDK 进行优化的手段主要有三个配置:juicefs.prefetch
、juicefs.max-uploads
和 juicefs.memory-size
。其中在调优 juicefs.memory-size
配置的过程中遇到了一些问题,这个配置的默认值是 300MB,官方的建议是
设置默认值 4 倍大小的堆外内存,也就是 1.2GB。目前我们大部分任务都是配置到 2GB 的堆外内存,但是有些任务即使配置了超过 2GB 的内存也偶尔会写入失败(HDFS 可以稳定写入)。不过这个并不一定是 JuiceFS 的问题,也有可能是 Spark 或者对象存储的原因导致。因此目前我们也在计划把 Spark 和 JuiceFS 深度适配以后,再一步一步来找原因,争取把这些坑都趟过去,在保证任务稳定的情况下把内存降下来。
第三点,由于整体架构(JuiceFS + 对象存储 + Lustre)变得复杂,可能的故障点变多,任务的稳定性可能会有一些下降,需要其它容错机制保障。例如 Spark 任务在 shuffle write 阶段可能会有类似「lost task」这样的报错,目前还没有定位到具体的错误原因。
前面提到的 JuiceFS + 对象存储 + Lustre 的架构组合一定程度上提升了读写性能,但同时也使得架构更加复杂,相应地增加了一些可能的故障点。比如说 Lustre 没有很强的容灾副本能力,如果 Lustre 突然挂了一个节点,正在运行的任务到底能不能稳定地继续读写 Lustre 里面的数据,或者 Lustre 里的数据意外丢失了,是否还能稳定的去 JuiceFS 里通过对象存储重新拉出来,这个目前是不确定的,目前我们在也在做这种灾难性的测试。
近期我们要做的一个是 Flink+ Hudi + JuiceFS 的实时数据湖方案。上图中左边是数据源,通过 Flink 、Kafka/Pulsar,把数据实时地写到 Hudi 里,同时 Hudi 的数据会落到 JuiceFS 里替换我们目前的实时数仓。
最后,介绍一下理想汽车大数据云原生的远期规划,也是一个展望。
第一点是统一的数据管理和治理系统。我们认为数据湖 2.0 时代,最大的需要解决的问题就是把数据湖 1.0 场景中的数据沼泽的问题解决掉。但现在好像并没有一个比较好的统一元数据管理、数据目录管理、数据安全管控的开源产品,类似 AWS Glue、AWS Lake Formation。目前我们在做一个「起源系统」的项目,这个系统第一步就是把上面的数据库、对象存储里边所有的元数据做统一的目录管理,统一的安全管控,以及统一的数据管理,这块儿我们正摸索着往前走。
第二点是更快、更稳定、更低成本的底层存储能力。目前所有的场景最大的难点是在对象存储上,对象存储的优势是稳定、低成本,同时对象存储也在持续迭代。就目前而言我觉得如果大数据云原生要发展,对象存储必须是要在确保稳定的前提下提供更好的性能。
同时 S3 可能宣称支持强一致性了,但是目前我理解基于对象存储的架构设计,可能很难能实现强一致性,或者说它为了实现强一致性,势必要牺牲一些东西,这可能是一个需要权衡的问题。JuiceFS 原生支持强一致性,这个功能对于大数据平台来说非常友好。
第三点,更智能、更高效、更易用的查询引擎。引申一下前面提到的对湖仓一体的思考,目前湖仓一体还是在发展初期 ,可能还需要经历 5~10 年的发展过程。Databricks、微软都在尝试做数据湖上的向量化 MPP 引擎,希望能把湖仓一体架构推起来。这可能是一个未来的发展方向,但是短时间内好像并没有办法用一个引擎来满足所有场景的需求。
我们目前的架构基本上是配备了所有的查询引擎,比如 Spark、Flink、关系型数据库(面向 OLTP 的场景)、时序数据库、OLAP 数据库。原则上还是谁优用谁,我们上层再通过统一的中间件去做管理。再比如 Snowflake,它现在虽然已经支持了同时查询结构化和半结构化的数据,但是未来像人工智能涉及的的非结构化数据(如图片、语音、视频)到底应该怎么支持,目前还是不太清楚。不过我认为这肯定是以后的一个发展方向,理想汽车也有类似的人工智能场景,所以我们会与各个业务方一起去探索和共建。
最后,整个大数据发展的最终目标还是要以最低的成本、最高的性能完成数据分析,从而实现真正的商业价值。
如有帮助的话欢迎关注我们项目 Juicedata/JuiceFS 哟! (0ᴗ0✿)