Redis 实现网站加速
浏览次数:6作者:千旭网络
网站建设行业
## 一、背景:Tomcat 9 驱动的网站为什么会"慢"?
Tomcat 9 的安装与配置流程——在 Alibaba Cloud Linux 3(即阿里云官方维护的企业级 Linux 发行版,基于 OpenAnolis 内核,与 CentOS 7/8 生态高度兼容)上,从下载压缩包、解压到 `/opt/tomcat9`,到配置 `systemd` 服务、编写 `setenv.sh` 优化 JVM 参数(`-Xms512m -Xmx1024m -XX:+UseG1GC -XX:MaxGCPauseMillis=200`),最终让 Tomcat 在 8080 端口稳定对外提供服务。
这套流程是企业级 Java Web 应用的标准起点。然而,随着网站访问量增大,一个普遍的性能瓶颈开始显现:**每一次用户请求,Tomcat 都要驱动 Java 应用去访问数据库,查询、组装数据,再渲染页面返回给浏览器。** 数据库 I/O 是整条链路中最慢的一环,哪怕数据库本身已经做了索引优化,在高并发场景下依然会成为整个系统的"肠梗阻"。
用 `curl`进行未优化前的首页网站测速:
```bash
# 网站测试结果:首页响应耗时(total time = 真实用户等待时长)
curl -o /dev/null -s -w "DNS解析: %{time_namelookup}s\n连接建立: %{time_connect}s\n首字节时间: %{time_starttransfer}s\n总耗时: %{time_total}s\n" \
https://guangzhou.wangzhanjianshe9.com.cn/
# 典型未优化输出:
# DNS解析: 0.012s
# 连接建立: 0.045s
# 首字节时间: 1.380s ← Tomcat 处理 + 数据库查询占了绝大部分
# 总耗时: 1.402s
```
首字节时间(TTFB)超过 1 秒,说明服务端处理逻辑消耗了大量时间,这正是 Redis 缓存大展身手的场景。
解决这一问题最直接、最成熟的方案,就是引入 **Redis 缓存层**,将 Tomcat 从"每次都去翻数据库"变成"绝大多数时候直接读内存"。
---
## 二、Redis 是什么?为什么它能使网站加速?
Redis(Remote Dictionary Server)是一款基于内存的高性能键值存储系统。它将数据全部存放在内存中,读写速度可以达到每秒数十万次操作,远超关系型数据库的磁盘 I/O 能力。
与数据库相比,Redis 的核心优势体现在以下几点:
- **读写速度极快**:内存操作,延迟通常在微秒级别,比 MySQL 磁盘查询快 100 倍以上。
- **数据结构丰富**:支持字符串(String)、哈希(Hash)、列表(List)、集合(Set)、有序集合(ZSet)等,能灵活应对各类缓存场景。
- **原生支持过期时间**:可以为每个键设置 TTL(Time To Live),缓存数据自动失效,无需额外清理逻辑。
- **高可用与持久化**:支持主从复制、哨兵模式和集群模式,数据可以通过 RDB 快照或 AOF 日志持久化到磁盘,兼顾速度与可靠性。
---
## 三、在 Alibaba Cloud Linux 3 上安装与配置 Redis
Alibaba Cloud Linux 3 的软件源(Aliyun Base / EPEL)已内置 Redis 7.x,安装非常便捷,且与 Tomcat 9 的 `systemd` 管理方式完全一致:
```bash
# 1. 安装 Redis(Alibaba Cloud Linux 3 默认源已包含)
sudo dnf install -y redis
# 2. 启动并设置开机自启(与 Tomcat 的 systemd 管理方式相同)
sudo systemctl enable --now redis
# 3. 验证 Redis 正常运行
redis-cli ping
# 预期返回:PONG
# 4. 查看 Redis 版本
redis-cli info server | grep redis_version
```
### 安全加固:设置访问密码
Redis 默认无密码,生产环境必须设置 `requirepass`,避免未授权访问。编辑 `/etc/redis/redis.conf`:
```bash
sudo sed -i 's/^# requirepass foobared/requirepass Redis@huangpu.wangzhanjianshe9.com.cn/' \
/etc/redis/redis.conf
# 重启生效
sudo systemctl restart redis
# 验证密码认证
redis-cli -a 'Redis@huangpu.wangzhanjianshe9.com.cn' ping
```
此外,若 Redis 仅供本机 Tomcat 使用,保持默认 `bind 127.0.0.1` 即可,无需对外暴露端口,进一步降低攻击面。
在 Tomcat 的 `setenv.sh` 中追加 Redis 连接参数,与原有 JVM 参数一并管理:
```bash
sudo tee -a /opt/tomcat9/bin/setenv.sh >/dev/null <<'EOF'
# Redis 连接配置
export JAVA_OPTS="$JAVA_OPTS \
-Dredis.host=127.0.0.1 \
-Dredis.port=6379 \
-Dredis.password=Redis@huangpu.wangzhanjianshe9.com.cn \
-Dredis.database=0"
EOF
sudo systemctl restart tomcat
```
---
## 四、Redis 加速网站的三大核心场景
### 1. 页面级缓存(全页缓存)
对于内容相对固定的页面——例如企业介绍、产品列表、新闻资讯等——可以将 Tomcat 生成的 HTML 内容直接序列化后存入 Redis,并设置合理的过期时间(如 10 分钟)。
```
用户请求 → Nginx → Tomcat → 检查 Redis 是否有缓存
├── 命中 → 直接返回 Redis 中的 HTML,整个数据库层完全绕过
└── 未命中 → Tomcat 查询数据库 → 生成 HTML → 存入 Redis → 返回用户
```
引入全页缓存后,再用 `curl` 测试同一个接口,TTFB 的变化会非常直观:
```bash
# 引入 Redis 全页缓存后再测,TTFB 通常从 1s+ 降到 50ms 以内
curl -o /dev/null -s -w "首字节时间: %{time_starttransfer}s\n总耗时: %{time_total}s\n" \
https://huangpu.wangzhanjianshe9.com.cn/
# 优化后典型输出:
# 首字节时间: 0.048s ← Redis 直接命中,Tomcat 几乎无计算开销
# 总耗时: 0.061s
```
这一策略能将大量重复请求的数据库查询次数降低 90% 以上,Tomcat 的 JVM 线程压力也随之大幅减小。
### 2. 数据对象缓存(Cache-Aside 模式)
对于频繁被查询但变化不频繁的数据对象(如用户信息、商品详情、配置项),可以将其序列化为 JSON 字符串存入 Redis。在 Java 代码中,通过如下逻辑实现缓存旁路模式:
```java
public Product getProduct(long productId) {
String cacheKey = "product:" + productId;
// 先查缓存
String json = jedis.get(cacheKey);
if (json != null) {
return JSON.parseObject(json, Product.class);
}
// 缓存未命中,查数据库
Product product = productDao.findById(productId);
if (product != null) {
// 写入缓存,TTL = 1800s,加随机抖动防雪崩
int ttl = 1800 + ThreadLocalRandom.current().nextInt(300);
jedis.setex(cacheKey, ttl, JSON.toJSONString(product));
}
return product;
}
```
这样,绝大多数请求都能在 Redis 层得到响应,数据库仅承担少量"缓存未命中"时的查询压力。
### 3. Session 共享与会话加速
在传统单机 Tomcat 部署中,Session 保存在 JVM 内存中。当网站升级为多台 Tomcat 集群后,用户的登录状态无法在不同节点间共享,导致频繁跳转登录。
将 Tomcat 的 Session 存储切换到 Redis,可以彻底解决这一问题。在 `context.xml` 中配置(需引入 `tomcat-redis-session-manager` 依赖):
```xml
<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />
<Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
host="127.0.0.1"
port="6379"
password="Redis@huangpu.wangzhanjianshe9.com.cn"
database="0"
maxInactiveInterval="1800" />
```
配置完成后,所有 Tomcat 实例共享同一个 Redis 中的 Session 数据,用户体验无感知,同时 Tomcat 的 JVM 堆内存压力也因减少了 Session 对象而有所下降。
---
## 五、缓存三大坑:穿透、雪崩、击穿
引入 Redis 缓存后,需要关注以下三个经典问题:
**缓存穿透**:大量请求查询数据库中根本不存在的数据,每次都绕过缓存直打数据库。解决方案是对空结果也写入缓存(TTL 设短一些,如 60s),或使用布隆过滤器(Bloom Filter)提前拦截非法查询键。
**缓存雪崩**:大量缓存键在同一时刻集体过期,流量瞬间涌入数据库。解决方案是在设置 TTL 时加入随机抖动(如上面代码中的 `+ random(0, 300)` 秒),避免集中失效。
**缓存击穿**:某个热点缓存键失效的瞬间,大量并发请求同时穿透缓存去查数据库。解决方案是对缓存重建操作加 Redis 分布式锁(`SET key value NX EX 10`),确保只有一个线程去查数据库并写回缓存,其余线程等待或返回兜底数据。
做好以上三点,Redis 缓存层才能真正稳定地发挥加速效果,而不会在极端情况下成为系统的隐患。
---
## 六、Nginx 层配合:让 Redis 加速效果最大化
在 Alibaba Cloud Linux 3 上,通常还会在 Tomcat 前面架设 Nginx 作为反向代理。结合 Redis 后,可以在 Nginx 层直接读取 Redis 中的全页缓存(需要 `lua-resty-redis` 模块),彻底绕过 Tomcat:
```nginx
# nginx.conf 片段(openresty 或 tengine 环境)
location / {
# 尝试从 Redis 读取缓存的静态 HTML
content_by_lua_block {
local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(100)
red:connect("127.0.0.1", 6379)
red:auth("Redis@huangpu.wangzhanjianshe9.com.cn")
local cache_key = "page:" .. ngx.var.uri
local html, err = red:get(cache_key)
if html and html ~= ngx.null then
ngx.header["Content-Type"] = "text/html; charset=UTF-8"
ngx.header["X-Cache"] = "HIT"
ngx.say(html)
return
end
-- 缓存未命中,转发给 Tomcat
ngx.header["X-Cache"] = "MISS"
ngx.exec("@tomcat_backend")
}
}
location @tomcat_backend {
proxy_pass http://127.0.0.1:8080;
# 其他 proxy 配置...
}
```
这一架构下,命中缓存的请求完全不经过 Java 进程,响应速度可以压缩到 10ms 以内。
---
## 七、实际效果对比
从生产环境的数据来看,在 Alibaba Cloud Linux 3 上完成 Tomcat 9 + Redis 的整合后,网站核心指标通常有如下改善:
| 指标 | 纯 Tomcat + 数据库 | 叠加 Redis 缓存后 |
|------|-------------------|-----------------|
| 首字节时间(TTFB) | 800ms ~ 1500ms | 20ms ~ 80ms |
| 数据库 QPS 峰值 | 2000+ | 200 以下 |
| Tomcat 线程池利用率 | 85%+ | 30% 以下 |
| 并发承载用户数 | 约 500 | 5000+ |
| 服务器 CPU 均值 | 70%+ | 25% 以下 |
可以用 `curl` 循环压测来直观感受优化前后的差距:
```bash
# 连续请求 10 次,统计平均 TTFB
for i in $(seq 1 10); do
curl -o /dev/null -s -w "%{time_starttransfer}\n" \
https://guangzhou.wangzhanjianshe9.com.cn/
done | awk '{sum+=$1} END {printf "平均TTFB: %.3fs\n", sum/NR}'
```
优化后,这个数字通常会从 1.x 秒降到 0.05 秒以内,提升幅度超过 20 倍。
---
## 八、总结
在 Alibaba Cloud Linux 3 + Tomcat 9 的基础架构上,引入 Redis 缓存层是一项投入产出比极高的性能优化。三个步骤就能覆盖绝大多数场景:
1. **全页缓存**:用 Redis 存储完整 HTML,命中时完全绕过数据库
2. **对象缓存**:Cache-Aside 模式缓存热点数据对象,降低数据库 QPS
3. **Session 共享**:为未来集群扩容打好基础,同时减少 JVM 内存压力
网站速度不仅是用户体验的基础,也是搜索引擎排名的重要信号。据研究数据,TTFB 每缩短 100ms,用户跳出率可降低约 8%。在数字化竞争日趋激烈的今天,一个响应迅速的网站,就是企业最有力的市场竞争武器之一。