这里有新鲜出炉的 Redis 命令参考,程序狗速度看过来!
Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。
这篇文章主要介绍了如何操作 Redis 和 zookeeper 实现分布式锁的相关资料, 需要的朋友可以参考下
如何操作 Redis 和 zookeeper 实现分布式锁
在分布式场景下,有很多种情况都需要实现最终一致性。在设计远程上下文的领域事件的时候,为了保证最终一致性,在通过领域事件进行通讯的方式中,可以共享存储(领域模型和消息的持久化数据源),或者做全局 XA 事务(两阶段提交,数据源可分开),也可以借助消息中间件(消费者处理需要能幂等)。通过 Observer 模式来发布领域事件可以提供很好的高并发性能,并且事件存储也能追溯更小粒度的事件数据,使各个应用系统拥有更好的自治性。
1. 分布式锁
分布式锁一般用在分布式系统或者多个应用中,用来控制同一任务是否执行或者任务的执行顺序。在项目中,部署了多个 tomcat 应用,在执行定时任务时就会遇到同一任务可能执行多次的情况,我们可以借助分布式锁,保证在同一时间只有一个 tomcat 应用执行了定时任务。
2. 分布式锁的实现方式
3. 使用 redis 的 setnx() 和 expire() 来实现分布式锁
- setnx(key,value) 如果key不存在,设置为当前key的值为value;如果key存在,直接返回。
- expire()来设置超时时间
定义注解类:
- @Target({ElementType.METHOD})
- @Retention(RetentionPolicy.RUNTIME)
- public @interface Lockable{
- // redis缓存key
- String key();
- // redis缓存key中的数据
- String value() default "";
- // 过期时间(秒),默认为一分钟
- long expire() default 60;
- }
定时任务增加注解 @Lockable:
- @Lockable(key = "DistributedLock:dealExpireRecords")
- public void dealExpireRecords() {
- }
定义一个 aop 切面 LockAspect,使用 @Around 处理所有注解为 @Lockable 的方法,通过连接点确认此注解是用在方法上,通过方法获取注解信息,使用 setIfAbsent 来判断是否获取分布式锁,如果没有获取分布式锁,直接返回;如果获取到分布式锁,通过 expire 设置过期时间,并调用指定方法。
- @Component
- @Slf4j
- @Aspect
- public class LockAspect {
- @Autowired
- private RedisTemplate redisTemplate;
- @Around("@annotation(com.records.aop.Lockable)")
- public Object distributeLock(ProceedingJoinPoint pjp) {
- Object resultObject = null;
- //确认此注解是用在方法上
- Signature signature = pjp.getSignature();
- if (!(signature instanceof MethodSignature)) {
- log.error("Lockable is method annotation!");
- return resultObject;
- }
- MethodSignature methodSignature = (MethodSignature) signature;
- Method targetMethod = methodSignature.getMethod();
- //获取注解信息
- Lockable lockable = targetMethod.getAnnotation(Lockable.class);
- String key = lockable.key();
- String value = lockable.value();
- long expire = lockable.expire();
- // 分布式锁,如果没有此key,设置此值并返回true;如果有此key,则返回false
- boolean result = redisTemplate.boundValueOps(key).setIfAbsent(value);
- if (!result) {
- //其他程序已经获取分布式锁
- return resultObject;
- }
- //设置过期时间,默认一分钟
- redisTemplate.boundValueOps(key).expire(expire, TimeUnit.SECONDS);
- try {
- resultObject = pjp.proceed(); //调用对应方法执行
- } catch (Throwable throwable) {
- throwable.printStackTrace();
- }
- return resultObject;
- }
- }
4. 使用 redis 的 getset() 来实现分布式锁
此方法使 redisTemplate.boundValueOps(key).getAndSet(value) 的方法,如果返回空,表示获取了分布式锁;如果返回不为空,表示分布式锁已经被其他程序占用
5. 使用 zookeeper 的创建节点 node
使用 zookeeper 创建节点 node,如果创建节点成功,表示获取了此分布式锁;如果创建节点失败,表示此分布式锁已经被其他程序占用 (多个程序同时创建一个节点 node,只有一个能够创建成功)
6. 使用 zookeeper 的创建临时序列节点
使用 zookeeper 创建临时序列节点来实现分布式锁,适用于顺序执行的程序,大体思路就是创建临时序列节点,找出最小的序列节点,获取分布式锁,程序执行完成之后此序列节点消失,通过 watch 来监控节点的变化,从剩下的节点的找到最小的序列节点,获取分布式锁,执行相应处理,依次类推......
来源: http://www.phperz.com/article/17/0811/344441.html