Go 언어는 go-redis를 연결하여 데이터베이스에 연결합니다. 아직 이 부분을 이해하지 못한다면 이 부분을 먼저 학습하는 것이 좋습니다.
그리고 이번 플래시세일은 주로 두 가지 문제를 해결하는데, 첫 번째는 과매도 문제이고, 다른 하나는 재고 문제입니다.
동시성을 시뮬레이션하도록 설계된 특별한 페이지는 없으며 요청을 호출하기 전에 goroutine을 직접 사용하고 10초 동안 유지됩니다.
과매도 문제를 해결하려면 트랜잭션 처리(낙관적 잠금과 동일) 기능을 갖춘 go-redis watch를 도입하세요.
인벤토리 문제는 좀 더 번거롭습니다. 스크립트를 편집하려면 Lua를 사용해야 하지만, 자체 컴퓨터에 Lua 컴파일 환경을 다운로드할 필요는 없습니다. Go는 관련 지원을 제공합니다. 이 부분에 대해서는 당황하지 마십시오. 기본 구조는 다음과 같습니다.
동시 상황에서는 Redis 데이터베이스에 과매도 및 음수 값이 나타날 수 있습니다. 조작하기 전에 데이터에 대한 판단을 한다고 해도 마찬가지입니다.
func MsCode(uuid, prodid string) bool { // 1、对uuid和prodid进行非空判断 if uuid == "" || prodid == "" { return false } //2、获取连接 rdb := DB //3、拼接key kcKey := "kc:" + prodid + ":qt" userKey := "sk:" + prodid + ":user" //4、获取库存 str, err := rdb.Get(ctx, kcKey).Result() if err != nil { fmt.Println(err) fmt.Println("秒杀还未开始.......") return false } // 5、判断用户是否重复秒杀操作 flag, err := rdb.SIsMember(ctx, userKey, userKey).Result() if err != nil { fmt.Println(err) } if flag { fmt.Println("你已经参加了秒杀,无法再次参加。。。。") return false } // 6、判断商品数量,如果库存数量小于1,秒杀结束 str, err = rdb.Get(ctx, kcKey).Result() if err != nil { fmt.Println(err) } n, err := strconv.Atoi(str) if err != nil { fmt.Println(err) } if n < 1 { fmt.Println("秒杀结束,请下次再来吧。。。。") return false } // 7、秒杀过程 // 7.1、库存减1 num, err := rdb.Decr(ctx, kcKey).Result() if err != nil { fmt.Println(err) } if num != 0 { // 7.2、添加用户 rdb.SAdd(ctx, userKey, uuid) } return true } func main() { // 并发的版本 for i := 0; i < 20; i++ { go func() { uuid := GenerateUUID() prodid := "1023" time.Sleep(10 * time.Second) MsCode(uuid, prodid) }() } time.Sleep(15 * time.Second) }
시계를 사용하여 키를 모니터링하세요. 하지만 이런 상황은 재고가 남아도 구매하지 못하는 분들이 계실 텐데요.
err = rdb.Watch(ctx, func(tx *redis.Tx) error { n, err := tx.Get(ctx, kcKey).Int() if err != nil && err != redis.Nil { return err } if n <= 0 { return fmt.Errorf("抢购结束了!请下次早点来。。。。") } _, err = tx.TxPipelined(ctx, func(pipeliner redis.Pipeliner) error { err := pipeliner.Decr(ctx, kcKey).Err() if err != nil { return err } err = pipeliner.SAdd(ctx, userKey, uuid).Err() if err != nil { return err } return nil }) return err }, kcKey)
Lua는 Redis를 운영하여 이 문제를 더 잘 해결할 수 있습니다. Redis에서 비관적 잠금으로 인해 발생할 수 있는 인벤토리 문제를 방지하려면 낙관적 잠금 사용을 고려해야 합니다. Redis에는 낙관적 잠금 지원이 내장되어 있지 않기 때문에 Lua를 사용하여 관련 스크립트를 작성해야 합니다. 주로 다음과 같은 장점이 있습니다.
복잡하거나 다단계 Redis 작업을 스크립트로 작성하고 Redis에 제출하여 한 번에 실행하면 반복되는 Redis 연결 횟수가 줄어듭니다. 성능을 향상시킵니다.
luan 스크립트는 redis 트랜잭션과 유사하고 어느 정도의 원자성을 가지며 다른 명령에 의해 대기열에 추가되지 않으며 일부 Redis 트랜잭션 작업을 완료할 수 있습니다.
redis의 Lua 스크립트 기능은 redis2.6 이상 버전에서만 사용할 수 있습니다.
lua 스크립트를 사용하여 사용자를 제거하고 과잉 판매 문제를 해결하세요.
redis 버전 2.6 이후 경합 문제는 Lua 스크립트를 통해 해결되었습니다. 실제로 Redis는 단일 스레드 기능을 사용하여 작업 대기열을 사용하여 다중 작업 동시성 문제를 해결합니다.
위 내용은 Go와 Lua를 사용하여 Redis 플래시 세일의 재고 및 과판매 문제를 해결하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!