黑马程序员Redis教程学习笔记(第1部分):多级缓存与JVM进程缓存
课程概述
本篇笔记涵盖黑马程序员Redis教程中关于多级缓存的几个重要章节,从多级缓存的概念入手,逐步深入到JVM进程缓存的实现,再到Lua语法的基础知识。这是Redis高级应用的重要组成部分。
1. 多级缓存概念与架构
传统缓存的问题
在传统的缓存架构中,用户请求需要经过Tomcat服务器处理,Tomcat再查询Redis缓存,如果未命中才访问数据库。这种架构存在两个主要问题:
- 瓶颈问题:Tomcat的并发能力不如Redis,成为整个系统的瓶颈
- 冲击问题:当Redis缓存失效或挂掉时,所有请求直接打到数据库,对数据库造成巨大冲击
多级缓存架构
多级缓存充分利用请求处理的每一个环节,通过以下层级实现缓存: 1. 浏览器客户端缓存:静态资源缓存在本地 2. NGX本地缓存:在NGX服务器上实现缓存 3. Redis缓存:分布式缓存 4. Tomcat进程缓存:JVM进程内的缓存
这种架构的优势在于: - 大多数请求由NGX处理,减轻Tomcat压力 - 当Redis缓存失效时,还有Tomcat进程缓存作为缓冲
2. JVM进程缓存 - Caffeine
分布式缓存 vs 进程缓存
- 分布式缓存(Redis):
- 优点:可在集群间共享,存储容量大,可靠性高
- 缺点:需要网络请求,存在网络延迟
- 进程缓存(Caffeine):
- 优点:直接读取本地内存,速度快
- 缺点:无法在多台服务器间共享,容量受限于JVM内存,服务重启数据丢失
Caffeine介绍
Caffeine是一个基于Java 8开发的高性能本地缓存库,Spring内部的缓存很多使用的就是Caffeine。它提供了近乎最佳命中率的本地缓存解决方案。
基本用法
// 创建缓存对象
Cache<String, String> cache = Caffeine.newBuilder()
.build();
// 存入数据
cache.put("key", "value");
// 获取数据(如果不存在返回null)
String value = cache.getIfPresent("key");
// 获取数据(如果不存在则从数据库加载并存入缓存)
String result = cache.get("key", key -> {
// 模拟从数据库查询
return queryFromDatabase(key);
});缓存驱逐策略
- 基于容量驱逐:设置缓存上限,超过后采用LRU策略清理
- 基于时间驱逐:设置过期时间,超过时间后自动清理
- 基于引用驱逐:利用Java GC机制回收数据(不推荐使用)
实现商品查询的JVM进程缓存
缓存配置
@Configuration
public class CacheConfig {
@Bean
public Cache<Long, Item> itemCache() {
return Caffeine.newBuilder()
.initialCapacity(100)
.maximumSize(10_000)
.build();
}
@Bean
public Cache<Long, ItemStock> stockCache() {
return Caffeine.newBuilder()
.initialCapacity(100)
.maximumSize(10_000)
.build();
}
}在Controller中使用缓存
@RestController
@RequestMapping("/item")
public class ItemController {
@Autowired
private Cache<Long, Item> itemCache;
@Autowired
private Cache<Long, ItemStock> stockCache;
// 根据ID查询商品,使用缓存
@GetMapping("/{id}")
public Item queryItemById(@PathVariable("id") Long id) {
return itemCache.get(id, key -> {
// 缓存未命中,查询数据库
return itemService.queryItemById(key);
});
}
// 根据ID查询库存,使用缓存
@GetMapping("/stock/{id}")
public ItemStock queryStockById(@PathVariable("id") Long id) {
return stockCache.get(id, key -> {
// 缓存未命中,查询数据库
return itemStockService.queryStockById(key);
});
}
}3. Lua语法基础
Lua简介
Lua是一种轻量级的脚本语言,底层使用C语言编写,设计目的是为了嵌入应用程序中。在我们的多级缓存架构中,NGX服务器将使用Lua编写业务逻辑。
数据类型
- nil:代表无效值,也可代表false
- boolean:布尔类型,true或false
- number:数值类型(整数、小数统一为number)
- string:字符串类型(双引号或单引号)
- function:函数类型
- table:表类型(类似Java中的Map,既可表示数组也可表示Map)
类型判断
使用type()函数判断变量的数据类型:
print(type("hello")) -- 输出: string
print(type(123)) -- 输出: number
print(type(true)) -- 输出: boolean变量声明
-- 局部变量
local str = 'hello'
local num = 123
local bool = true
-- 数组(table形式)
local arr = {'hello', 'world', 'java'}
-- Map(key-value结构的table)
local map = {name='Jack', age=21}访问Table元素
-- 访问数组元素(注意索引从1开始)
arr[1] -- 'hello'
-- 访问Map元素
map['name'] -- 'Jack'
map.name -- 'Jack'循环遍历
-- 遍历数组
for index, value in ipairs(arr) do
print(index, value)
end
-- 遍历Map
for key, value in pairs(map) do
print(key, value)
end总结
本篇笔记介绍了多级缓存的概念、JVM进程缓存的实现以及Lua语法基础。多级缓存通过在请求处理的各个环节都添加缓存,有效减轻了数据库压力并提升了系统性能。Caffeine作为JVM进程缓存的实现,提供了高效的本地缓存解决方案。而Lua语言将在NGX层实现业务逻辑,为多级缓存架构的重要组成部分。