Redisson使用-springmvc
日前在学习redisson,记录一下。
配置
1.首先官网连接:https://github.com/redisson/redisson
2.我采用的是xml配置,一下是官网配置(哨兵模式,其他模式在官网wiki中可以看到):
<redisson:client
id="redisson"
name="redisson1,redisson2"
threads="0"
netty-threads="0"
codec-ref="myCodec"
transport-mode="NIO"
redisson-reference-enabled="true"
codec-provider-ref="myCodecProvider"
resolver-provider-ref="myResolverProvider"
executor-ref="myExecutor"
event-loop-group-ref="myEventLoopGroup"
>
<!--
这里的name属性和qualifier子元素不能同时使用。
id和name的属性都可以被用来作为qualifier的备选值。
-->
<!--<qualifier value="redisson3"/>-->
<redisson:sentinel-servers
idle-connection-timeout="10000"
ping-timeout="1000"
connect-timeout="10000"
timeout="3000"
retry-attempts="3"
retry-interval="1500"
reconnection-timeout="3000"
failed-attempts="3"
password="do_not_use_if_it_is_not_set"
subscriptions-per-connection="5"
client-name="none"
load-balancer-ref="myLoadBalancer"
subscription-connection-minimum-idle-size="1"
subscription-connection-pool-size="50"
slave-connection-minimum-idle-size="10"
slave-connection-pool-size="64"
master-connection-minimum-idle-size="10"
master-connection-pool-size="64"
read-mode="SLAVE"
subscription-mode="SLAVE"
master-name="myMaster"
database="0"
>
<redisson:sentinel-address value="redis://127.0.0.1:26379" />
<redisson:sentinel-address value="redis://127.0.0.1:26380" />
</redisson:sentinel-servers>
</redisson:client>
<!-- 最基本配置 -->
<redisson:client>
<redisson:sentinel-servers master-name="myMaster">
<redisson:sentinel-address value="redis://127.0.0.1:26379" />
<redisson:sentinel-address value="redis://127.0.0.1:26380" />
....
</redisson:sentinel-servers>
</redisson:client>
一下是我自己的配置和部分标注:
bean id="stringCodec" class="org.redisson.client.codec.StringCodec"></bean>
<redisson:client id="redissonClient" codec-ref="stringCodec">
<redisson:sentinel-servers master-name="${redis.masterName}">
<redisson:sentinel-address value="http://${redis.host1}" />
<redisson:sentinel-address value="http://${redis.host2}" />
<redisson:sentinel-address value="http://${redis.host3}" />
</redisson:sentinel-servers>
</redisson:client>
<!--一下均摘抄自官网
master-name 主服务器名称
readMode 读取操作的负载均衡模式 默认 从节点读取
subscriptionMode 订阅操作的负载均衡模式默认 从节点读取
loadBalancer(负载均衡算法类的选择) 默认值: org.redisson.connection.balancer.RoundRobinLoadBalancer
org.redisson.connection.balancer.WeightedRoundRobinBalancer - 权重轮询调度算法
org.redisson.connection.balancer.RoundRobinLoadBalancer - 轮询调度算法
org.redisson.connection.balancer.RandomLoadBalancer - 随机调度算法
slaveConnectionMinimumIdleSize(从节点最小空闲连接数) 默认 32
slaveConnectionPoolSize(从节点连接池大小) 默认 64
masterConnectionMinimumIdleSize(主节点最小空闲连接数) 默认 32
masterConnectionPoolSize(主节点连接池大小) 默认 64
idleConnectionTimeout(连接空闲超时,单位:毫秒) 默认值:10000
timeout(命令等待超时,单位:毫秒) 默认值:3000
retryAttempts(命令失败重试次数) 默认值:3
retryInterval(命令重试发送时间间隔,单位:毫秒 默认值:1500
reconnectionTimeout(重新连接时间间隔,单位:毫秒) 默认值:3000
failedAttempts(执行失败最大次数) 默认值:3
database(数据库编号)默认值:0 尝试连接的数据库编号。
password(密码) 默认值:null 用于节点身份验证的密码。
subscriptionsPerConnection(单个连接最大订阅数量) 默认值:5 每个连接的最大订阅数量。
clientName(客户端名称) 默认值:null 在Redis节点里显示的客户端名称。
还有ssl的配置 待续
-->
3.写一个工具类orTemplate类
@Service
public class RedissonTemplate implements InitializingBean {
private static final Logger log = Logger.getLogger(RedissonTemplate.class);
@Autowired
RedissonClient redissonClient;
private static Redisson redisson;
private static final String LOCK_TITLE = "redisLock_";
public static boolean acquireSecond(String lockName, Integer waitTime, Integer timeOutSecond){
try {
String key = LOCK_TITLE + lockName;
RLock mylock = redisson.getLock(key);
//lock提供带timeout参数,timeout结束强制解锁,防止死锁
//先尝试在超时时间内获取锁,如果没有获取到,此时如果等待时间还有剩余进入循环不断取尝试获取锁 直到时间结束退出 循环中是订阅,时间结束取消订阅
return mylock.tryLock(waitTime, timeOutSecond, TimeUnit.SECONDS);
} catch (InterruptedException e) {
log.error(ExceptionFormatUtil.exception(e));
if (SysConfig.send()) DingdingNewsPushUtils.send("获取redisson锁异常:" + ExceptionFormatUtil.exceptionDD(e));
}
return false;
}
public static boolean acquireMinuts(String lockName, Integer waitTime, Integer timeOutMinuts){
return acquireSecond(lockName, waitTime, timeOutMinuts * 60);
}
public static void release(String lockName){
String key = LOCK_TITLE + lockName;
RLock mylock = redisson.getLock(key);
mylock.unlock();
}
@Override
public void afterPropertiesSet() throws Exception {
redisson = (Redisson) redissonClient;
log.info("[cos_redisson_config_info]" + redisson.getConfig().toJSON());
}
}
4.自己错误记录:
a.第一次调用redisson时候,参考资料直接使用一下方式
private static RedissonClient redisson = Redisson.create();
这种方法是用代码加载配置的时候用的,如下所示:
Config config = new Config();
config.setCodec(param);
config.setExecutor(param);
private static RedissonClient redisson = Redisson.create(config);
5.循环方式
a.while循环,一次接着一次的尝试,这个方法的缺点是会造成大量无效的锁申请。
b.Thread.sleep,在上面的while方案中增加睡眠时间以降低锁申请次数,缺点是这个睡眠的时间设置比较难控制。
c.基于信息量,当锁被其它资源占用时,当前线程订阅锁的释放事件,一旦锁释放会发消息通知待等待的锁进行竞争,有效的解决了无效的锁申请情况。核心逻辑是this.getEntry(threadId).getLatch().tryAcquire,this.getEntry(threadId).getLatch()返回的是一个信号量,有兴趣可以再研究研究。