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 了(因为是异步,所以总时间是最大那个的耗时)