项目简述
- 总体需求:实现一个类Twitter的网站(仅实现网页版)
- 功能列表:
- 帐号系统 (account)
- 个人资料页 (profile)
- 设置 (settings)
- 帮助 (help)
- 主页时间线 (home page, a.k.a., home timeline)
- 帖子 (post)
- 关注者,正在关注 (followers & following)
- 搜索 (search)
- 趋势 – 热门标签 (trending – popular hashtags)
- 热门用户 (popular users)
- 标签页 (搜索页的一种) – hashtags
- 通知 – notification
团队人员配置:
产品:1人,设计:1人,前端:1人,后端:2人
技术架构
参考文章: 支撑10亿用户的技术方案(思路篇)
Twitter架构图

开发实现
- 开发节奏
1. 产品需求细化
对每个功能模块做具体的描述,画出产品的线框图
2. 前后端基础框架选择和制定标准的通讯接口
前后端都有成熟的框架可用,根据团队人员的经验进行选择即可。标准的通讯接口通常包括:1)正常代码和错误代码;2)返回的数据结构; 3)通讯安全策略
3. 数据库结构设计
根据需求文档定义数据库结构。在这个产品需求里,很容易整理出来,需要的数据表如下:user, post, reply, like, user_relationship。更详细的表结构定义在后面。
4. 数据接口(API)设计
有了线框图,就有了页面,根据页面元素,就可以整理出需要的数据,API就能定义出来了。
5. 前端页面实现(根据API,用模拟数据)
6. 后端API实现(常规实现,不包括高并发的方案)
7. 前后端联调
8. 后端支持分库分表,应对高并发
9. 部署方案
10. 功能测试 & 安全测试
11. 高并发测试
- 时间评估
第一周:完成1和2
第二周:完成3和4
第三周~第五周:完成5、6、7
第六~第七周:完成8和9
第八~第十周:完成10和11,通过测试后就可以准备上线了
补充说明:时间的评估,要根据团队成员的经验和能力来,以上评估可以作为参考。由于产品有完全可参考的对象,无需原创;如果再机上团队成员能力很强,并且有丰富的高并发处理经验,以上评估是合理的。
数据库表结构设计
Mysql Database table structures
—
— Table structure for tabletb_user
—
CREATE TABLEtb_user
(id
bigint unsigned NOT NULL AUTO_INCREMENT,username
varchar(15) COLLATE utf8mb4_general_ci NOT NULL,password
varchar(64) COLLATE utf8mb4_general_ci NOT NULL,display_name
varchar(64) COLLATE utf8mb4_general_ci NOT NULL DEFAULT ”,banner_url
varchar(255) COLLATE utf8mb4_general_ci NOT NULL,avatar_url
varchar(255) COLLATE utf8mb4_general_ci NOT NULL,phone
varchar(32) COLLATE utf8mb4_general_ci NOT NULL DEFAULT ”,description
text COLLATE utf8mb4_general_ci NOT NULL,website
varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT ”,language
varchar(8) COLLATE utf8mb4_general_ci NOT NULL DEFAULT ”,time_zone
varchar(8) COLLATE utf8mb4_general_ci NOT NULL DEFAULT ”,location
varchar(16) COLLATE utf8mb4_general_ci NOT NULL DEFAULT ”,verified
tinyint unsigned NOT NULL DEFAULT ‘0’,suspended
tinyint unsigned NOT NULL DEFAULT ‘0’,dob_day
tinyint unsigned NOT NULL DEFAULT ‘0’,is_visible_dob_day
tinyint unsigned NOT NULL DEFAULT ‘0’,dob_month
tinyint unsigned NOT NULL DEFAULT ‘0’,is_visible_dob_month
tinyint unsigned NOT NULL DEFAULT ‘0’,dob_year
smallint unsigned NOT NULL DEFAULT ‘0’,is_visible_dob_year
tinyint unsigned NOT NULL DEFAULT ‘0’,activate_code
varchar(6) COLLATE utf8mb4_general_ci NOT NULL DEFAULT ”,is_activated
tinyint unsigned NOT NULL DEFAULT ‘0’,created_at
bigint NOT NULL DEFAULT ‘0’,updated_at
bigint NOT NULL DEFAULT ‘0’,
PRIMARY KEY (id
),
UNIQUE KEYuiq_username
(username
),
UNIQUE KEYuiq_email
(
) ENGINE=InnoDB AUTO_INCREMENT=1000001 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
—
— Table structure for tabletb_user_extended
—
CREATE TABLEtb_user_extended
(user_id
bigint unsigned NOT NULL,count_followers
int unsigned NOT NULL DEFAULT ‘0’,count_followings
int unsigned NOT NULL DEFAULT ‘0’,count_posts
int unsigned NOT NULL DEFAULT ‘0’,count_likes
int unsigned NOT NULL DEFAULT ‘0’,pinned_post_id
bigint unsigned NOT NULL DEFAULT ‘0’,last_login
bigint NOT NULL DEFAULT ‘0’,timeline_updated_at
bigint NOT NULL DEFAULT ‘0’,created_at
bigint NOT NULL DEFAULT ‘0’,updated_at
bigint NOT NULL DEFAULT ‘0’,
PRIMARY KEY (user_id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
—
— Table structure for tabletb_user_reset
—
CREATE TABLEtb_user_reset
(id
bigint unsigned NOT NULL AUTO_INCREMENT,user_id
bigint unsigned NOT NULL,username
varchar(16) COLLATE utf8mb4_general_ci NOT NULL,reset_code
varchar(64) COLLATE utf8mb4_general_ci NOT NULL,created_at
bigint NOT NULL,updated_at
bigint NOT NULL DEFAULT ‘0’,
PRIMARY KEY (id
),
KEYidx_email
(
KEYidx_username
(username
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
—
— Table structure for tabletb_reserved_username
—
CREATE TABLEtb_reserved_username
(id
bigint unsigned NOT NULL AUTO_INCREMENT,reserved_username
varchar(16) COLLATE utf8mb4_general_ci NOT NULL,notes
text COLLATE utf8mb4_general_ci NOT NULL,created_by
int unsigned NOT NULL,created_at
bigint unsigned NOT NULL,updated_at
bigint unsigned NOT NULL,
PRIMARY KEY (id
),
UNIQUE KEYreserved_username
(reserved_username
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
—
— Table structure for tabletb_post
—
CREATE TABLEtb_post
(id
bigint unsigned NOT NULL AUTO_INCREMENT,user_id
bigint unsigned NOT NULL,post_type
tinyint unsigned NOT NULL COMMENT ‘0: original post; 1: repost; 2: quoted repost; 3: comment (or reply)’,original_type
tinyint DEFAULT ‘0’,original_id
bigint unsigned NOT NULL,content_text
varchar(300) COLLATE utf8mb4_general_ci NOT NULL COMMENT ‘Text content; Max length 280’,image_url
varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT ”,video_url
varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT ”,hashtags
text COLLATE utf8mb4_general_ci NOT NULL,location
varchar(64) COLLATE utf8mb4_general_ci NOT NULL DEFAULT ”,place
varchar(64) COLLATE utf8mb4_general_ci NOT NULL DEFAULT ”,source
tinyint unsigned NOT NULL DEFAULT ‘0’ COMMENT ‘The source label of this post, e.g., iPhone, Android, Web, Default 0’,reply_settings
tinyint unsigned NOT NULL DEFAULT ‘0’ COMMENT ‘Shows you who can reply to a given Tweet. Fields returned are “everyone”, “mentioned_users”, and “followers”. default 0 “reply_settings”: “everyone” ‘,is_deleted
tinyint unsigned NOT NULL DEFAULT ‘0’,created_at
bigint NOT NULL DEFAULT ‘0’,updated_at
bigint NOT NULL DEFAULT ‘0’,deleted_at
bigint NOT NULL DEFAULT ‘0’,
PRIMARY KEY (id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
—
— Table structure for tabletb_post_extended
—
CREATE TABLEtb_post_extended
(post_id
bigint unsigned NOT NULL,user_id
bigint unsigned NOT NULL,count_comments
int unsigned NOT NULL DEFAULT ‘0’,count_likes
int unsigned NOT NULL DEFAULT ‘0’,count_reposts
bigint NOT NULL DEFAULT ‘0’,count_quote
int unsigned NOT NULL DEFAULT ‘0’,count_shares
int unsigned NOT NULL DEFAULT ‘0’,count_reported
bigint NOT NULL DEFAULT ‘0’,is_deleted
tinyint unsigned NOT NULL DEFAULT ‘0’,created_at
bigint NOT NULL DEFAULT ‘0’,updated_at
bigint NOT NULL DEFAULT ‘0’,deleted_at
bigint NOT NULL DEFAULT ‘0’ ,
PRIMARY KEY (post_id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
—
— Table structure for tabletb_post_like
—
CREATE TABLEtb_post_like
(id
bigint unsigned NOT NULL AUTO_INCREMENT,content_type
tinyint DEFAULT ‘0’ COMMENT ‘0 post, 1 reply’,record_id
bigint unsigned NOT NULL,liker_id
bigint unsigned NOT NULL,is_like
tinyint unsigned NOT NULL DEFAULT ‘0’,created_at
bigint unsigned NOT NULL DEFAULT ‘0’,updated_at
bigint unsigned NOT NULL DEFAULT ‘0’,
PRIMARY KEY (id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
—
— Table structure for tabletb_post_reply
—
CREATE TABLEtb_post_reply
(id
bigint unsigned NOT NULL AUTO_INCREMENT,user_id
bigint unsigned NOT NULL,post_id
bigint unsigned NOT NULL,content_text
varchar(300) COLLATE utf8mb4_general_ci NOT NULL COMMENT ‘Text content; Max length 280’,image_url
varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT ”,video_url
varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT ”,hashtags
text COLLATE utf8mb4_general_ci NOT NULL,location
varchar(64) COLLATE utf8mb4_general_ci NOT NULL DEFAULT ”,place
varchar(64) COLLATE utf8mb4_general_ci NOT NULL DEFAULT ”,source
tinyint unsigned NOT NULL DEFAULT ‘0’ COMMENT ‘The source label of this post, e.g., iPhone, Android, Web, Default 0’,is_deleted
tinyint unsigned NOT NULL DEFAULT ‘0’,created_at
bigint NOT NULL DEFAULT ‘0’,deleted_at
bigint NOT NULL DEFAULT ‘0’,
PRIMARY KEY (id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
—
— Table structure for tabletb_post_reply_extended
—
CREATE TABLEtb_post_reply_extended
(post_reply_id
bigint unsigned NOT NULL,user_id
bigint unsigned NOT NULL,post_id
bigint unsigned NOT NULL,count_comments
int unsigned NOT NULL DEFAULT ‘0’,count_likes
int unsigned NOT NULL DEFAULT ‘0’,count_reposts
bigint NOT NULL DEFAULT ‘0’,count_quote
int unsigned NOT NULL DEFAULT ‘0’,count_shares
int unsigned NOT NULL DEFAULT ‘0’,count_reported
bigint NOT NULL DEFAULT ‘0’,is_deleted
tinyint unsigned NOT NULL DEFAULT ‘0’,created_at
bigint NOT NULL DEFAULT ‘0’,updated_at
bigint NOT NULL DEFAULT ‘0’,deleted_at
bigint NOT NULL DEFAULT ‘0’,
PRIMARY KEY (post_reply_id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
—
— Table structure for tabletb_post_reply_hashtag
—
CREATE TABLEtb_post_reply_hashtag
(id
bigint unsigned NOT NULL AUTO_INCREMENT,content_type
tinyint DEFAULT NULL COMMENT ‘0 post, 1 reply’,record_id
bigint unsigned NOT NULL,hashtag_id
bigint unsigned NOT NULL,created_at
bigint NOT NULL DEFAULT ‘0’,updated_at
bigint NOT NULL DEFAULT ‘0’,
PRIMARY KEY (id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
—
— Table structure for tabletb_recommended_hashtag
—
CREATE TABLEtb_recommended_hashtag
(id
int NOT NULL AUTO_INCREMENT,hashtag_id
int NOT NULL,rank
int NOT NULL DEFAULT ‘0’,created_at
bigint unsigned DEFAULT ‘0’,
PRIMARY KEY (id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
—
— Table structure for tabletb_recommended_user
—
CREATE TABLEtb_recommended_user
(id
int NOT NULL AUTO_INCREMENT,user_id
bigint unsigned DEFAULT NULL,rank
int DEFAULT ‘0’,created_at
bigint unsigned DEFAULT ‘0’,
PRIMARY KEY (id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
—
— Table structure for tabletb_reported_content
—
CREATE TABLEtb_reported_content
(id
bigint unsigned NOT NULL AUTO_INCREMENT,content_type
tinyint DEFAULT ‘0’ COMMENT ‘0 post, 1 reply’,record_id
bigint unsigned NOT NULL,post_user_id
bigint unsigned NOT NULL,reporter_id
bigint unsigned NOT NULL,report_reason
tinyint unsigned NOT NULL,created_at
bigint NOT NULL DEFAULT ‘0’,updated_at
bigint NOT NULL DEFAULT ‘0’,
PRIMARY KEY (id
),
KEYidx_post_id
(record_id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
—
— Table structure for tabletb_reported_user
—
CREATE TABLEtb_reported_user
(id
bigint unsigned NOT NULL AUTO_INCREMENT,user_id
bigint unsigned NOT NULL,reporter_id
bigint unsigned NOT NULL,report_reason
tinyint unsigned NOT NULL,created_at
bigint unsigned NOT NULL DEFAULT ‘0’,updated_at
bigint unsigned NOT NULL DEFAULT ‘0’,
PRIMARY KEY (id
),
KEYidx_user_id_reporter_id
(user_id
,reporter_id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
—
— Table structure for tabletb_user_relationship
—
CREATE TABLEtb_user_relationship
(id
bigint unsigned NOT NULL AUTO_INCREMENT,user_id
bigint unsigned NOT NULL,target_user
bigint unsigned NOT NULL,status_follow
tinyint unsigned NOT NULL DEFAULT ‘0’ COMMENT ‘0: unfollow; 1: follow; 2: block’,status_mute
tinyint unsigned NOT NULL DEFAULT ‘0’ COMMENT ‘0: unmute; 1: mute’,created_at
bigint NOT NULL DEFAULT ‘0’,updated_at
bigint NOT NULL DEFAULT ‘0’,
PRIMARY KEY (id
),
UNIQUE KEYuiq_user_id_follwer_id
(user_id
,target_user
),
KEYidx_follower_id
(target_user
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
—
— Table structure for tabletb_user_relationship_reversed
—
CREATE TABLEtb_user_relationship_reversed
(id
bigint NOT NULL AUTO_INCREMENT,user_id
bigint DEFAULT NULL,follower_id
bigint DEFAULT NULL,created_at
bigint DEFAULT NULL,
PRIMARY KEY (id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
—
— Table structure for tabletb_hashtag
—
CREATE TABLEtb_hashtag
(id
bigint unsigned NOT NULL AUTO_INCREMENT,tag_name
varchar(128) COLLATE utf8mb4_general_ci NOT NULL,user_id
bigint unsigned NOT NULL,count_mentions
int unsigned NOT NULL DEFAULT ‘0’,created_at
bigint NOT NULL DEFAULT ‘0’,updated_at
bigint NOT NULL DEFAULT ‘0’,
PRIMARY KEY (id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
—
— Table structure for tabletb_parsed_url
—
CREATE TABLEtb_parsed_url
(id
bigint NOT NULL AUTO_INCREMENT,url
varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,title
varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,description
varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,created_at
bigint DEFAULT NULL,updated_at
bigint DEFAULT NULL,
PRIMARY KEY (id
),
UNIQUE KEYid_UNIQUE
(id
),
UNIQUE KEYurl_UNIQUE
(url
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
API设计
基本约定:
1.获取数据用get,提交数据用post
2.返回的数据格式:{“code”: 0, “message”:”ok”, “data”:{} }, 成功的时候code为0,否则为非0
Account部分
1.创建账户 account/create
Method:POST
Params:
{“username”:”yourname”, “email”:”you@email.com”,”password”:”yourpwd”}
Response:
{
“code”: 0,
“data”: {
“activeCode”: “147849”,
“avatarUrl”: “”,
“bannerUrl”: “”,
“countFollowers”: “0”,
“countFollowings”: “0”,
“countLikes”: “0”,
“countPosts”: “0”,
“createdAt”: “1624266544”,
“description”: “”,
“displayName”: “”,
“dobDay”: “0”,
“dobMonth”: “0”,
“dobYear”: “0”,
“email”: “youremail@gmail.com”,
“iD”: “100000003”,
“isActived”: “0”,
“isVisibleDobDay”: “0”,
“isVisibleDobMonth”: “0”,
“isVisibleDobYear”: “0”,
“language”: “”,
“lastLogin”: “0”,
“location”: “”,
“password”: “123456”,
“phone”: “”,
“pinnedPostId”: “0”,
“suspended”: “0”,
“timeZone”: “”,
“updatedAt”: “1624266544”,
“username”: “myname”,
“verified”: “0”,
“website”: “”
},
“message”: “ok”
}
2.激活账户 account/activate (通过email里面的链接进行激活)
Method:POST
Params:
{“username”:”yourname”, “activate_code”:”toatciveyouraction”}
Response:
{
“code”: 0,
“data”: null,
“message”: “ok”
}
3.发送重置密码代码 account/send_reset_code
Method:POST
Params:
{“email”:”you@email.com”}
Response:
{
“code”: 0,
“data”: null,
“message”: “ok”
}
校验代码: account/verify_code
Method:POST
Params:
{“email”:”youremail@google.com”,”code”:”resetcode123″}
重置密码: account/reset_password
Method:POST
Params:
{“email”:”youremail@google.com”, “reset_code”:”restcode123″,”password”}
Response:
{
“code”: 0,
“data”: null,
“message”: “ok”
}
User 部分
1.用户登陆 user/login
Method:POST
Params:
{“name”:”yourname”,”password”:”yourpwd”}
Notes: name是username或者email
Response:
{
“code”: 0,
“data”: {
“token”: “eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MjQ4NzA4MDAsImp0aSI6IjEwMDAwMDAwMyIsImlhdCI6MTYyNDI2NjAwMCwibmJmIjoxNjI0MjY2MDAwfQ.Hs2LTfG47Q1IDOhr9lY15usqyDPP1r7wKLk3l9nd4LQ”
},
“message”: “ok”
}
2.用户登出 user/logout(前端直接清理token)
Method:POST
3.修改语言 user/change_language
Method:POST
Params: {“language”:”en”}
Notes: 参数的值是options(目前只有en,zh),不能随意填写
Response:
{
“code”: 0,
“data”: {},
“message”: “ok”
}
4.修改密码 user/change_password
Method:POST
Params: {“password”:”newpasswd”,”old_password”:”oldpasswd”}
Notes: 密码有要求,最少8位,最少包含字母和数字
Response:
{
“code”: 0,
“data”: {},
“message”: “ok”
}
5.修改其它信息 user/save_info
Method:POST
Params:
{
“display_name”: “name1”,
“banner_url”: “”,
“avatar_url”: “”,
“location”: “bg”,
“website”: “http://www.mysite.com”,
“dob_year”: “2001”,
“dob_month”: “12”,
“dob_day”: “12”
}
Response:
{
“code”: 0,
“data”: {},
“message”: “ok”
}
6.查看用户页面(该页面有3个tab,所以一起有4个api)
6.1 user/profile
Method:GET
Params: {“username”:”yourname”}
Response:
{
“code”: 0,
“data”: {
“avatarUrl”: “”,
“bannelUrl”: “”,
“countFollowers”: “0”,
“countFollowings”: “0”,
“createdAt”: “1624266544”,
“description”: “”,
“displayName”: “name1”,
“dobDay”: “12”,
“dobMonth”: “12”,
“dobYear”: “2001”,
“email”: “youremail@gmail.com”,
“id”: “100000003”,
“isVisibleDobDay”: “0”,
“isVisibleDobMonth”: “0”,
“isVisibleDobYear”: “0”
},
“message”: “ok”
}
6.2 user/posts
Params: {“username”:”yourname”, “cursor”:101}
Notes: cursor初始不传,每次返回的结果中会带上新的cursor,下次请求的时候用这个值即可(后续所有的cursor都是一样的逻辑)
如果没有新的内容可加载,cursor会返回 -1
6.3 user/replies
Params: {“username”:”yourname”, “cursor”:101}
6.4 user/likes
Params: {“username”:”yourname”, “cursor”:101}
7.查看用户关注的人 user/following
Method:GET
Params: {“username”:”yourname”, “cursor”:101}
Response:
{
“code”: 0,
“data”: {
“cursor”: “0”,
“users”: [
{
“avatarUrl”: “”,
“description”: “”,
“displayName”: “”,
“id”: “100000001”
},
{
“avatarUrl”: “”,
“description”: “”,
“displayName”: “”,
“id”: “100000002”
},
{
“avatarUrl”: “”,
“description”: “”,
“displayName”: “name1”,
“id”: “100000003”
}
]
},
“message”: “ok”
}
8.查看关注该用户的人 user/followers
Method:GET
Params: {“username”:”yourname”,”cursor”:101}
用户部分2(在他人页面操作,登陆后可操作)
Response:
{
“code”: 0,
“data”: {
“cursor”: “0”,
“users”: [
{
“avatarUrl”: “”,
“description”: “”,
“displayName”: “”,
“id”: “100000001”
},
{
“avatarUrl”: “”,
“description”: “”,
“displayName”: “”,
“id”: “100000002”
},
{
“avatarUrl”: “”,
“description”: “”,
“displayName”: “name1”,
“id”: “100000003”
}
]
},
“message”: “ok”
}
——– 以下API需要用户登陆认证 ———
9.查看自己block的用户 user/blocked
Method:GET
Params: {“cursor”:101}
10.查看自己mute的用户 user/muted
Method:GET
Params: {“cursor”:101}
11.follow某个用户 user/follow
Method:POST
Params: {“target_username”:”tusername”, “flag”:1}
Notes: flag1表示follow, 0表示unfollow
database operation:在tb_user_relationship增加或者修改记录,具体参看表的定义
Response:
{
“code”: 0,
“data”: null,
“message”: “ok”
}
12.block某个用户 user/block
Method:POST
Params: {“target_username”:”tusername”, “flag”:1}
Notes: flag 1表示block, 0表示unblock
database operation:在tb_user_relationship增加或者修改记录,具体参看表的定义
Response:
{
“code”: 0,
“data”: null,
“message”: “ok”
}
13.mute某个用户 user/mute
Method:POST
Params: {“target_username”:”tusername”, “flag”:1}
Notes: flag1表示mute, 0表示unmute
database operation:在tb_user_relationship增加或者修改记录,具体参看表的定义
Response:
{
“code”: 0,
“data”: null,
“message”: “ok”
}
14.report某个用户 user/report
Method:POST
Params: {“target_username”:”tusername”, “report_reason”:1}
database operation: 在tb_reported_user表里增加记录
Response:
{
“code”: 0,
“data”: null,
“message”: “ok”
}
15.获取上传图片签名地址:upload/sign_image
Method: GET
Params: {“ext”:”jpg”} jpg|png|jpeg|gif
Response:
{
“code”: 0,
“data”: {
“url”: “https://twitter6-dev-bucket.s3.ap-northeast-1.amazonaws.com/images/20210622/cca1yk47jcsg92508.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIATWAJJDEPJQWRB524%2F20210622%2Fap-northeast-1%2Fs3%2Faws4_request&X-Amz-Date=20210622T095116Z&X-Amz-Expires=1800&X-Amz-SignedHeaders=host&X-Amz-Signature=fb349171cd2d3cb5e49b711d9bf1950bba154081ad55534a3fcada33fcd0700a”
},
“message”: “ok”
}
16.获取上传视频签名地址:upload/sign_video
Method: GET
Params: {“ext”:”mp4″}
Response:
{
“code”: 0,
“data”: {
“url”: “https://twitter6-dev-bucket.s3.ap-northeast-1.amazonaws.com/videos/20210622/cca1yk47jcsg92508.mp4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIATWAJJDEPJQWRB524%2F20210622%2Fap-northeast-1%2Fs3%2Faws4_request&X-Amz-Date=20210622T095116Z&X-Amz-Expires=1800&X-Amz-SignedHeaders=host&X-Amz-Signature=fb349171cd2d3cb5e49b711d9bf1950bba154081ad55534a3fcada33fcd0700a”
},
“message”: “ok”
}
Post部分
1.发布推特 post/create
Method:POST
Params: {“content_text”:”text”, “media”: “image or video”}
Response:
{
“code”: 0,
“data”: {id: “a”},
“message”: “ok”
}
2.回复推特 post/reply
Method:POST
Params: {“content_text”:”text”, “media”: “image or video”,”original_post_id”:11122,”usename”:”namename”}
Response:
{
“code”: 0,
“data”: {id: “a”},
“message”: “ok”
}
3.转发推特
3.1 post/repost
Method:POST
Params: {“original_post_id”:11122, “usename”:”namename”,”content_text”:”repost content”}
Notes: 转推的时候也可以补充内容,原贴的repost数量要+1
Response:
{
“code”: 0,
“data”: {id: “a”},
“message”: “ok”
}
3.2 post/undo_repost 取消转推
Method:POST
Params: {“post_id”:11122}
Notes:这个记录可以直接删除了,另外原贴的repost数量要-1
4.点赞推特/取消点赞 post/like
Method:POST
Params: {“islike”:”1″,”post_id”:11122, “usename”:”namename”}
Notes: islike 1表示点赞,0表示取消点赞
Response:
{
“code”: 0,
“data”: null,
“message”: “ok”
}
5.举报推特 post/report
Method:POST
Params: {“post_id”:123123, “usename”:”namename”,”report_reason”:1}
database operation: 在tb_reported_post表里增加记录
Response:
{
“code”: 0,
“data”: null,
“message”: “ok”
}
6.推特详情
6.1 post/detail
Method: GET
Params: {“post_id”:123456, “usename”:”namename”}
Response:
{
“code”: 0,
“data”: {
“contentText”: “us is sb”,
“countComments”: “2”,
“countLikes”: “1”,
“countRepots”: “1”,
“id”: “b”,
“imageUrl”: “”,
“originalPostId”: “0”,
“userId”: “100000003”,
“videoUrl”: “”
},
“message”: “ok”
}
6.2 post/replies
Method: GET
Params: {“post_id”:123456, “usename”:”namename”,”cursor”:101}
Response:
7.删除推特 post/delete
Method: POST
Params: {“post_id”:123456}
database operation:把tb_post对应的记录is_deleted设置为1,并设置deleted_at
Response:
{
“code”: 0,
“data”: null,
“message”: “ok”
}
8.内容置顶 post/pin
Method: POST
Params: {“post_id”:123456, “ispin”:1}
Notes: ispin 1表示置顶,0表示取消置顶,默认是1
database operation:设置tb_user对应的记录pinned_post_id
Response:
{
“code”: 0,
“data”: {},
“message”: “ok”
}
数据表和API设计的细节
- 分库分表策略:设计了tb_user_relationship和tb_user_relationship_reversed两个表,都按照user_id进行分库分表,这样不管是获取follower list还是following list,都是一次查询即可查到。
- 数据归档策略:由于Twitter访问最多的是最新几天的post数据,可以对post按照一定的时间(如:一个月或者一周)进行归档,这样可以保证最新的post表数据不会过大。
- 对于查询的优化:考虑数据的更新频率,把不会更新的数据放在一个表(如:tb_post),充分利用缓存;把经常更新的数据放在另外一个表(如:tb_post_extended),经常更新的字段是定长字段,mysql的查询性能也会非常高。
- 体验上的优化:API设计的时候,把获取帖子内容和帖子统计数据(评论数、点赞数)也分开了。前端先获取帖子的内容,并立即显示给用户;然后再异步请求统计数据。这样还可以做到定时更新列表的统计数据,特别是大V可以不用刷新页面,也能看到点赞数和评论数在增加,获得良好的用户体验感。
- Timeline处理细节:1.在cache中存放timeline的post id list,每次直接从cache中获取;2.用户如果是登陆后进入首页,登陆后异步生成timeline(生成时间小于3s),然后进入首页后再请求timeline,就可以直接从缓存获取到;3.用户如果已经是登陆状态,打开首页,前端从浏览器缓存中获取老的timeline数据先进行显示,同时异步请求timeline进行刷新。4.对于重要的用户,发了推之后,利用kafka的异步机制,主动刷新在线的关注者的timeline,以方便重要的post可以第一时间发出。