跳到主要内容

5 篇博文 含有标签「redis」

查看所有标签

记一次 redis cluster 事务 (transaction) 翻车及分析总结

· 阅读需 11 分钟

发现生产环境的业务报了好多错误, 涉及的 Node.js 代码是一个基于 Redis 的频率计数器,那部分逻辑大概是这样

// 查询并增加一次计数
async incr (id) {
const key = `${this.namespace}:${id}`
const now = getMicrotime()
const start = now - this.duration * 1000

const operations = [
['zremrangebyscore', key, 0, start],
['zcard', key],
['zadd', key, now, now],
['pexpire', key, this.duration]
]

const res = await this.redis.multi(operations).exec()
const count = toNumber(res[1][1])
return count
}

错误是:

Cannot read property '1' of undefined

Node.js 中监听 redis key 过期事件

· 阅读需 2 分钟

It is in fact possible to listen to the "expired" type keyevent notification using a subscribed client to the specific channel ( and listening to its message event.

通过 subscribe client 可以监听 __keyevent@{db}__:expired ( db 是你传入的配置 ) 频道来接收过期的事件 ,

const redis = require('redis')
const CONF = {db:3}

let pub, sub

// Activate "notify-keyspace-events" for expired type events
pub = redis.createClient(CONF)
pub.send_command('config', ['set','notify-keyspace-events','Ex'], subscribeExpired)

// Subscribe to the "notify-keyspace-events" channel used for expired type events
function subscribeExpired(e, r){
sub = redis.createClient(CONF)
const expired_subKey = `__keyevent@${CONF.db}__:expired`

sub.subscribe(expired_subKey, function () {
console.log(' [i] Subscribed to "'+expired_subKey+'" event channel : '+r)
sub.on('message', function (chan, msg){
console.log('[expired]', msg)}
)
TestKey()
})
}

//例如,设置一个 key 并设置 10s 超时
function TestKey(){
pub.set('testing', 'redis notify-keyspace-events : expired')
pub.expire('testing', 10)
}

启动 redis 出现 Creating Server TCP listening socket *:6379 bind No such file or directory

· 阅读需 2 分钟

平时直接启动没问题,今天出了这个问题,启动失败,加上配置文件也不行。

D:\redis2.8>redis-server.exe
[8264] 08 Nov 09:28:43.943 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server.exe /path/to/redis.conf
[8264] 08 Nov 09:28:43.948 # Creating Server TCP listening socket *:6379: bind: No such file or directory

Redis 报错:

[6644] 02 Apr 23:11:58.976 # Creating Server TCP listening socket *:6379: bind: No such file or directory

的解决方案如下按顺序输入如下命令就可以连接成功

1. redis-cli.exe
2. shutdown
3. exit
4. redis-server.exe redis.windows.conf

微信爬虫的cookie池的node.js实现

· 阅读需 2 分钟

之前的一篇文章说到了维护一个cookie池来降低500的概率。

记搜狗微信号搜索反爬虫

在知乎上看到有人说只需要SNUID替换,其他的不影响。 所以我就写了一个SNUID的池,存储在redis中。

思路:

  1. 通过随机关键字不带cookie请求weixin.sogou.com
  2. 从请求的header中抽取SNUID缓存在redis中。
  3. 每6个小时将SNUID池更新一遍。

代码在这里: https://github.com/luoyjx/weixin-crawler-es5

关于在环境监控中用到的 node.js 通讯

· 阅读需 20 分钟

关于环境在线监控这类项目,应该属于物联网范畴了(所谓物联网,在这里的意思大概就是将实实在在的硬件和物联网衔接了起来)。

其实我对物联网的概念也没有太深入的理解,毕竟才接触不到三个月吧,所了解到的就是,基本物联网这块的系统,软件是建立在硬件的基础之上的。

大致分为这么 3 个层次:

1)基础硬件,即用于生产监测数据的监测仪器。

2)通讯模块,这个大块被分成了现场和服务器两边,也就是说,通讯模块是衔接检测仪器和软件系统的桥。

3)软件系统,这块就是为了集中的监控和管理各个监测点的大致情况了。

讲的比较浅显,其实每个层次里都有很多高深的技术。

当然,这通讯里又会有国家或者自己规定的通讯协议。所谓协议,以前,我以为是什么类似于语法检查之类的东西,模模糊糊的。接触了大概就知道,这也就是为了标准化,或者是安全又或者是方便处理,从而双方约定的一种格式,比如环境在线监测中所用到的,212 传输协议,就是国家环保局制定的标准,其中规定了,一个数据包中比如前面必须要带两个#作为包头,然后接下来 4 位是后面整个数据段的长度 ,比如有 233 个字长,那么就是 0233,像这样的等等。

而我要说的是,在监控项目中通讯端中用到的一个 nodejs 与 redis 以及 mongodb。

大致是这样的,因为监测点设备分布在各个地方,数据要上传到我们所谓的数据中心,即软件系统这边,那么大概的关系就可以简化为一个多对一的关系,其实通讯并不一定是单个,可以是个集群什么的,暂且当做一个整体吧。

我来之前,其实通讯端是有了一个版本的,使用的是 java 和 ibm 的 MQ 来实现的,会启动两个进程,一个是接收端,用于接收现场发来的数据,在进行了初步加工之后,即通过 212 协议规定的内容,把数据包中的数据都解析出来,并已 json 格式的字符串存储到 mq(message queue 消息队列)中。另一个进程就是处理端,相反的,它是不断的从消息队列中取出数据,然后进行报警处理等过程后进行入库操作,然后这些数据后续管理就交给运营系统了。

而我当时选择用 nodejs 来重构的一个原因是,我们组的老大说,他们以前那个通讯程序经常挂,这是很不友好的,这样一来数据都等不到保障。

我只是简答的测试了一下,我在本地不断的开启线程去连接我本地的 java 的 socket server,不知道为什么,连到那么几百个的时候就出现连接拒绝的情况。知道的大虾望指教。

而我简单的写了个 nodejs 的 socket server 连接了上千个连接也没有什么异常出现。

可能是我自己机器的原因吧,java 作为老牌的语言,不应该这么脆。

但是作为通讯的话,感觉 java 似乎并不是特别的有优势,毕竟像这种工作大多数都是丢给 C/C++来做,具体原因吧,没研究过 C/C++我还是不讨论他了。

可能恰好把,nodejs 是事件机制,非阻塞模型,正好适合这种无脑疯狂 I/O(密集型 I/O)的场景,而 java 的那块做一些同步、多线程、密集型计算的还是要强大的多的。

说说我写的大概的结构吧:

现在是整在一个项目中的,因为还是前期做了一些简单的测试,都没上线测试,不过压力我觉得应该还是够了,1 天 1 千 4 百万的数据都没问题,我的同事告诉我说,他们一个月的数据似乎才有一千万的数量级。

1. 接收端

** 2. 消息队列**

** 3. 处理端**

这个是分成了三大块。

1. 接收端 顾名思义,就是接受数据用的,做了一些预处理,将数据包转成了 json 串,存入消息队列,至于预处理,这其中就需要协议的支撑了。

考虑的问题:

1)一个是,我需要怎么样把协议抽象成为配置式的,而不需要每次新增一种协议,我就必须要重新写一套处理流程

2)这也是泉哥提醒我的一个问题,粘包断包问题,其实这个问题,有协议应该处理起来还是难度相对不大的,有一次网络阻塞的时候确实出现了数据包也阻塞的问题,当时正在测试协议中的 16 位 CRC 校验算法,结果网络一阻塞,导致我数据包基本都被丢掉了。其实也是不可轻视的一个问题。

3)还有数据包到达的问题,这个的话,现在有一个机制就是应答,在收到某个设备的数据包之后会回发设备的编号,但是我并不知道这里面有什么作用,难道现场机还记录了上传成功率么?

4)还有一个问题是,我们现在并没有对通讯端 server 本身进行状态的监控,我怎么知道现在某时刻他的各方面参数,比如传输率、连接数、连接状态等等。

5)还有一个就是断线重连的问题。

2. 消息队列

这一部分,其实我也并没有做过实际的测试,使用的是 redis 中的 list 结构当做消息队列,这么做起因只是看到网上有关于 nodejs+redis 做消息队列的帖子,而 ibm 的 mq 对于 nodejs 应该是没有支持的。

而且 redis 的表现应该也不会很差,毕竟是个内存数据库,难道还会慢到哪去,他只管存,就行了。

3. 处理端

这部分,我个人对自己写的相当不满意,因为我在找不到很高效的办法的情况下,使用了 javascript 中的 setTimeout 函数来以 0 毫秒延迟循环执行取出操作,总觉得无限循环像是同步操作,不知道各位大神能否指点下。

考虑的问题:

1)其实我觉得直接就在接收到数据的时候处理之后直接处理之后入库 mongodb,会不会快一点,但是回头又想了想,这样的话是不是就回牺牲了写入的效率,而且,不进行读写分离的话,以后不方便扩展,同时在单服务器上写入和读取肯定效率会大大降低。所以暂时还是使用的消息队列在中间过程做为缓冲,当时尝试过在接收到数据包处理后马上通过事件发射机制发送给监听器来处理,但是这直接被老大否决了,所以也没有做测试。

大概的通讯端结构写完了,有什么好的建议或者疑问可以提给我或者留言讨论,也可以发我邮箱 yjk99@qq.com