最近在写一个脚手架,其中 redis
的使用场景还挺多,因而总结下它的常见使用场景javascript
<!--more-->前端
> set User:1:name shanyue EX 100 NX OK > get User:1:name "shanyue"
缓存是 redis
出镜率最高的一种使用场景,仅仅使用 set/get
就能够实现,不过也有一些须要考虑的点java
> set 5d27e60e6fb9a07f03576687 '{"id": 10086, role: "ADMIN"}' EX 7200 OK > get 5d27e60e6fb9a07f03576687 "{\"id\": 10086, role: \"ADMIN\"}"
这也是很经常使用的一种场景,不过相对于有状态的 session,也能够考虑使用 JWT,各有利弊node
> lpush UserEmailQueue 1 2 3 4 lpop UserEmailQueue > rpop UserEmailQueue 1 > rpop UserEmailQueue 2
能够把 redis
的队列视为分布式队列,做为消息队列时,生产者在一头塞数据,消费者在另外一头出数据: (lpush/rpop, rpush/lpop)。不过也有一些不足,而这些不足有多是致命的,不过对于一些丢几条消息也不要紧的场景仍是能够考虑的python
redis
的持久化配置> sadd UrlSet http://1 (integer) 1 > sadd UrlSet http://2 (integer) 1 > sadd UrlSet http://2 (integer) 0 > smembers UrlSet 1) "http://1" 2) "http://2"
scrapy-redis 做为分布式的爬虫框架,即是使用了 redis
的 Set
这个数据结构来对将要爬取的 url 进行去重处理。git
# https://github.com/rmax/scrapy-redis/blob/master/src/scrapy_redis/dupefilter.py def request_seen(self, request): """Returns True if request was already seen. Parameters ---------- request : scrapy.http.Request Returns ------- bool """ fp = self.request_fingerprint(request) added = self.server.sadd(self.key, fp) return added == 0
不过当 url
过多时,会有内存占用过大的问题github
set Lock:User:10086 06be97fc-f258-4202-b60b-8d5412dd5605 EX 60 NX # 释放锁,一段 LUA 脚本 if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end
这是一个最简单的单机版的分布式锁,有如下要点web
EX
表示锁会过时释放NX
保证原子性当你使用分布式锁是为了解决一些性能问题,如分布式定时任务防止执行屡次 (作好幂等性),并且鉴于单点 redis
挂掉的可能性很小,可使用这种单机版的分布式锁。面试
限流即在单位时间内只容许经过特定数量的请求,有两个关键参数redis
最多见的场景: 短信验证码一分钟只能发送两次
FUNCTION LIMIT_API_CALL(ip): current = GET(ip) IF current != NULL AND current > 10 THEN ERROR "too many requests per second" ELSE value = INCR(ip) IF value == 1 THEN EXPIRE(ip,1) END PERFORM_API_CALL() END
可使用计数器对 API 的请求进行限流处理,可是要注意几个问题
这时候能够经过编程,根据 TTL key
进行进一步限制,或者使用一个 LIST
来维护每次请求打来的时间戳进行实时过滤。如下是 node
实现的一个 Rate Limter
。参考源码 node-rate-limiter-flexible
this.client .multi() .set(rlKey, 0, 'EX', secDuration, 'NX') .incrby(rlKey, points) .pttl(rlKey) .exec((err, res) => { if (err) { return reject(err); } return resolve(res); }) if (res.consumedPoints > this.points) { // ... } else if (this.execEvenly && res.msBeforeNext > 0 && !res.isFirstInDuration) { // ... setTimeout(resolve, delay, res); } else { resolve(res); }
能够经过 redis 的 PUB/SUB
来在 websocket server 间进行交流。能够参考如下项目
我是山月,能够加我微信
shanyue94
与我交流,备注交流。另外能够关注个人公众号【全栈成长之路】