Самое важное в параллельных вычислениях - это реализация.
Без алгоритма может быть трудно точно определить узкое место, влияющее на производительность.
Я думаю, что проблема заключается в реализации, а не в самой GKE
.
Предварительные условия
Я пытался воссоздать параллельные вычисления Сценарий с недавно созданным кластером GKE и вот что я узнал:
- Версия GKE: 1.15.9
- Количество узлов: 1
- Спецификация узла:
- 22 ядра
- 64 ГБ оперативной памяти.
Вот определение YAML для контейнера, который использовался для тестирования:
apiVersion: v1
kind: Pod
metadata:
name: ubuntu
namespace: default
spec:
containers:
- image: ubuntu
resources:
limits:
cpu: "16"
memory: "32Gi"
requests:
cpu: "16"
memory: "32Gi"
command:
- sleep
- "infinity"
imagePullPolicy: IfNotPresent
name: ubuntu
restartPolicy: Always
Пожалуйста, определите c посмотрите на деталь requests
и limits
resources:
limits:
cpu: "16"
memory: "32Gi"
requests:
cpu: "16"
memory: "32Gi"
Это запросит 16 CPU, что будет важно позже.
Тестирование
Я пытался смоделировать рабочую нагрузку в модуле с помощью:
- приложения, называемого стрессом (
apt install stress
) - python программы с
joblib
и Parallel
:
Напряжение приложения
Я запускал это приложение в модуле 3 раза с различным используемым количеством процессора (4,16,32):
$ stress -c 4
$ stress -c 16
$ stress -c 32
4 ядра
Как видно из вышеприведенного вывода, это приложение полностью использует 4 ядра.
Вывод команды: $ kubectl top node
показывает, что загрузка процессора составляет около 18%:
❯ kubectl top node
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
gke-gke-high-default-pool-f7a17f78-0696 4090m 18% 948Mi 1%
1 ядро из 22 должно составлять около 4,5%, а после умножения его на 4 оно будет равно быть около 18%, что соответствует показателю выше.
Изучив GCP Monitoring
, вы можете увидеть коэффициент использования примерно в 0,25 (что составляет 4 ядра из 16 выделенных):
16 ядра
Как видно из вышеприведенного вывода, этим приложением полностью занято 16 ядер.
Вывод команды: $ kubectl top node
показывает, что загрузка ЦП составляет около 73%:
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
gke-gke-high-default-pool-f7a17f78-0696 16168m 73% 945Mi 1%
1 ядро из 22 должно составлять около 4,5%, а после умножения его на 16 оно составит около 72%, что примерно столько же, сколько указано выше вывод.
Если посмотреть на GCP Monitoring
, вы можете увидеть коэффициент использования примерно в 1,0 (то есть 16 ядер из 16 выделенных):
32 ядра
Невозможно запустить 32-ядерную рабочую нагрузку на 16-ядерном компьютере без разделения времени для каждого процесса. Посмотрите, как Kubernetes управляет этим:
Как вы можете видеть все ядра используются, но только примерно на 73% каждый , Это добавило бы около 16 ядер при 100% использования.
$ kubectl top node
и GCP Monitoring
будут иметь тот же выход, что и 16-ядерный корпус.
Python программа
Я пытался использовать программу basi c Python с joblib
и Parallel
, как показано ниже:
from joblib import Parallel, delayed
import sys
my_list = range(20000)
squares = []
# Function to parallelize
def find_square(i):
return i ** 131072
# With parallel processing
squares = Parallel(n_jobs=int(sys.argv[1]), verbose=1)(delayed(
find_square)(i)for i in my_list)
Я запустил вышеуказанная программа с количеством ядер от 4 до 16. Ниже приведены результаты:
[Parallel(n_jobs=4)]: Done 20000 out of 20000 | elapsed: 7.0min finished
[Parallel(n_jobs=5)]: Done 20000 out of 20000 | elapsed: 5.6min finished
[Parallel(n_jobs=6)]: Done 20000 out of 20000 | elapsed: 4.7min finished
[Parallel(n_jobs=7)]: Done 20000 out of 20000 | elapsed: 4.0min finished
[Parallel(n_jobs=8)]: Done 20000 out of 20000 | elapsed: 3.5min finished
[Parallel(n_jobs=9)]: Done 20000 out of 20000 | elapsed: 3.1min finished
[Parallel(n_jobs=10)]: Done 20000 out of 20000 | elapsed: 2.8min finished
[Parallel(n_jobs=11)]: Done 20000 out of 20000 | elapsed: 2.6min finished
[Parallel(n_jobs=12)]: Done 20000 out of 20000 | elapsed: 2.6min finished
[Parallel(n_jobs=13)]: Done 20000 out of 20000 | elapsed: 2.6min finished
[Parallel(n_jobs=14)]: Done 20000 out of 20000 | elapsed: 2.5min finished
[Parallel(n_jobs=15)]: Done 20000 out of 20000 | elapsed: 2.5min finished
[Parallel(n_jobs=16)]: Done 20000 out of 20000 | elapsed: 2.5min finished
Как видите, существует разница во времени, необходимая для вычислений между 4 ядрами и 16.
Ниже на графике показано использование процессора для модуля, который выполнял эти тесты. Как вы можете видеть, наблюдается постепенное увеличение использования. Пожалуйста, имейте в виду, что используемый алгоритм будет иметь огромное влияние на использование процессора.
Если бы программа имела:
n_jobs=4
, она работала бы на 4 ядрах при 100%, что означало бы около 25% загрузки процессора для модуля. n_jobs=16
он будет работать на всех ядрах при примерно 100% использовании, что повлечет за собой около 100% загрузки ЦП для модуля.
Пожалуйста, дайте мне знать, если у вас есть какие-либо вопросы к этому.