前言
Redis简介
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
查看Redis命令大全 → 访问Redis论坛 → Redis使用内存计算器 →
应用场景
最近工作中使用Nodejs编写后端程序操作redis,从redis缓存中获取对应的站房的监测环境数据,然后再提供http和websocket接口,提供给前端获取并实时展示。刚开始使用的是node-redis这个库,其对应的github地址是:https://github.com/NodeRedis/node-redis,npm官网地址是:https://www.npmjs.com/package/node-redis,后来发现了国内阿里的一个Nodejs的redis库,其npm官网地址是:https://www.npmjs.com/package/ioredis,ioredis库比node-redis更新维护快并且比较新,所以就改用ioredis库了。
从redis缓存中获取对应的站房的监测环境数据,然后再提供http接口,返回所有的站房监测数据,获取可以根据某个站点编码返回对应的站房监测数据 根据数据类型(用datatype表示),站房环境数据的数据缓存结构的datatype为env 所有的数据存储都是以key-value键值对形式存储在Redis中,编码为UTF8。数据存储的key结构都是一致的,形式为 “数据类型:解析类型:站点编码:日期(yyyyMMdd):时间(HHmmss)”
数据存储value键都是以hash方式存储,其中field为数据标识, value为数据值。 监测数据的field根据解析类型有两种形式,如下
- “监测项名称” 监测数据的value根据解析类型有两种形式,如下 “监测项名称|数值|标记|平台监测因子编码|平台监测因子单位标识”
站房环境数据结构在redis中存储的形式如下图所示:
1、使用node-redis库
使用npm或cnpm安装依赖
$ npm install node-redis
相关的nodejs代码node_redis_client_demo.js如下所示:
var express = require('express');
var app = express();
var http = require('http').Server(app);
var port = process.env.PORT || 3001;
const redis = require('redis')
http.listen(port, function(){
console.log('listening on localhost:' + port);
})
const redisClient = redis.createClient({
host: '127.0.0.1',
port: 6379,
password: '1234',
db: 3
});
// 站房环境数据信息
const envData = {
CylinderGasPress3: 'CylinderGasPress3|9.05||EP126|',
IA: 'IA|7.80||EP117|',
SmokeState: 'SmokeState|0||EP113|',
CylinderGasPress: 'CylinderGasPress|7.58||EP124|',
StationHum: 'StationHum|39.59||EP121|',
VB: 'VB|225.24||EP115|',
PipeTemp: 'PipeTemp|32.50||EP122|',
VC: 'VC|224.05||EP116|',
IB: 'IB|7.34||EP118|',
SwitchState: 'SwitchState|1||EP111|',
PipeHum: 'PipeHum|20.10||EP123|',
VA: 'VA|225.93||EP114|',
Water1: 'Water1|1||EP112|',
StationTemp: 'StationTemp|28.60||EP120|',
AlarmState: 'AlarmState|0||EP110|',
CylinderGasPress2: 'CylinderGasPress2|6.33||EP125|',
IC: 'IC|2.92||EP119|'
}
// 站房环境信息
var lastenvBuff = {};
// 写入Javascript(JSON)对象
// 站房环境监测数据(测试3个站点)
redisClient.hmset('env:hbxd:420100401:20200409:100901', envData, function(err){
console.log(err)
})
redisClient.hmset('env:hbxd:421000405:20200409:172000', envData, function(err){
console.log(err)
})
redisClient.hmset('env:hbxd:422800408:20200409:172800', envData, function(err){
console.log(err)
})
// 读取Javscript(JSON)对象
// redisClient.hgetall('env:*', function (err, object) {
// console.log(object)
// })
redisClient.keys('env:*', function(err,keys){
console.log(keys)
// 打印所有的站房环境数据的redis key
console.log(keys);
// 遍历站房环境数据的keys数组
for (let i = 0; i < keys.length; i++) {
// 从keys中解析得到站点编码、数据时间等信息
const strArrayTemp = keys[i].split(':');
const strstcode = strArrayTemp[2];
const strdataTime = strArrayTemp[3] + strArrayTemp[4];
// 将数据时间从 20200228135130 转换成 2020-02-28 13:51:30 的格式
let year = strdataTime.substr(0, 4);
let month = strdataTime.substr(4, 2);
let day = strdataTime.substr(6, 2);
let hour = strdataTime.substr(8, 2);
let minute = strdataTime.substr(10, 2);
let second = strdataTime.substr(12, 2);
// let date = Date();
//timestamp = moment().format('YYYY-MM-DD HH:mm:ss');
var strTimestamp = year + '-' + month + '-' + day + ' ' + hour + ':' + minute+ ':' + second;
// 根据每一个hash key获取到对应的filed和value
// hgetall(key):返回名称为key的hash中所有的键(field)及其对应的value
redisClient.hgetall(keys[i], function(err,obj) {
var envMonitorArr = []; // 当前站点的站房监测因子信息数组
console.log('第' + (i+1) + '个站点的站点编码为:' + strstcode + ',数据时间为:' + strTimestamp);
// 遍历某个站点的所有站房监测信息
for (var pkey in obj) {
// console.log('field:' + pkey + ',value:' + obj[pkey]);
// 从value中解析出监测因子编码,数值,标记位,单位
var strValArray = obj[pkey].split('|');
var sValue = strValArray[1];
var strMark = strValArray[2];
var strParamCode = strValArray[3];
var strUnit = strValArray[4];
console.log('监测因子编码:' + strParamCode + ',数值:' + sValue + ',标记位:' + (strMark ? strMark: 'N'));
// 将站房监测因子添加到监测因子数组中
envMonitorArr.push({
'code': strParamCode,
'value': sValue,
'mark': strMark ? strMark: 'N'
})
}
var jsonObj = {
'stcode': strstcode,
'time': strdataTime,
'envList': envMonitorArr
}
// 缓存每个站点的站房的最新数据
var env_data_arr = [];
env_data_arr.push(Object.assign({}, jsonObj));
// 遍历站房缓存数据数组
for (var ii = 0; ii < env_data_arr.length; ii++) {
var iitem = env_data_arr[ii];
console.log('站房监测信息:' + JSON.stringify(iitem));
var stacode = iitem.stcode;
if (!(stacode in lastenvBuff)) {
lastenvBuff[stacode] = {'stcode': stacode, 'time': strTimestamp, 'envList': iitem.envList};
} else {
if (strdataTime > lastenvBuff[stacode].time) {
lastenvBuff[stacode] = {'stcode': stacode, 'time': strTimestamp, 'envList': iitem.envList};
}
}
}
// 打印当前所有站点的站房环境信息
console.log(JSON.stringify(lastenvBuff))
})
}
})
// 获取某个站点的最新的站房环境数据
app.get('/api/envData/:stcode', function (req, res) {
console.log(req.params)
// 获取客户端传过来的站点编码
var stcode = req.params.stcode
// 以站点编码为key,返回缓存中的历史报警记录
res.send(lastenvBuff[stcode]);
});
// 获取当前所有站点的站房环境数据
app.get('/api/allEnvData/', function (req, res) {
res.send(lastenvBuff);
});
2、使用ioredis库
使用npm或者cnpm安装ioredis库
$ npm install ioredis
对应的noejs代码ioredis_client_demo.js如下:
var express = require('express');
var app = express();
var http = require('http').Server(app);
var port = process.env.PORT || 3001;
http.listen(port, function(){
console.log('listening on localhost:' + port);
})
const Redis = require("ioredis");
// redis配置
const redisConfig = {
host: "127.0.0.1", // Redis host
port: 7001, // Redis port
password: "1234",
db: 4,
retryStrategy: function(times){
return Math.min(times * 50, 5000)
},
// enableOfflineQueue: false
}
const redisClient = new Redis(redisConfig); // uses defaults unless given configuration object
// 站房环境数据信息
const envData = {
CylinderGasPress3: 'CylinderGasPress3|9.05||EP126|',
IA: 'IA|7.80||EP117|',
SmokeState: 'SmokeState|0||EP113|',
CylinderGasPress: 'CylinderGasPress|7.58||EP124|',
StationHum: 'StationHum|39.59||EP121|',
VB: 'VB|225.24||EP115|',
PipeTemp: 'PipeTemp|32.50||EP122|',
VC: 'VC|224.05||EP116|',
IB: 'IB|7.34||EP118|',
SwitchState: 'SwitchState|1||EP111|',
PipeHum: 'PipeHum|20.10||EP123|',
VA: 'VA|225.93||EP114|',
Water1: 'Water1|1||EP112|',
StationTemp: 'StationTemp|28.60||EP120|',
AlarmState: 'AlarmState|0||EP110|',
CylinderGasPress2: 'CylinderGasPress2|6.33||EP125|',
IC: 'IC|2.92||EP119|'
}
// 站房环境信息
var lastenvBuff = {};
// 写入Javascript(JSON)对象
// 站房环境监测数据(测试3个站点)
redisClient.hmset('env:hbxd:420100401:20200409:100901', envData, function(err){
console.log(err)
})
redisClient.hmset('env:hbxd:421000405:20200409:172000', envData, function(err){
console.log(err)
})
redisClient.hmset('env:hbxd:422800408:20200409:172800', envData, function(err){
console.log(err)
})
redisClient.on('connect', () => {
console.log('成功连接到Redis')
// 获取站房环境数据的所有key列表
redisClient.keys('env:hbxd:*', function(err,keys){
// 打印所有的站房环境数据的redis key
console.log(keys);
envKeys = keys;
// 遍历站房环境数据的keys数组
for (let i = 0; i < keys.length; i++) {
// 从keys中解析得到站点编码、数据时间等信息
const strArrayTemp = keys[i].split(':');
const strstcode = strArrayTemp[2];
const strdataTime = strArrayTemp[3] + strArrayTemp[4];
// 将数据时间从 20200228135130 转换成 2020-02-28 13:51:30 的格式
let year = strdataTime.substr(0, 4);
let month = strdataTime.substr(4, 2);
let day = strdataTime.substr(6, 2);
let hour = strdataTime.substr(8, 2);
let minute = strdataTime.substr(10, 2);
let second = strdataTime.substr(12, 2);
// let date = Date();
//timestamp = moment().format('YYYY-MM-DD HH:mm:ss');
var strTimestamp = year + '-' + month + '-' + day + ' ' + hour + ':' + minute+ ':' + second;
// 根据每一个hash key获取到对应的filed和value
// hgetall(key):返回名称为key的hash中所有的键(field)及其对应的value
redisClient.hgetall(keys[i], function(err,obj) {
var envMonitorArr = []; // 当前站点的站房监测因子信息数组
console.log('第' + (i+1) + '个站点的站点编码为:' + strstcode + ',数据时间为:' + strTimestamp);
// 遍历某个站点的所有站房监测信息
for (var pkey in obj) {
// console.log('field:' + pkey + ',value:' + obj[pkey]);
// 从value中解析出监测因子编码,数值,标记位,单位
var strValArray = obj[pkey].split('|');
var sValue = strValArray[1];
var strMark = strValArray[2];
var strParamCode = strValArray[3];
var strUnit = strValArray[4];
console.log('监测因子编码:' + strParamCode + ',数值:' + sValue + ',标记位:' + (strMark ? strMark: 'N'));
// 将站房监测因子添加到监测因子数组中
envMonitorArr.push({
'code': strParamCode,
'value': sValue,
'mark': strMark ? strMark: 'N'
})
}
var jsonObj = {
'stcode': strstcode,
'time': strdataTime,
'envList': envMonitorArr
}
// 缓存每个站点的站房的最新数据
var env_data_arr = [];
env_data_arr.push(Object.assign({}, jsonObj));
// 遍历站房缓存数据数组
for (var ii = 0; ii < env_data_arr.length; ii++) {
var iitem = env_data_arr[ii];
console.log('站房监测信息:' + JSON.stringify(iitem));
var stacode = iitem.stcode;
if (!(stacode in lastenvBuff)) {
lastenvBuff[stacode] = {'stcode': stacode, 'time': strTimestamp, 'envList': iitem.envList};
} else {
if (strdataTime > lastenvBuff[stacode].time) {
lastenvBuff[stacode] = {'stcode': stacode, 'time': strTimestamp, 'envList': iitem.envList};
}
}
}
// 打印当前所有站点的站房环境信息
// console.log(JSON.stringify(lastenvBuff))
})
}
})
})
// 获取某个站点的最新的站房环境数据
app.get('/api/envData/:stcode', function (req, res) {
console.log(req.params)
// 获取客户端传过来的站点编码
var stcode = req.params.stcode
// 以站点编码为key,返回缓存中的历史报警记录
res.send(lastenvBuff[stcode]);
});
// 获取当前所有站点的站房环境数据
app.get('/api/allEnvData/', function (req, res) {
res.send(lastenvBuff);
});
3、运行程序
保证在对应系统中安装好express和ioredis、node-redis依赖后,使用node ioredis_client_demo.js执行对应的nodejs后台程序,在localhost:3001端口上监听,提供http服务。
(1)、请求所有站房的环境数据
在浏览器中输入路径:http://localhost:3001/api/allEnvData/ 得到当前所有站点的站房环境数据,如下图所示: 完整的JSON数据如下所示:
{
420100401: {
stcode: "420100401",
time: "2020-04-09 17:28:00",
envList: [
{
code: "EP126",
value: "9.05",
mark: "N"
},
{
code: "EP117",
value: "7.80",
mark: "N"
},
{
code: "EP113",
value: "0",
mark: "N"
},
{
code: "EP124",
value: "7.58",
mark: "N"
},
{
code: "EP121",
value: "39.59",
mark: "N"
},
{
code: "EP115",
value: "225.24",
mark: "N"
},
{
code: "EP122",
value: "32.50",
mark: "N"
},
{
code: "EP116",
value: "224.05",
mark: "N"
},
{
code: "EP118",
value: "7.34",
mark: "N"
},
{
code: "EP111",
value: "1",
mark: "N"
},
{
code: "EP123",
value: "20.10",
mark: "N"
},
{
code: "EP114",
value: "225.93",
mark: "N"
},
{
code: "EP112",
value: "1",
mark: "N"
},
{
code: "EP120",
value: "28.60",
mark: "N"
},
{
code: "EP110",
value: "0",
mark: "N"
},
{
code: "EP125",
value: "6.33",
mark: "N"
},
{
code: "EP119",
value: "2.92",
mark: "N"
}
]
},
421000405: {
stcode: "421000405",
time: "2020-04-09 17:28:00",
envList: [
{
code: "EP126",
value: "9.05",
mark: "N"
},
{
code: "EP117",
value: "7.80",
mark: "N"
},
{
code: "EP113",
value: "0",
mark: "N"
},
{
code: "EP124",
value: "7.58",
mark: "N"
},
{
code: "EP121",
value: "39.59",
mark: "N"
},
{
code: "EP115",
value: "225.24",
mark: "N"
},
{
code: "EP122",
value: "32.50",
mark: "N"
},
{
code: "EP116",
value: "224.05",
mark: "N"
},
{
code: "EP118",
value: "7.34",
mark: "N"
},
{
code: "EP111",
value: "1",
mark: "N"
},
{
code: "EP123",
value: "20.10",
mark: "N"
},
{
code: "EP114",
value: "225.93",
mark: "N"
},
{
code: "EP112",
value: "1",
mark: "N"
},
{
code: "EP120",
value: "28.60",
mark: "N"
},
{
code: "EP110",
value: "0",
mark: "N"
},
{
code: "EP125",
value: "6.33",
mark: "N"
},
{
code: "EP119",
value: "2.92",
mark: "N"
}
]
},
422800408: {
stcode: "422800408",
time: "2020-04-09 17:28:00",
envList: [
{
code: "EP126",
value: "9.05",
mark: "N"
},
{
code: "EP117",
value: "7.80",
mark: "N"
},
{
code: "EP113",
value: "0",
mark: "N"
},
{
code: "EP124",
value: "7.58",
mark: "N"
},
{
code: "EP121",
value: "39.59",
mark: "N"
},
{
code: "EP115",
value: "225.24",
mark: "N"
},
{
code: "EP122",
value: "32.50",
mark: "N"
},
{
code: "EP116",
value: "224.05",
mark: "N"
},
{
code: "EP118",
value: "7.34",
mark: "N"
},
{
code: "EP111",
value: "1",
mark: "N"
},
{
code: "EP123",
value: "20.10",
mark: "N"
},
{
code: "EP114",
value: "225.93",
mark: "N"
},
{
code: "EP112",
value: "1",
mark: "N"
},
{
code: "EP120",
value: "28.60",
mark: "N"
},
{
code: "EP110",
value: "0",
mark: "N"
},
{
code: "EP125",
value: "6.33",
mark: "N"
},
{
code: "EP119",
value: "2.92",
mark: "N"
}
]
}
}
(2)、请求某个站点的站房环境数据
在浏览器中输入路径:http://localhost:3001/api/envData/421000405 得到站点421000405的站房环境数据,如下图所示: 对应的完整的json数据如下所示:
{
stcode: "421000405",
time: "2020-04-09 17:28:00",
envList: [
{
code: "EP126",
value: "9.05",
mark: "N"
},
{
code: "EP117",
value: "7.80",
mark: "N"
},
{
code: "EP113",
value: "0",
mark: "N"
},
{
code: "EP124",
value: "7.58",
mark: "N"
},
{
code: "EP121",
value: "39.59",
mark: "N"
},
{
code: "EP115",
value: "225.24",
mark: "N"
},
{
code: "EP122",
value: "32.50",
mark: "N"
},
{
code: "EP116",
value: "224.05",
mark: "N"
},
{
code: "EP118",
value: "7.34",
mark: "N"
},
{
code: "EP111",
value: "1",
mark: "N"
},
{
code: "EP123",
value: "20.10",
mark: "N"
},
{
code: "EP114",
value: "225.93",
mark: "N"
},
{
code: "EP112",
value: "1",
mark: "N"
},
{
code: "EP120",
value: "28.60",
mark: "N"
},
{
code: "EP110",
value: "0",
mark: "N"
},
{
code: "EP125",
value: "6.33",
mark: "N"
},
{
code: "EP119",
value: "2.92",
mark: "N"
}
]
}
4、参考资料:
-
[redis中文文档](http://www.redis.cn/documentation.html)
-
node-redis A high performance Node.js Redis client. http://redis.js.org/ https://github.com/NodeRedis/node-redis
-
ioredis A robust, performance-focused and full-featured Redis client for Node.js. https://www.npmjs.com/package/ioredis https://github.com/luin/ioredis 建议在Nodejs后台程序中使用ioredis,功能比较全,并且更新维护频率高,比node-redis维护要好。
来源:oschina
链接:https://my.oschina.net/u/4609891/blog/4775908