流量削峰案例:Redis的List类型实现秒杀
一:这种情况下使用redis比较有优势:
- redis基于内存而mysql基于硬盘,速度快。
- 用的数据库本就是mysql,这时再用mysql进行队列缓存更造成了mysql的负担
- redis比memcahe的优势在于 redis定时的将数据持久化到硬盘
二:
Redis list
LPUSH/LPUSHX :将值插入到(/存在的)列表头部
RPUSH/RPUSHX :将值插入到(/存在的)列表尾部
LPOP :移出并获取列表的第一个元素
RPOP :移出并获取列表的最后一个元素
LTRIM :保留指定区间内的元素
LLEN :获取列表长度
LSET :通过索引设置列表元素的值
LINDEX :通过索引获取列表中的元素
LRANGE :获取列表中指定范围内的元素
三:架构设计
四:代码级设计
- 秒杀程序把请求写入Redis.(Uid, time_stamp)
- 检查Redis已存放数据的长度,超出上限直接丢弃
- 死循环处理存入Redis的数据并入库
五: redis_queue数据库表的SQL语句:
CREATE TABLE `redis_queue` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`uid` int(11) NOT NULL DEFAULT '0',
`time_stamp` varchar(24) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=71 DEFAULT CHARSET=utf8;
User.php
<?php
$redis = new Redis();
$redis->connect('127.0.0.1',6379);
$redis_name = "miaosha";
for($i=1;$i<100;$i++){
$uid = rand(100000,999999);
//接受用户的id
//$uid = $_GET['uid'];
//获取redis里面已有的数量
$num = 10;
//如果当天人数少于10时,则加入这个队列
if($redis->lLen($redis_name)<10) {
$redis->rPush($redis_name,$uid.'%'.microtime());
echo $uid."秒杀成功";
}else{
//反之,则返回秒杀已完成
echo "秒杀已结束";
}
$redis->close();
}
savetodb.php
<?php
include '../include/db.php';
$redis = new Redis();
$redis->connect('127.0.0.1',6379);
$redis_name = "miaosha";
$db = DB::getIntance();
//死循环
while (1) {
//从队列最左侧取出一个值来,
$user = $redis->lPop($redis_name);
//然后判断这个值是否存在,
if(!$user || $user=='nil') {
sleep(2);
continue;
}
//切割出时间,uid
$user_arr = explode('%',$user);
$insert_data = array(
'uid' =>$user_arr[0],
'time_stamp'=>$user_arr[1]
);
//保存导数据库中
$res = $db->insert('redis_queue',$insert_data);
//数据插入失败的时候的回滚机制
if(!$res) {
$redis->rPush($redis_name,$user);
}
sleep(2);
}
//释放一下redis
$redis->close();