Requirements of Tinder
A design can start from either end. Starting from the ER diagram models the data first, then the services, then the clients. This order is too constrained and too abstract, because the data is modelled before anyone asks what users need.
The second approach goes from front to back: the features users need, then the services that fulfil them, then the data each service requires. The system is more flexible and easier to start.
Four features are picked for Tinder, each with one question:
- Storing profiles. A profile holds images, five images per user.
- Recommending matches. The question is the number of active users.
- Noting matches. The number of matches is taken as a share of active users. The assumption is that a swipe matches 0.1% of the time.
- Direct messaging, once two people have matched.
Too many questions about one feature means too much detail too early. Four features are enough for an interview of at most an hour, since the interviewer steers toward the details that matter.
Image Storage: Files vs. Database BLOB
An image is stored either as a file or as a BLOB, a binary large object in a database.
A database gives four extra guarantees, and an image needs none of them:
- Mutability. An update to an image is the entire image, so it is stored as a separate, immutable file.
- Transaction guarantees. There is no atomic operation on an image.
- Indexes. They improve search, and the content of an image is ones and zeros.
- Access control. A secure file system gives the same mechanisms and is almost as tedious to set up as a secure database.
A file is cheaper. It is faster, because large objects are stored separately, which a database does only through vertical partitioning. It is not pulled in by a select star. It is static, so a CDN is built over it for fast access.
The database stores the reference: the image ID, the image URL and the profile ID. The file itself sits in a distributed file system.
Profile Creation and Authentication
Profile creation registers a user with the profile service, and authentication checks that each later request comes from the user it claims.
The client on the mobile sends a username and password to the profile service, which stores them in the database.
An update profile request then has to be authenticated:
- The monolithic way: the profile service authenticates the username and password itself. This way is insecure, so the client sends a token.
- A new service has no information about tokens and usernames, so it talks to the profile service on every request, and that code is duplicated in each service that comes up.
- A gateway fixes this. Clients talk only to the gateway. It asks the profile service whether the request is authenticated, redirects it to the correct service on a yes, fails it on a no, and forwards the response.
Images go to a separate image service. It stores them in a distributed file system, and keeps the profile ID, the image ID and the URL of each image in a database.
One to One chat messaging
One to one chat sends a direct message from one client to another through the gateway, over a connection the server pushes on.
After a match, the client tells the gateway: message to user ID 1 from user ID 2.
- HTTP is a client server protocol. The client talks and the server responds, so the receiver has to poll the server every five seconds for messages, which is extremely inefficient.
- The fix is a peer-to-peer protocol, where both machines are equal and the server pushes messages to the client. XMPP is one.
- XMPP takes a WebSocket connection. A custom protocol over TCP also works, because the connection is made and maintained.
- Each user listens on one of the connections on the gateway service. To decouple the system, a sessions service stores which user ID is on which connection.
To deliver a message, the sessions service finds the connection the other user is using, and the message is sent to that socket.
Matching right-swiped users
A match is noted on the server by a matcher service, and the swipes are kept on the client.
The client is an app and stores information. If it stored the matches and the app was uninstalled, they would be lost, so the server is the source of truth.
A match is sent to the server. A matcher service keeps a table of user ID to user ID, with an index on the user ID. The records are duplicated: A matched with B, and B matched with A.
A direct message then takes a longer path:
- The message goes to the matcher, which confirms that the two users are matched.
- The matcher sends it to the sessions service, which finds the connection to use.
- The message is sent on that connection.
When the app is reinstalled, it pulls the matches from the matcher. The only information lost is who was swiped left or right, which lives on the phone. The loss is not critical: the same people are recommended again.
Serving recommendations to users
A recommendation is a set of users chosen by age, gender and location, and the core of it is finding which users are close.
The profile service stores the age, the gender and the location. Indexes on all three do not work: a table is sorted in one way, so a query uses only one of those indexes, and the query optimizer picks which.
- A distributed NoSQL database such as Cassandra or Amazon Dynamo, which replicates the data and builds a table for each query.
- Sharding on a relational database, also called horizontal partitioning. Ranges in one column direct the data to a node: names from A to J go to database node 36, and K to P to node 79. A master-slave architecture removes the single point of failure.
The data is sharded by location, in chunks of a city. All the users within a chunk are pulled out of one node, queried on the sorted age, and filtered by gender.
A recommendation service stores the user IDs and their current locations, updated every hour.