缓存
Redis 最常使用的场景是作为缓存,缓存用户信息,会话信息,还有一些热点信息。
淘汰策略
缓存内存是有限制的,当 Redis 内存超出物理内存限制时,内存的数据会开始和磁盘产生频繁的交换(swap)。交换会让 Redis 性能急剧下降。
Redis 提供了maxmemory 来限制内存期望的大小。
当实际内存超过 maxmemory 时,Redis 提供了几种可选策略。
- noeviciction 不会继续服务写请求。读请求可以继续执行。这样会保证数据不会丢失,但是会让线上业务不能继续进行。这个是默认的淘汰策略。
- volatile-lru 尝试淘汰设置了过期时间的 key, 最少使用的 key 优先被淘汰。没有设置过期时间的 key 不会被淘汰。这样可以保证持久化的数据不会被淘汰
- volatile-ttl 和volatil-lru 一样,也是淘汰设置过期的 key , 但是淘汰策略不是 LRU ,而是 key 的剩余寿命 ttl 的值,ttl 值越小,越优先淘汰。
- volatile-random 和 ttl lru 类似,前提条件是设置了过期时间, 是淘汰过期 key 集合中随机的 key。
- allkeys-lru 区别 volatile-lru 是对全体的key 对象进行淘汰,包含没有设置过期时间的 key.
- allkeys-random 和allkeys-lru 类似,不过淘汰策略是随机的 key
分布式锁
分布式锁的 本质上是在 Redis 中占一个位置,当别的进程来占用时,发现已经被占用,只能放弃或者稍后重试。
redis 占用操作一般使用 setnx (set if not exists)指令占用锁,然后使用 del 指令释放锁,但是可能会有问题。
172.31.1.135:7001> setnx lock:test true (integer) 1 172.31.1.135:7001> get lock:test "true" 172.31.1.135:7001>
但是这样存在温柔 setnx 之后,用户线程突然宕机了怎么办,永远无法解锁,这样就存在问题了。
下面给个正确使用实例:
/** * 尝试获取分布式锁 * @param jedis Redis客户端 * @param lockKey 锁 * @param requestId 请求标识 * @param expireTime 超期时间 * @return 是否获取成功 */ public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) { String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime); if (LOCK_SUCCESS.equals(result)) { return true; } return false; } /** * 释放分布式锁 * @param jedis Redis客户端 * @param lockKey 锁 * @param requestId 请求标识 * @return 是否释放成功 */ public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) { String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId)); if (RELEASE_SUCCESS.equals(result)) { return true; } return false; }