综述
自从红包功能火起来之后很多APP都开始添加上此功能以顺应“潮流”。技术流人员都开始研究各种红包算法,别看一个简单的红包功能看起来(说起来)简单,但是实现起来真不简单。首先我们不光要考虑到生成各个红包金额值的合理性(所有红包值不能大于总数),还要考虑各个类型的抢红包模式(例如:拼手气红包、指定金额红包等),最重要的还要考虑大数据下的并发情况(不能抢超了,例如发了5个红包抢走了7个)。下面博主就设计了方案来这些问题。
拼手气红包
拼手气红包主要还是随机去生成若干个红包值,博主写了一个方法用于生成若干个随机的红包值。代码如下:
<?php
/**
* =======================================
* Created by ZHIHUA·WEI.
* Author: ZHIHUA·WEI
* Date: 2019/06/11
* Time: 12:13
* Power: 拼手气红包生成算法
* =======================================
*/
/**
* 拼手气红包生成算法
* @param $red_total_money
* @param $red_num
* @return array
*/
function redEnvelopeRandomProduce($red_total_money, $red_num)
{
//1 声明定义最小红包值
$red_min = 0.01;
//2 声明定义生成红包结果
$result_red = array();
//3 惊喜红包计算
for ($i = 1; $i < $red_num; $i++) {
//3.1 计算安全上限 | 保证每个人都可以分到最小值
$safe_total = ($red_total_money - ($red_num - $i) * $red_min) / ($red_num - $i);
//3.2 随机取出一个数值
$red_money_tmp = mt_rand($red_min * 100, $safe_total * 100) / 100;
//3.3 将金额从红包总金额减去
$red_total_money -= $red_money_tmp;
$result_red[] = array(
'red_code' => $i,
'red_title' => '红包' . $i,
'red_money' => $red_money_tmp,
);
}
//4 最后一个红包
$result_red[] = array(
'red_code' => $red_num,
'red_title' => '红包' . $red_num,
'red_money' => $red_total_money,
);
return $result_red;
}
$red_total_money = 10;//红包总额
$red_num = 10;// 分成10个红包
print_r(redEnvelopeRandomProduce($red_total_money, $red_num));
exit;
指定金额红包
关于指定金额红包的这里就不写代码进行描述了,主要输入每个红包多少钱,一共多少个红包即可。
抢超情况
这个和秒杀商品处理有点相同,我们可以借助redis的队列进行处理,新建一个队列先进队的可以抢到红包,后进队的抢不到红包;具体思路如下:
- 根据所发红包数量,创建redis红包队列;
- 客户端访问抢红包API ;
- web服务器先从redis红包队列 中查询剩余数量;
- redis队列中有剩余,则在mysql中创建抢购成功,去除红包数量,抢红包成功 ;
- redis队列中没有剩余,则提示已抢完,抢红包失败。