Redis实现秒杀功能

Redis使用watch完成秒杀抢购功能:

redis使用watch完成秒杀抢购功能:
使用redis中两个key完成秒杀抢购功能,mywatchkey用于存储抢购数量和mywatchlist用户存储抢购列表。它的优点如下:

1.首先选用内存数据库来抢购速度极快。
2. 速度快并发自然没不是问题。
3. 使用悲观锁,会迅速增加系统资源。
4. 比队列强的多,队列会使你的内存数据库资源瞬间爆棚。
5. 使用乐观锁,达到综合需求。

代码如下:

<?php 
header("content-type:text/html;charset=utf-8"); 
$redis = new redis(); 
$result = $redis->connect('10.10.10.119', 6379); 
$mywatchkey = $redis->get("mywatchkey"); 
$rob_total = 100;   //抢购数量
if($mywatchkey<$rob_total){ 
	$redis->watch("mywatchkey"); 
	$redis->multi(); 
	 //设置延迟,方便测试效果。 
	 sleep(5); 
	  //插入抢购数据
	  $redis->hSet("mywatchlist","user_id_".mt_rand(1, 9999),time());
	  $redis->set("mywatchkey",$mywatchkey+1); 
	  $rob_result = $redis->exec(); 
	   if($rob_result){ 
	   		$mywatchlist = $redis->hGetAll("mywatchlist");
	   		echo "抢购成功!<br/>";
	   		echo "剩余数量:".($rob_total-$mywatchkey-1)."<br/>"; 
	   		echo "用户列表:<pre>"; 
	   		var_dump($mywatchlist); 
	  }else{
	  	echo "手气不好,再抢购!";exit;  
	  }
}
?>	

摘自 http://blog.csdn.net/Evankaka/article/details/70570200

本文使用redis来实现乐观锁,并以秒杀系统为实例来讲解整个过程

乐观锁
大多数是基于数据版本(version)的记录机制实现的。即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个”version”字段来实现读取出数据时,将此版本号一同读出,之后更新时,对此版本号加1。此时,将提交数据的版本号与数据库表对应记录的当前版本号进行比对,如果提交的数据版本号大于数据库当前版本号,则予以更新,否则认为是过期数据。redis中可以使用watch命令会监视给定的key,当exec时候如果监视的key从调用watch后发生过变化,则整个事务会失败。也可以调用watch多次监视多个key。这样就可以对指定的key加乐观锁了。注意watch的key是对整个连接有效的,事务也一样。如果连接断开,监视和事务都会被自动清除。当然了exec,discard,unwatch命令都会清除连接中的所有监视。

Redis事务
Redis中的事务(transaction)是一组命令的集合。事务同命令一样都是Redis最小的执行单
位,一个事务中的命令要么都执行,要么都不执行。Redis事务的实现需要用到 MULTI 和
EXEC 两个命令,事务开始的时候先向Redis服务器发送 MULTI 命令,然后依次发送需要在
本次事务中处理的命令,最后再发送 EXEC 命令表示事务命令结束。Redis的事务是下面4
个命令来实现

1.multi,开启Redis的事务,置客户端为事务态。
2.exec,提交事务,执行从multi到此命令前的命令队列,置客户端为非事务态。
3.discard,取消事务,置客户端为非事务态。
4.watch,监视键值对,作用时如果事务提交exec时发现监视的监视对发生变化,事务将被取消。

下面笔者简单实现一个用redis乐观锁实现的秒杀系统
和上文的使用悲观锁相比,乐观锁的实现更加的简单,并发性能也会更好

1、分布式锁
分布式锁在是一种用来安全访问分式式机器上变量的安全方案,一般用在全局id生成,秒杀系统,全局变量共享、分布式事务等。一般会有两种实现方案,一种是悲观锁的实现,一种是乐观锁的实现。悲观锁的并发性能差,但是能保证不会发生脏数据的可能性小一点。

2、Redis命令介绍
使用Redis实现分布式锁,有两个重要函数需要介绍

======================================
SETNX命令(SET if Not eXists)
语法:
SETNX key value
功能:
当且仅当 key 不存在,将 key 的值设为 value ,并返回1;若给定的 key 已经存在,则SETNX 不做任何动作,并返回0

======================================
GETSET命令(这是一个原子命令!)
语法:
GETSET key value
功能:
将给定 key 的值设为 value ,并返回 key 的旧值 (old value),当 key 存在但不是字符串类型时,返回一个错误,当key不存在时,返回nil

======================================
GET命令
语法:
GET key
功能:
返回 key 所关联的字符串值,如果 key 不存在那么返回特殊值 nil 。

======================================
DEL命令
语法:
DEL key [KEY …]
功能:
删除给定的一个或多个 key ,不存在的 key 会被忽略

    原文作者:隔壁小张丶
    原文地址: https://blog.csdn.net/weixin_44699468/article/details/89362099
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞