简介
InfluxDB 2.x 是 InfluxData 公司推出的时间序列数据库的最新版本。与 InfluxDB 1.x 相比,InfluxDB 2.x 引入了一些新的特性和改进,旨在提供更强大、灵活和易于使用的时间序列数据存储和查询解决方案
特点
- Flux 查询语言: InfluxDB 2.x 引入了 Flux 查询语言,用于执行强大的数据处理和分析操作。Flux 提供了更灵活的查询能力,支持复杂的数据转换、过滤、聚合和连接操作,以更好地支持用户对时间序列数据的操作和分析。
- 新的数据存储引擎: InfluxDB 2.x 使用 Flux Engine 作为新的数据存储引擎。Flux Engine 具有更好的性能和扩展性,支持高并发写入和高效查询。
- Bucket 和 Organization: InfluxDB 2.x 引入了 Bucket 和 Organization 的概念。Bucket 是数据的逻辑容器,用于组织和存储时间序列数据,而 Organization 用于隔离和管理不同的用户或应用程序。
- 新的用户界面(UI): InfluxDB 2.x 提供了全新的仪表板和可视化工具,使用户能够轻松创建、定制和共享漂亮的图表和仪表板,以直观地展示时间序列数据。
- API 密钥和访问令牌: 为了实现更安全的访问和操作,InfluxDB 2.x 引入了 API 密钥和访问令牌。API 密钥用于身份验证,访问令牌用于授权对数据的访问。
- 支持多租户: InfluxDB 2.x 提供更好的多租户支持,允许在同一实例中隔离和管理多个不同的组织和数据。
- 新的存储结构: InfluxDB 2.x 采用新的存储结构,支持更灵活的标签和更好的查询性能,同时改进了存储效率。
- 云原生和容器化: InfluxDB 2.x 被设计用于云原生环境和容器化部署,支持在 Kubernetes 或其他容器编排工具中运行。
- 更好的持久性查询支持: Flux 查询语言支持对查询结果进行持久性存储,使用户可以创建并定期执行持久性的计算任务。
基本概念
- Bucket(桶): Bucket 是 InfluxDB 中的基本存储单元,用于组织和存储时间序列数据。它是数据的逻辑容器,用于区分和隔离不同类型或来源的数据。
- Organization(组织): Organization 是 InfluxDB 中的组织概念,用于隔离和管理用户、应用程序或项目。每个用户可以属于一个或多个组织,Bucket 也属于一个组织。
- Measurement(测量值): Measurement 是 InfluxDB 中的数据表的概念。它类似于关系型数据库中的表,用于存储时间序列数据。每个 Measurement 包含一组字段和标签。
- Field(字段): Field 是 Measurement 中的一种数据类型,用于存储实际的数值数据。例如,温度、湿度等是字段的例子。
- Tag(标签): Tag 是 Measurement 中的一种索引类型,用于标识和过滤数据。标签通常用于存储维度信息,例如地理位置、设备 ID 等。
- Point(数据点): Point 是 InfluxDB 中时间序列数据的基本单位,它包含了时间戳、字段和标签。每个数据点都关联到一个 Measurement。
- API 密钥和访问令牌: 为了进行安全的访问和操作,InfluxDB 2.x 引入了 API 密钥和访问令牌。API 密钥用于身份验证,而访问令牌用于授权对数据的访问。
- Flux 查询语言: Flux 是 InfluxDB 2.x 中的查询语言,用于执行强大的数据处理和分析操作。它支持更灵活的查询、过滤、聚合和转换操作。
- 仪表板和可视化: InfluxDB 2.x 提供了仪表板和可视化工具,允许用户创建、定制和共享图表和仪表板,以直观地展示时间序列数据。
Bucket类似于关系型数据库中的库的概念。Measurement类似于数据库中表。
安装环境
安装
尝试过使用docker安装,不过没找到资源
wget https://dl.influxdata.com/influxdb/releases/influxdb2-2.1.1-linux-amd64.tar.gz
tar xvzf influxdb2-2.1.1-linux-amd64.tar.gz
sudo cp influxdb2-2.1.1-linux-amd64/influxd /usr/local/bin/
nohup influxd &
配置
打开游览器 输入127.0.0.1:8086,点击“Get Started”
进行初始化信息填写(账号、密码、桶、组织),并点击Continue
这个buckets和token在influxdb2的版本后续跟springboot集成有用
语法
Flux 是一种功能强大的查询语言,特别适用于处理时间序列数据。Flux 具有丰富的操作和函数,使用户能够执行复杂的数据处理、过滤、聚合和计算任务。其中bucket 和 range 是必填的。
buckets
buckets()返回当前组中所有的桶
from
指定从那个bucket查询数据
from(bucket:"bucket名称")
range
指定时间区间,range接收两个参数,start和stop 其中stop可以省略,缺省值是当前时间。start不能省略,否则会报语法错误。
start和stop 既可以使用相对的时间区间,也可以使用绝对的时间戳。相对时间区间格式为 时间间隔h/m/s例如 -1h,-5m。时间戳格式2021-01-01T00:00:00Z
#示例1
from(bucket:"bucket名称")
|> range(start: -1h)
#示例2
from(bucket:"bucket名称")
|> range(start: 2021-01-01T00:00:00Z, stop: 2021-01-01T12:00:00Z)
filter
对数据进行过滤,接收一个判断函数。类似于java中的lamda,它看起来像是下面这样
® => (r.recordProperty comparisonOperator comparisonExpression)
判断函数返回一个boolean类型值。只有符合条件的记录才会被返回。
#示例
from(bucket: "wxm-influx")
|> range(start: -24h)
|> filter(fn:(r)=>(r.owner=="wxm"))
#取最近24小时,含有owner标签且值为wxm的记录
当filter内含有多个条件时可用 and 或 or 连接各个条件
#示例
from(bucket: "wxm-influx")
|> range(start: -24h)
|> filter(fn:(r)=>(r.owner=="wxm" or r.key=="indoor"))
#取最近24小时,含有owner标签且值为wx或含有标签key且值为indoor的记录
其他
from(bucket: "your_bucket")
|> range(start: -1h)
|> filter(fn: (r) => r._measurement == "your_measurement")
|> filter(fn: (r) => r._field == "your_field")
|> mean()
# 计算平均值
from(bucket: "your_bucket")
|> range(start: -1h)
|> filter(fn: (r) => r._measurement == "your_measurement")
|> filter(fn: (r) => r._field == "your_field")
|> sum()
# 计算总和
集成springboot
配置
pom
<dependency>
<groupId>com.influxdb</groupId>
<artifactId>influxdb-client-java</artifactId>
<version>6.7.0</version>
</dependency>
yml配置文件
influx:
url: http://127.0.0.1:8086
token: 你的token
bucket: 你需要的桶
org: 你设置的组织
config文件
@Data
@Configuration
public class InfluxValues {
@Value("${influx.url}")
private String url;
@Value("${influx.token}")
private String token;
@Value("${influx.org}")
private String org;
@Value("${influx.bucket}")
private String bucket;
}
@Data
@Configuration
public class InfluxConfig {
@Autowired
private InfluxValues influxValues;
/**
* 创建 InfluxDBClient 客户端
* @return
*/
@Bean
public InfluxDBClient influxDBClient(){
return InfluxDBClientFactory.create(influxDBClientOptions());
}
private InfluxDBClientOptions influxDBClientOptions() {
return InfluxDBClientOptions.builder()
.url(influxValues.getUrl())
.org(influxValues.getOrg())
.bucket(influxValues.getBucket())
.authenticateToken(influxValues.getToken().toCharArray())
.build();
}
@Bean
public WriteApi writeApi() {
InfluxDBClient influxDBClient = influxDBClient();
return influxDBClient.makeWriteApi();
}
}
@Service
@Slf4j
public class InfluxDBService {
@Autowired
private InfluxDBClient influxDBClient;
@Autowired
private InfluxValues influxValues;
@Autowired
private WriteApi writeApi;
/**
* 获取表90天数据
*
* @param measurement 表
* @param bucket 桶
* @return
*/
public List<FluxTable> getList(String bucket, String measurement) {
StringBuffer buffer = new StringBuffer();
appendBucketFlux(buffer, bucket);
appendTimeRangeLastFlux(buffer, 2160, "h");
appendTableFlux(buffer, measurement);
return influxDBClient.getQueryApi().query(buffer.toString(), influxValues.getOrg());
}
/**
* 获取指定时间段内的数据
*
* @param hour 小时
* @return
*/
public List<FluxTable> getList(String bucket, int hour) {
StringBuffer buffer = new StringBuffer();
appendBucketFlux(buffer, bucket);
appendTimeRangeLastFlux(buffer, hour, "h");
return influxDBClient.getQueryApi().query(buffer.toString(), influxValues.getOrg());
}
/**
* 获取指定时间段内表的数据
*
* @param hour 小时
* @return
*/
public List<FluxTable> getList(String bucket, String measurement, int hour) {
StringBuffer buffer = new StringBuffer();
appendBucketFlux(buffer, bucket);
appendTimeRangeLastFlux(buffer, hour, "h");
if (measurement != null) {
appendTableFlux(buffer, measurement);
}
return influxDBClient.getQueryApi().query(buffer.toString(), influxValues.getOrg());
}
/**
* 获取表数据(时间筛选)
*
* @param measurement 表
* @return
*/
public List<FluxTable> getList(String bucket, String measurement, String start, String stop) {
StringBuffer buffer = new StringBuffer();
appendBucketFlux(buffer, bucket);
appendTimeRangeFlux(buffer, start, stop);
appendTableFlux(buffer, measurement);
return influxDBClient.getQueryApi().query(buffer.toString(), influxValues.getOrg());
}
/**
* 获取表数据(时间筛选)
*
* @param bucket 桶
* @param measurement 表
* @param start 开始时间
* @param stop 结束时间
* @param limit 限制几个
* @return
*/
// public List<FluxTable> getList(String bucket, String measurement, String start, String stop) {
// StringBuffer buffer = new StringBuffer();
// appendBucketFlux(buffer, bucket);
// appendTimeRangeFlux(buffer, start, stop);
// appendTableFlux(buffer, measurement);
// return influxDBClient.getQueryApi().query(buffer.toString(), influxValues.getOrg());
// }
/**
* 写入数据
*
* @param measurement 表
* @param map map键值对
*/
public void writeData(String measurement, Map<String, Object> map) {
Point point = Point
.measurement(measurement)
.addTag("diff", measurement + DateUtil.formatDate(new Date(), DateUtil.ssFormat))
.addFields(map)
.time(Instant.now(), WritePrecision.NS);
writeApi.writePoint(influxValues.getBucket(), influxValues.getOrg(), point);
}
/**
* 写入数据
* @param bucket 桶
* @param measurement 表
* @param map 参数
*/
public void writeData(String bucket,String measurement, Map<String, Object> map) {
Point point = Point
.measurement(measurement)
.addTag("diff", measurement + DateUtil.formatDate(new Date(), DateUtil.ssFormat))
.addFields(map)
.time(Instant.now(), WritePrecision.NS);
writeApi.writePoint(bucket, influxValues.getOrg(), point);
}
/**
* 数据源(桶)表达式
*
* @param buffer buffer
* @param bucketName 名称
*/
public static void appendBucketFlux(StringBuffer buffer, String bucketName) {
buffer.append("from(bucket: \"").append(bucketName).append("\") ");
}
/**
* 表名表达式
*
* @param buffer buffer
* @param tableName 名称
*/
public static void appendTableFlux(StringBuffer buffer, String tableName) {
buffer.append("|> filter(fn: (r) => r._measurement == \"").append(tableName).append("\") ");
}
/**
* 表名表达式
*
* @param buffer buffer
* @param tag 名称
*/
public static void appendTagFlux(StringBuffer buffer, String tag) {
buffer.append("|> filter(fn: (r) => r.tag == \"").append(tag).append("\") ");
}
/**
* field表达式
*
* @param buffer buffer
* @param field 名称
*/
public static void appendTagField(StringBuffer buffer, String field) {
buffer.append("|> filter(fn: (r) => r._field == \"").append(field).append("\") ");
}
/**
* 时间范围表达式 UTC时间
*
* @param buffer buffer
* @param start 开始时间
* @param stop 结束时间
*/
public static void appendTimeRangeFlux(StringBuffer buffer, String start, String stop) {
if (StringUtils.isEmpty(start)) {
start = "2000-01-01T00:00:00.000Z";
}
if (StringUtils.isEmpty(stop)) {
buffer.append("|> range(start:").append(start).append(") ");
} else {
buffer.append("|> range(start:").append(start).append(", stop:").append(stop).append(") ");
}
}
/**
* 最近多少时间
*
* @param buffer 参数
* @param time 时间
* @param unit 时间单位
*/
public static void appendTimeRangeLastFlux(StringBuffer buffer, int time, String unit) {
buffer.append("|> range(start: -").append(time).append(unit).append(" )");
}
}
测试写入
@ApiOperation(value = "write", notes = "write")
@GetMapping(value = "/write")
public Result<?> write(@ApiParam("用电1/用水2/用气3") @RequestParam(name = "type") Integer type) {
HashMap<String, Object> map = new HashMap<>();
if (type == 1) {
map.put("D2", "7");
map.put("D1", "8");
influxDBService.writeData("device1", map);
}
if (type == 2) {
map.put("S1", "47");
map.put("S2", "35");
influxDBService.writeData("device2", map);
}
if (type == 3) {
map.put("Q1", "3");
map.put("Q2", "3");
influxDBService.writeData("device3", map);
}
return Result.OK();
}
测试读取
@ApiOperation(value = "test", notes = "test")
@GetMapping(value = "/test")
public Result<?> test() {
List<FluxTable> record1 = influxDBService.getList(CollectConstants.BUCKET_ELECTRIC, null, "D1", DateUtil.dateToInFlux(new Date()), null);
return Result.OK(record1);
}