前言
用Docker跑LNMP环境的人不少,但很多人装完就完事了——Nginx、MySQL、PHP-FPM跑起来,网站能访问就收工。殊不知,少了Redis这一层缓存,你的网站在面对真实流量时,数据库压力会非常大。今天这篇文章,手把手教你在Docker LNMP环境中集成Redis缓存,让网站响应速度和并发能力上一个台阶。
为什么LNMP需要加Redis
LNMP架构中,PHP每次处理请求都要查MySQL数据库。访问量一大,数据库就成了瓶颈。Redis作为内存级缓存,能把热点数据放在内存里,PHP直接从Redis读数据,不再每次都打数据库。
实际效果:
- 数据库查询量减少70%~90%
- 页面响应时间从几百毫秒降到几十毫秒
- MySQL并发连接数压力大幅降低
- 整体QPS提升明显
环境准备
在开始之前,确保你已经有一个跑起来的Docker LNMP环境。如果还没有,可以参考之前的Docker部署LNMP环境教程搭建基础环境。
本文基于以下环境:
- 操作系统:Ubuntu 20.04/22.04
- Docker + Docker Compose
- 已有的LNMP容器:Nginx + MySQL 8.0 + PHP 8.x-FPM
第一步:修改docker-compose.yml添加Redis服务
在你的docker-compose.yml文件中,追加Redis服务定义:
version: '3.8'
services:
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d
- ./www:/var/www/html
depends_on:
- php
php:
image: php:8.2-fpm
volumes:
- ./www:/var/www/html
depends_on:
- mysql
- redis
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: your_password
MYSQL_DATABASE: your_database
volumes:
- mysql_data:/var/lib/mysql
redis:
image: redis:7-alpine
container_name: lnmp-redis
restart: always
ports:
- "6379:6379"
volumes:
- redis_data:/data
command: redis-server --appendonly yes --requirepass your_redis_password
volumes:
mysql_data:
redis_data:
几个关键配置说明:
- appendonly yes:开启AOF持久化,Redis重启后数据不丢失
- requirepass:设置访问密码,不要在生产环境裸奔
- redis_data:数据持久化到Docker卷,容器重建数据不丢
- alpine:用alpine版镜像,体积小,启动快
第二步:PHP安装Redis扩展
PHP默认不带Redis扩展,需要手动安装。推荐做法是自定义PHP镜像:
创建文件 Dockerfile-php:
FROM php:8.2-fpm
RUN apt-get update && apt-get install -y \
libpng-dev \
libzip-dev \
&& docker-php-ext-install pdo_mysql mysqli gd zip \
&& pecl install redis \
&& docker-php-ext-enable redis
然后在docker-compose.yml中,把PHP服务改成:
php:
build:
context: .
dockerfile: Dockerfile-php
volumes:
- ./www:/var/www/html
重新构建并启动:
docker-compose build php
docker-compose up -d
验证Redis扩展是否安装成功:
docker exec lnmp-php php -m | grep redis
输出 redis 就说明OK了。
第三步:PHP中连接Redis并使用
建一个测试文件 www/redis_test.php:
<?php
$redis = new Redis();
$redis->connect('redis', 6379);
$redis->auth('your_redis_password');
// 写入测试
$redis->set('test_key', 'Hello Redis in Docker LNMP', 3600);
echo $redis->get('test_key');
// 测试性能
$start = microtime(true);
for ($i = 0; $i < 10000; $i++) {
$redis->set("bench_$i", "value_$i");
}
$end = microtime(true);
echo "\n写入10000条耗时: " . round(($end - $start) * 1000, 2) . "ms";
?>
访问 http://your-server/redis_test.php,如果能看到输出就说明Redis连接正常。
第四步:实战配置——数据库查询缓存
光能连Redis还不够,关键是把缓存用到实际业务里。下面是一个通用的数据库查询缓存封装:
<?php
class RedisCache {
private $redis;
private $prefix = 'cache:';
private $ttl = 3600; // 默认缓存1小时
public function __construct() {
$this->redis = new Redis();
$this->redis->connect('redis', 6379);
$this->redis->auth('your_redis_password');
}
// 获取缓存,缓存未命中则查询数据库并写入
public function remember($key, $callback, $ttl = null) {
$cacheKey = $this->prefix . md5($key);
$data = $this->redis->get($cacheKey);
if ($data !== false) {
return json_decode($data, true);
}
$result = $callback();
$this->redis->setex($cacheKey, $ttl ?? $this->ttl, json_encode($result));
return $result;
}
// 手动清除缓存
public function forget($key) {
$this->redis->del($this->prefix . md5($key));
}
// 按前缀批量清除
public function flushByPrefix($prefix) {
$keys = $this->redis->keys($this->prefix . $prefix . '*');
if (!empty($keys)) {
$this->redis->del($keys);
}
}
}
// 使用示例
$cache = new RedisCache();
// 文章列表缓存
$articles = $cache->remember('article_list_page_1', function() {
global $pdo;
$stmt = $pdo->query("SELECT * FROM articles ORDER BY id DESC LIMIT 20");
return $stmt->fetchAll(PDO::FETCH_ASSOC);
});
// 数据更新后清除缓存
$cache->forget('article_list_page_1');
?>
第五步:Session存储到Redis
PHP默认把Session存到文件,多容器环境下不好共享。改成Redis存储很简单:
在PHP配置中添加(php.ini 或代码中设置):
session.save_handler = redis
session.save_path = "tcp://redis:6379?auth=your_redis_password"
或者在你的PHP入口文件中动态设置:
<?php
ini_set('session.save_handler', 'redis');
ini_set('session.save_path', 'tcp://redis:6379?auth=your_redis_password');
session_start();
?>
这样Session就存在Redis里了,多台PHP-FPM容器也能共享Session,方便后续做负载均衡。
Redis常用缓存策略
根据不同场景选择合适的缓存策略:
1. 主动缓存(Cache Aside)
最常用的模式。先查缓存,没有再查数据库,查到后写入缓存。上面的remember方法就是这个模式。适合读多写少的场景。
2. 过期时间策略
给缓存设TTL,到期自动失效。不同数据设不同过期时间:
- 热点文章列表:5~15分钟
- 用户信息:30分钟
- 配置项:1~2小时
- 统计数据:可适当延长
3. 主动失效
数据更新时主动删缓存,保证一致性。上面示例中的forget方法就是这样用的。
性能调优建议
Redis配置调优:
- maxmemory:设置最大内存限制,防止Redis吃满内存。建议设为系统总内存的50%~70%,例如
--maxmemory 2gb - maxmemory-policy:内存满时的淘汰策略,推荐
allkeys-lru(删除最近最少使用的key) - tcp-keepalive:保持TCP连接,避免频繁重建连接,设为60秒
- timeout 0:不主动断开空闲连接
docker-compose.yml中Redis的command改为:
command: >
redis-server
--appendonly yes
--requirepass your_redis_password
--maxmemory 2gb
--maxmemory-policy allkeys-lru
--tcp-keepalive 60
常见问题排查
1. PHP连不上Redis
检查容器网络:确保PHP容器和Redis容器在同一个Docker网络中。docker-compose默认会把所有服务放到同一个网络,通常不会有问题。如果连不上,检查container_name和连接地址是否一致。
2. Redis重启后数据丢失
确认appendonly已开启,且数据卷redis_data正常挂载。可以用 docker volume inspect 检查卷挂载情况。
3. 内存占用持续增长
设置maxmemory和maxmemory-policy,让Redis在内存满时自动淘汰旧数据。同时检查是否有设置过期时间的key没有正确设置TTL。
总结
在Docker LNMP环境中加入Redis缓存,改动不大但效果明显。核心就三步:加Redis服务、装PHP扩展、写缓存逻辑。做好持久化和内存管理,生产环境跑起来也很稳。如果你的网站已经开始有并发压力,Redis这一步建议尽早加上。
版权声明
本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论