一. Redis的常用客户端:
- Jedis:和命令最相似,API全面。缺点:多线程不安全(多线程可以使用连接池,安全使用Jedis)
- SpringData:线程安全的,底层基于Netty(异步的支持)
- Redisson:线程安全的,底层基于Netty,提供很多的分布式服务(分布式锁,分布式集合,分布式下的JUC的封装,延时队列)
二. Redis实现分布式锁
分布式锁和本地锁本质是一样的,都是将并行的操作转换为串行的操作。
- 实现过程:
- 利用setnx互斥性
- 加入TTL防止死锁问题
- 注意使用LUA脚本确保原子性
- 加入看门狗,防止业务拿锁时间过长导致的锁失效问题(业务拿锁时间>TTL)
如果担心应用先释放锁,再加锁,再释放锁,这样做
释放锁时候,要判断只有持有锁的线程才能释放锁,需要通过本地存储的唯一性ID和redis中写入的ID。那么有两步,拿redis里ID,然后判断,所以需要使用LUA脚本保证原子性。
三. Redisson实现分布式锁
Redisson的分布式锁默认有看门狗,必须无参数方法(lock.lock()方式,这种redis的TTL默认30秒,默认10秒运行一次)。
有time参数的方法这个看门狗会失效,因为看门狗本身是一个定时任务。
如果加了参数的方法,可以判断处理业务的时间,如果>time,则可以回滚抛出异常,因为业务处理异常了。
RLock lock = redisson.getLock("myLock");
// traditional lock method
lock.lock();
// or acquire lock and automatically unlock it after 10 seconds
lock.lock(10, TimeUnit.SECONDS);
// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);if (res) {
try {
...
} finally {
lock.unlock();
}
}
另外:
批量+多线程容易死锁,可以用redis的set集合,做交集
四. Redis常见的解决方案:
- 可以做分布式限流。
实现:
a.写一个lua脚本,如果key不存在,则incr +ttl 60s
b.如果key存在,则只执行incr
c.再写一个判断,是否被限制的lua脚本,获取value,get value >200,返回false,否则返回true
d.Redisson中提供了一个RateLimiter专门做限流 - Redis可以做信号量+分布式锁