Как и обещал в предыдущем посте - разберем каким образом Dan Luu смог сократить Твиттеру расходы на железо на 100 млн долларов в год и переложить часть себе в карман, став Senior Staff Engineer



Вступление



At Twitter, most CPU bound services start falling over at around 50% reserved container CPU utilization and almost all services start falling over at not much more CPU utilization even though CPU bound services should, theoretically, be able to get higher CPU utilizations. Because load isn't, in general, evenly balanced across shards and the shard-level degradation in performance is so severe when we exceed 50% CPU utilization, this makes the practical limit much lower than 50% even during peak load events.



Утверждение первое. Большинство сервисов в Твиттере уходили в отказ при нагрузке около 50% аллоцированных CPU, хотя в теории должно были работать и при большей 50%. А с учетом того, что нагрузка между разными частями системы была неравномерно распределена, а при 50% наступал отказ, реально нагрузка была еще ниже чем 50:, так как приходилось ориентироваться на самую нагруженную часть системы



Almost all services at Twitter run on Linux with the CFS scheduler, using CFS bandwidth control quota for isolation, with default parameters. The intention is to allow different services to be colocated on the same boxes without having one service's runaway CPU usage impact other services and to prevent services on empty boxes from taking all of the CPU on the box, resulting in unpredictable performance, which service owners found difficult to reason about before we enabled quotas. The quota mechanism limits the amortized CPU usage of each container, but it doesn't limit how many cores the job can use at any given moment. Instead, if a job "wants to" use more than that many cores over a quota timeslice, it will use more cores than its quota for a short period of time and then get throttled, i.e., basically get put to sleep, in order to keep its amortized core usage below the quota, which is disastrous for tail latency.



Почти все в твиттере работает на Линуксе через CFS scheduler, используется дефолтный CFS bandwidth control quota для изоляции. Идея в том, чтобы разные сервисы бегали на одной машинке, но не было ситуации, когда один сервис отжирает мощности у других или чтобы сервис, который бегает на пустой машинке, не потреблял все мощности, что приводило бы к труднопредсказуемому перформансу. Квотирование ограничивает амортизированное (то есть растянутое во времени) использование CPU, но не ограничивает как много ядер может быть использованному в отдельный момент времени. Если процесс попытается использоваться больше ядер, чем позволено квотой в определенных временных границах, он это сможет сделать в начале, а потом будет заглушен. То есть если моя квота это в среднем 2 ядра в 10 секунд, я могу использовать четыре ядра 5 секунд, а затем 5 секунд спать. Очевидно это жестко ломает p99/999 latency



Since the vast majority of services at Twitter use thread pools that are much larger than their mesos core reservation, when jobs have heavy load, they end up requesting and then using more cores than their reservation and then throttling. This causes services that are provisioned based on load test numbers or observed latency under load to over provision CPU to avoid violating their SLOs. They either have to ask for more CPUs per shard than they actually need or they have to increase the number of shards they use.



А так как многие сервисы в Твиттере могут требовать ресурсов больше, чем за ними зарезервировано (вспоминаем про амортизационное использование), когда идет высокая нагрузка, сервис запрашивает больше ресурсов, получает их, выходит за квоту и засыпает. Это в свою очередь приводит к тому, что сервисы с автомасштабированием CPU на основе латенси или нагрузки запрашивают больше CPU, чтобы не нарушить SLO. То есть либо больше CPU на шард, чем нужно, либо растет количество шардов

#SystemDesign