Эта статья, скорее даже не статья, а заметка, и цель ее - подсветить саму идею полезности построения моделей, которые можно использовать в процессе принятия решений, при проектировании IT инфаструктур, да и в целом любых систем. Ну и, конечно, еще раз показать сам инструмент, и подход к мышлению, необходимый при использовании этого инструмента.

Minizinc

На самом деле об инструменте minizinc уже упоминалось на хабре:

По этому я всего лишь в двух словах напомню. Minizinc - это "constraint modeling language". По сути язык, позволяющий, в некотором смысле, декларативно описать проблему, и попросить систему решить ее за вас. Говоря проще, язык предоставляет возможность написать что-то вроде следующего:

# рыночек
яблоки: стоят 13, утоляют голод на 2 часа, у нас их 1000 порций
гречка: стоит 21, утоляет голод на 4 часа, у нас ее 400 порций
хлеб: стоит 17, утоляет голод на 6 часов, у нас его 500 порций
мясо: стоит 100, утоляет голод на 9 часов, у нас его 150 порций

# у нас есть
бюджет = 10000

# покупаем продукты
ограничение: цена яблок*количество + цена гречки*количество + 
							цена хлеба*количество + цена мяса*количество <= бюджет

найти: сколько и чего мы можем купить в рамках ограничений,
			  максимизировать время, на которое утоляется голод

Как видите, тут нет ответа на вопрос "как решать". Мы декларативно описываем входные данные, ограничения, которые у нас есть, цель, которую мы хотим достичь. Затем мы просим систему попытаться найти решение задачи.

Что можно с этим делать

Довольно часто, при проектировании инфраструктуры под Kubernetes (AKS) в Microsoft Azure, у заказчиков возникают странные вопросы, типа: какого размера будет все это добро, или, сколько все это будет нам стоит? Для того чтобы хоть как-то ответить на этот вопрос надо предположить какого размера виртуальные машины выбрать, сколько их должно быть, сколько они стоят в нужном регионе. Размер машин, в свою очередь, зависит от количества и прожорливости приложений, а так же от количества экземпляров каждого из них. И так далее. А ведь нам хочется еще и подобрать все это по минимальной цене. В общем и целом, входных переменных довольно много и свести их в кучу, да еще и для каждого размера виртуальных машин отдельно, скажем прямо - не самая интересная работа в мире.

Давайте попробуем с одной стороны немного упростить себе жизнь, а с другой стороны пощупаем моделирование в minizinc.

Общие соображения по ограничениям

Начнем с виртуальных машин. Первое и, наверное, самое важное - ресурсов машины, должно хватить на все запущенные экземпляры приложения. Другими словами, в сумме, приложения должны сожрать меньше, чем доступно на ноде. Кроме того, здесь стоит учесть нагрузку, которую создает сам Kubernetes. Для этого имеет смысл зарезервировать некий процент ресурсов, и не отдавать его приложениям. С другой стороны, чтобы ресурсы не простаивали, нужно иметь некую нижнюю планку потребления ресурсов. Так же, было бы хорошо, чтобы суммарно, все приложения влезали в кластер, а для этого модель должна определять необходимое количество нод, держа в уме нагрузку на приложения.

Переходим к приложениям. Положим, каждое приложение должно исполняться как минимум в 2х экземплярах, на случай отказа одного из них. При этом, эти экземпляры должны исполняться на разных нодах, по той же причине. Плюс к этому, было бы очень неплохо, если бы модель умела оценить количество нод, в зависимости от предполагаемой нагрузки на приложение.

Начнём, пожалуй

Обычно, модель состоит из нескольких кусков: объектов, учавствующих в модели, ограничений (constraints), описания решений, которые она должна найти, целевой функции, к которой мы стараемся стремиться. Целевой функции может не быть. тогда модель просто выдаст все "решения", которые она приняла

Начнем с описания приложений. Мы хотим запускать в кластере некое, заранее известное количество приложений, с известными максимальными значениями потребления ресурсов. Все эти значения - переменные, что дает нам возможность настраивать модель и менять ее поведение. Для моделирования "сложных" объектов в minizinc применяется следующий трюк. Задается некий ENUM тип, который используется как индекс в массивах со значениями атрибутов

enum appNames = {A, B, C, D, E};
array[appNames] of int: appRAM = [2,4,6,8,4];
array[appNames] of int: appCPU = [200,400,400,450,2250];
array[appNames] of int: appConnectionsPerInstance = [5,2,2, 2,2];
array[appNames] of int: appConnectionsFact = [20,4,3,4,10];

B данном случае, enum appnames задает список приложений. И затем, каждому приложению из списка ставится в соотвествие набор атрибутов: максимальный объем потребления RAM, CPU, некий коэффициент нагрузки на экземпляр, и предполагаемая нагрузка на каждый экземпляр, измеренная в тех же единицах.

Хорошо, с приложениями разобрались, теперь ноды кластера. Там, собственно, ровно то же самое. Нам нужно смоделировать объект ноды с его атрибутами, поэтому

enum nodeKinds = {D2sv5, D4sv5, D8sv5}; 
array[nodeKinds] of int: clusterNodeRAM = [8,16,32];
array[nodeKinds] of int: clusterNodeCPU = [2000,4000,8000];
array[nodeKinds] of float: clusterNodePrice = [0.048, 0.096, 0.192];

Тут я использую имена размеров виртуальных машин Microsoft Azure, их стоимость и параметры. Но в целом, все ровно то же самое, что и с приложениями.

Стоит сделать отступление и упомянуть, что в minizinc есть два типа "переменных": обычные переменные, к которым мы все привыкли, и "decision variables". Последние представляют "решения", которые minizinc должен принять, чтобы требования и органичения модели были соблюдены. Иными словами, занчения обычных переменных мы должны задать вручную, а значения "decision variables" minizinc должен найти сам. До сих пор мы использовали только обычные переменные

Итак, с объектами модели определились, пришло время ограничений и "decision variables".

Прежде всего мы хотим описать сам кластер, который, как водится, состоит из одной или нескольких нод. Сделаем это примерно вот так

int: maxClusterSize = 6;
set of int: CLUSTER = 1..maxClusterSize;

Теперь начинается самое интересное. На каждой ноде этого кластера мы хотим запусить одно или несколько приложений. Смоделируем это как некую матрицу, в которой измерениями будут ноды кластера и имена приложений, а значениями флажки, запущено приложение или нет. Что-то вроде этого.

Сделать это можно примерно вот так. Тут каждой ноде кластера CLUSTER мы ставим в соответствие список приложений, которые на ней исполняются. На пересечении стоит флаг, который говорит запущен на этой ноде экземпляр этого приложения или нет. Такая схема, в дополнение ко всему, косвенно гарантирует, что на каждой ноде может исполняться только один экземпляр каждого приложения. Другими словами если нам понадобится запусить два экземпляра приложения А, они гарантированно попадут на разные ноды.

array[CLUSTER, appNames] of var bool: runningApps;

Обратите внимание на слово var в этой строке. Это индикатор "decision variable". По сути эта строка говорит, что мы создаем массив, индексами которого являются ноды кластера и приложения, а значениями "decision variables". Это значает что minizinc должен будет принять решения по каждой из этих переменных, решив, как распределить приложения по нодам кластера.

Отлично, переходим к ограничениям (constraints). Для кажой ноды кластера мы должны определить такие условия, чтобы все запущенные экземпляры приложени влезали на ноду, и учесть зарезервированный объем ресурсов. Попробуем для начала с RAM

constraint forall (i in CLUSTER) ( 
  sum(j in appNames) (runningApps[i,j] * appRAM[j]) >= 
  	(clusterNodeRAM[???] * minNodeRAMConsumption) /\
  sum(j in appNames) (runningApps[i,j] * appRAM[j]) <= 
  	(clusterNodeRAM[???] * maxNodeRAMConsumption)
);

Однако тут возникает несколько проблем, они помечены ???? поскольку он задан как множество с элементами типа int. Итерируя по CLUSTER, мы бежим по елементам типа int, а из них нельзя достать атрибутов ноды. Вторая проблема это выражение sum(j in appNames) (runningApps[i,j] * appRAM[j]) которое малость сбивает с толку, да еще и используется дважды.

Для того чтобы побороть первую проблему, введем еще один индекс, который свяжет CLUSTER и nodeKind. Это даст нам возможность по номеру ноды доставать ее атрибуты. Вторая проблема решается добавлением еще одного массива "decision variables". Тут мы позволим minizinc самому решить, каким будет потребление, но мы жестко ограничим его, потребовав равенства с суммой потребления RAM всеми приложениями ноды. И это решение можно затем использовать для сравнения. Выходит примерно вот так

% индекс по нодам кластера
array[CLUSTER] of var nodeKinds: nodes;

% дополнительный массив decision variable,
% хранящий потребление ресурсов приложениями на ноде
array[CLUSTER] of var int: nodeRAMConsumption;

% ну и собсно само ограничение, требующее чтобы значение в массиве
% совпадало с суммой потребления ресурсов
constraint forall (i in CLUSTER) ( 
  nodeRAMConsumption[i] =   sum(j in appNames) (runningApps[i,j] * appRAM[j])
);

% в этом случае ограничение по RAM упрощается
constraint forall (i in CLUSTER) ( 
  nodeRAMConsumption[i] >= (clusterNodeRAM[nodes[i]] * minNodeRAMConsumption) /\
  nodeRAMConsumption[i] <= (clusterNodeRAM[nodes[i]] * maxNodeRAMConsumption)
);

Кроме того, в рамках этого ограничения мы добавляем требования нижней и верхней границы потребления используя знак конъюнкции /\

Ну а поскольку CPU и RAM это примерно про одно и то же, то ограничения для него выглядят идентично

array[CLUSTER] of var int: nodeCPUConsumption;
constraint forall (i in CLUSTER) ( 
  nodeCPUConsumption[i] =   sum(j in appNames) (runningApps[i,j] * appCPU[j])
);

constraint forall (i in CLUSTER) ( 
  nodeCPUConsumption[i] >= (clusterNodeCPU[nodes[i]] * minNodeCPUConsumption) /\
  nodeCPUConsumption[i] <= (clusterNodeCPU[nodes[i]] * maxNodeCPUConsumption)
);

Итак, к этому моменту мы определили объекты application и потребовали от модели распределить их по node так, чтобы они влезали в каждую node . При этом учитывается требование к плотности и остается резерв на потребление самого кластера. Остался сущий пустяк, мы хотим, чтобы модель учитывала нагрузку на приложения. У нас есть максимальная нагрука на экземпляр, после которой необходимо добавить еще один -appConnectionsPerInstance, и текущая фактическая нагрузка - appConnectionsFact.На основе этих значений мы можем потребовать, чтобы модель посчитала количество экземпляров каждого приложения. И затем потребовать, чтобы суммарное количество экземпляров приложения в кластере совпадало с рассчетным.

% для каждого приложения нужна decision variable, в которой
% minizinc определит нужное количество экземпляров 
array[appNames] of var int: appInstanceCount;

% потребуем, чтобы количество нужных экземпляров совпадало
% c отношением фактической накрузки к базовой 
% округленное вверх до ближайшего целого
constraint forall (j in appNames)(
  appInstanceCount[j] = ceil(appConnectionsFact[j]/appConnectionsPerInstance[j])
);

% потребуем, чтобы количество приложений совпадало с решением
% о количестве экземпляров, принятым выше
constraint forall (j in appNames) ( 
  sum(i in CLUSTER) (runningApps[i,j]) = appInstanceCount[j]
);

Ну и наконец, целевая функция и требование к ее оптимизации. Сумма цен по всем нодам должна быть минимальной.

var float: cost =  (sum(i in nodes)(clusterNodePrice[i])) * 24 * 30 ; % target function to optimize
solve minimize cost;

Ну, вот вроде и все рассуждения. Осталось только задать нужные значения, и оформить немного

Модель целиком
include "all_equal.mzn";

% config section
int: maxClusterSize = 6;
float: minNodeRAMConsumption = 0.5;
float: maxNodeRAMConsumption = 0.8;
float: minNodeCPUConsumption = 0.1;
float: maxNodeCPUConsumption = 0.8;
% end config

% applications and their attributes
enum appNames = {A, B, C, D, E};
array[appNames] of int: appRAM = [2,4,6,8,4];
array[appNames] of int: appCPU = [200,400,400,450,2250];
array[appNames] of int: appConnectionsPerInstance = [5,2,2, 2,2];
array[appNames] of int: appConnectionsFact = [4*5,2*2,3*2,2*2, 5*2];

% cluster nodes and their attributes
enum nodeKinds = {D2sv5, D4sv5, D8sv5}; 
array[nodeKinds] of int: clusterNodeRAM = [8,16,32];
array[nodeKinds] of int: clusterNodeCPU = [2000,4000,8000];
array[nodeKinds] of float: clusterNodePrice = [0.048, 0.096, 0.192];

% CLUSTER node index
set of int: CLUSTER = 1..maxClusterSize;

array[CLUSTER, appNames] of var bool: runningApps; % apps running on a node
array[CLUSTER] of var nodeKinds: nodes; 

% CONSTRAINTS
% all nodes are of equal size
constraint all_equal(nodes);

% assuming the load, calculate target number of pods
array[appNames] of var int: appInstanceCount;
constraint forall (j in appNames)(
  appInstanceCount[j] = ceil(appConnectionsFact[j]/appConnectionsPerInstance[j])
);

% assuming the load, use calculated number of pods
constraint forall (j in appNames) ( 
  sum(i in CLUSTER) (runningApps[i,j]) = appInstanceCount[j]
);

% supporting constraint to calculate and store RAM consumption
array[CLUSTER] of var int: nodeRAMConsumption;
constraint forall (i in CLUSTER) ( 
  nodeRAMConsumption[i] =   sum(j in appNames) (runningApps[i,j] * appRAM[j])
);

% sum of RAM of all apps on the node >=minNodeRAMConsumption and <= maxNodeRAMConsumption of total node RAM
constraint forall (i in CLUSTER) ( 
  nodeRAMConsumption[i] >= (clusterNodeRAM[nodes[i]] * minNodeRAMConsumption) /\
  nodeRAMConsumption[i] <= (clusterNodeRAM[nodes[i]] * maxNodeRAMConsumption)
);

% supporting constraint to calculate and store CPU consumption
array[CLUSTER] of var int: nodeCPUConsumption;
constraint forall (i in CLUSTER) ( 
  nodeCPUConsumption[i] =   sum(j in appNames) (runningApps[i,j] * appCPU[j])
);

% sum of CPU of all apps on the node >= minNodeCPUConsumption and <= maxNodeCPUConsumption of total node CPU
constraint forall (i in CLUSTER) ( 
  nodeCPUConsumption[i] >= (clusterNodeCPU[nodes[i]] * minNodeCPUConsumption) /\
  nodeCPUConsumption[i] <= (clusterNodeCPU[nodes[i]] * maxNodeCPUConsumption)
);

var float: cost =  (sum(i in nodes)(clusterNodePrice[i])) * 24 * 30 ; % target function to optimize
solve minimize cost;

output [ if j = A then "\(nodes[i]); CPU:\(nodeCPUConsumption[i])/\(clusterNodeCPU[nodes[i]]); RAM:\(nodeRAMConsumption[i])/\(clusterNodeRAM[nodes[i]]), " else "" endif ++ 
         if fix(runningApps[i,j]) = 1 then show(fix(appNames[j])) ++ ";" else "" endif ++ 
         if j = E then "\n" else "" endif
         | i in CLUSTER, j in appNames
];

Я намеренно опускаю секцию output поскольку, к сожалению, minizinc плохо это умеет. В конечном итоге на выходе с саданными параметрами мы получам следующее

D4sv5; CPU:2700/4000; RAM:12/16, D;E;
D4sv5; CPU:2850/4000; RAM:10/16, A;B;E;
D4sv5; CPU:2850/4000; RAM:12/16, A;C;E;
D4sv5; CPU:2850/4000; RAM:12/16, A;C;E;
D4sv5; CPU:2700/4000; RAM:12/16, D;E;
D4sv5; CPU:1000/4000; RAM:12/16, A;B;C;
----------
==========

Это означает, что наша модель решила, что все ноды должны быть рамера D4sv5. Кроме того для проверки выводится потребление CPU и RАМ приложениями на ноде против количества доступных CPU и RAM. ну и наконец расположения приложений по нодам. Строка ========== в выводе, это специальный индикатор, который говорит о том, что для заданных параметров minizinc считает это решение оптимальным.

В заключении хочу отметить что это не единственный тип задач, который можно моделировать с применением minizinc. Есть два отличных курса, которые можно порекомендовать: Basic Modeling for Discrete Optimization | Coursera, Advanced Modeling for Discrete Optimization | Coursera. А если хочется больше матана - Discrete Optimization | Coursera.

Удачного моделирования и оптимизации!

Комментарии (26)


  1. amarao
    18.09.2021 09:24

    А оно само не должно отскейлиться по появлению replicas=N деплоймента? Вроде же, все приличные хостеры куба уже давно автоскейл сделали. И даунскейл, для приличия же.


    1. eosfor Автор
      18.09.2021 09:40

      Модель не скелит кластер. Цель - найти минимальный по цене кластер в который влезет наша нагрузка, не создавая сам кластер :). При ее росте, физически кластер отскейлится конечно. Но в нашем случае мы ищем минимальный размер по минимальной цене, чтобы сказать заказчику что-то навроде: если вы хотите это сделать, минимальная цена вопроса будет в районе X. При скейле она будет только расти.

      Некоторые заказчики в этот момент говорят, типа, что-то дорогой, этот ваш кубернетис. А еще его и поддерживать надо, так совсем ой.


      1. amarao
        18.09.2021 10:37

        Я понял, это для эстимейтов цены. Разумно, да.

        (Хотя это не отменяет того, что куб на виртуалках кратно дороже эквивалентного baremetal).


        1. vainkop
          18.09.2021 11:59

          У bare metal настолько много минусов, что при любой возможности его не использовать, не используйте.

          И далеко не во всех случая совокупная стоимость владения bare metal ниже cloud и ни о каких "кратно дороже" и речи быть не может, просто вы не умеете в FinOps.

          При использовании определенных техник возможно значительно(!) снизить расходы на облако: если подписываться брать у них машины в течении года/нескольких лет + spot instances + такие сервисы как https://spot.io/ + использование VPC endpoints + всякие https://www.infracost.io/ и ещё много что. Знаю многих, кто сходу тратил кучу денег в облаках не умея это правильно просчитать и не умея использовать правильные технологии.

          А ещё, например, стартапный план Амазона (если у любого серьёзного облака) позволяет получить бюджет в 100 тысяч долларов, чего для начала хватит очень многим.


          1. amarao
            18.09.2021 12:20

            Смотрите - чем меньше контора, тем больше у неё пользы от облаков. Если у вас утилизация ресурсов плавает от 1 до 10% (с пиками до 30%) одного сервера - вы, очевидно, заплатив 300 баксов в месяц за all inclusive, экономите.

            А вот если у вас baseline в несколько тысяч ядер, то как бы вы не крутили, есть "базовая цена сервера", "наценка за клауд" и всё. Чем меньше deployment events в единицу времени (месяц?), тем менее выгоден cloud, потому что нагрузка стационарна.


            1. vainkop
              18.09.2021 12:31

              Если огромное количество кейсов, когда облака также более выгодны и для small и для medium и для large компаний. Взять и описать всё в двух предложениях, как пытаетесь вы, невозможно, каждый кейс индивидуален и переменных влияющих на итоговую цифру много (включая расходы на персонал)

              Чаще всего компании, которые боятся облаков и говорят, что там дорого просто не умеют правильно проектировать и использовать то, что я перечислил в предыдущем сообщении.

              Единственное что никак не побороть в AWS/GCP/Azure это цена трафика, что не для всех компаний критично. Для кого очень очень критично часть нагрузок таки держат в каком-нибудь DO.


              1. amarao
                18.09.2021 12:51

                Эм... Противопоставлять DO и AWS - это так себе затея. equinix vs aws - вот это уже больше похоже на сравнение.


                1. vainkop
                  18.09.2021 13:11

                  "каком-нибудь DO" = хостинг вроде DO второго третьего и т.д. порядка не из первой тройки.


                  1. amarao
                    18.09.2021 13:22

                    Я именно про это и говорил. DO = дисконтер. Есть серьёзные конторы (IBM'овский softlayer), которые дают очень хороший baremetal через API. И оно всё равно дешевле aws'а, хоть IBM никогда скромными запросами не отличалась.


                    1. vainkop
                      18.09.2021 13:49

                      Есть причины по которым AWS дороже.

                      IBM может быть сколько угодно серьезной компанией, но в этом бизнесе им до AWS как до луны, поэтому у IBM bare metal и дешевле AWS bare metal.

                      Некоторые из причин, почему AWS в чём-то дороже условного IBM/Oracle & etc:

                      • прогнозируемая, испытанная, проверенная и проверяемая годами надёжность

                      • богатая несравнимая ни с одной другой экосистема. У них есть managed практически что угодно и это позволяет не тратить разного рода ресурсы. Например вместо HA Patroni Postgres берёте RDS (которым тоже естественно нужно уметь правильно пользоваться)

                      • наличие отличных top tier дц во многих зонах по миру. Не говорим про Россию т.к. с финансовой точки зрения этот рынок, к сожалению, не интересен

                      • очень качественное api и наличие нескольких хорошо поддерживаемых инструментов для него

                      • очень хорошая техническая поддержка

                      • commit to upstream including Kubernetes, Elasticsearch/OpenSearch & etc

                      При всем вышеперечисленным настаиваю на том, что в большинстве случаев при правильном подходе к оптимизации и планированию расходов их можно держать на уровне если не ниже, то вполне сравнимом с другими провайдерами/хостингами.


                      1. amarao
                        18.09.2021 13:59

                        В каком бизнесе ibm далеко? В клаудах? Посмотрите, у кого выручка от клаудов самая большая в мире.


                      1. vainkop
                        18.09.2021 14:11

                        IBM cloud безусловно далеко до AWS, хотя вы можете найти какие-то статьи, где IBM cloud где-то в чём-то впереди. Генеральным директором всего Amazon не зря стал бывший генеральный директор AWS.

                        Добавьте ко всему мной сказанному то, что для создания/поддержки инфраструктуры на AWS очень легко найти очень качественную команду инженеров с десятилетиями опыта, чего точно нельзя сказать про IBM cloud, а это расходы и расходы также не маленькие.


                      1. celebrate
                        19.09.2021 11:53

                        Последний квадрант Гартнера по публичным облакам утверждает, что IBM Cloud далеко позади AWS.


            1. vainkop
              18.09.2021 12:37

              Вы видимо берёте и сравниваете "в лоб" некую базовую цену сервера, которая, например в AWS в случае использования трехгодичной подписки + spot instances + других техник совершенно не та, что on demand.

              При чём тут вообще количество неких deployment events я не понял? Хоть каждую минуту деплойте и инфру и приложения, цена от этого не поменяется :)


              1. amarao
                18.09.2021 12:50

                нет, я не сравниваю "в лоб". Я видел достаточно деплойментов разного типа, чтобы говорить про это.

                Насчёт deployment events. Смотрите, представьте себе cloud, в котором у каждого ресурса был один deployment event и с тех пор конфигурация не менялась годами. Что выгоднее - cloud или бареметал? Очевидно, бареметал. Потому что по raw performance эквивалент будет дешевле.

                Теперь посмотрим на другой сценарий - инстансы/лямбды/whatever появляются и исчезают, под временный стенд для тестов, под внезапный 10х всплеск нагрузки, etc. В этой ситуации может оказаться, что клауд с baseline 1x и пиками 10x, плюс постоянной ротацией ephimerial фигни при тестах - кратно выгоднее, чем заказанные и простаивающие 10x ресурсы, плюс примерно столько же на стейджинги.

                В чём между ними разница? В числе deployment events. Экономия от "клауда" происходит в тот момент, когда кто-то что-то не использует и за это либо не берут деньги (лямбда), либо удаляют (инстансы). Если deplyment (в оба направления - на создание и удаление) не происходит достаточно часто, то экономического смысла клауды не имеют.

                (Это не отменяет де-факто аутсорс части обслуживания инфраструктуры, что совершенно отдельный вопрос).


                1. vainkop
                  18.09.2021 13:04

                  Не знаю что вы видели, я работаю с большим количеством компаний разного размера и вижу это каждый день.

                  Очевидно я рассматриваю кейсы с каким-либо трафиком/с каким либо взаимодействием с пользователем, а не сферического коня в вакууме, которого не трогают годами. Там ещё тоже смотря как не трогают. Если вызывают изредка, то может и лямбдой и тп можно заменить :) Нагрузка же в случаях наличия пользовательского трафика априори не константа, а значит имеет смысл масштабировать инфраструктуру под нагрузку.

                  Вопрос аутсорса обслуживания части инфраструктуры в облаках это конечно вопрос о дельный, но его точно стоит учитывать и добавлять к общей стоимости на инфраструктуру и в этом облако сильно впереди bare metal. Есть топовые компании с достаточно большой инфраструктурой которую обслуживает очень мало людей.


                  1. amarao
                    18.09.2021 13:21

                    В этом треде я сам для себя эту идею сформулировал - чем более динамичная среда, тем выше финансовая польза от облаков. Грубо говоря, если 90% константны, то оставшиеся 10% погоды не сделают. Если 90% динамические, то экономия на 90% ресурсов в моменты простоя кратно перевешивает финансовый оверхед.

                    Хотя, на самом деле, в разработке и прототипировании клаудный подход (возможность заказать ресурс asap, а не ждать месяц) - это бесценно. Но какой именно ресурс - это интерсный вопрос. Тот же scaleway и equinix выдают бареметал с почасовой оплатой за единицы минут, что мало отличается от времени запуска виртуалки в GCP, а производительность у условного Ryzen с nvme такая, что GCP'шный эквивалент будет стоить как оба крыла самолёта.


                    1. vainkop
                      18.09.2021 14:05

                      Вы пытаетесь переизобрести FinOps? Не нужно, он уже существует. Очень и очень много параметров влияют на итого. И это далеко не только константность/динамичность нагрузок на сервера. Не стоит недооценивать неумение неспециалиста в вопросе без специально заточенных под это инструментов и десятилетий опыта (а сейчас уже такое накопилось да) просчитать всю картину в целом. В серьезных компаниях для оценки таких миграций нанимаются специально обученные люди + косты режутся на регулярной основе, а не один раз.

                      Интересно было бы использовать инструмент из статьи для гораздо более сложных кейсов и добавить туда разные хостинги и т.д. посмотреть на вывод.


          1. identw
            18.09.2021 21:18

            И далеко не во всех случая совокупная стоимость владения bare metal ниже cloud и ни о каких "кратно дороже" и речи быть не может, просто вы не умеете в FinOps.

            Из практики:

            Переехали в yandex cloud из hetzner. Теперь платим в 4 раза дороже (вместо 4K евро, платим 16-18K долларов)

            Прерываемая виртуалка в яндекс облаке, стоит больше обычной вирталки в hetzner. Обычная виртуалка в яндекс облаке естественно еще дороже. С bare-metal даже сравнивать нет смысла.


            Надежность никак не поменялась. Возможно даже в облаке сеть моргает чаще чем моргала в hetzner. Не говоря уже о других проблемах, недавно например лег DNS на ощутимое время.

            Ценник в основном за инстансы с кластерами БД, managed БД стоят еще дороже, и не факт, что дадут какие-то плюшки, которые это окупят.

            Как было два девопса на той же зарплате, так и осталось. Только теперь в облаке требуется тратить дополнительные ресурсы на оптимизацию затрат и экономию. И в виду сложности, для экономии в облаке нужно потратить больше ресурсов чем в hetzner.

            Как научиться в FinOps чтобы платить меньше? Прерываемые/spot машины не станут чудесно дешевле, обычные инстансы тоже. На чем тогда экономить? На готовых сервисах? Ну у нас автоматизация для настройки пару типов кластеров бд и кластеров kubernetes не супер дорого вышла и вполне устраивает. Особенно учитывая, что один кластер managed БД по стоймости равен 50% зп одного девопса, а таких кластеров несколько. Да и managed решение далеко не идеальны, особенно по гибкости конфигурации. Например многие вещи в managed кубе яндекса, мы хотели бы сделать по другому (не использовать kube-proxy, вместо iptables для сервисов использовали бы ipvs, а в cilium хотели бы использовать native routing вместо тунелинга, хотели бы иметь возможность включить pod security policy и так далее и тому подобное). У меня если честно нет идей, но если вы что-то посоветуете, то я буду вам сильно благодарен. С облаками опыта имею не много.

            P.S. Переезд был обусловлен 152-ФЗ




            1. eosfor Автор
              18.09.2021 22:00

              Не знаю про яндекс клауд, но хочу узнать. По опыту ажуры скажу что единственный способ делать дешевле это уплотнять, и использовать всякий серверлесс и манажед сервисы, не смотря на то что они не идеальны. Не надо выдумывать велосипед. Само по себе оно будет только расти в цене. Девелоперы будут создавать больше и больше ресурсов бесконтрольно. Скейлить их куда не надо и так далее.

              Как бы цынично это не звучало, манажед сервисы уменьшают потребность в персонале. По сути вы перемещаете стоимость персонала в шареный сервис, частично. И "девопсы" становятся не нужны в таком количестве.


              1. identw
                19.09.2021 09:41

                Как бы цынично это не звучало, манажед сервисы уменьшают потребность в персонале. По сути вы перемещаете стоимость персонала в шареный сервис, частично. И "девопсы" становятся не нужны в таком количестве.

                Но в моем кейсе это ведь не так. managed решение покрывает всего 1% задач. Возьмем для примера тот же куб, managed решает проблему обслуживания control-plain и обновления, но это ведь мизерная часть того, что обычно надо делать. Есть еще уйма задач связанных с кубом, которые вообще никак managed решением не покрывается. И как же "девопсы" будут не нужны, а кто node-local-dns развернет? Кто напишет gatekeeper политики на rego? Логирование, мониторинг, ingress-controller, istio, cert-manager, т.д. Кто будет это обслуживать, исправлять проблемы, дорабатывать?
                P.S. На самом деле мы используем managed куб, поскольку он считай бесплатный. Но это никак не избавляет от того, что нужны компетентные люди, которые будут обслуживать его.

                С managed mysql мы покрываем задачи настройки отказоустойчивого кластера и бэкапов. Но на обслуживание этого, сейчас у нас уходит максимум 8 часов в месяц. Каждый managed mysql сейчас нам обойдется в лучшем случае на 1170$ дороже, таких кластеров у нас 6 (6*1170 = 7020). 7K$ чтобы покрыть 8 часов работы в месяц.

                Ну то есть окей мы возьмем managed решение, и закроем какой-то мелкий пласт задач по обслуживанию, но есть же большое количество задач для "девопсов", банально даже поддерживать terreaform код для развертки всего этого в облаке. Не совсем понятно, как это избавит от надобности в у словных "девопсах" и сократит персонал. В нашем кейсе работы например меньше не стало, местами стало даже больше. Как было два девопса так и осталось.

                Про серверлесс тоже непонятно, ну вот у нас есть 20-30 приложений, от 100 до 10000 rps, обычные бэкендики, что-то пишут в базу. Как серверлесс поможет сэкономить?


            1. vainkop
              19.09.2021 02:31

              Про Яндекс cloud ничего не знаю от слова совсем.

              Если будет возможность/желание рассмотреть топ 3 облаков, то обращайтесь, а так даже и прокомментировать не особо могу.


          1. eosfor Автор
            18.09.2021 21:55

            Я могу только одно тут сказать. Облако, оно точно не дешевле bare metal. На счет дороже или нет утверждать не буду. Его плюс - гибкость и уровень вхождения. Для построения более-менее нормальной HA инфрструктуры вам не нужны спецы по железу или какие-то хитрые варианты построенные на железе. Все накликивается в портале по инструкциям. Но стоит все это врядли меньше.


            1. vainkop
              19.09.2021 02:38

              Я ещё раз повторюсь: всё очень сильно зависит от кейса. Не утверждаю, что в 100% случаев облака дешевле даже при FinOps подходе, но он сильно меняет картину.

              Серьёзную инфраструктуру в облаках никто не "накликивает" , (хотя конечно в отдельных случаях бывает и с таким боремся. Называем это ClickOps :) , а раскатывают Terraform'ом и это достаточно серьезный отдельный инструмент, которым нужно владеть. Вокруг него есть целая экосистема разных прибамбасов вроде Infracost, driftctl, terraformer, кучи community модулей, terragrunt и т.д. и т п.


              1. identw
                07.10.2021 11:49

                Ну вот банальный кейс который я приводил выше.
                Вот сейчас я смотрю на детализацию и вижу что у меня только за трафик выходит 4000$. У меня на bare-metal вся инфра стоила столько =).

                А это не статика, а именно бэкенд трафик. Статику у нас CDN отдельно раздает. Отдельно за это платим.


                @eosfor

                 манажед сервисы уменьшают потребность в персонале


                Кого нам уволить, чтобы окупить цену за трафик? На bare-metal нам этот трафик бесплатно обходился и никакие люди его отдельно не обслуживали. А цена только за этот трафик равна цене всей нашей инфраструктуре которая была на bare-metal.


  1. vainkop
    18.09.2021 11:46

    Спасибо за статью.

    Интересный инструмент!