返回顶部
首页 > 资讯 > 数据库 >Redis缓存相关的几个问题
  • 826
分享到

Redis缓存相关的几个问题

Redis缓存相关的几个问题 2018-11-06 07:11:46 826人浏览 才女
摘要

1  缓存穿透 问题描述 缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,进而给数据库带来压力。 解决方案 缓存空值,即对于不存在的数

Redis缓存相关的几个问题

1  缓存穿透

问题描述

缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,进而给数据库带来压力。

解决方案

缓存空值,即对于不存在的数据,在缓存中放置一个空对象(注意,设置过期时间)

2  缓存击穿

问题描述

缓存击穿是指热点key在某个时间点过期的时候,而恰好在这个时间点对这个Key有大量的并发请求过来,从而大量的请求打到数据库。

解决方案

加互斥,在并发的多个请求中,只有第一个请求线程能拿到锁并执行数据库查询操作,其他的线程拿不到锁就阻塞等着,等到第一个线程将数据写入缓存后,直接走缓存。

3  缓存雪崩

问题描述

缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。

解决方案

可以给缓存的过期时间时加上一个随机值时间,使得每个 key 的过期时间分布开来,不会集中在同一时刻失效。

4  缓存服务器宕机

问题描述

并发太高,缓存服务器连接被打满,最后挂了

解决方案

  • 限流:Nginxspring cloud gateway、sentinel等都支持限流
  • 增加本地缓存(JVM内存缓存),减轻Redis一部分压力

5  Redis实现分布式

问题描述

如果用redis做分布式锁的话,有可能会存在这样一个问题:key丢失。比如,master节点写成功了还没来得及将它复制给slave就挂了,于是slave成为新的master,于是key丢失了,后果就是没锁住,多个线程持有同一把互斥锁。

解决方案

必须等redis把这个key复制给所有的slave并且都持久化完成后,才能返回加锁成功。但是这样的话,对其加锁的性能就会有影响。

ZooKeeper同样也可以实现分布式锁。在分布式锁的的实现上,zookeeper的重点是CP,redis的重点是AP。因此,要求强一致性就用zookeeper,对性能要求比较高的话就用redis

5  示例代码

pom.xml


 xmlns="Http://Maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.6.7
         
    
    com.example
    demo426
    0.0.1-SNAPSHOT
    demo426
    
        1.8
    
    
        
            org.springframework.boot
            spring-boot-starter-WEB
        
        
            org.springframework.boot
            spring-boot-starter-data-redis
        
        
            org.redisson
            redisson
            3.17.1
        
        
            com.GitHub.ben-manes.caffeine
            caffeine
            2.9.2
        
        
            com.alibaba
            fastJSON
            2.0.1
        
        
            org.apache.commons
            commons-lang3
            3.12.0
        
        
            org.projectlombok
            lombok
            true
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    
    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
                
                    
                        
                            org.projectlombok
                            lombok
                        
                    
                
            
        
    

Product.java

package com.example.demo426.domain;

import lombok.Data;

import java.io.Serializable;
import java.time.LocalDateTime;


@Data
public class Product implements Serializable {

    private Long productId;

    private String productName;

    private Integer stock;

    private LocalDateTime createTime;

    private LocalDateTime updateTime;

    private Integer isDeleted;

    private Integer version;
}

ProductController.java

package com.example.demo426.controller;

import com.alibaba.fastjson.JSON;
import com.example.demo426.domain.Product;
import com.example.demo426.service.ProductService;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.Random;
import java.util.concurrent.TimeUnit;


@RestController
@RequestMapping("/product")
public class ProductController {

    @Autowired
    private RedissonClient redissonClient;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private ProductService productService;

    private final Cache PRODUCT_LOCAL_CACHE = Caffeine.newBuilder()
            .maximumSize(100)
            .expireAfterWrite(Duration.ofMinutes(60))
            .build();

    private final String PRODUCT_CACHE_PREFIX = "cache:product:";
    private final String PRODUCT_LOCK_PREFIX = "lock:product:";
    private final String PRODUCT_RW_LOCK_PREFIX = "lock:rw:product:";

    
    @PostMapping("/update")
    public void update(@RequestBody Product productDTO) {
        RReadWriteLock readWriteLock = redissonClient.getReadWriteLock(PRODUCT_RW_LOCK_PREFIX + productDTO.getProductId());
        RLock wLock = readWriteLock.writeLock();
        wLock.lock();
        try {
            //  写数据库
            //  update product set name=xxx,...,version=version+1 where id=xx and version=xxx
            Product product = productService.update(productDTO);
            //  放入缓存
            PRODUCT_LOCAL_CACHE.put(product.getProductId(), product);
            stringRedisTemplate.opsForValue().set(PRODUCT_CACHE_PREFIX + product.getProductId(), JSON.toJSONString(product), getProductTimeout(60), TimeUnit.MINUTES);
        } finally {
            wLock.unlock();
        }
    }

    
    @GetMapping("/query")
    public Product query(@RequestParam("productId") Long productId) {
        //  1. 尝试从缓存读取
        Product product = getProductFromCache(productId);
        if (null != product) {
            return product;
        }
        //  2. 准备从数据库中加载
        //  互斥锁
        RLock lock = redissonClient.getLock(PRODUCT_LOCK_PREFIX + productId);
        lock.lock();
        try {
            //  再次先查缓存
            product = getProductFromCache(productId);
            if (null != product) {
                return product;
            }

            //  为了避免缓存与数据库双写不一致
            //  读写锁
            RReadWriteLock readWriteLock = redissonClient.getReadWriteLock(PRODUCT_RW_LOCK_PREFIX + productId);
            RLock rLock = readWriteLock.readLock();
            rLock.lock();
            try {
                //  查数据库
                product = productService.getById(productId);
                if (null == product) {
                    //  如果数据库中没有,则放置一个空对象,这样做是为了避免”缓存穿透“问题
                    product = new Product();
                } else {
                    PRODUCT_LOCAL_CACHE.put(productId, product);
                }
                //  放入缓存
                stringRedisTemplate.opsForValue().set(PRODUCT_CACHE_PREFIX + productId, JSON.toJSONString(product), getProductTimeout(60), TimeUnit.MINUTES);
            } finally {
                rLock.unlock();
            }
        } finally {
            lock.unlock();
        }

        return null;
    }

    
    private Product getProductFromCache(Long productId) {
        //  1. 尝试从本地缓存读取
        Product product = PRODUCT_LOCAL_CACHE.getIfPresent(productId);
        if (null != product) {
            return product;
        }
        //  2. 尝试从Redis中读取
        String key = PRODUCT_CACHE_PREFIX + productId;
        String value = stringRedisTemplate.opsForValue().get(key);
        if (StringUtils.isNotBlank(value)) {
            product = JSON.parseObject(value, Product.class);
            return product;
        }
        return null;
    }

    
    private int getProductTimeout(int initVal) {
        Random random = new Random(10);
        return initVal + random.nextInt();
    }
}

原文地址:https://www.cnblogs.com/cjsblog/arcHive/2022/04/26/16196302.html

您可能感兴趣的文档:

--结束END--

本文标题: Redis缓存相关的几个问题

本文链接: https://lsjlt.com/news/9297.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Redis缓存相关的几个问题
    1  缓存穿透 问题描述 缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,进而给数据库带来压力。 解决方案 缓存空值,即对于不存在的数...
    99+
    2018-11-06
    Redis缓存相关的几个问题
  • 关于golangtest缓存问题
    在使用vscode进行debug golang 时,出现test结果缓存的情况导致若干次test结果一致问题设置go test不用缓存官方说明https://pkg.go.dev/c...
    99+
    2024-04-02
  • Redis缓存问题的示例分析
    这篇文章给大家分享的是有关Redis缓存问题的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、Redis缓存的应用在我们的实际业务场景中,Redis 一般和其他数据库搭...
    99+
    2024-04-02
  • 面试攻略:如何回答 Java 缓存相关问题?
    在面试过程中,Java 缓存相关问题是经常被问到的一个话题。因为缓存是提高系统性能和用户体验的重要手段,而在 Java 语言中,缓存机制也是非常重要的一部分。本文将介绍 Java 缓存相关问题的常见问题和解决方法,并通过演示代码来帮助读者...
    99+
    2023-10-06
    缓存 学习笔记 面试
  • Redis缓存问题怎么解决
    这篇文章主要讲解了“Redis缓存问题怎么解决”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Redis缓存问题怎么解决”吧!LevelDB 来了!它是 Go...
    99+
    2024-04-02
  • Redis缓存中有哪些问题
    这篇文章给大家分享的是有关Redis缓存中有哪些问题的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、缓存穿透缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起 id 为-1 的数据或者特别大的不...
    99+
    2023-06-20
  • 如何解决redis缓存穿透、缓存击穿、缓存雪崩的问题
    这篇文章主要介绍了如何解决redis缓存穿透、缓存击穿、缓存雪崩的问题,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。缓存穿透:key中对应的...
    99+
    2024-04-02
  • 关于redis缓存的面试题有哪些
    这篇文章将为大家详细讲解有关关于redis缓存的面试题有哪些,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。redis缓存的面试题1、redis和memcached什么区别...
    99+
    2024-04-02
  • 如何解决Redis缓存异常的问题
    这篇文章将为大家详细讲解有关如何解决Redis缓存异常的问题,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。缓存雪崩缓存雪崩是指缓存同一时间大面积的失效,所以,后面的请求都...
    99+
    2024-04-02
  • Redis缓存一致性、缓存穿透、缓存击穿及缓存雪崩问题分析
    本篇内容介绍了“Redis缓存一致性、缓存穿透、缓存击穿及缓存雪崩问题分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,...
    99+
    2024-04-02
  • web面试常问http缓存解析相关
    目录为什么要有http缓存?http缓存之 强制缓存http缓存之 协商缓存(对比缓存)协商缓存中的资源标识为什么要有http缓存? 1.当输入网址到加载出页面, 电...
    99+
    2024-04-02
  • 如何解决Redis缓存穿透和缓存雪崩问题
    这篇文章主要为大家展示了“如何解决Redis缓存穿透和缓存雪崩问题”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“如何解决Redis缓存穿透和缓存雪崩问题”这篇文...
    99+
    2024-04-02
  • Redis缓存雪崩问题怎么解决
    本篇内容介绍了“Redis缓存雪崩问题怎么解决”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!缓存层承载着大量的请求,有效保护了存储层。但是如...
    99+
    2023-06-30
  • redis被动缓存问题怎么解决
    要解决Redis的被动缓存问题,可以考虑以下方法:1. 设置合适的过期时间:可以根据业务需求,为每个缓存设置适当的过期时间。这样可以...
    99+
    2023-08-24
    redis
  • redis怎么解决缓存不一致的问题
    本文小编为大家详细介绍“redis怎么解决缓存不一致的问题”,内容详细,步骤清晰,细节处理妥当,希望这篇“redis怎么解决缓存不一致的问题”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新...
    99+
    2024-04-02
  • SpringBoot中的Redis 缓存问题及操作方法
    目录1、五大基本数据类型和操作1.1 字符串-string1.2 列表-list1.3 集合-set1.4 键值对-hash1.5 有序集合-zset2、Redis整合2.1 spr...
    99+
    2022-11-13
    SpringBoot Redis 缓存 SpringBoot缓存
  • mysql5.7的几个问题
    1)mysql5.7的关闭: centos 7 上对于rpm方式安装的mysql ,必须使用 systemctl stop mysqld.service /service mysqld stop才能关闭 用...
    99+
    2024-04-02
  • Redis常见的几个问题及解决方法
    本篇内容主要讲解“Redis常见的几个问题及解决方法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Redis常见的几个问题及解决方法”吧! 1、如何保证Redis高可用和高并发Redi...
    99+
    2023-06-16
  • Redis中怎么应对缓存热key问题
    这篇“Redis中怎么应对缓存热key问题”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“R...
    99+
    2024-04-02
  • redis缓存一致性问题怎么解决
    在使用 Redis 缓存时,可能会遇到缓存一致性问题,即缓存中的数据与数据库中的数据不一致。以下是一些常见的解决方法: 缓存更新...
    99+
    2023-10-26
    redis
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作