diff --git a/运维/Linux/笔记/11.文本分析.md b/运维/Linux/笔记/11.文本分析.md index 6b73c9d..903c22f 100644 --- a/运维/Linux/笔记/11.文本分析.md +++ b/运维/Linux/笔记/11.文本分析.md @@ -1,130 +1,143 @@ -## 1、文本分析概览 +# 文本分析 -Linux 中很多日志分析和数据整理工作,都依赖文本分析命令。常见工具包括: +> Linux 日志分析与数据整理的常用命令。 -- `wc`:统计文本信息 -- `sort`:排序 -- `uniq`:去重或统计重复次数 -- `cut`:按列提取内容 +--- -它们经常和管道一起使用,是文本处理的基础组合。 +## 1. 命令概览 -## 2、`wc` +| 命令 | 用途 | +|------|------| +| `wc` | 统计行数、单词数、字节数 | +| `sort` | 文本排序 | +| `uniq` | 去重、统计重复次数 | +| `cut` | 按列提取 | -`wc` 用于统计文本的行数、单词数、字节数等。 +这些命令常通过管道组合使用,是文本处理的基础工具。 -### 2.1 常见选项 +--- -- `-l`:统计行数 -- `-w`:统计单词数 -- `-c`:统计字节数 +## 2. `wc` - 文本统计 -### 2.2 示例 +### 常用选项 -```shell +| 选项 | 说明 | +|------|------| +| `-l` | 统计行数 | +| `-w` | 统计单词数 | +| `-c` | 统计字节数 | + +### 示例 + +```bash +# 统计文件行数 wc -l access.log ``` -用于统计文件共有多少行。 +--- -## 3、`sort` +## 3. `sort` - 文本排序 -`sort` 用于对文本内容进行排序,默认输出到标准输出,不会直接修改原文件。 +> 默认输出到标准输出,不会修改原文件。 -### 3.1 常见选项 +### 常用选项 -- `-R`:随机排序 -- `-n`:按数值大小排序 -- `-h`:按人类可读格式排序,例如 `1K`、`2M` -- `-u`:排序后去重 -- `-r`:逆序排序 +| 选项 | 说明 | +|------|------| +| `-n` | 按数值排序 | +| `-h` | 按人类可读格式排序(1K、2M) | +| `-u` | 排序后去重 | +| `-k` | 按第几列排序 | +| `-t` | 指定分隔符 | +| `-r` | 逆序排序 | +| `-R` | 随机排序 | -### 3.2 示例 +### 示例 -```shell -sort -n scores.txt +```bash +sort -n scores.txt # 按数值排序 +sort -h disk_usage.txt # 按人类可读格式排序 ``` -```shell -sort -h disk_usage.txt -``` +--- -## 4、`uniq` +## 4. `uniq` - 去重与统计 -`uniq` 用于去除**相邻重复行**,因此通常会先配合 `sort` 使用。 +> 只能去除**相邻重复行**,需先配合 `sort` 使用。 -### 4.1 常见选项 +### 常用选项 -- `-c`:统计每行重复次数 -- `-d`:只显示重复行 -- `-u`:只显示不重复行 +| 选项 | 说明 | +|------|------| +| `-c` | 统计每行重复次数 | +| `-d` | 只显示重复行 | +| `-u` | 只显示不重复行 | -### 4.2 示例 +### 示例 -```shell +```bash +# 统计高频内容 sort access.log | uniq -c | sort -nr | head ``` -这个组合常用于统计高频内容。 +--- -## 5、`cut` +## 5. `cut` - 按列提取 -`cut` 用于按列或按字符位置提取文本。 +### 常用选项 -### 5.1 常见选项 +| 选项 | 说明 | +|------|------| +| `-d` | 指定分隔符 | +| `-f` | 按字段提取 | +| `-c` | 按字符位置提取 | -- `-d`:指定分隔符 -- `-c`:按字符位置提取 -- `-f`:按字段提取 +### 示例 -### 5.2 示例 - -按冒号分隔提取 `/etc/passwd` 的第一列和第三列: - -```shell +```bash +# 提取第一列和第三列(以冒号分隔) cut -d: -f1,3 /etc/passwd ``` -## 6、常见组合用法 +--- -### 6.1 统计访问次数最多的请求来源 +## 6. 实战组合 -```shell +### 统计访问次数最多的来源 + +```bash cut -d" " -f1 access_log | sort | uniq -c | sort -nr | head -3 ``` -这条命令的思路是: +**执行流程:** +1. `cut` → 提取第一列 +2. `sort` → 排序(让相同内容相邻) +3. `uniq -c` → 统计重复次数 +4. `sort -nr` → 按数字逆序 +5. `head -3` → 取前 3 条 -- 用 `cut` 取出第一列 -- 用 `sort` 排序 -- 用 `uniq -c` 统计重复次数 -- 再按数字逆序排序 -- 用 `head` 取前 3 条 +### 统计文件行数 -### 6.2 统计某个文件有多少行 - -```shell +```bash wc -l file.txt ``` -### 6.3 查看唯一用户列表 +### 获取唯一用户列表 -```shell +```bash cut -d: -f1 /etc/passwd | sort -u ``` -## 7、实战建议 +--- -- 只做统计:优先考虑 `wc` -- 只做排序:优先考虑 `sort` -- 去重或重复次数统计:优先考虑 `sort | uniq` -- 按列提取:优先考虑 `cut` -- 一旦涉及多步分析,优先用管道把几个命令串起来 +## 7. 小结 -## 8、小结 +| 场景 | 推荐命令 | +|------|---------| +| 统计数量 | `wc` | +| 排序 | `sort` | +| 去重/统计重复 | `sort \| uniq` | +| 按列提取 | `cut` | +| 多步分析 | 管道组合 | -- `wc` 用于统计 -- `sort` 用于排序 -- `uniq` 用于去重和统计重复行 -- `cut` 用于按列抽取文本 -- 这几个命令经常组合使用,是日志分析和文本整理的基础工具 +掌握这些命令,可高效处理各类日志与文本数据。 \ No newline at end of file diff --git a/运维/Linux/笔记/12.文本编辑-VIM.md b/运维/Linux/笔记/12.文本编辑-VIM.md index e9addc7..91b2213 100644 --- a/运维/Linux/笔记/12.文本编辑-VIM.md +++ b/运维/Linux/笔记/12.文本编辑-VIM.md @@ -1,179 +1,215 @@ -## 1、Vim 概览 +# 文本编辑 - Vim -Vim 是 Linux 中最常见的文本编辑器之一,特点是: +> Linux 中最常见的文本编辑器,适合终端快速编辑文件。 -- 几乎所有 Linux 环境都能遇到 -- 适合终端内快速编辑文件 -- 对运维排障、改配置、写脚本都很常用 +--- -学习 Vim 的关键,不是死记命令,而是先理解它的**模式切换**。 +## 1. 三种模式 -## 2、Vim 的常见模式 - -### 2.1 普通模式 - -打开 Vim 后默认进入普通模式,用于: - -- 移动光标 -- 删除、复制、粘贴 -- 查找 -- 执行命令 - -### 2.2 插入模式 - -用于输入和编辑文本。 - -常见进入方式: - -- `i`:在当前位置前插入 -- `a`:在当前位置后插入 -- `o`:在下一行插入 - -按 `Esc` 可以回到普通模式。 - -### 2.3 命令行模式 - -在普通模式下输入 `:` 进入,用于: - -- 保存 -- 退出 -- 查找替换 -- 设置选项 -- 执行外部命令 - -## 3、常用命令操作 - -### 3.1 文件读写 - -- `:w`:保存文件 -- `:q`:退出 -- `:wq`:保存并退出 -- `:q!`:强制退出不保存 -- `:w filename`:另存为其他文件 -- `:r filename`:把另一个文件内容读入当前文件 - -### 3.2 调用外部命令 - -- `:!command`:执行外部命令 -- `:r !command`:读取命令输出到当前文件 - -示例: - -```vim -:!ls -:r !date +``` +┌─────────────────────────────────────┐ +│ 插入模式 │ +│ (i / a / o 进入,输入文本) │ +└──────────────┬──────────────────────┘ + │ Esc + ▼ +┌─────────────────────────────────────┐ +│ 普通模式 │ +│ (默认模式,移动/删除/复制/查找) │ +└──────────────┬──────────────────────┘ + │ : 或 / + ▼ +┌─────────────────────────────────────┐ +│ 命令行模式 │ +│ (:w / :q / :s/// / !cmd) │ +└─────────────────────────────────────┘ ``` -### 3.3 删除、复制、粘贴 +### 1.1 普通模式(默认) -- `d`:删除 -- `dd`:删除当前行 -- `y`:复制 -- `yy`:复制当前行 -- `p`:在后面粘贴 -- `P`:在前面粘贴 +- 移动光标、删除、复制、粘贴、查找、执行命令 -### 3.4 撤销与恢复 +### 1.2 插入模式 -- `u`:撤销 -- `Ctrl + r`:恢复撤销的内容 -- `U`:某些版本中用于撤销当前行的修改,但现代 Vim 更常用 `u` +| 按键 | 说明 | +|------|------| +| `i` | 当前字符前插入 | +| `a` | 当前字符后插入 | +| `o` | 下一行插入新行 | +| `I` | 行首插入 | +| `A` | 行尾插入 | +| `O` | 上一行插入新行 | -## 4、常用设置项 +按 `Esc` 返回普通模式。 -以下命令通常在命令行模式执行: +### 1.3 命令行模式 -- `:set nu`:显示行号 -- `:set nonu`:取消行号 -- `:set ic`:查找时忽略大小写 -- `:set noic`:查找时区分大小写 -- `:set ai`:启用自动缩进 -- `:set noai`:关闭自动缩进 -- `:set list`:显示不可见字符 -- `:set nolist`:不显示不可见字符 +在普通模式下输入 `:` 或 `/` 进入,用于保存、退出、查找替换、设置选项、执行外部命令。 -### 4.1 加密说明 +--- -```vim -:set key=passwd +## 2. 基础操作 + +### 2.1 文件读写 + +| 命令 | 说明 | +|------|------| +| `:w` | 保存 | +| `:q` | 退出 | +| `:wq` | 保存并退出 | +| `:q!` | 强制退出不保存 | +| `:w filename` | 另存为 | +| `:r filename` | 读取文件内容到当前位置 | + +### 2.2 调用外部命令 + +| 命令 | 说明 | +|------|------| +| `:!command` | 执行外部命令 | +| `:r !command` | 读取命令输出到当前文件 | + +```bash +:!ls # 查看当前目录 +:r !date # 插入当前日期 ``` -可以为文件设置编辑时的加密口令。 +### 2.3 删除、复制、粘贴 -```vim -:set key= +| 命令 | 说明 | +|------|------| +| `d` | 删除 | +| `dd` | 删除当前行 | +| `dw` | 删除当前单词 | +| `y` | 复制 | +| `yy` | 复制当前行 | +| `yw` | 复制当前单词 | +| `p` | 粘贴到后面 | +| `P` | 粘贴到前面 | + +配合数字:`3dd` 删除 3 行,`2yy` 复制 2 行。 + +### 2.4 撤销与恢复 + +| 命令 | 说明 | +|------|------| +| `u` | 撤销 | +| `Ctrl + r` | 重做 | +| `U` | 撤销当前行修改 | + +--- + +## 3. 多行编辑(重点) + +### 3.1 可视模式(Visual Mode) + +在普通模式下按 `v` 进入可视模式,选择区域后可执行删除、复制等操作。 + +| 按键 | 说明 | +|------|------| +| `v` | 进入字符可视模式 | +| `V` | 进入行可视模式 | +| `Ctrl + v` | 进入块可视模式(多列编辑) | + +### 3.2 块可视模式(多列编辑) + +`Ctrl + v` 进入块可视模式后: + +1. **批量插入**:选中多行开头 → `I` → 输入内容 → `Esc` +2. **批量删除**:选中多列 → `d` 或 `x` +3. **批量替换**:选中多列 → `r` → 输入替换字符 + +**示例:在多行行首添加 `#` 注释** + +``` +1. Ctrl + v 进入块可视模式 +2. j/k 或 G 选择多行 +3. I 进入插入模式 +4. 输入 # +5. Esc 退出(所有选中行行首都会添加 #) ``` -取消口令。 +**示例:在多行行首删除 `#`** -不过这类方式现在并不是最常见的安全手段,实际生产中更常依赖系统权限和加密存储方案。 +``` +1. Ctrl + v 进入块可视模式 +2. 选择 # 所在列 +3. d 删除 +``` -## 5、查找与替换 +### 3.3 批量缩进 -### 5.1 查找 +| 命令 | 说明 | +|------|------| +| `>` |向右缩进 | +| `<` |向左缩进 | +| `3>` |连续 3 行向右缩进 | +| `=` | 自动缩进选中区域 | -在普通模式下输入: +--- -```vim +## 4. 查找与替换 + +### 4.1 查找 + +``` /关键字 +n # 下一个 +N # 上一个 ``` -然后: +### 4.2 替换 -- `n`:向下查找下一个 -- `N`:向上查找上一个 - -### 5.2 替换 - -基本格式: - -```vim +``` :s/旧内容/新内容/修饰符 ``` -### 5.3 常见修饰符 +| 修饰符 | 说明 | +|--------|------| +| `i` | 忽略大小写 | +| `g` | 全局替换(一行内全部) | +| `gc` | 逐个确认替换 | -- `i`:忽略大小写 -- `g`:一行内全局替换 -- `gc`:替换前逐个确认 +### 4.3 常用示例 -### 5.4 示例 - -替换当前行第一个 `old`: - -```vim -:s/old/new/ +```bash +:s/old/new/ # 替换当前行第一个 +:s/old/new/g # 替换当前行全部 +:%s/old/new/g # 替换全文 +:%s/old/new/gc # 替换全文(逐个确认) +:1,5s/old/new/g # 替换第 1-5 行 ``` -替换当前行全部 `old`: +--- -```vim -:s/old/new/g +## 5. 常用设置 + +| 命令 | 说明 | +|------|------| +| `:set nu` | 显示行号 | +| `:set nonu` | 隐藏行号 | +| `:set ic` | 忽略大小写查找 | +| `:set ai` | 自动缩进 | +| `:set list` | 显示不可见字符 | +| `:set wrap` | 自动换行 | + +### 5.1 文件加密 + +```bash +:set key=password # 设置密码 +:set key= # 取消密码 ``` -替换全文所有 `old`: +> 注意:生产环境建议使用系统权限和专业的加密方案。 -```vim -:%s/old/new/g -``` +--- -替换全文并逐个确认: +## 6. 小结 -```vim -:%s/old/new/gc -``` +| 场景 | 关键命令 | +|------|---------| +| 基础编辑 | `i`、`a`、`o`、`dd`、`yy`、`p` | +| 多行编辑 | `Ctrl + v` + `I` / `d` | +| 查找替换 | `/`、`:s///g` | +| 保存退出 | `:wq`、`:q!` | -## 6、日常使用建议 - -- 改系统配置文件前,先备份 -- 编辑大文件时优先用查找和行号定位 -- 做全局替换时,尽量先用 `gc` 确认,避免误改 -- 需要长期使用时,可以把常用设置写入 `~/.vimrc` - -## 7、小结 - -- Vim 的核心是理解普通模式、插入模式和命令行模式 -- `:w`、`:q`、`:wq`、`:q!` 是最常用的保存退出命令 -- `dd`、`yy`、`p`、`u` 是高频编辑命令 -- `/` 查找和 `:%s///g` 替换是最常用功能 -- 熟练掌握 Vim 后,终端下改配置文件会高效很多 +掌握普通模式、插入模式、命令行模式 + 块可视模式,即可高效完成大多数编辑任务。 \ No newline at end of file diff --git a/运维/Linux/笔记/3.硬件管理.md b/运维/Linux/笔记/3.硬件管理.md index efd6727..fc2f293 100644 --- a/运维/Linux/笔记/3.硬件管理.md +++ b/运维/Linux/笔记/3.硬件管理.md @@ -1,20 +1,164 @@ -## 1、硬件管理概览 +# 硬件管理 -在 Linux 中查看硬件信息,常见关注点主要有三类: +> 本文档涵盖服务器硬件基础知识与 Linux 系统硬件信息查看方法。 -- CPU:核心数、线程数、架构、缓存、是否虚拟化 -- 内存:总量、可用量、缓存、Swap 使用情况 -- 磁盘:设备、分区、文件系统类型、挂载点 +--- -做系统巡检或排障时,通常也是按这个顺序查看。 +## 第一部分:硬件基础知识 -## 2、查看 CPU 信息 +### 1. CPU -### 2.1 使用 `lscpu` +#### 1.1 指令集 -`lscpu` 是查看 CPU 信息最直观的命令,适合快速了解当前机器的处理器概况。 +| 类型 | 代表架构 | 特点 | +|------|---------|------| +| **CISC**(复杂指令集) | X86、AMD64 | 指令丰富但复杂,执行速度慢,编译程序复杂 | +| **RISC**(精简指令集) | ARM | 指令精简,MAC 已使用,Windows 生态待完善 | -```shell +#### 1.2 主频 + +CPU 主频是 CPU 的时钟频率,单位 Hz。主频越高,CPU 运算速度越快。 + +--- + +### 2. 存储 + +#### 2.1 ROM(只读存储器) + +- **作用**:存放 BIOS 信息 +- **特点**:断电后数据不丢失 + +#### 2.2 RAM(随机存取存储器) + +##### DRAM + +- **作用**:服务器的内存条 +- **带宽计算**:内存带宽 = 内存总线频率 × 数据总线位数 / 8 + +##### SRAM + +- **作用**:作为 CPU 内的高速缓存(Cache) + +##### DRAM vs SRAM + +| 特性 | DRAM | SRAM | +|------|------|------| +| 刷新电路 | 需要 | 不需要 | +| 性能 | 较低 | 高 | +| 价格 | 便宜 | 贵 | +| 集成度 | 高 | 低 | + +##### 内存分级 + +``` +CPU 寄存器(L0) → L1 Cache → L2 Cache → L3 Cache → 内存(DRAM) → 本地磁盘 → 远程存储(NAS) +``` + +**为什么需要分级?** CPU 处理速度远快于 IO,为避免 IO 阻塞,CPU 优先从高速缓存读取数据。 + +**缓存未命中时**:CPU 从 L1 找不到数据时会去 L2 查找,找到后会复制到 L1 以便后续快速访问。 + +--- + +### 3. 硬盘 + +#### 3.1 接口类型 + +| 接口 | 全称 | 速度 | +|------|------|------| +| **SATA** | Serial ATA | Ⅰ: 1.5Gb/s,Ⅱ: 3Gb/s,Ⅲ: 6Gb/s | +| **SAS** | Serial Attached SCSI | 更高 | +| **M.2** | 固态硬盘专用接口 | 10Gb/s | + +> 注意:以上为接口最大带宽上限,不代表实际速度。 + +#### 3.2 结构分类 + +| 类型 | 组成 | 特点 | +|------|------|------| +| **机械 HDD** | 盘片、磁头、马达 | 成本低,容量大,寿命长 | +| **固态 SSD** | 闪存芯片、主控 | 速度快,无噪音,抗震动 | + +#### 3.3 关键参数 + +- 容量、转速、传输速率、缓存 + +#### 3.4 磁盘尺寸 + +| 尺寸 | 应用场景 | 特点 | +|------|---------|------| +| **3.5 寸** | 企业级 | 转速快、容量大、需要外接电源 | +| **2.5 寸** | 个人电脑/便携 | 无需外接电源,支持热插拔 | + +--- + +### 4. 网卡 + +| 类型 | 说明 | +|------|------| +| 板载网卡 | 主板集成 | +| PCIE 拓展卡 | 通过 PCIE 插槽扩展 | + +--- + +### 5. 远程管理卡(BMC) + +- **全称**:Baseboard Manager Controller +- **特点**:服务器关机状态下也能运行 +- **协议**:IPMI +- **功能**:远程访问、查看状态、调整 BIOS、配置 RAID、安装系统、重启机器 + +--- + +### 6. 阵列卡(RAID 卡) + +- **作用**:实现磁盘阵列(RAID),释放 CPU 资源,提供缓存和阵列保护 +- **功能**:RAID 建立/重建、错误检测、故障磁盘自动监测 + +#### RAID 级别对比 + +| 级别 | 最少盘数 | 冗余 | 性能 | 适用场景 | +|------|---------|------|------|---------| +| **RAID 0** | 2 | 无 | 最高 | 不考虑数据安全的场景 | +| **RAID 1** | 2 | 镜像 | 读快写慢 | 系统盘、关键数据 | +| **RAID 5** | 3 | 校验 | 平衡 | 通用业务数据 | +| **RAID 6** | 4 | 双校验 | 较高 | 高可靠性场景 | +| **RAID 10** | 4 | 镜像+条带 | 高 | 数据库、高 IO 应用 | + +--- + +### 7. 电源 + +| 类型 | 说明 | +|------|------| +| 服务器电源 | 通常采用双电源冗余 | +| UPS(不间断电源) | 稳压,市电异常时提供备用供电 | + +--- + +### 8. 显卡 + +| 类型 | 说明 | +|------|------| +| 亮机卡 | 服务器显示输出用,通常为集成显卡 | +| 专业卡 | 图形渲染用,非服务器必选 | + +--- + +### 9. 机柜 + +- **计量单位**:U(1U ≈ 4.5cm) +- **用途**:标准 19 英寸机架式服务器安装 + +--- + +## 第二部分:Linux 硬件信息查看 + +### 2.1 查看 CPU 信息 + +#### 使用 `lscpu` + +```bash [root@tencentos ~]# lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit @@ -36,179 +180,132 @@ L2 cache: 4096K L3 cache: 36608K ``` -### 2.2 重点字段说明 +#### 关键字段说明 -- `Architecture`:CPU 架构,例如 `x86_64` 表示 64 位架构 -- `CPU op-mode(s)`:CPU 支持运行 32 位和 64 位操作系统 -- `CPU(s)`:逻辑 CPU 数量,不一定等于物理核心数 -- `Thread(s) per core`:每个核心的线程数,开启超线程时通常大于 1 -- `Core(s) per socket`:每个物理 CPU 的核心数 -- `Socket(s)`:物理 CPU 颗数 -- `Model name`:CPU 型号 -- `Hypervisor vendor`:当前是否运行在虚拟化环境中,例如 KVM -- `L1/L2/L3 cache`:不同层级的 CPU 缓存大小 +| 字段 | 含义 | +|------|------| +| Architecture | CPU 架构,如 x86_64 | +| CPU(s) | 逻辑 CPU 数量 | +| Thread(s) per core | 每核心线程数(超线程 >1) | +| Core(s) per socket | 每颗物理 CPU 的核心数 | +| Socket(s) | 物理 CPU 颗数 | +| Model name | CPU 型号 | +| Hypervisor vendor | 虚拟化环境(如 KVM) | +| L1/L2/L3 cache | 各层级缓存大小 | -### 2.3 使用 `/proc/cpuinfo` +#### 使用 `/proc/cpuinfo` -如果你想看更底层、更详细的信息,可以直接查看: - -```shell +```bash [root@tencentos ~]# cat /proc/cpuinfo ``` -这个文件会按每个逻辑 CPU 分别列出详细参数,例如: +可查看:processor、vendor_id、model name、cpu MHz、cache size、flags、bugs 等详细信息。 -- `processor`:逻辑 CPU 编号 -- `vendor_id`:CPU 厂商 -- `model name`:CPU 型号名称 -- `cpu MHz`:当前频率 -- `cache size`:缓存大小 -- `flags`:CPU 支持的指令集特性 -- `bugs`:已知 CPU 漏洞或风险标记 -- `address sizes`:物理地址和虚拟地址位数 +#### 使用场景建议 -### 2.4 使用场景建议 +- **快速巡检**:`lscpu` +- **深度分析**:`/proc/cpuinfo` +- **判断虚拟机**:关注 `Hypervisor vendor` +- **计算核心/线程数**:结合 CPU(s) × Thread(s) × Core(s) × Socket(s) -- **快速巡检**:优先用 `lscpu` -- **查看更细节的 CPU 参数**:使用 `/proc/cpuinfo` -- **判断是否是虚拟机**:关注 `Hypervisor vendor` -- **判断核心、线程、物理 CPU 数**:结合 `CPU(s)`、`Thread(s) per core`、`Core(s) per socket`、`Socket(s)` 一起看 +--- -## 3、查看内存信息 +### 2.2 查看内存信息 -### 3.1 使用 `free -h` +#### 使用 `free -h` -`free` 是查看内存最常用的命令,`-h` 可以用更适合阅读的单位显示。 - -```shell +```bash [root@tencentos ~]# free -h total used free shared buff/cache available Mem: 1.7Gi 323Mi 341Mi 35Mi 1.0Gi 1.2Gi Swap: 0B 0B 0B ``` -### 3.2 重点字段说明 +#### 关键字段说明 -- `total`:内存总量 -- `used`:已使用内存 -- `free`:完全空闲的内存 -- `shared`:共享内存 -- `buff/cache`:被缓冲区和页缓存占用的内存 -- `available`:当前可供应用程序使用的内存,通常比 `free` 更有参考价值 -- `Swap`:交换分区使用情况 +| 字段 | 含义 | +|------|------| +| total | 内存总量 | +| used | 已使用内存 | +| free | 完全空闲 | +| shared | 共享内存 | +| buff/cache | 缓冲区和页缓存 | +| available | 可用内存(推荐关注) | +| Swap | 交换分区 | -### 3.3 使用 `/proc/meminfo` +#### 使用 `/proc/meminfo` -如果需要更完整的内存明细,可以查看: - -```shell +```bash [root@tencentos ~]# cat /proc/meminfo ``` -其中比较常见的字段有: +常见字段:MemTotal、MemFree、MemAvailable、Buffers、Cached、SwapTotal、SwapFree、Slab、Dirty -- `MemTotal`:物理内存总量 -- `MemFree`:当前空闲内存 -- `MemAvailable`:当前可用内存 -- `Buffers`:块设备缓冲区使用量 -- `Cached`:页缓存使用量 -- `SwapTotal`:Swap 总量 -- `SwapFree`:Swap 剩余量 -- `Slab`:内核 slab 缓存占用 -- `Dirty`:等待写回磁盘的数据量 +#### 排障建议 -### 3.4 排障时怎么看内存 +- 日常巡检:`free -h` +- 重点关注 `available` 而非 `free` +- Swap 持续上升需关注内存压力 -- 日常巡检时优先看 `free -h` -- 不要只盯着 `free`,应重点关注 `available` -- 如果 `Swap` 持续上升,通常需要关注内存压力 -- 如果想进一步排查缓存、页表、HugePages 等问题,再看 `/proc/meminfo` +--- -## 4、查看磁盘与分区信息 +### 2.3 查看磁盘与分区 -### 4.1 使用 `lsblk` +#### 使用 `lsblk` -`lsblk` 用于查看块设备、分区和挂载关系,是查看磁盘结构时最常用的命令之一。 - -```shell +```bash [root@tencentos ~]# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT vda 253:0 0 50G 0 disk └─vda1 253:1 0 50G 0 part / ``` -### 4.2 重点字段说明 +#### 使用 `/proc/partitions` -- `NAME`:设备名称 -- `MAJ:MIN`:主设备号和次设备号 -- `RM`:是否可移动设备,`1` 表示是,`0` 表示否 -- `SIZE`:设备或分区大小 -- `RO`:是否只读 -- `TYPE`:设备类型,例如 `disk`、`part` -- `MOUNTPOINT`:挂载点 - -### 4.3 使用 `/proc/partitions` - -```shell +```bash [root@tencentos ~]# cat /proc/partitions major minor #blocks name 253 0 52428800 vda 253 1 52427759 vda1 ``` -这个文件更偏底层,适合查看系统识别到的块设备和分区情况。 +#### 使用 `blkid` -### 4.4 使用 `blkid` - -`blkid` 可以查看设备的文件系统类型、UUID、分区 UUID 等信息。 - -```shell +```bash [root@tencentos ~]# blkid /dev/vda1: UUID="ded6c45d-0699-43e5-bc44-f31c21449dcc" BLOCK_SIZE="4096" TYPE="ext4" PARTUUID="5f3d9d70-01" ``` -### 4.5 `blkid` 常见用途 +- 查看文件系统类型(ext4、xfs) +- 获取 UUID 用于 /etc/fstab -- 查看文件系统类型,例如 `ext4`、`xfs` -- 获取 `UUID`,便于写入 `/etc/fstab` -- 排查磁盘挂载失败、设备识别异常等问题 +--- -## 5、常用巡检思路 +### 2.4 常用巡检命令 -如果只是做一次简单的硬件巡检,通常可以按下面的顺序: - -### 5.1 看 CPU - -```shell +```bash +# 1. 看 CPU lscpu -``` -关注:架构、核心数、线程数、虚拟化信息。 - -### 5.2 看内存 - -```shell +# 2. 看内存 free -h -``` -关注:总量、可用内存、Swap 是否被使用。 - -### 5.3 看磁盘 - -```shell +# 3. 看磁盘 lsblk blkid ``` -关注:磁盘和分区结构、挂载点、文件系统类型。 +--- -## 6、小结 +## 小结 -- `lscpu` 适合快速查看 CPU 总体情况 -- `/proc/cpuinfo` 更详细,适合深入分析 CPU 参数 -- `free -h` 是查看内存使用最常用的命令 -- `/proc/meminfo` 提供更细的内存统计信息 -- `lsblk` 适合看块设备和挂载关系 -- `blkid` 适合看 UUID 和文件系统类型 +| 命令 | 用途 | +|------|------| +| `lscpu` | CPU 概况 | +| `/proc/cpuinfo` | CPU 详细信息 | +| `free -h` | 内存使用情况 | +| `/proc/meminfo` | 内存详细统计 | +| `lsblk` | 块设备与挂载 | +| `blkid` | UUID 与文件系统类型 | -这几个命令已经能覆盖 Linux 中大部分基础硬件巡检场景。 +掌握以上命令,可覆盖 Linux 基础硬件巡检的常见需求。 \ No newline at end of file diff --git a/运维/Linux/脚本/Shell实现进度条.sh b/运维/Shell脚本/Shell实现进度条.sh similarity index 100% rename from 运维/Linux/脚本/Shell实现进度条.sh rename to 运维/Shell脚本/Shell实现进度条.sh diff --git a/运维/Linux/脚本/bytes.sh b/运维/Shell脚本/bytes.sh similarity index 100% rename from 运维/Linux/脚本/bytes.sh rename to 运维/Shell脚本/bytes.sh diff --git a/运维/Linux/脚本/change.sh b/运维/Shell脚本/change.sh similarity index 100% rename from 运维/Linux/脚本/change.sh rename to 运维/Shell脚本/change.sh diff --git a/运维/Linux/脚本/createES.sh b/运维/Shell脚本/createES.sh similarity index 100% rename from 运维/Linux/脚本/createES.sh rename to 运维/Shell脚本/createES.sh diff --git a/运维/Linux/脚本/echo显示带颜色文字方法.sh b/运维/Shell脚本/echo显示带颜色文字方法.sh similarity index 100% rename from 运维/Linux/脚本/echo显示带颜色文字方法.sh rename to 运维/Shell脚本/echo显示带颜色文字方法.sh diff --git a/运维/Linux/脚本/判断上一条语句是否执行成功.sh b/运维/Shell脚本/判断上一条语句是否执行成功.sh similarity index 100% rename from 运维/Linux/脚本/判断上一条语句是否执行成功.sh rename to 运维/Shell脚本/判断上一条语句是否执行成功.sh diff --git a/运维/Linux/脚本/判断变量为空.sh b/运维/Shell脚本/判断变量为空.sh similarity index 100% rename from 运维/Linux/脚本/判断变量为空.sh rename to 运维/Shell脚本/判断变量为空.sh diff --git a/运维/Linux/脚本/HTTTP探测脚本.md b/运维/Shell脚本/常用脚本/HTTTP探测脚本.md similarity index 100% rename from 运维/Linux/脚本/HTTTP探测脚本.md rename to 运维/Shell脚本/常用脚本/HTTTP探测脚本.md diff --git a/运维/Linux/脚本/服务器初始化.sh b/运维/Shell脚本/服务器初始化.sh similarity index 100% rename from 运维/Linux/脚本/服务器初始化.sh rename to 运维/Shell脚本/服务器初始化.sh diff --git a/运维/加解密/OpenSSL/OpenSSL.md b/运维/加解密/OpenSSL/OpenSSL.md new file mode 100644 index 0000000..2e944fa --- /dev/null +++ b/运维/加解密/OpenSSL/OpenSSL.md @@ -0,0 +1,503 @@ +# OpenSSL + +> OpenSSL 是开源的 SSL/TLS 工具包,用于实现加密通信和数据安全。 + +--- + +## 1. 加密算法概述 + +### 1.1 对称加密 + +**特性**: +- 加密和解密使用同一个密钥,效率高 +- 将原始数据分割成固定大小的块,逐个进行加密 + +**缺陷**: +- 密钥过多:需要管理大量密钥 +- 密钥分发:安全分发密钥困难 +- 数据来源无法确认 + +**常见算法**: + +| 算法 | 密钥长度 | 说明 | +|------|---------|------| +| DES | 56 bits | 废弃,安全性低 | +| 3DES | 168 bits | 废弃,兼容性差 | +| **AES** | 128/192/256 bits | 当前主流 | +| Blowfish | 可变 | 开源免费 | +| Twofish | 128/192/256 bits | AES 候选 | + +**使用示例**: +```bash +# 加密 +openssl enc -aes-256-cbc -in plain.txt -out cipher.bin -pass pass:mypassword + +# 解密 +openssl enc -d -aes-256-cbc -in cipher.bin -pass pass:mypassword +``` + +### 1.2 非对称加密(公钥加密) + +#### 1.2.1 基础概念 + +**密钥对**: +- **公钥**(public key):公开给所有人,用于加密 +- **私钥**(secret key):自己留存,用于解密/签名 + +**功能**: +- 数据加密:适合加密较小数据(如对称密钥) +- 数字签名:确认发送方身份 + +**缺点**:密钥长、算法复杂、效率低 + +#### 1.2.2 加密原理 + +``` +接收者 B: + 1. 生成密钥对 (公钥 Pb, 私钥 Sb) + 2. 公开公钥 Pb,保管好私钥 Sb + +发送者 A: + 1. 使用接收者公钥 Pb 加密数据 M + 2. 发送加密数据 Pb(M) 给 B + +接收者 B: + 1. 使用私钥 Sb 解密 + 2. 得到原始数据 M = Sb(Pb(M)) +``` + +#### 1.2.3 数字签名原理 + +``` +发送者 A: + 1. 生成密钥对 (公钥 Pa, 私钥 Sa) + 2. 公开公钥 Pa,保管好私钥 Sa + 3. 使用私钥 Sa 对数据 M 签名 + 4. 发送 (M, Sa(M)) 给接收者 B + +接收者 B: + 1. 使用发送者公钥 Pa 验证签名 + 2. 验证通过 = 确认数据来自 A 且未被篡改 +``` + +> **关键**:私钥签名,公钥验证。签名只能由私钥产生,任何人可用公钥验证。 + +#### 1.2.4 常见算法对比 + +| 算法 | 密钥长度 | 用途 | 安全性 | 性能 | +|------|---------|------|--------|------| +| **RSA** | 2048/4096 bits | 加密/签名 | 高 | 慢 | +| **DSA** | 1024/2048 bits | 仅签名 | 高 | 快 | +| **ECC** | 256/384 bits | 加密/签名 | 高 | 快 | +| **Ed25519** | 256 bits | 仅签名 | 最高 | 最快 | + +#### 1.2.5 RSA 算法详解 + +**数学原理**: +- 基于大整数分解难题 +- 两个大素数相乘容易,但分解乘积困难 +- RSA 取名来自 Rivest、Shamir、Adleman 三位发明者 + +**密钥生成过程**: +``` +1. 选择两个大素数 p 和 q +2. 计算 n = p × q +3. 计算 φ(n) = (p-1)(q-1) +4. 选择 e,满足 1 < e < φ(n) 且 gcd(e, φ(n)) = 1 +5. 计算 d,满足 d × e ≡ 1 (mod φ(n)) +6. 公钥 = (n, e) +7. 私钥 = (n, d) +``` + +**数学公式**: +``` +加密:M^e mod n = C +解密:C^d mod n = M +签名:H(M)^d mod n = S +验证:S^e mod n = H(M) +``` + +**密钥长度选择**: + +| 密钥长度 | 安全性 | 推荐场景 | +|----------|--------|----------| +| 1024 bits | 不安全 | 已废弃 | +| 2048 bits | 安全 | 个人/小型业务 | +| 4096 bits | 高安全 | 金融/政府 | + +#### 1.2.6 ECC(椭圆曲线密码学) + +**优势**: +- 相同安全强度下,密钥更短 +- 256-bit ECC ≈ 2048-bit RSA +- 计算更快,资源消耗更低 + +**曲线类型**: + +| 曲线 | 密钥长度 | 应用 | +|------|---------|------| +| secp256r1 (P-256) | 256 bits | 通用 | +| secp384r1 (P-384) | 384 bits | 高安全 | +| secp521r1 (P-521) | 521 bits | 最高安全 | + +**OpenSSL 生成 ECC 密钥**: +```bash +# 生成 ECC 私钥(secp256r1) +openssl genpkey -algorithm EC -out ec Private key.pem -pkeyopt ec_paramgen_curve:secp256r1 + +# 生成 ECC CSR +openssl req -new -key ec_private.key -out request.csr + +# 自签名 ECC 证书 +openssl req -new -x509 -key ec_private.key -out cert.pem +``` + +#### 1.2.7 Ed25519(现代签名算法) + +**特点**: +- 现代签名算法,高性能 +- 密钥短(256 bits),签名短(64 bytes) +- 安全性极高,无侧信道攻击风险 + +**生成密钥**: +```bash +# Ed25519 私钥 +openssl genpkey -algorithm ed25519 -out ed25519key.pem + +# 自签名证书 +openssl req -new -x509 -key ed25519key.pem -out cert.pem +``` + +#### 1.2.8 非对称加密实战 + +**RSA 加密文件**: +```bash +# 方法1:使用公钥加密 +openssl rsautl -encrypt -pubin -inkey pub.key -in plaintext.txt -out ciphertext.bin + +# 方法2:使用私钥签名 +openssl rsautl -sign -inkey priv.key -in data.txt -out signature.bin +``` + +**AES 密钥交换(混合加密)**: +```bash +# 1. 生成随机 AES 密钥 +openssl rand -hex 32 > aes.key + +# 2. 用接收者公钥加密 AES 密钥 +openssl rsautl -encrypt -pubin -inkey recipient_pub.key -in aes.key -out aes.key.enc + +# 3. 用 AES 加密数据 +openssl enc -aes-256-cbc -in data.txt -out data.enc -pass file:aes.key + +# 接收者解密 +# 1. 用私钥解密 AES 密钥 +openssl rsautl -decrypt -inkey recipient_priv.key -in aes.key.enc -out aes.key + +# 2. 用 AES 解密数据 +openssl enc -d -aes-256-cbc -in data.enc -pass file:aes.key +``` + +#### 1.2.9 算法选择建议 + +| 场景 | 推荐算法 | 原因 | +|------|---------|------| +| HTTPS/TLS | ECDHE + RSA/ECDSA | 性能与安全平衡 | +| 代码签名 | Ed25519 或 RSA-2048 | 高安全性 | +| 文档签名 | Ed25519 | 快速、签名短 | +| 密钥交换 | ECDH 或 RSA | 成熟稳定 | +| IoT 设备 | ECC | 资源受限 | + +--- + +## 2. 非对称加密算法详解 + +### 2.1 RSA + +**生成 RSA 密钥**: +```bash +# 标准 RSA 私钥(2048位) +openssl genrsa -out rsa_private.key 2048 + +# 带密码保护的 RSA 私钥 +openssl genrsa -aes256 -out rsa_private.key 2048 + +# 提取公钥 +openssl rsa -in rsa_private.key -pubout -out rsa_public.key + +# 查看密钥信息 +openssl rsa -in rsa_private.key -noout -text +``` + +**加解密**: +```bash +# 加密(使用公钥) +openssl rsautl -encrypt -pubin -inkey pub.key -in plaintext.txt -out encrypted.bin + +# 解密(使用私钥) +openssl rsautl -decrypt -inkey priv.key -in encrypted.bin -out decrypted.txt + +# 签名(使用私钥) +openssl rsautl -sign -inkey priv.key -in data.txt -out signature.bin + +# 验证(使用公钥) +openssl rsautl -verify -pubin -inkey pub.key -in signature.bin -signed data.txt +``` + +### 2.2 DSA + +> DSA 仅用于签名,不能加密解密。 + +```bash +# 生成 DSA 参数 +openssl dsaparam -out dsaparam.pem 2048 + +# 生成 DSA 私钥 +openssl gendsaparam dsaparam.pem -out dsa_private.key + +# 生成 CSR +openssl req -new -key dsa_private.key -out request.csr + +# 签名 +openssl dgst -sha256 -sign dsa_private.key -out signature.bin data.txt +``` + +### 2.3 DH(密钥交换) + +```bash +# 生成 DH 参数 +openssl dhparam -out dhparam.pem 2048 + +# 生成 DH 私钥 +openssl genpkey -paramfile dhparam.pem -out dh_private.key + +# 提取公钥 +openssl pkey -in dh_private.key -pubout -out dh_public.key +``` + +--- + +## 3. 单向哈希算法 + +### 3.1 基础概念 + +将任意数据转换为固定长度的"指纹"(摘要)。 + +**特性**: +- 任意长度输入,固定长度输出 +- 雪崩效应:数据微小改变,指纹变化巨大 +- 单向性:无法从指纹恢复原数据 + +### 3.2 常见算法 + +| 算法 | 输出长度 | 安全性 | +|------|---------|--------| +| md5 | 128 bits | 不安全,仅用于兼容性 | +| sha1 | 160 bits | 弱安全,不推荐 | +| sha256 | 256 bits | 推荐 | +| sha512 | 512 bits | 推荐 | +| blake2b | 可变 | 高性能,高安全 | + +### 3.3 常用命令 + +```bash +echo -n "hello" | md5sum +sha256sum file +openssl dgst -sha256 file +带密钥的哈希(HMAC) +openssl dgst -sha256 -hmac "mykey" file +``` + +--- + +## 4. 密钥交换 + +### 4.1 DH(Diffie-Hellman) + +让双方通过不安全信道建立共享密钥。 + +**原理**: +``` +A: 选取 g, p → 计算 g^a%p → 发送给 B +B: 选取 g, p → 计算 g^b%p → 发送给 A +A: 计算 (g^b%p)^a%p = g^ab%p → 密钥 +B: 计算 (g^a%p)^b%p = g^ab%p → 密钥 +``` + +> 私密数据 a、b 在生成密钥后丢弃,不长期存储,安全性高。 + +### 4.2 ECDH(椭圆曲线 DH) + +更短密钥,更高安全性。 + +--- + +## 5. TLS/SSL 协议 + +### 5.1 协议版本 + +| 版本 | 年份 | 状态 | +|------|------|------| +| SSL 1.0 | 1994 | 从未公开 | +| SSL 2.0 | 1995 | 废弃,有漏洞 | +| SSL 3.0 | 1996 | 废弃(POODLE) | +| TLS 1.0 | 1999 | 废弃(BEAST) | +| TLS 1.1 | 2006 | 废弃 | +| **TLS 1.2** | 2008 | 推荐 | +| **TLS 1.3** | 2018 | 当前最佳 | + +### 5.2 TLS 1.3 改进 + +- 更快的握手(1-RTT / 0-RTT) +- 移除不安全算法(MD5、SHA1、RC4) +- 前向保密(FS)强制 +- 简化密码套件 + +### 5.3 密码套件格式 + +``` +TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + │ │ │ │ │ + │ │ │ │ 摘要算法 + │ │ │ 对称加密算法 + │ │ 密钥协商算法 + │ 签名算法 + 密钥交换算法 +``` + +--- + +## 6. CA 与证书 + +### 6.1 PKI 架构 + +``` +CA(证书颁发机构) + ├── Root CA(根CA)- 自签,可信锚点 + ├── Intermediate CA(中间CA)- 签名子CA + └── 最终用户/服务器 +``` + +### 6.2 证书格式 + +| 格式 | 说明 | +|------|------| +| PEM | Base64 文本 | +| DER | 二进制 | +| PKCS#12 | 含私钥(.pfx/.p12) | +| PKCS#7 | 证书链(.p7b/.p7c) | + +### 6.3 自建 CA 与证书管理 + +```bash +# 创建目录 +mkdir -p /etc/pki/CA/{certs,crl,newcerts,private} +touch /etc/pki/CA/index.txt +echo 01 > /etc/pki/CA/serial + +# CA 私钥 +openssl genrsa -aes256 -out /etc/pki/CA/private/cakey.pem 2048 + +# 自签 CA +openssl req -new -x509 -key /etc/pki/CA/private/cakey.pem -out /etc/pki/CA/cacert.pem -days 3650 + +# 用户申请证书 +openssl genrsa -out user.key 2048 +openssl req -new -key user.key -out user.csr +openssl ca -in user.csr -out user.crt -days 365 +``` + +### 6.4 证书吊销 + +```bash +# 吊销证书 +openssl ca -revoke /etc/pki/CA/newcerts/11.pem + +# 查看状态 +openssl ca -status 11 + +# 生成 CRL +openssl ca -gencrl -out /etc/pki/CA/crl/crl.pem +``` + +--- + +## 7. 实战应用 + +### 7.1 生成强密钥 + +```bash +# RSA 4096位 +openssl genrsa -aes256 4096 > server.key + +# ECC +openssl genpkey -algorithm EC -out ec.key -pkeyopt ec_paramgen_curve:secp256r1 + +# Ed25519 +openssl genpkey -algorithm ed25519 -out ed25519.key +``` + +### 7.2 测试 TLS 连接 + +```bash +openssl s_client -connect example.com:443 -showcerts +openssl s_client -tls1_2 -connect example.com:443 +``` + +### 7.3 随机数与哈希 + +```bash +openssl rand -hex 32 +openssl dgst -sha256 file +``` + +--- + +## 8. 常用命令速查 + +### 8.1 密钥操作 + +| 场景 | 命令 | +|------|------| +| 生成 RSA 私钥 | `openssl genrsa -out key.pem 2048` | +| 生成 RSA 私钥(带密码) | `openssl genrsa -aes256 -out key.pem 2048` | +| 提取公钥 | `openssl rsa -in key.pem -pubout -out pub.key` | +| 查看密钥 | `openssl rsa -in key.pem -noout -text` | + +### 8.2 证书操作 + +| 场景 | 命令 | +|------|------| +| 生成 CSR | `openssl req -new -key key.pem -out req.csr` | +| 自签证书 | `openssl req -new -x509 -key key.pem -out cert.pem` | +| CA 签发 | `openssl ca -in req.csr -out cert.pem` | +| 验证证书 | `openssl verify -CAfile ca.pem cert.pem` | +| 查看证书 | `openssl x509 -in cert.pem -noout -text` | + +### 8.3 加密/签名 + +| 场景 | 命令 | +|------|------| +| RSA 加密 | `openssl rsautl -encrypt -pubin -inkey pub.key -in f.txt -out f.enc` | +| RSA 解密 | `openssl rsautl -decrypt -inkey priv.key -in f.enc -out f.txt` | +| 签名 | `openssl dgst -sha256 -sign priv.key -out sig.bin data.txt` | +| 验证 | `openssl dgst -sha256 -verify pub.key -signature sig.bin data.txt` | + +--- + +## 9. 小结 + +| 类别 | 用途 | 推荐算法 | +|------|------|----------| +| 对称加密 | 数据加密 | AES-256 | +| 非对称加密 | 密钥交换 | RSA-2048 / ECDH | +| 数字签名 | 身份认证 | Ed25519 / RSA-2048 / ECDSA | +| 单向哈希 | 完整性校验 | SHA-256 | +| 密钥交换 | 协商会话密钥 | ECDH / X25519 | + +掌握非对称加密的核心概念: +- **公钥加密,私钥解密**:保密通信 +- **私钥签名,公钥验证**:身份认证 +- **混合加密**:用对称加密数据,用非对称加密密钥,兼顾效率与安全 + +> 生产环境推荐:TLS 1.3 + ECDHE-ECDSA + AES-256-GCM + SHA-384 \ No newline at end of file diff --git a/运维/数据库/MySQL/MySQL运维/MySQL误删数据.md b/运维/域名解析/DNS/DNS.md similarity index 100% rename from 运维/数据库/MySQL/MySQL运维/MySQL误删数据.md rename to 运维/域名解析/DNS/DNS.md diff --git a/运维/数据库/MySQL/mysql笔记/MySQL 索引优化.md b/运维/数据库/MySQL/mysql笔记/MySQL 索引优化.md deleted file mode 100644 index e2b47cc..0000000 --- a/运维/数据库/MySQL/mysql笔记/MySQL 索引优化.md +++ /dev/null @@ -1,289 +0,0 @@ -# MySQL 索引优化 - -索引就是为特定的mysql字段进行一些特定的算法排序,比如二叉树的算法和哈希算法,哈希算法是通过建立特征值,然后根据特征值来快速查找。而用的最多,并且是mysql默认的就是二叉树算法 BTREE,通过BTREE算法建立索引的字段,比如扫描20行就能得到未使用BTREE前扫描了2^20行的结果。 - -## Explain优化查询检测 - -EXPLAIN可以帮助开发人员分析SQL问题,explain显示了mysql如何使用索引来处理select语句以及连接表,可以帮助选择更好的索引和写出更优化的查询语句。 - -使用方法,在select语句前加上Explain就可以了: - -``` -Explain select * from peopleinfo where idCard = 167575863462536759; -``` - -执行explain 时,后面的SQL语句是不会执行的。 - -**示例** - -``` -mysql> Explain select * from peopleinfo where idCard = 167575863462536759; --- 结果: - -+----+-------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-------+ -| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | -+----+-------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-------+ -| 1 | SIMPLE | peopleinfo | NULL | const | PRIMARY | PRIMARY | 8 | const | 1 | 100.00 | NULL | -+----+-------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-------+ - - -select_type: SIMPLE -- 查询类型(简单查询、联合查询、子查询) - -table: user -- 显示这一行的数据是关于哪张表的 。 - -type: range -- 区间索引(在小于1990/2/2区间的数据),这是重要的列,显示连接使用了何种类型。从最好到最差的连接类型为system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL,const代表一次就命中,ALL代表扫描了全表才确定结果。一般来说,得保证查询至少达到range级别,最好能达到ref。 - -possible_keys: birthday -- 指出MySQL能使用哪个索引在该表中找到行。如果是空的,没有相关的索引。这时要提高性能,可通过检验WHERE子句,看是否引用某些字段,或者检查字段不是适合索引。 - -key: birthday -- 实际使用到的索引。如果为NULL,则没有使用索引。如果为primary的话,表示使用了主键。 - -key_len: 4 -- 最长的索引宽度。如果键是NULL,长度就是NULL。在不损失精确性的情况下,长度越短越好。 - -ref: const -- 显示哪个字段或常数与key一起被使用。 - -rows: 1 -- 这个数表示mysql要遍历多少数据才能找到,在innodb上是不准确的。 - -Extra: Using where; Using index -- 执行状态说明,这里可以看到的坏的例子是Using temporary和Using -``` - -**select_type** - -1. simple:简单select(不使用union或子查询)。 -2. primary:最外面的select。 -3. union:union中的第二个或后面的select语句。 -4. dependent union:union中的第二个或后面的select语句,取决于外面的查询。 -5. union result:union的结果。 -6. subquery:子查询中的第一个select。 -7. dependent subquery:子查询中的第一个select,取决于外面的查询。 -8. derived:导出表的select(from子句的子查询)。 - -**其它说明** - -1. Distinct:一旦MYSQL找到了与行相联合匹配的行,就不再搜索了。 -2. Not exists: MYSQL优化了LEFT JOIN,一旦它找到了匹配LEFT JOIN标准的行,就不再搜索了。 -3. Range checked for each Record(index map:#):没有找到理想的索引,因此对于从前面表中来的每一个行组合,MYSQL检查使用哪个索引,并用它来从表中返回行。这是使用索引的最慢的连接之一。 -4. Using filesort: 看到这个的时候,查询就需要优化了。MYSQL需要进行额外的步骤来发现如何对返回的行排序。它根据连接类型以及存储排序键值和匹配条件的全部行的行指针来排序全部行。 -5. Using index: 列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,这发生在对表的全部的请求列都是同一个索引的部分的时候。 -6. Using temporary 看到这个的时候,查询需要优化了。这里,MYSQL需要创建一个临时表来存储结果,这通常发生在对不同的列集进行ORDER BY上,而不是GROUP BY上。 -7. Where used 使用了WHERE从句来限制哪些行将与下一张表匹配或者是返回给用户。如果不想返回表中的全部行,并且连接类型ALL或index,这就会发生,或者是查询有问题不同连接类型的解释(按照效率高低的顺序排序)。 -8. system 表只有一行:system表。这是const连接类型的特殊情况。 -9. const:表中的一个记录的最大值能够匹配这个查询(索引可以是主键或惟一索引)。因为只有一行,这个值实际就是常数,因为MYSQL先读这个值然后把它当做常数来对待。 -10. eq_ref:在连接中,MYSQL在查询时,从前面的表中,对每一个记录的联合都从表中读取一个记录,它在查询使用了索引为主键或惟一键的全部时使用。 -11. ref:这个连接类型只有在查询使用了不是惟一或主键的键或者是这些类型的部分(比如,利用最左边前缀)时发生。对于之前的表的每一个行联合,全部记录都将从表中读出。这个类型严重依赖于索引匹配的记录多少,越少越好。 -12. range:这个连接类型使用索引返回一个范围中的行,比如使用>或<查找东西时发生的情况。 -13. index: 这个连接类型对前面的表中的每一个记录联合进行完全扫描(比ALL更好,因为索引一般小于表数据)。 -14. ALL:这个连接类型对于前面的每一个记录联合进行完全扫描,这一般比较糟糕,应该尽量避免。 - -其中type: - -1. 如果是Only index,这意味着信息只用索引树中的信息检索出的,这比扫描整个表要快。 -2. 如果是where used,就是使用上了where限制。 -3. 如果是impossible where 表示用不着where,一般就是没查出来啥。 -4. 如果此信息显示Using filesort或者Using temporary的话会很吃力,WHERE和ORDER BY的索引经常无法兼顾,如果按照WHERE来确定索引,那么在ORDER BY时,就必然会引起Using filesort,这就要看是先过滤再排序划算,还是先排序再过滤划算。 - -## 索引的类型 - -**UNIQUE唯一索引** - -不可以出现相同的值,可以有NULL值。 - -**INDEX普通索引** - -允许出现相同的索引内容。 - -**PRIMARY KEY主键索引** - -不允许出现相同的值,且不能为NULL值,一个表只能有一个primary_key索引。 - -**fulltext index 全文索引** - -上述三种索引都是针对列的值发挥作用,但全文索引,可以针对值中的某个单词,比如一篇文章中的某个词,然而并没有什么卵用,因为只有myisam以及英文支持,并且效率让人不敢恭维,但是可以用coreseek和xunsearch等第三方应用来完成这个需求。 - -## 索引的CURD - -**索引的创建** - -ALTER TABLE - -适用于表创建完毕之后再添加。 - -ALTER TABLE 表名 ADD 索引类型 (unique,primary key,fulltext,index)[索引名](字段名) - -``` -ALTER TABLE `table_name` ADD INDEX `index_name` (`column_list`) -- 索引名,可要可不要;如果不要,当前的索引名就是该字段名。 -ALTER TABLE `table_name` ADD UNIQUE (`column_list`) -ALTER TABLE `table_name` ADD PRIMARY KEY (`column_list`) -ALTER TABLE `table_name` ADD FULLTEXT KEY (`column_list`) -``` - -CREATE INDEX - -CREATE INDEX可对表增加普通索引或UNIQUE索引。 - -``` ---例:只能添加这两种索引 -CREATE INDEX index_name ON table_name (column_list) -CREATE UNIQUE INDEX index_name ON table_name (column_list) -``` - -**另外,还可以在建表时添加:** - -``` -CREATE TABLE `test1` ( - `id` smallint(5) UNSIGNED AUTO_INCREMENT NOT NULL, -- 注意,下面创建了主键索引,这里就不用创建了 - `username` varchar(64) NOT NULL COMMENT '用户名', - `nickname` varchar(50) NOT NULL COMMENT '昵称/姓名', - `intro` text, - PRIMARY KEY (`id`), - UNIQUE KEY `unique1` (`username`), -- 索引名称,可要可不要,不要就是和列名一样 - KEY `index1` (`nickname`), - FULLTEXT KEY `intro` (`intro`) -) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='后台用户表'; -``` - -**索引的删除** - -``` -DROP INDEX `index_name` ON `talbe_name` -ALTER TABLE `table_name` DROP INDEX `index_name` --- 这两句都是等价的,都是删除掉table_name中的索引index_name; - -ALTER TABLE `table_name` DROP PRIMARY KEY -- 删除主键索引,注意主键索引只能用这种方式删除 -``` - -**索引的查看** - -``` -show index from tablename; -``` - -**索引的更改** - -更改个毛线,删掉重建一个既可 - -## 创建索引的技巧 - -1. 维度高的列创建索引。 - - 数据列中**不重复值**出现的个数,这个数量越高,维度就越高。 - - 如数据表中存在8行数据a,b ,c,d,a,b,c,d这个表的维度为4。 - - 要为维度高的列创建索引,如性别和年龄,那年龄的维度就高于性别。 - - 性别这样的列不适合创建索引,因为维度过低。 -2. 对 where,on,group by,order by 中出现的列使用索引。 -3. 对较小的数据列使用索引,这样会使索引文件更小,同时内存中也可以装载更多的索引键。 -4. 为较长的字符串使用前缀索引。 -5. 不要过多创建索引,除了增加额外的磁盘空间外,对于DML操作的速度影响很大,因为其每增删改一次就得从新建立索引。 -6. 使用组合索引,可以减少文件索引大小,在使用时速度要优于多个单列索引。 - -## 组合索引与前缀索引 - -注意,这两种称呼是对建立索引技巧的一种称呼,并非索引的类型。 - -**组合索引** - -MySQL单列索引和组合索引究竟有何区别呢? - -为了形象地对比两者,先建一个表: - -``` -CREATE TABLE `myIndex` ( - `i_testID` INT NOT NULL AUTO_INCREMENT, - `vc_Name` VARCHAR(50) NOT NULL, - `vc_City` VARCHAR(50) NOT NULL, - `i_Age` INT NOT NULL, - `i_SchoolID` INT NOT NULL, - PRIMARY KEY (`i_testID`) -); -``` - -假设表内已有1000条数据,在这 10000 条记录里面 7 上 8 下地分布了 5 条 vc_Name=”erquan” 的记录,只不过 city,age,school 的组合各不相同。来看这条 T-SQL: - -``` -SELECT `i_testID` FROM `myIndex` WHERE `vc_Name`='erquan' AND `vc_City`='郑州' AND `i_Age`=25; -- 关联搜索; -``` - -首先考虑建MySQL单列索引: - -在 vc_Name 列上建立了索引。执行 T-SQL 时,MYSQL 很快将目标锁定在了 vc_Name=erquan 的 5 条记录上,取出来放到一中间结果集。在这个结果集里,先排除掉 vc_City 不等于”郑州”的记录,再排除 i_Age 不等于 25 的记录,最后筛选出唯一的符合条件的记录。虽然在 vc_Name 上建立了索引,查询时MYSQL不用扫描整张表,效率有所提高,但离我们的要求还有一定的距离。同样的,在 vc_City 和 i_Age 分别建立的MySQL单列索引的效率相似。 - -为了进一步榨取 MySQL 的效率,就要考虑建立组合索引。就是将 vc_Name,vc_City,i_Age 建到一个索引里: - -``` -ALTER TABLE `myIndex` ADD INDEX `name_city_age` (vc_Name(10),vc_City,i_Age); -``` - -建表时,vc_Name 长度为 50,这里为什么用 10 呢?这就是下文要说到的前缀索引,因为一般情况下名字的长度不会超过 10,这样会加速索引查询速度,还会减少索引文件的大小,提高 INSERT 的更新速度。 - -执行 T-SQL 时,MySQL 无须扫描任何记录就到找到唯一的记录! - -如果分别在 vc_Name,vc_City,i_Age 上建立单列索引,让该表有 3 个单列索引,查询时和上述的组合索引效率一样吗?答案是大不一样,远远低于我们的组合索引。虽然此时有了三个索引,但 MySQL 只能用到其中的那个它认为似乎是最有效率的单列索引,另外两个是用不到的,也就是说还是一个全表扫描的过程。 - -建立这样的组合索引,其实是相当于分别建立了: - -- vc_Name,vc_City,i_Age -- vc_Name,vc_City -- vc_Name - -这样的三个组合索引!为什么没有 vc_City,i_Age 等这样的组合索引呢?这是因为 mysql 组合索引 “最左前缀” 的结果。简单的理解就是只从最左面的开始组合。并不是只要包含这三列的查询都会用到该组合索引,下面的几个 T-SQL 会用到: - -``` -SELECT * FROM myIndex WHREE vc_Name=”erquan” AND vc_City=”郑州” SELECT * FROM myIndex WHREE vc_Name=”erquan” -``` - -而下面几个则不会用到: - -``` -SELECT * FROM myIndex WHREE i_Age=20 AND vc_City=”郑州” SELECT * FROM myIndex WHREE vc_City=”郑州” -``` - -也就是,name_city_age(vc_Name(10),vc_City,i_Age) 从左到右进行索引,如果没有左前索引Mysql不执行索引查询。 - -**前缀索引** - -如果索引列长度过长,这种列索引时将会产生很大的索引文件,不便于操作,可以使用前缀索引方式进行索引前缀索引应该控制在一个合适的点,控制在0.31黄金值即可(大于这个值就可以创建)。 - -SELECT COUNT(DISTINCT(LEFT(`title`,10)))/COUNT(*) FROM Arctic; — 这个值大于0.31就可以创建前缀索引,Distinct去重复 ALTER TABLE `user` ADD INDEX `uname`(title(10)); — 增加前缀索引SQL,将人名的索引建立在10,这样可以减少索引文件大小,加快索引查询速度。 - -## 什么样的sql不走索引 - -**要尽量避免这些不走索引的sql** - -``` -SELECT `sname` FROM `stu` WHERE `age`+10=30;-- 不会使用索引,因为所有索引列参与了计算 - -SELECT `sname` FROM `stu` WHERE LEFT(`date`,4) <1990; -- 不会使用索引,因为使用了函数运算,原理与上面相同 - -SELECT * FROM `houdunwang` WHERE `uname` LIKE'后盾%' -- 走索引 - -SELECT * FROM `houdunwang` WHERE `uname` LIKE "%后盾%" -- 不走索引 - --- 正则表达式不使用索引,这应该很好理解,所以为什么在SQL中很难看到regexp关键字的原因 - --- 字符串与数字比较不使用索引; -CREATE TABLE `a` (`a` char(10)); -EXPLAIN SELECT * FROM `a` WHERE `a`="1" -- 走索引 -EXPLAIN SELECT * FROM `a` WHERE `a`=1 -- 不走索引 - -select * from dept where dname='xxx' or loc='xx' or deptno=45 --如果条件中有or,即使其中有条件带索引也不会使用。换言之,就是要求使用的所有字段,都必须建立索引,我们建议大家尽量避免使用or 关键字 - --- 如果mysql估计使用全表扫描要比使用索引快,则不使用索引 -``` - -多表关联时的索引效率 - -- SELECT `sname` FROM `stu` WHERE LEFT(`date`,4) <1990; — 不会使用索引,因为使用了函数运算,原理与上面相同 -- SELECT * FROM `houdunwang` WHERE `uname` LIKE’后盾%’ — 走索引 -- SELECT * FROM `houdunwang` WHERE `uname` LIKE “%后盾%” — 不走索引 - -![img](C:\Users\zhengchiliu\Desktop\笔记汇总\数据库\Mysql\MySQL 索引优化.assets\efcba9a9093fafa3879f44db4a3808fb.jpeg) - -从上图可以看出,所有表的type为all,表示全表索引。也就是6 6 6,共遍历查询了216次。 - -除第一张表示全表索引(必须的,要以此关联其他表),其余的为range(索引区间获得),也就是6+1+1+1,共遍历查询9次即可。 - -所以我们建议在多表join的时候尽量少join几张表,因为一不小心就是一个笛卡尔乘积的恐怖扫描,另外,我们还建议尽量使用left join,以少关联多。因为使用join 的话,第一张表是必须的全扫描的,以少关联多就可以减少这个扫描次数。 - -## 索引的弊端 - -不要盲目的创建索引,只为查询操作频繁的列创建索引,创建索引会使查询操作变得更加快速,但是会降低增加、删除、更新操作的速度,因为执行这些操作的同时会对索引文件进行重新排序或更新。 - -但是,在互联网应用中,查询的语句远远大于DML的语句,甚至可以占到80%~90%,所以也不要太在意,只是在大数据导入时,可以先删除索引,再批量插入数据,最后再添加索引。 \ No newline at end of file diff --git a/运维/数据库/MySQL/mysql笔记/MySQL技术详解.md b/运维/数据库/MySQL/mysql笔记/MySQL技术详解.md deleted file mode 100644 index cc28667..0000000 --- a/运维/数据库/MySQL/mysql笔记/MySQL技术详解.md +++ /dev/null @@ -1,319 +0,0 @@ ---- -title: MySQL技术详解 -categories: - - 概念 -date: 2023-04-18 19:07:33 ---- - -# MySQL技术详解 - -## 一、数据和数据库 - -数据:可以是数字、文字、图片、视频等 - -数据库:存储数据的仓库,易共享、易拓展、高并发、支持事务(要么做完、要么不做) - -``` -DML(Data Manipulation Language,数据操作语言):用于检索或者修改数据。 - DML包括: - SELECT:用于检索数据; - INSERT:用于增加数据到数据库; - UPDATE:用于从数据库中修改现存的数据 - DELETE:用于从数据库中删除数据。 - - DDL(Data Definition Language,数据定义语言): 用于定义数据的结构,比如 创建、修改或者删除数据库对象。 - DDL包括:DDL语句可以用于创建用户和重建数据库对象。下面是DDL命令: - CREATE TABLE:创建表 - ALTER TABLE - DROP TABLE:删除表 - CREATE INDEX - DROP INDEX - - DCL(Data Control Language,数据控制语言):用于定义数据库用户的权限。 - DCL包括: - ALTER PASSWORD - GRANT - REVOKE - CREATE SYNONYM -``` - - - -## 二、数据库类型 - -### **关系型数据库 :二维表和表之间的联系组成** - -关系型:二维表模型,如下。 - -| | | -| ---- | ---- | -| | | - -**记录**:一行数据就叫记录 - -**字段**:列名叫字段 - -### **非关系型数据库 :强调Key-Value和文档数据库** - -Redis、MongoDB等 - -## 三、MySQL约束类型 - -| 约束类型 | 作用 | -| --------------------------------- | ------------------------------------------------------------ | -| 主键约束 primary key | 唯一约束+非空约束,每个表最多只允许一个主键,创建完成之后会默认创建一个唯一索引 | -| 外键约束 foreign key | 外键约束是保证一个或两个表之间的参照完整性,外键基于两个表的两个字段的参照关系 | -| 唯一约束 unique | 列或者列组合不能重复,保证数据的唯一性 | -| 非空约束not null 和默认值 default | 可以确保不为空或者空的时候为什么值 | - -## 四、MySQL索引 - -**定义**:**索引是存储引擎用于快速找到记录的一种数据结构**。举例说明:如果查找一本书中的某个特定主题,一般会先看书的目录(类似索引),找到对应页面。在MySQL,存储引擎采用类似的方法使用索引,高效获取查找的数据。 - -表的存储由数据和索引组成,如果没有索引就要从磁盘上读每一个数据页,如果有则只需查找索引页(类似于目录) - -### 索引分类 - -**普通索引:**一个索引只包含单个列,一个表可以有多个单列索引 - -**唯一索引:**索引的列的值必须唯一,但允许有空值 - -**复合索引:**一个索引包含多个列 - -数据库保存的数据是存储在磁盘上,**查找数据时需要将磁盘中的数据加载到内存中**,在介绍索引的实现之前 - -### 建立索引的原则 - -1. 最左前缀匹配原则,非常重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。 -2. =和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式。 -3. 尽量选择区分度高的列作为索引,区分度的公式是count(distinct col)/count(*),表示字段不重复的比例,比例越大我们扫描的记录数越少,唯一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度就是0,那可能有人会问,这个比例有什么经验值吗?使用场景不同,这个值也很难确定,一般需要join的字段我们都要求是0.1以上,即平均1条扫描10条记录。 -4. 索引列不能参与计算,保持列“干净”,比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很简单,b+树中存的都是数据表中的字段值,但进行检索时,需要把所有元素都应用函数才能比较,显然成本太大。所以语句应该写成create_time = unix_timestamp(’2014-05-29’)。 -5. 尽量的扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可。 - -**explain详解** - -| 列 | 作用 | -| ------------- | ------------------------------------------------------------ | -| id | id列的编号是 select 的序列号,有几个 select 就有几个id,并且id的顺序是按 select 出现的顺序增长的。MySQL将 select 查询分为简单查询(SIMPLE)和复杂查询(PRIMARY)。复杂查询分为三类:简单子查询、派生表(from语句中的子查询)、union 查询。id越大执行优先级越高 | -| select_type | 表示是简单还是复杂的查询 | -| table | 正在访问哪个表,当 from 子句中有子查询时,table列是 格式,表示当前查询依赖 id=N 的查询,于是先执行 id=N 的查询。当有 union 时,UNION RESULT 的 table 列的值为,1和2表示参与 union 的 select 行id。 | -| partitions | | -| type | MySQL决定如何查找表中的行,查找数据行记录的大概范围。依次从最优到最差分别为:null(直接查询索引,无需查询数据) > system > const > eq_ref > ref > range > index > ALL | -| possible_keys | 如果该列是NULL,则没有相关的索引。在这种情况下,可以通过检查 where 子句看是否可以创造一个适当的索引来提高查询性能,然后用 explain 查看效果。explain 时可能出现 possible_keys 有列,而 key 显示 NULL 的情况,这种情况是因为表中数据不多,mysql认为索引对此查询帮助不大,选择了全表查询。 | -| key | 这一列显示mysql实际采用哪个索引来优化对该表的访问。如果没有使用索引,则该列是 NULL。如果想强制mysql使用或忽视possible_keys列中的索引,在查询中使用 force index、ignore index。 | -| key_len | 这一列显示了mysql在索引里使用的字节数,通过这个值可以算出具体使用了索引中的哪些列。 | -| ref | 这一列显示了在key列记录的索引中,表查找值所用到的列或常量,常见的有:const(常量),字段名(例:film. id) | -| rows | 这一列是mysql估计要读取并检测的行数,注意这个不是结果集里的行数。 | -| filtered | | -| Extra | **Using index:**查询的列被索引覆盖,并且where筛选条件是索引的前导列(最左侧索引),是性能高的表现。一般是使用了覆盖索引(索引包含了所有查询的字段)。对于innodb来说,如果是辅助索引性能会有不少提高。
**Using where:**查询的列未被索引覆盖,where筛选条件非索引的前导列。
**Using where Using index:**查询的列被索引覆盖,并且where筛选条件是索引列之一但不是索引的前导列,意味着无法直接通过索引查找来查询到符合条件的数据, Using index代表select用到了覆盖索引。
**NULL:**查询的列未被索引覆盖,并且where筛选条件是索引的前导列,意味着用到了索引,但是部分字段未被索引覆盖,必须通过“回表”来实现,不是纯粹地用到了索引,也不是完全没用到索引。
**Using index condition:**与Using where类似,查询的列不完全被索引覆盖,where条件中是一个前导列的范围;
**Using temporary:**mysql需要创建一张临时表来处理查询。出现这种情况一般是要进行优化的,首先是想到用索引来优化。
**Using filesort:**mysql 会对结果使用一个外部索引排序,而不是按索引次序从表里读取行。此时mysql会根据联接类型浏览所有符合条件的记录,并保存排序关键字和行指针,然后排序关键字并按顺序检索行信息。这种情况下一般也是要考虑使用索引来优化的。 | - -### 操作索引 - -``` -###创建普通索引 -CREATE INDEX indexName ON table_name (column_name) - -###后增加索引 -ALTER table tableName ADD INDEX indexName(columnName) - -###创建表的时候增加索引 -CREATE TABLE mytable( -ID INT NOT NULL, -username VARCHAR(16) NOT NULL, -INDEX [indexName] (username(length)) -); - -###删除索引 -drop index [indexName] ON mytable; - -###创建唯一索引 -CREATE UNIQUE INDEX indexName ON mytable(username(length)) - -###后增加唯一索引c -ALTER table mytable ADD UNIQUE [indexName] (username(length)) - -###创建表时指定 -CREATE TABLE mytable( -ID INT NOT NULL, -username VARCHAR(16) NOT NULL, -UNIQUE [indexName] (username(length)) -); - -###显示索引 -SHOW INDEX FROM table_name\G -``` - - - -## 五、MySQL锁 - -当事务对某个数据对象进行操作前,先向系统发出加锁请求,在该事务释放锁之前,其他事物不能对此数据对象进行更新操作 - -## 六、MySQL的存储引擎 - -存储引擎就是存储数据,建立索引,更新查询数据等等技术的实现方式,存储引擎针对数据表的,oracle 和SQL Server等数据库只有一种存储引擎,而MySQL提供插件式的存储引擎 - -## 七、事务 - -事务主要用于处理操作量大,复杂度高的数据,比如脚本,比如银行转账,从一个账号扣款并使另外一个账号增款,这两个操作妖魔都执行,要么都不执行。 - -- 在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务。 -- 事务处理可以用来维护数据库的完整性,保证成批的 SQL 语句要么全部执行,要么全部不执行。 -- 事务用来管理 insert,update,delete 语句 - -一般来说,事务是必须满足4个条件(ACID):原子性(**A**tomicity,或称不可分割性)、一致性(**C**onsistency)、隔离性(**I**solation,又称独立性)、持久性(**D**urability)。 - -- **原子性:**一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。 -- **一致性:**在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。 -- **隔离性:**数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。 -- **持久性:**事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。 - -### 操作事务 - -``` -BEGIN 开始一个事务 -ROLLBACK 事务回滚 -COMMIT 事务确认 -``` - -## 八、复制 - -## 九、备份 - -**mysqldump** - -``` -mysqldump -u 用户名 -p 数据库名 > /备份路径/备份文件名 #备份整个数据库 -mysqldump -u 用户名 -p 数据库名 表1 表2 > /备份路径/备份文件名 #备份数据表 - --databases 库1,库2 #备份多个数据库 - --all-databases #备份所有数据库 - -mysql 数据库 < 备份文件 -``` - -**mysql-binlog日志备份** - -二进制日志(log-bin日志):所有对数据库状态更改的操作(create、drop、update等) - -``` -vim /etc/my.cnf -log-bin=mysql-bin #开启二进制日志 - -mysqlbinlog --start-datetime ‘YY-MM-DD HH:MM:SS’ --stop-datetime ‘YY-MM-DD HH:MM:SS’ 二进制日志 | mysql -u root -p #按照时间恢复 -``` - -## 十、MySQL运维 - -### 常识 - -服务:mysqld 端口:3306 - -主配置文件:/etc/my.cnf 初始化脚本:mysql_install_db - -启动命令:musqld_safe 数据目录:/var/lib/mysql - -日志文件:/var/log/mysql.log - -套接字文件:/var/lib/mysql/mysql.sock - -进程文件:/var/run/mysqld/mysqld.pid - -### 常用命令 - -**操作用户** - -``` -###创建用户 -create user 用户名@远程主机 indentified by ‘密码’; - %:代替可代替主机位,代表任意远程主机 - -###修改用户密码 -alter user 'root'@'localhost' identified with mysql_native_password by '密码'; -set password=password(‘密码’); #为自己修改密码 -set password for 用户名@‘%’ =password(‘新密码’); #root为其他人修改密码 - -###授权 -select user from mysql.user; #查看用户 -grant all on 数据库.表名 to 用户名@'%'; #授权 -revoke all on 数据库.表名 to 用户名@'%'; #取消授权 - -###设置root 用户远程登录 -update user set host='%' where user='root'; -``` - -**操作数据库** - -``` -###创建数据库 -create database 数据库名; #创建数据库 -CREATE DATABASE IF NOT EXISTS 数据库名 DEFAULT CHARSET utf8 COLLATE utf8_general_ci; - -###删除数据库 -drop database 数据库名; #删除数据库 - -###查看所有数据库 -show databases; #查看所有数据库 -``` - -**操作数据表** - -``` -###创建数据表 -create table 表名 ( -字段; -字段 -)ENGINE=InnoDB DEFAULT CHARSET=utf8; #指定使用的引擎和字符编码 - -###删除数据表 -drop table 表名; #删除数据表 -alter tabe 表名 drop 字段名; #删除表的字段 - -###删除外键约束 -alter table tableName drop foreign key keyName; - -###查看数据表 -describe 表名; #查看数据表 -SHOW COLUMNS FROM 表名 #查看表结构 - -###修改表的存储引擎 -alter table tableName engine=myisam; - -###修改表名 -alter table 旧表名 rename 新表名 #给表改名 -alter table 表名 change name 表名 字段名 char(50) not null defult; #给字段改名 - -###修改字段 -alter table tableName modify name1 type1 first|after name2; #修改字段的相对位置:这里name1为想要修改的字段,type1为该字段原来类型,first和after二选一,这应该显而易见,first放在第一位,after放在name2字段后面 -alter table 表名 add 字段名 字段属性; #增加字段 -``` - -**操作数据** - -``` -###插入数据 -insert into 表名 (字段1,字段2) values (1,2,3),(4,5,6); #插入多个数据 -insert into 表1 (字段1,字段2) select 字段1,字段2 from 表2; #复制数据 - -###删除数据 -delete from 表名 where 字段=值; #删除单条数据 - -###修改数据 -update 表名 set 字段=数值 where 字段=值; #修改表中数据 -``` - -**查询操作** - -``` -select 字段1,字段2 from 表名 where 字段[=> and or]数值 limit 数值 offset 偏移量 - group by #通过某个字段对数据分组 - order by #通过某个字段排序 -JOIN 按照功能大致分为如下三类: - INNER JOIN(内连接,或等值连接):获取两个表中字段匹配关系的记录。 - LEFT JOIN(左连接):获取左表所有记录,即使右表没有对应匹配的记录。 - RIGHT JOIN(右连接): 与 LEFT JOIN 相反,用于获取右表所有记录,即使左表没有对应匹配的记录。 - select 表1/2.字段 from 表1 inner join 表2 on 表1.字段=表2.字段 -``` - -**显示数据表的属性信息 SHOW COLUMNS FROM 数据表 ** - -**显示数据表的详细索引信息 SHOW INDEX FROM 数据表** \ No newline at end of file diff --git a/运维/数据库/MySQL/mysql笔记/MySQL查询.md b/运维/数据库/MySQL/mysql笔记/MySQL查询.md deleted file mode 100644 index eb91c49..0000000 --- a/运维/数据库/MySQL/mysql笔记/MySQL查询.md +++ /dev/null @@ -1,592 +0,0 @@ -用户对于数据表或视图等最常用的操作就是查询。也叫检索。通过select语句来实现 -语法规则: -``` -select {columns} - from {table|view|other select} - [where 查询条件] - [group by 分组条件] - [having 分组后再限定] - [order by 排序] -``` -注意事项: - -1. sql的语句对于大小写不敏感。数值也不分。(Oracle中数值区分大小写) -2. 关键字不能被分行 -## 一、简单查询 -select 的检索语句中,只有select ,以及from子句。也是一个select语句必须的。 -### 1.1 指定列名 -查询指定的列: -``` - select 列名,列名 from 表名 -``` -> 如果查询表中所有的字段,使用*。 - -### 1.2 指定别名 -``` -select 列名 as 别名,列名 别名 from 表名 -``` -> as关键字:其实也可以省略。 - -### 1.3 列运算 -可以使用算术表达式 -在select语句中,检索到字段类型如果是number,date可以使用算术表达式 -加:+,减:-,乘:*,除:/,括号 -> 如果某一列有null数值,那么计算后的结果也是null。通用函数:ifnull(a,b),a为null那么取b,如果a不为null那么取a的值。 - -### 1.4 字符串类型可以做连续运算 -concat(“我的名字是”, name,'我今年。。'); -把搜索到的列和列进行拼接显示。 -### 1.5 去重重复:distinct 字段名 -distinct 列名,表示去除重复 -distinct 列名1,列名2,一行的数据都相同,才会被认为是重复的数据,去除。 -## 二、 条件查询 -在实际查询的过程中, 我们需要根据需要来过滤出我们想要的数据, 这种查询就叫条件查询。在检索数据信息的时候,使用限定条件。表示满足条件才会被检索到。 -使用where子句语法格式: -``` -select 检索列 from 表名 where 筛选条件 -``` -> 条件查询使用`where`子句对表中的数据进行筛选, 结果为`true`的行会出现的结果集中. -> 条件的表达式支持多种运算: - -### 2.1 比较运算符 - -- 等于 `=` -- 大于 `>` -- 小于 `<` -- 大于等于 `>=` -- 小于等于 `<=` -- 不等于 `!=` 或 `<>` - ---- - -查找年龄大于30岁的: -``` -select * from stus where age>30; -``` -查询姓名不是`王二狗`的: -``` -select * from stus where name!='王二狗'; -或者 -select * from stus where name<>'王二狗'; -``` -### 2.2 逻辑运算符 - -- and, && (与) -- or, || (或) -- not, !(非) - ---- - -查询年龄大于30并且性别是女的: -``` -select * from stus where age>30 and sex='女'; -或 -select * from stus where age>30 && sex='女'; -``` -查询年龄小于30或者性别是男的: -``` -select * from stus where age<30 or sex='男'; -或 -select * from stus where age<30 || sex='男'; -``` - ---- - -### 2.3 模糊查询 -比如想查询姓名中含有'张'的这种需求, 就需要用到模糊查询. -模糊查询用到关键字 `like` -``` -select * from stus name like '%张%'; -李李张张 -王张 -张 -张三 -张三三 -``` -语法: - -1. `%`表示任意多个字符(0-多个) -2. `_`(下划线)表示任意一个字符 - -查询姓名是两个字符的: -``` -select * from stus where name like '张__'; -``` - ---- - -### 2.4 区间查询 -#### 2.4.1 in (...) - -- `in` 表示在一个离散的非连续的范围中查找 - -查找id的值等于1或3或4的: -``` -select * from stus where id in (1, 3,4); -``` -#### 2.4.2 between...and... - -- `between...and...` -- 表示在一个连续的区间中查找. - -查找id的值在3到7之间的: -``` -select * from stus where id between 3 and 7; -``` -### 2.5 NULL判断 -`is NULL` 用来判断某列是否为空. 注意: `NULL`用小写也是可以的. -## 三、排序 -默认情况下, 我们查到的顺序是按照数据在数据库中的插入顺序排列的. -但是在实际情况下,我们需要根据不同的条件来排序, 比如按照更新日期排序, 或者按照价格从低到高排序, 或者按照人气从高到底排序等等. -**mysql支持对查询的结果进行重新排序.** -使用order by 列子句可以完成排序的功能. 后面的列表示排序规则. -> order by 子句。语法上位于一条sql语句的末尾。 - -### 3.1 升序(asc) -默认是升序排序 -按照年龄从低到高排序. -``` -select * from stus order by age; -``` -> 说明: -> -> 1. 默认情况下是按照升序排序.asc -也可以在列的后面添加asc(ascend 提升)表示升序. -> 2. 使用desc表示降序 -desc是单词 descend(下降)的缩写, 来表示降序排序. - -### 3.2 降序(desc) -``` -select * from stus order by age asc; -``` -### 3.3 多种排序规则 -可以先按照一定规则来排序, 当碰到相同的情况下, 按照第二种规则来排序, ... -先按照年龄升序排序, 如果年龄相等再按照id的降序排序. -``` -select * from stus order by age asc,id desc; -``` -## 四、聚合函数 -在查询中,统计,求和等是很常用的,通过聚合函数完成能十分省事. -如果没有聚合函数,可能需要各种子查询,各种sql嵌套才能完成. -但是有了**聚合函数**,很多问题迎刃而解。 -mysql提供了5个常用的聚合函数:`sum(), max(), min(), avg(), count()` -当然配合聚合函数使用的还有分组`group by 和 having子句`, 下一节再细讲. -### 4.1 sum(列) -这个聚合函数用来对那些列不是`null`的值进行求和. - -- 对所有的age求和 -- 多所年龄小于100的age求和 -### 4.2 max(列) -这个聚合函数用来计算那些列不是`null`的值最大值. - -- 找到最大的年龄 -### 4.3 min(列) -这个聚合函数用来计算那些列不是`null`的值最小值. - -- 找到最小的年龄 -### 4.4 avg(列) -这个聚合函数用来计算那些列不是`null`的值平均值. - -- 计算`age`的平均值 -### 4.5 count(列) -统计函数. -count(*)--->统计所有行的数据,16 -count(主键列)-->16 -count(非主键列1),是否存在null数值。 -count(comm)-->6 - -- 统计一共有多少行数据 -- 统计性别不为`null`的数据 行数 -## 五、分组查询 -分组(group by) -group by 列名, 按照指定的列进行分组, 值相同的会分在一组. -语法: -``` -select 列名 from 表名 group by 列名; -``` -说明: - -1. select后面跟的列名必须和group by后的列列名保持一致. -2. 当group by单独使用时, 只显示每组的第一条记录. 所以group by单独使用的意义不大.大多要配合聚合函数。 -3. group by后面也可以给多个列进行分组, 表示这些列都相同的时候在一组. -### 5.1 按照某列分组 -``` -select sex from stus group by sex; -``` -### 5.2 按照多列分组 -``` -select name, sex from stus group by name,sex; -``` -### 5.3 分组后使用聚合函数 -``` -select sex,count(*) from stus group by sex; -``` -> 注意: -> 1. 如果没有分组,那么组函数(max,min,avg,count....)作用在整张表上。 -> 2. 如果有分组,组函数作用在分组后的数据上。 -> 3. 在写select 子句中列,如果没有在组函数里,那么就要在group by后边。 - -``` -select a,b,count(c),sum(d) from 表 group by a,b; -``` -### 5.4 分组后限定查询:having -二次筛选:二次筛选是指分组后再对数据进行筛选. -需要使用having子句来完成. -``` -select 列名 from 表名 group by 列名 having 条件 -``` -也就是说,分组后再限定,使用having子句 -having子句对于group by分组后的结果,进行再次筛选。最后输出的结果就满足having条件的。 -> having子句的和where子句的用法类似,都是用于限定条件。 -> -> 对比: -1. where和having后面都是跟条件 -2. where是对表中的数据的原始筛选 -3. having是对group by的结果的二次筛选 -4. having必须配合group by使用, 一般也会跟着聚合函数一起使用 -5. 可以先有where, 后面跟着group by和having -> - -``` -区别和结论: - 1.语法上:在having中使用组函数(max,min,avg,count...),而where后不能用组函数。 - 2.执行上:where是先过滤再分组。having是先分组再过滤。 -``` -例如:把sex不是null的过滤出来. -例如:把男或女的个数超过6的过滤出来 -## 六、分页查询 -Limit子句(方言) -> 方言的意思是limit是mysql特有的。 - -Limit用于限定查询结果的起始行,以及总行数。 -``` -select * from 表名 limit start,count; -``` -例如:查询起始行为第5行,一共查询3行 -select * from stus limit 4, 3; - 其中4表示从第5行开始,其中2表是查询3行。即5,6,7行记录。 -## 七、内置函数[扩展] -### 7.1 字符串函数 - -- 查看字符的ascii码值ascii(str),str是空串时返回0 -``` -select ascii('a'); -``` - -- 查看ascii码值对应的字符char(数字) -``` -select char(97); -``` - -- 拼接字符串concat(str1,str2...) -``` -select concat(12,34,'ab'); -``` - -- 包含字符个数length(str) -``` -select length('abc'); -``` - -- 截取字符串 - - left(str,len)返回字符串str的左端len个字符 - - right(str,len)返回字符串str的右端len个字符 - - substring(str,pos,len)返回字符串str的位置pos起len个字符,从1开始 -``` -select substring('abc123',2,3); -``` - -- 去除空格 - - ltrim(str)返回删除了左空格的字符串str - - rtrim(str)返回删除了右空格的字符串str - - trim([方向 remstr from str)返回从某侧删除remstr后的字符串str,方向词包括both、leading、trailing,表示两侧、左、右 -``` -select trim(' bar '); -select trim(leading 'x' FROM 'xxxbarxxx'); -select trim(both 'x' FROM 'xxxbarxxx'); -select trim(trailing 'x' FROM 'xxxbarxxx'); -``` - -- 返回由n个空格字符组成的一个字符串space(n) -``` -select space(10); -``` - -- 替换字符串replace(str,from_str,to_str) -``` -select replace('abc123','123','def'); -``` - -- 大小写转换,函数如下 - - lower(str) - - upper(str) -``` -select lower('aBcD'); -``` -### 7.2 数学函数 - -- 求绝对值abs(n) -``` -select abs(-32); -``` - -- 求m除以n的余数mod(m,n),同运算符% - -``` -select mod(10,3); -select 10%3; -``` - -- 地板floor(n),表示不大于n的最大整数 - -``` -select floor(2.3); -``` - -- 天花板ceiling(n),表示不小于n的最大整数 - -``` -select ceiling(2.3); -``` - -- 求四舍五入值round(n,d),n表示原数,d表示小数位置,默认为0 - -``` -select round(1.6); -``` - -- 求x的y次幂pow(x,y) - -``` -select pow(2,3); -``` - -- 获取圆周率PI() - -``` -select PI(); -``` - -- 随机数rand(),值为0-1.0的浮点数 - -``` -select rand(); -``` - -- 还有其它很多三角函数,使用时可以查询文档 - -### 7.3 日期时间函数 - -- 获取子值,语法如下 - - year(date)返回date的年份(范围在1000到9999) - - month(date)返回date中的月份数值 - - day(date)返回date中的日期数值 - - hour(time)返回time的小时数(范围是0到23) - - minute(time)返回time的分钟数(范围是0到59) - - second(time)返回time的秒数(范围是0到59) - -``` -select year('2016-12-21'); -``` - -- 日期计算,使用+-运算符,数字后面的关键字为year、month、day、hour、minute、second - -``` -select '2016-12-21'+interval 1 day; -select '2017-12-12' + interval 3 month; -select date_add('2017-12-12', interval 1 day); -``` - -- 日期格式化date_format(date,format),format参数可用的值如下 - - 获取年%Y,返回4位的整数 -* 获取年%y,返回2位的整数 -* 获取月%m,值为1-12的整数 - - 获取日%d,返回整数 -* 获取时%H,值为0-23的整数 -* 获取时%h,值为1-12的整数 -* 获取分%i,值为0-59的整数 -* 获取秒%s,值为0-59的整数 - -``` -select date_format('2016-12-21','%Y %m %d'); -select str_to_date('12/12/2017','%d/%m/%Y'); -``` - -- 当前日期current_date() - -``` -select current_date(); -``` - -- 当前时间current_time() - -``` -select current_time(); -``` - -- 当前日期时间now() - -``` -select now(); -``` - -## 七、多表查询 - -连接查询:当需要对有关系的多张表进行查询时,需要使用连接join - -**合并结果集** - -1. 要求被合并的表中,列的类型和列数相同 -2. UNION,去除重复行 -3. UNION ALL, 不去除重复行 - -**分类** - -``` -1. 内连接 -2. 外连接 - A:左外连接 - B:右外连接 - C:全外连接(Mysql不支持) -3. 自连接(术语一种简化方式) -``` - -### 7.1 笛卡尔积 - -如果两张表在连接查询时,如果没有连接条件,那么就会产生笛卡尔积。(冗余数据)。 - -### 7.1 内连接 - -内连接查询出的所有的记录都满足条件 - -``` -方言:select * from 表1 别名1, 表2 别名2 where 别名1.xx=别名2.xx - 也叫等值链接 -标准:select * from 表1 别名1 inner join 表2 别名2 on 别名1.xx=别名2.xx -自然:select * from 表1 别名1 natural join 表2 别名2 -``` - -### 7.2 外连接 - -内连接所检索出来的结果,都是满足连接条件的。外链接是扩展内连接检索出来的结果集。外链接返回的结果,除了包含满足链接条件的记录,还包括不满足连接条件。 - -#### 7.2.1 左外连接 - -左表记录无论是否满足条件都会查询出来,而右表只有满足条件才能查询出来。左表中不满足条件的记录,右表部分都为NULL - -语法格式: - -``` -左外: - select * from 表1 别名1 left outer join 表2 别名2 on 别名1.xx=别名2.xx - -左外自然: - select * from 表1 别名1 natural left outer join 表2 别名2 -``` - -#### 7.2.2 右外连接 - -右表记录无论是否满足条件都会查询出来,而左表只有满足条件才能查询出来。右表中不满足条件的记录,左表部分都为NULL - -语法格式: - -``` -右外: - select * from 表1 别名1 right outer join 表2 别名2 on 别名1.xx=别名2.xx - - -右外自然: - select * from 表1 别名1 natural right outer join 表2 别名2 -``` - -#### 7.2.3 全外连接 - -Mysql不支持全外连接(full outer join),但是可以使用union来合并左外连接以及右外连接的结果,达到全外连接的效果。 - -``` -左外连接 -SELECT e.ename,e.sal, d.dname,e.deptno,d.deptno -FROM emp e LEFT OUTER JOIN dept d -ON e.deptno=d.deptno -UNION -右外连接 -SELECT e.ename,e.sal, d.dname,e.deptno,d.deptno -FROM emp e RIGHT OUTER JOIN dept d -ON e.deptno=d.deptno -``` - -### 7.3 自连接 - -自连接(术语一种简化方式)。其实就是一张表连接字节。 - -查询员工的上级名称 - -``` -SELECT e.empno,e.ename,e.mgr,m.empno,m.ename -FROM emp e LEFT OUTER JOIN emp m -ON e.mgr=m.empno -``` - -## 八、子查询 - -子查询是指sql语句中包含另一个select语句。内查询或者内select语句 - -> 一条sql语句中,包含多个select关键字 -> -> 外查询,内查询 - - -子查询可以出现的位置: - - from后,作为表 - - where后,作为条件 - -注意事项: -1.子查询必须在()里 -2.在子查询中不能使用order by子句。 -3.子查询可以再嵌套子查询,最多不能超过255层。 - -子查询细分为:单行子查询,多行子查询,关联子查询。 - -1.单行子查询 -子查询的结果是单行数据。 -在where条件后需要配合单行运算符:>,<,>=,<=,!=,= -2.多行子查询 -子查询的结果是多行数据。 -在where条件后需要配合:in,any,all运算符 -in: -any:匹配上子查询的结果集中任意一个即可。 -all:匹配上子查询的所有的结果。 - -3.关联子查询 -对于单行子查询和多行子查询,外查询和内查询是分开执行的。 -如果外查询使用到内查询的结果,就使用关联子查询。 -关联子查询,是指在内查询中需要借助于外查询,而外查询离不开内查询的执行。就叫关联子查询。 - -## 九、总结 - -完整的select语句书写: - -``` -select distinct * -from 表名 -where .... -group by ... having ... -order by ... -limit start,count -``` - -执行顺序: - -``` -from 表名 -where ... -group by ... -having ... -select distinct*.. -order by ... -limit start,count -``` - -实际使用中,只是使用语句中某些部分的组合,而不是全部。 diff --git a/运维/数据库/MySQL/mysql笔记/MySQL运维.md b/运维/数据库/MySQL/mysql笔记/MySQL运维.md deleted file mode 100644 index dffdfbe..0000000 --- a/运维/数据库/MySQL/mysql笔记/MySQL运维.md +++ /dev/null @@ -1,49 +0,0 @@ -MySQL运维 - -1、建立连接 - -首先客户端与 MYSQL 服务器建立连接这个就不用说,客户端发起请求经过三次握手之后与服务器建立 TCP 连接;服务器收到请求之后对输入的用户名密码做权限校验, 校验通过之后后续的通信就基于这个长连接进行传输。 - -``` -mysql> show processlist; -+----+-----------------+-----------+-------+---------+------+------------------------+------------------+ -| Id | User | Host | db | Command | Time | State | Info | -+----+-----------------+-----------+-------+---------+------+------------------------+------------------+ -| 5 | event_scheduler | localhost | NULL | Daemon | 152 | Waiting on empty queue | NULL | -| 8 | root | localhost | mysql | Query | 0 | init | show processlist | -+----+-----------------+-----------+-------+---------+------+------------------------+------------------+ - -TIME参数:表示该连接已经多久没有发生过数据传输。默认如果超过 8 小时没有发生过数据传输服务端就会自动关闭该连接。可以通过 wait_timeout参数来设置超时时间。 -``` - -2、查询缓存 - -MySQL 查询缓存是 MySQL 中比较独特的一个缓存区域,用来缓存特定 Query 的整个结果集信息,且共享给所有客户端。为了提高完全相同的 Query 语句的响应速度,MySQL Server 会对查询语句进行 Hash 计算后,把得到的 hash 值与 Query 查询的结果集对应存放在Query Cache 中。当 MySQL Server 打开 Query Cache 之后,MySQL Server 会对接收到的每一个 SELECT 语句通过特定的 Hash 算法计算该 Query 的 Hash 值,然后通过该 hash 值到 Query Cache 中去匹配。 - -``` -mysql> show variables like '%query_cache%'; -+------------------------------+---------+ -| Variable_name | Value | -+------------------------------+---------+ -| have_query_cache | YES | --查询缓存是否可用 -| query_cache_limit | 1048576 | --可缓存具体查询结果的最大值 -| query_cache_min_res_unit | 4096 | --查询缓存分配的最小块的大小(字节) -| query_cache_size | 599040 | --查询缓存的大小 -| query_cache_type | ON | --是否支持查询缓存 -| query_cache_wlock_invalidate | OFF | --控制当有写锁加在表上的时候,是否先让该表相关的 Query Cache失效 -+------------------------------+---------+ -``` - -开启缓存 - -```sql -Copymysql> set global query_cache_size = 600000; --设置缓存内存大小 -mysql> set global query_cache_type = ON; --开启查询缓存 -``` - -关闭缓存 - -```sql -Copymysql> set global query_cache_size = 0; --设置缓存内存大小为0, 即初始化是不分配缓存内存 -mysql> set global query_cache_type = OFF; --关闭查询缓存 -``` \ No newline at end of file diff --git a/运维/数据库/MySQL/mysql笔记/Ⅰ、连接管理.md b/运维/数据库/MySQL/mysql笔记/Ⅰ、连接管理.md deleted file mode 100644 index 2fcfdae..0000000 --- a/运维/数据库/MySQL/mysql笔记/Ⅰ、连接管理.md +++ /dev/null @@ -1,3 +0,0 @@ -每当有一个客户端进程连接到服务器进程时,服务器进程都会创建一个线程来专门处理与这个客户端的交互,当该客户端退出时会与服务器断开连接,服务器并不会立即把与该客户端交互的线程销毁掉,而是把它缓存起来,在另一个新的客户端再进行连接时,把这个缓存的线程分配给该新客户端,这样就起到了不频繁创建和销毁线程的效果,从而节省开销。 - -当连接建立后,与该客户端关联的服务器线程会一直等待客户端发送过来的请求,MySQL服务器接收到的请求只是一个文本消息,该文本消息还要经过各种处理 diff --git a/运维/数据库/MySQL/mysql笔记/Ⅱ、解析和优化.md b/运维/数据库/MySQL/mysql笔记/Ⅱ、解析和优化.md deleted file mode 100644 index 48dfbcd..0000000 --- a/运维/数据库/MySQL/mysql笔记/Ⅱ、解析和优化.md +++ /dev/null @@ -1,15 +0,0 @@ -## 查询缓存 -MySQL服务器程序处理查询请求时会把刚刚处理过的查询请求和结果缓存起来,如果下一次有一模一样的请求过来,直接从缓存中查找结果 - -如果两个查询请求在任何字符上的不同(例如:空格、注释、大小写),都会导致缓存不会命中。另外,如果查询请求中包含某些系统函数、用户自定义变量和函数、一些系统表,如 mysql 、information_schema、 performance_schema 数据库中的表,那这个请求就不会被缓存。 - -MySQL的缓存系统会监测涉及到的每张表,只要该表的结构或者数据被修改,如对该表使用了INSERT、 UPDATE、DELETE、TRUNCATE TABLE、ALTER TABLE、DROP TABLE或 DROP DATABASE语句,那使用该表的所有高速缓存查询都将变为无效并从高速缓存中删除! - -虽然查询缓存有时可以提升系统性能,但也不得不因维护这块缓存而造成一些开销,比如每次都要去查询缓存中检索,查询请求处理完需要更新查询缓存,维护该查询缓存对应的内存区域。从MySQL 5.7.20开始,不推荐使用查询缓存,并在MySQL 8.0中删除。 - - -## 语法解析 -如果查询缓存没有命中,接下来就需要进入正式的查询阶段了。因为客户端程序发送过来的请求只是一段文本而已,所以MySQL服务器程序首先要对这段文本做分析,判断请求的语法是否正确,然后从文本中将要查询的表、各种查询条件都提取出来放到MySQL服务器内部使用的一些数据结构上来。 - -## 查询优化 -因为我们写的MySQL语句执行起来效率可能并不是很高,MySQL的优化程序会对我们的语句做一些优化,如外连接转换为内连接、表达式简化、子查询转为连接等等的一堆东西。优化的结果就是生成一个执行计划,这个执行计划表明了应该使用哪些索引进行查询,表之间的连接顺序是什么样的。我们可以使用EXPLAIN语句来查看某个语句的执行计划 diff --git a/运维/数据库/MySQL/mysql笔记/Ⅲ、存储引擎.md b/运维/数据库/MySQL/mysql笔记/Ⅲ、存储引擎.md deleted file mode 100644 index 7b60524..0000000 --- a/运维/数据库/MySQL/mysql笔记/Ⅲ、存储引擎.md +++ /dev/null @@ -1,51 +0,0 @@ - -截止到服务器程序完成了查询优化为止,还没有真正的去访问真实的数据表,MySQL服务器把数据的存储和提取操作都封装到了一个叫存储引擎的模块里,物理上如何表示记录,怎么从表中读取数据,怎么把数据写入具体的物理存储器上,这都是存储引擎负责的事情,我们可以为不同的表设置不同的存储引擎,不同的表可以有不同的物理存储结构,不同的提取和写入方式。 - -## 常用存储引擎 -| **存储引擎** | **描述** | -| --- | --- | -| ARCHIVE | 用于数据存档(行被插入后不能再修改) | -| BLACKHOLE | 丢弃写操作,读操作会返回空内容 | -| CSV | 在存储数据时,以逗号分隔各个数据项 | -| FEDERATED | 用来访问远程表 | -| InnoDB | 具备外键支持功能的事务存储引擎 | -| MEMORY | 置于内存的表 | -| MERGE | 用来管理多个MyISAM表构成的表集合 | -| MyISAM | 主要的非事务处理存储引擎 | -| NDB | MySQL集群专用存储引擎 | - -## 相关操作 -##### 查看当前服务器程序支持的存储引擎 -```shell -SHOW ENGINES; -``` -回显(字段说明:support[是否支持],Transactions[是否支持事务],XA[是否支持分布式事务],Savepoints[是否支持事务回滚]) -```shell -+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+ -| Engine | Support | Comment | Transactions | XA | Savepoints | -+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+ -| FEDERATED | NO | Federated MySQL storage engine | NULL | NULL | NULL | -| MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO | -| InnoDB | DEFAULT | Supports transactions, row-level locking, and foreign keys | YES | YES | YES | -| PERFORMANCE_SCHEMA | YES | Performance Schema | NO | NO | NO | -| MyISAM | YES | MyISAM storage engine | NO | NO | NO | -| MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO | -| BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears) | NO | NO | NO | -| CSV | YES | CSV storage engine | NO | NO | NO | -| ARCHIVE | YES | Archive storage engine | NO | NO | NO | -+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+ -``` -##### 创建表时指定存储引擎 -```shell -CREATE TABLE 表名( - 建表语句; -) ENGINE = 存储引擎名称; -``` -##### 修改表的存储引擎 -```shell -ALTER TABLE 表名 ENGINE = 存储引擎名称; -``` -##### 查看表结构 -```shell -SHOW CREATE TABLE 表名\G -``` diff --git a/运维/数据库/MySQL/mysql笔记/一、数据库三范式.md b/运维/数据库/MySQL/mysql笔记/一、数据库三范式.md deleted file mode 100644 index 61ee9e9..0000000 --- a/运维/数据库/MySQL/mysql笔记/一、数据库三范式.md +++ /dev/null @@ -1,6 +0,0 @@ -# 1、第一范式 -无重复的列,每一列都是不可分割的基本数据项,同一列中不能有多个值,及实体中的某个属性不能有多个值或者不能有重复的属性,确保每一列的原子性 -## 2、第二范式 -第二范式必须先满足第一范式,属性完全依赖于主键,要求表中的每隔行必须可以被唯一的区分,通常为表加上每行的唯一标识主键PK,非PK的字段需要与整个PK有直接相关性,即非PK的字段不能依赖于部分主键 -## 3、第三范式 -满足第三范式必须先满足第二范式的属性,非主键属性不依赖于其它非主键属性。第三范式要求一个数据表中不包含已在其他表中已包含的非主关键字信息,非PK的字段间不能有从属关系 diff --git a/运维/数据库/MySQL/mysql笔记/二、MySQL处理客户端请求.md b/运维/数据库/MySQL/mysql笔记/二、MySQL处理客户端请求.md deleted file mode 100644 index e84141a..0000000 --- a/运维/数据库/MySQL/mysql笔记/二、MySQL处理客户端请求.md +++ /dev/null @@ -1,2 +0,0 @@ -![image.png](https://cdn.nlark.com/yuque/0/2023/png/35086385/1698742857745-de9983cb-0ca2-4282-a34f-c882cf85d80e.png#averageHue=%23fefefe&clientId=u40c92775-8480-4&from=paste&height=434&id=u7748da2e&originHeight=559&originWidth=842&originalType=url&ratio=2.5&rotation=0&showTitle=false&size=99737&status=done&style=none&taskId=ua589b4b0-f212-4dc5-ae07-b359ba3285f&title=&width=653) - diff --git a/运维/数据库/MySQL/mysql笔记/字符集.md b/运维/数据库/MySQL/mysql笔记/字符集.md deleted file mode 100644 index c8e1e58..0000000 --- a/运维/数据库/MySQL/mysql笔记/字符集.md +++ /dev/null @@ -1,7 +0,0 @@ -计算机中只能存储二进制数据,那该怎么存储字符串呢?将一个字符映射成一个二进制数据的过程也叫做编码,将一个二进制数据映射到一个字符的过程叫做解码。人们抽象出一个字符集的概念来描述某个字符范围的编码规则。比如 -``` -'a' -> 00000001 (十六进制:0x01) -'b' -> 00000010 (十六进制:0x02) -'A' -> 00000011 (十六进制:0x03) -'B' -> 00000100 (十六进制:0x04) -``` diff --git a/运维/数据库/MySQL/mysql笔记/系统变量详解.md b/运维/数据库/MySQL/mysql笔记/系统变量详解.md deleted file mode 100644 index e19d5d3..0000000 --- a/运维/数据库/MySQL/mysql笔记/系统变量详解.md +++ /dev/null @@ -1,34 +0,0 @@ -每个系统变量都有一个默认值,我们可以使用命令行或者配置文件中的选项在启动服务器时改变一些系统变量的值。大多数的系统变量的值也可以在程序运行过程中修改,而无需停止并重新启动它。 -## 查看系统变量 -``` -SHOW VARIABLES [LIKE 匹配的模式]; -``` -## 服务器程序运行过程中设置 -系统变量比较牛逼的一点就是,对于大部分系统变量来说,它们的值可以在服务器程序运行过程中,进行动态修改而无需停止并重启服务器。不过系统变量有作用范围之分 -#### 设置不同作用范围的系统变量 -系统变量的作用范围的概念,具体来说作用范围分为这两种: - -- GLOBAL:全局变量,影响服务器的整体操作。 -- SESSION:会话变量,影响某个客户端连接的操作。(注:SESSION有个别名叫LOCAL) - -通过启动选项设置的系统变量的作用范围都是GLOBAL的,也就是对所有客户端都有效的,因为在系统启动的时候还没有客户端程序连接进来 -``` -SET [GLOBAL|SESSION] 系统变量名 = 值; -``` -#### 查看不同作用范围的系统变量 -SHOW VARIABLES语句默认查看的是SESSION作用范围的系统变量 -我们也可以在查看系统变量的语句上加上要查看哪个作用范围的系统变量 -``` -SHOW [GLOBAL|SESSION] VARIABLES [LIKE 匹配的模式]; -``` - -- 并不是所有系统变量都具有GLOBAL和SESSION的作用范围。 - - 有一些系统变量只具有GLOBAL作用范围,比方说max_connections,表示服务器程序支持同时最多有多少个客户端程序进行连接。 - - 有一些系统变量只具有SESSION作用范围,比如insert_id,表示在对某个包含AUTO_INCREMENT列的表进行插入时,该列初始的值。 - - 有一些系统变量的值既具有GLOBAL作用范围,也具有SESSION作用范围,比如我们前面用到的default_storage_engine,而且其实大部分的系统变量都是这样的, -- 有些系统变量是只读的,并不能设置值。比方说version,表示当前MySQL的版本,我们客户端是不能设置它的值的,只能在SHOW VARIABLES语句里查看 -## 状态变量 -MySQL服务器程序中维护了很多关于程序运行状态的变量,它们被称为状态变量。 -``` -SHOW [GLOBAL|SESSION] STATUS [LIKE 匹配的模式]; -``` diff --git a/运维/数据库/MySQL/mysql笔记/配置文件详解.md b/运维/数据库/MySQL/mysql笔记/配置文件详解.md deleted file mode 100644 index 8f45868..0000000 --- a/运维/数据库/MySQL/mysql笔记/配置文件详解.md +++ /dev/null @@ -1,55 +0,0 @@ -## 配置文件路径 -| **路径名** | **备注** | -| --- | --- | -| /etc/my.cnf | | -| /etc/mysql/my.cnf | | -| SYSCONFDIR/my.cnf | | -| $MYSQL_HOME/my.cnf | 特定于服务器的选项(仅限服务器) | -| defaults-extra-file | 命令行指定的额外配置文件路径 | -| ~/.my.cnf | 用户特定选项 | -| ~/.mylogin.cnf | 用户特定的登录路径选项(仅限客户端 | - -## 配置文件的内容 -与在命令行中指定启动选项不同的是,配置文件中的启动选项被划分为若干个组,每个组有一个组名,用中括号[]扩起来,像这样: -``` -[server] -(具体的启动选项...) - -[mysqld] -(具体的启动选项...) - -[mysqld_safe] -(具体的启动选项...) - -[client] -(具体的启动选项...) - -[mysql] -(具体的启动选项...) - -[mysqladmin] -(具体的启动选项...) -``` -像这个配置文件里就定义了许多个组,组名分别是server、mysqld、mysqld_safe、client、mysql、mysqladmin。每个组下面可以定义若干个启动选项 -配置文件中不同的选项组是给不同的启动命令使用的,如果选项组名称与程序名称相同,则组中的选项将专门应用于该程序。例如,[mysqld]和[mysql]组分别应用于mysqld服务器程序和mysql客户端程序。不过有两个选项组比较特别: - -- [server]组下面的启动选项将作用于所有的服务器程序。 -- [client]组下面的启动选项将作用于所有的客户端程序。 -| **启动命令** | **类别** | **能读取的组** | -| --- | --- | --- | -| mysqld | 启动服务器 | [mysqld]、[server] | -| mysqld_safe | 启动服务器 | [mysqld]、[server]、[mysqld_safe] | -| mysql.server | 启动服务器 | [mysqld]、[server]、[mysql.server] | -| mysql | 启动客户端 | [mysql]、[client] | -| mysqladmin | 启动客户端 | [mysqladmin]、[client] | -| mysqldump | 启动客户端 | [mysqldump]、[client] | - -## 同一个配置文件中多个组的优先级 -``` -[server] -default-storage-engine=InnoDB - -[mysqld] -default-storage-engine=MyISAM -``` -那么,将以最后一个出现的组中的启动选项为准 diff --git a/运维/数据库/MySQL/笔记/Mysql.md b/运维/数据库/MySQL/笔记/Mysql.md new file mode 100644 index 0000000..a157307 --- /dev/null +++ b/运维/数据库/MySQL/笔记/Mysql.md @@ -0,0 +1,1130 @@ +# MySQL 实战指南 + +> 最流行的开源关系型数据库。 + +--- + +## 1. 关系型数据库基础 + +### 1.1 数据库类型 + +| 类型 | 说明 | 代表产品 | +|------|------|---------| +| 关系型数据库(RDBMS) | 基于关系模型,表与表之间有关联 | MySQL、PostgreSQL、Oracle | +| 非关系型数据库(NoSQL) | 非关系模型,文档/键值/列式 | MongoDB、Redis、HBase | +| NewSQL | 分布式关系型数据库 | TiDB、CockroachDB | + +### 1.2 关系型数据库核心概念 + +``` +表(Table)→ 行(Row)→ 记录 + → 列(Column)→ 字段 + → 主键(Primary Key)→ 唯一标识 + → 外键(Foreign Key)→ 表间关联 + → 索引(Index)→ 加速查询 +``` + +### 1.3 范式 + +| 范式 | 要求 | +|------|------| +| 1NF | 字段原子性,不可再分 | +| 2NF | 消除部分依赖,非主键字段完全依赖于主键 | +| 3NF | 消除传递依赖,非主键字段不依赖于其他非主键字段 | + +### 1.4 SQL 分类 + +| 分类 | 命令 | 说明 | +|------|------|------| +| DDL | CREATE/ALTER/DROP | 定义数据结构 | +| DML | INSERT/UPDATE/DELETE | 操作数据 | +| DQL | SELECT | 查询数据 | +| DCL | GRANT/REVOKE | 权限控制 | +| TCL | COMMIT/ROLLBACK | 事务控制 | + +--- + +## 2. 安装 MySQL + +### 2.1 YUM/RPM 安装(CentOS/RHEL) + +```bash +# 1. 下载 Yum Repository +wget https://repo.mysql.com/mysql80-community-release-el8-4.noarch.rpm + +# 2. 安装 Repository +rpm -Uvh mysql80-community-release-el8-4.noarch.rpm + +# 3. 安装 MySQL Server +yum install -y mysql-community-server + +# 4. 启动服务 +systemctl start mysqld +systemctl enable mysqld + +# 5. 获取临时密码 +grep 'temporary password' /var/log/mysqld.log + +# 6. 安全初始化 +mysql_secure_installation +``` + +### 2.2 Dockerfile 安装 + +```dockerfile +FROM mysql:8.0 +ENV MYSQL_ROOT_PASSWORD=your_password +VOLUME /var/lib/mysql +EXPOSE 3306 +``` + +### 2.3 二进制安装 + +```bash +# 1. 下载二进制包 +wget https://downloads.mysql.com/archives/get/mysql-8.0.35-linux-glibc2.17-x86_64.tar.gz + +# 2. 解压并创建用户 +tar xf mysql-8.0.35-linux-glibc2.17-x86_64.tar.gz -C /usr/local/ +ln -s /usr/local/mysql-8.0.35-linux-glibc2.17-x86_64 /usr/local/mysql +useradd -r -s /sbin/nologin mysql + +# 3. 初始化 +cd /usr/local/mysql +mysqld --initialize-insecure --user=mysql + +# 4. 启动 +mysqld_safe --user=mysql & +``` + +### 2.4 常见安装问题 + +```bash +# 解决依赖 +yum install -y libaio numactl + +# 解决 SSL 问题 +yum update openssl -y +``` + +--- + +## 3. 管理数据库和表 + +### 3.1 数据库操作 + +```sql +-- 创建数据库 +CREATE DATABASE db_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- 查看数据库 +SHOW DATABASES; +SHOW CREATE DATABASE db_name; + +-- 删除数据库 +DROP DATABASE db_name; + +-- 使用数据库 +USE db_name; +``` + +### 3.2 表操作 + +```sql +-- 创建表 +CREATE TABLE users ( + id INT PRIMARY KEY AUTO_INCREMENT, + name VARCHAR(50) NOT NULL, + email VARCHAR(100) UNIQUE, + password VARCHAR(255) NOT NULL, + status TINYINT DEFAULT 1, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- 查看表 +SHOW TABLES; +DESC users; +SHOW CREATE TABLE users; + +-- 修改表结构 +-- 添加列 +ALTER TABLE users ADD COLUMN phone VARCHAR(20) AFTER email; + +-- 修改列 +ALTER TABLE users MODIFY COLUMN name VARCHAR(100); + +-- 删除列 +ALTER TABLE users DROP COLUMN phone; + +-- 重命名表 +RENAME TABLE users TO app_users; + +-- 删除表 +DROP TABLE users; +``` + +### 3.3 数据操作 + +```sql +-- 插入数据 +INSERT INTO users (name, email, password) VALUES ('张三', 'zhangsan@example.com', 'pass123'); + +-- 批量插入 +INSERT INTO users (name, email, password) VALUES +('李四', 'lisi@example.com', 'pass123'), +('王五', 'wangwu@example.com', 'pass123'); + +-- 更新数据 +UPDATE users SET name = '新名字' WHERE id = 1; + +-- 删除数据 +DELETE FROM users WHERE id = 1; + +-- 条件插入或更新 +INSERT INTO users (id, name) VALUES (1, '张三') ON DUPLICATE KEY UPDATE name = '张三'; + +-- 替换 +REPLACE INTO users (id, name) VALUES (1, '张三'); +``` + +### 3.4 查询 + +```sql +-- 基础查询 +SELECT * FROM users; +SELECT id, name FROM users WHERE status = 1; + +-- 排序 +SELECT * FROM users ORDER BY created_at DESC; + +-- 分页 +SELECT * FROM users LIMIT 10 OFFSET 20; + +-- 聚合 +SELECT COUNT(*) FROM users; +SELECT SUM(amount) FROM orders; +SELECT AVG(age) FROM users; +SELECT MAX(score) FROM users; + +-- 分组 +SELECT status, COUNT(*) FROM users GROUP BY status; + +-- HAVING +SELECT status, COUNT(*) as cnt FROM users GROUP BY status HAVING cnt > 10; + +-- 多表查询 +-- 内连接 +SELECT u.name, o.order_no FROM users u INNER JOIN orders o ON u.id = o.user_id; + +-- 左连接 +SELECT u.name, o.order_no FROM users u LEFT JOIN orders o ON u.id = o.user_id; + +-- 子查询 +SELECT * FROM users WHERE id IN (SELECT user_id FROM orders); + +-- 联合查询 +SELECT name FROM users WHERE status = 1 UNION ALL SELECT name FROM admins; +``` + +--- + +## 4. 用户和权限管理 + +### 4.1 用户操作 + +```sql +-- 创建用户 +CREATE USER 'username'@'localhost' IDENTIFIED BY 'password'; +CREATE USER 'username'@'%' IDENTIFIED BY 'password'; + +-- 查看用户 +SELECT user, host FROM mysql.user; + +-- 重命名用户 +RENAME USER 'old'@'localhost' TO 'new'@'localhost'; + +-- 删除用户 +DROP USER 'username'@'localhost'; +``` + +### 4.2 权限管理 + +```sql +-- 授予权限 +GRANT SELECT, INSERT ON db_name.* TO 'username'@'localhost'; +GRANT ALL PRIVILEGES ON *.* TO 'username'@'%'; + +-- 撤销权限 +REVOKE INSERT ON db_name.* FROM 'username'@'localhost'; + +-- 查看权限 +SHOW GRANTS FOR 'username'@'localhost'; + +-- 刷新权限 +FLUSH PRIVILEGES; +``` + +### 4.3 角色管理(MySQL 8.0) + +```sql +-- 创建角色 +CREATE ROLE app_read, app_write; + +-- 授予角色权限 +GRANT SELECT ON db_name.* TO app_read; +GRANT SELECT, INSERT, UPDATE, DELETE ON db_name.* TO app_write; + +-- 授予用户角色 +GRANT app_read TO 'username'@'localhost'; + +-- 查看角色 +SELECT * FROM mysql.user WHERE account_type = 'role'; +``` + +### 4.4 密码策略(MySQL 8.0) + +```sql +-- 查看密码策略 +SHOW VARIABLES LIKE 'validate_password%'; + +-- 设置密码策略 +SET GLOBAL validate_password.policy = 'LOW'; +SET GLOBAL validate_password.length = 8; + +-- 锁定账户 +ALTER USER 'username'@'localhost' ACCOUNT LOCK; +ALTER USER 'username'@'localhost' ACCOUNT UNLOCK; +``` + +--- + +## 5. 函数、存储过程、触发器和事件 + +### 5.1 内置函数 + +```sql +-- 字符串函数 +SELECT CONCAT('Hello', ' ', 'World'); +SELECT UPPER(name), LOWER(email); +SELECT SUBSTRING('Hello', 1, 3); +SELECT TRIM(' abc '); +SELECT LPAD('5', 5, '0'); + +-- 数值函数 +SELECT ABS(-5); +SELECT ROUND(3.14159, 2); +SELECT CEIL(3.1), FLOOR(3.9); +SELECT MOD(10, 3); + +-- 日期函数 +SELECT NOW(), CURDATE(), CURTIME(); +SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s'); +SELECT DATE_ADD(NOW(), INTERVAL 1 DAY); +SELECT DATEDIFF('2024-01-01', '2023-01-01'); + +-- 条件函数 +SELECT IF(status = 1, '启用', '禁用'); +SELECT CASE status WHEN 1 THEN '启用' ELSE '禁用' END; +SELECT COALESCE(NULL, 'default'); +``` + +### 5.2 自定义函数 + +```sql +-- 创建函数 +DELIMITER // +CREATE FUNCTION get_user_name(uid INT) +RETURNS VARCHAR(100) +DETERMINISTIC +BEGIN + DECLARE result VARCHAR(100); + SELECT name INTO result FROM users WHERE id = uid; + RETURN result; +END // +DELIMITER ; + +-- 调用函数 +SELECT get_user_name(1); + +-- 删除函数 +DROP FUNCTION get_user_name; +``` + +### 5.3 存储过程 + +```sql +-- 创建存储过程 +DELIMITER // +CREATE PROCEDURE get_user_by_id(IN uid INT) +BEGIN + SELECT * FROM users WHERE id = uid; +END // + +CREATE PROCEDURE insert_user(IN name VARCHAR(50), IN email VARCHAR(100)) +BEGIN + INSERT INTO users (name, email) VALUES (name, email); + SELECT LAST_INSERT_ID() AS user_id; +END // + +CREATE PROCEDURE update_users_status() +BEGIN + UPDATE users SET status = 1 WHERE status = 0; +END // +DELIMITER ; + +-- 调用 +CALL get_user_by_id(1); + +-- 查看 +SHOW PROCEDURE STATUS; + +-- 删除 +DROP PROCEDURE update_users_status; +``` + +### 5.4 触发器 + +```sql +-- 创建触发器(插入后更新) +DELIMITER // +CREATE TRIGGER after_user_insert +AFTER INSERT ON users FOR EACH ROW +BEGIN + INSERT INTO user_logs (user_id, action) VALUES (NEW.id, 'insert'); +END // + +-- 删除后记录 +CREATE TRIGGER after_user_delete +AFTER DELETE ON users FOR EACH ROW +BEGIN + INSERT INTO user_logs (user_id, action, created_at) VALUES (OLD.id, 'delete', NOW()); +END // + +-- 更新前记录 +CREATE TRIGGER before_user_update +BEFORE UPDATE ON users FOR EACH ROW +BEGIN + SET NEW.updated_at = NOW(); +END // +DELIMITER ; + +-- 查看 +SHOW TRIGGERS; + +-- 删除 +DROP TRIGGER after_user_insert; +``` + +### 5.5 事件(定时任务) + +```sql +-- 开启事件调度器 +SET GLOBAL event_scheduler = ON; + +-- 创建事件 + DELIMITER // +CREATE EVENT clean_old_logs +ON SCHEDULE EVERY 1 DAY +DO BEGIN + DELETE FROM logs WHERE created_at < DATE_SUB(NOW(), INTERVAL 30 DAY); +END // +DELIMITER ; + +-- 查看 +SHOW EVENTS; +SHOW EVENTS FROM db_name; + +-- 开启/关闭事件 +ALTER EVENT clean_old_logs ENABLE; +ALTER EVENT clean_old_logs DISABLE; + +-- 删除 +DROP EVENT clean_old_logs; +``` + +--- + +## 6. MySQL 架构 + +### 6.1 架构图 + +``` +┌─────────────────────────────────────────┐ +│ 连接层(Connection Layer) │ +│ 连接管理器 │ 认证 │ 线程池 │ 连接缓冲 │ +└──────────────────┬──────────────────────┘ + │ +┌──────────────────▼──────────────────────┐ +│ SQL 层(SQL Layer) │ +│ 解析器 │ 查询优化器 │ 预处理器 │ 执行器 │ +└──────────────────┬──────────────────────┘ + │ +┌──────────────────▼──────────────────────┐ +│ 存储引擎层(Storage Engine) │ +│ InnoDB │ MyISAM │ Memory │ CSV │ +└──────────────────┬──────────────────────┘ + │ +┌──────────────────▼──────────────────────┐ +│ 物理层(Physical Layer) │ +│ 数据文件 │ 索引文件 │ 日志文件 │ redo │ +└─────────────────────────────────────────┘ +``` + +### 6.2 解析流程 + +``` +SQL 语句 + ↓ +词法分析(分词)→ 语法分析(解析)→ 语义分析(理解)→ 逻辑计划→ 物理执行计划→ 执行 +``` + +### 6.3 缓冲池 + +| 缓冲池 | 说明 | +|--------|------| +| Buffer Pool | 缓存数据页和索引页 | +| Log Buffer | Redo 日志缓冲 | +| Change Buffer | 变更缓冲(二级索引) | +| Adaptive Hash Index | 自适应哈希索引 | + +--- + +## 7. 存储引擎 + +### 7.1 引擎对比 + +| 引擎 | 事务 | 行锁 | 外键 | 全文索引 | 使用场景 | +|------|------|------|------|----------|----------| +| **InnoDB** | 支持 | 支持 | 支持 | 支持 | 默认,事务应用 | +| MyISAM | 不支持 | 表锁 | 不支持 | 支持 | 只读/静态表 | +| Memory | 不支持 | 表锁 | 不支持 | 不支持 | 临时表/缓存 | +| CSV | 不支持 | 表锁 | 不支持 | 不支持 | 数据交换 | +| Archive | 不支持 | 行锁 | 不支持 | 不支持 | 日志/归档 | +| Blackhole | 不支持 | 不支持 | 不支持 | 不支持 | 复制中继 | + +### 7.2 InnoDB + +```sql +-- 查看表引擎 +SHOW CREATE TABLE users; + +-- 修改表引擎 +ALTER TABLE users ENGINE = InnoDB; + +-- 查看 InnoDB 状态 +SHOW ENGINE InnoDB STATUS; + +-- InnoDB 配置 +SHOW VARIABLES LIKE 'innodb_%'; +``` + +### 7.3 表空间 + +```sql +-- 独立表空间 +innodb_file_per_table = 1 + +-- 查看表空间文件 +SHOW VARIABLES LIKE 'innodb_data_file_path'; +``` + +--- + +## 8. 服务器选项和变量 + +### 8.1 重要系统变量 + +```sql +-- 查看 +SHOW VARIABLES; +SHOW VARIABLES LIKE 'max_connections'; +SHOW GLOBAL VARIABLES; + +-- 永久修改(配置文件) +max_connections = 500 + +-- 临时修改(会话) +SET GLOBAL max_connections = 500; +SET SESSION sort_buffer_size = 256*1024; +``` + +### 8.2 常用配置 + +| 变量 | 说明 | 推荐值 | +|------|------|--------| +| max_connections | 最大连接数 | 500-1000 | +| query_cache_size | 查询缓存(8.0 已移除) | - | +| innodb_buffer_pool_size | 缓冲池大小 | 70-80% 内存 | +| innodb_log_file_size | 日志文件大小 | 1-2GB | +| max_allowed_packet | 最大包大小 | 64M | +| character_set_server | 默认字符集 | utf8mb4 | + +### 8.3 状态变量 + +```sql +-- 查看 +SHOW STATUS; +SHOW GLOBAL STATUS LIKE 'Threads_connected'; +SHOW GLOBAL STATUS LIKE 'Qcache%'; + +-- 关键状态 +Threads_connected -- 当前���接数 +Threads_running -- 活跃连接数 +Questions -- 总查询数 +Slow_queries -- 慢查询数 +``` + +### 8.4 配置文件示例 + +```ini +[mysqld] +port = 3306 +datadir = /var/lib/mysql +socket = /var/lib/mysql/mysql.sock +user = mysql +character-set-server = utf8mb4 +collation-server = utf8mb4_unicode_ci +max_connections = 500 +innodb_buffer_pool_size = 2G +innodb_log_file_size = 1G +slow_query_log = 1 +slow_query_log_file = /var/log/mysql/slow.log +long_query_time = 2 +``` + +--- + +## 9. 优化查询和索引管理 + +### 9.1 索引类型 + +| 类型 | 说明 | 示例 | +|------|------|------| +| 主键索引 | 唯一,非空 | PRIMARY KEY | +| 唯一索引 | 唯一,可空 | UNIQUE | +| 普通索引 | 可重复 | INDEX | +| 全文索引 | 文本搜索 | FULLTEXT | +| 组合索引 | 多列复合 | INDEX(a, b, c) | + +### 9.2 索引操作 + +```sql +-- 创建索引 +CREATE INDEX idx_name ON users(name); +CREATE UNIQUE INDEX idx_email ON users(email); +ALTER TABLE users ADD INDEX idx_status_created(status, created_at); + +-- 查看索引 +SHOW INDEX FROM users; + +-- 删除索引 +DROP INDEX idx_name ON users; +ALTER TABLE users DROP INDEX idx_email; +``` + +### 9.3 慢查询分析 + +```sql +-- 开启慢查询日志 +SET GLOBAL slow_query_log = 'ON'; +SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log'; +SET GLOBAL long_query_time = 2; + +-- 查看慢查询 +SELECT * FROM mysql.slow_log ORDER BY start_time DESC; + +-- 使用 EXPLAIN +EXPLAIN SELECT * FROM users WHERE name = '张三'; +EXPLAIN ANALYZE SELECT * FROM users WHERE name = '张三'; +``` + +### 9.4 查询优化技巧 + +```sql +-- 避免 SELECT * +SELECT id, name FROM users WHERE name = '张三'; + +-- 使用 LIMIT +SELECT * FROM users LIMIT 10; + +-- 避免函数作用于索引列 +-- 低效:WHERE YEAR(created_at) = 2024 +-- 高效:WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01' + +-- 使用覆盖索引 +SELECT id, name FROM users WHERE name = '张三'; + +-- 避免隐式转换 +-- 低效:WHERE phone = 13800138000 +-- 高效:WHERE phone = '13800138000' + +-- 合理使用 UNION +-- 使用 UNION ALL 避免重复检查 +SELECT name FROM users WHERE status = 1 +UNION ALL +SELECT name FROM admins WHERE status = 1; +``` + +### 9.5 索引失效场景 + +- 使用 `!=`、`<>`、NOT IN +- 使用 `IS NULL`、`IS NOT NULL` +- 使用函数或运算 +- 类型转换 +- LIKE 开头使用通配符 +- 多列索引不遵循最左前缀 + +--- + +## 10. 锁和事务管理 + +### 10.1 事务特性(ACID) + +| 特性 | 说明 | +|------|------| +| Atomicity(原子性) | 事务要么全成功,要么全失败 | +| Consistency(一致性) | 事务前后数据库状态一致 | +| Isolation(隔离性) | 并发事务互不干扰 | +| Durability(持久性) | 事务提交后永久保存 | + +### 10.2 事务控制 + +```sql +-- 开启事务 +START TRANSACTION; +BEGIN; + +-- 提交 +COMMIT; + +-- 回滚 +ROLLBACK; + +-- 设置保存点 +SAVEPOINT sp1; + +-- 回滚到保存点 +ROLLBACK TO SAVEPOINT sp1; +``` + +### 10.3 隔离级别 + +| 级别 | 脏读 | 不可重复读 | 幻读 | +|------|------|-----------|------| +| READ UNCOMMITTED | 可能 | 可能 | 可能 | +| READ COMMITTED | 不可能 | 可能 | 可能 | +| REPEATABLE READ | 不可能 | 不可能 | 可能(InnoDB 不可能) | +| SERIALIZABLE | 不可能 | 不可能 | 不可能 | + +```sql +-- 查看/设置隔离级别 +SELECT @@transaction_isolation; +SET TRANSACTION ISOLATION LEVEL READ COMMITTED; +SET GLOBAL transaction_isolation = 'READ-COMMITTED'; +``` + +### 10.4 锁 + +```sql +-- 行锁 +SELECT * FROM users WHERE id = 1 FOR UPDATE; + +-- 读锁 +SELECT * FROM users WHERE id = 1 LOCK IN SHARE MODE; + +-- 表锁 +LOCK TABLES users READ; +LOCK TABLES users WRITE; +UNLOCK TABLES; + +-- 查看锁 +SHOW ENGINE InnoDB STATUS; +SELECT * FROM information_schema. innodb_lock_waits; +``` + +### 10.5 死锁 + +```sql +-- 查看死锁信息 +SHOW ENGINE InnoDB STATUS; + +-- 避免死锁 +-- 1. 按相同顺序操作数据 +-- 2. 缩短事务时间 +-- 3. 小批量更新 +-- 4. 使用低隔离级别 +``` + +--- + +## 11. 日志管理 + +### 11.1 日志类型 + +| 日志 | 说明 | 位置 | +|------|------|------| +| Error Log | 错误日志 | log_error | +| Slow Query Log | 慢查询日志 | slow_query_log_file | +| General Log | 通用查询日志 | general_log_file | +| Binary Log | 二进制日志(复制/恢复) | log_bin | +| Relay Log | 中继日志 | relay_log | +| Redo Log | 重做日志 | innodb_log_file | + +### 11.2 二进制日志 + +```sql +-- 开启 +log_bin = /var/log/mysql/mysql-bin +server_id = 1 +expire_logs_days = 7 + +-- 查看 +SHOW MASTER STATUS; +SHOW BINLOG EVENTS IN 'mysql-bin.000001'; + +-- 使用 binlog 恢复 +mysqlbinlog mysql-bin.000001 | mysql -u root -p + +-- 基于位置恢复 +mysqlbinlog --stop-position=1234 mysql-bin.000001 | mysql + +-- 基于时间恢复 +mysqlbinlog --stop-datetime="2024-01-01 12:00:00" mysql-bin.000001 | mysql +``` + +### 11.3 慢查询日志 + +```sql +SET GLOBAL slow_query_log = 'ON'; +SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log'; +SET GLOBAL long_query_time = 2; +SET GLOBAL log_queries_not_using_indexes = 'ON'; +``` + +### 11.4 通用查询日志 + +```sql +SET GLOBAL general_log = 'ON'; +SET GLOBAL general_log_file = '/var/log/mysql/query.log'; +``` + +--- + +## 12. 备份还原 + +### 12.1 逻辑备份(mysqldump) + +```bash +# 备份单个库 +mysqldump -u root -p db_name > backup.sql + +# 备份所有库 +mysqldump -u root -p --all-databases > backup.sql + +# 备份指定表 +mysqldump -u root -p db_name table1 table2 > backup.sql + +# 备份结构(不备份数据) +mysqldump -u root -p -d db_name > structure.sql + +# 备份数据(不备份结构) +mysqldump -u root -p -t db_name > data.sql + +# 远程备份 +mysqldump -h remote_host -u root -p db_name > backup.sql + +# 压缩备份 +mysqldump -u root -p db_name | gzip > backup.sql.gz +``` + +### 12.2 逻辑还原 + +```bash +# 还原 +mysql -u root -p db_name < backup.sql + +# 压缩还原 +gunzip < backup.sql.gz | mysql -u root -p db_name +``` + +### 12.3 物理备份(xtrabackup) + +```bash +# 安装 +yum install percona-xtrabackup + +# 全量备份 +xtrabackup --backup --target-dir=/backup/full/ + +# 增量备份 +xtrabackup --backup --target-dir=/backup/inc1/ --incremental-basedir=/backup/full/ + +# 准备还原 +xtrabackup --prepare --target-dir=/backup/full/ + +# 还原 +xtrabackup --copy-back --target-dir=/backup/full/ + +# 停止 MySQL +systemctl stop mysqld + +# 删除数据文件 +rm -rf /var/lib/mysql/* + +# 复制还原 +xtrabackup --copy-back --target-dir=/backup/full/ + +# 修改权限 +chown -R mysql:mysql /var/lib/mysql + +# 启动 +systemctl start mysqld +``` + +### 12.4 定时备份脚本 + +```bash +#!/bin/bash +BACKUP_DIR="/backup" +DATE=$(date +%Y%m%d_%H%M%S) +mysqldump -u root -p'your_password' --all-databases | gzip > $BACKUP_DIR/mysql_$DATE.sql.gz +find $BACKUP_DIR -mtime +7 -name "*.gz" -delete +``` + +crontab: +``` +0 2 * * * /path/to/backup.sh +``` + +--- + +## 13. MySQL 集群 + +### 13.1 主从复制 + +``` +主库(Master) → 从库(Slave) + ↓ +写入 Binary Log → 读取 Relay Log → 重放 +``` + +**主库配置**: +```ini +[mysqld] +server-id = 1 +log_bin = /var/log/mysql/mysql-bin +``` + +**从库配置**: +```ini +[mysqld] +server-id = 2 +relay_log = /var/log/mysql/mysql-relay-bin +read_only = 1 +``` + +**配置复制**: +```sql +-- 主库创建复制用户 +CREATE USER 'repl'@'%' IDENTIFIED BY 'replpass'; +GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%'; + +-- 从库配置主库 +CHANGE MASTER TO + MASTER_HOST='master_host', + MASTER_USER='repl', + MASTER_PASSWORD='replpass', + MASTER_LOG_FILE='mysql-bin.000001', + MASTER_LOG_POS=1234; + +-- 启动复制 +START SLAVE; + +-- 查看状态 +SHOW SLAVE STATUS; +``` + +### 13.2 主主复制 + +``` +库A ←→ 库B +``` + +配置双向复制即可,注意自增 ID 冲突: +```ini +auto_increment_increment = 2 +auto_increment_offset = 1 # 节点1 +auto_increment_offset = 2 # 节点2 +``` + +### 13.3 读写分离(ProxySQL) + +```bash +# 安装 +yum install proxysql2 + +# 配置 +SELECT * FROM mysql_servers; +SELECT * FROM mysql_users; +SELECT * FROM mysql_query_rules; +LOAD MYSQL SERVER TO RUNTIME; +LOAD MYSQL USER TO RUNTIME; +``` + +### 13.4 MySQL Router + +```bash +# 安装 +yum install mysql-router + +# 配置 +[logger] +level = INFO + +[metadata_cache] +cluster_type = gr +group_replication_group_name = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" +metadata_cluster = mycluster +router_uuid = cluster_router + +[bind_address] +address = 0.0.0.0 +force_primary_connection = true +``` + +--- + +## 14. 压力测试 + +### 14.1 sysbench + +```bash +# 安装 +yum install sysbench + +# 准备测试 +sysbench /usr/share/sysbench/oltp_common.lua \ + --mysql-host=127.0.0.1 \ + --mysql-port=3306 \ + --mysql-user=root \ + --mysql-password=password \ + --mysql-db=test \ + --tables=10 \ + --table-size=100000 \ + prepare + +# 运行测试 +sysbench /usr/share/sysbench/oltp_read_write.lua \ + --mysql-host=127.0.0.1 \ + --mysql-port=3306 \ + --mysql-user=root \ + --mysql-password=password \ + --mysql-db=test \ + --tables=10 \ + --table-size=100000 \ + --threads=100 \ + --time=60 \ + run + +# 清理 +sysbench /usr/share/sysbench/oltp_common.lua \ + --mysql-db=test \ + --tables=10 \ + cleanup +``` + +### 14.2 mysqlslap + +```bash +# 单轮测试 +mysqlslap --create-schema=testdb --query="SELECT * FROM users" --concurrency=50 --iterations=10 + +# 完整测试 +mysqlslap --user=root --password=password \ + --create-schema=testdb \ + --query="SELECT COUNT(*) FROM orders WHERE created_at > NOW()" \ + --concurrency=10,50,100 \ + --iterations=5 \ + --no-drop +``` + +### 14.3 tpcc-mysql + +```bash +# 安装 +wget https://github.com/PerconaLab/tpcc-mysql/archive/refs/heads/master.zip +unzip master.zip + +# 编译 +cd tpcc-mysql-master/src +make + +# 创建表 +mysql -u root -p -e "CREATE DATABASE tpcc;" +mysql -u root -p tpcc < create_table.sql +mysql -u root -p tpcc < add_fkeys.sql + +# 导入数据 +tpcc_load -h localhost -P 3306 -d tpcc -u root -p "" -w 10 + +# 运行测试 +tpcc_start -h localhost -P 3306 -d tpcc -u root -p "" -w 10 -c 10 -r 120 -l 1800 +``` + +### 14.4 测试报告解读 + +| 指标 | 含义 | 基准 | +|------|------|------| +| TPS | 每秒事务数 | > 1000 | +| QPS | 每秒查询数 | > 5000 | +| 响应时间 | 平均延迟 | < 50ms | +| 95%延迟 | P95 延迟 | < 100ms | +| 连接数 | 并发连接 | 可用连接 80% | + +--- + +## 15. 常用命令速查 + +### 15.1 连接管理 + +| 场景 | 命令 | +|------|------| +| 连接本地 | `mysql -u root -p` | +| 连接远程 | `mysql -h host -P 3306 -u root -p` | +| 导入 SQL | `mysql -u root -p db < file.sql` | +| 导出 SQL | `mysqldump -u root -p db > file.sql` | + +### 15.2 状态查看 + +| 场景 | 命令 | +|------|------| +| 查看进程 | `SHOW PROCESSLIST;` | +| 查看状态 | `SHOW STATUS;` | +| 查看变量 | `SHOW VARIABLES;` | +| 查看引擎 | `SHOW ENGINES;` | +| 查看连接 | `SHOW STATUS LIKE 'Threads%';` | + +### 15.3 性能分析 + +| 场景 | 命令 | +|------|------| +| 分析查询 | `EXPLAIN SELECT...` | +| 分析成本 | `EXPLAIN ANALYZE SELECT...` | +| 查看慢查询 | `SELECT * FROM mysql.slow_log;` | +| 查看索引 | `SHOW INDEX FROM table;` | + +--- + +## 16. 小结 + +| 类别 | 关键点 | +|------|--------| +| 存储引擎 | InnoDB(默认,事务安全) | +| 字符集 | utf8mb4(支持 emoji) | +| 隔离级别 | READ COMMITTED | +| 备份 | mysqldump(逻辑)/xtrabackup(物理) | +| 优化 | 索引 + EXPLAIN + 慢查询日志 | +| 集群 | 主从复制/读写分离 | + +> 建议:生产环境使用 MySQL 8.0 + InnoDB,配置主从复制,定期备份。 \ No newline at end of file diff --git a/运维/数据库/PostgreSQL/PostgreSQL.md b/运维/数据库/PostgreSQL/PostgreSQL.md index e69de29..d13ded2 100644 --- a/运维/数据库/PostgreSQL/PostgreSQL.md +++ b/运维/数据库/PostgreSQL/PostgreSQL.md @@ -0,0 +1,1165 @@ +# PostgreSQL 实战指南 + +## 目录 + +1. [PostgreSQL 介绍](#1-postgresql-介绍) +2. [PostgreSQL 安装](#2-postgresql-安装) +3. [PostgreSQL 管理](#3-postgresql-管理) +4. [PostgreSQL 体系架构](#4-postgresql-体系架构) +5. [PostgreSQL 备份还原](#5-postgresql-备份还原) +6. [PostgreSQL 高可用](#6-postgresql-高可用) + +--- + +## 1. PostgreSQL 介绍 + +### 1.1 什么是 PostgreSQL + +PostgreSQL 是一个功能强大的开源对象关系型数据库系统(ORDBMS),支持 SQL 标准并具有丰富的企业级特性。作为最先进的开源数据库,PostgreSQL 以其可靠性、数据完整性和扩展性著称。 + +### 1.2 PostgreSQL 特点 + +| 特性 | 说明 | +|------|------| +| 开源免费 | 完全开源,BSD/MIT 许可证 | +| ACID 完整 | 完全支持 ACID 事务特性 | +| MVCC | 多版本并发控制,支持高并发 | +| 丰富数据类型 | 支持数组、JSON、UUID、几何类型等 | +| 索引类型 | 支持 B-tree、Hash、GIN、GiST、BRIN 等 | +| 扩展性 | 支持自定义函数、操作符、数据类型 | +| 外键约束 | 完整的外键约束支持 | +| 视图 | 支持物化视图、普通视图 | +| 触发器 | 支持行级和语句级触发器 | +| 存储过程 | 支持存储过程(多种语言) | +| 分区表 | 支持范围分区、列表分区、哈希分区 | +| 复制 | 支持流复制、逻辑复制 | +| 集群 | 支持 Citus 分布式集群 | + +### 1.3 PostgreSQL 应用场景 + +| 场景 | 说明 | +|------|------| +| 企业应用 | ERP、CRM 等企业级应用数据库 | +| GIS 应用 | PostGIS 扩展支持地理信息系统 | +| 数据仓库 | 分析型数据库,大数据处理 | +| Web 应用 | LAMP/LEMP 架构数据存储 | +| 金融系统 | 对事务要求严格的系统 | +| 科研数据 | 科研数据存储和分析 | + +### 1.4 PostgreSQL 与 MySQL 对比 + +| 特性 | PostgreSQL | MySQL | +|------|------------|-------| +| 事务支持 | 完整 ACID | ACID(InnoDB) | +| 并发控制 | MVCC | MVCC(InnoDB) | +| 数据类型 | 丰富 | 基础 | +| 索引类型 | 多样 | 较少 | +| 扩展性 | 强大 | 一般 | +| 复制 | 流复制/逻辑复制 | 主从复制/GTID | +| 性能 | 复杂查询快 | 简单查询快 | +| 许可证 | BSD | GPL | + +--- + +## 2. PostgreSQL 安装 + +### 2.1 环境要求 + +- 操作系统:Linux(CentOS/Ubuntu/Debian)、macOS、Windows +- 内存:至少 1GB(生产环境建议 4GB+) +- 磁盘:至少 100GB + +### 2.2 YUM 安装(CentOS/RHEL) + +```bash +# 安装 PostgreSQL Yum 源 +yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-8-x86_64/pgdg-redhat-repo-latest.noarch.rpm + +# 安装 PostgreSQL 服务器和客户端 +yum install -y postgresql15-server postgresql15 + +# 初始化数据库 +/usr/pgsql-15/bin/postgresql-15-setup initdb + +# 启动服务 +systemctl start postgresql-15 +systemctl enable postgresql-15 + +# 检查服务状态 +systemctl status postgresql-15 +``` + +### 2.3 APT 安装(Debian/Ubuntu) + +```bash +# 安装 PostgreSQL APT 源 +sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' +wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - + +# 更新并安装 +apt update +apt install -y postgresql-15 postgresql-client-15 + +# 启动服务 +systemctl start postgresql +systemctl enable postgresql +``` + +### 2.4 源码编译安装 + +```bash +# 安装依赖 +yum install -y gcc make libxml2 libuuid openssl readline zlib + +# 下载源码 +wget https://ftp.postgresql.org/pub/source/v15.4/postgresql-15.4.tar.gz +tar -zxf postgresql-15.4.tar.gz +cd postgresql-15.4 + +# 配置 +./configure --prefix=/usr/local/pgsql-15 \ + --with-openssl \ + --with-readline \ + --with-uuid=libuuid \ + --with-libxml \ + --with-zlib + +# 编译安装 +make -j4 +make install + +# 创建用户 +useradd -m -s /bin/bash postgres +mkdir -p /usr/local/pgsql-15/data +chown -R postgres:postgres /usr/local/pgsql-15 + +# 切换用户初始化 +su - postgres +/usr/local/pgsql-15/bin/initdb -D /usr/local/pgsql-15/data + +# 启动数据库 +/usr/local/pgsql-15/bin/pg_ctl -D /usr/local/pgsql-15/data -l /usr/local/pgsql-15/logfile start +``` + +### 2.5 Docker 安装 + +```bash +# 拉取镜像 +docker pull postgres:15 + +# 运行容器 +docker run -d \ + --name postgres \ + -e POSTGRES_PASSWORD=your_password \ + -e POSTGRES_USER=admin \ + -e POSTGRES_DB=mydb \ + -p 5432:5432 \ + -v /data/postgres/data:/var/lib/postgresql/data \ + postgres:15 + +# 使用配置文件启动 +docker run -d \ + --name postgres \ + -e POSTGRES_PASSWORD=your_password \ + -v /data/postgres/postgresql.conf:/etc/postgresql/postgresql.conf \ + -v /data/postgres/data:/var/lib/postgresql/data \ + postgres:15 -c config-file=/etc/postgresql/postgresql.conf +``` + +### 2.6 基础配置 + +```bash +# postgresql.conf 主要配置 + +# 连接配置 +listen_addresses = '*' +port = 5432 +max_connections = 200 + +# 内存配置 +shared_buffers = 4GB +effective_cache_size = 12GB +work_mem = 256MB +maintenance_work_mem = 1GB + +# 持久化配置 +wal_level = replica +max_wal_size = 1GB +min_wal_size = 80MB + +# 日志配置 +log_destination = 'stderr' +logging_collector = on +log_directory = 'log' +log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' +log_statement = 'ddl' +log_min_duration_statement = 1000 + +# 复制配置 +wal_sender_timeout = 60s +wal_receiver_timeout = 60s + +# 客户端连接配置 +authentication_timeout = 1min +password_encryption = scram-sha-256 +``` + +### 2.7 pg_hba.conf 配置 + +```bash +# pg_hba.conf - 客户端认证 + +# 本地连接 +local all all trust + +# IPv4 本地回环 +host all all 127.0.0.1/32 scram-sha-256 + +# IPv6 本地回环 +host all all ::1/128 scram-sha-256 + +# 允许特定网段 +host all all 192.168.1.0/24 scram-sha-256 + +# 允许所有网段(生产环境谨慎) +# host all all 0.0.0.0/0 scram-sha-256 + +# 复制连接 +local replication all trust +host replication all 127.0.0.1/32 scram-sha-256 +host replication all ::1/128 scram-sha-256 +host replication all 192.168.1.0/24 scram-sha-256 +``` + +### 2.8 启动和停止 + +```bash +# 服务方式(使用 RPM/APT 安装) +systemctl start postgresql-15 +systemctl stop postgresql-15 +systemctl restart postgresql-15 +systemctl status postgresql-15 + +# 手动方式 +pg_ctl -D /var/lib/pgsql/15/data start +pg_ctl -D /var/lib/pgsql/15/data stop + +# 连接数据库 +psql -U postgres +psql -h localhost -U postgres -d mydb +``` + +--- + +## 3. PostgreSQL 管理 + +### 3.1 连接和基本操作 + +```bash +# 连接数据库 +psql -U username -d database_name +psql -h hostname -p 5432 -U username -d database_name + +# 常用命令 +\l # 列出所有数据库 +\d # 列出当前数据库的所有表 +\d table_name # 查看表结构 +\du # 列出所有用户 +\di # 列出所有索引 +\dv # 列出所有视图 +\dt # 列出所有表 +\db # 列出所有表空间 +\x # 展开显示 +\? # 帮助 +\q # 退出 +``` + +### 3.2 数据库操作 + +```bash +# 创建数据库 +CREATE DATABASE mydb; + +# 创建数据库(指定所有者、编码) +CREATE DATABASE mydb + OWNER postgres + ENCODING 'UTF8' + TEMPLATE template0; + +# 删除数据库 +DROP DATABASE mydb; + +# 修改数据库 +ALTER DATABASE mydb RENAME TO newdb; +ALTER DATABASE mydb SET work_mem = '256MB'; + +# 切换数据库 +\c mydb +\connect mydb +``` + +### 3.3 表操作 + +```bash +# 创建表 +CREATE TABLE users ( + id SERIAL PRIMARY KEY, + username VARCHAR(50) UNIQUE NOT NULL, + email VARCHAR(100) NOT NULL, + password VARCHAR(255) NOT NULL, + age INTEGER CHECK (age >= 0), + status SMALLINT DEFAULT 1, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +# 创建表(带约束) +CREATE TABLE orders ( + id SERIAL PRIMARY KEY, + user_id INTEGER REFERENCES users(id) ON DELETE CASCADE, + total_amount DECIMAL(10, 2) NOT NULL, + status VARCHAR(20) DEFAULT 'pending', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT valid_amount CHECK (total_amount >= 0) +); + +# 查看表结构 +\d users + +# 修改表 +ALTER TABLE users ADD COLUMN phone VARCHAR(20); +ALTER TABLE users DROP COLUMN phone; +ALTER TABLE users RENAME COLUMN email TO user_email; +ALTER TABLE users ALTER COLUMN age SET DEFAULT 18; +ALTER TABLE users ALTER COLUMN age DROP DEFAULT; +ALTER TABLE users ADD CONSTRAINT unique_email UNIQUE (user_email); + +# 删除表 +DROP TABLE users; +DROP TABLE IF EXISTS users; +``` + +### 3.4 索引操作 + +```bash +# 创建索引 +CREATE INDEX idx_users_email ON users(email); +CREATE INDEX idx_users_status ON users(status); +CREATE INDEX idx_users_created ON users(created_at DESC); + +# 创建唯一索引 +CREATE UNIQUE INDEX idx_users_username ON users(username); + +# 创建复合索引 +CREATE INDEX idx_orders_user_status ON orders(user_id, status); + +# 创建部分索引 +CREATE INDEX idx_orders_active ON orders(user_id) WHERE status = 'active'; + +# 创建表达式索引 +CREATE INDEX idx_users_lower_email ON users(LOWER(email)); + +# 查看索引 +\d users +SELECT * FROM pg_indexes WHERE tablename = 'users'; + +# 删除索引 +DROP INDEX idx_users_email; +``` + +### 3.5 用户和权限管理 + +```bash +# 创建用户 +CREATE USER username WITH PASSWORD 'password'; + +# 创建超级用户 +CREATE USER admin WITH SUPERUSER PASSWORD 'password'; + +# 修改用户 +ALTER USER username WITH PASSWORD 'newpassword'; +ALTER USER username VALID UNTIL '2025-01-01'; +ALTER USER username CREATEDB; +ALTER USER username CREATEROLE; + +# 删除用户 +DROP USER username; + +# 创建角色 +CREATE ROLE readonly; +CREATE ROLE readwrite; + +# 角色授权 +GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly; +GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO readwrite; +GRANT USAGE ON ALL SEQUENCES IN SCHEMA public TO readwrite; + +# 默认权限 +ALTER DEFAULT PRIVILEGES IN SCHEMA public + GRANT SELECT ON TABLES TO readonly; + +# 撤销权限 +REVOKE ALL PRIVILEGES ON TABLE users FROM username; +REVOKE INSERT ON ALL TABLES IN SCHEMA public FROM readwrite; + +# 查看权限 +\du username +``` + +### 3.6 视图操作 + +```bash +# 创建视图 +CREATE VIEW user_orders AS +SELECT u.username, o.id, o.total_amount, o.status, o.created_at +FROM users u +JOIN orders o ON u.id = o.user_id; + +# 创建物化视图 +CREATE MATERIALIZED VIEW monthly_sales AS +SELECT DATE_TRUNC('month', created_at) AS month, SUM(total_amount) AS total +FROM orders +GROUP BY DATE_TRUNC('month', created_at); + +# 刷新物化视图 +REFRESH MATERIALIZED VIEW monthly_sales; + +# 删除视图 +DROP VIEW user_orders; +DROP MATERIALIZED VIEW monthly_sales; +``` + +### 3.7 函数和存储过程 + +```bash +# 创建函数 +CREATE OR REPLACE FUNCTION get_user_count() +RETURNS INTEGER AS $$ +BEGIN + RETURN (SELECT COUNT(*) FROM users); +END; +$$ LANGUAGE plpgsql; + +# 创建存储过程( PostgreSQL 11+) +CREATE OR REPLACE PROCEDURE update_user_status(user_id INT, new_status INT) +LANGUAGE plpgsql AS $$ +BEGIN + UPDATE users SET status = new_status, updated_at = CURRENT_TIMESTAMP + WHERE id = user_id; +END; +$$; + +# 调用存储过程 +CALL update_user_status(1, 2); +``` + +### 3.8 触发器 + +```bash +# 创建触发器函数 +CREATE OR REPLACE FUNCTION update_timestamp() +RETURNS TRIGGER AS $$ +BEGIN + NEW.updated_at = CURRENT_TIMESTAMP; + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +# 创建触发器 +CREATE TRIGGER update_users_timestamp + BEFORE UPDATE ON users + FOR EACH ROW + EXECUTE FUNCTION update_timestamp(); + +# 查看触发器 +\dT+ users + +# 删除触发器 +DROP TRIGGER update_users_timestamp ON users; +``` + +### 3.9 分区表 + +```bash +# 创建范围分区表 +CREATE TABLE orders ( + id BIGSERIAL, + user_id INTEGER NOT NULL, + total_amount DECIMAL(10, 2) NOT NULL, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +) PARTITION BY RANGE (created_at); + +# 创建分区 +CREATE TABLE orders_2024 PARTITION OF orders + FOR VALUES FROM ('2024-01-01') TO ('2025-01-01'); + +CREATE TABLE orders_2025 PARTITION OF orders + FOR VALUES FROM ('2025-01-01') TO ('2026-01-01'); + +# 创建列表分区 +CREATE TABLE products ( + id SERIAL, + name VARCHAR(100), + category VARCHAR(50) +) PARTITION BY LIST (category); + +CREATE TABLE products_electronics PARTITION OF products + FOR VALUES IN ('electronics', 'computers'); + +CREATE TABLE products_clothing PARTITION OF products + FOR VALUES IN ('clothing', 'fashion'); +``` + +### 3.10 性能分析 + +```bash +# 查看慢查询 +SELECT query, calls, mean_time, total_time +FROM pg_stat_statements +ORDER BY total_time DESC +LIMIT 10; + +# 查看表大小 +SELECT relname, pg_size_pretty(pg_total_relation_size(relid)) +FROM pg_catalog.pg_statio_user_tables +ORDER BY pg_total_relation_size(relid) DESC; + +# 查看索引使用情况 +SELECT indexrelname, idx_scan, idx_tup_read, idx_tup_fetch +FROM pg_stat_user_indexes +ORDER BY idx_scan DESC; + +# 分析表 +ANALYZE users; + +# 清理缓存 +DISCARD ALL; +``` + +--- + +## 4. PostgreSQL 体系架构 + +### 4.1 架构概述 + +PostgreSQL 采用**进程/线程混合架构**,主要包括: + +``` +┌─────────────────────────────────────────────────────┐ +│ PostgreSQL 进程结构 │ +├─────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────┐ │ +│ │ Postmaster │ ← 主进程(父进程) │ +│ │ (PID 1234) │ │ +│ └──────┬───────┘ │ +│ │ │ +│ ┌─────┼─────┬─────────────┐ │ +│ │ │ │ │ │ +│ ▼ ▼ ▼ ▼ │ +│ ┌────┐ ┌────┐ ┌──────┐ ┌──────┐ │ +│ │Writer│ │Wal │ │Check-│ │Auto-│ │ +│ │Writer│ │Writer│ │pointer│ │vacuum│ │ +│ └────┘ └────┘ └──────┘ └──────┘ │ +│ │ +│ ┌──────────────────────────────────────────────┐ │ +│ │ Client Connections │ │ +│ │ ┌──────┐ ┌──────┐ ┌──────┐ │ │ +│ │ │postgres│ │postgres│ │postgres│ ... │ │ +│ │ │(PID 1) │ │(PID 2) │ │(PID 3) │ │ │ +│ │ └──────┘ └──────┘ └──────┘ │ │ +│ └──────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────┘ +``` + +### 4.2 进程说明 + +| 进程 | 说明 | +|------|------| +| **Postmaster** | 主进程,监听连接请求,创建子进程 | +| **Writer** | 负责将数据写入磁盘 | +| **Wal Writer** | 负责将 WAL 写入磁盘 | +| **Checkpointer** | 检查点进程,触发检查点 | +| **Autovacuum** | 自动 vacuum 进程 | +| **Archiver** | WAL 归档进程 | +| **Stats Collector** | 统计信息收集进程 | +| **Bgwriter** | 后台写进程 | +| **Client Process** | 每个客户端连接对应的服务进程 | + +### 4.3 内存结构 + +``` +┌─────────────────────────────────────────────────────┐ +│ PostgreSQL 内存结构 │ +├─────────────────────────────────────────────────────┤ +│ │ +│ 共享内存(Shared Memory) │ +│ ┌─────────────────────────────────────────────┐ │ +│ │ shared_buffers ← 数据缓存 │ │ +│ │ wal_buffers ← WAL 缓冲区 │ │ +│ │ commit_timestamp buffers │ │ +│ │ locks ← 锁管理 │ │ +│ │ predicate_locks ← 谓词锁 │ │ +│ │ transaction logs ← 事务日志 │ │ +│ └─────────────────────────────────────────────┘ │ +│ │ +│ 进程内存(Process Memory) │ +│ ┌─────────────────────────────────────────────┐ │ +│ │ work_mem ← 排序/哈希操作内存 │ │ +│ │ maintenance_work_mem ← 维护操作内存 │ │ +│ │ temp_buffers ← 临时表缓存 │ │ +│ │ parallel_worker ← 并行工作进程内存 │ │ +│ └─────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────┘ +``` + +### 4.4 核心概念 + +#### 4.4.1 共享内存 + +| 参数 | 说明 | +|------|------| +| `shared_buffers` | 数据页缓存,建议设置为系统内存的 25% | +| `wal_buffers` | WAL 缓冲区,默认 16MB | +| `effective_cache_size` | 操作系统缓存估计,影响查询规划 | + +#### 4.4.2 进程内存 + +| 参数 | 说明 | +|------|------| +| `work_mem` | 排序和哈希操作内存,每个操作独立分配 | +| `maintenance_work_mem` | 维护操作(VACUUM、CREATE INDEX)内存 | +| `temp_buffers` | 临时表缓存 | + +### 4.5 存储结构 + +#### 4.5.1 物理存储 + +``` +PostgreSQL 数据目录:$PGDATA + +$PGDATA/ +├── base/ # 表数据文件 +│ ├── 12345/ # 数据库 OID +│ │ ├── 12345 # 表文件 +│ │ ├── 12345.1 # 表文件(超过 1GB 自动分卷) +│ │ └── 12345_vm # 可见性映射 +│ └── ... +├── global/ # 系统表 +├── pg_wal/ # WAL 日志 +├── pg_xact/ # 事务状态 +├── pg_notify/ # LISTEN/NOTIFY +├── pg_serial/ # 可序列化事务 +├── pg_subtrans/ # 子事务 +├── pg_tblspc/ # 表空间链接 +├── pg_dynshmem/ # 动态共享内存 +├── pg_replslot/ # 复制槽 +├── pg_stat/ # 统计信息 +├── pg_stat_tmp/ # 临时统计信息 +├── pg_snapshots/ # 导出快照 +├── pg_logical/ # 逻辑解码 +├── pg_walwriter/ # WAL 写入器 +├── pg_conf/ # 配置文件 +├── postgresql.conf # 主配置文件 +├── pg_hba.conf # 客户端认证 +└── pg_ident.conf # 用户映射 +``` + +#### 4.5.2 逻辑存储 + +- **表(Table)**:由行组成的数据集合 +- **行(Row)**:一条记录 +- **页(Page)**:默认 8KB,存储基本单元 +- **元组(Tuple)**:行的物理表示 + +### 4.6 事务管理 + +#### 4.6.1 MVCC 机制 + +PostgreSQL 使用 MVCC(多版本并发控制)实现事务隔离: + +- 每次更新创建新版本,旧版本保留 +- 事务通过查看版本号判断可见性 +- 读写不冲突,提高并发性能 + +#### 4.6.2 事务隔离级别 + +```sql +-- 查看当前隔离级别 +SHOW transaction_isolation; + +-- 设置隔离级别 +SET TRANSACTION ISOLATION LEVEL READ COMMITTED; +SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE; +``` + +| 级别 | 说明 | 脏读 | 不可重复读 | 幻读 | +|------|------|------|------------|------| +| READ UNCOMMITTED | 读未提交 | 可能 | 可能 | 可能 | +| READ COMMITTED | 读已提交 | 不可能 | 可能 | 可能 | +| REPEATABLE READ | 可重复读 | 不可能 | 不可能 | 可能 | +| SERIALIZABLE | 串行化 | 不可能 | 不可能 | 不可能 | + +### 4.7 WAL 日志 + +#### 4.7.1 WAL 机制 + +WAL(Write Ahead Logging)预写日志,确保数据持久性: + +1. 事务提交时,先写 WAL +2. WAL 写入磁盘后,返回成功 +3. 后台将数据写入磁盘 + +#### 4.7.2 检查点 + +```sql +-- 手动执行检查点 +CHECKPOINT; + +-- 查看检查点统计 +SELECT * FROM pg_stat_checkpoints; +``` + +### 4.8 存储引擎 + +PostgreSQL 使用单一存储引擎(heap),通过不同索引实现不同访问模式: + +| 索引类型 | 适用场景 | +|----------|----------| +| B-tree | 范围查询、排序 | +| Hash | 精确匹配 | +| GiST | 几何、地理数据 | +| GIN | 全文搜索、数组 | +| BRIN | 顺序扫描、大表 | +| SP-GiST | 空间分割 | + +--- + +## 5. PostgreSQL 备份还原 + +### 5.1 备份类型 + +| 类型 | 说明 | 工具 | +|------|------|------| +| SQL 导出 | 逻辑备份,可跨版本 | pg_dump | +| 物理备份 | 直接复制数据文件 | pg_basebackup | +| 归档备份 | 增量备份 | WAL 归档 | + +### 5.2 逻辑备份(pg_dump) + +```bash +# 备份单个数据库 +pg_dump -U postgres -Fc mydb > mydb.dump +pg_dump -U postgres -Fp mydb > mydb.sql + +# 备份所有数据库 +pg_dumpall -U postgres > all_databases.sql + +# 备份指定表 +pg_dump -U postgres -t users -t orders mydb > tables.sql + +# 备份表结构 +pg_dump -U postgres -s mydb > schema.sql + +# 备份数据 +pg_dump -U postgres -a mydb > data.sql + +# 压缩备份 +pg_dump -U postgres -Fc mydb > mydb.dump.gz + +# 并行备份(PostgreSQL 13+) +pg_dump -U postgres -Fd -j 4 -f backup_dir mydb +``` + +### 5.3 逻辑还原(pg_restore) + +```bash +# 还原数据库 +psql -U postgres -d mydb < mydb.sql + +# 还原压缩备份 +pg_restore -U postgres -d mydb mydb.dump + +# 还原前删除原有对象 +pg_restore -U postgres -d mydb --clean mydb.dump + +# 还原到新数据库 +createdb -U postgres newdb +pg_restore -U postgres -d newdb mydb.dump + +# 还原并行备份 +pg_restore -U postgres -d mydb -j 4 backup_dir/ +``` + +### 5.4 物理备份(pg_basebackup) + +```bash +# 基础物理备份 +pg_basebackup -U postgres -D /backup/base -Ft -z -P + +# 流复制备份 +pg_basebackup -U postgres -D /backup/base -Xs -P + +# 带 WAL 的备份 +pg_basebackup -U postgres -D /backup/base -X stream -P + +# 备份到远程 +pg_basebackup -U postgres -h remote_host -D /backup/base -Xs -P +``` + +### 5.5 PITR(时间点恢复) + +#### 5.5.1 配置 WAL 归档 + +```bash +# postgresql.conf +wal_level = replica +archive_mode = on +archive_command = 'test ! -f /backup/wal/%f && cp %p /backup/wal/%f' +archive_timeout = 300 +``` + +#### 5.5.2 执行基础备份 + +```bash +pg_basebackup -U postgres -D /backup/base -Ft -z -P +``` + +#### 5.5.3 恢复配置 + +```bash +# postgresql.conf 恢复配置 +restore_command = 'cp /backup/wal/%f %p' +recovery_target_time = '2024-01-15 10:00:00' + +# 创建恢复信号文件 +touch /var/lib/pgsql/15/data/recovery.signal +``` + +#### 5.5.4 启动恢复 + +```bash +# 停止 PostgreSQL +pg_ctl -D /var/lib/pgsql/15/data stop + +# 修改配置后启动 +pg_ctl -D /var/lib/pgsql/15/data -l /var/lib/pgsql/15/data/logfile start +``` + +### 5.6 定时备份脚本 + +```bash +#!/bin/bash + +# 备份配置 +BACKUP_DIR="/backup/postgresql" +DATE=$(date +%Y%m%d_%H%M%S) +DB_NAME="mydb" +DB_USER="postgres" + +# 创建备份目录 +mkdir -p $BACKUP_DIR + +# 删除 7 天前的备份 +find $BACKUP_DIR -type f -mtime +7 -delete + +# 执行备份 +pg_dump -U $DB_USER -Fc $DB_NAME > $BACKUP_DIR/${DB_NAME}_${DATE}.dump + +# 记录日志 +echo "[$(date)] Backup completed: ${DB_NAME}_${DATE}.dump" >> /var/log/pg_backup.log +``` + +### 5.7 自动备份(cron) + +```bash +# 编辑 crontab +crontab -e + +# 每天凌晨 2 点执行备份 +0 2 * * * /usr/local/bin/backup.sh + +# 每天凌晨 2 点和下午 2 点执行备份 +0 2,14 * * * /usr/local/bin/backup.sh +``` + +--- + +## 6. PostgreSQL 高可用 + +### 6.1 高可用方案概述 + +| 方案 | 说明 | 复杂度 | 延迟 | +|------|------|--------|------| +| 流复制 | 主从同步复制 | 低 | 低 | +| 逻辑复制 | 表级别复制 | 中 | 低 | +| Patroni + etcd | 自动故障转移 | 高 | 低 | +| PgBouncer | 连接池 + 负载均衡 | 中 | - | +| Citus | 分布式集群 | 高 | 中 | + +### 6.2 流复制配置 + +#### 6.2.1 主库配置 + +```bash +# postgresql.conf +wal_level = replica +max_wal_senders = 10 +max_replication_slots = 10 +wal_keep_size = 1GB + +# 可选:同步复制 +synchronous_commit = on +synchronous_standby_names = 'standby1' +``` + +#### 6.2.2 从库配置 + +```bash +# postgresql.conf +primary_conninfo = 'host=192.168.1.100 port=5432 user=replica password=replica_pass' + +# 可选:只读模式 +hot_standby = on +max_standby_streaming_delay = 30s +``` + +#### 6.2.3 创建复制用户 + +```sql +-- 主库执行 +CREATE USER replica REPLICATION LOGIN PASSWORD 'replica_pass'; + +-- 配置 pg_hba.conf +host replication replica 192.168.1.0/24 scram-sha-256 +``` + +#### 6.2.4 启动从库 + +```bash +# 从主库基础备份 +pg_basebackup -U postgres -h 192.168.1.100 -D /var/lib/pgsql/15/data -Xs -P + +# 启动从库 +pg_ctl -D /var/lib/pgsql/15/data -l /var/lib/pgsql/15/data/logfile start +``` + +### 6.3 逻辑复制配置 + +#### 6.3.1 发布和订阅 + +```sql +-- 在发布库创建发布 +CREATE PUBLICATION mypub FOR TABLE users, orders; + +-- 在订阅库创建订阅 +CREATE SUBSCRIPTION mysub + CONNECTION 'host=192.168.1.100 port=5432 dbname=mydb user=postgres' + PUBLICATION mypub; +``` + +#### 6.3.2 复制槽 + +```sql +-- 创建复制槽(逻辑复制必须) +SELECT * FROM pg_create_logical_replication_slot('slot_name', 'pgoutput'); + +-- 查看复制槽 +SELECT * FROM pg_replication_slots; +``` + +### 6.4 Patroni 高可用 + +#### 6.4.1 Patroni 架构 + +``` +┌─────────────────────────────────────────────────────┐ +│ Patroni 高可用架构 │ +├─────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────┐ ┌─────────────┐ │ +│ │ etcd 1 │──────│ etcd 2 │ │ +│ └─────────────┘ └─────────────┘ │ +│ │ │ │ +│ └──────────┬─────────┘ │ +│ ▼ │ +│ ┌─────────────────┐ │ +│ │ Patroni Leader │ │ +│ │ 192.168.1.100 │ │ +│ └────────┬────────┘ │ +│ │ │ +│ ┌────────┴────────┐ │ +│ ▼ ▼ │ +│ ┌──────────┐ ┌──────────┐ │ +│ │ Standby 1│ │ Standby 2│ │ +│ │192.168.1│ │192.168.1│ │ +│ └──────────┘ └──────────┘ │ +│ │ +└─────────────────────────────────────────────────────┘ +``` + +#### 6.4.2 Patroni 配置 + +```yaml +# patroni.yml +scope: postgres-cluster +name: postgres-1 + +etcd: + hosts: 192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379 + +postgresql: + data_dir: /var/lib/pgsql/15/data + pgpass: /tmp/pgpass + parameters: + wal_level: replica + max_wal_senders: 10 + max_replication_slots: 10 + hot_standby: on + +bootstrap: + dcs: postgresql + method: basebackup + basebackup: + host: 192.168.1.100 + user: postgres + +restapi: + listen: 192.168.1.100:8008 + connect_address: 192.168.1.100:8008 +``` + +#### 6.4.3 启动 Patroni + +```bash +# 安装 Patroni +pip install patroni[etcd] etcd + +# 启动 Patroni +patroni patroni.yml +``` + +### 6.5 PgBouncer 连接池 + +```bash +# 安装 PgBouncer +yum install pgbouncer -y + +# 配置 pgbouncer.ini +[databases] +mydb = host=192.168.1.100 port=5432 dbname=mydb + +[pgbouncer] +listen_addr = * +listen_port = 6432 +auth_type = md5 +auth_file = /etc/pgbouncer/userlist.txt +pool_mode = transaction +max_client_conn = 1000 +default_pool_size = 20 + +# 配置 userlist.txt +"postgres" "md5d7f7a8..." + +# 启动 PgBouncer +systemctl start pgbouncer +systemctl enable pgbouncer +``` + +### 6.6 读写分离 + +```bash +# 应用程序配置 + +# 主库(写) +jdbc:postgresql://192.168.1.100:5432/mydb + +# 从库(读) +jdbc:postgresql://192.168.1.101:5432/mydb +jdbc:postgresql://192.168.1.102:5432/mydb + +# 伪代码:读写分离 +def execute_query(sql): + if sql.strip().upper().startswith('SELECT'): + return execute_on_slave(sql) + else: + return execute_on_master(sql) +``` + +### 6.7 故障转移 + +```sql +-- 手动故障转移(从库执行) +SELECT pg_promote(); + +-- 查看复制状态 +SELECT * FROM pg_stat_replication; + +-- 查看复制延迟 +SELECT now() - pg_last_xact_replay_timestamp() AS replication_lag; +``` + +### 6.8 监控指标 + +```sql +-- 查看连接数 +SELECT count(*) FROM pg_stat_activity; + +-- 查看慢查询 +SELECT query, state, wait_event, query_start +FROM pg_stat_activity +WHERE state != 'idle' +ORDER BY query_start DESC; + +-- 查看复制延迟 +SELECT client_addr, state, lag +FROM pg_stat_replication; + +-- 查看锁等待 +SELECT * FROM pg_locks WHERE NOT granted; +``` + +--- + +## 附录 + +### 常用命令速查 + +| 命令 | 说明 | +|------|------| +| `psql -U postgres` | 连接数据库 | +| `\l` | 列出数据库 | +| `\d` | 列出表 | +| `\du` | 列出用户 | +| `\x` | 展开显示 | +| `CREATE DATABASE db` | 创建数据库 | +| `DROP DATABASE db` | 删除数据库 | +| `CREATE USER user` | 创建用户 | +| `GRANT ALL ON db` | 授权 | + +### 配置文件参数速查 + +| 参数 | 说明 | +|------|------| +| `listen_addresses` | 监听地址 | +| `port` | 端口 | +| `max_connections` | 最大连接数 | +| `shared_buffers` | 共享缓存 | +| `work_mem` | 工作内存 | +| `wal_level` | WAL 级别 | +| `max_wal_senders` | 最大 WAL 发送数 | + +### 端口说明 + +| 端口 | 说明 | +|------|------| +| 5432 | PostgreSQL 主服务端口 | +| 5433 | PostgreSQL 主服务(多实例) | +| 6432 | PgBouncer 连接池端口 | +| 8008 | Patroni REST API 端口 | + +--- + +*文档创建时间:2024年* diff --git a/运维/数据库/PostgreSQL/搭建主从PostgreSQL.md b/运维/数据库/PostgreSQL/搭建主从PostgreSQL.md deleted file mode 100644 index e69de29..0000000 diff --git a/运维/数据库/Redis/Redis.md b/运维/数据库/Redis/Redis.md index 065513e..6f034b2 100644 --- a/运维/数据库/Redis/Redis.md +++ b/运维/数据库/Redis/Redis.md @@ -1,49 +1,907 @@ -# 简介 +# Redis 实战指南 -Redis是一个开源的key-value存储系统,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。为了保证效率,数据都是缓存在内存中。Redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件。并且在此基础上实现了master-slave(主从)同步。通过破坏一定的业务逻辑来换取性能。 +## 目录 -Redis默认16个数据库,默认为0库,所有库同样的密码。Redis 使用的单线程+多路IO复制技术。 +1. [Redis 介绍](#1-redis-介绍) +2. [Redis 部署](#2-redis-部署) +3. [Redis 使用](#3-redis-使用) +4. [Redis 数据类型](#4-redis-数据类型) +5. [Redis 主从复制](#5-redis-主从复制) +6. [Redis Sentinel](#6-redis-sentinel) +7. [Redis Cluster](#7-redis-cluster) -# NoSQL数据库概述 +--- -NoSQL(NoSQL = Not Only SQL ),指非关系型的数据库。NoSQL不依赖业务逻辑方式存储,而以简单的key-value模式存储。因此大大的增加了数据库的扩展能力。 +## 1. Redis 介绍 -- 不遵循SQL标准 -- 不支持ACID。 -- 远超于SQL的性能。 +### 1.1 什么是 Redis -## NoSQL适用场景 +Redis(Remote Dictionary Server)是一个开源的、基于内存的数据结构存储系统,可用作**数据库、缓存和消息队列**。 -- 对数据高并发的读写 -- 海量数据的读写 -- 对数据高可扩展性的 +### 1.2 Redis 特点 -## NoSQL不适用场景 +| 特性 | 说明 | +|------|------| +| 内存存储 | 数据存储在内存中,读写速度极快 | +| 持久化 | 支持 RDB 和 AOF 两种持久化方式 | +| 数据结构丰富 | 支持 String、Hash、List、Set、ZSet 等 | +| 主从复制 | 支持 master-slave 复制架构 | +| 集群 | 支持 Redis Cluster 分布式集群 | +| 发布/订阅 | 支持消息发布和订阅 | +| 事务 | 支持简单的事务操作 | +| Lua 脚本 | 支持 Lua 脚本执行 | +| 高可用 | 支持 Sentinel 哨兵机制 | -- 需要事务支持 -- 基于sql的结构化查询存储,处理复杂的关系。 +### 1.3 Redis 应用场景 -## NoSQL产品介绍 +| 场景 | 说明 | +|------|------| +| 缓存 | 热点数据缓存,减轻数据库压力 | +| 会话存储 | Session、Token 存储 | +| 实时排行 | ZSet 实现排行榜 | +| 消息队列 | List 实现消息队列 | +| 分布式锁 | SETNX 实现分布式锁 | +| 计数器 | 原子自增操作 | +| 限流 | 滑动窗口算法限流 | -**Memcache:** +### 1.4 Redis 与其他数据库对比 -- 很早出现的NoSQL数据库 -- 数据都在内存中,一般不持久化 -- 支持简单的key-value模式,支持类型单一 -- 一般是作为缓存数据库辅助持久化的数据库 +| 特性 | Redis | MySQL | MongoDB | +|------|-------|-------|---------| +| 数据模型 | Key-Value | 关系型 | 文档型 | +| 存储介质 | 内存+磁盘 | 磁盘 | 磁盘 | +| 性能 | 极高 | 中等 | 中等 | +| 扩展性 | 集群 | 主从/分片 | 分片 | +| 事务 | 弱事务 | 强事务 | 弱事务 | -**Redis:** +--- -- 几乎覆盖了Memcached的绝大部分功能 -- 数据都在内存中,支持持久化,主要用作备份恢复 -- 除了支持简单的key-value模式,还支持多种数据结构的存储,比如 list、set、hash、zset等。 -- 一般是作为缓存数据库辅助持久化的数据库 +## 2. Redis 部署 -**MongoDB:** +### 2.1 环境要求 -- 高性能、开源、模式自由(schema free)的**文档型数据库** -- 数据都在内存中, 如果内存不足,把不常用的数据保存到硬盘 -- 虽然是key-value模式,但是对value(尤其是**json**)提供了丰富的查询功能 -- 支持二进制数据及大型对象 -- 可以根据数据的特点**替代RDBMS**(关系型数据库) ,成为独立的数据库。或者配合RDBMS,存储特定的数据 +- 操作系统:Linux(CentOS/Ubuntu/Debian) +- 编译器:GCC 4.8+ +- 内存:至少 2GB(生产环境建议 4GB+) +### 2.2 编译安装 + +```bash +# 下载源码 +wget https://download.redis.io/redis-7.2.4.tar.gz +tar -zxf redis-7.2.4.tar.gz +cd redis-7.2.4 + +# 编译 +make -j4 + +# 安装 +make install PREFIX=/usr/local/redis + +# 创建配置目录 +mkdir -p /usr/local/redis/{etc,logs,data,run} +``` + +### 2.3 RPM 包安装(CentOS/RHEL) + +```bash +# 安装 EPEL 源 +yum install epel-release -y + +# 安装 Redis +yum install redis -y + +# 启动 Redis +systemctl start redis +systemctl enable redis +``` + +### 2.4 Docker 安装 + +```bash +# 拉取镜像 +docker pull redis:7.2 + +# 运行容器 +docker run -d \ + --name redis \ + -p 6379:6379 \ + -v /data/redis/data:/data \ + redis:7.2 \ + redis-server --appendonly yes + +# 使用配置文件启动 +docker run -d \ + --name redis \ + -p 6379:6379 \ + -v /data/redis/redis.conf:/usr/local/etc/redis/redis.conf \ + -v /data/redis/data:/data \ + redis:7.2 \ + redis-server /usr/local/etc/redis/redis.conf +``` + +### 2.5 基础配置 + +```bash +# /usr/local/redis/etc/redis.conf + +# 绑定地址 +bind 0.0.0.0 + +# 端口 +port 6379 + +# 守护进程运行 +daemonize yes + +# PID 文件 +pidfile /usr/local/redis/run/redis.pid + +# 日志文件 +logfile /usr/local/redis/logs/redis.log + +# 数据目录 +dir /usr/local/redis/data + +# 持久化 - RDB +save 900 1 +save 300 10 +save 60 10000 + +# 持久化 - AOF +appendonly yes +appendfsync everysec + +# 内存最大限制 +maxmemory 2gb + +# 内存淘汰策略 +maxmemory-policy allkeys-lru + +# 连接密码 +requirepass your_password + +# 最大客户端连接数 +maxclients 10000 +``` + +### 2.6 启动和停止 + +```bash +# 启动 +/usr/local/redis/bin/redis-server /usr/local/redis/etc/redis.conf + +# 停止 +/usr/local/redis/bin/redis-cli shutdown + +# 停止(强制) +/usr/local/redis/bin/redis-cli shutdown nosave + +# 连接客户端 +/usr/local/redis/bin/redis-cli -a your_password + +# 测试连接 +redis-cli ping +# 返回:PONG +``` + +--- + +## 3. Redis 使用 + +### 3.1 Redis 客户端 + +```bash +# 命令行客户端 +redis-cli + +# 带密码连接 +redis-cli -a password + +# 连接远程主机 +redis-cli -h 192.168.1.100 -p 6379 + +# 选择数据库(0-15) +redis-cli -n 1 + +# 交互模式 +redis-cli +> SELECT 0 +> KEYS * +``` + +### 3.2 Key 操作 + +```bash +# 查看所有 key +KEYS pattern +# 示例:KEYS user:* + +# 查看 key 类型 +TYPE key + +# 查看 key 存在性 +EXISTS key + +# 设置过期时间(秒) +EXPIRE key 3600 + +# 查看剩余过期时间 +TTL key + +# 移除过期时间 +PERSIST key + +# 删除 key +DEL key + +# 重命名 +RENAME key newkey + +# 序列化 +DUMP key + +# 反序列化 +RESTORE key 0 "serialized-value" +``` + +### 3.3 数据库操作 + +```bash +# 切换数据库 +SELECT db + +# 清空当前数据库 +FLUSHDB + +# 清空所有数据库 +FLUSHALL + +# 查看数据库 key 数量 +DBSIZE + +# 查看最后访问时间 +LASTSAVE +``` + +### 3.4 慢查询日志 + +```bash +# 查看慢查询配置 +SLOWLOG GET + +# 设置慢查询阈值(毫秒) +CONFIG SET slowlog-log-slower-than 1000 + +# 保留慢查询条数 +CONFIG SET slowlog-max-len 128 + +# 查看慢查询 +SLOWLOG GET 10 +``` + +### 3.5 服务器信息 + +```bash +# 服务器信息 +INFO + +# 内存信息 +INFO memory + +# CPU 信息 +INFO cpu + +# 复制信息 +INFO replication + +# 客户端信息 +CLIENT LIST +CLIENT KILL ip:port + +# 实时统计 +MONITOR +``` + +--- + +## 4. Redis 数据类型 + +### 4.1 String(字符串) + +最基本的数据类型,最大 512MB。 + +```bash +# 设置值 +SET key value +SET key value EX 3600 # 设置过期时间(秒) +SET key value PX 3600000 # 设置过期时间(毫秒) +SETNX key value # key 不存在时设置 +SETXX key value # key 存在时设置 +MSET key1 value1 key2 value2 # 批量设置 + +# 获取值 +GET key +MGET key1 key2 # 批量获取 + +# 数字操作 +INCR key # 加 1 +DECR key # 减 1 +INCRBY key 10 # 加 10 +DECRBY key 10 # 减 10 +INCRBYFLOAT key 1.5 # 加浮点数 + +# 字符串操作 +APPEND key "suffix" # 追加 +STRLEN key # 长度 +GETRANGE key 0 3 # 截取(0-3) +SETRANGE key 5 "xx" # 替换 + +# 位操作 +SETBIT key 7 1 # 设置位 +GETBIT key 7 # 获取位 +BITCOUNT key # 统计 1 的个数 +BITOP AND destkey key1 key2 # 位运算 +``` + +### 4.2 Hash(哈希) + +键值对集合,适合存储对象。 + +```bash +# 设置 +HSET key field value +HSET key field1 value1 field2 value2 +HSETNX key field value + +# 获取 +HGET key field +HMGET key field1 field2 +HGETALL key +HKEYS key # 所有字段 +HVALUES key # 所有值 +HLEN key # 字段数量 + +# 判断 +HEXISTS key field + +# 删除 +HDEL key field1 field2 + +# 数字操作 +HINCRBY key field 10 +HINCRBYFLOAT key field 1.5 +``` + +### 4.3 List(列表) + +有序字符串列表,支持两端操作。 + +```bash +# 插入 +LPUSH key value1 value2 # 头部插入 +RPUSH key value1 value2 # 尾部插入 +LINSERT key BEFORE/AFTER pivot value # 插入 + +# 获取 +LRANGE key 0 -1 # 获取所有 +LINDEX key 0 # 按索引获取 +LLEN key # 长度 + +# 修改 +LSET key index value # 设置指定索引 +LTRIM key 0 9 # 保留指定范围 + +# 删除 +LPOP key # 头部弹出 +RPOP key # 尾部弹出 +LREM key count value # 删除指定元素 +``` + +### 4.4 Set(无序集合) + +无序且不重复的字符串集合。 + +```bash +# 添加 +SADD key member1 member2 + +# 获取 +SMEMBERS key # 所有成员 +SCARD key # 成员数量 +SISMEMBER key member # 是否存在 + +# 删除 +SREM key member1 member2 +SPOP key # 随机弹出 +SRANDMEMBER key count # 随机获取 + +# 集合运算 +SUNION key1 key2 # 并集 +SINTER key1 key2 # 交集 +SDIFF key1 key2 # 差集 +SUNIONSTORE dest key1 key2 # 并集存储 +SINTERSTORE dest key1 key2 # 交集存储 +SDIFFSTORE dest key1 key2 # 差集存储 +``` + +### 4.5 ZSet(有序集合) + +有序且不重复的字符串集合,每个成员关联一个分数。 + +```bash +# 添加 +ZADD key score1 member1 score2 member2 + +# 获取 +ZRANGE key 0 -1 # 按索引获取 +ZREVRANGE key 0 -1 # 倒序获取 +ZRANGEBYSCORE key 0 100 # 按分数范围获取 +ZSCORE key member # 获取分数 +ZRANK key member # 排名(正序) +ZREVRANK key member # 排名(倒序) + +# 数量 +ZCARD key # 成员数量 +ZCOUNT key min max # 分数范围内数量 + +# 删除 +ZREM key member1 member2 +ZREMRANGEBYSCORE key min max +ZREMRANGEBYRANK key start stop +``` + +### 4.6 HyperLogLog + +用于基数统计,内存占用极低。 + +```bash +# 添加 +PFADD key element1 element2 + +# 统计 +PFCOUNT key1 key2 + +# 合并 +PFMERGE destkey key1 key2 +``` + +### 4.7 Geospatial + +地理坐标存储和查询。 + +```bash +# 添加坐标 +GEOADD key longitude latitude member + +# 获取坐标 +GEOPOS key member + +# 计算距离 +GEODIST key member1 member2 [km/m/ft/mi] + +# 附近查询 +GEORADIUS key longitude radius km +GEORADIUSBYMEMBER key member radius km +``` + +### 4.8 Stream + +消息队列功能。 + +```bash +# 添加消息 +XADD key * field1 value1 field2 value2 + +# 读取消息 +XRANGE key - + COUNT 10 +XREAD COUNT 10 STREAMS key 0 + +# 消费者组 +XGROUP CREATE key group 0 +XREADGROUP GROUP group consumer COUNT 10 STREAMS key > + +# 消息确认 +XACK key group message-id +``` + +--- + +## 5. Redis 主从复制 + +### 5.1 复制原理 + +Redis 主从复制采用**异步复制**模式,包含全量同步和增量同步。 + +``` +全量同步流程: +1. 从库发送 PSYNC 命令 +2. 主库执行 BGSAVE 生成 RDB 文件 +3. 主库发送 RDB 文件给从库 +4. 从库加载 RDB 文件 +5. 主库发送缓冲区命令给从库 + +增量同步流程: +1. 主库将写命令发送给从库 +2. 从库执行写命令 +``` + +### 5.2 配置主从复制 + +```bash +# 从库配置 - redis.conf +replicaof 192.168.1.100 6379 + +# 或者运行时执行 +REPLICAOF 192.168.1.100 6379 + +# 取消复制 +REPLICAOF NO ONE + +# 设置主库密码 +masterauth your_password + +# 只读模式(从库默认) +replica-read-only yes +``` + +### 5.3 一主多从配置 + +```bash +# 主库配置 +bind 0.0.0.0 +port 6379 +requirepass master_password +appendonly yes + +# 从库 1 配置 +replicaof 192.168.1.100 6379 +masterauth master_password + +# 从库 2 配置 +replicaof 192.168.1.100 6379 +masterauth master_password +``` + +### 5.4 拓扑结构 + +``` +├── 主库(Master) +│ ├── 从库 1(Slave) +│ ├── 从库 2(Slave) +│ └── 从库 3(Slave) +``` + +### 5.5 主从复制管理 + +```bash +# 查看复制状态 +INFO replication + +# 查看从库列表 +CLIENT LIST + +# 断开复制 +REPLICAOF NO ONE + +# 手动故障转移(从库执行) +CLUSTER FAILOVER +``` + +### 5.6 复制安全 + +```bash +# 主库设置密码 +requirepass your_password + +# 从库配置主库密码 +masterauth your_password + +# 加密复制流量 +repl-diskless-sync yes +repl-diskless-sync-delay 5 +``` + +--- + +## 6. Redis Sentinel + +### 6.1 Sentinel 概述 + +Redis Sentinel 是Redis 的高可用解决方案,负责监控主从库、自动故障转移、通知客户端。 + +### 6.2 Sentinel 架构 + +``` + ┌─────────────┐ + │ Client │ + └──────┬──────┘ + │ + ┌──────▼──────┐ + │ Sentinel │ + │ (Monitor) │ + └──────┬──────┘ + │ + ┌─────────────────┼─────────────────┐ + │ │ │ + ┌────▼────┐ ┌────▼────┐ ┌────▼────┐ + │ Master │ │ Slave 1 │ │ Slave 2 │ + └─────────┘ └─────────┘ └─────────┘ +``` + +### 6.3 Sentinel 配置 + +```bash +# sentinel.conf + +# 端口 +port 26379 + +# 守护进程 +daemonize yes + +# 日志 +logfile /var/log/redis/sentinel.log + +# 工作目录 +dir /tmp + +# 监控主库 +# sentinel monitor +sentinel monitor mymaster 192.168.1.100 6379 2 + +# 主库密码 +sentinel auth-pass mymaster your_password + +# 故障转移超时时间(毫秒) +sentinel down-after-milliseconds mymaster 30000 + +# 并行同步数量 +sentinel parallel-syncs mymaster 1 + +# 故障转移超时时间 +sentinel failover-timeout mymaster 180000 +``` + +### 6.4 启动 Sentinel + +```bash +# 方式 1:直接启动 +redis-sentinel /etc/redis/sentinel.conf + +# 方式 2:redis-server 启动 +redis-server /etc/redis/sentinel.conf --sentinel +``` + +### 6.5 Sentinel 管理命令 + +```bash +# 连接 Sentinel +redis-cli -p 26379 + +# 查看主库信息 +SENTINEL get-master-addr-by-name mymaster + +# 查看所有从库 +SENTINEL slaves mymaster + +# 查看 Sentinel 信息 +SENTINEL sentinels mymaster + +# 手动故障转移 +SENTINEL failover mymaster + +# 强制故障转移(主库宕机) +SENTINEL failover force mymaster +``` + +### 6.6 Java 客户端连接 + +```bash +# Jedis +JedisSentinelPool pool = new JedisSentinelPool( + "mymaster", + Set.of("192.168.1.101:26379", "192.168.1.102:26379"), + poolConfig, + timeout, + password +); + +# Lettuce +RedisSentinelConfiguration config = new RedisSentinelConfiguration() + .master("mymaster") + .sentinel("192.168.1.101", 26379) + .sentinel("192.168.1.102", 26379); +``` + +--- + +## 7. Redis Cluster + +### 7.1 Cluster 概述 + +Redis Cluster 是 Redis 的分布式解决方案,自动将数据分片到多个节点,支持高可用和水平扩展。 + +### 7.2 集群架构 + +``` +┌─────────────────────────────────────────────────┐ +│ Redis Cluster │ +├──────────┬──────────┬──────────┬──────────┬────┤ +│ Node 1 │ Node 2 │ Node 3 │ Node 4 │ .. │ +│ (Master) │ (Master) │ (Master) │ (Master) │ │ +│ Slot 0 │ Slot 5500│ Slot 1100│ Slot 5501│ │ +│ 5461 │ 10922 │ 5462 │ 10923 │ │ +├──────────┼──────────┼──────────┼──────────┼────┤ +│ Slave │ Slave │ Slave │ Slave │ │ +└──────────┴──────────┴──────────┴──────────┴────┘ +``` + +### 7.3 槽(Slot)分配 + +- Redis Cluster 有 **16384 个槽** +- 每个节点负责一部分槽(0-16383) +- 数据根据 key 的 CRC16 哈希值分配到对应槽 + +``` +槽号计算:CRC16(key) % 16384 +``` + +### 7.4 集群配置 + +```bash +# 节点配置 - redis.conf + +# 集群模式 +cluster-enabled yes + +# 集群配置文件 +cluster-config-file nodes-6379.conf + +# 节点超时时间 +cluster-node-timeout 15000 + +# 集群节点端口(客户端连接端口 + 10000) +cluster-announce-port 6379 +cluster-announce-bus-port 16379 + +# 集群节点 IP +cluster-announce-ip 192.168.1.100 +``` + +### 7.5 创建集群 + +```bash +# 启动所有节点 +redis-server /usr/local/redis/etc/redis-1.conf +redis-server /usr/local/redis/etc/redis-2.conf +redis-server /usr/local/redis/etc/redis-3.conf +redis-server /usr/local/redis/etc/redis-4.conf +redis-server /usr/local/redis/etc/redis-5.conf +redis-server /usr/local/redis/etc/redis-6.conf + +# 创建集群(6 节点,3 主 3 从) +redis-cli --cluster create \ + 192.168.1.101:6379 \ + 192.168.1.102:6379 \ + 192.168.1.103:6379 \ + 192.168.1.104:6379 \ + 192.168.1.105:6379 \ + 192.168.1.106:6379 \ + --cluster-replicas 1 + +# 参数说明:--cluster-replicas 1 表示每个主库有 1 个从库 +``` + +### 7.6 集群管理 + +```bash +# 连接集群 +redis-cli -c + +# 查看集群信息 +CLUSTER INFO + +# 查看节点信息 +CLUSTER NODES + +# 查看槽分配 +CLUSTER SLOTS + +# 手动分配槽 +CLUSTER ADDSLOTS 0 5460 + +# 槽迁移 +CLUSTER SETSLOT 16383 MIGRATING node_id +CLUSTER SETSLOT 16384 IMPORTING node_id + +# 重新分片 +redis-cli --cluster reshard 192.168.1.101:6379 + +# 添加节点 +redis-cli --cluster add-node new_host:new_port existing_host:existing_port + +# 删除节点 +redis-cli --cluster del-node host:port node_id + +# 故障转移(从库执行) +CLUSTER FAILOVER +``` + +### 7.7 集群高可用 + +```bash +# 检查集群状态 +redis-cli --cluster check 192.168.1.101:6379 + +# 手动故障转移 +redis-cli -h 192.168.1.104 -p 6379 CLUSTER FAILOVER + +# 修复集群 +redis-cli --cluster fix 192.168.1.101:6379 +``` + +### 7.8 Java 客户端连接 + +```bash +# Jedis +Set nodes = new HashSet<>(); +nodes.add(new HostAndPort("192.168.1.101", 6379)); +nodes.add(new HostAndPort("192.168.1.102", 6379)); +nodes.add(new HostAndPort("192.168.1.103", 6379)); + +JedisCluster cluster = new JedisCluster( + nodes, + 3000, + 10, + poolConfig +); + +# Spring Boot +spring.data.redis.cluster.nodes=192.168.1.101:6379,192.168.1.102:6379,192.168.1.103:6379 +``` + +--- + +## 附录 + +### 常用命令速查表 + +| 命令 | 说明 | +|------|------| +| `redis-cli ping` | 测试连接 | +| `redis-cli shutdown` | 关闭 Redis | +| `KEYS *` | 查看所有 key | +| `FLUSHDB` | 清空当前数据库 | +| `BGSAVE` | 后台保存 RDB | +| `LASTSAVE` | 上次保存时间 | + +### 配置文件参数速查 + +| 参数 | 说明 | +|------|------| +| `bind` | 绑定地址 | +| `port` | 端口 | +| `daemonize` | 守护进程 | +| `requirepass` | 密码 | +| `maxmemory` | 最大内存 | +| `maxmemory-policy` | 内存淘汰策略 | +| `appendonly` | AOF 持久化 | +| `save` | RDB 持久化策略 | + +### 内存淘汰策略 + +| 策略 | 说明 | +|------|------| +| `noeviction` | 不淘汰,返回错误 | +| `volatile-lru` | LRU 淘汰过期 key | +| `allkeys-lru` | LRU 淘汰所有 key | +| `volatile-random` | 随机淘汰过期 key | +| `allkeys-random` | 随机淘汰所有 key | +| `volatile-ttl` | 淘汰 TTL 最短的 key | +| `volatile-lfu` | LFU 淘汰过期 key | +| `allkeys-lfu` | LFU 淘汰所有 key | + +--- + +*文档创建时间:2024年* diff --git a/运维/数据库/Redis/Redis高并发.md b/运维/数据库/Redis/Redis高并发.md deleted file mode 100644 index a3d21af..0000000 --- a/运维/数据库/Redis/Redis高并发.md +++ /dev/null @@ -1,21 +0,0 @@ -# Redis高并发 - -虽然 Redis 是单线程的,但它通过多种方式来保证高并发性能: - -1. 异步非阻塞 I/O 模型:Redis 使用了一种非阻塞的 I/O 模型,即使用一个线程来处理多个连接。这个线程会监听多个客户端的连接,并在有数据可读时立即处理这些数据。这种方式可以大大提高 Redis 的并发性能,因为它可以同时处理多个客户端的请求。 -2. 内存数据库:Redis 将数据存储在内存中,而不是磁盘上,这使得 Redis 能够快速读写数据,从而提高了并发性能。 -3. 单线程避免了线程切换的开销:线程切换是一种非常昂贵的操作,因为它需要保存和恢复线程的上下文。由于 Redis 是单线程的,所以它避免了线程切换的开销,从而提高了并发性能。 -4. 多路复用技术:Redis 使用了多路复用技术来处理多个客户端的请求。这种技术可以让 Redis 在一个线程中同时处理多个客户端的请求,从而提高了并发性能。 -5. 基于事件驱动的编程模型:Redis 使用了基于事件驱动的编程模型,即在事件发生时触发相应的回调函数。这种模型可以让 Redis 在处理请求时更加高效,从而提高了并发性能。 - -虽然它是单线程的,但它的性能表现非常出色。 - -## 一、多路复用技术 - -多路复用技术是一种用于处理多个 I/O 事件的技术,它可以让一个线程同时处理多个 I/O 事件,从而提高系统的并发性能。在 Linux 系统中,多路复用技术主要有三种实现方式:select、poll 和 epoll。 - -1. select:select 是最早的多路复用技术之一,它可以同时监听多个文件描述符,当其中任何一个文件描述符上有事件发生时,select 就会返回。select 的缺点是它的效率比较低,因为它需要遍历所有的文件描述符,而且每次调用 select 都需要将文件描述符集合从用户态复制到内核态。 -2. poll:poll 是 select 的改进版,它也可以同时监听多个文件描述符,但它使用链表来存储文件描述符,避免了 select 的缺点。poll 的缺点是它需要遍历整个链表来查找有事件发生的文件描述符,因此效率也不是很高。 -3. epoll:epoll 是 Linux 内核中最新的多路复用技术,它可以同时监听多个文件描述符,并且只返回有事件发生的文件描述符。epoll 的优点是它使用了红黑树来存储文件描述符,可以快速查找有事件发生的文件描述符,而且它还支持边缘触发和水平触发两种模式,可以更加灵活地处理事件。 - -在 Redis 中,多路复用技术被广泛应用于网络通信和文件 I/O 等方面。Redis 使用多路复用技术来处理多个客户端的请求,从而提高了系统的并发性能。当一个客户端连接到 Redis 服务器时,Redis 会将这个客户端的文件描述符添加到 epoll 中,然后在 epoll 中监听这个文件描述符上的事件。当这个客户端有数据可读时,epoll 就会通知 Redis,Redis 就可以立即处理这个客户端的请求。这种方式可以让 Redis 在一个线程中同时处理多个客户端的请求,从而提高了系统的并发性能。 \ No newline at end of file diff --git a/运维/网络穿透/OpenVPN/OpenVPN.md b/运维/网络穿透/OpenVPN/OpenVPN.md new file mode 100644 index 0000000..4240a73 --- /dev/null +++ b/运维/网络穿透/OpenVPN/OpenVPN.md @@ -0,0 +1,575 @@ +# OpenVPN 实战指南 + +> 企业级开源 VPN 解决方案,实现安全远程访问。 + +--- + +## 1. OpenVPN 简介 + +### 1.1 什么是 VPN + +**VPN**(Virtual Private Network,虚拟专用网络): +- 在公共网络上建立的安全加密通道 +- 实现远程安全访问公司内网资源 +- 保证数据传输的机密性和完整性 + +### 1.2 OpenVPN 特点 + +| 特点 | 说明 | +|------|------| +| 开源免费 | GPL 协议,源码开放 | +| 跨平台 | Windows/Linux/macOS/Android/iOS | +| 安全性高 | 支持 AES、BF-CBC 等加密算法 | +| 简单易用 | 配置简洁,客户端友好 | +| 协议优势 | 基于 TLS/SSL | +| 多种认证 | 支持证书、用户名密码、双因子 | + +### 1.3 OpenVPN 与其他 VPN 对比 + +| VPN 方案 | 协议 | 安全性 | 复杂度 | 适用场景 | +|----------|------|--------|--------|----------| +| **OpenVPN** | SSL/TLS | 高 | 中 | 通用远程访问 | +| IPSec | IKEv2 | 高 | 高 | 企业级 | +| PPTP | PPP | 低 | 低 | 简单场景(已废弃) | +| L2TP/IPSec | L2TP | 高 | 中 | 兼容性好 | +| WireGuard | WireGuard | 高 | 低 | 现代方案 | + +### 1.4 原理架构 + +``` +┌──────────────────────────────────────────────┐ +│ Internet │ +│ (公网/不安全的网络) │ +└──────────────────┬───────────────────────────┘ + │ +┌──────────────────▼───────────────────────────┐ +│ OpenVPN Server │ +│ ┌─────────────┐ ┌─────────────────────┐ │ +│ │ TLS/SSL │ │ 虚拟网卡 tun/tap │ │ +│ │ 加密通道 │ │ 10.8.0.0/24 │ │ +│ └─────────────┘ └─────────────────────┘ │ +└──────────────────┬───────────────────────────┘ + │ +┌──────────────────▼───────────────────────────┐ +│ 内网(安全网络) │ +│ 192.168.1.0/24 │ +│ 文件服务器/数据库/内部系统 │ +└──────────────────────────────────────────┘ +``` + +### 1.5 工作流程 + +``` +客户端 服务端 + │ │ + │ 发起连接请求 │ + │ ─────────────────────>│ + │ │ + │ 返回证书 │ + │ <─────────────────────│ + │ │ + │ 验证证书 + 配置IP │ + │ ─────────────────────>│ + │ │ + │ 建立 TLS 通道 │ + │ <─────────────────────│ + │ │ + │ 启用虚拟网卡 │ + │ <─────────────────────│ + │ │ + │ 数据加密传输 │ + │◄─────────────────────►│ +``` + +--- + +## 2. OpenVPN 部署 + +### 2.1 环境准备 + +```bash +# 系统要求 +CentOS 7/8 / Ubuntu 20.04+ +内存:512MB+ +CPU:1核+ + +# 关闭 SELinux(如需要) +setenforce 0 +sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config + +# 关闭防火墙(或放行) +systemctl stop firewalld +systemctl disable firewalld + +# 放行端口 +firewall-cmd --permanent --add-port=1194/udp +firewall-cmd --reload +``` + +### 2.2 安装 OpenVPN + +```bash +# CentOS/RHEL +yum install -y openvpn easy-rsa + +# Ubuntu/Debian +apt update +apt install -y openvpn easy-rsa + +# 检查版本 +openvpn --version +``` + +### 2.3 配置证书环境 + +```bash +# 复制证书工具 +cp -r /usr/share/easy-rsa /etc/openvpn/easy-rsa +cd /etc/openvpn/easy-rsa + +# 初始化 PKI +./easyrsa init-pki + +# 创建 CA +./easyrsa build-ca nopass + +# 创建服务端证书 +./easyrsa build-server-full server nopass + +# 创建客户端证书 +./easyrsa build-client client1 nopass + +# 生成 Diffie-Hellman 参数 +./easyrsa gen-dh + +# 生成 TLS Auth 密钥(防止 DoS 攻击) +openvpn --genkey secret /etc/openvpn/easy-rsa/ta.key +``` + +> 证书文件说明: +> - `pki/ca.crt`:CA 证书(客户端和服务端都需要) +> - `pki/issued/server.crt`:服务端证书 +> - `pki/private/server.key`:服务端私钥 +> - `pki/issued/client1.crt`:客户端证书 +> - `pki/private/client1.key`:客户端私钥 +> - `pki/dh.pem`:DH 参数 +> - `ta.key`:TLS Auth 密钥 + +### 2.4 服务端配置 + +```bash +# 创建配置文件 +cat > /etc/openvpn/server.conf << 'EOF' +# 端口和协议 +port 1194 +proto udp +dev tun + +# 证书和密钥 +ca /etc/openvpn/easy-rsa/pki/ca.crt +cert /etc/openvpn/easy-rsa/pki/issued/server.crt +key /etc/openvpn/easy-rsa/pki/private/server.key +dh /etc/openvpn/easy-rsa/pki/dh.pem +tls-auth /etc/openvpn/easy-rsa/ta.key 0 + +# 加密算法 +cipher AES-256-GCM +auth SHA256 + +# 网络配置 +server 10.8.0.0 255.255.255.0 +ifconfig-pool-persist /etc/openvpn/ipp.txt +push "redirect-gateway def1 bypass-dhcp" +push "dhcp-option DNS 8.8.8.8" +push "dhcp-option DNS 8.8.4.4" + +# 客户端可以访问内网 +client-config-dir /etc/openvpn/ccd +route 192.168.1.0 255.255.255.0 + +# 权限和日志 +keepalive 10 120 +persist-key +persist-tun +status /etc/openvpn/openvpn-status.log +log /etc/openvpn/openvpn.log +verb 3 + +# 压缩(可选,兼容老客户端) +compress lz4-v2 +push "compress lz4-v2" +EOF +``` + +### 2.5 客户端配置(生成配置) + +```bash +# 创建客户端配置目录 +mkdir -p /etc/openvpn/ccd + +# 创建客户端配置 +cat > /etc/openvpn/ccd/client1 << 'EOF' +# 为客户端分配固定 IP +ifconfig-push 10.8.0.10 10.8.0.9 +EOF +``` + +### 2.6 启动服务 + +```bash +# 启动服务 +systemctl start openvpn@server +systemctl enable openvpn@server + +# 检查状态 +systemctl status openvpn@server +ip addr show tun0 +``` + +### 2.7 路由和转发配置 + +```bash +# 开启 IP 转发 +echo 1 > /proc/sys/net/ipv4/ip_forward +# 永久生效 +echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf +sysctl -p + +# 配置 NAT(如果需要访问内网) +iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE +# 永久保存 +iptables-save > /etc/sysconfig/iptables +``` + +### 2.8 客户端配置(Linux) + +```bash +# 安装客户端 +apt install -y openvpn + +# 复制配置文件 +# 方法1:从服务端拉取 +scp root@server:/etc/openvpn/easy-rsa/pki/issued/client1.crt /etc/openvpn/client.crt +scp root@server:/etc/openvpn/easy-rsa/pki/private/client1.key /etc/openvpn/client.key +scp root@server:/etc/openvpn/easy-rsa/pki/ca.crt /etc/openvpn/ca.crt + +# 创建客户端配置 +cat > /etc/openvpn/client.conf << 'EOF' +client +dev tun +proto udp +remote your-server-ip 1194 +resolv-retry infinite +nobind +persist-key +persist-tun + +remote-cert-tls server +cipher AES-256-GCM +auth SHA256 + +# 证书 +ca /etc/openvpn/ca.crt +cert /etc/openvpn/client.crt +key /etc/openvpn/client.key + +# TLS Auth +tls-auth /etc/openvpn/ta.key 1 + +verb 3 +EOF + +# 复制 TLS Auth +scp root@server:/etc/openvpn/easy-rsa/ta.key /etc/openvpn/ta.key + +# 启动连接 +openvpn --config /etc/openvpn/client.conf + +# 或使用 systemd +systemctl start openvpn@client +``` + +### 2.9 客户端配置(Windows) + +1. 从服务端下载证书文件: + - `ca.crt` + - `client1.crt` + - `client1.key` + - `ta.key`(可选) + +2. 下载 OpenVPN 客户端: + - https://openvpn.net/community-downloads/ + +3. 创建客户端配置 `client.ovpn`: +```ovpn +client +dev tun +proto udp +remote your-server-ip 1194 +resolv-retry infinite +nobind +remote-cert-tls server +cipher AES-256-GCM +auth SHA256 + +ca ca.crt +cert client1.crt +key client1.key +tls-auth ta.key 1 + +verb 3 +``` + +4. 导入配置: + - 将证书和配置放入 `C:\Program Files\OpenVPN\config\` + - 右键托盘图标 → 连接 + +### 2.10 客户端配置(macOS) + +```bash +# 使用 Homebrew 安装 +brew install openvpn +# 或下载 Tunnelblick:https://tunnelblick.net/ + +# 导入配置文件(.ovpn) +open -a Tunnelblick client.ovpn +``` + +### 2.11 客户端配置(iOS/Android) + +1. **iOS**:下载 OpenVPN Connect 应用,导入 `.ovpn` 配置 +2. **Android**:下载 OpenVPN for Android 或 OpenVPN Connect + +--- + +## 3. OpenVPN 管理 + +### 3.1 日常管理命令 + +```bash +# 查看连接状态 +systemctl status openvpn@server + +# 重启服务 +systemctl restart openvpn@server + +# 查看日志 +tail -f /etc/openvpn/openvpn.log + +# 查看连接的用户 +cat /etc/openvpn/openvpn-status.log +``` + +### 3.2 查看连接用户 + +```bash +# 方法1:查看状态文件 +cat /etc/openvpn/openvpn-status.log + +# 方法2:通过管理接口 +echo "status" | nc localhost 1194 + +# 方法3:检查虚拟网卡 +ip addr show tun0 +``` + +### 3.3 日志分析 + +```bash +# 实时查看日志 +tail -f /etc/openvpn/openvpn.log + +# 查看错误日志 +grep -i error /etc/openvpn/openvpn.log + +# 查看连接日志 +grep -i "client connect" /etc/openvpn/openvpn.log +``` + +### 3.4 添加新用户 + +```bash +cd /etc/openvpn/easy-rsa + +# 生成新客户端证书 +./easyrsa build-client newuser nopass + +# 导出证书 +# /etc/openvpn/easy-rsa/pki/issued/newuser.crt +# /etc/openvpn/easy-rsa/pki/private/newuser.key +# /etc/openvpn/easy-rsa/pki/ca.crt +``` + +### 3.5 撤销用户 + +```bash +cd /etc/openvpn/easy-rsa + +# 撤销证书 +./easyrsa revoke newuser + +# 生成新的 CRL +./easyrsa gen-crl + +# 重启服务 +systemctl restart openvpn@server +``` + +### 3.6 配置文件优化 + +```bash +# 调整日志级别 +verb 3 # 详细(生产环境建议 3) + +# 调整 MTU +tun-mtu 1500 + +# 调整 keepalive +keepalive 10 120 # 每 10 秒检测,120 秒超时 + +# 压缩设置 +compress lz4-v2 # 启用压缩 +``` + +### 3.7 性能优化 + +```bash +# 调整缓冲区大小 + sndbuf 393216 + rcvbuf 393216 + +# 多线程(如果 CPU 多核) +multihome + +# 连接数限制 +max-clients 100 +``` + +### 3.8 安全加固 + +```bash +# 限制客户端 IP +# 在 ccd 目录中配置 +cat > /etc/openvpn/ccd/client1 << 'EOF' +ifconfig-push 10.8.0.10 10.8.0.9 +# 绑定特定 IP +iroute 192.168.10.0 255.255.255.0 +EOF + +# 启用 LZO 压缩 +compress lz4-v2 + +# 使用强加密算法 +cipher AES-256-GCM +auth SHA256 + +# 定期更换证书 +# 每年更换一次 CA 和服务端证书 +``` + +### 3.9 常见问题处理 + +| 问题 | 原因 | 解决方案 | +|------|------|----------| +| 连接失败 | 端口被阻 | 检查防火墙/放行 1194 端口 | +| 连接成功但无法访问内网 | 未开启 IP 转发 | 开启 `net.ipv4.ip_forward` | +| 连接后无法解析 DNS | 未推送 DNS | 配置 `push "dhcp-option DNS"` | +| 证书过期 | 证书过期 | 重新签发证书 | +| 速度慢 | MTU 问题 | 调整 `tun-mtu` | + +### 3.10 配置文件示例 + +```bash +# 生产环境配置 +cat > /etc/openvpn/server.conf << 'EOF' +port 1194 +proto udp +dev tun +dev-type tun + +# 证书 +ca ca.crt +cert server.crt +key server.key +dh dh.pem +tls-auth ta.key 0 + +# 加密 +cipher AES-256-GCM +auth SHA256 + +# 网络 +server 10.8.0.0 255.255.255.0 +ifconfig-pool-persist ipp.txt +push "redirect-gateway def1 bypass-dhcp" +push "dhcp-option DNS 223.5.5.5" +push "dhcp-option DNS 119.29.29.29" + +# 客户端配置目录 +client-config-dir ccd + +# 路由 +route 192.168.1.0 255.255.255.0 + +# 权限 +keepalive 10 120 +persist-key +persist-tun +user nobody +group nobody + +# 日志 +status openvpn-status.log +log-append openvpn.log +verb 3 +compress lz4-v2 +push "compress lz4-v2" +EOF +``` + +--- + +## 4. 常用命令速查 + +### 4.1 服务端 + +| 场景 | 命令 | +|------|------| +| 启动 | `systemctl start openvpn@server` | +| 停止 | `systemctl stop openvpn@server` | +| 重启 | `systemctl restart openvpn@server` | +| 查看状态 | `systemctl status openvpn@server` | +| 查看日志 | `tail -f /etc/openvpn/openvpn.log` | + +### 4.2 客户端 + +| 场景 | 命令 | +|------|------| +| 启动连接 | `openvpn --config client.conf` | +| 后台运行 | `openvpn --config client.conf --daemon` | +| 测试配置 | `openvpn --config client.conf --test-crypto` | +| 查看连接 | `cat /etc/openvpn/openvpn-status.log` | + +### 4.3 证书操作 + +| 场景 | 命令 | +|------|------| +| 生成客户端证书 | `./easyrsa build-client name nopass` | +| 撤销证书 | `./easyrsa revoke name` | +| 生成 CRL | `./easyrsa gen-crl` | +| 查看证书 | `./easyrsa show cert name` | + +--- + +## 5. 小结 + +| 类别 | 关键点 | +|------|--------| +| 协议 | UDP(推荐)/TCP | +| 端口 | 1194 | +| 加密 | AES-256-GCM + SHA256 | +| 网络 | 10.8.0.0/24 | +| 认证 | 证书 + TLS | +| 客户端 | Windows/macOS/Linux/Android/iOS | + +> 生产环境建议:使用 UDP 协议、配置证书 + 密码双因子认证、定期更换证书。 \ No newline at end of file diff --git a/运维/自动化/Ansible/Ansible.md b/运维/自动化/Ansible/Ansible.md new file mode 100644 index 0000000..8b6b278 --- /dev/null +++ b/运维/自动化/Ansible/Ansible.md @@ -0,0 +1,1840 @@ +# Ansible 实战指南 + +## 目录 + +1. [运维自动化发展历程及技术应用](#1-运维自动化发展历程及技术应用) +2. [Ansible 架构和相关命令使用](#2-ansible-架构和相关命令使用) +3. [Ansible 常用模块详解](#3-ansible-常用模块详解) +4. [Ansible Playbook 基础](#4-ansible-playbook-基础) +5. [Playbook 变量、Tags、Handlers 使用](#5-playbook-变量tagshandlers使用) +6. [Playbook 模板 Templates](#6-playbook-模板-templates) +7. [Playbook 条件判断 When](#7-playbook-条件判断-when) +8. [Playbook 字典 with_items](#8-playbook-字典-with_items) +9. [Ansible Roles](#9-ansible-roles) + +--- + +## 1. 运维自动化发展历程及技术应用 + +### 1.1 运维自动化发展历程 + +``` +┌─────────────────────────────────────────────────────┐ +│ 运维自动化发展历程 │ +├─────────────────────────────────────────────────────┤ +│ │ +│ 1. 手动时代 │ +│ ├── 人工登录服务器 │ +│ ├── 逐台执行命令 │ +│ └── 效率低下,易出错 │ +│ │ +│ 2. 脚本时代 │ +│ ├── Shell/Python 脚本 │ +│ ├── 批量执行脚本 │ +│ └── 脚本难以维护,无标准化 │ +│ │ +│ 3. 工具时代 │ +│ ├── Puppet、SaltStack、Chef │ +│ ├── 配置管理工具 │ +│ └── 解决一致性,但复杂 │ +│ │ +│ 4. 自动化时代 │ +│ ├── Ansible、Terraform │ +│ ├── 简单易用,Agentless │ +│ └── 编排 + 自动化 │ +│ │ +│ 5. DevOps 时代 │ +│ ├── CI/CD + 自动化运维 │ +│ ├── Kubernetes + 容器 │ +│ └── GitOps 理念 │ +│ │ +└─────────────────────────────────────────────────────┘ +``` + +### 1.2 常见运维自动化工具对比 + +| 工具 | 类型 | 架构 | 优点 | 缺点 | +|------|------|------|------|------| +| **Ansible** | 配置管理/编排 | Agentless | 简单易学、YAML 语法、无 Agent | 执行速度稍慢 | +| **Puppet** | 配置管理 | C/S (Agent) | 功能强大、成熟 | 学习曲线陡峭 | +| **SaltStack** | 配置管理/执行 | C/S (Agent) | 高性能、可远程执行 | 语法复杂 | +| **Chef** | 配置管理 | C/S (Agent) | Ruby 语法、社区活跃 | 需要编写 Ruby 代码 | +| **Terraform** | 基础设施代码 | Agentless | 基础设施即代码、云原生 | 专注于基础设施 | + +### 1.3 Ansible 应用场景 + +| 场景 | 说明 | +|------|------| +| **配置管理** | 统一配置服务器、操作系统、应用软件 | +| **应用部署** | 自动化部署应用程序、容器 | +| **批量操作** | 批量执行命令、批量修改配置 | +| ** orchestration** | 多节点编排、任务编排 | +| **持续交付** | CI/CD 流水线集成 | +| **基础设施** | 云资源管理、容器编排 | + +### 1.4 Ansible 在企业中的应用 + +``` +┌─────────────────────────────────────────────────────┐ +│ Ansible 企业应用架构 │ +├─────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────────────────────────┐ │ +│ │ Ansible Control Node │ │ +│ │ (Ansible Server) │ │ +│ └────────────────────┬────────────────────────┘ │ +│ │ │ +│ ┌─────────────┼─────────────┐ │ +│ │ │ │ │ +│ ▼ ▼ ▼ │ +│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ +│ │ Web │ │ App │ │ Database │ │ +│ │ Servers │ │ Servers │ │ Servers │ │ +│ └──────────┘ └──────────┘ └──────────┘ │ +│ │ +│ 场景: │ +│ - 批量部署/配置服务器 │ +│ - 应用发布和回滚 │ +│ - 监控和日志收集 │ +│ - 安全合规检查 │ +│ │ +└─────────────────────────────────────────────────────┘ +``` + +--- + +## 2. Ansible 架构和相关命令使用 + +### 2.1 Ansible 架构 + +``` +┌─────────────────────────────────────────────────────┐ +│ Ansible 架构 │ +├─────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────────────────────────┐ │ +│ │ Ansible Engine │ │ +│ │ │ │ +│ │ Inventory ──→ Playbooks │ │ +│ │ │ │ │ │ +│ │ ▼ ▼ │ │ +│ │ Plugins ──→ Modules │ │ +│ │ │ │ │ │ +│ │ │ │ │ │ +│ │ └──────────────┘ │ │ +│ │ │ │ │ +│ └───────────┼────────────────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────────────────────────────────────┐ │ +│ │ Managed Nodes │ │ +│ │ (无 Agent) │ │ +│ │ │ │ +│ │ SSH Connection ──→ Execute Modules │ │ +│ │ │ │ +│ └─────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────┘ +``` + +### 2.2 Ansible 核心组件 + +| 组件 | 说明 | +|------|------| +| **Inventory** | 主机清单,定义管理的主机 | +| **Playbook** | 任务剧本,YAML 格式的任务定义 | +| **Module** | 模块,Ansible 执行的具体任务单元 | +| **Plugin** | 插件,扩展 Ansible 功能 | +| **API** | 编程接口,供二次开发使用 | + +### 2.3 Ansible 安装 + +```bash +# 使用 pip 安装 +pip install ansible + +# Ubuntu/Debian +apt install ansible + +# CentOS/RHEL +yum install epel-release +yum install ansible + +# macOS +brew install ansible + +# 验证安装 +ansible --version +``` + +### 2.4 Inventory 主机清单 + +#### 2.4.1 静态 Inventory + +```ini +# /etc/ansible/hosts 或 -i 指定文件 + +# 单主机 +192.168.1.10 + +# 主机组 +[web] +192.168.1.10 +192.168.1.11 +192.168.1.12 + +[db] +192.168.1.20 +192.168.1.21 + +# 嵌套组 +[production:children] +web +db + +# 主机变量 +[web] +192.168.1.10 ansible_user=admin ansible_ssh_pass=pass123 +192.168.1.11 ansible_user=admin ansible_ssh_pass=pass123 + +# 组变量 +[web:vars] +ansible_user=admin +ansible_ssh_pass=pass123 +http_port=80 +``` + +#### 2.4.2 动态 Inventory + +```bash +# 使用脚本获取主机列表 +ansible-playbook -i inventory.py playbook.yml + +# AWS EC2 动态 Inventory +ansible-playbook -i ec2.py playbook.yml +``` + +### 2.5 Ansible 配置文件 + +```ini +# ansible.cfg + +[defaults] +inventory = /etc/ansible/hosts +host_key_checking = False +retry_files_enabled = False +gathering = explicit +# 加速配置 +pipelining = True +# 并行数 +forks = 50 + +[privilege_escalation] +become = True +become_method = sudo +become_user = root +become_ask_pass = False + +[ssh_connection] +ssh_args = -o ControlMaster=auto -o ControlPersist=60s +pipelining = True +``` + +### 2.6 常用命令 + +```bash +# 帮助 +ansible-doc -h +ansible-doc +ansible-doc -l # 列出所有模块 + +# 测试连通性 +ansible all -m ping + +# 执行临时命令 +ansible all -m command -a "uptime" +ansible all -m shell -a "df -h" +ansible all -m setup # 获取主机信息 + +# 文件传输 +ansible all -m copy -a "src=/tmp/file dest=/tmp/" + +# 用户管理 +ansible all -m user -a "name=test state=present" + +# 包管理 +ansible all -m yum -a "name=httpd state=present" + +# 服务管理 +ansible all -m service -a "name=httpd state=started" + +# 查看配置 +ansible-config dump + +# 查看清单 +ansible-inventory --list +``` + +### 2.7 Playbook 命令 + +```bash +# 执行 playbook +ansible-playbook playbook.yml + +# 检查模式(不执行) +ansible-playbook --check playbook.yml + +# 差异化执行(检查变更) +ansible-playbook --diff playbook.yml + +# 指定主机 +ansible-playbook -i inventory.ini playbook.yml + +# 指定标签 +ansible-playbook --tags "web" playbook.yml + +# 跳过标签 +ansible-playbook --skip-tags "debug" playbook.yml + +# 启动步骤 +ansible-playbook --start-at-task "Install Apache" playbook.yml + +# 步骤执行 +ansible-playbook --step playbook.yml + +# 详细输出 +ansible-playbook -v playbook.yml +ansible-playbook -vv playbook.yml +ansible-playbook -vvv playbook.yml # 详细调试 + +# 清缓存 +ansible-playbook --flush-cache playbook.yml +``` + +--- + +## 3. Ansible 常用模块详解 + +### 3.1 模块分类 + +| 分类 | 说明 | 常见模块 | +|------|------|----------| +| **命令执行** | 执行远程命令 | command, shell, script, raw | +| **文件操作** | 文件管理 | copy, file, template, synchronize | +| **包管理** | 软件包管理 | yum, apt, package | +| **服务管理** | 服务管理 | service, systemd | +| **用户管理** | 用户管理 | user, group | +| **数据库** | 数据库操作 | mysql_db, postgresql_db | +| **云资源** | 云资源管理 | ec2, azure_rm, gce | +| **容器** | 容器管理 | docker, k8s | +| **通知** | 通知模块 | email, slack | + +### 3.2 命令执行模块 + +#### 3.2.1 command 模块 + +```yaml +- name: Execute command + command: uptime + +- name: Execute with args + command: systemctl start nginx + +- name: Check file exists + command: test -f /etc/nginx/nginx.conf + register: result + +- name: Create directory + command: mkdir -p /tmp/test + creates: /tmp/test # 存在则跳过 +``` + +#### 3.2.2 shell 模块 + +```yaml +- name: Execute shell + shell: echo $PATH + +- name: Execute with pipe + shell: cat /etc/passwd | grep root + +- name: Execute script + shell: | + #!/bin/bash + echo "Hello" +``` + +#### 3.2.3 script 模块 + +```yaml +- name: Run local script + script: /tmp/script.sh + +- name: Run with args + script: /tmp/script.sh --arg1 value1 + +- name: Run on remote + script: /tmp/script.sh + args: + creates: /tmp/result +``` + +### 3.3 文件操作模块 + +#### 3.3.1 copy 模块 + +```yaml +- name: Copy file + copy: + src: /tmp/source.conf + dest: /etc/nginx/nginx.conf + owner: root + group: root + mode: '0644' + +- name: Copy with backup + copy: + src: /tmp/source.conf + dest: /etc/nginx/nginx.conf + backup: yes + +- name: Copy content + copy: + dest: /tmp/test.txt + content: "Hello World" +``` + +#### 3.3.2 file 模块 + +```yaml +- name: Create directory + file: + path: /tmp/dir + state: directory + mode: '0755' + +- name: Create file + file: + path: /tmp/file + state: touch + +- name: Create symlink + file: + src: /tmp/source + dest: /tmp/link + state: link + +- name: Delete file + file: + path: /tmp/file + state: absent +``` + +#### 3.3.3 template 模块 + +```yaml +- name: Template file + template: + src: nginx.conf.j2 + dest: /etc/nginx/nginx.conf + owner: root + group: root + mode: '0644' + validate: 'nginx -t -c %s' +``` + +#### 3.3.4 synchronize 模块 + +```yaml +- name: Sync directory + synchronize: + src: /tmp/local/ + dest: /tmp/remote/ + delete: yes + rsync_opts: + - "--exclude=.git" +``` + +### 3.4 包管理模块 + +#### 3.4.1 yum 模块 + +```yaml +- name: Install package + yum: + name: nginx + state: present + +- name: Install latest + yum: + name: '*' + state: latest + +- name: Install multiple + yum: + name: + - nginx + - php-fpm + state: present + +- name: Remove package + yum: + name: nginx + state: absent + +- name: Install from repo + yum: + name: epel-release + enablerepo: epel +``` + +#### 3.4.2 apt 模块 + +```yaml +- name: Install package + apt: + name: nginx + state: present + update_cache: yes + +- name: Install without update + apt: + name: nginx + state: present + update_cache: no + +- name: Install from deb + apt: + deb: /tmp/package.deb + state: present +``` + +### 3.5 服务管理模块 + +#### 3.5.1 service 模块 + +```yaml +- name: Start service + service: + name: nginx + state: started + enabled: yes + +- name: Stop service + service: + name: nginx + state: stopped + +- name: Restart service + service: + name: nginx + state: restarted + +- name: Reload service + service: + name: nginx + state: reloaded +``` + +#### 3.5.2 systemd 模块 + +```yaml +- name: Enable and start service + systemd: + name: nginx + state: started + enabled: yes + daemon_reload: yes +``` + +### 3.6 用户管理模块 + +#### 3.6.1 user 模块 + +```yaml +- name: Create user + user: + name: appuser + comment: "Application User" + shell: /bin/bash + home: /home/appuser + create_home: yes + +- name: Create with password + user: + name: admin + password: "{{ 'password' | password_hash('sha512') }}" + +- name: Add to group + user: + name: appuser + groups: + - wheel + - docker + append: yes + +- name: Remove user + user: + name: appuser + state: absent + remove: yes +``` + +#### 3.6.2 group 模块 + +```yaml +- name: Create group + group: + name: mygroup + state: present + gid: 1000 +``` + +### 3.7 其他常用模块 + +#### 3.7.1 get_url 模块 + +```yaml +- name: Download file + get_url: + url: http://example.com/file.tar.gz + dest: /tmp/file.tar.gz + mode: '0644' +``` + +#### 3.7.2 unarchive 模块 + +```yaml +- name: Unarchive file + unarchive: + src: /tmp/file.tar.gz + dest: /tmp/ + remote_src: no +``` + +#### 3.7.3 lineinfile 模块 + +```yaml +- name: Add line + lineinfile: + path: /etc/selinux/config + regexp: '^SELINUX=' + line: SELINUX=enforcing + +- name: Remove line + lineinfile: + path: /etc/selinux/config + regexp: '^SELINUX=' + state: absent +``` + +#### 3.7.4 find 模块 + +```yaml +- name: Find files + find: + paths: /var/log + patterns: "*.log" + age: 7d + register: log_files +``` + +--- + +## 4. Ansible Playbook 基础 + +### 4.1 Playbook 概述 + +Playbook 是 Ansible 的任务配置文件,使用 YAML 格式编写,定义了一组有序的任务。 + +``` +┌─────────────────────────────────────────────────────┐ +│ Playbook 结构 │ +├─────────────────────────────────────────────────────┤ +│ │ +│ Playbook (剧本) │ +│ ├── Play 1 │ +│ │ ├── Hosts (主机) │ +│ │ ├── Vars (变量) │ +│ │ └── Tasks (任务) │ +│ │ ├── Task 1 (Module) │ +│ │ └── Task 2 (Module) │ +│ │ │ +│ └── Play 2 │ +│ ├── Hosts │ +│ ├── Vars │ +│ └── Tasks │ +│ │ +└─────────────────────────────────────────────────────┘ +``` + +### 4.2 基础 Playbook 示例 + +```yaml +# playbook.yml +--- +- name: Configure Web Server + hosts: web + become: yes + + vars: + http_port: 80 + + tasks: + - name: Install Apache + yum: + name: httpd + state: present + + - name: Ensure Apache is running + service: + name: httpd + state: started + enabled: yes + + - name: Copy configuration + copy: + src: files/httpd.conf + dest: /etc/httpd/conf/httpd.conf + notify: Restart Apache + + - name: Copy index page + template: + src: templates/index.html.j2 + dest: /var/www/html/index.html + + handlers: + - name: Restart Apache + service: + name: httpd + state: restarted +``` + +### 4.3 多个 Play + +```yaml +--- +- name: Configure Web Servers + hosts: web + become: yes + + tasks: + - name: Install Apache + yum: + name: httpd + state: present + + - name: Start Apache + service: + name: httpd + state: started + +- name: Configure Database Servers + hosts: db + become: yes + + tasks: + - name: Install MySQL + yum: + name: mysql-server + state: present + + - name: Start MySQL + service: + name: mysqld + state: started +``` + +### 4.4 Play 常用参数 + +| 参数 | 说明 | +|------|------| +| `name` | Play 名称 | +| `hosts` | 目标主机 | +| `become` | 是否提权 | +| `become_method` | 提权方式(sudo/su) | +| `become_user` | 提权用户 | +| `gather_facts` | 是否收集主机信息 | +| `vars` | 变量 | +| `tasks` | 任务列表 | +| `handlers` | 处理器 | +| `roles` | 角色 | + +### 4.5 Task 常用参数 + +| 参数 | 说明 | +|------|------| +| `name` | 任务名称 | +| `module` | 使用的模块 | +| `args` | 模块参数 | +| `when` | 条件判断 | +| `register` | 注册变量 | +| `changed_when` | 改变判断条件 | +| `failed_when` | 失败判断条件 | +| `loop` | 循环 | +| `until` | 循环直到 | +| `retries` | 重试次数 | +| `delay` | 重试延迟 | + +### 4.6 任务控制 + +```yaml +# 顺序执行 +- name: Task 1 + yum: + name: httpd + state: present + +- name: Task 2 + service: + name: httpd + state: started + +# 忽略错误 +- name: Ignore error + command: /some/command + ignore_errors: yes + +# 强制失败 +- name: Force fail + command: /some/command + failed_when: "'FAILED' in result.stderr" + +# 标签 +- name: Install packages + yum: + name: "{{ item }}" + tags: + - packages + - web +``` + +--- + +## 5. Playbook 变量、Tags、Handlers 使用 + +### 5.1 变量 + +#### 5.1.1 变量定义 + +```yaml +# 方式 1:Play 变量 +- hosts: web + vars: + http_port: 80 + server_name: example.com + + tasks: + - name: Use variable + debug: + msg: "Port is {{ http_port }}" + +# 方式 2:Task 变量 +- name: Task variable + debug: + msg: "{{ task_var }}" + vars: + task_var: "Hello" +``` + +#### 5.1.2 主机变量 + +```ini +# inventory +[web] +192.168.1.10 http_port=8080 +192.168.1.11 http_port=8090 +``` + +#### 5.1.3 组变量 + +```yaml +# group_vars/all.yml +--- +ansible_user: admin +ansible_ssh_pass: password + +# group_vars/web.yml +--- +http_port: 80 +``` + +#### 5.1.4 变量引用 + +```yaml +- name: Reference variables + debug: + msg: "{{ variable_name }}" + +- name: Complex reference + debug: + msg: "{{ hostvars[groups['web'][0]]['ansible_host'] }}" +``` + +#### 5.1.5 Facts 变量 + +```yaml +# 获取 facts +- name: Get facts + setup: + filter: ansible_* + +- name: Show facts + debug: + msg: "{{ ansible_hostname }}" + +# 常用 facts +# ansible_hostname - 主机名 +# ansible_default_ipv4.address - IP 地址 +# ansible_distribution - 发行版 +# ansible_distribution_version - 版本 +# ansible_memory_mb.real.total - 内存 +# ansible_processor_vcpus - CPU 核心数 +``` + +### 5.2 Tags + +#### 5.2.1 Tag 定义 + +```yaml +- name: Install Apache + yum: + name: httpd + state: present + tags: + - web + - httpd + +- name: Configure Apache + template: + src: httpd.conf.j2 + dest: /etc/httpd/conf/httpd.conf + tags: + - config + - httpd +``` + +#### 5.2.2 Tag 使用 + +```bash +# 只执行带 tag 的任务 +ansible-playbook --tags "web" playbook.yml + +# 跳过 tag +ansible-playbook --skip-tags "debug" playbook.yml + +# 多个 tag +ansible-playbook --tags "web,mysql" playbook.yml +``` + +### 5.3 Handlers + +#### 5.3.1 Handler 定义 + +```yaml +- name: Configure Apache + template: + src: httpd.conf.j2 + dest: /etc/httpd/conf/httpd.conf + notify: + - Restart Apache + +handlers: + - name: Restart Apache + service: + name: httpd + state: restarted +``` + +#### 5.3.2 多个 Handlers + +```yaml +- name: Configure Apache + template: + src: httpd.conf.j2 + dest: /etc/httpd/conf/httpd.conf + notify: + - Restart Apache + - Reload Nginx + +handlers: + - name: Restart Apache + service: + name: httpd + state: restarted + + - name: Reload Nginx + service: + name: nginx + state: reloaded +``` + +#### 5.3.3 Handler 监听 + +```yaml +- name: Config changed + template: + src: app.conf.j2 + dest: /etc/app.conf + notify: + - Notify handler + +handlers: + - name: Notify handler + service: + name: app + state: restarted + listen: "config changed" +``` + +--- + +## 6. Playbook 模板 Templates + +### 6.1 Jinja2 模板概述 + +Ansible 使用 Jinja2 作为模板引擎,支持变量、过滤器、循环等特性。 + +### 6.2 基础模板 + +```jinja +{# config.conf.j2 #} +# Server configuration +ServerName {{ server_name }} +Listen {{ http_port }} +DocumentRoot "{{ document_root }}" + +{% if enable_ssl %} +SSLEngine on +SSLCertificateFile {{ ssl_cert }} +SSLCertificateKeyFile {{ ssl_key }} +{% endif %} +``` + +### 6.3 变量和过滤器 + +```jinja +{# 使用变量 #} +{{ variable }} + +{# 默认值 #} +{{ variable | default('default_value') }} + +{# 过滤器 #} +{{ name | upper }} +{{ list | join(',') }} +{{ number | int }} + +{# 条件判断 #} +{% if var == 'value' %} +... +{% endif %} + +{# 循环 #} +{% for item in items %} +{{ item }} +{% endfor %} +``` + +### 6.4 完整示例 + +```yaml +# playbook.yml +--- +- name: Configure Nginx + hosts: web + become: yes + + vars: + server_name: example.com + http_port: 80 + document_root: /var/www/html + enable_ssl: true + ssl_cert: /etc/nginx/ssl/server.crt + ssl_key: /etc/nginx/ssl/server.key + + tasks: + - name: Ensure Nginx installed + yum: + name: nginx + state: present + + - name: Configure Nginx + template: + src: nginx.conf.j2 + dest: /etc/nginx/nginx.conf + validate: 'nginx -t -c %s' + notify: Restart Nginx + + handlers: + - name: Restart Nginx + service: + name: nginx + state: restarted +``` + +```jinja +{# nginx.conf.j2 #} +user nginx; +worker_processes {{ worker_processes | default('auto') }}; +error_log /var/log/nginx/error.log; + +events { + worker_connections {{ worker_connections | default(1024) }}; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout {{ keepalive_timeout | default(65) }}; + + upstream backend { + {% for server in upstream_servers %} + server {{ server.host }}:{{ server.port }}{% if server.weight %} weight={{ server.weight }}{% endif %}; + {% endfor %} + } + + server { + listen {{ http_port }}; + server_name {{ server_name }}; + + root {{ document_root }}; + + {% if enable_ssl %} + listen 443 ssl http2; + ssl_certificate {{ ssl_cert }}; + ssl_certificate_key {{ ssl_key }}; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256; + {% endif %} + + location / { + proxy_pass http://backend; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } + } +} +``` + +### 6.5 模板变量文件 + +```yaml +# group_vars/web.yml +--- +server_name: example.com +http_port: 80 +document_root: /var/www/html +enable_ssl: true +ssl_cert: /etc/nginx/ssl/server.crt +ssl_key: /etc/nginx/ssl/server.key + +upstream_servers: + - host: 192.168.1.10 + port: 8080 + weight: 5 + - host: 192.168.1.11 + port: 8080 + weight: 3 + +worker_processes: 4 +worker_connections: 2048 +keepalive_timeout: 60 +``` + +--- + +## 7. Playbook 条件判断 When + +### 7.1 when 基础 + +```yaml +- name: Install Apache on CentOS + yum: + name: httpd + state: present + when: ansible_os_family == "RedHat" + +- name: Install Apache on Debian + apt: + name: apache2 + state: present + when: ansible_os_family == "Debian" +``` + +### 7.2 多个条件 + +```yaml +# AND 条件 +- name: Install on specific OS + yum: + name: httpd + state: present + when: + - ansible_os_family == "RedHat" + - ansible_distribution_version | int >= 7 + +# OR 条件 +- name: Install web server + yum: + name: nginx + state: present + when: ansible_os_family == "RedHat" or ansible_os_family == "Debian" +``` + +### 7.3 变量判断 + +```yaml +- name: Register variable + command: /usr/bin/test -f /etc/httpd/conf/httpd.conf + register: httpd_conf + +- name: Check result + debug: + msg: "Config file exists" + when: httpd_conf.rc == 0 + +- name: Check changed + command: /usr/bin/some-command + register: result + changed_when: result.rc != 0 + +- name: Conditional execution + debug: + msg: "Command changed" + when: result is changed +``` + +### 7.4 内置条件测试 + +```yaml +- name: Test defined + debug: + msg: "Variable defined" + when: my_var is defined + +- name: Test undefined + debug: + msg: "Variable not defined" + when: my_var is not defined + +- name: Test true + debug: + msg: "Value is true" + when: my_var | bool + +- name: Test false + debug: + msg: "Value is false" + when: not my_var | bool + +- name: Test string + debug: + msg: "String test" + when: my_string == "value" + +- name: Test number + debug: + msg: "Number test" + when: my_number > 100 + +- name: Test in + debug: + msg: "In list" + when: ansible_hostname in groups['web'] +``` + +### 7.5 循环 + 条件 + +```yaml +- name: Install packages based on OS + yum: + name: "{{ item }}" + state: present + loop: + - httpd + - nginx + when: ansible_os_family == "RedHat" + +- name: Install specific packages + apt: + name: "{{ item.name }}" + state: present + loop: + - { name: 'apache2', os: 'Debian' } + - { name: 'httpd', os: 'RedHat' } + when: ansible_os_family == item.os +``` + +### 7.6 完整示例 + +```yaml +--- +- name: Configure servers based on OS + hosts: all + gather_facts: yes + + vars: + install_web: true + install_db: false + + tasks: + - name: Install Apache + yum: + name: httpd + state: present + when: + - install_web | bool + - ansible_os_family == "RedHat" + + - name: Install Apache on Debian + apt: + name: apache2 + state: present + when: + - install_web | bool + - ansible_os_family == "Debian" + + - name: Install MySQL + yum: + name: mysql-server + state: present + when: + - install_db | bool + - ansible_distribution == "CentOS" + + - name: Configure firewall for CentOS 7+ + firewalld: + service: http + permanent: yes + state: enabled + when: + - ansible_os_family == "RedHat" + - ansible_distribution_version | int >= 7 + + - name: Only on web servers + debug: + msg: "This is a web server" + when: "'web' in group_names" +``` + +--- + +## 8. Playbook 字典 with_items + +### 8.1 with_items 基础 + +```yaml +- name: Install multiple packages + yum: + name: "{{ item }}" + state: present + loop: + - httpd + - nginx + - php-fpm + +- name: Create users + user: + name: "{{ item }}" + state: present + loop: + - alice + - bob + - charlie +``` + +### 8.2 字典列表 + +```yaml +- name: Create multiple users with attributes + user: + name: "{{ item.name }}" + comment: "{{ item.comment }}" + shell: "{{ item.shell }}" + create_home: yes + loop: + - { name: 'alice', comment: 'Alice User', shell: '/bin/bash' } + - { name: 'bob', comment: 'Bob User', shell: '/bin/sh' } +``` + +### 8.3 嵌套循环 + +```yaml +- name: Create directories + file: + path: "{{ item.0 }}/{{ item.1 }}" + state: directory + loop: + - ['/tmp', 'dir1'] + - ['/tmp', 'dir2'] + - ['/var', 'log'] +``` + +### 8.4 with_dict + +```yaml +- name: Define dictionary + set_fact: + users: + alice: + shell: /bin/bash + home: /home/alice + bob: + shell: /bin/sh + home: /home/bob + +- name: Create users from dict + user: + name: "{{ item.key }}" + shell: "{{ item.value.shell }}" + home: "{{ item.value.home }}" + loop: "{{ dict(users) | dict2items }}" +``` + +### 8.5 with_fileglob + +```yaml +- name: Copy all files + copy: + src: "{{ item }}" + dest: /tmp/ + mode: '0644' + loop: + - "{{ playbook_dir }}/files/*" +``` + +### 8.6 with_sequence + +```yaml +- name: Create sequence files + file: + path: "/tmp/file{{ item }}" + state: touch + loop: "{{ range(1, 11) | list }}" +``` + +### 8.7 with_together + +```yaml +- name: Combine lists + debug: + msg: "{{ item.0 }} - {{ item.1 }}" + loop: "{{ list1 | zip(list2) | list }}" +``` + +### 8.8 with_nested + +```yaml +- name: Nested loop + debug: + msg: "{{ item.0 }} - {{ item.1 }}" + loop: "{{ ['a', 'b', 'c'] | product(['1', '2', '3']) | list }}" +``` + +### 8.9 注册变量 + 循环 + +```yaml +- name: Get file contents + command: cat {{ item }} + register: file_contents + loop: + - /tmp/file1.txt + - /tmp/file2.txt + +- name: Show contents + debug: + msg: "{{ item.stdout }}" + loop: "{{ file_contents.results }}" +``` + +### 8.10 完整示例 + +```yaml +--- +- name: Configure multi-tier application + hosts: app + + vars: + app_users: + - { name: 'appuser', uid: 1000, group: 'app', shell: '/bin/bash' } + - { name: 'deploy', uid: 1001, group: 'app', shell: '/bin/sh' } + + app_dirs: + - { path: '/opt/app', owner: 'appuser', mode: '0755' } + - { path: '/var/log/app', owner: 'appuser', mode: '0755' } + - { path: '/tmp/app', owner: 'appuser', mode: '1777' } + + packages: + - java-11-openjdk + - maven + - git + + tasks: + - name: Create groups + group: + name: "{{ item }}" + state: present + loop: + - app + - deploy + + - name: Create users + user: + name: "{{ item.name }}" + uid: "{{ item.uid }}" + group: "{{ item.group }}" + shell: "{{ item.shell }}" + create_home: yes + loop: "{{ app_users }}" + + - name: Create directories + file: + path: "{{ item.path }}" + owner: "{{ item.owner }}" + mode: "{{ item.mode }}" + state: directory + loop: "{{ app_dirs }}" + + - name: Install packages + yum: + name: "{{ item }}" + state: present + loop: "{{ packages }}" + when: ansible_os_family == "RedHat" + + - name: Install packages (Debian) + apt: + name: "{{ item }}" + state: present + update_cache: yes + loop: "{{ packages }}" + when: ansible_os_family == "Debian" +``` + +--- + +## 9. Ansible Roles + +### 9.1 Roles 概述 + +Roles 是 Ansible 的组织结构化机制,将 Playbook 分解为可重用的组件。 + +``` +┌─────────────────────────────────────────────────────┐ +│ Roles 目录结构 │ +├─────────────────────────────────────────────────────┤ +│ │ +│ roles/ │ +│ └── role_name/ │ +│ ├── defaults/ # 默认变量(最低优先级)│ +│ │ └── main.yml │ +│ ├── vars/ # 变量(最高优先级) │ +│ │ └── main.yml │ +│ ├── tasks/ # 任务 │ +│ │ └── main.yml │ +│ ├── handlers/ # 处理器 │ +│ │ └── main.yml │ +│ ├── templates/ # 模板 │ +│ │ └── *.j2 │ +│ ├── files/ # 静态文件 │ +│ │ └── * │ +│ ├── meta/ # 依赖关系 │ +│ │ └── main.yml │ +│ └── README.md # 文档 │ +│ │ +└─────────────────────────────────────────────────────┘ +``` + +### 9.2 创建 Role + +```bash +# 使用 ansible-galaxy 创建 +ansible-galaxy init role_name + +# 手动创建目录结构 +mkdir -p roles/nginx/{defaults,vars,tasks,handlers,templates,files,meta} +``` + +### 9.3 Role 示例:Nginx + +#### 9.3.1 defaults/main.yml + +```yaml +--- +# defaults/main.yml +nginx_version: "1.24" +nginx_port: 80 +nginx_worker_processes: auto +nginx_worker_connections: 1024 +nginx_server_name: localhost +nginx_document_root: /var/www/html +``` + +#### 9.3.2 vars/main.yml + +```yaml +--- +# vars/main.yml +nginx_user: nginx +nginx_group: nginx +nginx_conf_dir: /etc/nginx +nginx_log_dir: /var/log/nginx +``` + +#### 9.3.3 tasks/main.yml + +```yaml +--- +# tasks/main.yml +- name: Ensure nginx is installed + yum: + name: nginx + state: present + when: ansible_os_family == "RedHat" + +- name: Ensure nginx is installed + apt: + name: nginx + state: present + update_cache: yes + when: ansible_os_family == "Debian" + +- name: Copy nginx configuration + template: + src: nginx.conf.j2 + dest: /etc/nginx/nginx.conf + notify: Restart nginx + +- name: Ensure nginx is running + service: + name: nginx + state: started + enabled: yes +``` + +#### 9.3.4 handlers/main.yml + +```yaml +--- +# handlers/main.yml +- name: Restart nginx + service: + name: nginx + state: restarted + +- name: Reload nginx + service: + name: nginx + state: reloaded +``` + +#### 9.3.5 templates/nginx.conf.j2 + +```jinja +# nginx.conf.j2 +user {{ nginx_user }}; +worker_processes {{ nginx_worker_processes }}; +error_log {{ nginx_log_dir }}/error.log; + +events { + worker_connections {{ nginx_worker_connections }}; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log {{ nginx_log_dir }}/access.log main; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + + server { + listen {{ nginx_port }}; + server_name {{ nginx_server_name }}; + + root {{ nginx_document_root }}; + + location / { + index index.html index.htm; + } + } +} +``` + +### 9.4 使用 Role + +```yaml +# site.yml +--- +- name: Configure web servers + hosts: web + + roles: + - role: nginx + nginx_port: 8080 + nginx_server_name: example.com + +- name: Configure database servers + hosts: db + + roles: + - role: mysql + mysql_port: 3306 +``` + +### 9.5 Role 依赖 + +```yaml +# roles/common/meta/main.yml +--- +dependencies: + - role: common + vars: + common_version: 1.0 + - role: monitoring +``` + +### 9.6 完整 Playbook 示例 + +```yaml +# site.yml - 完整项目配置 +--- +- name: Infrastructure setup + hosts: all + gather_facts: yes + + roles: + - common + - ntp + +- name: Web servers setup + hosts: web + become: yes + + roles: + - nginx + - php-fpm + - firewall + +- name: Database servers setup + hosts: db + become: yes + + roles: + - mysql + - backup + +- name: Application deployment + hosts: app + become: yes + + roles: + - app_deploy + - monitoring_agent +``` + +### 9.7 导入 Role + +```yaml +# 静态导入 +- name: Import role + import_role: + name: nginx + vars: + nginx_port: 8080 + +- name: Import handlers + import_tasks: handlers.yml +``` + +### 9.8 动态 Role + +```yaml +# 动态导入 +- name: Include role + include_role: + name: nginx + vars: + nginx_port: 80 +``` + +### 9.9 Galaxy 角色 + +```bash +# 搜索角色 +ansible-galaxy search nginx + +# 安装角色 +ansible-galaxy install geerlingguy.nginx + +# 查看已安装角色 +ansible-galaxy list + +# 删除角色 +ansible-galaxy remove geerlingguy.nginx +``` + +--- + +## 附录 + +### 常用命令速查 + +| 命令 | 说明 | +|------|------| +| `ansible all -m ping` | 测试连通性 | +| `ansible-playbook site.yml` | 执行 Playbook | +| `ansible-playbook --check site.yml` | 模拟执行 | +| `ansible-playbook --tags "web" site.yml` | 指定标签 | +| `ansible-doc -l` | 列出模块 | +| `ansible-doc user` | 查看模块文档 | +| `ansible-galaxy init role` | 创建角色 | +| `ansible-config dump` | 查看配置 | + +### 配置参数速查 + +| 参数 | 说明 | +|------|------| +| `inventory` | 主机清单 | +| `forks` | 并行数 | +| `become` | 提权 | +| `host_key_checking` | 主机指纹检查 | +| `retry_files_enabled` | 重试文件 | + +### 变量优先级 + +| 优先级(低到高) | +|----------| +| role defaults | +| inventory file/script group vars | +| inventory group vars | +| playbook group vars | +| host facts | +| register vars | +| set_facts | +| role/vars | +| include vars | +| include params | +| extra vars | + +--- + +*文档创建时间:2024年* \ No newline at end of file diff --git a/运维/负载均衡/KeepAlived/KeepAlived实操.md b/运维/负载均衡/KeepAlived/KeepAlived实操.md index e69de29..988924e 100644 --- a/运维/负载均衡/KeepAlived/KeepAlived实操.md +++ b/运维/负载均衡/KeepAlived/KeepAlived实操.md @@ -0,0 +1,118 @@ +## 环境简介 +| hostname | ip | mark | +| --- | --- | --- | +| lvs-1 | 192.168.30.13 | 主lvs | +| lvs-2 | 192.168.30.14 | 备lvs | +| k8s-master-1 | 192.168.30.6 | rs-1 | +| k8s-master-2 | 192.168.30.7 | rs-2 | +| k8s-master-3 | 192.168.30.12 | rs-3 | + + +## 搭建主备LVS +```plain +apt install keepalived net-tools -y #安装keepalived 和 net-tools +``` + +配置keepalived 配置文件 + +```plain +global_defs { + no_email_faults +} + +# VRRP 实例配置 +vrrp_instance VI_1 { + state MASTER #如果使用主/备,另外一台机器需要设置为BACKUP + interface ens32 #检测网络端口 + virtual_router_id 100 #主备的虚拟机路由ID必须一致 + priority 100 #主备的优先级,主优先级要大于备 + advert_int 1 #VRRP Multicast广播周期秒数 + authentication { + auth_type PASS # VRRP认证方式 + auth_pass zhanxiaoyao # VRRP口令字 + } + virtual_ipaddress { + 192.168.30.200 # 如果有多个VIP,继续换行填写 + } +} + +# 虚拟服务器配置 +virtual_server 192.168.30.200 6443 { + delay_loop 1 # 每隔1秒查询realserver状态 + lb_algo wrr # lvs 算法 + lb_kind DR # Direct Route + protocol TCP # 用TCP协议检查realserver状态 + persistence_timeout 300 # 会话保持时间,这段时间内,同一ip发起的请求将被转发到同一个realserver + + # 第一台realserver物理环境 + real_server 192.168.30.6 6443 { + weight 1 + TCP_CHECK { + connect_port 6443 #设置监控检查的端口 + connect_timeout 3 #设置连接超时时间 + nb_get_retry 3 #设置重连次数 + delay_before_retry 2 #设置重连间隔 + } + } + + # 第二台realserver物理环境 + real_server 192.168.30.7 6443 { + weight 1 + TCP_CHECK { + connect_port 6443 #设置监控检查的端口 + connect_timeout 3 #设置连接超时时间 + nb_get_retry 3 #设置重连次数 + delay_before_retry 2 #设置重连间隔 + } + } + # 第三台realserver物理环境 + real_server 192.168.30.12 6443 { + weight 1 + TCP_CHECK { + connect_port 6443 #设置监控检查的端口 + connect_timeout 3 #设置连接超时时间 + nb_get_retry 3 #设置重连次数 + delay_before_retry 2 #设置重连间隔 + } + } +} +``` + +```plain +systemctl enable keepalived +systemctl start keepalived +ipvsadm +ip a +``` + +## 搭建rs +```plain +vim /etc/keepalived-rs.sh + +#!/bin/bash +VIP=192.168.30.200 +echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore +echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce +echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore +echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce +/sbin/ifconfig lo:0 $VIP broadcast $VIP netmask 255.255.255.255 up +/sbin/route add -host $VIP dev lo:0 + +chmod 777 /etc/keepalived-rs.sh + +vim /lib/systemd/system/keepalived-lvs-rs.service + +[Unit] +Description=My Script +After=network.target + +[Service] +ExecStart=/etc/keepalived-rs.sh + +[Install] +WantedBy=default.target +``` + +```plain +reboot +``` diff --git a/运维/负载均衡/Nginx/Nginx.md b/运维/负载均衡/Nginx/Nginx.md new file mode 100644 index 0000000..395c471 --- /dev/null +++ b/运维/负载均衡/Nginx/Nginx.md @@ -0,0 +1,1882 @@ +# Nginx 实战指南 + +## 目录 + +1. [Web 服务基础](#1-web-服务基础) +2. [HTTP 协议](#2-http-协议) +3. [I/O 模型](#3-io-模型) +4. [Nginx 介绍和架构](#4-nginx-介绍和架构) +5. [Nginx 安装](#5-nginx-安装) +6. [Nginx 各种模块实现 Web 服务](#6-nginx-各种模块实现-web-服务) +7. [Nginx 实现 HTTP 负载均衡](#7-nginx-实现-http-负载均衡) +8. [Nginx 实现 TCP 反向代理](#8-nginx-实现-tcp-反向代理) +9. [Nginx 实现 FastCGI 反向代理](#9-nginx-实现-fastcgi-反向代理) +10. [Nginx 二次开发版](#10-nginx-二次开发版) +11. [Nginx 高并发 Linux 内核优化](#11-nginx-高并发-linux-内核优化) + +--- + +## 1. Web 服务基础 + +### 1.1 Web 服务概念 + +Web 服务是一种基于 HTTP/HTTPS 协议的网络服务架构,主要分为前端(浏览器)和后端(服务器)两部分。 + +### 1.2 Web 服务架构演进 + +``` +┌─────────────────────────────────────────────────────┐ +│ Web 服务架构演进 │ +├─────────────────────────────────────────────────────┤ +│ │ +│ 单机架构 集群架构 │ +│ ┌──────────┐ ┌────────┬────────┐ │ +│ │ Apache │ │ Load │nginx │ │ +│ │ + PHP │ │ Balancer│ │ │ +│ └──────────┘ └─┬──────┴────────┘ │ +│ │ │ +│ ┌───────────┼───────────┐ │ +│ ▼ ▼ ▼ │ +│ ┌───────┐ ┌───────┐ ┌───────┐ │ +│ │App 1 │ │App 2 │ │App 3 │ │ +│ └───────┘ └───────┘ └───────┘ │ +│ │ +│ 微服务架构 云原生架构 │ +│ ┌────┬────┬────┐ ┌─────┬─────┬─────┐ │ +│ │API│Auth│Order│ │K8s │Docker│Istio│ │ +│ │Gateway│ │ │ │ │ │ │ │ +│ └────┴────┴────┘ └─────┴─────┴─────┘ │ +│ │ +└─────────────────────────────────────────────────────┘ +``` + +### 1.3 常见 Web 服务器 + +| 服务器 | 特点 | 适用场景 | +|--------|------|----------| +| Apache | 功能丰富,模块化,稳定 | 传统 Web 应用 | +| Nginx | 高性能,低内存,反向代理 | 高并发,负载均衡 | +| IIS | Windows 原生,集成 AD | Windows 环境 | +| Tomcat | Java 容器,Servlet 容器 | Java 应用 | +| Jetty | 轻量级,嵌入式 | 微服务 | + +--- + +## 2. HTTP 协议 + +### 2.1 HTTP 协议概述 + +HTTP(HyperText Transfer Protocol)是互联网应用最广泛的网络协议,属于应用层协议。 + +### 2.2 HTTP 请求结构 + +``` +┌─────────────────────────────────────────────────────┐ +│ HTTP 请求结构 │ +├─────────────────────────────────────────────────────┤ +│ │ +│ 请求行:GET /index.html HTTP/1.1 │ +│ ┌─────────────────────────────────────────────┐ │ +│ │ 方法 URL 协议版本 │ │ +│ └─────────────────────────────────────────────┘ │ +│ │ +│ 请求头: │ +│ Host: www.example.com │ +│ User-Agent: Mozilla/5.0 │ +│ Accept: text/html,application/json │ +│ Accept-Language: zh-CN,zh;q=0.9 │ +│ Cookie: session=xxx │ +│ │ +│ 空行 │ +│ │ +│ 请求体(POST/PUT): │ +│ username=admin&password=123456 │ +│ │ +└─────────────────────────────────────────────────────┘ +``` + +### 2.3 HTTP 响应结构 + +``` +┌─────────────────────────────────────────────────────┐ +│ HTTP 响应结构 │ +├─────────────────────────────────────────────────────┤ +│ │ +│ 状态行:HTTP/1.1 200 OK │ +│ ┌─────────────────────────────────────────────┐ │ +│ │ 协议版本 状态码 状态描述 │ │ +│ └─────────────────────────────────────────────┘ │ +│ │ +│ 响应头: │ +│ Server: nginx/1.24.0 │ +│ Content-Type: text/html; charset=utf-8 │ +│ Content-Length: 1234 │ +│ Date: Thu, 09 Apr 2026 01:17:00 GMT │ +│ Set-Cookie: session=xxx; HttpOnly │ +│ │ +│ 空行 │ +│ │ +│ 响应体: │ +│ ... │ +│ │ +└─────────────────────────────────────────────────────┘ +``` + +### 2.4 HTTP 方法 + +| 方法 | 说明 | 幂等 | +|------|------|------| +| GET | 获取资源 | 是 | +| POST | 创建资源 | 否 | +| PUT | 更新资源(完整) | 是 | +| PATCH | 更新资源(部分) | 否 | +| DELETE | 删除资源 | 是 | +| HEAD | 获取响应头 | 是 | +| OPTIONS | 获取支持的请求方法 | 是 | +| CONNECT | 建立隧道 | - | + +### 2.5 HTTP 状态码 + +| 状态码 | 说明 | +|--------|------| +| **1xx** | 信息响应 | +| 100 | Continue | +| 101 | Switching Protocols | +| **2xx** | 成功响应 | +| 200 | OK | +| 201 | Created | +| 204 | No Content | +| 206 | Partial Content | +| **3xx** | 重定向 | +| 301 | Moved Permanently | +| 302 | Found | +| 304 | Not Modified | +| 307 | Temporary Redirect | +| **4xx** | 客户端错误 | +| 400 | Bad Request | +| 401 | Unauthorized | +| 403 | Forbidden | +| 404 | Not Found | +| 405 | Method Not Allowed | +| 409 | Conflict | +| 429 | Too Many Requests | +| **5xx** | 服务器错误 | +| 500 | Internal Server Error | +| 502 | Bad Gateway | +| 503 | Service Unavailable | +| 504 | Gateway Timeout | + +### 2.6 HTTP 头部 + +#### 2.6.1 通用头部 + +| 头部 | 说明 | +|------|------| +| Connection | 连接管理 | +| Transfer-Encoding | 传输编码 | +| Cache-Control | 缓存控制 | +| Date | 日期时间 | + +#### 2.6.2 请求头部 + +| 头部 | 说明 | +|------|------| +| Host | 目标主机 | +| User-Agent | 客户端标识 | +| Accept | 可接受的媒体类型 | +| Accept-Encoding | 可接受的编码 | +| Accept-Language | 可接受的语言 | +| Cookie | Cookie 数据 | +| Referer | 来源页面 | +| Origin | 跨域请求源 | + +#### 2.6.3 响应头部 + +| 头部 | 说明 | +|------|------| +| Server | 服务器信息 | +| Content-Type | 内容类型 | +| Content-Length | 内容长度 | +| Set-Cookie | 设置 Cookie | +| Location | 重定向地址 | +| ETag | 资源版本标识 | +| Last-Modified | 最后修改时间 | +| Expires | 过期时间 | + +### 2.7 HTTPS 原理 + +``` +┌─────────────────────────────────────────────────────┐ +│ HTTPS 握手流程 │ +├─────────────────────────────────────────────────────┤ +│ │ +│ 1. Client Hello │ +│ ← 客户端发送支持的加密套件 │ +│ │ +│ 2. Server Hello + Certificate + Key Exchange │ +│ ← 服务器发送证书和公钥 │ +│ │ +│ 3. Certificate Verify + Finished │ +│ ← 客户端验证证书,生成预主密钥 │ +│ │ +│ 4. Finished │ +│ ← 服务器生成会话密钥 │ +│ │ +│ 5. 加密通信开始 │ +│ │ +│ 密码套件示例:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384│ +│ - ECDHE: 密钥交换算法 │ +│ - RSA: 签名算法 │ +│ - AES_256_GCM: 对称加密算法 │ +│ - SHA384: 消息认证码 │ +│ │ +└─────────────────────────────────────────────────────┘ +``` + +--- + +## 3. I/O 模型 + +### 3.1 I/O 模型概述 + +I/O 模型决定了服务器如何处理并发请求,主要有五种模型: + +### 3.2 阻塞 I/O(BIO) + +``` +┌─────────────────────────────────────────────────────┐ +│ 阻塞 I/O 模型 │ +├─────────────────────────────────────────────────────┤ +│ │ +│ 进程/线程 │ +│ │ │ +│ ▼ │ +│ ┌─────────────┐ │ +│ │ recv() │ ──→ 等待数据 │ +│ │ 阻塞 │ ←── 数据到达 │ +│ └─────────────┘ │ +│ │ │ +│ ▼ │ +│ 处理数据 │ +│ │ +│ 特点:每个连接一个线程,资源消耗大 │ +│ │ +└─────────────────────────────────────────────────────┘ +``` + +### 3.3 非阻塞 I/O(NIO) + +``` +┌─────────────────────────────────────────────────────┐ +│ 非阻塞 I/O 模型 │ +├─────────────────────────────────────────────────────┤ +│ │ +│ 进程/线程 │ +│ │ │ +│ ▼ │ +│ ┌─────────────┐ │ +│ │ recv() │ ──→ 立即返回(无数据) │ +│ │ 非阻塞 │ ←── 返回 EAGAIN │ +│ └─────────────┘ │ +│ │ │ +│ ▼ │ +│ 处理其他事务 │ +│ │ │ +│ ▼ │ +│ 再次调用 recv() │ +│ │ +│ 特点:需要轮询,CPU 空转 │ +│ │ +└─────────────────────────────────────────────────────┘ +``` + +### 3.4 I/O 多路复用(Select/Epoll) + +``` +┌─────────────────────────────────────────────────────┐ +│ I/O 多路复用模型 │ +├─────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────────────────────────────────────┐ │ +│ │ Select/Epoll │ │ +│ │ 监控多个 fd 集合 │ │ +│ └──────────────┬───────────────────────────────┘ │ +│ │ │ +│ ┌────────────┼────────────┐ │ +│ ▼ ▼ ▼ │ +│ ┌────┐ ┌────┐ ┌────┐ │ +│ │ fd1│ │ fd2│ │ fd3│ │ +│ └────┘ └────┘ └────┘ │ +│ │ +│ 特点:一个线程管理多个连接 │ +│ │ +└─────────────────────────────────────────────────────┘ +``` + +#### 3.4.1 Select 模型 + +```c +fd_set readfds; +FD_ZERO(&readfds); +FD_SET(fd1, &readfds); +FD_SET(fd2, &readfds); + +// 阻塞等待 +select(maxfd + 1, &readfds, NULL, NULL, NULL); + +// 遍历检查 +for (i = 0; i < maxfd; i++) { + if (FD_ISSET(i, &readfds)) { + // 处理可读事件 + } +} +``` + +#### 3.4.2 Epoll 模型 + +```c +// 创建 epoll 实例 +int epfd = epoll_create1(0); + +// 添加监听 +struct epoll_event ev; +ev.events = EPOLLIN; +ev.data.fd = fd1; +epoll_ctl(epfd, EPOLL_CTL_ADD, fd1, &ev); + +// 等待事件 +struct epoll_event events[1024]; +int n = epoll_wait(epfd, events, 1024, -1); + +// 处理事件 +for (int i = 0; i < n; i++) { + // 处理 events[i].data.fd +} +``` + +### 3.5 信号驱动 I/O(SIGIO) + +```c +// 设置信号处理函数 +signal(SIGIO, sigio_handler); + +// 设置异步 I/O +fcntl(fd, F_SETOWN, getpid()); +fcntl(fd, F_SETFL, O_ASYNC); + +// 信号处理 +void sigio_handler(int sig) { + // 处理 I/O 事件 +} +``` + +### 3.6 异步 I/O(AI/O) + +```c +struct aiocb cb; +bzero(&cb, sizeof(cb)); +cb.aio_fildes = fd; +cb.aio_buf = buffer; +cb.aio_nbytes = 1024; +cb.aio_sigevent.sigev_notify = SIGEV_THREAD; + +// 发起异步读 +aio_read(&cb); + +// 其他操作... + +// 等待完成 +aio_suspend(&cb, 1, NULL); +``` + +### 3.7 I/O 模型对比 + +| 模型 | 阻塞 | 同步/异步 | 性能 | +|------|------|------------|------| +| 阻塞 I/O | 是 | 同步 | 低 | +| 非阻塞 I/O | 否 | 同步 | 中 | +| I/O 多路复用 | 是 | 同步 | 高 | +| 信号驱动 I/O | 否 | 同步 | 高 | +| 异步 I/O | 否 | 异步 | 最高 | + +### 3.8 Nginx 使用的 I/O 模型 + +Nginx 默认使用 **Epoll**(Linux)和 **Kqueue**(FreeBSD/macOS)实现高效的事件驱动。 + +``` +┌─────────────────────────────────────────────────────┐ +│ Nginx 事件驱动架构 │ +├─────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────────────────────────┐ │ +│ │ Master Process │ │ +│ │ 加载配置 │ 启动 Worker 进程 │ │ +│ └──────────────────┬──────────────────────────┘ │ +│ │ │ +│ ┌──────────────────▼──────────────────────────┐ │ +│ │ Worker 进程 │ │ +│ │ │ │ +│ │ ┌─────────────────────────────────────┐ │ │ +│ │ │ Event Loop (Epoll/Kqueue) │ │ │ +│ │ │ │ │ │ +│ │ │ ┌─────┐ ┌─────┐ ┌─────┐ │ │ │ +│ │ │ │conn1│ │conn2│ │conn3│ ... │ │ │ +│ │ │ └─────┘ └─────┘ └─────┘ │ │ │ +│ │ └─────────────────────────────────────┘ │ │ +│ └─────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────┘ +``` + +--- + +## 4. Nginx 介绍和架构 + +### 4.1 Nginx 简介 + +Nginx(Engine X)是一个高性能的 HTTP 服务器和反向代理服务器,由俄罗斯工程师 Igor Sysoev 开发。 + +### 4.2 Nginx 特点 + +| 特点 | 说明 | +|------|------| +| 高并发 | 轻量级,高并发连接(支持 5 万+) | +| 低内存 | 内存占用极低(10MB/万连接) | +| 高可靠性 | 经过大量生产环境验证 | +| 热部署 | 不中断服务的情况下升级配置 | +| 模块化 | 丰富的官方和第三方模块 | +| 反向代理 | 支持 HTTP、HTTPS、TCP、UDP | +| 负载均衡 | 内置多种负载均衡策略 | +| 静态文件处理 | 高效的静态文件服务 | + +### 4.3 Nginx 架构 + +``` +┌─────────────────────────────────────────────────────┐ +│ Nginx 架构 │ +├─────────────────────────────────────────────────────┤ +│ │ +│ ┌────────────────────────────────────────────┐ │ +│ │ Master Process │ │ +│ │ 读取/验证配置 │ 管理 Worker │ 信号处理 │ │ +│ └─────────────────────┬──────────────────────┘ │ +│ │ │ +│ ┌─────────────────────▼──────────────────────┐ │ +│ │ Worker Process(多 worker) │ │ +│ │ │ │ +│ │ ┌──────────────────────────────────────┐ │ │ +│ │ │ Event Loop (Epoll) │ │ │ +│ │ │ │ │ │ +│ │ │ ┌────────┐ ┌────────┐ ┌────────┐ │ │ │ +│ │ │ │Request │ │ Request │ │Request │ │ │ │ +│ │ │ │ Handler│ │ Handler │ │ Handler│ │ │ │ +│ │ │ └────────┘ └────────┘ └────────┘ │ │ │ +│ │ └──────────────────────────────────────┘ │ │ +│ └────────────────────────────────────────────┘ │ +│ │ +│ ┌────────────────────────────────────────────┐ │ +│ │ Cache Manager/Loader │ │ +│ └────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────┘ +``` + +### 4.4 进程模型 + +```nginx +# nginx.conf +worker_processes auto; # Worker 进程数(auto = CPU 核心数) +worker_cpu_affinity auto; # CPU 亲和性 +worker_rlimit_nofile 65535; # 最大打开文件数 + +events { + worker_connections 10240; # 每个 worker 最大连接数 + use epoll; # 使用 epoll 事件模型 + multi_accept on; # 接受多个连接 +} +``` + +### 4.5 模块体系 + +Nginx 采用模块化设计,核心模块和功能模块: + +| 模块类型 | 示例 | 说明 | +|----------|------|------| +| 核心模块 | ngx_core | 核心功能 | +| 事件模块 | ngx_epoll_module | 事件处理 | +| HTTP 模块 | ngx_http_core | HTTP 处理 | +| 代理模块 | ngx_http_proxy | HTTP 反向代理 | +| 负载均衡 | ngx_http_upstream | 负载均衡 | +| 压缩模块 | ngx_http_gzip | 内容压缩 | +| SSL 模块 | ngx_http_ssl | HTTPS 支持 | +| 缓存模块 | ngx_http_proxy_cache | 响应缓存 | +| 日志模块 | ngx_http_log | 访问日志 | + +### 4.6 工作流程 + +``` +┌─────────────────────────────────────────────────────┐ +│ Nginx 请求处理流程 │ +├─────────────────────────────────────────────────────┤ +│ │ +│ 1. 接收请求 │ +│ ↓ │ +│ 2. HTTP 解析 │ +│ ↓ │ +│ 3. URI 匹配 location │ +│ ↓ │ +│ 4. 模块处理 │ +│ ↓ │ +│ 5. 过滤链处理 │ +│ ↓ │ +│ 6. 响应发送 │ +│ │ +└─────────────────────────────────────────────────────┘ +``` + +### 4.7 配置结构 + +```nginx +# 全局块 +user nginx; +worker_processes auto; +error_log /var/log/nginx/error.log; + +# events 块 +events { + worker_connections 10240; +} + +# http 块 +http { + # http 全局块 + include /etc/nginx/mime.types; + default_type application/octet-stream; + + # log 块 + log_format main '$remote_addr - $remote_user $request ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + access_log /var/log/nginx/access.log main; + + # server 块 + server { + listen 80; + server_name localhost; + + # location 块 + location / { + root /usr/share/nginx/html; + index index.html index.htm; + } + + location /api { + proxy_pass http://backend; + } + + error_page 404 /404.html; + } +} +``` + +--- + +## 5. Nginx 安装 + +### 5.1 YUM 安装(CentOS/RHEL) + +```bash +# 安装 EPEL 源 +yum install epel-release -y + +# 安装 Nginx +yum install nginx -y + +# 启动服务 +systemctl start nginx +systemctl enable nginx + +# 检查状态 +systemctl status nginx + +# 测试访问 +curl http://localhost +``` + +### 5.2 APT 安装(Debian/Ubuntu) + +```bash +# 更新源 +apt update + +# 安装 Nginx +apt install nginx -y + +# 启动服务 +systemctl start nginx +systemctl enable nginx + +# 检查版本 +nginx -v +``` + +### 5.3 编译安装 + +```bash +# 安装依赖 +yum install -y gcc make pcre pcre-devel zlib zlib-devel openssl openssl-devel + +# 下载源码 +wget https://nginx.org/download/nginx-1.24.0.tar.gz +tar -zxf nginx-1.24.0.tar.gz +cd nginx-1.24.0 + +# 配置 +./configure \ + --prefix=/usr/local/nginx \ + --sbin-path=/usr/local/nginx/sbin/nginx \ + --conf-path=/usr/local/nginx/conf/nginx.conf \ + --error-log-path=/var/log/nginx/error.log \ + --http-log-path=/var/log/nginx/access.log \ + --pid-path=/var/run/nginx.pid \ + --lock-path=/var/run/nginx.lock \ + --user=nginx \ + --group=nginx \ + --with-http_ssl_module \ + --with-http_v2_module \ + --with-http_realip_module \ + --with-http_stub_status_module \ + --with-http_gzip_static_module \ + --with-pcre \ + --with-stream \ + --with-stream_ssl_module + +# 编译安装 +make -j4 +make install + +# 创建用户 +useradd -M -s /sbin/nologin nginx + +# 启动 Nginx +/usr/local/nginx/sbin/nginx +``` + +### 5.4 Docker 安装 + +```bash +# 拉取镜像 +docker pull nginx:1.24 + +# 运行容器 +docker run -d \ + --name nginx \ + -p 80:80 \ + -p 443:443 \ + -v /data/nginx/conf:/etc/nginx/conf \ + -v /data/nginx/html:/usr/share/nginx/html \ + -v /data/nginx/logs:/var/log/nginx \ + nginx:1.24 + +# 测试配置 +docker exec nginx nginx -t +``` + +### 5.5 目录结构 + +```bash +/usr/local/nginx/ +├── sbin/ # 可执行文件 +│ └── nginx +├── conf/ # 配置文件 +│ ├── nginx.conf # 主配置文件 +│ ├── fastcgi_params +│ ├── scgi_params +│ └── uwsgi_params +├── html/ # 默认网页 +│ ├── index.html +│ └── 50x.html +└── logs/ # 日志目录 + ├── access.log + └── error.log +``` + +### 5.6 常用命令 + +```bash +# 检查配置文件 +nginx -t + +# 指定配置文件 +nginx -t -c /path/to/nginx.conf + +# 启动 +nginx + +# 重新加载配置 +nginx -s reload + +# 停止(快速) +nginx -s stop + +# 优雅停止 +nginx -s quit + +# 重新打开日志 +nginx -s reopen + +# 查看版本 +nginx -v + +# 详细版本信息 +nginx -V + +# 发送信号 +kill -s SIGTERM $(cat /var/run/nginx.pid) +kill -s SIGHUP $(cat /var/run/nginx.pid) +``` + +--- + +## 6. Nginx 各种模块实现 Web 服务 + +### 6.1 静态文件服务 + +```nginx +server { + listen 80; + server_name www.example.com; + + # 根目录 + root /usr/share/nginx/html; + + # 默认文件 + index index.html index.htm; + + # 访问控制 + location / { + allow 192.168.1.0/24; + deny all; + } + + # 禁止访问隐藏文件 + location ~ /\. { + deny all; + access_log off; + log_not_found off; + } + + # 缓存配置 + location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ { + expires 30d; + add_header Cache-Control "public, no-transform"; + } + + # 日志配置 + access_log /var/log/nginx/www_access.log combined; + error_log /var/log/nginx/www_error.log; +} +``` + +### 6.2 目录浏览 + +```nginx +server { + listen 80; + server_name files.example.com; + + location / { + root /data/files; + autoindex on; # 开启目录浏览 + autoindex_exact_size on; # 显示精确大小 + autoindex_localtime on; # 显示本地时间 + charset utf-8; # 字符集 + } +} +``` + +### 6.3 虚拟主机 + +```nginx +# 基于端口 +server { + listen 80; + server_name _; + root /data/site1; +} + +server { + listen 8080; + server_name _; + root /data/site2; +} + +# 基于域名 +server { + listen 80; + server_name www.site1.com; + root /data/site1; +} + +server { + listen 80; + server_name www.site2.com; + root /data/site2; +} +``` + +### 6.4 HTTPS 配置 + +```nginx +server { + listen 443 ssl http2; + server_name www.example.com; + + # 证书配置 + ssl_certificate /etc/nginx/ssl/example.com.crt; + ssl_certificate_key /etc/nginx/ssl/example.com.key; + + # 协议和加密套件 + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256; + ssl_prefer_server_ciphers on; + + # HSTS + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + + # OCSP Stapling + ssl_stapling on; + ssl_stapling_verify on; + resolver 8.8.8.8 8.8.4.4 valid=300s; + + # 会话复用 + ssl_session_timeout 1d; + ssl_session_cache shared:SSL:50m; + ssl_session_tickets off; + + root /usr/share/nginx/html; + index index.html; +} +``` + +### 6.5 访问控制 + +```nginx +# IP 黑名单 +location / { + deny 192.168.1.100; + deny 10.0.0.0/8; + allow all; +} + +# 用户认证 +location /admin { + auth_basic "Admin Area"; + auth_basic_user_file /etc/nginx/.htpasswd; +} + +# 防盗链 +location ~* \.(jpg|jpeg|png|gif)$ { + valid_referers none blocked www.example.com; + if ($invalid_referer) { + return 403; + } +} +``` + +### 6.6 限流配置 + +```nginx +# 连接数限制 +limit_conn_zone $binary_remote_addr zone=addr:10m; + +server { + limit_conn addr 10; +} + +# 请求速率限制 +limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s; + +server { + location /api { + limit_req zone=one burst=20 nodelay; + } +} + +# 带宽限制 +location /download { + limit_rate 1m; # 限速 1MB/s + limit_rate_after 10m; # 前 10MB 不限速 +} +``` + +### 6.7 Gzip 压缩 + +```nginx +http { + gzip on; + gzip_vary on; + gzip_proxied any; + gzip_comp_level 6; + gzip_min_length 1024; + gzip_types text/plain text/css text/xml application/json + application/javascript application/xml application/xml+rss; + + # 禁用老浏览器 + gzip_disable "MSIE [1-6]\."; +} +``` + +### 6.8 请求重写 + +```nginx +# 重定向 +server { + rewrite ^/old/(.*)$ /new/$1 permanent; + rewrite ^/redirect$ https://www.example.com permanent; + rewrite ^/temp$ https://www.example.com temporary; +} + +# 条件重写 +server { + if ($scheme != "https") { + return 301 https://$server_name$request_uri; + } +} + +# 隐藏 PHP 扩展名 +location / { + rewrite ^/([a-zA-Z0-9_-]+)\.php$ /$1 last; +} +``` + +### 6.9 状态监控 + +```nginx +location /nginx_status { + stub_status on; + access_log off; + allow 127.0.0.1; + allow 192.168.1.0/24; + deny all; +} + +# 返回示例 +# Active connections: 2 +# server accepts handled requests +# 10 10 100 +# Reading: 0 Writing: 1 Waiting: 0 +``` + +--- + +## 7. Nginx 实现 HTTP 负载均衡 + +### 7.1 负载均衡概述 + +Nginx 内置 Upstream 模块,支持多种负载均衡策略。 + +``` +┌─────────────────────────────────────────────────────┐ +│ Nginx 负载均衡架构 │ +├─────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────┐ │ +│ │ Client │ │ +│ └──────┬───────┘ │ +│ │ │ +│ ▼ │ +│ ┌──────────────┐ │ +│ │ Nginx │ │ +│ │ Upstream │ │ +│ └──────┬───────┘ │ +│ │ │ +│ ┌────┼────┬──────┐ │ +│ ▼ ▼ ▼ ▼ │ +│ ┌────┐┌────┐┌────┐┌────┐ │ +│ │ S1 ││ S2 ││ S3 ││ S4 │ Backend Servers │ +│ └────┘└────┘└────┘└────┘ │ +│ │ +└─────────────────────────────────────────────────────┘ +``` + +### 7.2 轮询负载均衡 + +```nginx +upstream backend { + server 192.168.1.10:8080; + server 192.168.1.11:8080; + server 192.168.1.12:8080; +} + +server { + location / { + proxy_pass http://backend; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } +} +``` + +### 7.3 加权轮询 + +```nginx +upstream backend { + server 192.168.1.10:8080 weight=5; + server 192.168.1.11:8080 weight=3; + server 192.168.1.12:8080 weight=2; +} +``` + +### 7.4 IP 哈希 + +```nginx +upstream backend { + ip_hash; + server 192.168.1.10:8080; + server 192.168.1.11:8080; + server 192.168.1.12:8080; +} +``` + +### 7.5 最少连接 + +```nginx +upstream backend { + least_conn; + server 192.168.1.10:8080; + server 192.168.1.11:8080; + server 192.168.1.12:8080; +} +``` + +### 7.6 最短响应时间 + +```nginx +upstream backend { + fair; + server 192.168.1.10:8080; + server 192.168.1.11:8080; + server 192.168.1.12:8080; +} +``` + +### 7.7 Hash 一致性 + +```nginx +upstream backend { + hash $request_uri; + server 192.168.1.10:8080; + server 192.168.1.11:8080; + server 192.168.1.12:8080; +} +``` + +### 7.8 健康检查 + +```nginx +upstream backend { + server 192.168.1.10:8080 max_fails=3 fail_timeout=30s; + server 192.168.1.11:8080 max_fails=3 fail_timeout=30s; + server 192.168.1.12:8080 down; # 标记为离线 + server 192.168.1.13:8080 backup; # 备份服务器 +} +``` + +### 7.9 完整示例 + +```nginx +http { + # 上游服务器组 + upstream api_backend { + least_conn; + + server 192.168.1.10:8080 weight=5 max_fails=3 fail_timeout=30s; + server 192.168.1.11:8080 weight=3 max_fails=3 fail_timeout=30s; + server 192.168.1.12:8080 weight=2 max_fails=3 fail_timeout=30s; + + keepalive 32; # 保持连接数 + } + + upstream static_backend { + server 192.168.1.20:80; + server 192.168.1.21:80; + } + + # 代理 API + server { + listen 80; + server_name api.example.com; + + location / { + proxy_pass http://api_backend; + + # 头部传递 + proxy_http_version 1.1; + 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_set_header X-Forwarded-Proto $scheme; + + # 连接超时 + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + + # 缓冲 + proxy_buffering on; + proxy_buffer_size 4k; + proxy_buffers 8 16k; + proxy_busy_buffers_size 24k; + } + } + + # 静态文件 + server { + listen 80; + server_name static.example.com; + + location / { + proxy_pass http://static_backend; + } + } +} +``` + +### 7.10 Lua 负载均衡 + +```lua +-- 使用 lua-resty-upstream 实现动态负载均衡 +location / { + content_by_lua_block { + local upstream = require "resty.upstream" + local up = upstream:new({ + name = "dynamic_backend", + servers = { + { addr = "192.168.1.10", weight = 10 }, + { addr = "192.168.1.11", weight = 10 }, + } + }) + + local server = up:select() + ngx.say(server) + } +} +``` + +--- + +## 8. Nginx 实现 TCP 反向代理 + +### 8.1 Stream 模块概述 + +Nginx 从 1.9.0 开始支持 TCP/UDP 反向代理,通过 `ngx_stream_module` 实现。 + +### 8.2 TCP 负载均衡 + +```nginx +stream { + # 日志配置 + log_format basic '$remote_addr [$time_local] ' + '$protocol $status $bytes_sent $bytes_received ' + '$session_time'; + + access_log /var/log/nginx/stream-access.log basic; + error_log /var/log/nginx/stream-error.log; + + # TCP 上游服务器组 + upstream mysql_backend { + least_conn; + + server 192.168.1.10:3306 weight=5; + server 192.168.1.11:3306 weight=3; + server 192.168.1.12:3306 backup; + } + + # TCP 代理配置 + server { + listen 3306; + proxy_pass mysql_backend; + proxy_connect_timeout 10s; + proxy_timeout 3600s; + + # TCP 相关配置 + proxy_buffer_size 16k; + proxy_download_rate 0; + proxy_upload_rate 0; + } + + # Redis 代理 + upstream redis_backend { + server 192.168.1.20:6379; + server 192.168.1.21:6379; + } + + server { + listen 6379; + proxy_pass redis_backend; + } +} +``` + +### 8.3 UDP 代理 + +```nginx +stream { + upstream dns_backend { + server 8.8.8.8:53; + server 8.8.4.4:53; + } + + server { + listen 53 udd; + proxy_pass dns_backend; + + # UDP 配置 + proxy_responses 2; + proxy_timeout 10s; + } +} +``` + +### 8.4 TCP 健康检查 + +```nginx +stream { + # 简单健康检查 + upstream backend { + server 192.168.1.10:8080; + server 192.168.1.11:8080; + } + + # 代理配置 + server { + listen 8080; + proxy_connect_timeout 1s; + proxy_timeout 10s; + } +} +``` + +### 8.5 SNI 分离(TCP 层) + +```nginx +stream { + # 基于 SNI 的 TCP 代理 + map $ssl_preread_server_name $backend { + www.example.com 192.168.1.10:443; + api.example.com 192.168.1.11:443; + default 192.168.1.20:443; + } + + server { + listen 443; + ssl_preread on; + proxy_pass $backend; + } +} +``` + +--- + +## 9. Nginx 实现 FastCGI 反向代理 + +### 9.1 FastCGI 概述 + +FastCGI 是 Web 服务器与应用程序通信的协议,Nginx 通过 `ngx_http_fastcgi_module` 实现。 + +### 9.2 PHP-FPM 配置 + +```nginx +server { + listen 80; + server_name www.example.com; + + root /data/www; + index index.php index.html; + + location / { + try_files $uri $uri/ /index.php?$query_string; + } + + # PHP-FPM 代理 + location ~ \.php$ { + fastcgi_pass 127.0.0.1:9000; + fastcgi_index index.php; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + + # 传递 FastCGI 参数 + include fastcgi_params; + + # 超时配置 + fastcgi_connect_timeout 60s; + fastcgi_send_timeout 60s; + fastcgi_read_timeout 60s; + + # 缓冲配置 + fastcgi_buffer_size 128k; + fastcgi_buffers 4 128k; + fastcgi_busy_buffers_size 256k; + fastcgi_max_temp_file_size 0; + } + + # 拒绝访问隐藏文件 + location ~ /\. { + deny all; + } +} +``` + +### 9.3 fastcgi_params 标准参数 + +```nginx +# 默认参数 +fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; +fastcgi_param QUERY_STRING $query_string; +fastcgi_param REQUEST_METHOD $request_method; +fastcgi_param CONTENT_TYPE $content_type; +fastcgi_param CONTENT_LENGTH $content_length; + +fastcgi_param SCRIPT_NAME $fastcgi_script_name; +fastcgi_param REQUEST_URI $request_uri; +fastcgi_param DOCUMENT_URI $document_uri; +fastcgi_param DOCUMENT_ROOT $document_root; +fastcgi_param SERVER_PROTOCOL $server_protocol; +fastcgi_param REQUEST_SCHEME $scheme; +fastcgi_param HTTPS $https if_not_empty; + +fastcgi_param GATEWAY_INTERFACE CGI/1.1; +fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; + +fastcgi_param REMOTE_ADDR $remote_addr; +fastcgi_param REMOTE_PORT $remote_port; +fastcgi_param SERVER_ADDR $server_addr; +fastcgi_param SERVER_PORT $server_port; +fastcgi_param SERVER_NAME $server_name; +``` + +### 9.4 FastCGI 缓存 + +```nginx +http { + # FastCGI 缓存配置 + fastcgi_cache_path /tmp/fastcgi_cache levels=1:2 + keys_zone=php_cache:10m + inactive=60m + max_size=1g; + + server { + # 开启 FastCGI 缓存 + location ~ \.php$ { + fastcgi_pass 127.0.0.1:9000; + fastcgi_index index.php; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + include fastcgi_params; + + # 启用缓存 + fastcgi_cache php_cache; + fastcgi_cache_valid 200 60m; + fastcgi_cache_valid 404 1m; + fastcgi_cache_min_uses 1; + fastcgi_cache_use_stale error timeout http_500; + + # 不缓存的请求 + fastcgi_cache_bypass $http_cookie; + fastcgi_no_cache $http_cookie $http_authorization; + + # 缓存 key + fastcgi_cache_key "$scheme$request_method$host$request_uri"; + } + } +} +``` + +### 9.5 多 PHP-FPM 负载均衡 + +```nginx +upstream php_backend { + least_conn; + server 127.0.0.1:9000 weight=5; + server 127.0.0.1:9001 weight=3; + server 127.0.0.1:9002 backup; +} + +server { + location ~ \.php$ { + fastcgi_pass php_backend; + fastcgi_index index.php; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + include fastcgi_params; + } +} +``` + +### 9.6 UWSGI 反向代理(Python) + +```nginx +server { + listen 80; + server_name python.example.com; + + location / { + uwsgi_pass 127.0.0.1:8000; + include uwsgi_params; + + uwsgi_param SCRIPT_NAME /app; + uwsgi_param HOME /app; + uwsgi_param PYTHONPATH /app; + } +} +``` + +### 9.7 SCGI 反向代理 + +```nginx +server { + location / { + scgi_pass 127.0.0.1:9000; + include scgi_params; + scgi_param SCRIPT_NAME $fastcgi_script_name; + } +} +``` + +--- + +## 10. Nginx 二次开发版 + +### 10.1 主流二次开发版 + +| 版本 | 说明 | 特点 | +|------|------|------| +| **Tengine** | 阿里巴巴开源 | 动态模块加载、组合SSI、内存优化 | +| **OpenResty** | 基于 Nginx + Lua | 强大的 Lua 脚本能力、高性能 API 网关 | +| **Apache** | 不适用 | 多进程模型 | +| **LiteSpeed** | 商业版本 | Apache 兼容、性能优异 | + +### 10.2 Tengine + +#### 10.2.1 Tengine 特点 + +- 继承 Nginx 所有特性 +- 动态模块加载(DSO) +- 组合 SSI(Server Side Include) +- 内存优化:更低的内存占用 +- 更好的负载均衡算法 +- 更完善的监控和统计 + +#### 10.2.2 Tengine 安装 + +```bash +# 安装依赖 +yum install gcc make zlib zlib-devel pcre pcre-devel openssl openssl-devel + +# 下载 Tengine +wget https://tengine.taobao.org/download/tengine-2.3.3.tar.gz +tar -zxf tengine-2.3.3.tar.gz +cd tengine-2.3.3 + +# 编译安装 +./configure --prefix=/usr/local/tengine +make -j4 +make install +``` + +#### 10.2.3 Tengine 特有配置 + +```nginx +# 动态模块加载 +load_module /usr/local/tengine/modules/ngx_http_upstream_consistent_hash_module.so; + +# 组合 SSI +ssi on; +ssi_types text/html; + +# 内存优化 +tengine_worker_processes auto; +tengine_worker_rlimit_nofile 102400; +tengine_multi_accept on; +tengine_http_upstream_check_interval=5s; +tengine_http_upstream_check_timeout=2s; +``` + +### 10.3 OpenResty + +#### 10.3.1 OpenResty 特点 + +- 基于 Nginx + LuaJIT +- 丰富的 Lua 库(lua-resty-*) +- 高性能 API 网关 +- 实时请求处理 +- 灵活的扩展能力 + +#### 10.3.2 OpenResty 安装 + +```bash +# 添加仓库(CentOS 7) +yum install yum-utils +yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo + +# 安装 +yum install openresty -y + +# 启动 +systemctl start openresty +``` + +#### 10.3.3 OpenResty 使用 + +```lua +-- hello.lua +ngx.say("Hello, OpenResty!") + +-- nginx.conf +location /hello { + content_by_lua_file /usr/local/openresty/lua/hello.lua; +} + +-- API 示例 +location /api/user { + content_by_lua_block { + local cjson = require "cjson" + + -- 获取请求参数 + local args = ngx.req.get_uri_args() + + -- 获取请求头 + local headers = ngx.req.get_headers() + + -- 响应 + ngx.status = ngx.HTTP_OK + ngx.say(cjson.encode({ + code = 0, + message = "success", + data = { user_id = args.id or "unknown" } + })) + ngx.exit(ngx.HTTP_OK) + } +} +``` + +#### 10.3.4 OpenResty 限流示例 + +```lua +-- rate_limit.lua +local limit = require("resty.limit.count") + +-- 每分钟 100 次 +local lim, err = limit.new("my_limit", 100, 60) + +if not lim then + ngx.exit(500) +end + +local key = ngx.var.binary_remote_addr +local delay, err = lim:incoming(key, true) + +if not delay then + if err == "rejected" then + ngx.exit(429) + end + ngx.exit(500) +end +``` + +### 10.4 选择建议 + +| 场景 | 推荐版本 | +|------|----------| +| 传统 Web 服务 | Nginx 官方版 | +| 需要动态模块 | Tengine | +| API 网关/实时处理 | OpenResty | +| 需要 Lua 扩展 | OpenResty | +| 阿里系技术栈 | Tengine | + +--- + +## 11. Nginx 高并发 Linux 内核优化 + +### 11.1 系统级优化 + +#### 11.1.1 文件描述符限制 + +```bash +# 修改系统限制 +echo "* soft nofile 65535" >> /etc/security/limits.conf +echo "* hard nofile 65535" >> /etc/security/limits.conf + +# 重启生效 +reboot +``` + +#### 11.1.2 网络连接优化 + +```bash +# /etc/sysctl.conf + +# TCP 连接优化 +net.core.somaxconn = 65535 +net.core.netdev_max_backlog = 65535 +net.ipv4.tcp_max_syn_backlog = 65535 + +# TCP 连接回收 +net.ipv4.tcp_fin_timeout = 30 +net.ipv4.tcp_keepalive_time = 1200 +net.ipv4.tcp_keepalive_probes = 3 +net.ipv4.tcp_keepalive_intvl = 15 + +# TIME_WAIT 优化 +net.ipv4.tcp_tw_reuse = 1 +net.ipv4.tcp_tw_recycle = 1 + +# 内存优化 +net.core.rmem_max = 16777216 +net.core.wmem_max = 16777216 +net.ipv4.tcp_rmem = 4096 87380 16777216 +net.ipv4.tcp_wmem = 4096 87380 16777216 + +# 生效配置 +sysctl -p +``` + +### 11.2 Nginx 配置优化 + +```nginx +# /usr/local/nginx/conf/nginx.conf + +# Worker 进程优化 +worker_processes auto; +worker_cpu_affinity auto; +worker_rlimit_nofile 65535; + +# 事件处理优化 +events { + worker_connections 10240; + use epoll; + multi_accept on; +} + +# Gzip 压缩优化 +gzip on; +gzip_min_length 1024; +gzip_types text/plain text/css application/json application/javascript; + +# 连接复用 +upstream backend { + server 192.168.1.10:8080; + keepalive 32; # 长连接数 +} + +server { + # 连接配置 + keepalive_timeout 65; + keepalive_requests 1000; + + # 缓冲区优化 + client_body_buffer_size 128k; + client_max_body_size 50m; + proxy_buffer_size 128k; + proxy_buffers 4 256k; + proxy_busy_buffers_size 256k; + + # 发送优化 + sendfile on; + tcp_nopush on; + tcp_nodelay on; + + # 缓冲写入 + aio on; + directio 512; +} +``` + +### 11.3 完整优化配置示例 + +```nginx +# nginx.conf - 高性能配置 + +user nginx; +worker_processes auto; +worker_cpu_affinity auto; +worker_rlimit_nofile 65535; +error_log /var/log/nginx/error.log warn; + +events { + worker_connections 20480; + use epoll; + multi_accept on; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + # 日志格式 + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for" ' + 'rt=$request_time uct=$upstream_connect_time ' + 'uht=$upstream_header_time urt=$upstream_response_time'; + + access_log /var/log/nginx/access.log main; + + # 基础优化 + sendfile on; + tcp_nopush on; + tcp_nodelay on; + + keepalive_timeout 65; + keepalive_requests 1000; + + # Gzip + gzip on; + gzip_vary on; + gzip_proxied any; + gzip_comp_level 6; + gzip_min_length 1024; + gzip_types text/plain text/css text/xml application/json + application/javascript application/xml; + + # 上游连接池 + upstream backend { + server 192.168.1.10:8080 max_conns=1000; + server 192.168.1.11:8080 max_conns=1000; + + keepalive 64; + } + + # 代理配置 + proxy_http_version 1.1; + proxy_set_header Connection ""; + + # 缓存配置 + proxy_cache_path /tmp/nginx_cache + levels=1:2 + keys_zone=api_cache:100m + inactive=60m + max_size=10g; + + server { + listen 80; + server_name _; + + location / { + proxy_pass http://backend; + + proxy_connect_timeout 10s; + proxy_send_timeout 30s; + proxy_read_timeout 30s; + + proxy_buffering on; + proxy_buffer_size 32k; + proxy_buffers 8 64k; + } + } +} + +# TCP 代理优化 +stream { + log_format stream '$remote_addr [$time_local] ' + '$protocol $status $bytes_sent $bytes_received ' + '$session_time'; + + access_log /var/log/nginx/stream.log stream; + + upstream mysql { + least_conn; + + server 192.168.1.20:3306 weight=5; + server 192.168.1.21:3306 weight=3; + + keepalive 32; + } + + server { + listen 3306; + proxy_pass mysql; + + proxy_connect_timeout 5s; + proxy_timeout 3600s; + + proxy_buffer_size 16k; + } +} +``` + +### 11.4 内核参数参考表 + +| 参数 | 默认值 | 推荐值 | 说明 | +|------|--------|--------|------| +| `fs.file-max` | 取决于系统 | 65535 | 系统最大文件数 | +| `net.core.somaxconn` | 128 | 65535 | socket 监听队列 | +| `net.core.netdev_max_backlog` | 1000 | 65535 | 网络设备队列 | +| `net.ipv4.tcp_max_syn_backlog` | 128 | 65535 | SYN 连接队列 | +| `net.ipv4.tcp_fin_timeout` | 60 | 30 | FIN_WAIT 超时 | +| `net.ipv4.tcp_keepalive_time` | 7200 | 1200 | 保活时间 | +| `net.ipv4.tcp_tw_reuse` | 0 | 1 | 复用 TIME_WAIT | +| `net.ipv4.ip_local_port_range` | 32768 60999 | 1024 65535 | 端口范围 | + +### 11.5 性能监控 + +```bash +# 查看 Nginx 连接状态 +netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' + +# 查看 Nginx 进程数 +ps -ef | grep nginx | wc -l + +# 查看 Nginx 内存使用 +ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%mem | head -n 10 + +# 查看 socket 统计 +ss -s + +# 查看 TCP 状态 +cat /proc/net/snmp + +# 查看连接数 +curl http://localhost/nginx_status +``` + +--- + +## 附录 + +### 常用命令速查 + +| 命令 | 说明 | +|------|------| +| `nginx -t` | 测试配置 | +| `nginx -s reload` | 重新加载 | +| `nginx -s stop` | 停止 | +| `nginx -v` | 查看版本 | +| `nginx -V` | 详细版本信息 | + +### 配置文件参数速查 + +| 参数 | 说明 | +|------|------| +| `worker_processes` | Worker 进程数 | +| `worker_connections` | 单 Worker 连接数 | +| `listen` | 监听端口 | +| `server_name` | 域名 | +| `proxy_pass` | 代理地址 | +| `root` | 根目录 | +| `index` | 默认文件 | + +### 常用模块 + +| 模块 | 说明 | +|------|------| +| `ngx_http_core_module` | 核心模块 | +| `ngx_http_proxy_module` | HTTP 代理 | +| `ngx_http_upstream_module` | 负载均衡 | +| `ngx_http_rewrite_module` | URL 重写 | +| `ngx_http_gzip_module` | Gzip 压缩 | +| `ngx_http_ssl_module` | SSL/TLS | +| `ngx_stream_module` | TCP/UDP 代理 | + +--- + +*文档创建时间:2024年* \ No newline at end of file