Redis实现多级缓存

本文实例为大家分享了Redis实现多级缓存的具体代码,供大家参考,具体内容如下

一、多级缓存

1. 传统缓存方案

请求到达tomcat后,先去redis中获取缓存,不命中则去mysql中获取

2. 多级缓存方案

  • tomcat的请求并发数,是远小于redis的,因此tomcat会成为瓶颈
  • 利用请求处理每个环节,分别添加缓存,减轻tomcat压力,提升服务性能

二、JVM本地缓存

缓存是存储在内存中,数据读取速度较快,能大量减少对数据库的访问,减少数据库压力

分布式缓存,如redis
 - 优点: 存储容量大,可靠性好,可以在集群中共享
 - 缺点: 访问缓存有网络开销
 - 场景: 缓存数据量大,可靠性高,需要在集群中共享的数据

进程本地缓存, 如HashMap, GuavaCache
- 优点:读取本地内存,没有网络开销,速度更快
- 缺点:存储容量有限,可靠性低(如重启后丢失),无法在集群中共享
- 场景:性能要求高,缓存数据量少

1. 实用案例

Caffeine是一个基于java8开发的,提供了近乎最佳命中率的高性能的本地缓存库
目前spring内部的缓存用的就是这个

<dependency>
     <groupId>com.github.ben-manes.caffeine</groupId>
     <artifactId>caffeine</artifactId>
     <version>3.0.5</version>
 </dependency>
package com.erick.cache;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;

import java.time.Duration;

public final class CacheUtil {
    private static int expireSeconds = 2;
    public static Cache<String, String> cacheWithExpireSeconds;

    private static int maxPairs = 1;
    public static Cache<String, String> cacheWithMaxPairs;

    static {
        /*过期策略,写完60s后过期*/
        cacheWithExpireSeconds = Caffeine.newBuilder()
                .expireAfterWrite(Duration.ofSeconds(expireSeconds))
                .build();

        /*过期策略,达到最大值后删除
         * 1. 并不会立即删除,等一会儿才会删除
         * 2. 会将之前存储的数据删除掉*/
        cacheWithMaxPairs = Caffeine.newBuilder()
                .maximumSize(maxPairs)
                .build();
    }

    /*从缓存中获取数据
     * 1. 如果缓存中有,则直接从缓存中返回
     * 2. 如果缓存中没有,则去数据查询并返回结果*/
    public static String getKeyWithExpire(String key) {
        return cacheWithExpireSeconds.get(key, value -> {
            return getResultFromDB();
        });
    }

    public static String getKeyWithMaxPair(String key) {
        return cacheWithMaxPairs.get(key, value -> {
            return getResultFromDB();
        });
    }

    private static String getResultFromDB() {
        System.out.println("数据库查询");
        return "db result";
    }
}
package com.erick.cache;

import java.util.concurrent.TimeUnit;

public class Test {

    @org.junit.Test
    public void test01() throws InterruptedException {
        CacheUtil.cacheWithExpireSeconds.put("name", "erick");
        System.out.println(CacheUtil.getKeyWithExpire("name"));
        TimeUnit.SECONDS.sleep(3);
        System.out.println(CacheUtil.getKeyWithExpire("name"));
    }

    @org.junit.Test
    public void test02() throws InterruptedException {
        CacheUtil.cacheWithMaxPairs.put("name", "erick");
        CacheUtil.cacheWithMaxPairs.put("age", "12");

        System.out.println(CacheUtil.getKeyWithMaxPair("name"));
        System.out.println(CacheUtil.getKeyWithMaxPair("age"));

        TimeUnit.SECONDS.sleep(2);

        System.out.println(CacheUtil.getKeyWithMaxPair("name")); // 查询不到了
        System.out.println(CacheUtil.getKeyWithMaxPair("age"));
    }
}

三、缓存一致性

1. 常见方案

1.1 设置有效期

  • 给缓存设置有效期,到期后自动删除。再次查询时可以更新
  • 优势:简单,方便
  • 缺点:时效性差,缓存过期之前可能不一致
  • 场景:更新频率低,时效性要求比较低的业务

1.2 同步双写

  • 在修改数据库的同时,直接修改缓存
  • 优势:有代码侵入,缓存与数据库强一致性
  • 缺点:代码进入,耦合性高
  • 场景:对一致性,失效性要求较高的缓存数据

1.3 异步通知

  • 修改数据库时发送事件通知,相关服务监听到后修改缓存数据
  • 优势:低耦合,可以同时通知多个缓存服务
  • 缺点:时效性一把,可能存在缓存不一致问题
  • 场景:时效性一般,有多个服务需要同步

2. 基于Canal的异步通知

  • 是阿里旗下的一款开源项目,基于java开发
  • 基于数据库增量日志解析,提供增量数据订阅和消费
  • 基于mysql的主从备份的思想

2.1 mysql主从复制

2.2 canal 工作原理

canal 模拟 MySQL slave 的交互协议,伪装自己为 MySQL slave ,向 MySQL master 发送dump 协议
MySQL master 收到 dump 请求, 开始推送 binary log 给 slave (即 canal )
canal 解析 binary log 对象(原始为 byte 流)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • redis缓存的简单操作(get、put)

    本文介绍简单的redis缓存操作,包括引入jedisjar包.配置redis.RedisDao需要的一些工具.向redis中放数据(put).从redis中取数据(get).访问redis时的逻辑 一.引入jedis jar包 <!-- java访问redis的jar包jedis --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId&g

  • 面试常问:如何保证Redis缓存和数据库的数据一致性

    目录 一.一致性 1.强一致性 2.弱一致性 3.最终一致性 二.redis缓存和mysql数据库数据一致性解决 1.方案一:采用延时双删策略 2.方案二:一步更新缓存(基于订阅Binlog的同步机制) 首先,我们先来看看有哪几种一致性的情况呢? 一.一致性 1.强一致性 如果你的项目对缓存的要求是强一致性的,那么请不要使用缓存.这种一致性级别是最符合用户直觉的,它要求系统写入什么,读出来的也会是什么,用户体验好,但实现起来往往对系统的性能影响大. 2.弱一致性 这种一致性级别约束了系统在写入成

  • 【Redis缓存机制】详解Java连接Redis_Jedis_事务

    Jedis事务 我们使用JDBC连接Mysql的时候,每次执行sql语句之前,都需要开启事务:在MyBatis中,也需要使用openSession()来获取session事务对象,来进行sql执行.查询等操作.当我们对数据库的操作结束的时候,是事务对象负责关闭数据库连接. 事务对象用于管理.执行各种数据库操作的动作.它能够开启和关闭数据库连接,执行sql语句,回滚错误的操作. 我们的Redis也有事务管理对象,其位于redis.clients.jedis.Transaction下. Jedis事

  • window手动操作清理redis缓存的技巧总结

    redis缓存知识点: 一.缓存穿透 缓存穿透是指查询一个缓存和数据库中都没有的数据,由于大部分缓存策略是被动加载的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义.用户不断发起请求,在流量大时,就可能对DB形成巨大的压力,利用不存在的key频繁攻击应用也是很大的问题. 二.缓存击穿 缓存击穿是指缓存中的一个热点Key(比如一个秒杀商品),在某个时间点过期的时候,恰好在这个时间点访问量剧增,对这个Key有大量的并发请求过

  • 图文详解Windows下使用Redis缓存工具的方法

    一.简介 redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合)和zset(有序集合). 这些数据类型都支持push/pop.add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的.在此基础上,redis支持各种不同方式的排序.与memcached一样,为了保证效率,数据都是缓存在内存中.区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记

  • Redis缓存常用4种策略原理详解

    我们都知道,提高系统性能的最简单也最流行的方法之一其实就是使用缓存.我们引入缓存,相当于对数据进行了复制.每当系统数据更新时,保持缓存和数据源(如 MySQL 数据库)同步至关重要,当然,这也取决于系统本身的要求,看系统是否允许一定的数据延迟. 最常见的几种缓存策略.它们的优缺点以及使用场景,分别是: Cache-Aside Read-Through Write-Through Write-Behind Cache-Aside 策略 Cache-Aside可能是最常用的缓存策略.在这种策略下,应

  • Redis缓存详解

    下面来正式分享今天的文章吧: .搭建Redis服务端,并用客户端连接 .封装缓存父类,定义Get,Set等常用方法 .定义RedisCache缓存类,执行Redis的Get,Set方法 .构造出缓存工厂调用方法 下面一步一个脚印的来分享: .搭建Redis服务端,并用客户端连接 首先,咋们去这个地址下载安装文件https://github.com/dmajkic/redis/downloads,我这里的版本是:redis-2.4.5-win32-win64里面有32位和64位的执行文件,我这里服

  • 在ssm项目中使用redis缓存查询数据的方法

    在项目中常常需要后台程序的持久层查询数据库来获取数据,然后将数据交给服务层.控制层,最后才交给视图层.如果数据访问缓慢,就会影响程序的运行. 为了加快程序的运行,可以将数据放入缓存中,包括数据缓存和页面缓存. 所谓缓存,就是将程序或系统经常要调用的对象存在内存中,一遍其使用时可以快速调用,不必再去创建新的重复的实例.这样做可以减少系统开销,提高系统效率. 其中页面缓存主要是oscache,可以整页或者指定网页某一部分缓存,同时指定他的过期时间,这样在此时间段里面访问的数据都是一样的 . 数据缓存

  • Redis整合Spring结合使用缓存实例

    一.Redis介绍 什么是Redis?       redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sorted set --有序集合)和hash(哈希类型).这些数据类型都支持push/pop.add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的.在此基础上,redis支持各种不同方式的排序.与memcached一样,为了保证效率,数据都是

  • 详解缓存穿透/击穿/雪崩原理及其解决方案

    目录 1. 简介 2. 缓存穿透 2.1描述 2.2 解决方案 3. 缓存击穿 3.1 描述 3.2 解决方案 4. 缓存雪崩 4.1 描述 4.1 解决方案 5. 布隆过滤器 5.1 描述 5.2 数据结构 5.3 "一定不在集合中" 5.4 "可能在集合中" 5.5 "删除困难" 5.6 为什么不使用HashMap呢? 1. 简介 如图所示,一个正常的请求 1.客户端请求张铁牛的博客. 2.服务首先会请求redis,查看请求的内容是否存在.

随机推荐