www.scling.com
Eventually, time will kill your
data processing
Øredev, 2019-11-07
Lars Albertsson
Scling
1
www.scling.com
Out of joint
“Time is out of joint. O cursed spite,
That ever I was born to set it right.”
- Hamlet, prince of Denmark
2
www.scling.com
Out of joint
“Time is out of joint. O cursed spite,
That ever I was born to set it right.”
- Hamlet, prince of Denmark
3
www.scling.com
Out of joint
“Time is out of joint. O cursed spite,
That ever I was born to set it right.”
- Hamlet, prince of Denmark
4
www.scling.com
Out of joint
5
Free users using
premium service
www.scling.com
Time will kill us all
● Time handling causes data processing problems
● Observed issues
● Principles, patterns, anti-patterns
Goals:
● Awareness, recognition
● Tools from my toolbox
6
www.scling.com
Big data - a collaboration paradigm
7
Stream storage
Data lake
Data
democratised
www.scling.com
Data pipelines
8
Data lake
www.scling.com
More data - decreased friction
9
Data lake
Stream storage
www.scling.com
Scling - data-value-as-a-service
10
Data lake
Stream storage
● Extract value from your data
● Data platform + custom data pipelines
● Imitate data leaders:
○ Quick idea-to-production
○ Operational efficiency
Our marketing strategy:
● Promiscuously share knowledge
○ On slides devoid of glossy polish
www.scling.com
Data platform overview
11
Data lake
Batch
processing
Cold
store
Dataset
Pipeline
Service
Service
Online
services
Offline
data platform
Job
Workflow
orchestration
www.scling.com
Data categories, time angle
● Facts
○ Events, observations
○ Time stamped by clock(s)
○ Continuous stream
12
www.scling.com
Data categories, time angle
● Facts
○ Events, observations
○ Time stamped by clock(s)
○ Continuous stream
● State
○ Snapshot view of system state
○ Lookup in live system. Dumped to data lake.
○ Regular intervals (daily)
13
www.scling.com
Data categories, time angle
● Facts
○ Events, observations
○ Time stamped by clock(s)
○ Continuous stream
● State
○ Snapshot view of system state
○ Lookup in live system. Dumped to data lake.
○ Regular intervals (daily)
● Claims
○ Statement about the past
○ Time window scope
14
www.scling.com
Domain time - scope of claim. “These are suspected fraudulent users for March 2019.”
Time scopes
15
Service
Registration time
Event time
Ingest time
Processing time
www.scling.com
Controlled backend - good clocks, UTC
Clocks
16
● Computer clocks measure elapsed time
● Good clocks, bad clocks, wrong clocks
Legacy systems - good clocks
Time zone?
Clients - bad clocks
Time zone?
www.scling.com
Calendars, naive
Maps time to astronomical and social domains
Naive calendar
● 365 days + leap years
● 12 months, 28-31 days
● 7 day weeks
● 24 hours
● 60 minutes
● 60 seconds
● 24 hour time zones
17
www.scling.com
Naive calendar properties
t + 1.day == t + 86400.seconds
(y + 45.years).asInt == y.asInt + 45
(date(y, 1, 1) + 364.days).month == 12
(t + 60.minutes).hour == (t.hour + 1) % 24
datetime(y, mon, d, h, m, s, tz).inZone(tz2).day in [d - 1, d, d + 1]
datetime(y, mon, d, h, m, s, tz).inZone(tz2).minute == m
date(y, 12, 29) + 1.day == date(y, 12, 30)
(date(y, 2, 28) + 2.days).month == 3
18
Can you find the counter
examples?
www.scling.com
Calendar reality
t + 1.day == t + 86400.seconds
(y + 45.years).asInt == y.asInt + 45
(date(y, 1, 1) + 364.days).month == 12
(t + 60.minutes).hour == (t.hour + 1) % 24
datetime(y, mon, d, h, m, s, tz).inZone(tz2).day in [d - 1, d, d + 1]
datetime(y, mon, d, h, m, s, tz).inZone(tz2).minute == m
date(y, 12, 29) + 1.day == date(y, 12, 30)
(date(y, 2, 28) + 2.days).month == 3
19
Leap seconds
Year zero
Julian / Gregorian
calendar switch
Sweden: 1712-02-30
Daylight savings time
Samoa crosses
date line. Again.
Time zones:
Span 26 hours
15 minute granularity
www.scling.com
Except DST
● Analytics quality
● Changes with political decision
● Might affect technical systems
● (Affects health!)
Small problems in practice
20
Leap seconds
Year zero
Julian / Gregorian
calendar switch
Sweden: 1712-02-30
Samoa crosses
date line. Again.
Time zones:
Span 26 hours
15 minute granularity
Daylight savings time
www.scling.com
Daylight savings example
Credits: Rachel Wigell, https://twitter.com/the_databae/status/1191479005192605698
21
www.scling.com
Typical loading dock ingress
22
● File arrives every hour
● Ingest job copies to lake,
applies data platform
conventions
● Source system determines
format, naming, and
timestamps
class SalesArrived(ExternalTask):
"""Receive a file with sales transactions every hour."""
hour = DateHourParameter()
def matches(self):
return [u for u in GCSClient().listdir(f'gs://ingress/sales/')
if re.match(rf'{self.hour:%Y%m%d%h}.*.json', u)]
def output(self):
return GCSTarget(self.matches()[0])
@requires(SalesArrived)
class SalesIngest(Task):
def output(self):
return GCSFlagTarget('gs://lake/sales/'
f'{self.hour:year=%Y/month=%m/day=%d/hour=%h}/')
def run(self):
_, base = self.input().path.rsplit('/', 1)
dst = f'{self.output().path}{base}'
self.output().fs.copy(src.path, dst)
self.output().fs.put_string('',
f'{self.output().path}{self.output().flag)}'
crontab:
*/10 * * * * luigi RangeHourly --of SalesIngest
www.scling.com
Typical loading dock ingress
23
● File arrives every hour
● Ingest job copies to lake,
applies data platform
conventions
● Source system determines
format, naming, and
timestamps, incl. zone
● Spring: halted ingest
Autumn: data loss
class SalesArrived(ExternalTask):
"""Receive a file with sales transactions every hour."""
hour = DateHourParameter()
def matches(self):
return [u for u in GCSClient().listdir(f'gs://ingress/sales/')
if re.match(rf'{self.hour:%Y%m%d%h}.*.json', u)]
def output(self):
return GCSTarget(self.matches()[0])
@requires(SalesArrived)
class SalesIngest(Task):
def output(self):
return GCSFlagTarget('gs://lake/sales/'
f'{self.hour:year=%Y/month=%m/day=%d/hour=%h}/')
def run(self):
_, base = self.input().path.rsplit('/', 1)
dst = f'{self.output().path}{base}'
self.output().fs.copy(src.path, dst)
self.output().fs.put_string('',
f'{self.output().path}{self.output().flag)}'
crontab:
*/10 * * * * luigi RangeHourly --of SalesIngest
www.scling.com
Using snapshots
● join(event, snapshot) → always time mismatch
● Usually acceptable
○ In one direction
24
DB’DB
join?
www.scling.com
Using snapshots
● join(event, snapshot) → always time mismatch
● Usually acceptable
○ In one direction
25
DB’DB
join?
Free users using
premium service
www.scling.com
● Time mismatch in both directions
Window misalign
26
DB
join
www.scling.com
Event sourcing
● Every change to unified log == source of truth
● snapshot(t + 1) = sum(snapshot(t), events(t, t+1))
● Allows view & join at any point in time
○ But more complex
27
DB’DB
www.scling.com
Easier to express with streaming?
state + event → state'
● State is a view of sum of all events
○ Join with the sum table
○ Beautiful!
○ Not simple in practice
● Mixing event time and processing time
○ Every join is a race condition
28
Stream
Stream
Stream
Stream
www.scling.com
Stream window operations
29
Stream
Stream
Stream
Stream
Sliding windows
Tumbling
windows
Stream
Stream
Stream
Window
join
www.scling.com
Window over what?
● Number of events
● Processing time
● Registration time
● Event time
30
Less relevant for domain
Deterministic
Predictable semantics
Predictable resources
More relevant for domain
Deterministic
Unpredictable semantics
Unpredictable resources
Less relevant for domain
Indeterministic
Unpredictable semantics
Predictable resources
www.scling.com
Batch is easier?
● Yes
● But, some pitfalls
Event ingest
31
How to divide events
to datasets?
When to start
processing?
www.scling.com
Ancient data collection:
● Events in log files, partitioned hourly
● Copy each hour of every host to lake
Anti-pattern: Bucket by registration time
32
Service
All hosts
represented?
www.scling.com
● Start processing optimistically
● Reprocess after x% new data has arrived
Anti-pattern: Reprocess
33
www.scling.com
● Start processing optimistically
● Reprocess after x% new data has arrived
Solution space:
● Apache Beam / Google → stream processing ops
● Data versioning
● Provenance
Requires good (lacking) tooling
Supporting reprocessing
34
www.scling.com
Event collection
35
Service
Registration time
Event time
Ingest time
Processing time
www.scling.com
● Bundle incoming events into datasets
○ Bucket on ingest / wall-clock time
○ Predictable bucketing, e.g. hour
Pattern: Ingest time bucketing
36
clicks/2016/02/08/14
clicks/2016/02/08/15
● Sealed quickly at end of hour
● Mark dataset as complete
○ E.g. _SUCCESS flag
www.scling.com
When data is late
37
or
www.scling.com
val orderLateCounter = longAccumulator("order-event-late")
val hourPaths = conf.order.split(",")
val order = hourPaths
.map(spark.read.avro(_))
.reduce(a, b => a.union(b))
val orderThisHour = order
.map({ cl =>
# Count the events that came after the delay window
if (cl.eventTime.hour + config.delayHours <
config.hour) {
orderLateCounter.add(1)
}
order
})
.filter(cl => cl.eventTime.hour == config.hour)
class OrderShuffle(SparkSubmitTask):
hour = DateHourParameter()
delay_hours = IntParameter()
jar = 'orderpipeline.jar'
entry_class = 'com.example.shop.OrderShuffleJob'
def requires(self):
# Note: This delays processing by N hours.
return [Order(hour=hour) for hour in
[self.hour + timedelta(hour=h) for h in
range(self.delay_hours)]]
def output(self):
return HdfsTarget("/prod/red/order/v1/"
f"delay={self.delay}/"
f"{self.hour:%Y/%m/%d/%H}/")
def app_options(self):
return [ "--hour", self.hour,
"--delay-hours", self.delay_hours,
"--order",
",".join([i.path for i in self.input()]),
"--output", self.output().path]
Incompleteness recovery
38
www.scling.com
class OrderShuffleAll(WrapperTask):
hour = DateHourParameter()
def requires(self):
return [OrderShuffle(hour=self.hour, delay_hour=d)
for d in [0, 4, 12]]
class OrderDashboard(mysql.CopyToTable):
hour = DateHourParameter()
def requires(self):
return OrderShuffle(hour=self.hour, delay_hour=0)
class FinancialReport(SparkSubmitTask):
date = DateParameter()
def requires(self):
return [OrderShuffle(
hour=datetime.combine(self.date, time(hours=h)),
delay_hour=12)
for h in range(24)]
Fast data, complete data
39
Delay: 0
Delay: 4
Delay: 12
www.scling.com
class ReportBase(SparkSubmitTask):
date = DateParameter()
jar = 'reportpipeline.jar'
entry_class = 'com.example.shop.ReportJob'
def requires(self):
return [OrderShuffle(
hour=datetime.combine(self.date, time(hour=h)),
delay_hour=self.delay)
for h in range(24)]
class PreliminaryReport(ReportBase):
delay = 0
class FinalReport(ReportBase):
delay = 12
def requires(self):
return super().requires() + [SuspectedFraud(self.date)]
Lambda in batch
40
www.scling.com
Human-delayed data
“These are my compensation claims for last January.”
● Want: accurate reporting
● Want: current report status
Anti-pattern: Reprocessing
41
www.scling.com
class ClaimsReport(SparkSubmitTask):
domain_month = MonthParameter()
date = DateParameter()
jar = 'reportpipeline.jar'
entry_class = 'com.example.shop.ClaimsReportJob'
def requires(self):
return [Claims(
domain_month=self.domain_month,
date=d)
for date in date_range(
self.domain_month + timedelta(month=1),
self.date)]
Dual time scopes
42
● What we knew about month X at date Y
● Deterministic
○ Can be backfilled, audited
● May require sparse dependency trees
www.scling.com
Recursive dependencies
● Use yesterday’s dataset + some delta
○ Starting point necessary
● Often convenient, but operational risk
○ Slow backfills
43
class StockAggregateJob(SparkSubmitTask):
date = DateParameter()
jar = 'stockpipeline.jar'
entry_class = 'com.example.shop.StockAggregate'
def requires(self):
yesterday = self.date - timedelta(days=1)
previous = StockAggregateJob( date=yesterday)
return [StockUpdate(date=self.date), previous]
www.scling.com
Recursive dependency strides
● Mitigation: recursive strides
● y/m/1 depends on y/m-1/1
● Others depend on y/m/1 + all previous
days in this month
44
class StockAggregateStrideJob(SparkSubmitTask):
date = DateParameter()
jar = 'stockpipeline.jar'
entry_class = 'com.example.shop.StockAggregate'
def requires(self):
first_in_month = self.date.replace(day=1)
base = first_in_month - relativedelta(months=1) 
if self.date.day == 1 else first_in_month
return ([StockAggregateStrideJob(date=base)] +
[StockUpdate(date=d) for d in
rrule(freq=DAILY, dtstart=base, until=self.date)])
www.scling.com
Business logic with history
Example: Forming sessions
● Valuable for
○ User insights
○ Product insights
○ A/B testing
○ ...
45
www.scling.com
What is a session?
● Sequence of clicks at most 5 minutes
apart?
● In order to emit sessions in one hour,
which hours of clicks are needed?
46
www.scling.com
What is a session?
● Sequence of clicks at most 5 minutes
apart?
● Maximum length 3 hours?
● In order to emit sessions in one hour,
which hours of clicks are needed?
47
www.scling.com
What is a session?
● Sequence of clicks at most 5 minutes
apart.
● Maximum length 3 hours.
Examples, window = 5am - 9am:
● Clicks at [6:00, 6:01, 6:03, 6:45, 6:47]?
○ Two sessions, 3 and 2 minutes long.
48
www.scling.com
What is a session?
● Sequence of clicks at most 5 minutes
apart.
● Maximum length 3 hours.
Examples, window = 5am - 9am:
● Clicks at [6:00, 6:01, 6:03, 6:45, 6:47]?
○ Two sessions, 3 and 2 minutes long.
● [5:00, 5:01, 5:03]?
○ One session, 3 minutes?
49
www.scling.com
What is a session?
● Sequence of clicks at most 5 minutes
apart.
● Maximum length 3 hours.
Examples, window = 5am - 9am:
● Clicks at [6:00, 6:01, 6:03, 6:45, 6:47]?
○ Two sessions, 3 and 2 minutes long.
● [5:00, 5:01, 5:03]?
○ One session, 3 minutes?
○ [(4:57), 5:00, 5:01, 5:03]?
○ [(2:01), (every 3 minutes), (4:57), 5:00,
5:01, 5:03]?
50
www.scling.com
Occurrences with unbounded time spans
● E.g. sessions, behavioural patterns
● You often need a broader time range than expected
● You may need data from the future
● You may need infinite history
○ Recursive strides?
○ Introduce static limits, e.g. cut all sessions at midnight?
○ Emit counters to monitor assumptions.
51
www.scling.com
Secrets of valuable data engineering
1. Avoid complexity and distributed systems
○ Your data fits in one machine.
2. Pick the slowest data integration you can live with
○ Batch >> streaming >> service.
○ Slow data → easy operations → high innovation speed
3. Functional architectural principles
○ Pipelines
○ Immutability
○ Reproducibility
○ Idempotency
4. Master workflow orchestration
52
www.scling.com
Team concurrency - DataOps
● Pipelines
○ Parallel development without risk
● Immutability
○ Data reusability without risk
● Reproducibility, idempotency
○ Preserving immutability
○ Reduces operational risk
○ Stable experiments
● Workflow orchestration
○ Data handover between systems & teams
○ Reduces operational overhead
53
Data science
reproducibility crisis!
www.scling.com
Resources, credits
Time libraries:
● Java: Joda time java.time
● Scala: chronoscala
● Python: dateutil, pendulum
Presentation on operational tradeoffs:
https://www.slideshare.net/lallea/data-ops-in-practice
Data engineering resources:
https://www.scling.com/reading-list
54
Thank you,
● Konstantinos Chaidos, Spotify
● Lena Sundin, independent
www.scling.com
Tech has massive impact on society
55
Product?
Supplier?
Employer?
Make an active
choice whether to
have an impact!
Cloud?
www.scling.com
Laptop sticker
Vintage data visualisations, by Karin Lind.
● Charles Minard: Napoleon’s Russian campaign of 1812. Drawn 1869.
● Matthew F Maury: Wind and Current Chart of the North Atlantic. Drawn 1852.
● Florence Nightingale: Causes of Mortality in the Army of the East. Crimean
war, 1854-1856. Drawn 1858.
○ Blue = disease, red = wounds, black = battle + other.
● Harold Craft: Radio Observations of the Pulse Profiles and Dispersion
Measures of Twelve Pulsars, 1970
○ Joy Division:
Unknown Pleasures, 1979
○ “Joy plot” → “ridge plot”
56

Eventually, time will kill your data processing

  • 1.
    www.scling.com Eventually, time willkill your data processing Øredev, 2019-11-07 Lars Albertsson Scling 1
  • 2.
    www.scling.com Out of joint “Timeis out of joint. O cursed spite, That ever I was born to set it right.” - Hamlet, prince of Denmark 2
  • 3.
    www.scling.com Out of joint “Timeis out of joint. O cursed spite, That ever I was born to set it right.” - Hamlet, prince of Denmark 3
  • 4.
    www.scling.com Out of joint “Timeis out of joint. O cursed spite, That ever I was born to set it right.” - Hamlet, prince of Denmark 4
  • 5.
    www.scling.com Out of joint 5 Freeusers using premium service
  • 6.
    www.scling.com Time will killus all ● Time handling causes data processing problems ● Observed issues ● Principles, patterns, anti-patterns Goals: ● Awareness, recognition ● Tools from my toolbox 6
  • 7.
    www.scling.com Big data -a collaboration paradigm 7 Stream storage Data lake Data democratised
  • 8.
  • 9.
    www.scling.com More data -decreased friction 9 Data lake Stream storage
  • 10.
    www.scling.com Scling - data-value-as-a-service 10 Datalake Stream storage ● Extract value from your data ● Data platform + custom data pipelines ● Imitate data leaders: ○ Quick idea-to-production ○ Operational efficiency Our marketing strategy: ● Promiscuously share knowledge ○ On slides devoid of glossy polish
  • 11.
    www.scling.com Data platform overview 11 Datalake Batch processing Cold store Dataset Pipeline Service Service Online services Offline data platform Job Workflow orchestration
  • 12.
    www.scling.com Data categories, timeangle ● Facts ○ Events, observations ○ Time stamped by clock(s) ○ Continuous stream 12
  • 13.
    www.scling.com Data categories, timeangle ● Facts ○ Events, observations ○ Time stamped by clock(s) ○ Continuous stream ● State ○ Snapshot view of system state ○ Lookup in live system. Dumped to data lake. ○ Regular intervals (daily) 13
  • 14.
    www.scling.com Data categories, timeangle ● Facts ○ Events, observations ○ Time stamped by clock(s) ○ Continuous stream ● State ○ Snapshot view of system state ○ Lookup in live system. Dumped to data lake. ○ Regular intervals (daily) ● Claims ○ Statement about the past ○ Time window scope 14
  • 15.
    www.scling.com Domain time -scope of claim. “These are suspected fraudulent users for March 2019.” Time scopes 15 Service Registration time Event time Ingest time Processing time
  • 16.
    www.scling.com Controlled backend -good clocks, UTC Clocks 16 ● Computer clocks measure elapsed time ● Good clocks, bad clocks, wrong clocks Legacy systems - good clocks Time zone? Clients - bad clocks Time zone?
  • 17.
    www.scling.com Calendars, naive Maps timeto astronomical and social domains Naive calendar ● 365 days + leap years ● 12 months, 28-31 days ● 7 day weeks ● 24 hours ● 60 minutes ● 60 seconds ● 24 hour time zones 17
  • 18.
    www.scling.com Naive calendar properties t+ 1.day == t + 86400.seconds (y + 45.years).asInt == y.asInt + 45 (date(y, 1, 1) + 364.days).month == 12 (t + 60.minutes).hour == (t.hour + 1) % 24 datetime(y, mon, d, h, m, s, tz).inZone(tz2).day in [d - 1, d, d + 1] datetime(y, mon, d, h, m, s, tz).inZone(tz2).minute == m date(y, 12, 29) + 1.day == date(y, 12, 30) (date(y, 2, 28) + 2.days).month == 3 18 Can you find the counter examples?
  • 19.
    www.scling.com Calendar reality t +1.day == t + 86400.seconds (y + 45.years).asInt == y.asInt + 45 (date(y, 1, 1) + 364.days).month == 12 (t + 60.minutes).hour == (t.hour + 1) % 24 datetime(y, mon, d, h, m, s, tz).inZone(tz2).day in [d - 1, d, d + 1] datetime(y, mon, d, h, m, s, tz).inZone(tz2).minute == m date(y, 12, 29) + 1.day == date(y, 12, 30) (date(y, 2, 28) + 2.days).month == 3 19 Leap seconds Year zero Julian / Gregorian calendar switch Sweden: 1712-02-30 Daylight savings time Samoa crosses date line. Again. Time zones: Span 26 hours 15 minute granularity
  • 20.
    www.scling.com Except DST ● Analyticsquality ● Changes with political decision ● Might affect technical systems ● (Affects health!) Small problems in practice 20 Leap seconds Year zero Julian / Gregorian calendar switch Sweden: 1712-02-30 Samoa crosses date line. Again. Time zones: Span 26 hours 15 minute granularity Daylight savings time
  • 21.
    www.scling.com Daylight savings example Credits:Rachel Wigell, https://twitter.com/the_databae/status/1191479005192605698 21
  • 22.
    www.scling.com Typical loading dockingress 22 ● File arrives every hour ● Ingest job copies to lake, applies data platform conventions ● Source system determines format, naming, and timestamps class SalesArrived(ExternalTask): """Receive a file with sales transactions every hour.""" hour = DateHourParameter() def matches(self): return [u for u in GCSClient().listdir(f'gs://ingress/sales/') if re.match(rf'{self.hour:%Y%m%d%h}.*.json', u)] def output(self): return GCSTarget(self.matches()[0]) @requires(SalesArrived) class SalesIngest(Task): def output(self): return GCSFlagTarget('gs://lake/sales/' f'{self.hour:year=%Y/month=%m/day=%d/hour=%h}/') def run(self): _, base = self.input().path.rsplit('/', 1) dst = f'{self.output().path}{base}' self.output().fs.copy(src.path, dst) self.output().fs.put_string('', f'{self.output().path}{self.output().flag)}' crontab: */10 * * * * luigi RangeHourly --of SalesIngest
  • 23.
    www.scling.com Typical loading dockingress 23 ● File arrives every hour ● Ingest job copies to lake, applies data platform conventions ● Source system determines format, naming, and timestamps, incl. zone ● Spring: halted ingest Autumn: data loss class SalesArrived(ExternalTask): """Receive a file with sales transactions every hour.""" hour = DateHourParameter() def matches(self): return [u for u in GCSClient().listdir(f'gs://ingress/sales/') if re.match(rf'{self.hour:%Y%m%d%h}.*.json', u)] def output(self): return GCSTarget(self.matches()[0]) @requires(SalesArrived) class SalesIngest(Task): def output(self): return GCSFlagTarget('gs://lake/sales/' f'{self.hour:year=%Y/month=%m/day=%d/hour=%h}/') def run(self): _, base = self.input().path.rsplit('/', 1) dst = f'{self.output().path}{base}' self.output().fs.copy(src.path, dst) self.output().fs.put_string('', f'{self.output().path}{self.output().flag)}' crontab: */10 * * * * luigi RangeHourly --of SalesIngest
  • 24.
    www.scling.com Using snapshots ● join(event,snapshot) → always time mismatch ● Usually acceptable ○ In one direction 24 DB’DB join?
  • 25.
    www.scling.com Using snapshots ● join(event,snapshot) → always time mismatch ● Usually acceptable ○ In one direction 25 DB’DB join? Free users using premium service
  • 26.
    www.scling.com ● Time mismatchin both directions Window misalign 26 DB join
  • 27.
    www.scling.com Event sourcing ● Everychange to unified log == source of truth ● snapshot(t + 1) = sum(snapshot(t), events(t, t+1)) ● Allows view & join at any point in time ○ But more complex 27 DB’DB
  • 28.
    www.scling.com Easier to expresswith streaming? state + event → state' ● State is a view of sum of all events ○ Join with the sum table ○ Beautiful! ○ Not simple in practice ● Mixing event time and processing time ○ Every join is a race condition 28 Stream Stream Stream Stream
  • 29.
    www.scling.com Stream window operations 29 Stream Stream Stream Stream Slidingwindows Tumbling windows Stream Stream Stream Window join
  • 30.
    www.scling.com Window over what? ●Number of events ● Processing time ● Registration time ● Event time 30 Less relevant for domain Deterministic Predictable semantics Predictable resources More relevant for domain Deterministic Unpredictable semantics Unpredictable resources Less relevant for domain Indeterministic Unpredictable semantics Predictable resources
  • 31.
    www.scling.com Batch is easier? ●Yes ● But, some pitfalls Event ingest 31 How to divide events to datasets? When to start processing?
  • 32.
    www.scling.com Ancient data collection: ●Events in log files, partitioned hourly ● Copy each hour of every host to lake Anti-pattern: Bucket by registration time 32 Service All hosts represented?
  • 33.
    www.scling.com ● Start processingoptimistically ● Reprocess after x% new data has arrived Anti-pattern: Reprocess 33
  • 34.
    www.scling.com ● Start processingoptimistically ● Reprocess after x% new data has arrived Solution space: ● Apache Beam / Google → stream processing ops ● Data versioning ● Provenance Requires good (lacking) tooling Supporting reprocessing 34
  • 35.
  • 36.
    www.scling.com ● Bundle incomingevents into datasets ○ Bucket on ingest / wall-clock time ○ Predictable bucketing, e.g. hour Pattern: Ingest time bucketing 36 clicks/2016/02/08/14 clicks/2016/02/08/15 ● Sealed quickly at end of hour ● Mark dataset as complete ○ E.g. _SUCCESS flag
  • 37.
  • 38.
    www.scling.com val orderLateCounter =longAccumulator("order-event-late") val hourPaths = conf.order.split(",") val order = hourPaths .map(spark.read.avro(_)) .reduce(a, b => a.union(b)) val orderThisHour = order .map({ cl => # Count the events that came after the delay window if (cl.eventTime.hour + config.delayHours < config.hour) { orderLateCounter.add(1) } order }) .filter(cl => cl.eventTime.hour == config.hour) class OrderShuffle(SparkSubmitTask): hour = DateHourParameter() delay_hours = IntParameter() jar = 'orderpipeline.jar' entry_class = 'com.example.shop.OrderShuffleJob' def requires(self): # Note: This delays processing by N hours. return [Order(hour=hour) for hour in [self.hour + timedelta(hour=h) for h in range(self.delay_hours)]] def output(self): return HdfsTarget("/prod/red/order/v1/" f"delay={self.delay}/" f"{self.hour:%Y/%m/%d/%H}/") def app_options(self): return [ "--hour", self.hour, "--delay-hours", self.delay_hours, "--order", ",".join([i.path for i in self.input()]), "--output", self.output().path] Incompleteness recovery 38
  • 39.
    www.scling.com class OrderShuffleAll(WrapperTask): hour =DateHourParameter() def requires(self): return [OrderShuffle(hour=self.hour, delay_hour=d) for d in [0, 4, 12]] class OrderDashboard(mysql.CopyToTable): hour = DateHourParameter() def requires(self): return OrderShuffle(hour=self.hour, delay_hour=0) class FinancialReport(SparkSubmitTask): date = DateParameter() def requires(self): return [OrderShuffle( hour=datetime.combine(self.date, time(hours=h)), delay_hour=12) for h in range(24)] Fast data, complete data 39 Delay: 0 Delay: 4 Delay: 12
  • 40.
    www.scling.com class ReportBase(SparkSubmitTask): date =DateParameter() jar = 'reportpipeline.jar' entry_class = 'com.example.shop.ReportJob' def requires(self): return [OrderShuffle( hour=datetime.combine(self.date, time(hour=h)), delay_hour=self.delay) for h in range(24)] class PreliminaryReport(ReportBase): delay = 0 class FinalReport(ReportBase): delay = 12 def requires(self): return super().requires() + [SuspectedFraud(self.date)] Lambda in batch 40
  • 41.
    www.scling.com Human-delayed data “These aremy compensation claims for last January.” ● Want: accurate reporting ● Want: current report status Anti-pattern: Reprocessing 41
  • 42.
    www.scling.com class ClaimsReport(SparkSubmitTask): domain_month =MonthParameter() date = DateParameter() jar = 'reportpipeline.jar' entry_class = 'com.example.shop.ClaimsReportJob' def requires(self): return [Claims( domain_month=self.domain_month, date=d) for date in date_range( self.domain_month + timedelta(month=1), self.date)] Dual time scopes 42 ● What we knew about month X at date Y ● Deterministic ○ Can be backfilled, audited ● May require sparse dependency trees
  • 43.
    www.scling.com Recursive dependencies ● Useyesterday’s dataset + some delta ○ Starting point necessary ● Often convenient, but operational risk ○ Slow backfills 43 class StockAggregateJob(SparkSubmitTask): date = DateParameter() jar = 'stockpipeline.jar' entry_class = 'com.example.shop.StockAggregate' def requires(self): yesterday = self.date - timedelta(days=1) previous = StockAggregateJob( date=yesterday) return [StockUpdate(date=self.date), previous]
  • 44.
    www.scling.com Recursive dependency strides ●Mitigation: recursive strides ● y/m/1 depends on y/m-1/1 ● Others depend on y/m/1 + all previous days in this month 44 class StockAggregateStrideJob(SparkSubmitTask): date = DateParameter() jar = 'stockpipeline.jar' entry_class = 'com.example.shop.StockAggregate' def requires(self): first_in_month = self.date.replace(day=1) base = first_in_month - relativedelta(months=1) if self.date.day == 1 else first_in_month return ([StockAggregateStrideJob(date=base)] + [StockUpdate(date=d) for d in rrule(freq=DAILY, dtstart=base, until=self.date)])
  • 45.
    www.scling.com Business logic withhistory Example: Forming sessions ● Valuable for ○ User insights ○ Product insights ○ A/B testing ○ ... 45
  • 46.
    www.scling.com What is asession? ● Sequence of clicks at most 5 minutes apart? ● In order to emit sessions in one hour, which hours of clicks are needed? 46
  • 47.
    www.scling.com What is asession? ● Sequence of clicks at most 5 minutes apart? ● Maximum length 3 hours? ● In order to emit sessions in one hour, which hours of clicks are needed? 47
  • 48.
    www.scling.com What is asession? ● Sequence of clicks at most 5 minutes apart. ● Maximum length 3 hours. Examples, window = 5am - 9am: ● Clicks at [6:00, 6:01, 6:03, 6:45, 6:47]? ○ Two sessions, 3 and 2 minutes long. 48
  • 49.
    www.scling.com What is asession? ● Sequence of clicks at most 5 minutes apart. ● Maximum length 3 hours. Examples, window = 5am - 9am: ● Clicks at [6:00, 6:01, 6:03, 6:45, 6:47]? ○ Two sessions, 3 and 2 minutes long. ● [5:00, 5:01, 5:03]? ○ One session, 3 minutes? 49
  • 50.
    www.scling.com What is asession? ● Sequence of clicks at most 5 minutes apart. ● Maximum length 3 hours. Examples, window = 5am - 9am: ● Clicks at [6:00, 6:01, 6:03, 6:45, 6:47]? ○ Two sessions, 3 and 2 minutes long. ● [5:00, 5:01, 5:03]? ○ One session, 3 minutes? ○ [(4:57), 5:00, 5:01, 5:03]? ○ [(2:01), (every 3 minutes), (4:57), 5:00, 5:01, 5:03]? 50
  • 51.
    www.scling.com Occurrences with unboundedtime spans ● E.g. sessions, behavioural patterns ● You often need a broader time range than expected ● You may need data from the future ● You may need infinite history ○ Recursive strides? ○ Introduce static limits, e.g. cut all sessions at midnight? ○ Emit counters to monitor assumptions. 51
  • 52.
    www.scling.com Secrets of valuabledata engineering 1. Avoid complexity and distributed systems ○ Your data fits in one machine. 2. Pick the slowest data integration you can live with ○ Batch >> streaming >> service. ○ Slow data → easy operations → high innovation speed 3. Functional architectural principles ○ Pipelines ○ Immutability ○ Reproducibility ○ Idempotency 4. Master workflow orchestration 52
  • 53.
    www.scling.com Team concurrency -DataOps ● Pipelines ○ Parallel development without risk ● Immutability ○ Data reusability without risk ● Reproducibility, idempotency ○ Preserving immutability ○ Reduces operational risk ○ Stable experiments ● Workflow orchestration ○ Data handover between systems & teams ○ Reduces operational overhead 53 Data science reproducibility crisis!
  • 54.
    www.scling.com Resources, credits Time libraries: ●Java: Joda time java.time ● Scala: chronoscala ● Python: dateutil, pendulum Presentation on operational tradeoffs: https://www.slideshare.net/lallea/data-ops-in-practice Data engineering resources: https://www.scling.com/reading-list 54 Thank you, ● Konstantinos Chaidos, Spotify ● Lena Sundin, independent
  • 55.
    www.scling.com Tech has massiveimpact on society 55 Product? Supplier? Employer? Make an active choice whether to have an impact! Cloud?
  • 56.
    www.scling.com Laptop sticker Vintage datavisualisations, by Karin Lind. ● Charles Minard: Napoleon’s Russian campaign of 1812. Drawn 1869. ● Matthew F Maury: Wind and Current Chart of the North Atlantic. Drawn 1852. ● Florence Nightingale: Causes of Mortality in the Army of the East. Crimean war, 1854-1856. Drawn 1858. ○ Blue = disease, red = wounds, black = battle + other. ● Harold Craft: Radio Observations of the Pulse Profiles and Dispersion Measures of Twelve Pulsars, 1970 ○ Joy Division: Unknown Pleasures, 1979 ○ “Joy plot” → “ridge plot” 56