周煦辰 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. 关于java web的笔记2018-01-12

    需求:1.写一个商品类,有商品编号.商品名称.商品分类.商品单价属性.2.写一个商品条目信息类,有商品和数量两个属性,有商品总价格方法.3.写一个购物车类,有添加商品方法.查看订单信息,删除商品,修改 ...

  2. rbac - 界面、权限

    一.模板继承 知识点: users.html / roles.html 继承自 base.html 滑动时,固定 position: fixed;top:60px;bottom:0;left:0;wi ...

  3. Python开发【笔记】:探索Python F-strings

    F-strings 在python3.6.2版本中,PEP 498 提出一种新型字符串格式化机制,被称为“字符串插值”或者更常见的一种称呼是F-strings(主要因为这种字符串的第一个字母是f) 简 ...

  4. KVM中断虚拟化浅析

    2017-08-24 今天咱们聊聊KVM中断虚拟化,虚拟机的中断源大致有两种方式,来自于用户空间qemu和来自于KVM内部. 中断虚拟化起始关键在于对中断控制器的虚拟化,中断控制器目前主要有APIC, ...

  5. mysql 整数类型 数值类型 tinyint

    1.整数类型 整数类型:TINYINT SMALLINT MEDIUMINT INT BIGINT 作用:存储年龄,等级,id,各种号码等 ============================== ...

  6. Spark Streaming里面使用文本分析模型

    功能:接收来自kafka的数据,数据是一篇文章,来判断文章的类型,把判断的结果一并保存到Hbase,并把文章建立索引(没有代码只有一个空壳,可以自己实现,以后有机会了可能会补上) import org ...

  7. PAT 1056 Mice and Rice[难][不理解]

    1056 Mice and Rice(25 分) Mice and Rice is the name of a programming contest in which each programmer ...

  8. 数据挖掘---支持向量机(SVM)

    •1.SVM 的基本思想: •SVM把分类问题转换成寻求分类平面的问题,并通过最大化分类边界点到分类平面的距离来实现分类.通俗的讲支持向量机的解决的问题是找到最好的分类超平面.支持向量机(Suppor ...

  9. java打印随机函数

    一 ,打印1-10的随机函数 public static void randomprint(){      for (int i=0;i<100;i++){          //打印一百次  ...

  10. pip 解决 ImportError: cannot import name 'main'

    当 pip 更新至最新版的时候,不管是执行 pip list 还说 pip install packageName 安装包,都会抛出一个异常 Traceback (most recent call l ...