Go-redis:执行 Lua 脚本

go-redis (github.com/redis/go-redis) 支持 Lua 脚本 redis.Script,本文在这里简单展示其在秒杀场景中使用的代码片段。

秒杀场景

在秒杀场景中,一个商品的库存对应了两个信息,分别是总库存量和已秒杀量。可以使用一个 Hash 类型的键值对来保存库存的这两个信息,如下所示:

key: product_id

value: {total: N, ordered: M}

其中,product_id 是商品的编号,total 是总库存量,ordered 是已秒杀量。

因为库存查验库存扣减这两个操作要保证一起执行,一个直接的方法就是使用 Redis 的原子操作。

原子操作可以是 Redis 自身提供的原子命令,也可以是 Lua 脚本。因为库存查验和库存扣减是两个操作,无法用一条命令来完成,所以需要使用 Lua 脚本原子性地执行这两个操作

go 复制代码
package main

import (
 "context"
 "fmt"
 "github.com/redis/go-redis/v9"
)

var stockHIncrBy = redis.NewScript(`
  local key = KEYS[1]
  local change = ARGV[1]

  local values = redis.call("HMGET", key, "total", "ordered")

  local total = tonumber(values[1])
  local ordered = tonumber(values[2])

  if( ordered + change <= total ) then
   redis.call("HINCRBY", key, "ordered", change)
   return change
  end
  return 0
 `)

func main() {
 rdb := redis.NewClient(&redis.Options{
  Addr:     "localhost:6379",
  Password: "",
  DB:       0,
 })

 key := "product_id:10001"                                    // id 为 10001 的商品 key
 value := map[string]interface{}{"total": 100, "ordered": 10} // 插入数据 total 总库存量 ordered 已秒杀量

 ctx := context.Background()
 rdb.HMSet(ctx, key, value) // 设置初始库存

 change := 20 // 库存扣减数量

 keys := []string{key}
 values := []interface{}{change}

 for i := 0; i < 5; i++ { // 尝试扣减库存 5 次
  result, err := stockHIncrBy.Run(ctx, rdb, keys, values...).Int()
  if err != nil {
   // ...
  }
  fmt.Println(result) // 如果返回值是当前请求的库存量,就是成功;如果是 0,就是失败。
 }
}

Lua 脚本的逻辑如下:

  1. 获取商品的 total(总库存量) 和 ordered(已秒杀量) 值。
  2. 检查 ordered(已秒杀量) + change(库存扣减量) 是否小于等于 total(总库存量)。
  • 是:执行 HINCRBY 更新 ordered,返回成功的数量。
  • 否:返回 0,表示库存不足,秒杀失败。

如果当前请求的库存扣减量加上已被秒杀的库存量仍然小于总库存量,就可以更新已秒杀的库存量。根据脚本的返回值,来确定秒杀是成功还是失败了。如果返回值是当前请求的库存量,就是成功了;如果是 0,就是失败。


References

redis.uptrace.dev/zh/guide/lu...

推荐阅读

相关推荐
IT毕设实战小研37 分钟前
电影数据可视化推荐系统
大数据·后端·爬虫·python·算法·信息可视化·课程设计
ssshooter43 分钟前
AI 时代你不能不知道的 git worktree
前端·后端·面试
Cosolar1 小时前
一文弄懂 Agent Harness 与 Agent Runtime 的区别
java·后端·github
长大19881 小时前
Python代码慢?这5个性能优化技巧让速度提升100倍
后端
超超不吵吵2 小时前
Java AI转型实战(十):Agent 智能体初探
后端
步行cgn2 小时前
@AllArgsConstructor 是 Lombok 提供的注解
后端
柠檬味拥抱2 小时前
鸿蒙原生 AI 应用开发实战:用蓝耘 MaaS 给纪念日 App 装上「大模型大脑」
后端
步行cgn2 小时前
Lombok 详解:通过注解消除样板代码
后端
用户41180034153412 小时前
MySql 事务和锁
后端