blob: f37cfc625bd6651809d5adb18e7366e65704b187 [file] [log] [blame] [view]
<!--
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.
-->
# OPC UA 协议
## 1. OPC UA
OPC UA 是一种在自动化领域用于不同设备和系统之间进行通信的技术规范,用于实现跨平台、跨语言和跨网络的操作,为工业物联网提供一个可靠和安全的数据交换基础。IoTDB 中支持 OPC UA协议, IoTDB OPC Server 支持 Client/Server 和 Pub/Sub 两种通信模式。
### 1.1 PC UA Client/Server 模式
- **Client/Server 模式**:在这种模式下,IoTDB 的流处理引擎通过 OPC UA Sink 与 OPC UA 服务器(Server)建立连接。OPC UA 服务器在其地址空间(Address Space) 中维护数据,IoTDB可以请求并获取这些数据。同时,其他OPC UA客户端(Client)也能访问服务器上的数据。
<div align="center">
<img src="/img/OPCUA01.png" alt="" style="width: 70%;"/>
</div>
- 特性:
- OPC UA 将从 Sink 收到的设备信息,按照树形模型整理到 Objects folder 下的文件夹中。
- 每个测点都被记录为一个变量节点,并记录当前数据库中的最新值。
### 1.2 OPC UA Pub/Sub 模式
- **Pub/Sub 模式**:在这种模式下,IoTDB的流处理引擎通过 OPC UA Sink 向OPC UA 服务器(Server)发送数据变更事件。这些事件被发布到服务器的消息队列中,并通过事件节点 (Event Node) 进行管理。其他OPC UA客户端(Client)可以订阅这些事件节点,以便在数据变更时接收通知。
<div align="center">
<img src="/img/OPCUA02.png" alt="" style="width: 70%;"/>
</div>
- 特性:
- 每个测点会被 OPC UA 包装成一个事件节点(EventNode)。
- 相关字段及其对应含义如下:
| 字段 | 含义 | 类型(Milo) | 示例 |
| :--------- | :--------------- | :------------ | :-------------------- |
| Time | 时间戳 | DateTime | 1698907326198 |
| SourceName | 测点对应完整路径 | String | root.test.opc.sensor0 |
| SourceNode | 测点数据类型 | NodeId | Int32 |
| Message | 数据 | LocalizedText | 3.0 |
- Event 仅会发送给所有已经监听的客户端,客户端未连接则会忽略该 Event。
## 2. IoTDB OPC Server 启动方式
### 2.1 语法
创建该 Sink 的语法如下:
```SQL
create pipe p1
with source (...)
with processor (...)
with sink ('sink' = 'opc-ua-sink',
'sink.opcua.tcp.port' = '12686',
'sink.opcua.https.port' = '8443',
'sink.user' = 'root',
'sink.password' = 'TimechoDB@2021', //V2.0.6.x 之前默认密码为root
'sink.opcua.security.dir' = '...'
)
```
### 2.2 参数
| **参数** | **描述** | **取值范围** | **是否必填** | **默认值** |
| ---------------------------------- | ------------------------------ | -------------------------------- | ------------ |------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| sink | OPC UA SINK | String: opc-ua-sink | 必填 | |
| sink.opcua.model | OPC UA 使用的模式 | String: client-server / pub-sub | 选填 | pub-sub |
| sink.opcua.tcp.port | OPC UA 的 TCP 端口 | Integer: [0, 65536] | 选填 | 12686 |
| sink.opcua.https.port | OPC UA 的 HTTPS 端口 | Integer: [0, 65536] | 选填 | 8443 |
| sink.opcua.security.dir | OPC UA 的密钥及证书目录 | String: Path,支持绝对及相对目录 | 选填 | iotdb 相关 DataNode 的 conf 目录下的 opc_security 文件夹 /<httpsPort:tcpPort><br>如无 iotdb 的 conf 目录(例如 IDEA 中启动 DataNode),则为用户主目录下的 iotdb_opc_security 文件夹 /<httpsPort:tcpPort> |
| sink.opcua.enable-anonymous-access | OPC UA 是否允许匿名访问 | Boolean | 选填 | true |
| sink.user | 用户,这里指 OPC UA 的允许用户 | String | 选填 | root |
| sink.password | 密码,这里指 OPC UA 的允许密码 | String | 选填 | TimechoDB@2021 //V2.0.6.x 之前默认密码为root |
### 2.3 示例
```Bash
create pipe p1
with sink ('sink' = 'opc-ua-sink',
'sink.user' = 'root',
'sink.password' = 'TimechoDB@2021'); //V2.0.6.x 之前默认密码为root
start pipe p1;
```
### 2.4 使用限制
1. **必须存在 DataRegion**:在 IoTDB 有 dataRegion 时,OPC UA 的服务器才会启动。因此,对于一个空的 IoTDB,需要写入一条数据,OPC UA 的服务器才有效。
2. **需连接才有数据**:每一个订阅该服务器的客户端,不会收到 OPC Server 在连接之前写入IoTDB的数据。
3. **多 DataNode 会有分散发送 / 冲突问题**:
- 对于有多个 dataRegion,且分散在不同 DataNode ip上的 IoTDB 集群,数据会在 dataRegion 的 leader 上分散发送。客户端需要对 DataNode ip 的配置端口分别监听。
- 建议在 1C1D 下使用该 OPC UA 服务器。
4. **不支持删除数据和修改测点类型:**在Client Server模式下,OPC UA无法删除数据或者改变数据类型的设置。而在Pub Sub模式下,如果数据被删除了,信息是无法推送给客户端的。
## 3. IoTDB OPC Server 示例
### 3.1 Client / Server 模式
#### 准备工作
1. 此处以UAExpert客户端为例,下载 UAExpert 客户端:https://www.unified-automation.com/downloads/opc-ua-clients.html
2. 安装 UAExpert,填写自身的证书等信息。
#### 快速开始
1. 使用如下 sql,创建并启动 client-server 模式的 OPC UA Sink。详细语法参见上文:[IoTDB OPC Server语法](#语法)
```SQL
create pipe p1 with sink ('sink'='opc-ua-sink');
```
2. 写入部分数据。
```SQL
insert into root.test.db(time, s2) values(now(), 2)
```
​ 此处自动创建元数据开启。
3. 在 UAExpert 中配置 iotdb 的连接,其中 password 填写为上述参数配置中 sink.password 中设定的密码(此处以密码root为例):
<div align="center">
<img src="/img/OPCUA03.png" alt="" style="width: 60%;"/>
</div>
<div align="center">
<img src="/img/OPCUA04.png" alt="" style="width: 60%;"/>
</div>
4. 信任服务器的证书后,在左侧 Objects folder 即可看到写入的数据。
<div align="center">
<img src="/img/OPCUA05.png" alt="" style="width: 60%;"/>
</div>
<div align="center">
<img src="/img/OPCUA06.png" alt="" style="width: 60%;"/>
</div>
5. 可以将左侧节点拖动到中间,并展示该节点的最新值:
<div align="center">
<img src="/img/OPCUA07.png" alt="" style="width: 60%;"/>
</div>
### 3.2 Pub / Sub 模式
#### 准备工作
该代码位于 iotdb-example 包下的 [opc-ua-sink 文件夹](https://github.com/apache/iotdb/tree/rc/2.0.1/example/pipe-opc-ua-sink/src/main/java/org/apache/iotdb/opcua)中
代码中包含:
- 主类(ClientTest)
- Client 证书相关的逻辑(IoTDBKeyStoreLoaderClient)
- Client 的配置及启动逻辑(ClientExampleRunner)
- ClientTest 的父类(ClientExample)
### 3.3 快速开始
使用步骤为:
1. 打开 IoTDB 并写入部分数据。
```SQL
insert into root.a.b(time, c, d) values(now(), 1, 2);
```
​ 此处自动创建元数据开启。
2. 使用如下 sql,创建并启动 Pub-Sub 模式的 OPC UA Sink。详细语法参见上文:[IoTDB OPC Server语法](#语法)
```SQL
create pipe p1 with sink ('sink'='opc-ua-sink',
'sink.opcua.model'='pub-sub');
start pipe p1;
```
​ 此时能看到服务器的 conf 目录下创建了 opc 证书相关的目录。
<div align="center">
<img src="/img/OPCUA08.png" alt="" style="width: 60%;"/>
</div>
3. 直接运行 Client 连接,此时 Client 证书被服务器拒收。
<div align="center">
<img src="/img/OPCUA09.png" alt="" style="width: 60%;"/>
</div>
4. 进入服务器的 sink.opcua.security.dir 目录下,进入 pki 的 rejected 目录,此时 Client 的证书应该已经在该目录下生成。
<div align="center">
<img src="/img/OPCUA10.png" alt="" style="width: 60%;"/>
</div>
5. 将客户端的证书移入(不是复制) 同目录下 trusted 目录的 certs 文件夹中。
<div align="center">
<img src="/img/OPCUA11.png" alt="" style="width: 60%;"/>
</div>
6. 再次打开 Client 连接,此时服务器的证书应该被 Client 拒收。
<div align="center">
<img src="/img/OPCUA12.png" alt="" style="width: 60%;"/>
</div>
7. 进入客户端的 <java.io.tmpdir>/client/security 目录下,进入 pki 的 rejected 目录,将服务器的证书移入(不是复制)trusted 目录。
<div align="center">
<img src="/img/OPCUA13.png" alt="" style="width: 60%;"/>
</div>
8. 打开 Client,此时建立双向信任成功, Client 能够连接到服务器。
9. 向服务器中写入数据,此时 Client 中能够打印出收到的数据。
<div align="center">
<img src="/img/OPCUA14.png" alt="" style="width: 60%;"/>
</div>
### 3.4 注意事项
1. **单机与集群**:建议使用1C1D单机版,如果集群中有多个 DataNode,可能数据会分散发送在各个 DataNode 上,无法收听到全量数据。
2. **无需操作根目录下证书**:在证书操作过程中,无需操作 IoTDB security 根目录下的 `iotdb-server.pfx` 证书和 client security 目录下的 `example-client.pfx` 目录。Client 和 Server 双向连接时,会将根目录下的证书发给对方,对方如果第一次看见此证书,就会放入 reject dir,如果该证书在 trusted/certs 里面,则能够信任对方。
3. **建议使用** **Java 17+**:在 JVM 8 的版本中,可能会存在密钥长度限制,报 Illegal key size 错误。对于特定版本(如 jdk.1.8u151+),可以在 ClientExampleRunner 的 create client 里加入 `Security.`*`setProperty`*`("crypto.policy", "unlimited");` 解决,也可以下载无限制的包 `local_policy.jar` 与 `US_export_policy `解决替换 `JDK/jre/lib/security `目录下的包解决,下载网址:https://www.oracle.com/java/technologies/javase-jce8-downloads.html。