Golang实现Redis分布式锁解决秒杀问题

先写一个脚本sql,插入2000个用户

INSERT INTO sys_users (mobile, password)
SELECT 
    numbers.n AS mobile,
    '$2a$10$zKQfSn/GCcR6MX4nHk3MsOMhJnI0qxN4MFdiufDMH2wzuTaR9G1sq' AS password
FROM 
    (
        SELECT ones.n + tens.n*10 + hundreds.n*100 + thousands.n*1000 + 1 AS n
        FROM 
            (SELECT 0 AS n UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) ones
            CROSS JOIN (SELECT 0 AS n UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) tens
            CROSS JOIN (SELECT 0 AS n UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) hundreds
            CROSS JOIN (SELECT 0 AS n UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) thousands
        ORDER BY n
    ) numbers
LIMIT 2000;

登录是通过2个字段,一个是mobile,一个是password,生成了mobile从1到2000,密码默认是123456

文章来源地址https://uudwc.com/A/3mbob

然后写一个单元测试,实现新注册的2000个用户登录,然后获取token

package system

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"strings"
	"sync"
	"testing"
	"time"
)

func TestBaseApi_TokenNext(t *testing.T) {
	start := time.Now()
	var wg sync.WaitGroup
	ch := make(chan string, 2000)
	for i := 1; i <= 5; i++ {
		fmt.Println(i)
		wg.Add(1)
		mobile := fmt.Sprintf("%d", i)
		password := "123456"
		go obtainToken(mobile, password, &wg, ch)
	}
	wg.Wait()
	close(ch)

	fmt.Println("All tokens obtained:")
	//tokens := ""
	i := 0
	for token := range ch {
		fmt.Println(i, token)
		i++
		err := AppendStringToFile("E:\\Go\\goproject\\LearnExam\\sever\\token.txt", token)
		if err != nil {
			fmt.Println(err)
		}
	}

	end := time.Now()
	latency := end.Sub(start)
	fmt.Println(fmt.Sprintf(" takes %v", latency))
}
func AppendStringToFile(filePath string, content string) error {
	file, err := os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		return err
	}
	defer file.Close()

	_, err = file.WriteString(content + "\n")
	if err != nil {
		return err
	}

	return nil
}
func obtainToken(mobile, password string, wg *sync.WaitGroup, ch chan string) {
	defer wg.Done()
	type Body struct {
		Mobile   string `json:"mobile"`
		Password string `json:"password"`
	}
	b := Body{
		mobile, password,
	}

	bodymarshal, err := json.Marshal(&b)
	if err != nil {
		return
	}
	//再处理一下
	reqBody := strings.NewReader(string(bodymarshal))
	req, err := http.NewRequest("POST", "http://127.0.0.1:8888/api/base/login", reqBody)
	if err != nil {
		fmt.Printf("Error creating request for user %s: %v\n", mobile, err)
		return
	}

	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		fmt.Printf("Error sending request for user %s: %v\n", mobile, err)
		return
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body) //把请求到的body转化成byte[]
	if err != nil {
		return
	}
	type Result struct {
		Data struct {
			Token string `json:"token"`
		} `json:"data"`
	}
	r := Result{}
	err = json.Unmarshal(body, &r)
	if err != nil {
		return
	}
	if resp.StatusCode == http.StatusOK {

		ch <- r.Data.Token
		fmt.Printf("Token obtained for user %s\n", mobile)
	} else {
		fmt.Printf("Failed to obtain token for user %s\n", mobile)
	}

}

我们使用有缓冲的通道和sync.WaitGroup信号量,来控制协程的数量在2000个以内

阅读剩余 61%

原文地址:https://blog.csdn.net/sunriseYJP/article/details/132136325

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请联系站长进行投诉反馈,一经查实,立即删除!

上一篇 2023年08月08日 09:18
【雕爷学编程】Arduino动手做(193)---移远 BC20 NB+GNSS模块13
下一篇 2023年08月08日 09:18