logo

一个兴趣使然的程序员

春节

从PHP到GO之导出数据

2020-03-25 Views go | excel | 性能 | php436字2 min read
featureimg

前情:

生产环境有客户经常从ES中导出不同时段的数据,一天数据大概有12W,现有的php导出速度在优化之后一次导出耗时需要27-35分钟,所以有了这次优化。

开始:

HBASE + ES

因为现在的主要耗时在于从es获取数据时的耗时比较久,首先尝试了,将相对大的数据字段存储到HBASE,然后每次查询都从es获取ID,再从HBASE获取文本的数据。经测试从ES + HBASE比单纯ES快,但是效果不显著,还是不能满足客户需要。

从PHP到Golang

在改造了存储结构没有好的结果的时候,从头理了一下整个流程。发现因为语言的限制php每次只有一个并发从ES取数据,那么我们使用高并发的语言GO来并发的从ES拿数据,速度应该会提升不少。选中了常用的go-for-es插件olivere/elastic.v5 。

首先我们再main里面以10个goroutine从ES拿数据。

    count := 10
	ch := make(chan bool, count)
	for i := 0; i < count; i++ {
		go queryEs(ch, i)
	}
	for i := 0; i < count; i++ {
		<-ch
	}
    sliceQuery := NewSliceQuery().Id(i).Max(10)
	boolQ := elastic.NewBoolQuery()
	boolQ.Must(elastic.NewMatchQuery("ai_status", 3))
	boolQ.Filter(elastic.NewRangeQuery("create_time").Gt(1583337600))
	boolQ.Filter(elastic.NewRangeQuery("create_time").Lt(1585151999))
	svc := client.Scroll("index").Query(boolQ).Slice(sliceQuery).Size(800)

然后就是对数据的处理:

    result, err := svc.Do(context.TODO())
		if err == io.EOF {
			break
		}

		if err != nil {
			//fmt.Printf(err)
			break
		}

		for _, r := range result.Hits.Hits {
			jsonstring := *r.Source
			var source Source
			err = json.Unmarshal(jsonstring, &source)

经测试导出数据20W条数据只需要10分钟

结论:

在觉得做到的最优解的时候,换个思路,跳出僵化思维,或许会有意外的收获。

EOF