質問: alpine dockerの画像がubuntuの画像よりも50%以上遅くなるのはなぜですか? 私のpythonアプリケーションはpython:2-alpine3.6上で実行するとubuntu上でdockerなしで実行するよりも遅く遅くなることに気づきました。私は2つの小さなベンチマークコマンドを思い付きました、そして私がubuntuサーバでそれらを実行している時と、私がdocker for macを使っている時の両方で、2つのオペレーティングシステムの間に目に見える大きな違いがあります。$ benchmark="import timeit; print(timeit.timeit('import json; json.dumps(list(range(10000)))', number=5000))" $ docker run python:2-alpine3.6 python -c $benchmark 7.6094589233 $ docker run python:2-slim python -c $benchmark 4.3410820961 $ docker run python:3-alpine3.6 python -c $benchmark 7.0276606959 $ docker run python:3-slim python -c $benchmark 5.6621271420 私はまたpythonを使用していない次の 'ベンチマーク'を試してみました。$ docker run -ti ubuntu bash root@6b633e9197cc:/# time $(i=0; while (( i < 9999999 )); do (( i ++ )); done) real 0m39.053s user 0m39.050s sys 0m0.000s $ docker run -ti alpine sh / # apk add --no-cache bash > /dev/null / # bash bash-4.3# time $(i=0; while (( i < 9999999 )); do (( i ++ )); done) real 1m4.277s user 1m4.290s sys 0m0.000s この違いの原因は何でしょうか。
回答: 私はあなたが行ったのと同じベンチマークを実行しました。python3だけを使います。$ docker run python:3-alpine3.6 python --version python 3.6.2 $ docker run python:3-slim python --version python 3.6.2 2秒以上の差があります。$ docker run python:3-slim python -c "$benchmark" 3.6475560404360294 $ docker run python:3-alpine3.6 python -c "$benchmark" 5.834922112524509 アルパインは、 muslプロジェクトとは異なるlibc(基本システムライブラリ)の実装を使用しています。 ( ミラーurl )。これらのライブラリの間には 多くの違いがあります 。その結果、特定のユースケースでは各ライブラリのパフォーマンスが向上する可能性があります。これが上記のコマンド間の strace diffです 。出力は269行目と異なり始めます。もちろん、メモリには異なるアドレスがありますが、それ以外は非常に似ています。ほとんどの時間は明らかにpythonコマンドが終了するのを待つのに費やされています。両方のコンテナにstraceをインストールした後、 より興味深いトレース を取得できます(ベンチマークの反復回数を10に減らしました)。たとえば、glibcは次の方法でライブラリをロードしています(182行目)。openat(at_fdcwd, "/usr/local/lib/python3.6", o_rdonly|o_nonblock|o_directory|o_cloexec) = 3 getdents(3, /* 205 entries */, 32768) = 6824 getdents(3, /* 0 entries */, 32768) = 0 musl内の同じコード:open("/usr/local/lib/python3.6", o_rdonly|o_directory|o_cloexec) = 3 fcntl(3, f_setfd, fd_cloexec) = 0 getdents64(3, /* 62 entries */, 2048) = 2040 getdents64(3, /* 61 entries */, 2048) = 2024 getdents64(3, /* 60 entries */, 2048) = 2032 getdents64(3, /* 22 entries */, 2048) = 728 getdents64(3, /* 0 entries */, 2048) = 0 これが大きな違いだとは言っていませんが、コアライブラリでのi/o操作の数を減らすと、パフォーマンスが向上する可能性があります。 diffから、まったく同じpythonコードを実行すると、わずかに異なるシステムコールが発生する可能性があることがわかります。おそらく最も重要なことは、ループのパフォーマンスを最適化することにあります。パフォーマンスの問題がメモリ割り当てによるのか、それとも他の命令によるのかを判断するのに十分な資格がありません。 10回の反復を含むglibc: write(1, "0.032388824969530106\n", 210.032388824969530106) 10回の反復を含むmusl: write(1, "0.035214247182011604\n", 210.035214247182011604) muslは0.0028254222124814987秒遅くなります。違いが繰り返し回数とともに増えるにつれて、違いはjsonオブジェクトのメモリ割り当てにあると思います。ベンチマークをjsonのみをインポートするように減らすと、違いはそれほど大きくないことがわかります。$ benchmark="import timeit; print(timeit.timeit('import json;', number=5000))" $ docker run python:3-slim python -c "$benchmark" 0.03683806210756302 $ docker run python:3-alpine3.6 python -c "$benchmark" 0.038280246779322624 pythonライブラリをロードすることは同等に見えます。 list()を生成すると、より大きな違いが生まれます。$ benchmark="import timeit; print(timeit.timeit('list(range(10000))', number=5000))" $ docker run python:3-slim python -c "$benchmark" 0.5666235145181417 $ docker run python:3-alpine3.6 python -c "$benchmark" 0.6885563563555479 明らかに最も高価な操作はjson.dumps()であり、これはそれらのライブラリー間のメモリー割り振りの違いを指す可能性があります。 ベンチマーク をもう一度見てください。muslは、メモリー割り当てが実際にはわずかに遅くなります。 musl | glibc -----------------------+--------+--------+ tiny allocation & free | 0.005 | 0.002 | -----------------------+--------+--------+ big allocation & free | 0.027 | 0.016 | -----------------------+--------+--------+ 「大きな割り当て」が何を意味するのかわからないが、muslはほぼ2倍遅いので、このような操作を数千から数百万回繰り返すと重大になる可能性があります。