测试基础知识进阶


服务器

  • 云服务器 + 微服务 + docker -----基本是标配

  • linux + springcould + docker

    • windows: 最开始的时候,主流的服务器的操作系统,确实是windows
      • windows server 2003 图像界面 windows98
  • 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
  • 获取命令的帮助:

    • 第一种: 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
    • 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数量的一个总体的使用率
  • 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 : 数字 现在有多少进程正在不可中断的休眠. 如果这个数字过大,就说明,资源不够用。
  • 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 至少有一个活跃请求的所占的时间百分比
  • 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
  • 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

===你们考虑一下,这个问题这么解决?

​ ----已经定位到了具体是哪个程序导致了

​ 要么换磁盘,要么迁移到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 弹出我们最后一个数据
    • 队列: FIFO 排队
      • 顺序队列,
      • 循环队列
    • 堆heap: 存储的数据比较复杂
      • 对象
  • 一个程序: 如: 这个程序启动要 256m

    • 先有一个虚拟内存地址 + 物理内存地址
    • 虚拟内存地址: 记录物理内存中存储了哪些数据,在什么地方
  • jvm: java虚拟机

    • 程序计数器、java虚拟机栈、本地方法栈、方法区、堆内存

    • 程序计数器:记录程序执行字节码的行号指示器

    • 内存泄漏: 内存的资源不及时释放,一直占用,导致可用的内存资源越来越少。

    • 内存溢出:内存泄漏到一定的时间,可用的空间就会越来越少,某一次我要用比较大的空间时,发现,我申请不到足够的空间了,我申请的空间已经超过最大可用空间,内存溢出。

      • 内存溢出,在错误日志,会出现
      • jmap
      • arthas

top: 进程列表中有3列, 虚拟内存、物理内存、共享内存

  • 堆内存:新生代、老年代、永久代(元空间)
    • 新生代new:昙花一现,朝生夕死的对
      • 如:你写的代码,方法里面变量
    • 老年代Tenured:
      • 新生代数据,经过copy算法,如copy了15次,

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信息
    • 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也有数
    • 我现在磁盘的写速度大概时400MB/s
  • 测试磁盘的速度

    • 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有,但是不是很大
  • 测试内存的速度

    • 1、先清空缓存 echo 3 >/proc/sys/vm/drop_caches
    • 2、脚本: dd if=/dev/zero of=/dev/null bs=10MB count=1000

结论: 磁盘的读写速度,几百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目标服务器
        • 看时间 没有测试前的时间 与在进行性能测试时的 时间之间有没有明显的差异
        • 看丢包: 如果有丢包 肯定时网络瓶颈

网络包

  • 源地址

  • 源端口:

    • 每发起一次请求,就要占用发起方一个端口
      • 端口数量是有限的,端口数量就可能成为性能瓶颈
      • 出现错误?: 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
        • 可能的原因2: 服务器要调优
          • os操作系统
            • sysctl
            • ulimit -n
          • 应用中间件
            • 连接池
              • 应用连接池
              • 数据库连接池
  • 目标地址

  • 目标端口

  • 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
        • 内存溢出
        • 内存泄漏
  • 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
    • 目标地址
      • 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部署多个项目

springcloud,自己带有tomcat,它打出来的jar包,可以直接运行

java -jar xxxx.jar 默认就是8080

回顾

  • tomcat配置文件

    • 堆栈:
      • bin文件夹中 catalina.sh文件
      • JAVA_OPTS 堆栈信息
    • 端口\线程池
      • conf文件夹 sever.xml文件
      • 修改port
      • 线程池
  • grafana+prometheus 监控tomcat

    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

因为关系型数据库,遵循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
      • 什么是存储引擎?
      • 存储引擎,不同的引擎,有不同的性能,所以,我们在建表的时候,要合理的选择存储引擎。
    • 索引

      • 主键索引: 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=? ×

数据库

  • 建表: 建表的时候,要特别注意,存储引擎,因为,存储引擎,直接影响这个表的性能。

  • 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
  • 分析慢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数据库

    Hub · DaoCloud

    Docker Hub

    # 下载镜像
    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部署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
      • IO: 换入换出
        • 磁盘: buff cache
          • dd
      • 网络:
        • 发起方1端口
        • 带宽
        • ulimit
        • sysctl
    • 应用

      • tomcat
        • 配置文件
          • 堆栈信息
          • 线程池
      • nginx: 负载均衡 集群策略
        • nginx.conf
      • 数据库:
        • mysql:
          • 安装数据、docker安装
          • 数据库配置my.cnf
          • 库、表
            • 表: 存储引擎 InnoDB MyISAM
            • 表:索引
              • 主键索引
              • 唯一索引
              • 复合索引
            • select: 编写顺序、解析顺序不一样
            • explain select
            • 慢查询脚本
            • 数据库配置的优化: too many connect \ 500
        • redis
          • 内存数据库
          • 安装、redis
    • 微服务: 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
  • 简历编写

    • 简历第一阅读人?
      • 专业词
      • 项目记录中,要有性能测试相关技术实践
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值