Русский
Русский
English
Статистика
Реклама

Серверная оптимизация

Перевод Как эффективно разделить пинг

15.03.2021 12:08:42 | Автор: admin


Информации об общей длительности обмена пакетами может оказаться недостаточно для целей подробного мониторинга и отладки сети. В этом случае будет кстати иметь возможность детального анализа задержки в каждом направлении. К одним из основным недостатков утилиты ping следует отнести отсутствие информации о времени следования пакета к хосту, и отдельно времени следования пакета от хоста. В статье мы рассмотрим способ точного замера времени передачи пакета как к хосту, так и обратно, попутно решив связанные с этим процессом сложности.

Ping является одной из основополагающих сетевых утилит. Эта утилита проста, легко поддерживается и, как правило, присутствует во всех сетевых стеках. С ее помощью мы узнаем о доступности хоста, а также выясняем приблизительное время задержки между исходной системой запроса и целью.

$ ping 8.8.8.8PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.64 bytes from 8.8.8.8: icmp_seq=1 ttl=120 time=3.29 ms64 bytes from 8.8.8.8: icmp_seq=2 ttl=120 time=2.78 ms64 bytes from 8.8.8.8: icmp_seq=3 ttl=120 time=3.09 ms64 bytes from 8.8.8.8: icmp_seq=4 ttl=120 time=3.11 ms^C--- 8.8.8.8 ping statistics ---4 packets transmitted, 4 received, 0% packet loss, time 3003msrtt min/avg/max/mdev = 2.789/3.073/3.298/0.186 ms$ 

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



Принцип работы


Базовый режим работы ping подразумевает отправку к цели сообщения ICMP Type 8, в ответ на которое хост ожидает возвращения пакета ICMP Type 0. При этом измеряется время, прошедшее с момента отправки до момента получения пакета:



Есть общая тенденция считать, что при делении значения задержки на два мы получаем время доставки данных в одном направлении (такое предположение часто используется в отношении netcode). И хотя в идеале так оно и должно быть, на деле интернет полон асимметричной маршрутизации, и путь пинга может выглядеть, к примеру, так:



В этом примере на передачу пакета уходит 63мс при том, что его возвращение занимает всего 35мс. Обычный показатель пинга просто представил бы общую задержку в 109мс. Но если делать расчет времени доставки в одном направлении, исходя из значения 109мс, то мы получим приличную долю ошибки, которая может варьироваться вплоть до 10мс.

Но как же тогда правильно разделить такой пинг на этапы отправки и получения?
Понимание пришло ко мне после просмотра выступления apenwarr (pdf), где он рассказывал о Google Fibre WiFi. В этом выступлении apenwarr упоминает инструмент под названием isoping.

Isoping это программа, которая определяет разницу в скорости передачи и получения пакетов.

# ./isoping test.benjojo.co.ukconnecting to ::ffff:185.230.223.69...                48.8 ms rx  (min=48.8)  loss: 0/2 tx  0/1 rxtime paradox: backsliding start by -396 usec  48.8 ms tx    48.6 ms rx  (min=48.6)  loss: 0/3 tx  0/2 rx  48.7 ms tx    49.0 ms rx  (min=48.6)  loss: 0/4 tx  0/3 rx  48.6 ms tx    48.9 ms rx  (min=48.5)  loss: 0/5 tx  0/4 rx  48.5 ms tx    49.0 ms rx  (min=48.5)  loss: 0/6 tx  0/5 rx  48.5 ms tx    48.9 ms rx  (min=48.5)  loss: 0/7 tx  0/6 rx^C# ping test.benjojo.co.ukPING test.benjojo.co.uk (185.230.223.69) 56(84) bytes of data.64 bytes from 185.145.203.147: icmp_seq=1 ttl=54 time=96.6 ms^C# # 48 + 48 = 96

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

Она производит вычисление на основе минимального наблюдаемого RTT (времени приема-передачи), а не фактического. Минимальное RTT это наименьшая доступная точность. Однако для обнаружения причин резких скачков пинга wifi до 500мс или увеличения задержки при загрузке файла этот инструмент очень эффективен.

Так что увы, Isoping отлично подходит для мониторинга джиттера (проблемы, которую Google Fiber решают с помощью WiFi-приставок) или обнаружения направленной потери пакетов, но не для нашей задачи определения систематической асимметрии в маршрутизации.

Так как же разделить пинг?



Как я уже говорил, ping ICMP измеряет время между отправкой и получением ответа. При отсутствии дополнительных метаданных невозможно выявить какую-либо асимметрию во времени передачи между RX и TX.



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

К нашему удобству, в ICMP уже есть такая возможность в виде Timestamp Requests (Запросы с временными метками).



В этом разложении Wireshark присутствуют Originate timestamp, указывающий время отправки пакета хостом, а также временные метки получения и передачи (обычно идентичные), указывающие время передачи встречной стороной.

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

$ sudo ./icmp-timestap-pinger TS reddit.com (151.101.65.140): Forward: -1ms Back: 3ms RTT(2ms)TS klir.benjojo.co.uk (5.231.83.4): Forward: 7ms Back: 5ms RTT(12ms)TS airmail.benjojo.co.uk (23.132.96.179): Forward: 66ms Back: 65ms RTT(131ms)TS syd-au-ping.vultr.com (108.61.212.117): Forward: 147ms Back: 153ms RTT(300ms)

Однако здесь есть проблема, поскольку нет гарантии, что на хосте, куда мы отправляем ICMP Timestamp Requests, установлено точное время, откалиброванное в соответствии с временем на машине отправки.

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

Можно обеспечить, чтобы на всех участвующих в мониторинге хостах были установлены NTPd/Chrony. Опять же, здесь возникнет другой вопрос, а именно Как обеспечить, чтобы наш IP-путь к этим NTP-серверам не подвергался той же асимметрии, которую мы хотим измерить. NTP и Chrony не могут сами предотвратить отклонение показателей из-за асимметрии задержки. В Chrony есть опция Estimation of asymmetric jitter, но она не сможет обнаружить систематическую асимметрию.

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

Какие NTP-сервера лучше?


Чтобы ответить на этот вопрос, я решил выполнить тест на популярных и общедоступных серверах:
  • Google
  • Facebook
  • Cloudflare
  • Apple

Для тестирования я использовал GPS-модуль uBlox 6M, который выступил в качестве генератора импульсов (PPS). Его я подключил к GPIO Raspberri Pi 4 для генерации прерываний, реализовав обработку импульсов с помощью LinuxPPS.

Можно предположить, что PPS, генерируемый uBlox, практически идеален, поскольку предоставляется GNSS (спутниковой системой навигации), то есть является наиболее точным из легко доступных. Производители uBox заявляют, что точность его импульса составляет примерно 100нс.

Это позволяет нам регистрировать момент возникновения импульса и сравнивать его близость с системным временем нашего NTP-сервера:

root@tempest:~# ppstest /dev/pps0 trying PPS source "/dev/pps0"found PPS source "/dev/pps0"ok, found 1 source(s), now start fetching data...source 0 - assert 1604603306.999999790, sequence: 1403151source 0 - assert 1604603307.999999554, sequence: 1403152source 0 - assert 1604603309.000000373, sequence: 1403153source 0 - assert 1604603310.000000803, sequence: 1403154source 0 - assert 1604603310.999999807, sequence: 1403155source 0 - assert 1604603311.999999830, sequence: 1403156

Чем дальше оказываются временные метки от точной секунды, тем менее точен NTP-источник (скорее всего из-за асимметрии или других сетевых факторов).



По VDSL-линии, предоставляемой оператором IDNet в Великобритании, видно, что служба времени Cloudflare дает наименьшую ошибку в сравнении с временем, откалиброванным по GNSS. Но здесь нужно учесть еще один нюанс, а именно то, что в Cloudflare маршрутизация NTP-траффика внутренней сети реализуется с помощью anycast, а в Apple для направления системы к ближайшему кластеру используется DNS.

Хорошо в этом то, что все кластеры Apple достижимы независимо (Сингапур, Сан-Паулу, Гон-Конг, Сан-Хосе, Лос-Анжелес, Нью-Йорк, Майами, Атланта, Сидней, Франкфурт, Лондон, Амстердам, Токио, Стокгольм, Сеул, Тайбэй).

И поскольку это позволяет гарантировать фиксированную привязку к NTP-кластеру, я решил использовать в качестве эталона серверы Apple несмотря на то, что их отклонение по времени было больше (в моем тесте для одной локации).

Кластеры Facebook и Google оказались несовместимы друг с другом из-за различий в реализации размазывания дополнительных секунд.

Таблицы времени


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



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

Помимо этого, также можно увидеть, какие пакеты были утеряны и при движении в каком направлении.

Вот ряд примеров:



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

В дополнении к этому следующая строчка демонстрирует достаточно высокую асимметрию задержки:

 [xxx.xxx.xxx.xxx] RX: 15.076895ms TX: 5.450551ms [Loss RX: 0/32 | Loss TX 0/32]

Здесь отправка пакетов происходит на 10мс дольше, чем их получение. Вероятно, это проявление определенной формы чередования DSL.

В еще одном эксперименте я настроил sping между моей квартирой и VM в Китае. Здесь видны печально известные ежедневные пиковые потери пакетов:



Интересно отметить, что основная потеря происходит при передаче из Великобритании в Китай и лишь небольшой период потерь приходится на обратное направление.

Поскольку этот инструмент очень полезен для отладки сетевых задержек и для определения возможности использования NTP с целью точного хронометража, я оформил его в программу, которую назвал sping: https://github.com/benjojo/sping

Usage of sping:  -clock-is-perfect    Enable userspace calibration against Apple's GPS NTP servers (default true)  -debug.showslots    Show incoming packet latency slots  -debug.showstats    Show per ping info, and timestamps  -listenAddr string    Listening address (default "[::]:6924")  -peers string    List of IPs that are peers  -pps.debug    Enable debug output for PPS inputs  -pps.path string    what PPS device to use (default "/dev/pps0")  -udp.pps int    max inbound PPS that can be processed at once (default 100)  -use.pps    If to use a PPS device instead of system clock  -web.listen-address string    Address on which to expose metrics and web interface (default "[::]:9523")  -web.telemetry-path string    Path under which to expose metrics. (default "/metrics")

Базово эта программа может полагаться на системное время. Если же в среде настройка времени невозможна (например, в контейнерах, OpenVZ и т.д.), то она может выполнять собственную калибровку в отношении NTP-серверов Apple, которые, как я выяснил, размещены глобально наиболее согласованным образом.

С целью повышения точности sping также можно использовать с устройством генерации PPS.
Для обмена данными пинга между пирами программа использует UDP, а для обмена рукопожатиями TCP. В IANA для этого был назначен порт 6924.

Подробнее..

Перевод Сравнение производительности ASP.NET Core-проектов на Linux и Windows в службе приложений Azure

08.05.2021 14:13:54 | Автор: admin
Что быстрее ASP.NET Core-приложение, развёрнутое в Docker-контейнере на Linux, или такая же программа, но запущенная на Windows-сервере, учитывая то, что всё это работает в службе приложений Azure? Какая из этих конфигураций предлагает более высокий уровень производительности, и о каком уровне производительности можно говорить?



Недавно меня заинтересовали эти вопросы, после чего я решил сам всё проверить, сделав следующее:

  • Подготовил простое ASP.NET Core-приложение, используя NET Core 2.0 и C#.
  • Развернул один экземпляр этого приложения в службе Standard S1 на Windows-хосте, расположенном в регионе Western Europe.
  • Развернул ещё один экземпляр этого приложения в службе Standard S1 с использованием Linux-хоста (регион Western Europe) и Docker-контейнера.
  • Для создания нагрузки на серверы использовал Apache Benchmark, запросы отправлялись из Варшавы (Польша) с клиентской системы, работающей под управлением Ubuntu 17.04 и подключённой к интернету по Wi-Fi.
  • Повторил испытания, воспользовавшись средством Visual Studio Web Performance Test. Запросы к исследуемым серверам выполнялись из того же города, но в данном случае роль клиента выполнял компьютер, на котором установлена Windows 10, подключённый к интернету через проводную сеть.
  • Проанализировал данные, полученные в ходе тестирования, и сравнил результаты.

В обоих случаях приложение собрано с использованием инструмента командной строки dotnet в конфигурации Release. Хостилось приложение с использованием кросс-платформенного сервера Kestrel и было размещено за прокси-сервером, используемым службами Azure. В распоряжении каждого экземпляра приложения были ресурсы, обеспечиваемые планом обслуживания Standard S1, то есть отдельная виртуальная машина. В ходе выполнения тестов я, кроме того, сравнил производительность ASP.NET Core-приложения, работающего в Docker-контейнере, с производительностью приложений, основанных на других стеках технологий, которые мне доводилось исследовать в последнее время (Go, Python 3.6.2, PyPy 3). В сервере Kestrel используется libuv поэтому мне интересно было сравнить его с uvloop, учитывая то, что последний является обёрткой для libuv и asyncio (это встроенный инструмент Python для создания конкурентного кода). Я думаю, что многие NET-разработчики гордятся скоростью Kestrel и работой, проведённой инженерами Microsoft, но при этом забывают о том, что им стоило бы испытывать чувство благодарности и к libuv С-библиотеке для организации асинхронного ввода-вывода, которая появилась до Kestrel и используется, кроме того, в Node.js и в других подобных проектах. И, кроме того, стоит помнить о том, что, когда перед ASP.NET Core-приложениями находится IIS, нужно принимать во внимание некоторые дополнительные соображения.

Подготовка веб-приложения


Приложение основано на шаблоне веб-проекта, созданного с помощью dotnet. Я специально старался как можно меньше его усложнять. В нём имеется один обработчик, возвращающий ответы двух типов:

  • При получении запроса без параметров сообщение Hello World с отметкой времени.
  • При получении запроса со строковым параметром n, представляющим собой число, находящееся в диапазоне от 1 до 100 ответ с телом размером n Кб.

app.Run(async (context) =>{var request = context.Request;var s = request.Query["s"];if (string.IsNullOrEmpty(s)) {// возврат простого Hello Worldvar now = DateTime.UtcNow;await context.Response.WriteAsync($"Hello World, from ASP.NET Core and Net Core 2.0! {now.ToString("yyyy-MM-dd HH:mm:ss.FFF")}");return;}// {...}});

Развёртывание приложения на Windows-машине


Для развёртывания проекта на Windows-машине я быстро создал проект в VSTS (Visual Studio Team Services), настроил службы с использованием шаблонов ARM, собрал и развернул приложение с применением задач VSTS.


Настройка проекта


Работа с Windows-проектом в Microsoft Azure

В этом GitHub-репозитории вы можете найти код приложения и ARM-шаблоны.

Развёртывание приложения на Linux-машине с использованием Docker-контейнеров


Образ Docker был подготовлен и опубликован с использованием того же подхода, о котором я уже писал, рассказывая о запуске образов Docker в Azure. Так как я уже об этом рассказывал, повторяться тут я не буду. Единственное, на что я хочу обратить ваше внимание это то, что в одной группе ресурсов Azure нельзя смешивать планы служб приложений, рассчитанные на Linux и Windows. Поэтому для каждого из вариантов приложения я создал собственную группу ресурсов.


Работа с Linux-проектом в Microsoft Azure

Код приложения и файлы для создания образов Docker можно найти в этом репозитории.

Тестирование приложений с использованием Apache Benchmark


Мне нравится утилита Apache Benchmark (ab). Ей удобно пользоваться и она выдаёт результаты, применимые при практической оценке производительности систем, такие, как количество запросов в секунду (Requests Per Second, RPS), время ответа на разных перцентилях (например сведения о том, что 95% запросов обрабатывается в пределах n мс, а 5% в пределах m мс, и так далее). Эта утилита идеально подходит для исследования производительности отдельных методов. Я выполнил несколько групп тестов, каждую в разное время дня. План испытаний выглядел так:
Сценарий Конфигурация
Hello World 5000 запросов, 150 одновременных пользователей
Ответ с телом в 1 Кб 5000 запросов, 150 одновременных пользователей
Ответ с телом в 10 Кб 2000 запросов, 150 одновременных пользователей
Ответ с телом в 100 Кб 2000 запросов, 150 одновременных пользователей

# пример командыab -n 5000 -c 150 -l http://linuxaspcorehelloworld-dev-westeurope-webapp.azurewebsites.net/

Выходные данные ab выглядят примерно так:

This is ApacheBench, Version 2.3 <$Revision: 1757674 $>Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/Licensed to The Apache Software Foundation, http://www.apache.org/Benchmarking linuxaspcorehelloworld-dev-westeurope-webapp.azurewebsites.net (be patient)Server Software:    KestrelServer Hostname:    linuxaspcorehelloworld-dev-westeurope-webapp.azurewebsites.netServer Port:      80Document Path:     /Document Length:    72 bytesConcurrency Level:   150Time taken for tests:  22.369 secondsComplete requests:   5000Failed requests:    0Keep-Alive requests:  0Total transferred:   1699416 bytesHTML transferred:    359416 bytesRequests per second:  223.53 [#/sec] (mean)Time per request:    671.065 [ms] (mean)Time per request:    4.474 [ms] (mean, across all concurrent requests)Transfer rate:     74.19 [Kbytes/sec] receivedConnection Times (ms)min mean[+/-sd] median  maxConnect:    40 489 289.9  425  3813Processing:  42 170 227.6  109  3303Waiting:    41 153 152.9  105  2035Total:    106 659 359.2  553  4175Percentage of the requests served within a certain time (ms)50%  55366%  65075%  75080%  78690%  94895%  103698%  128299%  1918100%  4175 (longest request)

И, наконец, я собрал результаты воедино с использованием Python-скрипта, после чего посчитал средние показатели по всем тестам и построил графики двух видов:

  • Количество запросов в секунду (Requests per seconds, RPS), обработанных сервером.
  • 95-й перцентиль времени ответа, другими словами показатель, отвечающий на вопрос о том, в пределах какого количества миллисекунд будет дан ответ на 95% запросов.

Анализ результатов, полученных с помощью Apache Benchmark


В ходе выполнения тестовых сценариев Hello World и Ответ с телом в 1 Кб на серверы было отправлено около 250 тысяч запросов. Их количество для сценариев, в которых применялись ответы с телом размером 10 Кб и 100 Кб, находилось в районе 110 70 тысяч запросов. Эти показатели не выражены в точных цифрах, так как иногда инфраструктура Azure закрывает соединения (connection reset by peer), но количество проанализированных запросов, всё равно, является достаточно большим. Не обращайте особого внимания на абсолютные значения, приводимые ниже: они имеют смысл лишь в плане сравнения друг с другом, так как они зависят и от клиента, и от сервера. Результаты, показанные в следующей таблице, получены с использованием клиента, подключённого к интернету по Wi-Fi-сети.
Хост Сценарий RPS (среднее значение) 95% запросов выполнено в пределах мс
Linux Hello World 232,61 1103,64
Linux Ответ с телом в 1 Кб 228,79 1129,93
Linux Ответ с телом в 10 Кб 117,92 1871,29
Linux Ответ с телом в 100 Кб 17,84 14321,78
Windows Hello World 174,62 1356,8
Windows Ответ с телом в 1 Кб 171,59 1367,23
Windows Ответ с телом в 10 Кб 108,08 2506,95
Windows Ответ с телом в 100 Кб 17,37 16440,27

Эти результаты позволяют сделать вывод о том, что, если тело ответа невелико, приложение, работающее в Docker-контейнере на Linux, гораздо быстрее обрабатывает HTTP-запросы, чем его версия, работающая в среде Windows. Разница между разными вариантами запуска приложения уменьшается по мере роста тела ответа, хотя, всё равно, Linux-вариант оказывается быстрее Windows-варианта. Такой результат может показаться удивительным, так как Windows-сервер, работающий в службе приложений Azure, представляет собой более зрелое решение, нежели Linux-сервер, работающий там же. С другой стороны, виртуализация Docker, в сравнении с другими технологиями виртуализации приложений, не отличается особой требовательностью к системным ресурсам. Возможно, имеются и другие отличия в конфигурациях, позволяющие Linux-хосту работать эффективнее, что особенно заметно при работе с ответами, тела которых невелики.
Сценарий Linux, прирост RPS в сравнении с Windows
Hello World +33,21%
Ответ с телом в 1 Кб +33,33%
Ответ с телом в 10 Кб +9,1%
Ответ с телом в 100 Кб +2,7%

Вот диаграммы, иллюстрирующие вышеприведённые данные.


Запросов в секунду, средний показатель (больше лучше)


Время, в течение которого обрабатываются 95% запросов (меньше лучше)


Время, в течение которого обрабатываются 95% запросов (меньше лучше)

Тестирование приложений с использованием инструментов Visual Studio Web Performance


Вышеописанные испытания производительности были повторены с использованием инструментов Visual Studio Ultimate Web Performance. Клиентская система, в географическом смысле, располагалась там же, где и раньше, но в этот раз она была подключена к интернету по проводной сети. Вот исходный код тестов. В данном случае использовались следующие настройки:

  • Тесты выполнялись по 5 минут.
  • В начале количество пользователей равнялось 50.
  • Каждые 10 секунд количество пользователей увеличивалось на 10.
  • Максимальным количеством пользователей было 150.


Тестирование серверов с помощью Visual Studio Web Performance (оригинал)

Анализ результатов, полученных с помощью Visual Studio Web Performance


Результаты тестов, проведённых с помощью Visual Studio Web Performance, отличаются от тех, что были проведены с помощью Apache Benchmark, но при этом Linux-система показала себя даже лучше, чем прежде. Различия в результатах испытаний можно объяснить следующими фактами:

  • Инструменты VS Web Performance, вероятно, по-другому работают с соединениями.
  • Для выполнения тестов использовались разные клиенты, по-разному подключённые к интернету.

Но, всё равно, допустимо напрямую сравнивать результаты испытаний только тогда, когда они выполнены с использованием одного и того же клиента, с применением одних и тех же инструментов и настроек.
Хост Сценарий RPS (среднее значение) 95% запросов выполнено в пределах мс
Linux Hello World 649 340
Linux Ответ с телом в 1 Кб 622 380
Linux Ответ с телом в 10 Кб 568 370
Linux Ответ с телом в 100 Кб 145 1220
Windows Hello World 391 400
Windows Ответ с телом в 1 Кб 387 420
Windows Ответ с телом в 10 Кб 333 510
Windows Ответ с телом в 100 Кб 108 1560

Вот таблица со сравнением Linux- и Windows-вариантов приложения.
Сценарий Linux, прирост RPS в сравнении с Windows
Hello World +65,98%
Ответ с телом в 1 Кб +60,72%
Ответ с телом в 10 Кб +70,57%
Ответ с телом в 100 Кб +34,26%

Вот визуализация этих данных.


Запросов в секунду, средний показатель (больше лучше)


Время, в течение которого обрабатываются 95% запросов (меньше лучше)

Сравнение с другими стеками технологий в Docker


Я могу провести сравнение Linux+Docker-варианта исследуемого приложения с приложениями, при создании которых использовались другие технологии, испытанные мной за последние дни, лишь используя сценарий Hello, World. Но при этом не могу не отметить, что даже при таком походе производительность Windows-варианта выглядит слишком низкой. Думаю, что стандартная конфигурация Kestrel (например количество потоков) не оптимизирована для планов Standard S1. Например вот средние значения RPS, полученные для других стеков технологий, испытания которых проводились с использованием тех же настроек.
Стек технологий Сценарий Hello World, RPS
Go 1.9.1 net/http ~1000, с пиками в ~1100
Python 3.6.1 uvloop, httptools ~1000, с пиками в ~1200
Python 3.6.1 Sanic, uvloop ~600, с пиками в ~650
PyPy 3, Gunicorn, Gevent, Flask ~600, с пиками в ~650

Эти результаты не снижают ценности ранее выполненных испытаний, в ходе которых одно и то же ASP.NET Core-приложение исследовалось в средах Windows и Linux.

Итоги


Развёртывание проектов в службе приложений Azure с использованием Linux и Docker не ухудшает производительности приложений, что идёт вразрез с тем, чего многие могли бы ожидать, учитывая то, что Windows-хостинг этой платформы представляет собой более зрелое решение. Применение Linux в Azure, на самом деле, выгоднее применения Windows, особенно в тех случаях, когда речь идёт об обработке запросов, предусматривающих отправку ответов, тела которых имеют небольшие размеры.

Чем вы пользуетесь на серверах Linux или Windows?

Подробнее..

Перевод Сравнение производительности ASP.NET Core-проектов на Linux и Windows в службе приложений Azure. Продолжение

09.05.2021 14:14:20 | Автор: admin
В моём предыдущем материале речь шла о сравнении производительности ASP.NET Core-приложений, запускаемых в Windows и в среде Linux + Docker, работающих в службе приложений Azure. Эта тема интересна многим поэтому я решил написать продолжение.



Я снова провёл испытания, используя подход, отличающийся от прежнего лучшей воспроизводимостью, такой, который даёт более надёжные результаты. Теперь я генерирую веб-нагрузку на серверы с помощью облачных инструментов Azure Cloud Agents, применяя Visual Studio и VSTS. И, более того, в то время как ранее я выполнял тесты с использованием HTTP, теперь тестирование проводилось с применением HTTPS.

Выполнение тестов в облачной среде


Благодаря отличной работе, проведённой Microsoft, запуск тестов в облаке это очень просто. Делается это с помощью инструментов Visual Studio Web Performance, с использованием учётной записи VSTS. Я провёл по две серии нагрузочных тестов для каждого из следующих сценариев:

  • Ответ, в теле которого содержится текст Hello World и отметка времени.
  • Ответ с телом в 1 Кб.
  • Ответ с телом в 10 Кб.
  • Ответ с телом в 50 Кб.
  • Ответ с телом в 100 Кб.

Вот как были настроены тесты:

  • Тесты выполнялись по 5 минут.
  • В начале количество пользователей равнялось 50.
  • Каждые 10 секунд количество пользователей увеличивалось на 10.
  • Максимальным количеством пользователей было 150.
  • Запросы выполнялись из того же региона (Western Europe), где были развёрнуты исследуемые приложения.


Результаты тестов (оригинал)

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


Пример выходных данных теста (оригинал)

Я использовал те же тесты, которые применялись в прошлый раз (найти соответствующий код можно здесь).

Что же у меня получилось теперь?

Анализ результатов


Полученные в этот раз результаты согласуются с теми, которые были получены в прошлый раз, при использовании клиентской системы, подключённой к интернету по проводной сети. А именно, ASP.NET Core-приложение, развёрнутое в Linux с применением Docker-контейнера, оказывается гораздо быстрее, чем оно же, развёрнутое на Windows-хосте (оба варианта работают в рамках соответствующего плана служб приложений). Результаты новых тестов даже сильнее, чем результаты прежних, указывают на превосходство Linux-варианта, особенно при работе с запросами, предусматривающими возврат ответов с более объёмными телами.

Вот сводные результаты испытаний, отражающие количество запросов, обработанных в секунду (RPS).
Сценарий Linux Windows Linux +%
Hello World 646,6 432,85 +49,38%
Ответ с телом в 1 Кб 623,05 431,95 +44,24%
Ответ с телом в 10 Кб 573,6 361,9 +58,5%
Ответ с телом в 50 Кб 415,5 210,05 +97,81%
Ответ с телом в 100 Кб 294,35 143,25 +105,48%

Вот среднее время ответа (мс).
Сценарий Linux Windows Linux +%
Hello World 168,85 242,2 -30,28%
Ответ с телом в 1 Кб 171,25 249,8 -31,45%
Ответ с телом в 10 Кб 184,2 292,7 -37,07%
Ответ с телом в 50 Кб 233,3 542,85 -57,02%
Ответ с телом в 100 Кб 365,05 817,35 -55,34%


Запросов в секунду, средний показатель (больше лучше)


Время, в течение которого обрабатываются 95% запросов (меньше лучше)

Вот .xlsx-файл с результатами тестирования, а вот аналогичный .ods-файл.

В чём Linux показывает себя хуже Windows (и так ли это на самом деле)?


Почти все нагрузочные тесты на Linux-хосте приводили к превышению допустимой нагрузки на процессор (Processor\% Processor Time) с выдачей соответствующих предупреждений. При этом ни один из тестов, проводимых на Windows-хосте, не привёл к появлению подобных предупреждений. Я не вполне уверен в том, что правильно понял документацию по этому показателю производительности, по умолчанию включаемому во все новые нагрузочные тесты, создаваемые в Visual Studio. Если кто-то в этом разбирается буду благодарен за пояснения.

Странные графики, касающиеся производительности и пропускной способности Windows-системы


Я обратил внимание на странную закономерность в графиках VSTS, отражающих производительность и пропускную способность систем в ходе нагрузочного тестирования. В случае с Linux-системами эти графики представляют собой довольно-таки плавные линии. А вот Windows-графики напоминают нечто вроде пил. Вот соответствующие графики для сценария, в котором в теле ответа содержится 10 Кб данных.


Графики производительности и пропускной способности для Linux


Графики производительности и пропускной способности для Windows

Другие графики можно найти здесь. Вот графики (Linux и Windows) для сценария, где в теле ответа содержится 50 Кб данных.

Итоги


В свете моих предыдущих испытаний учитывая полученные здесь результаты, могу сказать, что, с точки зрения производительности, в Azure оправдано использование конфигурации Linux + Docker.

Заключительные замечания


Мне нет никакой выгоды от того, чтобы представить Linux в более выгодном свете, чем Windows. Я опубликовал все исходные коды моих тестов и инструкции, касающиеся воспроизведения тестового окружения. Если кто-то подозревает, что я где-то что-то подкрутил, или сделал что-то неправильно пусть повторит мои тесты и укажет на мою ошибку. И будет неплохо, если кто-нибудь проведёт проверку моих результатов.

Я решил провести эти тесты производительности и опубликовать результаты лишь из-за того, что планирую создать веб-сервис для приложения, написанного мной на Python. Мне было интересно узнать о том, удастся ли мне получить удовлетворительные результаты в среде Azure с использованием Linux-хоста, на котором работает Docker. Для разработки моего сервиса я планирую использовать PyPy 3, Gunicorn, Gevent и Flask. И я полагаю, что проект, основанный на этом стеке технологий, будет работать быстрее аналогичного ASP.NET Core-проекта, использующего сервер Kestrel. Но это уже совсем другая история, и чтобы говорить об этом с уверенностью надо провести соответствующие тесты.

Какими стеками технологий вы пользуетесь для разработки веб-сервисов?

Подробнее..

Recovery mode Сборка ядра Linux 5.12.10 c LLVM 12 Clang и LTO оптимизацией

14.06.2021 18:13:31 | Автор: admin

Технический прогресс не стоит на месте, появляются новые компьютерные архитектуры, компиляторы становятся умнее и генерируют более быстрый машинный код. Современные задачи требуют все более креативного и эффективного решения. В данной статье пойдет речь, на мой взгляд, про один из самых прогрессивных тулчейнов LLVM и компиляторы на его основе Clang и Clang++, для языков программирования С и C++ соответственно. Хоть GCC конкурент Clang, может агрессивнее оптимизировать циклы и рекурсию, Clang дает на выходе более корректный машинный код, и чаще всего не ломает поведение приложений. Плюс оптимизация программ не заканчивается только оптимизацией циклов, поэтому Clang местами дает лучшую производительность. В GCC же за счет переоптимизации вероятность получить unpredictable behavior значительно выше. По этой причине на многих ресурсах не рекомендуют использовать -O3 и LTO(Link Time Optimization) оптимизации для сборки программ. Плюс в случае агрессивной оптимизации, размер исполняемых файлов может сильно увеличиться и программы на практике будут работать даже медленнее. Поэтому мы остановились на Clang не просто так и опции компиляции -O3 и LTO работают в нем более корректно. Плюс современные компиляторы более зрелые, и сейчас уже нет тех детских болячек переоптимизации и LTO.

Что меня побудило написать эту статью? В первую очередь это несколько фактов:

  1. Впервые прочел про сборку ядра Linux с LTO оптимизацией и Clang из новостей, где упоминалась компания Google. Она использует Clang и LTO оптимизацию для сборки ядра Linux и получения лучшей производительности. Компания Google для меня является синонимом инноваций, лучших программистов в мире и поэтому для меня ее опыт является самым авторитетным. Плюс она привнесла очень много в развитие open source, и ее наработками пользуются тысячи компаний во всем мире.
  2. Хоть компания Google начала использовать Clang и LTO оптимизацию раньше, только с выходом ядра Linux 5.12.6 и 5.12.7 было закрыто большое количество багов, и сборка ядра c LTO оптимизаций стала доступна многим. До этого при сборке ядра с LTO оптимизацией многие драйвера давали сбой.
  3. Мною уже протестирована работа ядра с LTO на Ryzen 9 3900x + AMD Radeon 5700 XT. Плюс уже давно использую LLVM 12 и Clang для сборки системных программ. Инструментарий LLVM12 и Clang стали основными в моей системе по причине лучшей поддержки моего процессора и нужные мне программы работают быстрее при сборке с помощью Clang. Для программистов Clang дает лучший контроль ошибок, оптимизации и unpredictable behavior. -fdebug-macro, -fsanitize=address, -fsanitize=memory, -fsanitize=undefined, -fsanitize=thread, -fsanitize=cfi, -fstack-protector, -fstack-protector-strong, -fstack-protector-all, -Rpass=inline, -Rpass=unroll, -Rpass=loop-vectorize, -Rpass-missed=loop-vectorize, -Rpass-analysis=loop-vectorize и т.д.
  4. Данная возможность толком нигде не была описана в связи с п.2 и есть подводные моменты, которые будут рассмотрены в данной статье.


В этой статье будет описана сборка ядра Linux 5.12.10 c LLVM 12 + Clang и LTO оптимизацией. Но так как статья получилась бы короткой, то так же бонусом будет рассмотрен вопрос как сделать утилиты LLVM 12 и Clang сборочным инструментарием по умолчанию, и какие программы и библиотеки имеет смысл собрать вручную, чтобы получить лучший отклик и производительность от системы. GCC имеет более лояльную лицензию на использование, и поэтому он установлен во многих дистрибутивах по умолчанию.

Так как в новом ядре фиксится немалое количество багов для работы с моим оборудованием(Ryzen 9 3900x + AMD Radeon 5700 XT) будет рассмотрен вопрос автоматизации сборки и установки нового ядра, чтобы это сильно не отвлекало и занимало минимум времени. Думаю многим это будет полезно. Будет рассмотрен принцип работы моего сборочного скрипта. Все действия будут проводиться в Arch Linux. Если статья будет хорошо оценена, то она станет вводной частью в серию статей про оптимизацию Linux, где будут рассмотрены внутренние механизмы ОС, и как оптимизировать их работу, будут рассмотрены вредные советы и ошибки оптимизации, и будет дан ответ на вопрос оптимизации системы Что для русского хорошо, то для немца смерть!.

Хоть тема оптимизации описывалась многократно, не мало где дают вредные советы, и некоторые механизмы ОС описаны с ошибками. Чаще всего это происходит из-за сложностей перевода или минимальной документации в интернете к компонентам ядра Linux. Где-то информация вовсе устарела. Плюс некоторые вещи понимают программисты, но не понимают системные администраторы, и наоборот. Изначально после установки Linux работает относительно медленно, но благодаря оптимизации и гибкой настройке, можно добиться более высокой производительности и значительно улучшить отклик системы. Arch Linux у меня используется как основная система, и отклик системы, производительность лучше, чем в Windows 10.
Внимание, автор статьи не несет ответственность за причиненный вред в следствии использования данной статьи! Все действия вы выполняете на свой страх и риск! Все действия должны выполнять только профессионалы!


Немного теории



LTO или Link Time Optimization это оптимизация на этапе линковки(компоновки). Чтобы понять, что такое LTO рассмотрим как работают компиляторы. В большинстве компиляторов используется двух этапная модель: этап компиляции и этап линковки.

На этапе компиляции:

Парсятся исходные тексты программ, строится AST Абстрактное Синтаксическое Дерево.

  • Оптимизируется Абстрактное Синтаксическое Дерево. Оптимизируются циклы, удаляется мертвый код, результат которого нигде не используется. Раскрываются выражения, например 2+5 можно заменить на 7, чтобы при работе приложения не вычислять его значение каждый раз и тем самым сделать его быстрее и т.д.
  • Оптимизированное дерево может быть преобразовано в машинный псевдокод понятный компилятору. Псевдокод используется для дополнительной оптимизации, упрощает разработку универсального компилятора для разных архитектур процессора, например для x86-64 и ARMv7\. Так же как ASM листинг, этот псевдокод еще используется, чтобы понять, как компилятор генерирует машинный код, и служит для понимания работы компилятора, поиска ошибок, например, ошибок оптимизации и unpredictable behavior. Стоит заметить этот этап не является обязательным и в некоторых компиляторах отсутствует.
  • Происходит векторизация. Векторизация ,Automatic Vectorization, SIMD
  • Генерируется объектный файл. Объектный файл содержит в себе машинный код для компьютера, и специальные служебные структуры, в которых все еще есть неизвестные адреса функций и данных, поэтому этот файл все еще не может быть запущен на исполнение. Чтобы разрешить неизвестные адреса, был добавлен этап линковки.


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

На этапе линковки:

  • Происходит подстановка адресов
  • Добавляются дополнительных данных для работы программы, например ресурсы
  • Происходит сборка всех объектных файлов в конечный исполняемый файл или распространяемую библиотеку, которая может быть использована в других программах


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

В Clang используется два вида LTO Оптимизации: Full LTO и Thin LTO. Full LTO это классическая реализация LTO оптимизации, которая обрабатывает конечный исполняемый файл за раз целиком и использует много оперативной памяти. Отсюда эта оптимизация занимает много времени, но дает на выходе самый быстрый код. Thin LTO это развитие LTO оптимизации, в которой нет оптимизации всего файла целиком, а вместо этого вместе с объектными файлами записывают дополнительные метаданные, и LTO оптимизатор работает с этими данными, что дает более высокую скорость получения оптимизированного исполняемого файла (скорость сравнима с линковкой файла без LTO оптимизации) и код сравнимый или чуть уступающий в производительности Full LTO. Но самое главное Full LTO может значительно увеличить размер файла, и код наоборот может из-за этого работать медленнее. Thin LTO лишен этого недостатка и в некоторых приложениях на практике мы можем получить лучшую производительность! Поэтому наш выбор будет сборка ядра Linux с Thin LTO.

Дополнительная информация:



Установка LLVM 12 и Clang



Поставить llvm и clang можно выполнив в консоли под root команду:

pacman -Syu base-devel llvm clang lld vim

Это самый простой вариант установки, но лично предпочитают новые версии ПО и git версия закрыла часть багов компилятора и даже стабильнее релиза. Так как за время написания статьи многое поменялось, вышел официальный пакет llvm 12, то чтобы понять ход мыслей, рекомендуется к прочтению прошлая версия по установке.

Прошлая версия
На момент написания статьи, в дистрибутиве Arch Linux используются LLVM и Clang версии 11\. А LLVM и Clang версии 12 находятся в staging репозитории Arch Linux [LLVM](http://personeltest.ru/aways/archlinux.org/packages/staging/x86_64/llvm/). Staging репозиторий это репозиторий, где находятся версии пакетов, которые ломают приложения, зависящие от прошлой версии. Он используется для компиляции всех зависящих программ, и когда все они будут собраны, все пакеты за раз переходит в общий репозиторий. Например, в Arch Linux от LLVM и Clang версии 11 зависят blender, rust и qt creator и т.д. Если мы поставим LLVM и Clang версии 12, то они перестанут работать.
Upd. Пакет уже перешел в основной репозиторий. Так как мною одним из первых была произведена миграция на LLVM и Clang 12, то было придумано простое решение, создать пакет [llvm11-libs](http://personeltest.ru/aways/aur.archlinux.org/packages/llvm11-libs-bin/) с необходимыми библиотеками для обратной совместимости, который позволяет оставить зависимые программы рабочими. Но данный пакет работает только с моим сборочным пакетом [llvm12-git](http://personeltest.ru/aways/aur.archlinux.org/packages/llvm12-git/). Поэтому мы будем собирать LLVM и Clang 12 из исходников. Но вы можете дождаться, когда LLVM и Clang 12 появятся в основном репозитории Arch Linux или использовать 11 версию. Лично предпочитают новые версии ПО, и LLVM и Clang 12 лучше поддерживают мой процессор Ryzen 9 3900X. Плюс git версия закрыла часть багов компилятора и даже стабильнее релиза. Релизный архив с официального сайта у меня не проходит больше тестов при сборке чем git версия. Не стоит пугаться того, что часть тестов компилятор провалил, там нет критических багов для x84-64 архитектуры, и большая часть затрагивают другие компоненты, например openmp и lldb. За очень долгое время тестирования llvm и clang 12 мною не было замечено ни одного бага влияющего на работу системы. Стоит заметить, на данный момент 13 версия является очень сырой и нам не подходит!

Поставим llvm и clang 11 версии(Если 12 версия появилась в основном репозитории, то поставится 12я версия) можно выполнив в консоли под root команду:

pacman -Syu base-devel llvm clang lld libclc vim

Обновить Arch Linux и поставить новые версии программ можно командой(это будет полезно тем кто будет ждать официального выхода 12 версии, думаю это произойдет уже через пару дней):

pacman -Syu

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


Cборка LLVM 12 из Arch User Repository



Для сборки нам понадобиться git и нам надо будет собрать программу yay.

Поставим необходимые зависимости, для этого нам будут нужны права root: pacman -Syu base-devel git go vim

Если вы хотите собрать llvm 12 с помощью clang 11, то надо поставить еще их: pacman -S llvm clang

Отредактируем конфигурационный файл сборщика пакетов makepkg в Arch Linux и увеличим количество потоков для сборки программ. Это ускорит скорость сборки. Под root выполним: vim /etc/makepkg.conf

Найдем строки MAKEFLAGS и NINJAFLAGS. Нажмем латинскую букву A. Нам после -j надо указать количество потоков для сборки. Рекомендуется ставить ваше количество ядер или потоков процессора, если ядер 4, то ставим 4 или 8\. У меня это 20, 12 ядер 24 потока, 4 остаются запасными для других задач. Или используем автоматическое определение $(nproc).

В итоге получим:

MAKEFLAGS="-j20"NINJAFLAGS="-j20"

или

MAKEFLAGS="-j$(nproc)"NINJAFLAGS="-j$(nproc)"


Нажмем ESC, дальше SHIFT + :(буква Ж). Внизу появится : строка для ввода команд, вводим wq. w write, записать изменения в файл. q quit, выйти из vim. q! выход из vim без сохранения файла. Кому сложно разобраться с vim, в Linux есть замечательная программа, называется она vimtutor. Если у вас настроена правильно локаль, то vimtutor будет на русском, запустить его можно командой vimtutor. Стоит заметить, вопреки распространенному мнению, обучение у вас не займет много времени. Обычно новичков пугают мифом: vi и vim люди изучают очень долго, и осилить их могут только единицы. На самом деле это не так и там нет ничего сложного.

Под обычным пользователем клонируем репозиторий yay, собираем и устанавливаем:
git clone https://aur.archlinux.org/yay.git && cd yay && makepkg -cfi

Импортирует открытый gpg ключ, он необходим для проверки подписи llvm12-git:
gpg --keyserver pgp.mit.edu --recv-keys 33ED753E14757D79FA17E57DC4C1F715B2B66B95

Поставим LLVM 12 и библиотеки совместимости с 11 версией. Стоит заметить, мой пакет LLVM 12 уже содержит все необходимые утилиты, включая Clang и LLD и их не надо ставить отдельно. Под обычным пользователем выполним команду: yay -Syu llvm12-git. Если llvm 12 есть в официальном репозитории, то llvm11-libs-bin не нужно ставить. Команда yay задаст вам несколько вопросов, нажмите Enter в ответ на все. Сборщик LLVM задаст 3 вопроса:

  • Build with clang and llvm toolchain? Собрать с помощью llvm и clang? Отвечаем Y или Enter если да, и N если нет. Рекомендую собирать LLVM с помощью Clang.
  • Skip build tests? Пропустить сборку тестов? Отвечаем Y или Enter. Так как во время сборки, не все тесты проходят проверку, то сборка будет прекращена. Поэтому мы пропускаем сборку тестов, и на самом деле сборка будет идти даже быстрее.
  • Skip build documentation? Пропустить сборку документации? Отвечаем Y или Enter если да, и N если нет. Если вам не нужна документация, то можно пропустить, это ускорит сборку. Лучше читать документацию на официальном сайте, это удобнее.
  • Skip build OCaml and Go bindings? Пропустить сборку OCaml и Go биндингов? Отвечаем Y или Enter если да, и N если нет. Для большинства ответ Y и их сборку можно смело пропустить в угоду скорости сборки. Для тех кому они нужны, а это очень маленькое количество людей могут ответить N.


Сборка может занять от 20 минут до пары часов. Ждете и в конце отвечаете Y на вопрос: хотите ли вы поставить собранные пакеты?

После установка LLVM надо собрать libclc12-git yay -S libclc12-git. libclc необходим для компиляции opencl и для сборки mesa.

Делаем LLVM и Clang сборочным тулчейном по умолчанию в Arch Linux



Большинство программ в Arch Linux собираются с помощью команды makepkg: man makepkg и PKGBUILD файлов. Поэтому в первую очередь внесем изменения в конфигурационный файл /etc/makepkg.conf. Выполним под root в консоли команду: vim /etc/makepkg.conf. Перейдем к строке CHOST="x86_64-pc-linux-gnu" поставим курсор на следующей пустой строке и нажмем латинскую букву A, и вставим после строки:

export CC=clangexport CXX=clang++export LD=ld.lldexport CC_LD=lldexport CXX_LD=lldexport AR=llvm-arexport NM=llvm-nmexport STRIP=llvm-stripexport OBJCOPY=llvm-objcopyexport OBJDUMP=llvm-objdumpexport READELF=llvm-readelfexport RANLIB=llvm-ranlibexport HOSTCC=clangexport HOSTCXX=clang++export HOSTAR=llvm-arexport HOSTLD=ld.lld

Дальше заменим строки CPPFLAGS, CXXFLAGS, LDFLAGS на содержимое ниже:

CFLAGS="-fdiagnostics-color=always -pipe -O2 -march=native -fstack-protector-strong"CXXFLAGS="-fdiagnostics-color=always -pipe -O2 -march=native -fstack-protector-strong"LDFLAGS="-Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now"

Если вкратце мы используем -O2 оптимизацию для всех программ, -fstack-protector-strong используем улучшенную защиту стека, что снижает вероятность потенциально опасных ошибок при работе со стеком в программах, она же включена у меня в ядре. Плюс на моем процессоре при сборке с Clang с -fstack-protector-strong код при работе с целыми числами работает чуть быстрее, при работе с числами с плавающей запятой есть небольшой оверхед. В GCC наоборот есть более заметный оверхед и производительность снижается. -march=native есть смысл заменить на ваш, у меня это -march=znver2 gcc.gnu.org/onlinedocs/gcc/x86-Options.html.

Изменим количество потоков в MAKEFLAGS и NINJAFLAGS для сборки программ. Это помогает ускорить сборку программ. После -j надо указать количество потоков для сборки. Рекомендуется ставить ваше количество ядер или потоков процессора, если ядер 4, то ставим 4 или 8\. У меня это 20, 12 ядер, 24 потока, 4 остаются запасными для других задач. Или используем автоматическое определение $(nproc).

В итоге получим:

MAKEFLAGS="-j20"
NINJAFLAGS="-j20"


или

MAKEFLAGS="-j$(nproc)"
NINJAFLAGS="-j$(nproc)"


Из DEBUG_CFLAGS и DEBUG_CXXFLAGS надо удалить -fvar-tracking-assignments. LLVM не поддерживает данный параметр.

Файл должен будет принять примерно такой вид:

CARCH="x86_64"CHOST="x86_64-pc-linux-gnu"CARCH="x86_64"CHOST="x86_64-pc-linux-gnu"#-- Compiler and Linker Flagsexport CC=clangexport CXX=clang++export LD=ld.lldexport CC_LD=lldexport CXX_LD=lldexport AR=llvm-arexport NM=llvm-nmexport STRIP=llvm-stripexport OBJCOPY=llvm-objcopyexport OBJDUMP=llvm-objdumpexport READELF=llvm-readelfexport RANLIB=llvm-ranlibexport HOSTCC=clangexport HOSTCXX=clang++export HOSTAR=llvm-arexport HOSTLD=ld.lldCPPFLAGS="-D_FORTIFY_SOURCE=2"CFLAGS="-fdiagnostics-color=always -pipe -O2 -march=native -fstack-protector-strong"CXXFLAGS="-fdiagnostics-color=always -pipe -O2 -march=native -fstack-protector-strong"LDFLAGS="-Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now"RUSTFLAGS="-C opt-level=2"#-- Make Flags: change this for DistCC/SMP systemsMAKEFLAGS="-j20"NINJAFLAGS="-j20"#-- Debugging flagsDEBUG_CFLAGS="-g"DEBUG_CXXFLAGS="-g"#DEBUG_CFLAGS="-g -fvar-tracking-assignments"#DEBUG_CXXFLAGS="-g -fvar-tracking-assignments"#DEBUG_RUSTFLAGS="-C debuginfo=2"

Нажмем ESC, дальше SHIFT + :(буква Ж). Внизу появится: строка для ввода команд, вводим wq. w write, записать изменения в файл. q quit, выйти из vim. q! выход из vim без сохранения файла. Кому сложно разобраться с vim, в Linux есть замечательная программа, называется она vimtutor. Если у вас настроена правильно локаль, то vimtutor будет на русском, запустить его можно командой `vimtutor`. Стоит заметить, вопреки распространенному мнению, обучение у вас не займет много времени. Обычно новичков пугают мифом: vi и vim люди изучают очень долго, и осилить их могут только единицы. На самом деле это не так и там нет ничего сложного.

Следующим этапом можно добавить настройки в файл .bashrc текущего пользователя. Не root, сборка программ под root очень плохая идея! Это относительно вредный совет и с помощью clang будут собираться все программы! Поэтому делайте это только если хорошо понимаете зачем это вам. Это можно сделать командой:

cat << 'EOF' >> "${HOME}/.bashrc"export CARCH="x86_64"export CHOST="x86_64-pc-linux-gnu"export CC=clangexport CXX=clang++export LD=ld.lldexport CC_LD=lldexport CXX_LD=lldexport AR=llvm-arexport NM=llvm-nmexport STRIP=llvm-stripexport OBJCOPY=llvm-objcopyexport OBJDUMP=llvm-objdumpexport READELF=llvm-readelfexport RANLIB=llvm-ranlibexport HOSTCC=clangexport HOSTCXX=clang++export HOSTAR=llvm-arexport HOSTLD=ld.lldexport CPPFLAGS="-D_FORTIFY_SOURCE=2"export CFLAGS="-fdiagnostics-color=always -pipe -O2 -march=native -fstack-protector-strong"export CXXFLAGS="-fdiagnostics-color=always -pipe -O2 -march=native -fstack-protector-strong"export LDFLAGS="-Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now"export RUSTFLAGS="-C opt-level=2"export MAKEFLAGS="-j20"export NINJAFLAGS="-j20"export DEBUG_CFLAGS="-g"export DEBUG_CXXFLAGS="-g"EOF


Список системных библиотек и программ которые стоит собирать вручную


Внимание, сборка всех программ и все консольные команды надо выполнять под обычным пользователем, перед установкой у вас попросит пароль root. Сборка всех библиотек и программ из списка не занимает много времени. Все кроме Mesa у меня собирается в районе 1 минуты. Список дан в той в последовательности в которой рекомендуется сборка! К примеру от zlib-ng и zstd зависит Mesa, а от Mesa зависит xorg-server.

Самое первое, что надо сделать в Arch Linux это заменить zlib на zlib-ng. Это дает хороший выигрыш производительности в приложениях, которые зависят от zlib. Больше всего это заметно на веб браузерах и веб серверах, которые используют gzip сжатие для передачи данных. На высоко нагруженных серверах это дает очень значительную прибавку к производительности. Сборка довольно быстрая. Поставить можно командой(под обычным пользователем): yay -Syu zlib-ng. На вопрос хотите ли вы удалить zlib отвечайте Y. Не бойтесь библиотеки полностью взаимозаменяемы, и ничего не сломается!

Дальше у нас идет zstd это вторая по популярности библиотека используемая в ядре и в программах для сжатия данных. Поэтому имеет смысл собрать так же ее. Чтобы собрать, вам нужно скопировать содержимое zstd, создать директорию, например zstd, а в ней создать файл PKGBUILD и в него вставить содержимое по ссылке. Дальше в консоли перейти в директорию содержащую PKGBUILD, выполнить команду makepkg -cfi .

libjpeg-turbo Библиотека для работы c jpeg файлами. Ее очень часто используют браузеры и программы рабочего стола. libjpeg-turbo собранный с clang дает у меня лучшую производительность. Действия такие же, как в zstd. Создать директорию, и вставить в файл PKGBUILD содержимое по ссылке libjpeg-turbo. Дальше в консоли перейдите в директорию содержащую PKGBUILD, выполнить команду makepkg -cfi.

libpng Библиотека для работы с PNG файлами. По сборке и установке все то же самое. libpng. Для сборки вам понадобится патч: 72fa126446460347a504f3d9b90f24aed1365595.patch, его надо положить в одну директорию с файлом PKGBUILD. Для сборки надо внести изменения в PKGBUILD, заменить source и sha256sums на строки ниже, и добавить функцию prepare.

source=("https://downloads.sourceforge.net/sourceforge/$pkgname/$pkgname-$pkgver.tar.xz"  "72fa126446460347a504f3d9b90f24aed1365595.patch")sha256sums=('505e70834d35383537b6491e7ae8641f1a4bed1876dbfe361201fc80868d88ca'  '84298548e43976265f414c53dfda1b035882f2bdcacb96ed1bc0a795e430e6a8')prepare() {  cd $pkgname-$pkgver  patch --forward --strip=1 --input="${srcdir:?}/72fa126446460347a504f3d9b90f24aed1365595.patch"}


Mesa это святой грааль для всех графических приложений. Стоит собирать всегда вручную, дает хорошую прибавку в десктоп приложениях, улучшается отклик рабочего стола. Одно время сидел на git версии, чтобы получить лучшую поддержку новых видеокарт AMD. Вот мой PKGBUILD оптимизированный для сборки с помощью Clang.

Для сборки вам надо отредактировать файл mesa.conf и установить необходимые вам драйвера dri, gallium, vulkan для сборки. У меня сборка только под новые видеокарты AMD. Подглядеть можно тут: Mesa OpenGL, mesa-git package, Mesa Documentation. При выходе новой версии Mesa не забудьте сменить 21.1.2 на новую версию. А после смены версии обновите контрольные суммы файлов, выполнив в директории с PKGBUILD команду updpkgsums.

xorg-server X сервер с которым взаимодействуют почти все среды рабочего стола. Сборка дает заметное улучшение отклика рабочего стола. Сборка такая же через mapkepkg -cfi. Скачать необходимые файлы для сборки можно тут: xorg-server Сборочный пакет немного кривой и собирает пакет без оптимизаций. Поэтому его надо пропатчить. Для это после строки arch-meson ${pkgbase}-$pkgver build \ надо добавить строки:

  -D debug=false \  -D optimization=2 \  -D b_ndebug=true \  -D b_lto=true \  -D b_lto_mode=thin \  -D b_pie=true \

Полный список критических важных программ влияющих на производительность системы вы можете посмотреть в поем github репозитории arch-packages. Список был создан с помощью системного профилировщика perf. Все сборочные файлы оптимизированы для сборки с помощью llvm и сборка полностью автоматизирована. На моем ryzen 9 3900x сборка всего занимает около 20 минут. Единственный пакет который невозможно собрать с помощью clang и llvm это glibc. Его надо собирать вручную, и с оптимизацией -march= под ваш процессор, это самая часто вызываемая библиотека. Сборку glibc могут проводить только профессионалы, понимающие, что они делают. Не правильная сборка может сломать систему!

Для того, что бы воспользоваться автоматизированной сборкой надо выполнить(под обычным пользователем):
git clone https://github.com/h0tc0d3/arch-packages.git && cd arch-packages && chmod +x build.sh

Дальше нам надо установить все gpg сертификаты и зависимости необходимые для сборки, выполним ./build.sh --install-keys, а затем ./build.sh --install-deps

Для сборки программ достаточно просто запустить скрипт: ./build.sh --install, скрипт вам будет задавать вопросы, какие программы хотите собрать и поставить. На вопрос: хотите ли вы отправить все ваши деньги и пароли автору статьи? хотите ли вы заменить программы?(например, zlib-ng и zlib конфликтуют. Удалить zlib? [y/N] ) ответьте Y . Если вам нужна принудительная пересборка всех программ, то надо выполнить ./build.sh --install --force. По умолчанию, если пакет был уже собран и найден с нужной версией, то он не собирается, а просто устанавливается.

Для сборки mesa надо отредактировать файл mesa/mesa.conf и установить необходимые вам драйвера dri, gallium, vulkan для сборки.

С помощью команды ./build.sh --check можно проверить различия версий в моем репозитории и в официальном, помогает быстро адаптировать сборочные файлы и собрать актуальные версии программ. Слева версия в моем репозитории, справа от стрелки в официальном. Мой репозиторий может служить удобной тренировочной точкой на пути к созданию своего дистрибутива, создания LFS и развитию навыка пересборки ПО не ломая систему.

[+] zstd 1.5.0-1[+] libpng 1.6.37-3[+] libjpeg-turbo 2.1.0-1[+] mesa 21.1.2-1[+] pixman 0.40.0-1[-] glib2 2.68.3-1 -> 2.68.2-1[+] gtk2 2.24.33-2[+] gtk3 1:3.24.29-2[+] gtk4 1:4.2.1-2[+] qt5-base 5.15.2+kde+r196-1[+] icu 69.1-1[+] freetype2 2.10.4-1[+] pango 1:1.48.5-1[+] fontconfig 2:2.13.93-4[+] harfbuzz 2.8.1-1[+] cairo 1.17.4-5[+] wayland-protocols 1.21-1[+] egl-wayland 1.1.7-1[+] xorg-server 1.20.11-1[+] xorgproto 2021.4-1[+] xorg-xauth 1.1-2[+] xorg-util-macros 1.19.3-1[+] xorg-xkbcomp 1.4.5-1[+] xorg-setxkbmap 1.3.2-2[+] kwin 5.22.0-1[+] plasma-workspace 5.22.0-2[+] glibc 2.33-5


Сборка Ядра с помощью LLVM и Clang с LTO оптимизацией


Внимание! Сборку ядра необходимо выполнять под обычным пользователем. Перед установкой ядра у вас попросит sudo пароль. Не рекомендуется использовать патчи ядра linux-ck, linux-zen, MuQSS и т.д. Мною были протестированы все, при кажущемся увеличении производительности системы, происходят кратковременные лаги и снижается стабильность системы, некоторые подсистемы ядра работают не стабильно! С выходом ядра 5.11 стандартный планировщик работает не хуже и значительно стабильнее! Единственный патч который мною применяется это патч для применения оптимизации под процессор github.com/graysky2/kernel_gcc_patch Выбрать ваш процессор можно в меню конфигуратора ядра Processor type and features-->Processor family.

Сборка ядра с помощью LLVM описана в официальной документации Linux Kernel Build with LLVM. Но там есть несколько подводных моментов, которые не описаны. Первый подводный момент заключается в OBJDUMP=llvm-objdump, тут идет переопределение objdump, но так как параметры objdump в llvm имеет другой синтаксис, то при сборке будет пропущена часть тестов для проверки корректности сборки, и будет warning ругающийся на objdump. Правильно будет оставить родной objdump OBJDUMP=objdump

Неправильно:

make CC=clang LD=ld.lld AR=llvm-ar NM=llvm-nm STRIP=llvm-strip \  READELF=llvm-readelf HOSTCC=clang HOSTCXX=clang++ \  HOSTAR=llvm-ar HOSTLD=ld.lld OBJCOPY=llvm-objcopy OBJDUMP=llvm-objdump


Правильно:

make CC=clang LD=ld.lld AR=llvm-ar NM=llvm-nm STRIP=llvm-strip \  READELF=llvm-readelf HOSTCC=clang HOSTCXX=clang++ \  HOSTAR=llvm-ar HOSTLD=ld.lld OBJCOPY=llvm-objcopy OBJDUMP=objdump

Второй подводный момент заключается в том, что если мы не добавим LLVM_IAS=1 в строку make, то нам не будет доступна LTO оптимизация в конфигураторе ядра!

Поэтому полная строка для сборки с LTO будет:

export BUILD_FLAGS="LLVM=1 LLVM_IAS=1 CC=clang CXX=clang++ LD=ld.lld AR=llvm-ar NM=llvm-nm STRIP=llvm-strip READELF=llvm-readelf HOSTCC=clang HOSTCXX=clang++ HOSTAR=llvm-ar HOSTLD=ld.lld OBJCOPY=llvm-objcopy OBJDUMP=objdump"make ${BUILD_FLAGS} -j$(nproc)

Полный список команд для сборки ядра. /tmp
надо заменить на вашу директорию куда будут распакованы исходные файлы ядра, а mykernel
надо заменить на ваш постфикс для имени ядра.

export BUILD_FLAGS="LLVM=1 LLVM_IAS=1 CC=clang CXX=clang++ LD=ld.lld AR=llvm-ar NM=llvm-nm STRIP=llvm-strip READELF=llvm-readelf HOSTCC=clang HOSTCXX=clang++ HOSTAR=llvm-ar HOSTLD=ld.lld OBJCOPY=llvm-objcopy OBJDUMP=objdump"tar -xf linux-5.12.10.tar.xz -C /tmpcd /tmp/linux-5.12.10zcat /proc/config.gz > .config # Берем конфигурацию запущенного ядра из /proc/config.gz и используем ее для сборкиecho "-mykernel" > .scmversionmake ${BUILD_FLAGS} oldconfigmake ${BUILD_FLAGS} -j$(nproc) nconfig

C помощью oldconfig конфигурация адаптируется под новое ядро и запускается конфигуратор nconfig. Подробнее о конфигураторах ядра можно прочесть в официальной документации [Kernel configurator](http://personeltest.ru/aways/www.kernel.org/doc/html/latest/kbuild/kconfig.html).

В конфигураторе переходим в General architecture-dependent option --> Link Time Optimization (LTO) и выбираем Clang ThinLTO (EXPERIMENTAL). Для дополнительной защиты стека в General architecture-dependent options ставим \* напротив Stack Protector buffer overflow detection и Strong Stack Protector. Жмем F9 и сохраняем новый конфигурационный файл. Далее идет список команд для сборки и установки нового ядра.

make ${BUILD_FLAGS} -j$(nproc)make ${BUILD_FLAGS} -j$(nproc) modulessudo make ${BUILD_FLAGS} -j$(nproc) modules_installsudo cp -v arch/x86_64/boot/bzImage /boot/vmlinuz-mykernel

Следующий подводный момент заключается в DKMS, после установки ядра собранного с помощью Clang, DKMS пытается собрать модули ядра с помощью GCC. По этой причине сборка и установка DKMS модулей в новое ядро завершается ошибкой. Решение проблемы заключается в передаче DKMS компилятора Clang таким образом:

sudo ${BUILD_FLAGS} dkms install ${dkms_module} -k 5.12.10-mykernel


Автоматизация сборки ядра Linux



Для автоматизации сборки ядра мы будем использовать мой bash скрипт github.com/h0tc0d3/kbuild. Клонируем репозиторий и перейдем в рабочую директорию: git clone https://github.com/h0tc0d3/kbuild.git && cd kbuild && chmod +x kbuild.sh

Отредактируем файл build.sh или поместим содержимое ниже в файл ${HOME}/.kbuild. Рекомендуется второй способ vim "${HOME}/.kbuild" т.к. при обновлении скрипта наши настройки сохранятся. Если использовалось клонирование репозитория git, то в директории со скриптом можно выполнить команду git pull, чтобы обновить скрипт. Ниже даны параметры по умолчанию, они формируют поведение скрипта по умолчанию, если соответствующий параметр не был передан. Эти параметры в дальнейшем можно будет переопределить с помощью параметров командной строки для скрипта. Так же можно добавить команду в ваш .bashrc. Для этого в директории со скриптом kbuild.sh надо выполнить echo "alias kbuild='${PWD}/kbuild.sh" >> "${HOME}/.bashrc", ${PWD} автоматом заменит на текущую директорию. Или из любой другой директории можно указать полный пусть к скрипту echo "alias kbuild='полный-путь/kbuild.sh'" >> "${HOME}/.bashrc" После редактирования .bashrc необходимо перезапустить терминал! Теперь можно будет запускать скрипт командой kbuild --help .

KERNEL_VERSION='5.12.10'         # Версия Linux для сборки. Любая версия с официального сайта kernel.org, включая rc версии.KERNEL_POSTFIX='noname'         # Постфикс для названия ядра. Ядро будет иметь имя версия-постфикс, 5.12.10-noname, нужно для разделения в системе ядер с одной версией.KERNEL_CONFIG='/proc/config.gz' # Конфигурационный файл ядра. Поддерживает любые текстовые файлы и с жатые с расширением gz.KERNEL_CONFIGURATOR='nconfig'   # Конфигуратор ядра nconfig, menuconfig, xconfig.# Рекомендую использовать nconfig, он лучше menuconfig.# Можно писать полную строку, например MENUCONFIG_COLOR=blackbg menuconfig# Дополнительную информацию можно найти в документации к ядру https://www.kernel.org/doc/html/latest/kbuild/kconfig.htmlMKINITCPIO=1 # Запускать "mkinitcpio -p конфигурационный_файл" После сборки? 0 - Нет, 1 - Да.MKINITCPIO_CONFIG="${KERNEL_POSTFIX}" # Имя конфигурационного файла mkinitcpio, по умолчанию равно постфиксу.CONFIGURATOR=0      # Запускать конфигуратор ядра? 0 - Нет, 1 - Да. Если вам не нужно конфигурировать ядро, то можно поставить 0.LLVM=0              # Использовать LLVM Для сборки? 1 - Да, 0 - Нет(Будет использован GCC или другой системный компилятор по умолчанию)THREADS=8           # Количество поток для сборки. Ускоряет сборку. Для автоматического определения надо заменить на $(nproc)BUILD_DIR='/tmp'    # Директория в которой будет проходить сборки ядра. У меня 32gb оперативной памяти и сборка происходит в tmpfs.DOWNLOAD_DIR=${PWD} # Директория для сохранения архивных файлов с исходниками ядра. ${PWD} - в папке из которой запущен скрипт сборки.DIST_CLEAN=0    # Если директория с исходниками существует выполнять make disclean перед сборкой? 0 - Нет, 1 - ДаCLEAN_SOURCE=0  # Выполнять make clean после сборки ядра? 0 - Нет, 1 - ДаREMOVE_SOURCE=1 # Удалять директорию с исходными файлами ядра после сборки? 0 - Нет, 1 - Да.SYSTEM_MAP=0    # Копировать System.map в /boot После сборки? 0 - Нет, 1 - Да.PATCH_SOURCE=1                          # Применять патчи ядра? 0 - Нет, 1 - Да.PATCHES=("${HOME}/confstore/gcc.patch") # Список патчей ядра. Нельзя поменять с помощью параметров скрипта.DKMS_INSTALL=1                                        # Выполнять DKMS Install? 0 - Нет, 1 - Да.DKMS_UNINSTALL=1                                      # Выполнять DKMS Uninstall? 0 - Нет, 1 - Да.DKMS_MODULES=('openrazer-driver/3.0.1' 'digimend/10') # Список DKMS модулей, который нужно собрать и установить. Нельзя поменять с помощью параметров скрипта.

Внимание! Сборку ядра необходимо выполнять под обычным пользователем. Перед установкой ядра у вас попросит sudo пароль. Не рекомендуется использовать патчи ядра linux-ck, linux-zen, MuQSS и т.д. Мною были протестированы все, при кажущемся увеличении производительности системы, происходят кратковременные лаги и снижается стабильность системы, некоторые подсистемы ядра работают не стабильно. С выходом ядра 5.11 стандартный планировщик работает не хуже и значительно стабильнее! Единственный патч который мною применяется это патч для применения оптимизации под процессор github.com/graysky2/kernel_gcc_patch. Нас интересует файл more-uarches-for-kernel-5.8+.patch. Путь к нему имеет смысл указать в PATCHES. Выбрать ваш процессор можно в меню конфигуратора ядра Processor type and features-->Processor family.

Принцип работы скрипта:

1) set -euo pipefail скрипт переходит в строгий режим, в случае ошибок скрипт завершается с ошибкой. Является хорошим тоном, при написании bash скриптов. Скрипт проверяет запущен ли он под рут, если запущен под рут, то выдает ошибку и завершается. Загружается настройки пользователя из файла ${HOME}/.kbuild

2) Скрипт проверяет существование директории linux-версия в директории BUILD_DIR. Если существует, то исходники распакованы. Перед сборкой может выполняться команда make distclean, поведение задается переменной DIST_CLEAN. Если этой директории не существует, то проверяется существование файла linux-версия.tar.gz

или linux-версия.tar.xz. Если файл найден, то он распаковывается в BUILD_DIR. Иначе файл скачивается с kernel.org в директорию DOWNLOAD_DIR.

3) Скрипт применяет патчи ядра и устанавливает постфикс для версии ядра(записывает его в файл .scmversion ).

4) Скрипт копирует настройки ядра из файла KERNEL_CONFIG в .config и выполняет make oldcofig для адаптации настроек под новое ядро и запускает конфигуратор ядра.

5) Скрипт собирает ядро и модули.

6) Скрипт удаляет модули DKMS из ядра которое сейчас запущено, если это необходимо. Это необходимо, чтобы в списке dkms status не отображались мертвые ядра. Удаляет директорию `/lib/modules/версия-постфикс` если она существует. Она существует в том случае, если мы собираем одну и туже версию несколько раз. Это дополнительная защита от unpredictable behavior .

7) Скрипт устанавливает модули ядра, копирует ядро в /boot/vmlinuz-постфикс.

8) Скрипт собирает DKMS модули и устанавливает их. Копирует System.map в /boot/System-постфикс.map, если это необходимо.

9) Обновляет загрузочный img файл для ядра. Выполняет mkinitcpio -p конфиг.

10) Выполняет make clean если необходимо. Удаляет директорию linux-версия в директории BUILD_DIR, если это необходимо.

Собрать ядро с llvm можно командой ./kbuild.sh -v 5.12.10 --llvm --start или kbuild -v 5.12.10 --llvm --start, если был установлен alias. -v 5.12.10 указывает версию ядра для сборки, --llvm указывает собирать ядро с помощью llvm и clang. --start указывает, что надо запускать конфигуратор ядра. Получить справку по параметрам скрипта можно выполнив команду kbuild --help.

Русская справка
Параметры: Описание: Пример:
--version, -v Версия ядра для сборки --version 5.12.10 | -v 5.13-rc4
--postfix, -p Постфикс ядра --postfix noname | -p noname
--config, -c Файл конфигурации ядра --config /proc/config.gz | -c /proc/config.gz
--dir, -d Директории сборки --dir /tmp | -d /tmp
--download, -z Директория загрузки --download /tmp | -z /tmp
--threads, -t Количество потоков сборки --threads 8 | -t 8
--configurator, -x Конфигуратор ядра --configurator nconfig | -x "MENUCONFIG_COLOR=blackbg menuconfig"

--start, -s Запускать конфигуратор
--disable-start, -ds Не запускать конфигуратор

--mkinitcpio, -mk Запускать mkinitcpio после установки ядра
--disable-mkinitcpio, -dmk Не запускать mkinitcpio после установки ядра
--mkinitcpio-config, -mc Конфиг mkinitcpio --mkinitcpio-config noname | -mc noname

--llvm, -l Использовать LLVM
--disable-llvm, -dl Не использовать LLVM

--patch, -ps Применять патчи ядра
--disable-patch, -dp Не применять патчи ядра

--map, -m Копировать System.map в /boot/System-постфикс.map
--disable-map, -dm Не копировать System.map

--clean, -cs Чистить исходники после сборки. make clean
--disable-clean, -dc Не чистить исходники после сборки.
--distclean, -cd Чистить исходники перед сборкой. make distclean
--disable-distclean, -dd Не чистить исходники перед сборкой.
--remove, -r Удалять директорию с исходниками после сборки
--disable-remove, -dr Не удалять директорию с исходниками после сборки

--dkms-install, -di Устанавливать DKMS модули
--disable-dkms-install, -ddi Не устанавливать DKMS модули
--dkms-uninstall, -du Деинсталлировать DKMS модули перед их установкой
--disable-dkms-uninstall, -ddu Не деинсталлировать DKMS модули перед их установкой

Список параметров которые помогают отлавливать ошибки на разных этапах и продолжить вручную:

--stop-download, -sd Стоп посл загрузки файла
--stop-extract, -se Стоп после распаковки архива с исходниками
--stop-patch, -sp Стоп после применения патчей ядрей
--stop-config, -sc Стоп после конфигуратора ядра
--stop-build, -sb Стоп после сборки ядра
--stop-install, -si Стоп после установки нового ядра и модулей




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

Всем кто дочитал до конца, спасибо! Комментарии и замечания приветствуются!


Подробнее..

Перевод Ускоряем загрузку веб-страниц тестируем 4 стратегии оптимизации изображений

13.05.2021 14:15:47 | Автор: admin


Статистика не устаёт повторять нам про устойчивую корреляцию между падением скорости загрузки страниц сайта и ростом частоты отказов со снижением конверсии. Я не открою Америку, если скажу, что работу сайта замедляет раздутая полезная нагрузка (с плохо оптимизированными изображениями и избыточным HTML-кодом). Это заставляет сервер выполнять лишнюю работу. Огромный пласт такой работы связан с проблемами оптимизации изображений.

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

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

В этой статье мы сведём решение к оптимизации изображений на этапе разработки, сборки проекта и/или на этапе обслуживания готового сайта.

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

Мы протестируем четыре стратегии. Сначала мы без оптимизации изображений просто скормим простой адаптивный код серверу со всеми брейкпоинтами и вариантами картинок для них. Затем мы рассмотрим оптимизацию на этапе сборки, когда специальные инструменты и сервисы помогают подготовить необходимые варианты изображений. Третья стратегия это run-time оптимизация: перед отправкой страницы автоматизированный инструмент или онлайн-сервис применяет оптимизацию к изображению по заданному шаблону или на основе информации из браузера. Последняя стратегия для формирования и доставки оптимизированных изображений использовать информацию об устройстве и браузере, полученную через другие специализированные сервисы (о них обязательно расскажу в конце статьи).

Внимание! Спойлер!





Стратегия оптимизации изображений с учётом особенностей устройства даст наилучшие результаты. В этой статье мы рассмотрим плюсы и минусы реализации каждой стратегии и их влияние на процесс разработки веб-приложения.

Конечная цель оптимизации изображений повысить скорость загрузки веб-страниц. Для аудита страниц я использую Google PageSpeed Insight. Он позволяет легко проанализировать эффективность отдельных стратегий. Как я писал выше, мы будем проводить аудит мобильных страниц.

Стратегия 1: адаптивный код без оптимизации


Я взял стандартный адаптивный код без использования какой-либо оптимизации изображений: браузер, отталкиваясь от размера экрана, просто выбирает из набора одинаковых изображений разных размеров более-менее подходящий вариант. В коде есть несколько брейкопоинтов для изображений разных размеров. Они определяются размерами дисплеев мобильных телефонов, планшетов и настольных компьютеров.

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

Вот пример с четырьмя брейкпоинтами, прописанными в атрибуте srcset:

<img srcset=image-1920.jpg 1920w,

image-1280.jpg 1280w, image-640.jpg 640w, image-480.jpg 480w sizes=(min-width: 36em) 50vw,100vw src=image-320.jpg alt=Responsive image syntax />
Теперь подумайте, сколько такого кода может быть у вас в проекте...

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

Можно реализовать адаптивность и с помощью медиа-запросов CSS. А можно использовать новые элементы и <source>, где <picture> служит контейнером для одного или более элементов <source&gt и одного элемента <img&gt. Однако все эти подходы не позволяют создать масштабируемые решения.

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

Преимущества:


  • не нужно покупать ПО или платить за подписку на дополнительный софт или сервисы;
  • относительно просто писать адаптивный код на основе хорошо документированного стандарта.

Недостатки:


  • требуется дополнительное пространство для хранения изображений разных размеров;
  • требуются дополнительные время и усилия на реализацию такой адаптивной многовариантности;
  • разрастание кода и сложности с его сопровождением;
  • не во всех браузерах этот код работает одинаково;
  • нет опоры на контекст устройства;
  • для масштабирования нужна отдельная CDN (Content Delivery Network Сеть доставки контента);
  • требуется много времени на доработку под новые устройства, форматы изображений и так далее.

Результаты тестов



Тесты показывают, что я выбрал не самые лучшие форматы, да ещё и без сжатия. И размеры моих изображений слишком велики.


Стратегия 2: Build-time оптимизация


Один из способов облегчить работу по созданию вариантов изображений использовать специализированные сервисы для редактирования или сжатия изображений, например, Kraken, Compressor.io, mozjpeg и squoosh.

Вы загружаете свои изображения и сервис обрабатывает и оптимизирует изображения на своём сервере. Затем вы можете использовать оптимизированные изображения в своём проекте. Можно установить стандартные или пользовательские настройки оптимизации: сжатие с потерями или без потерь, изменение размеров, даунскейлинг и так далее. Некоторые сервисы могут выдать сразу несколько вариантов одного и того же изображения в соответствии с необходимыми размерами.

А что, если пойти ва-банк и использовать сборщик Grunt или Gulp для оптимизации изображений? Для этого достаточно назначить соответствующие задачи, которые будут выполнены во время сборки. Саму обработку изображений может взять на себя js-пакет imagemin.

Его можно установить через npm или использовать через интерфейс командной строки. Это модульное решение с плагинами для сжатия различных форматов изображений: например, imagemin использует mozjpeg для JPEG и pngquant для сжатия PNG. Настройка параметров оптимизации изображений аналогична многим SaaS-инструментам.

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

Преимущества:


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

Недостатки:


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


Результаты тестов



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


Важно отметить, что суммарный объём полезной нагрузки снизился до 1,4 Мб. Это на 80% меньше, чем нам даёт решение без стратегии, и на 50% меньше, чем даёт стратегия с адаптивным кодом.

Стратегия 3: Run-time оптимизация


Когда мы заходим на страницу с некого устройства, браузер отправляет на сервер запрос с HTTP-заголовком. В заголовке хранится информация о контексте доступа и форматах изображения.

Run-time оптимизация запускается на сервере, как раз перед отправкой браузеру ответа (контента). Задача такой оптимизации уменьшить передаваемый объём данных, чтобы ускорить загрузку веб-страницы.

Например, заголовок из браузера Chrome выглядит так:

image/avif,image/webp,image/apng,image/*,*/*;q=0.8

С появлением Client Hints в дополнительных полях можно передать больше информации, например, DPR (device pixel ratio, плотность пикселей, величина аналогичная разрешению) и Viewport-Width (ширина экрана).

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

Используя эти данные, run-time оптимизаторы определяют, как сжимать изображения и в каком формате их выдавать. Однако вам для гибкого изменения размера всё равно потребуется руками реализовать адаптивную логику, основанную на брейкпоинтах.

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

ImgIx это надстройка над CDN (Amazon CloudFront), которая позволяет выполнять обработку изображений в реальном времени перед добавлением в кэш. ImgIx предоставляет весь необходимый функционал для обработки изображений, а также ряд дополнительных функций, например, Monochrome, Blur, Halftone.

Часто такие сервисы могут служить и в качестве CDN. А у Cloudinary есть своя система DAM (Digital Asset Management система управления медиа активами).

Всё бы хорошо, но такие оптимизатор пока не могут анализировать контекст устройства. HTTP-заголовок мог бы передавать данные пользовательского агента и сообщать, что страница открыта, например, из браузера Chrome на устройстве Android. Но этого мало. Ничего не говорится о том, телефон это или планшет, и каковы его диагональ, разрешение экрана.

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

Преимущества:


  • требуется очень мало усилий для оптимизации изображений;
  • часто run-time оптимизатор включает CDN для ускорения доставки;
  • оптимизатор может обладать другими возможностями, например, DAM или расширенный инструментарий обработки изображений;
  • автоматическая или ручная оптимизация изображений с помощью директив на основе URL;
  • имеет собственное хранилище изображений, освобождает ваше локальное / облачное хранилище
  • в этом смысле, сайту практически не требуется обслуживание или перенастройка;

Недостатки:


  • обычно дорогая ежемесячная подписка, потому что вы платите не только за оптимизацию изображений;
  • необходимо залезть в код и обновить значения src в тегах , чтобы отображать картинки, которые выдаёт сервис-оптимизатор;
  • для автоматического изменения размера по-прежнему требуется адаптивный код;
  • обычно работает медленнее при первых запросах, потому что сервису приходится получать изображение из стороннего источника, а затем оптимизировать его при полном отсутствии кеша.

Результаты тестов



Претензии по поводу сжатия и форматов почти сошли на нет, но всё ещё можно
придраться к размерам.


По сравнению с двумя предыдущими стратегиями полезная нагрузка снизилась на 88%. Теперь она составляет всего 897 Кб.

Стратегия 4: оптимизация с учётом контекста устройства


Как и в предыдущей стратегии, нам нужен сервис с сервером изображений. Он должен использовать заголовки запросов для динамической контекстно-зависимой оптимизации. Например, браузер может заявить о поддержке AVIF через Accept в HTTP-запросе. Тогда сервис задумается, какое именно изображение он должен выдать в формате AVIF. И вот тут начинается магия.

Для примера рассмотрим сервис ImageEngine. Он способен получить полноценную информацию об устройстве из контекста доступа с помощью js-библиотеки WURFL. Помимо браузера и ОС, он может определить точную марку и модель устройства, а также характеристики экрана (разрешение, PPI и многие другие). Он также поддерживает Client Hints, включая заголовок save-data, с которым работают далеко не все сервисы.

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

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

Эта стратегия практически не требует допиливания кода. Достаточно просто обновить значения атрибутов src тега img, связав их с сервисом оптимизации. И всё.

Преимущества:


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

Недостатки:


  • необходимо обновить значения src в тегах , чтобы отображать картинки, которые выдаёт сервис-оптимизатор (но сделать это нужно один раз);
  • платная ежемесячная подписка;
  • обычно работает медленнее при первых запросах, потому что сервису приходится получать изображение из стороннего источника, а затем оптимизировать его при полном отсутствии кеша.

Результаты тестов



Теперь Google PageSpeed Insights доволен.

Значительно улучшилось большинство показателей. Сервис автоматически начал использовать новые форматы изображений (например, AVIF с оптимальным сжатием в соответствии с контекстом доступа). Кроме того, для различных размеров экрана изображения автоматически меняют длину и ширину, а также масштабируются.

Наша суммарная полезная нагрузка уменьшилась примерно на 95%:



И будет вам счастье


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

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

Не стоит беспокоиться о возможной потере контроля над настройками оптимизации изображений, потому что вы можете вносить свои коррективы с помощью API или простых параметров URL.

Безусловно, за такое удовольствие придётся платить. Но представители сервисов уверяют, что для физических лиц, а также для малого и среднего бизнеса предусмотрены недорогие тарифные планы.



Облачные VDS от Маклауд отлично подходят для хостинга сайтов.

Зарегистрируйтесь по ссылке выше или кликнув на баннер и получите 10% скидку на первый месяц аренды сервера любой конфигурации!

Подробнее..

KubeHelper -упростите множество повседневных задач с Kubernetes через веб-интерфейс

15.02.2021 18:22:10 | Автор: admin

KubeHelper - это продукт который упрощает решение многих ежедневных задач связанных с управлением Kubernetes через веб интерфейс. Поиск, анализ, запуск команд, cron jobs, репорты, фильтры, git синхронизация и многое другое.

KubeHelper это не ещё одна попытка отобразить Kubernetes API в графическом интерфейсе. Не попытка заменить Lens, официальный Dashboard или другие продукты. Это мой скромный вклад в Kubernetes Open Source сообщество. Проект не имеет какого-то узко специализированного направления и содержит довольно много различных функций которые будут полезны в ежедневной работе с Kubernetes.

Итак, го к описанию и возможностям.

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

Мотивация

Считаю Kubernetes замечательным и революционным продуктом. Много лет изучаю и пользуюсь, но очень часто возникала надобность иметь под рукой много различных функций и команд. Каждый раз набирать в командной строке длинные команды, искать в истории, прописывать aliases и так д. конечно же, можно, но очень часто нет возможности залогинится в консоль, или не сохранилась история, или новый хост. Или много других причин.

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

Многие десктопные клиенты требуют сертификата для коннекта к серверу. И держать сертификат от кластера на локальной машине, не 100% безопасно.

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

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

Также постарался на ресурсы посмотреть с другой стороны. Многие готовые решения показывают ресурсы по namespace, ещё несколько полезных функций и на этом гибкость веб интерфейсов заканчивается и чтоб сделать что-то отличное чем просто показать список ресурсов в namespace, снова же приходится обращаться к консоли. Например group labels, find selector, view RBACs и так д

Тут у меня и возникла идея помочь сообществу организовать много команд в едином интерфейсе, установить kubectl, плагины, утилиты и сделать для пользования командной строкой графический web интерфейс. Внедрить другие функции которые будут полезны в ежедневной работе с Kubernetes кластером. Внести свой скромный вклад в Open Source сообщество. Ну и конечно же чтоб еще лучше познать и узнать Kubernetes. Вот что из этого получилось.

Общие принципы и понятия

На данный момент я подготовил 3 возможности инсталляции: kubectl, Helm, Terraform. Посмотреть инсталляции и настроить их можно здесь. Позже добавлю в публичный Helm Chart Repository и в Terraform Registry.

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

По умолчанию KubeHelper устанавливается с правами на чтение и просмотр. (get, list). Поэтому с уверенностью можно сказать, что вы ничего не поломаете используя его у себя в кластере. Но при инсталляции вы можете изменить ClusterRole под свои нужды, аж до статуса cluster-admin. Подробная настройка в Wiki.

Конфигурация и команды хранятся в формате TOML. Как по мне, этот формат очень удобен для такого рода задач. Снова же, подробное описание и как всё работает, вы можете почитать в Wiki.

Возможности и интерфейс

Dashboard

Здесь собрана общая информация о кластере. Общее количество процессорного времени, хостов(нод), памяти и так д. Отображена общая техническая информация о хосте(ноде), количество, имена и размеры docker images.

Search

Часто приходится искать что-то в кластере для этого нужно знать где искать и часто писать не тривиальные скрипты или команды. Поиск по всему кластеру или в определённой namespace по ключевому слову и выбранным ресурсам решает эту задачу.

Принцип довольно прост и интуитивен. Выбираем namespace(all = all namespaces) в котором мы хотим найти ресурсы по ключевому слову. Выбираем ресурсы нажимаем поиск, применяем фильтры.Также при нажатии на кнопку в столбце "Raws" можно посмотреть ресурс в различных форматахJava POJO, YAML или JSON.

Подробное описание всех функций и принцип работы вы можете почитать в Wiki.

Ips and Ports

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

Security

Этот раздел состоит из 6 секций. Каждая секция имеет одни и те же кнопки для выбора namespace и поиска соответственных ресурсов в ней.

Также при нажатии на кнопку в столбце "Raws" можно посмотреть ресурс в различных форматахJava POJO, YAML или JSON.

Секция "Roles": Поиск ролей в отдельном namespace или во всех namespaces. Просмотр subjects и role rules для каждого verb.Фильтр и группировка результатов.

Секция"RBAC: Построение матрицы доступа к ресурсам на основании ролей и правил.Фильтр и группировка результатов.

Секция"Pod Security Contexts: ПоказатьPodSecurityContext объекты в отдельной namespace или во всех namespaces.

Секция"Container Security Contexts": Показать ContainerSecurityContext объекты в отдельной namespace или во всех namespaces.

Секция"Service Accounts": Показать"Service Accounts" в отдельном namespace или во всех namespaces.

Секция"Pod Security Policies": Показать"Pod Security Policies" в отдельном namespace или во всех namespaces.

Labels Annotations Selectors

Поискlabels, selectors и annotations по выделенным ресурсам. Фильтр и группирование результатов.

Вкладка Grouped: На основании поиска labels, selectors и annotations будут сагрегированы и сгруппированы

Commands

Идея секции Commands сделатьKubeHelper гибко настраиваемый для каждого пользователя. Каждый пользователь может исполнять свои kubectl и shell команды с различных консолей. Просматривать результаты исполнения. Экспортировать свои подборки команд с git репозитория и многое другое. KubeHelper уже имеет много готовых к использованию команд.

Секция "Commands": Окно разделено на 3 части, команды которые можно фильтровать и искать. Окно редактирования выделенной команды и окно вывода результатов исполнения.

Секция "Management": В этой секции вы имеете возможность редактировать и создавать свои команды, а также просматривать уже имеющиеся команды.

СекцияHistory: В этой секции вы можете посмотреть все исполненные команды и результат их исполнения. Для удобности, история сохраняется по дням. Присутствует несколько удобных фильтров.

Cron Jobs

Идея секции Cron Jobs: сделать исполнение регулярных задач, проверки безопасности, построение и просмотр репортов исполнения команд - более простым и тривиальным заданием.

Секция "Jobs": Окно разделено на 3 части, команды которые можно фильтровать и искать. Окно редактирования выделенной команды и поля для создания новой cron job. Таблица со списком активных и остановленных cron jobs, кнопки управления.

Секция"Reports": Для каждой "cron job создаётся папка в которую по дням будут сохраняться выполненияcron jobs.Присутствует несколько удобных фильтров.

Configurations

Идея секции Configurations дать возможность пользователю синхронизировать свой конфигурационный файл с git также быстрее определить или изменить нужные cron jobs. Здесь же находятся функции для управление пользовательским репозиторием. Подробное описане можно почитать в Wiki.

Versions

ВKubeHelper уже предустановлен kubectl, огромное количество плагинов, утилит, командных оболочек и так д.. Эта вкладка отображает весь список предустановленных программ, их версии и другую информацию.

Вопрос к дочитавшим:

Какие новые функции вы бы добавили в первую очередь? Какая новая функция сделает вашу ежедневную работу легче?

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

Достаточно оставить комментарий с приоритетом в виде номеров или своё предложение.

Для предложения новой функции есть соответствующий Issue.

P.S.1 Буду рад репосту, звёздочке на GitHub. Пользуйтесь, делитесь информацией с коллегами, друзьями, знакомыми.

P.S.2 Буду рад желающим помогать развивать проект. На начальных стадиях особенно людям которые помогут сделать дизайн красивее. В первую очередь я работал над функциональностью.

Всем спасибо!

Подробнее..

Перевод Уход от проблемы TTL или Стратегии корректного и быстрого кэширования

23.03.2021 18:09:53 | Автор: admin

Определение TTL для некоторых кэшированных данных (time to live время существования или длительность хранения) может стать своего рода шарлатанской нумерологией для программистов. При кэшировании по значениям TTL корректность жертвуется ради достижения скорости. Но до какой степени можно отказаться от корректности? Как долго можно показывать где-то неправильное значение, прежде чем пользователь будет сбит с толку? Как скоро такие пользователи заподозрят наличие у себя проблемы и лягут бременем на службы поддержки клиентов? Давайте разбираться.


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

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

Это досадно, особенно потому, что часто переписывание не начинается (или никогда не заканчивается), а приложение PHP остается в рабочем состоянии, устойчиво и неподвижно, с упущенной простотой оптимизации.

Далее я подробно расскажу о стратегиях кэширования без отказа от корректности в целях достижения скорости. Во всех таких стратегиях вместо значений TTL используется активное аннулирование.

Стратегия 1: Просто никогда не аннулируйте

Самая простая стратегия - никогда не аннулировать. Некоторые данные не теряют актуальности. Содержимое CSV-файла upload #42345 не изменится. Как и HTML-преобразование некоторых данных продукта в формате markdown. Одна из причин, по которой люди не рассматривают эту стратегию, заключается в том, что они ошибочно опасаются, что кэш "заполнится". Краткосрочный кэш так не работает.

Вам не нужно управлять содержимым краткосрочного кэша с помощью TTL. Краткосрочный кэш будет управлять собственным содержимым с помощью вытеснения.

Кэши приложений, будь то Memcache или соответствующим образом настроенный Redis (см. ниже), работают по алгоритму LRU (least recently used). Редко используемые (холодные) данные вытесняются по мере необходимости, чтобы освободить место для более часто используемых (горячих) данных. Благодаря этому кэш в целом остаётся максимально горячим с учётом доступного пространства. Цель состоит в том, чтобы всегда иметь полный кеш.

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

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

Не путайте вытеснение (часть алгоритма удаления наиболее давно использованных элементов) с истечением срока действия (часть TTL). Данные могут быть вытеснены до истечения срока их действия. И так будет часто: в большинстве случаев в кэше не учитываются значения TTL при поиске данных, которые следует вытеснить.

Стратегия 2: Обновление при записи

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

Лучший подход здесь обновлять кеш всякий раз, когда вы обновляете данные в своём постоянном хранилище. Таким образом, кеш остается в актуальном состоянии, не требуя каких-либо нечетких значений TTL и всех связанных предположений о том, как долго что-то будет оставаться в силе.

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

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

Стратегия 3: Аннулирование при записи

Иногда изменение данных может повлиять на несколько объектов в кэше. Например: объект User может содержаться в кэше как в переменной user_id, так и в переменной email_address. При каждом изменении пользователя все данные уже будет в памяти, так что вы можете легко обновить оба кэшированных значения. Вы можете красиво инкапсулировать это в одном месте своей базы кода, где редактируются пользователи. Счастливые дни.

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

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

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

Стратегия 4: Использование пространства имен

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

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

Рабочий пример:

В /namespaces/user657 сохраняется монотонно возрастающая метка времени момента, когда пользователь 657 в последний раз изменил свой профиль, например, 1514937600.

Затем эта метка времени вносится в ключи, относящиеся к этому пользователю, например:

  • /user657/1514937600/likes/article-12312

  • /user657/1514937600/comments/article-12315

  • /user657/1514937600/something-else-completely

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

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

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

1. Ключ пространства имён должен быть не менее горячим, чем самый горячий вложенный в него ключ, в противном случае он может постоянно вытесняться перед этими ключами. Остерегайтесь оптимизаций, которые избегают необходимости извлекать ключ. Это приведёт к тому, что кэш LRU будет считать его холодным.

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

Стратегия 5: HTTP PUSH и PURGE

HTTP имеет встроенную систему кэширования, но эта система основана только на значениях TTL. Однако в самом широком смысле стратегия 1 продолжает работать: просто установите абсурдно большое значение TTL, и браузеры и CDN будут следовать ей в той мере, в какой им это нужно.

Стратегия 4 также хорошо работает в HTTP, за исключением того, что в этом контексте она обычно называется перебором кэша. Общее использование заключается в том, чтобы поместить строки версий или метки времени выпусков в URL-пути или строки-запросы, чтобы браузер загружал только последний пакет JavaScript.

Иногда CDN предоставляют явные API очистки, хотя это в основном удобно тем, кто развёртывает изменения в статических файлах. Традиционные операции очистки CDN обычно занимают несколько минут, поэтому, вероятно, не стоит полагаться на них на уровне приложений, хотя что-то вроде сервиса fly.io, где вы выполняете часть своего кода в CDN, может работать лучше.

При кэшировании инвертированных прокси-серверов, которые вы размещаете самостоятельно, например Varnish и Apache Traffic Server, могут использоваться нестандартные команды PUSH и PURGE, которые позволяют явно контролировать содержимое кэша. Если возможно явное аннулирование, можно использовать стратегии 2 и 3. Если под рукой есть нужный файл, почему бы также не заполнить кэш инвертированного прокси-сервера?

В целом хорошее свойство кэширования на уровне HTTP заключается в том, что оно снимает нагрузку с сервера приложений.

Советы и подводные камни

Кэширование не такое уж солнечное и приветливое. Вот некоторые проблемы, которых следует избегать, и некоторые советы, которые следует учитывать.

Не помещайте в кэш некэшируемые данные

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

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

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

Настройка максимально доступной памяти Redis по умолчанию (maxmemory) не ограничена. Это означает, что экземпляр всегда расширяется даже за пределами физической памяти без какого-либо вытеснения. Для кэширования задайте максимальный предел памяти, который строго меньше объёма физической памяти. Политика выселения по умолчанию (maxmemory-policy) заключается не в вытеснении, а в вызове ошибок в случае заполнения памяти. Опять же, если требуется вытеснение, это не хорошо для кэширования. В этом случае задайте значение allkeys-lru.

Большинство управляемых сервисов, таких как ElastiCache компании AWS, имеет другое значение по умолчанию для политики вытеснения: volatile-lru. При этой настройке для вытеснения рассматриваются только ключи, для которых задано значение TTL. Это умный подход, который позволяет дополнительно использовать экземпляр кэша для некэшируемых данных путём перегрузки флага TTL. По сути, volatile-lru это мина-ловушка, у которой есть множество неожиданных видов отказов. Во-первых, она побуждает программистов размещать некэшируемые данные на сервере, который сисадмины считают изменчивым и временным. Во-вторых, программисты, которые не знают об этой специальной настройке, склонны заполнять экземпляр по ошибке, многократно вставляя данные в кэше без TTL.

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

Никогда не требовать попадания в кэш

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

Одна из особенно сомнительных вещей хранить веб-сессии только в кэше. Тогда промах кэша невольно инициирует выход из системы незадачливого пользователя, который не сделал ничего плохого и ничего не нарушил. Вместо этого используйте стратегию 2, описанную выше, и храните веб-сессии в своей базе данных, используя кэш лишь для ускорения.

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

API в стиле декоратора

В стране Python люди любят декораторы. Например:

from functools import lru_cache@lru_cache(maxsize=1000)def get_slow_thing_v1(thing_id):    thing = get_slow_thing_from_a_database_layer(thing_id)    return thing

В приведённом выше коде нет ничего плохого, но он допускает только стратегию 1: никогда не аннулировать. Если есть необходимость в аннулировании/обновлении, код следует усложнить:

from pyappcache import RedisCachemy_cache = RedisCache()def get_slow_thing_v2(thing_id):    thing = my_cache.get_by_str(thing_id)    if thing is None:        thing = get_slow_thing_from_a_database_layer()        my_cache.set_by_str(thing_id, thing)    return thingdef update_something_slow(thing_id, new_thing):    set_thing_in_a_database_layer(new_thing)    my_cache.set_by_str(thing_id, new_thing)

Вторая версия более многословна, но зато позволяет обновлять кэш при настройке чего-либо.

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

Упоминание о собственной библиотеке

Если вы работаете с Python и хотите кэшировать данные, подумайте об использовании моей библиотеки: pyappcache (код здесь, документация здесь).

В ней много потрясающих функций, в том числе:

Есть и другие хорошие библиотеки для Python, в том числе dogpile.cache, cachew и, конечно, вы можете использовать Redis-py или pylibmc напрямую.

Иногда оно того стоит

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

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

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

Смотрите также

Мне нравится вот это объяснение, почему идея хранить сеансы в своем кэше не очень хорошая.

Apache (ne Inktomi) Traffic Server поддерживает PUSH и PURGE.

Я думаю, что Varnish поддерживает оба варианта, но вы должны их настроить.

На двух страницах, которые мне нравятся, описывается (слегка устаревшая, общая картина) конструкция Memcache: Memcache для чайников, автор Тиноу (Tinou), и Внутренние компоненты Memcache, автор Джошуа Тийссен (Joshua Thijssen). Документация memcache хороша и, хоть она и явно не закончена, включает некоторые трюки, о которых я не упоминал.

Документы системы Redis по её использованию в качестве кэша LRU необходимо прочитать, прежде чем пытаться использовать её таким образом. Как у большинства вещей у Redis, есть острые края. Важно знать, что при использовании кэширования значения по умолчанию вызывают проблемы.

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

Другие профессии и курсы
Подробнее..

Конвейер уникальная система мониторинга и управления для конвейерного производства

31.03.2021 14:23:38 | Автор: admin

Продуктовая компания Академпарка Сибирь Телематика получила поддержку по одному из самых крупных конкурсов Фонда содействия инновациям Развитие-Цифровые технологии в размере 10 млн рублей. Средства пошли на разработку и создание программно-аппаратного комплекса мониторинга и управления технологическими процессами конвейерного производства.

Компания Сибирь Телематика с 2017 года ведет научно-исследовательские и опытно-конструкторские работы по созданию технологической платформы программно-аппаратного комплекса Конвейер. Решение призвано эффективного управлять непрерывными конвейерными производствами, используя технологии Индустрия 4.0.

В 2019 году разработку поддержал Фонд содействия инновациям в рамках конкурса Развитие-ЦТ. Благодаря этому команда создала и запустила платформу, объединяющую автономно управляемые технологические участки конвейерного производства в единую систему. Кроме того, грантовая поддержка позволила существенно расширить штат разработчиков и создать уникальное, с точки зрения технической архитектуры, решение, не имеющие аналогов в мире.

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

На сегодняшний день все большую значимость приобретают решения в области цифровизации производственных процессов в различных отраслях промышленности, в первую очередь в сфере обрабатывающих производств. Особенно актуальными являются задачи по снижению себестоимости выпускаемой продукции, уменьшению объема потерь и брака при производстве. Мы, как компания, которая изначально занималась решением индивидуальных заказных задач, направленных на оптимизацию производственных процессов, искали возможности для масштабирования создания коробочного продукта. Благодаря Фонду содействия инновациям и его представительству в Академпарке, у нас это получилось, отметил Иван Корсуков, директор компании Сибирь Телематика.

Экономическую эффективность разработанного решения команда подтвердила, внедрив технологию на крупнейшем в России заводе по производству полых стеклянных изделий ООО Сибирское стекло.

За счет внедрения новых технических решений, в том числе, программного-аппаратного комплекса Конвейер от ООО Сибирь Телематика, производство стеклотары в сравнении с аналогичным периодом прошлого года выросло: на 6% в тоннах со 133,2 тысяч до 141,7 тысяч, и на 10% в штуках с 437 млн до 480 млн, отметил исполняющий обязанности генерального директора ООО Сибирское стекло Антон Мор.

Кроме того, Сибирь Телематика стала профильной организацией в ассоциации заводов-производителей стекла СтеклоСоюз России и в течении ближайших трех лет планирует внедрить ПАК Конвейер на шести крупных стекольных заводах России, Белоруссии и Казахстана. Общая сумма будущих контрактов составит около 350 млн рублей.

На сегодняшний день наша разработка показала высокий спрос в сфере обрабатывающих производств, поэтому мы планируем развивать производственные мощности для серийного выпуска аппаратной части ПАК Конвейер. Также важным аспектом является правовая охрана созданного решения на ключевых зарубежных рынках: странах Евросоюза, Китая и США. Поэтому мы решили снова принять участие в конкурсе Фонда содействия инновациям по программе Коммерциализация, который дает возможность в сжатые сроки решить задачи дальнейшего динамичного развития проекта, добавил Иван Корсуков.

Справка:

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

Подробнее..

Тестируем СХД OceanStor Dorado V6 Hyper и Smart

02.02.2021 16:10:30 | Автор: admin


Привет, меня зовут Павел. Я работаю ведущим системным инженером группы внедрения в департаменте вычислительных систем компании STEP LOGIC. В этом посте я поделюсь своими наблюдениями о флеш-системе хранения данных Huawei OceanStor Dorado V6, которую мы тестировали в полях в инфраструктуре заказчика.


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


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


Подробно остановлюсь на функциях:


  • HyperSnap мгновенный виртуальный снимок одна из разновидностей моментальных снимков, фиксация данных в определенный момент времени.
  • HyperCDP функция создания мгновенных снимков с высокой частотой (через малый промежуток времени).
  • HyperClone создает полные копии исходных данных с использованием расписания. Механизм применяется для резервного копирования, защиты, анализа и тестирования данных. В отличие от классического моментального снимка, на создание клона требуется определенное время, клон не грузит основной LUN.
  • SmartQOS позволяет настроить приоритеты ввода-вывода: повысить или понизить приоритет выделенному LUN'у и тем самым управлять скоростью обмена данными.

А о результатах тестирования производительности и отказоустойчивости я напишу во второй части.


О технических параметрах Dorado V6


СХД OceanStor Dorado V6 впервые представлена в сентябре 2019 года. В линейке продуктов пять моделей, условно распределенных на три класса low-end (Dorado 3000), mid-end (Dorado 5000/6000) и hi-end (Dorado 8000/18000). Модели в линейке объединяет схожая архитектура, интерфейс управления и набор функций. Основные различия в максимальной емкости и производительности.


Из отличительных особенностей OceanStor Dorado V6 базируется на процессорах и контроллерах производства компании Huawei. Из-за санкций США Huawei вынуждены были отказаться от процессоров Intel для своих СХД, перейдя на ARM-чипы собственного производства. У флагманских моделей Dorado 8000 V6 и 18000 V6 количество ядер на контроллер переваливает за сотню, а точнее 128 и 192 ядра соответственно. Если быть точным сам чип Kunpeng 920 на архитектуре ARMv8.2 может иметь от 24 до 64 ядер. Такое высокое суммарное количество ядер получается путем установки нескольких подобных процессоров в 1 контроллер.


Ниже речь пойдет о Huawei OceanStor Dorado 3000 V6 (24 ядра на контроллер), которая может применяться как для вспомогательных систем и сервисов, так и в качестве основной СХД для небольших компаний.


Почему выбрана именно Dorado 3000 V6?


Как это часто бывает младшие модели оборудования выглядят не так ярко на фоне представителей hi-end из этой же линейки и незаслуженно получают меньше внимания. Поэтому после 21 миллиона IOPS, которые были достигнуты Huawei на своей OceanStor Dorado 18000 V6, хотелось посмотреть, на что годится самая бюджетная All-flash СХД от Huawei.


Заказчик, совместно с которым проводилось тестирование, планировал купить аналогичную модель СХД, но с увеличенным суммарным сырым объемом и дополнительной полкой расширения (Disk Enclosure). У компании были опасения в части производительности системы, которые мы и постарались преодолеть в процессе тестирования.


Коротко о стенде для тестирования


В тесте мы использовали следующую конфигурацию Huawei OceanStor Dorado 3000 V6:


  • пара контроллеров Active-Active с единым кэшем 192 Гб;
  • 48 процессорных ядер, по 24 ядра на каждый контроллер;
  • восемь SSD-дисков 7,68 Тб;
  • две карты расширения Smart-IO 4х16Gb FC;
  • две карты расширения Smart-IO 4х10Gb Ethernet.

Примечание. Dorado V6 3000, в отличие от более мощных моделей в этой же линейке, поддерживает установку только накопителей SAS 3.0. NVMe формата Palm доступны начиная с модели 5000 V6.



Рисунок 1. Фронтальная панель установленной в стойку Huawei OceanStor Dorado V6 3000.


Для чистоты эксперимента, чтобы абстрагироваться от нюансов существующей инфраструктуры, уже используемой заказчиком для рабочих целей (и не нагружать лишний раз production SAN), было принято решение подключить СХД к серверу виртуализации (VMware ESXi 6.5) напрямую двумя FC-интерфейсами. Сервер виртуализации обеспечивал работу двух виртуальных машин, в которых мы запускали утилиту генерации и измерения нагрузки VDBench (Oracle), также был установлен драйвер multipath (Huawei Ultrapath).


На СХД мы создали дисковое пространство Storage Pool (далее SP), включающее в себя все восемь SSD дисков, с параметром отказоустойчивости RAID-6 и двумя резервными дисками Hot Spare. Диски LUN, созданные на данном SP, были подключены к виртуальным машинам как RDM-диски.


HyperSnap


HyperSnap представляет собой ни что иное, как Snapshot, созданный на LUN'е. Используется для резервного копирования, тестирования и других задач.


Важно отметить, что такой Snapshot работает по принципу ROW (redirect-on-write), вместо ранее считавшимся классическим COW (copy-on-write). Согласно этому алгоритму, новые данные не заменяют на старые, а записываются на свободное место. Такой Snapshot по сути является таблицей со ссылками. При создании снимка HyperSnap СХД записывает все сведения об изменениях в специально выделенную часть виртуального диска LUN Metadata. Снимок HyperSnap не является полной копией данных и поэтому не занимает много места.


Собственно, алгоритм ROW уже своего рода классика для Flash-массивов.



Рисунок 2. Отличия алгоритмов COW и ROW.


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


Технология HyperSnap позволяет подключать созданный снимок к серверу подобно обычным логическим дискам LUN. Их можно монтировать не только на чтение, но и на чтение-запись для оперативного подключения актуальных данных к тестовой среде.


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



Рисунок 3. Мгновенный снимок HyperSnap с именем LUNGroup006.


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



Рисунок 4. Консоль управления фирменного драйвера MultiPath от Huawei UltraPath.


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


Кроме того, LUN'ы можно добавлять в так называемые Consistency Groups, что позволяет делать снимки указанных данных в один и тот же момент данных. Это крайне важно, если вы придерживаетесь рекомендаций вендоров и раскладываете файлы и логи тех же баз данных по разным LUN'ам.


HyperCDP


Если HyperSnap механизм достаточно традиционный, то HyperCDP развитие Snapshot с возможностью создания снимков один за другим с большой частотой. Проще говоря, это набор мгновенных снимков, который можно создавать по расписанию с задержкой минимум 3 секунды.


Важно отметить, что подключение получившегося объекта напрямую к заведенным хостам невозможно из получившегося объекта необходимо сначала сделать копию. Из-за отсутствия записи и прямого чтения снимки HyperCDP могут быть использованы как инструмент для длительного хранения информации.


Помимо функции защиты, HyperCDP имеет еще одно важное преимущество. При использовании данной функции практически не страдает производительность. Это мы и проверим в процессе тестирования.


Для теста заведем на нашей СХД 16 LUN по 512 Гб, подключим их к одной ВМ и дадим нагрузку с помощью бенчмарка VDBench.


Примечание. VDBench сам по себе довольно прост, Oracle распространяет его бесплатно, из сопутствующего ПО требуется лишь установленный JRE.


В вызываемом файле конфигурации необходимо задать параметры, которые будут использоваться при тестировании. Допустим, VDBench будет писать блоком 8 килобайт с 70% полностью рандомного чтения и параметрами дедупликации и компрессии 2 к 1.


На СХД мы также настроим HyperCDP-план, который позволит в процессе делать снимки каждого из 16 LUN'ов с интервалом в 10 секунд. Ограничим эту задачу 500 объектами (для каждого LUN'а). Максимальное же количество в рамках одного плана может быть 60000.



Рисунок 5. Веб-интерфейс с примером созданного HyperCDP-плана.


Остается запустить VDBench с указанными ранее параметрами и наблюдать за текущей производительностью.


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



Рисунок 6. Результаты теста HyperCDP.


Подождем еще немного, пока количество HyperCDP-объектов всех LUN'ов не перевалит за сотню, и проверим еще раз.



Рисунок 7. Результаты теста HyperCDP с количеством объектов более 100.


Подводя промежуточные итоги, стоит отметить, что эмулируемый в рамках теста сервис не испытал каких-либо воздействий в плане деградации производительности, и за полтора часа мы получили 500 снимков 16-ти LUN'ов, что в сумме составляет 8000 объектов.


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


HyperClone


Из названия HyperClone становится очевидно, что эта функция делает точную копию указанного LUN'а.


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


При создании клона также можно выбрать скорость синхронизации:



В отличие от снимков HyperCDP клон не грузит основной LUN. В веб-интерфейсе соответствующего раздела доступна синхронизация в обе стороны: Synchronize и Reversе Sync. Если данные на первичном LUN'е были изменены и должны быть перенесены на вторичный, используется инкрементальная синхронизация, т.к. СХД отслеживает изменения созданных пар.


Примечание. Ранее рассмотренные варианты создания снимков HyperSnap и HyperCDP занимают намного меньше дополнительного пространства на хранилище, т.к. не являются полной копией данных



Рисунок 8. Настройка HyperClone.


Для разрыва связи достаточно удалить созданную пару в разделе веб-интерфейса Data Protection, в закладке Clone Pairs.



Рисунок 9. Удаление клон-пары.


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


SmartQOS


В принципе, сервис SmartQoS штука не новая. Системы, которые обеспечивают нужную полосу пропускания для критичных сервисов за счет приоритизации, существовали и ранее. Использовать разные LUN'ы под различные сервисы совершенно нормальная практика. В этом случае иногда возникает необходимость выставить максимальные показатели производительности по IOPS или Bandwidth на те или иные объекты.



Рисунок 10. Настройка политики SmartQoS.


Такой подход бывает необходим в определенных ситуациях, например, утренний Boot Storm у VDI. Инженеры Huawei учли этот факт есть возможность включать нужный режим QoS по расписанию.


Функция прячется под кнопкой Advanced.



Рисунок 11. Настройка расписания (раздел Advanced).


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



Рисунок 12. Созданная политика SmartQoS001.


Далее снова обратимся к помощи бенчмарка VDBench (в тестировании он встретится еще не раз). СХД с точностью как в аптеке отмеряет нашей эмуляции сервиса предоставляемые IOPS'ы. Для наглядности ниже привожу показания со стороны тестового ПО и со стороны Dorado.



Рисунок 13. Результат выполнения политики SmartQOS.


Выглядит SmartQOS весьма неплохо. По результатам его тестирования могу порекомендовать Dorado к использованию в любой инфраструктуре как для оптимизации работы уже существующих сервисов, так и для изначального планирования, особенно если в СХД размещены крупные базы данных или VDI, требующие особого подхода.


Для последних также важно наличие такой настройки как Burst, когда политика позволяет превысить максимальные значения на определенный срок, задаваемый администратором. Это поможет проще пережить уже упоминаемый ранее Boot Storm. Если у Dorado будет возможность не жертвовать другими сервисами, она спокойно перейдет в режим Burst в политике и обеспечит требуемые параметры производительности.


Подведение итогов для первой части


При подведении итогов принято говорить о преимуществах и недостатках. В данном случае хочется и похвалить, и поругать Huawei за новый веб-интерфейс. В целом, он простой и логичный. Разобраться с ним можно, даже не имея опыта общения с продуктами компании Huawei. С другой стороны, современные интерфейсы должны быть интуитивно понятны во всем. Здесь же выезжающие справа фреймы можно закрыть исключительно нажатием кнопок снизу ОК или Cancel, хотя интуитивно хочется просто тапнуть по неактивному полю страницы.


Что касается результатов тестов они говорят сами за себя. Dorado V6 в реальной жизни выглядит достаточно неплохо, даже в начальной своей конфигурации. По цене младшая Dorado V6 соперничает со многими гибридными СХД, которые показывают куда более скромные результаты в тестах производительности. Ее можно рассматривать к покупке практически под любые сервисы. Разве что для резервного копирования All-flash массивы все еще слишком дороги.

Подробнее..

Quantization Aware Training. Или как правильно использовать fp16 inference в TensorRT

21.05.2021 12:08:14 | Автор: admin

Low-precision inference в TensorRT сегодня - мастхэв, бест практис и прочие иностранные. Сконвертить из TensorFlow легко, запустить легко, использовать fp16 легко. Да и КПД выше, чем у pruning или distillation. На первый взгляд всё работает идеально. Но на самом деле всё ли так гладко? Рассказываем, как мы в TrafficData споткнулись об fp16, встали и написали статью.

Если ты читаешь эту статью ради подробного туториала о запуске TensorRT, то его тут нет. Он есть тут. Здесь же про опыт применения и несколько важных моментов, о которых не говорят в официальной документации.

Что за зверь ваш low-precision?

float16

И так, low-precision inference - запуск нейронных сетей в типе пониженной точности. Но зачем это нужно? По умолчанию все фреймворки учат и сохраняют модели в типе float32. Оказывается, что количество знаков во fp32 - часто избыточно. Ну а зачем нам эти сотни знаков после запятой? Можно просто скастовать fp32 веса во fp16, чтобы получить ускорение прямого прогона и уменьшение используемой памяти в 2 раза. При этом сохранив исходную точность модели. Единственное условие - наличие тензорных ядер в вашем GPU.

int8 и прочее

Кроме fp16 с простым кастованием есть много идей по более оптимальному использованию бит в 16-битном значении. Просто чтобы напомнить:

Но этого мало. Использование нейронных сетей в высоконагруженных системах и мобильных платформах заставляет еще сильнее ужимать сети и ускорять инференс. Добро пожаловать в мир int8 и int4. Да, в них квантуют. Да, в int8 всего 256 значений. Да, это работает. Со своими сложностями, конечно - здесь уже просто так не кастанёшь, как в случае с fp16. Нужно внимательно изучать распределения значений в слоях, чтобы эффективно использовать предоставленный небольшой диапазон значений.

Объясню, почему мы не смотрим на 8/4 битные квантизации. Дело в том, что здесь не обойтись без потери точности. Например, тут говорят как оптимально юзать int4 и радуются, что потеряли не 15%, а 8% точности. Или вот красноречивая табличка от Nvidia о западении точности при использовании int8:

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

TensorRT

Если у вас мобильные решения или просто инференс на CPU, то попробуйте TensorFlow Lite. Но в основном, говоря про low-precision inference в проде, сегодня имеют ввиду TensorRT - кроссплатформенный SDK для супер-быстрой работы на GPU от Nvidia. TensorRT легко превращает ваши модели в оптимизированные Engines. Сконвертить можно из любого нейросетевого фреймворка через ONNX. Engine - очень важная сущность в TensorRT. При билде происходит оптимизация под текущий GPU - на других GPU engine либо не запустится, либо будет работать неоптимально. Короче говоря, есть ряд параметров, которые нужно знать или задать заранее:

  • GPU. На чём собрали Engine, на том пусть он и работает. Но допустим общий билд для карточек одного семейства - Turing или Ampere. Например, мы билдили Engine для RTX 2060 и он замечательно работает на RTX 2080 Super. Создание отдельного Engine для RTX 2080 Super существенного ускорения не создает.

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

  • InputSize. Мы работаем с изображениями. И размер входного изображения иногда может меняться во время рантайма. Но TRT требует его задавать жестко, что логично. Да, есть возможность задать минимальный и максимальный размеры, а TRT создаст несколько профилей оптимизации. Но всё же это не так гибко, как в TensorFlow, а иногда нужно.

  • Precision. Собственно мы можем задать fp32/fp16/int8. Первые два различаются лишь выбором флага. С int8 я мало экспериментировал. Но судя по документации, отличие лишь в необходимости калибровочного датасета - набора картинок, на основании которого TRT определит распределения значений на разных слоях.

Ну и под конец еще добавлю, что в рантайме эти движки отжирают лишь необходимый минимум GPU RAM и замечательно работают параллельно (если правильно работать с TensorRT Context в вашем коде рантайма).

Контекст задачи

Окей, чтобы было понятнее, какие проблемы возникли, пара слов о нашем продукте. Мы пилим TrafficData - ПО для оценки трафика c камер и дронов, в рилтайме и постфактум, в дождь и снег. Нам важно, чтобы ночью детектилось вот так:

И не хуже.

На opentalks.ai2020 мы рассказывали, как, используя Pruning и физичность данных, ускорили обработку в 4 раза и не потеряли в точности. Статью про Pruning я уже выкладывал. Но сегодня давайте поговорим конкретно про low-precision inference.

Как мы запустились и потеряли нежные фичи

Скачивая либы TensorRT, бонусом вы получаете набор примеров с кодом для самых разных архитектур и ситуаций. Для билда движков мы использовали пример SampleUffSSD (UFF - универсальный формат описания сети, через который мы конвертили наши .pb), cлегка его закастомив под входной тензор от YOLO. И хотя TensorRT очень много обновляется и всё больше новых интересных слоев поддерживает, тогда мы запускались на версии, где не было реализации ResizeBilinear операции для Upsample слоя. И мы накостылили Conv2DTranspose вместо него, чтобы не писать кастомный слой. Первая сконверченная модель была радостью, как и её скорость работы.

Даже если перейти с fp32 из TF в fp32 TRT, то уже получается неслабое ускорение - на 15-20%. В конце концов TRT использует и много других оптимизаций, например горизонтальные, вертикальные и любые другие LayerFusion.

Для инференса мы закастомили пример trtExec, обернув его для использования в .NET коде. На вход - байты изображения, на выходе - нераспарсенные байты выхода YOLO. Здесь аккуратно работайте с CudaStream и ExecutionContext. Тогда ни память не утечет, ни потоки обработки не закорраптятся.

И так, мы реализовали TensorRT fp16 inference. Сбилдили движки для разных карточек. Прогнали основные тесты - колебания точности в пределах погрешности. И всё замечательно работало несколько месяцев. А дальше - история.
10:00. Звонок клиента:
- У нас тут на одном ролике TrafficData плохо работает - машинки двоятся.
- Окей, скиньте ролик разберемся.
Смотрим ролик - да, проблема есть. Ролик с тенями и на нём тени отмечаются, как второе авто.

13:00. Добрали изображения в основной датасет. Поставили доучиться с низким LR.

16:00. Тестим на версии с инференсом в TensorFlow - всё замечательно. Билдим новый Engine. Тестим на версии с инференсом в TensorRT - опять машины двоятся:

17:00. Идём домой.

Следующее утро началось с мема:

Стало очевидно, что проблема в TensorRT, а конкретно - в преобразовании весов во fp16. Мы проверили еще несколько других роликов со сложными условиями и увидели, что после преобразования во fp16 проблемы появились и в других местах. Стали появляться пропуски детекции на ночных видео, некоторые билборды стали определяться как авто. Короче вот так мы потеряли нежные, но важные фичи, про которые оригинальная сеть во fp32 знала, а вот во fp16 успешно забыла. Что делать?

Quntization Aware Training. Учи на том, на чем будет работать

Подсознательно мы сразу понимали, что если мы обучаем на fp32, а потом инференсим на fp16, то выйдет неприятная вещь. Вот эти жалкие циферки далеко после запятой потеряны и так влияют. Тогда зачем мы их учили на каждом батче? Идея Quntization Aware Training крайне проста - учи и помни о том типе, в котором будешь инференсить. Т.е. в типе fp16 должны быть все веса сверток, активаций и градиентов. Не удивляйтесь, если первые запуски в TensorFlow окажутся с NaN-лоссом. Просто внимательно инспектируйте происходящее. Мы потратили пару недель, переписали всё обучение на fp16 и проблема была решена.

Как в Tensorflow 2.0?

Тут небольшое отступление о том, как мы были рады обновлению TF2.0. Работая под TF1.15 мы кусали локти, заставляя запуститься обучение во fp16, переписывая слои. Но это заработало. А потом пришел TF2.0 - используешь tf.train.experimental.enable_mixed_precision_graph_rewrite над оптимизатором и всё заводится, как моя Lada Granta. Но всё же стоит обратить внимание на whitelist - не все ноды по умолчанию будут работать во fp16. Часть стоит поправить руками. Ну и дополнительный бонус - огромная экономия памяти, которой не получалось в TF1.15. Батч-сайз для нашей кастомной YOLOv4.5 увеличился в 2 раза - с 4 до 8. Больше батч - лучше градиенты.

Выводы

Fp16 inference - это здорово. Только не стоит забывать про Quntization Aware Training, если вы хотите сохранить точность оригинальной модели. Это позволило нам сделать еще шаг в сторону оптимизации наших и клиентских мощностей:

Что особенно важно в годы дефицита чипов и дорогих GPU. Я всё же за использование GPU в тех местах, где они приносят пользу людям, автоматизируя что-то. А не там, где они приносят прибыль, делая деньги из подогретого воздуха.

А вообще вся тематика ускорения инференса сетей сегодня - очень интересное поле для экспериментов. Хочется попробовать десятки новых способов Pruning, Distillation или квантования в int4, но всех Баксов Банни не догонишь. Пробуйте новое, но не забывайте отдыхать.

Подробнее..

Сколько CPU и RAM вам нужно, чтобы сделать бекап?

12.02.2021 10:14:08 | Автор: admin

Помните, как во второй половине 90-х один известный тогда профессор хрипло пел Бегут года, и грусть, печаль в твоих глазах, а я не знаю что тебе сказать. Так вот, года действительно бегут, а грусть-печаль в глазах из-за того, что гонка технологий уже достигла таких скоростей, что успеть за ними не может даже самый ловкий мангуст. Правда, некоторые вещи категорически отказываются меняться, и раз уж эта статья из блога компании, занимающейся бекапами, видимо, что-то не меняется в бекапах. А проблема, о которой хочется поговорить сегодня - это выбор сервера, который эти бекапы и будет делать. Все как-то привыкли думать только о размере стораджа, куда их предстоит складывать, а то, что процесс бекапа - это типичная задача обработки большого массива данных, которая жрёт RAM и CPU как не в себя, многие то ли забывают учесть, то ли по неопытности упускают этот момент. Так что сегодня учимся подбирать сервера для бекапов не только по размеру дисков. Или, как говорят зарубежные коллеги: backup server sizing best practices.

И да, в посте будет математика. Целых две формулы. Я предупредил.

Как и любое другое здравое современное приложение, Veeam Backup & Replication спроектирован таким образом, чтобы минимально загружать своему пользователю мозги и максимально эффективно справляться с поставленной задачей. На местах этот высокопарный посыл выражается в том, что независимо от масштаба вашей задачи устанавливается Veeam в три клика, ещё в пять делается первичная настройка и всё, полетели бекапы бекапироваться. Но как все мы отлично понимаем, это всего лишь радужная теория из мира с поняшками и бабочками. Ведь даже если самому приложению совершенно без разницы, бекапить ли ваш ноутбук на подключенный usb диск или гонять сотни терабайт снапшотов по FC фабрике (а ему действительно всё равно), то происходить это всё будет на вполне конкретном физическом железе, которому предстоит обработать все эти потоки данных. То есть, в то время, пока софтовая часть остаётся неизменной, архитектура решения в целом меняется до неузнаваемости.

Если скорость бекапа своего компа можно легко увеличить на порядок простой заменой USB 2.0 диска на USB 3.1, то имея задачу забекапить развесистую ферму серверов, да ещё и раскиданную по всему миру, можно столкнуться с тем, что в одном месте окажется слабый CPU, в другом процесс утыкается в объёмы доступной RAM, в третьем все ждут, когда контроллер дисковой полки соизволит записать очередную порцию данных, а в четвёртом так и вообще еле живой линк с внешним миром. Так что чем сложнее задача, тем проще и обиднее будет ошибиться с выбором любого из компонентов системы. И если за покупку слишком мощных серверов ругать вас не будут, то промашка в меньшую сторону скорее всего чревата большим числом неприятных разговоров в самом ближайшем будущем. Здесь - ты не поместился в бекапное окно, здесь - попытка сделать снепшот приводит к развалу кластера, а вот там просто нет ресурсов и придётся просить докупить новых железок. Так что тема планирования потребления CPU и RAM для бекапов не настолько и третьесортная задача, как к ней многие относятся.

Но прежде чем начать выписывать себе бюджеты на сотни CPU и тысячи гигабайт RAM, давайте освежим в памяти общую архитектуру Veeam Backup & Replication, чтобы точно не путаться в определениях и назначении компонентов.

  1. Сам VBR (Veeam Backup & Replication) сервер. Командный центр, оркестратор, ЦУП, разум улья, словом, называйте как хотите, но основная его роль - это синхронизация всех остальных компонентов и выдача команд на запуск разных увлекательных внутренних процессов, отслеживание расписания, и так далее. Технически ничего не мешает разместить вообще все компоненты на одной машине, и они даже будут работать. Однако такой сервер и ресурсов потребует соответствующих, и производительность его будет далека от совершенства. Так что лучше размещать всё остальное согласно назначению. Об этом ниже.

  2. База данных. Veeam - это классическое приложение, хранящее всю важную информацию в базе данных. Где и как вы расположите эту базу данных - его совершенно не волнует. Лишь бы до неё была связь и сервер стабильно работал. Хотите на одной машине с основной консолью? Пожалуйста! Для этого в установщике лежит Microsoft SQL Server 2016 SP2 Express Edition, который будет автоматически развёрнут и настроен самым лучшим образом. У вас уже есть своя инсталляция и вы хотите, чтобы база крутилась там? Без проблем! Просто укажите установщику адрес сервера и с какой учёткой туда идти. В процессе эксплуатации передумали и хотите перенести базу на другой сервер? Просто измените ключик в реестре или воспользуйтесь встроенной тулой. Всё для вас.

  3. Прокси сервер или просто прокся. Не знаю, почему когда-то давно было решено назвать их именно так, но точно знаю, что новичков это название иногда путает (именно путает, а не пугает). Но не будем искать виноватых, а просто зафиксируем, что прокси - это тот компонент инфраструктуры, который будет читать данные с бекапируемого объёкта и укладывать их в бекап. Это если упрощенно, потому что на самом деле данные будут сжиматься, дедуплицироваться, шифроваться, на их пути могут возникнуть другие прокси, нестабильные каналы связи и всякие хитрые хранилища. Не суть. Сейчас важно зафиксировать, что прокси - это то, что примет на себя основной удар по обработке данных. Они запускают пары data movers, один из которых что-то откуда-то читает, а второй что-то куда-то пишет. Чуете очевидную мораль? Чем ближе ваша прокся к бекапируемому объекту и чем ближе к ней хранилище бекапов, тем быстрее будет идти процесс. Но тут важно не увлекаться и помнить, что чудес не бывает. Ваши машины лежат на FC сторадже? Так будьте любезны и проксе предоставить FC подключение, иначе как ей данные получать? Ну не через managed интерфейс хоста же, ну честное слово. Хотя на самом деле с этой проблемой связана одна из самых частых ошибок при конфигурации - пользователь хочет, чтобы бекапы работали через Virtual Appliance, а работает через Network. Но не будем сейчас о грустном.

  4. Репозиторий. Он же бекапный сторадж. Может быть буквально чем угодно, к чему можно присоединиться, а ещё лучше, если там можно запустить наш дата мувер. Запустились на целевой системе - значит, можем контролировать процесс и часть операций проводить локально. Не можем запуститься на целевой системе - значит, приходится верить на слово, а каждый байт информации гонять взад-назад по сети. Так что во время любого синтетического трансформа бекапа, лежащего на сетевой шаре, ваша сеть будет вас ненавидеть. Поэтому Windows/Linux сервер - это твой бро, сетевые шары нет. Работать, конечно, будет, но медленно и не пойми как. Есть ещё целая россыпь вариантов вроде S3, дедуплицирующих систем и всяких специфических файловых систем вроде XFS, но это тема отдельного разговора. Просто помним, что репозиторий - это наше хранилище и гарант безопасного сна. Ну и особенно хорошо, если там можно запускать дата муверы.

  5. Enterprise Manager. Командир над командирами, в котором можно объединить управление несколькими VBR серверами и дать рядовым пользователям пользоваться частью функций через простенький веб-интерфейс. Например, можно выдать гранулярные права своему хелпдеску на восстановление определённых объектов на определённых машинах. Удалил пользователь письмо и корзину почистил, а хелпдеск ему хлоп - и вытаскивает это письмо из бекапа. Красота.

  6. И цифрой шесть давайте обозначим всё остальное, включая комбо-сервера, на которых крутится сразу по несколько ролей. Например, использовать один сервер в качестве и прокси, и репозитория - вполне нормальная идея, если серверу хватает ресурсов. Ну и помимо основных компонентов есть ещё целая россыпь вспомогательных: tape server, wan accelerator, cache repository и прочие gateway servers. Тут можно долго всё перечислять, тщательно объясняя, кто и зачем нужен, но мы здесь не за этим собрались. Лучше почитайте документацию, благо там всё очень понятно и подробно описано.

Главный посыл всего вышесказанного: VBR- это не одна конкретная машина, на которой вы прокликали мастер установки и получили работающее решение. Вернее, в небольших инсталляциях это, может, и так, но если у вас раскидистая инфраструктура, то VBR полностью готов ей соответствовать. Все эти компоненты и созданы, дабы дать возможность масштабироваться в зависимости от решаемой задачи. Странно будет поставить все компоненты VBR в европейском датацентре, если предстоит бекапить виртуалки по всему миру. Оставьте у себя в офисе управляющий сервер, а прокси и репозитории расположите рядом с машинами. Всё для вашего удобства.

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

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

  1. Первым шагом будет проработка ваших RPO и RTO метрик, про которые уже было сказано очень много раз. Главное - запомнить основной посыл: не вы должны решать, с какой периодичностью делать бекапы и как быстро они должны восстанавливаться, а владельцы сервисов и те, кто называется на западе applications team. Вам надо собраться всех вместе и решить, для какого сервиса какой простой будет допустим и какой объём потерянных данных вы сможете пережить без того, что вас всех уволят, а компания закроется. Исходя из этого вы уже сможете построить вашу схему ротации бекапов, известную в англоязычной литературе как retention scheme.

  2. После этого мы уже можем переходить к подсчётам необходимого места. И здесь не надо пытаться изобрести колесо: просто возьмите и посчитайте, сколько места сейчас занимает ваш продакшн.Да, реальный размер будет меньше за счёт дедупликации, компрессии и отбрасывания ненужных блоков, но это тот самый случай, когда никто вам не скажет как именно посчитать коэффициент сжатия (кроме эффективных маркетологов и продавцов). А запас, как мы знаем, карман не тянет.

  3. Посчитали свои терабайты? Отлично, теперь считаем, сколько у нас виртуальных машин/серверов. Совсем хорошо будет, если получится посчитать количество дисков на них, так как несколько дисков параллельно обрабатывать можно, а вот один в несколько потоков не получится. Соответственно, два диска по 500Гб забекапятся быстрее, чем один на терабайт, при прочих равных.

  4. Размер окна резервного копирования ака Backup window. Время, за которое должен состояться ваше бекап. Тут не всё так просто, как может показаться. Есть непосредственно бекап продакшена, который должен быть совершён вне времени основной офисной активности, чтобы не повлиять на сервисы. А есть некие побочные вещи, вроде бекап копи, синтетических трансформаций, записи бекапов на ленты и так далее. Если ваша инфраструктура резервного копирования находится на отдельном оборудовании и может спокойно заниматься своими делами, то вам повезло. Если нет, то ваша задача усложняется: надо, чтобы и сам бекап успел сделаться, и все последующие операции.

  5. И завершает наш парад вводных самая спорная метрика: сколько новых данных в день будет появляться на ваших серверах. Daily change rate, как называют на западе. К сожалению, тут нет единственно верного ответа, как посчитать этот параметр. Кто-то ограничивается примерными значениями, кто-то делает снапшоты и через сутки смотрит на их размеры. Вариантов много, и точного на сто процентов нет. Но вполне можно обойтись и средней температурой по больнице: для машин без высокой активности считается, что в день изменяется не более 5% диска, а в среднем по больнице принято считать, что 10% изменяющихся данных в день - это отличный показатель для дальнейших расчётов.

У пунктов 2 и 5 есть тонкий момент. Как вы прекрасно понимаете, требуемые мощности для того, чтобы успешно и вовремя забекапить весь прод, несколько отличаются от мощностей, необходимых для создания инкрементов. Иногда на порядок. То есть покупать супер-мощный сервер под прокси, который будет только раз в год (а вдруг вам достаточно) упаковывать все ваши петабайты за ночь, а все оставшиеся дни просто греть воздух, может статься и не очень разумным. Возможно, проще будет купить сервер в два раза меньше, но выделять под бекап не четыре часа, а восемь. Или вообще разбить процесс на несколько дней, делая полный бекап только части машин. Словом, момент тонкий и требует отдельного осмысления.

Зато теперь, когда у нас наконец-то есть все вводные данные, можно смело вооружаться калькулятором и начинать считать. При подсчётах мы будем исходить из того, что следуем рекомендациям VBR, и количество параллельно обрабатываемых тасок равно количеству имеющихся у процессора ядер. А одна таска - это один обрабатываемый диск. То есть если у нас на прокси CPU с четырьмя ядрами, то одновременно будут обрабатываться четыре диска с бекапируемых машин. И каждая таска, согласно всё тем же рекомендациям, для спокойной работы требует 2 Гб RAM.

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

Итак, берём вводные: у меня 640 Тб данных, я хочу делать Per-VM бекап (потому что могу), на бекап у меня есть 8 часов ночью, а мой change rate - классические 10%.

Шаг первый: делим объём данных на имеющееся время и получаем некую скорость обработки данных, которой нам надо достичь. В моём случае получается (640 Тб* 1024*1024)/(8 часов * 60* 60) = 23075 Мб/с - такова должна быть пропускная способность нашей системы.

Шаг второй. Пусть жизнь наша нелегка, и всё, что у нас есть - это сервера, которые могут выдать только 100 Мб/с. Делим желаемое на имеющееся и получаем 23075\100= 230. Округляем в большую сторону до 231. Получилось количество необходимых ядер. Да, блюстители размерностей и единиц измерений могут прибывать в ужасе от таких переходов, но куда деваться. Для примера давайте ещё представим, что наши сервера не настолько древние и от гигабита пропускной способности в обморок не падают. Получится, что нам вполне хватит 24 ядра. Более чем посильное число для современного оборудования.

На третьем шаге умножаем количество ядер на рекомендованные 2 Гб на таск и получаем 24*2 = 48 Гб RAM. Да в ноутбуки уже больше ставят, если честно. А вот у коллеги с более старым железом получится 2312 = 462 Гб RAM. Уже более интересное число, но чего только не сделаешь, дабы успеть забекапиться вовремя.

Затем просто делим это цифры на желаемое количество проксей, округляем в большую сторону и получаем искомые параметры. Повторюсь, никто не запрещает вам использовать хоть десять прокси, хоть один. Просто выдавайте им соответствующие ресурсы, и всё будет здорово. У вас по 12 ядер в сервере? Отлично, 231/12 = 20 серверов по 24 Гб оперативки в каждом. И так далее.

И вспоминаем нюанс с инкрементами. Мы договорились принять, что у нас будет меняться по 10% данных в день. Подставляем в наши формулы: (640 Тб*0,1% * 1024*1024)/(8 часов * 60* 60)= 2 331 Мб/c / 100 Мб/c = 24 ядра * 2 Гб RAM на таск = 48 Гб RAM. Значит, при прочих равных для инкрементальных бекапов нам будем достаточно двух серверов, по 24 гига оперативки в каждом.

Вот и вся математика. Как видите, никакой магии тут нет и всё считается довольно просто. Да, в своих подсчётах мы используем некую общую пропускную способность в вакууме, а не берём конкретные цифры по скорости сети, дисковых полок и так далее, но кто кроме вас знает вашу инфраструктуру, её слабые и сильные стороны?

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

Подробнее..

Антистресс для твоего сервера. Тестируем балансировщик нагрузки от Timeweb

07.06.2021 16:20:09 | Автор: admin

Привет, Хабр!


Сегодня мы расскажем сообществу о запуске нашего нового сервиса балансировщик нагрузки.

Сейчас услуга доступна для всех желающих в режиме открытого бета-тестирования в личном кабинете VDS. Это, конечно, бесплатно, а мы будем благодарны вам за комментарии и замечания.

Ребята, почему только сейчас?


Можете вполне резонно спросить вы. Мы, как и все, привыкаем к новой, постпандемийной (или еще нет?), реальности и отвечаем запросам наших клиентов.

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

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

Как это работает?


Балансировщик переправляет клиентские запросы на доступные рабочие серверы из группы. Регулярно опрашивая состояние серверов, балансировщик понимает, какие серверы активны и доступны для обработки клиентских запросов.

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

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

Окей, это всё понятно, а как попробовать?


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

В правилах переадресации задаем параметры проброса трафика, указываем входящий и исходящий порт, а также протокол трафика из доступных: tcp, https, http, http2.



Далее вы можете выбрать один из двух доступных алгоритмов балансировки: Round Robin или Least Connections.

Какой алгоритм выбрать?


Round Robin алгоритм, при котором серверы перебираются по кругу: первый запрос передается на первый сервер, следующий на второй сервер, и так далее до последнего сервера, после чего цикл начинается заново.

Least Connections алгоритм, при котором каждый новый запрос передается на сервер с меньшим количеством активных подключений.

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

Теперь остается только выбрать ваши VDS или указать IP-адреса серверов. Кстати, вы можете использовать балансировщик не только с нашими VDS. Мы будем только за!

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

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

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

Да начнется беспощадный бета-тест!



Подробнее..

Знакомство с exsc (EXtensible Server Core). Часть 1

06.03.2021 22:12:47 | Автор: admin
ПРИВЕТСТВИЕ
image
Всем привет! Хочу поделиться с общественностью библиотекой, на основе которой в данный момент множество серверов, обслуживают тысячи клиентов в различных серверных системах. exsc (EXtensible Server Core) это библиотека, написанная на языке C и позволяет в рамках одного приложения, иметь один или несколько серверных потоков. Каждый серверный поток способен обслужить большое количество клиентов. Хотя библиотеку, можно использовать в модели типа запрос-ответ, в первую очередь она была рассчитана на поддержание постоянного соединения с большим количеством клиентов и обменом сообщений в реальном времени. Поскольку я и сам люблю взять готовый HelloWorld проект, скомпилировать его и посмотреть как всё работает, то в конце статьи я выложу ссылку на такой проект.

ДОКУМЕНТАЦИЯ

Многие операции делаются для определённого соединения. В рамках данной библиотеки за соединение отвечает структура exsc_excon. У этой структуры есть следующие поля:

ix индекс соединения. Это порядковый номер соединения, которое было свободно в момент подключения клиента.
id идентификатор соединения. Это уникальный номер соединения. В отличие от индекса он не повторяется.
addr IP адрес клиента
name имя соединения. Несколько соединений можно назвать одним именем и затем отослать какое-либо сообщение всем соединениям с одинаковым именем (смотрите функцию exsc_sendbyname).

Инициализация ядра

Для того, чтобы работать с ядром, нам необходимо его инициализировать с помощью функции
void exsc_init(int maxsrvcnt);
Параметр maxsrvcnt сообщает ядру, сколько серверных потоков мы будем использовать в рамках нашего приложения.

Запуск серверного потока

Далее нам нужно запустить серверный поток с помощью функции
int exsc_start(uint16_t port, int timeout, int timeframe, int recvbufsize, int concnt,
void newcon(struct exsc_excon excon),
void closecon(struct exsc_excon excon),
void recv(struct exsc_excon excon, char *buf, int bufsize),
void ext());


port порт который будет прослушивать серверный поток.

timeout указывает сколько времени серверный поток будет ожидать какой-либо активности от клиента. Если в течении этого времени клиент не прислал ни одного сообщения, то серверный поток закрывает такое соединение. Поэтому если мы хотим держать постоянную связь и выставили этот параметр на пример 30 секунд, то необходимо раз в 10-15 секунд присылать какое-либо сообщение типа ping.

timeframe временные рамки, за которое мы позволяем выполнить запрос.Так на пример, если это значение выставлено на 100 миллисекунд и серверный поток обработал все текущие запросы от пользователей за 10 секунд, то он оставшиеся 90 миллисекунд оставит процессору для выполнения других задач. Таким образом, чем меньше это значение, тем быстрее серверный поток будет обрабатывать запросы, но тем больше он нагрузит процессор.

recvbufsize размер буфера который серверный поток будет вычитывать за один раз.

concnt максимальное количество соединений с которым серверный поток работает одновременно.

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

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

recv сallback функция, которая будет вызываться когда клиент будет присылать пакеты. В параметры этой функции будет передаваться соединение клиента от которого пришли данные, указатель на данные и размер буфера с данными.

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

Функция exsc_start возвращает дескриптор серверного потока, который понадобится для вызова некоторых функций.

Отправка сообщений
За отправку сообщений отвечает функция
void exsc_send(int des, struct exsc_excon *excon, char *buf, int bufsize);
Эта функция потокобезопасная (её можно вызывать её из любого потока). В качестве параметров необходимо передать ей дескриптор серверного потока (который мы получили как возвращаемое значение функции exsc_start), соединение на которое мы хотим отправить сообщение, указатель на буфер с сообщением и размер буфера.

Так же мы имеем возможность отправить сообщение группе клиентов. Для этого есть функция
void exsc_sendbyname(int des, char *conname, char *buf, int bufsize);
Она аналогична функции exsc_send, за исключением второго параметра, в который передаётся имя подключений которым будет отправлено сообщение.

Задание имени подключения
Для тог, чтобы в будущем как то дополнительно идентифицировать подключение, либо хранить вместе с подключением некоторую информацию о нём, либо отправлять сообщения группе клиентов, используется функция
void exsc_setconname(int des, struct exsc_excon *excon, char *name);
Эта функция потокобезопасная. В качестве первого параметра передаётся дескриптор серверного потока, вторым параметром передаём само подключение и третьим параметром передаём имя этого подключения.

Подключение серверного потока к другому серверу
Иногда, серверная логика требует того, чтобы подключиться к другому серверу, для того чтобы запросить или передать какие либо данные. Для таких задач была введена функция, которая создаёт такое подключение.
void exsc_connect(int des, const char *addr, uint16_t port, struct exsc_excon *excon);
Эта функция потокобезопасная. В качестве параметров нам необходимо передать дескриптор серверного потока, адресс сервера к которому нам необходимо подключиться, потр сервера к которому нам необходимо подключиться и последним параметром мы передаём указатель на соединение с помощью которого мы в дальнейшем сможем вызывать другие функции библиотеки. Стоит отметить что нам нет необходимости дожидаться, пока подключение состоится. Мы можем вызвать функции exsc_connect и exsc_send одну за другой и система сама проследит за тем, чтобы сообщение было отослано сразу после того как сможет подключиться к удалённому серверу.

ПРИМЕР СЕРВЕРА С КОММЕНТАРИЯМИ

#include <stdio.h>  // fgets#include <string.h> // strcmp#include "../exnetwork/exsc.h" // подключаем исходники ядраint g_des; // дескриптор серверного потока// ловим новое подключениеvoid exsc_newcon(struct exsc_excon con){    printf("the connection was open  %s\n", con.addr);}// подключение закрываетсяvoid exsc_closecon(struct exsc_excon con){    printf("the connection was closed  %s\n", con.addr);}// принимаем сообщение от клиентаvoid exsc_recv(struct exsc_excon con, char *buf, int bufsize){    char msg[512] = { 0 };    memcpy(msg, buf, bufsize);    printf("receive data from %s\n%s\n", con.addr, msg);    if (strcmp(msg, "say hello") == 0)    {        strcpy(msg, "hello");        exsc_send(g_des, &con, msg, strlen(msg));    }}void exsc_ext(){}int main(){    printf("server_test_0 is started\n");    exsc_init(2); // инициализируем ядро с расчётом на два серверных потока    // запускаем серверный поток на порту 7777    // он будет держать неактивные соединения 30 секунд    // будет обрабатывать входящие сообщения в рамках 10 миллисекунд    // размер буфера для приёма задаём 1024 байта    // максимальное количество подключений ограничиваем до 10000    g_des = exsc_start(7777, 30, 10, 1024, 10000, exsc_newcon, exsc_closecon, exsc_recv, exsc_ext);    // тормозим главный поток, чтобы программа не завершилась раньше времени    // программа завершится когда мы введём команду exit и нажмём клавишу ENTER    while (1)    {        const int cmdmaxlen = 256;        char cmd[cmdmaxlen];        fgets(cmd, cmdmaxlen, stdin);        if (strcmp(cmd, "exit\n") == 0)        {            break;        }    }    return 0;}


ЗАКЛЮЧЕНИЕ
Ядро exsc осуществляет только низкий уровень взоимодействия с клиентами. Хоть это и самый важный элемент серверной системы, основа на которой всё строится, помимо него нужно строить более верхние уровни, которые будут отвечать за управление подключений, генерирование сообщений, сборку сообщений (которые вероятно будут приходить за несколько этапов). Если статья будет иметь положительный отклик то я напишу вторую чать, в которой разовью тему более верхнего уровня этой библиотеки написанной с использованием Qt, а именно про класс ExServer.

Ссылка на библиотеку github.com/extenup/exnetwork

Пример расположен в архиве exsc_test_0.zip
Подробнее..

Многопоточный HTTP-сервер с ThreadPoolом и конечным автоматом

23.05.2021 12:20:57 | Автор: admin

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

Проблемы решения "один поток = один клиент"

Проблемы, которые описаны ниже, справедливы как для потоков, так и для процессов, поэтому "один поток = один клиент" также можно расценивать как и "один процесс - один клиент" в данном контексте.

Первая проблема - количество потоков, которые могут быть созданы в программе, ограничено. Следствием этого ограничено и количество пользователей, подключённых к нашему серверу. Такая проблема есть, например, у Apache.

Проблема вторая - один поток занят только одним клиентом. В связи с этим мы получаем неэффективное использование ресурсов. (поток может простаивать, пока ждёт события от клиента)

Плюсом ко всему этому нужно понимать, что создание потока (или процесса) - это довольно тяжелая операция, и иногда она требует затрат больше, чем само обслуживание клиента.

Решение, которое я приведу ниже, закрывает эти проблемы.

Решение есть

Первая проблема решается тем, что количество потоков мы сделаем независимым от количества наших клиентов. Количеством потоков мы управляем сами (оно может устанавливаться как статистически, при запуске сервера, так и динамически, подстраиваясь под нагрузку, например).

Вторая проблема закрывается тем, что потоки не прикреплены к клиентам. Фактически, обслуживание клиента разбивается на задачи, которые решают потоки. Таким образом, мы избавляемся от простоев потоков, если работа для них есть.

Конечный автомат

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

На каждое состояние у нас есть свой хэндлер. Рассмотрим пример. У клиента четыре состояния: readRequest, generateResponse, sendResponse и closeConnection (чтение запроса, создание ответа, отправка ответа и закрытие соединения, соответственно). На каждое состояние мы имеем хэндлер. readRequest читает и парсит запрос и, в зависимости от успеха чтения и парсинга (например, в зависимости от того, что вернула функция чтения запроса), переключает состояние либо на generateResponse, либо на closeConnection. generateResponse отвечает за генерацию ответа и переключает состояние клиента на sendResponse. sendResponse отправляет ответ клиенту и либо возвращет клиента на состояние readRequest, либо переключает на closeConnection. closeConnection, в свою очередь, просто отключает клиента и удаляет его.

Этот примитивный пример показывает суть принципа. Мы можем добавлять новые состояния клиентов (причем в коде делается это довольно просто: мы просто реализуем новый метод) и переключать их как угодно в зависимости от условий. Вы можете с легкостью разбивать состояние на два отдельных, если чувствуете в этом необходимость. В нашем примере парсинг запроса включен в состояние readRequest и его можно вынести в отдельное состояние - parsingRequest, например.

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

Довольно неплохая лекция на тему конечных автоматов. Также информации об этом методе в интернете полно, поэтому заострять внимание на деталях мы не будем.

ThreadPool (или пул потоков)

Пул потоков как таковым пулом потоков не является. Скорее он представляет собой пул (в виде очереди, например) задач для этих потоков.

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

Если наш клиент отправил нам только часть запроса, поток в сервере формата "один клиент=один поток" будет ожидать оставшуюся часть запроса. (то есть простаивать) В нашем же случае поток обработает часть запроса и пойдет обрабатывать следующих клиентов, если такие есть (простаивания потока не происходит).

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

Заключение

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

В этот раз я в общих чертах рассказал только про суть подхода. Если вам интересно увидеть продолжение статьи уже с практической частью (подходы к реализации и их подводные камни) - дайте знать об этом:)

На этом все. Делитесь своими вариантами, предложениями, дополнениями и критикой в комментариях! Благодарю за прочтение:)

Несколько полезных ссылок:

http://personeltest.ru/aways/habr.com/ru/post/260065/

http://personeltest.ru/aways/habr.com/ru/company/latera/blog/273283/

http://www.aosabook.org/en/nginx.html

Подробнее..

Перевод Прогрессивный рендеринг для лучшей производительности веб-приложений

07.02.2021 18:17:06 | Автор: admin

Понимание концепций рендера веб-страниц и измерение производительности рендера с помощью Chrome DevTools




Не важно, насколько хорош ваш сайт; если его загрузка занимает слишком много времени, никто не будет ждать, чтобы его увидеть. Если ваш сайт загружается более 3 секунд, есть большая вероятность, что вы потеряете часть посетителей. Но знаете ли вы, что можно значительно улучшить время загрузки своего веб-приложения, используя прогрессивный рендеринг? Прогрессивный рендеринг не только увеличивает скорость загрузки, но и решает некоторые серьёзные проблемы в методах рендеринга на стороне клиента и на стороне сервера. Чтобы лучше понять прогрессивный рендеринг, давайте посмотрим, как работает рендеринг на стороне клиента и на стороне сервера.



Рендеринг на стороне клиента


Рендеринг на стороне клиента (CSR) это метод, при котором контент рендерится в браузере с помощью JavaScript. Вместо того чтобы получать весь контент из самого HTML-файла, сервер отправляет HTML с пустым body и тегами script, в которых содержатся ссылки на JavaScript-бандлы, с помощью которых браузер будет рендерить контент. Теперь давайте посмотрим, как происходит рендеринг страницы на стороне клиента:

  1. Когда пользователь переходит на веб-страницу, отправляется запрос на получение HTML-документа.
  2. Сервер отправляет HTML-код с пустым телом и тегами script для загрузки JS-бандлов.
  3. Браузер анализирует HTML и шлёт HTTP-запросы для получения JS-бандлов. В это время пользователь видит либо часть содержимого HTML, либо пустую страницу, либо индикатор загрузки.
  4. Только после того как основной JS-бандл получен и отрисован, пользователь видит реальный, значимый контент.

В CSR после загрузки JS контент будет загружаться асинхронно. Мы можем сначала загрузить критически важный контент, а затем второстепенный.

Рендеринг на стороне клиента

CSR имеет небольшое преимущество благодаря кэшированию загруженных JS-бандлов и статического HTML, поэтому навигация между страницами становится очень быстрой. Однако в CSR контент начинает загружаться только после выполнения всего JavaScript-бандла, а пользователям приходится сидеть сложа руки, просто наблюдая за пустым экраном без понимания, что происходит. По мере увеличения размера бандла пользователям придется ждать всё больше и больше, прежде чем они увидят что-нибудь осмысленное или начнут использовать страницу. Но что, если мы сможем рендерить контент независимо от JS-бандла? Здесь на помощь приходит рендеринг на стороне сервера (SSR)!

Рендеринг на стороне сервера


При рендеринге на стороне сервера HTML-код рендерится на сервере и отправляется клиенту. Контент, который нам нужно отобразить на экране, становится доступен сразу после анализа HTML; следовательно, первичный рендеринг контента происходит быстрее, чем у CSR. Теперь давайте разберёмся, как работает SSR:

  1. Браузер запрашивает HTML с сервера.
  2. Сервер делает API запросы и рендерит HTML-контент на своей стороне.
  3. Скомпилированный HTML-код отправляется в браузер.
  4. Как только браузер загружает и анализирует HTML, веб-приложение становится доступным для конечного пользователя, не дожидаясь загрузки JS-бандлов.
  5. Браузер загружает и запускает JS-бандлы, чтобы сделать страницу интерактивной.

Поскольку API обычно размещён на сервере, а исходный JavaScript не блокирует контент, в SSR исходный контент загружается очень быстро.

Серверный рендеринг

Хотя мы и получаем быструю отрисовку контента, страница не будет интерактивной, пока мы не загрузим и не выполним JS.

Мы можем справиться с недостатками CSR с помощью SSR. Но остаются другие серьёзные недостатки, такие как рендеринг критического и некритического контента перед его отправкой клиенту. Я знаю, о чём вы сейчас думаете. Есть ли подход, в котором мы можем объединить оба упомянутых метода, верно? У меня есть хорошие новости для вас! Используя прогрессивный рендеринг, вы объедините преимущества CSR и SSR. Теперь давайте посмотрим, как мы можем сделать впечатления ваших клиентов приятнее с помощью техники прогрессивного рендеринга.

Прогрессивный рендеринг на стороне сервера


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

Прогрессивный рендеринг на стороне сервера (PSSR) основан на концепции потоковой передачи HTML. PSSR разбивает страницы на осмысленные компоненты с помощью разделения кода. Эти части страницы управляются разными скриптами, и теперь у нас есть возможность сделать гидратацию независимо. Давайте посмотрим, как работает PSSR:

  1. Браузер запрашивает у сервера HTML-код.
  2. Сервер делает API запросы и сначала рендерит критический контент, а затем отправляет его клиенту.
  3. Браузер анализирует HTML и отображает его на экране.
  4. Сервер рендерит некритический контент и передает его браузеру.
  5. Затем браузер анализирует и отображает некритичный контент.
  6. Между тем JS-бандлы загружаются и выполняются в фоновом режиме, а браузер передаёт интерактивность элементам DOM.

PSSR повышает производительность вашего веб-приложения, извлекая и визуализируя компоненты страницы параллельным и приоритетным образом. Этот подход известен как метод прогрессивной гидратации. Особенности метода прогрессивной гидратации:

  • Рендер компонента не происходит до тех пор, пока он не появится в поле зрения или не понадобится для взаимодействия с пользователем.
  • Загрузка контента при взаимодействии с пользователем (прокрутка) намного быстрее, чем при CSR или SSR
  • Тестирование показывает, что это может сократить время до появления первого интерактивного элемента.
  • Впечатления приятнее даже при медленном соединении.

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

Критические этапы рендеринга


Оптимизация критических этапов рендеринга относится к приоритизации расположения контента, который связан с текущей деятельностью пользователя. Браузер выполняет много негласной работы, чтобы впечатления от работы со страницей были приятнее. Критические этапы рендеринга это непосредственные шаги между получением HTML, CSS и JS и обработкой, необходимой для их преобразования в видимые пиксели.

Вы можете сократить время первичного рендеринга вашего веб-приложения, оптимизировав критические этапы рендеринга

Поскольку теперь у вас есть хорошее понимание клиентского, серверного и прогрессивного рендеринга, вы, наверное, думаете, есть ли способ оценить производительность рендеринга. Ответ есть! Chrome DevTools предоставляет отдельную вкладку для мониторинга и оценки производительности рендеринга. Давайте посмотрим, как мы можем её использовать.

Анализ производительности с помощью Chrome DevTools


Даже в небольшом приложении под капотом выполняется много рендеринга. Вкладку Rendering в Chrome DevTools можно использовать для выявления проблем, связанных с рендерингом в JavaScript приложениях.

Инструмент Paint flashing


По мере того как интерфейс становится более многофункциональным и сложным, жизненно важно рассмотреть способы оптимизации взаимодействия с пользователем за счёт уменьшения как времени загрузки, так и критического пути компонентов. Рендер контента на экране один из самых дорогостоящих процессов. Чтобы визуализировать этот процесс, можно использовать удобный инструмент Paint Flashing, доступный на вкладке Rendering.


Текущие области рендеринга будут подсвечены зелёным цветом, если эта опция включена в Chrome. Если вы видите области, которые вы не планировали рендерить, можно копнуть немного глубже.



Scrolling performance issues в Chrome DevTools


Scrolling performance issues это ещё один удобный инструмент, который вы можете использовать для выявления любых проблем, связанных с производительностью во время прокрутки страницы. Когда эта опция включена, она вешает на компоненты метку Repaints on scroll и подсвечивает зелёным цветом те компоненты, которые рендерятся при прокрутке страницы.


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

Заключение


При разработке веб-приложения очень важно понимать основные принципы рендеринга. Эти знания помогут вам оптимизировать производительность вашей веб-страницы. По статистике, задержка загрузки страницы на одну секунду снизит ваш коэффициент конверсии на 7 %. С другой стороны, длительная загрузка может оказать разрушительное влияние на конверсию приложения. В этой статье я рассказала о трёх методах рендеринга и объяснила, почему прогрессивный рендеринг на стороне сервера имеет больше преимуществ по сравнению с двумя другими методами, а также как он помогает повысить производительность вашего веб-приложения.



image



Подробнее..

Перевод Где поместить свой сервер, чтобы обеспечить максимальную скорость? Насколько это важно?

26.03.2021 18:19:00 | Автор: admin

Где поместить свой сервер, чтобы обеспечить максимальную скорость? Помимо времени, необходимого серверам для ответа на запросы, требуется время просто для доставки пакета из пункта А в пункт Б.

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


По мере роста сетевых задержек могут происходить странные вещи: толстые сайты могут стать более быстрыми (особенно если они полностью обслуживаются из CDN), а тонкие сайты, использующие API-интерфейсы, могут стать более медленными. Для пользователя настольного ПК/ноутбука типичная задержка достигает 200 мс, а для мобильного пользователя 4G составляет 300400 мс. В этой статье предполагается, что пропускная способность равна 40 Мбит/с, поддерживается TLS, задержка CDN равна 40 мс и нет существующих соединений. Исходная точка здесь означает основной веб-сервер (в отличие от пограничных кэшей CDN).

Почему местоположение имеет значение

Время пересечения Интернета добавляется ко времени, затраченному на ответ на запрос. Даже если ваш API-интерфейс способен ответить на запрос за 1 мс, когда пользователь находится в Лондоне, а API-сервер в Калифорнии, пользователю всё равно придется ждать ответа около 130 мс.

Весь процесс занимает немного больше 130 мс. В зависимости от того, что делают пользователи, в конечном счёте они могут совершить несколько таких операций передачи и подтверждения. Для загрузки веб-страницы обычно требуется пять полных операций передачи и подтверждения: одна для разрешения доменного имени с помощью DNS, одна для установления TCP-соединения, ещё две для настройки зашифрованного сеанса с TLS, и, наконец, одна для страницы, которую вы хотели получить в первую очередь.

В последующих запросах можно (но не всегда) повторно использовать настройки DNS, TCP и TLS, но при каждом обращении к серверу, например при вызове API-интерфейса или при создании новой страницы, по-прежнему требуется новая операция передачи и подтверждения.

Сначала кажется, что 130 мс это быстро, но вся эта долгая и муторная процедура с простым получением страницы и последующим выполнением пары API-вызовов может легко занять большую часть секунды только с точки зрения времени ожидания сетевого сигнала. Всё остальное необходимое время время выбора сервером ответа на запрос, время загрузки нужных данных, а затем время визуализации содержимого в браузере всё это дополнительное время.

Два вида понятия быстрый для сетей

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

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

API-интерфейсы, или сети CDN

Существует сеть, в которой операции выполняются быстрее, это сеть дистрибуции содержимого (Content Distribution Network, CDN). Вместо того чтобы пройти весь путь до Калифорнии, возможно, вы сможете получить часть веб-страницы из кэша в Центральном Лондоне. Такой подход экономит время. Операция может занять всего 50 мс. Экономия достигает 60 %. Кэш отлично работает для CSS-файлов, изображений и JavaScript, т. е. для ресурсов, которые не меняются для всех пользователей. Он не так хорошо работает для ответов на API-вызовы, так как ответы различны для каждого пользователя, а порой и всегда.

Количественный подход

Немногие счастливчики все запросы могут обрабатывать с помощью CDN. Новостные сайты, например, показывают всем одно и то же. Другие менее удачливы и могут применять кэширование лишь в ограниченном объёме или вообще не использовать его. Эти несчастные люди должны выбрать такое место для своего основного сервера, чтобы максимально быстро доставлять свои данные пользователям, которые в них нуждаются. Если этот выбор направлен лишь на уменьшение задержки, какое место они должны выбрать?

Вот что я сделал:

  1. Я взял собственные журналы доступа за две недели в сентябре сразу после того, как опубликовал что-то новое. За этот период я получил около миллиона запросов от 143 тыс. уникальных IP-адресов. Я исключил очевидных роботов (на которые пришлись около 10 % запросов).

  2. Я использовал базу данных GeoIP компании Maxmind для привязки каждого IP-адреса в этих журналах доступа к соответствующим географическим координатам.

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

  4. Я сопоставил (полуавтоматически, что было довольно мучительно) названия этих городов с идентификаторами Geonames, что позволило получить координаты городов.

  5. Затем я загрузили всё вышеперечисленное в базу данных Postgres с установленным расширением PostGIS для выполнения географических запросов.

  6. Я запросил оценку длительности (в процентах) выполнения запросов в ситуациях, когда мой сервер находился бы в каждом из 200 городов.

Результаты

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

  • среднее (P50);

  • для трёх четвертей запросов (P75);

  • для 99 % запросов (P99).

Все числа выражены в миллисекундах.

Все результаты см. в таблице

City

p50

p75

p99

Manhattan

74

97

238

Detroit

89

115

245

Secaucus

71

96

246

Piscataway

75

98

251

Washington

82

105

253

Chicago

90

121

253

Kansas City

98

130

254

Indianapolis

96

125

254

St Louis

96

127

256

Cincinnati

92

121

257

Houston

104

134

257

Syracuse

77

102

257

Scranton

78

103

258

Quebec City

83

113

259

South Bend

92

118

259

Montreal

83

104

259

Charlotte

91

110

259

Salem

74

98

259

Buffalo

80

111

259

Albany

75

100

260

Monticello

94

123

260

Baltimore

80

105

260

Asheville

95

118

260

New York

77

103

261

Berkeley Springs

84

112

261

Minneapolis

102

133

261

Barcelona

102

148

261

Dallas

112

140

262

Des Moines

104

131

262

San Jose

139

165

263

Brunswick

77

101

264

Atlanta

88

113

264

San Francisco

136

168

264

Halifax

80

102

265

Philadelphia

77

100

266

Basel

97

146

267

Green Bay

103

131

267

Pittsburgh

88

117

267

Bern

99

147

267

Denver

112

141

267

Miami

103

129

267

Raleigh

88

111

268

Knoxville

114

135

268

Boston

77

105

268

Valencia

108

148

268

Jackson

105

132

268

Memphis

101

131

268

Jacksonville

95

122

268

Madrid

95

138

268

London

76

130

268

San Diego

138

162

269

San Antonio

112

138

269

Salt Lake City

120

151

269

Toronto

87

111

269

Cleveland

97

122

269

Austin

113

141

270

Colorado Springs

110

136

270

Orlando

103

126

270

Antwerp

93

137

271

Oklahoma City

114

147

271

Saskatoon

115

140

272

Lansing

98

127

272

Seattle

141

164

272

Columbus

92

120

273

Bristol

76

129

274

Tampa

104

130

274

Lausanne

95

139

274

Ottawa

85

111

274

Falkenstein

91

137

275

Maidstone

76

129

275

Paris

80

129

275

Toledo

102

129

275

Savannah

117

146

276

The Hague

82

138

276

Liege

87

136

277

Lincoln

100

124

277

New Orleans

115

142

278

Amsterdam

82

140

278

Las Vegas

136

163

279

Vienna

102

149

279

Coventry

80

132

279

Cromwell

80

106

280

Arezzo

109

160

280

Cheltenham

79

131

280

Sacramento

137

167

280

Alblasserdam

82

137

281

Vancouver

142

165

281

Fremont

131

157

283

Gosport

76

137

284

Frankfurt

93

136

284

Carlow

88

136

285

Phoenix

128

153

285

Portland

132

159

285

Cardiff

78

131

285

Luxembourg

87

137

285

Bruges

83

135

285

Eindhoven

85

133

285

Groningen

87

139

286

Manchester

80

137

286

Brussels

90

139

287

Brno

106

148

287

Edinburgh

84

136

287

Nuremberg

89

136

288

Albuquerque

125

159

289

Los Angeles

141

164

289

Ljubljana

110

152

289

Lugano

97

147

290

Zurich

103

146

290

Dronten

84

133

290

Newcastle

87

147

290

Rome

96

147

291

Dusseldorf

90

140

291

Munich

98

144

291

Venice

106

156

292

Edmonton

139

165

292

Copenhagen

96

145

292

St Petersburg

113

163

293

Dublin

85

143

293

Redding

142

178

293

Vilnius

110

162

293

Belfast

79

125

294

Nis

113

158

294

Douglas

87

143

294

Rotterdam

82

139

295

Bergen

107

157

295

Strasbourg

89

141

295

Roseburg

148

172

296

Graz

104

147

296

San Juan

117

141

298

Warsaw

108

161

299

Frosinone

105

153

299

Riyadh

159

206

300

Prague

103

152

301

Ktis

102

158

302

Mexico

139

164

302

Belgrade

113

160

302

Guadalajara

128

155

303

Milan

96

146

305

Bratislava

102

154

306

Osaka

181

240

307

Zagreb

103

150

308

Tallinn

108

162

308

Helsinki

105

156

308

Hamburg

127

166

309

Oslo

98

153

311

Bucharest

120

162

311

Riga

113

159

312

Panama

150

177

313

Tokyo

188

238

313

Kiev

119

168

313

Stockholm

102

153

314

Budapest

110

162

314

Kharkiv

128

169

315

Gothenburg

115

167

316

Pristina

122

167

316

Tirana

128

184

316

Geneva

96

142

316

Siauliai

113

163

317

Cairo

133

182

318

Sapporo

196

255

318

Bogota

170

188

319

Palermo

119

183

320

Gdansk

107

152

320

Caracas

149

176

320

Sofia

114

161

321

Westpoort

79

134

321

Honolulu

173

196

321

Roubaix

102

157

321

Kazan

138

190

322

Winnipeg

169

190

322

Varna

120

173

322

Tel Aviv

138

194

322

Lisbon

115

166

324

Jerusalem

145

198

324

Ankara

139

195

327

Heredia

164

188

327

Athens

128

183

329

Reykjavik

127

180

329

Paramaribo

166

194

330

Algiers

120

173

332

Chisinau

127

180

333

Bursa

135

188

334

Thessaloniki

134

187

336

Limassol

141

186

337

Lyon

95

145

340

Mumbai

204

248

340

Medellin

163

186

344

Valletta

120

176

345

Baku

160

205

346

Melbourne

227

269

346

Fez

149

198

348

Tunis

124

180

348

Koto

217

254

348

Dubai

192

243

350

Tbilisi

153

208

351

Malaysia

195

235

352

Hyderabad

214

260

354

Bangalore

212

252

355

Izmir

137

187

357

Adelaide

241

272

359

Chennai

221

248

359

Moscow

127

172

359

Lahore

217

270

361

Novosibirsk

163

206

362

Sydney

237

272

363

Karaganda

180

231

363

Vladivostok

223

264

364

Taipei

265

293

364

Lima

169

199

364

Istanbul

135

182

366

Hong Kong

199

223

366

Auckland

244

291

367

Jakarta

207

245

368

Seoul

231

277

371

Beirut

136

195

372

Accra

168

216

373

Singapore

190

246

374

Sao Paulo

193

213

375

Joao Pessoa

182

220

378

Perth

243

267

379

Ho Chi Minh City

253

287

380

Wellington

251

295

383

Brasilia

226

249

384

Manila

251

281

385

Pune

202

251

386

Dhaka

231

268

386

Phnom Penh

243

267

386

Santiago

202

230

390

Lagos

191

233

391

Quito

162

188

392

New Delhi

230

264

395

Johannesburg

237

283

398

Bangkok

222

254

401

Canberra

262

295

402

Dar es Salaam

214

267

407

Dagupan

239

268

408

Christchurch

257

309

409

Hanoi

235

264

415

Cape Town

216

262

417

Buenos Aires

232

253

417

Guatemala

217

249

418

Brisbane

261

288

422

Indore

304

352

457

Zhangjiakou

236

264

457

Nairobi

233

277

468

Kampala

244

287

480

Hangzhou

239

267

517

Shenzhen

242

275

523

Shanghai

300

367

551

Montevideo

738

775

902

Вы также можете загрузить все результаты как csv-файл, если так проще.

Результат: восточное побережье Северной Америки хорошо, прямо в Атлантике лучше

Все лучшие места находятся в Северной Америке. Это, вероятно, не стало полным сюрпризом, учитывая, что это довольно плотный кластер носителей английского языка, от которого не так далеко (с точки зрения задержки), в Великобритании/Ирландской Республике, находится другой кластер. Кроме того, в Европе много тех, для кого английский второй язык. Лучше всего находиться прямо в Атлантике: в штатах Нью-Джерси и Нью-Йорк есть много отличных мест для P99, и показатели в верхней части, между P50 и P99, варьируются не слишком сильно.

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

В настоящее время мой сервер находится в Хельсинки. Это был самый дешёвый вариант, что необычно для Финляндии. За этот сервер я плачу около трёх фунтов в месяц, всего лишь. Если бы я переместил его куда-нибудь в Нью-Джерси и потратил больше денег, в целом пользователи определённо сэкономили бы время: половина операций передачи и подтверждения была бы завершена за 75, а не за 105 мс, что позволило бы сэкономить 30 %. За несколько операций передачи и подтверждения время, вероятно, увеличилось бы примерно на шестую долю секунды по сравнению со средним показателем загрузки первой страницы, что не так уж плохо. Если вы не можете сказать, что этот веб-сайт очень обременителен для веб-браузеров с точки зрения визуализации, сокращение времени ожидания в сети сделает его значительно быстрее.

Поскольку на этом сайте ничего не генерируется динамически, в действительности мне лучше всего использовать CDN. Это действительно сэкономило бы много времени для всех: обслуживание из CDN почти в два раза лучше (~40 мс) установки сервера в самом быстром месте (71 мс).

Как это может меняться со временем

Задержки не фиксированы, и со временем они могут уменьшиться. Здесь предлагается таблиц задержек операций передачи и подтверждения при передаче данных из Лондона в другие города мира с населением более 5 млн. человек. Значения сравниваются с теоретической максимальной скоростью скоростью света:

Город

Расстояние (км)

Реальная задержка

Теоретический максимум

Фактор замедления

Нью-Йорк

5 585

71

37

1,9

Лима

10 160

162

68

2,4

Джакарта

11 719

194

78

2,5

Каир

3 513

60

23

2,6

Санкт-Петербург

2 105

38

14

2,7

Бангалор

8 041

144

54

2,7

Богота

8 500

160

57

2,8

Буэнос-Айрес

11 103

220

74

3,0

Лагос

5 006

99

33

3,0

Москва

2 508

51

17

3,0

Сан-Паулу

9 473

193

63

3,1

Бангкок

9 543

213

64

3,3

Гонконг

9 644

221

64

3,4

Стамбул

2 504

60

17

3,6

Лахор

6 298

151

42

3,6

Токио

9 582

239

64

3,7

Ханчжоу

9 237

232

62

3,8

Шанхай

9 217

241

61

3,9

Mumbai

7 200

190

48

4,0

Тайбэй

9 800

268

65

4,1

Дакка

8 017

229

53

4,3

Сеул

8 880

269

59

4,5

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

Как видно из таблицы, задержка в Нью-Йорке находится в пределах коэффициента 2 от значения для скорости света, но маршруты в другие места, такие как Дакка и Сеул, намного медленнее: они в 4 раза превышают значения для скорости света. Вероятно, маршрут между Лондоном и Нью-Йорком так хорошо оптимизирован по вполне понятным причинам. Я сомневаюсь, что то, что между этими городами в основном лежит океан, представляет большую проблему, так как подводные кабели можно прокладывать напрямую. Добираться до Сеула или Дакки придётся более окольным путём.

Вероятно, следует упомянуть, что новые протоколы обещают уменьшить количество операций передачи и подтверждения. Версия TLS 1.3 позволяет создать зашифрованный сеанс с одной операцией передачи и подтверждения, а HTTP3 может объединить операции передачи и подтверждения протоколов HTTP и TLS. Это означает, что теперь нужны лишь три такие операции: одна для DNS, одна-единственная операция передачи и подтверждения для соединения и зашифрованного сеанса, и, наконец, третья для темы запроса.

Некоторые люди ложно надеются, что новые протоколы, такие как HTTP3, устранят необходимость в объединении (bundling) JavaScript/CSS. Это основано на недоразумении: в то время как HTTP/3 удаляет некоторые исходные операции передачи и подтверждения, эта версия не удаляет последующие операции передачи и подтверждения для дополнительных данных JavaScript или CSS. Так что объединение, к сожалению, никуда не делось.

Слабые стороны данных

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

Во-первых, база данных GeoIP неоднозначно показывает местоположение IP-адресов. Заявленная (т. е., вероятно, оптимистичная) точность колеблется до 1000 км в некоторых случаях, хотя для моего набора данных утверждается, что средняя точность составляет 132 км со стандартным отклонением 276 км. Это не так уж точно, но я думаю, всё ещё полезно.

Мой источник данных о задержке, WonderNetwork, действительно сообщает данные о задержке на момент их получения (30 ноября 2020 года) в отличие от долгосрочных данных. Иногда в определённых местах Интернет барахлит.

У WonderNetwork много станций, но их охват не идеален. На Западе всё отлично в Великобритании представлены даже второстепенные города (вроде Ковентри). Их охват во всём мире по-прежнему хорош, но более неоднозначен. У них не так много мест в Африке или Южной Америке, а некоторые задержки в Юго-Восточной Азии кажутся странными: задержка между Гонконгом и Шэньчжэнем составляет 140 мс, тогда как эти города находятся всего в 50 км друг от друга. Этот фактор замедления более чем в тысячу раз превышает значение для скорости света. Для других городов континентального Китая проверка связи также показывает плохие результаты (что странно), хотя и не в таком масштабе. Может быть, эти коммунисты проверяют каждый ICMP-пакет вручную?

Другая проблема с данными о задержке заключается в отсутствии истинных координат центров обработки данных, в которых находятся серверы. Мне пришлось самому геокодировать данные с помощью некоторых сценариев и большого количества ручного ввода данных в Excel (я опубликовал эту таблицу Excel в github, чтобы никому не пришлось делать эту работу заново). Я очень старательно проверял данные, но ошибки всё ещё могут быть.

Однако, по моему мнению, самая большая слабость заключается в том, что все начинают отсчёт прямо от центра своего ближайшего города. На практике это не так и добавляемое из-за этого смещение может варьироваться. Здесь, в Великобритании, домашний доступ к Интернету это сложный процесс, основанный на отправке высокочастотных сигналов по медным телефонным линиям. Моя собственная задержка для других хостов в Лондоне достигает 9 мс, что плохо для такого короткого расстояния, но всё ещё на 31 мс лучше среднего значения. Многие маршрутизаторы потребительского уровня не очень хороши и добавляют значительную задержку. Печально известная проблема излишней сетевой буферизации ещё один распространённый источник задержки. Особенно это влияет на процессы, для хорошей работы которых требуется последовательный уровень задержки. В качестве примера можно привести видеоконференц-связь и многопользовательские компьютерные игры. Использование сети мобильных телефонов тоже не помогает. Сети 4G в хороших условиях добавляют около 100 мс задержки, но, конечно, всё гораздо хуже, когда уровень сигнала низок и есть много ретрансляций на уровне канала.

Я пытался предположить глобальную среднюю задержку на километр (около 0,03 мс), чтобы компенсировать расстояние до ближайшего города, но обнаружил, что это просто добавило кучу шума к моим результатам, так как для многих IP-адресов в моём наборе данных окольный путь был нереалистичным: ближайший город, который я им приписал, совсем не так близок.

Универсальность

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

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

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

Бесплатные операции передачи и подтверждения

Выбор хорошего места для вашего сервера заходит так далеко. Даже в хороших случаях у вас всё ещё будет почти 100 мс задержки за каждую операцию передачи и подтверждения. Как я писал выше, при посещении страницы может быть до пяти операций передачи и подтверждения.

Наличие ненужных операция передачи и подтверждения действительно замедлит процесс. Одна дополнительная операция передачи и подтверждения сводит на нет изрядную долю выигрыша от размещения сервера в быстром месте.

Операции передачи и подтверждения легко добавить случайно. Особенно удивительным источником операций передачи и подтверждения служат предварительные запросы общего доступа к ресурсам независимо от источника (CORS). По соображениям безопасности, связанным с предотвращением атак на основе межсайтового скриптинга, браузеры должны проверять определённые HTTP-запросы, созданные кодом JavaScript. Для этого на тот же URL-адрес предварительно отправляется запрос с помощью специальной команды OPTIONS. На основе полученного ответа принимается решение о допустимости исходного запроса. Правила, определяющие точный момент отправки предварительных запросов, сложны, но в сети появляется удивительное количество запросов: в частности, включая POST-запросы JSON к поддоменам (например, к поддомену api.foo.com от домена foo.com) и сторонние веб-шрифты. В предварительных проверках на основе CORS-запросов используется другой набор заголовков кэширования по сравнению с остальным HTTP-кэшированием, которые редко задаются правильно и в любом случае применимы только к последующим запросам.

В наши дни многие сайты написаны как одностраничные приложения, где вы загружаете некоторый статический пакет JavaScript (надеюсь, из CDN), а затем создаёте (надеюсь, небольшое) количество API-запросов внутри своего браузера, чтобы решить, что показывать на странице. Есть надежда, что этот процесс станет быстрее после первого запроса, так как не придётся перерисовывать весь экран, когда пользователь попросит загрузить вторую страницу. Как правило, это не помогает, потому что одна HTML-страница обычно заменяется несколькими последовательными API-вызовами. Пара последовательных API-вызовов к исходному серверу почти всегда обрабатывается медленнее перерисовки всего экрана, особенно в сети мобильной связи.

Я всегда считаю немного вздорной ситуацию, когда я получаю загружающуюся панель на веб-странице вы уже отправили мне страницу, но почему сразу не отправили нужную мне страницу?! Один из величайших парадоксов Интернета заключается в том, что, хотя Google не очень хорошо справляется с обходом таких одностраничных приложений, эта компания, безусловно, создаёт большое их количество. Особенно дьявольской является консоль поиска (веб-сайт, ранее известный как средства веб-мастера). Я полагаю, Google не нужно слишком беспокоиться об оптимизации поисковых систем (SEO).

Пропускная способность быстро увеличивается, но задержка уменьшается медленно

Пропускная способность Интернета становится всё лучше и лучше. Сейчас можно передавать гораздо больше байт в секунду, чем даже несколько лет назад. Однако улучшения задержки довольно редки, и по мере приближения к значению для скорости света они совсем сойдут на нет.

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

Смотрите также

В прошлом году в центре APNIC проанализировали производительность CDN по всему миру и пришли к выводу, что задержка 40 мс типична. Мне бы хотелось, чтобы в эту публикацию были включены процентильные данные, но у меня сохраняется смутное впечатление, что сети CDN лучше всего работают на Западе и менее хорошо в Южной Америке, Китае и Африке, что является проблемой, учитывая, что большинство серверов находится на Западе.

Пока я писал эту статью, произошла вспышка клубов, основанных на весе страницы, таких как Клуб 1МБ и, предположительно, более элитный Клуб 512К. Пожалуй, я одобряю это чувство (и всё это во имя веселья, я уверен). Я думаю, что они слишком подчёркивают размер передаваемых данных. Если вы в Лондоне запрашиваете динамически генерируемую страницу из Калифорнии, весь процесс всё равно займёт большую часть секунды (130 мс умножить на 5 операций передачи и подтверждения), независимо от того, насколько велик размер этой страницы.

На карту подводных кабелей всегда приятно смотреть. Если вы хотите увидеть признак разной важности разных мест: Нормандские острова (население 170 тыс. человек) имеют 8 подводных кабелей, в том числе два, которые просто соединяют Гернси и Джерси. У Мадагаскара (население 26 млн. человек) их всего четыре. Я также считаю забавным то, что, хотя Аляска и Россия довольно близки, между ними нет ни одного кабеля.

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

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

Другие профессии и курсы
Подробнее..

Читаем EXPLAIN на максималках

02.03.2021 22:15:14 | Автор: admin

Многим, кто работает с MySQL, известно, что команда EXPLAIN используется для оптимизации запросов, получения информации об использованных и возможных индексах. Большинство разработчиков и администраторов СУБД этой информацией и ограничивается. Я же предлагаю изучить команду EXPLAIN максимально подробно.

Логическая архитектура MySQL

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

Её можно разделить на несколько уровней:

  1. Уровень приложения или клиентский уровень. Он не является уникальным для MySQL. Обычно здесь находятся утилиты, библиотеки или целые приложения, которые подключаются к серверу MySQL.

  2. Уровень сервера MySQL. Его можно разделить на подуровни:

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

    B. Сервер MySQL. Этот подуровень во многих источниках называют мозгами MySQL. К нему относятся такие компоненты, как кеши и буферы, парсер SQL, оптимизатор, а также все встроенные функции (например, функции даты/времени и шифрования).

  3. Уровень подсистем хранения. Подсистемы хранения отвечают за хранение и извлечение данных в MySQL.

Нас интересует второй уровень, точнее подуровень сервер MySQL, ведь именно здесь выполняет свои прямые обязанности оптимизатор запросов. Набор операций, которые оптимизатор выбирает для выполнения эффективного запроса, называется Планом выполнения запроса, также известного как EXPLAIN-план.

Команда EXPLAIN

Выражение EXPLAIN предоставляет информацию о том, как MySQL выполняет запрос. Оно работает с выражениями SELECT, UPDATE, INSERT, DELETE и REPLACE.

Если у вас версия ниже 5.6

До версии 5.6 команда EXPLAIN работала только с выражениями типа SELECT, и, если вам нужен анализ других выражений, то придется переписать запрос в эквивалентный запрос SELECT.

Для того, чтобы воспользоваться командой, достаточно поставить ключевое слово EXPLAIN перед запросом, и MySQL пометит запрос специальным флагом. Он заставит сервер возвращать информацию о каждом шаге, вместо выполнения. Однако, если в запросе встречается подзапросы в разделе FROM, то сервер будет вынужден выполнить все подзапросы и поместить их результаты во временную таблицу.

Стандартный вывод команды EXPLAIN покажет колонки:

idselect_typetablepartitionstypepossible_keyskeykey_lenrefrowsfilteredExtra
Если у вас версия ниже 5.6

В этом случае вы не увидите столбцов filtered и partitions. Для их вывода необходимо, после EXPLAIN, добавить ключевые слова EXTENDED или PARTITIONS, но не оба сразу.

Если у вас версия 5.6

В версии 5.6 и выше столбец partitions будет включено по-умолчанию, однако для вывода столбца filtered вам всё еще придется воспользоваться ключевым словом EXTENDED.

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

Для начала выполним простой запрос:

EXPLAIN SELECT 1
id: 1select_type: SIMPLEtable: NULLpartitions: NULLtype: NULLpossible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: NULLfiltered: NULLExtra: No tables used

Столбец ID

Этот столбец можно назвать идентификатором или порядковым номером каждого SELECT- запроса. Все выражения SELECT нумеруются последовательно, их можно отнести к простым (без подзапросов и объединений) и составным. Составные запросы SELECT можно отнести к:

A. Простым подзапросам

EXPLAIN SELECT (SELECT 1 from Orders) from Drivers

id

select_type

table

1

PRIMARY

Drivers

2

SUBQUERY

Orders

B. Подзапросам с производными таблицами, то есть с подзапросом в разделе FROM

EXPLAIN SELECT * FROM (SELECT 1, 2) AS tmp (a, b)

id

select_type

table

1

PRIMARY

<derived2>

2

SUBQUERY

null

Как я уже писал выше, этот запрос создаст временную таблицу и MySQL будет ссылаться на неё по псевдониму tmp. В более сложных запросах этот псевдоним будет указан в столбце ref. В первой строке, в столбце table можно увидеть название таблицы , которое формируется по правилу , где N ID запроса.

C. Подзапросам с объединением UNION

EXPLAIN SELECT id FROM Cars UNION SELECT id FROM Drivers

id

select_type

table

1

PRIMARY

Cars

2

UNION

Drivers

null

UNION RESULT

<union1,2>

Здесь есть несколько отличий от примера c FROM-подзапросом. Во-первых, MySQL помещает результат объединения во временную таблицу, из которой, затем, считывает данные. К тому же эта временная таблица отсутствует в исходной SQL-команде, поэтому в столбце id для неё будет null. Во-вторых, временная таблица, появившаяся в результате объединения, показана последней, а не первой.

Точно по такому же правилу формируется название таблица в столбце table <unionN,M>, где N ID первого запроса, а M второго.

Столбец select_type

Показывает тип запроса SELECT для каждой строки результата EXPLAIN. Если запрос простой, то есть не содержит подзапросов и объединений, то в столбце будет значение SIMPLE. В противном случае, самый внешний запрос помечается как PRIMARY, а остальные следующим образом:

  • SUBQUERY. Запрос SELECT, который содержится в подзапросе, находящимся в разделе SELECT (т.е. не в разделе FROM).

  • DERIVED. Обозначает производную таблицу, то есть этот запрос SELECT является подзапросом в разделе FROM. Выполняется рекурсивно и помещается во временную таблицу, на которую сервер ссылается по имени derived table.

    Обратите внимание: все подзапросы в разделе FROM являются производной таблицей, однако, не все производные таблицы являются подзапросами в разделе FROM.

  • UNION. Если присутствует объединение UNION, то первый входящий в него запрос считается частью внешнего запроса и помечается как PRIMARY (см. пример выше). Если бы объединение UNION было частью подзапроса в разделе FROM, то его первый запрос SELECT был бы помечен как DERIVED. Второй и последующий запросы помечаются как UNION.

  • UNION RESULT. Показывает результата запроса SELECT, который сервер MySQL применяет для чтения из временной таблицы, которая была создана в результате объединения UNION.

Кроме того, типы SUBQUERY, UNION и DERIVED могут быть помечены как DEPENDENT, то есть результат SELECT зависит от данных, которые встречаются во внешнем запросе SELECT.

Если у вас версия 5.7 и ниже

Поле DEPENDENT DERIVED появилось только в 8 версии MySQL.

Также типы SUBQUERY и UNION могут быть помечены как UNCACHABLE. Это говорит о том, что результат SELECT не может быть закеширован и должен быть пересчитан для каждой строки внешнего запроса. Например, из-за функции RAND().

Начиная с версии MySQL 5.7 в столбце select_type появилось еще одно значение MATERIALIZED, которое говорит о том, что результат подзапроса был сохранен как виртуальная временная таблица и не будет выполняться для каждой следующей строки внешнего запроса.

Столбец table

Показывает, к какой таблице относится эта строка. В самом простом случае это таблица (или её псевдоним) из вашей SQL- команды.

При объединении таблиц стоит читать столбец table сверху вниз.

EXPLAIN SELECT Clients.id        FROM Clients        JOIN Orders ON Orders.client_id = Clients.id        JOIN Drivers ON Orders.driver_id = Drivers.id

id

seelect_type

table

1

SIMPLE

Clients

1

SIMPLE

Orders

1

SIMPLE

Drivers

Здесь мы видим порядок объединения таблиц, который выбрал оптимизатор. Однако, порядок не всегда будет таким, в каком объединяются таблицы в вашем запросе.

Если запрос содержит подзапрос FROM или объединение UNION, то столбец table читать будет не так просто, потому что MySQL будет создавать временные таблицы, на которые станет ссылаться.

О столбце table для подзапроса FROM я уже писал выше. Ссылка derived.N является- опережающей, то есть N ID запроса ниже. А ссылка UNION RESULT (union N,M) является обратной, поскольку встречается после всех строк, которые относятся к объединению UNION.

Попробуем, для примера, прочитать столбец table для следующего странного запроса:

EXPLAIN SELECT id, (SELECT 1 FROM Orders WHERE client_id = t1.id LIMIT 1)       FROM (SELECT id FROM Drivers LIMIT 5) AS t1       UNION       SELECT driver_id, (SELECT @var1 FROM Cars LIMIT 1)       FROM (           SELECT driver_id, (SELECT 1 FROM Clients)           FROM Orders LIMIT 5       ) AS t2

id

select_type

table

1

PRIMARY

<derived3>

3

DERIVED

Drivers

2

DEPENDENT SUBQUERY

Orders

4

UNION

<derived6>

6

DERIVED

Orders

7

SUBQUERY

Clients

5

UNCACHEABLE SUBQUERY

Cars

null

UNION RESULT

<union1,4>

Не так просто разобраться в этом, но, тем не менее, мы попробуем.

  1. Первая строка является опережающей ссылкой на производную таблицу t1, помеченную как <derived3>.

  2. Значение идентификатора строки равно 3, потому что строка относится к третьему по порядку SELECT. Поле select_type имеет значение DERIVED, потому что подзапрос находится в разделе FROM.

  3. Третья строка с ID = 2 идет после строки с бОльшим ID, потому что соответствующий ей подзапрос выполнился позже, что логично, ведь нельзя получить значение t1.id, не выполнив подзапрос с ID = 3. Признак DEPENDENT SUBQUERY означает, что результат зависит от результатов внешнего запроса.

  4. Четвертая строка соответствует второму или последующему запросу объединения, поэтому она помечена признаком UNION. Значение <derived6> означает, что данные будут выбраны из подзапроса FROM и добавятся во временную таблицу для результатов UNION.

  5. Пятая строка - это наш подзапрос FROM, помеченный как t2.

  6. Шестая строка указывает на обычный подзапрос в SELECT. Идентификатор этой строки равен 7, что важно, потому что следующая строка уже имеет ID = 5.

  7. Почему же важно, что седьмая строка имеет меньший ID, чем шестая? Потому что каждая строка, помеченная как DERIVED , открывает вложенную область видимости. Эта область видимости закрывается, когда встречается строка с ID меньшим, чем у DERIVED (в данном случае 5 < 6). Отсюда можно понять, что седьмая строка является частью SELECT, в котором выбираются данные из <derived6>. Признак UNCACHEABLE в колонке select_type добавляется из-за переменной @var1.

  8. Последняя строка UNION RESULT представляет собой этап считывания строк из временной таблицы после объединения UNION.

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

Столбец partitions

Показывает, какой партиции соответствуют данные из запроса. Если вы не используете партиционирование, то значение этой колонки будет null.

Столбец type

Показывает информацию о том, каким образом MySQL выбирает данные из таблицы. Хотя в документации MySQL это поле описывается как The join type, многих такое описание смущает или кажется не до конца понятным. Столбец type принимает одно из следующих значений, отсортированных в порядке скорости извлечения данных:

  • ALL. Обычно речь идет о полном сканировании таблицы, то естьт.е. MySQL будет просматривать строчку за строчкой, если только в запросе нет LIMIT или в колонке extra не указано Distinct/not exists, к чему мы вернемся позже.

  • index. В этом случае MySQL тоже просматривает таблицу целиком, но в порядке, заданном индексом. В этом случае не требуется сортировка, но - строки выбираются в хаотичном порядке. Лучше, если в колонке extra будет указано using index, что означает, что вместо полного сканирования таблицы, MySQL проходит по дереву индексов. Такое происходит, когда удалось использовать покрывающий индекс

  • range. Индекс просматривается в заданном диапазоне. Поиск начинается в определенной точке индекса и возвращает значения, пока истинно условие поиска. range может быть использован, когда проиндексированный столбец сравнивается с константой с использованием операторов =, <>, >, >=, <, <=, IS_NULL, <=>, BETWEEN, LIKE или IN.

  • index_subquery. Вы увидите это значение, если в операторе IN есть подзапрос, для которого оптимизатор MySQL смог использовать поиск по индексу.

  • unique_subquery. Похож на index_subquery, но, для подзапроса используется уникальный индекс, такой как Primary key или Unique index.

  • index_merge. Если оптимизатор использовал range-сканирование для нескольких таблиц, он может объединить их результаты. В зависимости от метода слияния, поле extra примет одно из следующих значений: Using intersect пересечение, Using union объединение, Using sort_union объединение сортировки слияния (подробнее читайте здесь)

  • ref_or_null. Этот случай похож на ref, за исключением того, что MySQL будет выполнять второй просмотр для поиска записей, содержащих NULL- значения.

  • fulltext. Использование FULLTEXT-индекса.

  • ref. Поиск по индексу, в результате которого возвращаются все строки, соответствующие единственному заданному значению. Применяется в случаях, если ключ не является уникальным, то есть не Primary key или Unique index , либо используется только крайний левый префикс ключа. ref может быть использован только для операторов = или <=>.

  • eq_ref. Считывается всего одна строка по первичному или уникальному ключу. Работает только с оператором =. Справа от знака = может быть константа или выражение.

  • const. Таблица содержит не более одной совпадающей строки. Если при оптимизации MySQL удалось привести запрос к константе, то столбец type будет равен const. Например, если вы ищете что-то по первичному ключу, то оптимизатор может преобразовать значение в константу и исключить таблицу из соединения JOIN.

  • system. В таблице только одна строка. Частный случай const.

  • NULL. Означает, что оптимизатор смог сам найти нужные данные для запроса и обращаться к таблице не требуется. Например, для выборки минимального значения проиндексированного, в порядке возрастания, столбца достаточно выбрать первое значение из индекса.

Столбец possible_keys

Показывает, какие индексы можно использовать для запроса. Этот столбец не зависит от порядка таблиц, отображаемых EXPLAIN, поскольку список создается на ранних этапах оптимизации. Если в столбце значение NULL, то соответствующих индексов не нашлось.

Столбец keys

Указывает на ключ (индекс), который оптимизатор MySQL решил фактически использовать. Может вообще отсутствовать в столбце possible_keys. Так бывает в случаях, когда ни один из ключей в possible_keys не подходит для поиска строк, но все столбцы, выбранные запросом, являются частью какого-то другого индекса. Тогда оптимизатор может задействовать эти столбцы для поиска по покрывающему индексу, так как сканирование индекса эффективнее, чем сканирование таблицы целиком.

Столбец key_len

Показывает длину выбранного ключа (индекса) в байтах. Например, если у вас есть primary key id типа int, то, при его использовании, key_len будет равен 4, потому что длина int всегда равна 4 байта. В случае составных ключей key_len будет равен сумме байтов их типов. Если столбец key равен NULL, то значение key_len так же будет NULL.

EXPLAIN SELECT * FROM OrdersWHERE client_id = 1

id

table

possible_keys

key

key_len

1

Orders

Orders_Clients_id_fk

Orders_Clients_id_fk

4

EXPLAIN SELECT * FROM OrdersWHERE client_id = 1 AND driver_id = 2

id

table

possible_keys

key

key_len

1

Orders

Orders_Drivers_id_fk,

Orders_client_id_driver_id

Orders_client_id_driver_id

8

Столбец ref

Показывает, какие столбцы или константы сравниваются с указанным в key индексом. Принимает значения NULL, const или название столбца другой таблицы. Возможно значение func, когда сравнение идет с результатом функции. Чтобы узнать, что это за функция, можно после EXPLAIN выполнить команду SHOW WARNINGS.

EXPLAIN SELECT * FROM Drivers

id

table

ref

1

Drivers

null

EXPLAIN SELECT * FROM DriversWHERE id = 1

id

table

ref

1

Drivers

const

EXPLAIN SELECT * FROM DriversJOIN Orders ON Drivers.id = Orders.driver_id

id

table

ref

1

Orders

null

1

Drivers

Orders.driver_id

Столбец rows

Показывает количество строк, которое, по мнению MySQL, будет прочитано. Это число является приблизительным и может оказаться очень неточным. Оно вычисляется при каждой итерации плана выполнения с вложенными циклами. Часто это значение путают с количеством строк в результирующем наборе, что неверно, потому что столбец rows показывает количество строк, которые нужно будет просмотреть. При вычислении значения не учитываются буферы соединения и кеши (в том числе кеши ОС и оборудования), поэтому реальное число может быть намного меньше предполагаемого.

Столбец filtered

Показывает, какую долю от общего количества числа просмотренных строк вернет движок MySQL. Максимальное значение 100, то есть будет возвращено все 100 % просмотренных строк. Если умножить эту долю на значение в столбце rows, то получится приблизительная оценка количества строк, которые MySQL будет соединять с последующими таблицами. Например, если в строке rows 100 записей, а значение filtered 50,00 (50 %), то это число будет вычислено как 100 x 50 % = 50.

Столбец Extra

В этом столбце собрана различная дополнительная информация. Ниже я разберу все возможные значения. Наиболее важные из них будут помечены (!!!). Такие значения не всегда означают, что это плохо или хорошо, но точно стоит обратить на них внимание.

  • const row not found. Для запроса, вида SELECT FROM table, таблица table оказалась пустая.

  • Deleting all rows. Некоторые движки MySQL, такие как MyISAM, поддерживают методы быстрого удаления всех строк из таблицы. Если механизм удаления поддерживает эту оптимизацию, то значение Deleting all rows будет значением в столбце Extra.

  • Distinct. Если в запросе присутствует DISTINCT, то MySQL прекращает поиск, после нахождения первой подходящей строки.

  • FirstMatch (table_name). Если в системной переменной optimizer_switch есть значение firstmatch=on, то MySQL может использовать для подзапросов стратегию FirstMatch, которая позволяет избежать поиска дублей, как только будет найдено первое совпадение. Представим, что один и тот же водитель возил клиента с id = 10 больше, чем один раз, тогда для этого запроса:

    EXPLAIN
    SELECT id FROM Drivers
    WHERE Drivers.id IN (SELECT driver_id FROM Orders WHERE client_id = 10)

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

id

table

extra

1

Orders

Using index;

2

Drivers

Using index; FirstMatch(Orders)

  • Full scan on NULL key. Обычно такая запись идет после Using where как запасная стратегия, если оптимизатор не смог использовать метод доступа по индексу.

  • Impossible HAVING. Условие HAVING всегда ложно.

  • Impossible WHERE. Условие WHERE всегда ложно.

  • Impossible WHERE noticed after reading const tables. MySQL просмотрел все const (и system) таблицы и заметил, что условие WHERE всегда ложно.

  • LooseScan(m..n). Стратегия сканирования индекса при группировке GROUP BY. Подробнее читайте здесь.

  • No matching min/max row. Ни одна строка не удовлетворяет условию запроса, в котором используются агрегатные функции MIN/MAX.

  • No matching rows after partition pruning. По смыслу похож на Impossible WHERE для выражения SELECT, но для запросов DELETE или UPDATE.

  • No tables used. В запросе нет FROM или есть FROM DUAL.

  • Not exists. Сервер MySQL применил алгоритм раннего завершения. То есть применена оптимизация, чтобы избежать чтения более, чем одной строки из индекса. Это эквивалентно подзапросу NOT EXISTS(), прекращение обработки текущей строки, как только найдено соответствие.

  • Plan isnt ready yet. Такое значение может появиться при использовании команды EXPLAIN FOR CONNECTION, если оптимизатор еще не завершил построение плана.

  • Range check for each record (!!!). Оптимизатор не нашел подходящего индекса, но обнаружил, что некоторые индексы могут быть использованы после того, как будут известны значения столбцов из предыдущих таблиц. В этом случае оптимизатор будет пытаться применить стратегию поиска по индексу range или index_merge.

  • Recursive.Такое значение появляется для рекурсивных (WITH) частей запроса в столбце extra.

  • Scanned N databases. Сколько таблиц INFORMATION_SCHEMA было прочитано. Значение N может быть 0, 1 или all.

  • Select tables optimized away (!!!). Встречается в запросах, содержащих агрегатные функции (но без GROUP BY). Оптимизатор смог молниеносно получить нужные данные, не обращаясь к таблице, например, из внутренних счетчиков или индекса. Это лучшее значение поля extra, которое вы можете встретить при использовании агрегатных функций.

  • Skip_open_table, Open_frm_only, Open_full_table. Для каждой таблицы, которую вы создаете, MySQL создает на диске файл .frm, описывающий структуру таблицы. Для подсистемы хранения MyISAM так же создаются файлы .MYD с данными и .MYI с индексами. В запросах к INFORMATION_SCHEMA Skip_open_table означает, что ни один из этих файлов открывать не нужно, вся информация уже доступна в словаре (data dictionary). Для Open_frm_only потребуется открыть файлы .frm. Open_full_table указывает на необходимость открытия файлов .frm, .MYD и .MYI.

  • Start temporary, End temporary. Еще одна стратегия предотвращения поиска дубликатов, которая называется DuplicateWeedout. При этом создаётся временная таблица, что будет отображено как Start temporary. Когда значения из таблицы будут прочитаны, это будет отмечено в колонке extra как End temporary. Неплохое описание читайте здесь.

  • unique row not found (!!!). Для запросов SELECT FROM table ни одна строка не удовлетворяет поиску по PRIMARY или UNIQUE KEY.

  • Using filesort (!!!). Сервер MySQL вынужден прибегнуть к внешней сортировке, вместо той, что задаётся индексом. Сортировка может быть произведена как в памяти, так и на диске, о чем EXPLAIN никак не сообщает.

  • Using index (!!!). MySQL использует покрывающий индекс, чтобы избежать доступа к таблице.

  • Using index condition (!!!). Информация считывается из индекса, чтобы затем можно было определить, следует ли читать строку целиком. Иногда стоит поменять местами условия в WHERE или прокинуть дополнительные данные в запрос с вашего бэкенда, чтобы Using index condition превратилось в Using index.

  • Using index for group-by (!!!). Похож на Using index, но для группировки GROUP BY или DISTINCT. Обращения к таблице не требуется, все данные есть в индексе.

  • Using join buffer (Block nested loop | Batched Key Access | hash join). Таблицы, получившиеся в результате объединения (JOIN), записываются в буфер соединения (Join Buffer). Затем новые таблицы соединяются уже со строками из этого буфера. Алгоритм соединения (Block nested loop | Batched Key Access | hash join) будет указан в колонке extra.

  • Using sort_union, Using union, Using intersect. Показывает алгоритм слияния, о котором я писал выше для index_merge столбца type.

  • Using temporary (!!!). Будет создана временная таблица для сортировки или группировки результатов запроса.

  • Using where (!!!). Сервер будет вынужден дополнительно фильтровать те строки, которые уже были отфильтрованы подсистемой хранения. Если вы встретили Using where в столбце extra, то стоит переписать запрос, используя другие возможные индексы.

  • Zero limit. В запросе присутствует LIMIT 0.

Команда SHOW WARNINGS

Выражение EXPLAIN предоставляет расширенную информацию, если сразу после его завершения выполнить команду SHOW WARNINGS. Тогда вы получите реконструированный запрос.

Если у вас MySQL 5.6 и ниже

SHOW WARNINGS работает только после EXPLAIN EXTENDED.

EXPLAIN SELECT              Drivers.id,              Drivers.id IN (SELECT Orders.driver_id FROM Orders)FROM Drivers;SHOW WARNINGS;
/* select#1 */ select `explain`.`Drivers`.`id` AS `id`,<in_optimizer>(`explain`.`Drivers`.`id`,<exists>(<index_lookup>(<cache>(`explain`.`Drivers`.`id`) in Orders on Orders_Drivers_id_fk))) AS `Drivers.id IN (SELECT Orders.driver_id FROM Orders)` from `explain`.`Drivers`

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

SHOW WARNINGS содержит специальные маркеры, которые не являются допустимым SQL -выражением. Вот их список:

  • <auto_key>. Автоматически сгенерированный ключ для временной таблицы.

  • <cache> (expr). Выражение expr выполняется один раз, значение сохраняется в памяти. Если таких значений несколько, то вместо <cache> будет создана временная таблица с маркером <temporary table>.

  • <exists> (query fragment). Предикат подзапроса был преобразован в EXISTS -предикат, а сам подзапрос был преобразован таким образом, чтобы его можно было использовать совместно с EXISTS.

  • <in_optimizer> (query fragment). Внутренний объект оптимизатора, не обращаем внимания.

  • <index_lookup> (query fragment). Этот фрагмент запроса обрабатывается с помощью поиска по индексу.

  • <if> (condition, expr1, expr2). Если условие истинно, то выполняем expr1, иначе expr2.

  • <is_not_null_test> (expr). Тест для оценки того, что выражение expr не преобразуется в null.

  • <materialize> (query fragment). Подзапрос был материализован.

  • materialized-subquery.col_name. Ссылка на столбец col_name была материализована.

  • <primary_index_lookup> (query fragment). Фрагмент запроса обрабатывается с помощью индекса по первичному ключу.

  • <ref_null_helper> (expr). Внутренний объект оптимизатора, не обращаем внимания.

  • /* select # N */. SELECT относится к строке с номером id = N из результата EXPLAIN.

  • <temporary table>. Представляет собой временную таблицу, которая используется для кеширования результатов.

Читаем EXPLAIN

Учитывая всё вышесказанное, пора дать ответ на вопрос - так как же стоит правильно читать EXPLAIN?

Начинаем читать каждую строчку сверху вниз. Смотрим на колонку type. Если индекс не используется плохо (за исключением случаев, когда таблица очень маленькая или присутствует ключевое слово LIMIT). В этом случае оптимизатор намеренно предпочтет просканировать таблицу. Чем ближе значение столбца type к NULL (см. пункт о столбце type), тем лучше.

Далее стоит посмотреть на колонки rows и filtered. Чем меньше значение rows и чем больше значение filtered,- тем лучше. Однако, если значение rows слишком велико и filtered стремится к 100 % - это очень плохо.

Смотрим, какой индекс был выбран из колонки key , и сравниваем со всеми ключами из possible_keys. Если индекс не оптимальный (большая селективность), то стоит подумать, как изменить запрос или пробросить дополнительные данные в условие выборки, чтобы использовать наилучший индекс из possible_keys.

Наконец, читаем колонку Extra. Если там значение, отмеченное выше как (!!!), то, как минимум, обращаем на это вниманием. Как максимум, пытаемся разобраться, почему так. В этом нам может хорошо помочь SHOW WARNINGS.

Переходим к следующей строке и повторяем всё заново.

Если не лень, то в конце перемножаем все значения в столбце rows всех строк, чтобы грубо оценить количество просматриваемых строк.

При чтении всегда помним о том, что:

  • EXPLAIN ничего не расскажет о триггерах и функциях (в том числе определенных пользователем), участвующих в запросе.

  • EXPLAIN не работает с хранимыми процедурами.

  • EXPLAIN не расскажет об оптимизациях, которые MySQL производит уже на этапе выполнения запроса.

  • Большинство статистической информации всего лишь оценка, иногда очень неточная.

  • EXPLAIN не делает различий между некоторыми операциями, называя их одинаково. Например, filesort может означать сортировку в памяти и на диске, а временная таблица, которая создается на диске или в памяти, будет помечена как Using temporary.

  • В разных версиях MySQL EXPLAIN может выдавать совершенно разные результаты, потому что оптимизатор постоянно улучшается разработчиками, поэтому не забываем обновляться.

EXPLAIN TREE FORMAT и EXPLAIN ANALYZE

Если вы счастливый обладатель восьмой версии MySQL, то в вашем арсенале появляются очень полезные команды, которые позволяют читать план выполнения и информацию о стоимости запроса без использования SHOW WARNINGS.

С версии 8.0.16 можно вывести план выполнения в виде дерева, используя выражение FORMAT=TREE:

EXPLAIN FORMAT = TREE select * from Drivers   join Orders on Drivers.id = Orders.driver_id   join Clients on Orders.client_id = Clients.id
-> Nested loop inner join  (cost=1.05 rows=1)   -> Nested loop inner join  (cost=0.70 rows=1)       -> Index scan on Drivers using Drivers_car_id_index  (cost=0.35 rows=1)       -> Index lookup on Orders using Orders_Drivers_id_fk (driver_id=Drivers.id)  (cost=0.35 rows=1)   -> Single-row index lookup on Clients using PRIMARY (id=Orders.client_id)  (cost=0.35 rows=1)

Удобство такого формата в том, что мы можем видеть план запроса в виде вложенного дерева. Каждая вложенная строка означает новый цикл. В скобках указана информация об оценочной стоимости и расчетное количество прочитанных строк. Стоимость или стоимость запроса это некая внутренняя оценка того, насколько дорого для MySQL выполнять этот запрос, основанная на различных внутренних метриках.

Еще более подробную информацию можно получить, заменив FORMAT = TREE на выражение ANALYZE, которое предоставляет MySQL с версии 8.0.18.

EXPLAIN ANALYZE select * from Drivers   join Orders on Drivers.id = Orders.driver_id   join Clients on Orders.client_id = Clients.id
-> Nested loop inner join  (cost=1.05 rows=1) (actual time=0.152..0.152 rows=0 loops=1)   -> Nested loop inner join  (cost=0.70 rows=1) (actual time=0.123..0.123 rows=0 loops=1)       -> Index scan on Drivers using Drivers_car_id_index  (cost=0.35 rows=1) (actual time=0.094..0.094 rows=0 loops=1)       -> Index lookup on Orders using Orders_Drivers_id_fk (driver_id=Drivers.id)  (cost=0.35 rows=1) (never executed)   -> Single-row index lookup on Clients using PRIMARY (id=Orders.client_id)  (cost=0.35 rows=1) (never executed)

В дополнение к стоимости и количеству строк можно увидеть фактическое время получения первой строки и фактическое время получения всех строк, которые выводятся в формате actual time={время получения первой строки}..{время получения всех строк}. Также теперь появилось еще одно значение rows, которое указывает на фактическое количество прочитанных строк. Значение loops это количество циклов, которые будут выполнены для соединения с внешней таблицей (выше по дереву). Если не потребовалось ни одной итерации цикла, то вместо расширенной информации вы увидите значение (never executed).

Как видите, обновлять MySQL полезно не только с точки зрения производительности и улучшения оптимизатора, но и для получения новых инструментов для профилирования запросов.

Заключение

Команда EXPLAIN станет отличным оружием в вашем арсенале при работе с БД. Зная несложные правила, вы можете быстро оптимизировать ваши запросы, узнавать различную статистическую информацию, пусть и приближенную. Расширенный вывод подскажет, что было закешировано и где создаются временные таблицы.

Слишком большие запросы могут генерировать пугающие результаты EXPLAIN, но тут, как и в любом деле, важна практика. Переходите от простых запросов к сложным.

Пытайтесь, даже просто так, читать различные виды запросов, содержащие FROM, UNION и JOIN , и сами не заметите, как станете мастером оптимизации.

Литература и источники

  1. High Performance MySQL (by Baron Schwartz, Peter Zaitsev, Vadim Tkachenko)

  2. https://dev.mysql.com/

  3. https://stackoverflow.com/

  4. http://highload.guide/

  5. https://taogenjia.com/2020/06/08/mysql-explain/

  6. https://www.eversql.com/mysql-explain-example-explaining-mysql-explain-using-stackoverflow-data/

  7. https://dba.stackexchange.com/

  8. https://mariadb.com/

  9. https://andreyex.ru/bazy-dannyx/baza-dannyx-mysql/explain-analyze-v-mysql/

  10. https://programming.vip/docs/explain-analyze-in-mysql-8.0.html

  11. А также много страниц из google.com

Подробнее..

Recovery mode Как ускорить сайт в 4 раза, просто перенастроив сервер

02.06.2021 12:04:43 | Автор: admin

Если вы работаете с сайтом, который постепенно растет, - увеличивается количество товаров, трафик с рекламы - то рано или поздно придется перейти в режим работы highload, высоких нагрузок на сервер. Но что делать, если ваш сайт не растет, а сервер все чаще не выдерживает, и происходит блокировка данных? Именно с этой проблемой мы столкнулись, дорабатывая сайт для интернет-магазина светового оборудования с ассортиментом более чем 100 000 товаров.

Исходная ситуация

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

Поиск проблемы

Мы провели аудит настроек сервера и сайта, разделив работы на два этапа: анализ back-end и front-end, и обнаружили низкую скорость загрузки страниц на back-ende - порядка 80 секунд на самых посещаемых страницах, что в итоге приводило к существенному снижению конверсии.

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

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

Решение

Шаг 1. Настройка баз данных

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

Шаг 2. Смена типа хранения на InnoDB

Почему мы выбрали InnoDB?

В InnoDB данные хранятся в больших совместно используемых файлах, в отличие от используемого прежде MyISAM, где для каждой конкретной таблицы создается отдельный файл данных. InnoDB обеспечивает надежность хранения данных за счет блокировки данных на уровне строки и транзакционности.

Главное преимущество InnoDB заключается в скорости работы при выполнении запроса к базе InnoDB происходит блокировка только строки, при выполнении же запроса к базе MyISAM блокируется вся таблица. Дело в том, что пока запрос не будет выполнен, никакие другие обращения к таблице/строке будут невозможны. А поскольку строки значительно меньше целых таблиц, InnoDB обрабатывает запросы быстрее.

Также была произведена оптимизация работы самой базы данных InnoDB. Например, были оптимизированы параметры:

# InnoDB parameters

innodb_file_per_table

innodb_flush_log_at_trx_commit

innodb_flush_method

innodb_buffer_pool_size

innodb_log_file_size

innodb_buffer_pool_instances

innodb_file_format

innodb_locks_unsafe_for_binlog

innodb_autoinc_lock_mode

transaction-isolation

innodb-data-file-path

innodb_log_buffer_size

innodb_io_capacity

innodb_io_capacity_max

innodb_checksum_algorithm

innodb_read_io_threads

innodb_write_io_threads

Промежуточные результаты

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

Это в свою очередь привело к уменьшению потребляемой оперативной памяти.

Шаг 3. Перенастройка Nginx и установка модулей кэширования brotli, pagespeed, proxy_buffering

Nginx позиционируется как простой, быстрый и надежный сервер, неперегруженный функциями. Уже длительное время Nginx обслуживает серверы многих высоконагруженных российских сайтов, например, Яндекс, Mail.Ru, ВКонтакте и Рамблер. Для улучшения производительности при использовании дополнительных серверов, Nginx поддерживает буферизацию (proxy_buffering) и кеширование (proxy_cache), чем мы и воспользовались.

Не обошлось и без курьезов настроек Nginx. У клиента был обычный интернет-магазин с товарами, тогда как настройки буферизации, которые мы обнаружили во время аудита, позволяли ему быть чуть ли ни стриминговым сервисом. Мы существенно уменьшили значения в параметре client_max_body_size, что в совокупности с перенастройкой Nginx еще больше снизило потребление памяти.

Шаг 4. Оптимизация настроек PHP-FPM и Memcache и отключение Apache

PHP-FPM нередко используется в паре с веб-сервером Nginx. Последний обрабатывает статические данные, а обработку скриптов отдает PHP-FPM. Такая реализация работает быстрее, чем распространенная модель Nginx + Apache.

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

Необходимым шагом стал перевод работы PHP-FPM на unix socket. Зачем это понадобилось? Nginx сам по себе довольно быстрый веб-сервер, однако самостоятельно он не может обрабатывать скрипты. Для этого необходим бэкенд в виде PHP-FPM. Чтобы вся эта связка работала без потери скорости, мы использовали unix socket способ подключения к PHP-FPM, позволяющий избегать сетевые запросы и дающий значительный прирост в скорости работы сайта.

Результаты работ

1. Время отклика главной страницы уменьшилось с 24 секунд до чуть более 3 секунд, внутренних до 5-8 сек.

2. Уменьшилось потребление серверных ресурсов.

3. Стабилизировалось поведение сервера - он перестал зависать.

4. Глубина просмотров увеличилась на 30%, и как следствие, это дало улучшение в SЕО, а также последующих продаж: растут поведенческие показатели => растут позиции сайта в выдаче => растет трафик => растут продажи.

5. Клиенту были даны рекомендации по оптимизации front-end части сайта для ускорения работы сайта. Например:

  • оптимизировать графики и настройку выдачи изображений в формате webp;

  • настроить lazyload-загрузки данных;

  • вынести все некритические для отображения страницы скрипты в конец страницы.

Вывод

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

Подробнее..

Оптимизация хранимых данных на 93 (Redis)

12.03.2021 16:12:58 | Автор: admin

Хотелось бы поделиться опытом оптимизации данных с целью уменьшения расходов на ресурсы.

В системе рано или поздно встает вопрос об оптимизации хранимых данных, особенно если данные хранятся в оперативной памяти, как это БД Redis.

Как временное решение, можно увеличить RAM тем самым можно выиграть время.

Redis это no-sql база данных, профилировать ее можно с помощью встроенной команды redis-cli --bigkeys, которая покажет кол-во ключей и сколько в среднем занимает каждый ключ.

Объемными данными оказались исторические данные типо sorted sets. У них была ротация 10 дней из приложения.

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

Данные из себя представляли события измененияцены / даты доставки у оффера. Офферов было очень много порядка 15000 в каждом фиде (прайслисте).

Рассмотрим следующий пример данных события по офферу:

Сделано с помощью http://json.parser.online.fr/Сделано с помощью http://json.parser.online.fr/

{"EventName":"DELIVERY_CHANGED","DateTime":"2021-02-22T00:04:00.112593982+03:00","OfferId":"109703","OfferFrom":{"Id":"109703","Name":"Саундбар LG SN11R","Url":"https://www.example.ru/saundbar-lg-sn11r/?utm_source=yandex_market&utm_medium=cpc&utm_content=948&utm_campaign=3&utm_term=109703","Price":99990,"DeliveryAvailable":true,"DeliveryCost":0,"DeliveryDate":"2021-02-24T23:49:00+03:00"},"OfferTo":{"Id":"109703","Name":"Саундбар LG SN11R","Url":"https://www.example.ru/saundbar-lg-sn11r/?utm_source=yandex_market&utm_medium=cpc&utm_content=948&utm_campaign=3&utm_term=109703","Price":99990,"DeliveryAvailable":true,"DeliveryCost":0,"DeliveryDate":"2021-02-23T00:04:00.112593982+03:00"}}

Такое событие занимает 706 байт.

Оптимизация

  1. Для начала я уменьшил ротацию до 7 дней, так как использовалась именно последняя неделя. Здесь стоит отметить, что шаг весьма легкий(в исходном коде изменил 10 на 7), сразу сокращает размер RAM на 30%.

  2. Удалил из хранилища все данные, которые записывались, но не использовались во время чтения, такие как name, url, offerId что сократило еще примерно на 50%.

    Cтало:

    {"EventName":"DELIVERY_CHANGED","DateTime":"2021-02-22T00:04:00.112593982+03:00","OfferId":"109703","OfferFrom":{"Price":99990,"DeliveryAvailable":true,"DeliveryCost":0,"DeliveryDate":"2021-02-24T23:49:00+03:00"},"OfferTo":{"Price":99990,"DeliveryAvailable":true,"DeliveryCost":0,"DeliveryDate":"2021-02-23T00:04:00.112593982+03:00"}}

    Теперь событие занимает 334 байта.

    1. Переделал формат хранение с json в бинарный protobuf.

      Об этом шаге хотелось бы рассказать подробнее

      1. Составил схему хранение данных, в случее с protobuf это proto - файл:

        syntax = "proto3";import "google/protobuf/timestamp.proto";message OfferEvent {  enum EventType {    PRICE_CHANGED = 0;    DELIVERY_CHANGED = 1;    DELIVERY_SWITCHED = 2;    APPEARED = 3;    DISAPPEARED = 4;  }  EventType event_name = 1;  google.protobuf.Timestamp date_time = 2;  string offer_id = 3;  message Offer {    int32 price = 1;    bool delivery_available = 2;    int32 delivery_cost = 3;    google.protobuf.Timestamp  delivery_date = 4;  }  Offer offer_from = 4;  Offer offer_to = 5;} 
        
      2. Исходное сообщение в текстовом protobuf формате будет выглядеть так

        event_name: DELIVERY_CHANGEDdate_time {  seconds: 1613941440}offer_id: "109703"offer_from {  price: 99990  delivery_available: true  delivery_date {    seconds: 1614199740  }}offer_to {  price: 99990  delivery_available: true  delivery_date {    seconds: 1614027840  }}
        
      3. Сообщение в итоговом бинарном protobuf формате будет выглядеть так

        echo 'event_name: DELIVERY_CHANGEDdate_time {  seconds: 1613941440}offer_id: "109703"offer_from {  price: 99990  delivery_available: true  delivery_date {    seconds: 1614199740  }}offer_to {  price: 99990  delivery_available: true  delivery_date {    seconds: 1614027840  }}' | protoc --encode=OfferEvent offerevent.proto | xxd -p | tr -d "\n"0801120608c095cb81061a06313039373033220e08968d061001220608bcf7da81062a0e08968d061001220608c0b8d08106
        

      Теперь событие занимает 50 байт. Это сократило потребление памяти на 85%.

      Бинарное сообщение без proto-схемы можно посмотреть с помощью онлайн-сервиса https://protogen.marcgravell.com/

Итого

Оптимизация места более, чем в 14 раз (50 байт против 706 байт изначальных), то есть на 93%.

Подробнее..

Как сделать кластерный сервер на ARM процессоре и тестирование VPS на AWS Graviton2

28.04.2021 12:07:29 | Автор: admin
Cluster Server ARM

В предыдущей публикации рассматривались преимущества использование ARM серверов для хостинг провайдеров. В этом посте рассмотрим практические варианты создания кластерного сервера на ARM процессоре и протестируем инстанс Amazon EC2 T4g работающий на процессоре ARM AWS Graviton2, посмотрим на что он способен.

Создание серверного кластера на Raspberry/Banana/Orange Pi


На данный момент существует множество различных вариантов сборки кластера на базе различных одноплатных компьютеров. Можно собрать самостоятельно или купить готовую коробку (CASE) для наполнения модулями CoM Raspberry Pi.

Cluster Server ARM
Кластер на Raspberry/Banana/Orange Pi

Для личных и исследовательских целей подобные кластеры имеют право на жизнь. Но для массового рынка такой подход не приемлем по следующим причинам:

  1. Малая производительность используемых ARM-процессоров.
  2. В большинстве случаем хранение данных только на eMMC или microSD.
  3. Большой набор лишней периферии, такой как модуль связи Wi-Fi и Bluetooth, порты видеовыхода HMDI и т.д., что приводит к лишней стоимости платы и увеличению энергопотребления.
  4. Невозможна плотная компоновка модулей.
  5. Большое количество лишних проводов для подключения линий электропитания и Ethernet.

Для решения выше перечисленных недостатков необходимо перейти на концепцию Компьютер-на-Модуле (Computer on Module, CoM).

Компьютер на модуле (CoM)


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

Cluster Server ARM
Компьютер на модуле (CoM)

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

Cluster Server ARM
Подключение модуля CoM к несущей плате

Стартап miniNodes разрабатывает недорогие ARM сервера, предназначенные для небольших облачных сервисов, веб-сайтов и приложений Интернета вещей. Они разработали микро-сервер состоящий из несущей платы и 5 модулей Raspberry Pi 3 CoM. Несущая плата Carrier Board содержит встроенный гигабитный коммутатор, который обеспечивает подключение ко всем 5 модулям. С противоположной стороны платы размещен модуль питания для обеспечивания питание CoM. Каждый из вычислительных модулей также имеет отдельный переключатель включения/выключения питания. Модули Raspberry Pi CM3 + поставляются с 8 ГБ, 16 ГБ или 32 ГБ eMMC на борту, поэтому нет необходимости использовать SD-карты, как на обычных платах Raspberry Pi. Таким образом, при полной загрузке есть 5 узлов, состоящих из 4 ядер, 1 ГБ ОЗУ и до 32 ГБ eMMC каждый, всего 20 ядер, 5 ГБ ОЗУ и до 160 ГБ хранилища.

Cluster Server ARM
5 Node Raspberry Pi 3 CoM Carrier Board

Такой подход построения микро-серверов на базе Raspberry Pi безусловно хорош, но вряд ли будет серьезно воспринят бизнесом. Любой бизнес в первую очередь интересует длительность поддержки купленной системы, поэтому решения стартапов не вариант для бизнеса. Дополнительно, закрытость процессоров Broadcom для Raspberry Pi не добавляет популярности в этом сегменте рынка.

Блейд-сервер от Firefly на процессорах Rockchip


Среди доступных решений выделяются процессоры компании Rockchip. По сравнению с процессорами от других производителей, для процессоров Rockchip доступно больше драйверов под Linux и есть даташиты в публичном доступе. Компания Firefly разрабатывает модули CoM на процессорах Rockchip и комплектует из них блейд-серверы. В каталоге компании доступно 9 различных по производительности модулей CoM, которые можно использовать для комплектации сервера. Модули для подключения имеют стандартный интерфейс SODIMM.

Cluster Server ARM
Модули COM от компании Firefly

Компания разработала сервер Cluster Server R1 в 1U форм-факторе который может содержать до 11 модулей CoM.

Cluster Server ARM
Сервер Cluster Server R1

Сервер предназначен для запуска приложений на Linux, облачных игр, виртуальных рабочих столов, тестирования мобильных приложений (до 110 виртуальных телефонов на Android). Возможен запуск ОС: Linux и Android.

Для комплектации доступны модули CoM:

  • RK3399(AI) Core Board (Core-3399-JD4): два ядра A72 + четыре ядра A53, частота до 1.8GHz
  • RK3328 Core Board (Core-3328-JD4): четы ядра A53, частота до 1.5GHz
  • RK1808(AI) Core Board (Core-1808-JD4): два ядра с A35, частота до 1.6GHz

На лицевой панели блейд-сервера размещено: 4 порта Gigabit Ethernet, HDMI, два порта USB2.0, OTG, дополнительно для модулей доступен 3.5-дюймовый жесткий диск SATA/SSD с горячей заменой, слот для SIM карт модуля 4G-LTE.

Cluster Server ARM
Лицевая панель сервера Cluster Server R1

Для управления узлами используется BMC (Baseboard Management Controller) с помощью которой можно управлять узлами: включать/выключать, удаленный доступ, мониторинг состояния, управление аппаратной конфигурацией.

В начале этого года была представлена вторая версия кластерного сервера Cluster Server R2. Cluster Server R2 поставляется в 2U форм-факторе и содержит:

  • 9 блейд-узлов (каждый узел содержит 8 модулей CoM).
  • Два 3.5-дюймовых жестких дисков SATA/SSD.
  • 4 порта Gigabit Ethernet.
  • два порта USB 3.0, USB 2.0, порт HDMI.

Cluster Server ARM
Cluster Server Cluster Server R2

Кластерный север так же работает под управлением ОС: Android, Ubuntu или некоторых других дистрибутивов Linux. Варианты использования сервера: облачный телефон, виртуальный рабочий стол, облачные игры, облачное хранилище, блокчейн, декодирование многоканального видео, и т. Д. Наличие AI (NPU-нейронный процессор) делает кластер похожим на Solidrun Janux GS31 Edge AI. Сервер, предназначенный для вывода в режиме реальном времени нескольких видеопотоков для мониторинга умных городов и инфраструктуры, интеллектуального корпоративного/промышленного видеонаблюдения, обнаружения, распознавания и классификации объектов, интеллектуального визуального анализа и т. д.

Что можно запустить на ARM процессоре?


Запуск приложений с помощью Docker и Kubernetes давно стал де-факто стандартом для Linux. Поэтому рассмотрим какие наиболее популярные контейнеры можно запустить под ARM:

  1. Portainer.io управление и мониторинг контейнерами с помощью web-интерфейса.
  2. OpenVPN самый популярный бесплатный VPN сервер
  3. SoftEther VPN мультипротокольный VPN-сервер с графическим интересом под Windows.
  4. Базы данных все официальные Docker-образы так же собраны для ARM архитектуры: PostgreSQL, Mariadb, MongoDB.
  5. Nginx-proxy Nginx прокси-сервер, образ на базе Alpine
  6. Traefik обратный прокси-сервер, альтернатива Nginx
  7. Wordpress популярная CMS-система
  8. Elasticsearch поисковая система на Java
  9. Asterisk PBX компьютерная телефония (в том числе, VoIP) с открытым исходным кодом от компании Digium
  10. Zabbix система мониторинга и отслеживания статусов различных сервисов компьютерной сети, серверов и сетевого оборудования

Отдельно необходимо отметить проект linuxserver.io, которые собирает контейнеры на базе наиболее популярных приложения для Linux, сборки готовятся и для архитектуры ARM. Наиболее популярные приложений для Linux представлены в виде контейнеров для ARM-систем, поэтому можно уже начинать тестировать.

Тестирование VPS на AWS Graviton2


Amazon для тестирования предоставляет инстансы на базе процессора ARM AWS Graviton2. Это отличная возможность бесплатно протестировать ПО на совместимость с ARM архитектурой и просто получить опыт работы, эксплуатации системы на ARM процессоре. Бесплатно предоставляется инстанс t4g.micro до 30 июня 2021 года в режиме 24x7. Для тестирования достаточно зарегистрироваться и развернуть инстанс на Ubuntu Server 20.04 LTS.
Конфигурация инстанса t4g.micro:

  • 2 vCPUs 2.5 GHz
  • 1 GiB memory
  • 8 GB SSD

Инстанс t4g.micro доступен для развертывания на различных площадках. Ближайшая к нам площадка Europe (Frankfurt) eu-central-1, пинг от Питера в среднем составляет 78 ms.

Команда lscpu выдает следующую информацию:

ubuntu@host:~$ lscpuArchitecture:                    aarch64CPU op-mode(s):                  32-bit, 64-bitByte Order:                      Little EndianCPU(s):                          2...Vendor ID:                       ARMModel:                           1Model name:                      Neoverse-N1Stepping:                        r3p1BogoMIPS:                        243.75L1d cache:                       128 KiBL1i cache:                       128 KiBL2 cache:                        2 MiBL3 cache:                        32 MiBNUMA node0 CPU(s):               0,1...Flags:                           fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimdd                                 p ssbs

Железо:

root@host:/home/ubuntu# inxi -bSystem:    Host: host Kernel: 5.4.0-1038-aws aarch64 bits: 64 Console: tty 1           Distro: Ubuntu 20.04.2 LTS (Focal Fossa)Machine:   Type: Other-vm? System: Amazon EC2 product: t4g.micro v: N/A serial: ec21ba8c-f1b0-3f47-74e0-c648a84383c4           Mobo: Amazon EC2 model: N/A serial: N/A UEFI: Amazon EC2 v: 1.0 date: 11/1/2018CPU:       Dual Core: Model N/A type: MCP speed: 0Graphics:  Message: No Device data found.           Display: server: No display server data found. Headless machine? tty: 130x42           Message: Advanced graphics data unavailable for root.Network:   Device-1: Amazon.com Elastic Network Adapter driver: enaDrives:    Local Storage: total: 8.00 GiB used: 2.52 GiB (31.5%)Info:      Processes: 145 Uptime: 2d 23h 46m Memory: 952.5 MiB used: 336.2 MiB (35.3%) Shell: bash inxi: 3.0.38

Тест CPU

Тестируем процессор sysbenchем:

root@host:/home/ubuntu# sysbench --test=cpu --cpu-max-prime=20000 --num-threads=1 runsysbench 1.0.18 (using system LuaJIT 2.1.0-beta3)Running the test with following options:Number of threads: 1Initializing random number generator from current timePrime numbers limit: 20000...CPU speed:    events per second:  1097.02General statistics:    total time:                          10.0002s    total number of events:              10972Latency (ms):         min:                                    0.91         avg:                                    0.91         max:                                    0.95         95th percentile:                        0.92         sum:                                 9998.11Threads fairness:    events (avg/stddev):           10972.0000/0.00    execution time (avg/stddev):   9.9981/0.00

Тест ОЗУ:

root@host:/home/ubuntu# sysbench --test=memory --num-threads=4 --memory-total-size=512MB runsysbench 1.0.18 (using system LuaJIT 2.1.0-beta3)...Total operations: 524288 (3814836.42 per second)512.00 MiB transferred (3725.43 MiB/sec)General statistics:    total time:                          0.1360s    total number of events:              524288Latency (ms):         min:                                    0.00         avg:                                    0.00         max:                                    8.00         95th percentile:                        0.00         sum:                                  315.89

Тест диска

Посмотрим что покажет dd. Скорость до полноценного SSD недотягивает, но уже полноценный SATA:

root@home:/home/ubuntu# dd if=/dev/zero of=test bs=64k count=16k conv=fdatasync16384+0 records in16384+0 records out1073741824 bytes (1.1 GB, 1.0 GiB) copied, 7.03664 s, 153 MB/s

Результаты теста бенчмарка 7-zip:
root@host:/home/ubuntu# 7za b7-Zip (a) [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21p7zip Version 16.02 (locale=C.UTF-8,Utf16=on,HugeFiles=on,64 bits,2 CPUs LE)LECPU Freq: - - - - - - 512000000 - -RAM size:     952 MB,  # CPU hardware threads:   2RAM usage:    441 MB,  # Benchmark threads:      2                       Compressing  |                  DecompressingDict     Speed Usage    R/U Rating  |      Speed Usage    R/U Rating         KiB/s     %   MIPS   MIPS  |      KiB/s     %   MIPS   MIPS22:       6957   167   4054   6768  |       8353   199    358    71323:        757   172    448    772  |      22509   200    975   194824:       7073   185   4118   7606  |      80370   200   3535   705625:       6831   185   4227   7800  |      77906   199   3480   6934----------------------------------  | ------------------------------Avr:             177   3212   5736  |              199   2087   4163Tot:             188   2649   4950


Сравнение стоимости инстанса t4g.micro с VPS на x86


Воспользуемся калькулятором calculator.aws и рассчитаем на сколько ARM дешевле x86 VPS на AWS. Расчет будем производить для площадки Europe (Frankfurt) eu-central-1. Ближайшей аналог x86 по характеристикам это инстанс t2.micro.

Конфигурация инстанса t2.micro:
  • 1 vCPUs
  • 1 GiB memory
  • 8 GB SSD

Допустим инстанс будет работать 365 дней * 24 часа * 1 год = 8760.0000 часов.

Ежемесячный платеж за аренду инстанса по требованию без учета трафика составит:
  • t4g.micro (ARM): 5.33 USD ~ 400 р. (по курсу 1$ = 75 р.);
  • t2.micro (x86): 7.96 USD ~ 597 р. (по курсу 1$ = 75 р.).

Получает что сервер на ARM стоит на 33% дешевле аналога на x86. Отдельно необходимо рассчитывать объем сетевого трафика, стоимость не зависит от типа архитектуры инстанса. Первый гигабайт трафика в месяц будет бесплатным, далее объем до 10 ТБ оплачивается по цене $0.09 за каждый Гб. Входящий трафик не тарифицируется. Если будем исходить из средней сетевой нагрузки в 150 Гб исходящего трафика в месяц, то стоимость за трафик будет:

  • 150 Гб * $0.09 = $13.5 ~ 1000 р. (по курсу 1$ = 75 р.);

В итоге VPS инстанс t4g.micro (ARM) с объемом трафика в 150 Гб в месяц будет стоить 1 400 р./месяц.

Если для сравнения взять VPS от VDSina.ru за 330 р./месяц (1 ядро, 30 ГБ NVMe, 32 ТБ трафика), то для конкурентного преимущества серверам на ARM еще расти и расти.

Вывод: Отсутствие нативного ПО под ARM архитектуру еще долго будет останавливающим фактором массового перехода. Но так или иначе частичный переход на ARM сервера это уже тренд. Основными двигателями перехода выступают три мощных фактора. Первый фактор независимость от основных поставщиков процессоров x86. Можно выбрать решение максимально подходящее под себя. Второй фактор возможность максимальной оптимизации под себя, исключение всего лишнего и добавление специализированных блоков, таких как NPU, FPGA, и т.д. Третий фактор открытость и доступность Linux. Если сравнивать ARM сервера для массового потребительского сектора, то в этом сегменте еще очень долго будет господствовать x86 архитектура. Скорее всего мы увидим создание нового сегмент рынка для специальных задач ориентированных на преимущества ARM архитектуры, например сервера с FPGA модулями или NPU.



На правах рекламы


Наша компания предлагает в аренду серверы с современными процессорами от Intel и AMD под самые разнообразные задачи. Эпичные серверы это VDS с AMD EPYC, частота ядра CPU до 3.4 GHz. Максимальная конфигурация 128 ядер CPU, 512 ГБ RAM, 4000 ГБ NVMe. Создайте свой собственный тариф самостоятельно в пару кликов!

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru