前言
部门培训的时候让我讲缓存,然而平时用缓存也比较少,这边特意整理下相关的资料,仅概念性的,不深入
一、什么是缓存
缓存就是数据交换的缓冲区,位于速度相差较大的两种硬件/软件之间的,用于协调两者数据传输速度差异的结构。
软件中的缓存就是指,将会被频繁使用的数据保存到内存上,加快读取速度。
二、为什么要使用缓存
- 减少交互的通讯量——缓存数据能有效减少在进程和机器间的传输量
- 降低系统中的处理量——减少处理次数
- 降低需要做的磁盘访问次数——比如缓存在内存中的数据
IO的读写速度相对内存来说是比较慢的,通常一个web应用的瓶颈就出现在磁盘IO的读写上。
一般情况下,一个网站或者应用的形式是这样的,用户的请求通过用户层来到业务层,业务层再从数据层获取数据,返回给用户层。在用户量和数据量不大的情况下,这个系统运行得很顺畅。但是随着用户量越来越大,数据库中的数据越来越多,系统的响应速度就越来越慢。系统的瓶颈一般都在数据库访问上。
那么,如果我们在内存中建立一个存储区,将数据缓存起来,当浏览器端由请求到达的时候,直接从内存中获取相应的数据,这样一来可以降低服务器的压力,二来,可以提高请求的响应速度,提升用户体验。
综上,使用缓存是为了提高系统运行速度,将用户频繁访问的内容存放在访问速度快的地方,来提高系统的响应速度。
三、缓存的属性
-
命中率
命中率是指请求缓存次数和缓存返回正确结果次数的比例,比例越高,就证明缓存的使用率越高。 -
最大元素
缓存中可以存放得最大元素得数量,一旦缓存中元素数量超过这个值,那么将会起用缓存清空策略,根据不同的场景合理的设置最大元素值往往可以一定程度上提高缓存的命中率,从而更有效的时候缓存。 -
清空策略
- FIFO ,first in first out ,最先进入缓存得数据在缓存空间不够情况下被首先清理出去。
- LFU , Less Frequently Used ,一直以来最少被使用的元素会被被清理掉。这就要求缓存的元素有一个hit 属性,在缓存空间不够得情况下,hit 值最小的将会被清出缓存。
- LRU ,Least Recently Used ,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
四、哪些数据需要被缓存
查询比较高的热点数据、可以允许丢失的。
比如:平台管理中的平台配置、配置文件里的配置项、热门文章、点赞、阅读数等。
五、实现缓存的方式
java应用的缓存分两种,一是进程内缓存,就是使用java应用的虚拟机内存来进行缓存;另一个是进程外缓存,比如:redis。
相比较而言,进程内缓存比进程外缓存快很多,而且编码也简单;但是,进程内缓存的存储量有限,使用的是java应用虚拟机的内存,而且每个应用都要存储一份,有一定的资源浪费。进程外缓存相比进程内缓存,会慢些,但是,存储空间可以横向扩展,不受限制。
5.1 进程内缓存
Ehcache
Cacheonix
ASimpleCache
JBoss Cache
Voldemort
5.2 进程外缓存
Redis
Mencached
六、ehcache
EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider。
主要的特性有:
- 快速、简单,提供多种缓存策略
- 缓存数据有两级:内存和磁盘,因此无需担心容量问题
- 缓存数据会在虚拟机重启的过程中写入磁盘
- 可以通过RMI、可插入API等方式进行分布式缓存
- 具有缓存和缓存管理器的侦听接口
- 支持多缓存管理器实例,以一个实例的多个缓存区域
七、Redis
redis是一个远程内存数据库,可以存储键(key)与5种不同类型的值(value)之间的映射,可以将存储在内存中的键值对数据持久化到硬盘,可以使用复制特性扩展读性能,还可以使用客户端分片来扩展写性能。
主要的特性有:
- redis的数据完全存储在内存中,磁盘只用于持久性,所以redis的速度非常快;
- redis拥有较为丰富的数据类型;
- redis的操作都是原子性的,所以在异步的时候也是安全的;
- redis可以将数据复制到任意数量的从机。
7.1 redis数据类型
结构类型 | 结构存储的值 | 结构的读写能力 |
---|---|---|
STRING | 可以是字符串、整数或者浮点数 | 对整个字符串或者字符串的其中一部分执行操作;对整数和浮点数执行自增或者自减 |
LIST | 一个链表,链表上的每个节点都包含了一个字符串 | 从链表的两端推入或者弹出元素;根据偏移量对链表进行修剪;读取单个或者多个元素;根据值查找或者移除元素 |
SET | 包含字符串的无序收集器,并且被包含的每个字符串都是独一无二、各不相同的 | 添加、获取、移除单个元素;检查一个元素是否存在于集合中;计算交集、并集、差集;从集合里面随机获取元素 |
HASH | 包含键值对的无序散列表 | 添加、获取、移除单个键值对;获取所有键值对 |
ZSET | 字符串成员与浮点数分值之间的有序映射,元素的排列顺序由分值的大小决定 | 添加、获取、删除单个元素;根据分值范围或者成员来获取元素 |
7.2 使用场景
STRING
String是最常用的一种数据类型,普通的key/value存储都可以使用此类型。比如分布式系统下,用户登录信息的共享,使用userguid
键 | 值 |
---|---|
userid | token |
LIST
List就是链表,可以存储有先后顺序的数据,比如:文章列表、最新消息。也可以基于此实现消息队列。
键 | 值 |
---|---|
msglist | {msg1, msg2,...} |
SET
与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择。比如:用户关注
键 | 值 |
---|---|
userid | [followid1, followid2,...] |
HASH
存储一些结构化的数据,比如:用户信息
键 | 值 |
---|---|
userid | {"name":"n", "age":"20"} |
ZSET
sorted set的使用场景与set类似,区别是set不是自动有序的,而sorted set可以通过用户额外提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即自动排序。当你需要一个有序的并且不重复的集合列表,那么可以选择sorted set数据结构,比如:文章热度排行
键 | 值 |
---|---|
hot_article | [(id1, 20), (id2, 30),...] |
网友评论