Scaling Uber with Node.js
Amos Barreto @amos_barreto
Scaling Uber with Node.js Amos Barreto @amos_barreto Uber is - - PowerPoint PPT Presentation
Scaling Uber with Node.js Amos Barreto @amos_barreto Uber is everyones Private driver. REQUEST RIDE RATE Tap to select location Sit back and relax, tell your Help us maintain a quality service driver your destination by
Scaling Uber with Node.js
Amos Barreto @amos_barreto
REQUEST
Tap to select location
RIDE
Sit back and relax, tell your driver your destination
RATE
Help us maintain a quality service by rating your experience
Uber is everyone’s Private driver.
4
19
Your Drivers
UBER QUALIFIED
Uber only partners with drivers who have a keen eye for customer service and a passion for the trade.
RIDER RATED
Tell us what you think. Your feedback helps us work with drivers to constantly improve the Uber experience.
LICENSED & INSURED
From insurance to background checks, every driver meets or beats local regulations.
4
22
22
UberChopper
22
22
6
Trip State Machine (Simplified)
Request Dispatch Accept Arrive Begin End
6
Trip State Machine (Extended)
Request Dispatch (1) Expire / Reject Arrive Begin End Dispatch (2) Accept
4
6
PHP Cron
contractors in Midwest
Version 1
33
“I read an article on HackerNews about a new framework called Node.js”
Tradeoffs
Node.js
with 0.4
Version 2
33
“I really don’t see dispatch changing much in the next three years”
15
Expect the unexpected
SF
volume of GPS logs (global write lock)
and flat files
Version 3
NYC SEA CHI CN CN CN CN
Decoupling storage of different types of data
SF
to recognize replica set topology changes
Version 3 (continued)
NYC SEA CHI CN CN CN CN
Be wary of immature client libraries
Commits to client modules over time
SF
Version 3 (continued)
NYC SEA CHI BOS PAR
15
Focus on driving business value
15
15
15
Capacity planning, forecasting, and load testing are your friends
15
Measure everything
SF
source of truth
atomic operations
find nearby cars
Version 4
NYC SEA CHI CN CN CN SF SF NYC CHI CHI
15
clientStatus = redis.call('hget', clientHash, ‘status’) driverStatus = redis.call('hget', driverHash, ‘status’) if clientStatus == 'WaitingForPickup' and driverStatus == 'Open' then local clientPeerId = redis.call('hget', clientAssignmentHash, clientToken) redis.call('hset', driverHash, 'status', 'DispatchPending') redis.call('hset', clientAssignmentHash, clientToken, driverPeerId) if clientPeerId then redis.call('zincrby', countKey, -1, clientPeerId) end redis.call('zincrby', countKey, 1, driverPeerId) return redis.status_reply('SUCCESS') else return redis.error_reply('ERROR - clientStatus: '..tostring(clientStatus)..', driverStatus: '..tostring(driverStatus)) end
15
clientStatus = redis.call('hget', clientHash, ‘status’) driverStatus = redis.call('hget', driverHash, ‘status’) if clientStatus == 'WaitingForPickup' and driverStatus == 'Open' then local clientPeerId = redis.call('hget', clientAssignmentHash, clientToken) redis.call('hset', driverHash, 'status', 'DispatchPending') redis.call('hset', clientAssignmentHash, clientToken, driverPeerId) if clientPeerId then redis.call('zincrby', countKey, -1, clientPeerId) end redis.call('zincrby', countKey, 1, driverPeerId) return redis.status_reply('SUCCESS') else return redis.error_reply('ERROR - clientStatus: '..tostring(clientStatus)..', driverStatus: '..tostring(driverStatus)) end
15
clientStatus = redis.call('hget', clientHash, ‘status’) driverStatus = redis.call('hget', driverHash, ‘status’) if clientStatus == 'WaitingForPickup' and driverStatus == 'Open' then local clientPeerId = redis.call('hget', clientAssignmentHash, clientToken) redis.call('hset', driverHash, 'status', 'DispatchPending') redis.call('hset', clientAssignmentHash, clientToken, driverPeerId) if clientPeerId then redis.call('zincrby', countKey, -1, clientPeerId) end redis.call('zincrby', countKey, 1, driverPeerId) return redis.status_reply('SUCCESS') else return redis.error_reply('ERROR - clientStatus: '..tostring(clientStatus)..', driverStatus: '..tostring(driverStatus)) end
15
clientStatus = redis.call('hget', clientHash, ‘status’) driverStatus = redis.call('hget', driverHash, ‘status’) if clientStatus == 'WaitingForPickup' and driverStatus == 'Open' then local clientPeerId = redis.call('hget', clientAssignmentHash, clientToken) redis.call('hset', driverHash, 'status', 'DispatchPending') redis.call('hset', clientAssignmentHash, clientToken, driverPeerId) if clientPeerId then redis.call('zincrby', countKey, -1, clientPeerId) end redis.call('zincrby', countKey, 1, driverPeerId) return redis.status_reply('SUCCESS') else return redis.error_reply('ERROR - clientStatus: '..tostring(clientStatus)..', driverStatus: '..tostring(driverStatus)) end
SF1
Version 4 (continued)
SF3 SF2
SEA1
NY1 NY3 NY2 NY4
SEA2 SEA3 SEA4 CHI1 CHI2 CHI3
BOS1 BOS2
PAR1
Version 5
SF SF SF SF SF SF SF SF SF
Version 5
max # of loc queries # of nodes
SF
Version 5
NYC SEA CHI CN CN CN SF SF NYC CHI CHI ncar ncar ncar ncar
15
Break out services as needed
15
Understand v8 to optimize Node.js applications
SF1 SF3 SF2
SEA1
NY1 NY3 NY2 NY4
SEA2 SEA3 SEA4 CHI1 CHI2 CHI3
BOS1 BOS2
PAR1
Don’t take vacation ;)
15
Don’t live in Chicago!
15
Stateless applications… No single points of failure… Replicated data stores… Dynamic application topology…
SF1
Version 6
SF3 SF2
SEA1
NY1 NY3 NY2 NY4
SEA2 SEA3 SEA4 CHI1 CHI2 CHI3
BOS1 BOS2
PAR1
Grid Manager Grid Manager Grid Manager
Version 7
haproxy
15
Do the obvious
Pros
Never be satisfied
Cons
4
World Class
15
Every now and then it’s okay to bend the rules
Realtime Analytics
Realtime Analytics
So why did we stick with Node.js?
How to win with Node.js?
34
The Human Factor
Thank you. Questions?