2016-05-14 3 views
1

[要約&答え:明らかに問題は、乱数ジェネレータをシードするのに時間がかかることです。下の私の答えを見てください。 ]なぜscrypt()への最初の呼び出しは、わずか1%のCPUしか使用せず、GCEで30分かかりますか?

Google Compute Engine(GCE)では、Java仮想マシンアプリケーションがscryptのパスワードハッシュ関数に要する最初のリクエストは、コードがまだJust-In-Timeでコンパイルされていないため長くかかります。だから私は、 ダミーscrypt("pswd", 2,1,1)をサーバーの起動時に呼び出すことによって、scryptをウォームアップしています。しかし、何が起こるかは、CPUが300%+に上昇し、10-20秒間そこにとどまり、scrypt()への要求がまだ完了していないにもかかわらず、1%に戻るということです。現在では、scrypt()が完了するまで、CPUは1分で数分(2GCE vCPUで30分まで)維持されます。

なぜこの奇妙な動作ですか?

なぜ終了するまで、300%のCPUでscrypt()を実行し続けないのですか?メモリが不足しているのは ではありません。下のDockerの統計を見てください。

1回目のscrypt()要求の後、後続の要求は「すぐに」終了します。たとえば、これは: SCryptUtil.scrypt("pswd", 65536, 8, 1) はそれよりも多くの作業を行いますが、< 0.2秒かかる: SCryptUtil.scrypt("pswd", 2, 1, 1) た(前述のように)私の非常に最初のscrypt()の呼び出しであり、通常4 GCEの仮想CPUと、数分かかります - 2GCE vCPUを使用して、通常は30分ほどかかります。

私は、4 vCPU、3.6 GB RAMを搭載したGCEインスタンスを使用しています。ドッカー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のみ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.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、ライン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.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とは関係ありません。私はちょうどGCEインスタンスに直接インストールされたopenjdk 8を使ってDocker外でテストしましたが、結果は同じです:scrypt(..)は初めて3分かかるのですが、CPUは90-100%アイドルです。その後、即時に暗号化の要求が完了します。

答えて

1

問題は、乱数ジェネレータをシードするのに時間がかかることです。 Scryptはありません。この:

public static String scrypt(String passwd, int N, int r, int p) { 
    try { 
     byte[] salt = new byte[16]; 
     SecureRandom.getInstance("SHA1PRNG").nextBytes(salt); <--- look 

     byte[] derived = SCrypt.scrypt(passwd.getBytes("UTF-8"), salt, N, r, p, 32); 

here

nextBytes(salt)への呼び出しが自身をシードするSecureRandomオブジェクトを引き起こし、これが私のGoogleのCompute Engineのインスタンスで、半分の時間を要します。

これは、Javaやドッカーとは関係ありません、代わりに、ここを見て:(直接ホストマシン上ではなく、任意のドッカーコンテナ内)

# < /dev/random stdbuf -o0 strings --bytes 1 | stdbuf -o0 tr -d '\n\t ' 

これは、ランダムに/ dev /からランダム文字を読み取り、I今は数分稼働していましたが、数分後にはこれまで3つの文字しか出力されていませんでした。だから、それは非常に遅いです。

少ないランダム、より高速を使用して、は/ dev/urandomの代わりに、この:

# < /dev/urandom stdbuf -o0 strings --bytes 1 | stdbuf -o0 tr -d '\n\t ' 

はすぐに99999文字を印刷します。

(私はここでは上記< /dev/random ...コマンドが見つかりました:https://unix.stackexchange.com/a/114883/128585を)私のラップトップ上で

は、しかし、/dev/random/バージョンはすぐに30-40文字を印刷します。その後、ブロックされ、10秒ごとに1つまたは少数の文字が印刷されます。おそらく、私はマウスやキーボード、またはネットワークを使用すると、私からランダム性を得るでしょう。


アップデート私が何をしたか

:私は今、その代わり/dev/urandomを使用しています - 限り、私はインターネット上で読んだとして、それは完全に罰金です。

また、ハードウェア乱数生成器を使用し始めました。明らかにGCEのインスタンスにはこれらがあります。

apt install rng-tools # start using any hardware rand num gen, on Ubuntu 
関連する問題