用集群处理微信业务,微信的token存放在redis,当长时间没业务过来,token过期后,突然高并发同时请求到集群,不同服务器上的node同时去微信获取token,由于请求微信的返回的不确定性有可能导致最后存到redis的token无效。请问这种情况该如何避免比较好?
我的解决方法: 1.redis有2个功能:第一是用作token的缓存,第二是作为锁媒介 2.利用事件队列缓存请求 过程: 1.redis作为缓存,缓存住token 2.每次请求判断token是否过期 2.1 如果token未过期,则直接使用 2.2 如果token过期,则利用redis的setnx(只能设置不存在的key)命令获取锁(redis单线程,一次处理1个命令,如果一下子来了N多请求,也只能一条一条处理),设置成功的请求去做获取token的操作,其他的请求缓存到事件队列
var ev = new events.EventEmitter();
var status = '';
emitter.setMaxListeners(0);
var example = function(token, callback) {
ev.once('token', callback);
if (token.isExpired() && '' === status) {
status = 'pending';
getToken(function(_token){
ev.emit('token', null, _token);
status = '';
});
}
}
@WayneLiang 你所说的这种并发导致的错误情况还有可能很多,过期未刷新,或者缓存中并未存在token,却同时有多条处理需要用到token而导致并发发起获取token,或者token已刷新,但已有其他程序获取老token还没执行完,从逻辑上考虑这些问题是很多,所以应该加一个重试的机制,并对于获取token来说,错误的可能也就是token过期或失效,那么只要重试能获取到可用的token即可
我觉得比较靠谱的做法有:
- 主动定时刷新
- 博客中的第五种方法, 存储 key = (value, 过期时间), 在 redis 中 key 不过期, 代码中检测到过期, 则使用@swfbarhr 提到的 setnx , 过期时间短点, 成功 set 的做这个重新获取数据操作
与其他方法区别在于获取数据操作过程中, 取到是过期值, 而不是空值