nanoTwitter is a toy-mimic of the popular social service twitter, developed by 4 students at Brandeis University as a course project from Software Engineering for Scalability.
This is a free software under MIT license
Project website is accessible here: http://keighrim.github.io/cs105_nT/
Running instance of nanoTwitter is on Heroku: https://afternoon-peak-6349.herokuapp.com/
/
:- Homepage with 50 latest tweets from all users.
- When the user is logged in, it redirects to his/her own profile page. (
/profile/:username
)
/timeline
:- Redirects to the homepage. (
/
)
- Redirects to the homepage. (
/explorer
:- Follow suggestion page with randomly picked users and the most recent tweets.
/profile
:- When the user is logged in, it redirects to his/her profile page. (
profile/:username
). - If not, it does to the homepage. (
/
)
- When the user is logged in, it redirects to his/her profile page. (
/profile/:username
:- By default, it will show the timeline of the target. (50 latest tweets from the target and those he/she follows)
- It has links to tweeting history and relations of the target.
- HIstory and relations pages can also be acceessed using
m
parameter in URL,h
for history page,n
for network page.
Caching was handled using a redis instance hosted on the redis cloud service. This is linked through our Heroku instance.
The query to generate a users timeline (the list of tweets of all of the users that this user follows, ordered by tweet time) is the most expensive operation, so we'd focused on tackle this problem to improve scalability. The first time that a user requests their timeline, very expensive SQL operation happens, Then this will be cached in the redis instance as a list of JSON objects representing each tweet object. Future requests for the timeline will then get the list of tweets, stored as JSON, from redis. Then we advanced to use two-tier caching, adding an outer layer to cache HTML strings, to make timeline generation even faster by reducing cost of translating JSON's and rendering HTML strings. Outer level, HTML cache, expires very soon (in a few seconds) because we thought having users looking at outdated cached web pages for a long period is a bad idea. However, the deeper layer, JSON cache, stays longer (30 seconds). And only when the instance in inner layer expires, the app performs SQL call to get the most recent updates upon a user's request. In this way we can lazily generate timelines on user requests, not eagerly on every event of creating/deleting tweets. If one user follows or unfollows another user, the timeline is invalid, and must be rebuild. We invalidate redis caching by deleting relevant instances.
The home timeline, or the list of the 50 most recent tweets shown on the homepage of a non-logged in user, is stored in redis with the same two-tier strategy as individual timelines.
To set up load test scenarios, we provide a series of /test
routes.
/test/reset/all
- Delete everything and recreate testuser/test/status
- See the current state of server/test/seed/_u_
- create “u” new users/test/tweets/_t_
- have testuser tweet “t” times/test/follow/_f_
- have f users follow testuser
Also, for batch setup we have shell scripts in scripts
directory in the project.
$ ./scripts/loadtest_evn.sh
usage: loadtest_env.sh <#users> <#tweets> <#followers> (optional) <base-url>
e.g.: loadtest_env.sh 100 500 30 http://localhost:4567
For sake of convenience, we also have three wrapping scripts for three presets from the project specification: loadtest_evn1.sh
(100 500 30), loadtest_evn3.sh
(500 500 100), loadtest_evn3.sh
(3000 2000 1000).
- / - user tries to simply load up the home page (non-logged in)
Run 1:
0 - 250 clients over 1 min
1070 ms avg resp
0.0 % err rate
0 Timeouts
Run 2:
0 - 500 clients over 1min
1690 ms avg resp
0.2 % err rate
0 Timouts
Run 3:
0 - 1000 clients over 1min
2291 ms avg resp
0.1 % err rate
0 Timeouts
Run 4:
0 - 2000 clients over 1min
4337 ms avg resp
0.1 % err rate
0 Timeouts
Run 5:
0 - 4000 clients over 1min
Crashed at 00:54 with 3604 clients
2412 ms avg resp
71.9 % err rate
3311 Timeouts
- /user/testuser - specifically load “testusers” home page
Run 1:
0 - 1000 clients over 1 min
6908 ms avg resp
0.0 % err rate
0 Timeouts
Run 2:
0 - 2000 clients over 1 min
6970 ms avg resp
0.0 % err rate
0 Timeout
Run 3:
0 - 4000 clients over 1 min
Crashed at 00:54 with 3604 clients
4425 ms avg resp
79.0 % err rate
3485 Timeout
- /user/testuser/tweet (POST) - have testuser create one tweet
Run 1:
2000 clients over 1 min
236 ms avg resp
0.0 % err rate
0 Timeout
Run 2:
4000 clients over 1 min
1316 ms avg resp
0.0 % err rate
0 Timeout
Run 3:
8000 clients over 1 min
Crashed at 00:38
11311 ms avg resp
54.4 % err rate
1972 Timeout
as of 11/22/2015
- Description: Returns a tweet based on its ID.
- Resource URL: https://localhost:4567/api/v1/tweets?id
- Resource Information
- Response formats: JSON
- Requires authentication?: No
- Parameters
- id (required): The tweet id of the specific tweet to return.
GET https://localhost:4567/api/v1/tweets?id=123
{
"id": 123,
"content": "foo",
"user_id": 456,
"user_name": "bar",
"created": "jan-11-2015"
}
- Description: Creates a new tweet and returns it.
- Resource URL: https://localhost:4567/api/v1/tweets?user_id
- Resource Information
- Response formats: JSON
- Requires authentication?: No
- Parameters
- user_id (required): The user id to be designated as the creator of the tweet.
- text (optional): The text of the tweet. Defaults to random Faker string.
POST https://localhost:4567/api/v1/tweets?user_id=123&text=sample
{
"id": 101,
"text": "sample",
"creator_id": 123,
"created": "jan-11-2015"
}
- Description: Retrieve n latest tweets from all users.
- Resource URL: https://localhost:4567/api/v1/tweets/recent
- Resource Information
- Response formats: JSON
- Requires authentication?: No
- Parameters
- num (optional): Returns num recent tweets. Defaults to 10. Max of 50.
GET https://localhost:4567/api/v1/tweets/recent?num=2
[
{
"id": 1,
"text": "foobar",
"creator_id": 456,
"created": "jan-11-2015"
},
{
"id": 2,
"text": "foobar",
"creator_id": 789,
"created": "jan-12-2015"
}
]
- Description: Returns information of a user based on a ID.
- Resource URL: https://localhost:4567/api/v1/users?id
- Resource Information
- Response formats: JSON
- Requires authentication?: No
- Parameters
- id (required): The user id of the user whose information is to be returned.
GET https://localhost:4567/api/v1/users?id=123
{
"id": 123,
"name": "John Doe"
}
- Description: Creates a new account and returns it.
- Resource URL: https://localhost:4567/api/v1/users?name
- Resource Information
- Response formats: JSON
- Requires authentication?: No
- Parameters
- name (required): The name of the user to create.
- email (required): The e-mail address of the user to create.
POST https://localhost:4567/api/v1/users?name=John+Doe
{
"id": 101,
"name": "John Doe"
}
- Description: Updates user information and returns it. Changing password using this is not allowed.
- Resource URL: https://localhost:4567/api/v1/users?id
- Resource Information
- Response formats: JSON
- Requires authentication?: No
- Parameters
- id (required): The id of the user to update.
- name (optional): The new name of the user.
- email (optional): The new email address of the user.
PUT https://localhost:4567/api/v1/users?id=101&name=Jane+Doe
{
"id": 101,
"name": "Jane Doe"
}
- Description: Retrieve n latest tweets from a specifin user.
- Resource URL: https://localhost:4567/api/v1/users/:user_id/tweets
- Resource Information
- Response formats: JSON
- Requires authentication?: No
- Parameters
- user_id (required): The user id of the specific user whose tweets will be returned
- num (optional): The number of recent tweets for this user to return. Defaults to 10. Max of 50.
GET https://localhost:4567/api/v1/users/123/tweets?num=2
[
{
"id": 1,
"text": "foobar",
"creator_id": 456,
"created": "jan-11-2015"
},
{
"id": 2,
"text": "foobar",
"creator_id": 456,
"created": "jan-12-2015"
}
]
- Description: Return all followers of a user.
- Resource URL: https://localhost:4567/api/v1/users/:user_id/followers
- Resource Information
- Response formats: JSON
- Requires authentication?: No
- Parameters
- user_id (required): The user id of the specific user whose followers will be returned
GET https://localhost:4567/api/v1/users/123/followers
[
{
"id": 124,
"name": "Some Person"
},
{
"id": 125,
"name": "Other Person"
},
]