Tại sao hình ảnh Docker của Alpine chậm hơn 50% so với hình ảnh Ubuntu?


35

Tôi nhận thấy rằng ứng dụng Python của tôi chạy chậm hơn nhiềupython:2-alpine3.6 so với chạy ứng dụng mà không có Docker trên Ubuntu. Tôi đã đưa ra hai lệnh điểm chuẩn nhỏ và có một sự khác biệt lớn giữa hai hệ điều hành, cả khi tôi đang chạy chúng trên máy chủ Ubuntu và khi tôi đang sử dụng Docker cho 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

Tôi cũng đã thử 'điểm chuẩn' sau, không sử dụng 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

Điều gì có thể gây ra sự khác biệt này?


1
@ Hãy nhìn lại: thời gian bắt đầu sau khi bash được cài đặt, bên trong bash shell được khởi chạy
Underyx

Câu trả lời:


45

Tôi đã chạy điểm chuẩn giống như bạn đã làm, chỉ sử dụng 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

dẫn đến chênh lệch hơn 2 giây:

$ docker run python:3-slim python -c "$BENCHMARK"
3.6475560404360294
$ docker run python:3-alpine3.6 python -c "$BENCHMARK"
5.834922112524509

Alpine đang sử dụng một triển khai khác libc(thư viện hệ thống cơ sở) từ dự án musl ( URL phản chiếu ). Có nhiều sự khác biệt giữa các thư viện . Do đó, mỗi thư viện có thể hoạt động tốt hơn trong một số trường hợp sử dụng nhất định.

Đây là một khác biệt giữa các lệnh trên . Đầu ra bắt đầu khác với dòng 269. Tất nhiên có các địa chỉ khác nhau trong bộ nhớ, nhưng nếu không thì nó rất giống nhau. Hầu hết thời gian rõ ràng là dành cho việc chờ pythonlệnh kết thúc.

Sau khi cài đặt stracevào cả hai container, chúng ta có thể có được một dấu vết thú vị hơn (Tôi đã giảm số lần lặp trong điểm chuẩn xuống còn 10).

Ví dụ: glibcđang tải các thư viện theo cách sau (dòng 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

Cùng một mã trong 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

Tôi không nói rằng đây là điểm khác biệt chính, nhưng việc giảm số lượng thao tác I / O trong các thư viện lõi có thể góp phần mang lại hiệu suất tốt hơn. Từ diff bạn có thể thấy rằng việc thực thi cùng một mã Python có thể dẫn đến các cuộc gọi hệ thống hơi khác nhau. Có lẽ điều quan trọng nhất có thể được thực hiện trong việc tối ưu hóa hiệu suất vòng lặp. Tôi không đủ trình độ để đánh giá xem vấn đề hiệu năng có phải do cấp phát bộ nhớ hoặc một số hướng dẫn khác không.

  • glibc với 10 lần lặp:

    write(1, "0.032388824969530106\n", 210.032388824969530106)
    
  • musl với 10 lần lặp:

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

muslchậm hơn 0,0028254222124814987 giây. Khi sự khác biệt tăng theo số lần lặp, tôi giả sử sự khác biệt nằm ở việc cấp phát bộ nhớ cho các đối tượng JSON.

Nếu chúng tôi giảm điểm chuẩn xuống chỉ nhập, jsonchúng tôi nhận thấy sự khác biệt không quá lớn:

$ 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

Đang tải thư viện Python có vẻ tương đương. Tạo list()ra sự khác biệt lớn hơn:

$ 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

Rõ ràng hoạt động đắt nhất là json.dumps(), có thể chỉ ra sự khác biệt trong phân bổ bộ nhớ giữa các thư viện đó.

Nhìn lại điểm chuẩn , muslviệc phân bổ bộ nhớ thực sự chậm hơn một chút:

                          musl  | glibc
-----------------------+--------+--------+
Tiny allocation & free |  0.005 | 0.002  |
-----------------------+--------+--------+
Big allocation & free  |  0.027 | 0.016  |
-----------------------+--------+--------+

Tôi không chắc ý nghĩa của "phân bổ lớn" là gì, nhưng muslchậm hơn gần 2 lần, điều này có thể trở nên quan trọng khi bạn lặp lại các hoạt động như vậy hàng ngàn hoặc hàng triệu lần.


12
Chỉ cần sửa vài cái. musl không phải là triển khai glibc của riêng Alpine . 1 musl không phải là một (tái) thực hiện glibc, mà là triển khai libc khác nhau theo tiêu chuẩn POSIX. Musl thứ 2 không phải là thứ của riêng Alps , đó là một dự án độc lập, không liên quan và musl không chỉ được sử dụng ở Alpine.
Jakub Jiruska

cho rằng libc musl có vẻ như là một tiêu chuẩn tốt hơn dựa trên *, chưa kể đến việc thực hiện mới hơn tại sao nó dường như kém hơn glibc trong những trường hợp này? * cf. wiki.musl-libc.org/feftal-differences-from-glibc.html
Rừng

Là sự khác biệt của 0,0028 giây có ý nghĩa thống kê? Độ lệch tương đối chỉ là 0,0013% và bạn đang lấy 10 mẫu. Độ lệch chuẩn (ước tính) cho 10 lần chạy đó (hoặc thậm chí chênh lệch tối đa) là bao nhiêu?
Peter Mortensen

@PeterMortensen Đối với các câu hỏi liên quan đến kết quả điểm chuẩn, bạn nên tham khảo mã Eta Labs: etalabs.net/libc-bench.html Ví dụ: kiểm tra căng thẳng malloc được lặp lại 100 nghìn lần. Các kết quả có thể phụ thuộc nhiều vào phiên bản thư viện, phiên bản GCC và CPU được sử dụng, chỉ để nêu tên một vài khía cạnh.
Tombart
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.