CREATE TABLE weibo
( id
bigint(20) NOT NULL AUTO_INCREMENT, account_id
bigint(20) NOT NULL, photos_bin
blob, msg_content
varchar(2048) DEFAULT NULL, srv_timestamp
bigint(20) NOT NULL, msg_datetime
datetime(6) NOT NULL, thumbup_times
int(10) NOT NULL DEFAULT '0' COMMENT '点赞次数', PRIMARY KEY (id
), KEY accountId_msgDatetime
(account_id
,msg_datetime
) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
account_id
用户 id
photos_bin
存放微博上的图片链接的 ( 由 protobuf 序列化后的 ) 二进制, 读取时需要用 db_struct.proto 中的 message weiboPhotos 反序列化; 写入时需要用该 protobuf 结构体序列化为二进制
message weiboPhotos
{
repeated string photos = 1;
}
msg_content
微博的文字信息, 最大长度为 2048 个英文,或者 2048 / 3 = 682 个中文
srv_timestamp
(发)微博(时的服务器)时间戳, 表示用户的微博 id, 属于业务逻辑字段
msg_datetime
srv_timestamp 的日期格式
thumbup_times
这条微博的点赞次数: update weibo set thumbup_times = thumbup_times + 1 where .....
用 redis list 存储用户发的微博 id( weibo_id 字段 ), 用 [ list:weibo:account_id ] 作为这个 list 的 key
用 redis zset 存储用户发的微博 id( weibo_id 字段 ), 用 [ zset:weibo:account_id ] 作为这个 zset 的 key
redis string 保存此微博的内容 ( 可以是整条数据库记录 ),用 [ string:weibo:account_id:微博id ] 作为这个 string 的 key
用户发微博后,往 [ list:weibo:account_id ] 和 [ zset:weibo:account_id ] 中插入微博 id, 用 [ string:weibo:account_id:微博id ] 保存微博内容
用户要查看自己的微博,从 [ list:weibo:account_id ] 中获取到若干微博 id, 然后根据微博 id 用 redis MGET (参数是 微博 id ) 指令从 [ string:weibo:account_id:微博id ] 中获取到微博内容
好友要查看用户的微博, 从 [ zset:weibo:account_id ] 中获取到前3天微博 id, 然后根据微博 id 用 redis MGET (参数是 微博 id ) 指令从 [ string:weibo:account_id:微博id ] 中获取到微博内容
用户发微博后,往 mysql weibo 表中插入一条记录,
CREATE TABLE weibo_deleted
( id
bigint(20) NOT NULL AUTO_INCREMENT, account_id
bigint(20) NOT NULL, photos_bin
blob, msg_content
varchar(2048) DEFAULT NULL, srv_timestamp
bigint(20) NOT NULL, msg_datetime
datetime(6) NOT NULL, thumbup_times
int(10) NOT NULL DEFAULT '0' COMMENT '点赞次数', del_datetime
datetime(6) NOT NULL, PRIMARY KEY (id
), KEY accountId_msgDatetime_delDatetime
(account_id
,msg_datetime
,del_datetime
) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
最后一个字段 del_datetime
表示删除微博时的时间, 其他字段跟 weibo 表一致
从 [ list:weibo:account_id ] 和 [ zset:weibo:account_id ] 中删除微博 id( weibo_id 字段 ),
删除 [ string:weibo:account_id:微博id ]
用户删除一条微博时, 从 weibo 表中复制相关记录插入到 weibo_deleted 表中, 然后再删除 weibo 表中的记录
CREATE TABLE weibo_like
( id
bigint(20) NOT NULL AUTO_INCREMENT, account_id
bigint(20) NOT NULL, srv_timestamp
bigint(20) NOT NULL, liker_id
bigint(20) NOT NULL COMMENT '点赞者信息集合', thumbup_timestamp
datetime(6) NOT NULL COMMENT '点赞时刻', PRIMARY KEY (id
), KEY accountId_srvTimestamp_thumbupTimestamp
(account_id
,srv_timestamp
,thumbup_timestamp
) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
account_id
被点赞用户的 account_id
srv_timestamp
被点赞的微博 id, 也就是 weibo 表中的 srv_timestamp 字段
liker_id
点赞者的 account_id
thumbup_timestamp
点赞时刻
"我"的每条微博有一个 redis hash , 为"我"点赞的 [ 用户 id ] - [ 点赞时的服务器时间戳 ], 作为 [ 字段 ] - [ 值 ] 写入进去, 这个 redis hash 供 "我"本人和好友查看; [ hash:weibo_like:account_id:微博id ] 作为 hash 的 key
"我"的每条微博有一个 set, 为"我"点赞的用户 id 全部写入进去, 这个 set 用来计算和其他用户的共同好友, [ set:weibo_like:account_id:微博id ] 作为 set 的 key
"我"删除某条微博后, 就把这条微博对应的 redis hash ( hash:weibo_like:account_id:微博id ) 和 redis set ( set:weibo_like:account_id:微博id ) 删除掉
用户 A 为"我"的某条微博点赞后, 在 weibo_like 中插入新记录, 把 "我" 的用户 ID ( account_id 字段 )和微博 ID ( srv_timestamp 字段), 用户 A 的 account_id, 当前时间戳赋值给这条记录
CREATE TABLE weibo_reply
( id
bigint(20) NOT NULL AUTO_INCREMENT, account_id
bigint(20) NOT NULL COMMENT '朋友圈发布者Id', weibo_id
bigint(20) NOT NULL COMMENT '当前朋友圈Id', comment_id
bigint(20) NOT NULL COMMENT '此条朋友圈评论的评论Id', sender_id
bigint(20) NOT NULL COMMENT '此条朋友圈评论的发布者Id', be_comment_id
bigint(20) DEFAULT NULL COMMENT '此条朋友圈评论回复评论Id', receiver_id
bigint(20) DEFAULT NULL COMMENT '此条朋友圈回复评论的用户Id', msg_content
varchar(2048) NOT NULL, reply_datetime
datetime(6) NOT NULL, deleted
int(10) DEFAULT '0' COMMENT '此条评论所在是朋友圈状态,0为正常,1为删除状态', status
int(10) NOT NULL DEFAULT '0' COMMENT '用户评论状态,0为正常,1为删除', PRIMARY KEY (id
), KEY weiboId,commentId
(weibo_id
,comment_id
)) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4;
account_id
用户 id; B 在 A 的某条微博下留言,那么 account_id = A 用户 id
weibo_id
微博 id, 发微博时的时间戳, 也就是 weibo 表中的 weibo_id; B 在 A 的某条微博下留言,那么 weibo_id = A 的某条微博 id
sender_id
在微博下留言的用户 id, B 在 A 的某条微博下留言, send_id = B 用户 id
comment_id ( 雪花 id )
B 在 A 的微博下评论, 假设这个评论 ID = 3( comment_id = 3 ), sender_id 就是 B 的 ID; receiver_id 和 be_comment_id 为空
be_comment_id ( = 被评论的 id )
接上, A ( 或者 C ) 回复 B 的评论( id = 3), 生成评论 id = 4, 此时 comment_id = 4, be_comment_id = 3, receiver_id 是 B 的用户 id, send_id = A ( 或者 C ) 的用户 id
receiver_id
B 在"我"的某条微博下, @ C 用户,那么 receiver_id 就是 C 的用户 id; 如果 B 没有 @ 任何人, receiver_id = 0
msg_content
微博留言内容
reply_datetime
回复时间
deleted
发微博的人,删除微博后,这条微博下所有的留言记录, 都要把 deleted = 1, 并不从数据库删除,当做备份
status
用户评论状态,0为正常,1为删除
"我"的每条微博下的所有回复, 用一个 redis list 保存, 也就是说 有多少条微博,就有多少个 redis list for weibo reply
用 [ list:weibo_reply:account_id:微博id ] 来作为 list 的 key, 这个 list 供 "我" 和"我"的好友查看微博留言时使用
备注: 由于同一个用户会在微博下留言多次,所以无法使用 redis zset 来保存留言
"我"的每条微博有一个 set, 为"我"留言的用户 id 全部写入进去, 这个 set 用来计算和其他用户的共同好友, [ set:weibo_reply:account_id:微博id ] 作为 set 的 key
"我"删除某条微博后,要把 [ list:weibo_reply:account_id:微博id ] 和 [ set:weibo_reply:account_id:微博id ] 删除掉
用户 B 要在用户 A 的某条微博下留言时, 往 weibo_reply 表中插入一条记录, account_id = A 用户id, weibo_id = A 的微博 id, sender_id = B 用户id, receiver_id = 0, msg_content = 留言内容
如果用户 B 要在用户 A 的某条微博下 回复 C 用户, 就往 weibo_reply 表中插入一条记录, account_id = A 用户id, weibo_id = A 的微博 id, sender_id = B 用户id, receiver_id = C 用户id, msg_content = 留言内容
"我"删除某条微博后,执行: update weibo_reply set deleted = 1 where account_id = A 用户id and srv_timestamp = 微博 id
当"我"发了一条微博/为朋友的微博点赞/在某个朋友的微博下留言, 就会在 weibo_action_log 中插入一条记录,即生成一条动态
CREATE TABLE weibo_action_log
( id
bigint(20) NOT NULL AUTO_INCREMENT, account_id
bigint(20) NOT NULL, weibo_id
bigint(20) NOT NULL COMMENT '用户发微博,点赞,在别人微博下留言时的时间戳', action
int(6) NOT NULL DEFAULT '0' COMMENT '0 发微博, 1 点赞, 2 在某个朋友的微博下留言', friend_id
bigint(20) DEFAULT '0' COMMENT '只有为别人点赞或留言时, friend_id 才有意义', friend_srv_timestamp
bigint(20) DEFAULT NULL COMMENT '只有为别人点赞或留言时, friend_srv_timestamp 是对方的微博 id', action_datetime
datetime(6) NOT NULL, PRIMARY KEY (id
), KEY accountId_srvTimestamp
(account_id
,srv_timestamp
) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
account_id
产生微博动态的用户 id
srv_timestamp
微博 id, 就是 weibo 表中相关记录的 srv_timestamp 字段
action
行为类型, 0 发微博, 1 为好友点赞, 2 在某个朋友的微博下留言
friend_id
只有 action = 1 或者 2 时, 此字段才有意义; 表示好友的用户 id
friend_srv_timestamp
只有 action = 1 或者 2 时, 此字段才有意义; 表示好友的微博 id, 即 weibo 表中相关记录的 srv_timestamp 字段的值
action_datetime
当前时间
每个用户有 2 个 redis zset, zsetMine 保存个人动态, zsetFriend 保存朋友们的动态
用户发微博后,会产生一个动态,并进行两次 redis 操作
插入到个人的 zsetMine 中
用 redis 流水线打包多个命令到 redis, 往每个好友的 zsetFriend 插入一条动态日志
用户 B 为好友 A 点赞,在好友 A 的微博下留言时,会产生一个动态,并进行下面的 redis 操作
插入到 B 的 zsetMine 中
在 redis 中利用 set 查出 A, B 两个人的共同好友
用流水线打包多个命令到 redis, 往好友 A 以及每个AB共同好友的 zsetFriend 插入动态日志
用户 B 在好友 A 微博下,回复其他用户 C 时( B C 必须是好友才看得见对方,这里要做合法性判断,禁止回复非好友), 会产生一个动态,并进行下面的 redis 操作
插入到 B 的 zsetMine 中
在 redis 中利用 set 查出 A, B, C 三个人的共同好友
用流水线打包多个命令到 redis, 往好友 A, C 以及每个ABC共同好友的 zsetFriend 插入动态日志
用户登录后,依次从 zsetFriend 获取到一定数量的好友动态, 聚合后下发
用户从 zsetMine 中获取个人历史动态
用户发微博后, 往 weibo 表( 前面已完成 ) 和 weibo_action_log 中插入记录; 为 weibo_action_log 插入记录时, srv_timestamp = weibo 表中相关记录的 srv_timestamp 字段, action字段 = 0, friend_id, friend_srv_timestamp 两个字段为空
用户为好友某个微博点赞后, 往 weibo_like 表( 前面已完成 ) 和 weibo_action_log 中插入记录; 为 weibo_action_log 插入记录时, srv_timestamp = 0, action字段 = 1, friend_id 字段 = 好友 account_id, friend_srv_timestamp 字段 = 好友的微博 id
用户在好友微博留言后, 往 weibo_reply 表( 前面已完成 ) 和 weibo_action_log 中插入记录; 为 weibo_action_log 插入记录时, srv_timestamp = 0, action字段 = 2, friend_id 字段 = 好友 account_id, friend_srv_timestamp 字段 = 好友的微博 id
由于动态的数据量,与好友数量呈几何级增长,所以在 mysql 中就把个人动态存储到 weibo_action_log 中,如果需要获得好友动态,可以通过 weibo_action_log 中的记录计算出来(并加载到 redis), 需要专门做一个工具来实现这个功能(交给天文做)
接上, 每个用户有 2 个 redis zset, zsetMine 保存个人动态, zsetFriend 保存朋友们的动态
所以从 zsetFriend 中可以获取到最近几天的朋友们的动态; 由于朋友可能是先发动态,然后两者解除朋友关系,所以服务端下发动态给用户时,需要过滤掉非好友动态
A 只能看到 A B 共同好友为 B 点赞
1 设 redis 中 A 的好友集合为 setA
2 设 redis 中 B 的某条微博的点赞集合为 setB ( setB 的 key = set:weibo_like:account_id:微博id )
3 对 setA 和 setB 求交集,就是 A 能看见的点赞好友的 id 集合; 如果集合是空,就不用执行 4
4 对 hash:weibo_like:account_id:微博id 一次性取多个字段的值 ( 3 的结果 作为 redis 指令 HMGET 的参数 ),获得若干个 [ 好友 id ] - [ 留言时间戳 ], 下发给客户端; 客户端根据留言时间戳进行排序并显示在 UI 上
备注: 不确定使用 lua 是否可以一次完成 3, 4 的功能, 即一次 redis IO 访问就能计算出结果
A 只能看到 A B 共同好友的留言
1 设 redis 中 A 的好友集合为 setA
2 设 redis 中 B 的某条微博的好友回复集合为 setB ( setB 的 key = set:weibo_reply:account_id:微博id )
3 对 setA 和 setB 求交集,就是 A 能看见的留言的好友 id 集合; 如果集合是空,就不用执行 4
4 从 list:weibo_reply:account_id:微博 id 中获取到所有的留言者, 和 3 的结果取交集,就是 A 能看见的留言
备注: 不确定使用 lua 是否可以一次完成 3, 4 的功能, 即一次 redis IO 访问就能计算出结果