<menuitem id="dtdv5"><dl id="dtdv5"><address id="dtdv5"></address></dl></menuitem>
<cite id="dtdv5"><span id="dtdv5"></span></cite>
<del id="dtdv5"><noframes id="dtdv5"><del id="dtdv5"></del>
<ins id="dtdv5"></ins><ins id="dtdv5"></ins>
<ins id="dtdv5"></ins>
<var id="dtdv5"><span id="dtdv5"></span></var>
<del id="dtdv5"><noframes id="dtdv5"><ins id="dtdv5"></ins><del id="dtdv5"></del>
<del id="dtdv5"><noframes id="dtdv5"><ins id="dtdv5"></ins>

只要業務邏輯代碼寫正確,處理好業務狀態在多線程的并發問題,很少會有調優方面的需求。最多就是在性能監控平臺發現某些接口的調用耗時偏高,然后再發現某一SQL或第三方接口執行超時之類的。如果你是負責中間件或IM通訊相關項目開發,或許就需要偏向CPU、磁盤、網絡及內存方面的問題排查及調優技能

  • CPU過高,怎么排查問題
  • linux內存
  • 磁盤IO
  • 網絡IO
  • java 應用內存泄漏和頻繁 GC
  • java 線程問題排查
  • 常用 jvm 啟動參數調優

介紹一下linux 調優相關命令,傳送門:開發必備linux命令大全-穩賺不虧

關注公眾號,一起交流,微信搜一搜: 潛行前行

linux CPU 過高,怎么排查問題

CPU 指標解析

  • 平均負載
    • 平均負載等于邏輯 CPU 個數,表示每個 CPU 都恰好被充分利用。如果平均負載大于邏輯 CPU 個數,則負載比較重
  • 進程上下文切換
    • 無法獲取資源而導致的自愿上下文切換
    • 被系統強制調度導致的非自愿上下文切換
  • CPU 使用率
    • 用戶 CPU 使用率,包括用戶態 CPU 使用率(user)和低優先級用戶態 CPU 使用率(nice),表示 CPU 在用戶態運行的時間百分比。用戶 CPU 使用率高,通常說明有應用程序比較繁忙
    • 系統 CPU 使用率,表示 CPU 在內核態運行的時間百分比(不包括中斷),系統 CPU 使用率高,說明內核比較繁忙
    • 等待 I/O 的 CPU 使用率,通常也稱為 iowait,表示等待 I/O 的時間百分比。iowait 高,說明系統與硬件設備的 I/O 交互時間比較長
    • 軟中斷和硬中斷的 CPU 使用率,分別表示內核調用軟中斷處理程序、硬中斷處理程序的時間百分比。它們的使用率高,表明系統發生了大量的中斷

查看系統的平均負載

$ uptime
 10:54:52 up 1124 days, 16:31,  6 users,  load average: 3.67, 2.13, 1.79
  • 10:54:52 是當前時間;up 1124 days, 16:31 是系統運行時間; 6 users 則是正在登錄用戶數。而最后三個數字依次是過去 1 分鐘、5 分鐘、15 分鐘的平均負載(Load Average)。平均負載是指單位時間內,系統處于可運行狀態和不可中斷狀態的平均進程數
  • 當平均負載高于 CPU 數量 70% 的時候,就應該分析排查負載高的問題。一旦負載過高,就可能導致進程響應變慢,進而影響服務的正常功能
  • 平均負載與 CPU 使用率關系
    • CPU 密集型進程,使用大量 CPU 會導致平均負載升高,此時這兩者是一致的
    • I/O 密集型進程,等待 I/O 也會導致平均負載升高,但 CPU 使用率不一定很高
    • 大量等待 CPU 的進程調度也會導致平均負載升高,此時的 CPU 使用率也會比較高

CPU 上下文切換

  • 進程上下文切換:
    • 進程的運行空間可以分為內核空間和用戶空間,當代碼發生系統調用時(訪問受限制的資源),CPU 會發生上下文切換,系統調用結束時,CPU 則再從內核空間換回用戶空間。一次系統調用,兩次 CPU 上下文切換
    • 系統平時會按一定的策略調用進程,會導致進程上下文切換
    • 進程在阻塞等到訪問資源時,也會發生上下文切換
    • 進程通過睡眠函數掛起,會發生上下文切換
    • 當有優先級更高的進程運行時,為了保證高優先級進程的運行,當前進程會被掛起
  • 線程上下文切換:
    • 同一進程里的線程,它們共享相同的虛擬內存和全局變量資源,線程上下文切換時,這些資源不變
    • 線程自己的私有數據,比如棧和寄存器等,需要在上下文切換時保存切換
  • 中斷上下文切換:
    • 為了快速響應硬件的事件,中斷處理會打斷進程的正常調度和執行,轉而調用中斷處理程序,響應設備事件

查看系統的上下文切換情況:

vmstat 和 pidstat。vmvmstat 可查看系統總體的指標,pidstat則詳細到每一個進程服務的指標

$ vmstat 2 1 
procs --------memory--------- --swap-- --io--- -system-- ----cpu----- 
r b swpd free    buff   cache  si so  bi bo in cs us sy id wa st 
1 0    0 3498472 315836 3819540 0 0   0  1  2  0  3  1  96 0  0

--------
cs(context switch)是每秒上下文切換的次數
in(interrupt)則是每秒中斷的次數
r(Running or Runnable)是就緒隊列的長度,也就是正在運行和等待 CPU 的進程數.當這個值超過了CPU數目,就會出現CPU瓶頸
b(Blocked)則是處于不可中斷睡眠狀態的進程數
# pidstat -w
Linux 3.10.0-862.el7.x86_64 (8f57ec39327b)      07/11/2021      _x86_64_        (6 CPU)

06:43:23 PM   UID       PID   cswch/s nvcswch/s  Command
06:43:23 PM     0         1      0.00      0.00  java
06:43:23 PM     0       102      0.00      0.00  bash
06:43:23 PM     0       150      0.00      0.00  pidstat

------各項指標解析---------------------------
PID       進程id
Cswch/s   每秒主動任務上下文切換數量
Nvcswch/s 每秒被動任務上下文切換數量。大量進程都在爭搶 CPU 時,就容易發生非自愿上下文切換
Command   進程執行命令

怎么排查 CPU 過高問題

  • 先使用 top 命令,查看系統相關指標。如需要按某指標排序則 使用 top -o 字段名 如:top -o %CPU。 -o 可以指定排序字段,順序從大到小
# top -o %MEM
top - 18:20:27 up 26 days,  8:30,  2 users,  load average: 0.04, 0.09, 0.13
Tasks: 168 total,   1 running, 167 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.3 us,  0.5 sy,  0.0 ni, 99.1 id,  0.0 wa,  0.0 hi,  0.1 si,  0.0 st
KiB Mem:  32762356 total, 14675196 used, 18087160 free,      884 buffers
KiB Swap:  2103292 total,        0 used,  2103292 free.  6580028 cached Mem

PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND         
2323 mysql     20   0 19.918g 4.538g   9404 S 0.333 14.52 352:51.44 mysqld   
1260 root      20   0 7933492 1.173g  14004 S 0.333 3.753  58:20.74 java   
1520 daemon    20   0  358140   3980    776 S 0.333 0.012   6:19.55 httpd    
1503 root      20   0   69172   2240   1412 S 0.333 0.007   0:48.05 httpd                       
                   
---------各項指標解析---------------------------------------------------
第一行統計信息區
    18:20:27	                    當前時間
    up 25 days, 17:29	            系統運行時間,格式為時:分
    1 user	                    當前登錄用戶數
    load average: 0.04, 0.09, 0.13  系統負載,三個數值分別為 1分鐘、5分鐘、15分鐘前到現在的平均值

Tasks:進程相關信息
    running   正在運行的進程數
    sleeping  睡眠的進程數
    stopped   停止的進程數
    zombie    僵尸進程數
Cpu(s):CPU相關信息
    %us:表示用戶空間程序的cpu使用率(沒有通過nice調度)
    %sy:表示系統空間的cpu使用率,主要是內核程序
    %ni:表示用戶空間且通過nice調度過的程序的cpu使用率
    %id:空閑cpu
    %wa:cpu運行時在等待io的時間
    %hi:cpu處理硬中斷的數量
    %si:cpu處理軟中斷的數量
Mem  內存信息  
    total	物理內存總量
    used	使用的物理內存總量
    free	空閑內存總量
    buffers	用作內核緩存的內存量
Swap 內存信息  
    total	交換區總量
    used	使用的交換區總量
    free	空閑交換區總量
    cached	緩沖的交換區總量
  • 找到相關進程后,我們則可以使用 top -Hp pidpidstat -t -p pid 命令查看進程具體線程使用 CPU 情況,從而找到具體的導致 CPU 高的線程
    • %us 過高,則可以在對應 java 服務根據線程ID查看具體詳情,是否存在死循環,或者長時間的阻塞調用。java 服務可以使用 jstack
    • 如果是 %sy 過高,則先使用 strace 定位具體的系統調用,再定位是哪里的應用代碼導致的
    • 如果是 %si 過高,則可能是網絡問題導致軟中斷頻率飆高
    • %wa 過高,則是頻繁讀寫磁盤導致的。

linux 內存

查看內存使用情況

  • 使用 top 或者 free、vmstat 命令
# top 
top - 18:20:27 up 26 days,  8:30,  2 users,  load average: 0.04, 0.09, 0.13
Tasks: 168 total,   1 running, 167 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.3 us,  0.5 sy,  0.0 ni, 99.1 id,  0.0 wa,  0.0 hi,  0.1 si,  0.0 st
KiB Mem:  32762356 total, 14675196 used, 18087160 free,      884 buffers
KiB Swap:  2103292 total,        0 used,  2103292 free.  6580028 cached Mem

PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND         
2323 mysql     20   0 19.918g 4.538g   9404 S 0.333 14.52 352:51.44 mysqld   
1260 root      20   0 7933492 1.173g  14004 S 0.333 3.753  58:20.74 java       
....
  • bcc-tools 軟件包里的 cachestat 和 cachetop、memleak
    • achestat 可查看整個系統緩存的讀寫命中情況
    • cachetop 可查看每個進程的緩存命中情況
    • memleak 可以用檢查 C、C++ 程序的內存泄漏問題

free 命令內存指標

# free -m 
                total used   free   shared  buffers  cached 
Mem:            32107 30414  1692   0       1962     8489 
-/+ buffers/cache:    19962  12144 
Swap:               0     0     0

  • shared 是共享內存的大小, 一般系統不會用到,總是0
  • buffers/cache 是緩存和緩沖區的大小,buffers 是對原始磁盤塊的緩存,cache 是從磁盤讀取文件系統里文件的頁緩存
  • available 是新進程可用內存的大小

內存 swap 過高

Swap 其實就是把一塊磁盤空間或者一個本地文件,當成內存來使用。swap 換出,把進程暫時不用的內存數據存儲到磁盤中,并釋放這些數據占用的內存。swap 換入,在進程再次訪問這些內存的時候,把它們從磁盤讀到內存中來

  • swap 和 內存回收的機制
    • 內存的回收既包括了文件頁(內存映射獲取磁盤文件的頁)又包括了匿名頁(進程動態分配的內存)
    • 對文件頁的回收,可以直接回收緩存,或者把臟頁寫回磁盤后再回收
    • 而對匿名頁的回收,其實就是通過 Swap 機制,把它們寫入磁盤后再釋放內存
  • swap 過高會造成嚴重的性能問題,頁失效會導致頻繁的頁面在內存和磁盤之間交換
    • 一般線上的服務器的內存都很大,可以禁用 swap
    • 可以設置 /proc/sys/vm/min_free_kbytes,來調整系統定期回收內存的閾值,也可以設置 /proc/sys/vm/swappiness,來調整文件頁和匿名頁的回收傾向

linux 磁盤I/O 問題

文件系統和磁盤

  • 磁盤是一個存儲設備(確切地說是塊設備),可以被劃分為不同的磁盤分區。而在磁盤或者磁盤分區上,還可以再創建文件系統,并掛載到系統的某個目錄中。系統就可以通過這個掛載目錄來讀寫文件
  • 磁盤是存儲數據的塊設備,也是文件系統的載體。所以,文件系統確實還是要通過磁盤,來保證數據的持久化存儲
  • 系統在讀寫普通文件時,I/O 請求會首先經過文件系統,然后由文件系統負責,來與磁盤進行交互。而在讀寫塊設備文件時,會跳過文件系統,直接與磁盤交互
  • linux 內存里的 Buffers 是對原始磁盤塊的臨時存儲,也就是用來緩存磁盤的數據,通常不會特別大(20MB 左右)。內核就可以把分散的寫集中起來(優化磁盤的寫入)
  • linux 內存里的 Cached 是從磁盤讀取文件的頁緩存,也就是用來緩存從文件讀寫的數據。下次訪問這些文件數據時,則直接從內存中快速獲取,而不再次訪問磁盤

磁盤性能指標

  • 使用率,是指磁盤處理 I/O 的時間百分比。過高的使用率(比如超過 80%),通常意味著磁盤 I/O 存在性能瓶頸。
  • 飽和度,是指磁盤處理 I/O 的繁忙程度。過高的飽和度,意味著磁盤存在嚴重的性能瓶頸。當飽和度為 100% 時,磁盤無法接受新的 I/O 請求。
  • IOPS(Input/Output Per Second),是指每秒的 I/O 請求數
  • 吞吐量,是指每秒的 I/O 請求大小
  • 響應時間,是指 I/O 請求從發出到收到響應的間隔時間

IO 過高怎么找問題,怎么調優

  • 查看系統磁盤整體 I/O
# iostat -x -k -d 1 1
Linux 4.4.73-5-default (ceshi44)        2021年07月08日  _x86_64_        (40 CPU)

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.08     2.48    0.37   11.71  27.80   507.24  88.53   0.02     1.34   14.96    0.90   0.09   0.10
sdb      0.00     1.20    1.28   16.67  30.91   647.83  75.61   0.17     9.51    9.40    9.52   0.32   0.57
------ 
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:    采用周期內用于IO操作的時間比率,即IO隊列非空的時間比率

  • 查看進程級別 I/O
# pidstat -d
Linux 3.10.0-862.el7.x86_64 (8f57ec39327b)      07/11/2021      _x86_64_        (6 CPU)

06:42:35 PM   UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
06:42:35 PM     0         1      1.05      0.00      0.00  java
06:42:35 PM     0       102      0.04      0.05      0.00  bash
------
kB_rd/s   每秒從磁盤讀取的KB
kB_wr/s   每秒寫入磁盤KB
kB_ccwr/s 任務取消的寫入磁盤的KB。當任務截斷臟的pagecache的時候會發生
Command   進程執行命令
  • 當使用 pidstat -d 定位到哪個應用服務時,接下來則需要使用 strace 和 lsof 定位是那些代碼在讀寫磁盤里的哪些文件,導致IO高的原因
$ strace -p 18940 
strace: Process 18940 attached 
...
mmap(NULL, 314576896, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0f7aee9000 
mmap(NULL, 314576896, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0f682e8000 
write(3, "2018-12-05 15:23:01,709 - __main"..., 314572844 
) = 314572844 
munmap(0x7f0f682e8000, 314576896)       = 0 
write(3, "\n", 1)                       = 1 
munmap(0x7f0f7aee9000, 314576896)       = 0 
close(3)                                = 0 
stat("/tmp/logtest.txt.1", {st_mode=S_IFREG|0644, st_size=943718535, ...}) = 0 
  • strace 命令輸出可以看到進程18940 正在往文件 /tmp/logtest.txt.1 寫入300m
$ lsof -p 18940 
COMMAND   PID USER   FD   TYPE DEVICE  SIZE/OFF    NODE NAME 
java  18940 root  cwd    DIR   0,50      4096 1549389 / 
… 
java  18940 root    2u   CHR  136,0       0t0       3 /dev/pts/0 
java  18940 root    3w   REG    8,1 117944320     303 /tmp/logtest.txt 
----
FD 表示文件描述符號,TYPE 表示文件類型,NODE NAME 表示文件路徑
  • lsof 也可以看出進程18940 以每次 300MB 的速度往 /tmp/logtest.txt 寫入

linux 網絡I/O 問題

當一個網絡幀到達網卡后,網卡會通過 DMA 方式,把這個網絡包放到收包隊列中;然后通過硬中斷,告訴中斷處理程序已經收到了網絡包。接著,網卡中斷處理程序會為網絡幀分配內核數據結構(sk_buff),并將其拷貝到 sk_buff 緩沖區中;然后再通過軟中斷,通知內核收到了新的網絡幀。內核協議棧從緩沖區中取出網絡幀,并通過網絡協議棧,從下到上逐層處理這個網絡幀

  • 硬中斷:與系統相連的外設(比如網卡、硬盤)自動產生的。主要是用來通知操作系統系統外設狀態的變化。比如當網卡收到數據包的時候,就會發出一個硬中斷
  • 軟中斷:為了滿足實時系統的要求,中斷處理應該是越快越好。linux為了實現這個特點,當中斷發生的時候,硬中斷處理那些短時間就可以完成的工作,而將那些處理事件比較長的工作,交給軟中斷來完成

網絡I/O指標

  • 帶寬,表示鏈路的最大傳輸速率,單位通常為 b/s (比特 / 秒)
  • 吞吐量,表示單位時間內成功傳輸的數據量,單位通常為 b/s(比特 / 秒)或者 B/s(字節 / 秒)吞吐量受帶寬限制,而吞吐量 / 帶寬,也就是該網絡的使用率
  • 延時,表示從網絡請求發出后,一直到收到遠端響應,所需要的時間延遲。在不同場景中,這一指標可能會有不同含義。比如,它可以表示,建立連接需要的時間(比如 TCP 握手延時),或一個數據包往返所需的時間(比如 RTT)
  • PPS,是 Packet Per Second(包 / 秒)的縮寫,表示以網絡包為單位的傳輸速率。PPS 通常用來評估網絡的轉發能力,比如硬件交換機,通??梢赃_到線性轉發(即 PPS 可以達到或者接近理論最大值)。而基于 Linux 服務器的轉發,則容易受網絡包大小的影響
  • 網絡的連通性
  • 并發連接數(TCP 連接數量)
  • 丟包率(丟包百分比)

查看網絡I/O指標

  • 查看網絡配置
# ifconfig em1
em1       Link encap:Ethernet  HWaddr 80:18:44:EB:18:98  
          inet addr:192.168.0.44  Bcast:192.168.0.255  Mask:255.255.255.0
          inet6 addr: fe80::8218:44ff:feeb:1898/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:3098067963 errors:0 dropped:5379363 overruns:0 frame:0
          TX packets:2804983784 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:1661766458875 (1584783.9 Mb)  TX bytes:1356093926505 (1293271.9 Mb)
          Interrupt:83
-----
TX 和 RX 部分的 errors、dropped、overruns、carrier 以及 collisions 等指標不為 0 時,
通常表示出現了網絡 I/O 問題。
errors 表示發生錯誤的數據包數,比如校驗錯誤、幀同步錯誤等
dropped 表示丟棄的數據包數,即數據包已經收到了 Ring Buffer,但因為內存不足等原因丟包
overruns 表示超限數據包數,即網絡 I/O 速度過快,導致 Ring Buffer 中的數據包來不及處理(隊列滿)而導致的丟包
carrier 表示發生 carrirer 錯誤的數據包數,比如雙工模式不匹配、物理電纜出現問題等
collisions 表示碰撞數據包數
  • 網絡吞吐和 PPS
# sar -n DEV 1
Linux 4.4.73-5-default (ceshi44)        2022年03月31日  _x86_64_        (40 CPU)

15時39分40秒     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s   %ifutil
15時39分41秒       em1   1241.00   1022.00    600.48    590.39      0.00      0.00    165.00      0.49
15時39分41秒        lo    636.00    636.00   7734.06   7734.06      0.00      0.00      0.00      0.00
15時39分41秒       em4      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
15時39分41秒       em3      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
15時39分41秒       em2     26.00     20.00      6.63      8.80      0.00      0.00      0.00      0.01
----
rxpck/s 和 txpck/s 分別是接收和發送的 PPS,單位為包 / 秒
rxkB/s 和 txkB/s 分別是接收和發送的吞吐量,單位是 KB/ 秒
rxcmp/s 和 txcmp/s 分別是接收和發送的壓縮數據包數,單位是包 / 秒
  • 寬帶
# ethtool em1 | grep Speed 
Speed: 1000Mb/s
  • 連通性和延遲
# ping www.baidu.com
PING www.a.shifen.com (14.215.177.38) 56(84) bytes of data.
64 bytes from 14.215.177.38: icmp_seq=1 ttl=56 time=53.9 ms
64 bytes from 14.215.177.38: icmp_seq=2 ttl=56 time=52.3 ms
64 bytes from 14.215.177.38: icmp_seq=3 ttl=56 time=53.8 ms
64 bytes from 14.215.177.38: icmp_seq=4 ttl=56 time=56.0 ms
  • 統計 TCP 連接狀態工具 ss 和 netstat
[root@root ~]$>#ss -ant | awk '{++S[$1]} END {for(a in S) print a, S[a]}'
LISTEN 96
CLOSE-WAIT 527
ESTAB 8520
State 1
SYN-SENT 2
TIME-WAIT 660

[root@root ~]$>#netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
CLOSE_WAIT 530
ESTABLISHED 8511
FIN_WAIT2 3
TIME_WAIT 809

網絡請求變慢,怎么調優

  • 高并發下 TCP 請求變多,會有大量處于 TIME_WAIT 狀態的連接,它們會占用大量內存和端口資源。此時可以優化與 TIME_WAIT 狀態相關的內核選項
    • 增大處于 TIME_WAIT 狀態的連接數量 net.ipv4.tcp_max_tw_buckets ,并增大連接跟蹤表的大小 net.netfilter.nf_conntrack_max
    • 減小 net.ipv4.tcp_fin_timeout 和 net.netfilter.nf_conntrack_tcp_timeout_time_wait ,讓系統盡快釋放它們所占用的資源
    • 開啟端口復用 net.ipv4.tcp_tw_reuse。這樣,被 TIME_WAIT 狀態占用的端口,還能用到新建的連接中
    • 增大本地端口的范圍 net.ipv4.ip_local_port_range 。這樣就可以支持更多連接,提高整體的并發能力
    • 增加最大文件描述符的數量??梢允褂?fs.nr_open 和 fs.file-max ,分別增大進程和系統的最大文件描述符數
  • SYN FLOOD 攻擊,利用 TCP 協議特點進行攻擊而引發的性能問題,可以考慮優化與 SYN 狀態相關的內核選項
    • 增大 TCP 半連接的最大數量 net.ipv4.tcp_max_syn_backlog ,或者開啟 TCP SYN Cookies net.ipv4.tcp_syncookies ,來繞開半連接數量限制的問題
    • 減少 SYN_RECV 狀態的連接重傳 SYN+ACK 包的次數 net.ipv4.tcp_synack_retries
  • 加快 TCP 長連接的回收,優化與 Keepalive 相關的內核選項
    • 縮短最后一次數據包到 Keepalive 探測包的間隔時間 net.ipv4.tcp_keepalive_time
    • 縮短發送 Keepalive 探測包的間隔時間 net.ipv4.tcp_keepalive_intvl
    • 減少 Keepalive 探測失敗后,一直到通知應用程序前的重試次數 net.ipv4.tcp_keepalive_probes

java 應用內存泄漏和頻繁 GC

區分內存溢出、內存泄漏、內存逃逸

  • 內存泄漏:內存被申請后始終無法釋放,導致內存無法被回收使用,造成內存空間浪費
  • 內存溢出:指內存申請時,內存空間不足
    • 1-內存上限過小
    • 2-內存加載數據太多
    • 3-分配太多內存沒有回收,出現內存泄漏
  • 內存逃逸:是指程序運行時的數據,本應在棧上分配,但需要在堆上分配,稱為內存逃逸
    • java中的對象都是在堆上分配的,而垃圾回收機制會回收堆中不再使用的對象,但是篩選可回收對象,回收對象還有整理內存都需要消耗時間。如果能夠通過逃逸分析確定對象不會逃出方法之外,那就可以讓這個對象在棧上分配內存,對象所占用的內存就可以隨棧幀出棧而銷毀,就減輕了垃圾回收的壓力
    • 線程同步本身比較耗時,如果確定一個變量不會逃逸出線程,無法被其它線程訪問到,那這個變量的讀寫就不會存在競爭,對這個變量的同步措施可以清除
    • java 虛擬機中的原始數據類型(int,long及reference類型等) 都不能再進一步分解,它們稱為標量。如果一個數據可以繼續分解,那它稱為聚合量,java 中最典型的聚合量是對象。如果逃逸分析證明一個對象不會被外部訪問,并且這個對象是可分解的,那程序運行時可能不創建該對象,而改為直接創建它的若干個被方法使用到的成員變量來代替。拆散后的變量便可以被單獨分析與優化,可以各自分別在棧幀或寄存器上分配空間,原本的對象就無需整體分配空間

內存泄漏,該如何定位和處理

  • 使用 jmap -histo:live [pid]jmap -dump:format=b,file=filename [pid] 前者可以統計堆內存對象大小和數量,后者可以把堆內存 dump 下來
  • 啟動參數中指定-XX:+HeapDumpOnOutOfMemoryError來保存OOM時的dump文件
  • 使用 JProfiler 或者 MAT 軟件查看 heap 內存對象,可以更直觀地發現泄露的對象
    技能篇:linux服務性能問題排查及jvm調優思路-LMLPHP

java線程問題排查

java 線程狀態

  • NEW:對應沒有 Started 的線程,對應新生態
  • RUNNABLE:對于就緒態和運行態的合稱
  • BLOCKED,WAITING,TIMED_WAITING:三個都是阻塞態
    • sleep 和 join 稱為WAITING
    • sleep 和 join 方法設置了超時時間的,則是 TIMED_WAITING
    • wait 和 IO 流阻塞稱為BLOCKED
  • TERMINATED: 死亡態

線程出現死鎖或者被阻塞

  • jstack –l pid | grep -i –E 'BLOCKED | deadlock' , 加上參數 -l,jstack 命令可以快速打印出造成死鎖的代碼
# jstack -l 28764
Full thread dump Java HotSpot(TM) 64-Bit Server VM (13.0.2+8 mixed mode, sharing):
.....
"Thread-0" #14 prio=5 os_prio=0 cpu=0.00ms elapsed=598.37s tid=0x000001b3c25f7000 nid=0x4abc waiting for monitor entry  [0x00000061661fe000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at com.Test$DieLock.run(Test.java:52)
        - waiting to lock <0x0000000712d7c230> (a java.lang.Object)
        - locked <0x0000000712d7c220> (a java.lang.Object)
        at java.lang.Thread.run(java.base@13.0.2/Thread.java:830)

   Locked ownable synchronizers:
        - None

"Thread-1" #15 prio=5 os_prio=0 cpu=0.00ms elapsed=598.37s tid=0x000001b3c25f8000 nid=0x1984 waiting for monitor entry  [0x00000061662ff000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at com.Test$DieLock.run(Test.java:63)
        - waiting to lock <0x0000000712d7c220> (a java.lang.Object)
        - locked <0x0000000712d7c230> (a java.lang.Object)
        at java.lang.Thread.run(java.base@13.0.2/Thread.java:830)
.....
Found one Java-level deadlock:
=============================
"Thread-0":
  waiting to lock monitor 0x000001b3c1e4c480 (object 0x0000000712d7c230, a java.lang.Object),
  which is held by "Thread-1"
"Thread-1":
  waiting to lock monitor 0x000001b3c1e4c080 (object 0x0000000712d7c220, a java.lang.Object),
  which is held by "Thread-0"

Java stack information for the threads listed above:
===================================================
"Thread-0":
        at com.Test$DieLock.run(Test.java:52)
        - waiting to lock <0x0000000712d7c230> (a java.lang.Object)
        - locked <0x0000000712d7c220> (a java.lang.Object)
        at java.lang.Thread.run(java.base@13.0.2/Thread.java:830)
"Thread-1":
        at com.Test$DieLock.run(Test.java:63)
        - waiting to lock <0x0000000712d7c220> (a java.lang.Object)
        - locked <0x0000000712d7c230> (a java.lang.Object)
        at java.lang.Thread.run(java.base@13.0.2/Thread.java:830)
Found 1 deadlock.
  • 從 jstack 輸出的日志可以看出線程阻塞在 Test.java:52 行,發生了死鎖

常用 jvm 調優啟動參數

  • -verbose:gc 輸出每次GC的相關情況
  • -verbose:jni 輸出native方法調用的相關情況,一般用于診斷jni調用錯誤信息
  • -Xms n 指定jvm堆的初始大小,默認為物理內存的1/64,最小為1M;可以指定單位,比如k、m,若不指定,則默認為字節
  • -Xmx n 指定jvm堆的最大值,默認為物理內存的1/4或者1G,最小為2M;單位與-Xms一致
  • -Xss n 設置單個線程棧的大小,一般默認為512k
  • -XX:NewRatio=4 設置年輕代(包括Eden和兩個Survivor區)與年老代的比值(除去持久代)。設置為4,則年輕代與年老代所占比值為1:4,年輕代占整個堆棧的1/5
  • -Xmn 設置新生代內存大小。整個堆大小=年輕代大小 + 年老代大小 + 持久代大小。持久代一般固定大小為64m,所以增大年輕代后,將會減小年老代大小。此值對系統性能影響較大,Sun官方推薦配置為整個堆的3/8
  • -XX:SurvivorRatio=4 設置年輕代中Eden區與Survivor區的大小比值。設置為4,則兩個Survivor區與一個Eden區的比值為2:4,一個Survivor區占整個年輕代的1/6
  • -XX:MaxTenuringThreshold=0 設置垃圾最大年齡。如果設置為0的話,則年輕代對象不經過Survivor區,直接進入年老代。對于年老代比較多的應用,可以提高效率。如果將此值設置為一個較大值,則年輕代對象會在Survivor區進行多次復制,這樣可以增加對象再年輕代的存活時間,增加在年輕代即被回收的概率

歡迎指正文中錯誤

參考文章

04-01 16:48
护士巨好爽好大乳 - 成男女人看片免费视频播放人 - 久青青在线观看视频国产 - 97中文字幕在线