bff pattern in action: soundcloud’s microservices
TRANSCRIPT
BFF Pattern in ActionSoundCloud’s Microservices
Bora Tunca
Joined SoundCloud 2.5 years ago
soundcloud.com front-end
client specific apis
core-services
@grandbora
SoundCloud is the largest online audio distribution platform
12 HOURS OF AUDIOevery minute
MOTHERSHIP
MOTHERSHIP
Public API
MOTHERSHIP
Public API
messages
likes
MOTHERSHIP
Public API
messages
likes
Mic
rose
rvic
es
0
20
40
60
80
100
120
2013 2014 2015 2016
Mic
rose
rvic
es
0
20
40
60
80
100
120
2013 2014 2015 2016
Mic
rose
rvic
es
0
20
40
60
80
100
120
2013 2014 2015 2016
Mic
rose
rvic
es
0
20
40
60
80
100
120
2013 2014 2015 2016
http://martinfowler.com/bliki/HumaneRegistry.html
Humane Registry
Oriented around people
Humane Registry
Oriented around people
Don't rely on people to stay up to date
Humane Registry
Oriented around people
Don't rely on people to stay up to date
Expect humans to read and contribute
Humane Registry
SERVICES DIRECTORY
Public API
messages
likesMOTHERSHIP
Api-v2 Api-mobile Api-embedded Public API
Api-v2 Api-mobile Api-embedded Public API
messages
MOTHERSHIPlikes
search
stats
images
Api-v2 Api-mobile Api-embedded Public API
Edge Layer
messages
MOTHERSHIPlikes
search
stats
images
Api-v2 Api-mobile Api-embedded Public API
Edge Layer
Client Applications
Microservices
messages
MOTHERSHIPlikes
search
stats
images
Backend For Fronted
Microservices
BFFs
Microservices
Client ApplicationsBFFs
Microservices
BFF
BFF authentication geo location features
1
BFF
messages
MOTHERSHIPlikes
search
stats
images
2
authentication geo location features
1
messages
MOTHERSHIP
BFF
likes
search
stats
images
authentication geo location features
messages
MOTHERSHIP
BFF
likes
search
stats
images
authentication geo location features
messages
MOTHERSHIP
BFF
likes
search
stats
images
authentication geo location features
messages
MOTHERSHIP
BFF
likes
search
stats
images
authentication geo location features
messages
MOTHERSHIP
BFF
likes
search
stats
images
authentication geo location features
BFF
messages
MOTHERSHIPlikes
search
stats
images
2
authentication geo location features
1
messages
MOTHERSHIP
BFF
likes
search
stats
images
authentication geo location features
BFF
BFFBFF
BFFBFF
messages
MOTHERSHIP
BFF
likes
search
stats
images
authentication geo location features
BFF
BFFBFF
BFFBFF
Critical Path
On critical path…
Be ready for traffic bursts
On critical path…
Be ready for traffic bursts
Handle failures gracefully
On critical path…
messages
MOTHERSHIP
BFF
likes
search
stats
images
authentication geo location features
1
messages
MOTHERSHIP
BFF
likes
search
stats
images
authentication geo location features
1
2
Public API
messages
likesMOTHERSHIP
messages
MOTHERSHIP
BFF
likes
search
stats
images
messages
MOTHERSHIP
BFF
likes
search
stats
images
BFF
messages
MOTHERSHIP
BFF
likes
search
stats
images
BFF
messages
MOTHERSHIP
BFF
likes
search
stats
images
tracks
BFF
images userstracks
Foundation Layer
images userstracks
Foundation Layer
playlistsstream profiles
Value Added Layer
images userstracks
Foundation Layer
playlistsstream profiles
Value Added Layer
images userstracks
Foundation Layer
playlistsstream profiles
Value Added Layer
BFF BFF
images userstracks
Foundation Layer
playlistsstream profiles
Value Added Layer
BFF BFF
images userstracks
Foundation Layer
playlistsstream profiles
Value Added Layer
MOTHERSHIP
GRAPHITE
STATSD
GRAPHITE
STATSD
PROMETHEUS
Prometheus
Scalable data collection
Operational simplicity
Multi-dimensional data
Powerful query language
https://developers.soundcloud.com/blog/prometheus-monitoring-at-soundcloudhttp://prometheus.io/
Prometheus
Prometheus
My Service
Prometheus
My Service
jvm client
My Service
jvm client
My Service
jvm client
My Service
jvm client
My Service
jvm client
My Service
jvm client
My Service
jvm client
My Service
jvm client
My Service
jvm client
My Service
jvm client
val requestCount = telemetry.counter("outgoing_http_requests_total", "A counter for the HTTP requests", "service", "method", "status", "statusClass")
send
requestCount.labels( serviceName, request.getMethod, response.getStatus, response.getStatusClass).inc()
val requestCount = telemetry.counter("outgoing_http_requests_total", "A counter for the HTTP requests", "service", "method", "status", "statusClass")
send
requestCount.labels( serviceName, request.getMethod, response.getStatus, response.getStatusClass).inc()
query SUM(rate(outgoing_http_requests_total{statusClass!="2xx"}[10m])) by (service, method, status)
DISTRIBUTED TRACING
SERVICE LEVEL OBJECTIVES
manifest.json{ "name": "trackmetadata", "type": "internal_service", "description": "Track Metadata service", "contact_email": "xxxxxxx", "owner": "core-services", "status": "production", "alert_service": "pagerduty.com/xxxx", "telemetry_dashboard": "http://promdash/trackmetadata", "data_sensitivity": xxxx, "dependencies": xxxx, "slo": { "error_rate_threshold": 0.1, "latency_p99_threshold_seconds": 0.02, "availability_target": 0.99999, "metrics_server": "http://prometheus/trackmetadata" }}
manifest.json{ "name": "trackmetadata", "type": "internal_service", "description": "Track Metadata service", "contact_email": "xxxxxxx", "owner": "core-services", "status": "production", "alert_service": "pagerduty.com/xxxx", "telemetry_dashboard": "http://promdash/trackmetadata", "data_sensitivity": xxxx, "dependencies": xxxx, "slo": { "error_rate_threshold": 0.1, "latency_p99_threshold_seconds": 0.02, "availability_target": 0.99999, "metrics_server": "http://prometheus/trackmetadata" }}
manifest.json{ "name": "trackmetadata", "type": "internal_service", "description": "Track Metadata service", "contact_email": "xxxxxxx", "owner": "core-services", "status": "production", "alert_service": "pagerduty.com/xxxx", "telemetry_dashboard": "http://promdash/trackmetadata", "data_sensitivity": xxxx, "dependencies": xxxx, "slo": { "error_rate_threshold": 0.1, "latency_p99_threshold_seconds": 0.02, "availability_target": 0.99999, "metrics_server": "http://prometheus/trackmetadata" }}
manifest.json{ "name": "trackmetadata", "type": "internal_service", "description": "Track Metadata service", "contact_email": "xxxxxxx", "owner": "core-services", "status": "production", "alert_service": "pagerduty.com/xxxx", "telemetry_dashboard": "http://promdash/trackmetadata", "data_sensitivity": xxxx, "dependencies": xxxx, "slo": { "error_rate_threshold": 0.1, "latency_p99_threshold_seconds": 0.02, "availability_target": 0.99999, "metrics_server": "http://prometheus/trackmetadata" }}
RECAP
RECAP
Knowledge sharing
RECAP
Knowledge sharing
Evolving the architecture
RECAP
Knowledge sharing
Evolving the architecture
Monitoring
backstage.soundcloud.com
@pcalcado - How we ended up with microservices
@starcoffe - Why SoundCloud stopped using its own public API
InfoQ - Moving from a Monolith to Microservices at SoundCloud
Netflix API Gateway Pattern
http://techblog.netflix.com/2013/01/optimizing-netflix-api.html
http://samnewman.io/patterns/architectural/bff/
https://www.thoughtworks.com/insights/blog/bff-soundcloud
https://soundcloud.com/jobs
Thank you!
@grandbora