[總結&回答:顯然問題是播種隨機數發生器需要很長時間。請參閱下面的答案。 ]爲什麼第一次使用scrypt()只需要1%的CPU,而在GCE中需要半個小時?
在Google Compute Engine(GCE)中,我的Java虛擬機應用程序對scrypt密碼哈希函數的首次請求花費很長時間 - 因爲代碼尚未進行即時編譯。所以我通過在服務器啓動時調用 虛擬scrypt("pswd", 2,1,1)
調用來使scrypt變暖。然而,會發生什麼呢,是CPU上升到300%+,在那裏停留10-20秒,然後回落到1%,儘管對scrypt()的請求尚未完成。現在,CPU停留在1%,持續很多分鐘(長達半小時,2 GCE vCPU),直到最終完成scrypt()。
爲什麼這種奇怪的行爲?
爲什麼scrypt()會以300%的CPU持續運行,直到完成爲止?這不是 內存不足。看下面的Docker統計數據。
第1次scrypt()請求後,後續請求「立即」結束。例如,這樣的: SCryptUtil.scrypt("pswd", 65536, 8, 1)
需要< 0.2秒,雖然它做更多的工作比: SCryptUtil.scrypt("pswd", 2, 1, 1)
這(如前所述)是我的第一個scrypt()調用,通常只需要幾分鐘的時間,與4 GCE個vCPU - 並且通常在大約半個小時內,使用2個GCE vCPU。
我正在使用4個vCPU,3.6 GB RAM的GCE實例。 Docker 1.11.1。 OpenJDK 1.8.0_77。在Alpine Linux 3.3 Docker容器中,Ubuntu 16.04 Docker主機。無法在筆記本電腦上重現此問題;在我的筆記本電腦上,scrypt總是很快,不需要任何熱身。
docker stats
,5-10秒後:(現在edp_play_1,線路2,使用300 +%CPU)
CONTAINER CPU % MEM USAGE/LIMIT MEM % NET I/O BLOCK I/O PIDS
edp_nginx_1 0.02% 55.92 MB/104.9 MB 53.33% 6.191 kB/2.897 kB 0 B/0 B 6
edp_play_1 315.12% 914.7 MB/2.831 GB 32.31% 43.4 kB/66.09 kB 0 B/2.58 MB 67
edp_postgres_1 0.33% 29.84 MB/314.6 MB 9.49% 529.1 kB/307.9 kB 0 B/327.7 kB 17
edp_redis_1 0.08% 6.513 MB/52.43 MB 12.42% 4.984 kB/1.289 kB 0 B/0 B 3
docker stats
半分鐘後:(現在edp_play_1僅使用0.97%的CPU - 並保持等這一點,長達一個半小時,直到完成)
CONTAINER CPU % MEM USAGE/LIMIT MEM % NET I/O BLOCK I/O PIDS
edp_nginx_1 0.02% 55.92 MB/104.9 MB 53.33% 6.341 kB/3.047 kB 0 B/0 B 6
edp_play_1 0.97% 1.011 GB/2.831 GB 35.71% 130.2 kB/215.2 kB 0 B/5.546 MB 66
edp_postgres_1 0.28% 29.84 MB/314.6 MB 9.49% 678.2 kB/394.7 kB 0 B/458.8 kB 17
edp_redis_1 0.06% 6.513 MB/52.43 MB 12.42% 4.984 kB/1.289 kB 0 B/0 B 3
如果你想在斯卡拉& SBT測試,這是我在GCE會發生什麼:
scala> import com.lambdaworks.crypto.SCryptUtil
import com.lambdaworks.crypto.SCryptUtil
scala> def time[R](block: => R): R = { val t0 = System.nanoTime() ; val result = block ; val t1 = System.nanoTime() ; println("Elapsed time: " + (t1 - t0) + "ns") ; result ; }
time: [R](block: => R)R
scala> time { SCryptUtil.scrypt("dummy password 1", 2, 1, 1) }
Elapsed time: 313823ns <-- 5 minutes
res0: String = $s0$10101$2g6nrD0f5gDOTuP44f0mKg==$kqEe4TWSFXwtwGy3YgmIcqAhDvjMS89acST7cwPf/n4=
scala> time { SCryptUtil.scrypt("dummy password 1", 2, 1, 1) }
Elapsed time: 178461ns
res1: String = $s0$10101$C0iGNvfP+ywAxDS0ARoqVw==$k60w5Jpdt28PHGKT0ypByPocCyJISrq+T1XwmPlHR5w=
scala> time { SCryptUtil.scrypt("dummy password 1", 65536, 8, 1) }
Elapsed time: 130900544ns <-- 0.1 seconds
res2: String = $s0$100801$UMTfIuBRY6lO1asECmVNYg==$b8i7GABgeczVHKVssJ8c2M7Z011u0TMBtVF4VSRohKI=
scala> 313823L/1e9
res3: Double = 313.823
scala> 130900544L/1e9
res4: Double = 0.130900544
注意:這與Docker無關。我只是在Docker外面測試,openjdk 8直接安裝在GCE實例上,結果是一樣的:scrypt(..)
第一次需要3分鐘,但CPU空閒90-100%。此後,請求立即完成scrypt。