4.6、事务
MySQL 中的事务还是挺多道道的还要,而在Redis中的事务只要有如下三步:
关于事务具体结论:
1、redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。
2、Redis事务没有隔离级别的概念:批量操作在发送 EXEC 命令前被放入队列缓存,并不会被实际执行,也就不存在事务内的查询要看到事务里的更新,事务外查询不能看到。
3、Redis不保证原子性:Redis中单条命令是原子性执行的,但事务不保证原子性。
4、Redis编译型错误事务中所有代码均不执行,指令使用错误。运行时异常是错误命令导致异常,其他命令可正常执行。
5、watch指令类似于乐观锁,在事务提交时,如果watch监控的多个KEY中任何KEY的值已经被其他客户端更改,则使用EXEC执行事务时,事务队列将不会被执行。
4.7、正确开发步骤
上线前:Redis 高可用,主从+哨兵,Redis cluster,避免全盘崩溃。
上线时:本地 ehcache 缓存 + Hystrix 限流 + 降级,避免MySQL扛不住。上线后:Redis 持久化采用 RDB + AOF 来保证断点后自动从磁盘上加载数据,快速恢复缓存数据。
5、分布式锁
日常开发中我们可以用 synchronized 、Lock 实现并发编程。但是Java中的锁只能保证在同一个JVM进程内中执行。如果在分布式集群环境下用锁呢?日常一般有两种选择方案。
5.1、 Zookeeper实现分布式锁
你需要知道一点基本zookeeper知识:
1、持久节点:客户端断开连接zk不删除persistent类型节点 2、临时节点:客户端断开连接zk删除ephemeral类型节点 3、顺序节点:节点后面会自动生成类似0000001的数字表示顺序 4、节点变化的通知:客户端注册了监听节点变化的时候,会调用回调方法
大致流程如下,其中注意每个节点只监控它前面那个节点状态,从而避免羊群效应。关于模板代码百度即可。
缺点:
频繁的创建删除节点,加上注册watch事件,对于zookeeper集群的压力比较大,性能也比不上Redis实现的分布式锁。
5.2、 Redis实现分布式锁
本身原理也比较简单,Redis 自身就是一个单线程处理器,具备互斥的特性,通过setNX,exist等命令就可以完成简单的分布式锁,处理好超时释放锁的逻辑即可。
SETNX
SETNX 是SET if Not eXists的简写,日常指令是SETNX key value,如果 key 不存在则set成功返回 1,如果这个key已经存在了返回0。
SETEX
SETEX key seconds value 表达的意思是 将值 value 关联到 key ,并将 key 的生存时间设为多少秒。如果 key 已经存在,setex命令将覆写旧值。并且 setex是一个原子性(atomic)操作。
加锁:
一般就是用一个标识唯一性的字符串比如UUID 配合 SETNX 实现加锁。
解锁:
这里用到了LUA脚本,LUA可以保证是原子性的,思路就是判断一下Key和入参是否相等,是的话就删除,返回成功1,0就是失败。
缺点:
这个锁是无法重入的,且自己实心的话各种边边角角都要考虑到,所以了解个大致思路流程即可,工程化还是用开源工具包就行。
5.3、 Redisson实现分布式锁
Redisson 是在Redis基础上的一个服务,采用了基于NIO的Netty框架,不仅能作为Redis底层驱动客户端,还能将原生的RedisHash,List,Set,String,Geo,HyperLogLog等数据结构封装为Java里大家最熟悉的映射(Map),列表(List),集(Set),通用对象桶(Object Bucket),地理空间对象桶(Geospatial Bucket),基数估计算法(HyperLogLog)等结构。
这里我们只是用到了关于分布式锁的几个指令,他的大致底层原理: