PHP 中Lua嵌入redis

Posted Json2011315

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PHP 中Lua嵌入redis相关的知识,希望对你有一定的参考价值。

Lua 嵌入 Redis 优势:

  1. 减少网络开销: 不使用 Lua 的代码需要向 Redis 发送多次请求, 而脚本只需一次即可, 减少网络传输;
  2. 原子操作: Redis 将整个脚本作为一个原子执行, 无需担心并发, 也就无需事务;
  3. 复用: 脚本会永久保存 Redis 中, 其他客户端可继续使用.

注意:

首先要了解redis事务是不会滚的,所以在lua中嵌入多条redis执行,只是保证多条redis具有原子操作(不是mysql事务的原子性哦),原子操作指的是多条命令执行成功就是成功,其中一条执行就会失败,但是成功执行的redis命令不会回滚

编写php代码

redis_lua.php

<?php 
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

/*
模拟场景下单支付成功需要操作的redis:
1.扣减redis锁定的库存
2.添加redis待发货库存
3.添加redis商品销量
4.减少redis可销量库存

原始redis缺点:
1.命令多次发送,消耗IO
*/

/*
php引入lua脚本:https://www.php.net/manual/zh/book.lua.php
	
PHP引入lua方式执行redis原因:
    1.减少网络开销: 不使用 Lua 的代码需要向 Redis 发送多次请求, 而脚本只需一次即可, 减少网络传输;
    2.原子操作: Redis 将整个脚本作为一个原子执行, 无需担心并发, 也就无需事务;
    3.复用: 脚本会永久保存 Redis 中, 其他客户端可继续使用.

需要注意的是:
redis事务地址:https://blog.csdn.net/baidu_23086307/article/details/80461668?utm_source=blogxgwz7
首先要了解redis事务是不会滚的,所以在lua中嵌入多条redis执行,只是保证多条redis具有原子操作(不是mysql事务的原子性哦),原子操作指的是多条命令执行成功就是成功,其中一条执行就会失败,但是成功执行的redis命令不会回滚
*/

/*
 先手动在redis中添加锁定库存,待发货单库存,销量,可销量
 mset STOCK_LOCK_KEY 10 STOCK_FREEZE_KEY 0  GOODS_VALUME_KEY 0 STOCK_SALE_KEY 10
 */

/**
 * 地址:https://www.php.net/manual/zh/lua.eval.php
 * @param $lua_redis 第一个参数 lua中嵌入redis的字符串
 * @param $stock_lock  redis锁定的库存的key
 * @param $stock_lock_num 需要操作的锁定库存
 *
 * @param $stock_freeze redis待发货库存的key
 * @param $stock_freeze_num  需要操作的待发货库存
 *
 * @param $goods_volume redis商品销量key
 * @param $goods_valume_num 需要操作的商品销量
 *
 * @param $stock_sale redis可销量库存key
 * @param $stock_sale_num 需要操作的可销量
 *
 * @param $key_value_numbers 键值对数值
 */

//操作的数量
$goods_num=6;

$stock_lock='STOCK_LOCK_KEY';
$stock_lock_num=$goods_num;

$stock_freeze="STOCK_FREEZE_KEY";
$stock_freeze_num=$goods_num;

$goods_volume="GOODS_VALUME_KEY";
$goods_valume_num=$goods_num;

$stock_sale="STOCK_SALE_KEY";
$stock_sale_num=$goods_num;

//lua 嵌入redis
$lua_redis=<<<SCRIPT
    local stock_lock=KEYS[1]
    local stock_freeze=KEYS[2]
    local goods_volume=KEYS[3]
    local stock_sale=KEYS[4]
    
    local stock_lock_num=ARGV[1]
    local stock_freeze_num=ARGV[2]
    local goods_volume_num=ARGV[3]
    local stock_sale_num=ARGV[4]
    
    local stock_lock_res=redis.call("DECRBY",stock_lock,stock_lock_num)
    local stock_freeze_res=redis.call("INCRBY",stock_freeze,stock_freeze_num)
    local goods_volume_res=redis.call("INCRBY",goods_volume,goods_volume_num)
    local stock_sale_res=redis.call("DECRBY",stock_sale,stock_sale_num)
    
    return stock_freeze_res
SCRIPT;

//键值对数值
$key_value_numbers=4;
$paramsArr=array($stock_lock,$stock_freeze,$goods_volume,$stock_sale,$stock_lock_num,$stock_freeze_num,$goods_valume_num,$stock_sale_num);
$res  = $redis->eval($lua_redis,$paramsArr,$key_value_numbers);
var_dump($res);

进入redis-cli客户端,先添加数据

127.0.0.1:6379> mset STOCK_LOCK_KEY 10 STOCK_FREEZE_KEY 0  GOODS_VALUME_KEY 0 STOCK_SALE_KEY 10
OK
127.0.0.1:6379> keys *
1) "STOCK_FREEZE_KEY"
2) "GOODS_VALUME_KEY"
3) "STOCK_SALE_KEY"
4) "STOCK_LOCK_KEY"
127.0.0.1:6379> 

php cli方式执行redis_lua.php

[root@localhost phpwww]# php redis_lua.php 
int(6)

redis-cli客户端,查看数据

127.0.0.1:6379> mget STOCK_LOCK_KEY STOCK_FREEZE_KEY GOODS_VALUME_KEY STOCK_SALE_KEY
1) "4"
2) "6"
3) "6"
4) "4"

以上是关于PHP 中Lua嵌入redis的主要内容,如果未能解决你的问题,请参考以下文章

Redis使用LUA脚本

Redis使用LUA脚本

Redis与Lua脚本

redis lua脚本有啥用

Redis入门 - Lua脚本

Redis中如何优雅地使用Lua脚本