Redis并发以及实际运用

通常使用Redis的时候,在业务量很高的情况下都是使用了多服务端。也就是如下场景:

也就是多个服务器共用一个缓存Redis。那么在高并发情况下,传统的synchronized就无法实现控制并发的效果了。因为synchronizd无法跨进程同步控制,那么该如何解决?

分布式锁

我们可以转换思路,将锁控制的原理运用在Redis中,使用类似CAS的操作即可完成一个分布式锁的运用。

@Autowired
StringRedisTemplate stringRedisTemplate ;
public void addCount(){String lockKey = "lock_key";//在Redis中如果lockKey对应的value不存在则添加一个locakKey为Key,value为1的键值对,成功返回true表示加锁成功Boolean b = stringRedisTemplate.opsForValue().setIfAbsent(lockKey , "1" , 30 , TimeUnit.SECONDS);if( !b ){  System.out.println("error_code"); return; }try{/*业务逻辑*/}finally{//业务执行完删除,释放锁,放在finally中保证一定释放,防止抛出异常导致死锁stringRedisTemplate.delete(lockKey);}
​
}

以上则是一个简单的分布式锁,利用CAS和Redis串行化处理请求的机制,对Redis中做一个标记,如果添加成功则表示拿到锁,可以进行业务流程,否则就拿不到锁。最后在业务结束后删除标记释放锁。

这个锁存在很多很多问题,虽然使用了finally保证了锁的释放,但是,如果在try运行时系统宕机,那么依旧会出现死锁一段时间的情况。这还不算问题最严重的地方,如果中间业务逻辑使用的时间过长,在释放锁前,Redis因为时间到了自动解锁。那么并发问题会出现,而且并不是导致这两次请求出现问题,而是后续的请求都会出问题。因为A逻辑执行结束依旧会删除lockKey,也就是释放B线程新加的锁,导致C线程也能进行,B释放C的锁让D同步进行,直接崩盘了。

对于宕机运行超时问题,宕机也就亏一点点运行时间,但是运行超时会影响数据正确性。为了解决运行超时,需要利用一个监视线程,每隔10s对当前线程是否持有锁进行一次判定,如果还拿着,就对Redis中的标记进行一个延时增长,也就是锁续命

使用这种方式,代码的逻辑需要很严密,所以实现起来非常困难,一般情况下,企业中通常使用已经封装好的分布式锁类库来进行操作,也就是导入Redisson。

Redisson

Redisson就是使用了上述的思路,对分布式锁有一个极为稳定的实现,把它当成ReentrantLock的使用方式,就可以很方便地使用了。

<!-- 导入分布式锁Redisson的依赖 -->
<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.6.5</version>
</dependency>
//向容器中添加Redisson分布式锁
@Bean
public Redisson redisson(){Config config = new Config();//此时为单机模式//绑定Redis所在的IP和使用哪个DataBase,这里设置为第0个Databaseconfig.useSingleServer().setAddress("redis://182.92.123.117:6379").setDatabase(0);return (Redisson) Redisson.create(config);
}
@Autowired
Redisson redisson;
​
@RequestMapping("/useRedisson")
public String useRedisson(){String lockKey = "Lock_Key";RLock rLock = redisson.getLock(lockKey);try{//在这里没获取到锁的线程会进行阻塞rLock.lock();/*业务逻辑*/}finally {//在finally中释放锁rLock.unlock();}
}

这样就可以实现分布式锁

高并发优化

Redisson实现的分布式锁是将并发访问串行化,也就是通过阻塞的方式每次只能运行一个线程。这样效率会大大降低,如何进行优化?

使用ConcurrentHashMap底层所使用的的分段锁思想

假设我们进行一个商品秒杀活动,商品总共有200件,访问一次数量减1,不足则返回秒杀失败。在极大并发的情况下,单线程处理单秒几千几万次访问肯定是效率不够的,想要承受双11级别的并发,效率更是低的离谱。不妨我们可以将商品分段,分成10份,1份20个。对lockKey加一个下标,比如lockKey_0,lockKey_1 ..... lockKey_9。每个锁只锁住1份商品,也就是同时可以进行10个请求,阻塞时间极大幅度减少,运行效率提升了很多倍。

缓存数据库双写不一致

使用Redis时,一下代码块是常用的:

@RequestMapping("/update")
//不想用CachePut可以自定义Redis逻辑 AOP或者代码实现
@CachePut( cacheNames = "User" , key = " #result.email " )
public User updateUser(User user){//数据库操作return user;
}

此时并没有使用分布式锁,高并发情况下就会出现一下问题:

正常应该是以下流程

最终redis中结果为6。

高并发情况下的双写不一致:

分布式锁可以解决双写不一致问题

业务场景运用

抽奖

使用Set无需集合,将所有参与抽奖的用户装入这个集合,最后随机取出。

添加用户:sadd 集合名 用户ID

查看所有参与抽奖的用户:smembers 集合名

不放回抽取:srandmember 集合名 数量

放回抽取: spop 集合名 数量

关注推送

使用List

关注的人发消息,则对关注它的消息队列执行:lpush msg:{ID} 10018

查看消息:lrange msg:{ID} 0 4 拿出前5条消息

当一个人关注的人数较多怎么办呢?几百万粉丝一起推送的话,是不是处理量有点太大了。对此的策略是:没办法,只能这么玩,优化策略是对当前在线的粉丝进行优先推送,不在线的粉丝则慢慢推送。

点赞统计,浏览次数统计

set watchNum 1

inr watchNum

购物车

购物车可以使用HashMap,也就是哈希表,哈希表中存放(物品编号,数量)键值对。

添加商品:hset cart:用户编号 商品编号 1

增加数量:hincrby cart:用户编号 商品编号 1

商品总数:hlen cart:用户编号

删除商品:hdel cart:用户编号 商品编号

获取购物车所有商品:hgetall cart:用户编号

Redis进阶—分布式锁相关推荐

  1. 使用Redis作为分布式锁的错误用法

    前言 这段时间看到挺多人使用redis作为分布式锁来进行资源的控制,但是这种写法有挺多问题的,所以才特意写一篇文章让大家讨论一下. 锁的特性 安全性:当一个资源被占用后,其他线程不能占用 容错性:当一 ...

  2. 返回值带头信息 php_php与Redis实现分布式锁

    一.分布式锁的作用: redis写入时不带锁定功能,为防止多个进程同时进行一个操作,出现意想不到的结果,so...对缓存进行插入更新操作时自定义加锁功能. 二.Redis的NX后缀命令 Redis有一 ...

  3. 基于 Redis 实现分布式锁思考

    以下文章来源方志朋的博客,回复"666"获面试宝典 来源:blog.csdn.net/xuan_lu/article/details/111600302 分布式锁 基于redis实 ...

  4. Redis实现分布式锁的深入探究

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 一.分布式锁简介 锁 是一种用来解决多个执行线程 访问共享资源 错 ...

  5. nx set 怎么实现的原子性_基于Redis的分布式锁实现

    前言 本篇文章主要介绍基于Redis的分布式锁实现到底是怎么一回事,其中参考了许多大佬写的文章,算是对分布式锁做一个总结 分布式锁概览 在多线程的环境下,为了保证一个代码块在同一时间只能由一个线程访问 ...

  6. Zookeeper和Redis实现分布式锁,附我的可靠性分析

    作者:今天你敲代码了吗 链接:https://www.jianshu.com/p/b6953745e341 在分布式系统中,为保证同一时间只有一个客户端可以对共享资源进行操作,需要对共享资源加锁来实现 ...

  7. Redis——由分布式锁造成的重大事故

    作者:浪漫先生 原文:juejin.im/post/6854573212831842311 前言 基于Redis使用分布式锁在当今已经不是什么新鲜事了.本篇文章主要是基于我们实际项目中因为redis分 ...

  8. 基于Redis的分布式锁和Redlock算法

    来自:后端技术指南针 1 前言 今天开始来和大家一起学习一下Redis实际应用篇,会写几个Redis的常见应用. 在我看来Redis最为典型的应用就是作为分布式缓存系统,其他的一些应用本质上并不是杀手 ...

  9. 《Redis官方文档》用Redis构建分布式锁

    <Redis官方文档>用Redis构建分布式锁 用Redis构建分布式锁 在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段. 有很多三方库和文章描述如何用Redis实现 ...

最新文章

  1. [技术转载]C#知识点集合 (面试必备)
  2. PyTorch中如何使用tensorboard可视化
  3. Spring之LoadTimeWeaver——一个需求引发的思考---转
  4. CentOS 下多线程下载工具:axel
  5. 没想到单位的bt下载的速度可以到这么快,满意了
  6. portlet_平台策略:从Portlet到OpenSocial小工具再到渐进式Web应用程序:最新技术
  7. leetcode 461. 汉明距离(位运算)
  8. linux lp 打印中文,Linux基础命令---lp打印文件
  9. criteria函数_干货铺 | 二级MS office考试中一些常考函数(2)
  10. python comprehension_Python从题目中学习:List comprehension
  11. soap python_Zeep: Python SOAP 客户端
  12. 打开视频文件提示服务器异常,视频解析服务器异常
  13. 什么是大数据,大数据最缺什么样的人才?
  14. 没有公网IP,自建网站如何让外网访问?
  15. Golang DNS 随便写写
  16. JavaScript编辑器介绍
  17. 有苦有乐的算法 --- 归并排序
  18. 计算机图形学专业 国内大学排名,虚拟现实应用技术专业大学排名 2020全国排行榜...
  19. h5页面是html5么,H5是什么?5分钟就能全面了解什么是html5页面
  20. jstorm 读取mysql_jstorm集成kafka

热门文章

  1. chrome不显示数学公式
  2. Mantel test: 两个矩阵相关关系的检验
  3. 详解文件存储空间管理中的位示图法
  4. ES6语法总结(21)--Generator函数的异步应用
  5. linux 挂载3t硬盘分区,Ubuntu挂载3T硬盘或大于2T磁盘的方法
  6. 计算机使用计数制是,进位计数制
  7. 电脑设备管理器无端口显示怎么办?
  8. 使用VMware 5.5.3在Ubuntu Edgy上安装VMware Tools
  9. 1t硬盘怎么分区最好_1t硬盘怎么分区合理
  10. 颜色模型HSB-这么强大的工具,你居然还不知道?