缓存 redis

本文对比了Redis和Memcached两大缓存系统,深入探讨了它们的数据类型、持久化能力、主从复制、分片及集群模式。Redis支持丰富的数据结构和持久化存储,而Memcached则专注于简单数据存储。文章还介绍了两者在缓存机制、多线程模型及持久化机制上的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

redis

数据类型丰富
支持数据磁盘持久化存储
支持主从
支持分片

为什么redis快

完全基于内存,绝大部分请求是纯粹的内存操作,执行效率高
数据结构简单,对数据操作也简单
采用单线程,单线程也能处理高并发请求,想多核也可启动多实例
使用多路i/o复用模型,非阻塞i/o

redis数据类型

string:最基本的数据类型,二进制安全
hash:string元素组成的字典,适用于存储对象
list:按照string元素插入顺序排序
set:string组成的无序集合,通过hash表实现,不允许重复
sorted set:通过分数来为集合中的成员进行从小到大的排序
用于计数的hyperloglog,用于支持存储地理位置信息的geo

redis分布式缓存

  1. 获取锁时,使用setnx加锁,锁的value值为一个随机生成的uuid,在释放锁的时候进行判断,使用expire命令为锁添加一个超时时间,超过时间自动释放锁。
  2. 释放锁通过uuid,若是,用delete进行锁释放

redis异步队列

使用list作为队列,rpush生产消息,lpop消费信息
缺点:没有等待队列里有值就直接消费
弥补:在应用层引入sleep机制去调用lpop重试
blpop key timeout:阻塞知道队列有消息或者超时
缺点:只能供一个消费者消费
pub发送者/sub订阅者
缺点:消息的发布是无状态的,无法保证可达

redis持久化

  1. rdb快照持久化:保存某个数据点的全量数据快照,save:阻塞redis服务器进程,知道rdb文件被创建完毕,bgsave:fork出一个子线程来船舰rdb文件,不阻塞服务器进程
  2. 根据redis.conf配置里的save m n定时触发
  3. 主从复制时,主节点自动触发
  4. debug reload
  5. 执行shutdown且没有开启aof持久化

rdb持久化缺点:
内存数据的全量同步,数据量大会由于i/o严重影响性能
可能会因为redis挂掉而丢失从当前至最近一次快照期间的数据

aof持久化:日志重写解决aof文件大小不断增大的问题,原理如下(调用fork(),创建一个子进程,子进程把新写的aof写到一个临时文件里,不依赖原来的aof文件,主进程持续将新的变动写到内存和原来的aof,主进程获取子进程重写aof的完成信号,网aof同步增量变动,使用新的aof文件替换旧的aof文件)

rdb和aof优缺点

rdb优点:全量数据快照,文件小,恢复快
rdb缺点:无法保存最快一次快照之后的数据
aof优点:可读性高,适合保存增量数据,数据不易丢失
aof缺点:文件体积大,恢复时间长

使用pipeline的好处

pipeline和linux管道类似
redis基于请求/响应模型,单个请求处理需要一一应答
pipeline批量执行指令,节省多次io往返时间

redis下载地址:https://github.com/microsoftarchive/redis/releases/tag/win-3.2.100
运行:redis-server.exe redis.windows.conf

redis-cli.exe -h 127.0.0.1 -p 6379
服务命令
redis-server --service-install redis.windows-service.conf --loglevel verbose

redis相当于一个数据库,数据存在内存中,用于缓存
使用 redis 或 memcached 之类的称为分布式缓存,在多例时,各实例共用一份缓存数据,缓存具有一致性,但是具有复杂度
单线程,采用 IO 多路复用机制同时监听多个 socket,根据 socket 上的事件来选择对应的事件处理器进行处理。Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,zset,hash等数据结构的存储。memcache支持简单的数据类型,String。Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用,而Memecache把数据全部存在内存之中。
集群模式:memcached没有原生的集群模式,需要依靠客户端来实现往集群中分片写入数据;但是 redis 目前是原生支持 cluster 模式的.
Memcached是多线程,非阻塞IO复用的网络模型;Redis使用单线程的多路 IO 复用模型。
redis 持久化机制
Redis的一种持久化方式叫快照(snapshotting,RDB),另一种方式是只追加文件(append-only file,AOF)。
Redis创建快照之后,可以对快照进行备份,可以将快照复制到其他服务器从而创建具有相同数据的服务器副本(Redis主从结构,主要用来提高Redis性能),还可以将快照留在原地以便重启服务器的时候使用。

原文链接:https://blog.csdn.net/qq_34337272/article/details/80012284

memcached

代码层次类似hash
支持简单数据存储
不支持数据持久化存储
不支持主从
不支持分片

安装为服务 增加参数即可 memcached.exe -d install
​使用的默认端口号是11211 ,设置端口,还有很多参数,设置内存大小等
C:\Users\dashi.lu>netstat -ano | findstr “11211”
TCP 0.0.0.0:11211 0.0.0.0:0 LISTENING 3308
TCP [::]:11211 [::]:0 LISTENING 3308
UDP 0.0.0.0:11211 : 3308
UDP [::]:11211 : 3308

<dependency>
    <groupId>com.google.code.simple-spring-memcached</groupId>
    <artifactId>spymemcached</artifactId>
    <version>2.8.4</version>
</dependency>

memcached应用场景介绍
​ 比如 用户登陆或者注册 验证码
缓存中储存在是一些非业务必要数据(不是一些紧要的数据)
memcached查看工具[无需记忆命令]
http://www.treesoft.cn/dms.html

一级缓存
也称之为sqlsession缓存,作用域比较小
特点 【hashmap不可卸载,有办法设置存活实践更小】
默认配置

 <!--全局设置-->
    <settings>
        <!--一级缓存设置-->
        <!--默认已经设置好了-->
        <setting name="localCacheScope" value="SESSION"/>
    </settings>
//
  //同一个sqlsession,多次查询,共享一级缓存
        SqlSession sqlSession = sqlSessionFactory.openSession();
        AccountMapper mapper = sqlSession.getMapper(AccountMapper.class);
        Account account1 = mapper.selectByPrimaryKey(22);
        System.out.println(JSON.toJSONString(account1,true));
        Thread.sleep(10000);
        Account account2 = mapper.selectByPrimaryKey(22);
        System.out.println(JSON.toJSONString(account2,true));
        Account account3 = mapper.selectByPrimaryKey(22);
        System.out.println(JSON.toJSONString(account3,true));

 

mybatis一级缓存的生命周期和sqlsession一致【sqlsession,localcache】
​ mybatis一级缓存内部实现是hashmap
​ 如果有多个sqlsession对同一条数据进行操作,可能出现数据脏读的情况。

如果解决这个问题

另外在获取sqlsession的时候为自动提交模式 SqlSession sqlSession = sqlSessionFactory.openSession(true);
每一次都会查询数据库
二级缓存
跨sqlsession级别的缓存,作用域较大
特点【默认实现也是一个hashmap】
实际的应用场景是 用户查询 新闻id =1 信息,用户2 查询 新闻id=1 信息,这里所说的用户对应代码就是不同的sqlsession,在不同的sqlsession中共享数据就是二级缓存

<!--开启二级缓存 默认就是开启的-->
        <setting name="cacheEnabled" value="true"/>

//
<!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-memcached -->
  <dependency>
      <groupId>org.mybatis.caches</groupId>
      <artifactId>mybatis-memcached</artifactId>
      <version>1.0.0</version>
  </dependency>

//
编写memcached.properties 框架会在classes目录下默认寻找
#any string identifier
org.mybatis.caches.memcached.keyprefix=_biz-cache-wk_
#space separated list of ${host}:${port}
org.mybatis.caches.memcached.servers=127.0.0.1:11211
#org.mybatis.caches.memcached.servers=192.168.0.44:12000
#Any class that implementsnet.spy.memcached.ConnectionFactory
org.mybatis.caches.memcached.connectionfactory=net.spy.memcached.DefaultConnectionFactory
#the number of seconds in 30 days    the expiration time (in seconds)
org.mybatis.caches.memcached.expiration=6000
#flag to enable/disable the async get
org.mybatis.caches.memcached.asyncget=false
#the timeout when using async get
org.mybatis.caches.memcached.timeout=5
#the timeout unit when using async get
org.mybatis.caches.memcached.timeoutunit=java.util.concurrent.TimeUnit.SECONDS
#if true, objects will be GZIP compressed before putting them to
org.mybatis.caches.memcached.compression=false
#\u7f13\u5b58\u670d\u52a1\u5668\u5b95\u673a\u540e\u591a\u4e45\u4e0d\u4f7f\u7528memcached \u6beb\u79d2\u4e3a\u5355\u4f4d
#refuse time when connection refused
org.mybatis.caches.memcached.refuseperiod=1000


//
//不同的sqlsession如果没有调用commit方法二级缓存并无作用 
  SqlSession sqlSession = sqlSessionFactory.openSession(true);
        SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
        AccountMapper mapper = sqlSession.getMapper(AccountMapper.class);
        AccountMapper mapper2 = sqlSession2.getMapper(AccountMapper.class);
        Account account1 = mapper.selectByPrimaryKey(5);
        System.out.println(JSON.toJSONString(account1, true));
        System.out.println("========================================");
        Account account3 = mapper2.selectByPrimaryKey(5);
        System.out.println(JSON.toJSONString(account3, true));

一级缓存和二级缓存的区别
一级缓存
**Mybatis的一级缓存是指Session缓存。**一级缓存的作用域默认是一个SqlSession。Mybatis默认开启一级缓存。 实现在同一个会话中数据的共享
也就是在同一个SqlSession中,执行相同的查询SQL,**第一次会去数据库进行查询,并写到缓存中;
第二次以后是直接去缓存中取。
Statement级别的缓存,可以理解为缓存只对当前执行的这一个Statement有效,执行完后就会清空缓存
当执行SQL查询中间发生了增删改的操作,MyBatis会把SqlSession的缓存清空。
一级缓存的范围有SESSION和STATEMENT两种,默认是SESSION,如果不想使用一级缓存,可以把一级缓存的范围指定为STATEMENT,这样每次执行完一个Mapper中的语句后都会将一级缓存清除。
如果需要更改一级缓存的范围,可以在Mybatis的配置文件中,在下通过localCacheScope指定。
当Mybatis整合Spring后,直接通过Spring注入Mapper的形式,如果不是在同一个事务中每个Mapper的每次查询操作都对应一个全新的SqlSession实例,这个时候就不会有一级缓存的命中,但是在同一个事务中时共用的是同一个SqlSession。
如有需要可以启用二级缓存。

二级缓存
是指mapper映射文件,作用域是同一个namespace下的mapper映射文件内容,多个SqlSession共享。
SqlSessionFactory级别的缓存,实现不同会话中数据的共享,是一个全局变量
当开启缓存后,数据的查询执行的流程就是二级缓存-> 一级缓存 -> 数据库
Mybatis需要手动设置启动二级缓存。
二级缓存是默认启用的(要生效需要对每个Mapper进行配置),如想取消,则可以通过Mybatis配置文件中的元素下的子元素来指定cacheEnabled为false。

<settings>
  <setting name="cacheEnabled" value="false" />
</settings>

原文链接:https://blog.csdn.net/qq_26525215/article/details/79182637

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值