ElasticSearch文档新增可用性百分比字段的实现求助
Hey there! 作为刚入门Elasticsearch的新手,你这个计算系统可用性百分比的需求其实挺常见的,我来给你梳理几个实用的实现方案,你可以根据自己的使用场景来选~
首先先明确下你的公式逻辑:availability = (sysUpTimeT1 - sysUpTimeT0) / 300,这里的T1应该是当前时间点的系统运行时长,T0是300秒(5分钟)前的系统运行时长,差值除以300就是这5分钟内的系统可用占比对吧?比如如果差值是295,那可用性就是98.33%,说明这5分钟里系统有5秒是重启过的。
方案1:查询时实时计算(推荐新手先试这个,不用改原始数据)
这个方法的好处是完全不用改动你的原始索引数据,每次查询的时候实时算出可用性百分比,特别适合临时分析或者不需要永久存储这个字段的场景。
你可以用ES的聚合功能先把数据按300秒的时间窗口分组,再获取每个窗口里最早和最晚的sysUpTime值,最后代入公式计算。直接看下面的查询DSL示例:
GET /你的索引名称/_search { "size": 0, "aggs": { "按5分钟分组": { "date_histogram": { "field": "@timestamp", "fixed_interval": "300s", // 按5分钟(300秒)分割时间窗口 "format": "yyyy-MM-dd HH:mm:ss" }, "aggs": { "获取窗口内的运行时长": { "top_hits": { "size": 2, "sort": [{"@timestamp": "asc"}], "_source": ["sysUpTime", "@timestamp"] } }, "计算可用性百分比": { "bucket_script": { "buckets_path": { "T0时间点运行时长": "获取窗口内的运行时长.hits.hits.0._source.sysUpTime", "T1时间点运行时长": "获取窗口内的运行时长.hits.hits.1._source.sysUpTime" }, "script": "(params.T1时间点运行时长 - params.T0时间点运行时长) / 300 * 100" // 乘以100转成百分比格式 } } } } } }
这段DSL的逻辑拆解:
- 用
date_histogram把数据按300秒的时间窗口自动分组 - 每个窗口里用
top_hits拿到最早(T0)和最晚(T1)的两个文档的sysUpTime值 - 最后用
bucket_script执行公式计算,乘以100是为了转成直观的百分比格式
方案2:用Ingest Pipeline在数据写入时计算(适合永久存储字段)
如果你希望把这个可用性字段永久存在文档里,那可以在数据写入ES的时候就自动计算好。不过这个方法需要临时记录上一个时间点的sysUpTime值,这里可以用ES的脚本处理器结合缓存来实现:
首先创建一个数据处理管道(Ingest Pipeline):
PUT /_ingest/pipeline/计算可用性百分比 { "processors": [ { "script": { "source": """ // 用主机名作为缓存键,避免不同主机的运行时长数据混淆 def lastUpTime = ctx._cache.get('上一次运行时长_' + ctx.host.name); if (lastUpTime != null) { // 代入公式计算,保留两位小数 def availability = (ctx.sysUpTime - lastUpTime) / 300 * 100; ctx.availability_percent = Math.round(availability * 100) / 100; } // 更新缓存,存储当前的运行时长,300秒后自动过期 ctx._cache.put('上一次运行时长_' + ctx.host.name, ctx.sysUpTime, 300000); """, "lang": "painless" } } ] }
之后在写入数据的时候指定使用这个管道:
POST /你的索引名称/_doc?pipeline=计算可用性百分比 { "host": { "memory": { "availableSwap": 7040704, "used": 229712, "total": 4042716, "shared": 263628, "free": 7270416, "totalSwap": 7074752, "cached": 1196976 } }, "@timestamp": "2024-01-10T00:08:24.798Z", "sysUpTime": 141317970 }
注意事项:
- 第一次写入某台主机的数据时,缓存里没有上一个时间点的值,
availability_percent字段会为空,第二次写入就会正常计算了 - 缓存过期时间设为300000毫秒(也就是300秒),刚好对应你的时间窗口
方案3:用Transform预计算(适合大数据量定期统计)
如果你的数据量很大,不想每次查询都实时计算,那可以用ES的Transform功能定期把计算好的可用性字段存储到一个新的统计索引里,后续直接查这个统计索引就行:
首先创建一个Transform任务:
PUT /_transform/生成可用性统计 { "source": { "index": ["你的索引名称"] }, "dest": { "index": "可用性统计索引" }, "pivot": { "group_by": { "主机名": {"terms": {"field": "host.name"}}, "时间窗口": {"date_histogram": {"field": "@timestamp", "fixed_interval": "300s"}} }, "aggregations": { "窗口起始运行时长": {"min": {"field": "sysUpTime"}}, "窗口结束运行时长": {"max": {"field": "sysUpTime"}}, "可用性百分比": { "bucket_script": { "buckets_path": { "起始值": "窗口起始运行时长", "结束值": "窗口结束运行时长" }, "script": "(params.结束值 - params.起始值) / 300 * 100" } } } }, "frequency": "300s", // 每300秒自动执行一次 "sync": { "time": { "field": "@timestamp", "delay": "60s" } } }
然后启动这个Transform任务:
POST /_transform/生成可用性统计/_start
之后你就可以直接查询可用性统计索引,里面已经自动存好每台主机每5分钟的可用性百分比了~
上面这三个方案里,我推荐你先从方案1开始试,因为不用改任何数据,能快速看到计算结果,等你对ES更熟悉了再考虑方案2或3哦~
备注:内容来源于stack exchange,提问作者sara ichi

