数据库与自动化运维
第四篇:数据库与自动化运维
本篇从"为什么需要数据库"这个根本问题出发,逐步带你掌握 MySQL 关系型数据库、Redis 内存数据库,以及自动化运维的核心技能。每一个知识点都遵循"遇到问题 -> 分析原因 -> 动手解决"的思路。
目录
- 第一部分:MySQL 数据库
-
- 数据库介绍 | 2. MySQL 安装 | 3. MySQL 架构 | 4. SQL 语句
-
- 存储引擎 | 6. 用户及权限 | 7. 备份与恢复 | 8. 主从复制
-
- Mycat 中间件 | 10. MHA 高可用 | 11. LAMP 架构
-
- 第二部分:Redis 内存数据库
-
- Redis 介绍 | 2. Redis 部署 | 3. 主从复制 | 4. 哨兵集群 | 5. Cluster
-
- 第三部分:自动化运维简介
-
- Ansible | 2. Ansible Python API | 3. PXE+Kickstart | 4. OpenStack
-
第一部分:MySQL 数据库
1. 数据库介绍:为什么不能只用文件存数据?
问题场景
想象你是一个班主任,手里有一份 Excel 表格记录全班同学的成绩。如果只有你一个人用,文件就够了。但如果年级组长、各科老师、家长都要同时查看和修改呢?
- 文件无法多人同时操作(并发问题)
- 文件格式五花八门(格式不统一)
- 电脑坏了文件就没了(安全问题)
- 想查"年级前50名"要手动筛选半天(查询效率低)
解决方案:数据库管理系统(DBMS)
生活类比:数据库就像一个超大型的"智能档案柜"。
| 传统文件管理 | 数据库管理 |
|---|---|
| 一个 Excel 文件 | 一张"表"(Table) |
| 一个文件夹 | 一个"数据库"(Database) |
| 手动查找 | 用 SQL 语句秒级查询 |
| 只能一个人编辑 | 支持多人并发访问 |
| 没有权限控制 | 精确控制谁能看、谁能改 |
关系型数据库 vs 非关系型数据库
| 类型 | 代表产品 | 类比 | 适用场景 |
|---|---|---|---|
| 关系型数据库 | MySQL、Oracle、PostgreSQL | Excel 多表关联 | 结构化数据、事务处理 |
| 非关系型数据库 | Redis、MongoDB | 便签纸 / 便利贴 | 缓存、实时数据、灵活结构 |
关系模型:由数学家 Edgar Codd 于 1970 年提出。核心思想是用"二维表格"来表示数据,表与表之间通过"关系"(外键)关联。
MySQL vs MariaDB
MySQL 最初由瑞典 MySQL AB 公司开发,2008 年被 Sun 收购,2009 年 Sun 又被 Oracle 收购。原作者 Michael Widenius 因担心 Oracle 限制开源性,于 2009 年创建了分支项目 MariaDB(以女儿 Maria 命名)。
| 对比项 | MySQL | MariaDB |
|---|---|---|
| 维护方 | Oracle 公司 | 社区驱动 |
| 许可证 | GPL / 商业双许可 | GPL |
| 默认引擎 | InnoDB | InnoDB(也支持 Aria) |
| 适用场景 | 企业级生产环境 | 社区和开源项目 |
小贴士:在 CentOS/RHEL 7+ 中,默认数据库已从 MySQL 换成 MariaDB,两者高度兼容。
2. MySQL 安装:从零搭建你的第一个数据库
| 安装方式 | 优点 | 缺点 | 适合谁 |
|---|---|---|---|
| yum/rpm | 快速简单 | 路径固定 | 初学者 |
| 源码编译 | 完全自定义 | 步骤多 | 生产环境 |
方式一:YUM 安装(推荐入门)
wget https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm
rpm -ivh mysql57-community-release-el7-11.noarch.rpm
yum install mysql-community-server -y
systemctl start mysqld && systemctl enable mysqld
# 获取临时密码
grep 'temporary password' /var/log/mysqld.log
# 登录并密码
mysql -u root -p
ALTER USER 'root'@'localhost' IDENTIFIED BY 'YourNewPass123!';
关键路径:/etc/my.cnf(配置文件) | /var/lib/mysql/(数据) | /var/log/mysqld.log(日志)
方式二:源码编译
yum install cmake gcc gcc-c++ ncurses-devel openssl-devel -y
wget https://downloads.mysql.com/archives/get/p/23/file/mysql-boost-5.7.38.tar.gz
tar -xvf mysql-boost-5.7.38.tar.gz -C /usr/local/src/
cd /usr/local/src/mysql-5.7.38/
cmake \
-DCMAKE_INSTALL_PREFIX=/usr/local/mysql \
-DMYSQL_DATADIR=/usr/local/mysql/data \
-DDEFAULT_CHARSET=utf8 \
-DDOWNLOAD_BOOST=1 -DWITH_BOOST=/usr/local/boost
make && make install
mkdir -p /usr/local/mysql/data
chown -R mysql.mysql /usr/local/mysql/
/usr/local/mysql/bin/mysqld --initialize --user=mysql --datadir=/usr/local/mysql/data
/usr/local/mysql/bin/mysqld_safe --user=mysql &
常见错误:boost not found -> 加 -DDOWNLOAD_BOOST 参数;Curses not found -> yum install ncurses-devel;WITH_SSL -> yum install openssl-devel。
初始化后基本操作
SHOW DATABASES;
CREATE DATABASE mydb CHARACTER SET utf8;
USE mydb;
CREATE TABLE student (id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(30) NOT NULL, age TINYINT UNSIGNED);
INSERT INTO student (name, age) VALUES ('张三', 18);
SELECT * FROM student;
互动问题:学校 2000 名学生,用 Excel 和数据库分别查"年龄>17且姓张的学生"各需要多久?(提示:数据库的索引就像书的目录,可以秒级定位。)
3. MySQL 架构:一条 SQL 语句的旅程
输入 SELECT * FROM student WHERE age > 17; 时,MySQL 内部经历三层处理:
客户端(顾客点菜)
|
v
+-------------------------------+
| 连接层 (Connection Layer) | | 服务员:验证身份、权限检查
+-------------------------------+
| SQL 层 (Server Layer) | 厨师长:解析 SQL、优化执行计划
| - 查询解析器 - 查询优化器 |
+-------------------------------+
| 存储引擎层 (Storage Engine) | 厨师:取食材、做菜
| InnoDB / MyISAM / Memory |
+-------------------------------+
|
v
磁盘 / 内存(食材仓库)
关键理解:存储引擎是"插件式"的,同一张表可以选不同引擎,就像餐厅可以换厨师。
4. SQL 语句:和数据库对话的语言
SQL 按功能分为四大类:
| 类别 | 全称 | 命令 | 用途 |
|---|---|---|---|
| DDL | 数据定义语言 | CREATE, ALTER, DROP | 建库建表 |
| DML | 数据操作语言 | INSERT, UPDATE, DELETE | 增删改 |
| DQL | 数据查询语言 | SELECT | 查询 |
| DCL | 数据控制语言 | GRANT, REVOKE | 权限 |
4.1 DDL - 建库建表
CREATE DATABASE school CHARACTER SET utf8;
SHOW DATABASES;
ALTER DATABASE school CHARACTER SET utf8mb4;
DROP DATABASE school;
USE school;
CREATE TABLE class (
class_id INT PRIMARY KEY AUTO_INCREMENT,
class_name VARCHAR(30) NOT NULL, teacher VARCHAR(20)
);
CREATE TABLE student (
sid INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(30) NOT NULL,
age TINYINT UNSIGNED DEFAULT 18,
gender ENUM('M','F') NOT NULL DEFAULT 'M',
score FLOAT(5,2), class_id INT, email VARCHAR(50) UNIQUE,
jointime DATETIME NOT NULL,
FOREIGN KEY (class_id) REFERENCES class(class_id)
);
DESC student;
SHOW CREATE TABLE student\G
ALTER TABLE student ADD phone CHAR(11) AFTER email;
ALTER TABLE student DROP phone;
ALTER TABLE student MODIFY age SMALLINT UNSIGNED;
CREATE INDEX idx_name ON student(name);
CREATE UNIQUE INDEX idx_email ON student(email);
DROP INDEX idx_name ON student;
数据类型速查:
| 类型 | 字节 | 常用场景 |
|---|---|---|
| TINYINT | 1 | 年龄、状态码 |
| INT | 4 | 主键、ID |
| BIGINT | 8 | 大表主键 |
| FLOAT | 4 | 一般数值(7位有效) |
| DECIMAL | 可变 | 金额(无精度损失) |
| CHAR(n) | 固定 n | 身份证号 |
| VARCHAR(n) | 可变 | 姓名、地址 |
| DATE/DATETIME | 3/8 | 日期时间 |
| ENUM | - | 单选(性别) |
| SET | - | 多选(爱好) |
FLOAT 精度陷阱:FLOAT(10,2) 存 697302.68,取出可能变 697302.69!金额务必用 DECIMAL。
4.2 DML - 增删改
INSERT INTO student (name, age, gender, score, class_id, jointime) VALUES ('张三', 18, 'M', 95.5, 1, NOW());
INSERT INTO student (name, age, gender, score, class_id, jointime) VALUES
('李四', 17, 'F', 88.0, 1, NOW()),
('王五', 19, 'M', 92.3, 2, NOW());
UPDATE student SET score = 99.0 WHERE sid = 1;
DELETE FROM student WHERE sid = 4;
-- 警告:UPDATE/DELETE 不加 WHERE 会影响所有行!
4.3 SELECT 查询(重点)
SELECT * FROM student;
SELECT name, age, score FROM student;
SELECT DISTINCT class_id FROM student;
SELECT name FROM student LIMIT 5; -- 前5条
SELECT name FROM student LIMIT 5, 5; -- 第6~10条
SELECT * FROM student WHERE age > 18;
SELECT * FROM student WHERE age BETWEEN 17 AND 19;
SELECT * FROM student WHERE gender='M' AND score > 90;
SELECT * FROM student WHERE class_id IN (1, 2, 3);
SELECT * FROM student WHERE name LIKE '张%'; -- % 匹配多个字符
SELECT * FROM student WHERE name LIKE '_三%'; -- _ 匹配一个字符
SELECT * FROM student WHERE email IS NULL;
SELECT * FROM student ORDER BY score DESC;
-- 分组 + 聚合
SELECT class_id,
MAX(score) max_score, MIN(score) min_score,
AVG(score) avg_score, COUNT(*) cnt
FROM student GROUP BY class_id;
-- HAVING(分组后过滤)
SELECT class_id, AVG(score) avg_score
FROM student GROUP BY class_id HAVING avg_score > 90;
-- 子查询:找每个班最高分的同学
SELECT name, score, class_id FROM student
WHERE score IN (SELECT MAX(score) FROM student GROUP BY class_id);
4.4 多表联查(JOIN)
类比:通过"班级编号"把"成绩表"和"班级表"关联起来。
-- 内连接:只返回匹配的行
SELECT e.emp_name, d.dept_name
FROM employee e INNER JOIN department d ON e.dept_id = d.dept_id;
-- 左外连接:左表所有行 + 右表匹配(不匹配为 NULL)
SELECT e.emp_name, d.dept_name
FROM employee e LEFT JOIN department d ON e.dept_id = d.dept_id;
-- 右外连接:右表所有行 + 左表匹配
SELECT e.emp_name, d.dept_name
FROM employee e RIGHT JOIN department d ON e.dept_id = d.dept_id;
-- 综合:求各部门最高薪水员工
SELECT e.emp_name, e.salary, d.dept_name
FROM employee e INNER JOIN department d ON e.dept_id = d.dept_id
WHERE e.salary IN (SELECT MAX(salary) FROM employee GROUP BY dept_id);
注意:JOIN 本质是集合论中"笛卡尔积"再条件筛选。内连接=交集,左连接=左集合+交集补NULL。和数学集合运算一脉相承。
5. 存储引擎:InnoDB 与 MyISAM 该怎么选?
| 特性 | InnoDB | MyISAM |
|---|---|---|
| 事务 | 支持(ACID) | 不支持 |
| 锁 | 行级锁 | 表级锁 |
| 外键 | 支持 | 不支持 |
| 崩溃恢复 | 支持 | 不支持 |
| 适用 | 高并发、需要事务 | 读多写少 |
SHOW ENGINES\G
CREATE TABLE t1 (id INT) ENGINE=InnoDB;
CREATE TABLE t2 (id INT) ENGINE=MyISAM;
事务详解
事务像"银行转账"——要么完整执行,要么完全不做。
START TRANSACTION;
UPDATE account SET balance = balance - 2000 WHERE name = '张三';
UPDATE account SET balance = balance + 2000 WHERE name = '李四';
COMMIT; -- 正常则提交
ROLLBACK; -- 出错则回滚
-- 保存点
SAVEPOINT sp1;
ROLLBACK TO sp1; -- 只回滚到保存点
ACID 特性:
| 特性 | 含义 | 类比 |
|---|---|---|
| Atomicity(原子性) | 全做或全不做 | 考试卷:交或不交 |
| Consistency(一致性) | 数据始终一致 | 转账前后总额不变 |
| Isolation(隔离性) | 事务互不干扰 | 考场里各做各的 |
| Durability(持久性) | 提交后永久保存 | 交了卷不能改 |
外键
CREATE TABLE dept (did INT PRIMARY KEY, dname VARCHAR(20)) ENGINE=InnoDB;
CREATE TABLE emp (
id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(20), did INT,
FOREIGN KEY (did) REFERENCES dept(did)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB;
ALTER TABLE emp DROP FOREIGN KEY emp_ibfk_1;
6. 用户及权限管理:谁能看?谁能改?
-- 创建用户
CREATE USER 'teacher'@'localhost' IDENTIFIED BY 'Teach2024!';
CREATE USER 'student'@'192.168.1.%' IDENTIFIED BY 'Stu2024!';
CREATE USER 'admin'@'%' IDENTIFIED BY 'Admin2024!';
-- 授权
GRANT SELECT ON school.* TO 'teacher'@'localhost';
GRANT ALL PRIVILEGES ON *.* TO 'admin'@'%';
GRANT SELECT(name, age) ON school.student TO 'user1'@'localhost';
-- 撤销
REVOKE INSERT ON school.* FROM 'teacher'@'localhost';
FLUSH PRIVILEGES;
-- 查看权限
SHOW GRANTS FOR 'teacher'@'localhost'\G
权限存储:全局 mysql.user | 库级 mysql.db | 表级 mysql.tables_priv | 列级 mysql.columns_priv
忘记密码
systemctl stop mysqld
mysqld_safe --skip-grant-tables --user=mysql &
mysql -u root
UPDATE mysql.user SET authentication_string=PASSWORD('NewPass!') WHERE User='root';
FLUSH PRIVILEGES;
systemctl restart mysqld
7. 备份与恢复:数据丢了怎么办?
| 对比项 | 逻辑备份(mysqldump) | 物理备份(XtraBackup) |
|---|---|---|
| 备份内容 | SQL 语句 | 数据文件 |
| 速度 | 慢 | 快 |
| 跨平台 | 可以 | 不行 |
| 恢复速度 | 慢 | 快 |
mysqldump
# 全库
mysqldump -u root -p --all-databases > /backup/all_$(date +%F).sql
# 单库
mysqldump -u root -p --databases school > /backup/school.sql
# 指定表
mysqldump -u root -p school student class > /backup/tables.sql
# 生产推荐
mysqldump -u root -p \
--single-transaction --master-data=2 --flush-logs \
--all-databases > /backup/full_$(date +%F).sql
恢复:mysql -u root -p < /backup/all.sql
binlog 增量恢复
[mysqld]
server-id = 1
log-bin = /mysql-log/master
binlog-format = row
mysqlbinlog -v /mysql-log/master.00001 # 查看
mysqlbinlog --start-position=154 --stop-position=1024 \
/mysql-log/master.0001 | mysql -u root -p # 按位置恢复
mysqlbinlog --start-datetime="2024-01-15 10:00:00" \
/mysql-log/master.0001 | mysql -u root -p # 按时间恢复
完整恢复流程(误删数据后):
- 先恢复全量备份:
mysql -u root -p < /backup/full.sql - 用 binlog 恢复从备份到误操作之间的增量
- 跳过误操作,继续恢复后续 binlog
备份脚本
#!/bin/bash
BACKUP_DIR="/backup/mysql"
DATE=$(date +%F)
mkdir -p $BACKUP_DIR
mysqldump -u root -p'YourPass' \
--single-transaction --master-data=2 --flush-logs \
--all-databases > ${BACKUP_DIR}/full_${DATE}.sql
find $BACKUP_DIR -name "*.sql" -mtime +30 -delete
echo "[$DATE] Done." >> /var/log/mysql_backup.log
8. 主从复制(AB复制):让数据自动抄写
原理
Master Slave
binlog --- IO Thread ---> relay-log --> SQL Thread(执行SQL)
- Master 的 IO 线程把 binlog 发给 Slave
- Slave 的 IO 线程写入 relay-log(中继日志)
- Slave 的 SQL 线程读取 relay-log 并执行
配置
Master (/etc/my.cnf):
[mysqld]
server-id = 1
log-bin = master
binlog-format = row
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.10.2' IDENTIFIED BY 'Repl2024!';
SHOW MASTER STATUS\G -- 记下 File 和 Position
Slave (/etc/my.cnf):
[mysqld]
server-id = 2
STOP SLAVE;
CHANGE MASTER TO
MASTER_HOST='192.168.10.1', MASTER_USER='repl',
MASTER_PASSWORD='Repl2024!',
MASTER_LOG_FILE='master.0001', MASTER_LOG_POS=154;
START SLAVE;
SHOW SLAVE STATUS\G
-- 必须确认:Slave_IO_Running: Yes && Slave_SQL_Running: Yes
半同步复制
Master 提交事务后至少等一个 Slave 确认收到 binlog:
-- Master
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
SET GLOBAL rpl_semi_sync_master_enabled = 1;
SET GLOBAL rpl_semi_sync_master_timeout = 1000; -- 超时降级为异步
-- Slave
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
SET GLOBAL rpl_semi_sync_slave_enabled = 1;
GTID 复制
GTID = server_uuid:transaction_id,自动追踪事务:
[mysqld]
gtid_mode = on
enforce_gtid_consistency = on
log-slave-updates = 1
CHANGE MASTER TO MASTER_HOST='192.168.10.1', MASTER_USER='repl',
MASTER_PASSWORD='Repl2024!', MASTER_AUTO_POSITION = 1;
9. Mycat 中间件:一台数据库扛不住怎么办?
Mycat 是应用和多个 MySQL 之间的"智能路由器":
| 功能 | 说明 |
|---|---|
| 读写分离 | 写发给主库,读发给从库 |
| 垂直切分 | 不同业务表放不同库 |
| 水平切分 | 同表数据按规则分散 |
部署
# 安装 JDK
tar -xvf jdk-8u131-linux-x64.tar.gz -C /usr/lib/
# 配置 JAVA_HOME
tar -zxvf Mycat-server-1.6-RELEASE-*.tar.gz -C /usr/local/
/usr/local/mycat/bin/mycat start # 默认端口 8066
schema.xml 核心配置
<schema name="TESTDB" dataNode="dn1">
<table name="orders" primaryKey="id" dataNode="dn1,dn2" rule="rule1" />
<table name="employees" primaryKey="id" type="global" dataNode="dn1" />
</schema>
<dataNode name="dn1" dataHost="host1" database="mydb" />
<dataNode name="dn2" dataHost="host2" database="mydb" />
<dataHost name="host1" balance="1" writeType="0" dbType="mysql" dbDriver="native">
<heartbeat>select user()</heartbeat>
<writeHost host="master1" url="192.168.0.12:3306" user="mycat" password="pass">
<readHost host="slave1" url="192.168.0.13:3306" user="mycat" password="pass" />
</writeHost>
</dataHost>
balance 参数:0=不分离 | 1=读负载均衡(推荐) | 2=随机 | 3=只读从库
10. MHA 高可用:主库宕机了谁来接班?
问题
主从复制中主库宕机需手动切换——太慢!MHA 能在 0~30秒 内自动完成故障切换。
工作原理
- Manager 持续监控 Master 心跳
- Master 宕机后,MHA 尝试抢救 binlog
- 选择数据最新的 Slave 提升为新 Master
- 其他 Slave 自动指向新 Master
关键配置 (/etc/masterha/app1.cnf)
[server default]
manager_log=/var/log/masterha/app1/manager.log
manager_workdir=/var/log/masterha/app1
user=root
password=YourPass
repl_user=repl
repl_password=ReplPass
ssh_user=root
ping_interval=1
[server1]
candidate_master=1
hostname=192.168.0.202
master_binlog_dir=/var/lib/mysql
[server2]
candidate_master=1
hostname=192.168.0.203
master_binlog_dir=/var/lib/mysql
部署步骤
# 所有节点安装依赖和 MHA Node
yum install perl-DBD-MySQL perl-Config-Tiny perl-Log-Dispatch -y
rpm -ivh mha4mysql-node-0.56-0.el6.noarch.rpm
# Manager 节点安装 MHA Manager
rpm -ivh mha4mysql-manager-0.56-0.el6.noarch.rpm
# 配置 SSH 免密
ssh-keygen -t rsa && ssh-copy-id root@各节点
# 检查
masterha_check_ssh --conf=/etc/masterha/app1.cnf
masterha_check_repl --conf=/etc/masterha/app1.cnf
# 启动
masterha_manager --conf=/etc/masterha/app1.cnf &
11. LAMP 架构:把数据库接入 Web 应用
LAMP = Linux + Apache + MySQL + PHP
用户浏览器 -> Apache(httpd) -> PHP -> MySQL
yum install httpd php php-mysql mariadb mariadb-server -y
systemctl start httpd && systemctl start mariadb
# 测试 PHP
echo '<?php phpinfo(); ?>' > /var/www/html/test.php
# 创建应用数据库
mysql -u root -p -e "CREATE DATABASE owncloud;"
mysql -u root -p -e "GRANT ALL ON owncloud.* TO own@'localhost' IDENTIFIED BY 'Pass';"
第二部分:Redis 内存数据库
1. Redis 介绍:为什么需要便签纸式的数据库?
问题场景
假设你的成绩查询系统火了——每秒 1000 个家长同时查成绩。每次都去 MySQL 查,数据库扛不住。
类比:MySQL 像"笔记本"——内容全但翻找慢。Redis 像"便签纸"——贴在显示器旁,一眼看到。
Redis vs MySQL vs Memcached
| 对比项 | MySQL | Redis | Memcached |
|---|---|---|---|
| 存储位置 | 磁盘 | 内存(可持久化) | 内存 |
| 数据结构 | 二维表 | String/List/Hash/Set/ZSet | 只有 String |
| 持久化 | 天然支持 | RDB / AOF | 不支持 |
| 主从复制 | 支持 | 支持 | 不支持 |
| 集群 | 需中间件 | 原生支持(3.0+) | 不支持 |
| 速度 | 毫秒级 | 微秒级 | 微秒级 |
Redis 应用场景
- 缓存:热点数据(成绩查询结果、商品详情)
- 排行榜:ZSet 有序集合
- 计数器:网站访问量、在线人数
- Session 共享:分布式系统中的用户登录状态
- 消息队列:List 结构实现简单队列
2. Redis 部署:安装配置与持久化
安装
wget http://download.redis.io/releases/redis-5.0.7.tar.gz
tar xvf redis-5.0.7.tar.gz && cd redis-5.0.7
make && make install PREFIX=/usr/local/redis
cp redis.conf /usr/local/redis/bin/
启动与连接
# 修改为后台运行
sed -i 's/^daemonize no/daemonize yes/' /usr/local/redis/bin/redis.conf
# 启动
/usr/local/redis/bin/redis-server /usr/local/redis/bin/redis.conf
# 连接
/usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6379
# 关闭(正常关闭会先持久化)
/usr/local/redis/bin/redis-cli shutdown
基本操作
SET name "张三" # 设置
GET name # 获取
MSET k1 v1 k2 v2 k3 v3 # 批量设置
MGET k1 k2 k3 # 批量获取
DEL name # 删除
INCR counter # 自增(适合计数器)
SET session_id "abc" EX 3600 # 1小时后过期
TTL session_id # 查看剩余时间
SELECT 1 # 切换到库1(默认0~15共16个库)
关键配置 (redis.conf)
bind 192.168.0.12 # 绑定地址
port 6379
daemonize yes
requirepass YourRedisPass2024! # 密码(强烈建议!)
maxmemory 2gb
maxmemory-policy allkeys-lru # 内存淘汰策略
持久化:RDB vs AOF
| 对比 | RDB(快照) | AOF(追加日志) |
|---|---|---|
| 原理 | 定时生成快照 | 记录每条写命令 |
| 文件大小 | 小 | 大 |
| 恢复速度 | 快 | 慢 |
| 数据安全 | 可能丢最近数据 | 最多丢1秒数据 |
| 推荐 | 灾备 | 数据安全要求高 |
RDB:
save 900 1 # 900秒内1次写入则快照
save 300 10 # 300秒内10次
save 60 10000 # 60秒内10000次
dbfilename dump.rdb
AOF:
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec # 每秒刷盘(推荐)
3. Redis 主从复制:数据自动同步
问题
单台 Redis 有单点故障风险,内存有限(一般不超 20G)。主从复制实现数据冗余和读负载分担。
配置
Master:无需特殊配置即可。
Slave (redis.conf):
port 6380
slaveof 192.168.0.12 6379
masterauth YourRedisPass2024!
rm -f appendonly.aof dump.rdb # 清除旧持久化文件
/usr/local/redis/bin/redis-server /usr/local/redis/bin/redis.conf
验证:
# Master
redis-cli -p 6379
> SET test_key "hello"
> INFO replication
# Slave
redis-cli -p 6380
> GET test_key # "hello"
> SET foo bar # 报错:READONLY(从机只读,不能写)
4. Redis 哨兵集群:自动故障切换
问题
主从模式中 Master 挂了需手动切换。Sentinel(哨兵) 自动监控 Master,故障时自动将 Slave 提升为新 Master。
Sentinel 三大功能
- 监控:检查 Master 和 Slave 是否存活
- 提醒:节点出问题时通知管理员
- 自动切换:Master 故障时自动提升 Slave 为新 Master
工作流程
Sentinel1 ─┐
Sentinel2 ─┤── 监控 ──→ Master
Sentinel3 ─┘ │
├──→ Slave1
└──→ Slave2
- SDOWN(主观下线):单个 Sentinel 认为某节点不可达
- ODOWN(客观下线):多数 Sentinel 认为 Master 不可达 -> 触发故障转移
配置 (sentinel.conf)
port 26379
daemonize yes
sentinel monitor mymaster 192.168.0.12 6379 2 # 至少2个Sent才认为下线
sentinel down-after-milliseconds mymaster 30000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
sentinel auth-pass mymaster YourRedisPass2024!
/usr/local/redis/bin/redis-sentinel /usr/local/redis/bin/sentinel.conf
# 验证
redis-cli -p 26379> SENTINEL masters
redis-cli -p 26379> SENTINEL slaves mymaster
5. Redis Cluster:真正的分布式集群
问题
主从和哨兵都不能水平扩容——数据量受限于单台内存。Redis Cluster 通过哈希槽将数据分散到多个节点。
核心概念:16384 个哈希槽
客户端写入 key="user:1001"
|
v
CRC16("user:1001") % 16384 = 7365
|
v
哈希 7365 -> 节点 B(槽 5461~10922)
|
v
数据存入节点 B
- 16384 个哈希槽,通过 CRC16 算法平均分配给各 Master
- 每个 Master 负责一部分槽,每个 Master 可以有 Slave
- 最少 3 Master + 3 Slave = 6 节点
配置(每个节点 redis.conf)
daemonize yes
port 7000
bind 192.168.1.11 # 对外 IP(不能写127.0.0.1)
cluster-enabled yes
cluster-config-file nodes-7000.conf
cluster-node-timeout 5000
appendonly yes
创建集群
/usr/local/redis/bin/redis-cli --cluster create \
192.168.1.11:7000 192.168.1.12:7000 \
192.168.1.21:7000 192.168.1.22:7000 \
192.168.1.31:7000 192.168.1.32:7000 \
--cluster-replicas 1
### 使用
```bash
# 必须加 -c
redis-cli -h 192.168.1.11 -p 7000 -c
192.168.1.11:7000> SET a 123
-> Redirected to slot [15495] located at 192.168.1.31:7000
OK
CLUSTER NODES # 查看集群信息
节点管理
# 添加新节点
redis-cli --cluster add-node 192.168.1.41:7000 192.168.1.11:7000
# 重新分配槽
redis-cli --cluster reshard 192.168.1.41:7000
第三部分:自动化运维简介
1. Ansible 部署与使用
什么是 Ansible?
基于 Python 的自动化运维工具:
| 特性 | 说明 |
|---|---|
| 无 Agent | 被控机不需装软件 |
| 无 Server | 直接运行命令 |
| 基于 SSH | 利用 SSH 连接 |
| YAML 剧本 | 用 YAML 描述操作 |
安装
yum install ansible -y
# 或 pip install ansible
Inventory(主机清单)
# /etc/ansible/hosts
[webservers]
192.168.1.10
192.168.1.11
[dbservers]
192.168.1.20 ansible_ssh_user=root ansible_ssh_pass=123
Ad-hoc 命令
ansible all -m ping # 测试连通
ansible webservers -m shell -a "systemctl status httpd" # 执行命令
ansible webservers -m copy -a "src=/tmp/a dest=/opt/" # 拷贝文件
ansible webservers -m yum -a "name=httpd state=present" # 安装
ansible webservers -m service -a "name=httpd state=started" # 管理服务
常用模块:
| 模块 | 用途 |
|---|---|
ping | 测试连通性 |
shell | 执行命令 |
copy | 拷贝文件 |
yum | 安装软件 |
service | 管理服务 |
file | 文件操作 |
user | 用户管理 |
template | 模板渲染 |
Playbook(剧本)
# deploy_web.yml
---
- name: Deploy Web Server
hosts: webservers
become: yes
tasks:
- name: Install Apache
yum:
name: httpd
state: present
- name: Start Apache
service:
name: httpd
state: started
enabled: yes
- name: Deploy Content
copy:
src: index.html
dest: /var/www/html/index.html
handlers:
- name: Restart Apache
service:
name: httpd
state: restarted
ansible-playbook deploy_web.yml # 执行
ansible-playbook deploy_web.yml --syntax-check # 语法检查
ansible-playbook deploy_web.yml --check # 模拟执行
2. Ansible Python API
通过 Python 脚本调用 Ansible:
#!/usr/bin/env python3
from ansible.parsing.dataloader import DataLoader
from ansible.vars.manager import VariableManager
from ansible.inventory.manager import InventoryManager
from ansible.playbook.play import Play
from ansible.executor.task_queue_manager import TaskQueueManager
from ansible.plugins.callback import CallbackBase
class ResultCallback(CallbackBase):
def v2_runner_on_ok(self, result):
print(f"[OK] {result._host}: {result._result}")
def v2_runner_on_failed(self, result):
print(f"[FAIL] {result._host}: {result._result}")
loader = DataLoader()
inventory = InventoryManager(loader=loader, sources=['/etc/ansible/hosts'])
variable_manager = VariableManager(loader=loader, inventory=inventory)
play_source = dict(
name="Python API Demo",
hosts='webservers',
gather_facts='no',
tasks=[
dict(action=dict(module='shell', args='uptime')),
dict(action=dict(module='yum', args='name=vim state=present')),
]
)
play = Play().load(play_source, variable_manager=variable_manager, loader=loader)
tqm = TaskQueueManager(
inventory=inventory, variable_manager=variable_manager,
loader=loader, passwords=dict(), stdout_callback=ResultCallback()
)
try:
tqm.run(play)
finally:
tqm.cleanup()
3. PXE + Kickstart 批量装机
问题
给 100 台新电脑装系统,一台一台插 U 盘?太慢了。PXE 通过网络自动安装系统。
工作流程
新电脑开机(PXE 网卡启动)
|
v
DHCP 服务器 -> 分配 IP + 告知 TFTP 地址
|
v
TFTP 服务器 -> 下载启动内核和引导文件
|
v
Kickstart 应答文件 -> 自动完成分区、装包、设置密码
|
v
系统安装完成
DHCP 配置
# /etc/dhcp/dhcpd.conf
subnet 10.10.10.0 netmask 255.255.255.0 {
range 10.10.10.10 10.10.10.100;
option routers 10.10.10.1;
option domain-name-servers 10.10.10.1;
default-lease-time 600;
max-lease-time 7200;
next-server 10.10.10.1; # TFTP 服务器地址
filename "pxelinux.0"; # 引导文件
}
Kickstart 应答文件
# /var/ftp/ks.cfg
install
url --url=ftp://10.10.10.1/centos7
lang zh_CN.UTF-8
keyboard us
timezone Asia/Shanghai
rootpw --plaintext Admin2024!
clearpart --all
part /boot --fstype=xfs --size=500
part swap --fstype=swap --size=2048
part / --fstype=xfs --size=1 --grow
%packages
@base
@core
%end
%post
systemctl enable sshd
%end
PXE 引导菜单指向 ks 文件:
label linux
kernel vmlinuz
append initrd=initrd.img ks=ftp://10.10.10.1/ks.cfg
4. OpenStack 云计算简介
什么是云计算?
通过互联网按需提供计算资源(服务器、存储、网络)的服务模式。
类比:传统 IT 像自己打井取水,云计算像用自来水——按需使用,按量付费。
云的分类
| 类型 | 说明 | 例子 |
|---|---|---|
| 公有云 | 第三方提供 | 阿里云、AWS |
| 私有云 | 企业自建 | OpenStack |
| 混合云 | 公有 + 私有结合 | - |
云的分层
| 层次 | 全称 | 提供什么 | 用户需要做什么 |
|---|---|---|---|
| IaaS | 基础设施即服务 | 虚拟机 | 自己装系统、部署应用 |
| PaaS | 平台即服务 | 运行环境 | 只关注代码 |
| SaaS | 软件即服务 | 完整应用 | 直接使用 |
OpenStack 核心组件
| 组件 | 功能 | 类比 |
|---|---|---|
| Keystone | 身份认证 | 门卫 |
| Nova | 计算(虚拟机) | 房间管理 |
| Glance | 镜像管理 | 模板仓库 |
| Neutron | 网络管理 | 水电管线 |
| Cinder | 块存储 | 外接硬盘 |
| Swift | 对象存储 | 网盘 |
| Horizon | Web 管理界面 | 前台大厅 |
| Placement | 资源调度 | 调度员 |
工作流程
用户登录 Horizon (Web界面)
|
v
Keystone 验证身份 -> 选择镜像(Glance) + 配置(Nova)
|
v
Placement 调度 -> Nova 创建虚拟机 -> Neutron 分配网络
|
v
Cinder 挂载存储 -> 虚拟机启动完成
小结:OpenStack 是"云上操作系统",把服务器、存储、网络等硬件资源虚拟化,让用户通过 Web 界面申请和使用虚拟机。
总结与学习路径
知识体系
MySQL(持久化存储)
├── 基础:安装、SQL、存储引擎
├── 进阶:主从复制、备份恢复
└── 高级:Mycat 分库分表、MHA 高可用
Redis(内存缓存)
├── 基础:安装、数据类型、持久化
├── 进阶:主从复制、哨兵
└── 高级:Cluster 集群
自动化运维
├── Ansible:批量管理
├── PXE+Kickstart:批量装机
└── OpenStack:云计算平台
推荐运维新人学习顺序
- 先装 MySQL,练习 SQL 语句(第 1~4 节)
- 理解存储引擎和权限(第 5~6 节)
- 搭建主从复制(第 8 节)
- 部署 Redis(第 1~2 节)
- Redis 主从和哨兵(第 3~4 节)
- 用 Ansible 批量管理(第三部分)