先说结论和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