怎么利用Redis锁解决高并发

62次阅读
没有评论

共计 3296 个字符,预计需要花费 9 分钟才能阅读完成。

自动写代码机器人,免费开通

丸趣 TV 小编给大家分享一下怎么利用 Redis 锁解决高并发,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!

redis 技术的使用:

redis 真的是一个很好的技术,它可以很好的在一定程度上解决网站一瞬间的并发量,例如商品抢购秒杀等活动。。。

redis 之所以能解决高并发的原因是它可以直接访问内存,而以往我们用的是数据库 (硬盘), 提高了访问效率, 解决了数据库服务器压力。

为什么 redis 的地位越来越高,我们为何不选择 memcache,这是因为 memcache 只能存储字符串,而 redis 存储类型很丰富(例如有字符串、LIST、SET 等),memcache 每个值最大只能存储 1M, 存储资源非常有限, 十分消耗内存资源, 而 redis 可以存储 1G, 最重要的是 memcache 它不如 redis 安全, 当服务器发生故障或者意外关机等情况时,redsi 会把内存中的数据备份到硬盘中, 而 memcache 所存储的东西全部丢失; 这也说明了 memcache 不适合做数据库来用, 可以用来做缓存。

引言

这里我们主要利用 Redis 的 setnx 的命令来处理高并发。

setnx 有两个参数。第一个参数表示键。第二个参数表示值。如果当前键不存在,那么会插入当前键,将第二个参数做为值。返回 1。如果当前键存在,那么会返回 0。

创建库存表

CREATE TABLE `storage` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
 `number` int(11) DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1

设置初始库存为 10

创建订单表

CREATE TABLE `order` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
 `number` int(11) DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1

测试不用锁的时候

$pdo = new PDO( mysql:host=127.0.0.1;dbname=test ,  root ,  root 
$sql= select `number` from storage where id=1 limit 1 
$res = $pdo- query($sql)- fetch();
$number = $res[ number 
if($number 0)
 $sql = insert into `order` VALUES (null,$number) 
 $order_id = $pdo- query($sql);
 if($order_id)
 {
 $sql= update storage set `number`=`number`-1 WHERE id=1 
 $pdo- query($sql);
 }
}

ab 测试模拟并发,发现库存是正确的。

mysql  select * from storage;
+----+--------+
| id | number |
+----+--------+
| 1 | 0 |
+----+--------+
1 row in set (0.00 sec)

在来看订单表

mysql  select * from `order`;
+----+--------+
| id | number |
+----+--------+
| 1 | 10 |
| 2 | 10 |
| 3 | 9 |
| 4 | 7 |
| 5 | 6 |
| 6 | 5 |
| 7 | 5 |
| 8 | 5 |
| 9 | 4 |
| 10 | 1 |
+----+--------+
10 rows in set (0.00 sec)

发现存在几个订单都是操作的同一个库存数据,这样就可能引起超卖的情况。

修改代码加入 redis 锁进行数据控制

?php
 * Created by PhpStorm.
 * User: daisc
 * Date: 2018/7/23
 * Time: 14:45
 */
class Lock
 private static $_instance ;
 private $_redis;
 private function __construct()
 { $this- _redis = new Redis();
 $this- _redis - connect( 127.0.0.1 
 }
 public static function getInstance()
 { if(self::$_instance instanceof self)
 {
 return self::$_instance;
 }
 return self::$_instance = new self();
 }
 /**
 * @function  加锁
 * @param $key  锁名称
 * @param $expTime  过期时间
 */
 public function set($key,$expTime)
 {
 // 初步加锁
 $isLock = $this- _redis- setnx($key,time()+$expTime);
 if($isLock)
 {
 return true;
 }
 else
 {
 // 加锁失败的情况下。判断锁是否已经存在,如果锁存在切已经过期,那么删除锁。进行重新加锁
 $val = $this- _redis- get($key);
 if($val $val time())
 { $this- del($key);
 }
 return $this- _redis- setnx($key,time()+$expTime);
 }
 }

$pdo = new PDO( mysql:host=127.0.0.1;dbname=test ,  root ,  root $lockObj = Lock::getInstance(); // 判断是能加锁成功 if($lock = $lockObj- set( storage ,10))  $sql= select `number` from storage where id=1 limit 1  $res = $pdo- query($sql)- fetch();  $number = $res[ number  if($number 0)  { $sql = insert into `order` VALUES (null,$number)  $order_id = $pdo- query($sql);  if($order_id)  {  $sql= update storage set `number`=`number`-1 WHERE id=1  $pdo- query($sql);  }  }  // 解锁  $lockObj- del( storage  // 加锁不成功执行其他操作。}

再次进行 ab 测试,查看测试结果

mysql  select * from `order`;
+----+--------+
| id | number |
+----+--------+
| 1 | 10 |
| 2 | 9 |
| 3 | 8 |
| 4 | 7 |
| 5 | 6 |
| 6 | 5 |
| 7 | 4 |
| 8 | 3 |
| 9 | 2 |
| 10 | 1 |
+----+--------+
10 rows in set (0.00 sec)

发现订单表没有操作同一个库存数据的情况。所以利用 redis 锁是可以有效的处理高并发的。

这里在加锁的时候其实是可以不需要判断过期时间的,这里我们为了避免造成死锁,所以加一个过期时间的判断。当过期的时候主动删除该锁。

看完了这篇文章,相信你对“怎么利用 Redis 锁解决高并发”有了一定的了解,如果想了解更多相关知识,欢迎关注丸趣 TV 行业资讯频道,感谢各位的阅读!

向 AI 问一下细节

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-12-04发表,共计3296字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)