前言

Github:https://github.com/HealerJean

博客:http://blog.healerjean.com

一、数据库性能指标

1、磁盘性能指标

1、IOPS 和 数据吞吐量适用于不同的场合:

关注 IOPS:随机读写频繁的应用,如小文件存储(图片)、OLTP数据库、邮件服务器,关注随机读写性能,是关键衡量指标。

关注 IO Thruput :顺序读写频繁的应用,传输大量连续数据,如电视台的视频编辑,视频点播 VOD(Video On Demand),关注连续读写性能。数据吞吐量是关键衡量指标。

IOPS 和数据吞吐量适用于不同的场合:

追求 IOP :读取 100001KB 文件,用时 10Throught (吞吐量) = 1MB/sIOPS = 1000

追求吞吐量:读取1个10MB文件,用时0.2Throught(吞吐量) = 50MB/s, IOPS = 5

1)IOPS:磁盘的读/写操作次数

IOPS 是指单位时间内系统能处理的 I/O 请求数量,一般以每秒处理的 I/O 请求数量为单位,I/O请求通常为读或写数据操作请求。

read: 每秒磁盘的读操作次数

write: 每秒磁盘的写操作次数

image-20211231114534339

2)IO Thruput(KB)IO读写吞吐量

IOPS (Input / Output Per Second) 即每秒的读写次数,是衡量磁盘性能的主要指标之一。

read: 磁盘读吞吐量

write: 磁盘写吞吐量

image-20211231114430211

2、机器性能指标

1)cpu usage cpu load

cpu usagecpu 利用率,就是程序对CPU时间片的占用情况

load average 表示的是 CPU的负载,包含的信息不是CPU的使用率状况,而是在一段时间内CPU正在处理以及等待CPU 处理的进程数之和的统计信息,也就是是一段时间内正在使用和等待使用CPU的平均任务数。这个数字越小越好,CPU利用率高,并不意味着负载就一定大

如果load average值长期大于系统CPU的个数则说明CPU很繁忙,负载很高,可能会影响系统性能,导致系统卡顿响应时间长等等

举例来说:如果我有一个程序它需要一直使用 cpu 的运算功能,那么此时 cpu 的使用率可能达到100%,但是 cpu 的工作负载则是趋近于 “1”,因为 cpu 仅负责一个工作嘛!如果同时执行这样的程序两个呢?cpu 的使用率还是 100% ,但是工作负载则变成2了。所以也就是说,当cpu的工作负载越大,代表cpu必须要在不同的工作之间进行频繁的工作切换。

image-20211231114348705

2)Network Flow(kb):网卡出/入口流量

recv:网卡入口流量

send:网卡出口流量

image-20211231114453562

3)IOUTIL:机器的 IO 使用率

image-20211231114935940

3、MYSQL SQL相关

1)SQL:语句操作数量

ins: insert 语句操作的数量

upd: update 语句操作的数量

del: delete语句操作的数量

image-20211231113958428

2)ROWS:语句影响行

insinsert 语句操作的数量

updupdate语句操作的数量

deldelete语句操作的数量

read:读取的行数

image-20211231114125454

2.1.3、QPS/TPS

image-20211231115005063

4、Innodb

1)Innodb Buffer Poll Hit Ratio

image-20211231115023948

2)Thread Connect:当前已连接线程数

image-20211231115143202

3)Thread Running:当前活跃连接数

image-20211231115231959

4)Thead Other Status:线程其他状态

thead_create:新创建线程数

thread_cachethread_cache 中已缓存的线程数

image-20211231115329218

5)Innodb Buffer Poll Status(MB)

pages_data: Innodb 缓存池数据页占用量

pages_free: Innodb 缓存池空闲页占用量

pages_dirty: Innodb 缓存池脏页占用量

image-20211231115503255

6)Inodb Pages Flush

pages_flush: Innodb 缓存池每秒flush 操作请求数

image-20220112214016757

7)Innodb IOPS

data_reads: Innodb 数据每秒物理读请求数

data_writes: Innodb 数据每秒物理写请求数

image-20220112214208750

8)Innodb IO Thruput

data_read: Innodb 数据每秒物理读取量

data_written: Innodb 数据每秒物理写入量

image-20220112214405752

9Innodb Main Thread

read_view: 当前打开 read view 个数

query_queue: 当前 Innodb 等待队列中的线程数

query_inside: 当前 Innodb 内核线程数

image-20220112214634293

10)Undo History List Length

his_list: 当前 undo 表空间中还未purge 的事务个数

image-20220112214743539

2.4.11、Innodb ReDo Log(byte)

log_unflush: Innodb当前还未flush的redo日志大小

log_unchkpt: Innodb当前还未checkpoint的redo日志大小

image-20220112215001849

5、连接&线程

1)max_connections

**max_connections ** MYSQL 服务端允许的最大连接会话数量; (maxAcvie以它为主)

默认值是15MySQL 允许的最大连接数上限是 16384

mysql> show variables like 'max_connections';
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| max_connections | 3100 |
+-----------------+-------+

2)Thread

Threads_connected: 这个数值指的是打开的连接数,跟 show processlist 结果相同,表示当前连接数。

Threads_running:是代表当前并发数,这个数值指的是激活的连接数,这个数值一般远低于 connected 数值。

mysql> show status like 'Threads%';
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| Threads_cached | 429 |
| Threads_connected | 102 | 
| Threads_created | 1915 |
| Threads_running | 3 |
+-------------------+-------+

3)Max_used_connections

max_user_connections这MySQL服务器过去的最大连接数是245,没有达到最大连接数的上限

理想:max_used_connections / max_connections * 100%85%

mysql>show global status like 'Max_used_connections';
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| Max_used_connections | 762 |
+-------------------+-------+

查看上次 MYSQL 启动后的最大连接数

mysql> show global status like 'Max_used_connections';
+-----------------------------------+---------------------+
| Variable_name                     | Value               |
+-----------------------------------+---------------------+
| Max_used_connections              | 762                   |
| Max_used_connections_time         | 2021-04-29 17:36:51 |

4)innodb_thread_concurrency

支持的最大并发执行的线程数:这个是 innodb内核的并发线程处理参数,即同一时刻能够进入 innodb 层次并发执行的线程数(「注意是并发不是并行」)。比如前端有 100 个连接,发来 1000sql,如果这个参数被设置成2。那么这 1000sql 中,最多只有 2sqlinnodb 内核运行。其它都得等。(事实上,处理过程很复杂,可以先这么理解,不是所有 sql 都需要放在 Innodb 内核处理的)。

a、默认 0

默认 0 ,则表示没有并发线程数限制,所有请求都会直接请求线程执行。注意:当 innodb_thread_concurrency设置为 0 时,则 innodb_thread_sleep_delay 的设置将会被忽略,不起作用。如果数据库没出现性能问题时,使用默认值即可。

b、大于 0

当 > 0,则表示有并发数限制

1、 当一个新的请求发起时,会检查当前并发线程数是否达到了innodb_thread_concurrency 的限制值,如果有,则需要 sleep 一段时间,然后再再次请求

2、如果再次请求时,当前并发数还是达到限制值,那么就会进入 FIFO 队列等待执行。

3、当进入到内核执行时,会得到一个消费凭证 ` ticket,则这个线程,在后面的多次进入 innodb 执行操作是都不需要重复上面的检查步骤,当把次数消费完,那么这个线程就会被驱逐,等待下次再次进入 Innodb,再重新分配 ticket`。

4、那些等待获取锁的线程则不会被计入到并发执行线程 innodb_thread_concurrency 的数量中。

c、建议配置

⬤ 当并发用户线程数量小于 64,建议设置 innodb_thread_concurrency = 0

⬤ 如果负载不稳定,时而低,时而高到峰值,建议先设置 innodb_thread_concurrency = 128,并通过不断的降低这个参数,96 , 80 , 64 等等,直到发现能够提供最佳性能的线程数,例如,假设系统通常有 4050 个用户,但定期的数量增加至 6070,甚至 200。你会发现,性能在 80个并发用户设置时表现稳定,如果高于这个数,性能反而下降。在这种情况下,建议设置 innodb_thread_concurrency参数为80,以避免影响性能;

注意:

⬤ 如果 DB 服务器上还允许其他应用,需要限制 mysql 的线程使用情况,则可以设置可分配给 DB的线程数,但是不建议 DB上跑其他应用,也不建议这么设置,因为这样可能导致数据库没有对硬件最优使用;

⬤ 设置过高值,可能会因为系统资源内部争夺导致性能下降「在大多数情况下,最佳的值是小于并接近虚拟CPU的个数;」

⬤ 定期监控和分析 DB,因为随着数据库负载的变化,业务的增加,innodb_thread_concurrency 也需要动态的调整

6、问题

1)问题1:应用连接被打满

### Error updating database. Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is com.alibaba.druid.pool.GetConnectionTimeoutException: wait millis 5000, active 10, maxActive 10, creating 0

a、问题出现

在一次 JD 预发环境验证保险保单的时候,只有一台服务,数据库连接配置为:maxWait: 5000maxActive: 10initialSize: 5。很高流量的运费险到达之后,就出现了上面的报错信息。报错信息说明,已经把数据库连接池打满了,并且等待了 5s 还是不能获取连接,所以报错了。

b、问题解决

查询总连接数,增大连接解决

二、服务器性能指标

1、容器指标

1)线程和进程

a、批处理操作系统

批处理操作系统就是把一系列需要操作的指令写下来,形成一个清单,一次性交给计算机。用户将多个需要执行的程序写在磁带上,然后交由计算机去读取并逐个执行这些程序,并将输出结果写在另一个磁带上。

批处理操作系统在一定程度上提高了计算机的效率,但是由于批处理操作系统的指令运行方式仍然是串行的,内存中始终只有一个程序在运行,后面的程序需要等待前面的程序执行完成后才能开始执行,而前面的程序有时会由于I/O操作、网络等原因阻塞,导致CPU闲置所以批处理操作效率也不高

b、进程的提出

批处理操作系统的瓶颈在于内存中只存在一个程序,进程的提出,可以让内存中存在多个程序,每个程序对应一个进程,进程是操作系统资源分配的最小单位。

1、CPU 采用时间片轮转的方式运行进程:

2、CPU 为每个进程分配一个时间段,称作它的时间片。

3、如果在时间片结束时进程还在运行,则暂停这个进程的运行,并且CPU 分配给另一个进程(这个过程叫做上下文切换)。

4、如果进程在时间片结束前阻塞或结束,则 CPU立即进行切换,不用等待时间片用完。多进程的好处在于一个在进行IO操作时可以让出 CPU 时间片,让 CPU 执行其他进程的任务。

c、线程的提出

随着计算机的发展,对CPU的要求越来越高,进程之间的切换开销较大,已经无法满足越来越复杂的程序的要求了。于是就发明了线程,线程是程序执行中一个单一的顺序控制流程,是程序执行流的最小单元,是处理器调度和分派的基本单位。一个进程可以有一个或多个线程,各个线程之间共享程序的内存空间(也就是所在进程的内存空间)。

d、进程和线程的区别

进程是计算机中已运行程序的实体,进程是操作系统资源分配的最小单位。而线程是在进程中执行的一个任务,是CPU调度和执行的最小单位。他们两个本质的区别是是否单独占有内存地址空间及其它系统资源(比如I/O)

⬤ 一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程(通常说的主线程)。

进程单独占有一定的内存地址空间,所以进程间存在内存隔离,数据是分开的,数据共享复杂但是同步简单,各个进程之间互不干扰;而线程共享所属进程占有的内存地址空间和资源,数据共享简单,但是同步复杂

⬤ 进程单独占有一定的内存地址空间,一个进程出现问题不会影响其他进程,不影响主程序的稳定性,可靠性高;一个线程崩溃可能影响整个程序的稳定性,可靠性较低

⬤ 进程单独占有一定的内存地址空间,进程的创建和销毁不仅需要保存寄存器和栈信息,还需要资源的分配回收以及页调度,开销较大;线程只需要保存寄存器和栈信息,开销较小

另外一个重要区别是,进程是操作系统进行资源分配的基本单位,而线程是操作系统进行调度的基本单位,即CPU分配时间的单位

2)句柄数

指标含义:当前容器内打开的文件句柄数

指标解释:在文件 I/O 中,要从一个文件读取数据,应用程序首先要调用操作系统函数并传送文件名,并选一个到该文件的路径来打开文件。该函数取回一个顺序号,即文件句柄(file handle),该文件句柄对于打开的文件是唯一的识别依据。要从文件中读取一块数据,应用程序需要调用函数 ReadFile,并将文件句柄在内存中的地址和要拷贝的字节数传送给操作系统。当完成任务后,再通过调用系统函数来关闭该文件。

2、系统指标

1)CPU 使用率

CPU 使用率(CPU Utilization )是指CPU 正在执行任务的时间占总时间的百分比。它是衡量计算机性能的一个重要指标,反映了 CPU 的繁忙程度。CPU 使用率越高,说明CPU正在处理的任务越多,性能负载也就越大。

a、计算方法

CPU 使用率通常是通过比较在特定时间间隔内 CPU 执行指令的时间与总时间来计算的。

例如,如果在一个1秒的时间间隔内,CPU0.8 秒在执行指令,那么 CPU 使用率就是 80%

b、影响因素

⬤ 运行的程序数量和类型:同时运行的程序越多,特别是那些需要大量计算资源的程序,CPU 使用率就越高。

⬤ 系统负载:系统的整体负载,包括I/O 操作、内存使用等,也会影响 CPU 使用率。

⬤ 硬件规格:CPU 的核心数量、频率等硬件规格也会影响其处理能力,从而影响 CPU使用率。

c、优化建议

⬤ 关闭不必要的程序和服务:减少同时运行的程序数量,可以降低CPU使用率。

⬤ 升级硬件:如果经常遇到CPU使用率过高的问题,可能需要考虑升级CPU或增加内存等硬件资源。

优化软件:使用更高效的算法和编程技术,可以减少软件对CPU资源的占用。

2)RSS

RSSResident Set Size)内存使用率表示的是一个进程在物理内存中实际占用的空间量。当限制堆内存的情况下,RSS内存使用率的最高值会受到多个因素的影响,包括但不限于以下几点:

1、堆内存限制 直接因素:首先,RSS 会包含 JVM (或其他运行时环境)为堆内存分配的物理内存。因此,如果堆内存被限制在某个特定大小(如通过 JVM-Xmx 参数设置),那么这部分内存将是 RSS 的一个固定上限(或主要部分)。

2、非堆内存 间接因素:RSS 不仅包含堆内存,还包含非堆内存区域(如方法区、线程栈、本地方法栈、直接内存等)以及 JVM 进程所需的其他操作系统资源(如内核栈、进程管理数据结构等)。这些非堆内存区域的大小也会影响RSS的总量。

3、线程数量 影响因素:JVM 中线程的数量会直接影响 RSS,因为每个线程的栈都需要分配物理内存。因此,如果应用创建了大量的线程,即使堆内存被限制,RSS 也可能因为线程栈的增加而上升。

问题1:如果 4C8G-Xmx 配置了 6G RSS 最少是 75 吗?

答案:在大多数情况下,当 -Xmx 设置为 6G 时,JVM 进程的RSS 内存使用率会超过 75% 。然而,不意味着 JVM 进程在操作系统中实际占用的物理内存(即 RSS 内存)就恰好是 6G。在极少数特殊情况下(如非堆内存非常小、内存共享和重用、系统其他进程的内存使用等),RSS 内存使用率可能会低于 75% 。但请注意,这些情况在实际应用中较为罕见,且通常不会显著影响 RSS 的值。

3)系统负载

load average 表示的是 CPU的负载,包含的信息不是CPU的使用率状况,而是在一段时间内 CPU 正在处理以及等待 CPU 处理的进程数之和的统计信息,也就是是一段时间内正在使用和等待使用 CPU 的平均任务数。这个数字越小越好,CPU 利用率高,并不意味着负载就一定大

如果 load average 值长期大于系统 CPU 的个数则说明CPU很繁忙,负载很高,可能会影响系统性能,导致系统卡顿响应时间长等等

举例来说:

◯ 如果我有一个程序它需要一直使用 cpu 的运算功能,那么此时 cpu 的使用率可能达到100%,但是 cpu 的工作负载则是趋近于 “1”,因为 cpu 仅负责一个工作嘛!

◯ 如果同时执行这样的程序两个呢?cpu 的使用率还是 100% ,但是工作负载则变成2了。所以也就 是说,当cpu的工作负载越大,代表 cpu 必须要在不同的工作之间进行频繁的工作切换。

a、单核处理器的情况

 行车过桥一只单核的处理器可以形象得比喻成一条单车道。

  设想下,你现在需要收取这条道路的过桥费 ,忙于处理那些将要过桥的车辆。你首先当然需要了解些信息,例如车辆的载重、以及 还有多少车辆正在等待过桥。如果前面没有车辆在等待,那么你可以告诉后面的司机通过。 如果车辆众多,那么需要告知他们可能需要稍等一会。

  0.00 表示目前桥面上没有任何的车流,过往的车辆可以丝毫不用等待的通过。   1.00 表示刚好是在这座桥的承受范围内。 这种情况不算糟糕,只是车流会有些堵,不过这种情况可能会造成交通越来越慢。   超过 1.00,那么说明这座桥已经超出负荷,交通严重的拥堵。 那么情况有多糟糕? 例如 2.00 的情况说明车流已经超出了桥所能承受的一倍,那么将有多余过桥一倍的车辆正在焦急的等待。3.00 的话情况就更不妙了,说明这座桥基本上已经快承受不了,还有超出桥负载两倍多的车辆正在等待。

  上面的情况和处理器的负载情况非常相似。一辆汽车的过桥时间就好比是处理器处理某线程的实际时间。Unix 系统定义的进程运行时长为所有处理器内核的处理时间加上线程 在队列中等待的时间。

  **在实际情况中,有经验的系统管理员都会将这条线划在 0.70:所以你说的理想负荷为 1.00 ?”,负荷 1.00 说明系统已经没有剩余的资源了。 **

  “需要进行调查法则”: 如果长期你的系统负载在 0.70 上下,那么你需要在事情变得更糟糕之前,花些时间了解其原因。

  “现在就要修复法则”:1.00 。 如果你的服务器系统负载长期徘徊于 1.00,那么就应该马上解决这个问题。否则,你将半夜接到你上司的电话,这可不是件令人愉快的事情。

  “凌晨三点半锻炼身体法则”:5.00。 如果你的服务器负载超过了 5.00 这个数字,那么你将失去你的睡眠,还得在会议中说明这情况发生的原因,总之千万不要让它发生。

b、多个处理器的情况

  那么多个处理器呢?我的均值是 3.00,但是系统运行正常!,你有四个处理器的主机?那么它的负载均值在 3.00 是很正常的

​ 对于具有多个 CPU 核心的系统,Load Avg的值应该与 CPU 核心数相乘来理解。例如,在一个拥有 4CPU 核心的系统上,如果Load Avg的值为 4.0,那么这通常表示系统的负载是平衡的,每个核心都在满负荷工作,但没有过载。如果这个值大于 4.0,比如6.0,那么表示系统平均有 6.0 / 4 = 1.5个进程在等待 CPU 资源,即系统可能处于过载状态。

c、多核与多处理器

  我们来讨论下多核心处理器与多处理器的区别。从性能的角度上理解,一台主机拥有多核心的处理器与另台拥有同样数目的处理器性能基本上可以认为是相差无几。当然实际情况会复杂得多,  但即便这些因素造成的实际性能稍有不同,其实系统还是以处理器的核心数量计算负载均值 。这使我们有了两个新的法则:

  核心分布在分别几个单个物理处理中并不重要,其实两个四核的处理器 等于四个双核处理器 等于 八个单处理器。所以,它应该有八个处理器内核。 在多核处理中,你的系统均值不应该高于处理器核心的总数量。

d、分析

一般能够被接受的值是 load average <= CPU核数 * 0.7

  很多人会这样理解负载均值:三个数分别代表不同时间段的系统平均负载(一分钟、五 分钟、以及十五分钟),它们的数字当然是越小越好。数字越高,说明服务器的负载越 大,这也可能是服务器出现某种问题的信号。

  而事实不完全如此,是什么因素构成了负载均值的大小,以及如何区分它们目前的状况是 “好”还是“糟糕”?什么时候应该注意哪些不正常的数值?

  最后一个问题,"load average"一共返回三个平均值----1分钟系统负荷、5分钟系统负荷,15分钟系统负荷,----应该参考哪个值?

如果只有1分钟的系统负荷大于处理器内核,其他两个时间段都小于,这表明只是暂时现象,问题不大。

如果15分钟内,平均系统负荷大于处理器内核,表明问题持续存在,不是暂时现象。所以,你应该主要观察”15分钟系统负荷”,将它作为电脑正常运行的指标

4)系统时间偏差

指标含义:系统时间偏差指的是系统时间与网络时间(或标准时间)之间的误差。在 Linux 系统中,这一现象尤为值得关注,因为Linux系统使用两个时钟来跟踪时间:硬件时钟(RTC)和软件时钟(System clock)。

指标解释:实际上,linux 系统有两个时钟:

a、硬件时钟(RTC

定义:硬件时钟,也被称为 RTCReal Time Clock)或 CMOS 时钟,是由主板电池驱动的。

功能:在操作系统关机时,RTC 负责记录时间。它可以在 BIOS 中进行设置,并在系统启动时提供初始时间给软件时钟。

举例:假设你的电脑在晚上10点关机,此时操作系统不再运行。但是,RTC 会继续由主板电池供电并记录时间。当你第二天早晨开机时,RTC 能够提供准确的关机时间(即晚上10点)以及当前时间(假设是早晨 8 点,基于 RTC在关机期间持续计时)。

b、软件时钟(System clock

定义:软件时钟,也被称为内核时钟或系统时钟,是由软件根据时间中断来进行计数的。

特性:内核时钟在系统关机的情况下是不存在的。因此,当操作系统启动时,它会读取 RTC 的时间来进行同步。同时,系统也会将关机时的时间写回 RTC,以保持时间的一致性;如果你的电脑连接到了互联网,并且配置了 NTP 服务器,那么系统时钟可以定期与 NTP 服务器同步时间。这有助于确保系统时间的准确性,特别是在跨时区旅行或网络时间服务器提供更准确时间的情况下。

举例:假设你的电脑在启动时从 RTC 读取的时间是上午8点,但由于某种原因(如 RTC 电池电量不足导致的时钟漂移),这个时间实际上比真实时间慢了5分钟。此时,如果系统配置了 NTP 同步,并且与 NTP 服务器的连接正常,那么系统时钟会在一段时间后自动调整为正确的时间(即上午8点05分,假设这是真实时间)

c、系统时间偏差的产生原因

时钟漂移:即使是最精确的时钟,也会随着时间的推移而产生微小的偏差,这被称为时钟漂移。这种偏差可能是由于时钟晶体的物理特性、温度变化或其他环境因素引起的。

系统负载:系统负载的变化也可能影响时钟的准确性。例如,当系统处于高负载状态时,处理时间中断的延迟可能会增加,从而导致时钟偏差。

软件错误:软件中的错误或漏洞也可能导致时钟偏差。例如,如果系统时间更新程序存在缺陷,那么它可能无法正确地同步时间。

d、如何检测和修复系统时间偏差

使用命令检测:在 Linux 系统中,可以使用“date”命令来查看当前系统时间。通过与网络时间或标准时间进行比较,可以判断系统时间是否存在偏差。

手动调整:如果发现系统时间偏差较大,可以通过手动调整来修复。使用“ date -s”命令可以设置新的系统时间。

使用 NTP 同步NTP是一种网络时间协议,它可以帮助系统从互联网上获取准确的时间信息,并自动同步到本地系统中。通过设置 NTP服务器的地址,系统可以定期更新时间,以保持与标准时间的一致性。

5)用户态&内核态 CPU 使用率

a、用户态与内核态

⬤ 用户态:用户程序运行时的状态,不能执行特权指令,不能直接访问系统资源,也不能改变 CPU 的工作状态。用户态下的程序只能访问自己的存储空间。

⬤ 内核态:操作系统内核运行时的状态,具有较高的特权级别,可以执行特权指令,直接访问系统资源,并改变 CPU 的工作状态。

b、用户态CPU使用率的重要性

⬤ 高用户态 CPU 使用率可能意味着应用程序正在执行大量的计算任务,或者存在某些性能瓶颈,如算法效率低下、资源竞争等。

⬤ 低用户态 CPU 使用率则可能表明应用程序在等待I/O操作完成(如磁盘读写、网络通信等),或者处于空闲状态。

c、用户态与内核态的切换

⬤ 当用户程序需要执行特权操作(如访问系统资源、改变 CPU 状态等)时,它必须通过系统调用接口( API )请求操作系统内核的帮助。这时,用户态会切换到内核态,执行相应的特权操作,然后再切换回用户态继续执行用户程序。

⬤ 频繁的用户态与内核态切换会增加系统的开销,降低性能。因此,优化系统调用和减少不必要的特权操作是提高系统性能的重要手段。

d、CPU 使用率

⬤ 用户态CPU使用率:应用程序代码所执行的时间占 CPU 总执行时间的百分比。

系统态CPU使用率:应用程序调用操作系统代码所执行的时间占 CPU 总时间的百分比。

6)SWAP 使用率

SWAP 使用率指的是系统中交换分区( Swap Space)或交换文件(Swap File)被使用的程度。以下是对 SWAP 使用率的详细解释:

SWAP 使用率是指操作系统中交换空间( Swap Space)的使用程度,它是衡量系统内存压力的一个重要指标,就是当内存不足的时候,把一部分硬盘空间虚拟成内存使用,从而解决内存容量不足的情况。

交换分区是硬盘上的一部分空间,被操作系统用来作为虚拟内存。当系统的物理内存/运行内存(RAM)不足以应对当前运行的所有任务时,操作系统会将一些不常用的数据从物理内存移到交换分区,从而释放出更多的物理内存供其他任务使用。这样,即使物理内存不足,系统也能通过交换分区来继续运行程序,避免程序因内存不足而崩溃。

a、SWAP 使用率的影响

性能下降:当 SWAP 使用率较高时,系统可能会频繁地进行内存和交换空间之间的数据交换,这会导致磁盘 I/O 操作增加,从而降低系统性能。

系统不稳定:如果 SWAP 空间被完全耗尽,系统可能无法为新的任务分配内存,这可能导致程序崩溃或系统变得不稳定。

硬盘磨损:由于交换操作涉及磁盘读写,因此高 SWAP 使用率可能会增加硬盘的磨损,缩短其使用寿命。 ### SWAP使用率的管理

3、磁盘指标

1)Disk 使用率(磁盘使用率)

指标含义:磁盘使用率百分比 (%)

2)磁盘繁忙

磁盘负载百分比(%)

3)磁盘写速度

磁盘每秒写入的数据量( KB/s)

4)磁盘读速度

磁盘每秒读取次数(次/s)

5)磁盘写次数

磁盘每秒写入次数(次/s)

6)磁盘读次数

磁盘每秒读取次数(次/s)

4、网络指标

1)网络流入速率

网络入向流量(MB/s),网络向内接收的流量。

2)网络流出速率

网络出向流量(MB/s),网络向外发送的流量。

3)网络流入包数 /秒

指标含义:网络入向包速率(packet/s),指单位时间内(如1秒)从网络设备(如网卡)流出的数据包总数,这些数据包可能属于不同的网络协议(如 TCPUDPICMP 等)。

指标解释: 数据包:包( Packet )是 TCP/IP 协议通信传输中的数据单位,一般也称“数据包”。

4)网络流出包数 /秒

指标含义:网络出向包速率(packet/s);网络向外发送包的个数。

5)网络发送丢包数

网络数据的发送过程中被丢弃包的数量,在网络数据的收发过程中,由于种种原因,数据包还没传输到应用程序中,就被丢弃了

6)网络接收丢包数

网络数据的接收过程中被丢弃包的数量,在网络数据的收发过程中,由于种种原因,数据包还没传输到应用程序中,就被丢弃了

7)网络流入错误数

网络数据的接收过程中校验后错误包的数量

8)网络流出错误数

网络数据的发送过程中校验后错误包的数量

9)TCP 连接数 /秒

当前处于“ ESTABLISHED (正在连接)”状态的 tcp 连接数。

10)TCP 主动打开数 /秒

指标含义:主动建立 tcp 连接频率,既主动发送 SYN,进入“SYN-SENT”状态的频率(次/s)

指标解释SYN_SENT 表示请求连接,当你要访问其它的计算机的服务时首先要发个同步信号给该端口,此时状态为 SYN_SENT,如果连接成功了就变为 ESTABLISHED ,此时 SYN_SENT 状态非常短暂。但如果发现 SYN_SENT 非常多且在向不同的机器发出,那你的机器可能中了冲击波或震荡波之类的病毒了。这类病毒为了感染别的计算机,它就要扫描别的计算机,在扫描的过程中对每个要扫描的计算机都要发出了同步请求,这也是出现许多 SYN_SENT 的原因。

11)TCP 接收包数/秒

指单位时间内(如1秒)通过TCP协议成功接收的数据包数量。

12)TCP 发送包数 /秒

单位时间内(如1秒)通过TCP协议成功发送的数据包数量。

13)TCP 包传输错误数 /秒

TCP 是一个可靠的协议,TCP 包的头部带有标识,通过校验发现接收的包是错误的,然后将该包进行丢弃后返回一个值要求重新进行传送。

5、问题

1)一台服务器最大能打开的文件数

a、限制参数

我们知道在 Linux 中一切皆文件,那么一台服务器最大能打开多少个文件呢?Linux 上能打开的最大文件数量受三个参数影响,分别是:

参数 级别 说明
fs.file-max 系统 该参数描述了整个系统可以打开的最大文件数量。但是 root 用户不会受该参数限制(比如:现在整个系统打开的文件描述符数量已达到 fs.file-max ,此时 root 用户仍然可以使用 pskill 等命令或打开其他文件描述符)
soft nofile 进程 限制单个进程上可以打开的最大文件数。只能在 Linux 上配置一次,不能针对不同用户配置不同的值
fs.nr_open 进程 限制单个进程上可以打开的最大文件数。可以针对不同用户配置不同的值

这三个参数之间还有耦合关系,所以配置值的时候还需要注意以下三点:

1、如果想加大 soft nofile ,那么 hard nofile 参数值也需要一起调整。如果因为 hard nofile参数值设置的低,那么soft nofile 参数的值设置的再高也没有用,实际生效的值会按照二者最低的来。

2、如果增大了 hard nofile,那么 fs.nr_open 也都需要跟着一起调整( fs.nr_open 参数值一定要大于 hard nofile参数值)。如果不小心把 hard nofile 的值设置的比 fs.nr_open 还大,那么后果比较严重。会导致该用户无法登录,如果设置的是*,那么所有用户都无法登录

3、如果加大了 fs.nr_open,但是是用的 echo "xxx" > ../fs/nr_open 命令来修改的 fs.nr_open 的值,那么刚改完可能不会有问题,但是只要机器一重启,那么之前通过echo命令设置的fs.nr_open值便会失效,用户还是无法登录。所以非常不建议使用echo的方式修改内核参数!!!

b、调整服务器能打开的最大文件

假设想让进程可以打开 100 万个文件描述符,这里用修改 conf 文件的方式给出一个建议。如果日后工作里有类似的需求可以作为参考。

vim /etc/sysctl.conf
fs.file-max=1100000 // 系统级别设置成110万,多留点buffer
fs.nr_open=1100000 // 进程级别也设置成110万,因为要保证比 hard nofile大

使上面的配置生效 sysctl -p

vim /etc/security/limits.conf
// 用户进程级别都设置成100完
soft nofile 1000000
hard nofile 1000000

2)一台服务器最大能支持多少连接

我们知道 TCP连接,从根本上看其实就是 clientserver 端在内存中维护的一组【socket 内核对象】(这里也对应着 TCP四元组:源 IP、源端口、目标 IP、目标端口),他们只要能够找到对方,那么就算是一条连接。那么一台服务器最大能建立多少条连接呢?

问题1:理论上能支持多少连接呢?

答案:理论值:由于 TCP 连接本质上可以理解为是 client - server 端的一对 socket 内核对象,那么从理论上将应该是【2^32 (ip数) * 2^16 (端口数)】条连接(约等于两百多万亿)

问题2:实际上能达到那么多的连接吗?

答案:实际值:但是实际上由于受其他软硬件的影响,我们一台服务器不可能能建立这么多连接(主要是受 CPU 和 内存限制)

问题3:那如果不传入数据,只建立连接能支持多少呢?

答案:如果只以 ESTABLISH 状态的连接来算(这些连接只是建立,但是不收发数据也不处理相关的业务逻辑)那么一台服务器最大能建立多少连接呢?以一台 4GB内存的服务器为例!

这种情况下,那么能建立的连接数量主要取决于【内存的大小】(因为如果是)ESTABLISH 状态的空闲连接,不会消耗 CPU(虽然有TCP 保活包传输,但这个影响非常小,可以忽略不计)

我们知道一条 ESTABLISH 状态的连接大约消耗【3.3KB内存】,那么通过计算得知一台 4GB 内存的服务器,【可以建立 100w+TCP 连接】(当然这里只是计算所有的连接都只建立连接但不发送和处理数据的情况,如果真实场景中有数据往来和处理(数据接收和发送都需要申请内存,数据处理便需要 CPU ),那便会消耗更高的内存以及占用更多的 CPU,并发不可能达到 100w+

问题4:那建立连接后,又能支持多少呢?

答案:上面讨论的都是进建立连接的理想情况,在现实中如果有频繁的数据收发和处理(比如:压缩、加密等),那么一台服务器能支撑1000 连接都算好的了,所以一台服务器能支撑多少连接还要结合具体的场景去分析,不能光靠理论值去算。抛开业务逻辑单纯的谈并发没有太大的实际意义。

最重要的是:服务器的开销大头往往并不是连接本身,而是每条连接上的数据收发,以及请求业务逻辑处理!!

3)一台客户端机器最多能发起多少条连接

问题1:理论上能支持多少连接呢?

答案:我们知道客户端每和服务端建立一个连接便会消耗掉 client 端一个端口。一台机器的端口范围是【0 ~ 65535】,那么是不是说一台 client 机器最多和一台服务端机器建立 65535 个连接呢(这 65535个端口里还有很多保留端口,可用端口可能只有 64000个左右)?

TCP 连接的四元组特性可知,只要四元组里某一个元素不同,那么就认为这是不同的 TCP 连接。所以需要分情况讨论

【情况一】:如果一台 client 仅有一个 IPserver 端也仅有一个 IP 并且仅启动一个程序,监听一个端口的情况下,client 端和这台 server 端最大可建立的连接条数就是 65535 个。

原因:因为源 IP 固定,目标 IP 和端口固定,四元组中唯一可变化的就是【源端口】,【源端口】的可用范围又是【0 ~ 65535】,所以一台 client 机器最大能建立 65535个连接

以现在的技术,给一个 client 分配多个 IP 是非常容易的事情,只需要去联系你们网管就可以做到。

【情况二】:如果一台 client有多个IP(假设客户端有 nIP),server 端仅有一个IP并且仅启动一个程序,监听一个端口的情况下,一台 client 机器最大能建立的连接条数是:n· * 65535

原因:因为目标 IP 和端口固定,有 n 个源 IP,四元组中可变化的就是【源端口】+ 【源IP】,【源端口】的可用范围又是【0 ~ 65535】,所以一个IP最大能建立 65535个连接,那么 nIP 最大就能建立 n *65535个连接了

【情况三】:如果一台 client 仅有一个 IPserver 端也仅有一个 IP 但是 server 端启动多个程序,每个程序监听一个端口的情况下(比如server 端启动了m个程序,监听了 m 个不同端口),一台 client 机器最大能建立的连接数量为:65535 * m

原因:源 IP 固定,目标 IP 固定,目标端口数量为 m个,可变化的是源端口,而源端口变化范围是【0 ~ 65535】,所以一台 client机器最大能建立的 TCP 连接数量是 6553 * m

其余情况类推,但是客户端的可用端口范围一般达不到 65535个,受内核参数 net.ipv4.ip_local_port_range 限制,如果要修改client 所能使用的端口范围,可以修改这个内核参数的值。

所以,不光是一台 server 端可以接收 100w+TCP 连接,一台 client照样能发出 100w+个连接

4)服务器连接其他问题

a、”too many open files” 报错是怎么回事,该如何解决

你在线上可能遇到过 too many open files 这个错误,那么你理解这个报错发生的原理吗?如果让你修复这个错误,应该如何处理呢? 需要注意这三个参数之间的耦合关系!

1、因为每打开一个文件(包括 socket),都需要消耗一定的内存资源。为了避免个别进程不受控制的打开了过多文件而让整个服务器奔溃,Linux 对打开的文件描述符数量有限制。如果你的进程触发到内核的限制,那么” too many open files” 报错就产生了

2、可以通过修改 fs.file-maxsoft nofilefs.nr_open 这三个参数的值来修改进程能打开的最大文件描述符数量

b、一台服务端机器最大究竟能支持多少条连接

因为这里要考虑的是最大数,因此先不考虑连接上的数据收发和处理,仅考虑 ESTABLISH 状态的空连接。那么一台服务端机器上最大可以支持多少条 TCP 连接?这个连接数会受哪些因素的影响?

1、在不考虑连接上数据的收发和处理的情况下,仅考虑 ESTABLISH 状态下的空连接情况下,一台服务器上最大可支持的TCP连接数量基本上可以说是由内存大小来决定的。

2、四元组唯一确定一条连接,但服务端可以接收来自任意客户端的请求,所以根据这个理论计算出来的数字太大,没有实际意义。另外文件描述符限制其实也是内核为了防止某些应用程序不受限制的打开【文件句柄】而添加的限制。这个限制只要修改几个内核参数就可以加大。

3、一个 socket 大约消耗 3kb 左右的内存,这样真正制约服务端机器最大并发数的就是内存,拿一台 4GB 内存的服务器来说,可以支持的 TCP 连接数量大约是 100w+

c、一条客户端机器最大究竟能支持多少条连接

和服务端不同的是,客户端每次建立一条连接都需要消耗一个端口。在 TCP 协议中,端口是一个 2 字节的整数,因此范围只能是0~65535。那么客户端最大只能支持65535条连接吗?有没有办法突破这个限制,有的话有哪些办法?

1、客户度每次建立一条连接都需要消耗一个端口。从数字上来看,似乎最多只能建立 65535条连接。但实际上我们有两种办法破除65535 这个限制

2、为客户端配置多 IP 方式二,分别连接不同的服务端

3、 所以一台 client发起百万条连接是没有任何问题的

d、做一个长连接推送产品,支持1亿用户需要多少台机器

假设你是系统架构师,现在老板给你一个需求,让你做一个类似友盟 upush 这样的产品。要在服务端机器上保持一个和客户端的长连接,绝大部分情况下连接都是空闲的,每天也就顶多推送两三次左右。总用户规模预计是1亿。那么现在请你来评估一下需要多少台服务器可以支撑这1亿条长连接。

1、对于长连接推送模块这种服务来说,给客户端发送数据只是偶尔的,一般一天也就顶多一两次。绝大部分情况下 TCP 连接都是空闲的,CPU 开销可以忽略

2、再基于内存来考虑,假设服务器内存是 128G 的,那么一台服务器可以考虑支持 500w 条并发。这样会消耗掉大约不到 20GB 内存用来保存这500w 条连接对应的 socket 。还剩下 100GB 以上的内存来应对接收、发送缓冲区等其他的开销足够了。所以,一亿用户,仅仅需要 20台服务器就差不多够用了!

三、GC 指标

1、JVM GC 相关指标

JVM GC 相关指标 描述
jvm.gc.count GC的次数
jvm.gc.time GC的时间,单位毫秒
jvm.younggc.count 年轻代GC的次数 ,包括的GC算法(Copy,ParNew,PS Scavenge,G1 Young Generation)
jvm.younggc.time 年轻代GC的时间,单位毫秒
jvm.younggc.meantime 一分钟内的每次年轻带gc的平均时间
jvm.fullgc.count 年老代GC的次数 ,包括的GC算法(MarkSweepCompact,PS MarkSweep,ConcurrentMarkSweep,G1 Old Generation)
jvm.fullgc.time 年老代GC的时间,单位毫秒

2、JVM 内存 相关指标

JVM 内存 相关指标 描述
jvm.memory.used 内存使用总量
jvm.memory.used.percent 内存使用总量占比
jvm.memory.nonheap.used nonheap使用总量
jvm.memory.nonheap.used.percent nonheap使用总量占比
jvm.memory.oldgen.used oldgen使用总量
jvm.memory.oldgen.used.percent oldgen使用总量占比
jvm.memory.oldgen.used.percent.after.fullgc 触发fullgc之后使用oldgen的内存使用占比,此时基本剩下不可以回收对象
jvm.memory.eden.used eden使用总量
jvm.memory.eden.used.percent eden使用总量占比
jvm.memory.survivor.used survivor使用总量
jvm.memory.survivor.used.percent survivor使用总量占比
jvm.memory.perm.used perm使用总量
jvm.memory.perm.used.percent perm使用总量占比
jvm.nio.directbuffer.used directbuffer使用总量,这个一般是nio一些框架会用到
jvm.nio.mapped.used mapped使用总量,这个一般是使用java内存文件映射用到

3、JVM Thread 相关指标

JVM Thread 相关指标 描述
jvm.thread.blocked.count blocked线程数
jvm.thread.count 线程
jvm.thread.daemon.count daemon线程数
jvm.thread.deadlock.count deadlock线程数
jvm.thread.new.count new线程数
jvm.thread.runnable.count runnable线程数
jvm.thread.terminated.count terminated线程数
jvm.thread.time_waiting.count time_waiting线程数
jvm.thread.totalstarted.count totalstarted线程数
jvm.thread.waiting.count waiting线程数

4、JVM 类加载 相关指标

JVM 类加载 相关指标 描述
jvm.classloading.totalloaded.count jvm已经加载类的总数
jvm.classloading.unloaded.count jvm未加载类的总数

5、JVM GC 参数

export maxParameterCount="1000"
export acceptCount="1000"
export maxSpareThreads="750"
export maxThreads="1000"
export minSpareThreads="50"
export URIEncoding="UTF-8"
export JAVA_OPTS=" -Xms6144m  -Xmx6144m  -XX:MaxMetaspaceSize=256m -XX:MetaspaceSize=256m  -XX:MaxDirectMemorySize=583m  -XX:ConcGCThreads=1  -XX:ParallelGCThreads=4    -XX:+HeapDumpOnOutOfMemoryError  -XX:CICompilerCount=2  -Djava.library.path=/usr/local/lib -server -XX:+UseG1GC  -XX:HeapDumpPath=/export/Logs -Djava.awt.headless=true -Dsun.net.client.defaultConnectTimeout=60000 -Dsun.net.client.defaultReadTimeout=60000 -Djmagick.systemclassloader=no -Dnetworkaddress.cache.ttl=300 -Dsun.net.inetaddr.ttl=300 "

image-20240924170335737

image-20240924170346251

image-20240924170407638

image-20240924170416255

image-20240924170424255

ContactAuthor