容器隔離性帶來的問題--容器化Java應用比虛機啓動速度慢

引發的問題

同等配置下,虛機中的java 服務的啓動速度,要比容器快很多(將近兩倍)

實測數據

在同時1c1g的虛機和容器中,虛機啓動時間大概在1min20s,容器啓動時間大概在2min40s。

排查思路

懷疑網絡

最開始懷疑是網絡問題,因爲業務依賴外部數據庫,在容器和虛機中ping、telnet外部數據庫,能通而且延遲差不多。

諮詢熟悉java的小夥伴,說 spingboot可能有潛在的外部網絡請求延遲(如請求Spring官網等),請求可能多次失敗超時,不影響服務啓動,但會影響啓動時間。通過在虛機和容器中抓包,抓到了一個外部域名,但是虛機容器中都可以正常聯通。包括修改域名服務器,都沒有效果

硬件差異

排查問題陷入僵局後,諮詢小夥伴的建議,濤哥提出是不是因爲硬件差異導致的?這是個新的思路,之前只關注了軟件層面的。

google了下,確實有人遇到了因爲cpu頻率的差異,導致虛機和容器中業務性能的差異。查看了容器和虛機所在主機的cpu頻率後,進一步證實了濤哥的猜想,cpu頻率確實有將近一倍的差異。根據文章中提供的解決辦法,通過修改cpu的工作模式,從
powersave到performance,來提高cpu的工作頻率。命令如下:

# 查看cpu頻率
# lscpu    
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                48
On-line CPU(s) list:   0-47
Thread(s) per core:    2
Core(s) per socket:    12
Socket(s):             2
NUMA node(s):          2
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 79
Model name:            Intel(R) Xeon(R) CPU E5-2650 v4 @ 2.20GHz
Stepping:              1
CPU MHz:               2494.133
CPU max MHz:           2900.0000
CPU min MHz:           1200.0000
BogoMIPS:              4389.67
Virtualization:        VT-x
L1d cache:             32K
L1i cache:             32K
L2 cache:              256K
···
# 查看cpu工作模式
# cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
powersave
powersave
...

# 修改cpu工作模式
# cpupower -c all frequency-set -g performance
# 查看每個cpu的頻率
# grep -i mhz /proc/cpuinfo
cpu MHz        : 1870.495
cpu MHz        : 2348.156
cpu MHz        : 2160.900
cpu MHz        : 1918.896
··· 

在修改完cpu工作模式後,cpu MHz確實有很大的提高,但是實測容器中業務啓動時間並沒有預期的和虛機中的速度一樣,只有一點優化。看來cpu MHz不是決定的影響因素。

後來詳細查了一下,cpu MHz是個不斷浮動的素質,cpu性能要看CPU max MHz和工作模式。兩臺宿主機的cpu型號是一致的,改動cpu工作模式影響有線

容器對java的隔離缺陷

在之前容器化java業務的時候就遇到了OOMKilled,以及Runtime.getRuntime().availableProcessors()獲取的cpu核數問題。當時通過引入了lxcfs,以及替換jvm libnumcpus.so文件,通過環境變量注入cpu核數來解決這個問題。

在懷疑是隔離引起的問題後,對比了虛機和容器中java進程的線程數,發現確實有比較大的差異。命令如下:

# 虛機中
···
[root@data-message-b69c847c7-sjlrx /]# cat /proc/136/status |grep Threads
Threads:    42
[root@data-message-b69c847c7-sjlrx /]# cat /proc/136/status |grep Threads
Threads:    42
[root@data-message-b69c847c7-sjlrx /]# cat /proc/136/status |grep Threads
Threads:    42
[root@data-message-b69c847c7-sjlrx /]# cat /proc/136/status |grep Threads
Threads:    42
[root@data-message-b69c847c7-sjlrx /]# cat /proc/136/status |grep Threads
Threads:    42
[root@data-message-b69c847c7-sjlrx /]# cat /proc/136/status |grep Threads
Threads:    42
···


# 容器中
···
[root@data-message-79bb65797d-ffsfb /]# cat /proc/42/status |grep Threads
Threads:    74
[root@data-message-79bb65797d-ffsfb /]# cat /proc/42/status |grep Threads
Threads:    74
[root@data-message-79bb65797d-ffsfb /]# cat /proc/42/status |grep Threads
Threads:    76
[root@data-message-79bb65797d-ffsfb /]# cat /proc/42/status |grep Threads
Threads:    76
[root@data-message-79bb65797d-ffsfb /]# cat /proc/42/status |grep Threads
Threads:    76
···

解決辦法

使用包含了cpu-online /sys/devices/system/cpu/online的lxcfs(我們之前引入的lxcfs還未支持cpu-online)

在引入新版lxcfs cpu-online後,線程數下降明顯,啓動速度有明顯的改善,達到和虛機同等水平。

LXCFS 3.1.2 has been released

Virtualize /sys/devices/system/cpu/online

LXCFS now also partially virtualizes sysfs. The first file to virtualize is /sys/devices/system/cpu/online per container.

結論

容器java進程啓動慢的最終原因,還是容器的隔離性不夠,導致jvm啓動過多的線程,線程頻繁切換帶來的性能下降。目前使用包含cpu-online的lxcfs能解決這個問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章