(Incubating)
The Past, Present and Future
Of�Efficient Data Lake Architectures
Speakers
Vinoth Chandar
Balaji Varadarajan
Views are our own. Don’t represent views of our employers
Agenda
1) The Elevator Pitch
2) Past : How we built Data Lakes
3) Present : How could we build Data Lakes with Hudi
4) Future : How could do better?
5) Project Status
Apache Hudi : Overview
HUDI
Dataset
HDFS/Cloud Object Stores�(+ other DFS compatible storage)
Kafka Streams, Database Changelogs
Delta
Streamer
ML features,
ETL data
Spark Datasource
Columnar Read Optimized
Incremental
Change Streams
Real time
Hive/Spark ETLs
Dashboards/
Spark Notebooks
Incremental Data Pipelines
Interactive Queries
Why Should You Care?
Near real-time data ingestion to Cloud storage/DFS
Batch jobs on Steroids
Stream processing on batch data
Unified, Optimized analytical storage
GDPR, Data deletions, Compliance.
Building block for great data lakes!
Speaking Technically..
upsert() support with fast, pluggable indexing
Atomically publish data with rollback support
Snapshot isolation between writer & queries
Savepoints for data recovery
Manages file sizes, layout using statistics
Async compaction of row & columnar data
Timeline metadata to track lineage
Zooming in a bit
Hudi
Dataset
upsert(records) at time t
RDD[Records] : partial inserts/updates
All records updated/created in time range
incrementalPull(t-1, t))
snapshot_query()
at time t
Last committed value for each record in dataset
In the flesh ...
Query
Read Optimized View at 10:10
Query
Real time View at 10:10
Query
Incremental View (10:08, 10:10)
Past : How we built data lakes
Must be Simple?
Database
Events
Apps/
Services
Queries
DFS/Cloud Storage
Extract-Transform-Load
Real-time/OLTP
Analytics/OLAP
External Sources
Tables
But, what about?
Typical Data Lake
Database
Events
Apps/
Services
Queries
DFS/Cloud Storage
Ingestion
(Extract-Load)
Real-time/OLTP
Analytics/OLAP
External Sources
Raw Tables
Data Lake
Derived Tables
Schemas
Data Audit
An Uber Trip down memory lane
Database
Apps/
Services
Queries
DFS/Cloud Storage
Ingestion
(Extract-Load)
Real-time/OLTP
Analytics/OLAP
Raw Tables
Data Lake
Derived Tables
Schemas
Data Audit
Slow & In-efficient
Batch ingestion is too slow..
Rewrite entire tables/partitions several times a day!
ETLs off raw data have no smarts to recompute
Late arriving data is a nightmare
DFS/Cloud Storage
Raw Tables
Data Lake
Derived Tables
120TB HBase table ingested every 8 hrs; Actual change < 500GB
Full recompute every 6-8 hrs
Updated/
Created rows from databases
Streaming Data
Big Big Batch Jobs...
Plus, other unsolved problems
Solving the small file problem, while keeping data fresh(?!)
How to rollback a bad batch of ingestion?
Queries can see dirty data
What if bad data gets through? How to restore dataset?
How to avoid duplicate records in dataset?
Between A Rock & A Hard Place
Lots of equally bad or worse alternatives
DFS/Cloud Storage
Raw Tables
Data Lake
Derived Tables
1 raw trip table
100s of derived tables
Hudi Data Lake
Design principles :
DFS/Cloud Storage
Raw Tables
Data Lake
Derived Tables
Hudi
upsert()
Hudi
incrementalPull()
Queries
Updated/
Created rows from databases
Present : How to build a Data Lake using Hudi ?
Requirements
Plus much more
#Q1: Incremental Database Ingestion?
High-value data
Bulk loads don’t scale
MySQL
users
users
Inserts, updates, deletes
Replicate
userID | int |
country | string |
last_mod | long |
... | ... |
Data Lake
#A1: Obtain changelogs & upsert()
// Command to extract incrementals using sqoop
bin/sqoop import \
-Dmapreduce.job.user.classpath.first=true \
--connect jdbc:mysql://localhost/users \
--username root \
--password ******* \
--table users \
--as-avrodatafile \
--target-dir \
s3:///tmp/sqoop/import-1/users
// Spark Datasource
Import org.apache.hudi.DataSourceWriteOptions._
// Use Spark datasource to read avro
Dataset<Row> inputDataset spark.read.avro(‘s3://tmp/sqoop/import-1/users/*’);
// save it as a Hudi dataset
inputDataset.write.format(“org.apache.hudi”)
.option(HoodieWriteConfig.TABLE_NAME, “hoodie.users”)
.option(RECORDKEY_FIELD_OPT_KEY(), "userID")
.option(PARTITIONPATH_FIELD_OPT_KEY(),"country")
.option(PRECOMBINE_FIELD_OPT_KEY(), "last_mod")
.option(OPERATION_OPT_KEY(), UPSERT_OPERATION_OPT_VAL())
.mode(SaveMode.Append);
.save(“/path/on/dfs”)
Step 1: Extract new changes to users table in MySQL, as avro data files on DFS
(or)
Use data integration tool of choice to feed db changelogs to Kafka/event queue
Step 2: Use your fav datasource to read extracted data and directly “upsert” the users table on DFS/Hive
(or)�Use the Hudi DeltaStreamer tool
#Q2: De-Duping Log Events?
High-scale time series data
Cause of duplicates
Overcounting problems
Impressions
Impressions
Produce impression events
Replicate w/o duplicates
event_id | string |
datestr | string |
time | long |
... | ... |
Data Lake
#A2: De-Dupe on-the-fly using DeltaStreamer
// Deltastreamer command to ingest kafka events, dedupe, ingest
spark-submit --class org.apache.hudi.utilities.deltastreamer.HoodieDeltaStreamer \
/path/to/hudi-utilities-bundle-*.jar` \
--props s3://path/to/kafka-source.properties \
--schemaprovider-class org.apache.hudi.utilities.schema.SchemaRegistryProvider \
--source-class org.apache.hudi.utilities.sources.AvroKafkaSource \
--source-ordering-field time \
--target-base-path s3:///hudi-deltastreamer/impressions --target-table uber.impressions \
--op BULK_INSERT
--filter-dupes
// kafka-source-properties
include=base.properties
# Key fields, for kafka example
hoodie.datasource.write.recordkey.field=event_id
hoodie.datasource.write.partitionpath.field=datestr
# schema provider configs
hoodie.deltastreamer.schemaprovider.registry.url=http://localhost:8081/subjects/impressions-value/versions/latest
# Kafka Source
hoodie.deltastreamer.source.kafka.topic=impressions
#Kafka props
metadata.broker.list=localhost:9092
auto.offset.reset=smallest
schema.registry.url=http://localhost:8081
#Q3: Storage Management?
Small Files = Big Problem
Big Files = Big Delays
File Stitching?
#A3: Deliberate file sizing during write..
Enforce file sizes on write
If you really want to ingest quickly,
Layout data based on arrival order
#Q4: Transactional Writes?
Atomic publish of data
Consistency
Snapshot Isolation
Strong Durability
A
C
I
D
#A4: Multi-row transactions on single dataset
Atomic multi-row commits
Only Valid Data exposed to Queries
Snapshot Isolation
Commit protocol + DFS storage guarantees durability
#Q5: Faster Derived/ETL Data?
Multi stage ETL DAGS
Derived/ETL tables
Scaling challenges
raw_payments
std_payments
standardize_payments(row)
id | string |
datestr | string |
currency | string |
amount | double |
id | string |
datestr | string |
std_amount | double |
... | ... |
Raw Table
Derived Table
#A5: Streaming Style/Incremental pipelines!
// Spark Datasource
Import org.apache.hudi.{DataSourceWriteOptions, DataSourceReadOptions}._
// Use Spark datasource to read avro
Dataset<Row> hoodieIncViewDF = spark.read().format("org.apache.hudi")
.option(VIEW_TYPE_OPT_KEY(), VIEW_TYPE_INCREMENTAL_OPT_VAL())
.option(DataSourceReadOptions.BEGIN_INSTANTTIME_OPT_KEY(),
commitInstantFor8AM)
.load(“s3://tables/transactions”);
Dataset<Row> stdDF = standardize_payments(hoodieIncViewDF)
// save it as a Hudi dataset
inputDataset.write.format(“org.apache.hudi”)
.option(HoodieWriteConfig.TABLE_NAME, “hoodie.std_payments”)
.option(RECORDKEY_FIELD_OPT_KEY(), "id")
.option(PARTITIONPATH_FIELD_OPT_KEY(),"datestr")
.option(PRECOMBINE_FIELD_OPT_KEY(), "time")
.option(OPERATION_OPT_KEY(), UPSERT_OPERATION_OPT_VAL())
.mode(SaveMode.Append);
.save(“/path/on/dfs”)
Bring Streaming APIs on Data Lake
Incrementally pull
Transform + upsert
#Q6: Scaling DFS/Storage RPCs?
Ingestion/Query all list DFS
Subtle gotchas/differences
#A6: Optimized Timeline/FileSystem APIs
Embedded Timeline Server
Consistency Guards
#Q7: Compliance/ Data Deletions?
Strict rules on data retention
Need efficient delete()
#A7: Efficient/Fast Deletes
Soft deletes
Hard deletes
Indexing
Future : How can we do better?
Idea #1 : Smarter Storage Layouts
Cluster/group records based on query patterns
Use-cases:
Idea #2 : Unlock real-time data
(Contd)
Near Real-time data lakes with 1-2 mins data freshness
Use-cases:
Jira Tickets (log indexing, inserts to log, index performance)
Idea #3 : Universal file format/runtime support
Standardization should cover all major tools/environments
Use-cases :
(ORC PR/JIRA, Flink discussions,)
Idea #4 : Scalable Metadata Management
HUDI-241 (bundle, and new JIRA for standalone timeline server)
Leveraging granular metadata about dataset to plan queries and cut down DFS rpcs
Use-cases :
Idea #5 : Bootstrap historical data
Okay, all these ideas are great! How do I get it on my existing data?
Use-cases
HUDI-242 (migration story)
Hudi : State-Of-The-Union
Hudi : Open Sourcing & Evolution..
2015 : Published core ideas/principles for incremental processing (O’reilly article)
2016 : Project created at Uber & powers all database/business critical feeds @ Uber
2017 : Project open sourced by Uber & work begun on Merge-On-Read, Cloud support
2018 : Picked up adopters, hardening, async compaction..
2019 : Incubated into ASF and working towards first release
Community
Diverse PMC members with experience building data systems at scale
Mentors from Amazon/Lyft
Adopted by few companies, 5x more in testing/evaluation
Fast growing, with a challenging & interesting technical roadmap
Seeking solid, diverse new contributors
Dev mailing lists
Spark bundle downloads
Github Chatter
Project Management
Open collaboration in the “Apache” way
HIP process for design reviews of large features
Bug reports/Support via Github Issues
JIRAs for project issue management
Github PRs for code reviews & contributions
Resources
User Docs : https://hudi.apache.org
Technical Wiki : https://cwiki.apache.org/confluence/display/HUDI
Github : https://github.com/apache/incubator-hudi/
Twitter : https://twitter.com/apachehudi
Mailing list(s) : dev-subscribe@hudi.apache.org (send an empty email to subscribe)
dev@hudi.apache.org (actual mailing list)
Slack : https://join.slack.com/t/apache-hudi/signup
Big Picture
Fills a clear void in data ingestion, storage and processing!
Leads the convergence towards streaming style processing!
Brings transactional semantics to managing data
Positioned to solve impending demand for scale & speed
Evolve as “de facto”, open, vendor neutral standard for data storage!
Thanks!
Questions?