SlideShare a Scribd company logo
1 of 210
Download to read offline
Event Sourcing w/ Kafka Streams
Amitay Horwitz | @amitayh
Milan | November 29 - 30, 2018
AGENDA ✅
AGENDA ✅
• Event sourcing 101
AGENDA ✅
• Event sourcing 101
• Eventim
AGENDA ✅
• Event sourcing 101
• Eventim
• Kafka & Kafka Streams
AGENDA ✅
• Event sourcing 101
• Eventim
• Kafka & Kafka Streams
• Putting it all together
BACKGROUND 🖼
A SERVICE IS BORN ✒📃💰
• Wix Invoices was incepted
in mid 2015
• Rich domain model
• Auditing is important for
monetary products
invoices
invoice_id
customer_id
issue_date
due_date
sent_date
currency
status
line_items
line_item_id
invoice_id
description
quantity
price
customers
customer_id
name
email
address
payments
transaction_id
invoice_id
payment_type
payment_amount
taxes
tax_id
line_item_id
name
rate
NAÏVE SOLUTION
HOW DOYOU HYDRATE
YOUR DOMAIN OBJECTS?
SELECT	
		e.employee_id	AS	"Employee	#"	
		,	e.first_name	||	'	'	||	e.last_name	AS	"Name"	
		,	e.email	AS	"Email"	
		,	e.phone_number	AS	"Phone"	
		,	TO_CHAR(e.hire_date,	'MM/DD/YYYY')	AS	"Hire	Date"	
		,	TO_CHAR(e.salary,	'L99G999D99',	'NLS_NUMERIC_CHARACTERS	=	''.,''	NLS_CURRENCY	=	''$''')	AS	"Salary"	
		,	e.commission_pct	AS	"Comission	%"	
		,	'works	as	'	||	j.job_title	||	'	in	'	||	d.department_name	||	'	department	(manager:	'	
				||	dm.first_name	||	'	'	||	dm.last_name	||	')	and	immediate	supervisor:	'	||	m.first_name	||	'	'	||	m.last_name	AS	"Current	Job"	
		,	TO_CHAR(j.min_salary,	'L99G999D99',	'NLS_NUMERIC_CHARACTERS	=	''.,''	NLS_CURRENCY	=	''$''')	||	'	-	'	||	
						TO_CHAR(j.max_salary,	'L99G999D99',	'NLS_NUMERIC_CHARACTERS	=	''.,''	NLS_CURRENCY	=	''$''')	AS	"Current	Salary"	
		,	l.street_address	||	',	'	||	l.postal_code	||	',	'	||	l.city	||	',	'	||	l.state_province	||	',	'	
				||	c.country_name	||	'	('	||	r.region_name	||	')'	AS	"Location"	
		,	jh.job_id	AS	"History	Job	ID"	
		,	'worked	from	'	||	TO_CHAR(jh.start_date,	'MM/DD/YYYY')	||	'	to	'	||	TO_CHAR(jh.end_date,	'MM/DD/YYYY')	||	
				'	as	'	||	jj.job_title	||	'	in	'	||	dd.department_name	||	'	department'	AS	"History	Job	Title"	
FROM	employees	e	
--	to	get	title	of	current	job_id	
		JOIN	jobs	j	ON	e.job_id	=	j.job_id	
--	to	get	name	of	current	manager_id	
		LEFT	JOIN	employees	m	ON	e.manager_id	=	m.employee_id	
--	to	get	name	of	current	department_id	
		LEFT	JOIN	departments	d	ON	d.department_id	=	e.department_id	
--	to	get	name	of	manager	of	current	department	
--	(not	equal	to	current	manager	and	can	be	equal	to	the	employee	itself)	
		LEFT	JOIN	employees	dm	ON	d.manager_id	=	dm.employee_id	
--	to	get	name	of	location
HOW DOYOU HYDRATE
YOUR DOMAIN OBJECTS?
SELECT	
		e.employee_id	AS	"Employee	#"	
		,	e.first_name	||	'	'	||	e.last_name	AS	"Name"	
		,	e.email	AS	"Email"	
		,	e.phone_number	AS	"Phone"	
		,	TO_CHAR(e.hire_date,	'MM/DD/YYYY')	AS	"Hire	Date"	
		,	TO_CHAR(e.salary,	'L99G999D99',	'NLS_NUMERIC_CHARACTERS	=	''.,''	NLS_CURRENCY	=	''$''')	AS	"Salary"	
		,	e.commission_pct	AS	"Comission	%"	
		,	'works	as	'	||	j.job_title	||	'	in	'	||	d.department_name	||	'	department	(manager:	'	
				||	dm.first_name	||	'	'	||	dm.last_name	||	')	and	immediate	supervisor:	'	||	m.first_name	||	'	'	||	m.last_name	AS	"Current	Job"	
		,	TO_CHAR(j.min_salary,	'L99G999D99',	'NLS_NUMERIC_CHARACTERS	=	''.,''	NLS_CURRENCY	=	''$''')	||	'	-	'	||	
						TO_CHAR(j.max_salary,	'L99G999D99',	'NLS_NUMERIC_CHARACTERS	=	''.,''	NLS_CURRENCY	=	''$''')	AS	"Current	Salary"	
		,	l.street_address	||	',	'	||	l.postal_code	||	',	'	||	l.city	||	',	'	||	l.state_province	||	',	'	
				||	c.country_name	||	'	('	||	r.region_name	||	')'	AS	"Location"	
		,	jh.job_id	AS	"History	Job	ID"	
		,	'worked	from	'	||	TO_CHAR(jh.start_date,	'MM/DD/YYYY')	||	'	to	'	||	TO_CHAR(jh.end_date,	'MM/DD/YYYY')	||	
				'	as	'	||	jj.job_title	||	'	in	'	||	dd.department_name	||	'	department'	AS	"History	Job	Title"	
FROM	employees	e	
--	to	get	title	of	current	job_id	
		JOIN	jobs	j	ON	e.job_id	=	j.job_id	
--	to	get	name	of	current	manager_id	
		LEFT	JOIN	employees	m	ON	e.manager_id	=	m.employee_id	
--	to	get	name	of	current	department_id	
		LEFT	JOIN	departments	d	ON	d.department_id	=	e.department_id	
--	to	get	name	of	manager	of	current	department	
--	(not	equal	to	current	manager	and	can	be	equal	to	the	employee	itself)	
		LEFT	JOIN	employees	dm	ON	d.manager_id	=	dm.employee_id	
--	to	get	name	of	location	
😱
DOMAIN MODEL
≠
DBTABLE
EVENT SOURCING 101
MUTABLE STATE 🚫
MUTABLE STATE 🚫
• Instead of saving the current state, we save the
succession of events that brought us to this state
MUTABLE STATE 🚫
• Instead of saving the current state, we save the
succession of events that brought us to this state
• currentState	=	fold(events,	emptyState)
INVOICE LIFECYCLE
time
Invoice
created
INVOICE LIFECYCLE
{	
		"customer":	{...},	
		"issueDate":	"2018-01-01",	
		"dueDate":	"2018-02-01",	
		"lineItems:	[],	
		"status":	"DRAFT"	
}
time
Invoice
created
{	
		"customer":	{...},	
		"issueDate":	"2018-01-01",	
		"dueDate":	"2018-02-01",	
		"lineItems:	[{"price":	1.99,	"qty":	1}],	
		"status":	"DRAFT"	
}
Line item
added
time
INVOICE LIFECYCLE
Invoice
created
INVOICE LIFECYCLE
{	
		"customer":	{...},	
		"issueDate":	"2018-01-01",	
		"dueDate":	"2018-02-01",	
		"lineItems:	[{"price":	1.99,	"qty":	1},	{"price":	3.50,	"qty":	2}],	
		"status":	"DRAFT"	
}
Line item
added
Line item
added
time
Invoice
created
INVOICE LIFECYCLE
{	
		"customer":	{...},	
		"issueDate":	"2018-01-01",	
		"dueDate":	"2018-02-01",	
		"lineItems:	[{"price":	3.50,	"qty":	2}],	
		"status":	"DRAFT"	
}
Line item
added
Line item
added
Line item
removed
time
Invoice
created
INVOICE LIFECYCLE
{	
		"customer":	{...},	
		"issueDate":	"2018-01-01",	
		"dueDate":	"2018-02-01",	
		"lineItems:	[{"price":	3.50,	"qty":	2}],	
		"status":	"SENT"	
}
Line item
added
Line item
added
Line item
removed
Invoice
sent to
customer
time
Invoice
created
INVOICE LIFECYCLE
{	
		"customer":	{...},	
		"issueDate":	"2018-01-01",	
		"dueDate":	"2018-02-01",	
		"lineItems:	[{"price":	3.50,	"qty":	2}],	
		"status":	"PAID"	
}
Line item
added
Line item
added
Line item
removed
Invoice
sent to
customer
Payment
received
time
EVENTIM
DESIGN GOALS 👷
• Small and simple library
• Non-intrusive
• Maintain data integrity
• Easily add custom views
WRITE PATH ✏
Event Sourced

Command Handler
UserInterface
WRITE PATH ✏
Event Sourced

Command Handler
Command
UserInterface
WRITE PATH ✏
Event Sourced

Command Handler
Command
UserInterface
invoice	ID:	12345

expected	version:	5

amount:	$12.34

Add Payment
WRITE PATH ✏
Event Sourced

Command Handler
Command
UserInterface
invoice	ID:	12345

expected	version:	5

amount:	$12.34

Add Payment
Aggregare

Repository
Load
WRITE PATH ✏
Event Sourced

Command Handler
Command
UserInterface
invoice	ID:	12345

expected	version:	5

amount:	$12.34

Add Payment
Aggregare

Repository
Load
Event

Store
Get events
WRITE PATH ✏
Event Sourced

Command Handler
Command
UserInterface
invoice	ID:	12345

expected	version:	5

amount:	$12.34

Add Payment
Aggregare

Repository
Load
Event

Store
Get events
version:	5

customer:	{...}

line	items:	[...]

balance:	$12.34
Invoice #12345
WRITE PATH ✏
Event Sourced

Command Handler
Command
UserInterface
Aggregare

Repository
Load
Event

Store
Get eventsinvoice	ID:	12345

expected	version:	5

amount:	$12.34
Add Payment
version:	5

customer:	{...}

line	items:	[...]

balance:	$12.34
Invoice #12345
WRITE PATH ✏
Event Sourced

Command Handler
Command
UserInterface
Aggregare

Repository
Load
Event

Store
Get eventsinvoice	ID:	12345

expected	version:	5

amount:	$12.34
Add Payment
version:	5

customer:	{...}

line	items:	[...]

balance:	$12.34
Invoice #12345
WRITE PATH ✏
Event Sourced

Command Handler
Command
UserInterface
Aggregare

Repository
Load
Event

Store
Get events
WRITE PATH ✏
Event Sourced

Command Handler
Command
UserInterface
Aggregare

Repository
Load
Event

Store
Get events
Payment	Added:	$12.34
WRITE PATH ✏
Event Sourced

Command Handler
Command
UserInterface
Aggregare

Repository
Load
Event

Store
Get events
Payment	Added:	$12.34
Status	Changed:	Paid
WRITE PATH ✏
Event Sourced

Command Handler
Command
UserInterface
Aggregare

Repository
Load
Event

Store
Get events
Payment	Added:	$12.34
Status	Changed:	Paid
version:	7

customer:	{...}

line	items:	[...]

balance:	$0.00
Invoice #12345
WRITE PATH ✏
Event Sourced

Command Handler
Command
UserInterface
Aggregare

Repository
Load
Event

Store
Get events
Payment	Added:	$12.34
Status	Changed:	Paid
Publish events
(OCC)
version:	7

customer:	{...}

line	items:	[...]

balance:	$0.00
Invoice #12345
WRITE PATH ✏
Event Sourced

Command Handler
Command
UserInterface
Aggregare

Repository
Load
Event

Store
Get events
Payment	Added:	$12.34
Status	Changed:	Paid
Publish events
(OCC)
Event Bus
READ PATH 👓
Event Bus
READ PATH 👓
Event Bus
Events
READ PATH 👓
View Projector
Event Handler
Event Bus
Events
READ PATH 👓
View Projector
Event Handler
DB
Event Bus
Events
READ PATH 👓
View Projector
Event Handler
DB
Event Bus
Events
invoice_id customer balance status
12345 John	Doe $12.34 New
67890 Jane	Doe $34.56 Sent
READ PATH 👓
View Projector
Event Handler
DB
Event Bus
Events
invoice_id customer balance status
12345 John	Doe $12.34 New
67890 Jane	Doe $34.56 Sent
Payment	Added:	$12.34
READ PATH 👓
View Projector
Event Handler
DB
Event Bus
Events
invoice_id customer balance status
12345 John	Doe $0.00 New
67890 Jane	Doe $34.56 Sent
READ PATH 👓
View Projector
Event Handler
DB
Event Bus
Events
invoice_id customer balance status
12345 John	Doe $0.00 New
67890 Jane	Doe $34.56 Sent
Status	Changed:	Paid
READ PATH 👓
View Projector
Event Handler
DB
Event Bus
Events
invoice_id customer balance status
12345 John	Doe $0.00 Paid
67890 Jane	Doe $34.56 Sent
READ PATH 👓
View Projector
Event Handler
DB
Event Bus
Events
READ PATH 👓
View Projector
Event Handler
DB
Event Bus
Events
READ PATH 👓
View Projector
Event Handler
DB
Event Bus
Events
READ PATH 👓
View Projector
Event Handler
DB
Event Bus
Events
READ PATH 👓
View Projector
Event Handler
DB
Event Bus
EventsUserInterface
READ PATH 👓
View Projector
Event Handler
DB
Queries
Event Bus
EventsUserInterface
READ PATH 👓
Mailer ✉
Event Handler
View Projector
Event Handler
DB
Queries
Event Bus
EventsUserInterface
READ PATH 👓
Mailer ✉
Event Handler
View Projector
Event Handler
Reporting 📈
Event Handler
DB
Queries
Event Bus
EventsUserInterface
PAIN POINTS 😓
PAIN POINTS 😓
• Persisting events and publishing them is not transactional
PAIN POINTS 😓
• Persisting events and publishing them is not transactional
• Inherent eventual consistency is not integrated in the
product (read after write)
PAIN POINTS 😓
• Persisting events and publishing them is not transactional
• Inherent eventual consistency is not integrated in the
product (read after write)
• Rebuilding views is a complex operation
REBUILDINGVIEWS 🌄
version event_payload
REBUILDINGVIEWS 🌄
version event_payload
1 InvoiceCreated(...)
REBUILDINGVIEWS 🌄
version event_payload
1 InvoiceCreated(...)
2 LineItemAdded(...)
REBUILDINGVIEWS 🌄
version event_payload
1 InvoiceCreated(...)
2 LineItemAdded(...)
3 LineItemAdded(...)
REBUILDINGVIEWS 🌄
version event_payload
1 InvoiceCreated(...)
2 LineItemAdded(...)
3 LineItemAdded(...)
4 InvoiceSent(...)
REBUILDINGVIEWS 🌄
SELECT	*

FROM	events

WHERE	version	>	0

ORDER	BY	version

LIMIT	100;
REBUILDINGVIEWS 🌄
SELECT	*

FROM	events

WHERE	version	>	100

ORDER	BY	version

LIMIT	100;
REBUILDINGVIEWS 🌄
invoice_id invoice_version event_payload
REBUILDINGVIEWS 🌄
invoice_id invoice_version event_payload
12345 1 InvoiceCreated
REBUILDINGVIEWS 🌄
invoice_id invoice_version event_payload
12345 1 InvoiceCreated
12345 2 LineItemAdded
REBUILDINGVIEWS 🌄
invoice_id invoice_version event_payload
12345 1 InvoiceCreated
12345 2 LineItemAdded
67890 1 InvoiceCreated
REBUILDINGVIEWS 🌄
invoice_id invoice_version event_payload
12345 1 InvoiceCreated
12345 2 LineItemAdded
67890 1 InvoiceCreated
67890 2 InvoiceDeleted
REBUILDINGVIEWS 🌄
invoice_id invoice_version event_payload
12345 1 InvoiceCreated
12345 2 LineItemAdded
12345 3 InvoiceSent
67890 1 InvoiceCreated
67890 2 InvoiceDeleted
REBUILDINGVIEWS 🌄
invoice_id version payload timestamp
12345 1 ... 14:05
12345 2 ... 14:06
12345 3 ... 15:50
67890 1 ... 15:30
67890 2 ... 15:33
REBUILDINGVIEWS 🌄
invoice_id version payload timestamp
12345 1 ... 14:05
12345 2 ... 14:06
67890 1 ... 15:30
67890 2 ... 15:33
12345 3 ... 15:50
REBUILDINGVIEWS 🌄
invoice_id version payload order
12345 1 ... 1
12345 2 ... 2
67890 1 ... 3
67890 2 ... 4
12345 3 ... 5
KAFKA & KAFKA STREAMS 101
APACHE KAFKA
• Distributed append-only log
• Replicated, fault-tolerant
• Often used as pub-sub or queue
• Used heavily at LinkedIn, Netflix,
Wix and many others
KAFKATOPICS
654321
4321
7654321
P0
P1
P2
Producer
KAFKATOPICS
Consumer Group
Node #1
654321
4321
7654321
P0
P1
P2
KAFKATOPICS
Consumer Group
Node #1
654321
4321
7654321
P0
P1
P2
Node #2
KAFKATOPICS
7654321
Consumer #1
KAFKATOPICS
7654321
Consumer #1Consumer #2
KAFKATOPICS
7654321
Consumer #1Consumer #2
KAFKATOPICS
7654321
Consumer #1Consumer #2
KAFKA STREAMS
KAFKA STREAMS
Streams
KAFKA STREAMS
Streams Tables
STREAMS ✈
• "Data in flight"
• Unbounded, continuously updating data set
• Ordered, replayable, sequence of immutable
data key-value pairs
TABLES 😴
• "Data at rest"
• A collection of evolving facts
• A point-in-time view of aggregated data
STREAM-TABLE DUALITY
STREAM-TABLE DUALITY
STREAM-TABLE DUALITY
Stream of all
changes to a table
STREAM-TABLE DUALITY
Stream of all
changes to a table
Materialize a
stream into a table
STREAM-TABLE DUALITY
User Pageviews
alice 1
STREAM-TABLE DUALITY
User Pageviews
alice 1
User Pageviews
alice 1
charlie 1
STREAM-TABLE DUALITY
User Pageviews
alice 1
User Pageviews
alice 1
charlie 1
User Pageviews
alice 2
charlie 1
STREAM-TABLE DUALITY
User Pageviews
alice 1
User Pageviews
alice 1
charlie 1
User Pageviews
alice 2
charlie 1
("alice",	1)
STREAM-TABLE DUALITY
User Pageviews
alice 1
User Pageviews
alice 1
charlie 1
User Pageviews
alice 2
charlie 1
("alice",	1)
("charlie",	1)
STREAM-TABLE DUALITY
User Pageviews
alice 1
User Pageviews
alice 1
charlie 1
User Pageviews
alice 2
charlie 1
("alice",	1)
("charlie",	1)
("alice",	2)
STREAM-TABLE DUALITY
User Pageviews
alice 1
User Pageviews
alice 1
charlie 1
User Pageviews
alice 2
charlie 1
("alice",	1)
("charlie",	1)
("alice",	2)
User Pageviews
alice 1
STREAM-TABLE DUALITY
User Pageviews
alice 1
User Pageviews
alice 1
charlie 1
User Pageviews
alice 2
charlie 1
("alice",	1)
("charlie",	1)
("alice",	2)
User Pageviews
alice 1
User Pageviews
alice 1
charlie 1
STREAM-TABLE DUALITY
User Pageviews
alice 1
User Pageviews
alice 1
charlie 1
User Pageviews
alice 2
charlie 1
("alice",	1)
("charlie",	1)
("alice",	2)
User Pageviews
alice 1
User Pageviews
alice 1
charlie 1
User Pageviews
alice 2
charlie 1
STREAMTRANSFORMATIONS
STREAMTRANSFORMATIONS
STREAMTRANSFORMATIONS
STREAMTRANSFORMATIONS
• map
STREAMTRANSFORMATIONS
• map
• filter
STREAMTRANSFORMATIONS
• map
• filter
• flatMap
STREAMTRANSFORMATIONS
• map
• filter
• flatMap
• …
STREAMTRANSFORMATIONS
• map
• filter
• flatMap
• …
STREAMTRANSFORMATIONS
STREAMTRANSFORMATIONS
STREAMTRANSFORMATIONS
STREAMTRANSFORMATIONS
Stream-stream join
STREAMTRANSFORMATIONS
STREAMTRANSFORMATIONS
STREAMTRANSFORMATIONS
STREAMTRANSFORMATIONS
Stream-table join
STREAM PROCESSING APP
Streams
API
Your app
STREAM PROCESSING APP
Streams
API
Your app
• Transforms and enriches data
STREAM PROCESSING APP
Streams
API
Your app
• Transforms and enriches data
• Stateless / stateful processing
STREAM PROCESSING APP
Streams
API
Your app
• Transforms and enriches data
• Stateless / stateful processing
• Supports windowing operations
STREAM PROCESSING APP
Streams
API
Your app
• Transforms and enriches data
• Stateless / stateful processing
• Supports windowing operations
• Embedded in your app
STREAM PROCESSING APP
Streams
API
Your app
• Transforms and enriches data
• Stateless / stateful processing
• Supports windowing operations
• Embedded in your app
• Elastic, scaleable, fault-tolerant
val	props	=	new	Properties	
props.put(	
		StreamsConfig.BOOTSTRAP_SERVERS_CONFIG,

		"localhost:9092")	
props.put(	
		StreamsConfig.APPLICATION_ID_CONFIG,	
		"my-streams-app")
STREAM PROCESSING APP
Streams
API
Your app
Streams
API
Your app
Streams
API
Your app
PROCESSORTOPOLOGY
group map
join filter
join
Source
processor
Sink
processor
Source
processor
PROCESSOR API
• The most low-level
• Interact with state-stores, schedulers, etc.
• All standard operations are implemented like this
(map / filter / …)
• Create your own custom processing logic!
STREAMS DSL
• Programmatically describe your topology
STREAMS DSL
val	builder	=	new	StreamsBuilder
• Programmatically describe your topology
STREAMS DSL
val	builder	=	new	StreamsBuilder	
val	textLines:	KStream[String,	String]	=	
		builder.stream("TextLinesTopic")
• Programmatically describe your topology
STREAMS DSL
val	builder	=	new	StreamsBuilder	
val	textLines:	KStream[String,	String]	=	
		builder.stream("TextLinesTopic")	
val	wordCounts:	KTable[String,	Long]	=	textLines
• Programmatically describe your topology
STREAMS DSL
val	builder	=	new	StreamsBuilder	
val	textLines:	KStream[String,	String]	=	
		builder.stream("TextLinesTopic")	
val	wordCounts:	KTable[String,	Long]	=	textLines	
		.flatMapValues(textLine	=>	textLine.split("W+"))
• Programmatically describe your topology
STREAMS DSL
val	builder	=	new	StreamsBuilder	
val	textLines:	KStream[String,	String]	=	
		builder.stream("TextLinesTopic")	
val	wordCounts:	KTable[String,	Long]	=	textLines	
		.flatMapValues(textLine	=>	textLine.split("W+"))	
		.groupBy((_,	word)	=>	word)
• Programmatically describe your topology
STREAMS DSL
val	builder	=	new	StreamsBuilder	
val	textLines:	KStream[String,	String]	=	
		builder.stream("TextLinesTopic")	
val	wordCounts:	KTable[String,	Long]	=	textLines	
		.flatMapValues(textLine	=>	textLine.split("W+"))	
		.groupBy((_,	word)	=>	word)	
		.count(Materialized.as("counts-store"))
• Programmatically describe your topology
STREAMS DSL
val	builder	=	new	StreamsBuilder	
val	textLines:	KStream[String,	String]	=	
		builder.stream("TextLinesTopic")	
val	wordCounts:	KTable[String,	Long]	=	textLines	
		.flatMapValues(textLine	=>	textLine.split("W+"))	
		.groupBy((_,	word)	=>	word)	
		.count(Materialized.as("counts-store"))	
wordCounts.toStream.to("WordsWithCountsTopic")
• Programmatically describe your topology
STREAMS DSL
val	builder	=	new	StreamsBuilder	
val	textLines:	KStream[String,	String]	=	
		builder.stream("TextLinesTopic")	
val	wordCounts:	KTable[String,	Long]	=	textLines	
		.flatMapValues(textLine	=>	textLine.split("W+"))	
		.groupBy((_,	word)	=>	word)	
		.count(Materialized.as("counts-store"))	
wordCounts.toStream.to("WordsWithCountsTopic")
• Programmatically describe your topology
KSQL
• SQL dialect for streaming data
CREATE	TABLE	possible_fraud	AS	
SELECT	card_number,	count(*)	
FROM	authorization_attempts		
WINDOW	TUMBLING	(SIZE	5	SECONDS)	
GROUP	BY	card_number	
HAVING	count(*)	>	3;
PUTTING EVERYTHING
TOGETHER 🔗
HIGH LEVEL DESIGN
UserInterface
HIGH LEVEL DESIGN
UserInterface
HIGH LEVEL DESIGN
UserInterface
HIGH LEVEL DESIGN
UserInterface
{"create":…}
HIGH LEVEL DESIGN
UserInterface
invoice-commands
HIGH LEVEL DESIGN
UserInterface
Command
Handler
HIGH LEVEL DESIGN
UserInterface
Command
Handler
Stream processing app
HIGH LEVEL DESIGN
UserInterface
command-results
Command
Handler
Web Socket
HIGH LEVEL DESIGN
UserInterface
Projector
Projection
DB
Command
Handler
HIGH LEVEL DESIGN
UserInterface
Projector
Projection
DB
Command
Handler
HIGH LEVEL DESIGN
UserInterface
ProjectorProjector
Command
Handler
Command
Handler
Command
Handler
COMMAND HANDLER
COMMAND HANDLER
commands
stream
invoice-commands
COMMAND HANDLER
commands
stream
invoice-commands
invoice	ID:	12345

command	ID:	67890

amount:	$12.34

Add Payment
COMMAND HANDLER
commands
stream
invoice-commands
invoice	ID:	12345

command	ID:	67890

amount:	$12.34

Add Payment
COMMAND HANDLER
transform:
results
commands
stream
invoice-commands
invoice	ID:	12345

command	ID:	67890

amount:	$12.34
Add Payment
COMMAND HANDLER
transform:
results
commands
stream
invoice-commands
Snapshots
state-store
invoice	ID:	12345

command	ID:	67890

amount:	$12.34
Add Payment
COMMAND HANDLER
transform:
results
commands
stream
invoice-commands
Snapshots
state-store
invoice	ID:	12345

command	ID:	67890

amount:	$12.34
Add Payment
customer:	{...}

line	items:	[...]

balance:	$12.34
Invoice #12345
COMMAND HANDLER
transform:
results
commands
stream
invoice-commands
Snapshots
state-store
invoice	ID:	12345

command	ID:	67890

amount:	$12.34
Add Payment
customer:	{...}

line	items:	[...]

balance:	$12.34
Invoice #12345
COMMAND HANDLER
transform:
results
commands
stream
invoice-commands
Snapshots
state-store
COMMAND HANDLER
transform:
results
commands
stream
invoice-commands
Snapshots
state-store
Payment	Added:	$12.34
COMMAND HANDLER
transform:
results
commands
stream
invoice-commands
Snapshots
state-store
Payment	Added:	$12.34
Status	Changed:	Paid
COMMAND HANDLER
transform:
results
commands
stream
invoice-commands
Snapshots
state-store
Payment	Added:	$12.34
Status	Changed:	Paid
customer:	{...}

line	items:	[...]

balance:	$0.00
Invoice #12345
COMMAND HANDLER
command-results transform:
results
commands
stream
invoice-commands
Snapshots
state-store
command	ID:	67890

snapshot:	{...}

events:	[...]
Successful
COMMAND HANDLER
command-results transform:
results
commands
stream
invoice-commands
Snapshots
state-store
COMMAND HANDLER
command-results transform:
results
commands
stream
invoice-commands
Snapshots
state-store
command	ID:	67890

cause:	invoice	deleted



Failed
COMMAND HANDLER
command-results transform:
results
commands
stream
invoice-commands
Snapshots
state-store
COMMAND HANDLER
command-results transform:
results
commands
stream
invoice-commands
Snapshots
state-store
Short retention
(~1 hour)
COMMAND HANDLER
command-results
filter:
successful
transform:
results
commands
stream
invoice-commands
Snapshots
state-store
COMMAND HANDLER
command-results
invoice-events
filter:
successful
transform:
results
commands
stream
invoice-commands
Snapshots
state-store
flatMap:
events
COMMAND HANDLER
command-results
invoice-events
filter:
successful
transform:
results
commands
stream
invoice-commands
Snapshots
state-store
flatMap:
events
map:
snapshots
invoice-snapshots
COMMAND HANDLER
command-results
invoice-events
filter:
successful
transform:
results
commands
stream
invoice-commands
Snapshots
state-store
flatMap:
events
map:
snapshots
invoice-snapshots
Long retention
(forever)Compacted
PROJECTOR
PROJECTOR
snapshots
stream
invoice-snapshots
PROJECTOR
map:
records
snapshots
stream
invoice-snapshots
PROJECTOR
foreach:
persist
DB
map:
records
snapshots
stream
invoice-snapshots
PROJECTOR
foreach:
persist
DB
invoice-records
map:
records
snapshots
stream
invoice-snapshots
API
DB
Business Logic
Persistance
Service #2
Service #3
Service #4
Invoices
Invoices
Customers Orders
Products
Invoices
Inventory
Customers Orders
Products
Invoices
InventoryAnalytics
Customers Orders
Products
Stream
processors
Materialized
views
API
Writes
Reads
WINS 🏆
WINS 🏆
• Simple and declarative system
WINS 🏆
• Simple and declarative system
• Atomicity - Kafka used as event-store + notification
WINS 🏆
• Simple and declarative system
• Atomicity - Kafka used as event-store + notification
• Eventual consistency is handled gracefully
WINS 🏆
• Simple and declarative system
• Atomicity - Kafka used as event-store + notification
• Eventual consistency is handled gracefully
• Easy to add or change views
DEMO 🥁
TAKEAWAYS 🍔
TAKEAWAYS 🍔
• Event driven systems and event sourcing can help
create very flexible and scalable systems
TAKEAWAYS 🍔
• Event driven systems and event sourcing can help
create very flexible and scalable systems
• Know your tradeoffs (consistency, schema evolution,
debugging, error handling, …)
TAKEAWAYS 🍔
• Event driven systems and event sourcing can help
create very flexible and scalable systems
• Know your tradeoffs (consistency, schema evolution,
debugging, error handling, …)
• Kafka & Kafka Streams are powerful tools that can be
employed in many use cases
Stream on!
RESOURCES 📚
• Demo code:

https://github.com/amitayh/event-sourcing-kafka-streams
• Event sourcing by GregYoung -

https://youtu.be/8JKjvY4etTY
• Martin Kleppmann - Is Kafka a Database?

https://youtu.be/v2RJQELoM6Y
• Kafka Streams docs - http://wix.to/00C2ADs
• Blog post from Confluent - http://wix.to/Z0C2ADs
Q&A 🤓

More Related Content

Similar to Amitay Horwitz - Building event sourced systems with Kafka Streams - Codemotion Milan 2018

360652733 dispute-management-and-collections-management-pdf-pdf
360652733 dispute-management-and-collections-management-pdf-pdf360652733 dispute-management-and-collections-management-pdf-pdf
360652733 dispute-management-and-collections-management-pdf-pdf
jayaramreddy
 
Fresa-Gold-Presentation-v2210.pdf
Fresa-Gold-Presentation-v2210.pdfFresa-Gold-Presentation-v2210.pdf
Fresa-Gold-Presentation-v2210.pdf
Fresa Technologies
 

Similar to Amitay Horwitz - Building event sourced systems with Kafka Streams - Codemotion Milan 2018 (20)

SVCC Developing Asynchronous, Message-Driven Microservices
SVCC Developing Asynchronous, Message-Driven Microservices  SVCC Developing Asynchronous, Message-Driven Microservices
SVCC Developing Asynchronous, Message-Driven Microservices
 
Roberto Grassi e Fulvio De Giovanni - Migliorare l’esperienza d’acquisto con ...
Roberto Grassi e Fulvio De Giovanni - Migliorare l’esperienza d’acquisto con ...Roberto Grassi e Fulvio De Giovanni - Migliorare l’esperienza d’acquisto con ...
Roberto Grassi e Fulvio De Giovanni - Migliorare l’esperienza d’acquisto con ...
 
Integration of payment gateways using Paypal account
Integration of payment gateways using Paypal account Integration of payment gateways using Paypal account
Integration of payment gateways using Paypal account
 
QCon 2019 - Opportunities and Pitfalls of Event-Driven Utopia
QCon 2019 - Opportunities and Pitfalls of Event-Driven UtopiaQCon 2019 - Opportunities and Pitfalls of Event-Driven Utopia
QCon 2019 - Opportunities and Pitfalls of Event-Driven Utopia
 
PayPal Real Time Analytics
PayPal  Real Time AnalyticsPayPal  Real Time Analytics
PayPal Real Time Analytics
 
Social Gold in-Flash Webinar Jan 2010
Social Gold in-Flash Webinar Jan 2010Social Gold in-Flash Webinar Jan 2010
Social Gold in-Flash Webinar Jan 2010
 
Social Gold In-Flash Payments Webinar
Social Gold In-Flash Payments WebinarSocial Gold In-Flash Payments Webinar
Social Gold In-Flash Payments Webinar
 
Powering Consistent, High-throughput, Real-time Distributed Calculation Engin...
Powering Consistent, High-throughput, Real-time Distributed Calculation Engin...Powering Consistent, High-throughput, Real-time Distributed Calculation Engin...
Powering Consistent, High-throughput, Real-time Distributed Calculation Engin...
 
Boxcars and Cabooses: When one more XHR is too much - Peter Chittum - Codemot...
Boxcars and Cabooses: When one more XHR is too much - Peter Chittum - Codemot...Boxcars and Cabooses: When one more XHR is too much - Peter Chittum - Codemot...
Boxcars and Cabooses: When one more XHR is too much - Peter Chittum - Codemot...
 
360652733 dispute-management-and-collections-management-pdf-pdf
360652733 dispute-management-and-collections-management-pdf-pdf360652733 dispute-management-and-collections-management-pdf-pdf
360652733 dispute-management-and-collections-management-pdf-pdf
 
Fresa-Gold-Presentation-v2210.pdf
Fresa-Gold-Presentation-v2210.pdfFresa-Gold-Presentation-v2210.pdf
Fresa-Gold-Presentation-v2210.pdf
 
Deliverable 2
Deliverable 2Deliverable 2
Deliverable 2
 
Google Analytics as Database of Record
Google Analytics as Database of RecordGoogle Analytics as Database of Record
Google Analytics as Database of Record
 
Improve Customer Service with Automated Sales and Order Lifecycle Processes U...
Improve Customer Service with Automated Sales and Order Lifecycle Processes U...Improve Customer Service with Automated Sales and Order Lifecycle Processes U...
Improve Customer Service with Automated Sales and Order Lifecycle Processes U...
 
Presentation_IWD_ GDGNantes_2022
Presentation_IWD_ GDGNantes_2022Presentation_IWD_ GDGNantes_2022
Presentation_IWD_ GDGNantes_2022
 
Money Heist - A Stream Processing Original! | Meha Pandey and Shengze Yu, Net...
Money Heist - A Stream Processing Original! | Meha Pandey and Shengze Yu, Net...Money Heist - A Stream Processing Original! | Meha Pandey and Shengze Yu, Net...
Money Heist - A Stream Processing Original! | Meha Pandey and Shengze Yu, Net...
 
Biz Dev for Startups - Part 3, 4 and 5
Biz Dev for Startups - Part 3, 4 and 5Biz Dev for Startups - Part 3, 4 and 5
Biz Dev for Startups - Part 3, 4 and 5
 
Swipez Features
Swipez FeaturesSwipez Features
Swipez Features
 
Best Practices in Catalog Strategies
Best Practices in Catalog StrategiesBest Practices in Catalog Strategies
Best Practices in Catalog Strategies
 
Winning the Application Server Arms Race
Winning the Application Server Arms RaceWinning the Application Server Arms Race
Winning the Application Server Arms Race
 

More from Codemotion

More from Codemotion (20)

Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
 
Pompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending storyPompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending story
 
Pastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storiaPastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storia
 
Pennisi - Essere Richard Altwasser
Pennisi - Essere Richard AltwasserPennisi - Essere Richard Altwasser
Pennisi - Essere Richard Altwasser
 
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
 
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
 
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
 
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 - Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 -
 
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
 
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
 
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
 
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
 
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
 
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
 
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
 
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
 
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
 
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
 
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
 
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
 

Recently uploaded

IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
Enterprise Knowledge
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
giselly40
 

Recently uploaded (20)

[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 

Amitay Horwitz - Building event sourced systems with Kafka Streams - Codemotion Milan 2018