elasticsearch 大数据下 bulk 优化
es中 bulk api 可以在单个API调用中执行许多索引/删除操作,这可以大大提高索引速度。在线上突然遇到这样错误:
2019-02-27 12:19:07.836 [inner-job-enable-job-61] ERROR com.dangdang.ddframe.job.executor.handler.impl.DefaultJobExceptionHandler :? - Job 'enable-job' exception occur in job processing
java.lang.RuntimeException: ElasticsearchStatusException[Unable to parse response body]; nested: ResponseException[method [POST], host [http://10.80.229.22:9200], URI [/_bulk?timeout=1m], status line [HTTP/1.1 413 Request Entity Too Large]
];
at com.kxtx.opa.es.config.ElasticsearchTemplate.commonExceptionHandle(ElasticsearchTemplate.java:290)
at com.kxtx.opa.es.config.ElasticsearchTemplate.batchSave(ElasticsearchTemplate.java:153)
at com.kxtx.opa.timer.ProductEnableTimer.realSaveOrUpdateElastic(ProductEnableTimer.java:193)
at com.kxtx.opa.timer.ProductEnableTimer.execute(ProductEnableTimer.java:92)
at com.dangdang.ddframe.job.executor.type.SimpleJobExecutor.process(SimpleJobExecutor.java:41)
at com.dangdang.ddframe.job.executor.AbstractElasticJobExecutor.process(AbstractElasticJobExecutor.java:206)
at com.dangdang.ddframe.job.executor.AbstractElasticJobExecutor.access$000(AbstractElasticJobExecutor.java:47)
at com.dangdang.ddframe.job.executor.AbstractElasticJobExecutor$1.run(AbstractElasticJobExecutor.java:185)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: org.elasticsearch.ElasticsearchStatusException: Unable to parse response body
at org.elasticsearch.client.RestHighLevelClient.parseResponseException(RestHighLevelClient.java:598)
at org.elasticsearch.client.RestHighLevelClient.performRequest(RestHighLevelClient.java:501)
at org.elasticsearch.client.RestHighLevelClient.performRequestAndParseEntity(RestHighLevelClient.java:474)
at org.elasticsearch.client.RestHighLevelClient.bulk(RestHighLevelClient.java:246)
at com.kxtx.opa.es.config.ElasticsearchTemplate.batchSave(ElasticsearchTemplate.java:150)
... 11 common frames omitted
Suppressed: java.lang.IllegalStateException: Elasticsearch didn't return the [Content-Type] header, unable to parse response body
at org.elasticsearch.client.RestHighLevelClient.parseEntity(RestHighLevelClient.java:611)
at org.elasticsearch.client.RestHighLevelClient.parseResponseException(RestHighLevelClient.java:594)
... 15 common frames omitted
Caused by: org.elasticsearch.client.ResponseException: method [POST], host [http://10.80.229.22:9200], URI [/_bulk?timeout=1m], status line [HTTP/1.1 413 Request Entity Too Large]
at org.elasticsearch.client.RestClient$1.completed(RestClient.java:358)
业务反馈,才1w多条就报这个!如果你对nginx足够的了解会发现这个错误是它的,接下来要看nginx的配置文件,最终确人有个参数值 client_max_body_size 太小,那就改大些吧!那es能接受多大的呢?es的bulk的批量究竟该多大,之前讲过,这里不再啰嗦。
那就5000条一个批次,但是es还是比较慢!这里分享几个优化的小技巧
1. refresh间隔
调整refresh时间间隔,优化点: 减少刷新频率,降低潜在的写磁盘性能损耗, 默认的刷新时间间隔是1s,对于写入量很大的场景,这样的配置会导致写入吞吐量很低,适当提高刷新间隔,可以提升写入量,代价就是让新写入的数据在60s之后可以被搜索,新数据可见的及时性有所下降。
在bulk大量数据到ES集群的时候可以关闭刷新频率,把其值设置为-1就是关闭了刷新频率,在导入完之后设置成合理的值即可。
2. replica数目
调整replica数目,在bulk大量数据到ES集群的可以把副本数设置为0,在数据导入完成之后再设置为1或者你集群的适合的数目。
3. 去掉_all字段
Index中默认会有_all这个字段(es6.x已经禁用),默认会把所有字段的内容都拷贝到这一个字段里面,这样会给查询带来方便,但是会增加索引时间和索引尺寸。
4. translog优化
translog默认为512MB,flush操作达到512MB fsync刷新到硬盘(这个问题不大),而translog是默认是每次index请求都写磁盘,优化点: 减少写磁盘的频率,调整为index.translog.durability=async,index.translog.sync_interval=30s(默认值是5s)
5. segment合并
更多
6. mapping优化
由于es自动检测和添加新字段称为动态映射,我见过由于环境问题发生mapping漏设置,这时有300~400个字段自动映射为text类型(太多),导致每批次(5000条)插入响应时间都大于3分钟。总之,检查mapping的合理性很重要。
7. ES的JVM内存大小
修改配置文件调整ES的JVM内存大小,这个值不能超过32g,一般机器好点设置成十几个g速度就非常快了。具体要看自己机器的内存。
优化项按顺序进行,越靠前优化效果越明显。