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
为了让发布操作尽可能快地返回,我们在创建后会仅针对前 1000 个关注者的主页时间线添加新的状态消息,如果当前发布者的关注者超过了 1000 个,则使用 09. 实现任务队列、消息拉取和文件分发 中实现的任务队列异步处理后续的关注者。 P192
删除消息时同理操作即可,先删除状态消息本身,然后处理发布者自己的统计信息,再从个人时间线中删除该消息 id ,最后再从前 1000 个关注者的主页时间线中删除,若关注者人数超过 1000 ,再使用任务队列异步处理后续的关注者。 P193
流 API P194
构建一些函数来广播 (broadcast) 简单的事件 (event) ,然后由负责进行数据分析的事件监听器 (event listener) 来接收并处理这些事件,流 API 请求能在一段比较长的时间内持续地返回数据。 P194
流 API 的作用是随着时间的推移,产生一个由时间组成的序列,以此来让整个网络上的客户端和其他服务及时地了解到网站目前正在发生的事情。 P195
构建流 API 的过程中需要进行各种各样的决策,这些决策主要和以下 3 个问题有关: P195
- 流 API 需要对外公开哪些事件?
- 需要公开目前实现的四种用户操作:发布消息、删除消息、关注用户和取消关注用户。本节将以创建发布消息事件和删除消息事件为例进行实现
- 是否需要进行访问限制?如果需要的话,采取何种方式实现?
- 目前仅在涉及用户隐私或者系统资源的时候,考虑访问限制
- 流 API 应该提供哪些过滤选项?
- 既可以通过关注过滤器(基于用户进行过滤)、检测过滤器(基于关键字进行过滤)和位置过滤器来获取过滤后的消息,又可以通过类似推特的 firehose (可以获取所有公开消息) 和 sample (只能获取少量公开消息) 这样的流来获取一些随机的消息。
标识客户端 P198
为了区分不同的客户端,需要对其进行标识,大部分情况下来说只用考虑已登陆用户即可,那我么使用用户 id 进行标识,为了同时实现验证用户 id 的功能,可以使用 JWT 。
过滤消息 P200
我们将使用 Redis 的 PUBLISH 命令和 SUBSCRIBE 命令(05. Redis 其他命令简介 介绍了这两个命令的用法和缺陷)来实现订阅发布功能:当用户发布一条消息时,程序会通过 PUBLISH 发送给某个频道,而各个过滤器则通过 SUBSCRIBE 来订阅并接收那个频道的消息,并在发现与过滤器相匹配的消息时,将消息回传 (yield back) (如果是发布消息,则回传实体;如果是删除消息,则回传 id 和当前状态)给 Web 服务器,然后由服务器将这些消息发送给客户端。 P200
本文首发于公众号:满赋诸机(点击查看原文) 开源在 GitHub :reading-notes/redis-in-action
Redis 实战 —— 11. 实现简单的社交网站的更多相关文章
- redis实战笔记(8)-第8章 构建简单的社交网站
本章主要内容 用户和状态 主页时间线 关注者列表和正在关注列表 状态消息的发布与删除 流API
- Redis实战:如何构建类微博的亿级社交平台
微博及 Twitter 这两大社交平台都重度依赖 Redis 来承载海量用户访问.本文介绍如何使用 Redis 来设计一个社交系统,以及如何扩展 Redis 让其能够承载上亿用户的访问规模. 虽然单台 ...
- (转)国内外三个不同领域巨头分享的Redis实战经验及使用场景
随着应用对高性能需求的增加,NoSQL逐渐在各大名企的系统架构中生根发芽.这里我们将为大家分享社交巨头新浪微博.传媒巨头Viacom及图片分享领域佼佼者Pinterest带来的Redis实践,首先我们 ...
- Redis实战经验及使用场景
随着应用对高性能需求的增加,NoSQL逐渐在各大名企的系统架构中生根发芽.这里我们将为大家分享社交巨头新浪微博.传媒巨头Viacom及图片分享领域佼佼者Pinterest带来的Redis实践,首先我们 ...
- Redis实战
大约一年多前,公司同事开始使用Redis,不清楚是配置,还是版本的问题,当时的Redis经常在使用一段时间后,连接爆满且不释放.印象中,Redis 2.4.8以下的版本由于设计上的主从库同步问题,就会 ...
- Redis实战之Redis + Jedis
用Memcached,对于缓存对象大小有要求,单个对象不得大于1MB,且不支持复杂的数据类型,譬如SET 等.基于这些限制,有必要考虑Redis! 相关链接: Redis实战 Redis实战之Redi ...
- Redis实战之征服 Redis + Jedis + Spring (一)
Redis + Jedis + Spring (一)—— 配置&常规操作(GET SET DEL)接着需要快速的调研下基于Spring框架下的Redis操作. 相关链接: Redis实战 Re ...
- Redis实战之Redis + Jedis[转]
http://blog.csdn.net/it_man/article/details/9730605 2013-08-03 11:01 1786人阅读 评论(0) 收藏 举报 目录(?)[-] ...
- redis实战笔记(10)-第10章 扩展Redis
本章主要内容 扩展读性能 扩展写性能以及内存容量 扩展复杂的查询 随着Redis的使用越来越多, 只使用一台Redis服务器没办法存储所有数据或者没办法处理所有读写请求的问题迟早都会出现, 这 ...
随机推荐
- 【探索之路】机器人篇(2)-ROS系统并创建工作空间和项目
在ROS官网,已经给出了详细的教程.下面我就般一下砖,把相应的操作写到这里.官方网址:http://wiki.ros.org/cn/ 安装ROS系统 indigo在ubuntu上的安装教程.官网:ht ...
- 熬夜肝了一周!总结了这套对标阿里P8的java秘籍,限时发布3天!
前言 最近老是有粉丝私信我说感觉自己学java越来越难了,这其中有刚毕业的应届生说自己的技术找不到满意的工作,也有在学校的大学习说找不到学习方式,更多的是正在工作的java开发人员说是现在的技术更新太 ...
- 如何下载youtube的视频?
导言 当youtube视频需要下载时,发现需要会员等其他限制 别急,下面就是比较稳定的方法 准备 gitub链接 youtube-dl github 官网链接 官网 按照官网提示下载对应版本 我这里是 ...
- 地图开发笔记(一):百度地图介绍、使用和Qt内嵌地图Demo
前言 Qt在地图方面的研发. 百度地图 介绍 百度的地图分为多个开发,都是在线的(离线的需要自己提取,本篇解说在线地图). 百度地图JavaScript API支持HTTP和HTTPS, ...
- oracle 11.2.0.1.0 升级 11.2.0.4.0 并 patch 到11.2.0.4.7
升级步骤: (1) 备份数据库 (2) 运行patchset,升级oracle 软件 (3) 准备新的ORACLE_HOME (4) 运行dbua 或者脚本升级实例 (5) ...
- 直播预告 | 开源的云原生开发环境 —— Nocalhost
直播来啦!本次云原生学院邀请到腾讯云 CODING DevOps 后端工程师王炜为大家分享<开源的云原生开发环境 -- Nocalhost>. 直播信息 讲师:王炜 - 腾讯云 CODIN ...
- Java并发编程实战(5)- 线程生命周期
在这篇文章中,我们来聊一下线程的生命周期. 目录 概述 操作系统中的线程生命周期 Java中的线程生命周期 Java线程状态转换 运行状态和阻塞状态之间的转换 运行状态和无时限等待状态的切换 运行状态 ...
- python列表字符串集合常用方法
1.1 列表常用方法 # 1. append 用于在列表末尾追加新的对象a = [1,2,3]a.append(4) # the result : [1,2,3,4]# 2. count方法统计某个 ...
- 配置 Docker 镜像加速源地址
docker 安装官方文档 根据实例的操作系统类型,参考相应的文档进行安装. 查看 linux 是 CentOS 还是 Ubuntu uname -a #查看系统信息 lsb_release -a # ...
- Linux 使用命令行上传下载文件
基本语法: 服务器: 用户名@ip:/路径 scp 要拷贝的文件 要存放的文件 上传文件到服务器 # 把本地 source.md 文件上传到 152.116.113.13 服务器的/home目录 # ...
