Nginx Performance Test
写在最前面, 这个问题还在研究中, 我目前还没有合适的模型用来研究这个问题, Pending….
Nginx 性能测试与压力计算使用al2023 + 默认的yum仓库软件版本, 具体信息记录如下:
按照下面的配置, 在Nginx上面发布一个目录, 其中放了一个Fedora镜像, 大小大约2.3GB, 固定Nginx处理请求的大小, 控制大部分的因素来尝试获取精确的结果。
OS Version
[root@ip-172-31-53-146 ~]# cat /etc/os-release
NAME="Amazon Linux"
VERSION="2023"
ID="amzn"
ID_LIKE="fedora"
VERSION_ID="2023"
PLATFORM_ID="platform:al2023"
PRETTY_NAME="Amazon Linux 2023"
ANSI_COLOR="0;33"
CPE_NAME="cpe:2.3:o:amazon:amazon_linux:2023"
HOME_URL="https://aws.amazon.com/linux/"
BUG_REPORT_URL="https://github.com/amazonlinux/amazon-linux-2023"
SUPPORT_END="2028-03-01"
在一个机器上面部署MySQL 然后初始化配置一个密码和用户。
[root@ip-172-31-53-200 ~]# mysql --version
mysql Ver 8.0.32 for Linux on x86_64 (MySQL Community Server - GPL)
直接使用bitnami的wordpress, 仅部署wordpress在另一个机器上面,然后配置连接到上面的那台数据库。
额外配置一下Docker-compose 的CPU affinity, 绑到cpu0上面, 让这个Container只能用cpu0, 模拟只有一个核心, 后面应该还会给他放开。
---
version: '2'
services:
wordpress:
cpuset: "0"
network_mode: host
5. 尝试给点压力, 做个基准测试。
### 测试1 单线程计算QPS
> 公式: 1000ms/RT = QPS
>
> 这个是单线程的QPS 与 RT 的关系, 试图走一把流程验证这个。
运行命令 wrk 配置 1connection 1thread 进行测试, 测试时间5分钟。
获取 RT,HTTP请求从发出到响应的时间 :
![2023-04-27_10-38.png](https://s2.loli.net/2023/04/27/pf2Z5erTzcayPFJ.png)
基于当前获取到的RT就可以计算出单线程的QPS :
```bash
RT:45ms # 这个时候获取的RT是客户端从发出数据包 到 收到完整的请求的页面返回的时间, 基于上面的抓包结果计算。
1000ms/45ms = 22 QPS
实际命令返回的结果:
~ ❯❯❯ wrk -t1 -c1 -d5m --latency http://nginx.liarlee.site:8080
Running 5m test @ http://nginx.liarlee.site:8080
1 threads and 1 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 45.00ms 3.60ms 169.02ms 88.75%
Req/Sec 22.24 4.27 30.00 76.72%
Latency Distribution
50% 44.28ms
75% 46.23ms
90% 48.51ms
99% 54.40ms
6668 requests in 5.00m, 337.69MB read
Requests/sec: 22.23 # 确实是 22左右, 基本上和计算得出的结果一致。
Transfer/sec: 1.13MB
测试2 计算服务当前的最佳线程数量默认的情况下, 当一个进程处理的时候, 线程接收到请求, OnCPU处理这个请求, 发出数据库查询,切换到Sleep状态,数据库处理完成,线程回到CPU继续运算,发送结果给客户端,这样完成一个Request。
计算服务的最佳线程数量其实是 需要多少个线程占用CPU,最终可以填满 CPU 1s 的时间, 让CPU尽可能都用来处理业务请求。
所以最大的线程数量是变化的, 与CPU time 相关 或者说 与RT相关, 对于一些特定的请求,控制了大部分变量的场景下, 可以计算一个最佳的线程数量。 计算公式:
最佳线程数: CPU TIme + Wait Time / CPU Time = 2 + 42 / 2 = 22
打开文件数限制可能的并发数量测试 conntrack 的问题, 发现连接数不太高, 试图通过wrk 提高并发的连接数量。使用命令:
wrk -t2 -c30000 -d30s http://reg.liarlee.site:80
如果我的理解没有问题, 那么我应该可以创建30000个连接 在 客户端 和 服务端 之间。但是结果:
# 客户端尝试建立 8000c
ec2-user@arch ~> wrk -t1 -c8000 -d30s http://reg.liarlee.site:80
Running 30s test @ http://reg.liarlee.site:80
1 threads and 8000 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 49.94ms 42.36ms 428.68ms 92.65%
Req/Sec 21.15k 8.19k 41.30k 66.08%
608596 requests in 30.04s, 218.23MB read
Socket errors: connect 6980, read 0, write 0, timeout 0
Requests/sec: 20260.60
Transfer/sec: 7.27MB
# 服务端看到的是:
[root@reg tools]# ss -s
Total: 282
TCP: 1103 (estab 28, closed 1063, orphaned 0, timewait 2)
Transport Total IP IPv6
RAW 0 0 0
UDP 8 4 4
TCP 40 36 4
INET 48 40 8
FRAG 0 0 0
这和预期的差距挺大的, 1103 让我非常容易的想到了 1024 的文件描述符限制。 于是
ec2-user@arch ~> ulimit -n
1024
客户端 wrk 的文件描述符可用调大到 100000 。
# 客户端
ec2-user@arch ~ [127]> ulimit -n
100000
ec2-user@arch ~> wrk -t2 -c30000 -d30s http://reg.liarlee.site:80
Running 30s test @ http://reg.liarlee.site:80
2 threads and 30000 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 515.29ms 411.20ms 2.00s 78.35%
Req/Sec 1.76k 2.70k 11.96k 85.71%
39021 requests in 30.28s, 13.99MB read
Socket errors: connect 0, read 298852, write 16, timeout 3115
Requests/sec: 1288.65
Transfer/sec: 473.17KB
# 服务端
[root@reg tools]# ss -s
Total: 282
TCP: 7544 (estab 28, closed 7504, orphaned 1641, timewait 2)
Transport Total IP IPv6
RAW 0 0 0
UDP 8 4 4
TCP 40 36 4
INET 48 40 8
FRAG 0 0 0
如果从上面的角度来看, 那么客户端的打开文件数是限制, 现在打开文件数调大了, 服务端还是无法建立更多的连接, 这个还得继续看看 , 我感觉是cpu的问题, 毕竟我访问的页面的是有内容的, 不是一个空请求。
# 尝试看了以下服务端的ss 命令
ec2-user@arch ~> ss -s
Total: 31669
TCP: 31268 (estab 7959, closed 1182, orphaned 1250, timewait 1)
Transport Total IP IPv6
RAW 1 0 1
UDP 4 2 2
TCP 30086 30080 6
INET 30091 30082 9
FRAG 0 0 0
确实发起了30000 但是 进入estab状态的连接只有 8000 左右。这基本上可以确定是服务端的限制了,具体是什么地方限制了待查。客户端 : c5 实例类型上面的 wrk服务端 : t3.micro - docker compose 部署的 harbor
连接异常导致的orphans一个遗憾的事情, 最近遇到了一个可能是 cilium 的一个问题, 在小规模集群的场景下, Cilium 会错误的处理FIN , FIN ACK, 导致安全组的 Connection Track 数量被打满。 之前没有注意过这个行为,在Docker的环境中测试下, 尝试使用 iptables 屏蔽容器发送出来的FIN, 记录步骤和命令:
dnf install -y docker
systemctl enable --now docker
docker pull reg.liarlee.site/docker.io/library/nginx/nginx:latest
docker run -dt --rm --name nginx -p 81:80 reg.liarlee.site/docker.io/library/nginx:l ...
OOM行为
关于OOM行为的思考 以及Kswapd的动作和行为。http://evertrain.blogspot.com/2018/04/oom.html更详细的打分算法见源码 https://github.com/torvalds/linux/blob/master/mm/oom_kill.c
发生之后OOM killer会将kill的信息记录到系统日志/var/log/messages,检索相关信息就能匹配到是否触发。
grep 'Out of memory' /var/log/messages
也可以通过dmesg
dmesg -Tx | egrep -i 'killed process'
查看分数最高的进程#!/bin/bash
for proc in $(find /proc -maxdepth 1 -regex '/proc/[0-9]+'); do
printf "%2d %5d %s\n" \
"$(cat $proc/oom_score)" \
"$(basename $proc)" \
"$(cat $proc/cmdline | tr '\0' ' ' | head -c 50)"
done 2>/dev/null | sort -nr | head -n 10
保护措施设置OverCommit只有在OverCommit的时候才会触发OOM, 默认是许可一定程度的OverCommit的。
https://docs.kernel.org/vm/overcommit-accounting.html
vm.overcommit_memory 作用是控制OverCommit是否被许可。
0
Heuristic overcommit handling. Obvious overcommits of address space are refused. Used for a typical system. It ensures a seriously wild allocation fails while allowing overcommit to reduce swap usage. root is allowed to allocate slightly more memory in this mode. This is the default.
1
Always overcommit. Appropriate for some scientific applications. Classic example is code using sparse arrays and just relying on the virtual memory consisting almost entirely of zero pages.
2
Don’t overcommit. The total address space commit for the system is not permitted to exceed swap + a configurable amount (default is 50%) of physical RAM. Depending on the amount you use, in most situations this means a process will not be killed while accessing pages but will receive errors on memory allocation as appropriate.
Useful for applications that want to guarantee their memory allocations will be available in the future without having to initialize every page.
[root@ip-172-31-9-192 log]# cat /proc/meminfo | grep Comm
CommitLimit: 4794236 kB
Committed_AS: 2344744 kB
---
CommitLimit: 可提交内存的上限, 超过这个上限系统认为目前内存已经是OverCommit。
Committed_AS: 已经提交内存的上限,当前所有进程已经提交的内存使用,这个不是已经分配出去的, 是进程申请的。
设置Killer的行为root@ip-172-31-11-235:/home/ec2-user|⇒ cat /proc/sys/vm/oom_kill_allocating_task
# 值为0:会 kill 掉得分最高的进程
# 值为非0:会kill 掉当前申请内存而触发OOM的进程
设置进程
对于需要保护的进程可以使用OOM_ADJ=-17 将这个进程从OOM Killer的列表中移除(已经在内核的2.6之后废弃,处于兼容性保留了这个文件接口
调整OOM_SCORE_ADJ, 范围是 -1000 < oom_score_adj < 1000
直接调整到-1000,会出现在计算分数列表的最后 echo -1000 > /proc/31595/oom_score_adj
手动触发一次OOM规则, Kill符合要求的进程 echo f > /proc/sysrq-trigger
调整服务的OOM Score对于服务本身的保护方式, 可以采用使用Systemd Unit file里面进行 OOMADJSCORE=*** 的方式来指定,例如保护MySQL的进程不会在OOM Killer的列表中。
cat /usr/lib/systemd/system/mariadb.service
[Service]
Type=simple
User=mysql
Group=mysql
ExecStartPre=/usr/libexec/mariadb-prepare-db-dir %n
ExecStart=/usr/bin/mysqld_safe --basedir=/usr
ExecStartPost=/usr/libexec/mariadb-wait-ready $MAINPID
# Setting Here. and setting in the /proc/$PID/oom_score_adj.
OOMScoreAdjust=-1000
sudo systemctl daemon-reload && sudo systemctl restart mariadb
避免OOM的方式
关闭OverCommit: 关闭OverCommit会导致进程如果无法拿到内存就fast fail , 不会出现OOMKiller干掉无辜进程的情况。
开启OverCommit, 开启一定程度的Swap: 开启Swap会导致内存在接近99%的时候,会出现系统响应变慢的问题,但是会由于申请的内存没有超过TotalMEM + TotalSWAP,因此不会触发OOM ,但是会导致明显的系统响应问题。 如果超过了 TotalMEM + TotalSWAP 会立刻触发一次OOMkiller结束进程。
开启OverCommit, 调整进程的优先级: 对于特定的进程进行保护。OOM会按照设置的积分计算需要Kill的进程。
开启OverCommit, 调整OOMkiller的行为方式: 计算积分后Kill 或者 直接Kill当前新申请内存的进程。这个方式感觉和默认的关闭OverCommit的行为类型,都是拒绝新的进程以保证旧的进程可以存活。
更可靠的方式Faceboook的oomdhttps://github.com/facebookincubator/oomdoomd使用的是 PSI接口来评估内存的压力,可以通过自定义规则的方式来对来进行内存压力的分析,而不是简单的内存用量。
Fedora的Early OOMhttps://github.com/rfjakob/earlyoomEarlyOOM的作用是提前OOM,这样可以保障用户空间的图形桌面不会到交换空间去, 主要解决的问题是内存压力过大的交换动作会将桌面环境换出导致响应变慢。
输出结果记录Cgroup - Pod
首先是哪个程序超过了cgroup的limit, 触发了cgroup 的oom, 这里是 xray 这个进程自己。
kern :warn : [Thu Aug 17 17:29:27 2023] xray invoked oom-killer: gfp_mask=0x100cca(GFP_HIGHUSER_MOVABLE), order=0, oom_score_adj=-997
这个部分是触发kprint的信息, 解释如下:在哪个CPU(1)上, 运行的进程PID(1586622), commandline的名称(xray), 哪个版本的内核, 是否被标记为 taint.
kern :warn : [Thu Aug 17 17:29:27 2023] CPU: 1 PID: 1586622 Comm: xray Kdump: loaded Not tainted 5.14.0-333.el9.x86_64 #1
硬件信息, BIOS信息
kern :warn : [Thu Aug 17 17:29:27 2023] Hardware name: Red Hat KVM, BIOS 1.15.0-2.module_el8.6.0+2880+7d9e3703 04/01/2014
打印发生oom时刻的堆栈
kern :warn : [Thu Aug 17 17:29:27 2023] Call Trace:
kern :warn : [Thu Aug 17 17:29:27 2023] <TASK>
kern :warn : [Thu Aug 17 17:29:27 2023] dump_stack_lvl+0x34/0x48
kern :warn : [Thu Aug 17 17:29:27 2023] dump_header+0x4a/0x201
kern :warn : [Thu Aug 17 17:29:27 2023] oom_kill_process.cold+0xb/0x10
kern :warn : [Thu Aug 17 17:29:27 2023] out_of_memory+0xed/0x2e0
kern :warn : [Thu Aug 17 17:29:27 2023] mem_cgroup_out_of_memory+0x13a/0x150
kern :warn : [Thu Aug 17 17:29:27 2023] try_charge_memcg+0x79d/0x860
kern :warn : [Thu Aug 17 17:29:27 2023] ? __mem_cgroup_charge+0x55/0x80
kern :warn : [Thu Aug 17 17:29:27 2023] charge_memcg+0x7a/0xf0
kern :warn : [Thu Aug 17 17:29:27 2023] __mem_cgroup_ch ...
Perf 命令的Performance分析
https://blog.gmem.cc/perf 一个非常详细的博客, 太强啦。
使用perf进行性能的简单输出root@ip-172-31-11-235:~|⇒ perf stat htop -d 1
Performance counter stats for 'htop -d 1':
181.764747 task-clock (msec) # 0.055 CPUs utilized
52 context-switches # 0.286 K/sec
0 cpu-migrations # 0.000 K/sec
320 page-faults # 0.002 M/sec
<not supported> cycles
<not supported> instructions
<not supported> branches
<not supported> branch-misses
3.283236218 seconds time elapsed
使用perf记录性能指标到文件[root@ip-172-31-41-141 tmp]# perf record -F 99 -a -g -p 44551
[root@ip-172-31-41-141 tmp]# sudo perf record -F 99 -a -g -- sleep 60
Warning:
PID/TID switch overriding SYSTEM
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.021 MB perf.data (2 samples) ]
root@ip-172-31-11-235:~|⇒ sudo perf script > out.perf
生成火焰图通常的做法是将 out.perf 拷贝到本地机器,在本地生成火焰图:
$ git clone --depth 1 https://github.com/brendangregg/FlameGraph.git
# 折叠调用栈
$ perf script > out.perf
$ FlameGraph/stackcollapse-perf.pl out.perf > out.folded
# 生成火焰图
$ FlameGraph/flamegraph.pl out.folded > out.svg
生成火焰图可以指定参数,–width 可以指定图片宽度,–height 指定每一个调用栈的高度,生成的火焰图,宽度越大就表示CPU耗时越多。FlameGraph/flamegraph.pl < out.profile > out.svg
[root@ip-172-31-18-198 timechart]# perf timechart record -g – curl http://localhost:19999[root@ip-172-31-18-198 timechart]# perf timechartWritten 0.0 seconds of trace to output.svg.
制造一个D进程Most proper way is to use freezer cgroup. It puts process to uninterruptible sleep in case of FROZEN cgroup state.
mkdir /sys/fs/cgroup/freezermount -t cgroup -ofreezer freezer /sys/fs/cgroup/freezermkdir /sys/fs/cgroup/freezer/frozenecho FROZEN > /sys/fs/cgroup/freezer/frozen/freezer.stateecho pidof you_process > /sys/fs/cgroup/freezer/frozen/tasksecho pgrep cp > /sys/fs/cgroup/freezer/frozen/tasksecho THAWED > /sys/fs/cgroup/freezer/frozen/freezer.state
To put again to interruptible sleep, just change cgroup state to THAWED.
动态追踪
添加一个动态追踪的Tracepoint Eventperf probe --add="probe:io_schedule_timeout"
perf probe --add="probe:io_schedule_timeout%return"
# 使用
perf record -e probe:tcp_sendmsg -a -g -- sleep 5
# 分析
perf report --stdio
移除一个动态追踪的Tracepoint Eventperf probe --del="probe:io_schedule_timeout"
perf probe -d "probe:io_schedule_timeout"
列出所有存在的probe perf probe -l
查看追踪的结果perf script
perf probe -V tcp_sendmsg # 列出可用的变量列表
perf probe --add 'tcp_sendmsg size' # 追踪这个变量
# Add a tracepoint for tcp_sendmsg() return, and capture the return value:
perf probe 'tcp_sendmsg%return $retval'
关于Off-cpu进程的分析
按步骤生成]$ /usr/share/bcc/tools/offcputime -df -p `pgrep -nx mysqld` 30 > out.stacks
[...copy out.stacks to your local system if desired...]
]$ git clone https://github.com/brendangregg/FlameGraph
]$ cd FlameGraph
]$ ./flamegraph.pl --color=io --title="Off-CPU Time Flame Graph" --countname=us < out.stacks > out.svg
一条命令出图 ]$ grep do_command < out.stacks | ./flamegraph.pl --color=io --title="Off-CPU Time Flame Graph" --countname=us > out.svg
Perf命令的常见参数
内核设置要启用内核动态追踪,需要使用内核编译参数CONFIG_KPROBES=y、CONFIG_KPROBE_EVENTS=y。要追踪基于帧指针的内核栈,需要内核编译参数CONFIG_FRAME_POINTER=y。要启用用户动态追踪,需要使用内核编译参数CONFIG_UPROBES=y、CONFIG_UPROBE_EVENTS=y
子命令列表
perf支持一系列的子命令:子命令 说明annotate 读取perf.data并显示被注解的代码bench 基准测试的框架config 在配置文件中读写配置项diff 读取perf.data并显示剖析差异evlist 列出perf.data中的事件名称inject 用于增强事件流的过滤器kmem 跟踪/度量内核内存属性kvm 跟踪/度量KVM客户机系统list 显示符号化的事件列表lock 分析锁事件mem 分析内存访问record 执行剖析report 显示剖析结果sched 分析调度器stat 获取性能计数top 显示成本最高的操作并动态刷新trace 类似于strace的工具probe 定义新的动态追踪点
perrf record 命令参数 --exclude-perf 不记录perf自己发起的事件
-p 收集指定进程的事件,逗号分割的PID列表
-a 使用Per-CPU模式,如果不指定-C,则相当于全局模式。如果指定-C,则可以选定若干CPU
-g 记录调用栈
-F 以指定的频率剖析
-T 记录样本时间戳
-s 记录每个线程的事件计数器,配合 perf report -T使用
微基准测试From youtube video:
root@HaydenArchDesktop /tmp# perf bench sched pipe
# Running 'sched/pipe' benchmark:
# Executed 1000000 pipe operations between two processes
Total time: 2.407 [sec]
2.407455 usecs/op
415376 ops/sec
root@HaydenArchDesktop /tmp# taskset -c 0 perf bench sched pipe
# Running 'sched/pipe' benchmark:
# Executed 1000000 pipe operations between two processes
Total time: 2.381 [sec]
2.381081 usecs/op
419977 ops/sec
# 这里的时间提升不明显的原因是, 我的Archlinux是ZenKernel, 感觉可能在调度上已经做了不少的事情 ,如果随便启动一个redhat , 这个指标的差距会比较大。
Sysctl 云平台参数的收集以及一部分解释
一些关于sysctl参数设置的收集和解释。
/etc/sysctl.d/00-defaults.confkernel.printk输出内核日志信息的级别。
# 映射到的proc文件系统位置 - /proc/sys/kernel/printk
# Maximize console logging level for kernel printk messages
kernel.printk = 8 4 1 7
# (1) 控制台日志级别:优先级高于该值的消息将被打印至控制台。
# (2) 缺省的消息日志级别:将用该值来打印没有优先级的消息。
# (3) 最低的控制台日志级别:控制台日志级别可能被设置的最小值。
# (4) 缺省的控制台:控制台日志级别的缺省值。
内核中共提供了八种不同的日志级别,在 linux/kernel.h 中有相应的宏对应。
#define KERN_EMERG "<0>" /* systemis unusable */
#define KERN_ALERT "<1>" /* actionmust be taken immediately */
#define KERN_CRIT "<2>" /*critical conditions */
#define KERN_ERR "<3>" /* errorconditions */
#define KERN_WARNING "<4>" /* warning conditions */
#define KERN_NOTICE "<5>" /* normalbut significant */
#define KERN_INFO "<6>" /*informational */
#define KERN_DEBUG "<7>" /*debug-level messages */
kernel.panic设置内核的Panic之后自动重启
# Wait 30 seconds and then reboot
kernel.panic = 30
neigh.default.gc设置arp缓存相关的参数https://zhuanlan.zhihu.com/p/94413312
# Allow neighbor cache entries to expire even when the cache is not full
net.ipv4.neigh.default.gc_thresh1 = 0
net.ipv6.neigh.default.gc_thresh1 = 0
# Avoid neighbor table contention in large subnets
net.ipv4.neigh.default.gc_thresh2 = 15360
net.ipv6.neigh.default.gc_thresh2 = 15360
net.ipv4.neigh.default.gc_thresh3 = 16384
net.ipv6.neigh.default.gc_thresh3 = 16384
# gc_thresh1
存在于ARP高速缓存中的最少层数,如果少于这个数,
垃圾收集器将不会运行。
缺省值是128。
# gc_thresh2
保存在 ARP 高速缓存中的最多的记录软限制。
垃圾收集器在开始收集前,允许记录数超过这个数字 5 秒。
缺省值是 512。
# gc_thresh3
保存在 ARP 高速缓存中的最多记录的硬限制,
一旦高速缓存中的数目高于此,
垃圾收集器将马上运行。
缺省值是1024。
/etc/sysctl.d/99-amazon.confsched_autogroup_enabled通过CFS分组提高了桌面环境的性能表现。这个小小的补丁仅为 Linux Kernel 增加了 233 行代码,却将高负荷下桌面响应最大延迟降低到原先的十分之一,平均延迟降低到六十分之一!该补丁的作用是为每个 TTY 动态地创建任务分组。(https://linuxtoy.org/archives/small-patch-but-huge-improvement.html)
# https://cateee.net/lkddb/web-lkddb/SCHED_AUTOGROUP.html
# https://www.postgresql.org/message-id/50E4AAB1.9040902@optionshouse.com
# This setting enables better interactivity for desktop workloads and not
# suitable for many server workloads.
# 启用后,内核会创建任务组来优化桌面程序的调度。它将把占用大量资源的应用程序放在它们自己的任务组,根据PostgreSQL的测试, 关闭这个选项会将数据库的性能提高30%(上面的Link)。 在后台的服务进程中是提高性能的选项。
# 0:禁止
# 1:开启
kernel.sched_autogroup_enabled=0
/usr/lib/sysctl.d/00-system.confBridge-nf-call-iptables网桥设备关闭netfilter模块,开关需要按需求来指定。关闭这个模块会在网桥2层可以转发的时候直接转发, 不会走三层进行数据传输,也就是说不会过Iptables。Kubernetes需要开启这个参数的原因是: https://imroc.cc/post/202105/why-enable-bridge-nf-call-iptables/, 修复了Coredns不定期解析失败的问题。
# Disable netfilter on bridges.
net.bridge.bridge-nf-call-ip6tables = 0
net.bridge.bridge-nf-call-iptables = 0
net.bridge.bridge-nf-call-arptables = 0
/usr/lib/sysctl.d/10-default-yama-scope.confYamaYama is a Linux Security Module that collects system-wide DAC security protections that are not handled by the core kernel itself. This is selectable at build-time with CONFIG_SECURITY_YAMA, and can be controlled at run-time through sysctls in /proc/sys/kernel/yama
https://www.kernel.org/doc/html/latest/admin-guide/LSM/Yama.html
[root@ip-172-31-11-235 sysctl.d]$ cat 10-default-yama-scope.conf
# When yama is enabled in the kernel it might be used to filter any user
# space access which requires PTRACE_MODE_ATTACH like ptrace attach, access
# to /proc/PID/{mem,personality,stack,syscall}, and the syscalls
# process_vm_readv and process_vm_writev which are used for interprocess
# services, communication and introspection (like synchronisation, signaling,
# debugging, tracing and profiling) of processes.
#
# Usage of ptrace attach is restricted by normal user permissions. Normal
# unprivileged processes cannot interact through ptrace with processes
# that they cannot send signals to or processes that are running set-uid
# or set-gid.
#
# yama ptrace scope can be used to reduce these permissions even more.
# This should normally not be done because it will break various programs
# relying on the default ptrace security restrictions. But can be used
# if you don't have any other way to separate processes in their own
# domains. A different way to restrict ptrace is to set the selinux
# deny_ptrace boolean. Both mechanisms will break some programs relying
# on the ptrace system call and might force users to elevate their
# priviliges to root to do their work.
#
# For more information see Documentation/security/Yama.txt in the kernel
# sources. Which also describes the defaults when CONFIG_SECURITY_YAMA
# is enabled in a kernel build (currently 1 for ptrace_scope).
#
# This runtime kernel parameter can be set to the following options:
# (Note that setting this to anything except zero will break programs!)
#
# 0 - Default attach security permissions.
# 1 - Restricted attach. Only child processes plus normal permissions ...
关于BTRFS的一些测试
创建BTRFS卷mkfs.btrfs -d single -m raid1 /dev/nvme1n1 /dev/nvme2n1 /dev/nvme3n1
更改btrfs的元数据冗余 这里最好的办法当然是创建的时候就规划和指定好。 btrfs balance start -dconvert=raid1 -mconvert=raid1 /mnt
创建轻量副本文件cp --reflink source dest
记录测试结果:
如果是 -d raid0 -m raid1 可以直接将三个EBS IO1 3000IOPS的卷吃满, 直接到9000
如果是 -d raid1 -m raid1 只能达到3000IOPS, 但是容量会有冗余。
Randread[global]
directory=/mnt
ioengine=libaio
direct=1
rw=randread
bs=16M
size=64M
time_based
runtime=20
group_reporting
norandommap
numjobs=1
thread
[job1]
iodepth=2
Result[root@ip-172-31-10-64 fio]# fio ./job1
job1: (g=0): rw=randread, bs=16M-16M/16M-16M/16M-16M, ioengine=libaio, iodepth=2
fio-2.14
Starting 1 thread
job1: Laying out IO file(s) (1 file(s) / 64MB)
Jobs: 1 (f=1): [r(1)] [100.0% done] [256.0MB/0KB/0KB /s] [16/0/0 iops] [eta 00m:00s]
job1: (groupid=0, jobs=1): err= 0: pid=26359: Thu Nov 18 07:59:17 2021
read : io=5232.0MB, bw=266745KB/s, iops=16, runt= 20085msec
slat (msec): min=1, max=70, avg=21.39, stdev=23.43
clat (msec): min=2, max=130, avg=101.29, stdev=31.01
lat (msec): min=8, max=139, avg=122.68, stdev=24.96
clat percentiles (msec):
| 1.00th=[ 7], 5.00th=[ 60], 10.00th=[ 63], 20.00th=[ 66],
| 30.00th=[ 93], 40.00th=[ 110], 50.00th=[ 118], 60.00th=[ 120],
| 70.00th=[ 122], 80.00th=[ 126], 90.00th=[ 127], 95.00th=[ 128],
| 99.00th=[ 130], 99.50th=[ 131], 99.90th=[ 131], 99.95th=[ 131],
| 99.99th=[ 131]
lat (msec) : 4=0.31%, 10=3.36%, 20=0.92%, 50=0.31%, 100=28.75%
lat (msec) : 250=66.36%
cpu : usr=0.04%, sys=3.80%, ctx=994, majf=0, minf=8193
IO depths : 1=0.3%, 2=99.7%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
issued : total=r=327/w=0/d=0, short=r=0/w=0/d=0, drop=r=0/w=0/d=0
latency : target=0, window=0, percentile=100.00%, depth=2
Run status group 0 (all jobs):
READ: io=5232.0MB, aggrb=266744KB/s, minb=266744KB/s, maxb=266744KB/s, mint=20085msec, maxt=20085msec
Randwrite[global]
directory=/mnt
ioengine=libaio
direct=1
rw=randread
bs=16M
size=64M
time_based
runtime=20
group_reporting
norandommap
numjobs=1
thread
[job1]
iodepth=2
Result[root@ip-172-31-10-64 fio]# fio ./job1
job1: (g=0): rw=randwrite, bs=16M-16M/16M-16M/16M-16M, ioengine=libaio, iodepth=2
fio-2.14
Starting 1 thread
Jobs: 1 (f=1): [w(1)] [100.0% done] [0KB/256.0MB/0KB /s] [0/16/0 iops] [eta 00m:00s]
job1: (groupid=0, jobs=1): err= 0: pid=26385: Thu Nov 18 08:00:56 2021
write: io=5248.0MB, bw=267987KB/s, iops=16, runt= 20053msec
slat (msec): min=1, max=67, avg=12.64, stdev=21.62
clat (msec): min=12, max=141, avg=109.45, stdev=31.98
lat (msec): min=18, max=142, avg=122.10, stdev=25.25
clat percentiles (msec):
| 1.00th=[ 16], 5.00th=[ 23], 10.00th=[ 66], 20.00th=[ 72],
| 30.00th=[ 120], 40.00th=[ 124], 50.00th=[ 126], 60.00th=[ 127],
| 70.00th=[ 128], 80.00th=[ 130], 90.00th=[ 133], 95.00th=[ 135],
| 99.00th=[ 139], 99.50th=[ 139], 99.90th=[ 141], 99.95th=[ 141],
| 99.99th=[ 141]
lat (msec) : 20=4.57%, 50=0.91%, 100=19.21%, 250=75.30%
cpu : usr=1.51%, sys=0.82%, ctx=720, majf=0, minf=1
IO depths : 1=0.3%, 2=99.7%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
issued : total=r=0/w=328/d=0, short=r=0/w=0/d=0, drop=r=0/w=0/d=0
latency : target=0, window=0, percentile=100.00%, depth=2
Run status group 0 (all jobs):
WRITE: io=5248.0MB, aggrb=267987KB/s, minb=267987KB/s, maxb=267987KB/s, mint=20053msec, maxt=20053msec
Xfs 单独磁盘Randwrite[root@ip-172-31-10-64 fio]# fio ./job1
job1: (g=0): rw=randwrite, bs=16M-16M/16M-16M/16M-16M, ioengine=libaio, iodepth=2
fio-2.14
Starting 1 thread
job1: Laying out IO file(s) (1 file(s) / 64MB)
Jobs: 1 (f=1): [w(1)] [100.0% done] [0KB/128.0MB/0KB /s] [0/8/0 iops] [eta 00m:00s]
job1: (groupid=0, jobs=1): err= 0: pid=26541: Thu Nov 18 08:04:01 2021
write: io=2704.0MB, bw=137688KB/s, iops=8, runt= 20110msec
slat (msec): min=12, max=130, avg=118.63, stdev=24.61
clat (msec): min=12, max=130, avg=118.91, stdev=23.73
lat (msec): min=34, max=255, avg=237.54, stdev=47.53
clat percentiles (msec):
| 1.00th=[ 14], 5.00th=[ 32], 10.00th=[ 125], 20.00th=[ 125],
| 30.00th=[ 125], 40.00th=[ 125], 50.00th=[ 125], 60.00th=[ 126],
| 70.00th=[ 126], 80.00th=[ 126], 90.00th=[ 126], 95.00th=[ 126],
| 99.00th=[ 129], 99.50th=[ 131], 99.90th=[ 131], 99.95th=[ 131],
| 99.99th=[ 131]
lat (msec) : 20=1.78%, 50=3.55%, 100=0.59%, 250=94.08%
cpu : usr=0.74%, sys=0.49%, ctx=2132, majf=0, minf=1
IO depths : 1=0.6%, 2=99.4%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
submit ...
Fio 命令使用的说明
Fio 一些测试和思考, fio ,blktrace等等。
Github地址 https://github.com/axboe/fio https://tobert.github.io/post/2014-04-17-fio-output-explained.html http://xiaqunfeng.cc/2017/07/12/fio-test-ceph/ https://fio.readthedocs.io/en/latest/fio_doc.html http://linuxperf.com/?p=156
命令和说明# fio test file defination
# ini file format
; -- start job file --
[global]
size=1G # 设置测试文件的大小
runtime=30 # 设定运行时间, 如果运行时间之内已经完成了文件大小的写入则会保持文件大小和负载继续写。
bs=4k # 块大小
numjobs=1 # 定义测试的进程数量 默认是1
direct=1 # 是否绕过操作系统的Buffer缓冲区, 1 Enable
ioengine=libaio # io引擎使用libaio模式, 查看可用IO引擎的命令
group_reporting # 汇总信息显示
thread # 使用单进程多线程的模型, 默认是使用多进程模型。
time_based # 用运行时间为基准, 如果时间没有到达指定的值就继续执行相同的操作, 直接到时间满足要求。
[job1]
rw=write
[job2]
rw=read
[job3]
rw=randwrite
[job4]
rw=randread
[job5]
rw=randrw
; -- end job file --
关于硬盘性能 Iostat首先, 在man iostat的时候已经明确的提示了,iostat 的 svctm (也就是硬盘的servicetime)是一个不准确的值, 会在后续的版本中移除, 因为他所依赖的数据来源(/proc/diskstats)中,是从Block Level 出发来进行计算的, 所以svctm其实并不是IO控制器所需要的准确时间, 那么出现了两个问题, 我们能观察的数据是那个? 以及背后的含义是什么?
调度算法 和 读写请求的合并内核会对IO的请求进行合并, 但是这个合并不是一直存在的, 反映到IOstat的指标是 rrqm/s & wrqm/s, 这两个表示对于硬盘的读写请求中, 每秒合并的请求数量; 如果你去查看IO的调度算法, none 算法是完全不合并的, 所以这两列一直都是0.
队列的等待时间iostat中的await一列, 表示请求的等待时间,正常的情况下应该比较低,那么究竟什么情况下才是性能不佳的表现?await 每个I/O的平均耗时是用await表示(blktrace command results: Q2C – 整个IO请求所消耗的时间(Q2I + I2D + D2C = Q2C),相当于iostat的await。),包括了 IO请求在Kernel中的等待时间 + IO请求从内核出发处理完成回到内核的时间,也就是IO time + Service Time。await 一般情况下应该小于10ms , 如果没有或者比较大的情况下 , 应该考虑负载的类型, 来衡量硬盘的负载水平。
Blktrace一个I/O请求进入block layer之后,可能会经历下面的过程:
Q Remap: 可能被DM(Device Mapper)或MD(Multiple Device, Software RAID) remap到其它设备
G Split: 可能会因为I/O请求与扇区边界未对齐、或者size太大而被分拆(split)成多个物理I/O
I Merge: 可能会因为与其它I/O请求的物理位置相邻而合并(merge)成一个I/O
D 被IO Scheduler依照调度策略发送给driver
C 被driver提交给硬件,经过HBA、电缆(光纤、网线等)、交换机(SAN或网络)、最后到达存储设备,设备完成IO请求之后再把结果发回。
常见的状态切换 Q–G–I–D–C
259,2 0 2 0.000001080 7134 Q W 756856 + 800 [dd]
259,2 0 3 0.000004247 7134 X W 756856 / 757368 [dd]
259,2 0 4 0.000005806 7134 G W 756856 + 512 [dd]
259,2 0 5 0.000008792 7134 I W 756856 + 512 [dd]
259,2 0 6 0.000012844 7134 G W 757368 + 288 [dd]
259,2 0 7 0.000013202 7134 I W 757368 + 288 [dd]
259,2 0 8 0.000031708 1830 D W 756856 + 512 [kworker/0:1H]
259,2 0 9 0.000034250 1830 D W 757368 + 288 [kworker/0:1H]
259,2 0 10 0.001598439 7135 C W 756856 + 512 [0]
259,2 0 11 0.001689880 7135 C W 757368 + 288 [0]
# 主,从设备号 , 起始Sector 为0 , 写几个, 时间 , pid , 状态 , R/W , 未知
保留blktrace的结果为bin文件
blktrace -d /dev/sdb
使用blkparse 分析已经有的记录
# 记录性能数据 到 文件。
root@ip-172-31-11-235:/home/ec2-user|⇒ blktrace -d /dev/nvme0n1p1
^C=== nvme0n1p1 ===
CPU 0: 1 events, 1 KiB data
CPU 1: 0 events, 0 KiB data
Total: 1 events (dropped 0), 1 KiB data
# 每个cpu设备每个设备存储一个单独的文件。
root@ip-172-31-11-235:/home/ec2-user|⇒ ll
total 4.0K
-rw-r--r-- 1 root root 56 Nov 4 17:55 nvme0n1p1.blktrace.0
-rw-r--r-- 1 root root 0 Nov 4 17:55 nvme0n1p1.blktrace.1
root@ip-172-31-11-235:/home/ec2-user|⇒ blkparse -i nvme0n1p1.blktrace.0
# 格式化分析的数据为bin。
root@ip-172-31-11-235:/home/ec2-user|⇒ blkparse -i nvme0n1p1 -d nvme0n1p1.blktrace.bin
# 使用一个简易的图形方式分析结果。
root@ip-172-31-11-235:/home/ec2-user|⇒ btt -i nvme0n1p1.blktrace.bin
历史背景
mdadm 已经不怎么更新和开发了默认推荐使用LVMLVM 和 mdadm 在操作系统都是使用的Raid驱动(内核模块)。
其实也是可以使用btrfs , 这个测试的结果是 btrfs 的实现和管理成本比 LVM 要少的多。
相关的问题如果说有一个性能的问题, IOPS达不到指定的数值, 思路?首先查看队列深度是不是足够,看svctm时间长不长,看队列长度
/sys/block/sda/nr_requests
Iostat命令的理解iostat -xkt 1rrqm/s wrqm/s - 读写请求的合并数量r/s w/s - 读写请求数量avgrq - 队列长度await - 时延util - 时间度量 , 时间周期之内进行IO操作所占的比例。例如 1 秒的时间之内, 取样的点中有多少是在执行IO操作。
一个例子 , 如果采样的周期为1s, 那么采样的范围之内 , 前面的0.5秒有执行IO的操作, 后面的0.5秒没有执行任何的操作, 那么 最后 Util 现在的结果就是50% 。avgrq也是一直平均值, 在采样周期之内如果前后的状况不一致 也会进行平均。
一般情况下这个参数是准确的,但是大部分指标都是取决于监控取样周期的。
操作系统默认输出的块大小是 : 256 , 参数可见 :╰─# cat /sys/block/sda/queue/max_sectors_kb256
max_segments表示设备能够允许的最大段的数目。 – 这应该是一个内存或者buffer的分段指标。 (待定)max_sectors_kb表示设备允许的最大请求大小。 – 可改 。max_hw_sectors_kb表示单个请求所能处理的最大KB(硬约束) – 这个是上一个参数的Limit。
Shell脚本处理目录或者文件名中的空格
问题:问题是: 罗列指定的目录下面的文件, 符合要求的文件保留, 未匹配的删除。
解决:简单的Bash脚本, 使用ls拿文件名, 使用For + IF判断即可。但是文件的目录中有的文件名是带有空格的, 而Shell 使用空格做分隔符,因此无法正确的处理完整的文件名。解决方案有特别多, 只记录一个我最后使用的方案:使用IFS变量来定义Shell 的默认分隔符, 将空格替换成\n\b.
#!/bin/bash
#
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
for number in {1..10}
do
mkdir -pv "dir $number"
done
tree
FILE=`ls`
for i in $FILE;
do
echo "The DirName: $i"
done
IFS=$SAVEIFS
这样就可以拿到名称为dir 1的完整目录名字了,否则会默认吧空格分割的文件名称作为两个目录提取。
⚡ ./delete.sh
.
├── delete.sh
├── dir 1
├── dir 10
├── dir 2
├── dir 3
├── dir 4
├── dir 5
├── dir 6
├── dir 7
├── dir 8
└── dir 9
10 directories, 1 file
The DirName: delete.sh
The DirName: dir 1
The DirName: dir 10
The DirName: dir 2
The DirName: dir 3
The DirName: dir 4
The DirName: dir 5
The DirName: dir 6
The DirName: dir 7
The DirName: dir 8
The DirName: dir 9
Linux中一些常见的性能分析命令
记录性能分析的思路。
最近的这个半年越来越好奇的事情是, 为什么命令会卡住,为什么命令会执行不下去,为什么命令会等待,等等等等。
那么这些问题, 有的是可以有答案的, 目前也不知道的。
已经大概掌握的几个不同的方法以及观测的工具, 大概做一个记录。
Strace命令Strace 命令的常见用法strace命令是用来追踪系统调用的,常见的可以追踪的系统调用需要阅读内核部分的代码。 但是常见的系统调用就是集中, read() , write() , ioctl(), futex() , mmap()大部分的时候 我们都是可以观测到卡住的部分的 , 这种追踪我认为常见的使用场景就是命令卡住了, 或者执行中的程序卡住了。
命令卡住的分析对于命令卡住的情况, 可以使用类似于如下的命令:
strace -f -ttt -s 512 echo "123"
这样的话, 在执行的过程中就可以查看相关的内容,比如常见的卡在了系统调用的某个函数上, 这个可以用来定位,命令打开了那些文件,申请的那些内存地址,打开了什么文件,关闭Socket等等等等。目前我的办法的通过对比这个卡住的命令执行到什么函数出现的问题, 对应的在正常的机器上进行对比,就可以猜到大概的问题出现在了哪里。
已经运行中的程序分析strace -f -ttt -s 512 -p 123
执行进程的PID , 然后strace会attach到进程上, 输出的内容, 也可以查看到当前程序的运行状态。
总结如上面的两种方式,都可以对运行中明显的问题进行观察, 但是如果没有卡在系统调用的部分, 通过这个命令的观察其实是无法查看的, 因为他记录的是应用程序指令陷入到内核态的部分, 但是常见的应用程序基本上都是用户态的,所以这个部分如果是应用卡在用户态上, 观测的信息就比较有限了。
Perf命令Perf简单的分析perf命令的简单分析, 首先是
perf topperf top 可以用来实时的查看应用程序的相关问题, 收集指标的范围是整个操作系统,所以是比较消耗资源的, 输出的结果也是直接可以查看的, 看完了结果打断即可。
perf statperf stat 查看相关的统计信息,如下是一个样例,提供了一些静态的指标。
sudo perf stat
Performance counter stats for 'system wide':
61,167.25 msec cpu-clock # 16.000 CPUs utilized
4,955 context-switches # 81.007 /sec
63 cpu-migrations # 1.030 /sec
930 page-faults # 15.204 /sec
6,266,524,215 cycles # 0.102 GHz (83.32%)
244,046,608 stalled-cycles-frontend # 3.89% frontend cycles idle (83.34%)
66,809,179 stalled-cycles-backend # 1.07% backend cycles idle (83.34%)
818,170,826 instructions # 0.13 insn per cycle
# 0.30 stalled cycles per insn (83.34%)
155,602,840 branches # 2.544 M/sec (83.34%)
1,701,804 branch-misses # 1.09% of all branches (83.33%)
3.823037998 seconds time elapsed
显示的内容是从输入了命令之后的相关信息,主要是一些CPU相关的指标, 比如CPU时钟,上下文交换次数,cpu转移,缺页中断等等等等。
perf recordperf record 我常用的命令是这样的, 他会将记录到的指标输出到当前目录的文件中,然后供report命令来进行分析, 这两个一般来说会合用。
perf record -a -g -F 1000 -p 123
perf record -a -g -F 1000 echo 123
perf record -a -g -F 1000
perf record -a -g -F 1000 -- sleep 60
三个命令会记录相关的指标到当前目录的perf.data文件中。 大小和采样的频率,时间的数量有关。
perf reportperf report 我比较常用的参数就是 使用
perf record --stdio
来直接进行查看, 占用时间百分比比较高的函数,前提是 ,这个命令的运行需要有perf.data.
perf schedperf sched 通常是用来查看cpu调度延时的, 这个用的确实不多, 毕竟cpu调度现在基本上都是cfq, 改的人毕竟还是少数, 所以实际的使用比较少。这个指令常用的如下:
perf sched record
perf sched latency
perf sched report
上面的这些都是我比较常用的命令, 临时抓出来看下。
Perf命令输出火焰图perf 命令输出火焰图需要的是Github上面的一个项目, 这个项目的作者也是写性能之巅的作者。
具体的处理流程如下:
git clone --depth 1 https://github.com/brendangregg/FlameGraph.git
sudo perf script > out.perf
FlameGraph/stackcollapse-perf.pl out.perf > out.folded
FlameGraph/flamegraph.pl out.folded > out.svg
最后输出的out.svg就是结果了,可以通过浏览器来查看。至于查看的方法,其实是看函数所占有的面积, 面积越大说明函数运行的时间越长;那么还有说法是说, 越靠近顶端的应该越尖,如果有顶端比较大的平顶说明可能是有问题的, 这个答案还在求证中。
Kubernetes day2
对于etcd的操作和备份
Etcd的操作 - EtcdctlEtcd的规划
最好用 固态盘, Pod数量比较多的情况下会非常非常慢, 内存要大.
类似于redis 或者 Zookeeper, KV的存储.
支持watch机制,可以通知给node节点的数据变化.
etcd consul zookeeper 的区别
名称
优点
缺点
接口
一致性算法
zookeeper
1.功能强大,不仅仅只是服务发现2.提供watcher机制能实时获取服务提供者的状态3.dubbo等框架支持
1.没有健康检查2.需在服务中集成sdk,复杂度高3.不支持多数据中心
sdk
Paxos
consul
1.简单易用,不需要集成sdk2.自带健康检查3.支持多数据中心4.提供web管理界面
1.不能实时获取服务信息的变化通知
http/dns
Raft
etcd
1.简单易用,不需要集成sdk2.可配置性强
1.没有健康检查2.需配合第三方工具一起完成服务发现3.不支持多数据中心
http
Raft
Etcdctl 的命令
查看etcd的成员清单
]$ etcdctl --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/kubernetes/ssl/kubernetes.pem --key=/etc/kubernetes/ssl/kubernetes-key.pem --write-out=table --endpoints="192.168.31.21:2379,192.168.31.22:2379,192.168.31.23:2379" member list
查看etcd的节点状态
]$ etcdctl --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/kubernetes/ssl/kubernetes.pem --key=/etc/kubernetes/ssl/kubernetes-key.pem --endpoints="192.168.31.21:2379,192.168.31.22:2379,192.168.31.23:2379" endpoint status -w table
查看etcd存储的数据
]$ etcdctl --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/kubernetes/ssl/kubernetes.pem --key=/etc/kubernetes/ssl/kubernetes-key.pem --endpoints="192.168.31.21:2379,192.168.31.22:2379,192.168.31.23:2379" get /registry/ --prefix --keys-only | head
查看etcd中的pod信息
]$ etcdctl --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/kubernetes/ssl/kubernetes.pem --key=/etc/kubernetes/ssl/kubernetes-key.pem --endpoints="192.168.31.21:2379,192.168.31.22:2379,192.168.31.23:2379" get /registry/ --prefix --keys-only | grep pod
其他的操作
get / put / del 等基础操作
Watch机制watch机制是通过不断的查看数据,发生变化就主动的通知客户端,v3支持watch固定的key,也可以watch一个范围的数据。
# watch 一个pod的信息, 然后手动delete这个pod , 查看etcd 的watch行为和输出的结果。
]$ etcdctl --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/kubernetes/ssl/kubernetes.pem --key=/etc/kubernetes/ssl/kubernetes-key.pem --endpoints="192.168.31.21:2379,192.168.31.22:2379,192.168.31.23:2379" watch /registry/pods/monitoring/node-exporter-889hf
数据备份恢复和WAL日志WAL: watch ahead log - 预写日志, 可以通过预写日志来进行数据库的恢复。WAL记录了整个数据变化的过程,在操作写入数据之前先进行wal日志的写入。
etcd v2 的时候直接复制和备份目录,备份文件的方案etcd v3 的备份和恢复, 使用快照的方式。
备份使用的命令和恢复的命令不太一样, etcdctl vs etcdutl
可以写脚本来进行数据进行备份和恢复。
]$ etcdctl snapshot save
]$ etcdctl snapshot restore
]$ etcdctl snapshot status
]$ etcdctl --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/kubernetes/ssl/kubernetes.pem --key=/etc/kubernetes/ssl/kubernetes-key.pem --endpoints="192.168.31.21:2379" snapshot save snap-20211002.db
# 测试尝试恢复到临时的目录,测试用。 目录地址用的是tmp下面的。
]$ etcdutl snapshot restore ./snap-20211002.db --data-dir /tmp/etcd-restore
2021-10-02T12:01:13+08:00 info snapshot/v3_snapshot.go:251 restoring snapshot {"path": "./snap-20211002.db", "wal-dir": "/tmp/etcd-restore/member/wal", "data-dir": "/tmp/etcd-restore", "snap-dir": "/tmp/etcd-restore/member/snap", "stack": "go.etcd.io/etcd/etcdutl/v3/snapshot.(*v3Manager).Restore\n\t/tmp/etcd-release-3.5.0/etcd/release/etcd/etcdutl/snapshot/v3_snapshot.go:257\ngo.etcd.io/etcd/etcdutl/v3/etcdutl.SnapshotRestoreCommandFunc\n\t/tmp/etcd-release-3.5.0/etcd/release/etcd/etcdutl/etcdutl/snapshot_command.go:147\ngo.etcd.io/etcd/etcdutl/v3/etcdutl.snapshotRestoreCommandFunc\n\t/tmp/etcd-release-3.5.0/etcd/release/etcd/etcdutl/etcdutl/snapshot_command.go:117\ngithub.com/spf13/cobra.(*Command).execute\n\t/home/remote/sbatsche/.gvm/pkgsets/go1.16.3/global/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:856\ngithub.com/spf13/cobra.(*Command).ExecuteC\n\t/home/remote/sbatsche/.gvm/pkgsets/go1.16.3/global/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:960\ngithub.com/spf13/cobra.(*Command).Execute\n\t/home/remote/sbatsche/.gvm/pkgsets/go1.16.3/global/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:897\nmain.Start\n\t/tmp/etcd-release-3.5.0/etcd/release/etcd/etcdutl/ctl.go:50\nmain.main\n\t/tmp/etcd-release-3.5.0/etcd/release/etcd/etcdutl/main.go:23\nruntime.main\n\t/home/remote/sbatsche/.gvm/gos/go1.16.3/src/runtime/proc.go:225"}
2021-10-02T12:01:13+08:00 info membership/store.go:119 Trimming membership information from the backend...
2021-10-02T12:01:13+08:00 info membership/cluster.go:393 added member {"cluster-id": "cdf818194e3a8c32", "local-member-id": "0", "added-peer-id": "8e9e05c52164694d", "added-peer-peer-urls": ["http://localhost:2380"]}
2021-10-02T12:01:13+08:00 info snapshot/v3_snapshot.go:272 restored snapshot {"path": "./snap-20211002.db", "wal-dir": "/tmp/etcd-restore/member/wal", "data-dir": "/tmp/etcd-restore", "snap-dir": "/tmp/etcd-restore/member/snap"}
]$ ls /tmp/etcd-restore/
member
数据恢复的流程:
创建新的etcd集群
停止kubernetes以及其他的依赖etcd 的服务。
停止空白的新的集群
使用备份的文件进行集群的恢复
使用在集群的每个节点恢复相同的备份文件
每个节点启动etcd的集群并且进行验证
启动Kubernetes的相关集群和组件。
查看恢复的结果,验证各个组件的相关服务是否已经正常恢复。
Etcd节点的维护
etcdctl add-etcd
etcdctl del-etcd
资源清单以及API相关的外部服务接口
Container Runtime Interface - CRI
runc
RKT
Container Storage Interface - CSI
Container Network Interface - CNI
Node的相关操作
cordon
uncordon
drain
taint
Harbor Http 安装部署
Harbor的部署记录。
Harbor Info
Harbor 项目地址
Harbor HTTP部署因为是临时使用, 所以直接给了HTTP的权限, 为的是不走公网部署 CEPH Cluster, CEPH在BootStrap之后会默认去公网的镜像仓库尝试Pull镜像并且校验镜像和服务,所以给一个私有的仓库, 直接去找私有仓库就免了公网访问卡集群的正常启动的步骤。
下载解压~]$ wget https://github.com/goharbor/harbor/releases/download/v2.3.2/harbor-offline-installer-v2.3.2.tgz
~]$ mv harbor-offline-installer-v2.3.2.tgz /opt
~]$ tar zxvf /opt/harbor-offline-installer-v2.3.2.tgz
复制修改配置文件~]$ cp /opt/harbor/harbor.yml.tmpl /opt/harbor/harbor.yml
配置默认的存储位置# 注释掉https的部分,如果需要https的话签发一个证书写路径在配置文件中
# 修改默认的存储位置
data_volume: /opt/harbor/image_store
指定Harbor对外提供服务的域名# 修改Harbor的域名或者主机名(需要对应的解析),也可以直接使用IP地址
# The IP address or hostname to access admin UI and registry service.
# DO NOT use localhost or 127.0.0.1, because Harbor needs to be accessed by external clients.
hostname: harbor.local
设置harbor Admin的密码可以登录Dashboard 或者 Pull镜像
# Remember Change the admin password from UI after launching Harbor.
harbor_admin_password: Harbor12345
创建harbor存储镜像的目录# 创建Harbor的存储目录, 可以远程指定到Cephfs上面
~]$ mkdir /opt/harbor/image_store
配置Docker-ce 清华的镜像源这个配置是给Centos / RHEL来使用的,来自清华的Repo Help
# 添加repo文件,和修改配置到Tsinghua repo
~]$ wget -O /etc/yum.repos.d/docker-ce.repo https://download.docker.com/linux/centos/docker-ce.repo
~]$ sudo sed -i 's+download.docker.com+mirrors.tuna.tsinghua.edu.cn/docker-ce+' /etc/yum.repos.d/docker-ce.repo
# 安装Docker-ce
~]$ sudo yum install docker-ce
# CENTOS8 STREAM 特殊的配置,需要卸载 podman 和 Buildah
~]$ dnf install -y docker-ce --allowerasing
# 开机启动
~]$ sudo systemctl restart docker && sudo systemctl enable docker
# 安装Docker-compose ,因为CentOS8 默认是没有Docker-compose的 , 按照官网的流程走就可以。
~]$ sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
~]$ sudo chmod +x /usr/local/bin/docker-compose
~]$ sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
安装harbor~]$ cd /opt/harbor
/opt/harbor]$ ./install.sh
启动Harbor直接使用Docker-compose启动即可,如果需要的话可以在配置文件中指定镜像扫描器,来进行镜像的漏洞扫描。
# 进入Harbor运行所在的目录
~]$ cd /opt/harbor
# 使用Docker-compose的启动命令,适用于服务停止 或者 Docker 重启的时候, 容器没有正常运行。
~]$ docker-compose up -d -f /opt/harbor/docker-compose.yaml
# 查看容器的启动状态
/opt/harbor]$ docker-compose ps
/opt/harbor]$ watch -n 1 docker-compose ps
# 通过Docker-compose停止harbor
/opt/harbor]$ docker-compose down
验证
打开浏览器,访问harbor的地址 默认的端口80
在所有docker节点上配置不安全的私有仓库,docker login [HARBORIP:PORT]
在所有podman节点上配置不安全的私有仓库,podman login [HARBORIP:PORT]
提示Login Successed, 登录成功,可以正常pull镜像了
Cephadm Bootstrap编辑cephadm文件,修改如下的镜像名称,和仓库的前缀这里其实还是需要再测试的, 按照这个脚本的逻辑, 应该会把所有的镜像都从指定的仓库Pull下来,但是我执行的时候只有ceph/ceph:v16一个镜像下来了, 感觉还是有点儿问题的。
DEFAULT_IMAGE = 'harbor.local/ceph/ceph:v16'
DEFAULT_IMAGE_IS_MASTER = False
DEFAULT_IMAGE_RELEASE = 'pacific'
DEFAULT_PROMETHEUS_IMAGE = 'harbor.local/ceph/prometheus:v2.18.1'
DEFAULT_NODE_EXPORTER_IMAGE = 'harbor.local/ceph/node-exporter:v0.18.1'
DEFAULT_ALERT_MANAGER_IMAGE = 'harbor.local/ceph/alertmanager:v0.20.0'
DEFAULT_GRAFANA_IMAGE = 'harbor.local/ceph/ceph-grafana:6.7.4'
DEFAULT_HAPROXY_IMAGE = 'harbor.local/ceph/haproxy:2.3'
DEFAULT_KEEPALIVED_IMAGE = 'harbor.local/ceph/keepalived'
DEFAULT_REGISTRY = 'harbor.local' # normalize unqualified digests to this
Cephadm 使用私有仓库bootstrap~]$ cephadm bootstrap --mon-ip 192.168.1.211 --allow-overwrite \
--registry-url harbor.local \
--registry-username admin \
--registry-password Harbor12345
查看并且清除ceph-bootstrap的历史记录~]$ ls /etc/systemd/system/ceph*
~]$ ls /usr/lib/systemd/system/ceph*
~]$ rm -rf /etc/systemd/system/ceph*
~]$ rm -rf /usr/lib/systemd/system/ceph*
~]$ docker stop `docker ps -a -q`