redis分布式锁的实践

redis分布式锁的实践

Scroll Down

redis实践

CentOS7安装redis

  • 添加redis压缩包

  • 解压

  • make , make install

  • cp /root/redis-3.2.8/redis.conf /usr/local/redis/bin

  • 修改配置文件

整合redis

redisutil

public class RedisUtil {


    //创建链接池
    private JedisPool jedisPool;

    //初始化连接池
    public void initJedisPool(String host,int port,int database) {

        //创建一个配置类
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();

        //设置连接池最大连接数
        jedisPoolConfig.setMaxTotal(200);

        //设置等待时间
        jedisPoolConfig.setMaxWaitMillis(10*1000);

        //设置最小剩余数
        jedisPoolConfig.setMinIdle(10);

        //开启获取连接池阻塞队列
        jedisPoolConfig.setBlockWhenExhausted(true);

        //在借用连接后,自检是否可用
        jedisPoolConfig.setTestOnBorrow(true);

        jedisPool = new JedisPool(jedisPoolConfig,host,port,20*1000);
    }

    //获取jedis
    public Jedis getJedis() {

        Jedis jedis = jedisPool.getResource();
        return jedis;
    }
}

RedisConfig

@Configuration
public class RedisConfig {


    @Value("${spring.redis.host:disable}")
    private String host;

    @Value("${spring.redis.port:0}")
    private int port;

    @Value("${spring.redis.database:0}")
    private int database;

    //将获取到的参数传入initJedisPool方法中
    @Bean
    public RedisUtil getRedisUtil() {

        if ("disable".equals(host)) {
            return null;
        }

        RedisUtil redisUtil = new RedisUtil();

        redisUtil.initJedisPool(host,port,database);
        return redisUtil;
    }
}

application.properties

#redis的配置
spring.redis.host=192.168.113.132
spring.redis.port=6379
spring.redis.database=0

实践

@Override
    public SkuInfo getSkuInfo(String skuId) {

//        //保存到redis中
//        Jedis jedis = redisUtil.getJedis();
//
//        jedis.set("ok","测试");
//        jedis.close();
        SkuInfo skuInfo = null;

        Jedis jedis = null;
        //获取jedis
        try {
            jedis = redisUtil.getJedis();

            //获取缓存中的数据
            String key = ManageConst.SKUKEY_PREFIX+skuId+ManageConst.SKUKEY_SUFFIX;

            //判断redis中是否有key
            if (jedis.exists(key)) {
                //在redis中取出来
                String jedisString = jedis.get(key);
                //转化为对象
                skuInfo = JSON.parseObject(jedisString, SkuInfo.class);

                return skuInfo;
            }else {

                skuInfo = getSkuInfoDB(skuId);

                //放入redis中
                String s = JSON.toJSONString(skuInfo);

                jedis.setex(key,ManageConst.SKUKEY_TIMEOUT,s);
                return skuInfo;

            }


        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }

        }
        return getSkuInfoDB(skuId);

    }

    private SkuInfo getSkuInfoDB(String skuId) {
        SkuInfo skuInfo = skuInfoMapper.selectByPrimaryKey(skuId);
        SkuImage skuImage = new SkuImage();
        skuImage.setSkuId(skuId);
        List<SkuImage> skuImageList = skuImageMapper.select(skuImage);
        skuInfo.setSkuImageList(skuImageList);
        return skuInfo;
    }

redis分布式锁

redis实现分布式锁

解决缓存击穿问题:

(1)Redis:命令

# set sku:1:info “OK” NX PX 10000

EX second :设置键的过期时间为 second 秒。 SET key value EX second 效果等同于 SETEX key second value 。

PX millisecond :设置键的过期时间为 millisecond 毫秒。 SET key value PX millisecond 效果等同于 PSETEX key millisecond value 。

NX :只在键不存在时,才对键进行设置操作。 SET key value NX 效果等同于 SETNX key value 。

XX :只在键已经存在时,才对键进行设置操作。

ManageConst类
@Component
public class ManageConst {

    public static final String SKUKEY_PREFIX="sku:";

    public static final String SKUKEY_SUFFIX=":info";

    public static final int SKUKEY_TIMEOUT=24*60*60;

    public static final int SKULOCK_EXPIRE_PX=10000;
    public static final String SKULOCK_SUFFIX=":lock";//分布式锁


}
修改代码:
@Override
    public SkuInfo getSkuInfo(String skuId) {

//        //保存到redis中
//        Jedis jedis = redisUtil.getJedis();
//
//        jedis.set("ok","测试");
//        jedis.close();
        SkuInfo skuInfo = null;

        Jedis jedis = null;
        //获取jedis
        try {
            jedis = redisUtil.getJedis();

            //获取缓存中的数据
            String key = ManageConst.SKUKEY_PREFIX+skuId+ManageConst.SKUKEY_SUFFIX;

            //获取数据
            String skuJson = jedis.get(key);

            if (skuJson == null || skuJson.length() == 0) {

                //尝试加锁
                System.err.println("缓存中没有数据");

                //set加锁
                String skuLockKey = ManageConst.SKUKEY_PREFIX+skuId+ManageConst.SKULOCK_SUFFIX;
                String lockKey = jedis.set(skuLockKey, "good", "NX", "PX", ManageConst.SKULOCK_EXPIRE_PX);

                if ("OK".equals(lockKey)) {

                    //此时加锁成功
                    skuInfo = getSkuInfoDB(skuId);

                    //放入redis中
                    String s = JSON.toJSONString(skuInfo);

                    jedis.setex(key,ManageConst.SKUKEY_TIMEOUT,s);

                    //删除锁
                    jedis.del(lockKey);
                    return skuInfo;
                }else {
                    //线程等待
                    Thread.sleep(1000);

                    //调用getSkuInfo方法
                    return getSkuInfo(skuId);
                }
            }else {
                //在redis中取出来
                String jedisString = jedis.get(key);
                //转化为对象
                skuInfo = JSON.parseObject(jedisString, SkuInfo.class);

                return skuInfo;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }

        }
        return getSkuInfoDB(skuId);

    }

    private SkuInfo getSkuInfoDB(String skuId) {
        SkuInfo skuInfo = skuInfoMapper.selectByPrimaryKey(skuId);
        SkuImage skuImage = new SkuImage();
        skuImage.setSkuId(skuId);
        List<SkuImage> skuImageList = skuImageMapper.select(skuImage);
        skuInfo.setSkuImageList(skuImageList);
        return skuInfo;
    }
压力测试
  • 安装ab工具

  • yum install httpd-tools
    
  • ab –n 1000-c 200 -p /opt/upprofile -T "application/x-www-form-urlencoded" 192.168.0.106:8084/55.html
    
(2)redisson分布式锁
导入依赖
  • <dependency>
        <groupId>org.redisson</groupId>
        <artifactId>redisson</artifactId>
        <version>3.11.1</version>
    </dependency>
    
  • @Override
        public SkuInfo getSkuInfo(String skuId) {
    
    //        //保存到redis中
    //        Jedis jedis = redisUtil.getJedis();
    //
    //        jedis.set("ok","测试");
    //        jedis.close();
    
            return getSkuInfoRedisson(skuId);
    
    
    //        return getSkuInfoJedis(skuId);
    
        }
    
        private SkuInfo getSkuInfoRedisson(String skuId) {
            Config config = new Config();
            config.useSingleServer().setAddress("redis://192.168.113.132:6379");
    
            RedissonClient redissonClient = Redisson.create(config);
    
            //使用redisson调用getLock
            RLock myLock = redissonClient.getLock("myLock");
    
            //加锁
            myLock.lock(10, TimeUnit.SECONDS);
    
            //业务逻辑代码
    
            SkuInfo skuInfo = null;
    
            Jedis jedis = null;
            //获取jedis
            try {
                jedis = redisUtil.getJedis();
    
                //获取缓存中的数据
                String key = ManageConst.SKUKEY_PREFIX+skuId+ManageConst.SKUKEY_SUFFIX;
    
                //判断redis中是否有key
                if (jedis.exists(key)) {
                    //在redis中取出来
                    String jedisString = jedis.get(key);
                    //转化为对象
                    skuInfo = JSON.parseObject(jedisString, SkuInfo.class);
    
                    return skuInfo;
                }else {
    
                    skuInfo = getSkuInfoDB(skuId);
    
                    //放入redis中
                    String s = JSON.toJSONString(skuInfo);
    
                    jedis.setex(key,ManageConst.SKUKEY_TIMEOUT,s);
                    return skuInfo;
    
                }
    
    
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (jedis != null) {
                    jedis.close();
                }
    
                //解锁
                myLock.unlock();
            }
            return getSkuInfoDB(skuId);
        }