알파인 도커 이미지가 우분투 이미지보다 50 % 이상 느린 이유는 무엇입니까?


35

우분투에서 Docker없이 실행하는 것보다 Python 응용 프로그램을 실행할 때 훨씬 느리다 는 것을 알았습니다 python:2-alpine3.6. 두 가지 작은 벤치 마크 명령을 생각해 냈고 두 운영 체제 사이에 Ubuntu 서버에서 실행할 때와 Docker for Mac을 사용할 때 두 가지 운영 체제 사이에 큰 차이가 있습니다.

$ 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

또한 파이썬을 사용하지 않는 다음 '벤치 마크'를 시도했습니다.

$ 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

이 차이를 일으키는 원인은 무엇입니까?


1
@Seth 다시보기 : bash가 설치된 후 시작된 bash 쉘 내부에서 타이밍이 시작됩니다.
Underyx

답변:


45

Python 3 만 사용하여 동일한 벤치 마크를 실행했습니다.

$ 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 프로젝트 ( mirror URL ) 와 다른 libc(기본 시스템 라이브러리) 구현을 사용하고 있습니다. 이들 라이브러리 간에는 많은 차이점 이 있습니다 . 결과적으로 특정 사용 사례에서 각 라이브러리의 성능이 향상 될 수 있습니다.

여기의 위의 해당 명령 사이의 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 코드를 실행하면 시스템 호출이 약간 다를 수 있음을 알 수 있습니다. 아마도 루프 성능을 최적화하는 데 가장 중요 할 수 있습니다. 성능 문제가 메모리 할당 또는 다른 명령으로 인한 것인지 판단 할 수있는 자격이 없습니다.

  • glibc 10 회 반복 :

    write(1, "0.032388824969530106\n", 210.032388824969530106)
    
  • musl 10 회 반복 :

    write(1, "0.035214247182011604\n", 210.035214247182011604)
    

musl0.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

파이썬 라이브러리를로드하는 것은 비슷합니다. 생성 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 배 더 느립니다. 이러한 작업을 수천 또는 수백만 번 반복하면 의미가 커질 수 있습니다.


12
몇 가지 수정 만하면됩니다. musl은 glibc 의 Alpine 자체 구현 이 아닙니다 . 첫 번째 musl은 glibc의 (재) 구현이 아니라 POSIX 표준에 따라 다른 libc 구현입니다 . 두 번째 musl은 Alpine 자신의 것이 아니며 독립형이며 관련이없는 프로젝트이며 musl은 Alpine에서만 사용되지 않습니다.
Jakub Jirutka

musl libc가 더 나은 표준 기반 *처럼 보인다면, 새로운 구현은 말할 것도없고 왜 이런 경우에 glibc보다 성능이 낮은 것 같습니까? * cf. wiki.musl-libc.org/functional-differences-from-glibc.html
Forest

통계적으로 0.0028 초의 차이가 있습니까? 상대 편차는 0.0013 %에 불과하며 10 개의 샘플을 취합니다. 10 번의 런 (또는 최대-최소 차이)에 대한 (추정 된) 표준 편차는 무엇입니까?
Peter Mortensen

@PeterMortensen 벤치 마크 결과에 관한 질문은 Eta Labs 코드를 참조하십시오. etalabs.net/libc-bench.html 예를 들어 malloc 스트레스 테스트는 100k 회 반복됩니다. 결과는 라이브러리 버전, GCC 버전 및 사용 된 CPU에 따라 크게 좌우 될 수 있습니다.
톰 바트
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.