关于java:线上问题排查常用命令总结太全了建议收藏

4次阅读

共计 23354 个字符,预计需要花费 59 分钟才能阅读完成。

起源:https://my.oschina.net/xiaoly…

内存瓶颈

free

free 是查看内存应用状况,包含物理内存、替换内存 (swap) 和内核缓冲区内存。

free -h -s 3 示意每隔三秒输入一次内存状况,命令如下

[1014154@cc69dd4c5-4tdb5 ~]$ free
              total        used        free      shared  buff/cache   available
Mem:      119623656    43052220    45611364     4313760    30960072    70574408
Swap:             0           0           0
[1014154@cc69dd4c5-4tdb5 ~]$ free -h -s 3
              total        used        free      shared  buff/cache   available
Mem:           114G         41G         43G        4.1G         29G         67G
Swap:            0B          0B          0B

              total        used        free      shared  buff/cache   available
Mem:           114G         41G         43G        4.1G         29G         67G
Swap:            0B          0B          0B
  • Mem:是内存的应用状况。
  • Swap:是替换空间的应用状况。
  • total:零碎总的可用物理内存和替换空间大小。
  • used:曾经被应用的物理内存和替换空间。
  • free:还有多少物理内存和替换空间可用应用,是真正尚未被应用的物理内存数量
  • shared:被共享应用的物理内存大小。
  • buff/cache:被 buffer(缓冲区)和 cache(缓存)应用的物理内存大小。
  • available:还能够被应用程序应用的物理内存大小,它是从应用程序的角度看到的可用内存数量,available ≈ free + buffer + cache

替换空间 (swap space)

swap space 是磁盘上的一块区域,当零碎物理内存吃紧时,Linux 会将内存中不常拜访的数据保留到 swap 上,这样零碎就有更多的物理内存为各个过程服务,而当零碎须要拜访 swap 上存储的内容时,再将 swap 上的数据加载到内存中,这就是常说的换出和换入。替换空间能够在肯定水平上缓解内存不足的状况,然而它须要读写磁盘数据,所以性能不是很高。

vmstat(举荐)

vmstat(VirtualMeomoryStatistics,虚拟内存统计)是 Linux 中监控内存的常用工具,可对操作系统的虚拟内存、过程、CPU 等的整体状况进行监督,举荐应用。

vmstat 5 3 示意每隔 5 秒统计一次,一共统计三次。

[1014154@cc69dd4c5-4tdb5 ~]$ vmstat 5 3
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 8  0      0 45453212 374768 30763728    0    0    14    99    1    1 11 10 78  0  1
10  0      0 45489232 374768 30763360    0    0     2  1275 95118 97908 13 11 75  0  1
 6  0      0 45452908 374768 30765148    0    0     0  3996 89924 92073 12 10 78  0  1

procs

r:示意运行和期待 CPU 工夫片的过程数(就是说多少个过程真的调配到 CPU),这个值如果长期大于零碎 CPU 个数,阐明 CPU 有余,须要减少 CPUb:示意在期待资源的过程数,比方正在期待 I/O 或者内存替换等。

memory

swpd:示意切换到内存替换区的内存大小,即虚拟内存已应用的大小(单位 KB),如果大于 0,示意你的机器物理内存不足了,如果不是程序内存泄露的起因,那么你该降级内存了或者把耗内存的工作迁徙到其余机器free:示意以后闲暇的物理内存。buff:示意缓冲大小,个别对块设施的读写才须要缓冲 Cache:示意缓存大小,个别作为文件系统进行缓冲,频繁拜访的文件都会被缓存,如果 cache 值十分大阐明缓存文件比拟多,如果此时 io 中的 bi 比拟小,阐明文件系统效率比拟好。

swap

si:示意数据由磁盘读入内存;艰深的讲就是每秒从磁盘读入虚拟内存的大小,如果这个值大于 0,示意物理内存不够用或者内存泄露了,要查找耗内存过程解决掉so:示意由内存写入磁盘,也就是由内存替换区进入内存的数据大小。

留神:个别状况下 si、so 的值都为 0,如果 si、so 的值长期不为 0,则阐明零碎内存不足,须要减少零碎内存

io

bi:示意由块设施读入数据的总量,即读磁盘,单位 kb/s bo:示意写到块设施数据的总量,即写磁盘,单位 kb/s

留神:如果 bi+bo 的值过大,且 wa 值较大,则示意零碎磁盘 IO 瓶颈。

system

in:示意某一时间距离内观测到的每秒设施终端数。cs:示意每秒产生的上下文切换次数,这个值要越小越好,太大了,要思考调低线程或者过程的数目。例如在 apache 和 nginx 这种 web 服务器中,咱们个别做性能测试时会进行几千并发甚至几万并发的测试,抉择 web 服务器的过程能够由过程或者线程的峰值始终下调,压测,直到 cs 到一个比拟小的值,这个过程和线程数就是比拟适合的值了。零碎调用也是,每次调用零碎函数,咱们的代码就会进入内核空间,导致上下文切换,这个是很耗资源,也要尽量避免频繁调用零碎函数。上下文切换次数过多示意你的 CPU 大部分节约在上下文切换,导致 CPU 干正经事的工夫少了,CPU 没有充分利用,是不可取的。

留神:这两个值越大,则由内核耗费的 CPU 就越多。

CPU

us:示意用户过程耗费的 CPU 工夫百分比,us 值越高,阐明用户过程耗费 CPU 工夫越多,如果长期大于 50%,则须要思考优化程序或者算法 sy:示意零碎内核过程耗费的 CPU 工夫百分比, 一般来说 us+sy 应该小于 80%,如果大于 80%,阐明可能存在 CPU 瓶颈id:示意 CPU 处在空间状态的工夫百分比。wa:示意 IP 期待所占用的 CPU 工夫百分比,wa 值越高,阐明 I/O 期待越重大,依据教训 wa 的参考值为 20%,如果超过 20%,阐明 I/O 期待重大,引起 I/O 期待的起因可能是磁盘大量随机读写造成的,也可能是磁盘或者监控器的贷款瓶颈(次要是块操作)造成的

sar

sar 和 free 相似 sar -r 3 每隔三秒输入一次内存信息:

[root@localhost ~]# sar -r 3
Linux 3.10.0-1062.el7.x86_64 (localhost.localdomain)    2020 年 04 月 28 日  _x86_64_        (2 CPU)

15 时 40 分 10 秒 kbmemfree kbmemused  %memused kbbuffers  kbcached  kbcommit   %commit  kbactive   kbinact   kbdirty
15 时 40 分 13 秒    106800   1314960     92.49      2144    573248   4110864    116.82    563664    498888        36
15 时 40 分 16 秒    106816   1314944     92.49      2144    573248   4110864    116.82    563668    498888        36
15 时 40 分 19 秒    106816   1314944     92.49      2144    573248   4110864    116.82    563668    498888        36

CPU 瓶颈

查看机器 cpu 核数

CPU 总核数 = 物理 CPU 个数 * 每颗物理 CPU 的核数 
总逻辑 CPU 数 = 物理 CPU 个数 * 每颗物理 CPU 的核数 * 超线程数

查看 CPU 信息(型号)

[1014154@cc69dd4c5-4tdb5 ~]$ cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c
     32  Intel(R) Xeon(R) CPU E5-2650 v4 @ 2.20GHz

查看物理 CPU 个数

[1014154@cc69dd4c5-4tdb5 ~]$ cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l
16

查看每个物理 CPU 中 core 的个数 (即核数)

[1014154@cc69dd4c5-4tdb5 ~]$ cat /proc/cpuinfo| grep "cpu cores"| uniq
cpu cores       : 2

查看逻辑 CPU 的个数

[1014154@cc69dd4c5-4tdb5 ~]$ cat /proc/cpuinfo| grep "processor"| wc -l
32

top

在 Linux 内核的操作系统中,过程是依据虚构运行工夫(由过程优先级、nice 值加上理论占用的 CPU 工夫进行动静计算得出)进行动静调度的。在执行过程时,须要从用户态转换到内核态,用户空间不能间接操作内核空间的函数。通常要利用零碎调用来实现过程调度,而用户空间到内核空间的转换通常是通过软中断来实现的。例如要进行磁盘操作,用户态须要通过零碎调用内核的磁盘操作指令,所以 CPU 耗费的工夫被切分成用户态 CPU 耗费、零碎(内核)CPU 耗费,以及磁盘操作 CPU 耗费。执行过程时,须要通过一系列的操作,过程首先在用户态执行,在执行过程中会进行过程优先级的调整(nice),通过零碎调用到内核,再通过内核调用,硬中断、软中断,让硬件执行工作。执行实现之后,再从内核态返回给零碎调用,最初零碎调用将后果返回给用户态的过程。

top 能够查看 CPU 总体耗费,包含分项耗费,如 User,System,Idle,nice 等。Shift + H 显示 java 线程;Shift + M 依照内存应用排序;Shift + P 依照 CPU 应用工夫(使用率)排序;Shift + T 依照 CPU 累积应用工夫排序;多核 CPU,进入 top 视图 1,能够看到各各 CPU 的负载状况。

top - 15:24:11 up 8 days,  7:52,  1 user,  load average: 5.73, 6.85, 7.33
Tasks:  17 total,   1 running,  16 sleeping,   0 stopped,   0 zombie
%Cpu(s): 13.9 us,  9.2 sy,  0.0 ni, 76.1 id,  0.1 wa,  0.0 hi,  0.1 si,  0.7 st
KiB Mem : 11962365+total, 50086832 free, 38312808 used, 31224016 buff/cache
KiB Swap:        0 total,        0 free,        0 used. 75402760 avail Mem

   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
   300 ymmapp    20   0 17.242g 1.234g  14732 S   2.3  1.1   9:40.38 java
     1 root      20   0   15376   1988   1392 S   0.0  0.0   0:00.06 sh
    11 root      20   0  120660  11416   1132 S   0.0  0.0   0:04.94 python
    54 root      20   0   85328   2240   1652 S   0.0  0.0   0:00.00 su
    55 ymmapp    20   0   17432   1808   1232 S   0.0  0.0   0:00.00 bash
    56 ymmapp    20   0   17556   2156   1460 S   0.0  0.0   0:00.03 control.sh
    57 ymmapp    20   0   11880    740    576 S   0.0  0.0   0:00.00 tee
   115 ymmapp    20   0   17556   2112   1464 S   0.0  0.0   0:00.02 control_new_war
   133 root      20   0  106032   4240   3160 S   0.0  0.0   0:00.03 sshd
   134 ymmapp    20   0   17080   6872   3180 S   0.0  0.0   0:01.82 ops-updater
   147 ymmapp    20   0   17956   2636   1544 S   0.0  0.0   0:00.07 control.sh
  6538 ymmapp    20   0  115656  10532   3408 S   0.0  0.0   0:00.46 beidou-agent
  6785 ymmapp    20   0 2572996  22512   2788 S   0.0  0.0   0:03.44 gatherinfo4dock
 29241 root      20   0  142148   5712   4340 S   0.0  0.0   0:00.04 sshd
 29243 1014154   20   0  142148   2296    924 S   0.0  0.0   0:00.00 sshd
 29244 1014154   20   0   15208   2020   1640 S   0.0  0.0   0:00.00 bash
 32641 1014154   20   0   57364   2020   1480 R   0.0  0.0   0:00.00 top

第一行:15:24:11 up 8 days, 7:52, 1 user, load average: 5.73, 6.85, 7.33:15:24:11 零碎工夫,up 8 days 运行工夫,1 user 以后登录用户数,load average 负载平衡状况,别离示意 1 分钟,5 分钟,15 分钟负载状况。

第二行:Tasks: 17 total, 1 running, 16 sleeping, 0 stopped, 0 zombie:总过程数 17,运行数 1,休眠 16,进行 0,僵尸过程 0。

第三行:%Cpu(s): 13.9 us, 9.2 sy, 0.0 ni, 76.1 id, 0.1 wa, 0.0 hi, 0.1 si, 0.7 st用户空间 CPU 占比 13.9%,内核空间 CPU 占比 9.2%,扭转过优先级的过程 CPU 占比 0%,闲暇 CPU 占比 76.1IO 期待占用 CPU 占比 0.1%,硬中断占用 CPU 占比 0%,软中断占用 CPU 占比 0.1%, 以后 VM 中的 cpu 时钟被虚拟化偷走的比例 0.7%。

第四和第五行示意内存和 swap 区域的应用状况。

第七行示意:

  • PID: 过程 id
  • USER: 过程所有者
  • PR: 过程优先级
  • NI:nice 值。负值示意高优先级,正值示意低优先级
  • VIRT: 虚拟内存,过程应用的虚拟内存总量,单位 kb。VIRT=SWAP+RES
  • RES: 常驻内存,过程应用的、未被换出的物理内存大小,单位 kb。RES=CODE+DATA
  • SHR: 共享内存,共享内存大小,单位 kb
  • S: 过程状态。D = 不可中断的睡眠状态 R = 运行 S = 睡眠 T = 跟踪 / 进行 Z = 僵尸过程
  • %CPU: 上次更新到当初的 CPU 工夫占用百分比
  • %MEM : 过程应用的物理内存百分比
  • TIME+ : 过程应用的 CPU 工夫总计,单位 1/100 秒
  • COMMAND : 过程名称(命令名 / 命令行)

计算在 cpu load 外面的 uninterruptedsleep 的工作数量

top -b -n 1 | awk '{if (NR<=7)print;else if($8=="D"){print;count++}}END{print"Total status D:"count}'
[root@localhost ~]# top -b -n 1 | awk '{if (NR<=7)print;else if($8=="D"){print;count++}}END{print"Total status D:"count}'
top - 15:35:05 up 1 day, 26 min,  3 users,  load average: 0.00, 0.01, 0.05
Tasks: 225 total,   1 running, 224 sleeping,   0 stopped,   0 zombie
%Cpu(s):  2.5 us, 10.0 sy,  0.0 ni, 87.5 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  1421760 total,   104516 free,   777344 used,   539900 buff/cache
KiB Swap:  2097148 total,  2071152 free,    25996 used.   456028 avail Mem

   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
Total status D:

sar

通过 sar -u 3 能够查看 CUP 总体耗费占比:

[root@localhost ~]# sar -u 3
Linux 3.10.0-1062.el7.x86_64 (localhost.localdomain)    2020 年 05 月 01 日  _x86_64_        (2 CPU)

15 时 18 分 03 秒     CPU     %user     %nice   %system   %iowait    %steal     %idle
15 时 18 分 06 秒     all      0.00      0.00      0.17      0.00      0.00     99.83
15 时 18 分 09 秒     all      0.00      0.00      0.17      0.00      0.00     99.83
15 时 18 分 12 秒     all      0.17      0.00      0.17      0.00      0.00     99.66
15 时 18 分 15 秒     all      0.00      0.00      0.00      0.00      0.00    100.00
15 时 18 分 18 秒     all      0.00      0.00      0.00      0.00      0.00    100.00
  • %user:用户空间的 CPU 应用。
  • %nice:扭转过优先级的过程的 CPU 使用率。
  • %system:内核空间的 CPU 使用率。
  • %iowait:CPU 期待 IO 的百分比。
  • %steal:虚拟机的虚拟机 CPU 应用的 CPU。
  • %idle:闲暇的 CPU。

在以上的显示当中,次要看 %iowait%idle

  • %iowait 的值过高,示意硬盘存在 I/O 瓶颈;
  • %idle 的值高但零碎响应慢时,有可能是 CPU 期待分配内存,此时应加大内存容量;
  • %idle 的值继续低于 10,则零碎的 CPU 解决能力绝对较低,表明零碎中最须要解决的资源是 CPU;

定位线上最耗 CPU 的线程

筹备工作

启动一个程序。arthas-demo 是一个简略的程序,每隔一秒生成一个随机数,再执行质因数分解,并打印出合成后果。

curl -O https://alibaba.github.io/arthas/arthas-demo.jar
java -jar arthas-demo.jar
[root@localhost ~]# curl -O https://alibaba.github.io/arthas/arthas-demo.jar
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  3743  100  3743    0     0   3022      0  0:00:01  0:00:01 --:--:--  3023
[root@localhost ~]# java -jar arthas-demo.jar
1813=7*7*37
illegalArgumentCount:  1, number is: -180005, need >= 2
illegalArgumentCount:  2, number is: -111175, need >= 2
18505=5*3701
166691=7*23813
105787=11*59*163
60148=2*2*11*1367
196983=3*3*43*509
illegalArgumentCount:  3, number is: -173479, need >= 2
illegalArgumentCount:  4, number is: -112840, need >= 2
39502=2*19751
....

通过 top 命令找到最耗时的过程

[root@localhost ~]# top
top - 11:11:05 up 20:02,  3 users,  load average: 0.09, 0.07, 0.05
Tasks: 225 total,   1 running, 224 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.0 us,  0.7 sy,  0.0 ni, 99.3 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  1421760 total,   135868 free,   758508 used,   527384 buff/cache
KiB Swap:  2097148 total,  2070640 free,    26508 used.   475852 avail Mem
Change delay from 3.0 to
   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
 98344 root      20   0 2422552  23508  12108 S   0.7  1.7   0:00.32 java
     1 root      20   0  194100   6244   3184 S   0.0  0.4   0:20.41 systemd
     2 root      20   0       0      0      0 S   0.0  0.0   0:00.12 kthreadd
     4 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 kworker/0:0H
     6 root      20   0       0      0      0 S   0.0  0.0   0:20.25 ksoftirqd/0

找到过程号是 98344。

找到过程中最耗 CUP 的线程

应用 ps -Lp #pid cu 命令,查看某个过程中的线程 CPU 耗费排序:

[root@localhost ~]# ps -Lp 98344 cu
USER        PID    LWP %CPU NLWP %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root      98344  98344  0.0   10  4.1 2422552 59060 pts/0   Sl+  11:09   0:00 java
root      98344  98345  0.0   10  4.1 2422552 59060 pts/0   Sl+  11:09   0:04 java
root      98344  98346  0.0   10  4.1 2422552 59060 pts/0   Sl+  11:09   0:01 VM Thread
root      98344  98347  0.0   10  4.1 2422552 59060 pts/0   Sl+  11:09   0:00 Reference Handl
root      98344  98348  0.0   10  4.1 2422552 59060 pts/0   Sl+  11:09   0:00 Finalizer
root      98344  98349  0.0   10  4.1 2422552 59060 pts/0   Sl+  11:09   0:00 Signal Dispatch
root      98344  98350  0.0   10  4.1 2422552 59060 pts/0   Sl+  11:09   0:05 C2 CompilerThre
root      98344  98351  0.0   10  4.1 2422552 59060 pts/0   Sl+  11:09   0:00 C1 CompilerThre
root      98344  98352  0.0   10  4.1 2422552 59060 pts/0   Sl+  11:09   0:00 Service Thread
root      98344  98353  0.1   10  4.1 2422552 59060 pts/0   Sl+  11:09   0:19 VM Periodic Tas

TIME 列能够看出那个线程消耗 CUP 多,依据 LWP 列能够看到线程的 ID 号,然而须要转换成 16 进制才能够查问线程堆栈信息。

获取线程 id 的十六进制码

应用 printf '%x\n' 98345 命令做进制转换:

[root@localhost ~]# printf '%x\n' 98345
18029

查看线程堆栈信息

应用 jstack 获取堆栈信息 jstack 98344 | grep -A 10 18029

[root@localhost ~]# jstack 98344 | grep -A 10 18029
"main" #1 prio=5 os_prio=0 tid=0x00007fb88404b800 nid=0x18029 waiting on condition [0x00007fb88caab000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
        at java.lang.Thread.sleep(Native Method)
        at java.lang.Thread.sleep(Thread.java:340)
        at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
        at demo.MathGame.main(MathGame.java:17)

"VM Thread" os_prio=0 tid=0x00007fb8840f2800 nid=0x1802a runnable

"VM Periodic Task Thread" os_prio=0 tid=0x00007fb884154000 nid=0x18031 waiting on condition

通过命令咱们能够看到这个线程的对应的耗时代码是在 demo.MathGame.main(MathGame.java:17)

grep -C 5 foo file 显示 file 文件里匹配 foo 字串那行以及高低 5 行
grep -B 5 foo file 显示 foo 及前 5 行
grep -A 5 foo file 显示 foo 及后 5 行

网络瓶颈

定位丢包,错包状况

watch more /proc/net/dev 用于定位丢包,错包状况,以便看网络瓶颈,重点关注 drop (包被抛弃) 和网络包传送的总量,不要超过网络下限:

[root@localhost ~]# watch -n 2 more /proc/net/dev
Every 2.0s: more /proc/net/dev                                                                                                                                                   Fri May  1 17:16:55 2020

Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
    lo:   10025     130    0    0    0     0          0         0    10025     130    0    0    0     0       0          0
 ens33: 759098071  569661    0    0    0     0          0         0 19335572  225551    0    0    0     0       0          0
  • 最右边的示意接口的名字,Receive 示意收包,Transmit 示意发送包;
  • bytes:示意收发的字节数;
  • packets:示意收发正确的包量;
  • errs:示意收发谬误的包量;
  • drop:示意收发抛弃的包量;

查看路由通过的地址

traceroute ip 能够查看路由通过的地址,罕用来统计网络在各个路由区段的耗时,如:

[root@localhost ~]# traceroute 14.215.177.38
traceroute to 14.215.177.38 (14.215.177.38), 30 hops max, 60 byte packets
 1  CD-HZTK5H2.mshome.net (192.168.137.1)  0.126 ms * *
 2  * * *
 3  10.250.112.3 (10.250.112.3)  12.587 ms  12.408 ms  12.317 ms
 4  172.16.227.230 (172.16.227.230)  2.152 ms  2.040 ms  1.956 ms
 5  172.16.227.202 (172.16.227.202)  11.884 ms  11.746 ms  12.692 ms
 6  172.16.227.65 (172.16.227.65)  2.665 ms  3.143 ms  2.923 ms
 7  171.223.206.217 (171.223.206.217)  2.834 ms  2.752 ms  2.654 ms
 8  182.150.18.205 (182.150.18.205)  5.145 ms  5.815 ms  5.542 ms
 9  110.188.6.33 (110.188.6.33)  3.514 ms 171.208.199.185 (171.208.199.185)  3.431 ms 171.208.199.181 (171.208.199.181)  10.768 ms
10  202.97.29.17 (202.97.29.17)  29.574 ms 202.97.30.146 (202.97.30.146)  32.619 ms *
11  113.96.5.126 (113.96.5.126)  36.062 ms 113.96.5.70 (113.96.5.70)  35.940 ms 113.96.4.42 (113.96.4.42)  45.859 ms
12  90.96.135.219.broad.fs.gd.dynamic.163data.com.cn (219.135.96.90)  35.680 ms  35.468 ms  35.304 ms
13  14.215.32.102 (14.215.32.102)  35.135 ms 14.215.32.110 (14.215.32.110)  35.613 ms 14.29.117.242 (14.29.117.242)  54.712 ms
14  * 14.215.32.134 (14.215.32.134)  49.518 ms 14.215.32.122 (14.215.32.122)  47.652 ms
15  * * *
...

查看网络谬误

netstat -i 能够查看网络谬误:

[root@localhost ~]# netstat -i
Kernel Interface table
Iface             MTU    RX-OK RX-ERR RX-DRP RX-OVR    TX-OK TX-ERR TX-DRP TX-OVR Flg
ens33            1500   570291      0      0 0        225897      0      0      0 BMRU
lo              65536      130      0      0 0           130      0      0      0 LRU
  • Iface: 网络接口名称;
  • MTU: 最大传输单元,它限度了数据帧的最大长度,不同的网络类型都有一个上限值,如:以太网的 MTU 是 1500;
  • RX-OK:接管时,正确的数据包数。
  • RX-ERR:接管时,产生谬误的数据包数。
  • RX-DRP:接管时,抛弃的数据包数。
  • RX-OVR:接管时,因为过速(在数据传输中,因为接管设施不能接管依照发送速率传送来的数据而使数据失落)而失落的数据包数。
  • TX-OK:发送时,正确的数据包数。
  • TX-ERR:发送时,产生谬误的数据包数。
  • TX-DRP:发送时,抛弃的数据包数。
  • TX-OVR:发送时,因为过速而失落的数据包数。
  • Flg:标记,B 曾经设置了一个播送地址。L 该接口是一个回送设施。M 接管所有数据包(凌乱模式)。N 防止跟踪。O 在该接口上,禁用 ARP。P 这是一个点到点链接。R 接口正在运行。U 接口处于“流动”状态。

包的重传率

cat /proc/net/snmp 用来查看和剖析 240 秒内网络包量,流量,错包,丢包。通过 RetransSegsOutSegs 来计算重传率 tcpetr=RetransSegs/OutSegs

[root@localhost ~]# cat /proc/net/snmp
Ip: Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates
Ip: 1 64 241708 0 0 0 0 0 238724 225517 15 0 0 0 0 0 0 0 0
Icmp: InMsgs InErrors InCsumErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrors OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps
Icmp: 149 0 0 50 99 0 0 0 0 0 0 0 0 0 147 0 147 0 0 0 0 0 0 0 0 0 0
IcmpMsg: InType3 InType11 OutType3
IcmpMsg: 50 99 147
Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts InCsumErrors
Tcp: 1 200 120000 -1 376 6 0 0 4 236711 223186 292 0 4 0
Udp: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors InCsumErrors
Udp: 1405 438 0 1896 0 0 0
UdpLite: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors InCsumErrors
UdpLite: 0 0 0 0 0 0 0

重传率 = 292/223186≈0.13%

  • 均匀每秒新增 TCP 连接数:通过 /proc/net/snmp 文件失去最近 240 秒内 PassiveOpens 的增量,除以 240 失去每秒的均匀增量;
  • 机器的 TCP 连接数:通过 /proc/net/snmp 文件的 CurrEstab 失去 TCP 连接数;
  • 均匀每秒的 UDP 接收数据报:通过 /proc/net/snmp 文件失去最近 240 秒内 InDatagrams 的增量,除以 240 失去均匀每秒的 UDP 接收数据报;
  • 均匀每秒的 UDP 发送数据报:通过 /proc/net/snmp 文件失去最近 240 秒内 OutDatagrams 的增量,除以 240 失去均匀每秒的 UDP 发送数据报;

磁盘瓶颈

查磁盘空间

查看磁盘残余空间

查看磁盘残余空间应用 df -hl 命令:

[root@localhost ~]# df -hl
文件系统                       容量  已用  可用 已用 % 挂载点
devtmpfs                       678M     0  678M    0% /dev
tmpfs                          695M     0  695M    0% /dev/shm
tmpfs                          695M   28M  667M    4% /run
tmpfs                          695M     0  695M    0% /sys/fs/cgroup
/dev/mapper/centos_aubin-root   27G  5.6G   22G   21% /
/dev/sda1                     1014M  211M  804M   21% /boot

查看磁盘已应用空间

du -sh 命令是查看磁盘已应用空间的状况,这里的“已应用的磁盘空间”意思是指定的文件下的整个文件层次结构所应用的空间,在没给定参数的状况下,du 报告当前目录所应用的磁盘空间。其实就是显示文件或目录所占用的磁盘空间的状况

[root@localhost ~]# du -sh
64K  
  • -h:输入文件系统分区应用的状况,例如:10KB,10MB,10GB 等。
  • -s:显示文件或整个目录的大小,默认单位是 KB。

du 的详细信息能够通过 man du 查看。

查看磁盘读写状况

查看磁盘总体读写状况

iostat 查看磁盘总体的读写状况:

[root@localhost ~]# iostat
Linux 3.10.0-1062.el7.x86_64 (localhost.localdomain)    2020 年 05 月 02 日  _x86_64_        (2 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           0.17    0.00    0.20    0.46    0.00   99.17

Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
sda               1.56        30.45        39.61    4659620    6060644
scd0              0.00         0.02         0.00       3102          0
dm-0              1.96        30.01        38.42    4591998    5878155
dm-1              0.09         0.09         0.30      13840      45328
  • tps:该设施每秒的传输次数。
  • kB_read/s:每秒从设施(drive expressed)读取的数据量;
  • kB_wrtn/s:每秒向设施(drive expressed)写入的数据量;
  • kB_read:读取的总数据量;
  • kB_wrtn:写入的总数量数据量;

查看磁盘具体读写状况

通过 iostat -x 1 3 能够看到磁盘具体读写状况,没隔一秒输入一次一共输入 3 次,当看到 I/O 等待时间所占 CPU 工夫的比重很高的时候,首先要查看的就是机器是否正在大量应用替换空间,同时关注 iowait 占比 cpu 的耗费是否很大,如果大阐明磁盘存在大的瓶颈,同时关注 await,示意磁盘的响应工夫以便小于 5ms:

[root@localhost ~]# iostat -x 1 3
Linux 3.10.0-1062.el7.x86_64 (localhost.localdomain)    2020 年 05 月 02 日  _x86_64_        (2 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           0.17    0.00    0.20    0.46    0.00   99.16

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda               0.01     0.49    0.63    0.95    30.59    39.78    89.58     0.34  214.23   49.16  323.48   8.55   1.34
scd0              0.00     0.00    0.00    0.00     0.02     0.00    98.48     0.00    1.21    1.21    0.00   0.95   0.00
dm-0              0.00     0.00    0.62    1.35    30.15    38.59    69.70     0.91  460.67   49.12  648.54   6.66   1.31
dm-1              0.00     0.00    0.02    0.07     0.09     0.30     8.52     0.04  442.74   95.43  521.17   6.91   0.06

avg-cpu 示意总体 cpu 应用状况统计信息,对于多核 cpu,这里为所有 cpu 的平均值:

  • %user:CPU 处在用户模式下的工夫百分比。
  • %nice:CPU 处在带 NICE 值的用户模式下的工夫百分比。
  • %system:CPU 处在零碎模式下的工夫百分比。
  • %iowait:CPU 期待输入输出实现工夫的百分比,如果 % iowait 的值过高,示意硬盘存在 I/O 瓶颈
  • %steal:管理程序保护另一个虚构处理器时,虚构 CPU 的有意识等待时间百分比。
  • %idle:CPU 闲暇工夫百分比,如果 % idle 值高,示意 CPU 较闲暇;如果 % idle 值高但零碎响应慢时,可能是 CPU 期待分配内存,应加大内存容量;如果 % idle 值继续低于 10,表明 CPU 解决能力绝对较低,零碎中最须要解决的资源是 CPU。

Device 示意设施信息:

  • rrqm/s:每秒对该设施的读申请被合并次数,文件系统会对读取同块 (block) 的申请进行合并
  • wrqm/s:每秒对该设施的写申请被合并次数
  • r/s:每秒实现的读次数
  • w/s:每秒实现的写次数
  • rkB/s:每秒读数据量 (kB 为单位)
  • wkB/s:每秒写数据量 (kB 为单位)
  • avgrq-sz:均匀每次 IO 操作的数据量 (扇区数为单位)
  • avgqu-sz:均匀期待解决的 IO 申请队列长度
  • await:均匀每次 IO 申请等待时间 (包含等待时间和解决工夫,毫秒为单位)
  • svctm:均匀每次 IO 申请的解决工夫 (毫秒为单位)
  • %util:一秒中有百分之多少的工夫用于 I/O 如果 % util 靠近 100%,阐明产生的 I/O 申请太多,I/O 零碎曾经满负荷。idle 小于 70% IO 压力就较大了,个别读取速度有较多的 wait。

iostat -xmd 1 3:新增 m 选项能够在输入是应用 M 为单位。

查看最耗 IO 的过程

个别先通过 iostat 查看是否存在 io 瓶颈,再应用 iotop 命令来定位那个过程最消耗 IO:

[root@localhost ~]# iotop
Total DISK READ :       0.00 B/s | Total DISK WRITE :       0.00 B/s
Actual DISK READ:       0.00 B/s | Actual DISK WRITE:       0.00 B/s
   TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND
123931 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.02 % [kworker/1:30]
 94208 be/4 xiaolyuh    0.00 B/s    0.00 B/s  0.00 %  0.00 % nautilus-desktop --force [gmain]
     1 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % systemd --system --deserialize 62
     2 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [kthreadd]
 94211 be/4 xiaolyuh    0.00 B/s    0.00 B/s  0.00 %  0.00 % gvfsd-trash --spawner :1.4 /org/gtk/gvfs/exec_spaw/0
     4 be/0 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [kworker/0:0H]
     6 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [ksoftirqd/0]
     7 rt/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [migration/0]
     8 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [rcu_bh]
     9 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [rcu_sched]
    10 be/0 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [lru-add-drain]
...

通过 iotop -p pid 能够查看单个过程的 IO 状况:

[root@localhost ~]# iotop -p 124146
Total DISK READ :       0.00 B/s | Total DISK WRITE :       0.00 B/s
Actual DISK READ:       0.00 B/s | Actual DISK WRITE:       0.00 B/s
   TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND
124146 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % java -jar arthas-demo.jar

利用瓶颈

查看某个过程的 PID

如查看 java 的过程的 pid,ps -ef | grep java:

[root@localhost ~]# ps -ef | grep java
root     124146   1984  0 09:13 pts/0    00:00:06 java -jar arthas-demo.jar
root     125210  98378  0 10:07 pts/1    00:00:00 grep --color=auto java

查看特定过程的数量

如查看 java 过程的数量,ps -ef | grep java| wc -l

[root@localhost ~]# ps -ef | grep java| wc -l
2

查看线程是否存在死锁

查看线程是否存在死锁,jstack -l pid

[root@localhost ~]# jstack -l 124146
2020-05-02 10:13:38
Full thread dump OpenJDK 64-Bit Server VM (25.252-b09 mixed mode):

"C1 CompilerThread1" #6 daemon prio=9 os_prio=0 tid=0x00007f27f013c000 nid=0x1e4f9 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"C2 CompilerThread0" #5 daemon prio=9 os_prio=0 tid=0x00007f27f012d000 nid=0x1e4f8 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"main" #1 prio=5 os_prio=0 tid=0x00007f27f004b800 nid=0x1e4f3 waiting on condition [0x00007f27f7274000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
        at java.lang.Thread.sleep(Native Method)
        at java.lang.Thread.sleep(Thread.java:340)
        at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
        at demo.MathGame.main(MathGame.java:17)

   Locked ownable synchronizers:
        - None
...

查看某个过程的线程数

ps -efL | grep [PID] | wc -l,如:

[root@localhost ~]# ps -efL | grep 124146 | wc -l
12

查看具体有哪些线程用 ps -Lp [pid] cu:

[root@localhost ~]# ps -Lp 124146 cu
USER        PID    LWP %CPU NLWP %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root     124146 124146  0.0   11  2.5 2489116 35724 pts/0   Sl+  09:13   0:00 java
root     124146 124147  0.0   11  2.5 2489116 35724 pts/0   Sl+  09:13   0:01 java
root     124146 124148  0.0   11  2.5 2489116 35724 pts/0   Sl+  09:13   0:00 VM Thread
root     124146 124149  0.0   11  2.5 2489116 35724 pts/0   Sl+  09:13   0:00 Reference Handl
root     124146 124150  0.0   11  2.5 2489116 35724 pts/0   Sl+  09:13   0:00 Finalizer
root     124146 124151  0.0   11  2.5 2489116 35724 pts/0   Sl+  09:13   0:00 Signal Dispatch
root     124146 124152  0.0   11  2.5 2489116 35724 pts/0   Sl+  09:13   0:00 C2 CompilerThre
root     124146 124153  0.0   11  2.5 2489116 35724 pts/0   Sl+  09:13   0:00 C1 CompilerThre
root     124146 124154  0.0   11  2.5 2489116 35724 pts/0   Sl+  09:13   0:00 Service Thread
root     124146 124155  0.1   11  2.5 2489116 35724 pts/0   Sl+  09:13   0:05 VM Periodic Tas
root     124146 125362  0.0   11  2.5 2489116 35724 pts/0   Sl+  10:13   0:00 Attach Listener

统计所有的 log 文件中,蕴含 Error 字符的行

find / -type f -name "*.log" | xargs grep "ERROR",这个在排查问题过程中比拟有用:

[root@localhost ~]# find / -type f -name "*.log" | xargs grep "ERROR"
/var/log/tuned/tuned.log:2020-03-13 18:05:59,145 ERROR    tuned.utils.commands: Writing to file '/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor' error: '[Errno 19] No such device'
/var/log/tuned/tuned.log:2020-03-13 18:05:59,145 ERROR    tuned.utils.commands: Writing to file '/sys/devices/system/cpu/cpu1/cpufreq/scaling_governor' error: '[Errno 19] No such device'
/var/log/tuned/tuned.log:2020-04-28 14:55:34,857 ERROR    tuned.utils.commands: Writing to file '/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor' error: '[Errno 19] No such device'
/var/log/tuned/tuned.log:2020-04-28 14:55:34,859 ERROR    tuned.utils.commands: Writing to file '/sys/devices/system/cpu/cpu1/cpufreq/scaling_governor' error: '[Errno 19] No such device'
/var/log/tuned/tuned.log:2020-04-28 15:23:19,037 ERROR    tuned.utils.commands: Writing to file '/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor' error: '[Errno 19] No such device'
...

利用启动时指定 JVM 参数

java -jar -Xms128m -Xmx1024m -Xss512k -XX:PermSize=128m -XX:MaxPermSize=64m -XX:NewSize=64m -XX:MaxNewSize=256m arthas-demo.jar,如:

[root@localhost ~]# java -jar -Xms128m -Xmx1024m -Xss512k -XX:PermSize=128m -XX:MaxPermSize=64m -XX:NewSize=64m -XX:MaxNewSize=256m  arthas-demo.jar
OpenJDK 64-Bit Server VM warning: ignoring option PermSize=128m; support was removed in 8.0
OpenJDK 64-Bit Server VM warning: ignoring option MaxPermSize=64m; support was removed in 8.0
157518=2*3*3*3*2917
illegalArgumentCount:  1, number is: -187733, need >= 2
illegalArgumentCount:  2, number is: -102156, need >= 2
173379=3*57793

总结

在应用 linux 命令时,如果想看帮忙能够应用 --help 或者 man 查看帮忙信息:

[root@localhost ~]# grep --help
用法: grep [选项]... PATTERN [FILE]...
在每个 FILE 或是规范输出中查找 PATTERN。默认的 PATTERN 是一个根本正则表达式(缩写为 BRE)。例如: grep -i 'hello world' menu.h main.c
...
[root@localhost ~]# man grep

GREP(1)                                                        General Commands Manual                                                        GREP(1)

NAME
       grep, egrep, fgrep - 打印匹配给定模式的行

总览 SYNOPSIS
       grep [options] PATTERN [FILE...]
       grep [options] [-e PATTERN | -f FILE] [FILE...]

形容 DESCRIPTION
       Grep    搜寻以    FILE    命名的文件输出   (或者是规范输出,如果没有指定文件名,或者给出的文件名是   -   的话),寻找含有与给定的模式   PATTERN
...
类别 监控命令 形容 备注
内存瓶颈 free 查看内存应用
vmstat 3 (间隔时间) 100 (监控次数) 查看 swap in/out 具体定位是否存在性能瓶颈 举荐应用
sar -r 3 和 free 命令相似,查看内存的应用状况,然而不蕴含 swap 的状况
cpu 瓶颈 top -H 依照 cpu 耗费高下进行排序
ps -Lp 过程号 cu 查看某个过程的 cpu 耗费排序
cat /proc/cpuinfo \ grep ‘processor’\ wc -l 查看 cpu 核数
top 查看 cpu 总体耗费,包含分项耗费如 user,system,idle,nice 等耗费
top 而后 shift+h: 显示 java 线程,而后 shift+M: 依照内存应用进行排序;shift+P: 依照 cpu 工夫排序;shift+T: 依照 cpu 累计应用工夫排序多核 cpu,按“1”进入 top 视图 专项性能排查,多核 CPU 次要看 CUP 各个内核的负载状况
sar -u 3 (间隔时间) 查看 cpu 总体耗费占比
sar -q 查看 cpu load
top -b -n 1 \ awk ‘{if (NR<=7)print;else if($8==”D”){print;count++}}END{print “Total status D:”count}’ 计算在 cpu load 外面的 uninterruptedsleep 的工作数量 uninterruptedsleep 的工作会被计入 cpu load,如磁盘梗塞
网络瓶颈 cat /var/log/messages 查看内核日志,查看是否丢包
watch more /proc/net/dev 用于定位丢包,错包状况,以便看网络瓶颈 重点关注 drop (包被抛弃) 和网络包传送的总量,不要超过网络下限
sar -n SOCK 查看网络流量
netstat -na\ grep ESTABLISHED\ wc -l 查看 tcp 连贯胜利状态的数量 此命令特地耗费 cpu,不适宜进行长时间监控数据收集
netstat -na\ awk'{print $6}’\ sort \ uniq -c \ sort -nr 看 tcp 各个状态数量
netstat -i 查看网络谬误
ss state ESTABLISHED\ wc -l 更高效地统计 tcp 连贯状态为 ESTABLISHED 的数量
cat /proc/net/snmp 查看和剖析 240 秒内网络包量,流量,错包,丢包 用于计算重传率 tcpetr=RetransSegs/OutSegs
ping $ip 测试网络性能
traceroute $ip 查看路由通过的地址 罕用于定位网络在各个路由区段的耗时
dig $ 域名 查看域名解析地址
dmesg 查看零碎内核日志
磁盘瓶颈 iostat -x -k -d 1 具体列出磁盘的读写状况 当看到 I/O 等待时间所占 CPU 工夫的比重很高的时候,首先要查看的就是机器是否正在大量应用替换空间,同时关注 iowait 占比 cpu 的耗费是否很大,如果大阐明磁盘存在大的瓶颈,同时关注 await,示意磁盘的响应工夫以便小于 5ms
iostat -x 查看零碎各个磁盘的读写性能 重点关注 await 和 iowait 的 cpu 占比
iotop 查看哪个过程在大量读取 IO 个别先通过 iostat 查看是否存在 io 瓶颈,再定位哪个过程在大量读取 IO
df -hl 查看磁盘残余空间
du -sh 查看磁盘应用了多少空间
利用瓶颈 ps -ef grep java 查看某个过程的 id 号
ps -ef \ grep httpd\ wc -l 查看特定过程的数量
cat *.log \ grep *Exception\ wc -l 统计日志文件中蕴含特定异样数量
jstack -l pid 用于查看线程是否存在死锁
awk'{print $8}’ 2017-05-22-access_log\ egrep ‘301\ 302’\ wc -l 统计 log 中 301、302 状态码的行数,$8 示意第八列是状态码,能够依据理论状况更改 罕用于利用故障定位
grep ‘wholesaleProductDetailNew’ cookie_log \ awk ‘{if($10==”200″)}’print}’ awk ‘print $12’ \ more 打印蕴含特定数据的 12 列数据
grep “2017:05:22” cookielog \ awk ‘($12>0.3){print $12 “–” $8}’ \ sort > 目录地址 对 apache 或者 nginx 拜访 log 进行响应工夫排序,$12 示意 cookie log 中的 12 列示意响应工夫 用于排查是否是因为是某些拜访超长造成整体的 RT 变长
grep -v ‘HTTP/1.1″ 200’ 取出非 200 响应码的 URL
pgm -A -f $ 利用集群名称 “grep”‘301’ log 文件地址 \ wc -l” 查看整个集群的 log 中 301 状态码的数量
ps -efL \ grep [PID] \ wc -l 查看某个过程创立的线程数
find / -type f -name “*.log” \ xargs grep “ERROR” 统计所有的 log 文件中,蕴含 Error 字符的行 这个在排查问题过程中比拟有用
jstat -gc [pid] 查看 gc 状况
jstat -gcnew [pid] 查看 young 区的内存应用状况,包含 MTT (最大交互次数就被替换到 old 区),TT 是目前曾经替换的次数
jstat -gcold 查看 old 区的内存应用状况
jmap -J-d64 -dump:format=b,file=dump.bin PID dump 出内存快照 -J-d64 避免 jmap 导致虚拟机 crash (jdk6 有 bug)
-XX:+HeapDumpOnOutOfMemeryError 在 java 启动时退出,当呈现内存溢出时,存储内存快照
jmap -histo [pid] 依照对象内存大小排序 留神会导致 full gc
gcore [pid] 导出实现的内存快照 通常和 jmap -permstat /opt/**/java gcore.bin 一起应用,将 core dump 转换成 heap dump
-XX:HeapDumpPath=/home/logs -Xloggc:/home/log/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps 在 Java 启动参数中退出,打印 gc 日志
-server -Xms4000m -Xmx4000m -Xmn1500m -Xss256k -XX:PermSize=340m -XX:MaxPermSize=340m -XX:+UseConcMarkSweepGC 调整 JVM 堆大小 xss 是栈大小

近期热文举荐:

1.1,000+ 道 Java 面试题及答案整顿(2022 最新版)

2. 劲爆!Java 协程要来了。。。

3.Spring Boot 2.x 教程,太全了!

4. 别再写满屏的爆爆爆炸类了,试试装璜器模式,这才是优雅的形式!!

5.《Java 开发手册(嵩山版)》最新公布,速速下载!

感觉不错,别忘了顺手点赞 + 转发哦!

正文完
 0