Горшочек, вари: серверный ARM-чип Marvell ThunderX3 с 96 ядрами и SMT4 для 384 потоков

Недавно мы публиковали новость о 128-ядерном ARM-процессоре Altra Max. Также на Хабре упоминали серверные ARM-чипы, которые использует компания Amazon. Но, как оказалось, серверные процессоры c архитектурой ARM выпускают и другие компании.

Так, еще в конце марта этого года был анонсирован процессор Marvell ThunderX3, это новое поколение серверных чипов от компании Marvell. Производитель увеличил количество ядер в своих процессорах с 32 до 96, оставив поддержку SMT4, которая дает возможность обрабатывать четыре потока одним ядром. Соответственно, такой чип способен обрабатывать 384 потока.

По словам представителей компании, SMT4 — гарантия того, что конвейеры отдельных ядер нагружаются эффективно. Новые процессоры при этом способны отлично работать не только в условиях многопоточных, но и однопоточных вычислений. Что касается односокетной конфигурации, то здесь поддерживаются 64 линии PCI Express 4.0 lanes, в двухсокетной число линий PCIe 4.0 увеличено до 128. В случае двухсокетных конфигураций процессоры соединяются через 16 линий PCI Express 4.0.

В отличие от прочих поставщиков ARM-чипов, предназначенных для серверов, компания Marvell использует не ARM Neoverse N1 архитектуру, а кастомную ARM8.3+. Информации о подсистеме кешей пока нет, но известно, что уровень латентности постоянен и не зависит от взаимного расположения ядер. А подсистема памяти аналогична Graviton2 и не включает восьмиканальный контроллер DDR4 с поддержкой частот до 3200 МГц.

Компания выпустит несколько вариантов ThunderX3 с теплопакетами от 100 до 240 Вт. По словам разработчиков, энергоэффективность новинки на треть превосходит AMD Rome (EPYC 2 поколения). Техпроцесс новинки — TSMC 7 нм.

Источник. Двухсокетная конфигурация с процессорами предыдущего поколения Thunder X2.

Производительность чипа на 25% выше, чем у процессоров ThunderX2 предыдущего поколения. Это если говорить о многопоточном режиме работы. В однопоточном производительность увеличена на 60%. При этом с целочисленными операциями новинка справляется в три раза быстрее представителей предыдущего поколения, а с вычислениями с плавающей запятой — в пять раз.

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

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

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

Хотите попробовать сервер на ARM-процессоре уже сейчас?

Добро пожаловать в Selectel Lab!

ссылка на оригинал статьи https://habr.com/ru/company/selectel/blog/508970/

10 советов по тестированию в Symfony

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

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

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

Тем, кто пришёл из других экосистем, поясню, что означает термин «функциональные тесты» в Symfony. В документации дано такое определение:

Функциональные тесты проверяют интеграцию разных уровней приложения (от маршрутизации до представлений (views).

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

Хочу дать несколько советов на основании моего опыта написания функциональных тестов Symfony.

Тестирование вместе с уровнем хранения данных

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

Обычно при прогоне тестов Symfony-приложение подключают к другой базе. Если у вас Symfony 4 или 5, то вы можете определить в файле .env.test переменные окружения, которые будут использоваться при тестировании. Также сконфигурируйте PHPUnit, чтобы поменять переменную окружения APP_ENV на test. К счастью, это происходит по умолчанию, когда вы устанавливаете компонент Symfony PHPUnit Bridge.

Для версий ниже 4 можно применять загрузку ядра (kernel booting) в режиме тестирования, когда прогоняешь функциональные тесты. С помощью файлов config_test.yml можно определять свою тестовую конфигурацию.

LiipFunctionalTestBundle

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

Например, при тестировании вы можете эмулировать вход пользователя, загружать фикстуры (fixture) данных, подсчитывать запросы к БД для проверки производительности регрессий, и т.д. Рекомендую установить этот пакет в начале тестирования нового Symfony-приложения.

Очистка БД после каждого теста

Когда нужно очищать базу при тестировании? Инструментарий Symfony не даёт подсказки. Я предпочитаю обновлять базу после каждого тестового метода. Тестовый набор выглядит так:

<?php  namespace Tests;  use Tests\BaseTestCase;  class SomeControllerTest extends TestCase {     public function test_a_registered_user_can_login()     {         // Clean slate. Database is empty.         // Create your world. Create users, roles and data.         // Execute logic.         // Assert the outcome.         // Database is reset.     } } 

Я обнаружил, что прекрасный способ очистки БД — загрузить пустые фикстуры в особый метод setUp в PHPUnit. Вы можете сделать это, если у вас установлен LiipFunctionalTestBundle.

<?php  namespace Tests;  class BaseTestCase extends PHPUnit_Test_Case {     public function setUp()     {         $this->loadFixtures([]);     } } 

Создание данных

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

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

<?php  namespace Tests\Helpers;  use AppBundle\Entity\User;  trait CreatesUsers {     public function makeUser(): User     {         $user = new User();         $user->setEmail($this->faker->email);         $user->setFirstName($this->faker->firstName);         $user->setLastName($this->faker->lastName);         $user->setRoles([User::ROLE_USER]);         $user->setBio($this->faker->paragraph);          return $user;     } 

Я могу добавлять такие интерфейсы в желаемый тестовый набор:

<?php  namespace Tests;  use Tests\BaseTestCase; use Tests\Helpers\CreatesUsers;  class SomeControllerTest extends TestCase {     use CreatesUsers;     public function test_a_registered_user_can_login()     {         $user = $this->createUser();                  // Login as user. Do some tests.     } } 

Замена местами сервисов в контейнере

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

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

К счастью, в Symfony 4.1 можно обращаться к контейнеру и менять сервисы по своему желанию. Например:

<?php  namespace Tests\AppBundle;  use AppBundle\Payment\PaymentProcessorClient; use Tests\BaseTestCase;  class PaymentControllerTest extends BaseTestCase {     public function test_a_user_can_purchase_product()     {         $paymentProcessorClient = $this->createMock(PaymentProcessorClient::class);         $paymentProcessorClient->expects($this->once())             ->method('purchase')             ->willReturn($successResponse);          // this is a hack to make the container use the mocked instance after the redirects         $client->disableReboot();         $client->getContainer()->set(PaymentProcessorClient::class, $paymentProcessorClient)     } } 

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

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

Исполнение SQLite в памяти

SQLite очень часто используют в качестве уровня хранения данных при тестировании, потому что он очень компактен и очень легко настраивается. Эти качества также делают его очень удобным для использования в CI/CD-окружении.

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

При конфигурировании БД в Symfony-приложении не надо указывать файл database.sqlite, достаточно передать его с ключевым словом :memory:.

Исполнение SQLite в памяти с tmpfs

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

На Linux-системах можно выделить часть оперативной памяти, которая будет вести себя как обычное хранилище. Это называется tmpfs. По сути, вы создаёте tmpfs-папку, кладёте в неё файл SQLite и используете для прогона тестов.

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

Тестирование уровня Elasticsearch

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

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

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

Использование фильтров Xdebug для ускорения отчёта о покрытии

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

Обычно оценкой покрытия занимается Xdebug.

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

К счастью, можно сделать некоторые оптимизации. Когда Xdebug генерирует отчёт о покрытии исполняющихся тестов, он делает это для каждого PHP-файла в тесте. Сюда входят и файлы, находящиеся в вендорской папке — код, который нам не принадлежит.

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

Как создать фильтры? Это может сделать PHPUnit. Нужна только лишь одна команда для создания файла конфигурации фильтра:

phpunit --dump-xdebug-filter build/xdebug-filter.php 

А затем передаём этот конфиг при прогоне тестов:

phpunit --prepend build/xdebug-filter.php --coverage-html build/coverage-report 

Инструменты распараллеливания

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

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

Я смог использовать 6 ядер и 12 потоков на своём компьютере, и вместо 4 минут прогонял тесты за 25-30 секунд.

Дополнение: Некоторые полезные комментарии к этой статье можно почитать на r/php. А здесь вы найдёте другие советы и информацию об инструментах.

ссылка на оригинал статьи https://habr.com/ru/company/mailru/blog/508376/

Упрощаем фоновые рисунки c помощью конических градиентов

Один из известных способов создания повторяющихся фоновых узоров — это применение
линейных градиентов. Но если использовать с этой же целью conic-gradient(), требуется значительно меньшее количество CSS-кода. Данное преимущество конических градиентов проиллюстрировано в статье несколькими примерами, взятыми из галереи Лии Веру.

Нам предстоит рассмотреть

Если вдруг вы пропустили важную новость, Firefox теперь поддерживает конические градиенты.

75 версия Firefox, вышедшая 7 апреля, дала возможность, перейдя в редактор настроек about:config, найти параметр layout.css.conic-gradient.enabled и поменять его значение на true. Значение по умолчанию — false, и переключить его можно двойным кликом.

Активируем конические градиенты в Firefox 75+

Теперь мы готовы проверить, как отрабатывает наш CSS в разных браузерах, включая Firefox.

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

Что мне особенно нравится в конических градиентах, так это то, что они значительно облегчают создание фоновых узоров. Давайте возьмем несколько фоновых рисунков из галереи, созданной Лией Веру около 10 лет назад на основе linear-gradient(), и посмотрим, насколько их можно упростить, используя конический градиент.

Пирамиды

Орнамент из пирамид

В данном примере используются четыре линейных градиента:

background:   linear-gradient(315deg, transparent 75%, #d45d55 0) -10px 0,   linear-gradient(45deg, transparent 75%, #d45d55 0) -10px 0,   linear-gradient(135deg, #a7332b 50%, transparent 0) 0 0,   linear-gradient(45deg, #6a201b 50%, #561a16 0) 0 0 #561a16; background-size: 20px 20px; 

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

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

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

Выделяем элементы орнамента

По умолчанию конические градиенты начинаются в точке, соответствующей положению стрелки часов, указывающей на 12, и далее распределяются по часовой стрелке. Но в нашем случае нужно сдвинуть начальную точку на угол 45° по часовой стрелке, а затем поочередно отрисовать треугольники, каждый из которых занимает четверть (25%) площади квадрата.

Элемент орнамента на основе конического градиента с резкими переходами цветов через каждые 25% с началом, отстоящим от вертикальной оси на 45°. См. демо

Это означает, что узор из пирамид можно сократить следующим образом:

$s: 20px; background:   conic-gradient(from 45deg,      #561a16 25%,      #6a201b 0% 50%,      #a7332b 0% 75%,      #d45d55 0%)      50%/ #{$s $s}; 

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

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

Пример можно посмотреть в действии на CodePen:

Шахматный узор

Шахматный узор

Данный узор создан с помощью двух линейных градиентов:

background-color: #eee; background-image:   linear-gradient(45deg, black 25%, transparent 25%,      transparent 75%, black 75%, black),   linear-gradient(45deg, black 25%, transparent 25%,      transparent 75%, black 75%, black); background-size: 60px 60px; background-position: 0 0, 30px 30px;

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

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

Выделяем элементы орнамента

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

Участок узора, созданного с помощью конического градиента с резкими переходами цветов через каждые 25%, с началом в исходной точке по умолчанию. После 50% рисунок повторяется. Cм. демо.

Такое повторение на второй половине участка от 0 до 100% означает, что можно использовать repeating-conic-gradient(). С помощью последнего мы получим 76 байтов скомпилированного CSS вместо 263, сократив таким образом код более чем на 70%:

$s: 60px; background:   repeating-conic-gradient(#000 0% 25%, #eee 0% 50%)      50%/ #{$s $s};

Демо можно посмотреть на CodePen:

Шахматный рисунок по диагонали

Шахматный узор по диагонали

Данный рисунок также образован двумя линейными градиентами:

background-color: #eee; background-image:    linear-gradient(45deg, black 25%, transparent 25%,      transparent 75%, black 75%, black),   linear-gradient(-45deg, black 25%, transparent 25%,      transparent 75%, black 75%, black); background-size: 60px 60px;

Проведем горизонтальные и вертикальные линии, чтобы разбить рисунок на одинаковые квадраты:

Выделяем элементы узора

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

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

Обратите внимание, что демо не работает в браузерах, не поддерживающих конический градиент.

Итак, код выглядит следующим образом:

b$s: 60px; background:   repeating-conic-gradient(from 45deg,      #000 0% 25%, #eee 0% 50%)    50%/ #{$s $s};

Демо можно посмотреть на CodePen:

Код опять же не только стал проще для восприятия, но и сократился почти на две трети: получилось всего 83 байта скомпилированного СSS вместо 229.

Треугольники (половины ромбов)

Орнамент из треугольников

Рассматриваемый рисунок образован сочетанием четырех линейных градиентов:

background: #36c; background:   linear-gradient(115deg, transparent 75%, rgba(255,255,255,.8) 75%) 0 0,   linear-gradient(245deg, transparent 75%, rgba(255,255,255,.8) 75%) 0 0,   linear-gradient(115deg, transparent 75%, rgba(255,255,255,.8) 75%) 7px -15px,   linear-gradient(245deg, transparent 75%, rgba(255,255,255,.8) 75%) 7px -15px,   #36c; background-size: 15px 30px;

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

Выделяем элементы узора

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

Параллельные линии

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

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

На рисунке представлен конический градиент, начало которого смещено относительно начала по умолчанию на угол β. Первый участок градиента (верхний правый маленький треугольник) доходит до угла α, второй участок (нижний правый темный треугольник) — до угла 2·α. Третий участок (нижний светлый треугольник) завершается в точке, соответствующей 180° (50%) относительно начала градиента. Четвертый участок (нижний левый темный треугольник) доходит до угла 180° + α, а пятый (верхний левый светлый треугольник) — до угла 180° + 2·α, тогда как шестой занимает оставшуюся часть круга.

Получаем углы α и β (демо)

Для треугольника, выделенного справа на рисунке, получаем следующее:

tan(α) = (.5·h)/(.5·w) = h/w;

Зная ширину (w) и высоту (h) фрагмента рисунка, можно вычислить величины углов α и β:

α = atan(h/w) β = 90° - α

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

$w: 15px; $h: 30px; $a: atan($h/$w)*180deg/pi(); $b: 90deg - $a; $c0: #36c; $c1: #d6e0f5;  html {   background:      conic-gradient(from $b,        $c1 0% $a,        $c0 0% 2*$a,        $c1 0% 50%,        $c0 0% 180deg + $a,        $c1 0% 180deg + 2*$a,        $c0 0%)      0 0/ #{$w $h}; }

Таким образом, получается всего 157 байтов скомпилированного CSS вместо 343. Ниже можно посмотреть результат:

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

Существует особый случай, когда величина угла между 2*$a и 50% (180deg) равна $a, откуда следует, что величина $a равна 60deg, то есть равнобедренные треугольники являются равносторонними. В этом случае объем скомпилированного CSS можно сократить до менее чем 100 байтов за счет применения повторяющегося градиента:

$a: 60deg; $b: 90deg - $a; $w: 15px; $h: $w*tan($a); $c0: #36c; $c1: #d6e0f5;  html {   background:      repeating-conic-gradient(from $b,        $c1 0% $a, $c0 0% 2*$a)      0 0/ #{$w $h} }

Ниже можно посмотреть демо:

Бонус: фон из пересекающихся линий

Примеры фонов из пересекающихся линий

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

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

Структура бонусного фонового рисунка

Градиент распределен вокруг точки пересечения прямых с координатами (x,y). Он начинается от угла β, образованного вертикальной осью и отрезком прямой, расположенным в верхнем правом углу. Градиент имеет резкие переходы цветов на участках, соответствующих углам α, 50% (180°) и 180° + α.

Если необходимо создать несколько элементов с подобными фонами, образуемыми пересекающимися линиями разных цветов, для этого идеально подойдут CSS-переменные:

.panel {   background:      conic-gradient(from var(--b) at var(--xy),        var(--c0) var(--a), var(--c1) 0% 50%,        var(--c2) 0% calc(180deg + var(--a)), var(--c3) 0%); }

Нужно всего лишь задать значения положения центра градиента (—xy), угла начала градиента (—b), первого угла перехода цвета (—a) и цветов палитры с —c0 до —c3.

.panel {   /* same as before */      &:nth-child(1) {     --xy: 80% 65%;      --b: 31deg;     --a: 121deg;      --c0: #be5128;     --c1: #ce9248;     --c2: #e4c060;     --c3: #db9c4e   }      /* similarly for the other panels */ }

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

В данном примере в качестве аргументов conic-gradient() используются CSS-переменные, поэтому демо не работает в браузерах, которые их не поддерживают.

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

ссылка на оригинал статьи https://habr.com/ru/post/509016/

MQTTv5.0: Обзор новых функций

Привет всем любителям IoT и железок!

В этой статье я расскажу про, пожалуй, самый популярный протокол передачи данных, используемый в сфере Интернета вещей, — MQTT. А если конкретнее, то про MQTT Version 5.0 (версия, опубликованная 7 марта 2019 года). А если еще конкретнее, — про приятные нововведения версии 5.0 по сравнению с версией 3.1.1.

Кстати, а почему v5.0? Куда делась версия v4.0?

Коренная причина лежит в заголовке пакета CONNECT. Версия протокола или, если быть более точным, уровень версии протокола устанавливается в байте 7.




“The 8-bit unsigned value that represents the revision level of the protocol used by the Client. The value of the Protocol Level field for the version 3.1.1 of the protocol is 4 (0x04).”



Уровень протокола v3.1 определяется как 3, а v3.1.1 — 4. Следовательно, следующий уровень протокола — 5. Чтобы избежать несоответствия, группа спецификации согласилась назвать следующую версию MQTTv5.0:

“The value of the Protocol Version field for version 5.0 of the protocol is 5 (0x05).”

По словам (от 11 декабря 2019 года) Lee Stacey, product evangelist at Thingstream, скоро MQTT будет основным протоколом обмена данными между датчиками.

“В настоящее время устройства IoT используют разные протоколы обмена сообщениями, например: XMPP, AMQP, DDS. Такая фрагментация была препятствием для прогресса в IoT с самого начала.

Протоколы обмена сообщениями — одна из областей, где требуется стандартизация.

Вероятно, лидирующую позицию займет MQTT. Он существует уже более 25 лет, прост, потребляет мало энергии — в сочетании с другими преимуществами это делает его идеальным стандартом для IoT. Дополнительные функции, добавленные в MQTT для ретрансляции данных из сенсорных сетей, позволяют IoT-устройствам использовать для отправки сообщений еще меньше энергии.”

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

Прим. — Далее по тексту буду называть topic — топиком, а payload — полезной нагрузкой.

Наиболее важно, что MQTTv5.0 не имеет обратной совместимости (как v3.1.1). Очевидно, что введено слишком много нового, поэтому необходимо пересмотреть существующие реализации.

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

Основные функциональные цели MQTTv5.0:

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

Основные новые функции можно разделить, для наглядности, на следующие группы:

1. Особенности подключения

  • Расширенная аутентификация (Enhanced authentication)
  • Истечение сеанса (Session expiration)
  • Клиентские и серверные ограничения (Client and Server restrictions/limitations)
  • Интервал задержки Will Message (Will Delay Interval)
  • Перенаправление сервера (Server Reference or Server Redirect)

2. Особенности публикации сообщений

  • Интервал истечения сообщения (Message Expiry Interval)
  • Индикатор формата полезной нагрузки и тип содержимого (Payload format indicator & Content type)
  • Псевдонимы для топиков (Topic Aliases)
  • Ответ на запрос (Response Topic)

3. Особенности подписки

  • Отсутствие локальных публикаций (Non local publishing)
  • Контроль сохраненных сообщений (Retained message control)
  • Идентификатор подписки (Subscription identifier)
  • Общие подписки (Shared subscriptions)

4. Общие особенности

  • Коды и строки причин на все ACK-сообщения (Reason codes on all ACK messages)
  • Отключение сервера (Server disconnect)
  • Пользовательские свойства (User properties)

Особенности подключения

Расширенная аутентификация (см. п. 4.12 в спецификации)

В MQTTv5.0 теперь доступны дополнительные методы аутентификации, помимо имени пользователя и пароля как в MQTTv3.1.1 (см. свойства Authentication Method и Authentication Data).

Истечение сеанса

В MQTTv3.1.1 и более ранних версиях клиент может управлять тем, как сервер обрабатывает сеанс клиента (сеанс означает подписку клиента и любые сообщения в очереди) с помощью флага «чистый сеанс». Если установлено значение 1, сервер удалит любой существующий сеанс для этого клиента и не сохранит сеанс после отключения. Если установлено значение 0, сервер восстановит любой существующий сеанс для клиента при повторном подключении и сохранит сеанс при отключении клиента.

В MQTTv5.0 этот механизм в основном сохранился, за исключением того, что теперь появился таймер истечения сеанса (см. свойство Session Expiry Interval). Если флаг установлен как false, нужно указать значение окончания сеанса. Если этого не сделать, будет установлено значение 0, что делает соединение таким же, как если бы значение чистого сеанса было установлено как true.

Например, можно установить время истечения сеанса 300 секунд. Это означает, что если клиент отключается и повторно подключается в течение 5 минут со значением чистого сеанса false, QOS > 1, то данные состояния сеанса (например, подписка на топики, сообщения в очереди) сохраняются. Однако, если клиент отключается и повторно подключается по истечении 5 минут с теми же настройками, данные о состоянии сеанса удаляются и клиент должен повторно подписаться на топики, а сообщения, отправленные во время отсоединения клиента, теряются.

Клиентские ограничения

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

  • по размеру сообщений для отправки (см. свойство Maximum Packet Size),
  • по количеству сообщений QOS 1 и 2 (см. свойство Receive Maximum).

Ограничение размера сообщений

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

Ограничение количества сообщений

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

Серверные ограничения

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

Например, в сообщении CONNACK сервер может указать максимальное значение псевдонима топика (см. свойство Topic Alias Maximum) и время истечения сеанса (см. свойство Session Expiry Interval).

Интервал задержки Will Message

Используется для указания временной задержки (см. свойство Will Delay Interval) при отправке Will Message, предотвращая отправку сообщения при коротком прерывании соединения.

Перенаправление сервера (см. п. 4.11 в спецификации)

Это очень интересная функция, поскольку она позволяет серверу перенаправлять клиента к другому брокеру/серверу (см. свойство Server Reference).

Особенности публикации сообщений

Интервал истечения сообщения

Когда сообщение публикуется с QOS 1 или 2 и клиент-получатель имеет:

  1. чистый сеанс false,
  2. подписку с QOS 1 или 2,

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

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

Индикатор формата полезной нагрузки и тип содержимого

Индикатор формата полезной нагрузки устанавливается при публикации сообщения (см. свойство Payload Format Indicator) как один из двух вариантов:

  1. бинарный — то же самое, что в v3.1,
  2. строка UTF-8 — новая возможность v5.

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

Также при публикации сообщений можно указать тип содержимого в стиле MIME (см. свойство Content Type).

Псевдонимы для топиков

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

Созданный псевдоним топика можно использовать вместо самого топика. Если у топика homes/house1/upstairs/light1 есть псевдоним 1 (см. свойство Topic Alias), то это число можно использовать вместо строки топика при публикации сообщений.

Прежде чем использовать псевдонимы топиков, клиент должен указать максимальное количество псевдонимов (см. свойство Topic Alias Maximum) для сервера. По умолчанию, если это не установлено, псевдонимы топиков клиентом не используются.

Ответ на запрос

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


Использование топика для ответа (см. свойство Response Topic) в сообщении публикации позволяет реализовать шаблон запроса/ответа, распространенный в веб-приложениях. Таким образом создается виртуальное соединение между клиентами, так что один из клиентов может функционировать как традиционный сервер, хотя пакеты всё так же проходят через брокера.


Особенности подписки

Отсутствие локальных публикаций

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

Контроль сохраненных сообщений

Сохраненные сообщения по-прежнему работают, как в версии 3.1.1, но теперь добавлены параметры подписки для управления тем, что получает клиент:

  • 0 — отправить сохраненные сообщения, когда клиент подписывается. То же, что и в MQTT 3.1.1,
  • 1 — отправить сохраненные сообщения, когда клиент подписывается, если подписка в настоящее время не существует.
  • 2 — не отправлять сохраненные сообщения, когда клиент подписывается.

Идентификатор подписки

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

Общие подписки (см. п. 4.8.2 в спецификации)

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


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


Топик для такой подписки должен начинаться с ключевого слова $share.

Формат фильтра топиков следующий:
$share/{ShareName}/{filter}
$share — служебное слово, символьная строка, которая помечает фильтр топиков как фильтр топиков общей подписки
{ShareName} — название подписки, символьная строка, которая не должна включать "/", "+" или "#"
{filter} — то же самое, что топик в обычных подписках

Пример:

4 клиента подписываются на $share/group1/my/topic, 3 клиента подписываются на $share/group2/my/topic, и 3 клиента подписываются по обычной подписке (2 — my/topic и 1 — по wildcard подписке my/#).

Затем, если клиент публикует сообщение для топика my/topic:

  1. 1 сообщение отправлено одному из клиентов, подписавшихся на $share/group1/my/topic
  2. 1 сообщение отправлено одному из клиентов, подписавшихся на $share/group2/my/topic
  3. 3 сообщения отправлено клиентам с обычной подпиской

Таким образом, в общей сложности 5 сообщений отправляются клиентам.


Общие особенности

Коды и строки причин на все ACK-сообщения

В MQTTv3.1.1 было очень мало указаний от сервера относительно того, что пошло не так на разных этапах:

  • установление связи,
  • публикация сообщения,
  • подписка на топики.

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

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

Следует помнить, что коды причины являются необязательными, сервер/брокер все еще может решить просто отключить клиентов как в MQTTv3.1.1, например, по соображениям безопасности.

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

Отключение сервера

В MQQTv3.1.1 только клиент может отправить сообщение об отключении. Если сервер столкнулся с проблемами, он просто прервал бы сеанс TCP/IP. В MQTTv5 сервер может отправить клиенту сообщение о разъединении вместе с кодом причины (ошибка протокола, неавторизованное подключение и т.д.).

Примеры кодов причины из спецификации (см. п. 3.14.2.1 в спецификации):


Пользовательские свойства

Добавлены во все типы пакетов. Они определяются пользователем и представляют собой набор пар ключ-значение (см. свойство User Property). Полезны для отправки информации за рамками полезной нагрузки, в то время как в 3.1.1 любая информация отправлялась как часть полезной нагрузки.

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

Заключение

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

ссылка на оригинал статьи https://habr.com/ru/post/508194/

Я перегорел, уже как 2 года

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

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

Копаясь в себе, я определил для себя 2 главные причины происходящего:

  • отсутствие магии;
  • наличие конвейера.

Отсутствие магии

Увлекаться программированием я начал давно: класса с 7го, как открыл для себя робототехнику. Тогда магией казалось все: до заветного написания Hello World в Bascom еще добраться нужно было, пережив разводку и травление плат. А на выяснения того, что ты не довоткнул МК или криво пропаял дорожку могли уходить вечера.

Дальше — больше, стены рушились одна за другой:

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

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

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

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

Прям какая-то нездоровая зависимость от знаний и новых технологий.

Наличие конвейера

Как только я закончил универ, я вышел на полноценные 40 часов в неделю. До этого я или фрилансил или работал неполную неделю (в лучшем случае 24 часа). И тут я начинаю понимать, что что-то не то, что все, что я люблю в программировании превращается в работу у станка.

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

Так все устроено: невозможно все время разрабатывать что-то уникальное.

Попытки выхода

Охх… что я только не перепробовал: pet-проекты, хакатоны, статьи на хабр, менторство, DevOpsing, менеджерские и управленческие задачи, но исход всегда один: отсутствие магии и наличие конвейера.

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

Вместо заключения

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

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

Но ответ прост: я пришел ради магии будучи ребенком.

ссылка на оригинал статьи https://habr.com/ru/post/508996/