记一次百亿级es数据性能优化-未完成

先说结论和todo
结论:
todo:1.SSD没发挥性能问题问题继续测试
2.数据分片数量&大小对性能影响
3.行业对比,es最快就只能达到1亿1s的性能吗?

正好赶上一个规模比较大的项目,2000多台机器,所有组件及任务日志全部都要采集,我们采用的方案是Elasticsearch+logstash+filebeat的方案。

在项目上线一个月左右,出现了数据查询报错的问题,报错读超时SocketTimeoutException Read timed out。通过curl查询需要几十秒才能返回结果。这里首先想是解决jest的访问超时问题,后来想了想我们的业务场景,几十秒基本就为不可用了。所以还是应该优先解决es查询慢的问题。

jestClient execute exceptionjava.net.SocketTimeoutException: Read timed out
2019-11-08 11:36:09.175 [http-nio-8080-exec-4] ERROR c.b.m.r.m.j.service.JournalService -jestClient execute exception
java.net.SocketTimeoutException: Read timed out
	at java.net.SocketInputStream.socketRead0(Native Method)
	at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
	at java.net.SocketInputStream.read(SocketInputStream.java:171)
	at java.net.SocketInputStream.read(SocketInputStream.java:141)
	at org.apache.http.impl.io.SessionInputBufferImpl.streamRead(SessionInputBufferImpl.java:137)
	at org.apache.http.impl.io.SessionInputBufferImpl.fillBuffer(SessionInputBufferImpl.java:153)
	at org.apache.http.impl.io.SessionInputBufferImpl.readLine(SessionInputBufferImpl.java:282)
	at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:138)
	at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:56)
	at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:259)
	at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:163)
	at org.apache.http.impl.conn.CPoolProxy.receiveResponseHeader(CPoolProxy.java:165)
	at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:273)
	at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125)
	at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:272)
	at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185)
	at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
	at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:111)
	at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
	at my.io.searchbox.client.http.JestHttpClient.executeRequest(JestHttpClient.java:133)
	at my.io.searchbox.client.http.JestHttpClient.execute(JestHttpClient.java:67)
	at my.io.searchbox.client.http.JestHttpClient.execute(JestHttpClient.java:60)
	at com.bonc.manager.rest.modules.journal.service.impl.JournalServiceImpl.queryPhrase(JournalServiceImpl.java:122)
	at com.bonc.manager.rest.modules.journal.controller.JournalController.queryPhrase(JournalController.java:44)
	at com.bonc.manager.rest.modules.journal.controller.JournalController$$FastClassBySpringCGLIB$$c46d4359.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:746)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)

看了下此时的数据量,占用大小6T,日志条数在100亿+,其中95%以上为任务日志,这里因为是同事发现的,只记得大概数据。我们原来的方案设计很简单,只有一个索引,分片为默认的,自此开始了我们的优化测试之路。

背景说明

ES集群:8台256G内存32c服务器,1台管理节点,7台数据节点。
业务:支撑移动2000节点组件日志及任务日志,主要包括全文检索,简单范围检索,聚合检索三种场景。
  具体可以看最后的场景测试脚本。
系统:设计最大支撑数据30T, 数据量500亿。

测试方案:

1.索引大小对性能的影响
2.SSD对性能的影响
3.分片数量及大小对性能的影响

测试结果

性能与索引大小成线性关系。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vU1LoZy0-1578994055590)(https://i.loli.net/2020/01/14/TfC5aoDutZOcseg.png)]

SSD对性能影响有限。

分片数量及大小对性能的影响因时间关系未展开测试。

针对SSD补充测试

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y157WQno-1578994055600)(https://i.loli.net/2020/01/14/1EahMGv3cilkPjq.png)]
上图可看出,无缓存情况下SSD速度比机械硬盘还快一个数量级,但是在缓存情况下两者性能一致。

修改方案

根据以上测试结果。
目前评估数据量,峰值单日6T,100亿左右;预估峰值5倍,30T,500亿数据。
目前数据每天一个索引,单索引数据量过大,需要进行改造,将索引进行拆分;
目前任务日志所占数据量达到90%+,预计最大500亿;
需要先将任务日志拆除,然后任务日志还需要按照任务ID进行拆分,将数据放到不同的索引。(此部分通过logtstash的ruby脚本实现)
索引拆分的方式采用hash的方式,预先定义100个索引,根据hash结果存入对应索引。
这样但索引的平均数据量最大为5亿,

通过测试,在5亿数据量的情况下,
分页查询时间平均为5-10秒左右;
全文检索时间在5-10s;
聚合查询时间为10-20s;

以上情况为清除缓存后首次查询情况,使用缓存性能可提高1-2个数量级。
增加预热功能及模块,提前将相关数据加载到缓存。(此部分未做)
通过以上分析,经过改造,可以满足应用需求。

找了各种优化的方式,感觉都不是很理想。

关于造数据:

很多时间花在了造数据上,造数据我们没有用什么高大上的并发写入啥的,就是在通过在原始文件追加,然后filebeat采集进行的。这里花的时间最大,造数据的性能基本上上机械硬盘1亿/条,SSD 2-3亿/条(此处数据不甚精确)。

造数据优化,副本数修改为0,刷新索引间隔refresh_interval调大为60s。
参考:https://www.infoq.cn/article/HAdBrlW6FAO0FmshXKpZ

造数据过程曾想过使用es索引拷贝功能,在高版本es中,有专门的命令。我们用的es5.4版本中有类似命令reindex,可以重建索引,但是实际使用过程中,一是速度不够快,与造数据差不多,二是遇到字段长度超长问题。

在HDD与SSD差异测试过程中,尝试通过迁移分区shade的方式进行测试,速度同样很慢,与造数据类似,遂未使用该方案。

curl -XPOST 'http://172.16.31.154:9200/_reindex' -d '{"source":{"index":"testlog-2019-12-05--es_81"},"dest":{"index":"testindex"}}'
{
  "took": 599,
  "timed_out": false,
  "total": 324729043,
  "updated": 0,
  "created": 998,
  "deleted": 0,
  "batches": 1,
  "version_conflicts": 0,
  "noops": 0,
  "retries": {
    "bulk": 0,
    "search": 0
  },
  "throttled_millis": 0,
  "requests_per_second": -1.0,
  "throttled_until_millis": 0,
  "failures": [
    {
      "index": "testindex",
      "type": "sparktask",
      "id": "AW7Uh6AVpTSwMGQPHoIa",
      "cause": {
        "type": "illegal_argument_exception",
        "reason": "Document contains at least one immense term in field=\"message\" (whose UTF8 encoding is longer than the max length 32766), all of which were skipped.  Please correct the analyzer to not produce such terms.  The prefix of the first immense term is: '[50, 48, 49, 57, 45, 49, 50, 45, 48, 53, 32, 49, 51, 58, 50, 56, 58, 48, 54, 44, 54, 50, 53, 32, 73, 78, 70, 79, 32, 91]...', original message: bytes can be at most 32766 in length; got 49179",
        "caused_by": {
          "type": "max_bytes_length_exceeded_exception",
          "reason": "max_bytes_length_exceeded_exception: bytes can be at most 32766 in length; got 49179"
        }
      },
      "status": 400
    },
    {
      "index": "testindex",
      "type": "sparktask",
      "id": "AW7Uh6DWpTSwMGQPHoTE",
      "cause": {
        "type": "illegal_argument_exception",
        "reason": "Document contains at least one immense term in field=\"message\" (whose UTF8 encoding is longer than the max length 32766), all of which were skipped.  Please correct the analyzer to not produce such terms.  The prefix of the first immense term is: '[50, 48, 49, 57, 45, 49, 50, 45, 48, 53, 32, 49, 51, 58, 50, 56, 58, 48, 53, 44, 51, 50, 50, 32, 73, 78, 70, 79, 32, 91]...', original message: bytes can be at most 32766 in length; got 49181",
        "caused_by": {
          "type": "max_bytes_length_exceeded_exception",
          "reason": "max_bytes_length_exceeded_exception: bytes can be at most 32766 in length; got 49181"
        }
      },
      "status": 400
    }
  ]
}

遇到问题:

1.FIELDDATA过大,这里是缓存过大,首要问题还是索引数据过大,导致缓存的数据超出上限,而且默认缓存只进不出,这里理解的其实不是很透彻。
这个问题是在测试ES进程内存大小影响的时候,调低内存导致的。

{
    "error": "... CircuitBreakingException[[FIELDDATA] Data too large, data for [proccessDate] would be larger than limit of [10307921510/9.5gb]]; }]",
    "status": 500
}

参考:https://blog.csdn.net/hereiskxm/article/details/46744985

附测试所需

常用命令

清楚系统缓存

sync; echo 1 > /proc/sys/vm/drop_caches

控制内存

stress-ng --vm-bytes $(awk ‘/MemFree/{printf “%d\n”, $2 * 0.9;}’ < /proc/meminfo)k --vm-keep -m 1

伪造数据命令

nohup java -jar test-util-1.0-SNAPSHOT-jar-with-dependencies.jar >/dev/null 2>&1 &

查看索引信息

curl -XGET http://10.252.81.6:9200/_cat/indices?v
curl -XGET http://10.252.81.6:9200/_cat/nodes?pretty

查看 分片状态

curl -XGET http://10.252.81.6:9200/_cat/shards | grep 2019-12-05

curl -XGET http://10.252.81.6:9200/_cat/shards | grep 2019-12-05 | grep ssd | grep STARTED | wc -l

查看索引分片信息

curl -XGET http://10.252.81.6:9200/ssd-testlog/_search_shards?pretty

查看热点线程

curl -XGET http://10.252.81.6:9200/_nodes/hot_threads

修改副本数

curl -XPUT http://10.252.81.6:9200/ssd-testlog/_settings -d ‘{“number_of_replicas”: 1}’

修改索引刷新时间

curl -XPUT http://10.252.81.6:9200/ssd-100-testlog/_settings -d ‘{“index”:{“refresh_interval” : “60s”}}’

清除缓存

curl -XPOST http://10.252.81.6:9200/_cache/clear

索引重命名修改分片数

curl -XPOST ‘http://172.16.31.154:9200/_reindex’ -d ‘{“source”:{“index”:“testlog-2019-12-05–es_81”},“dest”:{“index”:“testindex”}}’

创建索引

curl -XPUT ‘http://10.252.81.6:9200/reindex-testlog’ -d ‘{“settings”:{“index.number_of_shards”:35,“number_of_replicas”:1,“analysis”:{“analyzer”:{“log”:{“type”:“pattern”,“pattern”:"[^\w]"}}}},“mappings”:{“ordinary”:{"_all":{“enabled”:true,“store”:true},"_field_names":{“enabled”:false},“properties”:{“cluster”:{“type”:“string”},“service”:{“type”:“string”},“hostip”:{“type”:“string”},“date”:{“type”:“date”,“format”:“yyyy-MM-dd HH:mm:ss,SSS”},“level”:{“type”:“string”},“class”:{“type”:“string”},“message”:{“type”:“keyword”,“index”:“not_analyzed”,“ignore_above”:10000},“hostname”:{“type”:“string”},“expection”:{“type”:“string”,“fields”:{“mylog”:{“type”:“string”,“analyzer”:“log”}}}}}}}’

附es测试脚本

ES_HOST=172.16.31.154
ES_INDEX=testlog-2019-12-08--es_168
ES_TYPE=datanode
REPEAT_TIME=5
ES_CLEAR_CACHE_SLEEP=30
#HOST_LIST=


##清缓存
clearCache(){
        echo "curl -XPOST http://${ES_HOST}:9200/_cache/clear"
    curl -XPOST http://${ES_HOST}:9200/_cache/clear
    sleep ${ES_CLEAR_CACHE_SLEEP}
}


##简单检索
simpleSearch(){
    startDate=$1
    endDate=$2
    hostName=$3
    querySize=$4
    requestHttp="http://${ES_HOST}:9200/${ES_INDEX}/${ES_TYPE}/_search?pretty"
    parameters='{"size":'${querySize}',"query":{"bool":{"must":[{"range":{"date":{"gte":"'${startDate}'","lte":"'${endDate}'"}}},{"match_phrase":{"host":"'${hostName}'"} }]}}, "sort" : [{"date" : {"order" :"desc"}},{"_uid" : {"order" : "asc"}}]}'
    echo "simpleSearch requestHttp:"${requestHttp}
    echo "simpleSearch parameters:"${parameters}
    curl -XGET  ${requestHttp} -d "${parameters}"
}

#全文检索
fullTextSearch(){
	startDate=$1
    endDate=$2
    match_phrase=$3
    querySize=$4
    requestHttp="http://${ES_HOST}:9200/${ES_INDEX}/${ES_TYPE}/_search?pretty"
    parameters='{"size":'${querySize}',"query":{"bool":{"must":[{"range":{"date":{"gte":"'${startDate}'","lte":"'${endDate}'"}}},{"match_phrase":{"expection":"'${match_phrase}'"} }]}}, "sort" : [{"date" : {"order" :"desc"}},{"_uid" : {"order" : "asc"}}]}'
    echo "fullTextSearch requestHttp:"${requestHttp}
    echo "fullTextSearch parameters:"${parameters}
    curl -XGET  ${requestHttp} -d "${parameters}"

}


#聚合
aggregationSearch(){
	startDate=$1
    endDate=$2
    hostName=$3
    aggregation_interval=$4
    requestHttp="http://${ES_HOST}:9200/${ES_INDEX}/${ES_TYPE}/_search?pretty"
    parameters='{"query":{"bool":{"must":[{"range":{"date":{"gte":"'${startDate}'","lte":"'${endDate}'"}}},{"match_phrase":{"host":"'${hostName}'"} }]}}, "sort" : [{"date" : {"order" :"desc"}},{"_uid" : {"order" : "asc"}}],"aggregations" : {"articles_over_time" : {"date_histogram" : {"field" : "date","interval" : "'${aggregation_interval}'","offset" :0,"order" : {"_key" : "asc"},"keyed" : false,"min_doc_count" : 0}}}}'
    echo "aggregationSearch requestHttp:"${requestHttp}
    echo "aggregationSearch parameters:"${parameters}
    curl -XGET  ${requestHttp} -d "${parameters}"
}

### 所有查询先执行清缓存,然后进行5次查询
##
clearCache
for ((i=1;i<=${REPEAT_TIME};i++))
do
	echo "execute id:$i"
    simpleSearch "2019-12-07 00:00:00,316" "2019-12-07 23:59:59,949" "hebsjzx-hadoop-81-9" 5
done

##
clearCache
for ((i=1;i<=${REPEAT_TIME};i++))
do
	echo "execute id:$i"
    fullTextSearch "2019-12-07 00:00:00,316" "2019-12-07 23:59:59,949" "Receving" 5
done

clearCache
for ((i=1;i<=${REPEAT_TIME};i++))
do
	echo "execute id:$i"
    simpleSearch "2019-12-07 00:00:00,316" "2019-12-07 23:59:59,949" "hebsjzx-hadoop-81-9" "3600s" 5
done
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值