想象一下你家里装了十几个智能设备,从温湿度传感器到智能灯泡,每个设备都在不断产生数据。这些数据通过MQTT协议发送到EMQX服务器后,就像一堆杂乱无章的快递包裹堆在仓库里。规则引擎就是那个聪明的分拣机器人,它能根据你的指令,把特定包裹(数据)精准投递到指定位置(云端数据库)。
我去年给一个智能农场项目做方案时就深刻体会到,没有规则引擎的话,光是处理不同作物区的传感器数据就要写一堆代码。而用了EMQX的规则引擎后,只需要配置几条SQL规则,就能把大棚A的温度数据存MySQL,大棚B的湿度数据发MongoDB,异常数据还能实时触发告警。
规则引擎本质上是个实时数据路由器,它通过三个核心组件工作:
最近帮朋友改造智能家居系统时,我们设计了一个典型的应用场景:客厅的温湿度传感器每分钟上报数据,智能插座记录用电量,门窗传感器触发安防告警。这些设备都通过MQTT发布到EMQX,但需要分类存储:
先看一个标准的MQTT消息结构(JSON格式):
json复制{
"clientid": "livingroom_sensor_01",
"topic": "smart_home/livingroom",
"payload": {
"device_type": "environment",
"values": {
"temperature": 26.5,
"humidity": 45
},
"timestamp": 1620000000
}
}
在设计消息结构时我踩过坑:最初把所有数据平铺在payload里,结果规则引擎的SQL处理特别麻烦。后来改成这种嵌套结构,既清晰又方便提取特定字段。
假设我们要提取温度超过30度的异常数据,SQL规则这样写:
sql复制SELECT
payload.values.temperature as temp,
payload.values.humidity as humi,
clientid as device
FROM
"smart_home/#"
WHERE
payload.device_type = 'environment'
AND payload.values.temperature > 30
几个实用技巧:
#通配符匹配多级主题payload.xx.xx访问嵌套字段在EMQX管理后台(默认地址http://localhost:18083),进入"规则引擎"-"资源":
http://your-api.com/env_datacode复制Content-Type: application/json
Authorization: Bearer your_token
重要提示:如果API部署在云服务器,记得在安全组开放对应端口。有次调试两小时才发现是阿里云端口没开...
默认情况下,Webhook会发送整个消息体。但通常我们只需要部分字段,这时可以用消息模板:
json复制{
"device": "${device}",
"temperature": ${temp},
"humidity": ${humi},
"alert": "温度过高"
}
这个模板会生成:
json复制{
"device": "livingroom_sensor_01",
"temperature": 31.5,
"humidity": 42,
"alert": "温度过高"
}
以Python Flask为例,接收端代码这样写:
python复制from flask import Flask, request
import json
app = Flask(__name__)
@app.route('/env_data', methods=['POST'])
def handle_data():
data = request.get_json()
# 写入数据库逻辑
print(f"收到告警数据: {data}")
return {'status': 'success'}
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
常见问题排查:
假设我们要存储到MySQL的sensor_data表,字段包括:
对应的API处理代码:
python复制import mysql.connector
def save_to_mysql(data):
conn = mysql.connector.connect(
host="localhost",
user="root",
password="yourpassword",
database="iot_db"
)
cursor = conn.cursor()
sql = """
INSERT INTO sensor_data
(device_id, temp, humi, record_time)
VALUES (%s, %s, %s, FROM_UNIXTIME(%s))
"""
cursor.execute(sql, (
data['device'],
data['temperature'],
data['humidity'],
data['timestamp']
))
conn.commit()
对于高频采集的数据,更适合用时序数据库:
python复制from influxdb import InfluxDBClient
client = InfluxDBClient(host='localhost', port=8086)
client.switch_database('iot_data')
def write_to_influx(data):
json_body = [{
"measurement": "environment",
"tags": {"device": data['device']},
"time": int(data['timestamp'])*1000000000,
"fields": {
"temperature": data['temperature'],
"humidity": data['humidity']
}
}]
client.write_points(json_body)
当设备量上来后,我发现规则引擎可能成为瓶颈。通过这几个优化手段,单机处理能力提升了3倍:
smart_home/+/environment代替通配符查询有次服务器宕机导致数据丢失后,我增加了这些保护措施:
在管理后台的"监控"选项卡里,我重点关注这些指标:
配合Grafana可以做出这样的监控面板:
sql复制SELECT
rate(topic_messages) as msg_rate,
rate(actions.success) as success_rate
FROM
"$SYS/rules"
上周有个客户反馈规则不生效,我们这样排查:
/var/log/emqx)遇到设备上报的数据格式不规范时,可以在SQL里用函数处理:
sql复制SELECT
payload.temp/10 as temperature, -- 原始数据是放大10倍的整型
timestamp/1000 as unix_time, -- 毫秒转秒
lower(payload.devicename) as device_id -- 统一转小写
FROM
"device/raw"
当设备超过1万台时,建议: