[Summary & Ответ: Очевидно, проблема в том, что для генерации генератора случайных чисел требуется много времени. См. Мой ответ ниже. ]Почему первый вызов scrypt() использует только 1% процессор и занимает полчаса в GCE?
В Google Compute Engine (GCE) самый первый запрос, который приложение моей виртуальной машины Java делает для функции хэширования scrypt, занимает много времени, потому что код еще не был скомпилирован Just-In-Time. Поэтому я разогреваю скриншот, создавая нужный код scrypt("pswd", 2,1,1)
при запуске сервера. Однако, что происходит, это то, что CPU поднимается до 300% +, остается там на 10-20 секунд, а затем падает до 1%, хотя запрос на scrypt() еще не закончен. Теперь процессор остается на уровне 1% в течение многих минут (до получаса с 2 GCE vCPU), пока не будет завершен scrypt().
Почему это странное поведение?
Почему не будет scrypt() продолжать работать на 300% до тех пор, пока это не будет выполнено? Это не заканчивается память. Посмотрите на статистику Докера немного ниже.
После первого запроса scrypt() последующие запросы заканчиваются «немедленно». Например, это: SCryptUtil.scrypt("pswd", 65536, 8, 1)
занимает < 0,2 секунды, хотя это делает гораздо больше работы, чем: SCryptUtil.scrypt("pswd", 2, 1, 1)
, который (как уже упоминалось) мой самый первый Scrypt() вызов и обычно занимает несколько минут, с 4 GCE VCPU - и часто около получаса, с 2 GCE vCPU.
Я использую экземпляр GCE с 4 vCPU, 3.6 GB RAM. Докер 1.11.1. OpenJDK 1.8.0_77. В контейнере Docker Alpine Linux 3.3, хостеле Ubuntu 16.04 Docker. Невозможно воспроизвести это на моем ноутбуке; на моем ноутбуке, scrypt всегда быстр, не нуждается в разминке.
docker stats
, через 5-10 секунд: (теперь edp_play_1, линия 2, использует 300% + ЦП)
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
Если вы хотите проверить в Scala & 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, с openjdk 8, установленным непосредственно на экземпляре GCE, и результат тот же: scrypt(..)
занимает 3 минуты в первый раз, но CPU составляет 90-100% бездействия. После этого запросы на скрипинг завершаются немедленно.