从PHP到GO之导出数据

前情:
生产环境有客户经常从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分钟
结论:
在觉得做到的最优解的时候,换个思路,跳出僵化思维,或许会有意外的收获。