elasticsearch學習系列:開發springboot程序進行定時刪除過期索引

場景

項目使用了elasticsearch技術來進行數據搜索,而單天的數據量比較大,隨着時間的流逝,整個elasticsearch集羣所佔的空間會越來越大。如果不進行定時的刪除,就會導致存儲滿載,進而影響系統。而elasticsearch支持使用curl命令調用elasticsearch集羣命令,定時刪除某一天的索引數據。但是沒有辦法刪除某個時間點之前的數據。那麼假如有一天腳本沒有執行,那沒有執行的日期數據就沒辦法刪除,只能手動去刪除。這樣還是會存在問題的。這個時候,就需要有一個程序,可以自定義對某個索引進行掃描,刪除自定義天數的數據。這樣,不管什麼時候執行,都會將保留週期之外的索引數據給刪除掉。

環境

軟件 版本
JDK 8
spring-data-elasticsearch 3.1.10.RELEASE
spring-boot 2.1.8.RELEASE
elasticsearch 6.2.2

正文

流程梳理

接下來,讓我們梳理一下整個程序的開發流程,如下:

Created with Raphaël 2.2.0開始初始化ElasticSearch組件獲取配置數據獲取全部索引從全部索引中,篩選出過期的索引數據刪除過期的索引數據結束

show the code

對於程序員來說,除了理論要溜,代碼也得溜。所以,接下來會展示整個過程有用的代碼。

maven依賴

這裏只展示主要的依賴,像微服務Spring-cloud相關的依賴就不放在裏面了。


 <parent>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-parent</artifactId>
     <version>2.1.8.RELEASE</version>
 </parent>
 
 <dependencies>
	 <!-- elasticsearch -->
	 <dependency>
	     <groupId>org.springframework.boot</groupId>
	     <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
	 </dependency>
</dependencies>

配置文件

配置文件主要是寫在application.properties文件裏面,下面展示一個樣例:

# es配置
spring.data.elasticsearch.cluster-nodes=localhost:9300
spring.data.elasticsearch.cluster-name=test
# 過期索引配置,值爲天數
index.delindex.service-test=7
index.delindex.service-test2=7

主要函數

配置類

@Component
@Configuration
@PropertySource(value = {"classpath:/application.properties"}, encoding = "utf-8")
@ConfigurationProperties(prefix = "index")
@Getter
@Setter
public class ElasticsearchDelIndexConfig {
    private Map delindex = new HashMap();
}

處理類

因爲功能比較簡單,所以是直接將代碼放到主類裏面,直接跑的。代碼如下,如果有需求,直接複製就可以跑起來的。

@Slf4j
@EnableEurekaClient
@SpringBootApplication
public class ElasticsearchDelApplication implements CommandLineRunner {

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    @Autowired
    private ElasticsearchDelIndexConfig delIndexConfig;

    /**
     * 主進程
     *
     * @param args
     */
    public static void main(String[] args) {
        SpringApplication.run(ElasticsearchDelApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        while (true) {
            delIndexConfig.getDelindex().forEach((k, v) -> {
                log.info("索引起始名稱爲{},保留週期爲{}天", k, v);
                Set<String> allIndexes = getAllIndices();
                if (allIndexes.size() > 0) {
                    log.info("當前索引總數爲:{}", allIndexes.size());

                    List<String> timeoutList = getIndicesTimeout(allIndexes, String.valueOf(k), Long.parseLong(String.valueOf(v)), TimeUnit.DAYS);
                    if (timeoutList.size() > 0) {
                        log.info("對於前綴爲 {} 的索引 過期數目爲:{}", k, timeoutList.size());
                        timeoutList.forEach(indexName -> {
                            if (elasticsearchTemplate.deleteIndex(indexName)) {
                                log.info("成功刪除 {} 索引", indexName);
                            } else {
                                log.error("刪除 {} 索引 失敗", indexName);
                            }
                        });
                    }
                }
            });
            log.info("休眠 10 分鐘");
            ThreadUtil.sleep(10, TimeUnit.MINUTES);
        }
    }

    /**
     * 獲取所有index
     */
    public Set<String> getAllIndices() {
        ActionFuture<IndicesStatsResponse> isr = elasticsearchTemplate.getClient().admin().indices().stats(new IndicesStatsRequest().all());
        Set<String> set = isr.actionGet().getIndices().keySet();
        return set;
    }


    /**
     * 獲取指定索引的創建時間
     * @param indexName 索引名稱
     * @return 索引的創建時間
     */
    public String getCreateTimeForIndex(String indexName) {
        String createTime = elasticsearchTemplate.getClient().admin()
                .indices().getSettings(new GetSettingsRequest().indices(indexName))
                .actionGet().getIndexToSettings().get(indexName)
                .getAsSettings("index").get("creation_date");
        return createTime;
    }

    /**
     * 獲取前綴相同的過時索引
     * @param allIndices 索引列表
     * @param indexName 要過濾的索引前綴
     * @param time 超時時間
     * @param timeUnit 時間單位
     * @return 超時的索引列表
     */
    public List<String> getIndicesTimeout(Set<String> allIndices, String indexName, Long time, TimeUnit timeUnit) {
        List<String> list = new ArrayList<>();
        allIndices.parallelStream()
                .filter(name -> name.startsWith(indexName))
                .forEach(one -> {
                    String createTime = getCreateTimeForIndex(one);
                    if (System.currentTimeMillis() - Long.parseLong(createTime) > timeUnit.toMillis(time)) {
                        log.info("索引 {} 已經過期,創建時間爲{}", one, createTime);
                        list.add(one);
                    }
                });
        return list;
    }
}

結果

程序跑起來之後,elasticsearch集羣的特定索引的過期數據都會被刪除。

總結

spring-boot可以封裝了很多開發細節,減少了我們很多工作。在懂得內部原理的時候,的確很好用。不過對於初學者,在使用spring-boot的時候,記得學習裏面內部的原理。這樣遇到問題才能快速鎖定問題,並解決。

隨緣求贊

如果我的文章對大家產生了幫忙,可以在文章底部點個贊或者收藏;
如果有好的討論,可以留言;
如果想繼續查看我以後的文章,可以點擊關注
可以掃描以下二維碼,關注我的公衆號:楓夜之求索閣,查看我最新的分享!
在這裏插入圖片描述
拜拜

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章