当前位置:网站首页>GoLang 抽奖系统 设计
GoLang 抽奖系统 设计
2022-07-26 02:57:00 【上后左爱】
业务难点
设计一个抽奖系统,这个系统并不是具体化,是抽象化,具有以下的几个难点:
1、抽奖业务需要 复杂多变
2、奖品类型和概率设置
3、公平的抽奖和安全的发奖
4、并发安全性问题 一个人不能枪多次
5、高效的抽奖和发奖,提供高并发和性能
6、 如何使用redies进行优化
技术选项
- 高并发 Go 协程优先于 PHP多进程,Java的 多线程模型
- 高性能编译后的二进制优先于PHP解释性和Java虚拟机
- 高效的网络模型 epoll 模型优先于PHPBIO模型和Java NIO模型
抽奖活动
- 年会抽奖,彩票刮奖,微信摇一摇,抽奖大转盘,集福卡等活动,本项目以
抽奖大转盘作为一种活动进行设计。 - 项目实战内容: 框架/核心代码后台功能 ,合理设置奖品和发送奖品, mysql+优化-使用redies 发奖计划与奖品池, 压力测试和更多的运营策略(系统的性能有更好的了解,运营产品的策略有更多), 引入 thirft 框架(RPC 框架), 设计接口生成代码, 服务端接口和客户端程序
需求分析
1. go mod 配置
2. 配置国内代理: go env -w GOPROXY=https://goproxy.cn,https://goproxy.io,direct
3. go get -u -v github.com/kataras/iris 下载包在 GOPATH的PKG目录下
4. iris:功能: 安全认证,缓存 cookies 文件 MVC, 模板 丰富的示例代码
5. https://iris-go.com/v10/recipe
*年会抽奖程序
使用的是iris 这个web 框架 进行处理
/** * curl http://localhost:8080/ * curl --data "users=123,567" http://localhost:8080/import * curl http://localhost:8080/lucky */
package main
import (
"fmt"
"github.com/kataras/iris/v12"
"github.com/kataras/iris/v12/mvc"
"math/rand"
"strings"
"sync"
"time"
)
var userList []string // 共享变量读写前后 需要增加 锁的设定 简单方式添加互斥锁
var mu sync.Mutex
type lotteryController struct {
Ctx iris.Context
}
// 启动一个 iris 应用
func newApp() *iris.Application {
app := iris.New()
mvc.New(app.Party("/")).Handle(&lotteryController{
})
return app
}
func main() {
app := newApp()
userList = []string{
}
mu = sync.Mutex{
}
err := app.Listen(":8080")
if err != nil {
panic(fmt.Sprintf("web server start error: %s\n", err))
return
}
}
func (c *lotteryController) Get() string {
count := len(userList)
return fmt.Sprintf("当前总共参与抽奖的用户数:%d\n", count)
}
// PostImport POST http://localhost:8090/import
// params : users
func (c *lotteryController) PostImport() string {
strUsers := c.Ctx.FormValue("users")
users := strings.Split(strUsers, ",")
// 批量线程导入时候 发现有多线程的问题 数据统计不正确
mu.Lock()
defer mu.Unlock()
count1 := len(userList)
for _, u := range users {
u = strings.TrimSpace(u)
if len(u) > 0 {
userList = append(userList, u)
}
}
count2 := len(userList)
return fmt.Sprintf("当前总共参与抽奖的用户数:%d, 成功导入的用户数:%d\n", count2, count2-count1)
}
// GetLucky GET http://localhost:8090/lucky
func (c *lotteryController) GetLucky() string {
// 抽奖地方进行锁的判断
mu.Lock()
defer mu.Unlock()
count := len(userList)
if count > 1 {
index := rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(int32(count))
user := userList[index]
// 需要 删除被挑选过的人 直接可以删除 当前index 下的数据 更好
userList = append(userList[0:index], userList[index+1:]...)
return fmt.Sprintf("当前中奖用户:%s, 剩余用户数:%d\n", user, count-1)
} else if count == 1 {
user := userList[0]
return fmt.Sprintf("当前中奖用户:%s, 剩余用户数:%d\n", user, count-1)
} else {
return fmt.Sprintf("当前中奖完毕,没有用户参与中奖\n")
}
}
单元测试问题,对于 userList 的 多线程下发生数据竞争问题 :
package main
import (
"fmt"
"github.com/kataras/iris/v12/httptest"
"sync"
"testing"
)
func TestMVC(t *testing.T) {
app := newApp()
e := httptest.New(t, app)
// 使用同步等待锁
var wg sync.WaitGroup
e.GET("/").Expect().Status(httptest.StatusOK).Body().Equal("当前总共参与抽奖的用户数:0\n")
for i := 0; i < 100; i++ {
wg.Add(1)
// 不会出现协程并发性问题
go func(i int) {
defer wg.Done()
e.POST("/import").WithFormField("users", fmt.Sprintf("test_u%d", i)).Expect().Status(httptest.StatusOK)
}(i)
}
wg.Wait()
e.GET("/").Expect().Status(httptest.StatusOK).Body().Equal("当前总共参与抽奖的用户数:100\n")
e.GET("/lucky").Expect().Status(httptest.StatusOK)
e.GET("/").Expect().Status(httptest.StatusOK).Body().Equal("当前总共参与抽奖的用户数:99\n")
}
边栏推荐
- How to design test cases according to the requirements of login testing?
- AMD64(x86_64)架构abi文档:中
- Longest Substring Without Repeating Characters
- AMD64 (x86_64) architecture ABI document: medium
- (PC+WAP)织梦模板蔬菜水果类网站
- 这种动态规划你见过吗——状态机动态规划之股票问题(上)
- Personally test five efficient and practical ways to get rid of orders, and quickly collect them to help you quickly find high-quality objects!
- Binary search 33. search rotation sort array
- Turn on the LED
- 持续交付和DevOps是一对好基友
猜你喜欢
随机推荐
GAMES101复习:着色(Shading)、渲染管线
Exclusive interview with ringcentral he Bicang: empowering future mixed office with innovative MVP
Annotation development
Self-supervised learning method to solve the inverse problem of Fokker-Planck Equation
Neo4j 导入csv数据报错:Neo4j load csv error : Couldn‘t load the external resource
Eslint common error reporting set
Image recognition (VII) | what is the pooling layer? What's the effect?
I hope you can help me with MySQL
MySQL教程:MySQL数据库学习宝典(从入门到精通)
MySQL建Websites数据表
How can users create data tables on Web pages and store them in the database
What if the test / development programmer gets old? Lingering cruel facts
How to design automated test cases?
Anti electronic ink screen st7302
循环与分支(一)
【方向盘】工具提效:Sublime Text 4的常用快捷键合集
[early knowledge of activities] list of recent activities of livevideostack
(PC+WAP)织梦模板蔬菜水果类网站
Is it safe to open galaxy securities account by mobile phone?
(九)属性自省








