周煦辰 2016年8月31日

本文介绍了一下本人在开发过程中遇到“定时推送提醒”的需求的时候所思考的三种解决方案。

明确问题

首先明确一下这个需求可能包含的几个“坑”:

  1. 系统内的用户量是否很大?所涉及的提醒任务是否会很多?
  2. 该提醒是否是用户自己设置的?中途是否会修改?
  3. 推送的时间是否固定(如每天固定时间推送或者每隔一个小时推送等)?还是用户自定义推送时间?

所需工具

  • Redis
  • crontab
  • 任何一种Linux上可以运行的脚本语言(Python、PHP等)

解决方案一:使用Redis队列(普通入队出队)

针对第一个问题,我们可以将需要推送的任务作为一个消息队列,这样可以减轻数据库的压力。因此这就引出第一种解决思路:使用Redis的队列命令实现一个简单的消息队列。

基本思路为,在一天中的某个时间(例如早上五点这种服务器不会遇到什么压力的时间段),通过crontab运行脚本,将推送任务整理完成并逐条插入Redis的队列中。基本的代码思路如下:

import redis
import json # 这里是你的数据库查询代码
# TODO # 这里将你需要推送的用户ID、内容等整合为一个字典
reminder = {
'id': 27149,
'content': 'The meaning of life is 42'
}
# 将字典编码为json字符串
reminder_str = json.dumps(reminder) # 连接redis并将数据插入redis中
r = redis.StrictRedis(hostname='localhost', port=6379, db=0)
print r.lpush('test_list', reminder_str) # 如果所有数据已入队
# 可以在最后插入一个空数据作为结束的标志
r.lpush('test_list', '{}')

到需要推送消息的时间(例如早上十点),通过crontab运行如下的出队命令,进行消息的推送。

import redis
import json r = redis.StrictRedis(hostname='localhost', port=6379, db=0)
while True:
item = r.rpop('test_list')
data = json.loads(item)
if not data:
break
# 这里是自定义的推送代码

以上这种方法的优点在于:

  1. 可以利用Redis实现不同服务端应用间的数据,例如你的服务端应用是用PHP写的,而入队的脚本希望使用Python,则可以采用这种方法。
  2. 可以减轻对数据库的压力,且Redis的查询效率非常高,可以提升该功能上的性能。

不足之处:

  • 假如推送的消息是用户自定义的,且中间会有修改,那这种方案就会遇到推送时的消息错误。

针对不足,我们来看方案二。

解决方案二:还是使用Redis队列,但是我们使用阻塞模式(Blocking)

这个方案我们还是会用到Redis的队列,不同的是我们会使用到Redis提供的阻塞出队接口(blpop、brpop)。阻塞出队简单来说,就是在出队命令在没有接收到队列内的数据前,会挂起,直到在设置的阻塞时间内队列中有新的数据入队,则弹出数据,命令结束;如果在设置的阻塞时间内没有数据入队,则返回空;如果阻塞时间被设置为0,则进程将一直被挂起直到队列中有数据入队。

若使用阻塞模式,假设我们的推送时间为早上的十点,那么在9:58左右,可以运行入队命令,将需要推送的数据加入Redis队列中。代码示例如方案一,这里就不放了。

到了十点整,运行如下代码进行出队。

import redis
import json r = redis.StrictRedis(hostname='localhost', port=6379, db=0)
while True:
item = r.brpop('test_list', 0)
data = json.loads(item)
if not data:
break
# 这里是自定义的推送代码

注意第6行代码item = r.brpop('test_list', 0),第二个参数即为阻塞的等待时间。

使用这种方法基本可以保证推送消息的准确性,一边生成消息塞进队列,一边从队列里拿即可。但是似乎这种方式并没有发挥到“缓存”的优势。

解决方案三:偷鸡摸狗,用Redis的Hash实现一个“队列”

这个方案中我们会使用到Redis中的Hash功能。简单来说Redis的Hash就是一个类似Python中的字典,不同的是Redis的一个Hash-Field只能对应一个字符串。

r.hset(hash_key, hask_field, value)

使用该方案可以在用户修改计划任务时快速找到需要推送的消息并修改。出队的时候使用HAVLS并且遍历即可。代码就不放了,毕竟是个偷鸡摸狗的思路。

后端利用Redis队列及哈希实现定时推送提醒的三个思路的更多相关文章

  1. (七)RabbitMQ消息队列-通过fanout模式将消息推送到多个Queue中

    原文:(七)RabbitMQ消息队列-通过fanout模式将消息推送到多个Queue中 前面第六章我们使用的是direct直连模式来进行消息投递和分发.本章将介绍如何使用fanout模式将消息推送到多 ...

  2. 使用redis进行消息推送

    Redis支持这样一种特性,你可以将数据推到某个信息管道中,然后其它客户端可以通过订阅这些管道来获取推送过来的信息.使用Redis的Pub/Sub,接收方在某个channel注册为一个订阅者,然后监听 ...

  3. Springboot21 整合redis、利用redis实现消息队列

    1 前提准备 1.1 创建一个springboot项目 技巧01:本博文基于springboot2.0创建 1.2 安装redis 1.2.1 linux版本 参考博文 1.2.2 windows版本 ...

  4. Java利用Redis实现消息队列

    应用场景 为什么要用redis?二进制存储.java序列化传输.IO连接数高.连接频繁 一.序列化 这里编写了一个java序列化的工具,主要是将对象转化为byte数组,和根据byte数组反序列化成ja ...

  5. 我心中的核心组件~MSMQ与Redis队列

    回到目录 这个文章其实是我心中的核心组件的第七回,确实在时间上有些滞后了,但内容并不滞后!本文MSMQ只是个引题,我确实不太想说它,它是微软自己集成的一套消息队列,寄宿在Window服务里,稳定性十在 ...

  6. (3)redis队列功能

    Redis队列功能介绍 List 常用命令: Blpop删除,并获得该列表中的第一元素,或阻塞,直到有一个可用 Brpop删除,并获得该列表中的最后一个元素,或阻塞,直到有一个可用 Brpoplpus ...

  7. 利用Redis keyspace notification(键空间通知)实现过期提醒

    一.序言: 本文所说的定时任务或者说计划任务并不是很多人想象中的那样,比如说每天凌晨三点自动运行起来跑一个脚本.这种都已经烂大街了,随便一个 Crontab 就能搞定了. 这里所说的定时任务可以说是计 ...

  8. 如何利用redis key过期事件实现过期提醒

    https://blog.csdn.net/zhu_tianwei/article/details/80169900 redis自2.8.0之后版本提供Keyspace Notifications功能 ...

  9. 第二百九十六节,python操作redis缓存-Hash哈希类型,可以理解为字典类型

    第二百九十六节,python操作redis缓存-Hash哈希类型,可以理解为字典类型 Hash操作,redis中Hash在内存中的存储格式如下图: hset(name, key, value)name ...

随机推荐

  1. 最小树形图(hdu4966多校联赛9)

    GGS-DDU Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total ...

  2. Linux系统下tomcat安装配置

    Linux系统中Tomcat的安装配置. 前提JDK已经安装好. 安装 下载tomcatwget http://mirrors.cnnic.cn/apache/tomcat/tomcat-8/v8.0 ...

  3. 阿里云服务器被挖矿程序minerd入侵的终极解决办法[转载]

    突然发现阿里云服务器CPU很高,几乎达到100%,执行 top c 一看,吓一跳,结果如下: root 386m S : /tmp/AnXqV -B -a cryptonight -o stratum ...

  4. 沈阳网络赛G-Spare Tire【容斥】

    17.64% 1000ms 131072K   A sequence of integer \lbrace a_n \rbrace{an​} can be expressed as: \display ...

  5. 南京网络赛B-The writing on the wall

    30.43% 2000ms 262144K Feeling hungry, a cute hamster decides to order some take-away food (like frie ...

  6. SVN库迁移整理方法----官方推荐方式

    以下是subversion官方推荐的备份方式. 关闭所有运行的进程,并确认没有程序在访问存储库(如 httpd.svnserve 或本地用户在直接访问). 备份svn存储库 #压缩备份 svnadmi ...

  7. 基于Nginx+FastDFS搭建图片文件系统

    Nginx+fastdfs:https://www.cnblogs.com/chiangchou/p/fastdfs.html#_label0_1 缩略图:https://blog.csdn.net/ ...

  8. HDU1796How many integers can you find(容斥原理)

    在计数时,必须注意无一重复,无一遗漏.为了使重叠部分不被重复计算,人们研究出一种新的计数方法,这种方法的基本思想是:先不考虑重叠的情况,把包含于某内容中的所有对象的数目先计算出来,然后再把计数时重复计 ...

  9. C++ lamda、function、bind使用

    参考资料: http://blog.csdn.net/augusdi/article/details/11771699 lambda 表达式的简单语法如下:[capture] (parameters) ...

  10. Amber安装并行

    现在简单介绍一下amber12中安装openmpi并行的过程. 1. 下载openmpi版本在1.5-1.9之间的(openmpi-1.6.5.tar.bz2) 这是因为$AMBERHOME/Ambe ...