/ buffers / buffers.html
buffers.html
  1  Название: Память сети. Как сохранить пакет
  2  
  3  
  4  
  5  
  6  Эта статья едва ли для широкого круга читателей, но будет небезынтересна тем, кто хотел бы знать, сколько максимум пакет может полежать где-нибудь в сети, добираясь от точки А к точке Б, и как выбрать коммутатор так, чтобы через месяц от него не тянуло протухшими пакетами.
  7  Для примера - на некоторых современных коммутаторах буферы по 4 гигабайта - спокойно можно четвёртый сезон Рика и Морти сохранить. Или вообще собрать кластер распределённого хранилища из коммутаторов. 
  8  
  9  Это вторая статья, копающаяся в кишочках сетевых микросхем - в первой!!! я уже рассмотрел архитектуру сетевых устройств и чипов коммутации. А в этой взглянем на архитектуру памяти, выделение буферов и поднимем самый горячий вопрос современности - что лучше: большие и маленькие буферы.
 10  
 11  <a href="https://fs.linkmeup.ru/images/articles/buffers/kdpv_buffers.jpg" target="_blank"><img src="https://fs.linkmeup.ru/images/articles/buffers/kdpv_buffers_s.jpg" width="800"></a>
 12  
 13  Настоятельно рекомендую ознакомиться с <a href="https://linkmeup.ru/blog/365.html">15-м выпуском СДСМ</a> перед тем, как приступить к чтению.
 14  <hr>
 15  
 16  <h1>Содержание</h1>
 17  <ul>
 18      <li><b><a href="#TERMINOLOGY">Терминология</a></b></li>
 19  
 20      <li><b><a href="#BUFERA">Память и буферы</a></b>
 21      <ul>
 22          <li><a href="#SFVSCT">Store-n-Forward vs Cut-Through</a></li>
 23          <li><a href="#CONGESTIONS">Перегрузки: причины и места</a>
 24          <ul>
 25              <li><i><a href="#CONGESTION_REASONS">Причины перегрузок</a></i></li>
 26              <li><i><a href="#CONGESTION_POINTS">Места образования перегрузок</a></i></li>
 27          </ul>
 28          </li>
 29          <li><a href="#BUFFER_ARCHITECTURE">Архитектура памяти</a>
 30          <ul>
 31              <li><i><a href="#CROSSBAR">Crossbar</a></i></li>
 32              <li><i><a href="#SHARED_BUFFER">Shared Buffers</a></i></li>
 33              <ul>
 34                  <li><i><a href="#DEDICATED">Dedicated + Shared buffers</a></i></li>
 35                  <li><i><a href="#HEADROOM">Headroom buffers</a></i></li>
 36                  <li><i><a href="#ADMISSION_CONTROL">Admission Control</a></i></li>
 37                  <li><i><a href="#ALPHA">Alpha</a></i></li>
 38              </ul>
 39              <li><i><a href="#OQ">Output queuing </a></i></li>
 40              <li><i><a href="#IQ">Input queuing </a></i></li>
 41              <li><i><a href="#CIOQ">Combined Input and Output queuing </a></i></li>
 42              <li><i><a href="#VOQ">Virtual Output Queueing</a></i></li>
 43          </ul>
 44          </li>
 45          <li><a href="#SHALLOW_VS_DIPPER">Shallow vs Deep buffers</a>
 46          <ul>
 47              <li><i><a href="#HYBRID_BUFFERING">Hybrid Buffering</a></i></li>
 48              <li><i><a href="#TRUE_EVIL">Большие буферы - это зло?</a></i></li>
 49          </ul>
 50          </li>
 51      </ul>
 52      </li>
 53      <li><b><a href="#LLLL">Lossless Low-Latency сети</a></b></li>
 54      <li><b><a href="#LINKS">Полезные ссылки</a></b></li>
 55  </ul>
 56  
 57  TL;DR
 58  <cut />
 59  
 60  
 61  <hr>
 62  <a name="TERMINOLOGY"></a>
 63  <h1>Терминология</h1>
 64  Задача этого параграфа не объять все непонятные слова, употребляемые в статье, а лишь внести некую ясность в неразбериху русско-английских терминов.
 65  <b>Чип коммутации</b>, <b>сетевой процессор</b>, <b>(Packet) Forwarding Engine</b>, <b>PFE</b> - микросхема, способная коммутировать пакет из входа в нужный выход с нужным набором заголовком.
 66  <b>Lookup</b> или <b>лукап</b> или <b>поиск</b> - поиск адресата в таблицах (FIB, LFIB, ARP Adjacencies, IPv6 ND Table итд.)
 67  <b>Pipeline</b> или <b>конвейер</b> - набор действий, которые происходят с пакетом по мере его продвижения от входа в чип до выхода из него.
 68  <b>Single-chip</b>, <b>одночиповый</b> - устройство, внутри которого только один чип.
 69  <b>Модульное сетевое устройство</b> - устройство, состоящее из шассии и отдельных карт, в него вставляющихся. В рамках статьи преполагаем, что каждая карта - это коммутатор с самостоятельным чипом коммутации, а друг с другом они связаны через фабрику коммутации.
 70  <b>Fixed</b>, <b>фиксированный</b>, <b>pizza-box</b> - немодульный коммутатор. Обычно внутри него нет фабрик коммутации. Часто эти термины используются как синоним Single-chip, хотя это не совсем верно - внутри может стоять два (back-to-back) чипа или даже больше.
 71  <b>Сериализация/Десериализация</b> - процесс перевода данных из параллельного низкоскоростного интерфейса (МГц) в
 72  последовательный высокоскоростной (ГГц) и наоборот. Например, из чипа в интерфейс или из чипа в фабрику.
 73  <b>Память</b> - физическая микросхема для хранения.
 74  <b>Буфер</b> - некий участок памяти, выделенный для хранения пакетов. <i>Здесь и далее в производных словах, таких как "буферов", ударение на "У"</i>.
 75  <b>Очередь</b> - абстракция над буфером, позволяющая <b>виртуально</b> выстраивать пакеты в упорядоченную очередь. Фактически в памяти они, конечно, хранятся "как попало".
 76  <b>OCB</b> - On-Chip Buffer. Память, встроенная в чип.
 77  <b>MMU</b> - Memory Management Unit - блок управления физической памятью.
 78  <b>TM</b> - Traffic Manager - блок, реализующий функции QoS, использует MMU для доступа к памяти.
 79  <hr>
 80  
 81  <a name="SFVSCT"></a>
 82  <h2>Назначение буферов</h2>
 83  
 84  Итак, в прошлый раз !!! мы проследили судьбу пакета внутри чипа - какие именно микросхема предпринимает шаги, чтобы передать сигнал со входного интерфейса в выходной. Этот набор шагов называется конвейером или Pipeline'ом.
 85  
 86  Ключевая часть процесса - это то, что чип отрезает от пакета значимую часть - а именно первые сколько-то байтов, содержащих управляющие заголовки. Блок Parser эти заголовки разбирает, а блок Match-Action делает лукап по таблицам и определяет, что с пакетом нужно сделать (интерфейс, инкапсуляции, шейпинг, полисинг, ремаркировка итд.)
 87  
 88  Все эти действия происходят только с заголовкамии пакетов.
 89  А где же прохлаждаются их тела всё это время?
 90  
 91  В сетевых чипсетах есть встроенная память (<b>on chip-OCB</b>) как раз для хранения тел. Её размер в силу физических ограничений очень мал (до 100Мб), но для большинства задач - это разумный компромисс.
 92  Лишь в редких сценариях этого не хватает и добавляется объёмная внешняя память - <b>off-chip</b>.
 93  <blockquote>
 94      Вообще про компромиссы мало-много памяти поговорим <a href="#SHALLOW_VS_DIPPER">отдельно</a>.
 95  </blockquote>
 96  
 97  <img src="https://fs.linkmeup.ru/images/articles/buffers/buffer_memory.png" width="500">
 98  
 99  Таким образом на входе в чип парсер отделяет заголовки от тел, первые отдаёт на анализ в блок Match-Action, вторые - складывает в буфер.
100  На выходе новые заголовки пришивают к извлечённым обратно телам и отправляют на выход.
101  
102  Будучи неоднократно обвинённым при рецензировании этой статьи, чувстую необходимость ещё раз повторить это: внутри чипа коммутации заголовки отделяются от тела пакета. В то время, как изначальные заголовки анализируются, помогают сделать лукап, уничтожаются, формируются новые, тело находится в одном месте физической памяти, не перемещаясь. Даже в тот момент, когда Traffic Manager выстраивает пакеты в очередь согласно их приоритетам, производит их диспетчеризацию и Congestion Avoidance, фактически он работает со внутенними временными заголовками, не двигая пакеты по памяти. 
103  
104  
105  Управляет доступом к физической памяти <b>MMU - Memory Management Unit</b>. Он довольно похож на MMU в компьютерах (по сути является <a href="https://en.wikipedia.org/wiki/Memory_management_unit">им</a>). Программа обращается к указателю, чтобы извлечь данные из памяти, MMU транслирует это в реальный адрес ячейки и возвращает данные. 
106  
107  MMU занимается размещением пакетов в буферах, их извлечением или отбрасыванием. Он же контролирует разделение памяти на области (dedicated, shared, headroom, voq) и их загрузку.
108  
109  За более верхнеуровневое управление очередями и перегрузками отвечает блок <b>TM - Traffic Manager</b>.
110  
111  Есть два подхода к размещению тел в буферах: <b>Store-and-Forward</b> и <b>Cut-Through</b>.
112  <hr>
113  
114  <a name="SFVSCT"></a>
115  <h2>Store-and-Forward vs Cut-Through</h2>
116  <b>SF - Store and Forward</b> предполагает, что чип сначала получает полностью пакет, сохраняет в буфере, а уже потом занимается вивисекцией.
117  После анализа заголовков пакет помещается в правильную выходную очередь.
118  Исторически это первый метод коммутации. Его преимущество в том, что он может, получив пакет целиком, проверить контрольную сумму и выбросить побитые.
119  
120  <b>CT - Cut-Through</b>, напротив, сразу после получения первых нескольких десятков байтов пакета, позволяющих принять решение о его судьбе, отправляет его в выходную очередь, не дожидаясь его полной доставки.
121  Это позволяет сэкономить до нескольких микросекунд на обработке пакета внутри коробки, ценою, однако, отсутствия проверки целостности - ведь FCS-то в конце. Эта задача перекладывается на протоколы более высокого уровня (или на следующий хоп).
122  
123  Такой режим используется для приложений, требующих ультра-коротких задержек.
124  
125  <blockquote>
126      К слову на сегодняшний день для коммутаторов 2-го уровня время обработки в пределах устройства порядка 200нс, 3-го - 250нс.
127  
128      Для коммутаторов 1-го уровня (фактически патч-панель) это время - около 5 нс.
129  </blockquote>
130  
131  Многие производители сегодня по умолчанию устанавливают режим Cut-Through, поскольку ошибки на Ethernet сегодня явление сравнительно нечастое, а приложение обычно само может обнаружить проблему и запросить переотправку (или не запрашивать, кстати).
132  
133  <b>Дальнейшее чтение</b>:
134  Весьма глубокий подкоп под режимы коммутации от циски: <a href="https://www.cisco.com/c/en/us/products/collateral/switches/nexus-5020-switch/white_paper_c11-465436.html">Cisco Nexus 5000 Series Switches</a>
135  <hr>
136  
137  <a name="CONGESTIONS"></a>
138  <h2>Перегрузки: причины и места</h2>
139  Буфер нужен на сетевом устройстве не только для того, чтобы похранить тело пакета, пока его заголовки перевариваются в кишках чипа.
140  Как минимум нужно сгладить поток пакетов до скорости выходного интерфейса. Грубо говоря, пока один пакет сериализуется для передачи в интерфейс, второму нужно где-то подождать.
141  Для этой задачи обычно хватит совсем небольшой FIFO очереди. 
142  Другая важнейшая сетевая задача - перегрузки (congestion). Если в один интерфейс одновременно сваливается много пакетов, их тоже нужно сохранить.
143  
144  Причём перегрузки - это наша повседневная легитимная реальность, а не что-то крайне редкое, что нужно перетерпеть и станет попроще.
145  Во времена коммутации каналов такой проблемы не стояло - для любой общающейся пары всегда было зарезервировано строго необходимое количество ресурсов.
146  Сегодня совершенно законно на порт может прийти больше трафика, чем тот готов сиюминутно пропустить.
147  <hr>
148  
149  <a name="CONGESTION_REASONS"></a>
150  <h3>Причины перегрузок</h3>
151  Самая простая - из высокоскоростного интерфейса трафик должен слиться в более низкоскоростной - из <b>10G в 1</b>, например.
152  Другая причина, очень распространённая в сетях крупных ДЦ, особенно в тех, где развёрнуты кластеры Map-Reduce - это <b>Incast</b>. Это ситуация, в которой одна машина отправляет запрос на десятки/сотни/тысячи, а те все разом начинают отвечать, и пакеты стопорятся на узком интерфейсе в сторону машины-инициатора.
153  Более общий случай - трафик с нескольких входящих портов должен влиться в один исходящий - <b>Backpressure</b>.
154  Прочие типы всплесков трафика, которые ещё называют бёрстовыми или просто бёрстами (<b>Bursts</b>).
155  
156  
157  Поэтому однозначно нужно побольше памяти для буферизации. Но фактически это место, где пакеты обрастают задержкой.
158  Так на заре 1G буферизация вызывала массу головной боли у трейдеров, чьи приложения получали свой бесценный трафик с задержкой и джиттером.
159  
160  И поэтому тут уже недостаточно везде FIFO. Это задача, во благо которой трудится <a href="https://linkmeup.ru/blog/365.html">QoS</a>.
161  
162  Если случилась конгестия, то нужно иметь возможность требовательный к задержкам трафик, пропустить первым, чувствительный к потерям - не дропнуть, а наименее ценным пожертвовать. 
163  Ещё нужно уметь пополисить и пошейпить. 
164  
165  Но в каком месте располагать эту память и где реализовывать QoS?
166  <hr>
167  
168  <a name="CONGESTION_POINTS"></a>
169  <h3>Места возникновения перегрузок</h3>
170  Их по большому счёту 4: 
171  <ol>
172      <li><b>на входном чипе</b> - если со стороны интерфейсов на него поступает больше, чем он способен обработать.</li>
173      <li><b>на фабрике коммутации</b> (если коробка модульная) - если линейные карты пытаются отправить на фабрику больше, чем она способна обработать.</li>
174      <li><b>на выходной линейной карте</b>, если фабрика пытается передать на линейную карту больше, чем её чип способен обработать</li>
175      <li><b>на выходном интерфейсе</b> - если чип шлёт в интерфейс больше, чем тот способен сериализовать.</li>
176  </ol>
177  
178  <img src="https://fs.linkmeup.ru/images/articles/buffers/congestion_points.svg" width="600">
179  
180  Но никто не хочет бороться с перегрузками в четырёх местах.
181  Поэтому обычно
182  А) Чип делают такой производительности, чтобы он смог обработать весь трафик, даже если тот начал одновременно поступать со всех портов на этой линейной карте. Поэтому для устройства со 128 портами 100Гб/с используется чип с производительностью 12,8Тб/с.
183  Очевидно бывают и исключения. Тогда или имеем непредсказуемые потери, или (чаще) невозможность использовать часть портов.
184  Б) Фабрику так же делают без переподписки, чтобы она могла провернуть весь трафик, который пытаются в неё передать все линейные карты, даже если они делают это одновременно на полной скорости. Таким образом не нужно буферизировать трафик и перед отправкой на фабрику. 
185  В) Управление перегрузками на выходном чипе и выходном интерфейсе сводят в одно место.
186  
187  <blockquote>
188      На самом деле фабрика без передподиски (или неблокируемая) - это та ещё спекуляция, к которой нередко прибегают маркетологи. 
189      Для некоторых сценариев, например, <a href="#CIOQ">CIOQ</a> даже со speedup фабрики в пару раз от необходимого есть строгие результаты, показывающие, при каких условиях она будет неблокируемой.
190      Можно почитать у достопочтенных выпускников MIT и Стэнфорда: <a href="http://yuba.stanford.edu/~nickm/papers/CSL-TR-97-738.pdf" target="_blank">On the speedup required for combined input and output queued switching</a>.
191  </blockquote>
192  
193  <hr>
194  
195  <a name="BUFFER_ARCHITECTURE"></a>
196  <h>Архитектура буферов</h1>
197  И вот тут на сцену выходит TM - Traffic Manager, который реализует функции QoS (и некоторые другие).
198  Он может быть частью чипа коммутации, а может быть отдельной микросхемой - для нас сейчас важно то, что он заправляет буферами.
199  
200  Буфер - это с некоторыми оговорками обычная память, используемая в компьютерах. В ней в определённой ячейке хранится пакет, который чип может извлечь, обратившись по адресу. 
201  
202  Любой сетевой ASIC или NP обладает некоторым объёмом встроенной (on-chip) памяти (порядка десятков МБ).
203  Так называемые Deep-Buffer свитчи имеют ещё внешнюю (off-chip) память, исчисляемую уже гигабайтами.
204  И той и другой управляет модуль чипа - MMU.
205  
206  В целом для нас пока местонахождение не имеет значения - взглянем на это <a href="#SHALLOW_VS_DIPPER">попозже</a>. Важно то, как имеющейся памятью чип распоряжается, а именно, где и какие очереди он создаёт и какие <a href="https://en.wikipedia.org/wiki/Active_queue_management" target="_blank">AQM</a> использует. 
207  
208  И тут практикуют:
209  
210  <ul>
211      <li><a href="#CROSSBAR">Crossbar</a></li>
212      <li><a href="#SHARED_BUFFER">Shared Buffer</a></li>
213      <li><a href="#OQ">Output Queuing</a></li>
214      <li><a href="#IQ">Input Queueing</a></li>
215      <li><a href="#CIOQ">Combined Input and Output Queueing</a></li>
216      <li><a href="#VOQ">Virtual Output Queueing</a></li>
217  </ul>
218  <hr>
219  
220  <a name="CROSSBAR"></a>
221  <h2>Crossbar</h2>
222  Идея в том, чтобы для каждой пары (входной интерфейс - выходной интерфейс) выделить аппаратный буфер.
223  <img src="https://fs.linkmeup.ru/images/articles/buffers/crossbar.png" width="500">
224  
225  Это, скорее, умозрительный эксперимент, потому что в плане сложности, стоимости реализации и эффективности это проигрышный вариант.
226  <hr>
227  
228  <a name="SHARED_BUFFER"></a>
229  <h2>Shared Buffer</h2>
230  По числу существующих в мире коробок этот вариант, однозначно, на первом месте. 
231  
232  <img src="https://fs.linkmeup.ru/images/articles/buffers/shared_buffer.png" width="500">
233  
234  Используется Shared Buffer на немодульных устройствах без фабрики коммутации, в которых установлен один чип (обычно, но может быть больше).
235  
236  Аппаратно - это память (обычно SRAM), встроенная прямо в чип - она так и называется <b>on-chip</b> (OCB)    . Много туда не засунешь, поэтому объём до 100 МБ.
237  Зачастую это единственная память, которая в одночиповых устройствах используется для буферизации.
238  Пусть, однако, эта кажущаяся простота не вводит вас в заблуждение - для того, чтобы в десятки мегабайтов поместить трафик сотни портов 100Гб/с, да ещё и обеспечить отсутствие потерь, за ними должны скрываться годы разработок и нетривиальная архитектура.
239  А так оно и есть - я чуть ниже неглубоко вас окуну.
240  
241  Итак, есть соблазн эту память взять и просто равномерно разделить между всеми портами. Такой статический дизайн имеет право на жизнь, но сводит на нет возможность динамически абсорбировать всплески трафика.
242  
243  Гораздо более привлекательным выглядит следующий вариант:
244  
245  <a name="DEDICATED"></a>
246  <h3>Dedicated + Shared</h3>
247  Из доступной памяти каждому порту выделяется определённая небольшая часть - это <b>Dedicated Buffer</b>. За каждым портом кусочек памяти законодательно закреплён и не может быть использован другими портами. То есть при любых обстоятельствах у порта будет свой защищённый кусочек. Минимальный размер Dedicated Buffer где-то настраивается, где-то нет. Но лучше без основательного понимания в дефолты не лезть.
248  Доля каждого порта в абсолютных цифрах очень маленькая - порядка единиц кБ.
249  Гарантируемый минимум выделяется для хранения как входящих пакетов, так и выходящих.
250  
251  Остальная часть памяти как раз общая - <b>Shared Buffer</b> - может быть использована любым портом по мере необходимости. Из неё динамически выделяются куски для тех интерфейсов, которые испытывают перегрузку. 
252  Например, если чип пытается на один из интерфейсов передать больше трафика, чем тот способен отправлять в единицу времени, то эти пакеты сначала заполняют выделенный для этого порта буфер, а когда он заканчивается, автоматически начинают складываться в динамически выделенный буфер из общей памяти. Как только все пакеты обработаны, память освобождается.
253  Под общий буфер может быть отдано 100% той памяти, что осталась после вычитания из неё выделенных для портов кусочков (Dedicated). Но она так же может быть перераспределена - за счёт общего буфера можно увеличить выделенные. Так, если выделить 80% под Shared, то оставшиеся 20% равномерно распределятся по Dedicated.
254  
255  Наличие Shared Buffer'а решает огромную проблему, позволяя сглаживать всплески трафика, когда перегрузку испытывает один или несколько интерфейсов.
256  
257  Однако вместе с тем за общую память начинаются соревноваться разные порты одновременно. И серьёзная перегрузка на одном порту может вызвать потери на другом, которому нужно было всего лишь несколько килобайтов общей памяти, чтобы не дропнуть пакет.
258  Одним из способов облегчить эту ситуацию является увеличение выделенных буферов за счёт уменьшения общего.
259  Но это всегда зона компромиссных решений - сокращая размер общей памяти, мы уменьшаем и объёмы всплесков, которые чип может сгладить.
260  Кроме того <a href="#LLLL">Lossless трафик</a> требует к себе ещё более щепетильного отношения.
261  
262  Поэтому зачастую, помимо Dedicated и Shared буферов, резервируют ещё <b>Headroom buffers</b>.
263  
264  <a name="HEADROOM"></a>
265  <h3>Headroom buffers</h3>
266  Это последний способ сохранить пакеты, когда даже общий буфер уже забит. Естественно, он тоже отрезается от общей памяти, поэтому на первый взгляд выглядит не очень логичным откусить от общей памяти кусок, назвать его по-другому и сказать, мол, мы всё оптимизировали.
267  На самом деле Headroom буферы решают довольно специфическую задачу - помочь lossless приложениям с <b>PFC</b> - <a href="https://www.juniper.net/documentation/en_US/junos/topics/concept/cos-qfx-series-congestion-notification-understanding.html#jd0e554" target="_blank">Priority-based Flow Control</a>.
268  
269  PFC - это механизм Ethernet Pause, который умеет притормаживать не всю отправку, а только по конкретным приоритетам Ethernet CoS.
270  Например, два приложения на отправителе: RoCE и репликация БД. Первое - чувствительная к задержкам и потерям вещь, второе - массивные данные.
271  Коммутатор, заметив заполнение общего буфера, отправляет Pause для более низкого приоритета, тем самым притормаживая репликацию, но не RoCE.
272  Задача буфера Headroom здесь в том, чтобы сохранить те пакеты приоритетной очереди, что сейчас в кабеле, пока Pause летит к отправителю с просьбой притормозить.
273  То есть пакеты репликации начнут дропаться, когда заполнится общий буфер, а пакеты RoCE будут складываться в Headroom. 
274  <blockquote>
275      Помимо lossless headroom бывает и headroom для обычного трафика, чтобы помочь сохранить более приоритетный. Но это на домашнее задание.
276  </blockquote>
277  
278  <img src="https://fs.linkmeup.ru/images/articles/buffers/buffer_types.svg" width="800">
279  
280  При наступлении перегрузки буферы будут задействованы в следующем порядке.
281  Для входящего best-effort трафика:
282  <ol>
283      <li>Dedicated buffers</li>
284      <li>Shared buffers</li>
285  </ol>
286  
287  Для входящего lossless трафика:
288  <ol>
289      <li>Dedicated buffers</li>
290      <li>Shared buffers</li>
291      <li>Lossless headroom buffers</li>
292  </ol>
293  
294  Для всего исходящего трафика:
295  <ol>
296      <li>Dedicated buffers</li>
297      <li>Shared buffers</li>
298  </ol>
299  
300  Разумеется, описанное выше лишь частный пример, и от вендора к вендору ситуация может различаться (разительно).
301  
302  Например бродкомовские чипы (как минимум Trident и Tomahawk) имеют внутреннее разделение памяти по группам портов. Общая память делится на порт-группы по 4-8 портов, которые имеют свой собственный кусочек общего буфера. Порты из одной группы, соответственно буферизируют пакеты только в своём кусочке памяти и не могут занимать другие. Это тоже один из способов снизить влияние перегруженных портов друг на друга. Такой подход иногда называют <b>Segregated Buffer</b>.
303  
304  <a name="ADMISSION_CONTROL"></a>
305  <h3>Admission Control</h3>
306  Admission Control - входной контроль - механизм, который следит за тем, можно ли пакет записывать в буфер. Он не является специфичным для Shared-буферов, просто в рамках статьи - это лучшее место, чтобы о нём рассказать.
307  
308  Формально Admission Control делится на Ingress и Egress.
309  Задача <b>Ingress Admission Control</b> - во-первых, вообще убедиться, что в буфере есть место, а, во-вторых, обеспечить справедливое использование памяти.
310  Это означает, что у каждого порта и очереди всегда должен быть гарантированный минимальный буфер. А ещё несколько входных портов не оккупируют целиком весь буфер, записывая в него всё новые и новые пакеты.
311  
312  Задача <b>Egress Admission Control</b> - помочь чипу абсорбировать всплески, не допустив того, чтобы один или несколько выходных портов забили целиком весь буфер, получая всё новые и новые пакеты с кучи входных портов.
313  
314  В случае Shared Buffer оба механизма срабатывают в момент первичного помещения пакета в буфер. То есть никакой двойной буферизации и проверки не происходит. 
315  
316  Как именно понять, сколько буфера занято конкретным портом/очередью и главное, сколько ещё можно ему выдать?
317  Это может быть статический порог, одинаковый для всех портов, а может быть и динамически меняющийся, регулируемый параметром <b>Alpha</b>.
318  
319  <a name="ALPHA"></a>
320  <h3>Alpha</h3>
321  Итак, почти во всех современных чипах память распределяется динамически на основе информации о том, сколько общей памяти вообще свободно и сколько ещё можно выделить для данного порта/очереди.
322  
323  На самом деле минимальной единицей аккаунтинга является не порт/очередь, а регион (в терминологии Мелланокс). Регион - это кортеж: <i>(входной порт, Priority Group на входном порту, выходной порт, Traffic Class на выходном порту)</i>.
324  
325  Каждому региону назначается динамический порог, сколько памяти он может под себя подмять. При его превышении, очевидно, пакеты начинают дропаться, чтобы не влиять на другие регионы.
326  Этот порог вычисляется по формуле, множителями которой являются объём свободной на данный момент памяти и параметр <b>alpha</b>, специфичный для региона и настраиваемый:
327  <code>Threshold [Bytes] = alpha * free_buffer [Bytes]</code>
328  
329  Его значение варьируется от 1/128 до примерно 8 с шагом х2. Чем больше эта цифра, тем больший объём свободной памяти доступен региону.
330  Например, если на коммутаторе 32 региона, то: 
331  при alpha=1/64 каждому региону будет доступна 1/64 часть свободной памяти, и даже при максимальной утилизации они все смогут использовать только половину буфера.
332  при alpha=1/32 вся память равномерно распределится между регионами, ни один из них не сможет влиять на другие, а при полной утилизации 100% памяти будет занято.
333  при alpha=1/16 каждый регион может претендовать на больший объём памяти. И если все регионы разом начнут потреблять место, то им всем не хватит, потому что памяти потребовалось бы 200%. То есть это своего рода переподписка, позволяющая сглаживать всплески.
334  <i>Предполагаем тут, что значение alpha одинаково для всех регионов, хотя оно может быть настроено отдельно для каждого.</i>
335  
336  При получении каждого пакета, механизм Admission Control вычисляет актуальный порог для региона, которому принадлежит пакет. Если порог меньше размера пакета, тот отбрасывается.
337  Если же больше, то он помещается в буфер и уже не будет отброшен никогда, даже если регион исчерпал все лимиты. Объём свободной памяти уменьшается на размер пакета.
338  Это происходит для каждого приходящего на чип пакета.
339  <hr>
340  
341  Написанное выше об Admission Control и Alpha может быть справедливо не только для Shared Buffers, но и для других архитектур, например, VoQ.
342  
343  <b>Дальнейшее чтиво:</b>
344  <ul>
345      <li>Если в жизни не хватает страданий: <a href="https://montazeri.iut.ac.ir/sites/montazeri.iut.ac.ir/files/file_pubwdet/32083_0.pdf" target="_blank">Design and Implementation of a Shared Memory Switch Fabric</a></li>
346      <li><a href="https://community.mellanox.com/s/article/understanding-the-alpha-parameter-in-the-buffer-configuration-of-mellanox-spectrum-switches" target="_blank">Understanding the Alpha Parameter in the Buffer Configuration of Mellanox Spectrum Switches</a></li>
347      <li>Programming Guide'ы коммерческих микросхем (NDA кровью, помним, да?).</li>
348  </ul>
349  <hr>
350  
351  Crossbar и Shared Buffer - это архитектуры, которые могут использоваться для устройств фиксированной конфигурации, но не подходят для модульных.
352  Взглянем же теперь на них.
353  
354  Дело в том, что они состоят из нескольких линейных карт, каждая из которых несёт как минимум один самостоятельный чип коммутации.
355  И этот чип, будь то ASIC, NP или даже CPU не может в своей внутренней памяти динамически выделять буферы для тысяч очередей выходных интерфейсов - кишка тонка. 
356  
357  <img src="https://fs.linkmeup.ru/images/articles/buffers/modular_chassis.svg" width="800">
358  
359  Далее поговорим про архитектуры памяти для модульных шасси:
360  <ul>
361      <li><a href="#OQ">Output Queueing</a></li>
362      <li><a href="#IQ">Input Queueing</a></li>
363      <li><a href="#CIOQ">Combined Input and Output Queueing</a></li>
364      <li><a href="#VOQ">Virtual Output Queueing</a></li>
365  </ul>
366  
367  <a name="OQ"></a>
368  <h3>Output Queueing</h3>
369  Наиболее логичным кажется буферизировать пакеты как можно ближе к месту возможного затора - около выходных интерфейсов.
370  Кому как не выходному чипу знать о здоровье своих подопечных интерфейсов, обслуживать по несколько QoS очередей для каждого и бороться с перегрузками?
371  
372  <img src="https://fs.linkmeup.ru/images/articles/buffers/oq.png" width="500">
373  
374  И это правда так.
375  Но есть одна фундаментальная проблема - в случае перегрузок пакеты будут приходить на Egress PFE, чтобы умирать. Они проделают весь огромный путь от входного интерфейса через фабрику коммутации до выходного буфера через фабрику для того, чтобы узнать, что мест нет и быть печально дропнутыми.
376  Это бессмысленная и бесполезная утилизация полосы пропускания фабрики.
377  
378  <img src="https://fs.linkmeup.ru/images/articles/buffers/drop.svg" width="800">
379  
380  И вот уже вырисовывается следующая логичная мысль - выбросить пакет нужно как можно раньше.
381  Как было бы здорово, если бы мы могли это сделать на входной плате.
382  <hr>
383  
384  <a name="IQ"></a>
385  <h3>Input Queuing</h3>
386  Более удачным вариантом оказывается буферизировать пакеты на входной плате после лукапа, когда уже становится понятно, куда пакет слать. Если выходной интерфейс заведомо занят, то и смысла гнать камикадзе на фабрику нет.
387  
388  <img src="https://fs.linkmeup.ru/images/articles/buffers/iq.png" width="500">
389  
390  Постойте! Как же входной чип узнает, что выходной интерфейс не занят? 
391  
392  С точки зрения Data Plane никакой обратной связи, от выходного чипа входному, очевидно, нет. Распространение между ними информации, необходимой для лукапа (некстхопы, интерфейсы, заголовки) производится средствами медленного Control Plane - тоже не подойдёт. 
393  Так вот для сигнализации такой информации между линейными платами появляется арбитр. У разных вендоров он может быть реализован по-разному, но суть его в следующем - входной чип регулярно запрашивает у выходного разрешение на отправку нового блока данных. И пока он его не получит - держит пакеты в своём буфере, не отправляя их в фабрику.
394  Соответственно выходной чип, получив такой запрос, смотрит на утилизацию выходного интерфейса и решает, готов ли он принять пакет. Если да - отправляет разрешение (<b>Grant</b>).
395  Это на первый взгляд контринтуитивное поведение - каковы же накладные расходы на такой арбитраж, насколько это увеличивает задержки, если на отправку пакета данных нужно дождаться RTT в пределах коробки - пока запрос улетит на выходной чип, пока тот обработает, пока ответ вернётся назад.
396  Тут для меня начинается область магического искусства, но вендоры эту революцию успели совершить и есть масса платформ, на которых арбитр прекрасно со своей задачей справляется. 
397  Хотя обычно он применяется не для Input Queueing в описанном виде.
398  Дело в том, что эффективность Input Queueing не очень высокая - очень часто придётся ждать, пока интерфейс освободится. Эх, прям вспоминается старый добрый Ethernet CSMA/CD.
399  <hr>
400  
401  <a name="CIOQ"></a>
402  <h3>Combined Input and Output Queueing</h3>
403  Гораздо выгоднее в этом плане разрешить буферизацию и на выходе.
404  Тогда арбитр будет проверять не занятость интерфейса, а степень заполненности выходного буфера - вероятность, что в нём есть место, гораздо выше.
405  
406  <img src="https://fs.linkmeup.ru/images/articles/buffers/cioq.png" width="700">
407  
408  Но такие вещи не даются даром. Очевидно, это и увеличенная цена из-за необходимости реализовывать дважды буферизацию, и увеличенные задержки - даже в отсутствие заторов этот процесс не бесплатный по времени.
409  
410  Кроме того, для обеспечения QoS придётся хоть какой-то минимум его функций реализовывать в двух местах, что опять же скажется на цене продукта
411  
412  Но у CIOQ (как и у IQ) есть фундаментальный недостаток, заставивший в своё время немало поломать голову лучшим умам - <b>Head of Line Blocking</b>. 
413  
414  Представьте себе ситуацию: однополосная дорога, перекрёсток, машине нужно повернуть налево, сквозь встречный поток. Она останавливается, и ждёт, когда появится окно для поворота. А за ней стоит 17 машин, которым нужно проехать прямо. Им не мешает встречный поток, но им мешает машина, которая хочет повернуть налево.
415  
416  <img src="https://fs.linkmeup.ru/images/articles/buffers/hlob.png" width="500">
417  <i><a href="https://www.cisco.com/c/dam/global/hr_hr/assets/ciscoconnect/2013/pdfs/Anatomy_of_Core_Network_Elements_Josef_Ungerman.pdf" target="_blank">Источник</a>.</i>
418  
419  Этот избитый пример иллюстрирует ситуацию HoLB. Входной буфер - один на всех. И если всего лишь один выходной интерфейс начинает испытывать затор, он блокирует полностью очередь отправки на выходном чипе, поскольку один пакет в начале этой очереди не получает разрешение на отправку на фабрику. 
420  
421  Трагическая история, как в реальной жизни, так и на сетевом оборудовании.
422  <hr>
423  
424  <a name="VOQ"></a>
425  <h3>Virtual Output Queueing</h3>
426  Как можно исправить эту дорожную ситуацию? Например, сделав три полосы - одна налево, другая прямо, третья направо.
427  
428  Ровно то же самое сделали разработчики сетевого оборудования.
429  Они взяли входной буфер побольше и подробили его на множество очередей.
430  Для каждого выходного интерфейса они создали по 8 очередей на каждом чипе коммутации. То есть перенесли все задачи по обеспечению QoS на входной чип. На выходном же при этом остаётся самая базовая FIFO очередь, в которой никогда не будет заторов, потому что их контроль взял себя входной чип.
431  
432  <img src="https://fs.linkmeup.ru/images/articles/buffers/voq.png" width="500">
433  
434  Если взять грубо коробку со 100 интерфейсами, то на каждой плате в буферах нужно будет выделить 800 очередей. 
435  Если в коробке всего 10 линейных карт, то общее число очередей на ней будет 100*8*10 = 8000.
436  
437  Однако V в VOQ означает виртуальный, не потому, что они как бы выходные, но на самом деле находятся на входных платах, а потому что Output Queue для каждого выходного интерфейса распределён между всеми линейными картами. То есть сумма 10и физических очередей для одного интерфейса на 10 чипах составляет 1 виртуальную. 
438  Собственно из-за распределённого характера этой виртуальной очереди от арбитра и здесь избавиться не получится - разным входным чипам всё же нужно знать, состояние выходной очереди. Поэтому даже несмотря на то, что выходная очередь - это FIFO, выходной чип всё ещё должен давать добро на отправку трафика. 
439  
440  Кстати, что касается трафика, который должен вернуться в интерфейс той же карты, на которую он пришёл изначально, то здесь никаких исключений - он томится в VOQ, пока чип не даст добро переложить его в выходную очередь. 
441  Причём зачастую такому трафику придётся даже выйти на фабрику, потому что Ingress и Egress части полностью разделены.
442  Поэтому перед лицом перегрузок все равны.
443  
444  На сегодняшний день подавляющее большинство модульных сетевых устройств используют архитектуру VOQ.
445  
446  <b>Дальнейшее чтиво: </b>
447  <ul>
448      <li>
449          <a href="https://people.ucsc.edu/~warner/Bufs/Buffering-WP_August_2017.pdf" target="_blank">An Update on Router Buffering</a>
450      </li>
451      <li>
452          <a href="https://forums.juniper.net/t5/forums/recentpostspage/post-type/message/category-id/Blogs/user-id/101479" target="_blank">What is VOQ and why you should care?</a>
453      </li>
454      <li>
455          <a href="https://archive.nanog.org/sites/default/files/wednesday_tutorial_szarecki_packet-buffering.pdf" target="_blank">Strategies of packet buffering inside Routers</a>
456      </li>
457      <li>
458          <a href="https://www.juniper.net/documentation/en_US/junos/topics/concept/cos-qfx-series-voq-understanding.html" target="_blank">Understanding CoS Virtual Output Queues (VOQs) on QFX10000 Switches</a>
459      </li>
460      <li>
461          <a href="https://books.google.ru/books?id=kzstoFdvZ2sC&pg=PR8&lpg=PR8&dq=shared+memory+vs+voq&source=bl&ots=mTy-1ifsRK&sig=ACfU3U0DHx37_i_oDKvDJTEh72g6pSW-Ng&hl=ru&sa=X&ved=2ahUKEwjnx9el0LPnAhWHAhAIHUF6CeIQ6AEwCHoECAgQAQ#v=onepage&q=shared%20memory%20vs%20voq&f=false" target="_blank">High Performance Switches and Routers</a> - если у вас есть лишних 14 к₽.
462      </li>
463  </ul>
464  
465  
466  <hr>
467  
468  <a name="SHALLOW_VS_DIPPER"></a>
469  <h1>Shallow vs Deep Buffers</h1>
470  Буферы - это то место, где пакеты можно похранить, вкачав в них смертельную порцию задержки.
471  Как сказали в <a href="https://www.youtube.com/watch?v=Ti3t9OAZL3g">видео Packet Pushers</a> - буферы - это религия. Хотя, скорее всего, неортодоксальная, а возможно даже секта.
472  
473  Чуть позже мы поговорим о том, что такое хорошо, а что такое плохо. А пока посмотрим на реализации. 
474  
475  <b>Shallow</b> - неглубокие - это буферы размером до 100МБ. Обычно это встроенная в кристалл <b>on-chip</b> память - <b>OCB</b> - On-Chip Buffer.
476  <b>Deep</b> - счёт уже идёт на гигабайты. Обычно <b>off-chip</b> и подключается к чипу по отдельной шине.
477  И нет ничего посередине.
478  
479  За последние лет десять производительность чипов выросла на порядки, трафика они теперь перемалывают терабиты в секунду вместо единиц гигабит. А размер памяти не то что не поспевает за этим ростом, он фактически почти стоит на месте. 
480  Давайте грубо прикинем: если для гигабитного порта буфер размером 16 мегабайт мог абсорбировать всплеск трафика длительностью примерно 100 мс, то для 100Гб/с - всего лишь 1мс. И это только один порт, фактически же плотность портов тоже растёт и максимальная комплектация для одночипового устройства сегодня - 64 порта 400Гб/с - или 25,6 Тб/с полосы пропускания. 
481  Используя только 64 МБ буфер, такой чип сможет хранить трафик 0.000005 c или 5 мкс.
482  
483  Такие буферы порой даже называют <a href="https://conferences.sigcomm.org/events/apnet2017/papers/bcc-bai.pdf">Extremely shallow buffers</a>. 
484  
485  Их воистину миниатюрный объём обусловлен в первую очередь тем, что они в прямом смысле встроены в чип. Такая память является составной частью микросхемы, и каждый дополнительный мегабайт, разумеется, будет обходиться в лишнюю тысячу долларов, больший размер и тепловыделение. Для справки Broadcom Trident 4 содержит 21 миллиард транзисторов, изготовленных по 7нм техпроцессу на нескольких квадратных сантиметрах.
486  Логично вытекающим следствием является скорость работы с этой памятью - она должна соответствовать производительности чипа.
487  
488  
489  <img src="https://fs.linkmeup.ru/images/articles/buffers/trident4_memory.png" width="400">
490  
491  
492  Очевидно, что не для всех задач такие маленькие буферы подходят. В частности модульные коробки с VOQ явно не могут позволить себе дробить 64 Мб на несколько тысяч очередей (на самом деле <a href="#HYBRID_BUFFERING">могут</a>).
493  
494  Поэтому рынок предлагает решения с большой внешней памятью (Deep Buffers), размер которой начинается от 1ГБ (обычно от 4ГБ).
495  Согласно <a href="https://people.ucsc.edu/~warner/buffer.html" target="_blank">этой таблице</a> существуют коммутаторы (Arista 7280QR-C48) с фантастическими 32-хгигабайтовыми буферами - это уже все сезоны Рика и Морти в неплохом качестве. Но это уже история про VOQ - всё-таки это память не одного чипа. На моём первом ПК такого объёма был жёсткий диск. 
496  
497  Как такая память реализована зависит уже от чипа и коробки.
498  Например, Broadcom <b>Jericho+</b> сгружает пакеты во внешнюю память в размере 4ГБ. Это обычная широко известная <b>GDDR5</b>, использующаяся в видеокартах.
499  
500  
501  
502  <img src="https://fs.linkmeup.ru/images/articles/buffers/jericho_deep_beffers.png" width="500">
503  <i><a href="https://xrdocs.io/ncs5500/blogs/2018-05-07-ncs-5500-buffering-architecture/" target="_blank">Источник</a></i>.
504  
505  
506  <b>Jericho2</b> несёт на борту новейшую память <b>HBM2</b> - High Bandwidth Memory - размером 8ГБ.
507  
508  
509  <img src="https://fs.linkmeup.ru/images/articles/buffers/jericho2_deep_beffers.png" width="400">
510  <i><a href="https://www.broadcom.com/products/ethernet-connectivity/switching/stratadnx/bcm88690" target="_blank">Источник</a></i>.
511  
512  
513  <img src="https://fs.linkmeup.ru/images/articles/buffers/chipset_die.png" width="800">
514  
515  А вот и фото Jericho2:
516  <img src="https://fs.linkmeup.ru/images/articles/buffers/hbm_photo.png" width="400">
517  <i><a href="https://people.ucsc.edu/~warner/Bufs/CSG-DNX-Switching-J2%20Feb%2016%202018.pdf">Источник</a>.</i>
518  
519  
520  Juniper QFX10000 использует чип <b>Q5</b> собственного производства с внешней памятью - <b>HMC</b> - Hybrid Memory Cube - в размере 4ГБ. HMC - это коммерческая память производства Micron, от которой ныне отказались в пользу HBM и GDDR6.
521  
522  <img src="https://fs.linkmeup.ru/images/articles/buffers/juniper_hmc.png" width="500">
523  <i><a href="https://forums.juniper.net/t5/Enterprise-Cloud-and/Not-all-deep-buffer-switches-are-created-equal/ba-p/318393" target="_blank">Источник</a></i>.
524  
525  Фото чипа ZX EXPRESS:
526  <img src="https://fs.linkmeup.ru/images/articles/buffers/zx_asic.png" width="500">
527  <i><a href="https://senetsy.ru/upload/juniper-summit-2019/New_in_Routing_and_%20Switching_Andrey_Pinaev_Juniper.pdf" target="_blank">Источник</a>.</i>
528  
529  А вот так выглядит сетевой процессор Cisco с внешней памятью:
530  
531  <img src="https://fs.linkmeup.ru/images/articles/buffers/cisco_npu.jpg" width="400">
532  <i><a href="https://servernews.ru/958639" target="_blank">Источник</a></i>.
533  
534  Перечислять можно и дальше.
535  Что здесь важно отметить, что внешняя память тоже не даётся бесплатно. Во-первых, цена таких решений значительно выше. Во-вторых, пропускная способность обычно ниже.   И основное ограничение - канал между чипом коммутации и чипом памяти. Для производимых массово чипов, вроде GDDR5 полоса не превышает 900ГБ в режиме half-duplex. Но это чип, явно не заточенный под задачи сетевых сервисов.
536  
537  Кастомный джуниперовский HMC <a href="https://forums.juniper.net/t5/Enterprise-Cloud-and/Not-all-deep-buffer-switches-are-created-equal/ba-p/318393">обещает</a> 1,25 Тб/с в обоих направлениях.
538  
539  Если верить <a href="https://en.wikipedia.org/wiki/High_Bandwidth_Memory#HBM2">вики</a>, то HBM 2-го поколения, используемый в последнем чипе Broadcom Jericho2, выдаёт порядка 2Тб/с.
540  
541  Но это всё ещё далеко от реальной производительности сетевого ASIC. Фактически шины до этой внешней памяти является узким местом, которое и определяет производительность чипа.
542  <hr>
543  
544  <a name="HYBRID_BUFFERING"></a>
545  <h2>Hybrid Buffering</h2>
546  Поэтому почти все вендоры сегодня практикуют <b>гибридную буферизацию</b>, или, если хотите - динамическую. В нормальных условиях используется только on-chip память, предоставляющая line-rate производительность. А в случае перегрузки пакеты автоматически начинают буферизироваться во внешней памяти.
547  Это позволяет уменьшить стандартные задержки, энергопотребление и в большинстве случаев вписаться в ограниченную полосу пропускания до памяти.
548  
549  
550  
551  <img src="https://fs.linkmeup.ru/images/articles/buffers/hybrid_buffering.png" width="800">
552  <i><a href="https://people.ucsc.edu/~warner/Bufs/CSG-DNX-Switching-J2%20Feb%2016%202018.pdf" target="_blank">Источник</a></i>.
553  
554  <blockquote>
555      Данный параграф отменяет сказанное выше о том, что on-chip памяти не хватит для VOQ. Фактически в случае гибридной буферизации она всё же дробится на тысячи очередей очень маленькой длины, чтобы обеспечить VOQ. Просто в нормальных условиях этой длины хватает, чтобы пропускать трафик мимо внешней памяти. 
556      При этом в первую очередь начнёт офлоадиться на внешнюю память массивный трафик, идущий в низкоприоритетных очередях, а требовательный к задержками будет по-прежнему пролетать фаст-пасом.
557  </blockquote>
558  
559  <hr>
560  
561  <a name="TRUE_EVIL"></a>
562  <h2>Большие буферы - добро или зло?</h2>
563  В целом это довольно старая дилемма. Подольше похранить или пораньше дропнуть?
564  
565  Конечно, всем приложениям хочется lossless low-latency сеть. Даже жирному некрасивому торренту. Но так не бывает и кем-то нужно жертвовать.
566  И мы долгое время живём с инертной мыслью , что часть приложений могут потерпеть задержки, а вот терять трафик совсем не хочется. Не в малой степени этому способствовало и то, что потери - это измеримая характеристика с более или менее понятными границами - потерь быть не должно. А что задержка? Вроде можно чётко сказать, что единицы миллисекунд - это хорошо, а секунды - это плохо. А между ними - зона спекуляций. Как оценить влияние вариаций задержки для рядового TCP-трафика?
567  Поэтому и спрос на устройства с большими буферами есть - никто не хочет терять трафик.
568  
569  А теперь я выскажу не самое популярное мнение - потери - это хорошо. 
570  Так уж вышло, что один из транспортных протоколов, фиксирует перегрузки, опираясь на потери. 
571  Дроп в очереди на сетевом устройстве означает, что на нём случился затор - это он не по своему капризу. И будет совсем не лишним, если отправители немного приуменьшат свои congestion window.
572  Именно так и работают все классические (и не очень) реализации TCP Congestion Control. 
573  Соответственно на устройствах с глубокими буферами во время заторов пакеты будут долго копиться, не отбрасываясь. Когда они всё-таки дойдут до получателя и тот их ACKнет, отправитель не только не снизит скорость, но может даже её увеличить, если у него сейчас режим Slow Start или Congestion Avoidance. 
574  Можно взглянуть и дальше: растущая очередь взвинчивает RTT, что соответственно влечёт за собой увеличение RTO таймеров на отправителях, тем самым замедляя обнаружение потерь. 
575  То есть сеть лишается своего практически единственного инструмента управления перегрузками.
576  И таким образом архитекторы, пытающиеся решить вопрос заторов на сети путём увеличения буферов, усугубляют ситуацию ещё больше.
577  
578  Ситуация, описанная выше, называется <b>bufferbloat</b> - распухание буфера.
579  Википедия иронично замечает:
580  <blockquote>
581      Проект www.bufferbloat.net иронично определил этот термин, как «ухудшение производительности Интернета, вызванное предыдущими попытками её улучшения»
582  </blockquote>
583  
584  Отбросы - санитары сети. Ко всеобщему удивлению, уменьшение очереди до одного пакета зачастую может кардинально улучшить ситуацию, особенно в условиях датацентра (только не сочтите это за дельный совет).
585  
586  <blockquote>
587      Справедливости ради следует заметить, что современные реализации TCP - BBR2, TIMELY ориентируются не только и не столько на потери, сколько на RTT и <a href="https://en.wikipedia.org/wiki/Bandwidth-delay_product" target="_blank">BDP</a>.
588      Гугловый QUIC - надстройку над UDP - следует отнести сюда же. 
589  </blockquote>
590  
591  Внутри фабрики датацентра RTT ультракороткий - зачастую меньше 1 мс. Это позволяет среагировать на потерю очень быстро и купировать перегрузку в её зачатке.
592  Собственно поэтому практически все ASIC'и для датацентровых коммутаторов имеют только крохотную on-chip память.
593  Хотя и появилась в последние годы тенденция к глубоких буферам и тут.
594  И этому даже находится <a href="https://forums.juniper.net/t5/Enterprise-Cloud-and/Not-all-deep-buffer-switches-are-created-equal/ba-p/318393" target="_blank">объяснение</a>.
595  <hr>
596  
597  Особая история на границе датацентра (или на устройствах доступа в сети провайдера или на магистральных сетях).
598  <b>Во-первых</b>, это места, которые обычно заведомо строятся с переподпиской, поскольку WAN-линки дорогие, что автоматически означает, что ситуации, в которых трафика приходит больше, чем способен переварить интерфейс, ожидаемы. А значит нужна возможность пакеты хранить и обрабатывать их в соответствии с приоритетами. Большие буферы позволяют сгладить всплески.
599  <b>Во-вторых</b>, обычно приложения настолько чувствительные к задержкам, никто не будет пытаться растягивать на этот сегмент. Например, RoCE или распределённое хранилище. Для чуть менее чувствительных, таких как телефония, в больших буферах выделяется приоритетная очередь. 
600  <b>В-третьих</b>, тут задержки на устройстве всё ещё делают основной вклад в общее время доставки, но уже не настолько драматический.
601  
602  Итак, устройства с большим объёмом памяти годятся в места где заложена переподписка или могут появиться заторы.
603  
604  Что стоит отметить, так это то, что в датацентрах тоже есть ситуации, в которых 16-64 МБ буферов может не хватить, даже несмотря на отсутствие переподписки.
605  Два типичных примера - это обработка Big Data и Storage. 
606  
607  <b>Анализ Big Data</b>. Кластера Map-Reduce - это сотни и тысячи машин, которые перемалывают параллельно огромные массивы данных по заданию Master-узла, заканчивают примерно одинаково и все разом начинают возвращать ответы на Master-узел. Ситуация называется <a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.447.1375&rep=rep1&type=pdf">Incast</a>. Длится она порядка нескольких десятков миллисекунд и потом исчезает. 
608  On-chip память неспособна вместить эти данные - значит будет много дропов, значит ретрансмиты, значит общее снижение производительности.
609  
610  <b>Storage</b>. Это штука крайне чувствительная к потерям и тоже гоняющая массивные объёмы данных. В случае хранилки тоже лучше не терять ничего. Но обычно она при этом и к задержкам предъявляет строгие требования, поэтому такие приложения обсудим <a href="#LLLL">пониже</a>.
611  
612  Однако при этом крайне редко они единственные потребители сети в датацентрах, другим приложениям нужна низкая задержка.
613  
614  Впрочем, это легко решается выделением очередей QoS с ограничением максимальной доступной глубины. И весь вопрос заключается тогда только в том, готова ли компания заплатить за глубокие буферы, возможно, не использовать их  и поддерживать конфигурацию QoS. 
615  
616  Но в любой ситуации лучше следовать правилу: <a href="https://www.nextplatform.com/2019/07/23/the-switch-router-war-is-over-and-hyperscalers-won/">use shallow ASIC buffers when you can and use deep buffers when you must</a>.
617  
618  <b>Критика глубоких буферов</b>: 
619  
620  <ul>
621      <li>
622          <a href="https://packetpushers.net/aristas-big-buffer-b-s/" target="_blank">Arista’s Big Buffer B.S.</a>
623      </li>
624      <li>
625          <a href="https://people.ucsc.edu/~warner/Bufs/incast.html" target="_blank">Incast</a>
626      </li>
627      <li>
628          <a href="http://miercom.com/pdf/reports/20160210.pdf" target="_blank">Speeding Applications in Data Center Networks. The Interaction of Buffer Size and TCP Protocol Handling and its Impact on Data-Mining and Large Enterprise IT Traffic Flows</a>
629      </li>
630  </ul>
631  <hr>
632  Кстати, показательная таблица типичных задержек:
633  
634  <img src="https://fs.linkmeup.ru/images/articles/buffers/latencies.png" width="630">
635  <i><a href="https://people.ucsc.edu/~warner/Bufs/Buffering-WP_August_2017.pdf" target="_blank">Источник</a></i>.
636  
637  
638  <hr>
639  
640  <a name="LLLL"></a>
641  <h1>Low-latency lossless сети</h1>
642  С развитием RoCE, RDMA, nVME over Fabric к сети стали появляться другие, неслыханные доселе требования: и каждый пакет ценен и времени терять нельзя. Одновременно. И хуже того, мы хотим по максимуму утилизировать имеющиеся линки, чтобы они не простаивали.
643  И все требования оправданы - осуждать их мы здесь не будем.
644  
645  Так что же можно сделать? На самом деле, как я уже говорил выше, условия сети датацентра хороши тем, что информация о перегрузке очень быстро доносится до отправителей. Поэтому и реакция на потерянный пакет не заставит себя долго ждать.
646  
647  Но что если нам не отбрасывать пакет, а каким-то другим способом сообщить отправителю, что нужно замедлиться? 
648  Здесь есть несколько конкурирующих подходов.
649  
650  ECN-Based
651  Bandwidth-Delay Product Based
652  RTT-BASED
653  
654  
655  <h2>ECN-Based</h2>
656  Транзитное устройство, говтовящееся испытать перегрузку, явным образом сообщает отправителям о том, что нужно охладить свою страсть.
657  
658  Прозорливые инженеры заложили в IP целых 8 бит под QoS, и только 6 мы задействовали под DSCP, а 2 бита были зарезервированы для целей <b>ECN - Explicit Congestion Notification</b>.
659  
660  Надолго забытый механизм сегодня извлекают из ящика стола, сдувают с него пыль, и вставляют в шкатулку, на которой нацарапано или <a href="https://tools.ietf.org/html/rfc8257" target="_blank">DCTCP</a>
661  
662  Транзитное устройство при заполнении буфера больше, чем до определённого порога, выставляет в заголовках IP обрабатываемых пакетов бит CE (Congestion Encountered) и отправляет пакет дальше.
663  Получатель, увидев в пришедшем пакете этот флаг, сообщает отправителю о перегрузке и о том, что нужно снизить скорость.
664  
665  Классический TCP может обнаружить только уже существующую перегрузку, а DCTCP, используя ECN, узнаёт о том, что она только приближается, и пробует её избежать. 
666  
667  Есть и другие реализации TCP, поддерживающие ECN, например, HTCP.
668  
669  Нюанс с ECN-based Congestion Control механизмами в том, что до поры до времени они ничего не знают о надвигающейся перегрузке, а потом должен пройти ещё целый RTT, чтобы отправитель узнал, что какое-то транзитное устройство к ней близко. К тому времени, как отправители начнут снижать скорость, перегрузка уже может или рассосаться или наоборот дойти до уровня, когда начнутся дропы. 
670  
671  
672  <h2>Bandwidth-Delay Product Based</h2>
673  Другие реализации замеряют эффективную полосу сети совместно с RTT, то есть сколько можно ещё напихать в трубу до того, как это создаст затор и увеличит задержку.
674  
675  Примерами таких протоколов являются <a href="https://habr.com/ru/post/322430/" target="_blank">BBR</a> и <a href="https://www.hamilton.ie/net/draft-leith-tcp-htcp-00.txt" target="_blank">H-TCP</a>.
676  
677  <h2>RTT-BASED</h2>
678  В конце концов есть элегантные механизмы, которые замеряют время прохода трафика туда-обратно.
679  Идея провальная для MAN/WAN-сегментов, и, честно говоря, при попытке программной вычисления RTT тоже.
680  TIMELY от Google с аппаратным offload'ом вычисления RTT один из наиболее удачных примеров.
681  
682  На самом деле, если бы не видео с прекрасной девушкой, рассказывающей про технические детали TIMELY, не знаю даже стал ли бы я упоминать про него. Наслаждайтесь, но берегите уши: <a href="https://dl.acm.org/action/downloadSupplement?doi=10.1145%2F2829988.2787510&file=p537-mittal.webm&download=true" target="_blank">TIMELY: RTT-based Congestion Control for the Datacenter</a>.
683  <hr>
684  
685  <a name="LINKS"></a>
686  <h1>Полезные ссылки</h1>
687  В этот раз хоть под кат убирай. Но, поверьте, я оставил тут только самые хорошие источники, прочитанные лично моими глазами и отобранные лично моими руками.
688  
689  <ul>
690      <li><b>Архитектура памяти</b>
691      <ul>
692          <li>
693              <a href="https://people.ucsc.edu/~warner/buffer.html" target="_blank">Packet Buffers</a>. Отсюда по ссылкам разворачиваются разнообразные материалы очень глубоко
694          </li>
695          <li>
696              <a href="https://people.ucsc.edu/~warner/Bufs/Buffering-WP_August_2017.pdf" target="_blank">An Update on Router Buffering</a>
697          </li>
698          <li>
699              <a href="https://xrdocs.io/ncs5500/blogs/2018-05-07-ncs-5500-buffering-architecture/" target="_blank">NCS 5500 Buffering Architecture</a>
700          </li>
701          <li>
702              <a href="https://www.cisco.com/c/en/us/products/collateral/switches/nexus-5020-switch/white_paper_c11-465436.html" target="_blank">Cisco Nexus 5000 Series Switches</a>. Cut-through and Store-and-Forward
703          </li>
704          <li>
705              <a href="https://www.juniper.net/documentation/en_US/junos/topics/concept/cos-qfx-series-congestion-notification-understanding.html#jd0e554" target="_blank">Understanding CoS Flow Control (Ethernet PAUSE and PFC)</a>
706          </li>
707          <li>
708              <a href="https://github.com/Mellanox/mlxsw/wiki/Quality-of-Service" target="_blank">Quality of Service</a>. Headroom buffers
709          </li>
710      </ul>
711      </li>
712      <li>
713      <b>Реализации очередей</b>
714      <ul>
715          <li>
716              <a href="https://archive.nanog.org/sites/default/files/wednesday_tutorial_szarecki_packet-buffering.pdf" target="_blank">Strategies of packet buffering inside Routers</a>
717          </li>
718          <li>
719              <a href="https://www.juniper.net/documentation/en_US/junos/topics/concept/cos-qfx-series-voq-understanding.html" target="_blank">Understanding CoS Virtual Output Queues (VOQs) on QFX10000 Switches</a>
720          </li>
721  
722          <li>
723              <a href="https://forums.juniper.net/t5/forums/recentpostspage/post-type/message/category-id/Blogs/user-id/101479" target="_blank">What is VOQ and why you should care?</a>
724          </li>
725      </ul>
726      </li>
727      <li>
728      <b>Deep Buffers</b>
729      <ul>    
730          <li>
731              <a href="https://forums.juniper.net/t5/Enterprise-Cloud-and/Not-all-deep-buffer-switches-are-created-equal/ba-p/318393" target="_blank">Not all deep buffer switches are created equal</a>
732          </li>
733          <li>
734              <a href="https://packetpushers.net/aristas-big-buffer-b-s/" target="_blank">Arista’s Big Buffer B.S.</a>
735          </li>
736          <li>
737              <a href="http://miercom.com/pdf/reports/20160210.pdf" target="_blank">Speeding Applications in Data Center Networks. The Interaction of Buffer Size and TCP Protocol Handling and its Impact on Data-Mining and Large Enterprise IT Traffic Flows</a>
738          </li>
739      </ul>
740      </li>
741      <li>
742          <a href="https://tools.ietf.org/html/rfc8257" target="_blank">Data Center TCP (DCTCP): TCP Congestion Control for Data Centers</a>
743      </li>
744      <li>
745          <a href="https://support.huawei.com/enterprise/en/doc/EDOC1100086962" target="_blank">Understanding Microburst</a>
746      </li>
747  </ul>
748  <hr>
749  
750  <h1>Заключение</h1>
751  Я предпринял несколько попыток написать короткое резюме всей статье, но каждый раз получалось почти полное её переписывание иными словами.
752  Поэтому просто замечу, что буферы - это неотъемлемая часть сетевого устройства. Но к тому же это место, где ко времени жизни пакетов могут добавиться лишние миллисекунды. И чем больше объём памяти, тем дольше трафик может в ней протомиться. Но даже в экстремальных случаях (8-игиговый буфер) нужно с большим подозрением и узкими глазами относиться к претензиям к сети о том, что, мол, у кого-то секундные задержки в пределах датацентра - ну негде там столько их хранить.
753  Вопрос большие или маленьки буферы обычно решается легко, когда отталкиваешься от задач и от позиции устройства в сети, но есть, конечно, места, где это вопрос философии или даже религии. 
754  
755  <hr>
756  
757  <h1>Спасибы</h1>
758  <ul>
759      <li>Андрею Глазкову за рецензию и дельные замечания, Shared Buffers и коммерческих чипах</li>
760      <li>Михаилу Соколову за разъяснения об устройстве чипов, SerDes и Silicon Photonics</li>
761      <li>Александру Клименко за обнаружение точек роста в вопросах Admission Control, Alpha, Pipeline'ов и минусов DCTCP</li>
762      <li>Александру Азимову за комментарии о Lossless Ethernet</li>
763      <li>Артёму Чернобаю за КДПВ</li>
764  </ul>