Golang优化DSP系统一例
Contents
JSON 解析
更新:2017-6-12 !!这里有问题,参考下文
因为是与微博WAX那边对接,使用的是JSON序列化协议,但偏偏Golang的标准库里的JSON解析却极慢。然后使用了 ffjson ,到 easyjson ,最后到现在的 jsoniter :
data, _ := ioutil.ReadAll(request.Body)
var bidRequest bean.BidRequest
err := jsoniter.Unmarshal(data, &bidRequest)
easyjson 比 ffjson 还快一点(但不是很明显),最后测试用了下 jsoniter ,发现差距还是很大(当然,要检测反序列化出来的结果是一致的,这个库还是有点限制,目前对自定义的 json 接口不友好)
下面是使用 ffjson 时监测到的性能数据
. . 20: if request.Method == "POST" {
. . 21: s := utils.CurrentMillis()
. 140ms 22: data, _ := ioutil.ReadAll(request.Body)
. . 23: //logrus.Infof("receive body =>%v", string(data))
. 20ms 24: var bidRequest bean.BidRequest
. 490ms 25: err := ffjson.UnmarshalFast(data, &bidRequest)
下面是使用 jsoniter 时监测到的性能数据
. . 21: if request.Method == "POST" {
. . 22: s := utils.CurrentMillis()
. 110ms 23: data, _ := ioutil.ReadAll(request.Body)
. . 24: //logrus.Infof("receive body =>%v", string(data))
. . 25: var bidRequest bean.BidRequest
. 80ms 26: err := jsoniter.Unmarshal(data, &bidRequest)
可以看到,还是提升得很大的。
这个 jsoniter 有内存泄漏的问题 !!!!!
后感:看来以后用国产的东西,真心要注意,打醒十二万精神!!!还是弃用它了,凡是打着高性能的旗号的,极可能写的代码是有问题的!换了这个JSON库后,内存升到 54% 多了(8GB物理内存),一般情况下,该进程占用的内存为 2%, 3 % 左右。
异步获取数据
在进行性能监测时,发现有个方法占用了极大的总时间:
0 960ms (flat, cum) 24.55% of Total
. . 3:import "github.com/company/golang-dsp-bid/bean"
. . 4:
. . 5:// CheckServiceISOk :
. . 6:// check ok
. . 7:func CheckServiceISOk(task *bean.TaskPostAd, price int32) bool {
. 520ms 8: taskMoneyMap := GetTaskMoneyRedis(task)
. 250ms 9: clientMoneyMap := GetClientMoney(task.UserID, task.ClientID)
. 190ms 10: userMoneyMap := GetUserMoney(task.UserID)
. . 11:
. . 12: if len(taskMoneyMap) == 0 || len(clientMoneyMap) == 0 || len(userMoneyMap) == 0 {
. . 13: return false
. . 14: }
这个是检测金额是否OK的,因为这里是串行了,所以时间是累加的,这里的结果是取样时累计的耗时(即30秒内,这个方法累计耗时)为 960ms 。
其实这里是可以分3个 goroutine 来获取,然后再汇总:
/Users/emacsist/Documents/go/company/dsp-bid/src/github.com/company/golang-dsp-bid/service/CheckService.go
0 410ms (flat, cum) 9.40% of Total
. . 12:
. . 13: var taskMoneyMap map[string]string
. . 14: wg.Add(1)
. . 15: go func(wg *sync.WaitGroup) {
. . 16: defer wg.Done()
. 370ms 17: taskMoneyMap = GetTaskMoneyRedis(task)
. 40ms 18: }(&wg)
. . 19:
. . 20: var clientMoneyMap map[string]string
. . 21: wg.Add(1)
. . 22: go func(wg *sync.WaitGroup) {
. . 23: defer wg.Done()
ROUTINE ======================== github.com/company/golang-dsp-bid/service.CheckServiceISOk.func2 in /Users/emacsist/Documents/go/company/dsp-bid/src/github.com/company/golang-dsp-bid/service/CheckService.go
10ms 170ms (flat, cum) 3.90% of Total
. . 17: taskMoneyMap = GetTaskMoneyRedis(task)
. . 18: }(&wg)
. . 19:
. . 20: var clientMoneyMap map[string]string
. . 21: wg.Add(1)
10ms 10ms 22: go func(wg *sync.WaitGroup) {
. . 23: defer wg.Done()
. 160ms 24: clientMoneyMap = GetClientMoney(task.UserID, task.ClientID)
. . 25: }(&wg)
. . 26:
. . 27: var userMoneyMap map[string]string
. . 28: wg.Add(1)
. . 29: go func(wg *sync.WaitGroup) {
ROUTINE ======================== github.com/company/golang-dsp-bid/service.CheckServiceISOk.func3 in /Users/emacsist/Documents/go/company/dsp-bid/src/github.com/company/golang-dsp-bid/service/CheckService.go
0 190ms (flat, cum) 4.36% of Total
. . 26:
. . 27: var userMoneyMap map[string]string
. . 28: wg.Add(1)
. . 29: go func(wg *sync.WaitGroup) {
. . 30: defer wg.Done()
. 180ms 31: userMoneyMap = GetUserMoney(task.UserID)
. 10ms 32: }(&wg)
. . 33:
. . 34: wg.Wait()
. . 35:
. . 36: if len(taskMoneyMap) == 0 || len(clientMoneyMap) == 0 || len(userMoneyMap) == 0 {
. . 37: return false
优化完后,可以看到降低到 410ms 了(因为是异步,所以总时间是最大那个的耗时)