(1)EMQX:EMQX是基于高并发的 Erlang/OTP 语言平台开发,支持百万级连接和分布式集群架构,发布订阅模式的开源 MQTT 消息服务器。EMQ X 内置了大量开箱即用的功能,其开源版 EMQ X Broker 及企业版 EMQ X Enterprise 均支持通过规则引擎将设备消息存储到 TDengine。
(2)INFLUXDB:InfluxDB是一个由InfluxData开发的开源时序型数据库。它由Go写成,着力于高性能地查询与存储时序型数据。InfluxDB被广泛应用于存储系统的监控数据,IoT行业的实时数据等场景。
(3)Grafana:Grafana 是一个跨平台、开源的度量分析和可视化工具,可以查询处理各类数据源中的数据,进行可视化的展示。它可以快速灵活创建的客户端图表,面板插件有许多不同方式的可视化指标和日志,官方库中具有丰富的仪表盘插件,比如热图、折线图、图表等多种展示方式;支持 Graphite,TDengine、InfluxDB,OpenTSDB,Prometheus,Elasticsearch,CloudWatch和 KairosDB 等数据源,支持数据项独立/混合查询展示;可以创建自定义告警规则并通知到其他消息处理服务或组件中。
以下使用平台为Linux Ubuntu 20.04 与 Docker。
MQTT-JSON内容如下:
{
"host": "test0",
"latitude": 123.123456,
"longitude": 22.564234,
"temperature": 16.22,
"battery": 4.3
}
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化,这里不一定要使用Docker。
使用指令
apt-get install docker docker.io
然后使用docker指令准备两个镜像 分别是emqx influxdb
EMQX:
docker pull emqx/emqx-ee:latest
INFLUXDB:
docker pull influxdb:1.8
此时使用指令
docker images
文件准备完成,开始配置安装EMQX。
这里简单列出使用到的指令
docker pull [images] //拉取镜像指令
docker run -d --name [镜像名称] -p [容器端口:服务器端口] [镜像文件] //运行镜像以指定名称 指定映射端口 运行的镜像名称
docker restart/stop/start/rm [镜像名称] //重启、停止、开始、移除容器但是不会吧镜像移除
docker ps //展示镜像
docker exec -it [镜像名称] bash(/bin/sh) //进入容器 使用bash/sh控制台
//进入容器之后可以输入exit退出容器
docker cp [本地文件/容器文件] [本地文件/容器文件]
//例如 docker cp influxdb.conf influxDb:/etc/influxdb/ 则是拷贝当前文件夹中的influxdb.conf到influxdb容器中的/etc/influxdb/文件夹下
//docker cp influxDb:/etc/influxdb/influxdb.conf . 则表示拷贝influxdb容器中/etc/influxdb/influxdb.conf到当前文件夹
由于docker容器环境中没有提供vi编辑器所以需要先拷贝文件夹下来更改再复制进入容器后再重启容器才能够生效
使用以下指令
docker run -d --name emqx-ee -p 1883:1883 -p 8083:8083 -p 8883:8883 -p 8084:8084 -p 18083:18083 emqx/emqx-ee:latest
docker ps
得到如图 则运行成功 我们使用浏览器输入服务器IP:18083 如xxx.xxx.xxx.xxx:18083进入网页
网页如图所示 默认用户名admin 密码public
如图所示安装成功
但是由于websocket工具占用了8083端口 会导致influxdb无法正常安装
解决方法1:在EMQX主界面左侧栏目->设置->启用->监听器->8083端口的ws->关闭
这样做会导致websocket工具无法使用 但是可以使用MQTT.fx测试工具代替
解决方法2: 在配置Influxdb更改8083的映射端口号,可能会有其他影响。
强调一下这里本文使用的是influx1.8版本,influx2.0版本之后各方面大改,想学习可以自行学习。
先在本地创建一个文件,名称为influxdb.conf
内容如下:配置文件详解
reporting-disabled = false
bind-address = "127.0.0.1:8088"
[meta]
dir = "/var/lib/influxdb/meta"
retention-autocreate = true
logging-enabled = true
[data]
dir = "/var/lib/influxdb/data"
index-version = "inmem"
wal-dir = "/var/lib/influxdb/wal"
wal-fsync-delay = "0s"
validate-keys = false
query-log-enabled = true
cache-max-memory-size = 1073741824
cache-snapshot-memory-size = 26214400
cache-snapshot-write-cold-duration = "10m0s"
compact-full-write-cold-duration = "4h0m0s"
compact-throughput = 50331648
compact-throughput-burst = 50331648
max-series-per-database = 1000000
max-values-per-tag = 100000
max-concurrent-compactions = 0
max-index-log-file-size = 1048576
trace-logging-enabled = false
tsm-use-madv-willneed = false
[coordinator]
write-timeout = "10s"
max-concurrent-queries = 0
query-timeout = "0s"
log-queries-after = "0s"
max-select-point = 0
max-select-series = 0
max-select-buckets = 0
[retention]
enabled = true
check-interval = "30m0s"
[shard-precreation]
enabled = true
check-interval = "10m0s"
advance-period = "30m0s"
[monitor]
store-enabled = true
store-database = "_internal"
store-interval = "10s"
[subscriber]
enabled = true
http-timeout = "30s"
insecure-skip-verify = false
ca-certs = ""
write-concurrency = 40
write-buffer-size = 1000
[http]
enabled = true
bind-address = ":8086"
auth-enabled = false
log-enabled = true
suppress-write-log = false
write-tracing = false
flux-enabled = false
pprof-enabled = true
debug-pprof-enabled = false
https-enabled = false
https-certificate = "/etc/ssl/influxdb.pem"
https-private-key = ""
max-row-limit = 0
max-connection-limit = 0
shared-secret = ""
realm = "InfluxDB"
unix-socket-enabled = false
unix-socket-permissions = "0777"
bind-socket = "/var/run/influxdb.sock"
max-body-size = 25000000
access-log-path = ""
max-concurrent-write-limit = 0
max-enqueued-write-limit = 0
enqueued-write-timeout = 30000000000
[logging]
format = "auto"
level = "info"
suppress-logo = false
[[graphite]]
enabled = false
bind-address = ":2003"
database = "graphite"
retention-policy = ""
protocol = "tcp"
batch-size = 5000
batch-pending = 10
batch-timeout = "1s"
consistency-level = "one"
separator = "."
udp-read-buffer = 0
[[collectd]]
enabled = false
bind-address = ":25826"
database = "collectd"
retention-policy = ""
batch-size = 5000
batch-pending = 10
batch-timeout = "10s"
read-buffer = 0
typesdb = "/usr/share/collectd/types.db"
security-level = "none"
auth-file = "/etc/collectd/auth_file"
parse-multivalue-plugin = "split"
[[opentsdb]]
enabled = false
bind-address = ":4242"
database = "opentsdb"
retention-policy = ""
consistency-level = "one"
tls-enabled = false
certificate = "/etc/ssl/influxdb.pem"
batch-size = 1000
batch-pending = 5
batch-timeout = "1s"
log-point-errors = true
[[udp]]
enabled = true
bind-address = ":8089"
database = "db"
retention-policy = ""
batch-size = 1
batch-pending = 1
read-buffer = 0
batch-timeout = "1s"
precision = ""
[continuous_queries]
log-enabled = true
enabled = true
query-stats-enabled = false
run-interval = "1s"
[tls]
min-version = ""
max-version = ""
生成文件在当前文件夹后使用命令
docker run --name=influxdb --rm -d -p 8086:8086 -p 8089:8089/udp -v influxdb.conf:/etc/influxdb/influxdb.conf:ro -e INFLUXDB_DB=db influxdb:1.8
参数介绍:
-e INFLUXDB_DB=db:创建一个名为db的数据库
-v: 需要配置的文件
-d:deamon,后台启动
-p:port, 端口映射,宿主机端口:容器内端口;8083是influxdb的web管理工具端口,8086是influxdb的HTTP API端口
--expose:允许容器接受外部传入的数据
--name:容器名称,此处为influxDb
influxdb:镜像名
使用指令
docker ps
得到如下图两个docker运行中的容器
我们进入容器 使用如下指令 发现最后展示两个数据库 一个是db 一个是自带的_internal
docker exec -it influxdb bash
influxdb
show databses
quit //退出数据库
输入指令获取grafana镜像并安装运行
docker run -d --name=grafana -p 3000:3000 grafana/grafana
自行下载grafana 完成后打开浏览器输入ip:3000 即可进入界面 账号密码admin
成功后界面如图所示
参考链接
这一部分目的是EMQX接收到MQTT信息之后能够解析并储存起来。
1.打开EMQX服务器登入选择左侧菜单栏->规则引擎->创建
2.SQL输入
SELECT
payload.host as host,
payload.temperature as temperature,
payload.battery as battery,
payload.latitude as latitude,
payload.longitude as longitude
FROM
"sensor/influxdb"
3.打开SQL测试 输入主题 sensor/influxdb 输入json数据
{
"host": "test0",
"latitude": 123.123456,
"longitude": 22.564234,
"temperature": 16.22,
"battery": 4.3
}
4.SQL测试初入正常
5.添加响应动作->动作类型:数据持久化->保存数据到InfluxDB
6.使用资源->新建 如果数据库写入失败这里的influxDB主机填写公网 IP试试
确定后返回填写Measurement Fields Tags等信息
7.根据传入Json内容填写内容如下
确定生成新规则。
1.这里提供一个随机数生成脚本测试,这里我使用了vscode terminal 安装了node.js
并安装了mock、mqtt库
npm install mqtt mockjs --save --registry=https://registry.npm.taobao.org
node mock.js
// mock.js
const mqtt = require('mqtt')
const Mock = require('mockjs')
const EMQX_SERVER = 'mqtt://xxx.xxx.xxx.xxx:1883' //根据ip进行修改
const CLIENT_NUM = 5 //连接设备 由于EMQX非认证版本有10个设备限制 建议最大不超过10
const STEP = 5000 // 模拟采集时间间隔 ms
const AWAIT = 5000 // 每次发送完后休眠时间,防止消息速率过快 ms
const CLIENT_POOL = []
const LONGITUDE_POOL = [113.584557, 113.624811, 113.596916, 113.590908, 113.587132, 113.587132, 113.592796, 113.621464, 113.611593, 113.627815]
const LATITUDE_POOL = [22.345233, 22.347377, 22.341899, 22.337374, 22.349282, 22.328561, 22.359046, 22.347774, 22.361983, 22.357696]
const HOST_POOL = ["test0", "test1", "test2", "test3", "test4", "test5", "test6", "test7", "test8", "test9"]
startMock()
function sleep(timer = 100) {
return new Promise(resolve => {
setTimeout(resolve, timer)
})
}
async function startMock() {
const now = Date.now()
for (let i = 0; i < CLIENT_NUM; i++) {
const client = await createClient(`mock_client_${i}`)
CLIENT_POOL.push(client)
}
// last 24h every 5s
const last = 24 * 3600 * 1000
for (let ts = now - last; ts <= now; ts += STEP) {
for (const client of CLIENT_POOL) {
const mockData = generateMockData()
const data = {
...mockData,
id: client.clientId,
area: 0,
ts,
}
client.publish('sensor/influxdb', JSON.stringify(data))
}
const dateStr = new Date(ts).toLocaleTimeString()
console.log(`${dateStr} send success.`)
await sleep(AWAIT)
}
console.log(`Done, use ${(Date.now() - now) / 1000}s`)
}
/**
* Init a virtual mqtt client
* @param {string} clientId ClientID
*/
function createClient(clientId) {
return new Promise((resolve, reject) => {
const client = mqtt.connect(EMQX_SERVER, {
clientId,
})
client.on('connect', () => {
console.log(`client ${clientId} connected`)
resolve(client)
})
client.on('reconnect', () => {
console.log('reconnect')
})
client.on('error', (e) => {
console.error(e)
reject(e)
})
})
}
/**
* Generate mock data
*/
function generateMockData() {
let i = Mock.Random.integer(0, 9);
return {
"host": HOST_POOL[i],
"latitude": LATITUDE_POOL[i],
"longitude": LONGITUDE_POOL[i],
//"geohash": GEOHASH_POOL[i],
"temperature": parseFloat(Mock.Random.float(10, 40).toFixed(2)),
"battery": parseFloat(Mock.Random.float(3, 4).toFixed(2))
}
}
使用vscode呼出控制台 node mock.js 运行
2.运行之后可以发现emqx上有5个设备连接
3.规则引擎->监控也有成功动作统计
4.然后我们docker 运行influxdb
docker exec -it influxdb bash //使用bash 进入influxdb容器
influx //influxdb数据库指令
use db //使用db数据库
show measurements //展示db下的measurement类似数据库的tables
select * from influx_location //查看所有influx_location里面的信息
5.发现有数据输入
6.表明EMQX收到数据->INFLUXDB转发写入数据成功!
1.进入grafana->datasource->influxdb界面如图
2.填写IP地址与database
user与password没设置就填写admin(可能空着也行没试过)
填写完之后点击save&test 如果返回如图则成功
3.图表测试
左侧选择explor 根据图选择最后展示出曲线图则证明Influxdb->Grafana成功!
测试成功!
(最好打开上面说的node脚本不断上传随机数来验证可视化)
先Create->Dashbord->Add new panel
这里只距离三类图标的引用。
1.在右侧panel->Visualization->stat
2.选择
form:influx_location
WHERE:host = test0
select:field(value)->temperature mean()->remove
GROUP BY:time()->remove
FORMAT AS:Table
实现数据展示
3.复制多一个 把host = test0 改为 host = test1
可以得到
以此类推可以得到更多数据源
4.初次之外还有Field->unit->temperature->Celsius(℃)符号展示
min max为最大最小值 decimals 小数多少位等等可以自行尝试
最后根据需求美化出结果如图所示
同理我们在Visualzation选择Bar gauge选择内容如下
根据需求美化后展示结果
Graph最大的去别是需要一个方位的时间,这里time(1m)和mean()分别代表以一分钟为一段做平均值。
单图表展示
美化后最终效果
Grafana地图大屏不是Grafana默认搭配的插件,需要自己去下载:网址点我
回到SSH工具 使用linux指令
docker exec -it grafana /bin/sh //这里不适用bash是该容器不支持bash
grafana-cli plugins install grafana-worldmap-panel //安装地图插件
exit //退出grafana容器
docker restart grafana //重启grafana容器
重启完刷新界面可以发现Visualzation下多出了Worlmap panel
但是此时由于网络原因地图加载十分缓慢 我们需要配置地图源文件
worldmap解决地图背景不显示的问题
其实主要的问题就是网络的问题,worldmap-panel的访问地址需要进行修改。
1.1 grafana-worldmap-panel\src\worldmap.ts
1.2 grafana-worldmap-panel\dist\module.js
1.3 grafana-worldmap-panel\dist\module.js.map
将文件中的url进行修改.
2.1 https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png 修改为 http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png
2.2 https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_all/{z}/{x}/{y}.png 修改为 http://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png
以上为引用 以下为操作步骤
docker cp grafana:/var/lib/grafana/plugins/grafana-worldmap-panel/src/worldmap.ts .
docker cp grafana:/var/lib/grafana/plugins/grafana-worldmap-panel/dist/module.js .
docker cp grafana:/var/lib/grafana/plugins/grafana-worldmap-panel/dist/module.js.map .
vi worldmap.ts
vi module.js
vi moduel.js.map
按照上述修改url
docker cp worldmap.ts grafana:/var/lib/grafana/plugins/grafana-worldmap-panel/src/
docker cp module.js grafana:/var/lib/grafana/plugins/grafana-worldmap-panel/dist/
docker cp module.js.map grafana:/var/lib/grafana/plugins/grafana-worldmap-panel/dist/
docker restart grafana
因为修改了文件所以在plugins下的worldmap panel出现modified signature是正常现象
现在我们就可以很快的刷新地图啦
配置图和展示图如下
其中alias表示重命名与右侧coordinates中的metric、latitude、longitude链接起来
query->data也能看到传入的数据
把一切部署完成后展示页面如图所示
Configuration->Users->Invite创建一个用户
根据需要起名字和邮箱 选择Viewer 关闭Send invite email Submit生成用户
按图选择 这里复制出来的链接是 localhost.com/… localhost需要改为服务器的公网IP
然后就进入用户登陆界面
第一次登陆输入密码就可以以游客身份登陆啦
可以看到游客仅有查看的权限没有编辑权限
此时我们先回到管理员权限进入dashboard->setting->permissions
如图所示
最终实现了只有单一游客用户查看此图功能!
修改时间查看方式
precision rfc3339
创建超级账户
create user "sitech" with password 'sitech' with all privileges
创建普通账户
create user "123" with password '123'
展示用户
show users
展示数据库
show databases
展示图表
show measurement
搜索语法
Select [avg(temperature)] from [measurement] [where/order/group]
登录有用户的数据库
influx -username sitech -password sitech
influxdb docker环境中:
重置系统时间
rm -rf /etc/localtime
ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime