基于Redis的分布式锁的简单应用

朴灿烈づ我的快乐病毒、 2022-06-09 03:27 278阅读 0赞

基于Redis的分布式锁

  1. 支持分布式
  2. 可以细粒度话的控制
  3. 实现多台机器多个进程对一个数据进行操作的互斥(存放于Redis存储系统,多台机器的业务可以共同到Redis系统上进行基于分布式锁的业务操作)

处理并发问题

处理并发问题,主要就是不发生异常的情况下,想办法提升访问速度。

第一种,可以提前把数据库中的数据以Map的形式加载到内存,处理完之后再将处理结果统一写入数据库,提高访问数据的速度。

第二种,使用数据库,要在对应使用线程的方法上加上Synchronized,使其变为单线程,保证了数据的一致性。

如下例子表示的秒杀下单的例子,为该方法加上synchronized:

  1. public synchronized void orderProductMockDiffUser(StringproductId)
  2. {
  3. {
  4. //1:查询该商品库存,0表示活动结束
  5. int stockNum=stock.get(productId);
  6. if(stockNum==0){
  7. thrownew SellException(100,"活动结束");
  8. }
  9. else{
  10. //2:下单,(不同用户的openid不同)
  11. orders.put(KeyUtil.genUniquekey().productId);
  12. stockNum--;
  13. try
  14. try{
  15. Thread.sleep(
  16. Thread.sleep(100);
  17. }
  18. catch(InterruptedException e){
  19. e.printStackTrace()
  20. e.printStackTrace();
  21. }
  22. Stock.put(productid
  23. Stock.put(productid,stockNum);
  24. }
  25. }
  26. }

上述第二种办法,是一种解决办法,但是还是有问题,这种情况只适合单点秒杀的情况。无法细粒度控制一些秒杀的情况。比如,一起秒杀的线程秒杀不同的商品,有的秒杀用户多,有的秒杀用户少,这种情况就会导致所有的秒杀一样的速度,忽略了那些用户少的情况。因此,需要根据情况个别对待,提高效率,这时就需要基于Redis的分布式锁来解决这个问题了。

Redis

百度百科这样解释Redis的:

Redis是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。它支持多种类型的数据结构,如字符串(strings), 散列(hashes), 列表(lists),集合(sets), 有序集合(sorted sets)与范围查询,bitmaps, hyperloglogs和地理空间(geospatial)索引半径查询。 Redis 内置了复制(replication),LUA脚本(Lua scripting),LRU驱动事件(LRU eviction),事务(transactions)和不同级别的磁盘持久化(persistence),并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。

首先要认识两个Redis的命令:

1)SETNX命令

命令形式:SETNX KEYVALUE

意思是:

SouthEast

该例子:在redis存储系统中,将mykey设置为“Hello”,返回1表示设置成功。重新给该key设置为world,不成功,因为已经存在了键值,则什么也不做,返回了0。GET KEY查询到key的value值为“Hello”;

2)GETSET命令

命令形式:GETSET keyvalue

意思是:

SouthEast 1

基于Redis的加解锁

加锁方法lock()

参数 key:传递的是商品productId,value:当前时间+超时时间,保证在上一个线程正常解锁时间之后。

首先在redis中进行键值对的设置(SETNX命令),返回true表示加锁成功,设置时间为value。

否则,获取redis中已有key对应的value值,如果其值不为空并且小于系统当前时间,表示上一个线程的锁已经过期了,此时应该重新设置覆盖以前redis中key的value值(对应Redis中GetAndSet命令),此时当前线程可以抢占锁了。

此时如果有多个线程抢占加锁,则每个线程都需要利用getAndSet得到的旧时间值来个当前key对应的时间值比较,如果相等,表示就是自己拿到的上一个锁的解锁时间,可以抢占加锁;如果不相等,则表示被其他线程捷足先登了,此时不可加锁,需要等到起解锁。

解锁方法unlock()

参数 key:传递的是商品productId,value:当前时间+超时时间,保证在上一个线程正常解锁时间之后。

判断当前商品加锁时间是否为空,如果不为空则并且等于当前传入的value时间戳的值则表示上一个锁已经过期了,此时可以直接删除redis中上一个线程的锁,以释放给其他线程来使用。

业务加解锁

对下单的方法进行加解锁:

  1. public synchronized void orderProductMockDiffUser(StringproductId)
  2. {
  3. //加锁
  4. longtime =System.currentTimeMillis()+TIMEOUT;
  5. if(!redisLock.lock(productId.String.valueOf(time)))
  6. {
  7. Throw new SellException(101,"人太多了,换个姿势再试试")
  8. }
  9. //1:查询该商品库存,0表示活动结束
  10. int stockNum=stock.get(productId);
  11. if(stockNum==0){
  12. thrownew SellException(100,"活动结束");
  13. }
  14. else{
  15. //2:下单,(不同用户的openid不同)
  16. orders.put(KeyUtil.genUniquekey().productId);
  17. stockNum--;
  18. try{
  19. Thread.sleep(100);
  20. }
  21. catch(InterruptedException e){
  22. e.printStackTrace();
  23. }
  24. Stock.put(productid,stockNum);
  25. }
  26. //解锁
  27. redisLock.unlock(productId,String.valueOf(time));
  28. }

Redis数据缓存

这一部分见 高并发优化Redis缓存部分

Jpa和Mybatis怎么选?

JPA:小型项目

Mybatis:SSM架构的则继续使用

建表格使用sql,不用JPA建立,因为不够直观,所以选择Mybatis.

压测模拟并发

Apache ab模拟并发,直接在命令行输入如下命令:

ab -n 100 -c 100 url地址 表示 模拟100条请求的url有100个人同时请求

ab -t 60 -c 100 url地址 表示模拟60秒内100个人同时发送请求

发表评论

表情:
评论列表 (有 0 条评论,278人围观)

还没有评论,来说两句吧...

相关阅读

    相关 基于 Redis 分布式

    前言 分布式锁在分布式应用中应用广泛,想要搞懂一个新事物首先得了解它的由来,这样才能更加的理解甚至可以举一反三。 首先谈到分布式锁自然也就联想到分布式应用。 在我们将