场景
项目使用了elasticsearch
技术来进行数据搜索,而单天的数据量比较大,随着时间的流逝,整个elasticsearch
集群所占的空间会越来越大。如果不进行定时的删除,就会导致存储满载,进而影响系统。而elasticsearch
支持使用curl
命令调用elasticsearch
集群命令,定时删除某一天的索引数据。但是没有办法删除某个时间点之前的数据。那么假如有一天脚本没有执行,那没有执行的日期数据就没办法删除,只能手动去删除。这样还是会存在问题的。这个时候,就需要有一个程序,可以自定义对某个索引进行扫描,删除自定义天数的数据。这样,不管什么时候执行,都会将保留周期之外的索引数据给删除掉。
环境
软件 | 版本 |
---|---|
JDK | 8 |
spring-data-elasticsearch | 3.1.10.RELEASE |
spring-boot | 2.1.8.RELEASE |
elasticsearch | 6.2.2 |
正文
流程梳理
接下来,让我们梳理一下整个程序的开发流程,如下:
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
的时候,记得学习里面内部的原理。这样遇到问题才能快速锁定问题,并解决。
随缘求赞
如果我的文章对大家产生了帮忙,可以在文章底部点个赞或者收藏;
如果有好的讨论,可以留言;
如果想继续查看我以后的文章,可以点击关注
可以扫描以下二维码,关注我的公众号:枫夜之求索阁,查看我最新的分享!