# 系统运维

# 系统运行过程产生的新数据

默认运行情况下,除了数据库,会在文件系统产生以下新数据:

目录 描述
/public/data/ 上传的文件数据(如果启用了云存储,文件是直接存储在云存储中,忽略本条)
/.env 系统基本配置文件
/storage/install.lock 系统安装锁定文件
/module/Xxx/ 新安装的模块代码

# 如何防止系统更新时已修改文件被覆盖

伴随着系统的更新,许多文件需要不断升级才能适配最新的版本,不能只简单的使用旧文件,否则会导致系统出现异常。

为了防止已修改的文件被覆盖,可以通过以下方式进行操作:

💄样式文件的修改

如果是样式文件,可通过创建新的样式文件(如 public/theme/custom/css/style.css),在新文件中写入自定义样式覆盖已有样式。

同时在 resources/views/theme/default/pc/frame.blade.php 中全局引入新的样式文件。

这样在更新系统时,只需要更新系统的样式文件,不会影响到自定义的样式。

💻 代码文件的修改

如果是代码文件的修改,升级会不可避免的覆盖掉已修改的文件,这时候建议使用 git 等版本控制工具,将自定义的代码提交到版本库中,升级后再合并自定义的代码。

推荐的 git 工作流方式

sequenceDiagram participant A as 测试环境 participant C as 代码仓库 participant B as 生产环境 A->>A: 本地升级代码文件 A->>C: git 提交代码修改到仓库<br />git push C->>B: 同步代码到生产<br />git pull B->>B: 运行迁移命令<br />php artisan migrate<br />php artisan modstart:module-install-all

# 系统运行过程所有缓存文件目录位置

目录 描述
/public/data_temp/ 文件上传的临时文件,可以全部删除
/public/data_chunk/ 文件上传的临时文件,可以全部删除
/public/temp/ 系统处理临时文件
/bootstrap/cache/ 配置项等缓存文件,可以全部删除
/storage/framework/cache/ 系统缓存文件,可以全部删除
/storage/framework/sessions/ 会话缓存文件,可以全部删除
/storage/framework/views/ 视图缓存文件,可以全部删除
/storage/logs/ 系统日志文件,可以全部删除

注意:以上所有目录在清理过程中注意不要删除目录本身。

# 系统服务器间迁移网站和数据

1)复制整个网站目录到新的服务器

2)在新的服务器上配置系统,参照「安装入门」中的说明文档,保证访问可达

配置好新系统后,保证访问 http://example.com/install/ping 返回 ok 文本

如果有异常信息请参照「使用常见问题」解决。

3)修改必要的配置信息 /.env 文件

4)清理系统缓存

php artisan cache:clear
php artisan view:clear
1
2

5)访问新的系统

# 文件存储类型变更如何迁移

举例说明

  • 原存储
    • 类型:阿里云 OSS
    • 访问URL:https://xxx.oss-cn-hangzhou.aliyuncs.com/data/xxxx.jpg
  • 新存储
    • 类型:腾讯云 COS
    • 访问URL:https://xxx.cos.ap-guangzhou.myqcloud.com/data/xxxx.jpg

操作步骤

第一步,修改系统配置

安装新的存储模块,在后台完成新的文件上传存储配置。

本例需要安装 腾讯云COS云存储 (opens new window),在后台配置腾讯云 COS 上传模块,停用阿里云 OSS 上传模块。

第二步,迁移已上传的文件到新的存储

上传的文件位于 /public/data/ 目录,变更存储类型时需要转移所有已上传的文件到新的存储中。

迁移文件时,建议讲云存储 mount 到服务器本地,使用 rsync 等工具进行文件迁移。

本例需要将阿里云 COS 和腾讯云 COS 挂载到本地,然后使用 rsync 工具将文件从阿里云 COS 迁移到腾讯云 COS

第三步,修复数据库中的文件路径

下载并安装 文件路径迁移助手 (opens new window),在后台勾选表中包含路径的字段,处理预览开始处理,完成数据库中路径的修复。

程序会自动识别处理富文本、单图路径、多图路径字段。

本例中原路径为 https://xxx.oss-cn-hangzhou.aliyuncs.com,新路径为 https://xxx.cos.ap-guangzhou.myqcloud.com

# 如何为网站强制增加 www

Nginx 参考配置

server {
    listen 80;
    server_name modstart.com;
    location / {
        rewrite ^/(.*)$ http://www.modstart.com/$1 permanent;
    }
}
1
2
3
4
5
6
7

# 网站强制跳转为 https

Nginx 参考配置

server {
    listen 80;
    server_name www.modstart.com;
    location / {
        rewrite ^/(.*)$ https://www.modstart.com/$1 permanent;
    }
}
1
2
3
4
5
6
7

# 为网站开通 CDN 加速

通过CDN可以将动态请求、静态资源分离,加速网站的访问。我们推荐如下的CDN加速方式

image-20220517205009684

CDN静态资源更新问题

系统内置了静态资源自动计算Hash的问题来避免缓存,静态资源加载的路径格式为 https://example.com/xxx.js?<Hash数字> ,当静态资源发生更新时,Hash数字会发生变化,从而让CDN加速节点感知资源的变化,拉取最新的静态资源。

部分CDN加速可能会忽略请求参数,在配置CDN加速服务时,请勿忽略请求的参数(即静态资源请求链接?后的Hash数字参数)

# 如何开启 Redis 作为缓存驱动

系统已经默认安装了 predis/predis 扩展,只需要以下简单配置即可完成缓存驱动切换。

## 切换缓存驱动为 redis
CACHE_DRIVER=redis

## 设置 Redis 连接信息
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=xxxxx
REDIS_PORT=6379
1
2
3
4
5
6
7

配置完成后清除系统缓存

更详细的配置参考 config/cache.phpconfig/database.php 文件

# 如何将系统安装到子目录

系统默认安装到根目录,如果需要安装到子目录,可以通过以下方式实现。

系统只推荐安装到根目录,安装到子目录可能会导致部分功能异常,需要自行测试,这里只提供一个实现方式。 所有的链接生成都是基于根目录的,如果安装到子目录,需要自行修改链接生成的逻辑。

第①步,增加配置文件,修改 .env 文件

# 系统子目录外部访问地址
SUBDIR_URL=https://example.com/subdir
# 系统子目录名称
SUBDIR=subdir
1
2
3
4

第②步,修改 Nginx 配置,设置子目录反向代理

Nginx 参考配置

server {
    listen 80;
    server_name example.com;
    location /subdir {
        proxy_pass http://localhost:9000;
        proxy_set_header Host $host;
    }
}
1
2
3
4
5
6
7
8

Apache 参考配置

<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /path/to/your/subdir
    <Directory /path/to/your/subdir>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>
1
2
3
4
5
6
7
8
9

# 优化网站打开速度

# 优化静态资源加载速度

网络传输会很大程度影响加载速度,服务器的带宽再大同时访问的人数增多带宽也会打满。

使用 CDN 优化静态资源加载速度,如七牛、网易、百度、阿里云等,具体方法可网上自行查找。

# 优化后端服务响应速度

第一步,安装并开启 OPCache ,可以让网站加载速度提升。

修改 php.ini

[opcache]
opcache.enable=1
; 可用内存, 酌情而定, 单位为:Mb
opcache.memory_consumption=528
; Zend Optimizer + 暂存池中字符串的占内存总量.(单位:MB)
; opcache.interned_strings_buffer=8
; 对多缓存文件限制, 命中率不到 100% 的话, 可以试着提高这个值
opcache.max_accelerated_files=10000
; Opcache 会在一定时间内去检查文件的修改时间, 这里设置检查的时间周期, 默认为 2, 定位为秒
; 生产环境,代码不变可以关闭0
opcache.revalidate_freq=1
1
2
3
4
5
6
7
8
9
10
11

第二步,使用Laravel优化命令优化系统加载流程

## 缓存路由
php artisan route:cache
## 缓存配置
php artisan config:cache
## 类映射加载优化
php artisan optimize
1
2
3
4
5
6

对应的清空缓存

## 清除缓存路由
php artisan route:clear
## 清除缓存配置
php artisan config:clear
## 清除类映射加载优化
php artisan clear-compiled
1
2
3
4
5
6

我们强烈推荐使用 Linux 部署 PHP 服务,性能会比 Windows 提升不少。

# mysql

# 开启全文搜索 fulltext

开启全文索引需要使用 MySQL 版本大于 5.7,由于该配置比较繁琐,所以所有系统默认不支持,需要通过运维手动开启。

全文索引是为了解决需要基于相似度的查询,而不是精确数值比较。

可以通过 SQL 命令查看当前配置的最小搜索长度(分词长度):

SHOW VARIABLES LIKE 'ft%';
1
变量名 描述
ft_boolean_syntax 全文搜索的布尔语法
ft_max_word_len 最大词长度
ft_min_word_len 最小词长度
ft_query_expansion_limit 查询扩展限制
ft_stopword_file 停用词文件

全文索引的相关参数都无法进行动态修改,必须通过修改 MySQL 的配置文件来完成。修改最小搜索长度的值为 1,首先打开 MySQL 的配置文件 /etc/my.cnf,在 [mysqld] 的下面追加以下内容:

[mysqld]
innodb_ft_min_token_size = 1
ft_min_word_len = 1
1
2
3

配置完后重启 MySQL 服务器。

完成后可使用以下脚本测试全文搜索:

## 查看索引
SHOW INDEX FROM config;
## 删除全文索引
ALTER TABLE config DROP INDEX xxx;
## 创建全文索引,注意该字段只能创建一个全文索引,多余的使用以上的删除语句删除
ALTER TABLE config ADD FULLTEXT(value) WITH PARSER ngram;

## 使用以下语句测试查询
SELECT `id`,`key`,`value`,MATCH(`value`) AGAINST('测试查询') AS _score
    FROM config
    WHERE MATCH(`value`) AGAINST('测试查询')
    ORDER BY _score DESC;
1
2
3
4
5
6
7
8
9
10
11
12

# 备份与恢复 mysqldump

备份

#!/bin/bash

PASSWORD="123456"
DIRECTORY="/mysql-backup"

databases=$(mysql -u root -p$PASSWORD -e "SHOW DATABASES;" | grep -Ev '^(information_schema|performance_schema|mysql|sys)$')
for db in $databases; do
    echo "backup: $db"
    temp_file=$(mktemp)
    mysqldump -u root -p$PASSWORD --databases "$db" > "$temp_file"
    echo "CREATE DATABASE IF NOT EXISTS \`$db\`;" > "${db}_backup.sql"
    echo "USE \`$db\`;" >> "${db}_backup.sql"
    cat "$temp_file" >> "$DIRECTORY/${db}_backup.sql"
    rm "$temp_file"
done
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

恢复

#!/bin/bash

PASSWORD="123456"
DIRECTORY="/mysql-backup"

for sql_file in "$DIRECTORY"/*.sql; do
    if [[ -f "$sql_file" ]]; then
        echo "正在导入文件: $sql_file"
        mysql -u root -p$PASSWORD mysql < "$sql_file"
    fi
done
1
2
3
4
5
6
7
8
9
10
11

# nginx

# https证书

配置HTTP证书,除了基础的服务器配置外,还需额外增加以下配置信息,打开 443 端口,配置证书路径。

server {
    listen 443 ssl;
    server_name  example.com;
    ssl_certificate      /xxx/cert.pem;
    ssl_certificate_key  /xxx/key.pem;
    # ...
}
1
2
3
4
5
6
7

# 反向代理

server {
    server_name old.example;
    location / {
        proxy_pass http://xx.xx.xx.xx:8080;
        proxy_set_header Host $host;
    }
}
1
2
3
4
5
6
7

# openresty

# 每秒每个IP最多一个请求限流

作用域 http

limit_req_zone $binary_remote_addr zone=limit_by_ip:64m rate=1r/s;
1

作用域 http, server, location

limit_req zone=limit_by_ip burst=10;
1

nginx http_limit_req 参考 (opens new window)

# php

# 查看php-fpm执行状态

## 端口方式
curl http://localhost:9000/status
## sock方式
SCRIPT_NAME=/status SCRIPT_FILENAME=/status REQUEST_METHOD=GET cgi-fcgi -bind -connect /sock/php-fpm.sock
1
2
3
4

# docker

# 清除无用镜像

docker images | awk '{print $3}' | xargs docker rmi
1

# 修改 Docker 的 IP

修改 /etc/docker/daemon.json

{
    // ...
    "bip": "198.18.0.0/16"
    // ...
}
1
2
3
4
5

完成后重启 docker 服务

sudo systemctl daemon-reload
sudo systemctl restart docker
1
2

# 镜像手动打包、推送、加载

# 保存一个镜像到本地 tar 文件
docker save -o /tmp/ExampleImage.tar ExampleImage:1.0.0
# 推送到远程存储(此处以支持 PUT 方法的 OSS 为例)
curl -T /tmp/ExampleImage.tar https://some-bucket.oss-cn-shanghai.aliyuncs.com/image/ExampleImage.tar
# 加载一个远程 tar 镜像到本地
docker load -i https://some-bucket.oss-cn-shanghai.aliyuncs.com/image/ExampleImage.tar
1
2
3
4
5
6

# Linux Swap 交换区

如果你的服务器的总是报告内存不足,并且时常因为内存不足而引发服务被强制kill的话,在不增加物理内存的情况下,启用swap交换区作为虚拟内存是一个不错的选择,如果硬盘使用的是 SSD,正常读写速度都在 300MB/s 以上,启用 swap 后性能提高了不少,特别是在处理消耗大内存的脚本方面。

创建交换区原则:

  • 创建的swap交换区大小应该大于实际物理内存的容量大小,但是不要过大,以免造成硬盘空间浪费。
  • 如果内存IO请求频繁,而单一swap交换区IO队列等待时间过长的话,可以多创建几个swap交换区。
  • 原则上优先在IO速度最快的设备上创建。

(1)创建swap交换区硬盘存储用的空白文件。

通常创建物理内存2~2.5倍大小的文件作为交换区。

# 创建一个1个G的SWAP交换区空白文件
dd if=/dev/zero of=/swap bs=1M count=1024
1
2

(2)使用mkswap格式化文件为swap文件系统

# -f 使用文件作为swap交换区
mkswap -f /swap
# 设定为推荐的 0600 权限
chmod 0600 /swap
1
2
3
4

(3)启用刚才创建的Swap文件

swapon /swap
1

(4)如果有必要可以设置开机自动启用swap文件交换区,修改/etc/fstab,增加一行

# 启动即启用swap
/swap swap swap defaults 0 0
1
2

(5)如果不需要启用swap或需要调整swap大小,可以使用swapoff命令关闭swap。

# 关闭swap
swapoff /swap
1
2

关闭swap后删除对应的swap文件即可删除swap交换区,如需要调整swap交换区大小,从第一部开始重新创建即可。

# git 代码仓库管理

## git忽略文件权限变更
git config --add core.filemode false

## 清空git历史
git checkout --orphan temp_branch
git add -A
git commit -am "init"
git branch -D master
git branch -m master

## 修改最近一次提交信息
git commit --amend -m "some msg"

## 存储用户名密码信息
git config --global credential.helper store

## 从HEAD往前打1个patch
git format-patch -1 HEAD
## 根据 commit 打 patch,指从 commit 往后将每一个 commit 打成一个 patch 文件
git format-patch <commit>
## 根据 commit 打 patch,指从 commit 往前只打一个 patch 文件
git format-patch -1 <commit>
## 将暂存区中的修改保存为一个 patch 文件,对于新增加文件可使用 git add -N xxx 加入暂存区
git diff > 0001-xxx.patch

## 应用一个patch到当前分支,合并失败的文件生成 rej 文件
git apply --reject 0001-xxx.patch

## 交互式部分提交
# ① 进入交互式
git add -i
# ② 按p进入patch模式
# ③ 按*进入选择模式
# ④ 按y/n表示接受/拒绝
# ⑤ 按q退出
# ⑥ 提交
git commit -m "some msg" 

## 暂存区
git stash push
git stash apply
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

# zip unzip 压缩与解压缩

zipunzip 是用于压缩和解压缩文件的命令行工具。

  • zip 可以将文件或目录压缩成一个 .zip 文件
  • unzip 可以解压缩一个 .zip 文件
# 压缩目录
zip -r /path/to/your/zip.zip /path/to/your/folder
# 解压缩
unzip /path/to/your/zip.zip -d /path/to/your/folder
1
2
3
4

# lrzsz 数据传输

lrzsz 是一组用于文件传输的命令行工具,主要用于通过串行端口或网络连接在本地和远程计算机之间传输文件。它包括两个主要命令:rzsz

  • rz:用于从本地计算机上传文件到远程计算机。
  • sz:用于从远程计算机下载文件到本地计算机。
## 安装
yum install -y lrzsz
## 下载
sz /path/to/your/file
## 上传
cd /path/to/your/folder
rz
1
2
3
4
5
6
7

# 为命令行工具设置 Proxy 上网

# Windows

在 Windows 的 PowerShell 中,可以通过设置 http_proxy 和 https_proxy 环境变量来配置代理。

# 设置 HTTP 代理,设置后,所有的 HTTP 请求都会通过代理服务器
$env:http_proxy="http://127.0.0.1:1080"
# 设置 HTTPS 代理,设置后,所有的 HTTPS 请求都会通过代理服务器
$env:https_proxy="http://127.0.0.1:1080"
1
2
3
4

# MacOS / Linux

在 macOS 或 Linux 的 Terminal 中,可以通过设置 http_proxy 和 https_proxy 环境变量来配置代理。

# 设置 HTTP 代理,设置后,所有的 HTTP 请求都会通过代理服务器
export http_proxy=http://127.0.0.1:1087
# 设置 HTTPS 代理,设置后,所有的 HTTPS 请求都会通过代理服务器
export https_proxy=http://127.0.0.1:1087
1
2
3
4

# pt-online-schema-change 在线DDL

pt-online-schema-change 是 Percona Toolkit 中的一个工具,用于在不锁表的情况下对 MySQL 表进行在线模式更改(DDL)。它通过创建一个新的表并逐行复制数据来实现这一点,从而避免了长时间的表锁定。

## 使用
pt-online-schema-change \
  --alter "ADD COLUMN new_column INT" \
  D=mydatabase,t=mytable \
  --execute
1
2
3
4
5

# linux 常用命令

# 使用sed替换所有文件内容
cd /path/to/your/folder
sed -i 's/foo/bar/g' *

# 在BSD系统上,你需要提供一个备份扩展名,比如 -i '.bak',否则可能会损坏或者部分内容。
cd /path/to/your/folder
sed -i '.bak' 's/foo/bar/g' *

# 使用echo写入文件
## 覆写
echo 'xxx' > /path/to/file
## 追加
echo 'xxx' >> /path/to/file 

# 使用tee+sudo写入文件
## 覆写
sudo tee /path/to/file <<-'EOF'
xxx
EOF
## 追加
echo 'xxx' | sudo tee -a /path/to/file

# 其他命令
bash
unset HISTFILE
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 持续集成

使用专业的代码管理工具(gitsvn)是一个不错的选择,通过专业的代码管理工具+部署脚本,可以让系统实现持续开发集成,加速迭代。

# 自动部署PHP脚本参考

专业的 CI 固然好,在早期通过简单的脚本实现持续集成也是个不错的选择。

在服务端通过脚本拉取最新的仓库代码,实现持续集成功能。

# 下载自动部署脚本到项目目录
curl "https://modstart.com/devops/deploy?php=php" -o public/xxx.php
1
2

# 项目到新目录的迁移

在老的项目中执行一下命令

# 下载迁移脚本
curl "https://modstart.com/devops/migrate" -o migrate.php
# 执行迁移脚本
php migrate.php
1
2
3
4

# 项目迁移到新目录脚本生成

Git地址
项目原目录
项目新目录
# 1. 复制代码到新目录
git clone https://example.com/path/to/repo.git example.com.new
chmod -R www.www example.com.new
# 2. 复制资源到新目录
su www
cd example.com.new
touch storage/install.lock
cp -a ../example.com/.env .
php artisan migrate
php artisan modstart:module-install-all
curl "https://modstart.com/devops/deploy?php=php" -o public/xxx.php
cd ..
# 3. 迁移新资源
cd example.com
curl "https://modstart.com/devops/migrate" -o migrate.php
php migrate.php
mv public/data/* ../example.com.new/public/data/
cd ..
# 4. 切换到新目录
mv example.com example.com.old
mv example.com.new example.com
# 5. 手动重启服务,重启后台队列等任务
Last Updated: a month ago