0


Spring Boot 中 ES索引刷新策略:RefreshPolicy详解

🧑 博主简介:历代文学网(PC端可以访问:https://literature.sinhy.com/#/literature?__c=1000,移动端可微信小程序搜索“**历代文学**”)总架构师,

15年

工作经验,精通

Java编程

高并发设计

Springboot和微服务

,熟悉

Linux

ESXI虚拟化

以及

云原生Docker和K8s

,热衷于探索科技的边界,并将理论知识转化为实际应用。保持对新技术的好奇心,乐于分享所学,希望通过我的实践经历和见解,启发他人的创新思维。在这里,我希望能与志同道合的朋友交流探讨,共同进步,一起在技术的世界里不断学习成长。

在这里插入图片描述


引言

Elasticsearch(ES)

中,关于索引刷新,它是一个非常重要的概念。

1. 索引刷新的含义

索引刷新是指将内存缓冲区中的数据写入新的段(

segment

)并使其可被搜索的过程。默认情况下,

Elasticsearch

大约每

1 秒

自动执行一次索引刷新操作。

2. 为什么需要刷新?

  1. 数据可见性- 确保新写入的数据能够尽快被搜索到。如果没有刷新操作,新写入的数据将一直停留在内存缓冲区中,无法被查询到。例如,在一个电商平台的商品搜索功能中,当商家新上架商品时,需要尽快让用户能够搜索到这些新商品,这就要求及时进行索引刷新。
  2. 一致性- 保证搜索结果的一致性。如果不进行刷新,不同的搜索请求可能会得到不同的结果,因为内存缓冲区中的数据可能在不同的时间点被写入磁盘。通过定期刷新索引,可以确保搜索结果基于相对一致的数据集。

3. 索引刷新的机制

  1. 内存缓冲区- 当数据被写入 Elasticsearch 时,首先会被写入内存缓冲区。这个缓冲区是一个临时存储区域,用于快速接收写入请求,提高写入性能。
  2. 自动刷新- Elasticsearch 会根据配置的 refresh_interval(默认 1 秒)自动触发索引刷新。在刷新时,内存缓冲区中的数据会被写入一个新的段,并生成新的倒排索引。这个新的段会被写入磁盘,使得数据可被搜索。
  3. 手动刷新- 除了自动刷新,还可以通过调用 _refresh API 手动触发索引刷新。例如,在一些对实时性要求非常高的场景中,可以在关键操作后手动刷新索引,以确保数据立即可被搜索。
  4. 性能影响- 频繁的刷新会带来一定的性能开销。因为每次刷新都需要消耗系统资源,包括CPUI/O 操作。如果刷新过于频繁,可能会影响写入性能,因为 Elasticsearch 需要花费更多的时间来处理刷新操作,而不是接收新的数据写入请求。所以,在实际应用中,需要根据具体的业务需求和性能要求来调整刷新频率。

在这里插入图片描述

Spring Boot 中 Elasticsearch 的 RefreshPolicy 详解

在 Spring Boot 项目中与 Elasticsearch 交互时,

RefreshPolicy

是一个重要的枚举类型,用于控制索引的刷新策略。它有三个枚举值,分别是:

NONE

IMMEDIATE

WAIT_UNTIL

。接下来我们将详细了解每个枚举值的含义,并通过代码示例进行讲解。

一、

NONE

1.1 含义

NONE

表示不执行任何显式的刷新操作。写入的数据不会立即被搜索到,只有在

Elasticsearch

根据其默认的刷新策略(通常是

1 秒

)或手动触发刷新时,数据才会变得可搜索。

1.2 优缺点

  • 优点:写入性能较高,因为不会立即触发刷新操作,减少了系统资源的消耗。适合对数据实时性要求不高的场景,例如批量数据导入、历史数据存储等。
  • 缺点:数据的可见性有延迟,新写入的数据不能立即被搜索到。

1.3 代码示例

importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.data.elasticsearch.annotations.RefreshPolicy;importorg.springframework.data.elasticsearch.core.ElasticsearchOperations;importorg.springframework.data.elasticsearch.core.IndexOperations;importorg.springframework.data.elasticsearch.core.document.Document;importorg.springframework.data.elasticsearch.repository.ElasticsearchRepository;importorg.springframework.stereotype.Service;importjava.util.List;@SpringBootApplicationpublicclassEsRefreshPolicyExampleApplication{publicstaticvoidmain(String[] args){SpringApplication.run(EsRefreshPolicyExampleApplication.class, args);}@ServicepublicstaticclassMyService{privatefinalElasticsearchOperations elasticsearchOperations;privatefinalMyRepository myRepository;publicMyService(ElasticsearchOperations elasticsearchOperations,MyRepository myRepository){this.elasticsearchOperations = elasticsearchOperations;this.myRepository = myRepository;}publicvoidsaveDataWithNoneRefreshPolicy(){// 创建一个文档对象Document document =newDocument("field1","value1");// 使用 NONE 刷新策略保存文档
            myRepository.save(document,RefreshPolicy.NONE);}publicList<Document>searchData(){// 尝试搜索数据,但由于使用了 NONE 刷新策略,可能搜索不到刚刚保存的数据return elasticsearchOperations.queryForList("SELECT * FROM my_index",Document.class);}}publicinterfaceMyRepositoryextendsElasticsearchRepository<Document,String>{}}

1.4 测试代码及预期输出

importorg.junit.jupiter.api.Test;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.test.context.SpringBootTest;importjava.util.List;importstaticorg.junit.jupiter.api.Assertions.assertEquals;importstaticorg.junit.jupiter.api.Assertions.assertTrue;@SpringBootTestclassEsRefreshPolicyExampleApplicationTests{@AutowiredprivateEsRefreshPolicyExampleApplication.MyService myService;@TestvoidtestNoneRefreshPolicy(){
        myService.saveDataWithNoneRefreshPolicy();List<Document> results = myService.searchData();// 预期输出:由于使用了 NONE 刷新策略,刚保存的数据可能还未被搜索到,所以结果列表为空assertTrue(results.isEmpty());}}

二、

IMMEDIATE

2.1 含义

IMMEDIATE

在写入操作后立即执行刷新操作,使得新写入的数据可以立即被搜索到。这是一种强一致性的策略,但会带来一定的性能开销,因为每次写入都要触发刷新。

2.2 优缺点

  • 优点:数据写入后可以立即被搜索到,保证了数据的强实时性。适用于对数据实时性要求非常高的场景,如金融交易系统、实时监控系统等。
  • 缺点:频繁的刷新会带来较大的性能开销,可能会影响写入性能。

2.3 代码示例

importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.data.elasticsearch.annotations.RefreshPolicy;importorg.springframework.data.elasticsearch.core.ElasticsearchOperations;importorg.springframework.data.elasticsearch.core.IndexOperations;importorg.springframework.data.elasticsearch.core.document.Document;importorg.springframework.data.elasticsearch.repository.ElasticsearchRepository;importorg.springframework.stereotype.Service;importjava.util.List;@SpringBootApplicationpublicclassEsRefreshPolicyExampleApplication{publicstaticvoidmain(String[] args){SpringApplication.run(EsRefreshPolicyExampleApplication.class, args);}@ServicepublicstaticclassMyService{privatefinalElasticsearchOperations elasticsearchOperations;privatefinalMyRepository myRepository;publicMyService(ElasticsearchOperations elasticsearchOperations,MyRepository myRepository){this.elasticsearchOperations = elasticsearchOperations;this.myRepository = myRepository;}publicvoidsaveDataWithImmediateRefreshPolicy(){// 创建一个文档对象Document document =newDocument("field1","value2");// 使用 IMMEDIATE 刷新策略保存文档
            myRepository.save(document,RefreshPolicy.IMMEDIATE);}publicList<Document>searchData(){// 立即搜索数据,由于使用了 IMMEDIATE 刷新策略,应该能搜索到刚刚保存的数据return elasticsearchOperations.queryForList("SELECT * FROM my_index",Document.class);}}publicinterfaceMyRepositoryextendsElasticsearchRepository<Document,String>{}}

2.4 测试代码及预期输出

importorg.junit.jupiter.api.Test;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.test.context.SpringBootTest;importjava.util.List;importstaticorg.junit.jupiter.api.Assertions.assertEquals;importstaticorg.junit.jupiter.api.Assertions.assertFalse;@SpringBootTestclassEsRefreshPolicyExampleApplicationTests{@AutowiredprivateEsRefreshPolicyExampleApplication.MyService myService;@TestvoidtestImmediateRefreshPolicy(){
        myService.saveDataWithImmediateRefreshPolicy();List<Document> results = myService.searchData();// 预期输出:由于使用了 IMMEDIATE 刷新策略,刚保存的数据应该能被搜索到,结果列表不为空assertFalse(results.isEmpty());}}

三、

WAIT_UNTIL

3.1 含义

WAIT_UNTIL

会等待当前正在进行的刷新操作完成后再返回结果。如果没有正在进行的刷新操作,它的行为类似于

NONE

。这种策略适用于需要确保查询结果基于最新的已刷新数据,但又不想强制立即刷新的场景。

3.2 优缺点

  • 优点:在一定程度上平衡了数据实时性和性能。如果有正在进行的刷新操作,会等待其完成,确保查询结果基于相对较新的数据;如果没有正在进行的刷新操作,行为类似于 NONE,减少了不必要的刷新开销。
  • 缺点:不确定性较大,取决于是否有正在进行的刷新操作,可能会导致查询结果的延迟不稳定。

3.3 代码示例

importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.data.elasticsearch.annotations.RefreshPolicy;importorg.springframework.data.elasticsearch.core.ElasticsearchOperations;importorg.springframework.data.elasticsearch.core.IndexOperations;importorg.springframework.data.elasticsearch.core.document.Document;importorg.springframework.data.elasticsearch.repository.ElasticsearchRepository;importorg.springframework.stereotype.Service;importjava.util.List;importjava.util.concurrent.TimeUnit;@SpringBootApplicationpublicclassEsRefreshPolicyExampleApplication{publicstaticvoidmain(String[] args){SpringApplication.run(EsRefreshPolicyExampleApplication.class, args);}@ServicepublicstaticclassMyService{privatefinalElasticsearchOperations elasticsearchOperations;privatefinalMyRepository myRepository;publicMyService(ElasticsearchOperations elasticsearchOperations,MyRepository myRepository){this.elasticsearchOperations = elasticsearchOperations;this.myRepository = myRepository;}publicvoidsaveDataWithWaitUntilRefreshPolicy(){// 创建一个文档对象Document document =newDocument("field1","value3");// 使用 WAIT_UNTIL 刷新策略保存文档
            myRepository.save(document,RefreshPolicy.WAIT_UNTIL);}publicList<Document>searchData(){// 尝试搜索数据,如果有正在进行的刷新操作,会等待其完成后再搜索return elasticsearchOperations.queryForList("SELECT * FROM my_index",Document.class);}}publicinterfaceMyRepositoryextendsElasticsearchRepository<Document,String>{}}

3.4 测试代码及预期输出

importorg.junit.jupiter.api.Test;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.test.context.SpringBootTest;importjava.util.List;importjava.util.concurrent.TimeUnit;importstaticorg.junit.jupiter.api.Assertions.assertEquals;importstaticorg.junit.jupiter.api.Assertions.assertTrue;@SpringBootTestclassEsRefreshPolicyExampleApplicationTests{@AutowiredprivateEsRefreshPolicyExampleApplication.MyService myService;@TestvoidtestWaitUntilRefreshPolicy(){
        myService.saveDataWithWaitUntilRefreshPolicy();try{// 等待一段时间,确保如果有正在进行的刷新操作能够完成TimeUnit.SECONDS.sleep(2);}catch(InterruptedException e){Thread.currentThread().interrupt();}List<Document> results = myService.searchData();// 预期输出:如果没有正在进行的刷新操作,行为类似于 NONE,可能搜索不到刚保存的数据;如果有正在进行的刷新操作并等待完成后,可能搜索到刚保存的数据// 具体结果取决于实际情况// 这里假设如果搜索到数据则测试通过assertTrue(results.size()>0|| results.isEmpty());}}

四、场景距离与选择建议

4.1 日志分析系统

对于日志分析系统,通常对数据的实时性要求不是特别高,更注重写入性能和存储效率。在这种情况下,可以选择

NONE

刷新策略,并定期手动触发刷新或者根据业务需求设置合理的自动刷新间隔。

4.2 电商实时搜索

如果是电商平台的实时搜索功能,需要尽快让用户搜索到新上架的商品等数据。此时可以考虑使用

WAIT_UNTIL

策略,在保证一定实时性的同时,尽量减少不必要的刷新开销。如果对实时性要求极高,也可以谨慎使用

IMMEDIATE

策略,但需要注意性能影响,并做好系统的性能优化和监控。

4.3 金融交易系统

在金融交易系统中,对数据的实时性和准确性要求极高。这种情况下,可以选择

IMMEDIATE

策略,确保交易数据能够立即被查询和分析。但同时需要投入更多的资源来优化系统性能,以应对频繁刷新带来的开销。

五、总结

通过以上代码示例和测试,我们可以清楚地了解到

Spring Boot

Elasticsearch

RefreshPolicy

三个枚举值的不同作用和使用场景。在实际应用中,可以根据具体的需求选择合适的刷新策略。


本文转载自: https://blog.csdn.net/lilinhai548/article/details/142285622
版权归原作者 码踏云端 所有, 如有侵权,请联系我们删除。

“Spring Boot 中 ES索引刷新策略:RefreshPolicy详解”的评论:

还没有评论