MySQL忘记root密码重置(Linux环境)

MySQL root密码忘了进不去数据库?别慌,按下面步骤操作,5分钟就能重置。

1. 先停止MySQL服务

systemctl stop mysqld

CentOS 7 默认是这个命令,如果是 mariadb 就改成 systemctl stop mariadb。

2. 跳过权限验证启动MySQL

mysqld_safe --skip-grant-tables &

这一步会跳过密码验证,直接进入MySQL,不需要输密码。

3. 无密码登录MySQL

mysql -u root

现在直接就能进去了,不需要密码。

4. 重置root密码

USE mysql;

-- MySQL 5.7 及以上版本
UPDATE user SET authentication_string = PASSWORD('你的新密码') WHERE User = 'root';

-- 如果是 MySQL 5.6 及以下版本
UPDATE user SET password = PASSWORD('你的新密码') WHERE User = 'root';

FLUSH PRIVILEGES;

EXIT;

把 你的新密码 换成你想设置的新密码,注意密码强度。

5. 重启MySQL服务

systemctl start mysqld

6. 用新密码登录测试

mysql -u root -p

输入刚才设置的新密码,能登录就成功了。

常见坑

坑1:mysqld_safe 找不到
有些系统用的是 mysqld,试试:

mysqld --skip-grant-tables &

坑2:改完密码登录还是不行
一定要执行 FLUSH PRIVILEGES;,不然不生效。

坑3:密码太简单报错
MySQL 有密码强度要求,新密码最好是字母+数字+符号,8位以上。

坑4:MySQL 8.0 版本
MySQL 8.0 改密码的语法不一样:

ALTER USER 'root'@'localhost' IDENTIFIED BY '新密码';

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:16 

Redis 缓存雪崩解决

Redis 缓存雪崩解决

缓存雪崩是指大量缓存同时失效,请求全部打到数据库,数据库直接挂掉。

1. 什么是缓存雪崩

原理:

  • 大量 key 同时过期
  • 请求都查数据库
  • 数据库压力瞬间暴增
  • 数据库扛不住挂掉

和缓存穿透的区别:

  • 穿透:查询不存在的数据
  • 雪崩:大量缓存同时失效

2. 产生原因

1)缓存大面积过期:

  • 大量数据设置了相同过期时间
  • 到时间一起失效

2)Redis 宕机:

  • Redis 服务挂了
  • 所有请求都走数据库

3. 解决方案

方案一:过期时间加随机值

// 不要设置相同过期时间
$expire = 3600 + rand(0, 600);
$redis->setex("key", $expire, $value);

加随机值,让 key 分散过期,不会同时失效。

方案二:缓存永不过期

  • 热点数据不设置过期时间
  • 更新数据时主动更新缓存
  • 异步更新缓存

方案三:Redis 高可用

  • 搭建 Redis 集群
  • 主从复制
  • 哨兵模式
  • 一台挂了还有其他的

方案四:熔断降级

  • 请求量太大时直接返回默认值
  • 不让请求打到数据库
  • 保护数据库

4. 代码示例

function getData($id) {
    global $redis, $db;

    $key = "data:".$id;
    $data = $redis->get($key);

    if ($data) {
        return json_decode($data, true);
    }

    // 查数据库
    $data = $db->query("SELECT * FROM table WHERE id=$id");

    // 缓存,过期时间加随机值
    $expire = 3600 + rand(0, 600);
    $redis->setex($key, $expire, json_encode($data));

    return $data;
}

5. 最佳实践

  • 过期时间加随机值
  • 搭建 Redis 集群
  • 热点数据永不过期
  • 加熔断降级机制
  • 数据库做限流

总结

缓存雪崩解决要点:

  • 过期时间加随机值,不要同时失效
  • Redis 做主从高可用
  • 热点数据不设置过期
  • 做好降级兜底

做高并发系统,缓存雪崩一定要防。


emer 发布于  2026-10-8 07:16 

Nginx HTTPS 配置详解

Nginx HTTPS 配置详解

现在网站都要上 HTTPS,Nginx 配置 SSL 很简单。

1. 准备证书

免费证书可以用:

  • Let's Encrypt
  • 阿里云免费证书
  • 腾讯云免费证书

下载后有两个文件:

  • 证书文件:xxx.pem
  • 私钥文件:xxx.key

2. 基础配置

server {
    listen 443 ssl;
    server_name www.example.com;

    ssl_certificate /etc/nginx/ssl/xxx.pem;
    ssl_certificate_key /etc/nginx/ssl/xxx.key;

    location / {
        root /www/wwwroot/html;
        index index.html;
    }
}

3. HTTP 跳转 HTTPS

# HTTP 重定向到 HTTPS
server {
    listen 80;
    server_name www.example.com;
    return 301 https://$server_name$request_uri;
}

4. 优化配置

server {
    listen 443 ssl http2;
    server_name www.example.com;

    ssl_certificate /etc/nginx/ssl/xxx.pem;
    ssl_certificate_key /etc/nginx/ssl/xxx.key;

    # SSL 优化
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    location / {
        root /www/wwwroot/html;
        index index.html;
    }
}

5. 验证配置

# 检查配置是否正确
nginx -t

# 重载配置
nginx -s reload

6. 常见问题

1)证书不生效:

  • 检查证书路径对不对
  • 检查证书文件名
  • 重载 Nginx

2)浏览器提示不安全:

  • 证书域名不对
  • 证书过期了
  • 缺少中间证书

3)HTTP 打不开:

  • 检查 80 端口是否放行
  • 检查防火墙

7. Let's Encrypt 免费证书

用 certbot 自动申请:

# 安装
yum install certbot python3-certbot-nginx

# 自动申请并配置
certbot --nginx -d www.example.com

# 自动续期
certbot renew

总结

Nginx HTTPS 配置要点:

  • 443 端口监听 SSL
  • 配置证书和私钥路径
  • HTTP 跳转 HTTPS
  • 开启 http2 提升性能
  • 定期续期证书

现在做网站,HTTPS 是标配。


emer 发布于  2026-10-8 07:15 

MySQL 备份恢复实战

MySQL 备份恢复实战

数据库备份是运维的基本功,数据丢了就找不回来了。

1. 备份方式

1)物理备份:

  • 直接拷贝数据文件
  • 速度快,适合大数据库

2)逻辑备份:

  • 导出 SQL 语句
  • 体积小,跨平台

2. mysqldump 备份

备份整个数据库:

mysqldump -u root -p 数据库名 > backup.sql

备份单个表:

mysqldump -u root -p 数据库名 表名 > table.sql

备份所有数据库:

mysqldump -u root -p --all-databases > all.sql

3. 恢复数据

mysql -u root -p 数据库名 < backup.sql

注意: 恢复前要先创建数据库。

4. 压缩备份

# 备份并压缩
mysqldump -u root -p 数据库名 | gzip > backup.sql.gz

# 恢复压缩文件
gunzip < backup.sql.gz | mysql -u root -p 数据库名

5. 定时备份脚本

#!/bin/bash
# 数据库备份脚本

DB_USER="root"
DB_PASS="123456"
DB_NAME="test"
BACKUP_DIR="/data/backup"
DATE=$(date +%Y%m%d)

# 创建备份目录
mkdir -p $BACKUP_DIR

# 备份
mysqldump -u$DB_USER -p$DB_PASS $DB_NAME | gzip > $BACKUP_DIR/$DB_NAME_$DATE.sql.gz

# 删除7天前的备份
find $BACKUP_DIR -name "*.sql.gz" -mtime +7 -delete

加 crontab 定时执行:

# 每天凌晨3点备份
0 3 * * * /bin/bash /root/backup.sh

6. 常见问题

1)备份太大:

  • 用 --quick 参数
  • 压缩备份

2)备份报错:

  • 检查用户名密码
  • 检查权限

3)恢复失败:

  • 检查 SQL 文件是否完整
  • 检查数据库字符集

7. 最佳实践

  • 每天定时备份
  • 备份文件存到异地
  • 定期测试恢复
  • 重要数据做双备份

总结

MySQL 备份恢复要点:

  • mysqldump 导出 SQL
  • gzip 压缩减小体积
  • crontab 定时执行
  • 定期测试恢复

做运维,数据备份永远是第一位的。


emer 发布于  2026-10-8 07:14 

MySQL索引失效常见场景,避免踩坑

明明建了索引,查询还是很慢?十有八九是索引失效了。MySQL 索引失效是开发中最常见的坑,下面整理了最容易导致索引失效的场景,写SQL的时候一定要避开。

1. 对索引字段做函数操作

-- 索引失效
SELECT * FROM user WHERE DATE(create_time) = '2026-10-01';

-- 正确写法,走索引
SELECT * FROM user WHERE create_time >= '2026-10-01' AND create_time < '2026-10-02';

对索引字段用了 DATE()、YEAR()、SUBSTRING() 等函数,索引就失效了。

2. 隐式类型转换

-- 假设 phone 是 varchar 类型
-- 索引失效(数字和字符串比较,MySQL自动转换)
SELECT * FROM user WHERE phone = 13800138000;

-- 正确写法,走索引
SELECT * FROM user WHERE phone = '13800138000';

字符串类型的字段,查询条件一定要加引号。

3. 联合索引不满足最左匹配原则

-- 联合索引:(a, b, c)
-- 走索引
SELECT * FROM t WHERE a = 1 AND b = 2;

-- 不走索引(跳过了a)
SELECT * FROM t WHERE b = 2 AND c = 3;

-- 走部分索引(a走,b和c不走)
SELECT * FROM t WHERE a = 1 AND c = 3;

联合索引必须从最左边的列开始用,不能跳过。

4. 使用了 != 或 <>

-- 索引大概率失效
SELECT * FROM user WHERE status != 1;

-- 可以改成范围查询
SELECT * FROM user WHERE status < 1 OR status > 1;

不等于操作通常会导致全表扫描,因为要返回的结果太多了。

5. LIKE 以 % 开头

-- 索引失效
SELECT * FROM user WHERE name LIKE '%张';

-- 走索引
SELECT * FROM user WHERE name LIKE '张%';

模糊查询左边带 %,索引就用不上了。

6. OR 连接的条件有一个没索引

-- name 有索引,age 没索引 → 整个SQL不走索引
SELECT * FROM user WHERE name = '张三' OR age = 20;

OR 两边只要有一个字段没索引,整个查询就不走索引。

7. 用 explain 验证索引是否生效

EXPLAIN SELECT * FROM user WHERE name = '张三';

看 key 列:

  • 显示索引名 → 走索引了
  • 显示 NULL → 没走索引

看 type 列:

  • ref、eq_ref → 正常
  • ALL → 全表扫描,索引失效了

常见坑总结

  1. 不要在索引字段上做运算:WHERE age + 1 = 20 → 改成 WHERE age = 19
  2. 不要用 NOT IN / NOT EXISTS:大数据量下很慢
  3. **不要用 SELECT ***:只查需要的字段,覆盖索引更快
  4. 数据量小的表不要建索引:全表扫描可能比索引还快

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:14 

PHP 会话管理详解

PHP 会话管理详解

Session 是 PHP 做用户登录状态管理的核心功能,搞懂它很重要。

1. 什么是 Session

  • Cookie: 存在客户端(浏览器)
  • Session: 存在服务器端
  • 通过 SessionID 关联用户

2. 基础用法

// 开启会话(必须放在最前面)
session_start();

// 存数据
$_SESSION['user_id'] = 1;
$_SESSION['username'] = "test";

// 取数据
echo $_SESSION['username'];

// 判断是否登录
if (isset($_SESSION['user_id'])) {
    echo "已登录";
} else {
    echo "未登录";
}

// 销毁会话
session_destroy();

3. 登录验证示例

// 登录页
session_start();

if ($_POST['password'] == "123456") {
    $_SESSION['user'] = $_POST['username'];
    header("Location: dashboard.php");
}

// 验证页
session_start();
if (!isset($_SESSION['user'])) {
    header("Location: login.php");
    exit;
}

4. 常用配置

php.ini 里的配置:

; 会话有效期(分钟)
session.gc_maxlifetime = 1440

; Cookie 有效期(秒)
session.cookie_lifetime = 0

; 是否只允许 HTTP 访问 Cookie
session.cookie_httponly = On

5. 常见问题

1)session 丢失:

  • 检查是否有输出(session_start 前不能有空格)
  • 检查 Cookie 是否被禁用

2)多服务器共享 Session:

  • 存在数据库里
  • 存在 Redis 里
  • 不要用文件 Session

3)安全问题:

  • 登录后重新生成 SessionID
    session_regenerate_id();
  • 防止 Session 固定攻击

6. Cookie vs Session

对比 Cookie Session
存储位置 客户端 服务器端
大小限制 4KB 无限制
安全性 低 高
生命周期 可长期保存 浏览器关闭就没了

7. 登出销毁

session_start();

// 清除所有 session 变量
$_SESSION = array();

// 清除 session cookie
if (isset($_COOKIE[session_name()])) {
    setcookie(session_name(), '', time()-42000, '/');
}

// 销毁 session
session_destroy();

总结

PHP 会话管理要点:

  • session_start() 必须在最前面
  • 登录验证用 $_SESSION 判断
  • 生产环境用 Redis 存 Session
  • 登录后重新生成 SessionID 防攻击

做用户系统,Session 是必须掌握的。


emer 发布于  2026-10-8 07:13 

Docker 镜像加速配置

Docker 镜像加速配置

国内拉取 Docker 镜像很慢,配置镜像加速器很有必要。

1. 为什么要加速

Docker Hub 在国外,国内拉镜像经常超时,配置加速器能快很多。

2. 配置方法

Linux(CentOS/Ubuntu):

编辑配置文件:

mkdir -p /etc/docker
vi /etc/docker/daemon.json

写入内容:

{
  "registry-mirrors": [
    "https://docker.mirrors.ustc.edu.cn",
    "https://hub-mirror.c.163.com"
  ]
}

重启生效:

systemctl daemon-reload
systemctl restart docker

3. 常用加速器

# 中科大
https://docker.mirrors.ustc.edu.cn

# 网易
https://hub-mirror.c.163.com

# 阿里(需要自己的地址)
https://xxxx.mirror.aliyuncs.com

4. 验证是否生效

docker info

看到 Registry Mirrors 下面有地址就说明成功了。

5. 常见问题

1)拉取还是很慢:

  • 换个加速器试试
  • 网络问题

2)配置不生效:

  • 检查 json 格式对不对
  • 重启 docker

3)企业内网:

  • 可以自己搭建私有镜像仓库
  • 或者用阿里云私有镜像服务

6. 常用镜像源

# 官方
docker pull nginx
docker pull mysql
docker pull redis

# 指定版本
docker pull nginx:1.25
docker pull mysql:8.0

总结

Docker 镜像加速核心:

  • 配置 daemon.json
  • 用国内加速器地址
  • 重启 docker 生效
  • docker info 验证

做运维开发,Docker 镜像加速是第一步。


emer 发布于  2026-10-8 07:11 

Nginx 反向代理配置

Nginx 反向代理配置

反向代理是 Nginx 最常用的功能,前端请求 Nginx,Nginx 再转发给后端服务。

1. 什么是反向代理

  • 正向代理: 代理客户端,比如翻墙
  • 反向代理: 代理服务器,客户端不知道真正的后端

2. 基础配置

server {
    listen 80;
    server_name www.example.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

意思是:访问 80 端口的请求,转发到 8080 端口的服务。

3. 常用配置说明

location / {
    # 转发地址
    proxy_pass http://127.0.0.1:8080;

    # 传递真实IP
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    # 超时设置
    proxy_connect_timeout 5s;
    proxy_read_timeout 60s;
    proxy_send_timeout 60s;
}

4. 按路径转发不同服务

# 访问 /api/ 转发到后端API服务
location /api/ {
    proxy_pass http://127.0.0.1:8080;
}

# 访问 /admin/ 转发到后台管理服务
location /admin/ {
    proxy_pass http://127.0.0.1:8081;
}

# 其他访问静态文件
location / {
    root /www/wwwroot/html;
}

5. 常见应用场景

1)前后端分离:

  • 前端静态文件 Nginx 直接处理
  • API 请求转发到后端服务

2)Node.js/Python 后端:

  • Nginx 处理 80/443 端口
  • 转发到 Node.js 的 3000 端口

3)负载均衡:

  • 配合 upstream 转发到多台服务器

6. 常见问题

1)后端获取不到真实 IP:

  • 要配置 X-Real-IP 和 X-Forwarded-For
  • 后端从请求头里取

2)WebSocket 不支持:

  • 需要加特殊头
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

3)上传文件大小限制:

client_max_body_size 100m;

总结

Nginx 反向代理核心:

  • proxy_pass 转发地址
  • proxy_set_header 传递真实信息
  • 按 location 转发不同服务
  • 注意超时和文件大小限制

做 Web 开发,Nginx 反向代理一定要会配置。


emer 发布于  2026-10-8 07:10 

PHP 错误处理机制

PHP 错误处理机制

做开发离不开错误处理,搞懂 PHP 的错误机制才能写出健壮的代码。

1. 错误级别

PHP 错误分几个级别:

1)致命错误(E_ERROR)

  • 脚本停止执行
  • 比如调用不存在的类、方法

2)警告(E_WARNING)

  • 脚本继续执行
  • 比如包含不存在的文件

3)注意(E_NOTICE)

  • 不影响执行
  • 比如使用未定义的变量

2. 错误报告配置

php.ini 里的配置:

; 开发环境:显示所有错误
display_errors = On
error_reporting = E_ALL

; 生产环境:不显示错误,记录日志
display_errors = Off
log_errors = On
error_reporting = E_ALL & ~E_NOTICE

3. 自定义错误处理

// 设置错误报告级别
error_reporting(E_ALL);

// 自定义错误处理函数
set_error_handler(function($errno, $errstr, $errfile, $errline) {
    echo "错误:[$errno] $errstr 在 $errfile 第 $errline 行";
    return true; // 阻止默认错误处理
});

// 测试
echo $undefined_var;

4. 异常处理

try {
    if (!file_exists("test.txt")) {
        throw new Exception("文件不存在");
    }
    $file = fopen("test.txt", "r");
} catch (Exception $e) {
    echo "错误:" . $e->getMessage();
} finally {
    echo "\n执行完成";
}

5. 错误日志

// 记录错误日志
error_log("这是一条错误日志", 3, "/tmp/php_errors.log");

// 手动触发错误
trigger_error("自定义错误", E_USER_WARNING);

6. 开发 vs 生产

开发环境:

  • 显示错误
  • 所有错误都报告
  • 方便调试

生产环境:

  • 不显示错误(防止泄露敏感信息)
  • 记录错误日志
  • 只报告致命错误和警告

7. 常用技巧

1)错误抑制符 @

// 不推荐,会影响性能
@include("config.php");

2)die/exit

// 简单粗暴
if (! $db) {
    die("数据库连接失败");
}

3)抛异常

  • 推荐用异常处理
  • 代码更清晰,容易维护

总结

PHP 错误处理要点:

  • 开发环境显示错误,生产环境记录日志
  • 用 try-catch 处理异常
  • 错误日志要记录,方便排查
  • 不要用 @ 错误抑制符

写代码多做错误处理,线上少踩坑。


emer 发布于  2026-10-8 07:09 

MySQL 索引优化技巧

MySQL 索引优化技巧

索引是数据库性能的关键,建对了快10倍,建错了反而更慢。这篇讲实战技巧。

1. 索引类型

普通索引: 最基本的索引,没有限制
唯一索引: 列值不能重复
主键索引: 特殊的唯一索引,一张表只能一个
联合索引: 多个字段组成的索引

2. 建索引原则

1)where 条件经常用的字段建索引

-- 常用查询
SELECT * FROM users WHERE email = 'xxx@qq.com';

-- 给 email 建索引
CREATE INDEX idx_email ON users(email);

2)联合索引最左前缀原则

-- 建联合索引 (name, age)
CREATE INDEX idx_name_age ON users(name, age);

-- 能用索引
WHERE name = '张三'
WHERE name = '张三' AND age = 25

-- 不能用索引(跳过了name)
WHERE age = 25

3)避免建太多索引

  • 索引不是越多越好
  • 每个索引都占空间,影响写入速度
  • 一张表索引不要超过5个

3. 索引失效场景

1)不要在索引字段上做运算

-- 坏(索引失效)
SELECT * FROM users WHERE age + 1 = 26;

-- 好
SELECT * FROM users WHERE age = 25;

2)不要用函数

-- 坏
SELECT * FROM users WHERE DATE(create_time) = '2026-10-01';

-- 好
SELECT * FROM users WHERE create_time >= '2026-10-01' AND create_time < '2026-10-02';

3)like 前导模糊

-- 坏(用不到索引)
SELECT * FROM users WHERE name LIKE '%张%';

-- 好
SELECT * FROM users WHERE name LIKE '张%';

**4)避免 select ***

-- 坏(查所有字段,可能回表)
SELECT * FROM users WHERE name = '张三';

-- 好(覆盖索引)
SELECT id, name FROM users WHERE name = '张三';

4. 查看索引使用

-- 查看表索引
SHOW INDEX FROM users;

-- 用 explain 分析
EXPLAIN SELECT * FROM users WHERE name = '张三';

重点看:

  • type:const/ref 好,ALL 全表扫描坏
  • key:实际用到的索引
  • rows:扫描行数

5. 总结

索引优化记住:

  • where 字段建索引
  • 联合索引最左前缀
  • 别在索引字段上做运算
  • 避免前导模糊查询
  • 用 explain 检查

索引是数据库优化的第一步,做好了性能提升很大。


emer 发布于  2026-10-8 07:08 

Linux 查看系统资源

Linux 查看系统资源

服务器卡了慢了,得知道哪个进程占资源多。整理常用的查看命令。

1. 查看内存使用

# 查看内存使用情况
free -h

# 持续查看
free -h 1

输出说明:

  • total:总内存
  • used:已使用
  • free:空闲
  • buff/cache:缓存
  • available:可用

2. 查看 CPU 负载

# 查看 CPU 信息
top

# 按 q 退出

top 常用快捷键:

  • P:按 CPU 排序
  • M:按内存排序
  • 1:查看每个核心

3. 查看磁盘使用

# 查看磁盘空间
df -h

# 查看目录大小
du -sh /www/

# 查看当前目录下每个文件大小
du -sh *

4. 查看进程

# 查看所有进程
ps aux

# 查看 PHP 进程
ps aux | grep php

# 查看端口占用
netstat -tlnp

5. 查看系统信息

# 查看系统版本
cat /etc/os-release

# 查看内核版本
uname -a

# 查看 CPU 核心数
nproc

# 查看内存大小
cat /proc/meminfo | head -5

6. 查找大文件

# 查找大于100M的文件
find / -type f -size +100M

# 查找最近7天修改的文件
find /www -type f -mtime -7

7. 常用场景

网站卡了:

  1. top 看 CPU 和内存
  2. df -h 看磁盘满没满
  3. 看日志

内存不够用:

  1. free -h 看内存
  2. top 按 M 排序找占内存大的进程

总结

常用命令记这几个:

  • 内存:free -h
  • CPU:top
  • 磁盘:df -h / du -sh
  • 进程:ps aux
  • 端口:netstat

做运维这些命令天天用,必须熟。


emer 发布于  2026-10-8 07:07 

Redis 缓存穿透解决

Redis 缓存穿透解决

缓存穿透是常见问题,大量请求查询不存在的数据,直接打到数据库。这篇讲怎么解决。

1. 什么是缓存穿透

用户查询一个不存在的数据,Redis 里没有,每次都去查数据库。恶意攻击的话,数据库扛不住。

2. 解决方案一:缓存空值

查询数据库也没结果,就缓存一个空值,设置短过期时间。

function getUser($id) {
    $key = "user:$id";

    // 先查缓存
    $user = $redis->get($key);
    if ($user !== false) {
        return json_decode($user, true);
    }

    // 查数据库
    $user = $db->query("SELECT * FROM users WHERE id = $id");

    if ($user) {
        // 缓存有数据的结果
        $redis->setex($key, 3600, json_encode($user));
    } else {
        // 缓存空值,短时间过期
        $redis->setex($key, 60, '');
    }

    return $user;
}

优点: 简单粗暴
缺点: 浪费内存,可能导致不一致

3. 解决方案二:布隆过滤器

在缓存前面加一层布隆过滤器,不存在的 key 直接拦截。

// 使用 RedisBloom 模块
// 添加到布隆过滤器
$redis->rawCommand("BF.ADD", "user_filter", "1001");

// 查询是否存在
$exists = $redis->rawCommand("BF.EXISTS", "user_filter", "1001");
if (!$exists) {
    return null; // 直接返回,不查数据库
}

原理: 用二进制数组和多个哈希函数,判断一个 key 一定不存在或者可能存在。

优点: 内存占用小,效率高
缺点: 有一定误判率,不支持删除

4. 两种方案对比

方案 优点 缺点 适用场景
缓存空值 简单 浪费内存 数据量小
布隆过滤器 高效省内存 有误差 数据量大

5. 其他注意事项

  • 接口增加参数校验,不合法的 id 直接拒绝
  • 增加接口访问限流,防止恶意攻击
  • 黑名单机制,频繁查不存在的 IP 封掉

总结

缓存穿透解决思路:

  1. 缓存空值: 简单,适合小数据量
  2. 布隆过滤器: 高效,适合大数据量
  3. 加限流和校验: 从入口防护

生产环境推荐布隆过滤器 + 缓存空值组合使用。


emer 发布于  2026-10-8 07:06 

PHP 数组常用函数

PHP 数组常用函数

数组是 PHP 最常用的数据结构,数组函数用熟了开发效率翻倍。整理一份常用清单。

1. 数组创建和遍历

// 索引数组
$arr1 = [1, 2, 3];

// 关联数组
$arr2 = ['name' => '张三', 'age' => 25];

// 遍历
foreach ($arr2 as $key => $value) {
    echo "$key: $value\n";
}

2. 数组增删改查

// 追加元素
$arr[] = 4;
array_push($arr, 5, 6);

// 头部插入
array_unshift($arr, 0);

// 删除末尾元素
array_pop($arr);

// 删除头部元素
array_shift($arr);

// 删除指定元素
unset($arr[0]);

3. 数组合并和拆分

// 合并数组
$arr1 = [1, 2];
$arr2 = [3, 4];
$merged = array_merge($arr1, $arr2); // [1,2,3,4]

// 拆分
$slice = array_slice($arr, 0, 2);

4. 查找和过滤

// 判断键是否存在
array_key_exists('name', $arr);

// 判断值是否存在
in_array('张三', $arr);

// 查找值对应的键
array_search('张三', $arr);

// 数组过滤
$filtered = array_filter([1, 2, 3, 4], function($n) {
    return $n > 2;
}); // [3,4]

5. 排序

sort($arr);      // 升序
rsort($arr);     // 降序
asort($arr);     // 按值升序,保留键
ksort($arr);     // 按键升序

6. 常用操作

// 数组长度
count($arr);

// 去重
array_unique($arr);

// 反转
array_reverse($arr);

// 随机取一个
array_rand($arr);

7. 实际应用

统计数组中出现次数:

$counts = array_count_values(['a', 'b', 'a', 'c', 'a']);
// ['a' => 3, 'b' => 1, 'c' => 1]

二维数组按某列排序:

$users = [
    ['name' => '张三', 'age' => 25],
    ['name' => '李四', 'age' => 20]
];
array_multisort(array_column($users, 'age'), SORT_ASC, $users);

总结

PHP 数组函数非常多,日常开发记住这些常用的就够了:

  • 增删改查:array_push / array_pop / unset
  • 合并拆分:array_merge / array_slice
  • 查找过滤:in_array / array_filter
  • 排序:sort / asort / ksort

数组是 PHP 的灵魂,多用多练就熟了。


emer 发布于  2026-10-8 07:05 

MySQL慢查询开启,定位慢SQL语句方法

前言

网站越来越慢,不知道哪条 SQL 拖后腿。MySQL 自带慢查询日志功能,能把执行慢的 SQL 记录下来,方便优化。

什么是慢查询

就是执行时间超过某个阈值的 SQL 语句。默认阈值是 10 秒,太久了,一般改成 1 秒或者 2 秒。

临时开启(重启不丢)

登录 MySQL:

mysql -u root -p

开启慢查询:

-- 开启慢查询
SET GLOBAL slow_query_log = ON;

-- 设置超过1秒就记录
SET GLOBAL long_query_time = 1;

-- 查看慢查询日志位置
SHOW VARIABLES LIKE 'slow_query_log_file';

永久开启(改配置文件)

改 my.cnf:

vi /etc/my.cnf

加上:

slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1

重启 MySQL:

systemctl restart mysqld

慢查询日志长什么样

# Time: 2026-10-07T07:00:00.000000Z
# User@Host: root[root] @ localhost []  Id:  1234
# Query_time: 5.234567  Lock_time: 0.000123 Rows_sent: 1000  Rows_examined: 1000000
SET timestamp=1728270000;
SELECT * FROM users WHERE name LIKE '%张%';

重点看:

  • Query_time:执行时间
  • Rows_examined:扫描了多少行
  • 最后一行就是慢 SQL 语句

分析慢查询日志

用 mysqldumpslow 工具:

# 找出最慢的10条SQL
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log

# 找出返回数据最多的10条
mysqldumpslow -s r -t 10 /var/log/mysql/slow.log

参数说明:

参数 说明
-s t 按时间排序
-s r 按返回行数排序
-t 10 显示前10条

常见坑

坑1:没开启慢查询

不知道怎么开,或者开了忘了。

解决: 用 SHOW VARIABLES LIKE 'slow_query_log'; 确认一下。

坑2:阈值设太大

默认是 10 秒,10 秒以下的慢 SQL 都没记录到。

解决: 改成 1 秒,够用了。

坑3:日志太大占磁盘

慢查询日志一直写,磁盘满了。

解决: 配 logrotate 定期切割。

坑4:没记录没走索引的SQL

有些 SQL 虽然快,但没走索引,数据量一大就慢了。

解决: 加上这个参数,没走索引的也记录:

log_queries_not_using_indexes = 1

总结

三步开启慢查询:

  1. 开 slow_query_log
  2. 设 long_query_time
  3. 用 mysqldumpslow 分析

记住: 慢查询日志是优化数据库的第一步,先开了再说。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-7 07:53 

Nginx报"no input file specified"错误解决

前言

访问 PHP 页面,直接报 "No input file specified",意思是 PHP-FPM 找不到要执行的 PHP 文件。这是 Nginx 配置里 root 路径不对导致的。

报错长什么样

页面上直接显示:

No input file specified.

没有其他信息,就这么一句话。

常见原因

原因1:root 路径不对

PHP location 里的 root 和 server 里的 root 不一致。

错误示例:

server {
    root  /var/www/html;

    location ~ \.php$ {
        fastcgi_param SCRIPT_FILENAME /var/www/php$fastcgi_script_name;
    }
}

这样 PHP 找文件的时候就找错目录了。

正确做法:

server {
    root  /var/www/html;

    location ~ \.php$ {
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

用 $document_root 自动取 server 里的 root。

原因2:文件真的不存在

URL 对应的 PHP 文件根本就没有。

检查:

ls /var/www/html/test.php

原因3:文件权限不对

文件存在,但 Nginx/PHP-FPM 读不了。

解决: 确保文件权限是 644,目录是 755,属主是 www。

完整正确的配置

server {
    listen       80;
    server_name  www.example.com;

    root  /var/www/html;
    index index.php index.html;

    location / {
        try_files $uri $uri/ =404;
    }

    location ~ \.php$ {
        fastcgi_pass   unix:/run/php-fpm/www.sock;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }
}

排查步骤

第一步:确认文件在不在

ls /var/www/html/test.php

第二步:看 Nginx 错误日志

tail -f /var/log/nginx/error.log

访问一下报错的页面,看日志里写的路径是什么。

第三步:确认 root 路径

grep root /etc/nginx/conf.d/你的站点.conf

常见坑

坑1:fastcgi_param 写错了

写成了 $request_filename 或者其他变量。

解决: 一定要用 $document_root$fastcgi_script_name。

坑2:伪静态和 PHP 冲突

配了伪静态,导致 PHP 请求被重写到别的地方了。

解决: 确保伪静态规则在 PHP location 之前,而且 PHP location 能正常匹配到 .php 请求。

坑3:多站点 root 不一致

A 站点的 PHP 请求跑到 B 站点去了。

原因: 多个站点的 root 配置不对。

解决: 每个站点的 root 都写清楚,别共用。

坑4:PHP-FPM 配置不对

PHP-FPM 的 www.conf 里的 listen 路径和 Nginx 配置的不一致。

解决: 确认两边的 socket 路径一样。

总结

90% 的情况都是 root 路径不对。

检查这三点:

  1. root 路径写对了没
  2. 文件真的存在不
  3. 文件权限对不对

记住: PHP 配置里一定要用 $document_root$fastcgi_script_name,别写死路径。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-7 07:51 

Nginx配置访问密码,限制后台访问

前言

网站后台地址公开,谁都能访问,容易被别人扫到然后暴力破解。给后台加一层 Nginx 访问密码,多一道防护。

什么是访问密码

就是访问某个目录前,浏览器先弹一个登录框,输入用户名密码才能进去。和网站本身的登录是两回事。

第一步:生成密码文件

用 htpasswd 命令生成密码文件:

htpasswd -c /etc/nginx/.htpasswd admin

第一次加 -c 创建文件,输入两次密码。

不加 -c 是追加新用户:

htpasswd /etc/nginx/.htpasswd user2

如果没有 htpasswd 命令,先装:

yum install -y httpd-tools

第二步:Nginx 配置

给后台目录加密码:

location /admin/ {
    auth_basic "Admin Login";
    auth_basic_user_file /etc/nginx/.htpasswd;
}

完整配置示例

server {
    listen       80;
    server_name  www.example.com;

    root  /var/www/html;
    index index.php index.html;

    # 后台加密码
    location /admin/ {
        auth_basic "Admin Login";
        auth_basic_user_file /etc/nginx/.htpasswd;

        # 后台本身的 PHP 配置
        location ~ \.php$ {
            fastcgi_pass   unix:/run/php-fpm/www.sock;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            include        fastcgi_params;
        }
    }

    # 前台正常访问
    location / {
        try_files $uri $uri/ =404;
    }
}

重载生效

nginx -t
nginx -s reload

常见坑

坑1:.htpasswd 文件权限不对

Nginx 读不到密码文件。

解决: 确保文件权限是 644,属主是 www:

chown www:www /etc/nginx/.htpasswd
chmod 644 /etc/nginx/.htpasswd

坑2:PHP 文件不弹密码

访问 /admin/index.php 直接就进了,没弹密码框。

原因: PHP 的 location 把请求拦截了,没走 auth_basic。

解决: 把 auth_basic 配置放到 PHP 的 location 里,或者放到 server 级别。

坑3:忘记密码

自己把密码忘了。

解决: 重新生成:

htpasswd -b /etc/nginx/.htpasswd admin 新密码

坑4:密码文件放网站目录里

把 .htpasswd 放在了网站根目录下,别人能直接下载。

解决: 密码文件放在网站目录外面,比如 /etc/nginx/ 下面。

总结

两步搞定:

  1. htpasswd 生成密码文件
  2. Nginx 加 auth_basic 配置

记住: 密码文件别放网站目录里,放在外面安全。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-7 07:50 

Nginx日志切割,按天切割nginx日志

前言

Nginx 的访问日志一直写在一个文件里,越写越大,几百GB都有可能。磁盘满了网站就挂了。本文讲一下怎么用 logrotate 自动按天切割 Nginx 日志。

为什么要切割日志

  • 日志太大占磁盘
  • 分析大文件慢
  • 出问题查日志不方便

方法一:用系统自带的 logrotate

CentOS 自带 logrotate,直接配就行。

第一步:写配置文件

vi /etc/logrotate.d/nginx

内容:

/var/log/nginx/*.log {
    daily
    missingok
    rotate 30
    compress
    notifempty
    create 0644 www www
    postrotate
        /bin/kill -USR1 `cat /run/nginx.pid 2>/dev/null` 2>/dev/null || true
    endscript
}

参数说明:

参数 说明
daily 按天切割
rotate 30 保留30天的日志
compress 压缩旧日志
notifempty 空文件不切割
missingok 日志文件不存在不报错

第二步:测试一下

logrotate -d /etc/logrotate.d/nginx

-d 是调试模式,不会真执行,看一下有没有报错。

第三步:立即执行一次

logrotate -f /etc/logrotate.d/nginx

方法二:自己写脚本

不想用 logrotate,自己写个 shell 脚本:

vi /root/nginx_log.sh

内容:

#!/bin/bash

LOG_PATH=/var/log/nginx
YESTERDAY=$(date -d "yesterday" +%Y%m%d)

cd $LOG_PATH

mv access.log access_$YESTERDAY.log
mv error.log error_$YESTERDAY.log

nginx -s reopen

加执行权限:

chmod +x /root/nginx_log.sh

加到 crontab,每天凌晨执行:

crontab -e

加一行:

0 0 * * * /root/nginx_log.sh

常见坑

坑1:切割后日志不写了

把日志文件改名了,Nginx 还往旧文件写。

原因: Nginx 打开的是文件句柄,改名后它不知道。

解决: 切割后要通知 Nginx 重新打开日志文件:

nginx -s reopen

坑2:旧日志没删,磁盘还是满的

配了切割,但旧日志还留着。

原因: 没配 rotate 参数。

解决: 加上 rotate 30,自动只保留30天。

坑3:压缩太占CPU

所有日志都压缩,CPU 飙高。

解决: 错峰压缩,比如凌晨3点再压缩,或者用 delaycompress 延迟一天再压缩。

坑4:日志权限不对

切割后新日志文件属主不对,Nginx 写不了。

解决: logrotate 配置里加 create 0644 www www。

总结

推荐用 logrotate,系统自带,不用自己维护脚本。

核心配置就这些:

/var/log/nginx/*.log {
    daily
    rotate 30
    compress
    postrotate
        /bin/kill -USR1 `cat /run/nginx.pid`
    endscript
}

记住: 切割完一定要通知 Nginx 重新打开日志文件,不然新日志不写。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-7 07:49 

Nginx配置websocket反向代理

前言

做实时聊天、推送、在线游戏,需要用 WebSocket。Nginx 当反向代理的时候,默认不支持 WebSocket 协议,需要额外配置。本文讲一下怎么配。

WebSocket 是什么

WebSocket 是一种全双工通信协议,浏览器和服务器建立连接后,可以一直保持连接,互相实时推送消息。

为什么需要特殊配置

普通 HTTP 请求是短连接,请求完就断了。WebSocket 是长连接,而且用的是 Upgrade 协议头。Nginx 默认的反向代理不支持这种升级,需要加特殊配置。

基础配置

location /ws/ {
    proxy_pass http://127.0.0.1:8080;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

关键就是这三行:

proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

完整配置示例

server {
    listen       80;
    server_name  www.example.com;

    root  /var/www/html;
    index index.html;

    # WebSocket 代理
    location /ws/ {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_read_timeout 300s;
    }

    # 普通 HTTP 代理
    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

超时配置

WebSocket 是长连接,默认超时时间短了会自动断开。

proxy_read_timeout 300s;
proxy_send_timeout 300s;

意思是:5分钟没有数据传输才断开。

常见坑

坑1:WebSocket 连接失败

前端连 WebSocket 一直失败。

原因: Nginx 没配 Upgrade 和 Connection 头。

解决: 加上那三行关键配置。

坑2:连接几秒就自动断了

连上了,过一会儿就断了。

原因: Nginx 默认超时时间太短(60秒)。

解决: 调大 proxy_read_timeout。

坑3:HTTPS 下 WebSocket 连不上

HTTP 下正常,HTTPS 下连不上。

原因: 前端用了 ws://,但网站是 https 的,浏览器不让。

解决: 前端用 wss://(加密的 WebSocket)。

坑4:连接数太多被拒

很多人同时在线,新的连接被拒了。

原因: Nginx 或后端服务器连接数限制。

解决: 调大 Nginx 和后端的连接数限制。

总结

WebSocket 代理就三行核心配置:

proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

记住: WebSocket 是长连接,记得调大超时时间,别让它自动断了。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-7 07:48 

Nginx防盗链配置,防止图片被别人盗用

前言

网站的图片被别人盗链了,他的网站直接用你的图片地址,流量全从你服务器走,白白消耗带宽。Nginx 可以配置防盗链,防止这种情况。

什么是盗链

就是别人在自己网站里直接引用你服务器上的图片。用户看他的网站,实际图片是从你服务器加载的。

防盗链原理

Nginx 检查请求头里的 Referer 字段,看是从哪个页面过来的。如果不是自己网站的 Referer,就拒绝或者返回一张提示图。

基础配置

location ~* \.(jpg|png|gif|jpeg)$ {
    valid_referers none blocked www.example.com example.com;
    if ($invalid_referer) {
        return 403;
    }
}

解释:

  • valid_referers:允许哪些来源访问
  • none:允许直接输入地址访问
  • blocked:允许伪装的 Referer
  • www.example.com:自己的域名

配置示例

server {
    listen       80;
    server_name  www.example.com;

    root  /var/www/html;
    index index.html;

    # 防盗链
    location ~* \.(jpg|png|gif|jpeg|webp)$ {
        valid_referers none blocked www.example.com example.com *.example.com;
        if ($invalid_referer) {
            return 403;
        }
    }
}

替换成提示图

不想直接 403,可以返回一张"禁止盗链"的提示图:

location ~* \.(jpg|png|gif|jpeg)$ {
    valid_referers none blocked www.example.com example.com;
    if ($invalid_referer) {
        rewrite ^/.*\.(jpg|png|gif)$ /no-hotlink.png last;
    }
}

这样别人盗链就显示一张提示图。

常见坑

坑1:自己网站图片也加载不出来

配了防盗链,自己网站的图片也打不开了。

原因: valid_referers 里没写全自己的域名。

解决: 把 http 和 https 的域名都写上:

valid_referers none blocked www.example.com example.com;

坑2:搜索引擎图片也被挡了

百度图片搜不到你的图片了。

原因: 防盗链把搜索引擎也挡了。

解决: 加上搜索引擎的 Referer:

valid_referers none blocked www.example.com example.com *.baidu.com *.google.com;

坑3:CDN 后面防盗链不生效

用了 CDN,防盗链配置不生效。

原因: 请求经过 CDN,Referer 是 CDN 的。

解决: CDN 那边配置防盗链,或者把 CDN 的 Referer 加到白名单。

坑4:微信里打开图片不显示

在微信里打开自己的文章,图片显示不出来。

原因: 微信的 Referer 被挡了。

解决: 加上微信的 Referer:

valid_referers none blocked www.example.com example.com *.weixin.qq.com;

总结

防盗链就三行配置:

valid_referers none blocked www.example.com example.com;
if ($invalid_referer) {
    return 403;
}

记住: 配完防盗链,先测试一下自己网站图片能不能正常打开。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-7 07:47 

Nginx安装后找不到配置文件,编译安装路径

前言

编译安装 Nginx 后,想用 nginx 命令提示 command not found,找配置文件也找不到。这是因为编译安装的 Nginx 不在系统默认 PATH 里,路径和包管理器安装的不一样。

编译安装的默认路径

一般编译安装 Nginx,默认装在:

/usr/local/nginx/

目录结构:

/usr/local/nginx/
├── sbin/
│   └── nginx          # 主程序
├── conf/
│   ├── nginx.conf     # 主配置文件
│   ├── mime.types
│   └── fastcgi_params
├── html/              # 默认网站目录
└── logs/
    ├── access.log
    └── error.log

怎么确认安装路径

方法一:nginx -V

/usr/local/nginx/sbin/nginx -V

输出里 --prefix= 后面就是安装路径。

方法二:ps 命令看进程

ps aux | grep nginx

进程路径就是 Nginx 在哪。

把 nginx 加到 PATH

不想每次都输完整路径,加个软链接:

ln -s /usr/local/nginx/sbin/nginx /usr/local/bin/nginx

之后直接用 nginx 命令就行。

配置文件在哪

编译安装的配置文件在:

/usr/local/nginx/conf/nginx.conf

编辑:

vi /usr/local/nginx/conf/nginx.conf

常用命令

# 启动
/usr/local/nginx/sbin/nginx

# 重载
/usr/local/nginx/sbin/nginx -s reload

# 停止
/usr/local/nginx/sbin/nginx -s stop

# 检查配置
/usr/local/nginx/sbin/nginx -t

开机自启

编译安装的 Nginx 没有 systemd 服务,需要自己写:

vi /etc/systemd/system/nginx.service

内容:

[Unit]
Description=Nginx Web Server
After=network.target

[Service]
Type=forking
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/usr/local/nginx/sbin/nginx -s stop

[Install]
WantedBy=multi-user.target

然后:

systemctl daemon-reload
systemctl enable nginx
systemctl start nginx

常见坑

坑1:nginx: command not found

执行 nginx 提示找不到命令。

原因: 编译安装的不在 PATH 里。

解决: 加软链接,或者用完整路径。

坑2:改了配置不生效

改了 /etc/nginx/nginx.conf,但重载后还是老配置。

原因: 你改的是包管理器安装的配置文件,实际跑的是编译安装的。

解决: 用 nginx -t 确认一下实际加载的是哪个配置文件。

坑3:多个 nginx 共存

系统里同时有 yum 安装的和编译安装的 Nginx,不知道哪个在跑。

解决: 先停掉一个,再看进程。

坑4:日志找不到

日志不在 /var/log/nginx/。

原因: 编译安装的日志在自己的目录里。

解决: 看 nginx.conf 里的 error_log 和 access_log 配置。

总结

编译安装 Nginx 记住三个路径:

内容 路径
主程序 /usr/local/nginx/sbin/nginx
配置文件 /usr/local/nginx/conf/nginx.conf
日志 /usr/local/nginx/logs/

记住: 编译安装的和 yum 安装的路径不一样,别搞混了。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-7 07:46 
'); })();