redis+mysql+quartz 一种红包发送功能的实现

概要:

这篇文章主要是对半年前开发的红包模块进行整理,把其中主要的设计思想以及具体的实现方案进行介绍,如有设计以及实现上的缺陷,或是存在漏洞,请大家批评指正!

红包功能大家都很熟悉了,那在这里就简单的对红包功能进行描述...

功能描述:红包业务主要的功能包括四部分,分别是红包发送,红包接收,红包回收,以及红包记录查询。

1)红包发送:发送者账户->红包中间层

2)红包接收:红包中间层->接收者账户

3)红包回收:红包中间层中若存在红包留存超过24小时,则将其回收,红包中间层->发送者账户

功能描述大体了解之后,那接下来就是实现方案了...

首先给出设计流程,这部分将依次对红包发送、红包接收、红包回收的流程进行分析...

1. 设计流程

首先是红包发送功能,以群红包为例,其流程图如下所示:

图1 红包发送流程图

首先,采用基于高斯分布的方法,将金额100随机的分配成8份,然后将这8份数据存入到redis缓存队列(list)中,同时将队列的过期时间设置成24h;考虑到在抢红包的时候会出现重复抢的问题,那在这里采用的去除重复的方案是在redis缓存中维护一个已分配集合(set),集合里面存储的是已经接收过红包的用户ID;另外,在大量的用户同时抢红包的 情况,出于优化方面的考虑,为了起到一定的限流作用,同时减少对数据库的访问压力(考虑这种情况:一个时间段内,大量的用户在抢红包,在红包已经分配完的时刻之后 到来的请求,会给数据库带来一定的访问压力),那做法是在redis缓存中维护一个红包已分配完的标记(key-value),有0(为分配完)/1(已分配完)两种状态,从而起到一定的限流作用。

继缓存层面之后,接下来是数据库层面,那在MySQL中的红包发送表(account_coin_records_user_coin_package_send)中生成一条记录,同时呢在把上面经高斯分布方法得到的8份金额插入到红包分配表(account_coin_records_user_coin_package_assign)中,初始化分配标记为0(未分配),至此,红包发送的整个流程完成。

然后是红包接收功能,其流程图如下所示:

图2 红包接收流程图

红包接收者发起请求(请求中包含红包ID、请求人的用户ID)去抢红包,首先需要一系列的验证,这个验证操作要同时基于redis缓存以及MySQL数据库中的数据进行 验证,主要是验证红包ID对应的红包是否存在、红包是否已经分配完了、红包是否已经过期了、红包接收者是否重复接收红包等。如果验证通过,那么这个用户是允许接收到红包的,接下来就是账户同步(红包中间层->用户账户,事务处理),若数据库操作成功,则红包接收成功,否则失败,至此,红包接收整体流程完成。

最后就是红包回收功能,其流程图如下所示:

图3 红包回收流程图

红包回收是采用定时调度策略发起的,时间间隔为5min不间断的轮询访问MySQL数据库,查询是否有待回收的红包(红包在红包中间层留存已经超过24h,且红包 未 分配完),若有需要回收的红包,这个时候基于效率方面的考虑,采用多线程方案来进行回收操作,每个红包对于一个线程,策略是:一个线程,一个请求,一个事务(这 个 方案只适用于待回收的红包个数不是很多的情况)。(注意:若需要回收的红包很多,若不断的申请线程,可能造成内存溢出问题,这时候具体问题具体分析,可以考虑生产者-消费者模式);分布式架构,远程调用,接下来处理红包回收的服务器接收到红包回收请求后,进行账户同步以及红包状态标记(标记为已回收),若数据库事务出现异常,那么事务回滚,此时,这个红包没有回收成功,只能等待下一个5min后再次被回收。

到这里,流程基本介绍完了,那接下来介绍一下数据模型...

2. 数据模型

数据库用的是MySQL。将红包记录进行持久化存储,用于查询红包分配记录以及后期的历史记录查询。红包分配的数据模型如下图所示:

图4 红包分配数据模型

图4中展示了部分的比较重要的数据信息,表之间的关联是靠红包ID建立起来的,红包记录以及状态标记图中已经标识出来了,就不一一介绍了。

在数据库层面,接收红包功能存在高并发问题,那接下来就简单介绍下是如何处理并发的...

3. 并发处理

是如何处理高并发问题的呢?

分析:

首先,由于红包的金额存放在redis缓存队列中,由于redis是单线程的,那么在获取红包的阶段不存在并发问题...

然后,下一步是MySQL数据库一系列的update操作,存在高并发问题...

最后,是记录保存,insert操作,也不存在并发问题...

数据库中update操作,主要应用乐观锁和X锁两种方式来保证数据一致性的。

4. 并发测试

在一段时间的并发测试中,测试通过,不会出现数据不一致问题,红包回收功能也能正常进行。

目前在并发方面,至少支持同一时刻并发量为3000的抢红包操作不会出现问题。

总结,由于能力以及技术有限,目前的方案基本适用用户量不是很大的应用场景,后期随着用户量的增大,会进一步的进行优化...

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

时间: 2017-01-16

PHP的Laravel框架结合MySQL与Redis数据库的使用部署

相对于熟读官方文档,更重要的是要把框架环境搭起来. 零.环境介绍 操作系统:centOS 数据库: mysql 5.6 (阿里云RDS) PHP 5.4.4 (>=5.4即可) Laravel 5.0 一.安装LNMP 在安装Laravel之前,需要把Linux + Nginx + Mysql + Php的环境搭建好.具体的搭建步骤这里就不再详述了. P.S. Linux阿里云已经自带了,本文使用的是centOS 6.5 64位的ECS 关于Nginx和Apache的选择看自己喜好,本文使用的是

python连接MySQL、MongoDB、Redis、memcache等数据库的方法

用Python写脚本也有一段时间了,经常操作数据库(MySQL),现在就整理下对各类数据库的操作,如后面有新的参数会补进来,慢慢完善. 一,python 操作 MySQL:详情见:[apt-get install python-mysqldb] 复制代码 代码如下: #!/bin/env python# -*- encoding: utf-8 -*-#-------------------------------------------------------------------------

CentOS 安装 PHP5.5+Redis+XDebug+Nginx+MySQL全纪录

启动ssh服务 service sshd start yum -y update 查看centos版本 centos 5 执行: 复制代码 代码如下: rpm -Uvh http://mirror.webtatic.com/yum/el5/latest.rpm centos 6 执行: 复制代码 代码如下: rpm -Uvh http://mirror.webtatic.com/yum/el6/latest.rpm yum安装php 复制代码 代码如下: yum install php55w 

从MySQL到Redis的简单数据库迁移方法

从mysql搬一个大表到redis中,你会发现在提取.转换或是载入一行数据时,速度慢的让你难以忍受.这里我就要告诉一个让你解脱的小技巧.使用"管道输出"的方式把mysql命令行产生的内容直接传递给redis-cli,以绕过"中间件"的方式使两者在进行数据操作时达到最佳速度. 一个约八百万行数据的mysql表,原本导入到redis中需要90分钟,使用这个方法后,只需要两分钟.不管你信不信,反正我是信了. Mysql到Redis的数据协议 redis-cli命令行工具有

PHP使用redis实现统计缓存mysql压力的方法

本文实例讲述了PHP使用redis实现统计缓存mysql压力的方法.分享给大家供大家参考,具体如下: <?php header("Content-Type:text/html;charset=utf-8"); include 'lib/mysql.class.php'; $mysql_obj = mysql::getConn(); //redis $redis = new Redis(); $redis->pconnect('127.0.0.1', 6379); if(is

Redis中统计各种数据大小的方法

如果 MySQL 数据库比较大的话,我们很容易就能查出是哪些表占用的空间:不过如果 Redis 内存比较大的话,我们就不太容易查出是哪些(种)键占用的空间了. 有一些工具能够提供必要的帮助,比如 redis-rdb-tools 可以直接分析 RDB 文件来生成报告,可惜它不能百分百实现我的需求,而我也不想在它的基础上二次开发.实际上开发一个专用工具非常简单,利用 SCAN和 DEBUG等命令,没多少行代码就能实现: 复制代码 代码如下: <?php $patterns = array(    

MySQL和Redis实现二级缓存的方法详解

redis简介 Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库 Redis 与其他 key - value 缓存产品有以下三个特点: Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用 Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储 Redis支持数据的备份,即master-slave模式的数据备份 优势 性能极高 - Redis能读的速度是110

redis服务器环境下mysql实现lnmp架构缓存

配置环境:redhat6.5 server1:redis(172.25.254.1) server2:php(172.25.254.2) server3:mysql(172.25.254.3) 配置步骤: server2: 1.server2安装php的redis相应模块 2.nginx安装 [root@server2 php-fpm.d]# rpm -ivh nginx-1.8.0-1.el6.ngx.x86_64.rpm warning: nginx-1.8.0-1.el6.ngx.x86_

Laravel使用Caching缓存数据减轻数据库查询压力的方法

本文实例讲述了Laravel使用Caching缓存数据减轻数据库查询压力的方法.分享给大家供大家参考,具体如下: 昨天想把自己博客的首页做一下缓存,达到类似于生成静态页缓存的效果,在群里问了大家怎么做缓存,都挺忙的没多少回复,我就自己去看了看文档,发现了Caching这个部分,其实之前也有印象,但是没具体接触过,顾名思义,就是缓存了,那肯定和我的需求有点联系,我就认真看了看,发现的确是太强大了,经过很简单的几个步骤,我就改装好了首页,用firebug测试了一下,提高了几十毫秒解析时间,当然了有人

mysql压力测试脚本实例

本文实例讲述了mysql压力测试的脚本,分享给大家供大家参考.具体如下: 创建表DEPT 复制代码 代码如下: CREATE TABLE dept( /*部门表*/ deptno MEDIUMINT   UNSIGNED  NOT NULL  DEFAULT 0, dname VARCHAR(20)  NOT NULL  DEFAULT "", loc VARCHAR(13) NOT NULL DEFAULT "" ) ENGINE=MyISAM DEFAULT C

在ssm项目中使用redis缓存查询数据的方法

在项目中常常需要后台程序的持久层查询数据库来获取数据,然后将数据交给服务层.控制层,最后才交给视图层.如果数据访问缓慢,就会影响程序的运行. 为了加快程序的运行,可以将数据放入缓存中,包括数据缓存和页面缓存. 所谓缓存,就是将程序或系统经常要调用的对象存在内存中,一遍其使用时可以快速调用,不必再去创建新的重复的实例.这样做可以减少系统开销,提高系统效率. 其中页面缓存主要是oscache,可以整页或者指定网页某一部分缓存,同时指定他的过期时间,这样在此时间段里面访问的数据都是一样的 . 数据缓存

laravel实现按月或天或小时统计mysql数据的方法

在PHP里怎么比较简单的实现按时间(如按月,按天,按小时)来统计表里的数据呢? 如:要实现获取下图曲线图数据(ps:当然也可能是柱状图等,数据都是一样的),默认获取七天内的数据,点击今天,7天,15天,30天可任意切换,其中今天是按小时统计. 不过我的实现方法有一个小缺点,当某个小时内是没有数据的,那么该小时不会出现,不过这个应该可以通过前端的形式弥补 好了,废话不多说,上图上代码! 1. 控制器内容 /** * [getsellerdata 获取某时间段内商户结算查询数据] * @param

mybatis plus使用redis作为二级缓存的方法

建议缓存放到 service 层,你可以自定义自己的 BaseServiceImpl 重写注解父类方法,继承自己的实现.为了方便,这里我们将缓存放到mapper层.mybatis-plus整合redis作为二级缓存与mybatis整合redis略有不同. 1. mybatis-plus开启二级缓存 mybatis-plus.configuration.cache-enabled=true 2. 定义RedisTemplate的bean交给spring管理,这里为了能将对象直接存取到redis中,

spring整合redis实现数据缓存的实例代码

数据缓存原因:有些数据比较多,如果每次访问都要进行查询,无疑给数据库带来太大的负担,将一些庞大的查询数据并且更新次数较少的数据存入redis,能为系统的性能带来良好的提升. 业务逻辑思路:登入系统,访问数据时,检查redis是否有缓存,有则直接从redis中提取,没有则从数据库查询出,并存入redis中做缓存. 为什么要用redis做缓存: (1)异常快速:Redis的速度非常快,每秒能执行约11万集合,每秒约81000+条记录. (2)支持丰富的数据类型:Redis支持最大多数开发人员已经知道