Обзор счётчиков Морриса

27 мая 2021

Мы рады представить вам заметку, написанную инженером Qrator Labs Дмитрием Камальдиновым. Если вы хотите быть частью нашей команды Core и заниматься подобными задачами - пишите нам на hr@qrator.net.

1 Введение

При реализации потоковых алгоритмов часто возникает задача подсчёта каких-то событий: приход пакета, установка соединения; при этом доступная память может стать узким местом: обычный \(n\)-битный счётчик позволяет учесть не более \(2^n - 1\) событий.
Одним из способов обработки большего диапазона значений, используя то же количество памяти, является вероятностный подсчёт. В этой статье будет предложен обзор известного алгоритма Морриса, а также некоторых его обобщений.

Другой способ уменьшить количество бит, необходимое для хранения значения счётчика, — использование распада. Об этом подходе мы рассказываем здесь, а также собираемся в ближайшее время опубликовать ещё одну заметку по теме.

Мы начнём с разбора простейшего алгоритма вероятностного подсчёта, выделим его недостатки (раздел 2). Затем (раздел 3) опишем алгоритм, впервые преложенный Робертом Моррисом в 1978 году, укажем его важнейшие свойства и приемущества. Для большинства нетривиальных формул и утверждений в тексте присутствуют наши доказательства — интересующийся читатель сможет найти их во вкладышах. В трёх последующих разделах мы изложим полезные расширения классического алгоритма: вы узнаете, что общего у счётчиков Морриса и экспоненциального распада, как можно уменьшить ошибку, пожертвовав максимальным значением, и как эффективно обрабатывать взвешенные события.

2 Вероятностный подсчёт, проблемы тривиального подхода

Основная идея вероятностного подсчёта — учёт очередного события с некоторой вероятностью. Рассмотрим сначала пример с постоянной вероятностью обновления:

\(\begin{equation*} C_{n+1} = \left\{\begin{array}{ll} C_n + 1 & \textit{с вероятностью $p = const$} \\ C_n & \textit{с вероятностью $1-p$.} \end{array}\right. \end{equation*}\)

Где через \(C_n\) обозначено значение счётчика после \(n\)-ой попытки обновления. Несложно понять, что \(C_n\) задаёт количество успехов среди \(n\) независимых испытаний Бернулли. Иначе говоря, \(C_n\) имеет биномиальное распределение:

\(\begin{align*} C_n \sim Bin(&n, p) \\ {\sf E} C_n = &np \\ {\sf D} C_n = &np(1-p). \end{align*}\)

В качестве оценки числа событий \(n\) естественно использовать \(\widehat{n}(C) := C/p\). Ясно, что такая оценка несмещённая: \({\sf E}\widehat{n}(C_n) = ({\sf E}C_n)/p = np/p = n\).

Описанный подход имеет несколько недостатков: во-первых, он позволяет учесть лишь в \(1/p = const\) раз больше событий по сравнению с простым инкрементальным счётчиком, чем заметно уступает счётчикам Морриса, как мы увидим далее. Во-вторых, относительная ошибка оценки велика при маленьких \(n\). Например, при \(n=1\) она вообще равна 100%. Оценить относительную ошибку можно с помощью коэффициента вариации:

\(\begin{align*} {\sf CV}\widehat{n}(C_n) = \frac{\sqrt{{\sf D}\widehat{n}(C_n)}}{{\sf E} \widehat{n}(C_n)} = \sqrt{\frac{1-p}{pn}}. \end{align*}\)

3 Счётчики Морриса

Счётчик Морриса обновляется с вероятностью, зависящей от текущего значения: первое обновление происходит с вероятностью 1, следующее с вероятностью 1/2, потом 1/4 и т.д.:

\(\begin{equation*} C_{n+1} = \left\{\begin{array}{ll} C_n + 1 & \textit{с вероятностью $2^{-C_n}$} \\ C_n & \textit{с вероятностью $1 - 2^{-C_n}$.} \end{array}\right. \end{equation*}\)

Как по значению счётчика оценить, сколько было событий? Обновление счётчика с \(x\) на \(x + 1\) происходит в среднем за \(2^x\) итераций, отсюда оценка числа событий \(\widehat{n}(C) := \sum_{i=0}^{C-1} 2^{i} = 2^C - 1\).

Важнейшими свойствами этой оценки являются

  • её несмещённость, то есть значение оценки после \(n\) вероятностных обновлений в среднем равно \(n\),

Доказательство

\(\begin{align*} {\sf E}\left(2^{C_n} | C_{n-1} = y\right) =& \underbrace{2^{y + 1} 2^{-y}}_{\textit{счётчик обновился}} + \underbrace{2^y (1 - 2^{-y})}_{\textit{значение не изменилось}} = 2^y + 1 \implies \\ {\sf E}\left(2^{C_n}|C_{n-1}\right) =& 2^{C_{n-1}} + 1 \implies {\sf E}2^{C_n} = {\sf E}2^{C_{n-1}} + 1 = {\sf E}2^{C_{n-2}} + 2 = \dots \end{align*}\)

В самом начале значение счётчика равно 0: \(C_0 = 0\), тогда \({\sf E}2^{C_0} = 2^{0} = 1\), а значит \({\sf E} 2^{C_n} = \dots = n + 1\). Итого \({\sf E}\widehat{n}(C_n) = {\sf E}2^{C_n} - 1 = n\).

  • а также независимость её относительной ошибки от \(n\).

Доказательство

Сначала посчитаем дисперсию \(\widehat{n}(C_n)\). Согласно известной формуле, \({\sf D}\widehat{n} = {\sf E}\widehat{n}^2 - ({\sf E}\widehat{n})^2\). Мы уже знаем, что \({\sf E}\widehat{n}(C_n) = n\). Осталось получить \({\sf E}\widehat{n}(C_n)^2\). Заметим, что

\( \begin{align*} {\sf E}\left(2^{C_n} - 1\right)^2 = {\sf E}2^{2C_n} - 2(n+1) + 1 = {\sf E}2^{2C_n} - 2n - 1. \end{align*}\)

Таким образом, остаётся узнать, чему равно \({\sf E}2^{2C_n}\).

\(\begin{align*} {\sf E}\left(2^{2C_n} | C_{n-1} = y\right) &= \underbrace{2^{2(y + 1)} 2^{-y}}_{\textit{счётчик обновился}} + \underbrace{2^{2y}(1 - 2^{-y})}_{\textit{значение не изменилось}} = \\ 3 \cdot 2^y +2^{2y} &\implies {\sf E}\left(2^{2C_n} | C_{n-1}\right) = 3 \cdot 2^{C_{n-1}} + 2^{2C_{n-1}} \implies \\ {\sf E} 2^{2C_n} = 3n &+ {\sf E}2^{2C_{n-1}} = 3n + 3(n-1) + {\sf E}2^{2C_{n-2}} = \dots = \sum_{i=1}^n 3i \end{align*}\)

Итого

\( \begin{equation*} {\sf D}\widehat{n}(C_n) = \frac{3n(n+1)}{2} - 2n - 1 - n^2 = \frac{n^2 - n - 2}{2} \end{equation*}\)

\(\begin{equation*} {} {\sf CV}\widehat{n}(C_n) = \frac{\sqrt{{\sf D}\widehat{n}(C_n)}}{{\sf E}\widehat{n}(C_n)} = \sqrt{\frac{n^2-n-2}{2n^2}} \sim \frac{1}{\sqrt{2}}. \end{equation*}\)

Таким образом, относительная ошибка оценки числа событий при использовании счётчика Морриса ограничена, примерно постоянна и почти не зависит от \(n\).
    
Оценить вероятность больших отклонений от среднего можно с помощью неравенства Чебышёва:

\(\begin{align*} {\sf P}(|\widehat{n}(C_n) - n| \ge \varepsilon n) \le \frac{{\sf D}\widehat{n}(C_n)}{\varepsilon^2n^2} \sim \frac{1}{2\varepsilon^2}. \end{align*}\)

  • отметим здесь также, что покрываемый диапазон количества событий при использовании \({\bf X}\) бит памяти будет \(2^{2^{\bf X}} - 1\). Иначе говоря, для учёта \(n\) событий достаточно \(\mathcal{O}(\log \log n)\) бит памяти!
Рис. 1: Относительная ошибка оценки числа событий при использовании биномиальных счётчиков и счётчиков Морриса*

*для построения графика \(sample\_size=100\) раз запускался процесс обновления счётчика, затем каждой точке \(n\) сопоставлялось среднее значение по этой выборке относительной ошибки после \(n\) обновлений

4 Взвешенные обновления

Счётчики Морриса можно использовать для подсчёта взвешенных событий: например, для суммирования размеров приходящих пакетов. Простейший способ — обновление счётчика <вес события> раз — приводит к линейной по весу сложности обновления.

Заметим, что в каждый момент времени мы знаем, как распределено количество неудач до ближайшего изменения счётчика, — это геометрическое рапределение:

\(\begin{align*} {\sf P}(n_{fail} = k) = (1 - 2^{-C})^k 2^{-C} \implies n_{fail} \sim Geom(2^{-C}). \end{align*}\)

Учитывая этот факт, мы можем ускорить алгоритм, сразу пропуская все подряд идущие неудачные попытки обновления:

5 Распад

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

Идея очень проста: будем периодически вычитать \(1\) из счётчика. Напомним, что значение \(C\) оценивает количество событий как \(\sum_{i=0}^{C-1} 2^i = 2^C - 1 =: n_0\). Соответственно, после вычитания \(1\) оценка станет \(2^{C-1} - 1 = \frac{1}{2}n_0 - \frac{1}{2}\). Иначе говоря, вычитание \(1\) уменьшает оценку в \(\sim 2\) раза! Мы можем добиться распада ровно в \(2\) раза, обновив с вероятностью \(\frac{1}{2}\) счётчик сразу после вычитания \(1\):

6 Мантисса и экспонента

Рассмотрим следующее обобщение счётчика Морриса: вероятность обновления уменьшается в \(2\) раза не на каждое успешное обновление, а на каждые \({\bf X}\). Возможной реализацией такого подхода будет разделение битов счётчика на две части: экспоненту, отвечающую за вероятность, и мантиссу, считающую количество успешных обновлений при текущей вероятности (чем-то похоже на представление чисел с плавающей точкой).

Рис. 2: разбиение битов счётчика на мантиссу (\({\bf M} = 5\) бит) и экспоненту (\({\bf E} = 3\) бит)

Введём обозначения для мантиссы и экспоненты:

\(\begin{align*} {\rm e}(C) &= C \gg {\bf M} \\ {\rm m}(C) &= C \& (2^{\bf M} - 1). \end{align*}\)

Теперь правило обновления и оценка числа событий записываются так:

\(\begin{align*} C_{n+1} &= \left\{\begin{array}{ll} C_n + 1, & \textit{с вероятностью $2^{-{\rm e}(C)}$} \\ C_n, & \textit{с вероятностью $1 - 2^{-{\rm e}(C)}$} \end{array}\right. \\ \widehat{n}(C) &= (2^{{\rm e}(C)} - 1)2^{\bf M} + 2^{{\rm e}(C)}{\rm m}(C). \end{align*}\)

Например, на рисунке 2 значение счётчика \(C = 89\), мантисса и экспонента равны \({\rm m} = 25\) и \({\rm e} = 2\) соответственно. А значит число событий оценивается как \(\widehat{n} = (2^2 - 1) \times 2^5 + 2^2 \times 25 = 196\).

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

Описанный вариант счётчиков Морриса обладает следующими свойствами:

  • покрываемый диапазон значений равен

\(\begin{align*} {\bf N}_{max} = 2^{2^{\bf E} + {\bf M}} - \left(2^{2^{\bf E} - 1} + 2^{\bf M}\right); \end{align*}\)

Доказательство

Покрываемый диапазон получить несложно, подставив в формулу для \(\widehat{n}\) максимальные возможные значения \({\rm m} = 2^{\bf M} - 1\) и \({\rm e} = 2^{\bf E} - 1\):

\(\begin{align*} {\bf N}_{max} = \left(2^{2^{\bf E} - 1} - 1\right)2^{\bf M} + 2^{2^{\bf E} - 1}\left(2^{\bf M} - 1\right) = 2^{2^{\bf E} + {\bf M}} - \left(2^{2^{\bf E} - 1} + 2^{\bf M}\right) \end{align*}\)

  • новая оценка \(\widehat{n}\) также несмещённая: \({\sf E}\widehat{n}(C_n) = n\);

Доказательство

Аналогично доказательству утверждения для обычных счётчиков Морриса посчитаем условное мат.~ожидание \({\sf E}(C_n | C_{n - 1} = y)\). Причём сделаем это отдельно для \(y \equiv -1 \pmod{2^{\bf M}}\) (вероятность обновления изменится в случае успеха) и \(y \not\equiv -1 \pmod{2^{\bf M}}\).

\(\begin{align*} y \not\equiv -1 \pmod{2^{\bf M}} &\implies {\rm e}(y + 1) = {\rm e}(y), \quad {\rm m}(y + 1) = {\rm m}(y) + 1 \\ &\implies \widehat{n}(y + 1) = \widehat{n}(y) + 2^{{\rm e}(y)} \\ y \equiv -1 \pmod{2^{\bf M}} & \implies {\rm e}(y + 1) = {\rm e}(y) + 1,\\ &\phantom{\implies} \phantom{Z} {\rm m}(y) = 2^{\bf M} - 1, \quad {\rm m}(y + 1) = 0 \implies \\ \widehat{n}(y + 1) = \widehat{n}(y) &- 2^{{\rm e}(y)}\left(2^{\bf M} - 1\right) + 2^{{\rm e}(y) + {\bf M}} = \widehat{n}(y) + 2^{{\rm e}(y)} \end{align*}\)

В обоих случаях

\(\begin{align*} {\sf E}(2^{C_n} | C_{n-1} = y) &= \widehat{n}(y)\left(1 - 2^{-{\rm e}(y)}\right) + \left(\widehat{n}(y) + 2^{{\rm e}(y)}\right)2^{-{\rm e}(y)} = \widehat{n}(y) + 1. \end{align*}\)

  • коэффициент вариации (и относительная ошибка) становятся ещё меньше! Мы не знаем его точное значение, но имеется такая оценка (сравните её с аналогичной для классического счётчика Морриса):

\(\begin{align*} {\sf CV}\widehat{n}(C_n) \le 2^{-\frac{{\bf M} + 1}{2}}. \end{align*}.\)

Рис. 3: Чтение и обновление счётчика Морриса с ненулевой мантиссой

Алгоритмы взвешенных обновлений и распада тоже немного изменятся.

Аналогично подходу, описанному в разделе 4, чтобы эффективно выполнить взвешенное обновление, нужно понять, через сколько попыток обновления вероятность изменится. При отсутствии мантиссы вероятность меняется после каждого успешного обновления, теперь же после каждых \(2^{\bf M}\). А значит нам нужно распределение количества испытаний Бернулли (искомое число событий), среди которых ровно \(2^{\bf M}\) успешных. Такое распределение называется отрицательным биномиальным.

Замечание. Существует несколько определений отрицательного биномиального распределения. Будем придерживаться написанного в русскоязычной википедии, где сказано, что это распределение задаёт не общее число событий, а число неудач. Тогда чтобы получить число событий, нужно к случайной величине добавить количество успехов:

\(\begin{align*} n \sim \underbrace{ NegativeBinomial\left(2^{-{\rm e}(C)}, 2^{\bf M} - {\rm m}(C)\right)}_{\textit{неудач}} + \underbrace{\left(2^{\bf M} - {\rm m}(C)\right)}_{\textit{успехов}}. \end{align*}\)

Чтобы не генерировать отрицательное биномиальное распределение, можно загрубить алгоритм, всегда выбирая среднее этого распределения:

Чтобы выполнить распад, будем вычитать \(1\) из экспоненциальной части (иначе говоря, \(2^{\bf M}\) из значения счётчика). Тогда

\(\begin{align*} \widehat{n}(C - 2^{\bf M}) = (2^{{\rm e}(C) - 1} - 1)2^{\bf M} + 2^{{\rm e}(C) - 1}{\rm m}(C) = 1/2\widehat{n}(C) - 2^{{\bf M} - 1}. \end{align*}\)

Заметим, что при \({\bf M} > 0\) (а именно этот случай изучается в этом разделе) \(2^{{\bf M} - 1} \in \mathbb{N}\). Поэтому исправить оценку можно, вероятностно увеличив счётчик на \(2^{{\bf M} - 1}\):

7 Заключение

Счётчики Морриса — это очень круто! Пользуйтесь!

Последний раздел не содержит полезных на практике результатов, но...

8 Обобщённые вероятностные счётчики

В общем виде правило обновления счётчика определяется функцией вероятности \(F : C \mapsto [0, 1]\):

\(\begin{equation*} C_{n+1} = \left\{\begin{array}{ll} C_n + 1 & \textit{с вероятностью $F(C_n)$} \\ C_n & \textit{с вероятностью $1 - F(C_n)$.} \end{array}\right. \end{equation*}\)

В случае счётчиков Морриса \(F(C_n) = 2^{-C_n}\). При изучении вероятностных счётчиков мы попробовали взять линейную функцию вероятности: \(F(C_n) = 1 - \frac{C_n}{C_{max}}\) (\(C_{max}\) — некоторая константа, максимальное значение счётчика). Это привело к некоторым интересным результатам, которые будут кратко изложены в этом разделе.

Прежде чем представить эти результаты, напомним о двух математических сущностях.
Полный однородный симметрический многочлен степени \(n\) от \(m\) переменных \(x_1, \dots, x_m\) — это сумма всех возможных одночленов степени \(n\) от этих переменных с коэффициентами \(1\):

\(\begin{align*} \mathcal{H}_n(x_1, \dots x_m) = \sum_{\begin{array}{cc} & 0 \le i_j \le n \\ & i_1 + \dots + i_m = n \end{array}} x_1^{i_1} \cdots x_m^{i_m}. \end{align*}\)

Другая конструкция, которая нам понадобится, — число Стирлинга второго рода. Один из способов определить это число — комбинаторный: число Стирлинга второго рода \(\genfrac\{\}{0pt}{}{n}{m}\) — количество разбиений \(n\)-элементного множества на \(m\) непустых подмножеств. Числа Стирлинга связаны с полными симметрическим многочленами:

\(\begin{align*} \genfrac\{\}{0pt}{}{n+m}{m} = \mathcal{H}_m(1, 2, \dots, m). \end{align*}\)

С помощью \(\mathcal{H}\) можно записать в общем виде вероятность того, что после \(n\) попыток обновления значение счётчика равно \(m\):

\(\begin{align*} {\sf P}(C_n = m) = \left[\prod_{k=0}^{m-1} F(k) \right] \mathcal{H}_{n-m}(1-F(1), \dots 1-F(m)). \end{align*}\)

Эту формулу легко доказать по индукции, но также она несложно следует из простых комбинаторных рассуждений: фактически в ней записано, что для того, чтобы получить значение \(m\), нужны \(m\) успешных обновлений: с \(0\) до \(1\), с \(1\) до \(2\) и т.д., — за это отвечает множитель \(\prod_{k=0}^{m-1} F(k)\), и \(n - m\) неудачных, которые разбиваются на \(m\) групп: \(i_1\) неудачных обновлений с \(1\) до \(2\), \(i_2\) с \(2\) до \(3\) и т.д., что выражено \(\mathcal{H}_{n-m}\).

Наконец, при использовании линейной функции вероятности \(F(C) = 1 - \frac{C}{C_{max}}\) вероятность принимает вид

\(\begin{equation*} {\sf P}(C_n = m) = \genfrac\{\}{0pt}{}{n}{m}\frac{C_{max}!}{(C_{max} - m)!C_{max}^n}. \end{equation*}\)

Это и есть анонсированный выше интересный результат. Мы заметили число Стирлинга в значении вероятности достаточно случайно и до сих пор не знаем, можно ли обосновать его присутствие комбинаторынми рассуждениями (опираясь, на его комбинаторное определение). Другой вопрос — можно красиво записать аналогичную вероятность для счётчиков Морриса.

Математическое ожидание и дисперсия \(C_n\) (доказательства опускаем, но их несложно получить, используя формулу для \({\sf P}\) и свойства чисел Стирлинга).

\(\begin{align*} {\sf E}C_n &= C_{max}\left(1 - \left(1 - \frac{1}{C_{max}}\right)^n\right) \\ {\sf D}C_n &= C_{max}^2\left(\frac{1}{C_{max}}\left(1 - \frac{1}{C_{max}}\right)^n + \left(1 - \frac{1}{C_{max}}\right)\left(1 - \frac{2}{C_{max}}\right)^n - \left(1 - \frac{1}{C_{max}}\right)^{2n}\right). \end{align*}\)

Оценить число событий можно по методу моментов:

\(\begin{equation*} \widehat{n}_{MM} := \frac{\ln \left(1 - \frac{C_n}{C_{max}}\right)}{\ln \left(1 - \frac{1}{C_{max}}\right)} \end{equation*}\)

или аналогично счётчикам Морриса, учитывая, что \(1 + 1/2 + \dots + 1/n \sim \ln n\):

\(\begin{equation*} \widehat{n} := C_{max}\ln \left(\frac{1}{1 - \frac{C_n}{C_{max}}}\right). \end{equation*}\)

Список литературы

[1] Morris, R.Counting large numbers of events in small registersCommunications of the ACM, 1978 21(10), 840-842.

[2] http://gregorygundersen.com/blog/2019/11/11/morris-algorithm/ − хороший обзор счётчиков Морриса на английском языке

[3] https://habr.com/ru/company/qrator/blog/334354/ − наша статья про EMA-счётчики

[4] https://habr.com/ru/post/208268/ − сторонний материал про счётчики Морриса

Ознакомьтесь со всеми функциями
в 7-дневной пробной версии

Наши специалисты готовы оказать вам поддержку

Будьте в курсе наших новостей и продуктов!

Подпишитесь на ежемесячный обзор самых популярных идей Интернета от CURATOR!

E-mail *

Читайте также

Curator
Ценность партнерских программ Qrator Labs
В чем заключается ценность участия в одной из партнерских программ Qrator Labs? Мы твердо верим — работая вместе, можно добиться лучшего результата, нежели по отдельности. Это основная причина, по которой мы годами прикладывали усилия к построению осмысленных партнерских отношений с самыми разнообразными компаниями. Но на верхнем уровне все наши партнеры делятся на два типа. Первые хотят предоставить собственному потребителю первоклассную технологию защиты от DDoS-атак, разрабатываемую в Qrator Labs, вместе со всеми экосистемными продуктами и услугами. Вторые заинтересованы в том, чтобы предоставить продукт собственной разработки клиентам Qrator Labs, интегрировавшись в нашу сеть фильтрации.
14 апреля 2021
Curator
Десять (с плюсом) лет в лабе
В начале 2021 года Qrator Labs отмечает собственный десятилетний юбилей. 19 января наша компания пройдет через формальную отметку 10 лет деятельности, войдя во вторую декаду существования. Хотя, на самом деле, все началось несколько ранее - когда в возрасте десяти лет Александр первый раз увидел Robotron K 1820 - в 2008 году, когда Александр Лямин - основатель и директор Qrator Labs, пришел с идеей к начальникам в МГУ, где на тот момент времени он работал сетевым инженером, о создании исследовательского проекта по нейтрализации DDoS-атак. Сеть МГУ тогда была одной из крупнейших в стране и, как мы знаем сейчас, это было лучшее место для того, чтобы посеять зерно будущей технологии. Тогда администрация МГУ согласилась, и Александр перенёс собственное оборудование в университет, одновременно с этим собирая команду. Через два года, летом 2010, стало ясно, что проект успешен. Он принял на себя DDoS-атаку, превышающую емкость вышестоящего поставщика МГУ. И 22 июня боссы выдвинули ультиматум г-ну Лямину - закрываться или уходить. Александр Лямин решил инкорпорироваться на свои собственные средства, что буквально значило за свои строить инфраструктуру с нуля. При этом изначальная архитектура сети должна быть распределенной вместо концентрированной, так как ресурсы последней бы точно не справились со столь специфической задачей. В сентябре 2010 года первая площадка была введена в эксплуатацию.
14 января 2021
Curator
Linux Switchdev по-мелланоксовски
Это транскрипция выступления прозвучавшего на Yandex NextHop 2020 — видео в конце страницы Приветствую. Меня зовут Александр Зубков, я хочу рассказать про Linux Switchdev — что это такое и как мы с ним живем в Qrator Labs.
09 ноября 2020
Ваша подписка успешно активирована
На главную