专注Java教育14年 全国咨询/投诉热线:400-8080-105
动力节点LOGO图
始于2009,口口相传的Java黄埔军校
首页 hot资讯 Redis解决高并发问题方案

Redis解决高并发问题方案

更新时间:2022-10-24 09:49:05 来源:动力节点 浏览1858次

1.redis技术的使用:

redis真的是一个很棒的技术,在一定程度上可以解决网站的并发问题,比如抢购商品等活动……

redis高的原因并发可以解决的是它可以直接访问内存,我们以前使用数据库(硬盘),提高了访问效率,解决了数据库服务器压力。

为什么?redis 越来越高了,我们为什么不选择 memcache,那是因为 memcache 只能存储字符串,而 redis 的存储类型非常多(比如有字符串,LIST,SET等),memcache 各有千秋value 最大只能存储1M,存储资源非常有限,会消耗大量内存资源,而redis可以存储1G,最重要的是memcache还不如redis安全,万一服务器故障或意外关机等,redsi内存中的数据会备份到硬盘,而memcache存储的东西全部丢失;这也说明了 memcache 不适合做数据库,可以用来做缓存。

下面就使用 redis 解决即时秒杀活动进行说明:

下面的程序模拟20w人秒冲进这个页面,只有能秒成功的500人,我们把高级用户放到redis中排队,当队列中的用户达到500的时候,后来用户转向第二杀页结束。这里我们使用随机数来代表不同的用户。

这里我们可以看到第一个秒杀成功的用户id是208522,最后一个秒杀成功的用户是176260,秒杀的总参与人数是20w。(大家关注的原因是为了验证下面的准确性)。

接下来我们依次从队列中杀掉第二个500个用户取出来,观察第一个用户和最后一个用户是否和之前的记录值一样

我们可以看到秒杀队列的第一个用户成功id是208522,最后一个用户是176260,可以看出结果非常准确。

redis 解决高并发问题的能力确实不错。

2.Redis可能存在的高并发问题,解决:

(1)如果redis挂了,或者没有链接,怎么办??

解决方法:

1)配置主从复制,配置哨兵模式(相当于古派的长辈级别,可以选择leader的权利),一旦发现主机宕机,让下一个slave做master。

2)最坏的情况,只能关闭 Redis 连接,去数据库连接。但是由于数据量很大,这样的 SQL 数据库会崩溃。

(2)如果redis的缓存在高峰期会过期,此时请求就会像雪崩一般,直接访问数据库怎么处理?

设置条件查询判断,判断redis缓存中是否有数据,没有,然后去数据库连接。分布式锁,当然是利用redis单线程+多IO复用技术,原子性原理,让其他线程请求等待,如果第一个线程进去拿到分布式锁,就在查询数据的途中down掉, 不能让其他线程等待, 设置等待一定时间来判断是否取回数据, 没有, 递归调用自己的方法让第二个线程继续用分布式锁查询数据库。当第二把锁从数据库中获取数据时,将数据值设置到redis的数据库缓存中,设置过期时间,避免占用内存,使用方便,提高效率。

(3)如果用户一直在寻找一条不存在的数据,没有缓存,没有数据库,那么会发生什么

如果数据不存在,缓存中没有,没有数据库,当然如果不设置判断,会一直调用数据库,降低数据库效率,访问量大的时候甚至会down .

解决方法:从数据库中查询,如果数据库没有,则返回值为Null,判断数据库返回的值,如果为Null,则将用户定义的字段保存到Redis中,使用key,value方法,jedis。 setex(key,"empty"),设置失败时间视具体情况而定,然后调用String

json=jedis.get(key),判断是否获取值"empty".equal(json),如果相等,则抛出自定义异常,提示用户,或者直接返回

无效的。这样,当用户再次查询时,需要在 reids 缓存中查询,redis 会有对应的 Key 获取之前设置的 value 值,这样就不会再次调用数据库,影响效率等问题。

具体代码如下:

@Override public SkuInfo getSkuInfo(String skuId) { try {
Thread.sleep(3*1000); // 从redis自定义工具类中jedis对象 Jedis jedis =
redisUtil.getJedis(); // 拼接字符串创建 Redis Inside Key value String skuInfoKey=
JedisConst.SKU_PREFIX+skuId+JedisConst.SKU_SUFFIX; // 根据key值获取value值 String
skuInfoJson = jedis.get(skuInfoKey); // 如果返回为空,则调用本地数据库连接 if (skuInfoJson==null
|| skuInfoJson.length()==0){
System.out.println(Thread.currentThread().getName()+"当前缓存中没有找到数据"); // 判断是否有人去取锁
String skuLockKey=JedisConst.SKU_PREFIX+skuId+JedisConst.SKULOCK_SUFFIX; 字符串
结果 = jedis.set(skuLockKey, "OK", "NX", "PX", JedisConst.SKULOCK_EXPIRE_PX);
if ("OK".equals(result)){
System.out.println(Thread.currentThread().getName()+"获取分布式锁"); SkuInfo skuInfo=
getSkuInfoDB(skuId); // 如果数据库中没有值,如果别人恶意攻击,直接设置到redis缓存中 if (skuInfo==null){
jedis.setex(skuInfoKey,JedisConst.TIME_OUT,"empty"); 返回空值;} skuInfoJson
= JSON.toJSONString(skuInfo); jedis.setex(skuInfoKey, JedisConst.TIME_OUT,
skuInfoJson); jedis.close(); 返回 skuInfo;} else {
// 假设后来有人拿了锁 dang 没了,递归调用自己找钥匙。
System.out.println(Thread.currentThread().getName()+" 未获得分布式锁,开启自旋模式,俗称递归。");
// 等待 1 秒 Thread.sleep(1*1000); jedis.close(); 返回 getSkuInfo(skuId); } }else
if (skuInfoJson.equals("empty")){ return null; } else {
System.out.println(Thread.currentThread().getName()+"缓存中已经有数据被查询"); SkuInfo
skuInfo = JSON.parseObject(skuInfoJson, SkuInfo.class); jedis.close(); 返回
sku信息;} }catch (JedisConnectionException e){ e.printStackTrace(); } catch
(InterruptedException e) { e.printStackTrace(); } 返回 getSkuInfoDB(skuId);

以上就是关于“Redis解决高并发问题方案”的介绍,大家如果对此比较感兴趣,想了解更多相关知识,不妨来关注一下动力节点的Redis教程,里面还有更丰富的知识等着大家去学习,希望对大家能够有所帮助哦。

提交申请后,顾问老师会电话与您沟通安排学习

免费课程推荐 >>
技术文档推荐 >>