一、linux #
1. linux系统启动流程 #
- 第一步:开机自检,加载BIOS
- 第二步:读取MBR
- 第三步:Boot Loader grub引导菜单
- 第四步:加载kernel内核
- 第五步:init进程依据inittab文件夹来设定运行级别
- 第六步:init进程执行rc.sysinit
- 第七步:启动内核模块
- 第八步:执行不同运行级别的脚本程序
- 第九步:执行/etc/rc.d/rc.lo
Linux 系统启动流程是一个多阶段的过程,涉及多个重要的系统组件。以下是 Linux 系统从开机到完全启动的详细步骤:
1. 加电自检 (POST) #
- 当电脑通电后,首先会执行硬件自检(POST,Power-On Self-Test),由 BIOS 或 UEFI(现代系统通常使用 UEFI)来完成。这一步检查硬件设备是否正常,比如内存、硬盘、显示器等。
2. 加载引导程序 (Bootloader) #
- BIOS 或 UEFI 会查找并加载存储设备(如硬盘或 SSD)上的引导加载程序(Bootloader)。常见的引导加载程序有 GRUB(GRand Unified Bootloader)和 LILO(Linux Loader)等。
- 引导加载程序的作用是加载并启动操作系统。它会显示可用的操作系统列表(如果有多个系统),并允许用户选择要启动的操作系统。
3. 加载内核 (Kernel) #
- 选择操作系统后,引导加载程序会加载操作系统的内核(通常是
vmlinuz
文件)。内核是操作系统的核心,负责管理硬件资源和提供系统服务。 - 内核首先会解压并加载到内存中,然后初始化硬件设备(如处理器、内存、硬盘等)。
4. 初始化硬件和挂载根文件系统 (Root Filesystem) #
- 内核在加载完毕后,会开始初始化硬件,包括磁盘驱动程序、输入设备、网络设备等。
- 内核通过 initramfs 或 initrd(初始 RAM 文件系统)来帮助加载根文件系统(通常是
/
)到内存中。initramfs 是一个压缩的文件系统镜像,包含必要的驱动程序和工具,确保系统能够挂载根文件系统。
5. 启动 init 进程 #
- 内核初始化完成后,会启动系统的第一个用户空间进程,即 init 进程(PID 1)。这是 Linux 系统中最重要的进程,它负责启动和管理系统的其他进程。
- 在现代 Linux 系统中,
init
进程通常由 systemd 替代,systemd 是一种系统和服务管理器,负责管理系统启动过程、服务和进程。
6. 运行 init 脚本或服务管理器 #
systemd
或其他 init 系统(如
SysVinit
或
Upstart
)会根据配置文件(如
/etc/systemd/system/
中的单元文件)启动各个系统服务和进程。
- 对于 systemd,它会根据目标(如
multi-user.target
或graphical.target
)启动相关的服务。
- 对于 systemd,它会根据目标(如
这包括启动网络服务、硬件驱动、用户登录管理器、数据库服务、应用程序等。
7. 启动用户空间进程 #
- 系统服务启动完毕后,开始启动用户空间的应用程序和守护进程。这些进程提供系统的功能,如网络连接、图形界面、文件共享等。
- 例如,login 或 getty 等进程会启动终端(TTY)或图形用户界面(GUI)。
8. 登录界面 #
- 如果启用了图形用户界面(GUI),例如使用 X Window 系统(如
X11
)或 Wayland,系统会启动图形显示管理器(如 GDM,LightDM,SDDM)。 - 用户在图形界面中输入用户名和密码,或者在终端中使用 login 命令进行登录。
9. 用户登录 #
- 用户登录后,会进入到其个人的 shell 环境(如 bash 或 zsh),并可以开始使用系统。
简要总结 #
- 硬件自检 (POST): BIOS/UEFI 检查硬件。
- 加载引导程序 (Bootloader): 引导程序如 GRUB 加载内核。
- 加载内核 (Kernel): 内核初始化硬件并启动 initramfs。
- 启动 init 进程: 由 init(或 systemd)启动系统服务。
- 初始化服务和进程: 启动必要的服务(如网络、硬件驱动等)。
- 用户界面: 启动图形界面或终端,用户登录。
- 登录并使用系统: 用户可以使用系统进行操作。
这个过程是 Linux 系统启动的标准流程,虽然不同的发行版或配置可能有细微的差别,但大致步骤是一样的。
2. linux文件类型 #
文件属性 | 文件类型 |
---|---|
- | 常规文件,即file |
d | 目录文件 |
b | block device 即块设备文件,如硬盘;支持以block为单位进行随机访问 |
c | character device 即字符设备文件,如键盘支持以character为单位进行线性访问 |
l | symbolic link 即符号链接文件,又称软链接文件 |
p | pipe 即命名管道文件 |
s | socket 即套接字文件,用于实现两个进程进行通信 |
在 Linux 中,文件是系统的基本单位,每个文件都有一个特定的类型。文件类型决定了文件的性质和如何操作该文件。Linux 文件类型可以分为以下几种:
1. 普通文件(Regular File) #
- 描述:普通文件是最常见的文件类型,存储着用户数据,如文本文件、图片、音频、视频、程序二进制文件等。
- 常见扩展名:
.txt
(文本文件),.jpg
(图片文件),.mp3
(音频文件),.bin
(二进制文件),.cpp
(C++源代码文件)等。 - 查看方式:在
ls -l
命令的输出中,普通文件的文件类型表示为-
。
2. 目录文件(Directory File) #
- 描述:目录文件包含指向其他文件或目录的指针。目录文件本身并不存储实际数据,而是存储文件名与文件的 inode 之间的映射关系。
- 查看方式:在
ls -l
命令的输出中,目录文件的文件类型表示为d
。
3. 符号链接文件(Symbolic Link,或 Symlink) #
- 描述:符号链接文件是一种指向另一个文件的引用。符号链接本身是一个指向目标文件路径的特殊文件。当访问符号链接时,系统会自动将操作转发到目标文件。
- 查看方式:在
ls -l
命令的输出中,符号链接文件的文件类型表示为l
,并且会显示链接的目标路径。
4. 字符设备文件(Character Device File) #
- 描述:字符设备文件代表可以按字符流进行读写的设备。例如终端、打印机、键盘等。数据通过字符设备以字节为单位顺序处理。
- 查看方式:在
ls -l
命令的输出中,字符设备文件的文件类型表示为c
。
5. 块设备文件(Block Device File) #
- 描述:块设备文件代表可以按块进行读写的设备,如硬盘、光驱、U 盘等。数据是以块(通常是 512 字节或更大)的形式进行传输和处理的。
- 查看方式:在
ls -l
命令的输出中,块设备文件的文件类型表示为b
。
6. FIFO 文件(FIFO, 也叫命名管道) #
- 描述:FIFO 文件是用于进程间通信(IPC)的特殊文件。它提供了一种单向的、按顺序流动的数据通道。通过 FIFO,数据可以从一个进程流向另一个进程。通常用于进程间的同步或数据传输。
- 查看方式:在
ls -l
命令的输出中,FIFO 文件的文件类型表示为p
。
7. 套接字文件(Socket File) #
- 描述:套接字文件是一种特殊的文件类型,通常用于进程间通信(IPC),尤其是网络通信。套接字可以用于本地进程间通信,或者通过网络进行通信。
- 查看方式:在
ls -l
命令的输出中,套接字文件的文件类型表示为s
。
8. 空文件(Empty File) #
- 描述:空文件是一个文件,但是它不包含任何数据。通常可以创建一个空文件用于占位或临时存储。
- 查看方式:空文件没有特殊的标识符,仍然是普通文件的一种。
查看文件类型 #
可以使用 ls -l
命令查看文件的详细信息,文件类型会出现在第一列:
-
:普通文件d
:目录l
:符号链接c
:字符设备文件b
:块设备文件p
:FIFO 文件(命名管道)s
:套接字文件
例如:
$ ls -l
-rw-r--r-- 1 user user 12345 Jan 1 12:34 example.txt # 普通文件
drwxr-xr-x 2 user user 4096 Jan 1 12:34 dir1 # 目录
lrwxrwxrwx 1 user user 10 Jan 1 12:34 symlink -> example.txt # 符号链接
crw-rw---- 1 root tty 5, 0 Jan 1 12:34 /dev/tty0 # 字符设备文件
brw-rw---- 1 root disk 8, 0 Jan 1 12:34 /dev/sda # 块设备文件
prw-r--r-- 1 user user 0 Jan 1 12:34 mypipe # FIFO 文件
srw-rw---- 1 user user 0 Jan 1 12:34 mysocket # 套接字文件
总结 #
- 普通文件(Regular File): 存储实际数据。
- 目录文件(Directory File): 包含文件名和 inode 的映射。
- 符号链接文件(Symbolic Link): 指向其他文件的引用。
- 字符设备文件(Character Device): 按字符流读写的设备。
- 块设备文件(Block Device): 按块读写的设备。
- FIFO 文件(FIFO,命名管道): 用于进程间通信。
- 套接字文件(Socket): 用于网络或进程间通信。
3. centos6和7怎么将源码安装的程序添加到开机自启动? #
- 通用方法:编辑/etc/rc.d/rc.local文件,在文件末尾添加启动服务命令
- centos6:①进入到/etc/rc.d/init.d目录下,②新建一个服务启动脚本,脚本中指定chkconfig参数,③添加执行权限,④执行chkconfig –add 添加服务自启动
- centos7:①进入到/usr/lib/systemd/system目录下,②新建自定义服务文件,文件中包含[Unit] [Service] [Install]相关配置,然后添加下执行权限,③执行systemctl enable 服务名称
在 CentOS 6 和 CentOS 7 中,尽管系统的初始化方式有所不同,但将源码安装的程序添加到开机自启动的方式基本相同。以下是针对这两个版本的操作方法。
CentOS 6 和 CentOS 7 开机自启动的基本步骤 #
创建启动脚本: 无论是 CentOS 6 还是 CentOS 7,首先需要为你的程序编写一个启动脚本。假设你有一个程序
/usr/local/bin/myprogram
,你可以创建一个启动脚本myprogram.sh
,内容如下:#!/bin/bash # 启动程序 /usr/local/bin/myprogram &
这里的
&
确保程序在后台运行。设置脚本权限: 确保你的脚本可执行:
chmod +x /path/to/myprogram.sh
将启动脚本添加到开机自启动:
CentOS 6(使用
init.d
和chkconfig
): #CentOS 6 使用
SysVinit
初始化系统,启动脚本一般放在/etc/init.d/
目录下,并通过chkconfig
命令将其设置为开机自启动。将脚本移动到
/etc/init.d/
目录:mv /path/to/myprogram.sh /etc/init.d/myprogram
使用
chkconfig
命令将脚本设置为开机自启动:chkconfig --add myprogram chkconfig myprogram on
可以使用以下命令检查脚本是否已添加到启动项:
chkconfig --list myprogram
CentOS 7(使用
systemd
): #CentOS 7 引入了
systemd
,因此你需要创建一个systemd
服务单元文件来管理程序的启动。在
/etc/systemd/system/
目录下创建一个.service
文件。例如,创建一个名为myprogram.service
的文件:sudo nano /etc/systemd/system/myprogram.service
文件内容如下:
[Unit] Description=My Program After=network.target [Service] ExecStart=/usr/local/bin/myprogram Restart=always User=root [Install] WantedBy=multi-user.target
After=network.target
:表示该服务将在网络服务之后启动。ExecStart
:指定程序的路径和启动命令。Restart=always
:程序崩溃后会自动重启。WantedBy=multi-user.target
:将服务添加到multi-user.target
,表示程序将在多用户模式下启动。
保存并退出后,重新加载
systemd
,使其识别新的服务单元文件:sudo systemctl daemon-reload
启动服务:
sudo systemctl start myprogram
设置服务为开机自启动:
sudo systemctl enable myprogram
可以使用以下命令检查服务状态:
sudo systemctl status myprogram
重启测试: 在完成上述设置后,重启系统进行测试,确认程序是否在开机时自动启动。
在 CentOS 6 中使用:
sudo reboot
在 CentOS 7 中使用:
sudo systemctl reboot
总结: #
- CentOS 6:使用
init.d
脚本并通过chkconfig
设置开机自启动。 - CentOS 7:使用
systemd
创建服务单元文件并通过systemctl
设置开机自启动。
两种方式的共同点是都需要为程序创建一个启动脚本,然后将其添加到开机自启动项中。
4. 简述lvm,如何给使用lvm的/分区扩容? #
- 功能:可以对磁盘进行动态管理。动态按需调整大小
- 概念:
①PV - 物理卷:物理卷在逻辑卷管理中处于最底层,它可以是实际物理硬盘上的分区,也可以是整个物理硬盘,也可以是raid设备。 ②VG - 卷组:卷组建立在物理卷之上,一个卷组中至少要包括一个物理卷,在卷组建立之后可动态添加物理卷到卷组中。一个逻辑卷管理系统工程中可以只有一个卷组,也可以拥有多个卷组。 ③LV - 逻辑卷:逻辑卷建立在卷组之上,卷组中的未分配空间可以用于建立新的逻辑卷,逻辑卷建立后可以动态地扩展和缩小空间。系统中的多个逻辑卷可以属于同一个卷组,也可以属于不同的多个卷组。
- 给/分区扩容步骤:
①添加磁盘 ②使用fdisk命令对新增加的磁盘进行分区 ③分区完成后修改分区类型为lvm ④使用pvcreate创建物理卷 ⑤使用vgextend命令将新增加的分区加入到根目录分区中 ⑥使用lvextend命令进行扩容 ⑦使用xfs_growfs调整卷分区大小
LVM(Logical Volume Management)简介 #
LVM(逻辑卷管理)是 Linux 中一种高级的磁盘管理方式,允许用户在逻辑层面上管理磁盘空间。LVM 将磁盘分为物理卷(Physical Volume,PV)、卷组(Volume Group,VG)和逻辑卷(Logical Volume,LV)。通过 LVM,用户可以更灵活地管理存储空间,进行动态扩展、缩减、迁移和快照等操作。
- 物理卷(PV):物理存储设备(如硬盘、分区或 LUN),可以通过
pvcreate
命令初始化。 - 卷组(VG):由多个物理卷组成的存储池,用户可以在卷组中分配空间。
- 逻辑卷(LV):从卷组中划分出的存储空间,类似于传统分区,但更加灵活。
如何给使用 LVM 的 /
分区扩容
#
假设你已经有一个使用 LVM 的 /
分区,并且需要扩容。扩容过程涉及以下几个步骤:
1. 检查当前 LVM 结构 #
首先,使用以下命令查看当前的磁盘布局和 LVM 结构,确保你已经有足够的未分配空间,或者有一个可以扩展的物理卷(PV)。
# 查看所有物理卷
sudo pvdisplay
# 查看所有卷组
sudo vgdisplay
# 查看所有逻辑卷
sudo lvdisplay
2. 添加新的物理卷(如果需要) #
如果当前卷组(VG)没有足够的空间,你需要添加一个新的物理磁盘或分区,并将其添加到卷组中。
假设你有一个新的磁盘 /dev/sdb
,可以通过以下命令初始化该磁盘并将其添加到卷组(如 centos
卷组):
# 创建物理卷
sudo pvcreate /dev/sdb
# 将物理卷添加到卷组
sudo vgextend centos /dev/sdb
3. 扩展逻辑卷 #
一旦有了足够的空间,下一步是扩展 /
分区的逻辑卷。假设 /
分区的逻辑卷是 /dev/centos/root
,可以使用以下命令扩展逻辑卷:
# 扩展逻辑卷
sudo lvextend -l +100%FREE /dev/centos/root
-l +100%FREE
表示使用卷组中所有剩余的未分配空间。如果你只想使用一部分空间,可以指定实际的扩展大小,如 -L +10G
扩展 10GB。
4. 扩展文件系统 #
扩展逻辑卷后,你还需要扩展文件系统,以便操作系统可以使用新的空间。根据你使用的文件系统类型(如 ext4
或 xfs
),扩展命令不同。
对于
ext4
文件系统,使用以下命令:sudo resize2fs /dev/centos/root
对于
xfs
文件系统,使用以下命令(xfs
文件系统不需要指定大小,自动调整):sudo xfs_growfs /dev/centos/root
5. 验证扩容 #
完成扩容后,使用以下命令验证分区是否已成功扩展:
# 查看文件系统的使用情况
df -h
# 查看逻辑卷信息
sudo lvdisplay /dev/centos/root
总结 #
- 检查现有 LVM 配置:使用
pvdisplay
、vgdisplay
和lvdisplay
命令。 - 添加新的物理卷(如果需要):
pvcreate
和vgextend
。 - 扩展逻辑卷:使用
lvextend
命令扩展逻辑卷。 - 扩展文件系统:根据文件系统类型,使用
resize2fs
(ext4)或xfs_growfs
(xfs)进行扩展。 - 验证扩容结果:使用
df -h
和lvdisplay
确认空间是否已扩展。
通过 LVM,你可以非常灵活地管理磁盘空间,进行动态扩展而不需要重新分区或重新格式化磁盘。
5. 为何du和df统计结果不一致? #
- 用户删除了大量的文件被删除后,在文件系统目录中已经不可见了,所以du就不会再统计它。
- 然而如果此时还有运行的进程持有这个已经被删除的文件句柄,那么这个文件就不会真正在磁盘中被删除,分区超级块中的信息也就不会更改,df仍会统计这个被删除的文件。
- 可通过 lsof命令查询处于deleted状态的文件,被删除的文件在系统中被标记为deleted。如果系统有大量deleted状态的文件,会导致du和df统计结果不一致。
du
和 df
都是用于查看磁盘使用情况的命令,但它们的统计方式和报告的内容不同,因此有时会导致它们显示的结果不一致。以下是导致 du
和 df
统计结果不一致的原因:
1. du
命令的工作原理
#
du
(Disk Usage)命令通过递归地扫描文件系统中的文件和目录,计算出文件或目录所占的磁盘空间。它的计算基于 文件实际占用的磁盘块。du
统计的是 文件系统中每个文件和目录的实际占用空间,包括文件内容和文件系统的元数据(如 inode 信息、目录项等)。du
默认会以块为单位(通常是 1K 或 4K)显示磁盘使用情况,且其结果是基于 文件系统中的数据,包括但不限于实际数据、磁盘对齐和文件系统元数据等。
2. df
命令的工作原理
#
df
(Disk Free)命令报告文件系统的整体磁盘空间使用情况,显示文件系统的总空间、已用空间、可用空间和挂载点。df
报告的是 整个文件系统的空间,并且它计算的是 块设备的容量,包括文件系统的元数据、日志和预留空间(例如:ext4 文件系统会保留一部分空间供超级用户使用)。df
通常显示的是 文件系统层面的空间信息,它会考虑到预留空间、磁盘格式化信息等,而不仅仅是文件的实际占用空间。
3. 为什么 du
和 df
显示不一致?
#
- 保留空间:某些文件系统(如 ext4)会为 root 用户预留一部分空间,以防止非管理员用户填满整个文件系统。
df
会显示包括这些保留空间在内的总空间,而du
不会计算这些保留空间,因此du
的结果通常会比df
少。 - 文件系统元数据:
df
统计的空间包含了文件系统的元数据(如 inode、目录项、日志等),而du
只计算文件和目录的实际数据占用。因此,df
的总空间可能会显示为比du
更多的空间。 - 挂载点:
du
只会计算指定目录(及其子目录)下的文件占用空间,而df
计算的是整个挂载点(包括所有子目录和挂载的其他文件系统)。如果有其他挂载点(如/mnt
或/home
)在当前目录下,df
会包括这些挂载点的空间,而du
则不会。 - 文件系统特性:某些文件系统(如 Btrfs 或 ZFS)具有快照功能,
du
可能会统计到这些快照的空间,而df
可能不显示这些快照占用的空间,或者显示的是快照所使用的空间。 - 软链接、挂载点和文件系统限制:如果文件系统有软链接或其他挂载点,
du
会统计软链接指向的文件所占的空间,但不会考虑挂载点。如果某个文件系统的磁盘空间被多次挂载或链接,df
会报告总体空间,而du
可能只计算一次。
4. 常见场景示例 #
保留空间:对于 ext4 文件系统,默认情况下,会保留 5% 的空间供超级用户使用,
df
会显示这些保留空间,而du
不会。示例:
# df 显示包括保留空间 $ df -h / Filesystem Size Used Avail Use% Mounted on /dev/sda1 50G 20G 25G 43% / # du 只显示实际使用的空间 $ du -sh / 18G /
挂载点和软链接:如果你挂载了某个分区(例如
/mnt
),df
会显示整个文件系统的空间,包括/mnt
,而du
只会统计/mnt
目录下的空间。
5. 如何让 du
和 df
的结果更接近?
#
排除挂载点:可以使用
du
命令的--one-file-system
选项,避免计算挂载在当前文件系统之外的其他文件系统。du -sh --one-file-system /
排除保留空间:使用
df
时可以使用--total
选项查看所有文件系统的总使用情况,这样可以忽略一些特殊文件系统的影响。
总结: #
du
和df
显示不一致主要是因为它们统计的内容不同:du
统计的是文件实际占用的空间,而df
统计的是文件系统级别的空间,包括保留空间、元数据和日志等。- 要更准确地理解磁盘空间使用情况,建议结合
du
和df
的输出,并注意它们各自的局限性。
6. 如何升级内核? #
- 方法一
# 添加第三方yum源进行下载安装。
Centos 6 YUM源:http://www.elrepo.org/elrepo-release-6-6.el6.elrepo.noarch.rpm
Centos 7 YUM源:http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm
# 先导入elrepo的key,然后安装elrepo的yum源:
rpm -import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm
# 查看可用的内核相关包
yum --disablerepo="*" --enablerepo="elrepo-kernel" list available
yum -y --enablerepo=elrepo-kernel install
- 方法二
# 通过下载kernel image的rpm包进行安装。
官方 Centos 6: http://elrepo.org/linux/kernel/el6/x86_64/RPMS/
官方 Centos 7: http://elrepo.org/linux/kernel/el7/x86_64/RPMS/
# 获取下载链接进行下载安装即可
wget https://elrepo.org/linux/kernel/el7/x86_64/RPMS/kernel-lt-4.4.185-1.el7.elrepo.x86_64.rpm
rpm -ivh kernel-lt-4.4.185-1.el7.elrepo.x86_64.rp
# 查看默认启动顺序
[root@localhost ~]# awk -F\' '$1=="menuentry " {print $2}' /etc/grub2.cfg
CentOS Linux (5.2.2-1.el7.elrepo.x86_64) 7 (Core)
CentOS Linux (4.4.182-1.el7.elrepo.x86_64) 7 (Core)
CentOS Linux (3.10.0-957.21.3.el7.x86_64) 7 (Core)
CentOS Linux (3.10.0-957.10.1.el7.x86_64) 7 (Core)
CentOS Linux (3.10.0-327.el7.x86_64) 7 (Core)
CentOS Linux (0-rescue-e34fb4f1527b4f2d9fc75b77c016b6e7) 7 (Core)
由上面可以看出新内核(4.12.4)目前位置在0,原来的内核(3.10.0)目前位置在1
# 设置默认启动
[root@localhost ~]# grub2-set-default 0 // 0代表当前第一行,也就是4.12.4版本
# 重启验证
升级 Linux 内核是一个相对常见的操作,尤其是当你需要使用某些新功能或解决安全问题时。下面是如何在 CentOS 6 和 CentOS 7 上升级内核的详细步骤。请根据你的系统版本和需求选择适合的方式。
1. 通过官方仓库更新内核(CentOS 7) #
在 CentOS 7 上,默认情况下会从官方仓库安装和更新内核。通过 yum
命令可以轻松进行内核更新,但有时这些仓库可能不会提供最新版本的内核。尽管如此,这仍然是升级内核的最简单方法。
步骤: #
更新当前系统:
sudo yum update
安装最新内核版本:
默认情况下,CentOS 7 会自动将内核更新到最新版本。如果不确定,执行以下命令来确保已安装最新版本的内核:
sudo yum install kernel
该命令会确保安装官方仓库中最新的稳定内核。
查看当前内核版本:
你可以通过以下命令检查当前的内核版本:
uname -r
重启系统:
更新内核后,重启系统以使新内核生效:
sudo reboot
确认新内核是否生效:
重启后,再次执行
uname -r
命令检查内核版本,确认系统已经使用了新的内核。uname -r
2. 通过 ELRepo 安装最新的内核(CentOS 7) #
CentOS 官方仓库通常不会提供最新的内核版本,因此你可以通过第三方仓库 ELRepo 安装最新的内核。
步骤: #
安装 ELRepo 仓库:
首先,安装 ELRepo 仓库:
sudo yum install -y https://www.elrepo.org/elrepo-release-7.el7.elrepo.rpm
安装最新的稳定内核:
ELRepo 提供了最新的内核版本。通过以下命令安装最新的内核(一般是
kernel-ml
,即 Mainline Kernel):sudo yum --enablerepo=elrepo-kernel install kernel-ml
如果你希望安装长期支持版本(LTS),可以安装
kernel-lt
:sudo yum --enablerepo=elrepo-kernel install kernel-lt
检查内核版本:
安装后,执行以下命令检查内核版本:
uname -r
重启系统:
重启系统以加载新内核:
sudo reboot
确认新内核:
再次使用
uname -r
命令检查当前内核版本。
3. 通过源代码手动编译安装内核(适用于所有版本) #
手动编译内核的步骤适用于那些需要非常具体内核配置或想要安装最新稳定版内核的用户。
步骤: #
下载内核源代码:
你可以从内核官方网站下载最新的内核源代码压缩包,网址:https://www.kernel.org。
例如,使用
wget
下载最新内核源代码:wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.x.x.tar.xz
解压源代码并进入目录:
解压下载的内核源代码:
tar -xvf linux-5.x.x.tar.xz cd linux-5.x.x
配置内核:
配置内核参数。你可以使用以下命令来加载当前系统的配置,或者手动进行选择:
make menuconfig
如果你想使用当前内核的配置,可以执行:
cp /boot/config-$(uname -r) .config
编译内核:
使用
make
命令编译内核,通常会花费一些时间:make
安装内核模块:
编译完成后,安装内核模块:
sudo make modules_install
安装内核:
然后安装内核:
sudo make install
更新引导加载器(GRUB):
安装完成后,更新 GRUB 配置:
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
对于 UEFI 系统,使用:
sudo grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg
重启并选择新内核:
重启系统并选择新安装的内核。如果你使用的是 UEFI 系统,确保在 BIOS 或引导菜单中选择正确的启动项。
验证内核版本:
重启后使用以下命令确认新内核已生效:
uname -r
4. 常见问题和注意事项 #
保留旧内核:安装新内核时,旧内核通常不会被删除。你可以通过
yum remove kernel
删除不需要的旧内核,或者手动删除/boot
中的旧内核文件。务必保留至少一个旧内核,以防新内核出现问题时能回滚。sudo yum remove kernel-<version>
使用 GRUB 选择内核:在系统启动时,可以通过 GRUB 菜单选择启动哪个内核。在启动时按下
Esc
键或Shift
键(取决于你的系统配置),选择你需要的内核。引导加载器问题:如果在系统启动时遇到问题,可以进入 GRUB 进行内核选择,或者从 Live CD 启动修复。
总结 #
- CentOS 7 用户可以使用
yum
命令更新内核,或者通过安装 ELRepo 提供的最新内核。 - 手动编译内核 是一种高级选项,适用于需要自定义内核配置的用户。
- 在更新内核后,记得重启系统并验证内核版本。
通过这些步骤,你可以根据自己的需求顺利升级 Linux 内核。
7. nginx日志访问量前十的ip怎么统计? #
awk '{array[$1]++}END{for (ip in array)print ip,array[ip]}' access.log |sort -k2 -rn|head
要统计 Nginx 日志中访问量前十的 IP 地址,可以通过 awk
、sort
和 uniq
等命令来处理 Nginx 的访问日志。以下是一些常见的步骤和命令来实现这个目标。
1. 基本的 Nginx 访问日志格式 #
假设 Nginx 的访问日志格式为以下标准格式:
127.0.0.1 - - [12/Oct/2023:14:28:14 +0000] "GET /index.html HTTP/1.1" 200 1024 "-" "Mozilla/5.0"
其中,第一个字段(127.0.0.1
)是访问的客户端 IP 地址。
2. 通过命令统计访问量前十的 IP #
你可以使用 awk
提取 IP 地址,然后使用 sort
和 uniq
统计每个 IP 的访问量,并显示访问量前十的 IP。
统计步骤: #
提取 IP 地址并统计次数:
假设你的 Nginx 访问日志文件是
/var/log/nginx/access.log
,你可以使用以下命令:cat /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -nr | head -n 10
解释:
cat /var/log/nginx/access.log
:输出 Nginx 访问日志。awk '{print $1}'
:提取日志中的 IP 地址(假设 IP 是日志的第一个字段)。sort
:对 IP 地址进行排序,sort
是为uniq
做准备。uniq -c
:统计每个 IP 出现的次数。sort -nr
:按照访问次数进行降序排序。head -n 10
:输出访问量前十的 IP 地址。
该命令会输出类似如下的结果:
320 192.168.1.1 210 10.0.0.2 180 192.168.0.3 150 10.0.0.4 ...
其中数字表示该 IP 地址的访问次数。
3. 详细的字段输出 #
如果你希望输出 IP 地址和访问次数,并且显示更详细的信息(比如每个 IP 的访问量),可以使用以下命令:
cat /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -nr | head -n 10 | awk '{print "IP:", $2, "访问量:", $1}'
输出示例:
IP: 192.168.1.1 访问量: 320
IP: 10.0.0.2 访问量: 210
IP: 192.168.0.3 访问量: 180
IP: 10.0.0.4 访问量: 150
...
4. 按日期/时间过滤日志 #
如果你只关心某个时间段内的访问量,可以通过 grep
结合时间过滤日志。例如,查看 2023 年 10 月 12 日的日志:
grep '12/Oct/2023' /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -nr | head -n 10
5. 按请求类型(如 GET, POST)进行过滤 #
如果你只关心某种请求类型的访问量(如 GET
请求),可以通过 grep
过滤:
grep 'GET' /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -nr | head -n 10
这样,你可以针对特定类型的请求来统计访问量前十的 IP。
6. 自动化统计并输出到文件 #
如果你想将统计结果保存到文件中,可以将命令输出重定向到一个文件:
cat /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -nr | head -n 10 > top_ip.txt
然后可以查看 top_ip.txt
文件获取统计信息。
总结: #
- 使用
awk
提取 IP 地址,sort
排序,uniq -c
统计访问次数,sort -nr
按次数降序排列。 - 可选择将日志按日期或请求类型进行过滤。
- 可以将统计结果保存到文件中以便后续查看。
通过这种方式,你可以轻松统计 Nginx 日志中的访问量前十的 IP 地址。
8. 如何删除/var/log/下.log结尾的30天前的日志? #
find /var/log/ -type f -name .*.log -mtime 30|xargs rm -f
要删除 /var/log/
目录下所有 .log
结尾且超过 30 天的日志文件,可以使用 find
命令来查找这些文件并执行删除操作。以下是具体的步骤:
1. 查看 .log
文件中超过 30 天的文件
#
首先,你可以使用 find
命令查看 /var/log/
目录下所有 .log
文件,且这些文件的最后修改时间超过 30 天:
find /var/log/ -type f -name "*.log" -mtime +30
解释:
/var/log/
:指定要搜索的目录。-type f
:查找普通文件。-name "*.log"
:查找以.log
结尾的文件。-mtime +30
:查找修改时间超过 30 天的文件(+30
表示大于 30 天)。
如果执行该命令后,你可以看到符合条件的日志文件列表。
2. 删除超过 30 天的 .log
文件
#
如果确认要删除这些文件,可以将 find
命令与 -exec
选项结合,执行删除操作:
find /var/log/ -type f -name "*.log" -mtime +30 -exec rm -f {} \;
解释:
-exec rm -f {} \;
:对于找到的每个文件,执行rm -f
删除操作。{}
是一个占位符,表示当前找到的文件名,\;
表示命令的结束。
3. 在删除前进行确认 #
为了避免误删,可以先运行一个测试命令,确认哪些文件将被删除:
find /var/log/ -type f -name "*.log" -mtime +30 -exec ls -l {} \;
这个命令将列出所有符合条件的文件及其详细信息(包括文件大小、修改时间等),你可以检查确认是否正确。
4. 使用 logrotate
自动管理日志
#
如果你需要定期删除过期日志文件,建议使用 logrotate
工具来管理日志文件的轮换和删除。logrotate
是 Linux 系统上用于自动化日志文件管理的工具,通常它会配置为定期归档和删除旧日志文件。
配置示例: #
/etc/logrotate.d/
目录下存放着每个服务的日志轮换配置文件。你可以在该目录中为 /var/log/
下的日志创建或修改一个配置文件来自动管理日志。
一个基本的 logrotate
配置示例:
/var/log/*.log {
daily # 每天轮换
rotate 7 # 保留7个历史日志
compress # 压缩归档的日志
missingok # 如果日志文件缺失,则不报错
notifempty # 如果日志文件为空,不进行轮换
create 0644 root root # 新日志文件创建时的权限
dateext # 使用日期作为归档文件名的一部分
maxage 30 # 删除超过30天的日志文件
}
总结: #
- 使用
find
命令查找并删除/var/log/
目录下修改时间超过 30 天的.log
文件。 - 可以先使用
ls -l
查看将要删除的文件,确保删除操作不会误删重要文件。 - 建议使用
logrotate
工具自动管理和清理日志文件,避免手动删除。
9. ansible有哪些模块?功能是什么? #
模块 | 功能 |
---|---|
copy | 拷贝文件到被控端 |
cron | 定时任务 |
fetch | 拷贝被控端文件到本地 |
file | 文件模块 |
group | 用户组模块 |
user | 用户模块 |
hostname | 主机名模块 |
script | 脚本模块 |
service | 服务启动模块 |
command | 远程执行命令模块 |
shell | 远程执行命令模块,command高级用法 |
yum | 安装包组模块 |
setup | 查看主机系统信息 |
Ansible 提供了大量的模块来实现各种自动化任务。这些模块是 Ansible 执行任务的基本单元,它们负责执行特定的操作,例如文件管理、系统管理、应用部署等。模块可以分为不同的类别,每个模块实现不同的功能。以下是 Ansible 常见模块的分类和功能概述。
1. 文件和目录管理模块 #
这些模块用于文件和目录的创建、删除、修改、权限管理等操作。
file
:管理文件或目录的属性,如权限、所有者和群组。- 示例:
ansible -m file -a "path=/tmp/testfile state=touch mode=0644"
- 示例:
copy
:将本地文件或目录复制到远程主机。- 示例:
ansible -m copy -a "src=/path/to/local/file dest=/path/to/remote/file"
- 示例:
template
:将模板文件(通常是 Jinja2 格式的)从本地复制到远程主机,并渲染模板。- 示例:
ansible -m template -a "src=/path/to/template.j2 dest=/path/to/remote/file"
- 示例:
fetch
:从远程主机下载文件到本地。- 示例:
ansible -m fetch -a "src=/path/to/remote/file dest=/path/to/local/dir flat=yes"
- 示例:
lineinfile
:修改文件中的某一行。- 示例:`ansible -m lineinfile -a “path=/etc/hosts line=‘192.168.1.1 myhost’”
file
:改变文件的属性,移动文件,或删除文件。- 示例:
ansible -m file -a "path=/path/to/file state=absent"
- 示例:
2. 系统管理模块 #
这些模块用于管理操作系统中的各种资源。
user
:管理用户账户。- 示例:
ansible -m user -a "name=test_user state=present"
- 示例:
group
:管理用户组。- 示例:
ansible -m group -a "name=test_group state=present"
- 示例:
service
:管理服务的状态(启动、停止、重启等)。- 示例:
ansible -m service -a "name=httpd state=started"
- 示例:
command
:在远程主机上执行命令。- 示例:
ansible -m command -a "df -h"
- 示例:
shell
:在远程主机上执行 shell 命令。- 示例:
ansible -m shell -a "echo 'Hello' > /tmp/hello.txt"
- 示例:
cron
:管理定时任务。- 示例:
ansible -m cron -a "name='run_backup' minute='0' hour='2' job='/usr/bin/backup.sh' state=present"
- 示例:
reboot
:重启远程主机。- 示例:
ansible -m reboot -a "connect_timeout=5"
- 示例:
hostname
:设置主机名。- 示例:
ansible -m hostname -a "name=myhost"
- 示例:
3. 网络管理模块 #
这些模块用于网络设备的管理和配置。
uri
:与 REST API 进行交互,发送 HTTP 请求。- 示例:
ansible -m uri -a "url=http://example.com method=GET"
- 示例:
ping
:测试与远程主机的连接。- 示例:
ansible -m ping all
- 示例:
firewalld
:管理 firewalld 防火墙规则。- 示例:
ansible -m firewalld -a "service=http permanent=true state=enabled"
- 示例:
docker
:管理 Docker 容器和镜像。- 示例:
ansible -m docker_container -a "name=test_container state=started image=ubuntu"
- 示例:
4. 包管理模块 #
这些模块用于管理操作系统上的软件包(安装、更新、删除)。
yum
:用于管理基于 RPM 的 Linux 发行版(如 CentOS、RHEL)的软件包。- 示例:
ansible -m yum -a "name=httpd state=present"
- 示例:
apt
:用于管理基于 Debian 的 Linux 发行版(如 Ubuntu)的软件包。- 示例:
ansible -m apt -a "name=nginx state=present"
- 示例:
pip
:用于安装和管理 Python 包。- 示例:
ansible -m pip -a "name=flask state=present"
- 示例:
npm
:用于管理 Node.js 包。- 示例:
ansible -m npm -a "name=express state=present"
- 示例:
5. 数据库管理模块 #
这些模块用于管理数据库实例和执行相关任务。
mysql_db
:管理 MySQL 数据库的创建、删除、备份等操作。- 示例:
ansible -m mysql_db -a "name=testdb state=present"
- 示例:
postgresql_db
:管理 PostgreSQL 数据库。- 示例:
ansible -m postgresql_db -a "name=testdb state=present"
- 示例:
mongodb
:管理 MongoDB 数据库。- 示例:
ansible -m mongodb -a "name=testdb state=present"
- 示例:
6. 云服务模块 #
这些模块用于云平台的资源管理,如 AWS、Azure、Google Cloud 等。
ec2
:在 AWS 上创建、管理 EC2 实例。- 示例:
ansible -m ec2 -a "image=ami-xxxxxxxx region=us-west-2 instance_type=t2.micro count=1"
- 示例:
gce_instance
:管理 Google Cloud 上的实例。- 示例:
ansible -m gce_instance -a "name=my-instance zone=us-central1-a image_family=debian-9 image_project=debian-cloud"
- 示例:
azure_rm_virtualmachine
:在 Azure 上创建、管理虚拟机。- 示例:
ansible -m azure_rm_virtualmachine -a "resource_group=myResourceGroup name=myVM image=UbuntuLTS size=Standard_B1s"
- 示例:
7. 监控与报警模块 #
这些模块用于监控和报警管理。
prometheus
:与 Prometheus 进行集成,管理和查询 Prometheus 指标。- 示例:
ansible -m prometheus -a "job=myjob target=localhost"
- 示例:
grafana_dashboard
:用于管理 Grafana 仪表盘。- 示例:
ansible -m grafana_dashboard -a "name=MyDashboard state=present json=/path/to/dashboard.json"
- 示例:
8. 用户输入和通知模块 #
这些模块用于处理与用户的交互或向外部系统发送通知。
pause
:暂停执行一段时间,或等待用户输入。- 示例:
ansible -m pause -a "minutes=5"
- 示例:
debug
:输出调试信息。- 示例:
ansible -m debug -a "msg='This is a debug message'"
- 示例:
slack
:向 Slack 通道发送消息。- 示例:
ansible -m slack -a "token=YOUR_SLACK_TOKEN channel=#general msg='Deployment Complete'"
- 示例:
9. 容器和虚拟化管理模块 #
这些模块用于容器和虚拟机的管理。
docker_image
:管理 Docker 镜像的拉取和删除。- 示例:
ansible -m docker_image -a "name=nginx state=present"
- 示例:
docker_container
:管理 Docker 容器的启动、停止、重启等操作。- 示例:
ansible -m docker_container -a "name=my-container state=started image=nginx"
- 示例:
virt
:管理虚拟机。- 示例:
ansible -m virt -a "name=my-vm state=running"
- 示例:
总结: #
Ansible 提供了丰富的模块,涵盖了系统管理、文件管理、数据库管理、云服务管理、网络管理等多个领域。你可以根据任务需求,选择相应的模块来实现自动化操作。Ansible 的模块功能非常灵活,支持不同操作系统和云平台,极大地方便了系统管理和应用部署。
10. nginx为什么比apache快? #
- nginx采用epoll模型
- apache采用select模型
Nginx 通常比 Apache 快,主要有以下几个原因:
1. 事件驱动架构 #
Nginx 采用的是事件驱动(Event-Driven)架构,而 Apache 默认使用的是基于进程(或线程)模型。Nginx 的事件驱动模型使得它能够处理大量的并发连接,而不需要为每个连接创建新的进程或线程。
- Nginx:使用单个或少数线程来处理请求,所有请求都由事件循环(event loop)管理,且每个连接在处理时都不阻塞其他连接。这使得 Nginx 在处理高并发请求时非常高效。
- Apache:默认使用进程/线程池(比如
prefork
模块),每个请求都会启动一个独立的进程或线程来处理。这样虽然能处理并发请求,但每个请求都需要额外的内存和上下文切换,导致效率较低。
2. 内存消耗 #
由于 Nginx 是基于异步非阻塞的事件驱动模式,它能在一个工作进程中处理成千上万的并发连接。每个连接消耗的资源非常少,通常只有几十个字节的内存。
相比之下,Apache 的线程/进程模式需要为每个请求分配独立的内存和操作系统资源。即使请求量不高,资源消耗也相对较大,因此在高并发场景下性能不如 Nginx。
3. 高效的静态内容处理 #
Nginx 被设计为一个高效的反向代理服务器,特别擅长处理静态文件请求(如图片、CSS、JavaScript、HTML 等)。它能够高效地使用操作系统的内存和硬件缓存机制,快速响应静态内容的请求。
Apache 虽然也支持静态内容的处理,但在处理静态文件时,Apache 的性能通常低于 Nginx,因为 Apache 需要通过多个模块进行处理,并且涉及更多的进程/线程调度。
4. 非阻塞 I/O #
Nginx 使用非阻塞 I/O(Non-blocking I/O)模型,即使在处理大量请求时,进程不会被阻塞等待 I/O 操作完成。通过异步事件通知机制,Nginx 可以高效地在多个连接之间切换,从而避免了传统的线程/进程阻塞。
Apache 默认使用阻塞 I/O,这意味着当一个请求在处理时,如果需要等待 I/O 操作(比如访问数据库或文件系统),它会阻塞当前线程,直到操作完成。这样在高并发情况下,Apache 的响应时间会变慢。
5. 更低的 CPU 和内存开销 #
由于 Nginx 的事件驱动模式和非阻塞 I/O,它通常需要更少的 CPU 和内存资源来处理大量的请求。它的工作进程不需要频繁的上下文切换,也不会为每个请求分配大量的内存。
Apache 在高并发情况下,由于每个请求都创建一个新的进程或线程,导致 CPU 和内存消耗较高。因此,Nginx 在处理大量并发请求时比 Apache 更加高效。
6. 负载均衡和反向代理能力 #
Nginx 作为反向代理服务器和负载均衡器,提供了非常高效的请求分发和负载均衡机制。它能够通过多个算法(如轮询、IP 哈希、最少连接等)将请求分发到后端服务器,支持高效的分布式架构,极大提高了性能和扩展性。
虽然 Apache 也支持反向代理和负载均衡,但 Nginx 通常比 Apache 更高效,并且对请求的分发和处理更加精细。
7. 配置简洁与优化 #
Nginx 的配置文件相对简洁且高效,能够快速加载和应用配置。而 Apache 的配置文件可能更加复杂,尤其在启用多个模块时,可能会引入不必要的复杂性和性能开销。
总结: #
Nginx 比 Apache 快的主要原因是其采用了事件驱动的非阻塞 I/O 模型,能够高效处理大量并发连接,而不需要为每个请求创建新的进程或线程。此外,Nginx 对静态内容的处理非常高效,内存消耗较少,并且通过负载均衡和反向代理功能提高了性能。而 Apache 的多进程/多线程模式虽然灵活,但在高并发和资源消耗方面通常不如 Nginx 高效。
11. 四层负载和七层负载区别是什么? #
- 四层基于IP+端口进行转发
- 七层就是基于URL等应用层信息的负载均衡
四层负载均衡和七层负载均衡的区别主要体现在它们处理请求的层次不同,以及基于不同协议和信息进行流量分配。具体区别如下:
1. OSI模型层次 #
- 四层负载均衡(Layer 4 Load Balancing):操作在 OSI 模型的第四层,也就是 传输层。它处理的是 TCP 或 UDP 协议的数据包,主要根据 IP 地址和端口号来进行流量分配。
- 七层负载均衡(Layer 7 Load Balancing):操作在 OSI 模型的第七层,也就是 应用层。它根据应用层协议(如 HTTP、HTTPS、FTP 等)中的内容来做决策,可以基于请求的 URL、头部、Cookie、HTTP 方法等信息来进行流量调度。
2. 负载均衡决策依据 #
四层负载均衡
:
- 基于 IP 地址和端口:四层负载均衡在流量到达服务器之前,主要基于客户端 IP 地址、目标 IP 地址和端口号来决定如何将流量转发到后端服务器。
- 它不理解上层协议的内容,仅仅是在传输层(TCP、UDP)进行决策,因此它的处理速度通常较快,适用于简单的流量分发。
七层负载均衡
:
- 基于应用层信息:七层负载均衡可以理解并使用更复杂的应用层协议信息来进行决策。例如,它可以根据 HTTP 请求的 URL、请求头、Cookie 等信息来决定请求应该转发到哪个后端服务器。
- 七层负载均衡提供了更多的灵活性,能够进行内容交换、SSL 终止、基于会话的负载分配等。
3. 处理复杂度和性能 #
四层负载均衡
:
- 性能更高,处理更简单:由于四层负载均衡只关注网络层和传输层的基本信息,处理速度较快,适合高并发的网络流量。它通常用于较为简单的负载均衡需求,如 TCP、UDP 服务的流量分发。
七层负载均衡
:
- 处理较复杂,性能较低:七层负载均衡需要解析应用层的内容,计算量较大,可能影响性能,但它能提供更多的功能和灵活性。例如,应用层负载均衡可以对不同的请求类型执行不同的策略,如按请求 URL 或 HTTP 方法进行流量分配。
4. 应用场景 #
- 四层负载均衡:
- 适合简单的 TCP 或 UDP 服务,通常用于数据库集群、VPN、邮件服务器、实时通信等应用场景。
- 常见的四层负载均衡设备或软件如:硬件负载均衡器(F5 Big-IP)、Nginx、IPVS(Linux Virtual Server)等。
- 七层负载均衡:
- 适用于 Web 应用和更复杂的应用场景,特别是需要基于请求内容(如 HTTP 头部、URL)进行智能流量分配的情况。七层负载均衡器常用于高效的 Web 应用服务、微服务架构和 API 网关等场景。
- 常见的七层负载均衡器如:Nginx、HAProxy、Traefik、Apache HTTP Server等。
5. 功能特性 #
四层负载均衡
:
- 支持基于源 IP 或端口号的流量分配。
- 支持透明传输和高效的负载分配,但不处理任何应用层协议的内容。
- 支持高并发连接的负载均衡,通常用于低延迟的服务。
七层负载均衡
:
- 支持更细粒度的流量控制,如基于 URL 路径、HTTP 方法(GET、POST)、头部字段、Cookie、查询字符串等进行流量分发。
- 可以实现内容交换(如缓存、压缩、SSL 终止等),对请求进行智能化的转发。
- 支持 A/B 测试、蓝绿部署、会话保持等高级功能。
6. SSL/TLS 终止 #
- 四层负载均衡:不处理 SSL/TLS 加密和解密操作,流量会以加密的形式传递到后端服务器。
- 七层负载均衡:通常可以处理 SSL/TLS 终止,即解密客户端的加密请求后,再转发给后端服务器。这样可以减轻后端服务器的负担,并提供对 HTTPS 流量的更多控制。
总结: #
- 四层负载均衡关注的是 传输层(IP 地址、端口),适用于简单的 TCP/UDP 流量分发,性能高,适合高并发和低延迟需求。
- 七层负载均衡则可以解析 应用层 协议(如 HTTP、HTTPS),能够做基于内容的精细化流量调度,功能更强大,但处理复杂度较高,适合 Web 应用和其他需要基于内容进行智能流量分配的场景。
12. lvs有哪些工作模式?哪个性能高? #
- dr:直接路由模式,请求由 LVS 接受,由真实提供服务的服务器直接返回给用户,返回的时候不经过 LVS。(性能最高)
- tun:隧道模式,客户端将访问vip报文发送给LVS服务器。LVS服务器将请求报文重新封装,发送给后端真实服务器。后端真实服务器将请求报文解封,在确认自身有vip之后进行请求处理。后端真实服务器在处理完数据请求后,直接响应客户端。
- nat:网络报的进出都要经过 LVS 的处理。LVS 需要作为 RS 的网关。当包到达 LVS 时,LVS 做目标地址转换(DNAT),将目标 IP 改为 RS 的 IP。RS 接收到包以后,仿佛是客户端直接发给它的一样。RS 处理完,返回响应时,源 IP 是 RS IP,目标 IP 是客户端的 IP。这时 RS 的包通过网关(LVS)中转,LVS 会做源地址转换(SNAT),将包的源地址改为 VIP,这样,这个包对客户端看起来就仿佛是 LVS 直接返回给它的。客户端无法感知到后端 RS 的存在。
- fullnat模式:fullnat模式和nat模式相似,但是与nat不同的是nat模式只做了两次地址转换,fullnat模式却做了四次。
LVS(Linux Virtual Server)是一个高性能的负载均衡解决方案,它提供了几种不同的工作模式,用于处理不同类型的负载均衡需求。LVS 的工作模式包括:
1. NAT (Network Address Translation) 模式 #
在 NAT 模式下,LVS 会修改客户端请求的目标 IP 地址(即将目标 IP 地址更改为后端服务器的 IP 地址),然后将请求转发到合适的后端服务器。后端服务器的响应也会通过 LVS 转发回客户端。
特点
:
- LVS 充当了客户端和后端服务器之间的代理,客户端认为自己在与 LVS 交互,而 LVS 再将请求转发到实际的后端服务器。
- 每个后端服务器的 IP 地址是私有地址,LVS 充当路由器,NAT 会更改请求的目标地址。
- LVS 需要修改网络数据包,因此需要较多的计算资源。
适用场景
:
- 当后端服务器的 IP 地址是私有的,且不直接暴露在公网时,NAT 模式是最常用的。
2. DR (Direct Routing) 模式 #
在 DR 模式下,LVS 直接将请求转发到后端服务器,而不需要修改目标地址。LVS 只是根据请求选择合适的后端服务器,然后将请求转发给该服务器,后端服务器直接将响应返回给客户端,LVS 不参与响应的转发。
- 特点:
- 在 DR 模式下,客户端请求的目标 IP 地址不需要改变,后端服务器的 IP 地址必须是公有 IP 地址,且 LVS 的虚拟 IP 地址(VIP)必须在后端服务器的网络接口上。
- 后端服务器直接发送响应,LVS 不会再次转发响应。
- 性能高,因为没有修改数据包,也没有代理响应数据,减少了系统负载。
- 适用场景:
- 后端服务器有公有 IP 地址,并且 LVS 和后端服务器位于同一网络。
3. TUN (IP Tunneling) 模式 #
在 TUN 模式下,LVS 使用 IP 隧道技术将客户端请求转发到后端服务器。LVS 将客户端请求封装在一个新的数据包中,传输给后端服务器,后端服务器解封装并处理请求。与 NAT 模式不同,TUN 模式没有直接修改目标 IP 地址,而是通过 IP 隧道将数据包传递给后端服务器。
特点
:
- 适用于后端服务器与 LVS 在不同网络之间进行通信的情况。
- LVS 通过 IP 隧道将请求转发给后端服务器,这样可以跨越网络边界,但需要更多的网络带宽和计算资源。
适用场景
:
- 后端服务器和 LVS 位于不同的子网,且需要通过隧道进行通信。
性能对比: #
- NAT 模式:性能相对较低,因为每个数据包都需要被 LVS 修改,增加了处理负担。特别是在高负载时,NAT 模式的性能可能会受到影响。
- DR 模式:性能最高。因为 DR 模式不需要修改数据包,也不需要代理响应,所以它的效率非常高,几乎不会给系统带来额外的负载。适用于高并发场景。
- TUN 模式:性能次之。虽然数据包不需要修改,但 IP 隧道的开销较大,尤其在跨网络传输时需要额外的计算资源。因此,TUN 模式的性能通常低于 DR 模式,但比 NAT 模式要好。
总结: #
- DR 模式 性能最好,适用于 LVS 和后端服务器在同一网络中的情况。
- TUN 模式 性能较高,但会受到隧道开销的影响,适用于跨网络传输的场景。
- NAT 模式 性能相对较低,适用于需要将后端服务器的私有 IP 地址隐藏的场景。
因此,DR 模式 被认为是性能最优的工作模式,尤其是在 LVS 和后端服务器在同一网络中时。
13. lvs nginx haproxy keeplived区别,优缺点? #
参考链接:https://blog.51cto.com/816885/2529993?source=dra
LVS、Nginx、HAProxy 和 Keepalived 都是常见的负载均衡解决方案,它们各有优缺点,适用于不同的场景。以下是这四者的区别、优缺点以及适用场景的详细对比。
1. LVS (Linux Virtual Server) #
LVS 是一种基于 Linux 的高性能负载均衡解决方案,主要通过不同的工作模式(NAT、DR、TUN)来进行负载均衡。
优点: #
- 高性能:LVS 是内核级负载均衡器,直接在 Linux 内核中实现,处理速度非常快。
- 支持高并发:能够处理大量的并发连接,适用于大规模应用。
- 灵活性:支持多种负载均衡模式(NAT、DR、TUN),可以根据实际需求选择合适的模式。
- 故障切换:支持高可用配置,可以和 Keepalived 配合使用,提供故障切换和虚拟 IP 高可用性。
缺点: #
- 配置复杂:相对于 Nginx 和 HAProxy,LVS 的配置和管理较为复杂,调试和排错也较为困难。
- 缺少应用层负载均衡功能:LVS 主要操作在传输层(L4),不支持深入的应用层(L7)负载均衡,如基于 URL、HTTP 方法等。
适用场景: #
- 高流量网站和高并发应用,尤其适用于 Web 服务器集群、数据库集群等。
2. Nginx #
Nginx 是一个高性能的 Web 服务器和反向代理服务器,也可以作为负载均衡器使用。它支持应用层负载均衡,能够处理 HTTP、HTTPS、TCP、UDP 流量。
优点: #
- 高性能:作为反向代理和负载均衡器,Nginx 性能非常好,能够处理大量并发请求。
- 灵活性:支持 L4 和 L7 负载均衡,可以根据 URL、请求头、Cookie 等应用层信息进行流量分发。
- 易于配置和管理:配置文件简洁,管理方便,支持热部署。
- 功能丰富:支持 SSL 终止、缓存、会话保持等功能,适用于 Web 应用。
缺点: #
- 仅限于 HTTP/S 和 TCP/UDP 负载均衡:虽然支持多种协议,但在一些特殊应用场景(如数据库负载均衡)可能不如 LVS 高效。
- 在大规模集群环境下的性能不如 LVS:对于超高并发的负载均衡,Nginx 的性能可能不如 LVS。
适用场景: #
- Web 服务、API 网关、微服务架构,适用于处理 HTTP、HTTPS 等应用层流量的负载均衡。
3. HAProxy #
HAProxy 是一个高性能的负载均衡器,广泛用于 Web 应用的负载均衡,尤其擅长高可用性和高并发环境。
优点: #
- 高性能:HAProxy 在 L4 和 L7 负载均衡方面表现非常好,特别适用于高并发、高可用性要求的环境。
- 灵活性:支持多种负载均衡算法(轮询、最少连接等),并且可以基于 HTTP 请求头、URL、IP 地址等进行智能流量分配。
- 高可用性:支持健康检查、会话保持、SSL 终止等功能,并且和 Keepalived 配合使用时可以提供高可用性。
- 监控和统计:提供详细的日志和监控功能,便于性能分析和故障排查。
缺点: #
- 配置复杂:HAProxy 的配置文件相对较为复杂,尤其是在需要自定义负载均衡规则时。
- 不支持静态内容缓存:HAProxy 不能像 Nginx 一样处理静态文件,通常需要与其他 Web 服务器结合使用。
适用场景: #
- 高并发 Web 服务、微服务架构、API 网关,适用于需要高可用性和高性能负载均衡的场景。
4. Keepalived #
Keepalived 主要用于提供高可用性,它与 LVS、Nginx 或 HAProxy 配合使用,管理虚拟 IP 地址,提供故障切换和负载均衡功能。
优点: #
- 高可用性:Keepalived 通过 VRRP 协议提供虚拟 IP 地址,能够在主节点故障时自动切换到备节点,保证系统的高可用性。
- 简单配置:Keepalived 配置相对简单,能够与 LVS、Nginx 或 HAProxy 等负载均衡器无缝集成。
- 支持健康检查:Keepalived 可以监控负载均衡器的状态,自动进行故障转移。
缺点: #
- 单独使用不提供负载均衡功能:Keepalived 本身并不提供负载均衡功能,必须与 LVS、Nginx 或 HAProxy 配合使用。
- 主要针对高可用性设计:对于负载均衡功能,Keepalived 本身并不提供复杂的负载均衡策略,更多侧重于故障转移。
适用场景: #
- 高可用性场景,特别是与 LVS、Nginx 或 HAProxy 配合使用,确保虚拟 IP 地址的故障转移和负载均衡器的高可用性。
总结与适用场景: #
- LVS:性能最强,适用于大规模高并发的流量负载均衡,尤其适用于需要高效 TCP/UDP 负载均衡的场景。配置较复杂。
- Nginx:适用于 Web 应用和 API 的负载均衡,支持 L4 和 L7,能够基于应用层信息做智能流量分发,配置简单,性能优秀,适合中小规模应用。
- HAProxy:适用于高可用性和高并发的 Web 应用负载均衡,支持 L4 和 L7,配置较复杂,但在高性能和高可用性场景下非常出色。
- Keepalived:提供高可用性和故障切换功能,通常与 LVS、Nginx 或 HAProxy 配合使用,确保系统的容错和高可用性。
通常,LVS 和 Keepalived 配合使用适用于需要极高性能的负载均衡环境,而 Nginx 和 HAProxy 更适合 Web 应用和高可用负载均衡。
14. 如下url地址,各个部分的含义 #
https://www.baidu.com/s?word=123&ie=utf-8
- https: 使用https加密协议访问
- www.baidu.com/s: 请求地址
- ?word&ie=utf-8: get请求的参数,多个参数&连接
这个 URL 地址是一个典型的 HTTP 请求 URL,通常用于发起一个搜索请求。下面是对各个部分的解析:
https://www.baidu.com/s?word=123&ie=utf-8
1. 协议部分:https://
#
- https 表示使用的是安全的超文本传输协议(HTTP Secure),即对数据进行加密传输。
- :// 是协议与后续内容的分隔符。
2. 主机名部分:www.baidu.com
#
- www.baidu.com 是服务器的域名,指向百度的官方网站。
- 这个部分用于定位服务器的地址,也就是目标主机。
3. 路径部分:/s
#
- /s 是一个路径,表示对百度网站上的某个页面进行请求。在百度中,通常
/s
表示进行搜索的页面。
4. 查询参数部分:?word=123&ie=utf-8
#
? 表示后面跟随的是查询字符串。
查询字符串由多个参数组成,每个参数之间通过 & 符号分隔。
word=123
:
word
是一个查询参数的名称,表示搜索的关键字。123
是该参数的值,表示搜索内容是123
。
ie=utf-8
:
ie
是一个查询参数的名称,表示字符编码格式。utf-8
是该参数的值,表示使用 UTF-8 编码格式来传输数据。
总结: #
https://www.baidu.com/s
是访问百度搜索页面的路径。word=123
表示搜索关键字是123
。ie=utf-8
表示使用 UTF-8 编码格式。
所以这个 URL 的含义是:通过 HTTPS 协议访问百度的搜索页面,搜索内容是 123
,并使用 UTF-8 编码格式来处理请求和响应。
15. tomcat各个目录含义,如何修改端口,如何修改内存数? #
- bin 存放tomcat命令
- conf 存放tomcat配置文件
- lib 存放tomcat运行需要加载的jar包
- log 存在Tomcat运行产生的日志
- temp 运行过程中产生的临时文件
- webapps 站点目录
- work 存放tomcat运行时的编译后的文件
- conf/server.xml 修改端口号
- bin/catalina.sh 修改jvm内存
Tomcat 目录结构含义 #
Tomcat 的目录结构主要包含以下几个重要的文件夹和文件,每个文件夹的含义如下:
bin/
: 包含 Tomcat 的启动脚本和控制脚本。startup.sh
:启动 Tomcat 的脚本(Linux/Unix 系统)。startup.bat
:启动 Tomcat 的脚本(Windows 系统)。shutdown.sh
:关闭 Tomcat 的脚本(Linux/Unix 系统)。shutdown.bat
:关闭 Tomcat 的脚本(Windows 系统)。catalina.sh
:Tomcat 启动的核心脚本。catalina.bat
:Tomcat 启动的核心脚本(Windows 系统)。
conf/
: 包含 Tomcat 的配置文件。server.xml
:Tomcat 的主要配置文件,定义了 Tomcat 的各项配置,包括端口、连接器、虚拟主机等。web.xml
:Web 应用的默认配置文件,定义了 Tomcat 如何处理特定请求,配置 servlet、过滤器等。context.xml
:为每个 Web 应用提供单独的配置,可以在其中定义数据库连接、路径等。tomcat-users.xml
:定义 Tomcat 的用户及权限,常用于设置管理员权限。
lib/
: 包含 Tomcat 所需的库文件(.jar
文件)。- 这些是 Tomcat 运行时所依赖的 Java 类库。
logs/
: 存放 Tomcat 运行过程中的日志文件。catalina.out
:Tomcat 启动和运行时的标准输出日志。localhost.log
、manager.log
等:具体的日志文件,用于记录不同方面的日志。
webapps/
: 存放 Web 应用的目录。- 默认情况下,Tomcat 会将其 Web 应用放在这个目录下,每个 Web 应用对应一个文件夹。
- 你可以将自己的 Web 应用程序(如
.war
文件)放在这里,Tomcat 会自动解压并部署。
work/
: 存放 Tomcat 编译过程中生成的工作文件。- 包含 JSP 编译后的文件、Servlet 生成的临时文件等。
temp/
: 存放 Tomcat 在运行时使用的临时文件。ROOT/
: 这是默认的 Web 应用程序目录,也就是 Tomcat 部署时会映射到/
路径。
如何修改 Tomcat 的端口? #
Tomcat 默认的 HTTP 端口是 8080
,要修改端口,可以编辑 server.xml
文件:
- 打开
conf/server.xml
文件。 - 找到以下内容,修改端口号:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
- 将
port="8080"
修改为你想要的端口(如:port="9090"
)。 - 保存并关闭文件。
- 重启 Tomcat。
如何修改 Tomcat 的内存设置? #
Tomcat 的内存配置通常通过 Java 虚拟机(JVM)的启动参数进行设置,这些设置可以在 bin/catalina.sh
(Linux/Unix)或 bin/catalina.bat
(Windows)中找到。
1. 修改 catalina.sh
(Linux/Unix):
#
- 打开
bin/catalina.sh
文件。 - 找到
JAVA_OPTS
变量,并设置你想要的内存大小。
例如,设置最大堆内存为 2GB,初始堆内存为 1GB:
JAVA_OPTS="-Xms1g -Xmx2g"
其中:
-Xms1g
:指定初始内存为 1GB。-Xmx2g
:指定最大内存为 2GB。
- 保存并关闭文件。
2. 修改 catalina.bat
(Windows):
#
- 打开
bin/catalina.bat
文件。 - 找到类似的行并设置内存大小:
set JAVA_OPTS=-Xms1g -Xmx2g
- 保存并关闭文件。
3. 其他内存设置(可选): #
PermGen/Metaspace(JVM)
: 如果使用的是较旧的 JDK(例如 JDK 7),可以配置
PermGen
内存:
JAVA_OPTS="-XX:PermSize=128m -XX:MaxPermSize=256m"
对于 JDK 8 及以后版本,
PermGen
被替换为
Metaspace
,可以配置:
JAVA_OPTS="-XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m"
总结: #
- 修改端口:编辑
conf/server.xml
文件,修改<Connector port="8080" />
部分的端口。 - 修改内存:在
bin/catalina.sh
或bin/catalina.bat
文件中,通过JAVA_OPTS
设置内存参数(例如:-Xms1g -Xmx2g
)。
16. nginx反向代理时,如何使后端获取真正的访问来源ip? #
在location配置段添加以下内容: proxy_set_header Host $http_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;
在使用 Nginx 作为反向代理时,后端服务器通常只能看到来自 Nginx 的 IP 地址,而无法直接获取客户端的真实 IP 地址。为了使后端服务器能够获取到客户端的真实 IP 地址,你需要在 Nginx 中设置一些特殊的头部信息(X-Forwarded-For
)来传递客户端的 IP 地址。
步骤: #
修改 Nginx 配置文件:
打开 Nginx 的配置文件(通常是
/etc/nginx/nginx.conf
或者是/etc/nginx/sites-available/default
等文件,具体路径根据安装方式而不同)。添加或修改
proxy_set_header
指令:在反向代理相关的
location
块中,添加X-Forwarded-For
头部。通常,你需要确保传递正确的客户端 IP 地址。修改或添加如下内容:
location / { proxy_pass http://backend_server; proxy_set_header X-Real-IP $remote_addr; # 将客户端真实IP传递给后端 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 保留原有的X-Forwarded-For头 proxy_set_header X-Forwarded-Proto $scheme; # 如果需要,还可以传递协议类型(http 或 https) }
解释:
proxy_set_header X-Real-IP $remote_addr;
:将客户端的真实 IP 地址($remote_addr
)传递给后端服务器。proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
:将客户端的 IP 地址添加到X-Forwarded-For
头部。$proxy_add_x_forwarded_for
会将客户端的 IP 地址追加到现有的X-Forwarded-For
头部(如果该头部已经存在的话)。proxy_set_header X-Forwarded-Proto $scheme;
:如果你的服务器使用了 HTTPS 或者 HTTP,可以通过此头部传递协议类型,后端可以根据此值判断请求是使用的 HTTPS 还是 HTTP。
确保后端服务器正确解析
X-Forwarded-For
:- 后端应用程序(如 Web 服务器)需要从
X-Forwarded-For
头部获取客户端的真实 IP 地址,而不是直接使用REMOTE_ADDR
。通常,大多数 Web 框架(如 PHP、Django、Node.js)会自动处理这一点,但如果需要,可能需要手动配置代码来读取该头部。 - 在一些常见的 Web 服务器配置中,可以参考以下方法:
- Apache: 可以使用
mod_remoteip
模块来读取X-Forwarded-For
头部。 - PHP: 使用
$_SERVER['HTTP_X_FORWARDED_FOR']
来获取客户端 IP 地址。 - Node.js: 在请求对象中查看
req.headers['x-forwarded-for']
。
- Apache: 可以使用
- 后端应用程序(如 Web 服务器)需要从
重启 Nginx:
配置修改完成后,记得重启 Nginx 使更改生效:
sudo nginx -t # 测试配置是否正确 sudo systemctl restart nginx # 重启 Nginx
重要提示: #
代理链中的多个代理:如果请求经过多个代理服务器(比如 Nginx 后面还有其他的负载均衡器),
X-Forwarded-For
头部将包含多个 IP 地址。第一个 IP 地址通常是客户端的真实 IP,后面的 IP 地址是中间代理服务器的 IP 地址。你可以根据需要处理这些地址。例如,如果后端希望获取真实的客户端 IP 地址(即第一个 IP),需要从
X-Forwarded-For
头部获取第一个 IP 地址。# 示例:从 X-Forwarded-For 获取第一个 IP 地址 client_ip = request.headers.get('X-Forwarded-For', '').split(',')[0]
安全性:由于
X-Forwarded-For
头部可以被客户端伪造,因此在没有可信代理的情况下,最好只信任来自 Nginx 服务器的X-Forwarded-For
头部。为了避免头部被伪造,可以只允许特定的代理服务器添加此头部,而不信任来自客户端的请求。
总结: #
通过在 Nginx 中设置 proxy_set_header X-Real-IP
和 proxy_set_header X-Forwarded-For
,你可以将客户端的真实 IP 地址传递到后端服务器。后端可以从这些头部获取客户端的真实 IP 地址,而不是 Nginx 的 IP 地址。
17. nginx负载均衡算法有哪些? #
- rr 轮训
- weight 加权轮训
- ip_hash 静态调度算法
- fair 动态调度算法
- url_hash url哈希
- leat_conn 最小连接数
Nginx 提供了多种负载均衡算法,用于将客户端请求分发到多个后端服务器。根据不同的需求和场景,你可以选择不同的算法。下面是 Nginx 支持的常见负载均衡算法:
1. 轮询(Round Robin) #
默认算法:Nginx 默认使用的是轮询(Round Robin)算法。
描述:将请求按顺序轮流分发给每个后端服务器,适合后端服务器性能相似的场景。
特点
:
- 简单有效,负载分配均匀。
- 没有考虑每个服务器的负载情况。
- 对于大部分场景是有效的,但在后端服务器性能不均衡时,可能导致一些服务器负载过高,另一些服务器几乎没有负载。
upstream backend {
server backend1.example.com;
server backend2.example.com;
}
2. 最少连接(Least Connections) #
描述:将请求转发给当前连接数最少的后端服务器。这个算法适合请求处理时间不均匀的应用场景。
特点
:
- 更加智能,根据每个后端服务器的负载情况分配请求。
- 可以避免某些服务器被过载(当请求处理时间不均匀时)。
- 对于高并发和长连接场景(如 HTTP 长连接)效果显著。
upstream backend {
least_conn;
server backend1.example.com;
server backend2.example.com;
}
3. IP 哈希(IP Hash) #
描述:根据客户端的 IP 地址计算哈希值,然后将请求分发到与该哈希值对应的服务器。这样,同一个客户端的请求会始终发送到同一台后端服务器(持久连接)。
特点
:
- 保证同一个客户端的请求总是分发到相同的后端服务器。
- 适用于需要会话保持的场景(例如购物车等状态依赖于会话的应用)。
- 不一定能平衡负载,特别是在客户端 IP 分布不均匀时,某些服务器可能会收到更多请求。
upstream backend {
ip_hash;
server backend1.example.com;
server backend2.example.com;
}
4. 加权轮询(Weighted Round Robin) #
描述:在轮询的基础上为每个服务器设置一个权重值,根据权重值来调整请求的分配比例。权重高的服务器将获得更多的请求。
特点
:
- 适用于后端服务器性能不均衡的场景。
- 权重可以设置为任意正整数,表示每台服务器的负载能力。
- 更灵活,可以根据后端服务器的性能调整请求的分配策略。
upstream backend {
server backend1.example.com weight=3;
server backend2.example.com weight=1;
}
5. 加权最少连接(Weighted Least Connections) #
描述:结合最少连接和权重的概念,根据每个后端服务器的当前连接数和设置的权重来分配请求。服务器的权重较高且连接较少时,将获得更多的请求。
特点
:
- 动态分配请求,根据每个服务器的连接数和权重调整负载。
- 适用于负载情况较为复杂的场景。
upstream backend {
least_conn;
server backend1.example.com weight=3;
server backend2.example.com weight=1;
}
6. 随机(Random) #
描述:将请求随机地分发到后端服务器。这个算法简单,适用于负载非常均衡的情况。
特点
:
- 非常简单且随机,适用于请求不太频繁的负载均衡场景。
- 可能会导致请求不均匀分布。
upstream backend {
random;
server backend1.example.com;
server backend2.example.com;
}
7. 最少响应时间(Least Time) (Nginx Plus) #
描述:这个算法基于服务器的响应时间来分配请求,选择响应时间最短的服务器。Nginx Plus 提供了这个功能,它会选择响应时间最短的服务器来处理请求。
特点
:
- 会动态根据服务器的响应时间来分配请求。
- 可以避免服务器因响应过慢导致其他请求堆积。
upstream backend {
least_time;
server backend1.example.com;
server backend2.example.com;
}
总结: #
- Round Robin:简单、均衡,适合负载相对均衡的场景。
- Least Connections:根据连接数选择后端,适合负载不均的情况。
- IP Hash:基于客户端 IP 保证同一个客户端始终访问同一服务器,适合需要会话保持的应用。
- Weighted Round Robin:为每台服务器指定权重,适合后端服务器性能不均的情况。
- Weighted Least Connections:结合了最少连接和权重,适用于更复杂的负载均衡场景。
- Random:简单、随机,适用于负载非常均衡的情况。
- Least Time:基于响应时间选择后端,适合需要低延迟的场景(仅限 Nginx Plus)。
选择负载均衡算法时,需要根据后端服务器的性能、应用场景、请求处理时长等因素来决定最合适的算法。
18. 如何进行压力测试? #
例如:模拟10个用户,对百度首页发起总共100次请求。 测试命令: ab -n 100 -c 10 https://www.baidu.com/index.htm
进行压力测试是评估系统、应用程序或网络在高负载情况下表现的一个重要步骤。通过压力测试,可以发现系统的瓶颈、性能瓶颈和潜在的可扩展性问题。常见的压力测试包括并发用户负载测试、请求吞吐量测试、延迟测试等。
以下是进行压力测试的常见方法和工具:
1. 使用 Apache JMeter 进行压力测试 #
JMeter 是一个流行的开源性能测试工具,广泛用于 Web 应用程序、数据库和其他服务器的压力测试。
步骤: #
- 下载并安装 JMeter:
- 从 JMeter 官网 下载并解压。
- 创建测试计划:
- 打开 JMeter,创建一个新的测试计划(Test Plan)。
- 在测试计划中添加线程组(Thread Group),线程组指定了模拟的虚拟用户数和循环次数。
- 配置线程组:
- Thread Group:设置用户数(Number of Threads)、循环次数(Loop Count)以及启动延迟(Ramp-Up Period)。
- 每个线程代表一个模拟的并发用户。
- 添加 HTTP 请求:
- 在线程组下,添加 HTTP 请求(HTTP Request),配置目标 Web 服务器的地址、端口和请求参数。
- 添加监听器:
- 在测试计划中添加不同的监听器(Listener),如聚合报告、图形结果、查看结果树等,用于记录测试结果并生成报告。
- 运行测试并分析结果:
- 点击运行按钮开始测试,查看实时结果和图表,分析系统的响应时间、吞吐量、错误率等。
典型场景: #
- 测试 Web 应用、API 的并发性能。
- 负载、压力、容量和稳定性测试。
2. 使用 Locust 进行压力测试 #
Locust 是一个基于 Python 的开源负载测试工具,支持分布式压力测试。
步骤: #
安装 Locust:
pip install locust
编写测试脚本:
创建一个 Python 脚本,定义用户行为(任务),例如:
from locust import HttpUser, task, between class WebsiteUser(HttpUser): wait_time = between(1, 5) @task def load_main_page(self): self.client.get("/") @task def load_about_page(self): self.client.get("/about")
运行 Locust:
locust -f your_locust_file.py
访问 Web 界面:
- 默认情况下,Locust 会在
http://localhost:8089
启动一个 Web 界面,您可以在界面中配置并发用户数、生成报告、查看测试结果等。
- 默认情况下,Locust 会在
典型场景: #
- API、Web 应用的性能测试。
- 分布式负载测试,多个机器可以一起参与。
3. 使用 ab (Apache Bench) 进行压力测试 #
Apache Bench 是一个轻量级的命令行工具,通常用于简单的 HTTP 负载测试。
步骤: #
运行 ab 命令:
ab -n 1000 -c 10 http://your-server.com/
-n 1000
:指定总请求数为 1000。-c 10
:设置并发请求数为 10。
分析结果:
ab
会输出请求的响应时间、吞吐量、请求成功率等性能指标。
典型场景: #
- 简单的压力测试,适用于快速验证 Web 服务器的性能。
- 测试 API 或静态资源的吞吐量。
4. 使用 siege 进行压力测试 #
Siege 是一个命令行压力测试工具,支持对 Web 应用进行负载测试。
步骤: #
安装 Siege:
在 Linux 系统上,使用以下命令安装:
sudo apt install siege
运行 Siege 测试:
siege -c 50 -t 30S http://your-server.com/
-c 50
:指定并发用户数为 50。-t 30S
:指定测试持续时间为 30 秒。
分析结果:
- Siege 会显示测试的响应时间、成功请求数、错误率等指标。
典型场景: #
- 测试 Web 服务器在不同负载下的性能。
- 持续压力测试,分析系统在长时间运行下的表现。
5. 使用 Gatling 进行压力测试 #
Gatling 是一个高性能的负载测试工具,适用于 HTTP、WebSocket 和其他协议的压力测试。
步骤: #
下载并安装 Gatling:
- 从 Gatling 官网 下载并安装。
编写测试脚本:
使用 Scala 编写测试脚本,模拟用户行为和负载,例如:
class BasicSimulation extends Simulation { val httpProtocol = http .baseUrl("http://your-server.com") .acceptHeader("application/json") val scn = scenario("Basic Load Test") .exec(http("request_1").get("/")) setUp( scn.inject(atOnceUsers(100)) ).protocols(httpProtocol) }
运行测试:
./bin/gatling.sh -s BasicSimulation
分析结果:
- Gatling 会生成 HTML 格式的报告,展示响应时间、吞吐量、错误率等。
典型场景: #
- 高并发用户模拟。
- 跨多协议的压力测试。
6. 使用 Artillery 进行压力测试 #
Artillery 是一个轻量级、强大的负载测试工具,支持 HTTP、WebSocket 等协议。
步骤: #
安装 Artillery:
npm install -g artillery
编写测试脚本:
使用 YAML 配置文件定义测试场景:
config: target: 'http://your-server.com' phases: - duration: 60 arrivalRate: 10 scenarios: - flow: - get: url: "/"
运行测试:
artillery run your_test_config.yml
分析结果:
- Artillery 会输出实时测试结果,并生成详细报告。
典型场景: #
- Web 应用和 API 性能测试。
- 简单的压力和负载测试,支持高并发。
总结: #
- JMeter:功能强大,适用于复杂的负载测试,支持分布式测试。
- Locust:基于 Python,适合高并发分布式测试。
- ab:简单易用,适合基础的压力测试。
- Siege:命令行工具,适用于快速的压力测试。
- Gatling:高性能,适用于高并发的应用程序测试。
- Artillery:现代的负载测试工具,适用于简单和高效的负载测试。
选择工具时,根据你的具体需求(如并发数、分布式支持、脚本编写难易度等)来选择最合适的压力测试工具。
19. curl命令如何发送https请求?如何查看response头信息?如何发送get和post表单信息? #
- 发送https请求:curl –tlsv1 ‘https://www.bitstamp.net/api/v2/transactions/btcusd/’
- response头信息 :curl -I
- get:curl 请求地址?key1=value1&key2=value2&key3=value3
- post: curl -d “key1=value1&key2=value2&key3=value3”
curl
是一个非常常用的命令行工具,支持多种协议,包括 HTTP 和 HTTPS。你可以使用 curl
发送 HTTPS 请求、查看响应头信息,并发送 GET 或 POST 请求。下面是一些常见用法:
1. 发送 HTTPS 请求 #
要发送一个简单的 HTTPS 请求,只需要指定 URL,并且 curl
会自动使用 HTTPS 协议。
curl https://www.example.com
2. 查看响应头信息 #
如果你只想查看响应头,而不关心响应体,可以使用 -I
(大写字母 i)选项。这样 curl
会发送一个 HEAD
请求,只返回响应头。
curl -I https://www.example.com
如果你想同时查看响应头和响应体,可以使用 -i
(小写字母 i)选项:
curl -i https://www.example.com
3. 发送 GET 请求 #
curl
默认使用 GET 方法,如果你只需要发送一个 GET 请求,可以直接写 URL:
curl https://www.example.com?key=value&anotherkey=anothervalue
如果你希望更加明确地指定使用 GET 请求,可以使用 -X
选项(尽管 curl
默认是 GET):
curl -X GET https://www.example.com?key=value
4. 发送 POST 请求 #
发送 POST 请求时,你需要使用 -X POST
来指定请求方法为 POST,并且用 -d
来传递请求的表单数据。
发送表单数据(x-www-form-urlencoded) #
curl -X POST https://www.example.com -d "key1=value1&key2=value2"
或者使用 --data
(等同于 -d
):
curl --data "key1=value1&key2=value2" https://www.example.com
发送 POST 请求并传递 JSON 数据 #
如果你需要发送 JSON 格式的数据,可以设置 Content-Type
头部为 application/json
,并传递 JSON 数据:
curl -X POST https://www.example.com \
-H "Content-Type: application/json" \
-d '{"key1": "value1", "key2": "value2"}'
发送带文件的 POST 请求 #
如果你需要发送文件,可以使用 -F
选项来模拟表单文件上传:
curl -X POST https://www.example.com/upload -F "file=@/path/to/file"
发送带 Cookie 的 POST 请求 #
如果你需要在 POST 请求中携带 Cookie,可以使用 -b
(或者 --cookie
)选项:
curl -X POST https://www.example.com \
-b "name=value" \
-d "key1=value1&key2=value2"
5. 发送带自定义头的请求 #
你可以使用 -H
选项来设置自定义的请求头。例如,设置 User-Agent
和 Authorization
头:
curl -X POST https://www.example.com \
-H "User-Agent: MyCustomAgent" \
-H "Authorization: Bearer your_token_here" \
-d "key1=value1&key2=value2"
总结 #
- 发送 HTTPS 请求:
curl https://example.com
- 查看响应头:
curl -I https://example.com
- 查看响应头和响应体:
curl -i https://example.com
- 发送 GET 请求:
curl https://example.com?key=value
- 发送 POST 请求(表单数据):
curl -X POST https://example.com -d "key=value"
- 发送 JSON 数据的 POST 请求:
curl -X POST https://example.com -H "Content-Type: application/json" -d '{"key": "value"}'
- 发送文件的 POST 请求:
curl -X POST https://example.com -F "file=@/path/to/file"
- 携带 Cookie 的 POST 请求:
curl -X POST https://example.com -b "name=value" -d "key=value"
通过这些基本命令,你可以使用 curl
进行各种类型的 HTTP/HTTPS 请求,并控制请求和响应的各个方面。
二、mysql #
1. 索引的为什么使查询加快?有啥缺点? #
默认的方式是根据搜索条件进行全表扫描,遇到匹配条件的就加入搜索结果集合。如果我们对某一字段增加索引,查询时就会先去索引列表中一次定位到特定值的行数,大大减少遍历匹配的行数,所以能明显增加查询的速度 缺点:
- 创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加
- 索引需要占物理空间,除了数据表占用数据空间之外,每一个索引还要占用一定的物理空间,如果需要建立聚簇索引,那么需要占用的空间会更大
- 以表中的数据进行增、删、改的时候,索引也要动态的维护,这就降低了整数的维护速度
索引 是数据库管理系统(DBMS)中的一种数据结构,用于加速数据的检索过程。索引通过在表中创建一个排序的数据结构,使得数据库可以更高效地查找数据。简单来说,索引就像书籍的目录,它帮助我们快速找到目标信息,而不需要从头到尾逐一查找。
为什么索引能加快查询? #
- 减少全表扫描:
- 如果没有索引,数据库查询通常需要对整个表进行全表扫描(扫描每一行)。对于大表,这种方式非常慢。
- 索引通过提供一个有序的数据结构(如 B+ 树),使得数据库可以通过二分查找或者树形查找等高效算法快速定位到目标数据,而不需要扫描整个表。
- 提高检索效率:
- 在没有索引时,查找某个值的时间复杂度是 O(n),即需要逐行扫描。
- 有了索引后,查找时间复杂度降低为 O(log n)(例如 B+ 树),可以大大提升查询速度。
- 减少磁盘 I/O:
- 索引通常存储在磁盘上,但它比整个数据表小,因此查找一个值时,只需要读取少量的磁盘数据。
- 在磁盘和内存之间的 I/O 操作是数据库操作中的瓶颈,使用索引可以显著减少这种 I/O 操作,提升性能。
- 加速排序和聚合操作:
- 索引不仅能加速查询,还能加速排序(ORDER BY)和聚合(GROUP BY)操作。
- 如果查询涉及到排序和分组,索引可以直接提供有序的数据,避免了额外的排序操作。
索引的缺点和限制 #
虽然索引在提高查询性能方面有显著的优势,但它也存在一些缺点和限制:
- 占用存储空间:
- 每个索引都会消耗一定的存储空间,特别是在有大量索引的情况下。对于大表,多个索引的存储开销可能非常大,尤其是当表的数据量不断增加时。
- 索引本身也是需要存储在磁盘上的,如果不合理使用索引,可能会导致磁盘空间的浪费。
- 降低写入性能:
- 每当向表中插入、更新或删除数据时,相关的索引也需要更新。因此,写操作(如
INSERT
、UPDATE
、DELETE
)的性能会受到影响,尤其是在有多个索引的情况下。 - 例如,插入新记录时,不仅要将数据插入到表中,还要将该数据的索引条目添加到相应的索引中。更新和删除操作也同样会导致索引的重新调整。
- 每当向表中插入、更新或删除数据时,相关的索引也需要更新。因此,写操作(如
- 索引的选择和维护成本:
- 在大型数据库系统中,选择哪些列建立索引、使用哪种类型的索引(例如 B+ 树、哈希索引等)需要根据具体查询的情况进行评估。这需要一定的经验和知识。
- 随着数据量的增长,索引的维护也变得更加复杂。例如,某些索引可能变得过时或不再有效,可能需要重新设计或调整。
- 影响查询优化器的选择:
- 在某些情况下,过多的索引可能会影响查询优化器的决策。查询优化器可能选择一个较差的索引路径,导致查询性能下降。
- 在有多个索引的情况下,数据库可能需要评估哪些索引最优,但优化器的选择并不总是完美的,可能会选择不适合当前查询的索引。
- 索引的更新和重建:
- 当表的数据发生变化时,索引会被更新,随着时间的推移,索引可能会变得不平衡或碎片化,影响查询性能。
- 在某些情况下,可能需要定期重建索引或重新组织索引,以保持查询性能。
总结: #
- 优点:
- 加速查询:通过减少全表扫描,使得数据检索更加高效。
- 提高排序和聚合操作:索引可以加速排序(
ORDER BY
)和聚合(GROUP BY
)操作。 - 减少磁盘 I/O:减少查询过程中的磁盘读取,提高查询效率。
- 缺点:
- 占用存储空间:索引占用额外的磁盘空间。
- 降低写入性能:每次写操作都需要更新相关的索引。
- 索引维护成本:需要定期更新和优化索引,维护复杂。
- 不当索引选择:可能导致查询优化器选择错误的索引,影响查询性能。
合理地使用索引,可以显著提升查询性能。但也要平衡索引带来的开销,根据具体业务需求和查询特点,选择合适的索引类型和数量。
2. sql语句左外连接 右外连接 内连接 全连接区别 #
在 SQL 中,JOIN
用于从多个表中查询数据,LEFT JOIN
、RIGHT JOIN
、INNER JOIN
和 FULL JOIN
是常见的几种连接类型,它们用于指定表之间数据的连接方式。每种连接类型的行为有所不同,以下是它们的详细区别:
1. 内连接 (INNER JOIN) #
定义:INNER JOIN
返回的是两个表中满足连接条件的交集,即只返回两个表中都有的匹配数据。
- 行为:如果两个表中有相同的匹配记录,则返回这些记录。对于没有匹配的记录,
INNER JOIN
不会返回。
示例: #
SELECT *
FROM employees e
INNER JOIN departments d ON e.department_id = d.department_id;
这个查询将返回所有有匹配的 employees
和 departments
的记录。
特点: #
- 只返回两个表中匹配的记录。
- 如果一个表中没有匹配,数据行就不会出现在结果中。
2. 左外连接 (LEFT JOIN 或 LEFT OUTER JOIN) #
定义:LEFT JOIN
返回的是左表(LEFT
)中的所有记录以及右表(RIGHT
)中与左表匹配的记录。如果右表没有匹配的记录,右表的列将包含 NULL
。
- 行为:返回左表中的所有行,即使右表没有与左表匹配的行。对于没有匹配的右表行,将会显示
NULL
。
示例: #
SELECT *
FROM employees e
LEFT JOIN departments d ON e.department_id = d.department_id;
这个查询将返回 employees
表中的所有记录,即使某些员工没有对应的 department_id
(右表为空时会返回 NULL
)。
特点: #
- 返回左表(
LEFT
)中的所有记录。 - 如果右表没有匹配,右表的值将为
NULL
。
3. 右外连接 (RIGHT JOIN 或 RIGHT OUTER JOIN) #
定义:RIGHT JOIN
返回的是右表(RIGHT
)中的所有记录以及左表(LEFT
)中与右表匹配的记录。如果左表没有匹配的记录,左表的列将包含 NULL
。
- 行为:返回右表中的所有行,即使左表没有与右表匹配的行。对于没有匹配的左表行,将会显示
NULL
。
示例: #
SELECT *
FROM employees e
RIGHT JOIN departments d ON e.department_id = d.department_id;
这个查询将返回 departments
表中的所有记录,即使某些部门没有员工(左表为空时会返回 NULL
)。
特点: #
- 返回右表(
RIGHT
)中的所有记录。 - 如果左表没有匹配,左表的值将为
NULL
。
4. 全外连接 (FULL JOIN 或 FULL OUTER JOIN) #
定义:FULL JOIN
返回的是两个表中的所有记录。如果某个表中没有与另一个表匹配的行,缺少的部分将用 NULL
填充。
- 行为:返回两个表中的所有行。如果某个表中没有匹配,另一个表的列会显示
NULL
。
示例: #
SELECT *
FROM employees e
FULL JOIN departments d ON e.department_id = d.department_id;
这个查询将返回 employees
和 departments
表中的所有记录。如果一个表中的某些记录在另一个表中没有匹配,则会填充 NULL
。
特点: #
- 返回两个表中的所有记录。
- 如果某个表没有匹配,结果中的缺失部分用
NULL
填充。
总结: #
连接类型 | 返回记录 | 含义 |
---|---|---|
INNER JOIN | 只返回两个表中匹配的记录。 | 只返回两个表中满足连接条件的记录。 |
LEFT JOIN | 返回左表的所有记录,以及右表中匹配的记录。右表没有匹配时返回 NULL 。 | 返回左表的所有记录,并且如果右表没有匹配,右表的值为 NULL 。 |
RIGHT JOIN | 返回右表的所有记录,以及左表中匹配的记录。左表没有匹配时返回 NULL 。 | 返回右表的所有记录,并且如果左表没有匹配,左表的值为 NULL 。 |
FULL JOIN | 返回两个表的所有记录。若某个表没有匹配,缺失部分为 NULL 。 | 返回两个表中的所有记录,若某个表没有匹配,用 NULL 填充。 |
举例说明: #
假设有两张表:employees
和 departments
。
employees 表:
employee_id | name | department_id |
---|---|---|
1 | Alice | 101 |
2 | Bob | 102 |
3 | Charlie | NULL |
departments 表:
department_id | department_name |
---|---|
101 | HR |
102 | IT |
103 | Finance |
- INNER JOIN 结果:
- 只会返回
department_id
为 101 和 102 的员工,即 Alice 和 Bob。
- 只会返回
- LEFT JOIN 结果:
- 返回所有员工,Bob 和 Alice 会显示部门名称,Charlie 会显示
NULL
部门。
- 返回所有员工,Bob 和 Alice 会显示部门名称,Charlie 会显示
- RIGHT JOIN 结果:
- 返回所有部门,HR 和 IT 部门对应的员工会显示,Finance 部门没有员工,所以员工列为
NULL
。
- 返回所有部门,HR 和 IT 部门对应的员工会显示,Finance 部门没有员工,所以员工列为
- FULL JOIN 结果:
- 返回所有员工和所有部门,无论是否匹配。没有匹配的部门或员工都会显示
NULL
。
- 返回所有员工和所有部门,无论是否匹配。没有匹配的部门或员工都会显示
通过选择适合的连接类型,可以根据实际需求灵活地获取所需的数据。
3. mysql数据备份方式,如何恢复?你们的备份策略是什么? #
- 物理完全备份
备份所有数据库文件:/var/lib/mysql/* 备份所有binlog文件: /var/lib/mysql/mysql-bin.* 备份选项文件: /etc/my.cnf
- mysqldump逻辑备份
mysqldump -uroot -p –all-databases > /backup/mysqldump/all.db
- 物理备份恢复
mv /var/lib/mysql /var/lib/mysql.old #先把原来的数据目录改名 cp -a /backups/mysql /var/lib
- 逻辑备份数据恢复
mysql > use db_name mysql > source /backup/mysqldump/db_name.db
在 MySQL 中,数据备份是保障数据安全和防止数据丢失的重要措施。备份方式有多种,每种备份方式在不同场景下有不同的优劣。下面是常见的 MySQL 数据备份方式和恢复方法,并提供一份备份策略的参考。
常见的 MySQL 数据备份方式 #
逻辑备份(Logical Backup)
方式:通过 SQL 脚本导出数据库的表结构和数据。
工具:
mysqldump
优点
:
- 备份文件是纯文本,可以跨平台恢复。
- 适用于小型数据库、迁移数据库到不同平台。
缺点
:
- 备份速度较慢,尤其对于大规模数据表,备份文件会很大。
- 需要更多的存储空间来存放备份文件。
如何备份 #
mysqldump -u username -p database_name > backup.sql
如何恢复 #
mysql -u username -p database_name < backup.sql
物理备份(Physical Backup)
方式:直接复制数据库数据文件,通常通过
xtrabackup
或文件系统的备份。工具:
Percona XtraBackup
,cp
或rsync
(在停机或只读模式下)优点
:
- 备份速度快,适合大规模数据备份。
- 恢复速度快,直接复制数据文件即可恢复。
缺点
:
- 需要确保备份期间没有修改数据,通常会要求停机或者锁定表。
- 备份文件是二进制文件,跨平台恢复较麻烦。
如何备份 #
使用
Percona XtraBackup
:innobackupex --user=username --password=password /path/to/backup
如何恢复 #
innobackupex --apply-log /path/to/backup innobackupex --copy-back /path/to/backup
增量备份(Incremental Backup)
方式:只备份自上次备份以来发生变化的数据。
工具:
Percona XtraBackup
(支持增量备份)。优点
:
- 备份速度比全量备份快,节省存储空间。
- 适用于需要频繁备份和恢复的场景。
缺点
:
- 恢复时需要先恢复最后的全量备份,然后再恢复所有增量备份。
- 增量备份需要管理更多的备份文件,增加了恢复复杂度。
如何备份 #
使用
Percona XtraBackup
:innobackupex --user=username --password=password --incremental /path/to/incremental_backup --incremental-basedir /path/to/previous_backup
如何恢复 #
首先恢复全量备份,然后按顺序恢复增量备份:
innobackupex --apply-log /path/to/full_backup innobackupex --apply-log --incremental-dir /path/to/incremental_backup /path/to/full_backup
二进制日志备份(Binary Log Backup)
方式:备份 MySQL 的二进制日志,以便在全量备份后,捕获和恢复增量变更。
工具:
mysqlbinlog
优点
:
- 可以记录所有的数据修改操作,用于恢复和点时间恢复(PITR)。
- 支持备份期间的数据变化捕获。
缺点
:
- 需要定期备份和归档二进制日志。
- 恢复过程相对复杂。
如何备份 #
在 MySQL 配置文件中启用二进制日志:
[mysqld] log-bin=mysql-bin
获取二进制日志:
mysqlbinlog /var/lib/mysql/mysql-bin.000001 > binary_log.sql
如何恢复 #
将二进制日志应用到备份数据库中:
mysqlbinlog /path/to/binary_log | mysql -u username -p database_name
恢复的常见方式 #
恢复的方式与备份方式相关。常见的恢复方式有以下几种:
- 从逻辑备份恢复:直接执行
.sql
文件恢复。 - 从物理备份恢复:将备份文件复制回数据库的相关目录,并确保权限正确。
- 从增量备份恢复:先恢复全量备份,再应用所有增量备份。
- 从二进制日志恢复:将二进制日志文件中的操作应用到备份数据中,恢复到特定时间点。
MySQL 备份策略 #
一个良好的备份策略应该根据业务的需求、数据量和恢复要求来制定,以下是一个常见的备份策略:
- 全量备份: 每周进行一次全量备份(比如每周日进行)。这确保了我们可以快速恢复到一个较为完整的状态。
- 增量备份: 每天进行增量备份,备份自上次全量或增量备份以来变化的数据。增量备份可以减少备份数据的大小和备份时间。
- 二进制日志备份: 开启二进制日志,并每小时或每次应用更新时备份日志。这样可以保证在全量和增量备份之间的变更也能被备份,并在需要时进行点时间恢复(PITR)。
- 备份存储:
- 将备份存储在不同的物理位置(如备份到云端,或使用本地和远程存储)。
- 保持一定数量的备份副本(如保留过去 7 天的备份)。
- 使用加密来保护备份数据的安全性。
- 定期验证备份:
- 定期执行恢复演练,确保备份文件有效且恢复过程可行。
- 备份保留策略:
- 保留一定时间内的备份(如每月的全量备份保留一个月,日常增量备份保留一周)。
- 自动化备份:
- 使用脚本或备份工具(如
cron
、Percona XtraBackup
等)自动化备份过程,减少人为干预。
- 使用脚本或备份工具(如
总结: #
- 备份方式:
- 逻辑备份(
mysqldump
)适用于小型数据库或跨平台迁移。 - 物理备份(
Percona XtraBackup
)适用于大规模数据库,恢复速度快。 - 增量备份适用于大数据量并且需要频繁备份的场景。
- 二进制日志备份用于捕获和恢复数据库的变更操作。
- 逻辑备份(
- 恢复方式:
- 根据备份方式,恢复流程也会有所不同。通常包括从备份文件恢复或应用增量备份、二进制日志恢复等。
- 备份策略:
- 定期全量备份+增量备份+二进制日志备份,并确保备份存储的安全性、可恢复性和备份文件的有效性。
4. 如何配置数据库主从同步,实际工作中是否遇到数据不一致问题?如何解决? #
为每个服务器配置唯一值的server-id
- 主库
开启binlog日志 创建主从复制用户 查看master的状态
- 从库
change master to设置主库信息 start slave开始复制
数据库主从同步配置 #
在 MySQL 中,主从同步(Master-Slave Replication)是一种常见的数据库复制方式,用于实现数据的高可用性和负载均衡。配置 MySQL 主从同步通常涉及以下几个步骤:
1. 配置主服务器(Master) #
首先,确保主服务器配置为允许复制操作,并创建一个专门的复制用户。
步骤 1: 配置主服务器的 my.cnf
配置文件
#
编辑主服务器上的 my.cnf
(或 my.ini
,视操作系统而定)配置文件,启用二进制日志(binlog
)并配置唯一的服务器 ID。
[mysqld]
server-id = 1
log-bin = mysql-bin
binlog-do-db = your_database_name # 可选,只复制指定的数据库
server-id
:每个 MySQL 实例必须有唯一的server-id
,且主服务器和从服务器的server-id
必须不同。log-bin
:启用二进制日志,这样从服务器可以获取主服务器上的所有变更事件。binlog-do-db
:如果只希望同步某个特定数据库的数据,可以在这里配置。
步骤 2: 创建复制用户 #
登录到主服务器的 MySQL,创建一个用于复制的专用用户,并授权。
CREATE USER 'replica_user'@'%' IDENTIFIED BY 'password';
GRANT REPLICATION SLAVE ON *.* TO 'replica_user'@'%';
FLUSH PRIVILEGES;
replica_user
:复制用户,%
表示允许所有 IP 连接。REPLICATION SLAVE
权限:允许从服务器读取二进制日志。
步骤 3: 获取主服务器的二进制日志位置 #
在配置主从同步之前,需要获取主服务器的当前二进制日志文件名和位置。执行以下命令:
SHOW MASTER STATUS;
输出类似于:
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000001 | 1234 | your_database_name | |
+------------------+----------+--------------+------------------+
记录下 File
和 Position
,稍后需要在从服务器配置时使用。
2. 配置从服务器(Slave) #
接下来,配置从服务器使其能够接收并执行主服务器的更新。
步骤 1: 配置从服务器的 my.cnf
配置文件
#
编辑从服务器的 my.cnf
配置文件,设置唯一的 server-id
。
[mysqld]
server-id = 2 # 从服务器的 ID 必须与主服务器不同
步骤 2: 启动从服务器复制 #
登录到从服务器的 MySQL,执行以下命令配置复制信息:
CHANGE MASTER TO
MASTER_HOST = 'master_ip', -- 主服务器的 IP 地址
MASTER_USER = 'replica_user', -- 复制用户
MASTER_PASSWORD = 'password', -- 复制用户密码
MASTER_LOG_FILE = 'mysql-bin.000001', -- 主服务器的二进制日志文件名
MASTER_LOG_POS = 1234; -- 主服务器的二进制日志位置
START SLAVE;
MASTER_HOST
:主服务器的 IP 地址。MASTER_USER
和MASTER_PASSWORD
:复制用户和密码。MASTER_LOG_FILE
和MASTER_LOG_POS
:主服务器的二进制日志文件名和位置(通过SHOW MASTER STATUS
获取)。
步骤 3: 检查复制状态 #
使用以下命令查看从服务器的复制状态,确保没有错误:
SHOW SLAVE STATUS\G
你应该看到如下信息:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Slave_IO_Running
:表示从服务器是否能从主服务器读取二进制日志。Slave_SQL_Running
:表示从服务器是否能执行读取到的 SQL 语句。
如果都为 Yes
,说明主从同步已经正常工作。
3. 验证同步是否正常 #
插入测试数据:在主服务器上插入数据,检查从服务器是否同步。
INSERT INTO your_table (column1, column2) VALUES ('value1', 'value2');
在从服务器查询:在从服务器上检查该数据是否已同步。
SELECT * FROM your_table;
如果数据同步正常,那么配置成功。
实际工作中遇到的数据不一致问题 #
在实际工作中,主从同步通常能工作良好,但也可能会遇到以下常见的 数据不一致问题:
1. 延迟(Replication Lag) #
问题:从服务器延迟同步主服务器上的数据,导致从服务器的数据滞后。
原因
:
- 主服务器的写入频繁,二进制日志增长过快。
- 从服务器的性能较差,无法及时执行来自主服务器的更新。
- 网络延迟或主从服务器的硬件瓶颈。
解决方案
:
- 优化从服务器性能,增加硬件资源(CPU、内存、磁盘 IO)。
- 调整 MySQL 配置,增加
slave_parallel_workers
参数并启用并行复制(适用于 MySQL 5.7 及以上版本)。 - 使用
pt-heartbeat
等工具来监控延迟并优化。 - 监控复制延迟并根据需要进行警告。
2. 数据丢失(Data Loss) #
问题:主服务器发生故障,导致主服务器的数据丢失,但从服务器数据尚未同步。
原因
:
- 主服务器停机或崩溃时,未及时备份或持久化数据。
- 从服务器的复制延迟过大,主服务器的数据还未同步到从服务器。
解决方案
:
- 启用 MySQL 的 GTID(全局事务标识符)或 binlog,以确保事务的完整性。
- 定期进行备份,确保有最新的数据库备份。
- 使用双主或多主复制架构来减少单点故障的风险。
3. 复制失败(Replication Errors) #
问题:复制过程中出现错误,导致从服务器无法同步主服务器的数据。
原因
:
- 主服务器上执行了从服务器无法理解或执行的 SQL 语句(例如,删除字段、数据类型变化)。
- 网络或连接问题导致复制中断。
解决方案
:
- 使用
SHOW SLAVE STATUS
查看错误信息,识别并解决复制失败的原因。 - 可以通过执行
STOP SLAVE;
,然后使用START SLAVE UNTIL SQL_AFTER_GTIDS='gtid_set'
指令来跳过错误的事务,确保复制继续。 - 使用
pt-table-sync
等工具进行数据对齐,确保主从数据一致。
- 使用
4. 不一致的数据库结构(Schema Divergence) #
问题:主从服务器的数据库结构(表结构、索引等)不一致,导致从服务器复制失败。
原因
:
- 主服务器上的数据库结构发生了变化(例如添加了新表、修改了字段),但未同步到从服务器。
解决方案
:
- 确保主从数据库的结构一致,可以使用工具(如
pt-table-checksum
)来校验主从数据库结构是否一致。 - 在执行结构变更时,确保主从服务器一起变更。
- 确保主从数据库的结构一致,可以使用工具(如
总结 #
- 主从同步配置:配置主从同步需要在主服务器和从服务器上分别做配置,确保二进制日志启用并且设置复制用户。通过
CHANGE MASTER TO
和START SLAVE
命令在从服务器配置主服务器的信息。 - 数据不一致问题:常见问题包括复制延迟、数据丢失、复制失败和数据库结构不一致等。解决这些问题的办法包括优化硬件、调整配置、使用工具进行同步检查,并且确保主从数据库结构一致。
- 解决方案:监控复制状态,定期备份,优化性能,使用并行复制和工具来确保主从同步的稳定性。
通过正确配置和监控,能够保证 MySQL 主从同步的可靠性和高效性。
5. mysql约束有哪些? #
- 非空约束
- 唯一约束
- 主键约束
- 外键约束
MySQL 中的 约束(Constraints) 是用来确保数据库中的数据符合特定规则的机制。约束可以用于保证数据的完整性、准确性和一致性。MySQL 提供了以下几种常见的约束:
1. 主键约束(PRIMARY KEY) #
定义:主键约束用于唯一标识表中的每一行记录。一个表只能有一个主键。
特点
:
- 主键列中的值必须是唯一的。
- 主键列不能包含 NULL 值。
- MySQL 会自动为主键列创建索引。
示例: #
CREATE TABLE users (
id INT PRIMARY KEY,
username VARCHAR(50)
);
2. 唯一约束(UNIQUE) #
定义:唯一约束确保列中的所有值都是唯一的,但与主键不同,唯一约束允许有 NULL 值,且 NULL 值可以重复。
特点
:
- 一列或多列组合起来定义唯一性。
- 允许多个 NULL 值。
示例: #
CREATE TABLE users (
id INT PRIMARY KEY,
email VARCHAR(100) UNIQUE
);
3. 外键约束(FOREIGN KEY) #
定义:外键约束用于确保一个表中的列值必须存在于另一个表中的列中。外键约束用于实现表之间的关系(如一对多、多对多关系)。
特点
:
- 外键列的值必须在参照表的主键或唯一键列中。
- 外键约束可以设置删除和更新时的操作(如
CASCADE
、SET NULL
、NO ACTION
等)。
示例: #
CREATE TABLE orders (
order_id INT PRIMARY KEY,
user_id INT,
FOREIGN KEY (user_id) REFERENCES users(id)
);
4. 检查约束(CHECK) #
定义:检查约束用于确保列中的数据满足特定的条件或规则。
特点
:
- 在插入或更新数据时,MySQL 会检查是否满足
CHECK
条件。 - 该约束通常用于保证数据的合理性,如限制某个字段的取值范围。
- 在插入或更新数据时,MySQL 会检查是否满足
示例: #
CREATE TABLE products (
product_id INT PRIMARY KEY,
price DECIMAL(10, 2) CHECK (price >= 0)
);
注意:
CHECK
约束从 MySQL 8.0.16 版本开始才被支持。在此之前,MySQL 并不强制执行CHECK
约束。
5. 非空约束(NOT NULL) #
定义:非空约束用于确保列中的值不能为 NULL。对于需要保证某一列有数据的字段,通常会使用该约束。
特点
:
- 在插入或更新数据时,列值不能为 NULL。
示例: #
CREATE TABLE users (
id INT PRIMARY KEY,
username VARCHAR(50) NOT NULL
);
6. 默认值约束(DEFAULT) #
定义:默认值约束用于在插入数据时,如果没有指定某个列的值,则该列会自动使用预设的默认值。
特点
:
- 可以为列指定一个默认值。
- 如果插入数据时没有显式给某个列赋值,那么该列会使用默认值。
示例: #
CREATE TABLE employees (
employee_id INT PRIMARY KEY,
hire_date DATE DEFAULT CURRENT_DATE
);
7. 自动递增约束(AUTO_INCREMENT) #
定义:自动递增约束通常用于主键列,MySQL 会自动为每次插入的新记录生成一个唯一的数字值。
特点
:
- 用于整型字段,MySQL 会自动为每次插入的记录生成一个唯一的增量值。
- 每次插入记录时,该字段的值会自动增加,无需手动赋值。
示例: #
CREATE TABLE employees (
employee_id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100)
);
8. 索引约束(INDEX) #
定义:索引约束用于加速数据查询的速度。它通常用于表中经常查询的列上。
特点
:
- 索引会提高数据检索速度,但会稍微降低插入和更新操作的性能。
- 你可以显式为某列创建索引,也可以在主键、唯一键等约束上自动创建索引。
示例: #
CREATE TABLE users (
id INT PRIMARY KEY,
username VARCHAR(50),
INDEX idx_username (username)
);
9. 联合唯一约束(UNIQUE CONSTRAINT) #
定义:通过组合多列来创建唯一约束,以确保这些列的组合在表中是唯一的。
特点
:
- 允许列中有 NULL 值,但 NULL 值也可以是唯一的(这取决于数据库引擎)。
- 可以确保某些列组合的唯一性。
示例: #
CREATE TABLE employees (
first_name VARCHAR(50),
last_name VARCHAR(50),
email VARCHAR(100),
UNIQUE (first_name, last_name)
);
总结 #
- 主键约束(PRIMARY KEY):确保列的唯一性且不允许 NULL 值。
- 唯一约束(UNIQUE):确保列的唯一性,允许 NULL 值。
- 外键约束(FOREIGN KEY):确保数据表间的关系完整性,引用另一个表的主键。
- 检查约束(CHECK):限制列的值符合特定条件。
- 非空约束(NOT NULL):确保列的值不能为 NULL。
- 默认值约束(DEFAULT):为列提供默认值。
- 自动递增约束(AUTO_INCREMENT):为每条记录自动生成唯一的整数值。
- 索引约束(INDEX):加速查询操作,提高查询性能。
- 联合唯一约束(UNIQUE CONSTRAINT):确保多列的组合值唯一。
这些约束确保了数据库中数据的完整性、准确性和一致性,帮助实现更高效、可维护的数据库管理。
6. 二进制日志(binlog)用途? #
BINLOG记录数据库的变更过程。例如创建数据库、建表、修改表等DDL操作、以及数据表的相关DML操作,这些操作会导致数据库产生变化,开启binlog以后导致数据库产生变化的操作会按照时间顺序以“事件”的形式记录到binlog二进制文件中
二进制日志(binlog) 是 MySQL 中用于记录所有更改数据库状态的操作日志(包括数据表结构变化和数据修改操作)。它是 MySQL 数据库的核心日志之一,具有重要的用途。
主要用途: #
- 数据复制(Replication)
- 主从复制:二进制日志是 MySQL 主从复制的基础。主服务器将所有更改数据的操作记录到 binlog 中,从服务器读取这些日志并执行相同的操作,保持与主服务器数据的一致性。
- 复制通常使用异步方式,binlog 记录了所有修改数据的操作,通过复制进程将这些操作传输到从服务器。
- 数据恢复(Point-in-time Recovery)
- 时间点恢复:通过使用 binlog,您可以将数据库恢复到某个特定的时间点。例如,数据库在某个时刻被误操作,您可以利用 binlog 恢复到错误发生之前的状态。
- 备份时,通常先做全量备份,然后利用 binlog 来恢复自备份以来的所有变动数据。
- 审计与监控(Auditing and Monitoring)
- 操作追踪:通过分析 binlog,可以追踪到数据库执行的所有写操作,如
INSERT
、UPDATE
、DELETE
等。它是进行审计的一个重要手段。 - 通过定期查看 binlog,您可以监控哪些操作被执行,哪些数据被修改。
- 操作追踪:通过分析 binlog,可以追踪到数据库执行的所有写操作,如
- 数据库优化(Optimization)
- 查询优化:有时候,分析 binlog 可以帮助数据库管理员识别数据库中可能存在的性能瓶颈,例如频繁的写操作或重复的事务。
binlog 格式: #
MySQL 提供了几种不同的 binlog 格式,分别是:
- STATEMENT(语句模式)
- 记录的是 SQL 语句本身,例如
UPDATE table SET col = val
。 - 优点:占用空间小,因为只记录 SQL 语句。
- 缺点:某些操作可能无法完全复制,特别是涉及到非确定性函数的情况(如
NOW()
、RAND()
等)。
- 记录的是 SQL 语句本身,例如
- ROW(行模式)
- 记录的是每一行数据的变化。例如,更新某一行的数据时,会记录该行的旧值和新值。
- 优点:能够确保复制的准确性,尤其在有非确定性查询的情况下。
- 缺点:日志量较大,因为每个修改操作都需要记录每一行的变化。
- MIXED(混合模式)
- 结合了 STATEMENT 和 ROW 模式,MySQL 会自动选择适合的模式来记录操作。
- 优点:在保证准确性的同时,尽量减少日志的空间消耗。
启用与配置 binlog: #
为了使用 binlog,需要在 MySQL 配置文件(通常是 my.cnf
或 my.ini
)中进行配置:
[mysqld]
log-bin=mysql-bin # 启用 binlog
binlog-format=ROW # 设置 binlog 格式(可选)
总结: #
- 数据复制:binlog 用于主从复制,确保主服务器和从服务器数据同步。
- 数据恢复:提供基于时间点的恢复能力。
- 审计与监控:帮助监控数据变更,进行操作审计。
- 数据库优化:通过分析 binlog,发现潜在的性能瓶颈。
通过合理利用 binlog,能够提高 MySQL 数据库的可靠性、可维护性以及性能优化。
7. mysql数据引擎有哪些? #
- 常用的 myisam、innodb
- 区别:
InnoDB 支持事务,MyISAM 不支持,这一点是非常之重要。事务是一种高级的处理方式,如在一些列增删改中只要哪个出错还可以回滚还原,而 MyISAM就不可以了; MyISAM 适合查询以及插入为主的应用,InnoDB 适合频繁修改以及涉及到安全性较高的应用; InnoDB 支持外键,MyISAM 不支持; MyISAM 是默认引擎,InnoDB 需要指定; InnoDB 不支持 FULLTEXT 类型的索引; InnoDB 中不保存表的行数,如 select count() from table 时,InnoDB;需要扫描一遍整个表来计算有多少行,但是 MyISAM 只要简单的读出保存好的行数即可。注意的是,当 count()语句包含 where 条件时 MyISAM 也需要扫描整个表; 对于自增长的字段,InnoDB 中必须包含只有该字段的索引,但是在 MyISAM表中可以和其他字段一起建立联合索引; 清空整个表时,InnoDB 是一行一行的删除,效率非常慢。MyISAM 则会重建表; InnoDB 支持行锁(某些情况下还是锁整表,如 update table set a=1 where user like ‘%lee%’
MySQL 支持多种存储引擎(Storage Engines),每种存储引擎具有不同的特性,适用于不同的场景。以下是 MySQL 常见的存储引擎及其简要介绍:
1. InnoDB #
特点
:
- 事务支持:InnoDB 支持 ACID 事务,能够确保数据的原子性、一致性、隔离性和持久性。
- 外键支持:InnoDB 支持外键约束,用于维护表与表之间的关系。
- 行级锁:InnoDB 支持行级锁,以提高并发性能,适合高并发的读写操作。
- 崩溃恢复:通过日志文件进行崩溃恢复,保证数据的一致性。
- 自动增长主键:支持自动递增字段(如
AUTO_INCREMENT
)。 - 事务日志:提供事务日志来记录对数据的更改,可以用于恢复数据。
适用场景:适用于需要支持事务、外键以及高并发的应用场景,如金融、电商、CRM 等。
示例: #
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50),
age INT
) ENGINE=InnoDB;
2. MyISAM #
特点
:
- 表级锁:MyISAM 采用表级锁,不支持行级锁,适合读操作较多的场景,但在高并发写入时性能较差。
- 不支持事务:MyISAM 不支持事务管理,因此无法保证 ACID 特性。
- 快速读操作:MyISAM 对于读密集型应用表现较好,特别是对于复杂查询的优化。
- 存储方式:每个表由三个文件组成:数据文件、索引文件和表定义文件。
适用场景:适用于读操作频繁、对事务支持要求较低的场景,如日志记录、数据分析等。
示例: #
CREATE TABLE logs (
id INT AUTO_INCREMENT PRIMARY KEY,
log_message TEXT
) ENGINE=MyISAM;
3. MEMORY(HEAP) #
特点
:
- 内存存储:所有数据都存储在内存中,速度非常快,适用于需要快速读写的场景。
- 表级锁:支持表级锁。
- 不支持事务和外键:不支持事务和外键约束。
- 数据丢失:由于数据存储在内存中,服务器重启时数据会丢失。
适用场景:适用于需要快速访问且对持久化要求不高的临时表、缓存等场景。
示例: #
CREATE TABLE temp_table (
id INT PRIMARY KEY,
name VARCHAR(50)
) ENGINE=MEMORY;
4. CSV #
特点
:
- 文本格式存储:数据以 CSV(逗号分隔值)格式存储为文件。
- 不支持索引:CSV 引擎不支持索引,查询性能较差。
- 易于导入导出:数据以文本格式存储,适合用于与其他系统的导入导出。
适用场景:适用于需要将数据导出为 CSV 格式的场景,如数据交换、备份等。
示例: #
CREATE TABLE csv_table (
id INT PRIMARY KEY,
name VARCHAR(50)
) ENGINE=CSV;
5. ARCHIVE #
特点
:
- 适合归档数据:ARCHIVE 引擎专为存储归档数据设计,适合需要存储大量历史数据的场景。
- 只支持 INSERT 和 SELECT:仅支持插入和查询操作,不支持更新、删除操作。
- 压缩存储:自动压缩数据以节省存储空间。
- 不支持索引:ARCHIVE 表没有索引,查询性能较差。
适用场景:适用于存储长期归档数据,且该数据大多不需要更新的场景。
示例: #
CREATE TABLE archive_table (
id INT PRIMARY KEY,
data TEXT
) ENGINE=ARCHIVE;
6. NDB (Cluster) #
特点
:
- 分布式存储:NDB 存储引擎用于 MySQL Cluster,提供分布式数据库解决方案,能够支持高可用和高并发。
- 数据分片:数据可以在多台服务器上分布存储,提供水平扩展能力。
- 支持事务:NDB 支持事务,但性能开销较大。
- 高可用性:NDB 引擎的数据库集群通常是高可用的,能够容忍节点故障。
适用场景:适用于需要高可用、分布式存储、高并发访问的场景,如大规模在线应用、金融等。
示例: #
CREATE TABLE ndb_table (
id INT PRIMARY KEY,
name VARCHAR(50)
) ENGINE=NDB;
7. BLACKHOLE #
特点
:
- 数据“黑洞”:数据写入后直接丢弃,不存储任何数据,适用于特定的复制场景。
- 不存储数据:所有插入操作都会被丢弃,但操作日志会被记录。
适用场景:用于主从复制中,作为从服务器接收主服务器数据,但不需要存储数据的场景。
示例: #
CREATE TABLE blackhole_table (
id INT PRIMARY KEY,
name VARCHAR(50)
) ENGINE=BLACKHOLE;
8. TokuDB #
特点
:
- 面向大数据存储:TokuDB 是一个高效的存储引擎,适用于需要处理大规模数据的场景。
- 支持压缩和索引:TokuDB 提供高效的数据压缩,并支持高效的索引机制。
- ACID 支持:支持事务,并具备较好的事务性能。
适用场景:适用于大数据量的存储和复杂查询的场景,如大规模分析和数据仓库。
示例: #
CREATE TABLE toku_table (
id INT PRIMARY KEY,
name VARCHAR(50)
) ENGINE=TokuDB;
总结 #
MySQL 提供了多种存储引擎,每种引擎在性能、支持的功能和适用场景上有所不同。常用的存储引擎包括:
- InnoDB:支持事务、外键、行级锁,适合高并发、高一致性的应用。
- MyISAM:无事务支持,适合读密集型应用。
- MEMORY:数据存储在内存中,适合临时表和快速存取。
- ARCHIVE:适用于归档数据,数据压缩存储。
- NDB:用于 MySQL Cluster,适合分布式、高可用场景。
- BLACKHOLE:数据写入黑洞,通常用于复制。
- TokuDB:适合大数据量存储,提供高效的压缩和索引。
选择合适的存储引擎要根据具体的业务需求、性能要求以及数据的特性来决定。
8. 如何查询mysql数据库存放路径? #
mysql> show variables like 'datadir%';
+---------------+------------------------+
| Variable_name | Value |
+---------------+------------------------+
| datadir | /usr/local/mysql/data/ |
+---------------+------------------------+
1 row in set (0.00 sec)
要查询 MySQL 数据库的存放路径,可以通过以下几种方式:
1. 查询 MySQL 数据目录配置 #
MySQL 的数据文件存储路径可以通过查询 MySQL 的 datadir
配置项来获取。你可以使用以下 SQL 语句来查询:
SHOW VARIABLES LIKE 'datadir';
这个命令会返回 datadir
配置项的值,表示 MySQL 数据库的存储目录路径。
示例: #
mysql> SHOW VARIABLES LIKE 'datadir';
+---------------+-----------------------------------+
| Variable_name | Value |
+---------------+-----------------------------------+
| datadir | /var/lib/mysql/ |
+---------------+-----------------------------------+
1 row in set (0.00 sec)
在这个例子中,MySQL 数据库的存储路径是 /var/lib/mysql/
。
2. 检查 MySQL 配置文件 #
你还可以通过查看 MySQL 配置文件来查找数据库存储路径。MySQL 配置文件通常位于 /etc/my.cnf
或 /etc/mysql/my.cnf
,具体路径取决于你的操作系统和安装方式。
打开配置文件并查找 datadir
配置项,类似这样:
[mysqld]
datadir = /var/lib/mysql
3. 查看操作系统文件系统 #
如果你不确定 MySQL 配置文件的位置,也可以检查操作系统中 MySQL 数据目录的位置,尤其是通过文件系统的查找:
在 Linux 系统中,可以通过查找 mysql
进程的工作目录来找到数据存储路径:
ps aux | grep mysql
这条命令会显示 MySQL 服务的进程信息,在信息中可能会包含数据目录的路径。
4. 通过 MySQL 启动命令检查 #
如果你知道 MySQL 是如何启动的,也可以通过启动命令查看 MySQL 的数据目录。MySQL 启动时会使用 --datadir
参数指定数据目录。
例如,可以使用 ps
命令查找 MySQL 进程,并检查是否有 --datadir
参数:
ps aux | grep mysqld
如果 MySQL 启动时指定了 --datadir
,它会显示数据目录的路径。
总结 #
- 通过 SQL 查询:使用
SHOW VARIABLES LIKE 'datadir';
获取 MySQL 数据目录。 - 查看 MySQL 配置文件:检查
/etc/my.cnf
或/etc/mysql/my.cnf
中的datadir
配置项。 - 操作系统级别查找:通过
ps
或其他系统命令查找 MySQL 进程的启动信息。
通常,datadir
默认是 /var/lib/mysql
,但如果在安装时做了修改,数据目录路径也可能会有所不同。
9. mysql数据库文件后缀名有哪些?用途什么? #
- myisam
.frm文件:保护表的定义 .myd:保存表的数据 .myi:表的索引文件
- innodb
.frm:保存表的定义 .ibd:表空间
MySQL 数据库文件的后缀名通常与存储引擎相关,具体来说,不同的存储引擎会使用不同的文件格式来存储数据。下面是常见的 MySQL 数据库文件后缀名及其用途:
1. .frm #
- 用途:
frm
文件用于存储表的定义(即表的结构)。每个表都有一个对应的.frm
文件,记录了表的列、索引、数据类型等元数据。 - 存储引擎:不论是
InnoDB
还是MyISAM
存储引擎,都会为每个表创建一个.frm
文件。
示例: #
/var/lib/mysql/database_name/my_table.frm
2. .ibd #
- 用途:
ibd
文件是 InnoDB 存储引擎使用的表空间文件,专门用来存储表的数据和索引。每个使用 InnoDB 存储引擎的表(如果启用了独立表空间模式)都会有一个.ibd
文件,存储实际的数据和索引。 - 存储引擎:仅 InnoDB 存储引擎使用。
- 位置:在启用了独立表空间(
innodb_file_per_table=1
)的情况下,每个表会有一个独立的.ibd
文件。
示例: #
/var/lib/mysql/database_name/my_table.ibd
3. .myd #
- 用途:
myd
文件是 MyISAM 存储引擎的数据文件,用来存储表中的数据。 - 存储引擎:仅 MyISAM 存储引擎使用。
- 位置:每个 MyISAM 表都会有一个
.myd
文件,用来存储实际的行数据。
示例: #
/var/lib/mysql/database_name/my_table.myd
4. .myi #
- 用途:
myi
文件是 MyISAM 存储引擎的索引文件,用来存储表的索引数据。 - 存储引擎:仅 MyISAM 存储引擎使用。
- 位置:每个 MyISAM 表都有一个
.myi
文件,用来存储该表的索引。
示例: #
/var/lib/mysql/database_name/my_table.myi
5. .log(日志文件) #
用途
:
log
文件通常是 MySQL 的日志文件,主要用于记录数据库的操作过程(如查询、事务等)。
- 错误日志(
error.log
):记录启动、运行和关闭时的错误信息。 - 查询日志(
query.log
):记录所有 SQL 查询(如果启用)。 - 慢查询日志(
slow_query.log
):记录执行时间较长的查询。 - 二进制日志(
binlog
):记录数据库的更改操作,用于数据复制和数据恢复。
- 错误日志(
存储引擎:日志文件与存储引擎无关,而是 MySQL 的全局配置项。
示例: #
/var/log/mysql/mysql-bin.000001 # 二进制日志
/var/log/mysql/error.log # 错误日志
6. .ib_logfile #
用途
:
ib_logfile
文件是
InnoDB
存储引擎的重做日志文件,用于事务日志的存储。InnoDB 采用两种日志:重做日志和撤销日志,这些日志文件用于崩溃恢复。
ib_logfile0
和ib_logfile1
:是 InnoDB 存储引擎的日志文件,记录事务的重做操作(Redo log)。
存储引擎:仅 InnoDB 存储引擎使用。
示例: #
/var/lib/mysql/ib_logfile0
/var/lib/mysql/ib_logfile1
7. .cnd #
- 用途:
cnd
文件是 InnoDB 存储引擎的表空间的变化日志文件,记录数据库表空间的增删改操作。 - 存储引擎:仅 InnoDB 存储引擎使用。
示例: #
/var/lib/mysql/database_name/your_table.cnd
8. .tmp #
- 用途:
tmp
文件用于存储临时数据。在 MySQL 执行查询时,如果需要临时存储数据(例如在复杂的查询中使用临时表),MySQL 会使用.tmp
文件。 - 存储引擎:与存储引擎无关,MySQL 在执行查询时可能会使用临时文件来存储中间数据。
示例: #
/tmp/mysql_temp_file.tmp
9. .ibdata #
- 用途:
ibdata
文件是 InnoDB 存储引擎的系统表空间文件,用于存储所有的表数据、索引和元数据(例如表的结构信息),如果没有启用独立表空间模式(innodb_file_per_table=0
),则所有 InnoDB 表的数据都存储在这个文件中。 - 存储引擎:仅 InnoDB 存储引擎使用。
示例: #
/var/lib/mysql/ibdata1
总结 #
MySQL 中常见的数据库文件后缀名和用途如下:
- .frm:存储表的结构信息,适用于所有存储引擎。
- .ibd:用于 InnoDB 存储引擎的表数据和索引文件。
- .myd:用于 MyISAM 存储引擎的表数据文件。
- .myi:用于 MyISAM 存储引擎的表索引文件。
- .log:日志文件,如错误日志、查询日志、二进制日志等。
- .ib_logfile:InnoDB 的重做日志文件。
- .cnd:InnoDB 的表空间变化日志文件。
- .tmp:用于临时存储的数据文件。
- .ibdata:InnoDB 的系统表空间文件。
这些文件在 MySQL 中具有不同的作用,帮助管理和存储数据库的结构、数据、索引以及日志信息。
10. 如何修改数据库用户的密码? #
- mysql8之前
set password for 用户名@localhost = password('新密码');
mysqladmin -u用户名 -p旧密码 password 新密码
update user set password=password('123') where user='root' and host='localhost';
- mysql8之后
# mysql8初始对密码要求高,简单的字符串不让改。先改成:MyNewPass@123;
alter user 'root'@'localhost' identified by 'MyNewPass@123';
# 降低密码难度
set global validate_password.policy=0;
set global validate_password.length=4;
# 修改成简易密码
alter user 'root'@'localhost'IDENTIFIED BY '1111';
在 MySQL 中修改数据库用户的密码,可以通过以下几种方式:
1. 使用 ALTER USER
语句(推荐)
#
在 MySQL 5.7.6 及以上版本中,可以使用 ALTER USER
语句来修改用户密码:
ALTER USER 'username'@'host' IDENTIFIED BY 'new_password';
'username'
是数据库用户名。'host'
是该用户的主机名(一般是%
,表示任何主机,或者localhost
,表示本机)。'new_password'
是新的密码。
示例: #
ALTER USER 'myuser'@'localhost' IDENTIFIED BY 'newpassword123';
2. 使用 SET PASSWORD
语句
#
对于 MySQL 5.7.5 及以下版本,或者如果 ALTER USER
不可用时,可以使用 SET PASSWORD
:
SET PASSWORD FOR 'username'@'host' = PASSWORD('new_password');
示例: #
SET PASSWORD FOR 'myuser'@'localhost' = PASSWORD('newpassword123');
3. 使用 UPDATE
语句修改 mysql.user
表
#
在一些特殊情况下(例如:忘记了管理员密码),也可以直接通过更新 mysql.user
表来修改密码。不过这种方法在高版本 MySQL 中较少使用,推荐使用上面的方法。
UPDATE mysql.user SET authentication_string = PASSWORD('new_password') WHERE User = 'username' AND Host = 'host';
FLUSH PRIVILEGES;
authentication_string
字段保存密码(旧版本是password
字段)。FLUSH PRIVILEGES
用于刷新权限,使改动生效。
示例: #
UPDATE mysql.user SET authentication_string = PASSWORD('newpassword123') WHERE User = 'myuser' AND Host = 'localhost';
FLUSH PRIVILEGES;
4. 重置 root
密码
#
如果需要重置 root
密码(例如忘记了密码),可以进入 MySQL 的安全模式进行修改:
停止 MySQL 服务:
sudo systemctl stop mysql
启动 MySQL 无密码模式:
sudo mysqld_safe --skip-grant-tables &
进入 MySQL:
mysql -u root
修改密码:
UPDATE mysql.user SET authentication_string = PASSWORD('newpassword123') WHERE User = 'root'; FLUSH PRIVILEGES;
退出 MySQL 并重启 MySQL 服务:
sudo systemctl restart mysql
总结: #
- 推荐使用
ALTER USER
来修改密码。 SET PASSWORD
适用于较旧的版本。- 在特殊情况下,可以直接修改
mysql.user
表并执行FLUSH PRIVILEGES
。
使用这些方法后,用户的密码就会被成功修改。
在 MySQL 8.0 中,修改数据库用户密码的方法与 MySQL 5.7 版本有所不同,主要是通过 ALTER USER
语句来实现。下面是针对 MySQL 8.0 的几种常用修改密码的方式:
1. 使用 ALTER USER
语句(推荐)
#
MySQL 8.0 版本推荐使用 ALTER USER
语句来修改用户的密码:
ALTER USER 'username'@'host' IDENTIFIED BY 'new_password';
'username'
是要修改密码的用户名。'host'
是用户的主机(如%
或localhost
)。'new_password'
是新的密码。
示例: #
ALTER USER 'myuser'@'localhost' IDENTIFIED BY 'newpassword123';
2. 使用 SET PASSWORD
语句
#
在 MySQL 8.0 中,虽然 ALTER USER
是推荐方法,但 SET PASSWORD
仍然有效,可以通过该方法修改密码:
SET PASSWORD FOR 'username'@'host' = 'new_password';
示例: #
SET PASSWORD FOR 'myuser'@'localhost' = 'newpassword123';
3. 直接修改 mysql.user
表(不推荐)
#
虽然可以直接更新 mysql.user
表来修改密码,但这种做法在 MySQL 8.0 中并不推荐,因为它可能导致安全问题,且需要手动刷新权限。
UPDATE mysql.user SET authentication_string = PASSWORD('new_password') WHERE User = 'username' AND Host = 'host';
FLUSH PRIVILEGES;
authentication_string
存储的是用户的加密密码。
示例: #
UPDATE mysql.user SET authentication_string = PASSWORD('newpassword123') WHERE User = 'myuser' AND Host = 'localhost';
FLUSH PRIVILEGES;
4. 重置 root
密码(如果忘记密码)
#
如果忘记了 root
密码,可以通过以下步骤重置密码:
停止 MySQL 服务:
sudo systemctl stop mysql
启动 MySQL 安全模式(跳过授权表):
sudo mysqld_safe --skip-grant-tables &
进入 MySQL 命令行:
mysql -u root
修改
root
密码:ALTER USER 'root'@'localhost' IDENTIFIED BY 'newpassword123'; FLUSH PRIVILEGES;
退出 MySQL 并重启 MySQL 服务:
sudo systemctl restart mysql
5. 查看密码加密方式 #
在 MySQL 8.0 中,密码加密方式有所变化。如果你需要查看当前用户的加密方式,可以执行以下命令:
SELECT user, host, authentication_string FROM mysql.user WHERE user = 'username';
总结 #
- 推荐方法:使用
ALTER USER
语句修改用户密码。 - 次推荐方法:使用
SET PASSWORD
来修改密码。 - 不推荐的做法:直接修改
mysql.user
表。 - 如果忘记
root
密码,可以通过跳过授权表的方式重置密码。
MySQL 8.0 加强了对安全性的保护,推荐使用 ALTER USER
和 SET PASSWORD
来修改密码。
11. 如何修改用户权限?如何查看? #
- 授权:
grant all on *.* to user@'%' identified by 'passwd'
- 查看权限
show grants for user@'%';
在 MySQL 中,修改用户权限和查看用户权限是常见的操作。这里提供如何修改和查看权限的详细步骤。
1. 查看用户权限 #
要查看 MySQL 中某个用户的权限,可以使用以下查询:
SHOW GRANTS FOR 'username'@'host';
'username'
是用户名。'host'
是用户连接数据库的主机(通常是localhost
或%
,表示任意主机)。
示例: #
SHOW GRANTS FOR 'myuser'@'localhost';
这条命令会返回该用户在 MySQL 中的所有授权信息,输出类似如下:
GRANT USAGE ON *.* TO 'myuser'@'localhost'
GRANT SELECT, INSERT, UPDATE, DELETE ON `mydb`.* TO 'myuser'@'localhost'
2. 修改用户权限 #
修改用户权限的操作一般通过 GRANT
或 REVOKE
命令来实现。
(1) 授予权限 #
通过 GRANT
语句,可以授予用户权限。常见的权限有 SELECT
、INSERT
、UPDATE
、DELETE
,以及数据库级、表级、列级权限等。
语法如下:
GRANT <privileges> ON <database>.<table> TO 'username'@'host';
<privileges>
是要授予的权限,如SELECT
、INSERT
等,多个权限用逗号分隔,或使用ALL PRIVILEGES
授予所有权限。<database>
是要授予权限的数据库,*
表示所有数据库。<table>
是要授予权限的表,*
表示所有表。'username'
是要授予权限的用户。'host'
是用户可以连接的主机,%
表示任意主机。
示例 1:授予 myuser
用户对 mydb
数据库的 SELECT
和 INSERT
权限
#
GRANT SELECT, INSERT ON mydb.* TO 'myuser'@'localhost';
示例 2:授予 myuser
用户对所有数据库的所有权限
#
GRANT ALL PRIVILEGES ON *.* TO 'myuser'@'localhost';
示例 3:授予 myuser
用户对特定表的 SELECT
权限
#
GRANT SELECT ON mydb.mytable TO 'myuser'@'localhost';
(2) 撤销权限 #
使用 REVOKE
语句可以撤销用户的某些权限。
语法如下:
REVOKE <privileges> ON <database>.<table> FROM 'username'@'host';
示例 1:撤销 myuser
用户对 mydb
数据库的 SELECT
权限
#
REVOKE SELECT ON mydb.* FROM 'myuser'@'localhost';
示例 2:撤销 myuser
用户对所有数据库的所有权限
#
REVOKE ALL PRIVILEGES ON *.* FROM 'myuser'@'localhost';
3. 刷新权限 #
当授予或撤销权限后,需要刷新权限表以使更改生效,使用以下命令:
FLUSH PRIVILEGES;
4. 删除用户权限 #
如果你想要删除一个用户,删除用户时会自动撤销该用户的所有权限:
DROP USER 'username'@'host';
示例: #
DROP USER 'myuser'@'localhost';
总结 #
- 查看用户权限:使用
SHOW GRANTS FOR 'username'@'host';
。 - 授予权限:使用
GRANT
命令。 - 撤销权限:使用
REVOKE
命令。 - 刷新权限:修改权限后使用
FLUSH PRIVILEGES;
来使改动生效。 - 删除用户:使用
DROP USER
删除用户及其所有权限。
通过这些操作,你可以灵活地管理 MySQL 用户的权限。
三、nosql #
1. redis数据持久化有哪些方式? #
- rdb
- aof
Redis 提供了两种主要的数据持久化方式,以确保数据在重启或故障后不会丢失。它们分别是 RDB(Redis 数据库快照) 和 AOF(Append Only File)。除了这两种主要的持久化方式,Redis 还支持 混合持久化(RDB + AOF),具体如下:
1. RDB(Redis 数据库快照) #
RDB 是 Redis 默认的持久化方式,它通过在指定的时间间隔内创建数据库的快照来保存数据。
工作原理: #
- Redis 会定期将数据库的状态(即数据)保存到硬盘上的一个
.rdb
文件中。 - RDB 文件是压缩的二进制文件,可以在 Redis 启动时快速加载。
- 快照的创建是异步的,不会影响 Redis 的主操作。
配置: #
在
redis.conf
文件中,通过save
指令配置保存快照的条件。例如:save 900 1 # 如果在 900 秒(15分钟)内有至少 1 个 key 被修改,则进行快照 save 300 10 # 如果在 300 秒内有至少 10 个 key 被修改,则进行快照 save 60 10000 # 如果在 60 秒内有至少 10000 个 key 被修改,则进行快照
快照文件的路径和文件名可以通过
dir
和dbfilename
指定:dir /var/lib/redis dbfilename dump.rdb
优缺点: #
- 优点:RDB 持久化方式对 Redis 性能影响较小,特别是在写入频繁的情况下,因为它是在后台异步操作的。
- 缺点:由于是周期性的保存快照,如果 Redis 崩溃,最后一次保存的数据和崩溃时的数据之间的更改会丢失,数据持久化的精度较低。
2. AOF(Append Only File) #
AOF 通过记录所有写操作的日志来持久化数据,每次对 Redis 的写操作都会被追加到 AOF 文件中,Redis 启动时可以通过重放 AOF 文件来恢复数据。
工作原理: #
- 每当发生写操作时,Redis 会将操作写入 AOF 文件。
- AOF 文件是以追加的方式记录的,保留了 Redis 中所有的写操作,可以精确恢复数据。
- Redis 提供了三种不同的同步策略:
- always:每次操作都同步写入磁盘,性能最差,持久化最可靠。
- everysec:每秒钟同步写入一次,这是性能和可靠性的折衷方案,也是默认选项。
- no:从不同步写入磁盘,性能最好,但一旦发生故障,数据会丢失。
配置: #
在
redis.conf
文件中通过appendonly
和appendfsync
配置 AOF 持久化:appendonly yes # 启用 AOF 持久化 appendfsync everysec # 每秒钟同步写入一次磁盘
AOF 文件的路径可以通过
dir
和appendfilename
配置:dir /var/lib/redis appendfilename "appendonly.aof"
优缺点: #
- 优点:AOF 能够提供更高的数据可靠性,因为它记录了所有的写操作,可以做到“最小丢失”。
- 缺点:AOF 文件会不断增长,尤其是对大量数据写入的场景,AOF 文件可能会变得很大。为了优化 AOF 文件的大小,可以定期进行 AOF 重写(
BGREWRITEAOF
),将 AOF 文件压缩到更小的体积。
3. 混合持久化(RDB + AOF) #
Redis 4.0 引入了混合持久化机制,结合了 RDB 和 AOF 两种持久化方式的优点。混合持久化允许 Redis 同时使用 RDB 快照和 AOF 日志文件,在 Redis 启动时能够尽量减少数据恢复的时间,同时保证数据的持久性。
工作原理: #
- 在进行 AOF 重写时,Redis 会将数据存储在内存中的一个混合格式中(即 RDB 快照 + AOF 追加日志),这可以减少 AOF 重写时的性能开销。
- 启动时,Redis 会首先加载 RDB 快照文件,然后读取 AOF 文件中的操作来恢复数据。
配置: #
通过
redis.conf
文件中的aof-use-rdb-preamble
配置来启用混合持久化:aof-use-rdb-preamble yes
优缺点: #
- 优点:结合了 RDB 的启动速度和 AOF 的数据可靠性。
- 缺点:增加了配置复杂度,需要合理选择使用场景。
4. 持久化相关配置的选择 #
根据你的使用场景,选择合适的持久化方式至关重要:
- 如果 对数据丢失的容忍度较低,且希望保证数据的完整性,建议使用 AOF(最好是
everysec
配置)。 - 如果希望 性能优先,并且可以接受 部分数据丢失,可以使用 RDB。
- 如果希望兼顾 性能和可靠性,可以考虑使用 RDB + AOF 混合持久化。
5. 如何优化 AOF 文件 #
AOF 文件会随着时间的推移不断增长,因此 Redis 提供了 AOF 重写机制,可以压缩 AOF 文件:
BGREWRITEAOF
通过 BGREWRITEAOF
命令,Redis 会生成一个新的 AOF 文件,合并其中的命令,从而减小 AOF 文件的大小。
总结 #
- RDB:通过定期快照方式持久化,性能较高,但数据丢失可能性较大。
- AOF:记录所有写操作,数据可靠性高,但文件会较大,可能影响性能。
- 混合持久化:结合了 RDB 快照和 AOF 日志,兼顾启动速度和数据可靠性。
根据实际的需求和对数据持久化的要求,可以选择最合适的持久化方式。
2. redis集群方案有哪些? #
- 官方cluster方案
- twemproxy代理方案
- 哨兵模式
- codis 客户端分片
Redis 集群是为了实现分布式数据存储而设计的一种方案,它将数据分布在多个 Redis 实例(节点)上,提供高可用、分布式存储、负载均衡和故障恢复功能。Redis 集群支持水平扩展(sharding),使得 Redis 可以在多个机器上分布式地存储大量数据。
Redis 集群方案主要有以下几种: #
1. 原生 Redis 集群(Redis Cluster) #
Redis Cluster 是 Redis 官方提供的分布式集群方案,旨在提供高可用和可扩展的 Redis 服务。
特点: #
- 数据分片:数据被分散存储在多个 Redis 节点上,每个节点存储数据的一个子集。
- 自动分片:Redis 集群支持将数据分成多个 “槽”(hash slots),并自动将这些槽分配到不同的 Redis 节点。
- 高可用性:通过 Redis 集群的复制机制,每个主节点都有一个或多个副本节点,保证主节点故障时可以自动切换。
- 无中心化管理:Redis 集群没有一个中央的控制节点,每个节点都包含自己的配置和集群状态,所有节点通过协议进行通信。
工作原理: #
- Redis 集群将数据按一定的规则(哈希槽)分散到集群中的不同节点上。
- Redis 集群默认将数据划分为 16384 个槽,每个键值会通过一致性哈希算法映射到一个槽,槽再由各个节点存储。
- 节点之间通过 Gossip 协议 和 TCP 连接 进行状态同步,确保集群中所有节点的状态一致。
优缺点: #
优点
:
- 提供水平扩展能力,可以通过增加节点来扩展集群容量。
- 内建故障恢复,主节点宕机时会自动将从节点提升为主节点。
- 对外暴露单一的 Redis 端口,客户端自动路由。
缺点
:
- 需要集群中的每个节点都有足够的内存来存储一部分数据。
- 配置较为复杂,需要至少 3 个主节点和 3 个副本来确保高可用性。
- 集群中发生故障时,可能会暂时导致部分槽的不可用。
配置: #
Redis 集群需要至少 3 个主节点和 3 个从节点来实现高可用,并且节点数量是 2 的倍数。 具体配置可以参考 Redis 官方文档中的集群部署指南。
2. Redis Sentinel #
Redis Sentinel 是 Redis 官方提供的高可用性解决方案。它可以监控 Redis 主从架构的节点,自动进行故障转移。
特点: #
- 高可用性:通过对 Redis 实例的监控,Sentinel 可以自动进行故障转移,主节点发生故障时,自动选举新的主节点。
- 自动恢复:当主节点发生故障,Sentinel 会将一个从节点提升为主节点,并更新集群中的配置。
- 集群监控:Redis Sentinel 提供对 Redis 实例的监控服务,并支持对集群进行通知和警告。
工作原理: #
- Sentinel 通过定期 ping 主节点和从节点来检查它们的状态。
- 如果检测到主节点不可用,Sentinel 会启动自动故障转移,将一个从节点提升为主节点,并通知其他 Sentinel 进行配置更新。
- Sentinel 实例之间通过心跳机制和投票机制来选举新的主节点。
优缺点: #
优点
:
- 容错能力强,能够自动恢复主节点故障。
- 配置简单,适合大多数 Redis 部署。
- 可以与 Redis 单机模式结合使用,增加高可用性。
缺点
:
- Sentinel 本身并不提供数据分片能力,只适用于主从复制架构。
- 故障转移过程可能会有短暂的服务中断。
配置: #
- 至少需要 3 个 Sentinel 实例来保证故障转移的正常工作。
- 需要至少 1 个主节点和 1 个从节点来构建 Redis 集群。
3. Redis 代理方案(如 Twemproxy) #
Twemproxy(又称 Nutcracker)是一个开源的代理工具,可以作为 Redis 集群的代理层。它允许在客户端与多个 Redis 实例之间进行负载均衡和路由。Twemproxy 适用于 Redis 主从架构或 Redis 集群架构。
特点: #
- 负载均衡:通过代理进行请求路由,可以在多个 Redis 实例之间均衡负载。
- 透明代理:客户端与 Twemproxy 通信,Twemproxy 会根据请求路由到相应的 Redis 节点。
- 高性能:Twemproxy 是一个非常高效的代理,适用于高并发场景。
优缺点: #
优点
:
- 可以作为 Redis 集群的代理层,简化客户端操作。
- 支持连接池和负载均衡,提供性能优化。
缺点
:
- 不支持 Redis 集群的所有功能(如自动故障转移、复制等)。
- 需要额外的代理层,可能会增加系统复杂度。
配置: #
- 配置 Twemproxy 需要指定多个 Redis 实例作为后端,并在前端处理客户端请求。
4. Redis Sharding(手动分片) #
手动分片 是通过在多个 Redis 实例之间人工分配数据来实现的。客户端通过特定的规则来决定数据应该存储在哪个 Redis 实例上。
特点: #
- 简单:不需要复杂的集群配置,适合小规模的 Redis 部署。
- 灵活:可以根据具体业务需求来设计数据分片策略。
优缺点: #
优点
:
- 简单易用,适合小规模应用。
- 可以灵活地进行分片和扩展。
缺点
:
- 数据分片的管理较为复杂,需要手动配置分片规则。
- 不提供自动故障转移和数据恢复机制。
总结 #
- Redis 集群(Redis Cluster) 是 Redis 原生的分布式集群方案,支持数据分片、自动故障转移和高可用性。
- Redis Sentinel 主要提供高可用性和自动故障转移,但不提供数据分片功能,适用于主从架构。
- Twemproxy 提供负载均衡和代理服务,适用于 Redis 集群和主从架构,但没有 Redis 集群的完整功能。
- Redis Sharding 是手动分片方式,适合小规模部署,灵活但管理复杂。
选择哪种方案,取决于你的需求:
- 如果需要 数据分片和高可用性,建议使用 Redis Cluster。
- 如果只需要 高可用性 而不需要分片,可以选择 Redis Sentinel。
- 如果需要 代理和负载均衡,可以使用 Twemproxy。
- 如果是 小规模部署,可以使用 手动分片。
这些方案都可以根据不同的应用场景和架构要求进行调整和优化。
3. redis如何进行数据备份与恢复? #
- 备份
redis 127.0.0.1:6379> SAVE 创建 redis 备份文件也可以使用命令 BGSAVE,该命令在后台执行。
- 还原
只需将备份文件 (dump.rdb) 移动到 redis 安装目录并启动服务即可 redis 127.0.0.1:6379> CONFIG GET dir
- “dir”
- “/usr/local/redis/bin”
Redis 提供了多种数据备份和恢复的方式,主要通过 持久化机制(RDB 和 AOF)以及 手动备份 来实现数据备份与恢复。以下是详细的备份与恢复方法:
1. RDB 持久化备份与恢复 #
RDB(Redis DataBase)是 Redis 的默认持久化方式,它将内存中的数据快照保存在硬盘上,以便在重启或故障时恢复数据。
RDB 备份 #
自动备份:Redis 默认会根据配置(
redis.conf
)定期进行数据持久化。在
redis.conf
文件中,
save
指令配置了定期备份的规则。例如:
save 900 1 # 900秒(15分钟)内有至少1次写操作时,自动生成快照 save 300 10 # 300秒(5分钟)内有至少10次写操作时,自动生成快照 save 60 10000 # 60秒内有至少10000次写操作时,自动生成快照
在这种配置下,Redis 会在满足这些条件时自动生成 RDB 文件。
手动备份:可以使用
BGSAVE
命令进行手动备份,该命令会在后台生成数据快照,不会阻塞 Redis 服务。命令:
BGSAVE
这会在后台异步生成
dump.rdb
文件。
RDB 文件位置:默认情况下,生成的 RDB 文件
dump.rdb
会存放在 Redis 数据目录下,通常在/var/lib/redis/
或./
(Redis启动目录)。
RDB 恢复 #
- 停止 Redis 服务。
- 将备份的
dump.rdb
文件放回 Redis 数据目录。 - 启动 Redis 服务,Redis 会在启动时自动加载
dump.rdb
文件中的数据。
如果你手动备份了 dump.rdb
文件,只需要将其恢复到 Redis 的数据目录并启动 Redis 服务即可。
2. AOF 持久化备份与恢复 #
AOF(Append-Only File)持久化将所有写操作记录到日志文件中,可以确保数据更持久和可靠。每个写命令都会记录在 AOF 文件中,因此 AOF 提供了比 RDB 更高的持久性。
AOF 备份 #
自动备份:当 Redis 启用 AOF 持久化时,会将每一个写操作追加到 AOF 文件中。
在
redis.conf
中配置 AOF 相关参数:
appendonly yes # 启用 AOF 持久化 appendfilename "appendonly.aof" # AOF 文件名 appendfsync everysec # 每秒同步一次 AOF 文件
appendfsync
参数可以设置为:
always
:每次写操作都同步到磁盘,性能较差。everysec
:每秒同步一次到磁盘,通常是推荐的设置。no
:不进行同步,由操作系统进行同步(性能最好,但可靠性最差)。
手动备份:使用
BGREWRITEAOF
命令来重写 AOF 文件,这会生成一个新的 AOF 文件并删除旧的 AOF 文件,从而节省空间。命令:
BGREWRITEAOF
这会在后台进行 AOF 重写操作,生成一个新的压缩后的 AOF 文件。
AOF 恢复 #
- 停止 Redis 服务。
- 将备份的
appendonly.aof
文件复制到 Redis 的数据目录。 - 启动 Redis 服务,Redis 会在启动时根据 AOF 文件恢复数据。
如果你启用了 AOF 持久化,只需要将备份的 appendonly.aof
文件放回 Redis 数据目录并重启 Redis 即可。
3. 混合持久化(RDB + AOF) #
Redis 4.0 及以后的版本支持同时启用 RDB 和 AOF 持久化(混合持久化)。这种方式能够结合 RDB 的快速启动和 AOF 的高可靠性,在启动时首先使用 RDB 快照,如果没有 RDB 快照,才使用 AOF 文件。
启用混合持久化: #
在
redis.conf
中配置:appendonly yes # 启用 AOF appendfsync everysec # 每秒同步到 AOF save 900 1 # 900秒有一次写操作时进行 RDB 快照
使用混合持久化时,Redis 会在保存 RDB 快照时将 AOF 也作为增量记录保留。
4. 手动备份(通过文件复制) #
如果你只是希望进行简单的备份,可以直接复制 Redis 的数据文件(dump.rdb
和 appendonly.aof
文件)。这种方式适用于备份频率较低的场景。
- 停止 Redis 服务。
- 复制
dump.rdb
和appendonly.aof
文件到备份存储。 - 启动 Redis 服务。
5. 增量备份 #
Redis 本身不直接支持增量备份,但可以通过以下方式实现:
- RDB + AOF:结合 RDB 和 AOF 可以达到类似增量备份的效果。定期备份 RDB 快照,然后通过 AOF 文件记录增量数据。
- 外部工具:可以使用一些备份工具(如
redis-dump
、redis-py
等)定期获取 Redis 数据并实现增量备份。
6. 备份策略与最佳实践 #
- 定期备份:定期进行 RDB 快照备份,建议根据业务量的大小、数据的重要性、磁盘容量等来调整备份频率。
- 多地备份:将备份文件存储在不同的物理位置,以防止硬盘损坏等不可预见的事件。
- 自动化备份:设置定时任务(如 cron job)来自动备份 Redis 数据。
- 监控与报警:结合监控工具,设置 Redis 数据备份的成功或失败的报警机制。
总结 #
- RDB:适合做定期的快照备份,恢复速度较快,数据丢失较少,但持久化操作可能较慢,适合对数据丢失容忍度较高的场景。
- AOF:适合需要高可靠性、保证不丢失数据的场景,写入性能相对较低,恢复速度较慢。
- 混合持久化:结合了 RDB 的快速恢复和 AOF 的高可靠性,是目前较为推荐的方式。
选择备份方式时,可以根据实际需求决定是采用 RDB、AOF,还是两者结合使用。
4. MongoDB如何进行数据备份? #
mongoexport / mongoimport mongodump / mongorestore
MongoDB 提供了几种数据备份方式,主要有以下几种:
1. 使用 mongodump
进行备份
#
mongodump
是 MongoDB 提供的命令行工具,用于将数据库的内容导出为二进制格式的备份文件。
备份操作 #
备份整个数据库:
mongodump --host <host> --port <port> --out /path/to/backup/directory
这将备份所有数据库到指定目录。
备份指定数据库:
mongodump --host <host> --port <port> --db <database_name> --out /path/to/backup/directory
只备份指定的数据库。
备份指定集合:
mongodump --host <host> --port <port> --db <database_name> --collection <collection_name> --out /path/to/backup/directory
只备份指定数据库中的某个集合。
指定认证: 如果 MongoDB 实例启用了认证,需要提供
--username
和--password
:mongodump --host <host> --port <port> --db <database_name> --username <user> --password <password> --out /path/to/backup/directory
备份压缩数据: 可以使用
--gzip
参数压缩备份文件:mongodump --host <host> --port <port> --out /path/to/backup/directory --gzip
备份数据的存储路径 #
- 备份的数据默认存储在
--out
指定的目录下,通常备份的数据会生成*.bson
格式的文件以及一些元数据文件。
注意事项 #
mongodump
是基于查询的方式进行备份的,因此会导致备份的时间较长,并且可能会对 MongoDB 的性能产生影响。- 使用
mongodump
时会锁定数据库,所以在进行备份时,数据库的写操作可能会受到一定影响。
2. 使用 mongorestore
进行恢复
#
mongorestore
是 MongoDB 提供的工具,用于将 mongodump
生成的备份文件恢复到数据库中。
恢复整个备份:
mongorestore --host <host> --port <port> /path/to/backup/directory
该命令将从备份目录恢复所有数据库和集合。
恢复指定数据库:
mongorestore --host <host> --port <port> --db <database_name> /path/to/backup/directory/<database_name>
恢复指定集合:
mongorestore --host <host> --port <port> --db <database_name> --collection <collection_name> /path/to/backup/directory/<database_name>/<collection_name>.bson
恢复压缩的备份:
mongorestore --host <host> --port <port> --gzip /path/to/backup/directory
注意事项 #
恢复时会根据备份文件覆盖数据库中的现有数据,如果你需要保留现有数据,请使用
--drop
参数来删除现有集合再恢复数据:
mongorestore --host <host> --port <port> --drop /path/to/backup/directory
3. 使用文件系统级备份 #
如果 MongoDB 以复制集的方式运行,可以通过文件系统级别的备份来实现备份。这种方法适合大规模的数据备份,通常用于生产环境中的定期备份。
步骤: #
停用写操作(可选): 你可以使用
fsync
命令让 MongoDB 进行一次同步操作,这有助于确保备份的一致性。db.fsyncLock()
复制 MongoDB 数据目录: 备份 MongoDB 数据目录(默认情况下,数据目录为
/data/db
)。 你可以使用操作系统的cp
或rsync
命令将数据库文件复制到备份存储。rsync -avz /data/db /path/to/backup/directory
解锁同步(可选): 完成备份后,使用以下命令解锁写操作:
db.fsyncUnlock()
注意事项 #
- 使用文件系统备份时需要确保数据库的
journal
文件夹处于一致的状态,因此最好在 MongoDB 副本集的情况下进行备份。 - 此方法适用于大规模备份和恢复,但需要停机或锁定写操作,因此不适合高可用性要求非常高的场景。
4. 使用 MongoDB Atlas 进行备份(云托管服务) #
如果使用的是 MongoDB Atlas(MongoDB 的托管云服务),则可以利用其内建的自动备份功能。
- 自动备份:MongoDB Atlas 提供了自动备份服务,可以按日、周、月等频率自动进行备份。
- 恢复备份:可以通过 Atlas 控制面板恢复备份,或者使用 MongoDB Atlas 的 API 恢复指定时间点的备份。
5. 增量备份 #
MongoDB 本身并不直接支持增量备份,但可以通过以下方式实现类似的功能:
- 复制集备份:通过
oplog
(操作日志)实现增量备份。可以监控 MongoDB 的操作日志并提取增量数据,通常结合mongodump
进行备份。
6. 定期备份和自动化 #
建议使用定时任务(如 cron job)来自动执行 mongodump
命令,以便定期备份数据库。这样可以确保数据定期得到保护,并且在数据库崩溃时能恢复。
总结 #
- mongodump 是最常见的备份方式,适合大多数场景,使用时需要注意备份过程对性能的影响。
- mongorestore 用于从
mongodump
备份恢复数据。 - 文件系统级备份 对于大规模数据库非常有效,但需要额外的同步和锁定操作。
- MongoDB Atlas 提供了便捷的云备份和恢复服务,适合云环境。
根据具体业务需求选择合适的备份方式。
5. kafka为何比redis rabbitmq快? #
Kafka 通常比 Redis 和 RabbitMQ 在消息传递性能上要快,主要是由于它的架构设计和使用的技术不同。以下是一些关键原因:
1. 顺序写入与高效磁盘存储 #
Kafka 通过顺序写入磁盘来优化性能。磁盘的顺序写入性能通常比随机写入要好得多,这也是 Kafka 高效的关键。消息在 Kafka 中被追加到日志文件的末尾,这使得磁盘 I/O 性能得到极大提升。而 Redis 和 RabbitMQ 则依赖于不同的存储和数据结构,通常会发生更多的随机访问操作,从而影响性能。
2. 持久化与内存管理 #
- Kafka 的消息持久化是基于日志文件的,它通过将消息追加到文件系统的顺序日志中,从而使得消息可以高效地写入磁盘,并通过日志分段来管理大规模的数据。Kafka 将存储和传输解耦,支持高吞吐量的写入和读取。
- Redis 在默认情况下将所有数据存储在内存中(即使可以选择持久化数据到磁盘),这就意味着当处理大规模数据时,内存成为瓶颈。虽然 Redis 也支持磁盘持久化,但其持久化机制(RDB 或 AOF)可能会导致性能下降。
- RabbitMQ 使用 Erlang 构建,并将消息持久化到磁盘时,会有更高的延迟,尤其是在消息需要强一致性保障时。其高吞吐量的能力不如 Kafka,且在高并发时可能会遇到性能瓶颈。
3. 分布式架构与水平扩展 #
Kafka 从设计之初就支持分布式架构和水平扩展。它使用 分区 来水平分割数据,并可以通过增加分区和副本的数量来提高吞吐量。每个分区内的消息是按顺序存储的,并且可以并行处理,这使得 Kafka 能够支持大规模的并发消息传输。
- Redis 是单线程的,虽然它支持分片(Cluster),但是在高并发的场景下,它的性能和吞吐量会受到单个节点的 CPU 和内存限制。
- RabbitMQ 可以通过集群和镜像队列来实现分布式,但是它的消息传递和存储机制相对复杂,且吞吐量通常比 Kafka 要低。
4. 消息顺序和消费模型 #
Kafka 提供了更高效的消费者模型。Kafka 中的消费者是基于偏移量(offset)来消费消息的,可以非常灵活地在消息流中前进或回溯。并且,由于消息在分区内是按顺序写入的,因此 Kafka 能够提供更高的消息吞吐量和低延迟。
- Redis 通常依赖于发布/订阅模型,在高频率的数据推送场景下,消息的处理和消费可能会受到阻塞,尤其是在消息量非常大的情况下。
- RabbitMQ 使用队列来存储和分发消息,虽然支持多个消费者并行消费,但其消费效率通常低于 Kafka,尤其是在大规模并发场景下。
5. 消息存储机制 #
Kafka 是基于 append-only logs(仅追加日志)的方式进行存储的。这意味着一旦写入 Kafka,消息将被持久化并按时间顺序存储。这种方式大大减少了锁的竞争,写入性能非常高。
- Redis 是内存存储系统,数据放在内存中时速度快,但当数据量过大时,内存成为瓶颈,存储限制更为严格。
- RabbitMQ 中的队列消息在传输和存储时需要在内存和磁盘之间频繁切换,尤其是当消息队列积压时,会引起更多的 I/O 操作,从而影响性能。
6. 延迟与吞吐量 #
Kafka 设计时注重高吞吐量(high throughput)和低延迟,适合大规模的数据流传输,并且支持高并发的生产者和消费者。它能够处理数百万的消息和高频率的数据传输,而 RabbitMQ 和 Redis 虽然也能处理高吞吐量的场景,但相比之下,Kafka 更加专注于大规模、高并发的消息传递和持久化。
7. 容错性和数据持久化 #
Kafka 的设计有 日志复制 和 数据持久化 机制,确保了在节点发生故障时数据不丢失。同时,Kafka 的日志压缩功能使得消息可以存储较长时间,并且可以进行高效的回放和数据重放。
总结 #
Kafka 相对于 Redis 和 RabbitMQ 的优势主要在于:
- 顺序写入和高效的磁盘存储。
- 高吞吐量和低延迟的分布式消息传递。
- 大规模扩展能力和高并发支持。
如果是处理需要高吞吐量、高并发、大规模数据流的场景,Kafka 无疑是更好的选择;而 Redis 和 RabbitMQ 更适合小规模、高频次的消息传递场景。
四、docker #
1. dockerfile有哪些关键字?用途是什么? #
Dockerfile 是一个用于自动化创建 Docker 镜像的脚本文件,其中包含了构建镜像所需的所有命令和参数。Dockerfile 中的关键字定义了如何构建镜像。常用的关键字及其用途如下:
1. FROM #
用途:指定基础镜像,是 Dockerfile 中的第一个命令。所有的 Dockerfile 都必须以
FROM
开始,表示从哪个镜像基础上构建。示例
:
FROM ubuntu:20.04
2. RUN #
用途:在镜像构建过程中执行命令。通常用于安装依赖、更新系统等操作。
示例
:
RUN apt-get update && apt-get install -y curl
3. CMD #
用途:为容器设置默认执行的命令。可以覆盖容器启动时的命令。
CMD
可以接受命令和参数,通常用于运行容器时的入口点。示例
:
CMD ["python", "app.py"]
4. ENTRYPOINT #
用途:定义容器启动时的默认命令。与
CMD
类似,但ENTRYPOINT
是不可覆盖的,CMD
是可选的。如果CMD
和ENTRYPOINT
同时存在,CMD
提供默认参数。示例
:
ENTRYPOINT ["python", "app.py"]
5. COPY #
用途:将文件或目录从主机复制到镜像内。
示例
:
COPY ./app /usr/src/app
6. ADD #
用途:类似于
COPY
,但还支持从 URL 下载文件以及自动解压 tar 包。示例
:
ADD https://example.com/app.tar.gz /usr/src/app
7. EXPOSE #
用途:声明容器运行时监听的端口。它不会主动发布端口,而是作为文档的说明。
示例
:
EXPOSE 80
8. ENV #
用途:设置环境变量。在容器内部可以使用这些环境变量。
示例
:
ENV APP_HOME /usr/src/app
9. ARG #
用途:定义构建时使用的变量。可以在
docker build
时通过--build-arg
提供参数。示例
:
ARG VERSION=1.0
10. VOLUME #
用途:创建挂载点,允许容器与主机或其他容器之间共享数据。
示例
:
VOLUME ["/data"]
11. WORKDIR #
用途:设置工作目录。后续的
RUN
、CMD
、ENTRYPOINT
等指令将在此目录下执行。示例
:
WORKDIR /usr/src/app
12. USER #
用途:指定镜像中的用户。容器在启动时会以指定的用户身份运行。
示例
:
USER appuser
13. LABEL #
用途:给镜像添加元数据(如版本号、作者等)。
示例
:
LABEL version="1.0" maintainer="yourname@example.com"
14. SHELL #
用途:设置
RUN
命令使用的 shell,默认为/bin/sh -c
,可以通过SHELL
指令改变。示例
:
SHELL ["/bin/bash", "-c"]
15. STOPSIGNAL #
用途:指定容器停止时要发送的信号,默认是
SIGTERM
。示例
:
STOPSIGNAL SIGINT
总结 #
这些关键字在 Dockerfile 中分别用于定义镜像的基础、运行时的命令、容器的配置等,帮助用户灵活配置和构建自定义镜像。通过合理的使用这些关键字,可以大大提高镜像构建的效率和可维护性。
2. 如何减小dockerfile生成镜像体积? #
- 尽量选取满足需求但较小的基础系统镜像,例如大部分时候可以选择debian:wheezy或debian:jessie镜像,仅有不足百兆大小;
- 清理编译生成文件、安装包的缓存等临时文件;
- 安装各个软件时候要指定准确的版本号,并避免引入不需要的依赖;
- 从安全角度考虑,应用要尽量使用系统的库和依赖;
- 如果安装应用时候需要配置一些特殊的环境变量,在安装后要还原不需要保持的变量值;
减小 Dockerfile 生成镜像体积是优化 Docker 镜像大小的一个重要步骤。较小的镜像不仅节省存储空间,还能提高镜像的拉取速度和启动速度。以下是一些减小 Docker 镜像体积的最佳实践:
1. 选择合适的基础镜像 #
使用较小的基础镜像,例如
alpine
,而不是较大的镜像如ubuntu
或centos
。Alpine
是一个非常轻量的 Linux 发行版,通常它的体积只有 5 MB 左右。示例
:
FROM alpine:3.12
2. 尽量减少 RUN
指令的层数
#
Dockerfile 中的每个命令都会创建一个新的镜像层。尽量将多个命令合并到一个
RUN
指令中,从而减少镜像层数。示例
:
# 不推荐 RUN apt-get update RUN apt-get install -y curl RUN apt-get install -y vim # 推荐 RUN apt-get update && apt-get install -y curl vim
3. 删除临时文件和缓存 #
在安装软件时,通常会产生缓存文件和临时文件,这些文件在最终镜像中是没用的。在安装完成后,使用
&&
将删除缓存的操作合并到同一个RUN
命令中。示例
:
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
4. 使用 .dockerignore
文件
#
类似于
.gitignore
文件,.dockerignore
文件可以防止不需要的文件被复制到镜像中,减少镜像体积。通常应该忽略不需要的源代码文件、临时文件、日志文件等。示例
:
.git *.log *.md
5. 使用多阶段构建(Multi-stage Build) #
使用多阶段构建可以将构建过程和最终的运行镜像分开,在构建阶段安装依赖并进行编译,然后只将最终生成的二进制文件复制到一个更小的运行镜像中。这种方式可以有效减小最终镜像的大小。
示例
:
# 构建阶段 FROM golang:1.15 as builder WORKDIR /src COPY . . RUN go build -o /bin/myapp # 运行阶段 FROM alpine:3.12 COPY --from=builder /bin/myapp /bin/myapp CMD ["/bin/myapp"]
6. 使用压缩格式的文件 #
如果你需要将文件添加到镜像中,可以考虑使用压缩文件。然后在镜像构建时解压这些文件,这样可以减小源文件的大小。
示例
:
COPY app.tar.gz /app/ RUN tar -zxvf /app/app.tar.gz -C /app && rm /app/app.tar.gz
7. 避免使用 ADD
除非需要
#
ADD
可以处理压缩包并自动解压缩文件,但它也会带来不必要的文件操作。除非需要解压缩或从 URL 下载文件,否则应使用COPY
代替。示例
:
# 不推荐 ADD app.tar.gz /app/ # 推荐 COPY app.tar.gz /app/
8. 精简镜像中的文件和依赖 #
避免安装不必要的库和工具。安装后删除不需要的文件,例如开发依赖和文档文件。
示例
:
RUN apt-get update && apt-get install -y --no-install-recommends \ curl vim && rm -rf /var/lib/apt/lists/*
9. 使用合适的压缩格式 #
- Docker 镜像支持多种压缩格式,使用
gzip
格式可能会产生较大的镜像,而使用xz
或lzma
格式会使得镜像体积更小。通过 Docker 工具docker export
和docker import
还可以重新压缩镜像。
10. 减少日志文件和调试信息 #
- 在容器镜像中避免包含不必要的日志文件或调试信息,这些文件在生产环境中并不需要。
总结: #
通过合理的优化 Dockerfile,可以显著减小生成镜像的体积,提高部署速度、减少网络带宽消耗。最重要的优化措施是选择合适的基础镜像、合并 RUN
命令、清理临时文件以及使用多阶段构建。
3. dockerfile中CMD与ENTRYPOINT区别是什么? #
- CMD 和 ENTRYPOINT 指令都是用来指定容器启动时运行的命令。
- 指定 ENTRYPOINT 指令为 exec 模式时,CMD指定的参数会作为参数添加到 ENTRYPOINT 指定命令的参数列表中。
在 Dockerfile 中,CMD
和 ENTRYPOINT
都是用来指定容器启动时执行的命令,它们在功能上有些相似,但也有一些关键的区别:
1. CMD(命令) #
用途:设置容器启动时的默认命令及其参数。可以通过
docker run
时提供的命令来覆盖。语法:
CMD ["executable", "param1", "param2"]
(JSON 数组格式)CMD ["param1", "param2"]
(Shell 格式,假设默认使用某个命令,比如/bin/sh -c
)CMD command param1 param2
(Shell 格式)
特点:
- 如果 Dockerfile 中既有
CMD
,也有ENTRYPOINT
,则CMD
提供默认的参数,ENTRYPOINT
定义默认的执行程序。 - 如果通过
docker run
命令指定了其它命令,CMD
中的命令会被覆盖。
- 如果 Dockerfile 中既有
示例:
CMD ["echo", "Hello, World!"]
运行时:
docker run <image>
会输出Hello, World!
。通过
docker run <image> <new command>
可以覆盖CMD
设置的命令。
2. ENTRYPOINT(入口点) #
用途:设置容器启动时的入口命令,通常是容器启动时的主命令。与
CMD
不同,ENTRYPOINT
定义的是容器的执行方式,CMD
可以为ENTRYPOINT
提供默认参数。语法:
ENTRYPOINT ["executable", "param1", "param2"]
(JSON 数组格式)ENTRYPOINT command param1 param2
(Shell 格式)
特点:
ENTRYPOINT
不会被docker run
命令覆盖。如果需要动态地给ENTRYPOINT
提供参数,通常通过CMD
提供默认参数。ENTRYPOINT
使容器执行的命令更固定,通常用于像服务程序等容器主程序。
示例:
ENTRYPOINT ["echo"] CMD ["Hello, World!"]
运行时:
docker run <image>
会输出Hello, World!
,这是因为CMD
提供了默认参数Hello, World!
给ENTRYPOINT
。通过
docker run <image> <new param>
可以覆盖CMD
的参数,但ENTRYPOINT
不会被覆盖,echo
命令始终会执行。
区别总结 #
特性 | CMD | ENTRYPOINT |
---|---|---|
作用 | 定义默认命令及其参数,容器启动时执行。 | 定义容器的主命令,通常不被覆盖。 |
能否被覆盖 | 可以通过 docker run 时指定命令覆盖。 | 不会被 docker run 指定的命令覆盖。 |
与 ENTRYPOINT 结合使用 | 可以为 ENTRYPOINT 提供默认参数。 | 一般作为主命令,CMD 提供默认参数。 |
用法 | 通常用于提供默认的参数或执行的命令。 | 用于定义容器的主进程命令,确保容器启动时执行。 |
常见的组合方式 #
只使用
CMD
:适合容器启动时可以有灵活的命令行参数。CMD ["echo", "Hello, World!"]
只使用
ENTRYPOINT
:适合容器启动时执行固定的命令。ENTRYPOINT ["echo"] CMD ["Hello, World!"]
这样可以通过
docker run
时指定不同的参数来改变输出内容:docker run <image> "New Message"
使用
ENTRYPOINT
+CMD
:这种方式组合可以确保容器始终执行主命令,而CMD
提供默认参数,且可以通过docker run
覆盖。ENTRYPOINT ["python"] CMD ["app.py"]
通过
docker run
可以指定不同的脚本:docker run <image> app2.py
结论 #
- 使用
ENTRYPOINT
来定义固定的主命令,不希望用户覆盖。 - 使用
CMD
来为命令提供默认参数,或者提供默认命令,可以被用户覆盖。
4. dockerfile中COPY和ADD区别是什么? #
- COPY指令和ADD指令都可以将主机上的资源复制或加入到容器镜像中
- 区别是ADD可以从 远程URL中的资源不会被解压缩。
- 如果是本地的压缩包ADD进去会被解压缩
在 Dockerfile 中,COPY
和 ADD
都是用来将文件或目录从宿主机复制到 Docker 镜像中,但它们有一些不同的功能和用途。下面是它们的主要区别:
1. COPY #
用途:
COPY
是最简单的文件复制指令,用于将宿主机的文件或目录复制到镜像中。它只做简单的复制操作,不会进行任何解压或额外的操作。语法:
COPY <src> <dest>
<src>
:源路径,可以是宿主机中的文件或目录。<dest>
:目标路径,将文件或目录复制到镜像中。
特点:
- 只做文件复制,不支持解压压缩文件。
- 不会自动从 URL 下载文件。
- 适用于普通的文件复制需求。
示例:
COPY ./myapp /usr/src/app/
2. ADD #
用途:
ADD
是一个功能更强大的指令,不仅可以将文件从宿主机复制到镜像中,还支持从 URL 下载文件并解压 tar 文件到镜像中。语法:
ADD <src> <dest>
<src>
:源路径,可以是宿主机中的文件、目录或 URL。<dest>
:目标路径,将文件或目录复制到镜像中。
特点:
- 如果源是一个
.tar
文件,ADD
会自动解压到目标路径。 - 支持从 URL 下载文件并将其复制到镜像中。
- 由于功能更多,因此
ADD
可能会引入一些不必要的复杂性,特别是在没有解压需求的情况下。
- 如果源是一个
示例:
ADD ./myapp.tar /usr/src/app/ # 自动解压 myapp.tar ADD https://example.com/file.tar.gz /usr/src/app/ # 从 URL 下载并解压
区别总结 #
特性 | COPY | ADD |
---|---|---|
功能 | 仅仅复制文件或目录 | 复制文件或目录,同时支持解压 .tar 文件和从 URL 下载文件 |
解压支持 | 不支持自动解压文件 | 支持自动解压 .tar 文件 |
从 URL 下载文件 | 不支持 | 支持从 URL 下载文件并复制到镜像中 |
推荐场景 | 简单的文件复制操作,无需解压或下载功能 | 当需要解压 .tar 文件或从 URL 下载文件时 |
安全性和可控性 | 更加简洁和明确,推荐用于复制文件 | 由于额外功能(自动解压和下载),使用时需要小心,避免不必要的复杂性 |
使用建议 #
- 推荐使用
COPY
:对于普通的文件复制操作,COPY
更加简单明了,避免了额外的复杂性。如果不需要解压或从 URL 下载文件,使用COPY
更加合适。 - 使用
ADD
时:仅当你确实需要从 URL 下载文件或需要自动解压.tar
文件时,才应使用ADD
,因为ADD
的额外功能可能会增加不必要的复杂性。
示例 #
简单复制文件:
COPY ./myapp /usr/src/app/
- 使用
COPY
来将文件从宿主机复制到镜像。
- 使用
下载并解压文件:
ADD https://example.com/file.tar.gz /usr/src/app/
- 使用
ADD
从 URL 下载文件并解压到镜像中。
- 使用
结论 #
- 如果只是复制文件,优先使用
COPY
,它更简洁且不会做多余的操作。 - 如果需要从 URL 下载文件或解压文件,才使用
ADD
。
5. docker的cs架构组件有哪些? #
Docker 的 CS(Client-Server)架构是 Docker 的核心架构模式,其中包含以下主要组件:
1. Docker Client(客户端) #
- 作用:Docker 客户端是用户与 Docker 引擎交互的接口,负责发送命令并接收输出。它通过命令行界面(CLI)与 Docker 引擎通信。
- 常见命令:
docker run
、docker ps
、docker build
、docker images
等。 - 与 Docker Engine 通信:客户端通过 Docker API 与 Docker 引擎进行交互,通常是通过 HTTP 或 Unix socket 来与 Docker 守护进程通信。
2. Docker Daemon(守护进程) #
- 作用:Docker 守护进程是 Docker 的核心,它负责管理容器生命周期(创建、启动、停止和销毁容器)。它还负责管理镜像、网络、卷等其他 Docker 组件,并处理来自 Docker 客户端的请求。
- 常见操作:
docker run
、docker build
、docker network
、docker volume
等。 - 通信方式:守护进程通常运行在后台,监听来自 Docker 客户端的请求并返回相应的结果。
3. Docker Registry(镜像仓库) #
- 作用:Docker Registry 是一个用于存储和分发 Docker 镜像的服务。官方的 Docker 镜像仓库是 Docker Hub,用户可以将自己的镜像上传到此仓库,也可以从仓库拉取所需的镜像。
- 常见操作:
docker push
(上传镜像)、docker pull
(拉取镜像)、docker search
(搜索镜像)。 - 本地仓库:除了 Docker Hub,还可以配置私有仓库来存储自己的镜像。
4. Docker Image(镜像) #
- 作用:Docker 镜像是一个包含了应用程序及其所有依赖项、库、配置文件等的只读模板。镜像是容器的蓝图。
- 构建过程:可以通过
Dockerfile
文件来构建镜像。 - 从镜像启动容器:通过
docker run
命令启动一个容器实例。
5. Docker Container(容器) #
- 作用:Docker 容器是镜像的一个可执行实例。它是一个轻量级的、可移植的、封装了应用及其依赖环境的运行时环境。容器运行在宿主操作系统内,且与宿主系统隔离。
- 常见操作:
docker start
、docker stop
、docker exec
、docker logs
等。 - 隔离性:容器提供进程、网络、文件系统的隔离,但与宿主系统共享内核。
6. Docker Volume(数据卷) #
- 作用:Docker 卷是持久化和共享容器数据的机制,允许容器和主机共享数据或在多个容器之间共享数据。数据卷独立于容器的生命周期存在,即使容器被删除,数据卷中的数据仍然存在。
- 常见操作:
docker volume create
、docker volume inspect
、docker volume rm
。
7. Docker Network(网络) #
- 作用:Docker 网络功能使容器能够互相通信。Docker 提供了几种网络模式,包括桥接网络(bridge)、主机网络(host)、覆盖网络(overlay)等。
- 常见操作:
docker network create
、docker network inspect
、docker network connect
。
8. Docker Swarm(集群管理) #
- 作用:Docker Swarm 是 Docker 提供的集群管理和编排工具。它使得多个 Docker 主机可以联合起来,共同运行容器,形成一个集群,提供容器的负载均衡、服务发现、扩展性等功能。
- 常见操作:
docker swarm init
(初始化集群)、docker service create
(创建服务)、docker node ls
(列出集群节点)。
9. Docker Compose(编排工具) #
- 作用:Docker Compose 是一个工具,用于定义和运行多容器 Docker 应用。通过
docker-compose.yml
配置文件,用户可以定义多个容器服务的组成、配置及其之间的依赖关系,方便进行多容器环境的管理和部署。 - 常见操作:
docker-compose up
(启动应用)、docker-compose down
(停止应用)、docker-compose build
(构建服务)。
10. Docker CLI(命令行工具) #
- 作用:Docker CLI 是与 Docker 守护进程进行交互的命令行工具,允许用户通过命令行来操作 Docker,管理容器、镜像、网络、卷等。
- 常见命令:
docker ps
(列出容器)、docker run
(运行容器)、docker build
(构建镜像)等。
总结 #
Docker 的 CS 架构组件包括:
- Docker Client:用户与 Docker 引擎交互的客户端。
- Docker Daemon:Docker 引擎,负责处理命令并管理容器、镜像等。
- Docker Registry:用于存储和分发镜像的仓库。
- Docker Image:容器的静态模板。
- Docker Container:镜像的运行实例,具有隔离性。
- Docker Volume:持久化容器数据。
- Docker Network:容器之间的网络通信管理。
- Docker Swarm:容器集群管理和编排工具。
- Docker Compose:用于管理和编排多个容器的工具。
- Docker CLI:命令行界面,允许与 Docker 引擎进行交互。
这些组件共同作用,确保 Docker 提供高效、灵活、易于扩展的容器化平台。
6. docker网络类型有哪些? #
- host模式
- container模式
- none模式
- bridge模式
Docker 提供了几种不同的网络类型,以满足不同应用场景下的容器通信需求。以下是 Docker 支持的主要网络类型及其特点:
1. Bridge Network(桥接网络) #
作用:这是 Docker 的默认网络模式。它在宿主机上创建一个虚拟的网络桥(bridge),容器会连接到这个网络上,所有容器共享此网络接口。容器之间通过桥接网络进行通信。
特点:
- 每个容器会获得一个私有 IP 地址,并且能够通过宿主机的 IP 地址与外界通信。
- 容器之间可以互相通信,但只能通过网络桥接接口(如
docker0
)实现。 - 通常适用于单机环境,容器相互之间需要隔离但仍可以共享宿主机的网络。
使用场景:
- 默认网络模式,适合单机环境下的容器通信。
常见命令:
docker network create --driver bridge my_bridge_network
2. Host Network(主机网络) #
作用:在这种模式下,容器直接使用宿主机的网络接口。容器不会获得独立的 IP 地址,而是与宿主机共享网络栈。
特点:
- 容器与宿主机共享网络 IP 和端口(容器中的端口映射到宿主机的端口)。
- 适用于要求低延迟和高性能的网络应用,因为它消除了网络隔离。
- 由于容器与宿主机共享网络,因此容器暴露的端口不会经过虚拟网络桥。
使用场景:
- 性能要求高的场景,特别是需要访问宿主机网络资源的应用(如数据库连接、低延迟通信等)。
常见命令:
docker run --network host my_container
3. Overlay Network(覆盖网络) #
作用:覆盖网络是 Docker Swarm 模式下使用的网络类型,允许跨多个宿主机的容器之间进行通信。Overlay 网络使得分布式应用中的容器能够通过一个虚拟的网络在不同宿主机之间进行通信。
特点:
- 容器无需知道实际所在的宿主机,所有容器都可以使用相同的虚拟 IP 地址。
- 通过 VXLAN 隧道技术实现跨宿主机的容器网络连接。
- 适用于多主机集群中容器之间的通信,特别是 Docker Swarm 或 Kubernetes 集群中的容器通信。
使用场景:
- 在 Docker Swarm 或 Kubernetes 等集群环境中使用,适合分布式微服务架构的部署。
常见命令:
docker network create --driver overlay my_overlay_network
4. Macvlan Network(Macvlan 网络) #
作用:Macvlan 网络为容器提供一个独立的 MAC 地址和 IP 地址,使得容器像物理设备一样直接连接到物理网络中。这种模式适合需要与物理网络设备直接通信的场景。
特点:
- 每个容器都有独立的 MAC 地址和 IP 地址,因此容器可以被视为网络中的独立设备。
- 容器可以直接与物理网络中的其他设备进行通信,如访问外部网络中的其他机器。
- 常用于要求容器与物理网络设备直接交互的情况,如通过 DHCP 获取 IP 地址等。
使用场景:
- 容器需要与宿主机外的网络设备直接通信,或需要与其他物理主机共享网络。
常见命令:
docker network create -d macvlan --subnet=192.168.1.0/24 --gateway=192.168.1.1 my_macvlan_network
5. None Network(无网络) #
作用:这种网络模式下,容器不会连接任何网络接口,也没有自己的 IP 地址。容器可以完全隔离与外界的网络通信。
特点:
- 容器没有网络接口,无法访问外部网络,适用于容器不需要网络连接的场景。
- 如果容器需要使用其他网络,可以通过自定义配置实现。
使用场景:
- 对于某些需要完全隔离的容器,或者某些只处理计算任务而不需要网络连接的场景。
常见命令:
docker run --network none my_container
6. Container Network(容器网络) #
作用:容器网络是指通过
--link
选项将一个容器的网络连接到另一个容器。容器与容器之间通过共享网络栈来进行通信。特点:
- 一个容器的网络栈被直接共享给另一个容器,使得两个容器之间能够直接通信。
- 容器共享 IP 地址和端口,适用于需要高度耦合的应用。
使用场景:
- 当容器之间需要直接共享网络环境时,例如服务间需要高度耦合并直接访问对方网络资源。
常见命令:
docker run --network container:<container_name> my_container
总结 #
Docker 支持的网络类型包括:
- Bridge Network:默认网络模式,适用于单机容器间的通信。
- Host Network:容器与宿主机共享网络,适用于高性能场景。
- Overlay Network:适用于 Docker Swarm 集群环境,跨主机容器通信。
- Macvlan Network:给容器分配独立的 MAC 地址和 IP 地址,适用于与物理网络直接通信。
- None Network:容器不使用任何网络接口,完全隔离。
- Container Network:容器间共享网络栈,适用于需要紧密耦合的应用。
每种网络类型适用于不同的场景,根据你的应用需求选择合适的网络模式来保证容器间通信的效率与安全性。
7. 如何配置docker远程访问? #
- vim /lib/systemd/system/docker.service
- 在ExecStart=后添加配置,注意,需要先空格后,再输入 -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock
要配置 Docker 远程访问,需要修改 Docker 的配置,使其监听在一个可供远程访问的 IP 地址和端口上。以下是配置 Docker 远程访问的步骤:
1. 修改 Docker 配置文件 #
默认情况下,Docker 只监听本地的 Unix Socket(/var/run/docker.sock
),不允许远程访问。要启用远程访问,需要修改 Docker 的配置,使其监听 TCP 端口。
步骤: #
打开 Docker 服务的配置文件,通常是
/lib/systemd/system/docker.service
或/etc/systemd/system/docker.service
,取决于你的 Linux 发行版和 Docker 的安装方式。找到以
ExecStart
开头的行。它会指定 Docker 的启动命令。ExecStart=/usr/bin/dockerd --host=unix:///var/run/docker.sock
修改为:
ExecStart=/usr/bin/dockerd --host=unix:///var/run/docker.sock --host=tcp://0.0.0.0:2375
这将使 Docker 同时监听 Unix Socket 和 0.0.0.0 的 TCP 端口 2375(所有 IP 地址的 2375 端口)。你可以根据需要修改监听的 IP 地址和端口。若只允许特定 IP 访问,可以将
0.0.0.0
改为服务器的实际 IP 地址,例如tcp://192.168.1.100:2375
。
2. 配置防火墙 #
确保防火墙允许访问 Docker 的 2375 端口。如果使用 firewalld
,可以运行以下命令:
sudo firewall-cmd --zone=public --add-port=2375/tcp --permanent
sudo firewall-cmd --reload
如果使用 ufw
,可以执行:
sudo ufw allow 2375/tcp
3. 重启 Docker 服务 #
修改配置后,需要重启 Docker 服务使配置生效:
sudo systemctl daemon-reload
sudo systemctl restart docker
4. 测试远程访问 #
在客户端机器上使用 Docker 命令连接远程 Docker 守护进程。
例如,使用以下命令:
docker -H tcp://<docker_host_ip>:2375 info
如果配置成功,你应该能够看到 Docker 服务器的详细信息。
5. 使用 TLS 安全连接(推荐) #
暴露 Docker 的远程访问接口时,默认是没有加密和认证的,任何可以访问该端口的人都能控制 Docker 服务。这非常不安全,尤其是在生产环境中。为确保安全,建议启用 TLS 加密和认证。
生成 SSL 证书并配置 Docker 使用它们:
你可以使用
openssl
生成证书,或者使用 Let’s Encrypt 等证书提供商。配置 Docker 使用证书和私钥:
修改 Docker 服务启动命令来指定证书和私钥:
ExecStart=/usr/bin/dockerd --host=tcp://0.0.0.0:2376 --tlsverify --tlscacert=/etc/docker/ca.pem --tlscert=/etc/docker/server-cert.pem --tlskey=/etc/docker/server-key.pem
在这种情况下,Docker 远程访问需要客户端提供相应的证书。
6. 在客户端连接时使用 TLS #
客户端连接 Docker 服务时,必须使用 TLS 认证。
docker --host=tcp://<docker_host_ip>:2376 --tlsverify --tlscacert=/path/to/ca.pem --tlscert=/path/to/cert.pem --tlskey=/path/to/key.pem info
总结 #
- 开放端口:修改 Docker 配置,监听 TCP 端口(如 2375)来允许远程访问。
- 防火墙配置:确保防火墙允许外部访问 Docker 的端口。
- 远程连接:通过
docker -H tcp://<docker_host_ip>:2375
来进行远程连接。 - 安全:建议使用 TLS 加密和认证来保护 Docker 远程接口,防止未授权的访问。
通过以上步骤,你就可以配置 Docker 进行远程访问并与远程主机进行交互。
8. docker核心namespace CGroups 联合文件系统功能是什么? #
- namespace:资源隔离
- cgroup:资源控制
- 联合文件系统:支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下
Docker 作为一个容器化平台,依赖于操作系统的几个核心技术来实现容器的轻量化和高效性。Docker 主要通过 Namespace、Cgroups 和 联合文件系统(Union File System) 来实现容器的隔离性、资源限制和文件系统共享。下面是这三种技术的功能和作用:
1. Namespace(命名空间) #
命名空间(Namespace) 是 Linux 内核的一个特性,提供了对系统资源的隔离,使得每个容器都可以拥有独立的视图,而互相之间是隔离的。Docker 使用命名空间来确保容器之间的资源不会互相干扰。Docker 支持以下几种命名空间:
PID Namespace(进程命名空间)
:
- 每个容器有独立的进程 ID 空间。容器内的进程 ID 从 1 开始,和宿主机的进程 ID 是完全隔离的。这使得容器内的进程与宿主机或其他容器的进程互不干扰。
NET Namespace(网络命名空间)
:
- 每个容器有独立的网络栈,包括 IP 地址、路由表、网络接口、端口等。这样可以确保容器之间的网络是隔离的,不会互相干扰。
MNT Namespace(挂载命名空间)
:
- 每个容器可以拥有自己的文件系统挂载点,容器的挂载点与宿主机的文件系统是隔离的。这样可以使容器内的文件系统和宿主机或其他容器的文件系统互不干扰。
UTS Namespace(UNIX时间命名空间)
:
- 每个容器有独立的主机名和域名。容器内的主机名和域名与宿主机或其他容器的主机名和域名是隔离的。
IPC Namespace(进程间通信命名空间)
:
- 每个容器有独立的进程间通信资源(如共享内存、信号量、消息队列等)。这意味着容器内的进程不能与宿主机或其他容器中的进程共享内存或进行通信。
USER Namespace(用户命名空间)
:
- 容器内的用户和组 ID 被映射到宿主机的用户和组 ID,这可以有效地增强容器的安全性。容器内的 root 用户可以映射为宿主机上的非特权用户,从而降低安全风险。
总结:命名空间的作用是 资源隔离,每个容器在自己的命名空间中拥有独立的资源视图,互不干扰。
2. Cgroups(控制组) #
Cgroups(Control Groups) 是 Linux 内核的一个特性,用于限制、控制和监控进程组的资源使用。Docker 利用 Cgroups 来限制每个容器使用的 CPU、内存、磁盘 I/O 和网络等资源,以确保资源的公平分配和容器的限制性使用。
CPU 限制
:
- 通过 Cgroups,可以为容器分配一定的 CPU 配额和权重,控制容器的 CPU 使用量。
内存限制
:
- Cgroups 可以为容器指定最大内存使用量,一旦超过该限制,容器内的进程会被 OOM Killer 杀死,避免因内存耗尽导致系统崩溃。
磁盘 I/O 限制
:
- Cgroups 可以限制容器的磁盘 I/O 性能,如读取和写入速度等,避免某些容器过度占用磁盘资源影响其他容器。
网络带宽限制
:
- 通过 Cgroups,容器的网络带宽也可以被控制和限制。
总结:Cgroups 的作用是 资源限制和管理,它确保每个容器使用的资源不会超出预定的限制,防止某个容器占用过多资源导致其他容器和宿主机资源不足。
3. Union File System(联合文件系统) #
联合文件系统(Union FS) 是一种文件系统,它允许将多个目录合并成一个虚拟的文件系统。Docker 使用联合文件系统来实现容器文件系统的共享和隔离,从而避免重复的数据存储。
- 层叠存储:
- Docker 使用 Union File System(如 AUFS、OverlayFS、Btrfs、ZFS 等)来将多个文件系统层叠在一起,形成一个单一的文件系统。每个容器的文件系统由多个只读层和一个可写层组成。容器启动时,会从镜像中加载文件系统的只读层,而容器写入的数据会存储在容器的可写层中。
- 镜像共享:
- 镜像的每一层是不可修改的,可以被多个容器共享。这使得容器能够快速启动并节省磁盘空间,因为不同容器共享相同的镜像层,只为容器的个性化修改保留单独的可写层。
- 文件系统效率:
- 由于文件系统层是基于差异(如只读层与可写层的差异),容器不会浪费存储空间来重复存储相同的数据,从而提高了文件系统的效率和节省存储空间。
总结:联合文件系统的作用是 高效的存储和层叠文件系统,它通过文件系统的层叠存储,使得容器能够共享镜像层、节省存储空间并提高性能。
综合总结: #
- Namespace 提供了容器之间的 资源隔离,每个容器都有独立的资源视图。
- Cgroups 用于 资源限制,保证容器不会占用过多的 CPU、内存等资源。
- Union File System 实现了容器文件系统的 共享和高效存储,通过层叠文件系统降低存储浪费,提高效率。
这三种技术共同作用,使得 Docker 能够在保证容器资源隔离、限制和高效存储的同时,提供轻量级和高性能的容器化解决方案。
9. 命令相关:导入导出镜像,进入容器,设置重启容器策略,查看镜像环境变量,查看容器占用资源 #
- 导入镜像 docker load -i xx.tar
- 导出镜像docker save -o xx.tar image_name
- 进入容器docker exec -it 容器命令 /bin/bash
- 设置容器重启策略启动时 –restart选项
- 查看容器环境变量 docker exec {containerID} env
- 查看容器资源占用docker stats test2
以下是 Docker 常用命令及其用途,帮助你完成常见操作:
1. 导入和导出镜像 #
导入镜像(从 tar 包导入镜像):
将一个 tar 文件(例如备份的镜像)导入到 Docker 本地镜像中:
docker import /path/to/your/image.tar
你也可以指定标签(tag):
docker import /path/to/your/image.tar my_image:tag
导出镜像(将容器文件系统导出为 tar 包):
从容器中导出文件系统为 tar 包:
docker export <container_id> > /path/to/your/container_backup.tar
这将导出容器的文件系统,但不会导出镜像层。
2. 进入容器 #
使用 docker exec
命令进入正在运行的容器:
docker exec -it <container_id_or_name> /bin/bash
-i
:保持标准输入流(stdin)打开,允许你与容器交互。-t
:为容器分配一个伪终端。
如果容器内没有 /bin/bash
,可以尝试 /bin/sh
:
docker exec -it <container_id_or_name> /bin/sh
3. 设置重启策略 #
使用 --restart
标志设置容器的重启策略,确保容器在特定情况下自动重启。常见的重启策略包括:
- no:默认值,容器退出时不重启。
- always:容器退出时始终重启。
- unless-stopped:容器退出时重启,除非它被手动停止。
- on-failure:只有在容器非零退出时才会重启。
例如,创建一个总是重启的容器:
docker run -d --restart always my_image
或者,修改现有容器的重启策略:
docker update --restart always <container_id_or_name>
4. 查看镜像环境变量 #
要查看镜像中的环境变量,可以使用以下命令:
docker inspect --format '{{.Config.Env}}' <image_id_or_name>
这将返回镜像中定义的环境变量列表。
如果你想查看容器的环境变量,可以执行:
docker exec <container_id_or_name> printenv
这将显示容器内所有的环境变量。
5. 查看容器占用资源 #
要查看容器的资源使用情况,可以使用以下命令:
docker stats <container_id_or_name>
这将显示容器的 CPU 使用率、内存使用、网络 I/O 等实时信息。
docker stats
命令会持续输出资源使用情况,直到你按Ctrl + C
停止。要查看所有容器的资源使用情况,可以不指定容器 ID,直接运行
docker stats
:docker stats
这个命令显示的是容器实时的资源消耗情况,可以帮助你识别资源瓶颈。
总结:
- 导入镜像:
docker import
- 导出容器文件系统:
docker export
- 进入容器:
docker exec -it <container_id> /bin/bash
- 设置重启策略:
--restart
或docker update --restart
- 查看镜像环境变量:
docker inspect --format '{{.Config.Env}}'
- 查看容器占用资源:
docker stats
10. 构建镜像有哪些方式? #
- dockerfile
- 容器提交为镜像
构建 Docker 镜像的方式有多种,常见的方式包括使用 Dockerfile、通过 docker commit
命令以及从已有镜像创建自定义镜像。以下是详细介绍:
1. 通过 Dockerfile 构建镜像 #
最常见的方式是使用 Dockerfile
构建镜像。Dockerfile
是一组指令,用于定义镜像的构建过程。每一条指令都会创建一个新的镜像层。
步骤:
- 编写
Dockerfile
,并指定基础镜像、安装应用、配置环境等。 - 使用
docker build
命令来构建镜像。
- 编写
示例 Dockerfile:
# 使用官方的 Ubuntu 镜像作为基础镜像 FROM ubuntu:20.04 # 设置维护者信息 LABEL maintainer="yourname@example.com" # 安装必要的软件包 RUN apt-get update && apt-get install -y \ curl \ vim # 设置工作目录 WORKDIR /app # 复制文件到容器中 COPY . /app # 设置容器的启动命令 CMD ["python3", "app.py"]
构建命令:
docker build -t my_image_name:tag .
-t my_image_name:tag
:指定镜像的名称和标签(例如my_image_name:latest
)。.
:指定Dockerfile
的路径,.
表示当前目录。
2. 使用 docker commit
构建镜像
#
如果你已经运行了一个容器,并且对容器进行了某些修改(比如安装了软件包或改变了配置),你可以通过 docker commit
命令将容器的当前状态保存为一个新的镜像。
步骤:
- 启动一个容器并对其进行修改。
- 使用
docker commit
命令将容器的当前状态保存为一个新的镜像。
命令:
docker commit <container_id_or_name> <new_image_name>:<tag>
container_id_or_name
:容器的 ID 或名称。new_image_name:tag
:要创建的镜像的名称和标签。
示例:
假设你已经运行了一个容器,并且在容器中安装了一个新的软件包:
docker commit my_container my_new_image:v1
这样,你就创建了一个新的镜像
my_new_image:v1
,其中包含你在容器中所做的修改。
3. 从现有镜像创建自定义镜像 #
你也可以基于现有的镜像,手动修改容器并保存为新的镜像。这通常是通过交互式地进入容器进行修改,然后使用 docker commit
命令保存这些修改。
步骤:
- 启动一个容器并进入容器。
- 在容器内部进行修改。
- 使用
docker commit
保存容器的状态为新镜像。
命令:
启动容器:
docker run -it ubuntu:20.04 /bin/bash
在容器内做一些修改(例如安装软件):
apt-get update && apt-get install -y curl
退出容器后,使用
docker commit
创建一个新的镜像:docker commit <container_id> my_custom_image:v1
4. 通过 docker buildx
构建多平台镜像
#
docker buildx
是 Docker 提供的一个构建工具,支持构建跨平台的多架构镜像(如 ARM、x86)。
步骤:
- 使用
docker buildx
创建支持多平台的镜像。 - 需要安装
buildx
插件并启用多平台支持。
- 使用
示例:
docker buildx create --use docker buildx build --platform linux/amd64,linux/arm64 -t my_multiarch_image .
5. 使用 BuildKit 构建镜像 #
Docker BuildKit 是 Docker 18.09 引入的一个功能,提供了更快、更高效、更灵活的构建方式。
启用 BuildKit:
通过设置环境变量启用 BuildKit:
export DOCKER_BUILDKIT=1
然后使用
docker build
命令构建镜像:docker build -t my_image_name:tag .
优势:
- 支持缓存优化、并行构建、以及更精细的构建控制。
- 提供更强的支持来构建多阶段构建(multi-stage builds)。
6. 使用 Docker Compose 构建镜像 #
如果你使用 Docker Compose 来管理多个容器,可以通过 docker-compose.yml
文件来定义镜像的构建过程。
步骤:
- 在
docker-compose.yml
文件中定义服务。 - 使用
docker-compose build
构建镜像。
- 在
示例
docker-compose.yml
文件:version: '3' services: web: build: . ports: - "80:80"
build: .
表示使用当前目录下的Dockerfile
构建镜像。
构建镜像:
docker-compose build
总结: #
- Dockerfile 构建镜像:标准的镜像构建方式,灵活、可复用,适用于复杂的镜像构建。
- docker commit 构建镜像:通过修改容器并保存为镜像,适用于快速创建镜像,通常不推荐用于生产环境。
- 现有镜像创建自定义镜像:手动修改容器后,通过
docker commit
保存修改,适用于基于已有镜像做定制化开发。 - docker buildx 构建多平台镜像:支持跨平台架构构建,适用于构建多种平台的镜像。
- Docker BuildKit:提供更高效的构建,支持并行构建和缓存优化,适用于复杂的构建场景。
- Docker Compose 构建镜像:适用于多容器应用的镜像构建和管理。
这些方法可以根据项目需求、工作流程和团队协作的需要来选择。
11. docker和vmware虚拟化区别? #
Docker 和 VMware 都是虚拟化技术,但它们的工作原理和使用场景有很大的不同。以下是它们的主要区别:
1. 虚拟化类型 #
- Docker(容器化):Docker 是一种 操作系统级虚拟化 技术,基于 Linux 内核的 cgroups 和 namespace 实现。容器在共享宿主机操作系统内核的基础上运行,每个容器是一个独立的用户空间环境,但它们共享宿主操作系统的内核。
- VMware(虚拟机):VMware 是一种 硬件级虚拟化 技术,使用虚拟机管理程序(Hypervisor)直接在硬件上创建和管理多个虚拟机(VM)。每个虚拟机都包含一个完整的操作系统,包括内核和用户空间。
2. 资源开销 #
- Docker:容器是共享宿主操作系统内核的,因此启动速度快,资源占用低,不需要为每个容器分配完整的操作系统。Docker 容器的资源开销相对较小。
- VMware:虚拟机包含完整的操作系统和虚拟化的硬件资源,因此每个虚拟机的启动速度较慢,资源开销也较大。每个虚拟机都需要分配一定的内存、CPU、存储等硬件资源。
3. 启动时间 #
- Docker:容器启动速度非常快,通常只需几秒钟。因为容器仅包含运行应用程序所需的文件系统和依赖,它们不会像虚拟机一样加载完整的操作系统。
- VMware:虚拟机启动速度相对较慢,需要加载整个操作系统,并进行硬件初始化,通常需要几分钟。
4. 隔离级别 #
- Docker:容器共享宿主机操作系统的内核,容器之间的隔离度较低。虽然 Docker 使用了 cgroups 和 namespaces 来实现一定程度的资源隔离和安全性,但容器间仍然存在一定的安全风险。
- VMware:虚拟机完全隔离,虚拟机之间的资源是完全独立的,每个虚拟机运行自己的操作系统和内核,因此隔离性更强,安全性较高。
5. 性能 #
- Docker:由于容器直接运行在宿主操作系统上,资源占用少,性能接近宿主机本身的性能。容器化应用在性能方面相对虚拟机来说更加高效。
- VMware:虚拟机需要模拟硬件资源,运行完整的操作系统,因此性能相较于容器会有一定的损耗。尤其是当虚拟机数量增多时,性能下降会更加明显。
6. 操作系统支持 #
- Docker:容器通常需要依赖宿主操作系统的内核。例如,Docker 在 Linux 上运行的容器使用 Linux 内核,而在 Windows 上的容器则使用 Windows 内核。Docker 仅能在兼容的操作系统上运行。
- VMware:虚拟机可以运行不同的操作系统(包括 Linux、Windows、macOS 等),每个虚拟机都带有完整的操作系统和内核,因此可以在同一硬件上运行不同的操作系统。
7. 应用场景 #
Docker
:
- 微服务架构:由于容器启动快、资源消耗少,适合部署微服务应用。
- 开发和测试:开发人员可以使用 Docker 快速构建、共享和运行应用程序,方便测试和持续集成。
- CI/CD:容器化环境使得持续集成和持续交付变得更加高效,能够快速迭代和部署应用。
VMware
:
- 虚拟化数据中心:VMware 是数据中心虚拟化的主流技术,适合企业级虚拟化部署。可以虚拟化整个服务器,提供资源的独立性和完整性。
- 多种操作系统支持:适合需要多种不同操作系统和软件栈的场景,如同时运行多个操作系统。
- 企业级高可用性:VMware 提供了包括高可用性、容错、灾难恢复等企业级功能。
8. 资源分配 #
- Docker:容器使用宿主机的操作系统内核,通常直接共享宿主机的硬件资源(CPU、内存、磁盘等)。Docker 支持资源限制(如 CPU 限制、内存限制等),但不会像虚拟机那样为每个容器分配完整的虚拟硬件资源。
- VMware:每个虚拟机都有自己的虚拟硬件(包括 CPU、内存、硬盘等),需要为每个虚拟机分配特定的资源。虚拟机的资源管理通常更加独立。
9. 迁移与扩展性 #
- Docker:容器的迁移通常更简单,可以轻松将容器从一台机器迁移到另一台机器上。Docker 也支持在云环境中快速扩展和部署。
- VMware:虚拟机迁移和扩展通常需要更多的配置和资源调配,尤其是在跨不同硬件和虚拟化平台时。VMware 提供了 vMotion 等工具来实现虚拟机迁移,但仍然比容器迁移要复杂。
总结: #
- Docker 更加轻量级,适合应用级别的虚拟化,资源开销小,启动速度快,适用于微服务、开发/测试环境和 CI/CD 等场景。
- VMware 更适合进行硬件虚拟化,提供完全的隔离和更强的安全性,适合运行不同操作系统的虚拟机,常用于企业级数据中心和多操作系统支持的场景。
根据需求,选择适合的虚拟化技术可以更高效地利用资源。
五、kubernetes #
1. k8s的集群组件有哪些?功能是什么? #
Kubernetes(K8s)是一个开源的容器编排平台,旨在自动化容器化应用程序的部署、扩展和管理。K8s 集群由多个组件组成,主要分为 控制平面(Control Plane)和 工作节点(Node)。以下是 Kubernetes 集群的核心组件及其功能:
1. 控制平面组件 #
控制平面负责管理 Kubernetes 集群,处理所有的控制任务,确保集群的工作状态与期望状态一致。
1.1 kube-apiserver #
- 功能:API 服务器是 Kubernetes 控制平面的入口点。它接收来自客户端(如 kubectl)、内部组件(如 kube-scheduler 和 kube-controller-manager)和外部系统的 REST 请求,并将其转发到适当的组件。API 服务器也提供了集群的配置和状态信息接口。
- 作用:作为集群的前端,所有的操作和请求都通过它,所有的对象都在 etcd 中存储,通过它进行 CRUD 操作。
1.2 etcd #
- 功能:etcd 是一个高可用的键值存储数据库,存储 Kubernetes 集群的所有配置数据、状态信息和元数据。
- 作用:所有的集群数据(如节点、Pod、服务等资源对象)都保存在 etcd 中。它是 Kubernetes 的 “单一数据源”,保证了集群数据的持久性。
1.3 kube-scheduler #
- 功能:kube-scheduler 是 Kubernetes 控制平面的一个组件,负责监控待调度的 Pod,并根据一系列调度策略将其分配到合适的工作节点上。
- 作用:它根据集群的资源情况、约束条件和调度策略将 Pod 分配到最合适的节点上,确保负载均衡和资源的合理利用。
1.4 kube-controller-manager #
- 功能:kube-controller-manager 是一个控制器的集合,管理 Kubernetes 集群中各类控制循环。每个控制器负责监视集群的某个资源,并根据需要采取行动。
- 作用:如:ReplicaSet 控制器确保有指定数量的 Pod 副本在运行,Deployment 控制器管理应用程序的版本升级等。
1.5 cloud-controller-manager #
- 功能:cloud-controller-manager 是 Kubernetes 控制平面的一个可选组件,旨在与云服务提供商的 API 进行集成。它使得 Kubernetes 可以与不同的云平台(如 AWS、GCP、Azure)进行交互。
- 作用:它通过与云平台的 API 交互,管理节点、负载均衡器和存储卷等云资源。
2. 工作节点组件 #
工作节点负责运行容器化应用和服务,承载实际的业务负载。
2.1 kubelet #
- 功能:kubelet 是运行在每个工作节点上的代理,负责管理该节点上的容器和 Pod。它与 Kubernetes API 服务器进行通信,确保容器按照预期运行。
- 作用:它从 API 服务器获取 Pod 描述,并确保 Pod 中的容器处于运行状态。如果容器崩溃,kubelet 会重新启动它们。
2.2 kube-proxy #
- 功能:kube-proxy 是一个网络代理,运行在每个节点上,负责处理 Pod 的网络通信。它通过负载均衡将流量路由到合适的 Pod 中。
- 作用:提供服务抽象(如 Kubernetes 服务),并将流量从集群外部或集群内部路由到正确的 Pod。它可以使用 iptables 或 IPVS 来实现负载均衡。
2.3 Container Runtime #
- 功能:容器运行时是负责在节点上运行容器的工具,kubelet 会调用容器运行时来创建和管理容器。Kubernetes 支持多种容器运行时(如 Docker、containerd、CRI-O 等)。
- 作用:它是运行容器的基础,负责容器的生命周期管理(如拉取镜像、启动容器等)。
3. 其他组件 #
这些组件有助于集群的管理、监控和运行。
3.1 Helm #
- 功能:Helm 是 Kubernetes 的包管理工具,类似于 Linux 的 apt 或 yum,它使得在 Kubernetes 中部署应用变得更加简单。
- 作用:Helm 使用 Charts(Kubernetes 应用程序的包)来管理和部署应用程序,支持版本控制和应用配置的共享。
3.2 Ingress Controller #
- 功能:Ingress Controller 负责处理进出 Kubernetes 集群的 HTTP 和 HTTPS 流量。它可以通过设置规则,将外部流量路由到集群内部的服务。
- 作用:它通过配置 Ingress 资源,定义外部访问 Kubernetes 服务的 URL 路由规则。
3.3 CNI 插件 #
- 功能:CNI(Container Network Interface)插件提供容器网络功能,它决定了 Pod 和服务之间如何进行通信。
- 作用:它是容器网络的重要组成部分,负责容器之间的网络连接和网络策略的执行。常见的 CNI 插件有 Flannel、Calico、Weave 等。
3.4 监控与日志管理 #
- 功能:监控工具(如 Prometheus 和 Grafana)和日志管理工具(如 ELK Stack、Fluentd)用于收集和展示集群及容器的监控指标、日志信息。
- 作用:通过监控和日志收集,可以及时发现系统问题、优化资源、提升可用性。
总结 #
Kubernetes 集群的核心组件包括 控制平面组件(kube-apiserver、etcd、kube-scheduler、kube-controller-manager、cloud-controller-manager)和 工作节点组件(kubelet、kube-proxy、容器运行时)。这些组件协同工作,保证集群的高效运行与自动化管理,同时也有助于扩展、监控和维护 Kubernetes 集群。
2. kubectl命令相关:如何修改副本数,如何滚动更新和回滚,如何查看pod的详细信息,如何进入pod交互? #
- 修改副本数 kubectl scale deployment redis –replicas=3
- 活动更新kubectl set image deployments myapp-deploy myapp=myapp:v2
- 回滚kubectl rollout undo deployments myapp-deploy
- 查看pod详细信息kubectl describe pods/
- 进入pod交互kubectl exec -it -c bash
以下是 kubectl
命令相关操作,用于修改副本数、滚动更新、回滚、查看 Pod 的详细信息以及进入 Pod 进行交互。
1. 修改副本数 #
要修改部署(Deployment)中 Pod 的副本数,可以使用 kubectl scale
命令:
kubectl scale deployment <deployment-name> --replicas=<number-of-replicas>
例如,将名为 my-app
的部署副本数修改为 5:
kubectl scale deployment my-app --replicas=5
2. 滚动更新 #
滚动更新是 Kubernetes 中一种无停机的更新方式,使用 kubectl apply
或 kubectl rollout
进行:
使用 kubectl apply
更新 Deployment:
#
修改 Deployment 的配置文件,然后使用 kubectl apply
更新。
kubectl apply -f <deployment-file.yaml>
使用 kubectl rollout
进行滚动更新:
#
kubectl rollout restart deployment <deployment-name>
例如,重启 my-app
部署:
kubectl rollout restart deployment my-app
3. 回滚 #
回滚到上一个版本的部署,可以使用 kubectl rollout undo
命令:
kubectl rollout undo deployment <deployment-name>
例如,回滚 my-app
部署:
kubectl rollout undo deployment my-app
如果你希望回滚到指定版本:
kubectl rollout undo deployment <deployment-name> --to-revision=<revision-number>
4. 查看 Pod 的详细信息 #
要查看 Pod 的详细信息,可以使用 kubectl describe
命令:
kubectl describe pod <pod-name>
例如,查看名为 my-app-pod
的 Pod 的详细信息:
kubectl describe pod my-app-pod
这将显示 Pod 的详细信息,包括容器状态、事件、挂载的卷、环境变量等。
5. 进入 Pod 进行交互 #
要进入一个运行中的 Pod 进行交互,可以使用 kubectl exec
命令。你可以进入 Pod 并执行命令(如进入 shell):
进入 Pod 并启动交互式终端: #
kubectl exec -it <pod-name> -- /bin/bash
例如,进入 my-app-pod
的交互式终端:
kubectl exec -it my-app-pod -- /bin/bash
如果容器使用的是 sh
而不是 bash
,可以使用:
kubectl exec -it my-app-pod -- /bin/sh
通过这些命令,你可以方便地修改副本数、执行滚动更新、查看 Pod 的详细信息以及进入 Pod 进行交互操作。
3. etcd数据如何备份? #
- etcdctl –endpoints=“https://192.168.32.129:2379,https://192.168.32.130:2379,192.168.32.128:2379” –cacert=/etc/kubernetes/cert/ca.pem –key=/etc/etcd/cert/etcd-key.pem –cert=/etc/etcd/cert/etcd.pem snapshot save snashot1.db
- Snapshot saved at snashot1.db
etcd 数据备份是确保集群数据安全和恢复的关键步骤。etcd 提供了命令行工具来进行备份和恢复。以下是备份和恢复 etcd 数据的步骤:
1. 备份 etcd 数据 #
etcd 使用 etcdctl
工具来执行备份操作,备份是对 etcd 数据的快照。
备份命令: #
ETCDCTL_API=3 etcdctl snapshot save <backup-path>
例如,将备份保存到 /tmp/etcd-backup.db
:
ETCDCTL_API=3 etcdctl snapshot save /tmp/etcd-backup.db
备份选项: #
ETCDCTL_API=3
:指定使用 etcd 3.x API。<backup-path>
:备份文件的路径。
确保运行该命令的机器可以访问 etcd 集群,或者你需要设置相关的认证参数(如证书和密钥)。
2. 指定备份时使用的 etcd 集群信息 #
如果 etcd 集群有多个节点或启用了身份验证,可能需要添加额外的参数:
--endpoints
:指定 etcd 集群的节点地址。--cert-file
和--key-file
:如果启用了 SSL 加密通信。--cacert
:指定 CA 证书的路径(用于身份验证)。
例如,备份时指定集群端点:
ETCDCTL_API=3 etcdctl snapshot save /tmp/etcd-backup.db \
--endpoints=https://etcd1:2379,https://etcd2:2379,https://etcd3:2379 \
--cert-file=/path/to/cert \
--key-file=/path/to/key \
--cacert=/path/to/ca-cert
3. 恢复 etcd 数据 #
如果需要恢复 etcd 数据,使用 etcdctl snapshot restore
命令。
恢复命令: #
ETCDCTL_API=3 etcdctl snapshot restore <backup-path> \
--data-dir=<new-data-dir> \
--name=<node-name> \
--initial-cluster=<cluster-config> \
--initial-cluster-token=<cluster-token>
例如,恢复备份到 /tmp/etcd-backup.db
,并将数据存储到 /var/lib/etcd
:
ETCDCTL_API=3 etcdctl snapshot restore /tmp/etcd-backup.db \
--data-dir=/var/lib/etcd \
--name=etcd-node-1 \
--initial-cluster=etcd-node-1=https://etcd-node-1:2380,etcd-node-2=https://etcd-node-2:2380,etcd-node-3=https://etcd-node-3:2380 \
--initial-cluster-token=etcd-cluster-1
--data-dir
:指定恢复后的数据存储目录。--name
:指定节点的名称。--initial-cluster
:指定集群节点的地址。--initial-cluster-token
:集群的标识。
恢复操作后,需要重新启动 etcd 服务。
4. 定期备份 #
建议定期备份 etcd 数据,以防止意外数据丢失。可以使用脚本或定时任务(如 cron)来定期执行备份操作。
5. 检查备份有效性 #
备份后,建议检查备份文件的完整性,确保在需要时能够恢复。
4. k8s控制器有哪些? #
- 副本集(ReplicaSet)
- 部署(Deployment)
- 状态集(StatefulSet)
- Daemon集(DaemonSet)
- 一次任务(Job)
- 计划任务(CronJob)
- 有状态集(StatefulSet)
Kubernetes 控制器是用于管理 Kubernetes 集群中资源和对象的控制循环(control loop)。这些控制器定期检查集群状态并根据当前状态与期望状态之间的差异进行调整。以下是 Kubernetes 中一些常见的控制器及其功能:
1. ReplicationController #
- 功能:确保某个特定的 Pod 副本数始终运行。当 Pod 数量低于指定副本数时,ReplicationController 会创建新的 Pod;当 Pod 数量超过指定副本数时,它会删除多余的 Pod。
- 用途:确保应用程序的高可用性和负载均衡。
2. ReplicaSet #
- 功能:ReplicaSet 是 ReplicationController 的增强版,用于确保某个特定副本数的 Pod 始终在集群中运行。通常用于支持 Deployment 资源,确保部署的 Pod 数量正确。
- 用途:与 Deployment 一起工作,确保在滚动更新时的稳定性。
3. Deployment #
- 功能:Deployment 控制器负责管理应用程序的部署,支持零停机的滚动更新、回滚等操作。它使用 ReplicaSet 来管理 Pod 副本。
- 用途:简化应用程序的部署和版本管理。
4. StatefulSet #
- 功能:StatefulSet 是用于管理有状态应用的控制器。它确保 Pod 在更新时能够保持其稳定的标识(如 Pod 名称和存储卷),适用于有持久化存储要求的应用,如数据库。
- 用途:管理有状态服务,例如数据库、缓存等,提供稳定的网络身份和持久化存储。
5. DaemonSet #
- 功能:DaemonSet 控制器确保每个节点上运行一个特定的 Pod。通常用于需要在每个节点上运行的守护进程(如日志收集、监控代理等)。
- 用途:确保每个节点上都有 Pod(例如:fluentd、prometheus-node-exporter 等)。
6. Job #
- 功能:Job 控制器用于管理批处理任务的执行。它确保指定数量的 Pod 成功执行一次任务。Job 会创建 Pod 来执行一次性任务,完成后 Pod 会被删除。
- 用途:用于执行短期批处理任务,例如数据迁移、批量计算等。
7. CronJob #
- 功能:CronJob 是 Job 控制器的扩展,允许定期执行任务,类似于 Linux 系统中的 Cron 作业。它定期创建 Job 来执行计划任务。
- 用途:例如定期备份、定时任务等。
8. HorizontalPodAutoscaler (HPA) #
- 功能:HPA 控制器根据 Pod 的 CPU 或内存使用情况自动调整 Pod 的副本数,以应对负载的变化。
- 用途:自动水平扩展应用程序的 Pod,适应流量的波动。
9. NetworkPolicy #
- 功能:NetworkPolicy 控制器用于定义和管理 Pod 之间的网络访问策略。它允许你控制哪些 Pod 可以通信,哪些不能。
- 用途:增强集群内的安全性,通过限制 Pod 之间的网络流量来隔离不同服务。
10. IngressController #
- 功能:IngressController 控制器管理 Ingress 资源,负责将外部请求路由到集群内的服务。它通常使用反向代理的形式,如 Nginx 或 Traefik,来处理 HTTP/S 流量。
- 用途:暴露服务给外部网络,并提供负载均衡、SSL 终止等功能。
11. Custom Controller #
- 功能:Kubernetes 允许用户创建自定义控制器,以便根据特定的业务需求自动化资源管理。用户可以根据自己的需求编写自定义控制器,并将其作为 Kubernetes 的一部分运行。
- 用途:满足一些特定需求的自动化任务,例如定期清理日志、资源调整等。
12. CertManager #
- 功能:CertManager 是一个 Kubernetes 控制器,用于自动化管理和签发 SSL/TLS 证书。它通过与外部证书颁发机构(如 Let’s Encrypt)交互来自动更新证书。
- 用途:为 Kubernetes 集群中的应用提供自动化证书管理。
总结 #
Kubernetes 控制器的核心作用是确保集群中的资源按照预期方式运行,并自动处理集群资源的管理与维护。不同的控制器满足了不同场景下的需求,包括无状态服务的管理(Deployment),有状态服务的管理(StatefulSet),批处理任务的管理(Job、CronJob),以及对网络和安全的管理(NetworkPolicy、IngressController)等。
5. 哪些是集群级别的资源? #
- Namespace
- Node
- Role
- ClusterRole
- RoleBinding
- ClusterRoleBinding
在 Kubernetes 中,集群级别的资源是指跨整个集群范围的资源,它们的作用通常涉及对集群的管理、调度和配置。以下是一些常见的集群级别资源:
1. Node #
- 功能:节点(Node)是 Kubernetes 集群中的物理或虚拟机器,它为 Pod 提供计算资源。每个节点都包含运行 Pod 的 Kubelet、容器运行时(如 Docker)以及其他必要的组件。
- 用途:管理集群中的计算资源,决定 Pod 的调度位置。
2. Namespace #
- 功能:命名空间(Namespace)用于在 Kubernetes 中划分集群中的资源。通过使用不同的命名空间,可以将资源分隔开,以便于不同团队或项目的管理。
- 用途:用于逻辑上分隔和组织集群中的资源,例如服务、Pod 和其他对象,可以在同一集群中支持多租户环境。
3. PersistentVolume (PV) #
- 功能:持久化卷(PersistentVolume)是集群级别的存储资源,用于提供持久化的存储,以便容器在 Pod 之间可以持久化数据。PV 是由管理员创建的,管理员定义了存储的大小、访问模式等属性。
- 用途:为集群中的 Pod 提供存储卷。
4. PersistentVolumeClaim (PVC) #
- 功能:持久化卷声明(PVC)是用户请求存储资源的方式。它是 Pod 访问持久化存储的接口,用户可以通过 PVC 来申请持久化存储,PVC 会与 PV 绑定。
- 用途:在集群中申请并绑定到合适的 PV,确保 Pod 获得持久化存储。
5. StorageClass #
- 功能:存储类(StorageClass)是管理员定义的存储策略,用于动态地供应存储卷。它定义了存储的类型、访问模式和其他属性。
- 用途:为 PVC 提供具体的存储供应方式,控制持久化存储的分配和使用策略。
6. ClusterRole 和 ClusterRoleBinding #
- 功能:ClusterRole 和 ClusterRoleBinding 是与权限管理相关的集群级别资源。ClusterRole 定义了一组集群范围内的权限,而 ClusterRoleBinding 将这些权限授予用户、组或服务账户。
- 用途:管理集群级别的访问控制和权限。
7. ConfigMap #
- 功能:ConfigMap 用于存储集群级别的配置信息。它允许您将配置数据与应用程序容器分离,便于管理和更新。
- 用途:存储应用程序配置或集群配置,不包含敏感数据。
8. Secret #
- 功能:Secret 用于存储敏感数据(如密码、密钥等)。它提供了一种安全的方式来存储和访问敏感信息。
- 用途:存储和管理集群中应用程序的敏感信息。
9. Ingress #
- 功能:Ingress 是集群级别的资源,用于管理外部 HTTP/S 流量的路由。它提供了一种通过负载均衡器将外部请求路由到集群内部服务的方式。
- 用途:暴露服务到集群外部,并通过反向代理进行流量控制。
10. ResourceQuota #
- 功能:ResourceQuota 用于限制命名空间内可用的资源数量和种类(如 CPU、内存、存储等)。它是在集群级别对资源使用进行管控的机制。
- 用途:帮助管理员限制和控制集群中资源的使用,防止某些命名空间消耗过多资源。
11. LimitRange #
- 功能:LimitRange 是用于限制命名空间中容器资源(如 CPU、内存)的请求和限制值。它是集群级别的资源,用于设置资源的默认限制。
- 用途:为命名空间内的容器设置资源使用的范围。
12. HorizontalPodAutoscaler (HPA) #
- 功能:HPA 控制器在集群级别运行,自动调整 Pod 的副本数以响应负载变化,通常基于 CPU 或内存使用情况。
- 用途:动态调整 Pod 副本数,确保集群资源能够自动适应流量的变化。
13. ServiceAccount #
- 功能:ServiceAccount 是 Kubernetes 中用于为 Pod 提供身份的集群级别资源。它关联了 API 访问权限,允许 Pod 在集群中进行身份验证和访问控制。
- 用途:为运行在 Kubernetes 上的应用程序分配身份,允许它们安全地访问集群中的资源。
14. ClusterOperator #
- 功能:ClusterOperator 是一个由 Operator 管理的集群级别资源,用于对集群进行自动化管理。它负责维护应用程序或基础设施的生命周期管理。
- 用途:简化集群管理过程,自动化常见任务。
15. API Aggregation Layer (API Server) #
- 功能:API Aggregation Layer 使得不同版本和功能的 API 被聚合到 Kubernetes API Server 中,这样可以让用户或系统使用不同的 API 资源。
- 用途:为集群提供统一的 API 接入点。
总结 #
集群级别的资源一般是跨整个 Kubernetes 集群的管理资源,涉及集群的配置、权限管理、存储管理等。它们通常由管理员来配置和管理,以确保集群内资源的合理使用、访问控制以及集群的安全性与稳定性。
6. pod状态有哪些? #
- Pending 等待中
- Running 运行中
- Succeeded 正常终止
- Failed 异常停止
- Unkonwn 未知状态
在 Kubernetes 中,Pod 的状态反映了 Pod 的生命周期和运行状况。Pod 状态由 Kubelet 和 API Server 更新,并且每个 Pod 会经历不同的阶段。以下是 Pod 状态的常见类型:
1. Pending #
描述:Pod 已经被 Kubernetes 调度到某个节点上,但某些容器还没有被创建或启动。通常是因为容器镜像正在拉取、资源请求尚未满足、或者是其他初始化过程尚未完成。
可能的原因
:
- 节点资源不足
- 容器镜像还在下载
- 需要挂载的卷还未准备好
2. Running #
描述:Pod 中的容器正在运行,并且至少有一个容器处于运行状态。Pod 被调度到一个节点,并且容器已经启动并在运行中。
可能的原因
:
- 容器已启动且健康
- Pod 正在执行指定的任务
3. Succeeded #
描述:Pod 中的所有容器都已成功运行并退出,且退出状态码为 0。这个状态通常表示 Pod 中的任务(例如批处理任务)已经完成。
可能的原因
:
- 容器执行任务并成功退出
- 没有错误退出
4. Failed #
描述:Pod 中的至少一个容器已经结束,但退出状态码非 0。该状态表示 Pod 中的容器执行过程中发生了错误或故障。
可能的原因
:
- 容器执行错误并退出
- 程序崩溃或其他失败
5. CrashLoopBackOff #
描述:Pod 中的容器持续崩溃并重启。Kubernetes 会尝试重新启动容器,但容器未能成功运行。这通常是由应用程序崩溃或容器配置错误引起的。
可能的原因
:
- 容器启动后失败并退出,Kubernetes 尝试重启容器
- 容器配置错误或应用程序 bug
6. Unknown #
描述:Kubernetes 无法确定 Pod 的状态。这个状态通常是由于 Kubelet 与 API Server 之间的通信中断或节点失联。
可能的原因
:
- 节点不可用
- Kubelet 或 API Server 出现问题
7. Terminating #
描述:Pod 正在终止过程中。这通常表示 Pod 正在被删除,所有容器和相关资源正在被清理。
可能的原因
:
- 用户或控制器删除 Pod
- 正在执行正常的关闭过程
8. Initializing (仅适用于 StatefulSet) #
描述:Pod 正在初始化阶段。在 StatefulSet 中,当某个 Pod 启动时,容器可能会按照顺序启动,并且 Pod 的状态会经历“Initializing”阶段。
可能的原因
:
- StatefulSet 中的 Pod 初始化时需要等待其他 Pod 完成启动
总结 #
Pod 的状态反映了其在 Kubernetes 集群中的生命周期。管理员可以通过这些状态来诊断和排查问题,比如容器崩溃、资源不足、网络问题等。理解 Pod 的各种状态有助于有效地管理和调度应用程序。
7. pod创建过程是什么? #
在 Kubernetes 中,Pod 的创建过程是 Kubernetes 调度和管理 Pod 的一系列步骤。Pod 是 Kubernetes 中最小的部署单位,由一个或多个容器组成。以下是 Pod 创建过程的详细步骤:
1. 用户提交请求 #
- 用户通过
kubectl
或 Kubernetes API 提交一个 Pod 资源对象的定义,通常是一个 YAML 或 JSON 文件,描述了 Pod 的配置、容器、卷挂载等信息。 - 请求可以来自:
kubectl
命令行工具- Kubernetes 控制器(如 Deployment、StatefulSet、DaemonSet 等)
- 其他系统(如 Helm 等)
2. API Server 接收请求 #
- 用户提交的 Pod 定义会被 Kubernetes API Server 接收。
- API Server 将请求转化为集群中的资源对象,并将其存储在 etcd(Kubernetes 的分布式存储系统)中。
- 这个 Pod 对象进入 etcd 中的队列,等待调度。
3. 调度(Scheduler)选择节点 #
Kubernetes Scheduler
负责选择一个合适的节点来运行这个 Pod。调度过程基于 Pod 的资源请求、节点的资源状况、标签匹配等条件。
- 资源请求(如 CPU 和内存)
- 节点亲和性(如节点的标签和 Pod 的调度要求)
- Taints 和 Tolerations(节点的污点和 Pod 的容忍度)
- 其他调度策略(如 Pod 的优先级和抢占)
调度器根据这些条件选择一个符合要求的节点,并将 Pod 分配到该节点。
4. Node 接收 Pod 配置 #
- 一旦调度完成,API Server 将调度结果发送给选定的节点(Node)。
- 该节点的 Kubelet(Kubernetes 节点代理)接收到 Pod 的配置并开始处理。
5. Kubelet 创建容器 #
- Kubelet 在目标节点上创建 Pod。Kubelet 会根据 Pod 配置文件中的容器信息启动相应的容器。
- 容器的启动过程包括:
- 拉取镜像:Kubelet 会确保容器镜像已经被拉取到本地节点(如果镜像尚未存在)。
- 配置容器:Kubelet 会按照 Pod 配置设置容器的 CPU、内存、环境变量、挂载卷等配置。
- 启动容器:Kubelet 会通过容器运行时(如 Docker、containerd)启动容器。
6. Pod 启动和就绪检查 #
- 容器启动后,Kubelet 会执行 Pod 中定义的 就绪探针(Readiness Probe) 和 存活探针(Liveness Probe),以确保容器正常工作。
- 如果就绪探针返回成功,Pod 会被标记为 Ready 状态,表示它已经可以开始接受流量。
- 如果存活探针失败,Kubelet 会尝试重新启动容器。
7. 网络和服务关联 #
- 一旦容器启动并且健康检查通过,Kubelet 会为容器分配一个 IP 地址。
- Kubernetes 内部的 CNI(容器网络接口)插件 会为 Pod 配置网络,使得 Pod 中的容器能够通过内部网络相互通信。
- 如果 Pod 被关联到某个 Service,Kubernetes 会更新 Service 的 Endpoints,使得流量能够通过 Service 路由到新创建的 Pod。
8. Pod 完成启动 #
- 一旦容器成功运行并且健康检查通过,Pod 被标记为 Running 状态。
- 如果是通过 Controller(如 Deployment 或 StatefulSet)创建的 Pod,控制器会继续监控该 Pod 的运行状态,以确保副本数保持一致。
9. 监控和维护 #
- Kubelet 会继续监控 Pod 的状态和运行情况。如果 Pod 中的容器崩溃或死锁,Kubelet 会尝试重启容器或重建 Pod。
- 如果 Pod 所在的节点不可用或失败,调度器会根据策略重新调度该 Pod 到其他可用节点。
总结:Pod 创建的整个流程 #
- 用户提交 Pod 配置,通过 API Server 接收。
- 调度器选择节点,确定在哪个节点上运行 Pod。
- Kubelet 在节点上创建容器,并启动容器。
- 网络配置和服务关联,Pod 配置好网络并准备好接受流量。
- Pod 运行并就绪,容器完成启动,Pod 状态转为 Running。
通过这一过程,Kubernetes 管理和调度 Pod,实现容器化应用的高效运行与自动化管理。
8. pod重启策略有哪些? #
Pod的重启策略有3种,默认值为Always。
- Always : 容器失效时,kubelet 自动重启该容器;
- OnFailure : 容器终止运行且退出码不为0时重启;
- Never : 不论状态为何, kubelet 都不重启该容器
在 Kubernetes 中,Pod 的重启策略定义了容器如何在失败后重新启动。Kubernetes 提供了三种常见的重启策略,每种策略适用于不同的场景。Pod 的重启策略是在 Pod 的规格文件中定义的,特别是对于容器化应用,重启策略的选择非常重要。
1. Always #
描述:无论容器退出的状态是什么,Kubernetes 都会重新启动容器。这是最常用的重启策略,适用于那些需要始终运行的服务。
应用场景
:
- 持续运行的应用程序,例如 Web 服务、数据库、后台任务等。
默认值:如果你没有在 Pod 规范中显式设置重启策略,Kubernetes 会默认使用
Always
。示例
:
apiVersion: v1 kind: Pod metadata: name: example-pod spec: restartPolicy: Always containers: - name: example-container image: example-image
2. OnFailure #
描述:当容器正常退出时(即退出码为 0)不会重启容器,但如果容器因错误退出(即退出码非 0)时,Kubernetes 会尝试重新启动容器。适用于那些正常结束时无需重启的应用。
应用场景
:
- 用于执行一次性任务的容器,如果任务失败则需要重新启动进行重试,但如果任务成功就不需要重启。
示例
:
apiVersion: v1 kind: Pod metadata: name: example-pod spec: restartPolicy: OnFailure containers: - name: example-container image: example-image
3. Never #
描述:Kubernetes 在容器退出后不会自动重启容器。适用于那些不需要容器重新启动的场景,通常用于批处理任务或一次性作业。
应用场景
:
- 执行完任务后容器终止,且不需要再次启动。
示例
:
apiVersion: v1 kind: Pod metadata: name: example-pod spec: restartPolicy: Never containers: - name: example-container image: example-image
4. Pod 重启策略与控制器的关系 #
- 当 Pod 是由控制器(如 Deployment、StatefulSet、DaemonSet 等)管理时,Kubernetes 会自动使用
Always
重启策略,因为控制器的目标是始终保持 Pod 的期望副本数。 - 在这种情况下,重启策略通常不需要显式设置,因为控制器会自动处理 Pod 的调度和重启。
总结 #
- Always:适用于需要持续运行的应用,容器退出时会自动重启。
- OnFailure:适用于有可能失败的任务,容器异常退出时重启。
- Never:适用于一次性任务或不希望重启的容器,容器退出后不会重启。
选择正确的重启策略有助于 Kubernetes 高效管理容器生命周期,提高服务的可用性和容错能力。
9. 资源探针有哪些? #
- ExecAction:在容器中执行一个命令,并根据其返回的状态码进行诊断的操作称为Exec探测,状态码为0表示成功,否则即为不健康状态。
- TCPSocketAction:通过与容器的某TCP端口尝试建立连接进行诊断,端口能够成功打开即为正常,否则为不健康状态。
- HTTPGetAction:通过向容器IP地址的某指定端口的指定path发起HTTP GET请求进行诊断,响应码为2xx或3xx时即为成功,否则为失败。
在 Kubernetes 中,资源探针(Probes)是用来检测容器的健康状况和可用性的机制。探针帮助 Kubernetes 了解容器的状态,以便采取相应的措施,例如重新启动容器、停止请求流量等。Kubernetes 主要有三种类型的探针,分别是 存活探针(Liveness Probe)、就绪探针(Readiness Probe) 和 启动探针(Startup Probe)。
1. 存活探针(Liveness Probe) #
目的:检查容器是否处于健康状态。如果容器不健康(即探测失败),Kubernetes 会重新启动容器。
适用场景:适用于判断应用是否死锁、挂起或进入无法恢复的状态,及时重启容器恢复服务。
常见配置
:
httpGet
:通过 HTTP 请求检查容器健康。tcpSocket
:通过 TCP 连接检查容器的健康状况。exec
:执行指定的命令检查容器是否健康。
示例
:
livenessProbe: httpGet: path: /healthz port: 8080 initialDelaySeconds: 3 periodSeconds: 5 failureThreshold: 3
2. 就绪探针(Readiness Probe) #
目的:检查容器是否已准备好接受流量。如果探测失败,Kubernetes 会停止将流量路由到该容器。这个探针可以帮助 Kubernetes 确保容器处于就绪状态后才开始接收请求。
适用场景:适用于判断容器是否准备好对外提供服务。例如,应用启动期间可能需要时间加载资源或者连接外部服务,准备好后再开始接收流量。
常见配置
:
httpGet
:通过 HTTP 请求检查容器是否准备好接收流量。tcpSocket
:通过 TCP 连接检查容器是否准备好接收流量。exec
:执行指定的命令检查容器是否准备好接收流量。
示例
:
readinessProbe: httpGet: path: /readiness port: 8080 initialDelaySeconds: 5 periodSeconds: 10
3. 启动探针(Startup Probe) #
目的:检查容器是否已成功启动,适用于启动时间较长的应用。如果启动探针失败,Kubernetes 会终止容器并根据重启策略重新启动容器。启动探针通常用于长时间启动的应用,如数据库或其他大型应用。
适用场景:用于容器启动过程较长,且不希望在启动阶段因存活探针失败而误判容器不健康的情况。
常见配置
:
httpGet
:通过 HTTP 请求检查容器是否成功启动。tcpSocket
:通过 TCP 连接检查容器是否成功启动。exec
:执行指定的命令检查容器是否成功启动。
示例
:
startupProbe: httpGet: path: /startup port: 8080 failureThreshold: 30 periodSeconds: 5 initialDelaySeconds: 10
4. 探针配置的常见字段 #
initialDelaySeconds
:探针开始检查容器状态之前的延迟时间(秒)。通常在容器启动后需要等待一段时间才能开始检查。periodSeconds
:探针检查的间隔时间(秒)。即每隔多久执行一次探针。timeoutSeconds
:探针请求的超时时间(秒)。如果探针在这个时间内没有响应,则会被视为失败。failureThreshold
:探针失败的最大次数。如果探针连续失败超过该次数,容器会被认为不健康并进行重启(仅适用于存活探针)。successThreshold
:探针成功的最小次数。如果探针成功超过该次数,容器才会被认为是健康的(仅适用于就绪探针)。
5. 探针之间的区别 #
- 存活探针(Liveness Probe):用于检查容器是否健康,探测失败时会触发重启。
- 就绪探针(Readiness Probe):用于检查容器是否准备好接受流量,探测失败时会停止流量的路由。
- 启动探针(Startup Probe):用于容器启动期间的检查,防止启动慢的应用因为存活探针误判失败,适用于启动较慢的应用。
总结 #
- 存活探针(Liveness Probe):判断容器是否健康,若失败则重新启动容器。
- 就绪探针(Readiness Probe):判断容器是否准备好接受流量,若失败则停止将流量路由到容器。
- 启动探针(Startup Probe):判断容器是否启动完成,通常用于启动时间较长的容器。
配置探针可以帮助 Kubernetes 更加精确地管理容器的生命周期,确保容器在正常情况下提供服务,减少服务中断和故障恢复时间。
10. requests和limits用途是什么? #
- “requests”属性定义其请求的确保可用值,即容器运行可能用不到这些额度的资源,但用到时必须要确保有如此多的资源可用
- ”limits”属性则用于限制资源可用的最大值,即硬限制
在 Kubernetes 中,requests
和 limits
是容器资源管理的重要配置项,用来控制容器在运行时的 CPU 和内存资源使用情况。它们可以在 Pod 的规格中为每个容器指定,帮助 Kubernetes 更好地管理资源分配和调度。以下是 requests
和 limits
的详细说明及用途:
1. Requests #
用途:
requests
是容器在运行时请求的资源量,Kubernetes 调度器基于这些请求来决定在哪个节点上运行容器。requests
表示容器正常运行时所需的最小资源。它是容器启动时必须分配的资源量,调度器将根据requests
值来安排 Pod 运行的节点。功能
:
- 控制容器所需的最小资源。
- 用于调度容器到合适的节点上。
- 如果容器实际使用的资源量低于请求的资源量,系统不会强制回收资源,保证容器在该节点上运行时能有足够的资源。
例子
:容器请求 100 毫核 CPU 和 256 MiB 内存。
resources: requests: cpu: 100m # 100毫核 memory: 256Mi # 256 MiB 内存
2. Limits #
用途:
limits
是容器允许使用的最大资源量。如果容器使用的资源超过了limits
的限制,Kubernetes 会采取措施(例如,CPU 资源限制会导致容器被限制使用更多的 CPU,内存资源限制则可能导致容器被杀死并重启)。limits
用来防止容器在消耗大量资源时影响到其他容器和服务。功能
:
- 设置容器允许使用的最大资源量。
- 防止容器消耗过多资源,影响集群中的其他工作负载。
- 在内存限制(memory limit)超出时,容器会被 OOM(Out of Memory)杀死。
例子
:容器最大使用 200 毫核 CPU 和 512 MiB 内存。
resources: limits: cpu: 200m # 最大 200毫核 CPU memory: 512Mi # 最大 512 MiB 内存
3. Requests 和 Limits 的关系 #
请求资源 vs 限制资源
:
requests
是容器实际启动时的资源需求,决定容器的调度。limits
是容器可以消耗的最大资源量,一旦超出此限制,Kubernetes 会限制容器使用更多资源,或者在内存超过时会杀死容器。
在资源请求和限制上最好设定相同的值
:
- 如果
requests
和limits
设置得差不多,可以确保容器能在稳定的资源使用下运行。 - 如果
requests
设置较低而limits
设置较高,则容器可以在不超过limits
的情况下,使用更多的资源,但调度时会考虑请求的最小资源。
- 如果
4. CPU 和 内存的不同处理 #
CPU
:
- Kubernetes 的 CPU 资源是以“毫核”计算的。
requests
指定了容器启动时所需的 CPU 资源,limits
指定了容器可以使用的最大 CPU。 - 资源限制在 CPU 上是通过 CPU 限制 来实现的,超出时容器会被“限制”而不是终止。
- Kubernetes 的 CPU 资源是以“毫核”计算的。
内存
:
- 对于内存,
requests
是容器启动时请求的内存量,而limits
是容器能够使用的最大内存。 - 如果容器的内存使用超过
limits
,Kubernetes 会 杀死容器,并尝试根据策略重新启动它(通常是根据restartPolicy
来控制)。
- 对于内存,
5. 例子 #
假设你有一个 Pod,其中的容器请求 100m 的 CPU 和 200Mi 的内存,并且设置了资源限制,最多使用 200m 的 CPU 和 400Mi 的内存。
apiVersion: v1
kind: Pod
metadata:
name: example-pod
spec:
containers:
- name: example-container
image: example-image
resources:
requests:
cpu: 100m # 请求 100 毫核 CPU
memory: 200Mi # 请求 200 MiB 内存
limits:
cpu: 200m # 限制最大 200 毫核 CPU
memory: 400Mi # 限制最大 400 MiB 内存
6. 总结 #
- Requests:容器在启动时需要的最小资源量,决定了 Pod 调度时所需的资源,保证容器运行时有足够资源。
- Limits:容器能够使用的最大资源量,防止容器过度消耗资源,影响其他容器。
- 设置合理的
requests
和limits
,可以提高资源的利用率,避免容器过度占用资源,也有助于 Kubernetes 集群资源的合理分配和调度。
11. kubeconfig文件包含什么内容,用途是什么? #
包含集群参数(CA证书、API Server地址),客户端参数(上面生成的证书和私钥),集群context 信息(集群名称、用户名)。
kubeconfig
文件是 Kubernetes 的配置文件,它包含了连接到 Kubernetes 集群所需要的信息。Kubernetes 的 kubeconfig
文件存储了与集群交互所需的认证、访问控制和连接信息。它通常用于配置 kubectl
(Kubernetes 命令行工具)和其他 Kubernetes 客户端与集群的连接。
kubeconfig
文件的内容结构
#
kubeconfig
文件是一个 YAML 格式的文件,通常包含以下几部分内容:
apiVersion
:apiVersion
字段指定了kubeconfig
文件的版本,通常是v1
。
clusters
:clusters
字段定义了集群的配置。每个集群包括集群的名称和 Kubernetes API 服务器的地址及证书信息。通过这些信息,kubectl
可以连接到指定的 Kubernetes 集群。示例
:
clusters: - name: my-cluster cluster: server: https://my-cluster-api-server:6443 certificate-authority: /path/to/ca.crt
contexts
:contexts
字段包含了多个上下文配置。每个上下文定义了与集群交互的方式,包括集群名称、用户、命名空间等信息。上下文是 Kubernetes 配置中的一个组合,它将集群、用户和命名空间关联起来。用户可以通过切换上下文来在不同的集群和用户环境中工作。示例
:
contexts: - name: my-context context: cluster: my-cluster user: my-user namespace: default
current-context
:current-context
字段指定当前使用的上下文名称。kubectl
会使用该上下文进行所有后续操作,直到切换到其他上下文。示例
:
current-context: my-context
users
:users
字段定义了用于访问 Kubernetes API 的用户信息。每个用户包含认证信息,例如用户名、密码、令牌或客户端证书。通过这些认证信息,kubectl
可以验证用户身份。示例
:
users: - name: my-user user: client-certificate: /path/to/cert.crt client-key: /path/to/cert.key token: my-token
kubeconfig
文件示例
#
以下是一个完整的 kubeconfig
文件示例:
apiVersion: v1
kind: Config
clusters:
- name: my-cluster
cluster:
server: https://my-cluster-api-server:6443
certificate-authority: /path/to/ca.crt
contexts:
- name: my-context
context:
cluster: my-cluster
user: my-user
namespace: default
current-context: my-context
users:
- name: my-user
user:
client-certificate: /path/to/cert.crt
client-key: /path/to/cert.key
token: my-token
kubeconfig
的用途
#
- 配置
kubectl
和其他客户端工具:kubeconfig
文件为kubectl
等客户端工具提供了所需的集群信息和认证信息。当用户运行kubectl
命令时,工具会自动从kubeconfig
中获取集群的连接信息并使用正确的认证方式。
- 支持多个集群和上下文:
- 一个
kubeconfig
文件可以存储多个集群的配置信息,以及多个上下文。用户可以通过切换上下文(kubectl config use-context
)来在不同的集群之间切换工作。
- 一个
- 用户认证:
kubeconfig
文件存储了与集群交互所需的认证信息,支持多种认证方式,如证书、令牌、用户名和密码等。这些认证信息保证了用户能够访问集群,并在集群中执行相应的操作。
- 命名空间管理:
kubeconfig
文件还可以指定与集群交互时使用的命名空间。通过设置上下文中的namespace
字段,用户可以在默认命名空间之外指定特定的命名空间。
kubeconfig
文件的管理
#
- 文件位置:
- 默认情况下,
kubeconfig
文件位于用户的主目录下~/.kube/config
。也可以通过KUBECONFIG
环境变量指定自定义位置。
- 默认情况下,
- 合并多个
kubeconfig
文件:- 可以将多个
kubeconfig
文件合并为一个文件。kubectl
会合并并优先使用KUBECONFIG
环境变量中指定的文件。通过配置文件中的contexts
字段,可以同时管理多个集群的访问。
- 可以将多个
- 修改当前上下文:
- 使用
kubectl config use-context <context-name>
来切换当前上下文,这样可以在不同的集群或用户间切换操作。
- 使用
总结 #
kubeconfig
文件是 Kubernetes 集群管理的核心配置文件,包含了集群、用户认证和上下文等信息,用于指导客户端工具(如 kubectl
)如何访问集群。通过合理配置 kubeconfig
文件,可以方便地管理多个集群和用户,同时确保操作的安全性和准确性。
12. RBAC中role和clusterrole区别,rolebinding和 clusterrolebinding区别? #
- Role 可以定义在一个 namespace 中,如果想要跨 namespace则可以创建ClusterRole,ClusterRole 具有与 Role相同的权限角色控制能力,不同的是 ClusterRole 是集群级别的
- RoleBinding 适用于某个命名空间内授权,而 ClusterRoleBinding 适用于集群范围内的授权
在 Kubernetes 中,RBAC(基于角色的访问控制)用于控制用户或服务账户对集群资源的访问权限。Role
和 ClusterRole
,以及 RoleBinding
和 ClusterRoleBinding
是 RBAC 中的关键对象,它们定义了权限和如何分配这些权限。它们之间的区别如下:
1. Role
和 ClusterRole
的区别
#
Role
:Role
是一个集群范围内(namespace 内)的角色,定义了在特定命名空间中对资源的访问权限。它只限于该命名空间内的资源。- 只能授予对特定命名空间内的资源进行访问的权限(例如 Pod、Service 等)。
- 典型场景:当你需要在某个命名空间内限制某个用户或服务账户的权限时使用。
ClusterRole
:ClusterRole
是一个集群范围内的角色,定义了对集群中的资源进行访问的权限。它不受命名空间的限制,适用于整个集群。- 可以授予集群级别的权限(例如访问集群中的节点、PersistentVolume 等资源),也可以授予跨命名空间的权限(例如访问所有命名空间中的 Pod、Deployment 等资源)。
- 典型场景:当你需要跨多个命名空间或集群级别的权限时使用。
2. RoleBinding
和 ClusterRoleBinding
的区别
#
RoleBinding
:RoleBinding
将Role
(命名空间范围内的角色)绑定到一个用户、组或服务账户,并赋予该角色定义的权限。- 只能将
Role
绑定到特定命名空间内的资源上,作用范围仅限于该命名空间。 - 典型场景:当你想将一个特定的权限绑定到某个命名空间的用户或服务账户时使用。
ClusterRoleBinding
:ClusterRoleBinding
将ClusterRole
(集群范围内的角色)绑定到一个用户、组或服务账户,并赋予该角色定义的权限。- 适用于集群范围的权限,能够绑定跨多个命名空间的用户或服务账户,或授予集群级别的权限。
- 典型场景:当你需要为一个用户或服务账户分配跨命名空间或集群级别的权限时使用。
总结 #
Role
和ClusterRole
都定义了权限,但Role
限制在单一命名空间内,而ClusterRole
是集群级别的,可以跨命名空间或授予集群级别的权限。RoleBinding
和ClusterRoleBinding
都将角色绑定到用户或服务账户,但RoleBinding
只在特定命名空间内有效,而ClusterRoleBinding
可以绑定到整个集群,应用于多个命名空间或集群级别的资源。
示例 #
Role(命名空间内权限):
kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: namespace: default name: pod-reader rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "list"]
ClusterRole(集群范围权限):
kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: # No namespace field needed for ClusterRole name: cluster-admin rules: - apiGroups: [""] resources: ["nodes"] verbs: ["get", "list", "create"]
RoleBinding(将 Role 绑定到用户):
kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: read-pods namespace: default subjects: - kind: User name: jane apiGroup: rbac.authorization.k8s.io roleRef: kind: Role name: pod-reader apiGroup: rbac.authorization.k8s.io
ClusterRoleBinding(将 ClusterRole 绑定到用户):
kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: admin-binding subjects: - kind: User name: jane apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: cluster-admin apiGroup: rbac.authorization.k8s.io
通过这些对象,Kubernetes 可以灵活地控制用户和服务账户在集群中的权限。
13. ipvs为啥比iptables效率高? #
IPVS模式与iptables同样基于Netfilter,但是ipvs采用的hash表,iptables采用一条条的规则列表。iptables又是为了防火墙设计的,集群数量越多iptables规则就越多,而iptables规则是从上到下匹配,所以效率就越是低下。因此当service数量达到一定规模时,hash查表的速度优势就会显现出来,从而提高service的服务性能
IPVS(IP Virtual Server)比 iptables 更高效的原因主要在于它们的工作原理、性能优化和用途上的差异。下面是两者效率差异的几个关键因素:
1. 工作方式不同 #
- iptables:
iptables
是基于包过滤的工具,主要用于流量的过滤、NAT(网络地址转换)和路由转发。它对每个传入的网络包都会进行处理,包括检查每个包的目标端口、源地址、目标地址等,来决定如何处理。iptables
主要通过链(chains)来过滤网络包,这在复杂的网络流量处理中可能会引入较大的性能开销。
- IPVS:
IPVS
是一个专门为负载均衡设计的解决方案。它工作在网络层(L4),并且直接使用了内核的负载均衡机制,处理的是传入的流量,而不是每个独立的包。IPVS 通过定义虚拟服务器、负载均衡算法(如轮询、加权轮询、最少连接等),将流量定向到后端真实服务器。- IPVS 基于流(connection-based)进行处理,它一次性建立一个流的映射,而不是逐个包进行检查。这减少了不必要的处理,因此能在高并发环境中提供更高的效率。
2. 性能优化 #
- iptables:
iptables
由于需要逐个包进行检查,其性能会受到规则复杂度、包量以及匹配条件的影响,尤其在流量大、规则多时,可能导致性能瓶颈。
- IPVS:
IPVS
在内核级别实现负载均衡,它在数据包到达时,会直接通过查找流表来决定如何转发流量,从而避免了对每个包的逐一处理。IPVS 通过利用内核提供的高效机制,在性能上优于iptables
。- 它使用了特定的高效算法来管理流量映射,减少了计算的开销。
3. 用途差异 #
- iptables 主要用于包过滤、防火墙规则、NAT 和简单的路由控制,它并不专门针对负载均衡优化。
- IPVS 则是专门为大规模负载均衡设计的系统,特别适用于处理大量的并发连接和高性能的流量转发。它能够处理非常高的吞吐量,尤其在服务端和客户端之间有大量的连接时,能够显著提高效率。
4. 流量转发方式 #
- iptables:每次收到新的连接包时,
iptables
都需要进行规则检查,尤其在规则复杂或者流量大的情况下,效率会下降。 - IPVS:采用的是基于连接的负载均衡,它将每个连接映射到一个后端服务器,而不是每次处理单个包。这样,在流量较大时,减少了每个包都需要处理的负担,从而提高了处理效率。
总结 #
- 效率高:由于
IPVS
是为负载均衡专门设计的,且基于流的转发机制,减少了对每个包的处理开销,因此在大规模流量的场景下,性能要优于iptables
。 - 适用场景:
iptables
是通用的包过滤工具,而IPVS
是为负载均衡设计的专用工具,在需要高性能、高吞吐量的负载均衡环境中,IPVS
更具优势。
因此,IPVS 在进行负载均衡时,能够更高效地处理大规模并发连接,而 iptables 更适合用于防火墙和包过滤任务。
14. sc pv pvc用途,容器挂载存储整个流程是什么? #
- PVC:Pod 想要使用的持久化存储的属性,比如存储的大小、读写权限等。
- PV :具体的 Volume 的属性,比如 Volume 的类型、挂载目录、远程存储服务器地址等。
- StorageClass:充当 PV 的模板。并且,只有同属于一个 StorageClass 的 PV 和 PVC,才可以绑定在一起。当然,StorageClass 的另一个重要作用,是指定 PV 的 Provisioner(存储插件)。这时候,如果你的存储插件支持 Dynamic Provisioning 的话,Kubernetes 就可以自动为你创建 PV 了。
在 Kubernetes 中,SC(StorageClass)、PV(PersistentVolume) 和 PVC(PersistentVolumeClaim) 是管理和使用存储资源的关键组件。下面是它们的用途以及容器挂载存储的整个流程。
1. StorageClass (SC) #
用途:
- StorageClass 是一种 Kubernetes 资源类型,它为存储提供了一个抽象层,用于定义不同类型的存储,指定如何动态地分配存储资源。
StorageClass
可以指定存储提供者、存储类型、存储的性能要求(如 IOPS,延迟等)、存储的生命周期等。- 它允许用户通过声明 PVC 时指定存储类型(例如高性能存储、标准存储等),从而实现存储的动态管理。
2. PersistentVolume (PV) #
用途:
- PersistentVolume 是一个持久化存储资源,表示一个已分配给 Kubernetes 集群的存储资源。
- 它的生命周期独立于 Pod。也就是说,即使 Pod 被销毁,PV 仍然存在,数据不会丢失。
PV
可以是由管理员手动创建,也可以通过StorageClass
动态创建。它通常与底层存储(如本地磁盘、NFS、云存储等)关联。
3. PersistentVolumeClaim (PVC) #
用途:
- PersistentVolumeClaim 是用户对存储资源的请求,它指定了存储的大小、访问模式等。
- PVC 允许用户声明他们需要的存储资源,并与集群中的 PV 进行绑定。
- PVC 是对存储资源的需求声明,Kubernetes 会根据 PVC 的请求找到一个合适的 PV 并进行绑定。
4. 容器挂载存储的整个流程 #
容器挂载存储的整个流程包括以下步骤:
1. 定义 StorageClass(可选) #
用户定义一个
StorageClass
,指定动态分配存储的细节,如存储类型、参数等。如果不指定,Kubernetes 默认使用标准的存储类。示例:
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: fast-storage provisioner: kubernetes.io/aws-ebs parameters: type: gp2
2. 定义 PVC #
用户创建一个
PersistentVolumeClaim
,它声明了对特定大小的存储的需求,并可以指定存储的访问模式(如 ReadWriteOnce, ReadOnlyMany 等)。Kubernetes 根据 PVC 请求来寻找合适的 PV 进行绑定。
示例:
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: my-claim spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi storageClassName: fast-storage
3. 动态创建 PV(如果没有现成的 PV) #
- 如果没有符合 PVC 的 PV,Kubernetes 会根据 PVC 中的
StorageClass
自动创建一个 PV。 - 创建的 PV 会根据
StorageClass
中指定的存储类型和参数进行配置。
4. PVC 和 PV 绑定 #
- Kubernetes 会将符合条件的
PersistentVolumeClaim
与PersistentVolume
进行绑定。PVC 和 PV 绑定后,存储资源就分配给用户使用。
5. 挂载到 Pod #
在 Pod 配置文件中,用户声明需要挂载的 PVC,Kubernetes 会将绑定的 PV 挂载到 Pod 中的容器。
示例:
apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: mycontainer image: nginx volumeMounts: - mountPath: /usr/share/nginx/html name: my-pvc volumes: - name: my-pvc persistentVolumeClaim: claimName: my-claim
6. 容器访问存储 #
- 容器内的应用程序可以通过指定的挂载路径(如
/usr/share/nginx/html
)来访问持久化存储中的数据。 - 存储会在 Pod 生命周期内持续存在,即使 Pod 被删除,数据仍然保存在 PV 中,除非指定 PV 被删除。
总结: #
- StorageClass:定义存储的类型和配置。
- PersistentVolume (PV):表示一个具体的存储资源,生命周期与 Pod 无关。
- PersistentVolumeClaim (PVC):用户请求存储资源,它将请求映射到 PV。
- Pod挂载存储:Pod 配置中引用 PVC,Kubernetes 将 PV 挂载到容器中。
这个流程通过 Kubernetes 的存储管理实现了对存储资源的动态配置和管理,使得容器化应用可以方便地使用持久化存储。
15. nginx ingress的原理本质是什么? #
- ingress controller通过和kubernetes api交互,动态的去感知集群中ingress规则变化,
- 然后读取它,按照自定义的规则,规则就是写明了哪个域名对应哪个service,生成一段nginx配置,
- 再写到nginx-ingress-controller的pod里,这个Ingress controller的pod里运行着一个Nginx服务,控制器会把生成的nginx配置写入/etc/nginx.conf文件中,
- 然后reload一下使配置生效。以此达到域名分配置和动态更新的问题。
Ingress 是 Kubernetes 中用于管理外部访问集群内服务的资源类型。其本质是提供一种 HTTP 和 HTTPS 路由机制,允许从外部网络访问集群内的应用服务。Ingress 资源配置了一些路由规则,这些规则将外部请求根据 URL 路径或主机名转发到集群中的不同服务。
Ingress 的原理本质: #
- 反向代理:
- Ingress 实际上是一个 反向代理,它处理来自外部的请求,将这些请求根据配置的规则路由到集群中的相应服务。
- 例如,可以根据请求的路径(如
/api
、/web
)或主机名(如api.example.com
、www.example.com
)来决定将请求转发到哪个服务。
- 基于规则的路由:
- Ingress 通过定义一组规则来指定如何路由流量。这些规则可以基于 HTTP 请求的 host、path,或者基于其他请求头进行路由。
- 这些规则会由 Ingress 控制器(如 NGINX Ingress Controller)解析,并根据规则将请求转发到相应的后端服务。
- Ingress Controller:
- Ingress Controller 是一个处理实际请求的组件,它根据定义在 Ingress 中的规则将流量路由到相应的服务。
- Ingress 本身并不处理流量,它只是一个资源类型。真正处理流量的逻辑由 Ingress Controller 实现。常见的 Ingress Controller 有 NGINX、Traefik、HAProxy、Istio 等。
- Ingress Controller 实际上在 Kubernetes 集群中运行,是集群外部流量的入口点。
- SSL/TLS 终结:
- Ingress 还可以配置 HTTPS 路由,允许在入口处终止 SSL/TLS 连接。这意味着 Ingress Controller 负责解密 HTTPS 请求,然后将明文的 HTTP 请求转发到集群内的服务。
- 负载均衡:
- Ingress 也支持负载均衡,可以将流量均匀地分发到多个后端服务实例。
- 在一些 Ingress Controller(如 NGINX)中,负载均衡的方式可以是轮询(Round Robin)、最少连接(Least Connections)等。
Ingress 路由流程: #
- 外部用户通过浏览器或其他 HTTP 客户端发送请求,指定的主机名和路径。
- 这些请求首先由外部的负载均衡器或 DNS 服务传递到集群中的 Ingress Controller。
- Ingress Controller 根据 Ingress 资源中定义的规则对请求进行匹配。
- Ingress Controller 根据匹配的规则将请求转发到正确的服务和相应的 Pod。
- 服务和 Pod 响应请求并返回数据,数据最终通过 Ingress Controller 返回给外部客户端。
总结: #
Ingress 的本质是提供一种 基于 HTTP(S) 请求的路由机制,通过 Ingress Controller 实现将外部请求转发到集群内的服务,支持负载均衡、路径路由、主机名路由以及 SSL/TLS 终结等功能。
16. 描述不同node上的Pod之间的通信流程 #
在 Kubernetes 中,不同节点(Node)上的 Pod 之间的通信是通过 Kubernetes 网络模型来实现的。根据 Kubernetes 的网络模型,集群内的每个 Pod 都有一个唯一的 IP 地址,并且任何 Pod 都可以与其他 Pod 进行通信,而无需考虑它们是否位于同一个节点上。
以下是不同 Node 上的 Pod 之间通信的基本流程:
1. Kubernetes 网络模型 #
Kubernetes 的网络模型确保了以下几点:
- 每个 Pod 在集群中都有一个唯一的 IP 地址。
- 每个 Pod 可以与其他 Pod 通信,不论它们位于同一节点还是不同节点。
- 网络插件(如 Calico、Flannel、Weave 等)负责提供集群内部的网络连接。
2. 通信流程 #
假设有两个 Pod,分别位于两个不同的 Node 上,Pod1 位于 Node1 上,Pod2 位于 Node2 上。Pod1 想要访问 Pod2:
步骤 1:DNS 查询或直接 IP 访问 #
- 如果 Pod1 知道 Pod2 的 IP 地址,它可以直接通过该 IP 地址进行通信。
- 如果 Pod1 通过 DNS 进行通信(Kubernetes 中的服务会为 Pod 提供 DNS 名称解析),则 Pod1 会查询 Kubernetes DNS 服务来解析 Pod2 所在服务的 IP 地址。
步骤 2:请求到达节点的网络插件 #
- 当 Pod1 发送请求时,请求首先到达 Pod1 所在节点(Node1)的网络插件。网络插件负责将请求发送到 Kubernetes 集群中其他节点。
- 如果 Pod1 访问的目标 Pod2 在 Node2 上,Node1 的网络插件会将请求转发给 Node2。
步骤 3:跨节点通信(通过 Overlay 网络或路由) #
在跨节点通信中,网络插件(如 Flannel、Calico、Weave 等)会为 Pod 之间的流量提供
Overlay 网络
或直接使用
路由
。
- Overlay 网络:网络插件会创建一个虚拟网络,将每个节点的虚拟网络接口通过隧道(如 VXLAN 或 GRE)连接起来。这允许不同节点上的 Pod 通过虚拟网络进行通信,即使它们位于物理上不同的服务器上。
- 直接路由:某些网络插件可能会采用直接路由的方式,直接使用集群内的路由来实现跨节点的流量转发。
步骤 4:Node2 上的网络插件接收请求 #
- 请求到达 Node2 后,Node2 上的网络插件会处理该请求,并将其转发到 Pod2。
- 网络插件确保请求通过正确的路由或隧道送到 Pod2。
步骤 5:Pod2 响应请求 #
- Pod2 接收到请求后,处理该请求并返回响应。响应过程与请求过程类似,Pod2 通过其所在节点的网络插件将响应发送回 Pod1。
步骤 6:返回响应 #
- 网络插件会将 Pod2 的响应传递给 Pod1,最终请求和响应通过网络插件成功传递到 Pod1。
3. 使用 Service 实现 Pod 访问 #
在 Kubernetes 中,直接通过 Pod 的 IP 地址进行通信并不推荐,通常通过 Kubernetes 的 Service 机制来实现 Pod 之间的通信。Service 提供了负载均衡和 DNS 解析服务,可以跨多个 Pod 实现高可用。
Service 的作用: #
- DNS 解析:Kubernetes 会为 Service 分配一个 DNS 名称(如
my-service.default.svc.cluster.local
),其他 Pod 可以通过这个 DNS 名称访问该 Service。 - 负载均衡:Service 会将请求均衡地转发到其背后所有 Pod,无论这些 Pod 是否位于同一个节点上。
- 透明通信:Service 对客户端透明,它会根据 Pod 的 IP 地址变化动态更新后端 Pod 的列表,确保负载均衡。
4. 安全性和网络策略 #
在跨节点通信时,Kubernetes 还可以通过 网络策略(Network Policies)来限制或允许不同 Pod 之间的通信。例如,可以限制某些 Pod 只能与同一命名空间下的 Pod 通信,或者允许特定的 Pod 之间的流量通过防火墙策略控制。
总结: #
- Kubernetes 网络模型确保每个 Pod 都有一个唯一的 IP 地址,并支持跨节点通信。
- 跨节点通信通过网络插件实现,通常采用 Overlay 网络(如 VXLAN)或直接路由。
- Service 提供了 Pod 间的高层通信抽象,支持 DNS 名称解析和负载均衡。
- 网络策略可以控制 Pod 间的访问权限,增强集群的安全性。
这个过程确保了在不同 Node 上的 Pod 之间能够高效、安全地进行通信。
17. k8s集群节点需要关机维护,需要怎么操作 #
- 进行pod驱逐:kubelet drain <node_name>
- 检查node上是否无pod运行,切被驱逐的pod已经在其他节点运行正常
- 关机维护
- 开机启动相关服务(注意启动顺序)
- 解除node节点不可调度:kubectl uncordon node
- 创建测试pod,并使用节点标签测试节点可以被正常调度
在 Kubernetes 集群中,如果需要对某个节点进行关机维护,必须采取一些操作步骤来确保服务不中断,同时避免出现 Pod 的意外丢失或服务中断。以下是进行节点关机维护的推荐步骤:
步骤 1:驱逐节点上的 Pod #
首先,需要将节点上的 Pod 移动到其他健康节点。Kubernetes 会在节点关闭时自动将 Pod 从该节点驱逐,但为了保证在维护时不会影响服务,可以提前手动驱逐 Pod。
标记节点为不可调度 将该节点标记为
cordon
,使 Kubernetes 不再在该节点上调度新的 Pod:kubectl cordon <node-name>
驱逐节点上的 Pod 使用
kubectl drain
命令来驱逐该节点上的所有 Pod(除了DaemonSet
和PodDisruptionBudget
控制的 Pod):kubectl drain <node-name> --ignore-daemonsets --delete-local-data
--ignore-daemonsets
:保留由DaemonSet
管理的 Pod。--delete-local-data
:删除节点上没有持久化存储的 Pod(如有本地存储)。
该命令会将该节点上的 Pod 逐个迁移到集群中的其他健康节点。
等待 Pod 被迁移 等待 Kubernetes 将节点上的 Pod 调度到其他健康的节点,确保 Pod 状态恢复正常。
步骤 2:检查集群状态 #
在节点被驱逐之后,需要检查集群的状态,确保所有的服务和 Pod 都已经成功调度到其他节点上,并且没有出现新的故障。
查看节点状态:
kubectl get nodes
节点状态应该是
SchedulingDisabled
。查看 Pod 的状态,确保它们都已迁移并正常运行:
kubectl get pods --all-namespaces
步骤 3:关闭维护节点 #
在确保节点上没有重要任务运行,且其他节点上的 Pod 已经调度完毕后,可以开始关闭该节点进行维护。
如果是物理机或者虚拟机,直接在操作系统层面执行关机命令:
sudo shutdown -h now
如果是云环境中的虚拟机,可以通过云平台的控制台关闭该虚拟机。
步骤 4:维护完成后重新启动节点 #
节点维护完成后,需要重新启动节点。
启动节点 启动节点并确保它能够恢复正常运行。
标记节点为可调度 一旦节点重启并恢复正常运行,使用以下命令将节点标记为可调度状态,使其可以再次接收 Pod:
kubectl uncordon <node-name>
检查节点状态 确保节点恢复为
Ready
状态,表示其正常加入集群:kubectl get nodes
验证 Pod 状态 确保节点上的 Pod 能够正常运行。如果该节点之前有被驱逐的 Pod,可以确认它们是否已成功重新调度并运行:
kubectl get pods -o wide
步骤 5:确保服务正常 #
维护完成后,需要确保所有的服务、Pod 和应用程序正常运行,检查是否有 Pod 无法调度或服务不可用的情况。
注意事项: #
- PodDisruptionBudget (PDB):如果你有设置 PodDisruptionBudget,确保在执行
kubectl drain
时不会违反 PDB 规则。PDB 可以保证在维护节点时,最小副本数和应用程序可用性。 - DaemonSets:DaemonSet 会自动在每个节点上创建 Pod,所以在节点关闭时,它们不会被删除。维护节点时,DaemonSet 管理的 Pod 不会被驱逐。如果需要停止 DaemonSet 的 Pod,可以先删除相应的 DaemonSet。
- 持久化存储:确保有持久化存储的 Pod 在驱逐时能够正常挂载到其他节点,否则会出现数据丢失或服务中断的问题。
- 集群资源健康:维护过程中,确保集群中的资源(如 CPU、内存、网络等)能够满足其他 Pod 的需求,以避免资源瓶颈影响服务。
通过这些步骤,可以确保在节点维护期间,Kubernetes 集群中的服务不会受到影响,维护工作完成后,节点可以安全地恢复并重新加入集群。
18. Calico和flannel区别 #
- Flannel(简单、使用居多):基于Vxlan技术(叠加网络+二层隧道),不支持网络策略
- Calico(较复杂,使用率少于Flannel):也可以支持隧道网络,但是是三层隧道(IPIP),支持网络策略
- Calico项目既能够独立地为Kubernetes集群提供网络解决方案和网络策略,也能与flannel结合在一起,由flannel提供网络解决方案,而Calico此时仅用于提供网络策略。
Calico 和 Flannel 都是 Kubernetes 中常用的网络插件,用于为容器提供网络连接。它们都可以实现跨 Pod 的网络通信,但是在架构、功能和性能方面有所不同。下面是它们的主要区别:
1. 网络模型和架构 #
Flannel
:
- Flannel 是一个简单的 Overlay 网络插件。它为 Kubernetes 集群中的 Pod 提供虚拟网络,将不同节点的 Pod 通过隧道连接起来。Flannel 使用 VXLAN 或其他隧道协议来创建跨节点的虚拟网络。
- Flannel 的网络模型一般是 Layer 3 Overlay,它会为每个 Pod 分配一个 IP 地址并通过隧道进行通信。
Calico
:
- Calico 是一个功能更强大的网络插件,支持多种模式,包括 Overlay 网络 和 路由模式。Calico 的核心功能是基于 BGP(边界网关协议)进行 IP 路由,因此它可以在 Kubernetes 集群中提供高性能的 L3 网络。
- Calico 支持 无代理的网络模型,通过直接路由实现容器之间的通信,这使得其在某些场景下具有更高的性能。
2. 网络类型 #
Flannel
:
- Overlay 网络:Flannel 创建一个虚拟的 Overlay 网络,通过 VXLAN、GRE 或其他协议将不同节点的网络连接起来。Flannel 会在每个节点上创建一个虚拟网卡,利用隧道协议将 Pod 之间的流量转发。
Calico
:
- Overlay 网络:Calico 也支持 Overlay 模式,但它同时支持 路由模式,即不需要额外的隧道协议。在路由模式下,Calico 会通过直接路由的方式连接集群中的不同节点。这使得它的性能在大多数情况下比 Flannel 要好。
- 无代理模式:Calico 不使用网络代理(如 Flannel 中的 VXLAN)来转发流量,而是直接使用主机路由表,从而减少了网络开销。
3. 性能 #
- Flannel:
- Flannel 的性能受限于其使用的隧道协议(如 VXLAN)。虽然 VXLAN 为跨节点通信提供了灵活性,但它引入了额外的开销,可能导致网络性能较差,尤其在大规模集群中。
- 隧道协议可能会导致额外的延迟和带宽消耗,尤其在集群规模增大时,性能可能会受到影响。
- Calico:
- Calico 的性能通常较好,因为它通过路由模式(而非隧道)来实现节点间的通信。Calico 可以直接将流量路由到目标节点,无需通过额外的隧道协议。
- 在支持路由模式的情况下,Calico 提供了比 Flannel 更低的延迟和更高的吞吐量,特别是在大规模集群中。
4. 安全性 #
- Flannel:
- Flannel 本身不提供强大的安全性功能,它仅负责网络通信,通常与网络策略(Network Policies)配合使用。
- 安全性依赖于其他工具或服务(例如,Kubernetes 本身的网络策略)。
- Calico:
- Calico 内置了强大的网络安全功能,包括 网络策略(Network Policies)。这些策略允许用户根据网络流量的来源和目的控制通信,从而提高集群的安全性。
- Calico 支持更细粒度的流量控制,可以定义哪些 Pod 或服务可以进行通信,哪些不能,从而提升网络的安全性。
5. 网络策略 #
Flannel
:
- Flannel 本身不提供网络策略功能,但可以与 Kubernetes 的 NetworkPolicy 进行集成,来实现访问控制。
Calico
:
- Calico 内置了强大的网络策略功能,支持复杂的访问控制和流量过滤。通过 Calico,你可以创建更细粒度的安全策略,控制哪些 Pod 或 IP 之间的流量可以通过。
6. 可扩展性 #
Flannel
:
- Flannel 设计较简单,适用于小型和中型集群,但在大规模集群中可能会受到性能瓶颈的影响。
Calico
:
- Calico 适用于大规模集群,并且可以与 BGP(边界网关协议)等协议一起工作,实现跨数据中心的容器网络。Calico 的可扩展性比 Flannel 更强,适用于更复杂的网络需求。
7. 安装和配置 #
- Flannel:
- Flannel 安装和配置较为简单,易于上手。它通常用于简单的 Kubernetes 集群,适合没有复杂网络需求的场景。
- Calico:
- Calico 配置更复杂一些,虽然它也支持简单的安装方式,但由于其强大的功能和灵活性,可能需要更精细的配置。特别是在使用 Calico 的网络策略时,管理员需要更多的管理和配置工作。
8. 支持的环境 #
- Flannel:
- Flannel 支持多种环境,包括本地部署的 Kubernetes 集群、云环境以及混合云环境。它也支持多种存储插件和网络插件。
- Calico:
- Calico 除了支持 Kubernetes 外,还可以与 OpenShift、Docker EE、Mesos 等其他容器编排平台一起使用。它支持多种类型的云环境,并且可以跨数据中心实现连接。
总结: #
特性 | Flannel | Calico |
---|---|---|
网络模型 | Overlay 网络(VXLAN, GRE) | Overlay 网络或路由模式(BGP) |
性能 | 较低(有隧道协议开销) | 较高(路由模式,低延迟) |
网络策略 | 依赖 Kubernetes 的 NetworkPolicy | 内置强大的网络策略功能 |
安全性 | 基础安全性,依赖外部工具 | 内置强大的安全性控制,支持流量过滤 |
可扩展性 | 适合小中型集群 | 适合大规模集群,支持跨数据中心 |
安装复杂度 | 简单易安装 | 配置和安装较复杂 |
支持的环境 | 本地云环境、混合云环境 | 本地云环境、跨数据中心支持 |
选择建议: #
- 如果你的 Kubernetes 集群规模较小,且对性能没有严格要求,可以使用 Flannel,它安装简单,适合快速部署。
- 如果你需要高性能的网络、跨数据中心连接或者更复杂的网络安全控制,建议使用 Calico。它适用于更大规模的集群,并提供内置的网络策略和安全功能。
六、prometheus #
1. prometheus对比zabbix有哪些优势? #
https://blog.csdn.net/wangyiyungw/article/details/85774969**
Prometheus 和 Zabbix 都是非常流行的监控工具,但它们的设计理念和实现方式有所不同。以下是 Prometheus 相对于 Zabbix 的一些优势:
1. 监控模式:Pull vs Push #
- Prometheus:采用 Pull 模式,定期从目标(如应用、服务器、数据库、容器等)主动拉取监控数据。这使得 Prometheus 可以轻松适应动态变化的环境(如容器、微服务等),并且可以通过多种方式实现监控(例如使用 exporters 进行自定义指标采集)。
- Zabbix:主要采用 Push 模式,通过代理或被监控设备主动推送数据,或者使用被动的 Pull 模式。虽然 Zabbix 支持 Push 模式,但它的监控主要还是依赖于代理的推送,因此对于大规模动态环境的适应性较差。
优势:Prometheus 的 Pull 模式使其更加适应云原生和容器化环境,尤其是 Kubernetes 等动态变化的集群环境。
2. 时序数据存储和查询 #
- Prometheus:专门为时序数据设计,具有高效的时间序列数据存储引擎。Prometheus 存储的所有数据都有时间戳,允许对时间序列数据进行强大的查询和聚合操作,支持 PromQL 查询语言,可以轻松进行复杂的数据分析。
- Zabbix:使用传统的关系型数据库(如 MySQL、PostgreSQL)存储数据。虽然 Zabbix 支持时间序列数据的存储,但它的存储引擎和查询语言没有 Prometheus 的时序数据库那么高效,特别是在大规模数据量下。
优势:Prometheus 的时序数据库设计和强大的查询能力使其在大数据量的监控和高效查询方面比 Zabbix 更具优势。
3. 动态环境支持 #
- Prometheus:具有出色的支持云原生和容器化环境的能力。通过与 Kubernetes 的集成,可以自动发现和监控集群中的所有容器和服务。同时,Prometheus 对动态 IP、服务发现等场景有很好的适应能力。
- Zabbix:虽然 Zabbix 支持动态环境,但相对于 Prometheus,它的配置和维护较为复杂,特别是在大规模动态环境(如 Kubernetes、Docker)中,Zabbix 的自动发现和动态监控能力相对较弱。
优势:Prometheus 在动态环境(如微服务、容器化)中的自动化、灵活性和可扩展性更强。
4. 集成与生态系统 #
- Prometheus:具有丰富的生态系统,支持多种数据采集方式和监控工具集成。例如,通过 exporters 可以从各种第三方服务(如数据库、消息队列等)收集指标,并且可以与 Grafana 等可视化工具无缝集成,提供强大的监控面板和仪表盘。
- Zabbix:虽然也有丰富的插件和集成工具,但与 Prometheus 相比,Zabbix 的集成方式和灵活性较为有限,尤其在容器化、微服务架构的集成上,Prometheus 更加友好和高效。
优势:Prometheus 的生态系统更加开放,能够轻松集成各种监控需求,尤其适用于微服务和容器化应用。
5. 告警和通知 #
- Prometheus:通过 Alertmanager 提供强大的告警功能,支持灵活的告警规则、告警抑制、告警分组等功能。同时,Prometheus 的告警系统与数据查询紧密集成,能够根据 PromQL 查询结果动态触发告警。
- Zabbix:提供内置的告警系统,支持自定义告警条件、自动化恢复和通知。Zabbix 的告警系统较为传统,灵活性和可扩展性略逊色于 Prometheus,尤其在大规模系统中的复杂告警配置可能需要更多的人工干预。
优势:Prometheus 的告警机制更加灵活、易于配置,并且能与监控数据和查询紧密结合,能够为云原生应用提供更好的告警体验。
6. 安装和配置 #
- Prometheus:相对简单,尤其在容器化环境中,可以通过 Docker 或 Kubernetes 等快速部署 Prometheus 集群,具有很好的易用性和自动化配置能力。
- Zabbix:安装和配置相对复杂,尤其在大规模分布式环境中,Zabbix 需要配置数据库、代理、服务器等多个组件,较为繁琐。
优势:Prometheus 的安装和配置更加简便,尤其在现代 DevOps 环境和云原生环境中更加高效。
7. 资源消耗 #
- Prometheus:由于其设计为轻量级的时序数据存储,Prometheus 在资源消耗上相对较低,特别是在小型或中型集群中。
- Zabbix:在资源消耗方面,Zabbix 可能会较为沉重,尤其是当需要通过代理收集大量数据时,资源消耗可能会增加。
优势:Prometheus 在资源消耗和扩展性方面比 Zabbix 更具优势,尤其是在大规模环境中。
8. 水平扩展 #
- Prometheus:支持水平扩展,Prometheus 可以与 Thanos 或 Cortex 等工具配合,进行跨集群查询和高可用性部署。通过将多个 Prometheus 实例集成,可以支持大规模集群监控。
- Zabbix:Zabbix 的扩展性较差,虽然支持分布式监控,但相比 Prometheus 的水平扩展,Zabbix 更依赖集中式架构,扩展性和灵活性较差。
优势:Prometheus 提供更好的水平扩展能力,适应大规模集群和跨区域监控。
总结: #
Prometheus 相对于 Zabbix 的优势在于:
- 更适合容器化、云原生和微服务架构。
- 支持 Pull 模式,灵活应对动态变化的环境。
- 高效的时序数据库和强大的查询语言(PromQL)。
- 灵活的告警系统和自动化集成。
- 良好的生态系统与其他工具(如 Grafana)集成。
- 安装、配置简单,易于扩展和维护。
当然,Zabbix 也有其优点,特别是在传统 IT 环境中的监控和大规模基础设施的管理,但对于现代化的应用监控和云原生架构,Prometheus 无疑是更优的选择。
2. prometheus组件有哪些,功能是什么? #
Prometheus 是一个开源的监控系统,专门用于监控多种微服务架构、容器化环境等场景。它由多个组件构成,每个组件都负责不同的功能。以下是 Prometheus 的主要组件及其功能:
1. Prometheus Server #
功能:Prometheus 服务器是核心组件,负责数据的采集、存储、查询和管理。它通过 Pull 模式定期从配置的目标(如应用程序、服务或节点)拉取时间序列数据。
主要功能
:
- 拉取数据:根据配置从 exporter 或其他 Prometheus 实例拉取指标数据。
- 存储:将拉取的数据存储在时序数据库中,支持高效查询。
- 查询:使用 PromQL(Prometheus 查询语言)提供灵活的数据查询能力。
- 警报:根据配置的规则,触发告警并将告警信息发送到 Alertmanager。
2. Alertmanager #
功能:Alertmanager 负责接收来自 Prometheus 的告警信息,处理告警并进行相应的通知(例如,通过邮件、Slack、PagerDuty 等)。
主要功能
:
- 告警聚合:Alertmanager 可以聚合多个相同类型的告警,并合并重复的告警信息。
- 告警路由:根据告警的不同标签(如严重性、团队等)将告警路由到不同的接收器(如 Slack、邮件等)。
- 告警抑制:可以设置告警抑制规则,避免相同问题的重复告警。
- 告警分组:可以将多个告警按时间或内容分组,减少告警的噪声。
3. Prometheus Exporters #
功能:Exporters 是用于从不同的系统(如操作系统、数据库、硬件等)收集监控数据的应用程序或服务。它们将系统的度量指标暴露为 Prometheus 可以拉取的 HTTP 格式。
常见的 Exporter
:
- Node Exporter:用于暴露 Linux/Unix 系统级别的度量指标,如 CPU 使用率、内存使用量、磁盘 I/O 等。
- Blackbox Exporter:用于测试外部服务的可用性,比如 HTTP 请求、TCP 连接等。
- MySQL Exporter、Redis Exporter:用于暴露数据库或中间件的指标数据。
- Kube-state-metrics:用于暴露 Kubernetes 资源(如 Pod、Node、Deployment 等)相关的度量指标。
4. Prometheus Query Language (PromQL) #
功能:PromQL 是 Prometheus 提供的查询语言,用于从 Prometheus 数据库中提取、聚合和过滤时间序列数据。
主要功能
:
- 查询:用户可以通过 PromQL 编写复杂的查询,从 Prometheus 存储的时间序列数据中提取所需的信息。
- 聚合:PromQL 支持多种聚合操作(如 sum、avg、max、min 等)来对时间序列数据进行处理。
- 时间操作:PromQL 提供时间范围选择功能,可以指定查询的时间范围,支持相对时间(如过去 5 分钟)和绝对时间。
5. Prometheus UI #
功能:Prometheus 提供了一个 Web 界面,用户可以通过它查看查询结果、配置告警规则、查看存储的时序数据等。
主要功能
:
- 查询功能:可以直接在界面上执行 PromQL 查询。
- 查看指标:查看所有可用的指标以及其时间序列数据。
- 配置告警:可以通过 UI 配置告警规则,进行告警通知设置。
6. Prometheus Pushgateway #
功能:Pushgateway 允许应用程序将度量指标主动推送到 Prometheus,而不是通过 Prometheus 的 Pull 方式来拉取数据。常用于短生命周期的批处理作业或定时任务(例如 ETL 作业),它们在运行时将数据推送到 Pushgateway。
主要功能
:
- Push:应用程序将指标推送到 Pushgateway。
- Pull:Prometheus 从 Pushgateway 拉取数据。
- 用于短期存在的任务,避免 Prometheus 无法拉取数据的情况。
7. Thanos (可选) #
功能:Thanos 是一个用于扩展 Prometheus 的组件,提供高可用性、长期存储和全局查询的功能。Thanos 通过集成多个 Prometheus 实例,将多个 Prometheus 集群的数据汇聚到一个全局查询层。
主要功能
:
- 高可用:Thanos 可以使 Prometheus 集群成为高可用,多个 Prometheus 实例可以同时工作,避免单点故障。
- 长期存储:Thanos 支持将 Prometheus 存储的数据迁移到对象存储(如 AWS S3),从而提供长期存储功能。
- 全局查询:Thanos 允许跨多个 Prometheus 实例查询数据,提供全局视图。
8. Cortex (可选) #
功能:Cortex 是另一种用于扩展 Prometheus 的解决方案,支持多租户、长期存储和水平扩展。它支持将 Prometheus 的时间序列数据存储在分布式对象存储(如 Amazon S3)中,并提供高可用性和扩展性。
主要功能
:
- 多租户:Cortex 支持多租户环境,每个租户有独立的存储和查询空间。
- 长期存储:支持将 Prometheus 数据持久化到外部存储后端,如 S3。
- 水平扩展:Cortex 设计为高度可扩展,可以根据需求动态增加存储和查询能力。
总结 #
Prometheus 由多个关键组件组成,各自负责不同的功能:
- Prometheus Server:负责数据的采集、存储和查询。
- Alertmanager:处理告警信息并进行通知。
- Exporters:从不同的服务和系统收集指标数据。
- PromQL:查询 Prometheus 数据库的查询语言。
- Pushgateway:允许应用主动推送数据到 Prometheus。
- Thanos 或 Cortex:扩展 Prometheus 提供高可用性、长期存储和跨集群查询功能。
3. 指标类型有哪些? #
- Counter(计数器)
- Guage(仪表盘)
- Histogram(直方图)
- Summary(摘要)
Prometheus 支持多种类型的指标(metrics),每种指标类型都有不同的用途和特性。以下是 Prometheus 中常见的指标类型:
1. Counter(计数器) #
定义:计数器是单调递增的值。它只能增加或重置为零。常用于记录事件的总次数,比如请求次数、错误次数等。
用途:适用于记录某个事件发生的总数,如请求数、成功数、失败数等。
特点
:
- 只能递增,无法减少。
- 在 Prometheus 查询中,经常与
rate()
或increase()
函数一起使用来计算某个事件的增长速率。
示例
:
http_requests_total{status="200"} # 记录 HTTP 请求总数(状态为 200)
2. Gauge(仪表盘) #
定义:仪表盘指标表示一个可以任意增加或减少的值。适用于表示当前状态或度量。
用途:用于表示一些瞬时变化的值,如内存使用量、CPU 使用率、当前活跃的连接数等。
特点
:
- 值可以递增,也可以递减。
- 可以表示“当前”某个状态的实时值。
示例
:
memory_usage_bytes # 当前内存使用量(单位:字节)
3. Histogram(直方图) #
定义:直方图用于记录数据分布。它将数据分成多个“桶”,可以记录每个桶的计数值,并且可以计算数据的分布情况(例如请求时延的分布)。
用途:用于统计某些值的分布,如请求时延、响应大小等。可以通过设置不同的桶(buckets)来统计不同范围内的数据。
特点
:
- 提供多个桶,以便对数据进行分布统计。
- 可通过
rate()
函数计算事件的平均时间、请求时延等指标。 - 可以与
sum()
和count()
一起使用计算平均值等。
示例
:
http_request_duration_seconds_bucket # HTTP 请求持续时间的桶
4. Summary(摘要) #
定义:摘要用于计算观测值的分位数(percentiles)。它是对直方图的扩展,除了提供直方图的桶计数,还提供如
0.5
(50th percentile)等分位数的估算值。用途:用于获取值的分位数,比如计算 95% 请求的响应时延。Summary 能够直接给出某个百分位(如 90th、95th)的数据。
特点
:
- 会提供统计数据的分位数,如
p50
、p90
等。 - 比直方图更加精确地计算分位数,但它的存储开销和计算开销相对较高。
- 会提供统计数据的分位数,如
示例
:
http_request_duration_seconds_sum # HTTP 请求持续时间的总和 http_request_duration_seconds_count # HTTP 请求持续时间的请求计数 http_request_duration_seconds{quantile="0.9"} # HTTP 请求持续时间的 90th 百分位
总结: #
- Counter:只增不减,用于表示累计的总数(例如,请求数量、错误次数)。
- Gauge:可以增可以减,用于表示当前瞬时的数值(例如,CPU 使用率、内存占用)。
- Histogram:用于记录数据分布,支持多个桶,适合用于计算数据的分布情况(如请求时延分布)。
- Summary:用于计算分位数(百分位),能够获取某些统计值的分位数,适合用于监控响应时间等。
Prometheus 的指标类型可以根据不同的监控需求选择和使用,在云原生应用、微服务架构和容器化环境中,合理选择这些指标类型可以帮助精确地监控系统的状态和性能。
4. 在应对上千节点监控时,如何保障性能 #
- 降低采集频率
- 缩小历史数据保存天数,
- 使用集群联邦和远程存储
在处理大规模 Kubernetes 集群或包含上千个节点的监控时,Prometheus 可能面临性能瓶颈,包括存储、查询延迟、数据收集速度等问题。为了保障 Prometheus 在这种大规模环境下的性能,可以采取以下几种策略:
1. 水平扩展(Horizontal Scaling) #
Prometheus 分区(Sharding)
:
- 将 Prometheus 集群水平扩展,通过多个 Prometheus 实例进行分片(shard)。每个实例负责监控集群的一部分节点,这样可以减轻单个实例的负载。
- 在分片时,需要在
Prometheus
配置中使用federation
或外部聚合方式,将多个 Prometheus 实例的数据汇总到一个集中的查询接口。
多集群 Prometheus 集群
:
- 使用多个 Prometheus 实例,每个实例负责不同的数据中心或 Kubernetes 集群。然后使用 Prometheus 的 联邦(federation) 功能将多个集群中的指标汇聚到一个中央 Prometheus 进行统一查询和存储。
- 这种方式可以避免单个 Prometheus 实例承载全部负载,提高可扩展性和高可用性。
2. 使用 *Prometheus Operator* #
- Prometheus Operator 可以简化多实例 Prometheus 集群的管理。它支持自动化部署、配置管理和扩展,帮助简化 Prometheus 集群的维护。
- 配置 Prometheus Operator 时,可以使用 k8s CustomResourceDefinitions (CRD) 来管理 Prometheus 实例、Alertmanager 和其他组件,确保系统能够根据需求动态扩展。
3. 优化数据存储 #
- 长期存储(Long-Term Storage):
- 对于大规模集群,单个 Prometheus 实例的存储很可能会成为瓶颈。可以将 Prometheus 数据存储与外部持久化存储(如 Thanos 或 Cortex)集成,以提供高可用和高扩展性的长期存储。
- Thanos:Thanos 是一个针对 Prometheus 的聚合层,它将 Prometheus 存储与长期存储(如对象存储)结合起来,支持查询多个 Prometheus 实例的聚合数据。
- Cortex:Cortex 是另一种支持 Prometheus 数据长期存储的方案,提供了分布式和可扩展的存储解决方案,适用于大规模环境。
- 数据压缩与降采样:
- 配置适当的数据采集频率,减少无用的数据采集,可以通过
scrape_interval
和scrape_timeout
来调优。 - 使用 数据降采样(downsampling)技术,减少存储中的数据精度。例如,存储高精度数据只有一段时间,然后对其进行降采样。
- 配置适当的数据采集频率,减少无用的数据采集,可以通过
4. 优化指标收集 #
- 控制 Scrape 频率:
- 对不同的指标设置合理的采集频率,例如,对于某些不频繁变化的指标(如主机负载、磁盘空间等),可以减少 scrape 频率,避免过多的数据采集。
- 分组采集指标:
- 将同一类型的指标聚合在一起,避免每个指标独立采集。通过调整采集配置,减少不必要的指标收集,降低负载。
- 使用 Pushgateway:
- 对于短期存在的批量作业(如批量任务或一次性任务),可以使用 Pushgateway 将数据推送到 Prometheus,而不是通过 scrape 进行轮询。Pushgateway 可以减少 Prometheus 本身的 scrape 负担。
5. 优化查询性能 #
- 查询优化:
- 为了避免 Prometheus 查询时的性能瓶颈,尽量避免查询过于复杂的多维度数据。尽量简化查询条件,减少聚合和 Join 操作。
- 适当调整查询缓存配置,减少不必要的实时计算。
- PromQL 查询优化:
- 使用高效的 PromQL 查询语法,避免不必要的
rate
、avg
等聚合操作。尽量将查询范围限制在必要的数据范围内,避免全量查询。
- 使用高效的 PromQL 查询语法,避免不必要的
6. 引入 *Thanos* 或 *Cortex* 来实现高可用和长期存储 #
- Thanos 或 Cortex 是 Prometheus 的外部聚合层,提供高可用、持久化存储以及全局查询功能,可以帮助处理超大规模数据。
- Thanos:将多个 Prometheus 实例的数据集中到一个全局查询层,支持对象存储后端,解决了数据冗余和高可用问题。
- Cortex:与 Thanos 类似,Cortex 提供了高度可扩展的存储后端,适用于大规模 Prometheus 集群,支持多租户和跨集群查询。
7. 使用 Alertmanager 的集群模式 #
- 在大规模集群中,Alertmanager 的配置也需要优化。使用 Alertmanager 的集群模式,可以将告警请求分散到多个实例,从而提高告警的处理能力。
8. 使用外部高效的存储后端 #
- 考虑将数据存储引入更为高效的存储系统,如 分布式对象存储(例如 Amazon S3、Google Cloud Storage)以提高读写性能。
9. 优化网络 #
- 通过合适的网络带宽、延迟优化,确保 Prometheus 与所有节点的连接稳定,避免网络瓶颈导致数据丢失或延迟。
总结: #
在大规模 Kubernetes 集群或包含上千节点的环境中,Prometheus 的性能可以通过以下几种方式保障:
- 水平扩展:通过分片和联邦部署多个 Prometheus 实例来减轻单实例负载。
- 长期存储解决方案:使用 Thanos 或 Cortex 进行数据的长期存储和高可用。
- 查询和存储优化:通过合理的查询语句、数据降采样和减少不必要的采集频率来降低系统负担。
- 数据收集优化:合理配置 Scrape 间隔、使用 Pushgateway 等方式减少不必要的数据流量。
- 监控网络性能:通过优化 Prometheus 集群的网络、存储及告警管理等各方面的配置,保障整体性能。
5. 简述从添加节点监控到grafana成图的整个流程 #
- 被监控节点安装exporter
- prometheus服务端添加监控项
- 查看prometheus web界面——status——targets
- grafana创建图表
在 Prometheus + Grafana 环境下,添加监控节点并在 Grafana 上生成图表的整个流程通常包含以下几个步骤:
1. 安装 Prometheus 监控系统 #
安装 Prometheus:首先确保 Prometheus 已经安装并启动。Prometheus 作为监控系统,负责从各种节点(如应用服务器、容器、数据库等)收集指标。
配置 Prometheus 配置文件(prometheus.yml)
:配置 Prometheus 从哪些目标(节点)采集数据。
scrape_configs
:在
prometheus.yml
中,使用
scrape_configs
配置需要监控的目标节点及其端口。例如:
scrape_configs: - job_name: 'node_exporter' static_configs: - targets: ['<node-ip>:9100']
2. 安装并配置 Node Exporter(在被监控节点上) #
安装 Node Exporter:Node Exporter 是 Prometheus 用来收集服务器硬件和操作系统指标(如 CPU 使用率、内存、磁盘等)的工具。
启动 Node Exporter
:在每个被监控的节点上安装并启动 Node Exporter。默认端口为
9100
。
# 在每个被监控的节点上启动 Node Exporter ./node_exporter
确保节点可以被 Prometheus 访问:Prometheus 需要能够访问节点的
9100
端口。
3. Prometheus 收集数据 #
- Prometheus 会根据配置的
scrape_interval
定期从每个节点(通过 Node Exporter)拉取指标数据。例如,Prometheus 每 15 秒拉取一次数据。 - 通过
http://<node-ip>:9100/metrics
访问 Node Exporter 提供的监控数据(例如 CPU 使用率、内存、磁盘空间等)。
4. 安装 Grafana #
安装 Grafana
:Grafana 是一个开源的数据可视化工具,它与 Prometheus 配合使用,提供图形化的监控面板。
# 安装 Grafana sudo apt-get install grafana
5. 配置 Grafana 数据源 #
登录 Grafana
:默认情况下,Grafana 在
http://<grafana-server-ip>:3000
上提供 Web 界面。
- 默认用户名和密码是
admin
/admin
。
- 默认用户名和密码是
添加 Prometheus 数据源
:
- 进入 Grafana 控制台后,点击左侧菜单的 “Configuration” > “Data Sources”。
- 选择 “Prometheus” 数据源,并填写 Prometheus 的 URL(例如:
http://<prometheus-server-ip>:9090
)。 - 保存并测试连接。
6. 创建仪表板和图表 #
创建仪表板
:
- 进入 Grafana 后,点击左侧菜单的 “+” > “Dashboard” 创建新的仪表板。
- 在新仪表板中,可以添加多个面板(Panel)来展示不同的监控指标。
选择指标
:
每个面板都可以选择一个 Prometheus 查询,Grafana 会显示该查询的实时结果。例如,查询 CPU 使用率:
avg(rate(node_cpu_seconds_total{mode="user"}[5m])) by (instance)
选择不同的时间范围和图表类型(如时间序列图、条形图、饼图等)。
7. 设置警报(可选) #
设置警报
:可以为某些面板设置告警规则,当某个指标超出预定范围时,Grafana 会通过邮件、Slack、Webhook 等方式发送通知。
- 在面板的设置中,进入 “Alert” 标签页,配置警报规则。
8. 查看监控数据 #
- 完成配置后,Grafana 会开始通过 Prometheus 数据源实时获取数据,并以图表的形式展示在仪表板上。您可以通过 Grafana 控制面板来监控不同节点的各种性能指标,如 CPU 使用率、内存、磁盘 IO、网络流量等。
9. 优化和调整 #
- 优化 Prometheus 配置:根据监控需求,可以调整
prometheus.yml
中的scrape_interval
、scrape_timeout
等参数,以获得更高的采集频率或更低的延迟。 - 调整 Grafana 面板:可以根据需要调整面板的布局、查询频率、时间范围等。
总结: #
- 安装 Prometheus 和配置目标节点,确保 Prometheus 能定期从 Node Exporter 等数据源拉取指标。
- 安装 Grafana,并在 Grafana 中配置 Prometheus 作为数据源。
- 创建 Grafana 仪表板,并设置相应的查询和图表。
- 查看和监控节点数据,使用 Grafana 可视化数据,并根据需要设置警报。
通过以上步骤,您就能实现从添加节点监控到 Grafana 上生成实时图表的完整流程。
6. 在工作中用到了哪些exporter #
- node-exporter监控linux主机
- cAdvisor监控容器
- MySQLD Exporter监控mysql
- Blackbox Exporter网络探测
- Pushgateway采集自定义指标监控
- process exporter进程监控
在工作中,常用的 exporter 主要有以下几种:
- Node Exporter:
- 用于收集主机的硬件和操作系统指标,如 CPU、内存、磁盘使用情况、网络流量等。通常用于监控整个主机的性能。
- Blackbox Exporter:
- 用于监控外部服务的可达性(如 HTTP、HTTPS、TCP、DNS 等)。可以用来监控网站、API、数据库等外部服务的健康状况。
- MySQL Exporter:
- 用于从 MySQL 数据库收集各种性能指标,如连接数、查询执行情况、慢查询等。帮助监控数据库的性能和健康状况。
- Redis Exporter:
- 用于收集 Redis 的性能指标,包括内存使用、连接数、命令执行情况等。适用于 Redis 的性能监控和优化。
- JMX Exporter:
- 用于从 Java 应用程序(如 Tomcat、Kafka、Hadoop 等)收集指标。通过暴露 JMX(Java Management Extensions)指标,将 Java 应用的性能数据提供给 Prometheus。
- Kubernetes Metrics Server:
- Kubernetes 集群中用于收集各个 Pod 和 Node 的资源使用数据(如 CPU、内存使用量)。通常与 Prometheus 配合使用,提供集群级别的监控数据。
- NGINX Exporter:
- 用于收集 Nginx 服务器的运行指标,如请求数量、响应时间、连接数等。帮助监控 Nginx 的负载和健康状况。
- Kafka Exporter:
- 用于监控 Kafka 集群的健康和性能指标,如主题(topic)大小、分区状态、消费者延迟等。
- PostgreSQL Exporter:
- 用于从 PostgreSQL 数据库收集指标,包括连接数、查询性能、索引使用情况等,帮助分析数据库的运行状态。
- Docker Exporter:
- 用于收集 Docker 容器的资源使用情况,如 CPU、内存、磁盘等,适用于容器化环境的监控。
- Consul Exporter:
- 用于从 HashiCorp Consul 中收集监控数据,主要是关于服务健康检查的状态和元数据。
这些 exporters 使得 Prometheus 能够全面地监控基础设施、应用程序和数据库等关键组件,并结合 Grafana 提供实时的可视化数据。