测试知识进阶
服务器
-
云服务器 + 微服务 + docker -----基本是标配
-
linux + springcould + docker
- windows: 最开始的时候,主流的服务器的操作系统,确实是windows
- windows server 2003 图像界面 windows98
- windows: 最开始的时候,主流的服务器的操作系统,确实是windows
-
linux:
- 命令行: 运行效率高, 对于用户交互,不是很好
- 1、命令行,运行效率要高,
- 2、资源占用少
- 3、安全与稳定性比较
- 4…
- 图像界面linux, 不会用于服务器
- 命令行: 运行效率高, 对于用户交互,不是很好
-
有没有一个误区?
- 我一开始就给大家 讲 服务器
- 结果 我一上来 linux
- 难道 服务器就是linux系统 Linux系统就是服务器?----这个是错误的!!!
-
服务器 : 在一些硬件 + 操作系统 + 应用程序 ===输出 应用能力输出
- 缩小到我们的 IT行业中,我们要讲服务器: 这三个都要讲 + 三者的集成
- 我们要写书:
- 1支笔写不下, 2.4.5.6.7.8 才能把这本书写下来 ------堆硬件
- 我把书,拆开成多个章节, 每个章节分给不同的人,不同时间来写--------加快这本书的成型速度—分工合作
- 再精细分工
-
服务器:
- 服务器的演变,其实就是我们不断追求高性能,高性价比的一个结果。
- 服务器一:
- 单一服务器、 应用服务和数据库服务分离、 应用服务与文件服务器分离+ 数据库服务器
- linux
- 应用程序:程序本身 + 架构
- 服务器二:
- 服务器三:
- 服务器四:
-
Linux
- centos、ubuntu、suse、redhat、debain、deepin
- debian家族: ubuntu
- 安装命令: apt apt-get
- .deb
- fedora家族: centos
- yum dnf
- .rpm包
- 统一的安装命令
- tar.gz 安装包
- 安装时,依赖 gcc 但是 不一定会安装 可能需要手工安装
- make
linux: centos 7
-
无图像界面的服务器,一般才会作为 服务器
-
通过客户端 xshell、putty、cmd、finalshell
- 客户端工具要能连接到linux机器上,机器必须开发ssh服务,这个服务端口22
- centos系统默认是安装了ssh服务,开放了22端口
- ubuntu系统 默认没有安装ssh服务,所以,ubuntu这种图像界面系统,有时候不能通过客户端来连接。
- 你想要连接到一台服务器上:
- 1、服务器必须启动ssh服务,
- 2、服务器要开放ssh服务的端口
- 3、你本地与服务器之间网络要能通
- 检查: telnet server_ip 22
-
linux 的根路径
- /boot 核相关文件
- /bin 存放系统中可用的命令
- /etc 系统管理所需要的所有配置文件
- /usr unix shared resource 用户共享程序文件夹
- /opt optional 给主机额外安装的软件目录 相当于window d盘
- /home 它用户目录,它下一级文件夹,默认是被系统当作用户名的根路径
- 在企业中,你们操作服务器,一般会给你们非root权限的账号,那这个账号,肯定会在/home目录下面有一个文件夹,文件夹的名称是你的用户名,你的所有操作权限,都受这个用户的权限控制,所以你默认的操作都是在这个路径下
- /sys
- /proc process进程,虚拟文件系统,存储当前内核运行状态的特殊文件
- cpuinfo: 记录着系统在启动时,读取的cpu相关信息
- meminfo: 记录着系统在启动时,读取的memory相关信息
- 数字: 都是进程的id pid 进入这个文件夹,可以查看这个进程启动时相关信息
- /var 不断扩充的东西,如日志
- /var/log/你的程序名称 日志文件
sda:我们用虚拟机方式产生的硬盘,都是sd盘,其实就是 机械硬盘
hd是固态, 他们的区别是,接口不一样
a\b\c… 第几个硬盘
a1\a2\a3… 第1个硬盘的第几个分区
sda1:
-
ls -lth
- d 目录 l 链接 - 文件
- 每3个一组: r读 w写 x执
-
安装:
- fedora家族
- centos
- 可执行文件 rpm
- rmp -ivh *.rpm
- yum
- debain家族
- ubuntu
- 可执行文件 deb
- dpkg -i *.deb
- apt apt-get
- fedora家族
-
获取命令的帮助:
- 第一种: command –help
- 第二种:man command 获取比上面更多的帮助
- 第三种: info command
linux性能分析命令
- 第1个 top\ htop\ atop
- top 查看系统进程的资源使用情况, 也可以查看线程
- top - 21:28:23 up 1:30, 3 users, load average: 0.00, 0.01, 0.05
- 3 users : 当前系统有几个用户连接进来, 这个用户,可以是同一个user
- load average: 0.00, 0.01, 0.05 系统瓶颈负载值
- 第1个: 系统过去1分钟系统的平均负载值
- 第2个:系统过去5分钟系统的平均负载值
- 第3个:系统过去15分钟系统的平均负载值
- 系统负载值,不等于cpu使用率值。因为系统的负载值,它主要由两部分组成: cpu的使用率 + io使用率
- 历史的经验,系统负载高低,与cpu的数量有一定关系。
- io:换入 换出
- cpu使用率高: us sy ni hi si
- us:用户态使用cpu的时间占比
- sy: 系统态 在cpu的内核中进行计算消耗的时间占比
- ni:优先级切换
- hi:hard interrupt 硬中断 中断会导致时间浪费,也会导致资源占用升高
- si:soft interrupt 软中断
- wa: wait 等待 等待资源
- st: 管理者占用资源
- id: 休闲
- 以后,不要说系统负载值大于cpu数量,就一定负载高。
- load average: 0.00, 0.01, 0.05 如何知道我们现在系统的负载情况?
- 看第1个值 是上升趋势,还是下将======我们现在系统负载正在上升,可能还会继续上升
- 第1个值小于第二值,现在系统负载正在下降,再过一段时间可能会恢复正常。
- 数字 1 可以看到cpu的数量, 核数
- Tasks: 112 total, 1 running, 111 sleeping, 0 stopped, 0 zombie
- Tasks进程数:Threads: 可以按 H 来切换为线程
- 任务列表中, S列 对应
- S sleep
- R running
- T stoped
- Z zombie
- 任务列表中, S列 对应
- Tasks进程数:Threads: 可以按 H 来切换为线程
- Mem : 1881936 total, 808532 free, 468140 used, 605264 buff/cache
KiB Swap: 4063228 total, 4063228 free, 0 used. 1255740 avail Mem - buff/cache: 缓存
- buffer 缓冲区
- cache 缓存
- swap: 交互分区
- vmstat
- pidstat
- iostat
- netstat
- sar…
load average
-
Task Thread 两个数字不相同, Thread数字大于Task数字, 因为 一个进程可能有多个线程
-
top命令中按数字1可以看到 多个核,每个核的cpu的使用情况
- 在没有按1, 在我们用监控工具\平台来收集cpu的使用率
- 看到是 所有cpu数量的一个总体的使用率
- 在没有按1, 在我们用监控工具\平台来收集cpu的使用率
-
mem: buffer cache swap
- buffer是磁盘虚拟出来的一个缓冲区,用于内存读取磁盘数据时,加快读取速度
- cache 缓存,存在内存、cpu中,
- swap 交互分区 主要是用来,交换内存空间。它也是由磁盘虚拟而来,一般为内存的2倍
-
任何一个程序启动,都会在内存中占用:虚拟内存核物理内存
-
PID 进程id
-
USER 进程的归属用户
-
PR 优先级的级别
-
NI 优先级的值,越低,优先级越高
- VIRT 虚拟内存 进程使用虚拟内存大小 默认是KB
- RES 物理内存大小 进程使用的物理内存大小 默认是KB
- SHR 共享内存大小 默认单位也是KB
这三个都是进程的内存相关数据,按小写e 可以切换单位
- S 进程的状态
- %CPU 进程占用的cpu率
- %MEM 进程使用men率
- TIME+ 进程使用cpu的时间
- COMMAND 进程名称
查看当前系统cpu使用率最高的4个进程: n 4 回车
top命令默认3秒钟刷新一次数据: s\d 数字
我只想看某个进程下的线程资源使用情况: top -H -p pid值
us\usr、sy\sys
- ps
- ps -ef\-eF\-ely 使用标准语法查看系统上的每个进程
ps aux |grep mysqld |grep -v grep
- vmstat
- 这个命令是系统自带
- 虚拟内存统计的缩写,可对虚拟内存、进程、cpu活动进行监控
[root@vircent7 ~]# vmstat 1 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
2 0 0 1094548 2108 362988 0 0 58 7 40 52 0 0 100 0 0
-
procs
- r : 数字 显示cpu中有多少个进程正在等待
- 如果r列是数字,大于cpu核数,那么说明现在现在有大量的进程在等待cpu进行计算,现在可能出现了cpu不够用的情况。----cpu成了我们的性能瓶颈,此时,可能需要去增加cpu数量;或者减少运行的进程数。
- b : 数字 现在有多少进程正在不可中断的休眠. 如果这个数字过大,就说明,资源不够用。
- r : 数字 显示cpu中有多少个进程正在等待
-
memory
- swap
- free
- buff\buffer
- cache
-
swap
- si 交换分区中的换入
- so 交换分区中的换出
-
io
- bi 块设备的读
- bo 块设备的写
-
system
- in interrupet cpu中断 数字
- cs cpu上下文切换 数学
-
cpu
- us
- sy
- id
- wa
- st
-
sysstat的工具包,这个工具包中带了很性能分析命令
yum install sysstat -y
- mpstat 查看cpu的相关数据
- mpstat -P ALL 2 5
- %usr
- %nice
- %sys
- %iowait
- %irq 硬中断
- %soft 软中断
- %steal
- %guest 显示cpu或cpu运行虚拟机处理器所花费的时间占比
- %gnice 显示cpu或cpu运行nices客户机所花费的时间占比
- %idle
-
pidstat: 能看磁盘、内存、cpu的数据,主要看cpu的上下文数据
-
pidstat -u -w 1 5
- -u 用于查看cpu的数据
- -w 看cpu的上下文数据
- UID PID
- cswch/s 自愿上下文切换次数
- nvcswch/s 非自愿上下文切换次数
- Command
-
中断 VS 上下文切换:
- 中断: 中断当前正在运行的,去做其他事情
- 上下文切换: 资源的切换
- 中断,一定会导致上下文切换,但是上下文切换,不一定会中断。
-
-
iostat: 看数据换入换出
- iostat -dx 1 3 ------没有带m,数据单位,默认kb
- rrqm/s 合并的每秒读请求
- wrqm/s 合并的每秒写请求
- r/s 读/秒
- w/s 写/s
- rkB/s 读kb/s
- wkB/s
- avgrq-sz 平均情况的扇区数
- avgqu-sz 等待大的请求数
- await 等待的时间
- r_await 读等待的时间
- w_await 写等待的时间
- svctm 实际请求的时间
- %util 至少有一个活跃请求的所占的时间百分比
- iostat -dx 1 3 ------没有带m,数据单位,默认kb
-
dstat
- yum install dstat -y
- dstat -lcmdry
性能分析命令
- top
- vmstat
- sysstat:
- mpstat
- iostat
- pidstat
- netstat
- dstat
- sar: 主要用在网络相关数据的查看
- -n 网络相关数据统计
- -d -b 磁盘驱动
- -r 内存相关
- -u -P cpu相关
块:从磁盘中读取数据的 最小单位
页:从内存中交互数据的 最小单位 页的大小要比 块要大
性能测试分析的思路:先分析硬件 、网络、 系统配置、应用程序
硬件: cpu、内存、磁盘、网络、io
- cpu 中央处理器
- 架构、主频、核
- cpu:结构 主要物理结构是3个,实际是有4
- 运算器: 真正进行计算的单元
- 控制器: leader
- 寄存器: 存储 指令、数据、地址
- 时钟
内存: 程序代码、网络数据,外部数据进入cpu的桥梁,内存的速度,要比cpu的速度
cpu中: 内核、线程、架构
cpu的内核,医院中的医生
cpu的线程,医生配备的护士
cpu的架构,医院的结构
看cpu的数据信息: top
lscpu
cat /proc/cpuinfo
/proc 虚拟文件,操作系统启动时,读取的信息,这些信息放内存中
cat /proc/cpuinfo |grep "physical id" |sort |uniq |wc -l
查看物理cpu数量
cat /proc/cpuinfo | grep "cpu cores" |uniq
查看CPU的core数,即核数
cat /proc/cpuinfo | grep "processor" |wc -l
查看逻辑CPU数量
load average = cpuload + ioload
- 上下文切换: 寄存器中的资源进行切换
- 自愿上下文切换: 资源不够,自觉的切换到另外指令上
- 非自愿上下文切换: 有可能有优先级更高的指令、指令执行的时间已经到了,被迫中止当前的指令,去执行其他指令
top、 mpstat
-
sys高 系统态cpu使用率高, 内核中计算
- 程序进行计算,非内核态 进入 内核态,重点关注 上下文切换的数据
- 自愿上下文切换, 资源不够用,所以要进行切换,===资源有关,===可能存在IO/内存资源
- 非自愿上下文切换 -----强制进行资源切换 =====考虑cpu不够用
- 解决:
- 要么在服务器上,减少启动的程序
- 要么增加cpu的数量
- 解决:
- 程序进行计算,非内核态 进入 内核态,重点关注 上下文切换的数据
-
si 软中断高
-
us 用户态比较高
-
真正在做性能测试时,你要管理好你的被测服务器,loadaverage要恢复正常,第一个值,没有明显的上升或下降的趋势,也就是说第1个值,基本不变。
- 要把服务器的资源监控弄起来,上课,用的grafana+prometheus + 硬件资源\应用资源
-
服务器硬件资源监控: grafana(前端) + prometheus(时序数据库) + node_exporter(硬件资源收集器)
- 被测服务器上 部署 node_exporter
- node_exporter上传到被测服务器
- 解压、启动
./node_exporter
- 端口:9100
- 监控平台机器上,启动 grafana + prometheus
- 进入prometheus文件夹,修改Prometheus.yml的配置文件
- 保存好配置文件,启动Prometheus
./prometheus
默认端口:9090 - 启动grafana
systemctl restat grafana-server
默认端口: 3000 - http://grafanan_ip:3000 admin admin
- 被测服务器上 部署 node_exporter
-
stress-ng: 性能测试模拟工具,可以直接模拟服务器各种压力情况
- stress-ng 我可以通过它,来模拟,你们企业中的响应有cpu相关性能问题
- 安装
# 安装epel源,更新系统 yum install -y epel-release.noarch && yum -y update # 安装stess-ng 的工具 yum install -y stress-ng
-
进程上下文切换
(( proc_cnt = `nproc`*10 )); stress-ng --cpu $proc_cnt --pthread 1 --timeout 150
# nproc 这个命令可以获得服务器cpu的数量
# (( proc_cnt = `nproc`*10 )); 把cpu核的数量乘以10倍,给变量proc_cnt
# --cpu $proc_cnt $proc_cnt shell编程中的变量引用
# --pthread 每个进程有多少个线程
# --timeout 超时时间,在命令执行多长时间之后自动结束
总结:
1、top命令,可以到 loadaverage 有持续上升,cpu被100%使用 us + sy + si
2 vmstat proc中r列有非常大的数据 有非常多的进程在抢cpu的资源
memory: free 数据变小, 内存有一部分被使用
system: in有一点点, cs 有明显数据变大,说明有大量的 上下文切换
3 pidstat -w 1----这个命令可以上下文的信息
我们看到的大量 stress-ng–cpu cswch/s 自愿 nvcswch/s非自愿上下文的值
现在可以得出 ,我们线程有大量的 进程上下文切换问题,而这个问题的进程:stress-ng–cpu
当你的服务器,使用top命令发现,系统负载比较高,所有的cpu的使用率接近或等于 100%,我们要排查问题,vmstat 1 , 结果我们看到有procs 中r列 有大量数据,说明我们有大量进程在竞争cpu的资源。--------可能服务器的cpu数量不够, 也可能是 进程启动的太多
vmstat 我们还看 system中 cs 比较高 --------肯定有大量的上下文切换
但是,此时,我并不知道,是哪个进程导致 抢占cpu,-----找具体是哪个进程
==== 应该是某个经常有大量的上下文切换,而导致的cpu使用率过高,系统负载过高的问题
—问题的关键点,找到具体的进程
pidstat -w 3 看到具体的 上下文切换的数据比较大的进程。-------得到具体进程 和进程id
-
结论
Ø1、top: load值一直在增加,而且增长的非常大
Ø2、top:CPU的 us + sy ≈ 100%,us较高,sy较低
Ø3、vmstat: procs的r 就绪队列长度,正在运行和等待的CPU进程数很大
Ø4、vmstat: system的in(每秒中断次数) 和 cs(上下文切换次数) 都很大
Ø5、vmstat:free、buff、cache变化不大
Ø6、pidstat: nvcswch/s 非自愿上下文切换在逐步升高
只要系统运行,那么 中断和 上下文切换,就不可避免,只不过这些数据比较小
stress-ng --cpu `nproc` --pthread 1024 --timeout 60
-
分析命令:
+ top
+ vmstat 1
+ pidstat -w 5 -
结论:
Ø1、top: load值一直在增加,而且增长的非常大
Ø2、top:CPU的 us + sy ≈ 100%,us较低,sy较高
Ø3、vmstat: procs的r 就绪队列长度,正在运行和等待的CPU进程数很大
Ø4、vmstat: system的in(每秒中断次数) 和 cs(上下文切换次数) 都很大
Ø5、vmstat:free变小、buff基本不变、cache变大
Ø6、pidstat: cswch/s 自愿上下文切换 升高
实战
-
stress-ng
- 模拟了进程上下文切换
- 模拟了线程上下文切换
- IO密集型
- IO不要再理解为:读写操作,换入换出
-
IO密集型,导致服务器平均负载比较高
stress-ng -i 6 --hdd 1 --timeout 150
- top:
- loadaverage 上升
- cpu: wa值很大 us、sy不是很大, buff/cache有增大
- vmstat 1: mem free减少, cache有明显的增大, bo有明显数据, 说明有大量磁盘数据交换
- mpstat -P ALL 3 : %iowat 数值比较大 再次证明,我们线程系统负载比较高的原因是,系统的磁盘读写测试性能瓶颈, 哪到底是哪个进程导致我们的磁盘读写高?
- pidstat -w 1 stress-ng-hdd这个进程的 自愿上下文切换数据比较大,pid的值 进程id
- top:
===你们考虑一下,这个问题这么解决?
----已经定位到了具体是哪个程序导致了
要么换磁盘,要么迁移到io性能更好的服务器
如果你是整体的迁移你的数据库,这个风险比较大,我们可以再另外一个IO性能比较好服务器,再安装一个数据库,做要给数据库读写分离。
要么 减少io操作
要定位到具体代码:
思路:具体进程id之后, 找到进程线程id,然后把线程id进行16进制转换, 进程id日志打印出来,过滤出线程id(16进程)
-
内存知识
- 当打开一个软件,就会分配虚拟内存、物理内存空间,cpu读取虚拟内存
- 程序在启动时,并不会把所有的数据,加到内存
- 32位的系统,最大支持的内存条,只有4g,64位系统,最大可以支持128T
- 程序在启动时,会有一个内存配置信息,就会告诉系统,我要在整改内存条中,申请多少m内存空间。
-
内存中,内存地址与存储单元组成的
- 存储单元中,就是来真正存储内容
- 不同的数据类型,存储单元大小不一样
- int float, char
- 列表 数组
- python:列表 [8,‘nmb’,[‘vip8’,‘vip12’],]
- 列表中,插入一个数据,要把插入位置之后的所有数据都移动位置
- 所以,这种,速度是比较慢
-
数据结构
- 链表: 自行车链条
- 每一个数据,都有自己的地址 + 数据 +下一个数据的地址
- 插入数据时, 数据本身可以在内存空间的任意位置,然后,在插入数据的位置前一个数据改变下一个数据地址,指向我的这位置,我的数据位置记录的下一个位置…
- 这种数据插入方式,速度要比列表要块
- 但是,读取某个数据的速度降低,因为我们每查询一个数据,都要从链表的第1个数据开始查找,一直到找到为止,这个中间,我们可能要进行大量IO数据交互
-
堆栈: 两种数据结构
- 栈: LIFO
- 队列:FIFO
- 堆:
内存
内存地址 + 内存存储单元
-
内存中数据结构
- 列表:往列表中插入数据,插入点之后的数据,全部都需要移动,这个插入速度比较慢
- 链表:每一个数据,它都存储了下一个数据的地址(内存地址),在插入数据的时候,我可以把数据放在任何位置
- 链表在查数据时,它的链路可能会很长,那么它的IO可能消耗比较高
- 二叉树
- 它也链表
- 插入数据时,数据进行比较,比数据小的在左边,比数据大的插入在右边
- 查找数据时,比数据大的,我就去右边找,比数据小,我就去左边找,这个时候,IO就比链表要少很多。
-
数据类型:
- 栈stack: 存储的数据比较小,比如某个变量
- LIFO 后进先出
- 压入 push
- 弹出 pop 弹出我们最后一个数据
- LIFO 后进先出
- 队列: FIFO 排队
- 顺序队列,
- 循环队列
- 堆heap: 存储的数据比较复杂
- 对象
- 栈stack: 存储的数据比较小,比如某个变量
-
一个程序: 如: 这个程序启动要 256m
- 先有一个虚拟内存地址 + 物理内存地址
- 虚拟内存地址: 记录物理内存中存储了哪些数据,在什么地方
-
jvm: java虚拟机
-
程序计数器、java虚拟机栈、本地方法栈、方法区、堆内存
-
程序计数器:记录程序执行字节码的行号指示器
-
内存泄漏: 内存的资源不及时释放,一直占用,导致可用的内存资源越来越少。
-
内存溢出:内存泄漏到一定的时间,可用的空间就会越来越少,某一次我要用比较大的空间时,发现,我申请不到足够的空间了,我申请的空间已经超过最大可用空间,内存溢出。
- 内存溢出,在错误日志,会出现
- jmap
- arthas
-
top: 进程列表中有3列, 虚拟内存、物理内存、共享内存
- 堆内存:新生代、老年代、永久代(元空间)
- 新生代new:昙花一现,朝生夕死的对
- 如:你写的代码,方法里面变量
- 老年代Tenured:
- 新生代数据,经过copy算法,如copy了15次,
- 新生代new:昙花一现,朝生夕死的对
YGC:Young Generation Minor GC
FGC:Major GC
资源回收的时候,都会出现卡顿,YGC的卡断时间会比较短,FGC卡顿的时间会比较长
性能测试中,就对于这个gc是要关注
-
如果 新生代资源分配过多,那么,老年代这变就要少, 老年代的空间,我可能就要经常的进行FGC, FGC频率高了,那么累计的gc的时间就长,导致性能比较差
-
如果 新生代分配的资源少了,那么老年代就分配多些,我的新生代的资源回收频率YGC就要高, 那么累计的ygc的时间也可能长,我的性能也可能较差
-
gc资源回收
- 哪些是可以被回收?
- 是否已死
- 哪些是可以被回收?
-XX:SurivivorRatio=8 eden空间、from空间、to空间的比例 8:1:1
-XX:MaxMetaspaceSize jdk1.7 jdk1.8这个元空间参数配置名称变了
- 查看内存:
- free -h
oom项目环境部署
-
准备一台linux
-
检查 jdk1.8
-
tomcat Jvmpertest.war 丢到webapps文件夹下
- catalina.sh
JAVA_OPTS="-Xms256m -Xmx256m -Xmn128m"
-
启动tomcat
-
jmeter调用: http://ip:8080/JvmPertest/pertest1
- 设置性能场景进行调用
-
确定oom问题:
- 看请求的响应信息, 一般的情况下,出现内存溢出问题,在响应信息中都会有所体现
nested exception is java.lang.OutOfMemoryError: Java heap space
- 有些项目,在log日志中,会有体现, ===不一定有
- 我们看 系统的 内存
- 内存并没有被完全消耗掉
- 看请求的响应信息, 一般的情况下,出现内存溢出问题,在响应信息中都会有所体现
-
定位这个问题:
- 生成内存溢出堆栈文件
- 获得进程id
ps -ef |grep java
jps
jmap -dump:live,format=b,file=heap_jvmpertest_20210811002.hprof 2419
- 方法2:arthas
- curl -O https://arthas.aliyun.com/arthas-boot.jar
- 启动:
java -jar arthas-boot.jar pid
heapdump
,在出现内存溢出的错误是,执行这个命令,可以直接下载heapdump信息
- 获得进程id
- MAT
- 解压MemoryAnalyer工具
- 打开工具,open hprof文件
- 点击 histogram
- 没有java基础的同学, hprof文件给开发去定位, 有基础的同学,mat工具自己来分析
- 生成内存溢出堆栈文件
看jvm的 gc信息: -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimestamps -XX:+PrintGCApplicationStopedTime
IO操作,所以,生产环境,一般不添加
jstat -gcutil 3122 1000 10
分析gc
ØS0:新生代susvivor0区
ØS1:新生代susvivor1区
ØE:新生代eden区
ØO:年老代
ØM:方法区回收比例 CCS:类空间回收比例
ØYGC:minor gc次数
ØYGCT: minor gc耗费的时间
ØFGC: full gc的次数
ØFGCT: full gc的耗时
ØGCT: gc总耗时
cpu相关问题,应用服务器中高频率
内存: 工作中,比较难
网络:见的多,但是不是最难,只是因为大家 见多,网络知识跟不上
磁盘问题: 相对来说问题是最少, 一般集中在 文件服务器\数据服务器
- 磁盘
- 服务器 最大存储空间,但是速度比较慢
- 磁盘的格式化: 最大化的利用磁盘,以及加快磁盘的读写
内存
-
扇区扇区sector:磁盘组成的最小单元(512b),磁盘磁道中一个弧段
-
块Block:操作系统与磁盘数据交换的最小单位,块=2n x 扇区
Ølinux:类似Ext4文件系统,就是磁盘分块
Øwindows:类似NTFS文件系统,也是块,只是被叫做‘簇’
-
页page:操作系统与内存数据交换的最小单位 一页的大小,一般是4K
-
缓冲区buffer:
-
磁盘阵列RAID:
- RAID0: 数据分片存在2块磁盘,读写速度提升2倍,但是,数据没有冗余,万一数据出错,很难恢复
- RAID1:相同数据冗余存入2块磁盘,写速度不变,读速度提升2倍,数据有冗余,恢复数据很简单
- RAID5:数据分片和校验码混合存储3份,读写速度提升2倍,数据没有冗余,但是有校验,数据恢复时,比较容易。
- RAID10:2块磁盘1组先做RAID1,多组RAID1,再做RAID0。读写速度N倍 n为组数
-
测试磁盘写的速度
- 1、先清空缓存:
echo 3 >/proc/sys/vm/drop_caches
- 2、写操作:
dd if=/dev/zero of=$PWD/optfile bs=20MB count=100
- 3、
vmstat 1
cache增大, bo有明显数据,in也有明显数据变化 - 4、
iostat -dx 1
wkB/s有非常大的数据, await也有数
- 3、
- 我现在磁盘的写速度大概时400MB/s
- 1、先清空缓存:
-
测试磁盘读的速度
- 1、先清空缓存
echo 3 >/proc/sys/vm/drop_caches
- 2、写操作:
dd if=/dev/sda of=/dev/null bs=20MB count=100
- 3、
vmstat 1
buff 有明显的数据,cache有数据变化,但是不明显, bi有明显的数据 - 4、
iostat -dx 1
rKB/s有明显的数据,await有,但是不是很大
- 3、
- 1、先清空缓存
-
测试内存的速度
- 1、先清空缓存
echo 3 >/proc/sys/vm/drop_caches
- 2、脚本:
dd if=/dev/zero of=/dev/null bs=10MB count=1000
- 1、先清空缓存
结论: 磁盘的读写速度,几百MB/s 内存 几GB/s 内存速度比磁盘快很多。
写操作时,cache增大, bo有明显数据,
读数据时,buff增大, bi有明显数据
实战项目: python3 + flask
-
安装python3
-
yum install gcc -y yum groupinstall 'Development tools' -y yum install openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel sqlite-devel libffi-devel -y
-
# 上传python3.9.1包 # 解压,进入解压后的文件夹 ./configure --prefix=/usr/local/python3/ make && make install ln -s /usr/local/python3/bin/python3 /usr/bin/python3 ln -s /usr/local/python3/bin/pip3 /usr/bin/pip3
-
安装flask
pip3 install flask
-
运行项目:
python3 pertest_io.py
-
jmeter请求 http://ip:9800/pertestio/随机数字
-
发现: 系统平均负载在上升
-
定位:
- top cpu的wa值 非常高
- vmstat 2 : io的bo值,有明显的数据 ====== 有大量的写磁盘操作,
- mpstat -P ALL 2
- iostat -dx 2 看到 wKB/S 有非常大的数据, 现在的磁盘 有大量的写操作
-
-
网络
- TCP协议:通过数据发送者和接收者相互回应对方发来的确认信息,可靠的进行数据传输
- IP协议:指定数据发送的ip信息,以及通过路由转发数据
”数据“ + tcp + ip + 帧头\帧尾
-
TCP组成:源地址、源端口、目的地址、目的端口
-
电脑最多: 65535个端口
-
1- 1023 公认端口 21、22、25、80、443
-
1024-49151 注册端口 8080 9800 3000
-
49152~65535 私有端口 约16800
-
问题: Address already in use: connect
-
优化方向:
- 扩大端口范围: 1024 ~ 65535 达到6.4w端口
- 让端口占用的时长缩短: 去掉keepalive
-
定位问题:
-
1、看到报错
-
获取商品列表
-
分析
-
windows:
netstat -ano | find "TCP" /i /c
- /i 不匹配大小写
- /c 统计
如果你发起方机器,这个命令的数值,约1.4w,可以肯定,你本地端口成为性能瓶颈
-
linux:
netstat -ano | grep "TCP" | wc -l
-
-
-
2、调优
-
去掉: keepalive 并不能解决问题,只是把这个报错时间往后延迟一点
-
修改注册表:计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
- 添加 MaxUserPort 十进制 65534
- 添加TcpTimedWaitDelay 十进制 30
- 重启系统
-
linux,如果你发发起方是Linux
-
sysctl -a |grep net.ipv4.ip_local_port_range
-
net.ipv4.ip_local_port_range = 32768 60999 =====2.8w
-
改端口范围:
sysctl -w net.ipv4.ip_local_port_range="1024 65535" sysctl -p
-
-
-
-
-
判断带宽有没有问题:
- 吞吐率
- 1Mbps = 1024Kbps = 1024/8 KB/s = 128KB/s
- ping
- ping目标服务器
- 看时间 没有测试前的时间 与在进行性能测试时的 时间之间有没有明显的差异
- 看丢包: 如果有丢包 肯定时网络瓶颈
- ping目标服务器
- 吞吐率
网络包
-
源地址
-
源端口:
- 每发起一次请求,就要占用发起方一个端口
- 端口数量是有限的,端口数量就可能成为性能瓶颈
- 出现错误?: Address already is used Connection refused
- 可能的原因1: 源端口不够用
- 源端口问题,怎么调优?
- 1、keepalve 勾去掉
- 2、修改发起方的系统信息
- windows: 注册表:
- MaxUsePort: 十进制65535
- TcpTimedWaitDelay: 十进制 30
- linux:
- sysctl net.ipv4.ip_local_port_range 1024 65535
- windows: 注册表:
- 源端口问题,怎么调优?
- 可能的原因2: 服务器要调优
- os操作系统
- sysctl
- ulimit -n
- 应用中间件
- 连接池
- 应用连接池
- 数据库连接池
- 连接池
- os操作系统
- 可能的原因1: 源端口不够用
- 每发起一次请求,就要占用发起方一个端口
-
目标地址
-
目标端口
-
ulimit
ulimit -a
查看所有的限制-
ulimit -n
open files 打看文件数量限制 默认1024. 某一个应用程序,最多可以打开的文件数量 -
修改配置项:
ulimit -选项参数 配置值
----这种修改,只是临时修改,系统重启之后,自动还原。 -
持久化\永久性的修改
vim /etc/security/limits.conf * soft nproc 32768 * hard nproc 32768 * soft nofile 16000 * hard nofile 16000
不管你是用 ulimit命令修改,还是 修改文件limits.conf, 你的应用程序要使用这个配置,那么你的应用程序需要重启
-
检查系统配置是否成为瓶颈:
lsof -p pid |wc -l lsof |wc -l cat /proc/PID/limits # 看具体某个进程运行打开的文件数量
-
-
禁ping
# 禁ping
sysctl -w net.ipv4.icmp_echo_ignore_all=1
sysctl -w net.ipv4.route.flush=1
sysctl -p
# 开启
sysctl -w net.ipv4.icmp_echo_ignore_all=0
sysctl -w net.ipv4.route.flush=1
sysctl -p
cpu、内存、磁盘、网络 回顾
-
cpu
- 进程上下文切换高问题
- 减少服务器上进程数量
- 增加cpu
- 线程上下文切换高问题
- 进程上下文切换高问题
-
内存
-
一个程序启动,在内存中分配一定量的 内存空间 (物理内存)
-
一个线程的内存,是由 虚拟内存 + 物理内存
- 虚拟内存中: 链表、页表
- 物理内存中: 存储程序的相关数据
-
内存溢出
-
内存泄漏
-
服务器上的应用中间件
服务器上数据库
USE方法
-
use
-
cpu分析: top
-
loadaverage: 1 5 15分钟
- cpuload + ioload
-
上下文切换
- 进程上下文切换
- 线程上下文切换
- 同一个进程中,线程上下文切换,只需要保存,线程所私有资源
- 不同进程中,线程上下文切换, 先保存线程私有资源 + 进程的资源
- 中断切换
-
cpu性能分析:
- top
- vmstat proc r列
- pidstat 具体看 自愿上下文切换 非自愿上下文切换 定位具体的pid
-
-
内存:
- 虚拟内存
- 物理内存
- 内存问题怎么定位:
- OOM:
- jstat dump
- arthas threaddump
- MAT
- 内存溢出
- 内存泄漏
- OOM:
- 内存问题怎么定位:
-
io问题
- iostat
- vmstat io bi/bo
- buff
- cache
-
网络:
- 源地址
- 源端口:
- 发起方window:
- 1、去掉keepalive
- 2、改注册表: MaxUserPort 65535、 TcpTimedWaitDelay 30
- 发起方linux
- 1、去掉keepalive
- 2、sysctl -w net.ipv4.ip_local_port_range=“1024 65535”; sysctl -p
- 3、ulimit -n 16000
- 发起方window:
- 目标地址
sysctl -w net.ipv4.ip_local_port_range=“1024 65535”; sysctl -p- ulimit -n 16000 ulimit -u 65535
- nproc、 nofile
- 目标端口: 线程池
如果看到响应信息中有,too many open file too many connection
-
tps上不去,可能的原因
- 带宽
- io
- 连接池: 应用连接池、数据库连接池 默认151
- 资源回收: gc、堆栈配置
- 数据库的配置
- linux服务器的配置
- 通信连接机制: http websocket
- 硬件
- 脚本本身, beanshell
- 压力机
- 业务逻辑
- 系统架构
-
java:
- 包: war jar
- 运行: jre\jdk 运行的中间件tomcat
- apache托管
- tomcat
- bin文件夹中 catalina.sh 文件中,配置堆栈
- conf 文件夹中 server.xml 文件 修改协议端口的
- 如果你一台电脑上想要启动多个tomcat,你这个server.xml文件,要修改3个端口
- logs文件夹
- 看日志,看哪个文件 catalina.out
- webapps文件夹
- 项目工程包
- 包: war 自动解压, 其他格式,不会自动解压
- 在webapps下丢多个项目包,解压后,就可以实现一个tomcat部署多个项目
- 项目工程包
- tomcat
springcloud,自己带有tomcat,它打出来的jar包,可以直接运行
java -jar xxxx.jar 默认就是8080
回顾
-
tomcat配置文件
- 堆栈:
- bin文件夹中 catalina.sh文件
- JAVA_OPTS 堆栈信息
- 端口\线程池
- conf文件夹 sever.xml文件
- 修改port
- 线程池
- 堆栈:
-
grafana+prometheus 监控tomcat
- jvm_exporter
- 放到tomcat的bin文件夹
- tomcat.yml 文件也上传到tomcat的bin文件夹中
- 修改 catalina.sh文件
JAVA_OPTS="-javaagent:./jmx_prometheus_javaagent-0.16.1.jar=3088:./tomcat.yml"
- 重启动 grafana
systemctl restart grafana-server
- 修改prometheus.yml
- job_name: 'jvm_exporter' static_configs: - targets: ['192.168.3.41:3088']
- 启动prometheus
- 浏览器访问 http://grafana_ip:3000
- 添加prometheus的数据源
- 引入模板: 8563 3457
-
nginx
- 反向代理、域名服务器、web服务器
- nginx的安装(一)
yum install make zlib zlib-devel gcc-c++ libtool openssl openssl-devel -y
# 安装必须的pcre
wget https://sourceforge.net/projects/pcre/files/pcre/8.44/pcre-8.44.tar.gz
tar -xzvf pcre-8.44.tar.gz
cd pcre-8.44
./configure
make && make install
- 安装nginx
wget http://nginx.org/download/nginx-1.19.5.tar.gz
tar -xzvf nginx-1.19.5.tar.gz
cd nginx-1.19.5
./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module
make && make install
启动nginx的命令: /usr/local/nginx/sbin/nginx
配置文件地址: /usr/local/nginx/conf/nginx.conf
检查nginx的配置文件是否正常: /usr/local/nginx/sbin/nginx -t
重新加载配置文件/usr/local/nginx/sbin/nginx -s reload
-
安装nginx方法2:
- 安装对于操作系统的nginx源
rpm install http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm -y yum install nginx -y systemctl restart\stop\status nginx # 检查配置文件是否正常 nginx -t # 重新家族nginx的配置文件 nginx -s reload #配置文件地址 /etc/nginx/nginx.conf
-
两种方式优缺点:
- 第1种,源码安装, 安装比较麻烦一点,但是可以灵活配置,方便后续进行功能扩展
- 第2种,yum来安装,这种安装简单,但是,后续无法进行功能扩展。
-
用nginx来配置一个集群
- 我上课用的是 一台电脑种配置了多个tomcat
- 修改一个tomcat种的server.xml文件
- 2个tomcat, 一个tomcat端口 8080 另一个tomcat的端口 8880
- ip有几个?
nginx
-
两种安装方式
- 源码安装:
- 优点: 可以后续扩展
- 缺点: 安装稍微麻烦一些
- 系统安装
- rpm源 + yum 安装
- 优点:安装简单
- 缺点: 后续无法进行扩展
- 源码安装:
-
源码安装nginx:
- 启动:
/usr/local/nginx/sbin/nginx
- 配置文件: /usr/local/nginx/conf/nginx.conf
- 检查配置文件是否正常:
/usr/local/nginx/sbin/nginx -t
- 重新加载已经修改的配置文件:
/usr/local/nginx/sbin/nginx -s reload
- 启动:
-
我们的监控平台: grafana + prometheus 监控nginx
- 1、nginx机器上 下载nginx-module-vts
# nginx-module-vts.tar.gz git clone https://gitee.com/mirrors/nginx-module-vts.git tar -xzvf nginx-module-vts.tar.gz # 路径: /opt/nginx-module-vts
# 重新安装nginx # 进入nginx的解压文件夹中 ./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --add-module=/opt/nginx-module-vts/ make && make install
# 杀调nginx # 启动nginx /usr/local/nginx/sbin/nginx
- 2、安装 nginx-vts-exporter
# 下载 wget https://github.com/hnlq715/nginx-vts-exporter/releases/download/v0.10.3/nginx-vts-exporter-0.10.3.linux-amd64.tar.gz tar -xzvf nginx-vts-exporter-0.10.3.linux-amd64.tar.gz cd nginx-vts-exporter-0.10.3.linux-amd64 # 启动 nohup ./nginx-vts-exporter -nginx.scrape_uri=http://localhost/status/format/json &
现在用 http://nginx_ip:9913/metrics 访问 可以访问,但是没有数据
没有数据是什么原因呢?==-====我们需要修改nginx.conf配置
- 3、修改nginx.conf配置文件
# 在http节点下 vhost_traffic_status_zone; vhost_traffic_status_filter_by_host on; # 再在 server location /status { vhost_traffic_status_display; vhost_traffic_status_display_format html; }
# 重新加载 nginx.conf文件 /usr/local/sbin/nginx -t /usr/local/sbin/nginx -s reload
这个时候 刷新 http://nginx_ip:9913/metrics 我们看到页面中多了很多数据,nginx_vts_exporter 已经开始收集数据
- 4、启动grafana
systemctl restart grafana-server
- 5、配置prometheus
# 修改Prometheus.yml - job_name: 'nginx_exporter' static_configs: - targets: ['192.168.3.41:9913']
nohup ./prometheus &
-
6、访问: http://grafana_ip:3000 admin admin
-
7、添加数据源,引入模板: 2949
-
到现在,我们做性能测试同时,收集了 tomcat、nginx、node
-
服务器架构演进(三)
- 数据库演进
- 数据库 database
- 数据库管理系统 dbms
- 关系型数据库: mysql、sqlserver
- 是指采用关系模型来组织数据库的数据,以行+列的方式存储数据
- 二维表: 结构化我们的数据
- 关系型数据库,有统一标准的sql
- DCL 数据库控制语言 主要用于创建数据库的用户和角色
- DDL 数据库定义语言 主要用于创建或删除数据库以及表
- DML 数据库操作语言 主要用于表数据操作
- DQL 数据库查询语言 主要对数据库表进行查询操作
- 非关系型数据库: mongodb、redis
- 时序数据库: influxdb、Prometheus
- 关系型数据库: mysql、sqlserver
因为关系型数据库,遵循ACID原则,所以,一般情况,要数据库入库准确,而且字段数量并更不是很频繁的情况下,使用关系型数据。
存储信息的字段数量不相等,或不确定情况时,我们一般就用 非关系型数据库
现在企业中,关系型数据库 + 非关系型数据库 组合 存储数据的情况,非常场景
数据库锁: 两种常见的
行锁: 每次锁定一行
只有获得了某一行操作的锁了,才能操作这一行数据, 当有高并发时,我可以不同的线程来操作不同的行。
表锁: 每次把整张表锁定
在操作前,先获得整张表的操作锁,只有获得到锁的这个线程,才能操作整张表,其他的线程,没有拿到锁,就只能等待。
mysql数据库一般是5.5以上的版本,它的锁默认是 行锁。mysql5.5以前的版本,默认 表锁。
数据库
- mysql =====关系型数据
- dbms
- 关系型数据
- MySQL
- 非关系型
- redis
- 时序型数据
- 关系型数据
mysql
- 安装:数据库的版本 mysql5.7版
- 现在企业中mysql版本,大多在mysql5.7
rpm -Uvh http://dev.mysql.com/get/mysql57-community-release-el7-10.noarch.rpm
# 安装mysql-server
yum install mysql-community-server -y
# 启动数据库
systemctl restart mysqld
# 配置开机自启动
systemctl enable mysqld
最简单, 但是因为网络的原因,要下载,可能时间会比较长
安装方法
使用rpm包安装
速度很块,但是,包有先后顺序的依赖关系,
安装方法3:----速度最块
docker方式安装
速度很快,但是,需要有docker的技能
# 安装docker
curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
docker run -itd --name mysql -p 3337:3306 -e MYSQL_ROOT_PASSOWORD=123456 mysql:5.7
-
修改数据库的密码:
-
通过
grep "password" /var/log/mysqld.log
可以找到密码,但是这个密码是高复杂度的密码,这个密码不好记忆 -
我们想要修改为低复杂度好记忆的密码
-
修改 mysql数据库的配置文件 /etc/my.cnf
- 这个路径,是直接安装mysql数据库方式的 数据库的配置文件路径
- 在[mysqld]节点下
[mysqld] validate_password_policy=0 # 设置为 弱密码 validate_password=off # 关闭密码策略 character_set_server=utf8 init_connect='SET NAMES utf8'
重启动mysql:
systemctl restart mysqld
进入mysql客户端
mysql -uroot -p
回车alter user 'root'@'localhost' identified by '123456'; GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION; FLUSH PRIVILEGES; exit;
mysql的默认端口 3306
-
-
安装mysql方法2,使用docker安装
- 安装docker
# 安装docker依赖: yum install -y yum-utils device-mapper-persistent-data lvm2 #安装docker: curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyuncurl -sSL # 重启docker systemctl restart docker # 配置开机自启动 systemctl enable docker
# 创建一个mysql容器 docker run -itd --name mysql5735 -p 3337:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7.35
-
创建库
-
创建表:
- 存储引擎: 默认是InnoDB
- 在mysql5.5以后版本,默认存储引擎InnoDB
- 5.5以前是MyISAM
- 什么是存储引擎?
- 存储引擎,不同的引擎,有不同的性能,所以,我们在建表的时候,要合理的选择存储引擎。
- 存储引擎: 默认是InnoDB
-
索引
- 主键索引: id
- 唯一索引: 不可重复,NULL 有多个
- 复合索引: 多列的名称一起建立一个索引,列的字段是有顺序
+ 复合索引,字段顺序非常关键,你在使用时,就一定要安装它的顺序来,如果不是安装它顺序,那么你就没有使用这个符合索引。- 举例:
- st_student (col1,col2,col3,col4,col5,col6)
- fhindex (col1, col3, col4)
- 顺序:
- col1 --> col3 —col4
- col1 —> col3
- col1
- 顺序:
- sql的where条件,就一定要按照fhindex的顺序
- where条件
- 1: col1=?,col2=? ×
- 2: col1=?,col3=? √
- 3: col1=?, col3=?, col4=? √
- 4: col1=? col4=?, col3=? ×
- 5: col3=?, col4=? ×
- 6: col1=?, col4=? ×
- 7: col1=? √
- 8: col3=? ×
- 9: col4=?, col3=? ×
- where条件
- 举例:
数据库
-
建表: 建表的时候,要特别注意,存储引擎,因为,存储引擎,直接影响这个表的性能。
-
mysql5.5版本,表默认存储引擎是 InnoDB
- 事务有限型,行锁,索引B树
-
mysql5.5版本,表的默认存储引擎 MyISAM
- 性能优先,表锁,索引B树、hash索引
-
建立好了表,表就会有多个字段,往里面写入数据。
- 一般不建议在关系型数据库表中,填加过多字段。
- 表列建立索引,主键,默认就是索引。
-
索引:
- 建立索引的目的,是加快数据查找速度。
- 建索引,会增大真个文件,写入数据时,表的文件大小会发生变化,索引也会发生变化,写入数据,降低修改速度。
- 但是,在数据库的使用过程中,查 使用频率时远远高于 修改频率。
- 索引种类:
- 主键索引: 表的主键 create index 索引名称 on table(col);
- 唯一索引: NULL 可以为多个
- 符合索引: 就要特别注意,字段顺序。create index 索引名称 on table(col,col…);
- 我们在写sql语句时,where条件后面的顺序,要和复合索引字段顺序要一致。
-
建立了数据库和表之后,在/var/lib/mysql路径下,就有数据库名称文件夹
- 文件夹中,就有表名称的文件
- Innodb
- ibd文件,这个表是InnoDB存储引擎时, 数据文件
- frm文件,就是表结构文件
- MyISAM
- frm文件,表结构文件
- MYD文件,数据文件
- MYI文件,索引文件
-
索引的优劣:
- 不足:
- 建立索引,文件比较大,时间也比较长
- 并不是所有的表都可以建索引,数据量太少,根本就无法发现性能问题。
- 建索引,会降低 修改 数据速度
- 优势:
- 提升我们查询速度
- 不足:
-
B树
- 链表
- 二叉树
- B树,可以理解为二叉树,进行旋转而建立一个立体的二叉树集
-
存储引擎 vs 存储过程
- 存储引擎表的类型
- 存储过程,是sql函数
-
视图:
- 虚拟表
-
查询语句的写法:
- select语句的解析过程,是按照写的顺序来解析的吗?
- 不同
-
查询语句的解析过程:
- from 表
- where 条件 过滤数据 ===== 条件,影响性能
- group by 查询结果条件来分组 ====列没有变化
- select 字段 ======这一步的时候,列的数量才会变化
- order by 字段 ===== 排序
- limit 数量
-
梳理前面我们说的影响数据库性能的地方:
- 1、表的存储引擎
- 2、表的字段
- 3、表的索引
- 4、sql语句,where条件
- 5、sql语句,oder by
-
数据库的性能优化:
- 数据库的优化,两个方向: os+库, 表+sql
- 数据库,存储数据,必然有服务器磁盘操作,磁盘的读写速度也会影响性能,所以,数据库服务器,一般选择IO性能比较高的磁盘,磁盘空间比较大
- os: ulimit -n 打开文件数量
mysql数据库的优化
-
os + 库
- 磁盘io比较高磁盘、磁盘空间比较大
- os: linux
- os本身就有一些限制
- ulimit 打开文件数量,操作系统可以运行最大进程+线程数
- ulimit -a
- 库本身配置参数
- show variables;
- table_open_cache 数据表缓存
- 数据库缓存有两种:
- 数据库本身的缓存: 库本身 cache、buff
- 缓存数据库: redis
- 数据库缓存有两种:
- 数据库本身的缓存大小是可以被配置,配置的越大,数据库要用的内存也就越大
- max_heap_table_size 是说 memory存储引擎表的大小为多少 默认16M
- slow_query_log 慢查询的开关
- slow_query_log_file 慢查询开关开启启,慢查询脚本会自动写入文件
- long_query_time 慢查询时间的阈值, 当sql的执行时间超过这个设定时间,就是慢查询。单位: 秒
- 如何获取到慢查询脚本?
- 生产环境中,默认是不会写慢查询日志的。
- slow_query_log 这个开关默认是关闭的,就要开启这个开关
- 开关开启之后,日志,就根据long_query_time的时间,判断,超过这个时间,那么就会写入slow_query_log_file文件中去。
- 如何获取到慢查询脚本?
-
实操 慢查询:
-
易捷支付项目的数据库开启慢查询日志
-
# 进入数据库容器 docker exec -it centos7_mysql57 /bin/bash # 找到容器中 mysql的配置文件路径 /etc/mysql/mysql.cnf exit # 退出容器 # 从容器中,拷贝路径下 mysql.cnf文件到当前路径 docker cp centos7_mysql57:/etc/mysql/mysql.cnf $PWD #### 如果你不知道怎么去找这个配置文件,你就用我这个命令 docker cp centos7_mysql57:/etc/mysql/mysql.conf.d/mysqld.cnf $PWD # 在本地修改mysqld.cnf文件 slow_query_log=ON long_query_time=1 #把修改后的mysqld.cnf文件,拷贝到容器中去 docker cp mysqld.cnf centos7_mysql57:/etc/mysql/mysql.conf.d/mysqld.cnf # 重启容器 docker restart centos7_mysq57
-
我们在做性能测试时,响应时间超过 long_query_time这个设置的时间,才可能出现慢sql
-
如果出现 Too many connections 适当的调整max_connections
-
应用程序 ,调用数据库,是不是 还有一个配置文件?
-
配置文件
-
netstat -ano|grep dbms_prot |grep ESTABLISHED |wc -l # 这个命令,在数据库机器中执行 看数据库当前总共有多少的连接数 netstat -ano|grep dbms_prot |grep pjserver_ip |grep ESTABLISHED |wc -l # 这个命令,在数据库机器中执行 可以看到 应用程序pjserver与 数据库建立连接数有多少
-
-
-
表 + 脚本
mysql数据库的优化
-
获取慢sql?
- show variables like ‘%slow_%’
- slow_query_log 确认这个的值 是否为 ON 默认是OFF
- 找mysql的配置文件
- 系统直接安装mysql /etc/my.cnf
- 如果是用docker方式安装, 配置文件的路径
- 修改配置文件:
- slow_query_log=ON 开启慢查询的开关
- long_query_time=1 设置慢查询的阈值,1,代表1s,当sql的执行时间超过1s时,就认为时慢sql,这个时候慢sql,就会默认自动写慢sql的日志文件中
- 重启动mysql
- 系统直接安装的mysql启动:systemctl restart mysqld
- docker方式安装的启动: docker restart 容器名称
- 运行性能测试脚本
- 观察 响应时间,看平均响应时间,是否超过上面设置的阈值。 也就时说,在运行过程中,响应时间一定要出现了超过阈值的时间,才可能出现慢sql。
- 拿到慢sql的文件,里面就有慢sql
- show variables like ‘%slow_%’
-
分析慢sql,只是数据库表层面的优化的一种。
-
数据库表层面的优化:
- 建表的时候: 存储引擎选择
- 建表的时候,表字段数量
- 查表方式: 垂直拆表、水平拆表
- 表字段: 索引 数据量比较大时,有索引和没有索引,在查询数据上时有差异的。
-
表优化:
-
慢sql的优化: 找到sql语句
-
explain sql语句 -----分析你的sql
- id: 编号
- select_type: 查询类型
- table: 表
- type: 类型
- possible_keys: 预测用到的索引
- key: 实际用到的索引
- key_len: 使用的索引长度
- ref: 表之间的匹配条件
- rows:行数 在sql语句执行时,使用了多少行数据
- extra: 额外的 在这个里面会告诉你,我们脚本是否有使用条件
-
id:id值大 先被执行;id相同的,执行顺序从上往下
-
select_type: 查询类型,种类有多种
- PRIMARY:查询中包含复杂的子查询,最外层的select被标记为PRIMARY
- SUBQUERY:子查询的第一个select
- SIMPLE:简单的SELECT,不使用union或子查询
- UNION:union中第二个或后面的select语句
- DEPENDENT UNION: union中的第二个或后面的select语句,取决于外面的查询
- UNION RESULT: union的结果
- DEPENDENT SUBQUERY:子查询中的第一个select,取决于外面的查询
- DERIVED:衍生查询,使用了临时表(select、from子句的子查询)
- UNCACHEABLE SUBQUERY: 一个子查询的结果不能被缓存,必须重新评估外链接的第一行
-
type: 查询的类型,也是有多种值
- system:
- const:
- eq_ref:类似ref,只是使用的索引为唯一索引
- ref:使用了索引列上值进行查询
- range:使用一个索引来检索给定范围的行
- index:索引 遍历索引数据Full index scan
- ALL : 全表扫描,你要找数据,要全表查找。
- 性能效率:system > const > eq_ref > ref > range > index > all 左边效率高于右边
-
key: 脚本真正用到索引
-
rows: 总共查询了多少行
-
extra:
- using where:显示的字段,不在索引
- Using index: 使用了索引,不 用回表查询,能够起到性能提升
- Using temporary: 使用了临时表,性能消耗比较大,常见于group by语句
- Using filesort:使用文件排序,无法利用索引完成排序操作,性能消耗非常大
- Using join buffer:mysql引擎使用了连接缓存
- Impossible where: where子句永远为false
- Select tables optimized away:仅通过使用索引,优化器可能仅从聚合函数结果中返回一行
-
sql优化:
- on语句时, 左边小表、右边大表
- where 字段尽可能使用 索引
- where 后面有in语句,建议放在索引字段后面
- where 条件使用like模糊查询, 不要用模糊匹配开头
- where 条件 多个 尽可能不要使用or
-
-
mysql数据库的监控
-
方法1
-
方法2: docker方式来安装 mysqld_exporter
docker run -itd --name kyj_mysqld_exporter -p 9404:9104 -e DATA_SOURCE_NAME="root:123456@(192.168.3.41:3337)" prom/mysqld-exporter
-
mysql
-
主从同步、读写分离====实现 热备份(同时), 异步
-
分表分区
-
主从同步、读写分离
- 至少两个数据,一个做存、读,进行数据变更时候,会自动同步到两个数据中
- 这种方式,可以提升,io利用,从而提供数据写、读速度。
- 关键点: 数据同步
- 数据库的数据操作,其实,都是日志操作。
- 企业中,会要求有两个以上的数据库服务器
-
课程中,主从同步环境搭建,1台机器中,使用docker安装多个不同的数据库容器
- 安装docker
yum install -y yum-utils device-mapper-persistent-data lvm2 curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun # 开机自启动、重启docker systemctl enable docker systemctl restart docker
- 安装mysql数据库
# 下载镜像 docker pull daocloud.io/library/mysql:5.7.7
docker run -itd --name mysq577_master -p 3336:3306 -e MYSQL_ROOT_PASSWORD=123456 daocloud.io/library/mysql:5.7.7 docker run -itd --name mysq577_slave -p 3346:3306 -e MYSQL_ROOT_PASSWORD=123456 daocloud.io/library/mysql:5.7.7
-
定义主数据库、从数据库
-
找到数据库的配置文件,修改配置文件
-
配置文件路径: /etc/mysql/my.cnf
-
修改
# 从容器中,拷贝文件到宿主机 docker cp mysq577_master:/etc/mysql/my.cnf $PWD # 修改配置文件 [mysqld] server-id = 100 log-bin = mysql-bin # server-id值得大小来区分主、从数据库,越小的为主数据库,越大的为从数据 # 把修改后的,拷贝到容器中 docker cp my.cnf mysq577_master:/etc/mysql/my.cnf # 重启动容器
-
两个数据库之间要建立关联关系
# 从数据库中执行 CHANGE MASTER TO MASTER_HOST='192.168.2.42', MASTER_PORT=3336, MASTER_USER='root', MASTER_PASSWORD='123456'; start slave;
show slave status; -- 查看slave的状态
- 重点关注:
- Slave_IO_Runing 必须为 Yes
- Slave_SQL_Runing 必须为 Yes
- 重点关注:
-
数据库操作
- 主数据库的操作,都会同步给从数据
- 一般情况下, 主数据库当作 写数据库, 从数据库,当作读数据
- 代码中,配置两个数据库的信息,存操作时候, 主数据库, 查询操作 使用读数据库
- 主数据库的操作,都会同步给从数据
-
-
分表分区:
- 当数据库的数据量非常大时候,才会去考虑, 一般数据库表中,有大几千万、上亿数据的时候,你们才会考虑分表分区
- 分表:
- 垂直分表: 把表的结构进行拆分,列的数量进行拆分。 把一个大表文件,拆成多个小表,没有个表数据的大小(磁盘占用空间变小)
- 常用字段拆分: 创建视图
- 水平分表
- 把表的总行数变少,列没有变少
- 常见的方法: 时间(月\年, id尾数)
- 垂直分表: 把表的结构进行拆分,列的数量进行拆分。 把一个大表文件,拆成多个小表,没有个表数据的大小(磁盘占用空间变小)
- 分区:
- 分别存储到不同的地方,那么每一份的数据大小变小,同时io利用率变高
CREATE TABLE stu_info_master(
ID
int(8) NOT NULL,
name
varchar(32) DEFAULT NULL,
teacher
varchar(32) DEFAULT NULL,
remark
varchar(32) DEFAULT NULL
) ENGINE=MRG_MYISAM UNION=(stu_info_1, stu_info_2, stu_info_3) INSERT_METHOD=LAST DEFAULT CHARSET=utf8mb4;
MySQL
-
主从同步、读写分离
-
2个以上的数据库
-
主数据库、从数据库配置:
- 1、修改配置文件 server-id 越小,主数据库 大,从数控
- 2、从数据库配置,配置主数据库的host、port、user、password
-
关键点: Slave_IO_Runing Slave_SQL_Runing 一定要为yes
-
-
分表分区
- 分表:
- 垂直分表: 是把表的结构发生变化,列数量发生了变化
- 水平分表: 表结构可能没有变量,行数量发生了变化
- 分表:
CREATE TABLE stu_info_all(
ID
int(8) NOT NULL,
name
varchar(32) DEFAULT NULL,
teacher
varchar(32) DEFAULT NULL,
remark
varchar(32) DEFAULT NULL
)ENGINE=MRG_MYISAM UNION(stu_info_new_1, stu_info_new_2, stu_info_new_3) insert_method=LAST DEFAULT CHARSET=utf8mb4;
- 分区: 数据存到不同的磁盘位置上
- 数据库是否支持分区:
show plugins;
看 partition 这个的值是否为 active。是,说明,我们的数据库支持分区。
- 数据库是否支持分区:
range分区: 给定区间
create table 表名(id,col1,col2…) partition by range(id)
(partition less_10000 values less than(10000) data directory = ‘/opt/less_1w/’ index directory = ‘/opt/less_1w’,
partition less_20000 values less than(20000) data directory = ‘/home/less_2w/’ index directory = ‘/home/less_2w’,
…)
list分区
columns
hash分区
key分区
composite 分区
数据库数据量级 在几千,你连索引都可以不建; 几万,到几十万,上百万数据时,考虑索引;上千万的数据时,考虑 分表; 大几千万,甚至上亿级别数据,这个时候考虑分区。
-
非关系型数据库
- redis 现在企业中普遍使用它来做 缓存数据库
- 内存数据库,但是支持数据持久化
-
redis 常见的数据类型
- 字符串
- 列表
- 集合
- 有序集合
- hash
-
安装redis
yum install gcc-c++ make -y
# 升级gcc
$ yum -y install centos-release-scl
$ yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
$ scl enable devtoolset-9 bash
$ echo "source /opt/rh/devtoolset-9/enable" >>/etc/profile
# 此时,通过gcc -v 看到gcc的版本应该是在9以上
$ wget http://download.redis.io/releases/redis-6.0.8.tar.gz
$ tar xzf redis-6.0.8.tar.gz
$ cd redis-6.0.8
$ make
# 如果想安装到指定路径: make PREFIX=/usr/local/redis install 指定安装到/usr/local/redis路径
# 启动
$ src/redis-server
进入安装路径中 src/redis-cli
进入客户端模式
config get *
# 获取redis的所有配置信息
项目的服务要获取数据 =>redis 获取数据=没有==>底层的数据库
项目的服务要获取数据 =>redis 获取数据=有==>把数据返回给服务
服务器演进架构
- 容器: docker
- 服务: 微服务
- 以前,所有的代码写再一个工程下面,生产项目部署包 就是一个 war、jar
- 现在拆成为微服务: 根据功能模块来拆分, 拆成很多个服务之后,生成项目部署包 就是多个
- 项目部署包多了,使用传统的部署方式, 多个tomcat 消耗非常大的资源
- 想办法把部署的容器发生变化,容器运行消耗资源越少越好。
- 用docker来虚拟容器
- docker: 虚拟化技术发展的一个产品。
- vmware、virtualbox、 + 一个完整的操作系统os ======比较大的资源
- docker一个软件 + 一个不完整的os(最小操作系统) ====对于资源的消耗很少
- 最小的操作系统os: cgroups、namespace、unionFS
- docker虚拟出来的小的操作系统,我们较容器, docker容器
- k8s:一个容器编排与管理的平台\工具
- 目前企业中,使用k8s来管理容器,它创建容器,基本上都是使用docker,2022年,k8s中,将不再支持docker创建容器
docker: 软件
docker容器container: 它是一个沙箱。每一个沙箱之间是相互隔离,默认只有一个出入口,
仓库repository:管理容器的镜像的地方,
Docker Hub Container Image Library | App Containerization
Hub · DaoCloud 国内的镜像
镜像image: 根据你的要求,封装好的一个文件集合
docker容器: docker软件+镜像,运行, 就可以提供服务出来
- docker安装
yum install -y yum-utils device-mapper-persistent-data lvm2
curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
#docker 加速
vim /etc/docker/daemon.json
{"registry-mirrors": ["http://f1361db2.m.daocloud.io", "http://hub-mirror.c.163.com", "https://registry.docker-cn.com"]}
systemctl daemon-reload
systemctl restart docker systemctl enable docker
检查你的系统是否安装docker docker -v
在不知道用,获取帮助 docker --help
[root@centos7 ~]# docker --help
Usage: docker [OPTIONS] COMMAND
A self-sufficient runtime for containers
Options:
--config string Location of client config files (default "/root/.docker")
-c, --context string Name of the context to use to connect to the daemon (overrides DOCKER_HOST env var and
default context set with "docker context use")
-D, --debug Enable debug mode
-H, --host list Daemon socket(s) to connect to
-l, --log-level string Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info")
--tls Use TLS; implied by --tlsverify
--tlscacert string Trust certs signed only by this CA (default "/root/.docker/ca.pem")
--tlscert string Path to TLS certificate file (default "/root/.docker/cert.pem")
--tlskey string Path to TLS key file (default "/root/.docker/key.pem")
--tlsverify Use TLS and verify the remote
-v, --version Print version information and quit
Management Commands:
app* Docker App (Docker Inc., v0.9.1-beta3)
builder Manage builds
buildx* Build with BuildKit (Docker Inc., v0.6.1-docker)
config Manage Docker configs
container Manage containers
context Manage contexts
image Manage images
- 创建一个tomcat容器
- 找镜像 docker pull tomcat:8.5-jdk8-corretto
- 创建容器:
docker run -itd --name tomcat85 -p 8989:8080 tomcat:8.5-jdk8-corretto
- 把项目包丢到里面去
docker run -itd --name tomcat_erp -p 9898:8080 -v $PWD:/usr/local/tomcat/webapps tomcat:8.5-jdk8-corretto
-
留思考:把我们易捷支付项目,使用docker方式来部署
- 一个项目 应用程序 + 数据库
- docker部署应用程序
- jdk1.7 + tomcat
- docker pull 下载 jre7的tag的tomcat镜像
- 项目包 给搭建的kyj机器中 tomcat\webapps下面的app文件夹打包
- 修改配置文件 数据库配置 不一样
- dockers部署数据库
- 容器来安装数据库
- 数据库初始化
-
自己动手
docker
-
安装
-
配置docker
- 1、源
- 2、启动: systemctl restart docker
- 3、开机自启动: systemctl enable docker
-
docker命令
- docker run -----创建一个容器,同时运行这个容器
- docker create ----创建容器,但是不会运行
- docker pull 镜像:tag -----下载镜像
- docker images ----- 查看机器上的镜像
- docker ps ----查看机器上已经创建了哪些容器
- 不再跟参数, 看正在运行的容器
- -a 查看所有的容器,包括未启动的容器
- docker rm -f 容器名称 -----删除容器, 可以删除正在运行的容器
- docker rmi -f 镜像 -----删除镜像
- docker logs 容器名称 ----- 查看容器中的服务运行日志
- dockers network ------容器网络相关配置
- docker exec -----进入容器
- docker cp ----拷贝
- docker inspec 容器名称 ----- 查看容器信息
-
docker 网络
- docker network --help
- docker network create
- docker network connect
- docker network disconnect
docker安装一个mysql数据库容器
docker run -itd --always restart --name=vip11_mysql -p 3336:3306 -e MYSQL_ROOT_PASSWORD=123456 daocloud.io/library/mysql:5.7.31
docker inspect 容器 |grep “IPAddress” -----查看容器的ip
-
kyj项目用docker方式来部署
- 数据库: docker
- 初始化
- 数据库: docker
-
docker部署kyj项目
- kyj项目 jdk1.7
- 创建容器
docker run -itd --name tomcat_1 -p 8484:8080 -v $PWD/webapps/:/usr/local/tomcat/webapps/ daocloud.io/library/tomcat:8.0.44-jre7
docker run -itd --name tomcat_2 -p 8585:8080 -v $PWD/webapps/:/usr/local/tomcat/webapps/ daocloud.io/library/tomcat:8.0.44-jre7
- 项目包: 从原来kyj项目机器中 下载 app.tar.gz包,上传到机器上
数据库的ip : 172.17.0.2 172.18.0.2
tomcat_1: 172.17.0.3
tocmat_2: 172.17.0.4
application.properties: 数据库ip和端口 宿主机的ip和端口 192.168.3.40:3336
application.properties: 数据库ip和端口 宿主机的ip和端口 172.17.0.2:3306
性能测试与调优、 nginx搭建集群
docker run -itd --name vip11-nginx -p 8888:80 daocloud.io/nginx
Ø安装mysql数据库
Ø初始化数据库 redis_goods
CREATE TABLE goods_item
(
id
int(11) NOT NULL AUTO_INCREMENT,
code
varchar(255) DEFAULT NULL COMMENT ‘商品编号’,
name
varchar(255) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT ‘商品名称’,
create_time
datetime DEFAULT NULL,
update_time
datetime DEFAULT NULL,
PRIMARY KEY (id
)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT=‘商品信息表’;
Ø反复执行插入数据
INSERT INTO goods_item(code,name,create_time,update_time) VALUES(‘good_10001’,'高级性能测试VIP课,NOW(),NOW());
-
项目环境搭建
- 上传项目包
- 修改配置文件 conf/application.properties
- 修改conf/wrapper.conf文件
- wrapper.java.command=jdk路径
-
bin文件夹 ./server.sh start
-
http://ip:8089/api/cache/goods/info?itemCode=good_10001
实战
- docker + mysql + kyj项目 + nginx
- 性能测试
- 调优: 数据库优化 -------增加索引
- dockers + kyj + nginx
docker run -itd --name nginx_kyj -p 80:80 nginx
nginx.conf 集群的文件
-
知识回顾
- 服务器架构演进一
- 所有的项目代码,放在一个工程下面------对于服务器硬件要求很高
- 服务器架构演进二
- 拆分: 数据库服务器、文件服务器、应用服务器、集群
- 服务器架构演进三
- 应用拆分: 应用集群、 数据库集群
- 服务器架构演进四
- 应用再拆分: 微服务、 docker容器化
- 服务器架构演进一
-
性能知识:
-
硬件: cpu、内存、磁盘、io、网络
- top\vmstat\pidstat\mpstat\iostat\netstat\sar…
- yum install sysstat -y
- cpu:
- cpu的组成: 控制单元、寄存单元、计算单元、 + 时钟
- 上下文切换
- 进程上下文切换
- 线程上午文切换
- 内存:
- 虚拟内存
- 物理内存
- GC: YGC FGC 回收资源的时候,会导致 卡顿。
- 内存泄漏、内存溢出
- OOM
- jmap 堆栈信息dump下来
- arthas 堆栈信息dump下来
- MAT
- OOM
- IO: 换入换出
- 磁盘: buff cache
- dd
- 磁盘: buff cache
- 网络:
- 发起方1端口
- 带宽
- ulimit
- sysctl
- top\vmstat\pidstat\mpstat\iostat\netstat\sar…
-
应用
- tomcat
- 配置文件
- 堆栈信息
- 线程池
- 配置文件
- nginx: 负载均衡 集群策略
- nginx.conf
- 数据库:
- mysql:
- 安装数据、docker安装
- 数据库配置my.cnf
- 库、表
- 表: 存储引擎 InnoDB MyISAM
- 表:索引
- 主键索引
- 唯一索引
- 复合索引
- select: 编写顺序、解析顺序不一样
- explain select
- 慢查询脚本
- 数据库配置的优化: too many connect \ 500
- redis
- 内存数据库
- 安装、redis
- mysql:
- tomcat
-
微服务: docker + 项目(springcloud)
- docker命令
- docker run
- docker rm
- docker pull
- docker images
- docker rmi
- docker ps
- docker logs
- docker inspect
- docker exec
- docker network
- docker restart
- docker stats
- docker命令
-
-
简历编写
- 简历第一阅读人?
- 专业词
- 项目记录中,要有性能测试相关技术实践
- 简历第一阅读人?