从 Nginx 配置到 Memcached 页面缓存:一次服务器崩溃后的完整踩坑记录

从 Nginx 配置到 Memcached 页面缓存:一次服务器崩溃后的完整踩坑记录 保姆级实操Nginx重定向防盗链PHP8编译负载均衡Memcached页面缓存全流程很多刚接触服务端运维的朋友学完Nginx基础配置后想上手进阶实战却经常卡在编译依赖报错、配置不生效、环境崩溃不知道怎么补救这些问题上。这篇博客就把一次完整的服务端进阶实验全流程拆解开来从301重定向、图片防盗链这类常用配置到PHP 8.3源码编译、Nginx模块热升级再到负载均衡会话保持、Memcached全页面缓存一步一步带大家走通完整链路。中途还遇到了服务器意外崩溃的小事故也顺便把环境迁移、应急重建的思路分享出来不管是做课程实验还是入门生产环境运维都能直接参考。前置环境说明操作系统CentOS 7实验节点server2前期主节点负责基础配置与PHP环境搭建、server7后期迁移节点负责负载均衡与缓存功能落地核心软件版本Nginx 1.28.3server2/ Nginx 1.24.0server7、PHP 8.3.32、OpenSSL 1.1.1w、Memcached 1.x前置条件两台机器均已关闭防火墙与SELinux配置好国内yum源安装了gcc、make等基础编译工具一、基础配置阶段server2 上的 Nginx 进阶与 PHP 部署1.1 Nginx 301 重定向路径统一跳转至子域名需求背景把主站shturl.cc下所有/bbs开头的请求永久重定向到bbs.shturl.cc子域名既做路径规整也能保证SEO权重的正常转移。我们先进入Nginx配置目录用vim打开主配置文件vim/usr/local/nginx/conf/nginx.conf在主站的server块中添加两条rewrite规则编辑完成后按Esc输入:wq保存并退出。这里写两条规则是为了覆盖所有场景rewrite ^/bbs$ http://bbs.shturl.cc permanent;精准匹配裸路径/bbs直接跳转到子域名首页rewrite ^/bbs/(.*)$ http://bbs.shturl.cc/$1 permanent;匹配/bbs/开头的所有路径$1捕获原路径后缀保证/bbs/index.html能正确跳转到对应页面末尾的permanent代表301永久重定向区别于302临时重定向更利于搜索引擎收录权重转移。修改完配置后必须先执行配置语法检查这是所有Nginx配置修改后的必做操作能避免配置写错导致服务重启失败/usr/local/nginx/sbin/nginx-t看到syntax is ok和test is successful的提示说明配置没有语法错误再执行平滑重载服务不会中断新配置直接生效/usr/local/nginx/sbin/nginx-sreload最后用curl工具测试验证-I参数表示只查看响应头curl-Ishturl.cc/bbs可以看到返回301状态码Location头已经正确指向子域名地址重定向配置生效。完整的nginx.conf主配置结构如下包含events块、http全局块、主站server块、bbs分站server块四个部分重定向规则和后续的防盗链配置都写在主站server块中。1.2 图片防盗链实现从基础拦截到友好提示核心原理通过Nginx的valid_referers指令校验请求头中的Referer字段只放行白名单内的来源阻止其他站点直接引用本站图片、白白消耗服务器带宽。第一步准备测试资源我们的站点根目录为/web2如果目录不存在需要先创建mkdir-p/web2用find命令在root目录下全局查找jpg格式的测试图片find/root-name*.jpg找到图片后用mv命令移动到站点目录并重命名方便后续测试访问mv/root/nginx-1.28.3/4aab6ffd40248617e89118f14dee480.jpg /web2/test.jpg用ls命令确认文件已经成功放入站点目录。方案一非法请求直接返回 403这是最基础的防盗链方案直接在主站server块中添加一个location块正则匹配所有jpg、png格式的图片请求location ~ \.(jpg|png)$ { root /web2; valid_referers none blocked shturl.cc; if ($invalid_referer) { return 403; } }这里逐行解释配置含义valid_referers定义合法的来源白名单none允许空Referer请求也就是用户直接在浏览器地址栏访问图片地址blocked允许被隐藏/篡改的Referer避免误伤正常用户shturl.cc本站域名站内引用的图片正常放行$invalid_refererNginx内置变量请求来源不在白名单内时为真此时返回403拒绝访问配置完成后同样先检查语法、重载服务然后分三轮测试验证效果直接访问图片地址 → 返回200 OK ✅携带本站Referer模拟站内访问 → 返回200 OK ✅携带百度Referer模拟盗链请求 → 返回403 Forbidden ✅方案二返回防盗提示图更友好直接返回403会让盗链页面出现裂图体验比较生硬。优化方案是盗链请求不返回错误而是返回一张提前准备好的防盗提示图既阻止了原图被盗用还能做品牌提示。先准备第二张提示图用find命令过滤掉已有的test.jpg找到第二张图片后移动到站点目录命名为daolian.jpgfind/root-name*.jpg|grep-vtest.jpgmv/root/771c18b8d83b356210efe2dc60bf6d9c.jpg /web2/daolian.jpg然后修改防盗链location块把return 403替换为重定向规则让非法请求直接返回提示图。修改完成后检查语法、重载生效。再次用百度Referer测试此时状态码变为200但Content-Length明显小于原图说明返回的已经不是原图而是我们的防盗提示图效果符合预期。1.3 OpenSSL 升级为 PHP 8.3 编译铺路问题背景CentOS 7默认yum源中的OpenSSL版本为1.0.2k而PHP 8.3要求OpenSSL最低版本为1.1.1版本不满足的话PHP预编译阶段会直接报错终止因此必须手动编译高版本OpenSSL。先安装epel扩展源它提供了很多默认源没有的软件包和依赖后续编译会经常用到yuminstall-yepel-release这里有个小插曲原本想升级cmake工具做个软链接统一命令结果发现系统已经自带了cmake。查看版本后确认2.8.12.2足够编译OpenSSL就没有额外升级直接进入源码编译步骤。先解压OpenSSL源码包进入源码目录tarzxf openssl-1.1.1w.tar.gzcdopenssl-1.1.1w执行预编译配置指定安装路径和编译参数./config--prefix/usr/local/openssl shared zlib参数说明--prefix/usr/local/openssl指定安装目录独立存放不污染系统自带版本shared编译生成动态链接库不然后续PHP无法链接调用zlib启用zlib压缩支持配置完成后执行编译安装这一步耗时较长耐心等待即可makemakeinstall重点注意编译安装完成后还需要配置系统动态链接库。系统默认不会去/usr/local/openssl/lib目录查找库文件需要手动把路径加入配置再刷新缓存echo/usr/local/openssl/lib/etc/ld.so.conf ldconfig这一步非常容易遗漏漏掉的话即使OpenSSL编译成功PHP也会提示找不到OpenSSL库。1.4 PHP 8.3.32 源码编译与 FPM 部署OpenSSL环境就绪后正式开始编译PHP。我们把日常开发常用的扩展一次性编入避免后续缺功能还要重新编译。先解压PHP源码包进入源码目录tarzxf php-8.3.32.tar.gzcdphp-8.3.32执行预编译配置参数较多我们逐组说明./configure\--prefix/usr/local/php\--with-config-file-path/usr/local/php/etc\--enable-fpm\--with-fpm-usernginx\--with-fpm-groupnginx\--with-openssl/usr/local/openssl\--with-zip\--enable-mbstring\--enable-pdo\--with-pdo-mysql\--with-mysqli\--with-gd\--with-curl\--enable-bcmath\--enable-sockets核心参数含义基础路径类指定安装目录、配置文件路径FPM相关开启PHP-FPM模式指定进程运行用户与用户组和Nginx保持一致避免权限问题依赖类关联我们手动编译的OpenSSL路径扩展类开启压缩、多字节字符串、数据库连接、图像处理、网络请求等常用扩展预编译通过后执行完整编译与安装PHP编译耗时较长通常需要10-20分钟取决于机器性能makemakeinstall编译完成后开始配置服务与配置文件复制开发版php.ini配置模板到配置目录开发版错误显示更全面适合实验环境复制PHP-FPM主配置文件、进程池配置文件复制systemd服务文件到系统服务目录方便用systemctl管理服务执行systemctl daemon-reload让系统识别新添加的服务创建nginx运行用户提示已存在属于正常现象——安装Nginx时已经创建过同名用户执行php-fpm -t测试配置确认语法无误最后启动PHP-FPM服务并设置开机自启systemctl start php-fpm systemctlenablephp-fpm用ss命令查看9000端口PHP-FPM默认监听端口看到LISTEN状态且有多个fpm子进程在运行说明PHP环境部署完成。二、环境迁移阶段server2 崩溃后在 server7 重建环境就在准备继续做Memcached扩展和页面缓存的时候server2虚拟机突然出现内核报错终端完全无响应强制重启也无法进入系统。判断是环境配置混乱导致的系统崩溃与其花一两个小时排查修复不如直接切换到备用的server7节点重建后半段环境效率更高。这里也提醒大家做实验时重要配置随时备份关键节点拍虚拟机快照能省很多麻烦。2.1 迁移准备确认环境与传输扩展包server7上已经提前部署好了基础的Nginx和PHP环境核心功能兼容不影响后续实验。先用ls命令查看root目录下的源码包和模块包确认需要的文件都在。再通过scp命令从另一台备用机器把memcache扩展包传输过来scproot192.168.241.136:/root/memcache-8.2.tgz /root/scp基于SSH协议传输安全可靠输入对方root密码即可完成传输。传输完成后解压扩展包tarzxf memcache-8.2.tgz2.2 编译安装 PHP memcache 扩展要实现Nginx页面缓存需要PHP加载memcache扩展来和Memcached服务交互同时也方便后续做程序级的缓存测试。PHP扩展编译有标准流程第一步先执行phpize生成configure配置文件它是PHP自带的扩展编译工具必须在扩展源码目录下执行cdmemcache-8.2 /usr/local/php/bin/phpize接下来执行预编译、编译安装./configure --with-php-config/usr/local/php/bin/php-configmakemakeinstall安装完成后扩展文件会自动放到PHP的扩展目录下。经典踩坑点很多人编译完就以为扩展生效了结果php -m看不到就是因为php.ini里没有开启扩展。我们先grep查看配置文件中的memcache项能看到默认前面有分号处于注释状态。这里不用手动打开vim编辑直接用sed命令批量替换注释符高效又不容易出错sed-is/;extensionmemcache.so/extensionmemcache.so//usr/local/php/etc/php.ini修改完php.ini必须重启PHP-FPM才会生效因为PHP-FPM是常驻进程配置不会热加载killallphp-fpm /usr/local/php/sbin/php-fpm最后用php -m | grep memcache验证看到输出memcache说明扩展加载成功。2.3 Nginx 热升级平滑新增功能模块为什么用热升级而不是重新安装生产环境中Nginx承载着业务直接重装会导致服务中断热升级可以做到几乎无感的模块更新服务中断时间只有几秒甚至更短。server7原有Nginx只编译了sticky会话保持模块要做页面缓存还需要新增echo、memc、srcache三个模块。热升级步骤如下进入Nginx源码目录重新执行./configure必须把原有模块和新增模块全部写上不然会覆盖原有功能./configure--prefix/usr/local/nginx\--add-module../nginx_sticky_module_ng-0.0.2\--add-module../echo-nginx-module-master\--add-module../memc-nginx-module-master\--add-module../srcache-nginx-module-master配置完成后可以看到配置摘要确认PCRE、zlib都正常识别模块全部加载成功。执行make编译千万不要执行make install这是最容易踩的坑make install会直接覆盖整个Nginx安装目录导致配置和站点数据丢失。备份原有二进制文件生产环境必做实验环境也建议养成习惯cp/usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.bak优雅停止Nginx用新编译的二进制文件覆盖旧文件再重新启动服务/usr/local/nginx/sbin/nginx-sstopcpobjs/nginx /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx最后用nginx -V查看编译参数确认四个模块都已经成功编入。2.4 Memcached 服务部署与连通验证Memcached是高性能的分布式内存缓存系统数据全部存在内存中读取速度极快非常适合做页面缓存。安装非常简单直接用yum安装即可yuminstall-ymemcached启动服务并设置开机自启systemctlenable--nowmemcached用netstat查看11211端口Memcached默认端口看到tcp和tcp6都处于LISTEN状态说明服务运行正常。此时再确认PHP的memcache扩展正常加载Nginx的缓存模块全部就绪三者环境连通就可以开始配置核心功能了。三、核心功能阶段负载均衡与页面缓存落地3.1 负载均衡 Sticky 会话保持负载均衡的作用是把请求分发到多台后端服务器分摊访问压力同时提高服务可用性一台服务器挂了还有其他节点可以承接流量。在nginx.conf的http块中添加upstream负载池配置upstream backend { sticky; server 192.168.241.137:80; server 192.168.241.xxx:80; }配置说明sticky开启粘性会话Nginx会给客户端种下一个route cookie后续同一个客户端的请求都会分发到同一台后端适合有登录状态的业务避免出现登录后突然掉线的问题两行server为后端服务器地址默认采用轮询调度算法依次分发请求随后在对应的虚拟主机server块中配置location规则用proxy_pass把请求转发到负载池。配置完成后检查语法、重载生效。测试时用curl携带Host头模拟域名访问因为没有配置DNS解析手动指定Host头就能访问对应的虚拟主机。连续发送两次请求可以看到分别落到了不同的后端节点同时响应头中都带有Set-Cookie: routexxx说明sticky会话保持生效。最后用ab工具做简单的性能压测ab是最常用的HTTP压测工具轻量易用。ab-c10-n1000-HHost: lb.shturl.cchttp://127.0.0.1/参数含义-c 10并发数10模拟10个用户同时访问-n 1000总请求数1000次-H指定请求头和测试的域名保持一致压测结果中重点看Requests per second每秒请求数即QPS静态页面下能达到两万六千多平均响应时间不到0.4毫秒Nginx的性能表现非常优异。3.2 Nginx Memcached 全页面缓存这是本次实验最核心的功能实现全页面缓存后缓存命中的请求无需转发到后端Nginx直接从Memcached中读取数据返回性能提升非常显著。实现原理请求到达Nginxsrcache_fetch模块先去Memcached中查询是否有对应key的缓存如果缓存命中HIT直接把缓存内容返回给用户请求结束如果缓存未命中MISS请求继续转发到后端服务器处理后端返回响应后srcache_store模块把响应内容存入Memcached并设置过期时间下一次相同请求到达时就能直接命中缓存配置核心注意点存取缓存的key必须完全一致一般用$request_method$request_uri作为key即请求方式请求地址保证不同页面对应不同缓存只缓存GET请求不缓存POST请求POST请求用于提交数据每次内容都不相同没有缓存价值设置合理的缓存过期时间避免内容更新后缓存长期不刷新功能测试先清空Memcached中的所有旧缓存避免影响测试结果用printf配合nc命令发送清空指令printfflush_all\r\n|nc127.0.0.111211第一次访问测试页面响应头显示X-SRCache-Fetch: MISS、X-SRCache-Store: STORE说明没有命中缓存且响应内容已经成功存入Memcached。第二次访问同一个页面响应头变为X-SRCache-Fetch: HIT、X-SRCache-Store: BYPASS说明缓存命中成功。后续又对真实的后端首页做了缓存测试动态页面缓存效果同样稳定。中间清空缓存时手滑输错了命令返回了ERROR修正后功能完全正常也算是实操中的真实小插曲。写在最后实操心得与建议这一套流程走下来基本上覆盖了Linux运维中最常用的Nginx进阶玩法、PHP编译部署、缓存架构落地。最后给刚入门的朋友几点实操建议配置修改先测试再重载不管是Nginx还是PHP-FPM改完配置先跑一遍语法测试确认无误再重载这是运维的基本素养能避免很多线上事故。编译安装别着急依赖先理清楚源码编译最容易出问题的就是依赖缺失缺什么装什么版本不匹配就升级对应依赖耐心一步步来。环境崩了别死磕学会及时止损实验环境崩溃很正常如果排查半小时还没头绪直接换机器重建反而比硬啃更快还能顺便再练一遍部署流程。缓存配置先理清存取逻辑做缓存的时候先想清楚“怎么存、存哪里、存多久、怎么取”key的规则前后统一绝大多数不生效的问题都是key不匹配导致的。重要节点留备份无论是做实验还是生产环境关键配置修改前先备份环境搭好可以拍个快照出问题直接回滚能节省大量时间。