Redis 实战 —— 11. 实现简单的社交网站

前面介绍了广告定向的实现,它是一个查询密集型 (query-intensive) 程序,所以每个发给它的请求都会引起大量计算。本文将实现一个简单的社交网站,则会尽可能地减少用户在查看页面时系统所需要做的工作。 P184

用户和状态 P185

用户对象存储了用户的基本身份标识信息、用户的关注者人数、用户已发布的状态消息数量等信息,它是构建其他可用且有趣的数据的起点。 P185

状态消息记录了不同的用户都说了什么,以及不同用户之间进行了什么交流,这些由用户创建的状态消息是社交网站真正的内容。 P185

用户信息 P185

用户信息使用 HASH 来存储,用户信息包括:用户名、用户拥有的关注者人数、用户正在关注的人的数量、用户已发布的状态消息的数量、用户的注册日期以及其他一些元信息 (meta-information) 。示例: "user:139960061": {"login": "dr_josiah", "id": "139960061", "name": "Josiah Carlson", "followers": "176", "following": "79", "posts": "386", "signup": "1272948506"} P185

创建用户 P185

创建用户时需要根据用户指定的用户名以及当时的时间戳,创建一个正在关注数量、关注者数量、已发布状态消息数量都被设置为 0 的对象。 P185

创建时除了要对用户信息进行初始化,还需要对用户名进行加锁,用以防止多个请求 (request) 在同一时间内使用相同的用户名来创建新用户(可以使用 08. 实现自动补全、分布式锁和计数信号量 中实现的分布式锁进行加锁操作)。

状态消息 P186

状态消息使用 HASH 来存储,状态消息包括:消息本身、消息发布的时间、消息发布者的 id 、用户名(冗余用户名是为了展示时避免用户信息的 HASH ,因为用户名是不会改变的)以及其他一些关于状态消息的附加信息。示例: "status:223499221154799616": {"message": "My pleasure. I was amazed that...", "posted": "1342908431", "id": "223499221154799616", "uid": "139960061", "login": "dr_josiah"} P186

创建消息时需要先获取用户名,再将相关的信息组合起来存储到 HASH 中。 P187

主页时间线 P187

主页时间线是一个列表,它由用户以及用户正在关注的人所发布的状态消息组成。个人时间线与主页时间线类似,它只包含用户自己所发布的状态消息。因为主页时间线是用户访问网站时的主要入口,所以这些数据必须尽可能地易于获取。 P187

主页时间线使用有序集合存储,成员为状态消息的 id ,成员的分值为状态消息发布的时间戳。示例: "home:139960061": {..., "227138379358277633": "1342988984", ...} P188

获取主页时间线分为两步: P188

使用 ZREVRANGE 分页获取最新状态消息的 id 列表

使用流水线和 HGETALL 获取到状态消息 id 列表中所有状态消息

关注者列表和正在关注列表 P189

用户正在关注列表以及关注者列表同样用有序集合存储,成员为用户的 id ,成员的分值为用户开始关注某人或被某人关注的时间戳。示例:"followers:139960061": {..., "558960079": "1342915440", "14502701": "1342917840", ...} "following:139960061": {..., "18697326": "1339286400", "558960079": "1342742400"} P188

当用户开始关注或者停止关注另一个用户时,就需要对这两个用户的正在关注有序集合和关注者有序集合进行更新 (ZADD, ZREM),并修改他们用户信息中的关注数量和被关注数量 (HINCRBY),同时还需要操作者的主页时间线,添加或删除另一个用户的状态消息 (ZUNIONSTORE)。 P189

删除操作需要两个命令,因为有序集合没有求差集的命令,有两种方式可以实现:

使用 ZREVRANGE 获取另一用户个人主页对应的有序集合的成员列表,然后再使用 ZREM 从操作用户主页流水线对应的有序集合中删除这些成员

先使用 ZUNIONSTORE 合并集合,操作用户主页流水线对应的有序集合的权重为 1 ,另一用户个人流水线对应的有序集合的权重为 0 ,聚合方式使用 MIN ,然后再使用 ZREMRANGEBYSCORE key 0 0 移除所有分值为 0 的成员(可以使用流水线合并)

所思

练习题让在给定的基础上支持批量关注和取消关注的操作。其实业务中大部分情况下单个和批量操作都是类似的,并且后续很可能会支持批量操作,为了减少后期后端开发量、避免改动接口签名或类似功能接口爆炸性增长,我常常都会提前实现批量操作的接口。我们平时开发时不能仅对当前需求进行处理,还要去理解整体功能并站在用户的角度进行思考,尽早关注可能的变动,这样才能开发出具有扩展性的接口。

状态消息的发布与删除 P191

用户可以执行的一个最基本的操作就是发布状态消息,前面已将实现了创建状态消息的逻辑,接下来将实现把新的状态消息添加到每个关注者的主页时间线中。 P191

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wspsyp.html