[Résumé &] réponse: Apparemment, le problème est qu'il faut beaucoup de temps pour semer le générateur de nombres aléatoires. Voir ma réponse ci-dessous.Pourquoi le 1er appel de scrypt() n'utilise que 1% de CPU et prend une demi-heure en GCE?
Dans Google Compute Engine (GCE), la toute première requête de mon application Java Virtual Machine pour la fonction de hachage par mot de passe scrypt prend longtemps car le code n'a pas encore été compilé Just-In-Time. Donc, je réchauffe scrypt, en faisant un factice scrypt("pswd", 2,1,1)
appel au démarrage du serveur. Cependant, ce qui se passe, c'est que le CPU monte à 300% +, reste là pendant 10-20 secondes, puis redescend à 1%, bien que la requête à scrypt() ne soit pas encore terminée. Maintenant, le CPU reste à 1%, pendant de nombreuses minutes (jusqu'à une demi-heure, avec 2 GCE vCPU), jusqu'à ce que finalement scrypt() soit fait.
Pourquoi ce comportement étrange?
Pourquoi scrypt() ne continuera pas à fonctionner à 300% de CPU jusqu'à ce que ce soit fait? Ce n'est pas à court de mémoire. Regardez les statistiques de Docker un peu plus bas.
Après la première requête scrypt(), les requêtes suivantes se terminent "immédiatement". Par exemple, ceci: SCryptUtil.scrypt("pswd", 65536, 8, 1)
prend < 0,2 secondes, même si elle fait beaucoup plus de travail que: SCryptUtil.scrypt("pswd", 2, 1, 1)
qui (comme indiqué) est mon premier scrypt() appel et prend généralement quelques minutes, avec 4 GCE vCPU - et souvent autour d'une demi-heure, avec 2 GCE vCPU. J'utilise une instance GCE avec 4 vCPU, 3,6 Go de RAM. Docker 1.11.1. OpenJDK 1.8.0_77. Dans un conteneur Docker Alpine Linux 3.3, hôte Ubuntu 16.04 Docker. Impossible de reproduire ceci sur mon ordinateur portable; sur mon ordinateur portable, scrypt est toujours rapide, n'a pas besoin d'échauffement.
docker stats
, après 5-10 secondes: (maintenant edp_play_1, ligne 2, utilise 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
après une demi-minute: (maintenant edp_play_1 utilise uniquement CPU 0,97% - et reste comme ce, jusqu'à une demi-heure, jusqu'à ce que fait)
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
Si vous voulez tester à Scala & SBT, c'est ce qui se passe pour moi dans 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
Remarque: Ceci n'est pas lié à Docker. Je viens de tester en dehors de Docker, avec openjdk 8 installé directement sur l'instance GCE, et le résultat est le même: scrypt(..)
prend comme 3 minutes la première fois, mais le processeur est de 90-100% inactif. Par la suite, les demandes de scrypt sont complétées immédiatement.