vortex metrics是一款用Java写的,轻量级的分布式时序计算框架。
vortex metrics是分布式流式计算框架vortex关于时序计算场景的一个具体实现
相比另一个时序数据库OpenTSDB,vortex metrics更偏向实时计算,将延迟尽可能地保持在秒级,但由于是内存计算,计算结果是存储在内存中的,有限的存储空间让它并不适用于存储大量指标的业务场景。但同时,对于一个指标的窗口数据需要保留的时间跨度较长时,vortex metrics提供了定制接口,可以保存到外部存储,比如数据库或缓存,但这需要做一些额外的开发工作。此外,vortex metrics也提供了Web查询界面,并且在持续改进中。
实际上,vortex metrics的功能是很单一的,因为它只做一件事,那就是根据客户端源源不断的上报数据实时地计算并输出单位时间窗口内的统计数据,记住这点很重要。
环境配置
Maven:
<dependency>
<groupId>com.github.paganini2008.atlantis</groupId>
<artifactId>vortex-spring-boot-starter</artifactId>
<version>1.0-RC2</version>
</dependency>
vortex metrics它首先是一个基于SpringBoot的应用程序,前面说过,它依赖vortex框架, 而vortex是通过微服务分布式协调框架tridenter实现集群模式的,并支持动态水平扩展,默认端口为6150
参考配置
# 集群配置
spring.application.name=vortex-metrics
spring.application.cluster.name=vortex-metrics-cluster
# vortex配置
atlantis.framework.vortex.bufferzone.collectionName=metric # 缓冲区集合名称
atlantis.framework.vortex.bufferzone.pullSize=1000 # 缓冲区每次拉取的消息数量
atlantis.framework.vortex.processor.threads=200 # 数据消费者线程数
输入地址:http://192.168.159.1:6150/met...
可以看到这个界面
vortex metrics是将server数据接收端和监控界面做在同一个应用中的,高并发场景下,可能会出现数据计算完成并已同步,但界面会滞后更新的情况。
HTTP API说明
vortex metrics目前只提供了2个接口:
上报数据接口:
POSThttp://192.168.159.1:6150/met...{dataType}
请求体示例:{ "name": "car", "metric": "speed", "value": 120, "timestamp": 1613200609281 }
参数说明:
参数名 类型 描述 举例 dateType 字符串 数据类型,取值范围:bigint,numeric,bool bigint name 字符串 应用名称 car metric 字符串 上报指标名称 speed value 数值 上报数值 120 timestamp 长整型 上报时间戳 1613200609281 查看数据接口:
GEThttp://192.168.159.1:6150/met...{dataType}/{name}/{metric}
响应体示例:{ "dataType": "bigint", "name": "car", "metric": "speed", "data": { "00:03:00": { "speed": { "middleValue": 5052, "count": 155796, "highestValue": 9999, "lowestValue": 100, "timestamp": 1623513794876 } }, "00:04:00": { "speed": { "middleValue": 5051, "count": 79754, "highestValue": 9999, "lowestValue": 100, "timestamp": 1623513840003 } }, "00:05:00": { "speed": { "middleValue": 5039, "count": 61014, "highestValue": 9999, "lowestValue": 100, "timestamp": 1623513933165 } }, "00:06:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623513960876 } }, "00:07:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623514020876 } }, "00:08:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623514080876 } }, "00:09:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623514140876 } }, "00:10:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623514200876 } }, "00:11:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623514260876 } }, "00:12:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623514320876 } }, "00:13:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623514380876 } }, "00:14:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623514440876 } }, "00:15:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623514500876 } }, "00:16:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623514560876 } }, "00:17:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623514620876 } }, "00:18:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623514680876 } }, "00:19:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623514740876 } }, "00:20:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623514800876 } }, "00:21:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623514860876 } }, "00:22:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623514920876 } }, "00:23:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623514980876 } }, "00:24:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623515040876 } }, "00:25:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623515100876 } }, "00:26:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623515160876 } }, "00:27:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623515220876 } }, "00:28:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623515280876 } }, "00:29:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623515340876 } }, "00:30:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623515400876 } }, "00:31:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623515460876 } }, "00:32:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623515520876 } }, "00:33:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623515580876 } }, "00:34:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623515640876 } }, "00:35:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623515700876 } }, "00:36:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623515760876 } }, "00:37:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623515820876 } }, "00:38:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623515880876 } }, "00:39:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623515940876 } }, "00:40:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623516000876 } }, "00:41:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623516060876 } }, "00:42:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623516120876 } }, "00:43:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623516180876 } }, "00:44:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623516240876 } }, "00:45:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623516300876 } }, "00:46:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623516360876 } }, "00:47:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623516420876 } }, "00:48:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623516480876 } }, "00:49:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623516540876 } }, "00:50:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623516600876 } }, "00:51:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623516660876 } }, "00:52:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623516720876 } }, "00:53:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623516780876 } }, "00:54:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623516840876 } }, "00:55:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623516900876 } }, "00:56:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623516960876 } }, "00:57:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623517020876 } }, "00:58:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623517080876 } }, "00:59:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623517140876 } }, "01:00:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623517200876 } }, "01:01:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623517260876 } }, "01:02:00": { "speed": { "middleValue": 0, "count": 0, "highestValue": 0, "lowestValue": 0, "timestamp": 1623517320876 } } } }
响应体json中的data为时序数据,vortex metrics默认的统计窗口为1分钟,滚动保留前60条记录,也就是用户可以通过界面看到前60分钟的统计数据。其中,highestValue,lowestValue,middleValue分别为最大值,最小值,平均值,count是 这1分钟内的数据条数,timestamp是时间戳,准确点讲,是这1分钟内最后一条数据的时间戳。
说明一下,vortex metrics默认的统计窗口,保留前多少条记录,可以通过配置文件设置的,但系统需要重启才能生效。
如何监控指标
vortex metrics框架为了方便用户内置了3个不同数据类型的测试接口:http://192.168.159.1:6150/met...{name}/{metric}
http://192.168.159.1:6150/met...{name}/{metric}
http://192.168.159.1:6150/met...{name}/{metric}
都是GET方式,设置name和metric参数即可
这里以统计小客车的平均速度为例,数据上报地址为:http://192.168.159.1:6150/met...
打开压测工具,这里以JMeter为例
- 设置线程组
- 设置HTTP请求
(关于Jmeter如何使用,大家可以自行百度,这里仅供测试)
- 点击绿色箭头运行
然后在界面中,location输入框里查询接口地址:http://192.168.159.1:6150/met...
点击[Search], 可以看到:
vortex metrics集群如何保证数据一致性?
vortex metrics集群内的应用节点通过内部网络通讯(默认Netty4实现)实现相互复制,保证数据的最终一致性,即每个节点的数据最终都是一致的,全量的。
比如现在再起2台服务,端口分别为6151和6152
这样的话http://192.168.159.1:6151/met...
http://192.168.159.1:6152/met...
http://192.168.159.1:6150/met...
这3个不同地址的接口返回的数据是应该是最终一致的
192.168.159.1:6151:
192.168.159.1:6152
如图,应用启动之后加入到vortex metrics集群,应用间会互相同步数据,达到最终一致的。
然后现在对任一一台服务进行压测,比如端口为6152的服务
观察192.168.159.1:6150地址的接口数据变化:
结果验证了vortex metrics集群中应用数据是双向同步的。
前面说过,vortex metrics是内存计算型的,即计算结果是驻留在内存中的,同步之后,多个应该同样是占据大量的内存,如果存在大量的指标数据,可能会有延迟,所以vortex metrics不适用于存储大量指标的运算场景,但是你可以部署多个vortex metrics集群来解决这个问题,目前经压测,单集群可以较好的支持1000个左右的指标数据的业务场景,高并发下延迟保持在1~5分钟内。
如何保存历史数据
前面说到,vortex metrics默认的统计窗口为1分钟,滚动保留前60条记录,那如果你想保留之前的历史记录,需要另外做开发。
首先要实现接口:
public interface MetricEvictionHandler<I, T extends Metric<T>> {
void onEldestMetricRemoval(I identifier, String metric, T metricUnit);
}
具体可参考:LoggingMetricEvictionHandler类(默认实现)
你还要实现接口:
public interface MetricSequencerFactory {
GenericUserMetricSequencer<String, BigInt> getBigIntMetricSequencer();
GenericUserMetricSequencer<String, Numeric> getNumericMetricSequencer();
GenericUserMetricSequencer<String, Bool> getBoolMetricSequencer();
}
具体可参考:DefaultMetricSequencerFactory类(默认实现)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。