从KEPServerEX6到IoTDB的心路历程

写在前面:文章内容为本人的学习过程,路过大神不喜勿喷!

一、准备条件

  • KEPServerEX 6 : 连接设备侧软件
  • IoTDB:数据存储侧软件
  • EMQX 或 Mosquitto:中间转发MQTT消息的服务端
  • Java8 x64 和 x86:64位为运行环境,x86为KEP6的MQTT客户端运行环境
  • MQTTX:客户端连接工具
  • WorkBench:数据库操作工具

二、安装KEPServerEX6

  • 大家自行网络遨游寻找KEPServerEX 6 下载,下载安装以后还需要进行破解(破解版仅学习使用吧,如果大家商用请支持正版),由于需要使用KEPServerEX的Iot GetWay组件,如果不破解有可能会提示到期时间的警告。
  • 当安装好KEPServerEX 6后需要配置下32位的jre环境
  • 在开始菜单中启动
    在这里插入图片描述
  • 在桌面右下角,右键KEPServerEX选择设置,配置32位jre的根目录位置。
    在这里插入图片描述
    在这里插入图片描述

至此,KEPServerEX6基础已经安装好。

三、安装IoTDB

  • IoTDB为Apache的开源项目,所以直接去官网或者Git上下载即可

在这里插入图片描述
在这里插入图片描述

选择Http下载压缩包,解压缩到本地即可使用。

四、整体数据流转方式

方式一
方式二

  • 个人认为,根据实际数据量、设备数量、点位数量选择不同的数据流转方式吧。

IoTDB的官方示例:1000设备,每个设备100 测点,共 100000 序列,INT32类型。采样频率1Hz(每秒一次),存储1年,3副本。
完整计算公式:1000设备 * 100测点 * 12字节每数据点 * 86400秒每天 * 365天每年 * 3副本/10压缩比=11T
简版计算公式:1000 * 100 * 12 * 86400 * 365 * 3 / 10 = 11T

  • 方式二对比方式一来看,多了一个独立的MQTT服务端,以至于更好的可以对外提供服务,但是需要多布置一台MQTT服务端,增加维护和部署的难度。
  • 此处,我使用第一种方式进行学习和试验。

五、配置KEPServer点位

此处,遵循一下IoTDB的存储形式,来增加KEPServer的设备点位。以下是官网的一段描述:

  • 我们以风电场物联网场景为例,说明如何在 IoTDB 中创建一个正确的数据模型。
  • 根据企业组织结构和设备实体层次结构,我们将其物联网数据模型表示为如下图所示的属性层级组织结构,即电力集团层-风电场层-实体层-物理量层。其中 ROOT 为根节点,物理量层的每一个节点为叶子节点。IoTDB 采用树形结构定义数据模式,以从 ROOT 节点到叶子节点的路径来命名一个时间序列,层次间以“.”连接。例如,下图最左侧路径对应的时间序列名称为ROOT.ln.wf01.wt01.status

在这里插入图片描述

  • 在KEPServer中添加测试点位
    在这里插入图片描述
  • 右键连接性新建通道 —> 右键通道新建设备 —> 右键设备新建分组 —> 右键分组新建标记
    在这里插入图片描述
  • 使用KEPServer的IoT Getway组件,右键IoT Getway选择New Agent。
    在这里插入图片描述
  • 配置MQTT的URL和Topic,其他选项根据需要修改吧。
    在这里插入图片描述
  • 根据MQTT服务端的需要,配置ClientID、用户名和密码。注意要确保ClientID不在整个流程中重复。用户名和密码如果MQTT服务端需要身份验证,则需要填写,如何没有配置身份验证空着即可。
    在这里插入图片描述
  • 选择完成后,双击打开编辑器,选择Message,选择Message Fomat类型为Advanced Template,修改Template格式。此处要考虑到后面IoTDb的一些格式化问题。MQTT的消息有效载荷可以由 Java SPI 加载的PayloadFormatter格式化为事件,默认实现为JSONPayloadFormatter,此处格式与后面自定义格式化的Java类所处理的格式对应,根据实际情况修改。为方便处理,我将默认格式修改成了一下格式:
[
   |#each VALUES|
    {"device": "|TAGNAME|", "values": |VALUE|,  "timestamp": |TIMESTAMP| } |#unless @last|,|/unless|
   |/each|
]

在这里插入图片描述

六、配置IoTDB

  • 修改${IOTDB_HOME}/conf/iotdb-datanode.properties , 根据需要修改IP和Port即可,其他就默认。
####################
### Data Node RPC Configuration
####################

# Used for connection of IoTDB native clients(Session)
# Could set 127.0.0.1(for local test) or ipv4 address
# Datatype: String
dn_rpc_address=192.168.20.131

# Used for connection of IoTDB native clients(Session)
# Bind with dn_rpc_address
# Datatype: int
dn_rpc_port=8007

# Used for communication inside cluster.
# could set 127.0.0.1(for local test) or ipv4 address.
# Datatype: String
dn_internal_address=192.168.20.131

# Used for communication inside cluster.
# Bind with dn_internal_address
# Datatype: int
dn_internal_port=10730

# Port for data exchange among DataNodes inside cluster
# Bind with dn_internal_address
# Datatype: int
dn_mpp_data_exchange_port=10740

# port for consensus's communication for schema region inside cluster.
# Bind with dn_internal_address
# Datatype: int
dn_schema_region_consensus_port=10750

# port for consensus's communication for data region inside cluster.
# Bind with dn_internal_address
# Datatype: int
dn_data_region_consensus_port=10760

# Datatype: long
# The time of data node waiting for the next retry to join into the cluster.
# dn_join_cluster_retry_interval_ms=5000

####################
### Seed ConfigNode
####################

# dn_seed_config_node points to any running ConfigNode's cn_internal_address:cn_internal_port.
# Note: After this DataNode successfully joins the cluster for the first time, this parameter is no longer used.
# Each node automatically maintains the list of ConfigNodes and traverses connections when restarting.
# Format: address:port   e.g. 127.0.0.1:10710
# Datatype: String
dn_seed_config_node=192.168.20.131:10710 
  • 修改 ${IOTDB_HOME}/conf/iotdb-common.properties , 此处需要打开IoTDB自带的MQTT服务器端,配置基础的IP和端口,注意1883是MQTT服务器的默认端口,如果开启2个或者多个MQTT服务,需要修改成不同端口监听,否则启动报错。
####################
### Config Node RPC Configuration
####################

# Used for RPC communication inside cluster.
# Could set 127.0.0.1(for local test) or ipv4 address.
# Datatype: String
cn_internal_address=192.168.20.131

# Used for RPC communication inside cluster.
# Datatype: int
cn_internal_port=10710

# Used for consensus communication among ConfigNodes inside cluster.
# Datatype: int
cn_consensus_port=10720

####################
### Seed ConfigNode
####################

# For the first ConfigNode to start, cn_seed_config_node points to its own cn_internal_address:cn_internal_port.
# For other ConfigNodes that to join the cluster, cn_seed_config_node points to any running ConfigNode's cn_internal_address:cn_internal_port.
# Note: After this ConfigNode successfully joins the cluster for the first time, this parameter is no longer used.
# Each node automatically maintains the list of ConfigNodes and traverses connections when restarting.
# Format: address:port   e.g. 127.0.0.1:10710
# Datatype: String
cn_seed_config_node=192.168.20.131:10710 
  • mqtt_payload_formatter为自定义Json格式化类,默认是json,但是有可能数据并不满足IoTDB的存储要求。以下是
    IoTDB官方提供的 MQTT 消息有效负载:
 {
      "device":"root.sg.d1",
      "timestamp":1586076045524,
      "measurements":["s1","s2"],
      "values":[0.530635,0.530635]
 }

或者

 {
      "device":"root.sg.d1",
      "timestamps":[1586076045524,1586076065526],
      "measurements":["s1","s2"],
      "values":[[0.530635,0.530635], [0.530655,0.530695]]
 }

七、自定义 MQTT 消息格式

事实上可以通过简单编程来实现 MQTT 消息的格式自定义。
可以在源码的 example/mqtt-customize 项目中找到一个简单示例。

  • 创建一个 Java 项目,增加如下依赖。
  • 打开官网实例直接修改的话,在mvn package的时候有可能会报错(我再次坑了很久),新建项目就没问题。
  • 在下载相关依赖的时候会很慢,反正我等待了很长时间,有些依赖阿里源的镜像中没有,至于其他镜像源有没有此处我也不得而知了,所以我使用的是官方源下载的相关依赖,等…。
        <dependency>
            <groupId>org.apache.iotdb</groupId>
            <artifactId>iotdb-server</artifactId>
            <version>1.3.0</version>
        </dependency>
  • 创建一个实现类,实现接口 org.apache.iotdb.db.mqtt.protocol.PayloadFormatter , 此处对应传输过来的格式,是上面KEPServer 中Message配置的Template格式。
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.apache.iotdb.mqtt.server;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import io.netty.buffer.ByteBuf;
import org.apache.iotdb.db.protocol.mqtt.Message;
import org.apache.iotdb.db.protocol.mqtt.PayloadFormatter;

import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class CustomizedJsonPayloadFormatter implements PayloadFormatter {

    @Override
    public List<Message> format(ByteBuf payload) {
        if (payload == null) {
            return Collections.emptyList();
        }

        String json = payload.toString(StandardCharsets.UTF_8);
        JsonElement element = JsonParser.parseString(json);
        JsonArray array = element.getAsJsonArray();

        Map<String, Message> map = new ConcurrentHashMap<>();
        for (int i = 0; i < array.size(); i++) {
            JsonObject object = array.get(i).getAsJsonObject();
            String device = object.get("device").getAsString();
            Long timestamp = object.get("timestamp").getAsLong();
            String value = object.get("values").getAsString();
            String[] deviceArr = device.split("\\.");
            String[] deviceHead = Arrays.copyOf(deviceArr, deviceArr.length - 1);
            String deviceName = String.join(".", deviceHead);
            String deviceSub = deviceArr[deviceArr.length - 1];
            Message message = map.getOrDefault(deviceName, new Message());
            if (message.getDevice() != null) {
                List<String> measurements = message.getMeasurements();
                measurements.add(deviceSub);
                message.setMeasurements(measurements);

                List<String> values = message.getValues();
                values.add(value);
                message.setValues(values);
            } else {
                message.setDevice(deviceName);
                message.setTimestamp(timestamp);
                message.setMeasurements(new ArrayList<>(Collections.singletonList(deviceSub)));
                message.setValues(new ArrayList<>(Collections.singletonList(value)));
                map.put(deviceName, message);
            }
        }
        return new ArrayList<>(map.values());
    }

    @Override
    public String getName() {
        // set the value of mqtt_payload_formatter in iotdb-common.properties as the following string:
        return "CustomizedJson";
    }
}
  • 修改项目中的 src/main/resources/META-INF/services/org.apache.iotdb.db.protocol.mqtt.PayloadFormatter文件: 将示例中的文件内容清除,并将刚才的实现类的全名(包名.类名)写入文件中。注意,这个文件中只有一行。在本例中,文件内容为 : org.apache.iotdb.mqtt.server.CustomizedJsonPayloadFormatter
  • 编译项目生成一个 jar 包: mvn package -DskipTests

在 IoTDB 服务端:

  • 找到 ${IOTDB_HOME}/ext/mqtt/ 文件夹, 将刚才的 jar 包放入此文件夹。
  • 打开 MQTT 服务参数. (enable_mqtt_service=true in conf/iotdb-common.properties)
  • 用刚才的实现类中的 getName() 方法的返回值 设置为 conf/iotdb-common.properties 中
    mqtt_payload_formatter 的值,在本例中,为 CustomizedJson
  • 启动 IoTDB

至此,整个需要配置的部分基本完成,接下来就可以启动 KEPServer 中 IoT Getway服务,在控制台出现以下内容,说明连接上了IoTDB的MQTT服务端,并且开始持续发送点位数据。
在这里插入图片描述

八、其他组件

  • 可以安装一个MQTTX客户端订阅和发布消息,用来调试很方便。这里的配置连接很简单,网上也有很多教程,在此就不再过多赘述。

在这里插入图片描述

  • 可以在安装一个WorkBench(开源版和企业版功能上会有差距,大家按需要下载),用来操作IoTDB,类似与Navicat等操作数据库的工具。启动后台,使用浏览器访问,配置上IoTDB即可看到所有点位信息。
    在这里插入图片描述
    最后的最后:希望文章可以帮到大家,我们共同学习,加油吧!!!!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值