Обзор OpenStack Neutron PTG июнь 2020

PTG (Project Team Gathering) – это мероприятие, на котором команды разработчиков встречаются для обсуждения текущих задач, статусов и планов. Несколько лет назад PTG отделилось от основного OpenStack саммита.

PTG впервые проводился в онлайн формате через Zoom и Jitsi Meet. Однако сочетание картинки и звука на встрече сделало это изменение совсем незаметным, особенно на фоне ныне привычных командных митингов через IRC.
Трехчасовые сессии, посвященные Neutron, проходили со вторника по пятницу. Основной протокол встреч опубликован в OpenStack Etherpad и в списке рассылки OpenStack. Повестка мероприятия была сформирована на основе предложений разработчиков Neutron, а расписание встреч подготовил ее председатель, PTL (Project Team Lead) команды Neutron Slawek Kaplonski.

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

OVN

На этом PTG было много разговоров об OVN, что неудивительно, поскольку большинство членов core команды представляют RedHat – основной contributor в OVN.
Что же такое OVN?

  • Open source L2/L3 network virtualization для Open vSwitch (OVS):
    • Логические свитчи
    • Логические IPv4 и IPv6 роутеры
    • L2/L3/L4 ACLs (Security Groups)
    • Multiple tunnel overlays (Geneve, STT, and VXLAN)
    • Логические балансировщики нагрузки
    • TOR-based логико-физические L2 шлюзы
    • Software-based логико-физические L2/L3 шлюзы
  • Работает на тех же платформах, что и OVS:
    • Linux
    • Контейнеры
    • DPDK
  • Интеграция с:
    • OpenStack Neutron
    • Docker Swarm
    • Kubernetes

Архитектура OVN

“OVN в 75 словах.
Open Virtual Network управляется в рамках проекта OVS и разрабатывалась изначальным коллективом создателей OVS. Это решение является попыткой переработать ML2/OVS control plane опираясь на накопленный годами опыт. Оно предназначено для использования в OpenStack и Kubernetes. OVN построен на новой архитектуре, которая отказалась от концепции взаимодействия Python агентов с сервисом Neutron API через RabbitMQ в пользу C daemons общающихся через OpenFlow и OVSDB.” — Slawek Kaplonsky, Neutron PTL.

Изначально Neutron OVN драйвер разрабатывался как отдельный проект в Neutron stadium — networking-ovn, а в релизе Ussuri был включен в основной репозиторий Neutron.

Таким образом, в этом решении исчезает основная проблема ML2/OVS — RabbitMQ, что является несомненным плюсом, да и в целом “OVN’s design goal is to have a production-quality implementation that can operate at significant scale”. Однако поддерживает ли OVN тот функционал, который доступен при использовании ML2/OVS? Кажется, что это не совсем так, что стало одной из тем для обсуждения на PTG. По итогам было выделено несколько пробелов (полный список доступен на странице проекта). В первую очередь разработчики отметили отсутствие либо неполную поддержку routed networks, некоторые QoS фичи, BGP и Availability Zones. Хоть команда OVN и готова заняться всем перечисленным, в ходе встречи они признали, что это ранее не было для них приоритетной задачей – так как внутренние интересы были важнее. Кроме того, разработка ML2/OVS, разумеется, не приостанавливается, а значит могут появляться новые пробелы.

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

  • Один из основных компонентов, ovn-northd, на данный момент поддерживает только active/passive режим HA, active/active пока только в планах
  • Другой центральный компонент, ovsdb-server, также поддерживает только active/passive режим

Не исключено, что последний пункт на самом деле уже устарел, поскольку поддержка кластера ovsdb (на основе алгоритма Raft) была добавлена с версии OVS 2.9, однако неочевидно, тестировалось ли это во варианте с OVN и OpenStack. Например, связанный с этим тикет в openstack-ansible пока не закрыт.
Кроме того, беспокойство вызывает то, что OVN использует Geneve туннели вместо VxLAN, что влияет на настройки MTU (заголовки Geneve больше VxLAN) и поддержку аппаратного ускорения обработки туннелей.

Как бы то ни было, проект быстро набирает обороты и кажется, что уже через пару релизов OVN должен стать базовым Neutron плагином. Более того, во время PTG разработчики core команды договорились сделать OVN дефолтным плагином для DevStack.
К чему приведут эти изменения:

  • Поскольку большинство OpenStack проектов используют Neutron в своих CI, это нововведение потенциально имеет большое значение
  • По идее оно не должно привести к сокращению поддержки ML2/OVS (однако по сути это и подразумевается)
  • В самом Neutron CI джобы для других плагинов остаются, например ML2/Linuxbridge и ML2/OVS – здесь ничего не изменится, кроме названий отдельных джоб
  • Сообществу станет ясно, что core команда считает OVN будущим проекта

Что касается последнего пункта, Neutron PTL опубликовал следующее сообщение: “Neutron команда полагает, что OVN и драйвер Neutron OVN построены на современной архитектуре, которая создает лучшую основу для работы более простого и производительного решения. Мы наблюдаем рост активности участия в kubernetes-ovn, что приводит к расширению core сообщества OVN, и мы бы хотели, чтобы OpenStack также воспользовался этим вложением в OVN со стороны Kubernetes.
На данный момент у Neutron OVN драйвера есть пробелы в поддерживаемом функционале по сравнению с ML2/OVS, однако наша команда старается закрыть эти бреши, и мы считаем, что этот драйвер станет будущим для Neutron, а потому мы хотим сделать его дефолтным Neutron ML2 бэкендом для DevStack.”
Пока реакция на эти новости скорее позитивная, хотя все еще есть сомнения касательно перехода от VxLAN к Geneve туннелям, способы миграции с ML2 OVS на ML2 OVN, а также производительности и поддерживаемого функционала.

Применение нового EngineFacade

EngineFacade – это фреймворк поверх sqlalchemy который объединяет логику, касающуюся баз данных, используемую во всех проектах OpenStack. Несколько релизов назад он прошел через рефакторинг, что привело к появлению так называемого “new EngineFacade”. Следующим шагом стала адаптация этого фреймворка в OpenStack.

На мой взгляд, эту тему включили в повестку PTG в связи с тем, что работа над ней тянется уже на протяжении нескольких релизов и до сих пор не завершена. Причинами такого развития событий являются большой объем необходимых изменений, отдельные нетривиальные проблемы в процессе адаптации и, как мне кажется, недостаток мотивации, а значит и людских ресурсов. И действительно, зачем менять то, что уже работает и даже не выдает кучу багов? Довольно подробный ответ на этот вопрос изложен в спецификации Майка Байера. Здесь же я постараюсь дать краткий пересказ соображений в поддержку EngineFacade, чтобы вам не пришлось читать этот длиный текст:

  • Старый EngineFacade предоставляет низкоуровневые API вместо высокоуровневых API подогнанных под конкретный use case, поэтому это по сути фабрика, а не фасад. В результате:
    • Нет согласованности в использовании старого EngineFacade в разных проектах OpenStack
    • Неправильное использование сессий, подключений БД и транзакций ведет к проблемам с производительностью, стабильностью работы и удобством поддержки

  • Новый EngineFacade скрывает всю логику сессий/подключений/транзакций и предоставляет только два контекст менеджера: reader и writer, в зависимости от того, что именно необходимо в текущем методе.

Звучит просто и логично, так в чем же тогда проблема с адаптацией EngineFacade? Честно говоря, я не очень сильно вникал в детали, но кажется, что основной причиной проблем становится то, что в некоторых сложных сценариях старый EngineFacade неправильно использовался в Neutron и оно работало (!), а новый EngineFacade пытается все сделать правильно, но, тем не менее, ломает рабочие сценарии (по моему довольно типичная проблема при работе с легаси кодом :D). Очевидно, в таком случае нужно сначала исправить логику этих сценариев.
На самом деле, осталось править не так уж и много – всего один патч, и core команда договорилась совместно решить эту задачу. Разумеется, любой заинтересовавшийся может помочь с анализом и ревью!

Neutron-lib

Несколько топиков было посвящено neutron-lib. Начну с того, что напомню, что это такое для тех, кто не сильно вовлечен в разработку Neutron. Во-первых, Neutron не является единым проектом – на самом деле он состоит из нескольких репозиториев, работающих с разными областями сети OpenStack под общим названием Neutron Stadium, и “neutron” – это лишь один, хоть и основной проект. Остальные проекты – это так называемые advanced сервисы (например neutron-lbaas, -fwaas, -vpnaas, -dynamic-routing и т.д.) и сторонние/вендорские плагины (например networking-midonet, -odl, -ovn). В этот список входят проекты, которые разрабатывают Neutron PTL и core команда и непосредственно занимаются ими на ежедневной основе. Чтобы это было возможно, они следят за соблюдением общих принципов и правил работы во всем Stadium во всех аспектах разработки – структура, разработка, code style, тестирование, документирование и т.д. Честно говоря, на сегодняшний день это не совсем так, и основная нагрузка все же ложится на плечи проект мейнтейнеров.

До создания neutron-lib все проекты с префиксом networking- импортировали весь общий код – константы, интерфейсы (абстрактные базовые классы), вспомогательные функции и прочее — из основного репозитория neutron. Любые изменения такого кода в neutron могли нарушить работу зависимых проектов. Тогда в релизе Ocata для решения этой проблемы была запущена neutron-lib initiative: весь общий код теперь должен храниться в отдельным репозитории и должен был версионированным. Более конкретно цели формулировались следующим образом:

  • Убрать зависимость подпроектов от Neutron (т.е. убрать прямые импорты из neutron в подпроектах)
  • Сделать домашнюю работу в Neutron путем рефакторинга кода или переработки архитектуры неоптимальных паттернов в соответствующих разделах neutron-lib

По сути, neutron-lib выглядит как win-win вариант: как основной Neutron, так и сервисы сторонних проектов должны быть в плюсе по итогу. Что же пошло не так?

Недостаточная поддержка

Ни один open-source проект не может существовать без поддержки контрибьюторов и мейнтейнеров – людей, готовых инвестировать свое время в работу над проектом. Для neutron-lib таких желающих начало не хватать, и в результате перестала работать первоначальная логика, т.е. чтобы здесь хранился весь общий код, который можно было бы импортировать вместо импорта neutron. Некоторое время назад основной maintainer neutron-lib (boden) покинул проект. Во время PTG была высказано предложение отказаться от идеи переноса всего общего кода в neutron-lib или даже перенести код neutron-lib обратно в neutron. Это предложение не прошло по двум причинам:

  • neutron-lib по-прежнему широко используется
  • neutron-lib несет в себе определенную ценность, поскольку он выделяет стандартные интерфейсы, которые нельзя менять, чтобы не сломать сразу несколько проектов

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

Проблема с тестированием

Другая проблема связана с тестированием в процессе разработки. Если часть патча в neutron вводит новый или меняет существующий общий код, она по правилами должна отправиться в neutron-lib. Так neutron часть патча становится зависимой от этих изменений в lib. Однако сейчас патчи в neutron тестируются на релизной версии neutron-lib, чтобы проверить работу с последним релизом. В итоге такие патчи не будут проходить тесты в CI.
Переход к тестированию всех neutron патчей с neutron-lib кодом из мастера также имеет некоторые недостатки. Например, нет никаких гарантий что мастер neutron работает с последним релизом neutron-lib, а ведь конечные пользователи работают именно с этой версией.
Вот способы решения этого вопроса (спасибо Bence Romsics за отличную сводку):

  • Если нет срочности, можно дождаться, пока ваш neutron-lib патч будет принят и уйдет в релиз, после чего продолжить работу над neutron патчем.
  • Если нужно двигаться быстрее, то зачастую может быть приемлимо работать с временным скопированным кодом:
    • Предположим, вы хотите добавить модуль “foo” в neutron-lib, но он еще не принят и не добавлен в релиз. Можно спокойно добавить в neutron патч его точную копию, назвать ее “_foo” и прикрепить TODO комментарий о том, что ее нужно убрать, когда ее оригинал появится в neutron-lib.
    • Когда часть из neutron-lib появится в релизе, не забудьте добавить патч в neutron, который бы убрал _foo и заменил “import _foo” на “from neutron-lib import foo”.

  • Кроме того, можно запускать отдельные проверки на CI и с мастером, и с последним релизом neutron-lib. Но голосующей может быть только одна из них. Простое удвоение количества задач даст огромную дополнительную нагрузку на CI инфраструктуру OpenStack

В ходе обсуждения на PTG прозвучало три предложения:

  • Использовать мастер neutron-lib для “Check CI”; использовать релиз-версию neutron-lib для “Gate CI” – однако если neutron патч будет проходить проверки “Check CI” и падать на “Gate CI”, это будет выглядеть странно
  • Ничего не менять: лучше проводить тесты на релиз-версии neutron-lib. Например, так сейчас делается для OSC (OpenStackClient)
  • Запускать тесты с мастером neutron-lib и добавить периодическую задачу для тестов с релиз-версией neutron-lib

Итоговое решение: создать новую неголосующую задачу в “Check CI” c neutron-lib из master ветки. По сути все остается как есть, но появится возможность проверить, что фича, включающая в себя изменения в neutron и neutron-lib, проходит CI прежде чем принимать ее в master ветку.

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

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

Золотая эпоха компьютерных юзер-групп

Задолго до появления сабреддитов компьютерные энтузиасты собирались вместе – причём вживую!

Кружок любителей компьютеров Homebrew Computer Club, где зародился компьютер Apple I, имеет заслуженную известность – однако это далеко не единственное сообщество, члены которого собирались из-за своей любви к вычислительным машинам. С 70-х до 90-х группы по всём мире помогали беспомощным пользователям разобраться с их компьютерами, узнавали о новых технологических тенденциях, открывали для себя новейшие супер-приложения. И эти группы не ограничивались Slack, цепочками электронных писем или форумами – встречи часто происходили в реальности.

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

И это было очень весело.

К примеру, в 1975 году Дэвид Интерсаймон начал посещать встречи компьютерного общества Южной Калифорнии. На одной из встреч он приобрёл ранний набор IMSAI 8080 и спаял его дома. «Огоньки зажглись, но процессор не перезапускался и останавливался», — вспоминает Интерсаймон.

Поэтому на следующей встрече он познакомился с «компьютерным доктором», которого рекомендовали ему как человека, готового помочь новичкам. «Доктор» исправил ошибки пайки, и предложил Интерсаймон купить карточку-терминатор шины Godbout Electronics S-100. «Наконец, мой IMSAI 8080 заработал, — говорит Интерсаймон, — и работает до сих пор!»

Программисты старой школы могут помнить долгую карьеру Интерсаймона в компании Borland. Сегодня он вице-президент сообщества разработчиков в Evans Data Corporation. А компьютерным «доктором» был Джордж Тейт, один из основателей Ashton-Tate, где разработали программу dBase.

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

Что собой представляли юзер-группы

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

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


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


Этот номер группы Apple 2000 (национальной юзер-группы поклонников компьютера Apple) от октября 1990 года содержал обзор игры «Moriarty’s Revenge»


Информационные бюллетени не должны были быть красивыми, как иллюстрирует эта публикация группы Commodore Eight Bit Boosters от октября 1994


Владельцам OS9 из Австралии повезло с этим бюллетенем, выходившим в 1989 году


Synchro Sette, листок юзер-группы, посвящённый ZX-81, имел подписчиков ещё в 1982


У Time Designs было очень много выпусков. Это сборник лучших материалов от энтузиастов компьютеров Timex и Sinclair, 1986 год.


«Для серьёзных программистов» из 1979 года


Некоторые журналы, издаваемые юзер-группами, выглядели профессионально. Это издание на 32 страницы привлекло подписчиков из 28 стран.

В небольших группах презентация могла представлять собой выступление одного члена группы перед другими. Группы с большим количеством членов и хорошими связями могли привлекать производителей, (правильно) расценивавших их, как первых пользователей продукта, с которыми стоит считаться. К примеру, на типичной встрече пользователей Phoenix PC в начале 90-х человек 300 могли собраться в конференц-зале отеля. Затем производитель мог час показывать им последнюю версию ПО — WordPerfect или Photoshop. Эти выступления были больше похожи на продуманные обучающие материалы, чем на презентации, нацеленные на продажи. В любом случае, присутствующие обучались чему-то новому. За демонстрацией могла последовать лотерея с неплохим призом – если учесть, что коммерческое ПО продавалось по $495 за копию.

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

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

Новая сенсационная технология

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

Гарри Маккракен посещал встречи бостонского компьютерного сообщества в 1979 году, и с нежностью вспоминает их сессии вопросов и ответов. «Вопросы были очень сложными, — вспоминает журналист, давно работающий в сфере технологий. – Не было никакого поклонения героям, просто умные пользователи компьютеров задавали осмысленные вопросы». Видеозаписи с некоторых из этих встреч можно посмотреть и в онлайне – к примеру, форум по будущему персональных компьютеров от 1981 года.

В 1981 году бостонское сообщество любителей компьютеров убедило выступить на одной из его встреч молодого Билла Гейтса

«Звёздами были Microsoft, WordPerfect и Adobe, — вспоминает член оклахомской группы пользователей ПК 1980-е годы. – На их презентации приходили сотни людей. Они раздавали полные версии своего ПО. Можно всегда было ожидать, что презентация новой версии продукта будет большим событием – примерно как сегодня Samsung и Apple запускают новые продукты».

Помощь с удовольствием

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

«Когда для поддержки работы Linux на настольном компьютере требовалось тратить всё рабочее время, — вспоминает член юзер-группы Triangle Linux, — было очень круто иметь доступ к сети людей с личным присутствием, с которыми можно было побеседовать, если ваше последнее откомпилированное ядро делало из вашей системы кирпич».

На общих встречах часто можно было получить неожиданные знания, и вы постоянно знакомились с различными технологиями. Вы могли ничего не знать о ПО для CAD, пока кто-нибудь не показал бы вам, что можно сделать с его помощью. В один месяц на презентации юзер-группы могли показывать графический редактор (Arts & Letters), в другой – инструмент для обслуживания компьютера (Norton Backup), в третий – объяснять принципы разбиения жёсткого диска на разделы.

Существовали и другие группы, специально посвящённые единой теме или продукту. К примеру, в сообществе Phoenix PC User Group существовало порядка десятка групп по интересам с ежемесячными встречами. Один из компьютерных магазинов в деловой части города разрешал им бесплатно встречаться на своей территории. Несколько десятков человек могли собираться там и делиться впечатлениями и советами по поводу Corel Draw, Lotus 1-2-3 или инструментов для веб-мастеров. Группа любителей OS/2 назначала «дни установки», во время которых члены юзер-группы помогали всем членам сообщества искать драйвера устройств и решать проблемы с установкой ОС. Несколько членов сообщества вызвались добровольцами для демонстрации в магазинах CompUSA своих любимых операционок.

Некоторые группы по интересам в итоге отпочковывались, становясь отдельными юзер-группами. В 90-х Роберт, ныне – ведущий канала RetroCAD на YouTube, был сопредседателем юзер-группы пользователей AutoCAD юго-восточного Висконсина (CADDIES), где было 500 членов, 50 постоянных посетителей встреч и выпускавшийся на бумаге новостной бюллетень.

«Встречи были хорошо структурированы, — вспоминает он. – Было вступление, обновления, касающиеся событий в мире CAD (интернета тогда не было, поэтому большая часть посетителей узнавала всю информацию именно так). Мы часто демонстрировали инструменты, железо (дигитайзеры, видеокарты, модемы) и техники рисования. Несколько раз в год мы приглашали гостей из разных компаний типа Autodesk».


Предводители сообществ регулярно встречались для оттачивания лидерских качеств (на фото – 1990-й год).

Запуск карьер

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

«Мне нравились социальные аспекты каждой из групп, но они ещё значительно повлияли и на мою карьеру, — говорит Джеральд Комбс. – В особенности юзер-группа UNIX из Канзаса, где я некоторое время был президентом». После доклада Комбса по поводу управления NNTP-серверами один из посетителей попросил провести консультации у местного интернет-провайдера. «После этого они меня наняли, но поскольку они не могли позволить себе Sniffer, я в итоге занялся разработкой анализатора протоколов для Solaris и Linux. А теперь у этого анализатора Wireshark есть активное онлайн-сообщество пользователей».

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

«Эти группы были необходимы мне для поддержания моих навыков», — говорит Тони Алан, присоединившийся к юзер-группе по планированию загрузки производственных мощностей в 1990-х. Он поддерживал контакты с профессионалами в области IT, с которыми познакомился в то время, и которые работали с мейнфреймами, а теперь – с облачными технологиями. «Доклады на конференциях пользователей были отличным способом для распространения опыта и поддержания своего статуса в индустрии», — добавляет он.

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

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

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

В 90-е Бренда Кристенсен отвечала за связи с юзер-группами в компании GoldMine Software. «Приятнее всего было видеть неподдельный энтузиазм и невероятно честную обратную связь, — говорит она. – Они были честными и не имели скрытых целей. Полученная от них обратная связь была сравнимой с неискажёнными данными от фокус-группы, причём хорошо информированной и технически подкованной. А ещё они были очень дружелюбными!»

Это работало в обе стороны. Члены радовались возможности рассказать производителям, что они хотят. Через несколько PR-фильтров можно было достучаться до директора почти любой компании. Хотите спросить Питера Нортона, что он думает о будущем компьютеров? Пожаловаться на одно из свойств Quicken? Поднимите руку во время сессии вопросов и ответов, и задайте вопрос директору компании.

Мыслите глобально, мыслите как гик

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

К примеру, когда Дори Смит в начале 90-х переехала в Лос-Анджелес, она там почти никого не знала. «Я решила, что хорошим способом познакомиться с будущими друзьями будет вызваться добровольцем в местной группе пользователей Mac, — говорит она. – Я вступила в группу, попала на их BBS, нашла интересные встречи, и начала ходить».


Награда лучшему добровольцу юзер-группы Island/Reach на основе дискеты

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

«На третьей встрече я пожаловалась Сюзи, что до сих пор ничего не слышала по поводу волонтёрской работы. Она сказала, что у LAMG пока нет координатора добровольцев – не хочу ли я занять это место? Вот так, всего через несколько недель после вступления в группу, без всяких связей, я благодаря своей надоедливости получила один из самых ответственных постов», — говорит Смит.

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

Для молодых участников этот опыт часто выливался в пожизненную любовь к технологиям. К примеру, в городе Лондон штата Онтарио группу любителей Atari ST начал посещать 13-летний подросток со своим отцом. «Это реально заложило во мне основы, — говорит он сегодня. – От той группы до технологии BBS, которая просто снесла мне крышу, это была возможность познакомиться с миром, казавшимся мне волшебным».

Другой человек вспоминает о времени, проведённом в юзер-группе Tandy из города Талса: «Я делал несколько презентаций, и даже вёл курсы по ассемблеру на Z-80 для нескольких пожилых чуваков, интересовавшихся этой темой. Мне тогда было 16».


Юзер-группа OS/2 спонсировала техноконференции – такие, как эта, от 2000 года


Некоторые юзер-группы существуют и сегодня – на сайте Apple в 2020 году даже есть особое место для таких групп (хотя сейчас, наверное, личные встречи пока не проводятся)

Так что же случилось?

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

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

Сегодня типичных юзер-групп уже нет. Исключения можно найти в неполном, и в основном, устаревшем списке ассоциации юзер-групп ПК, хотя если поискать в онлайне, вы, вероятно, найдёте и другие варианты. К примеру, Toronto PET Users Group (TPUG) является самой долгоживущей группой пользователей Commodore. Apple Pi из Вашингтона всё ещё удерживает позиции, как и Triangle Linux Users Group. Юзер-группа от IBM, SHARE, ведёт свою историю с 1950-х, и продолжает поддержку промышленных пользователей, хотя сегодня это в основном происходит посредством конференций.

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

Вы также можете поддерживать дух юзер-групп, находя способы помогать вашим соседям-энтузиастам. К примеру, Hack Club обучает школьников техническим навыкам в школах, и существует в 35 штатах США и 17 странах – каждый год хакатоны и клубы посещает порядка 10 000 школьников.

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

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

Трассировка сервисов в мобильной транспортной сети. Как мы пришли к графовой БД Neo4j

Часть 1. Начало

1.1 Введение и постановка задачи

В компании МТС мы централизованно занимаемся контролем качества сетей передачи данных или, проще – транспортной сети (не путать с логистической транспортной сетью), далее по тексту – ТС. И, в рамках нашей деятельности, нам постоянно приходиться решать две основные задачи:

  1. Обнаружена деградация клиентских (по отношению к ТС) сервисов – нужно определить путь их проключения через ТС, и выяснить, является ли причиной деградации сервисов какой-либо участок ТС. Далее, будем называть это Прямой задачей.
  2. Обнаружена деградация качества транспортного канала или последовательности каналов – нужно определить, какие сервисы зависят от данного канала/каналов, чтобы определить влияние. Далее, будем называть это Обратной задачей.

Под сервисами ТС понимается любое проключение клиентского оборудования. Это могут базовые станции (БС), В2В клиенты (использующие ТС МТС для организации доступа в сеть Интернет и/или наложенных сетей VPN), клиенты фиксированного доступа (т.н. ШПД), и т.д. и т.п.

В нашем распоряжении – две централизованные информационные системы:

Система Performance Monitoring Данные о параметрах и топологии сети
Метрики, КПЭ ТС Параметры конфигурации, L2/L3 каналы

Любая транспортная сеть по своей сути является ориентированным графом $G=(V,E)$, в котором каждое ребро $(u,v) in E$ имеет неотрицательную пропускную способность. Потому с самого начала поиск решения указанных задач выполнялся в рамках теории графов.

Сначала вопрос сопоставления показателей качества ТС и сервисов – с топологией ТС решался путем буквального объединения и представления данных топологии и качества в виде сетевого графа.

Просмотр сформированного по данным топологии и производительности графа был реализован на open source ПО Gephi. Это позволило решить задачу автоматического представления топологии, без ручной работы по её актуализации. Выглядит это так:

Здесь, узлы – это, собственно узлы ТС (маршрутизаторы, коммутаторы) и базовые, рёбра – каналы ТС. Цветовая маркировка, соответственно, обозначает наличие деградаций качества и статусы обработки этих деградаций.

Казалось бы – вполне наглядно и можно работать, но:

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

Также, надо иметь ввиду, что в общем случае топология сети гораздо сложнее (выше приведенный фрагмент обведён красным):

И это не самый маленький сегмент — есть гораздо больше и сложнее по топологии:

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


Часть 2. Автоматизация v1.0

Напоминаю, какие задачи мы решали:

  1. Определение пути проключения сервиса через ТС — Прямая задача.
  2. Определение зависимых сервисов от канала ТС — Обратная задача.

2.1. Транспортные сервисы для Базовых Станций (БС)

Обобщенно, организация транспорта от центрального узла (контроллера/шлюза) до БС выглядит так:

На сегментах агрегации и ядра ТС проключения выполняются через транспортные сервисы MPLS сети: L2/L3 VPN, VLL. На сегментах доступа проключения выполняются, как правило, через выделенные VLAN-ы.

Напоминаю, что у нас есть БД где лежит вся актуальная (в пределах определенного срока) параметрия и топология ТС.

2.2. Решение для коммутируемого сегмента (доступ)

Берем данные о VLAN логического интерфейса БС, и пошагово “идём” по связям, порты которых содержат этот Vlan ID, пока не дойдем до граничного маршрутизатора (МВН).

Для решения такой простой постановки задачи в итоге пришлось:

  1. Написать алгоритм пошаговой трассировки “распространения” VlanID от БС по каналам сети агрегации
  2. Учесть имеющиеся пробелы в данных. Особенно это касалось стыков между узлами на площадках.
  3. Фактически написать SPF алгоритм для того чтобы отбросить в конце тупиковые ветки, которые не ведут к МВН маршрутизатору.

Алгоритм получился из одного основного процесса и семи подпроцессов. На его реализацию и отладку было потрачено недели 3-4 чистого рабочего времени.

Кроме того, особое удовольствие нам доставили…

2.2.1. SQL JOIN

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

По понятным причинам не могу здесь приводить содержимое запросов к БД, но оцените – каждый “уступ” в тексте запроса – это подключение очередной таблицы, которая нужна для, в данном случае, получения в унифицированном виде соответствия Порт — VlanID:

А этот запрос – для получения, в унифицированном виде кросс-коннектов VlanID внутри коммутатора:

Учитывая, что кол-во портов составляло несколько десятков тысяч, а VLAN – в 10 раз больше – ворочалось всё это очень нехотя. А такие запросы нужно было сделать для каждого узла и VlanID. И “выгрузить всё сразу и вычислить” – нельзя, т.к. это последовательное вычисление пути c с пошаговыми операциями, которые зависят от результатов предыдущего шага.

2.3. Определение пути сервиса в маршрутизируемых сегментах

Здесь мы начали с одного вендора МВН, система управления которого предоставляла данные о текущем и резервном LSP через сегмент MPLS. Зная Access интерфейс, который стыковался с доступом (L2 Vlan) можно было найти LSP а затем – через серию запросов к NBI системы, получить путь LSP, состоящий из маршрутизаторов и линков между ними.

  • Аналогично коммутируемому сегменту, описание выгрузки пути LSP MPLS сервиса вылилось в алгоритм с уже 17-ю подпрограммами.
  • Решение работало только на сегментах, которые обслуживались данным вендором
  • Нужно было решать определение стыков между сервисами MPLS (например, в центре сегмента был общий VPLS сервис, а от него расходились или EPIPE либо L3VPN)

Мы проработали вопрос и для других вендоров МВН, где систем управления не было, или они не предоставляли данных о текущем прохождении LSP в принципе. Решение для нескольких мы нашли, но – кол-во LSP, проходящее через маршрутизатор – это уже не кол-во VanID, которое прописано на коммутаторе. Затягивая такой объем данных “по запросу” (ведь нам нужна оперативная информация) — есть риск положить железо.

Кроме этого, возникали дополнительные вопросы:

  • Сеть МВН в общем случае – мультивендорная, и на одном сегменте встречаются маршрутизаторы разных производителей, управляемых разными СУ. Т.е. – у нас будут данные только о куске пути MPLS сервиса.
  • СУ вендора, которая могла предоставлять данные об основном и резервном LSP, на деле прописывала и первый и второй по одному и тому же пути. Это мы видели очень часто. А нам бы хотелось знать про потенциальные пути обхода при анализе ограничений на сети.

2.4. Где и как хранить результаты. Как запрашивать данные

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

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

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

В качестве тестового решения был выбран формат XML и Native-XML БД – Exist.

Каждый сервис в результате записывался в БД в формате (подробности опущены для компактности записи):

<services> 	<service>  		<id>,<description> Описание сервиса (например, наименование БС) 		<source> Интерфейс условной точки А 		<target> Интерфейс условной точки Z 		<<segment>> Сегменты L2/L3 			<topology> Информация о пути через сегмент (узлы, порты/интерфейсы, соединения) 		<<joints>> Стыки между сегментами (узлы, порты/интерфейсы, соединения) 	</service> </services>

Запрос данных по прямой и обратной задачам выполнялся по протоколу XPath:

Всё. Теперь система заработала – на запрос с наименованием БС возвращается топология проключения её через транспортную сеть, на запрос с наименованием узла и порта ТС возвращается список БС, которые от него зависят по подключению. Поэтому, выводы мы сделали следующие…

2.5.

Вместо заголовка о выводах по части 2

2.5.1. Для коммутируемого сегмента (сети на L2 коммутаторах Ethernet)

  • Обязательно нужны полные данные о топологии и соответствии Port – VlanID. Если на каком-то линке нет данных о VlanID – алгоритм останавливается, путь не найден
  • Многоэтажные непроизводительные запросы к реляционной БД. При появлении нового вендора со своей спецификой параметрии – добавление запросов на всех этапах работы

2.5.2. Для маршрутизируемого сегмента

  • Ограничено возможностями СУ МВН по предоставлению данных о топологии LSP MPLS сервисов.
  • Запросы конфигурации непосредственно с МВН – потенциально опасны, т.к. счёт обслуживаемых LSP идет на тысячи.
  • Резервные LSP часто прописываются системой по тому же маршруту что и основные – нет информации о потенциальных альтернативных путях (в том числе и помимо тех, которые “держит” система).

2.5.3. Общее

  • Чтобы решить, по сути, задачу в сетевом графе, мы постоянно собираем данные из табличных источников, чтобы представить их в виде графа ( визуально – в голове, или в памяти программы), реализовать алгоритм, а потом – разобрать обратно.
  • Алгоритмизация решений и их реализация традиционными методами требует значительных трудозатрат. На реализацию данного этапа у нас ушло в целом 3-4 месяца.
  • Масштабирование очень затруднено, т.к. любое изменение, в виде появления нового вендора либо MPLS сервиса ведёт за собой внесение изменений в структуру запросов к БД и в сам программный код.
  • Приходится писать Дейкстра – подобные алгоритмы, а не использовать готовые инструменты.

2.6. Чего всё-таки хотим

  • Чтобы данные о сетевом графе ТС и хранились, и обрабатывались как сетевой граф, т.е. – набор узлов и зависимостей.
  • Чтобы использовались уже готовые алгоритмы работы с графами
  • Чтобы модель данных была универсальной, а не вендорно-зависимой
  • Чтобы трассировка была возможна и на неполных данных (например, частичное отсутствие данных о VlanID)

После того как мы провели оценку возможных вариантов реализации наших хотелок — определились с классом систем, которые бы всё это обеспечили “из коробки” – это т.н. графовые базы данных.

Хоть и читается последнее предложение как нечто линейное и простое, учитывая что ранее с таким классом БД никому из нас (и наших айтишников, как потом выяснилось – тоже) сталкиваться не приходилось — к решению пришли в некоторой степени случайно: подобные базы данных упоминались (но не разбирались) в обзорном курсе по Big Data. В частности, там упоминался продукт Neo4j. Мало того, что он, судя по описанию, удовлетворял всем нашим требованиям, у него ещё есть полностью бесплатная функциональная community-версия. Т.е. – не 30-дневный триал, не обрезанный основной функционал, а полностью рабочий продукт, который можно не спеша изучить. Не последнюю (если не основную) роль в выборе сыграла широкая поддержка графовых алгоритмов.


Часть 3. Пример реализации прямой задачи в Neo4j

Чтобы не затягивать линейное повествование о том, как реализуется модель ТС в графовой БД Neo4j — сразу покажем конечный результат на примере.

3.1. Трассировка пути проключения интерфейса Iub для БС 3G

Путь проключения сервиса проходит по двум сегментам – маршрутизируемому МВН, и коммутируемому РРЛ (радиорелейные станции работают как Ethernet-коммутаторы). Путь через РРЛ сегмент определяется также, как было описано в части 2 – по прохождению VlanID интерфейса БС по сегменту РРЛ до граничного маршрутизатора МВН. Сегмент МВН соединяет граничный (с сегментом РРЛ) маршрутизатор — с маршрутизатором к которому подключен контроллер БС (RNC).

Изначально, из параметрии Iub, мы знаем точно — какой МВН является шлюзом для БС (граничный МВН), и каким контроллером обслуживается БС.

Исходя из этих начальных условий, построим 2 запроса к БД для каждого из сегментов. Все запросы к БД строятся на языке Cypher. Чтобы сейчас не отвлекаться на его описание, воспринимайте его просто как “SQL для графов”.

3.1.1. Сегмент РРЛ. Путь по VlanID

Cypher-запрос трассировки пути сервиса по имеющимся данным о VlanID и топологии L2:

Фрагмент Cypher-запроса
(конструкция WITH – передача результатов одного этапа запроса на следующий (конвейеризация обработки) )
Промежуточные результаты запроса (визуальное представление в консоли Neo4j – “Neo4j Browser”)
Получение узлов БС и МВН между которыми будет проводиться поиск пути сервиса Iub

match (bts:node {name:'BTS_29_ХХХХ_N}), (mbh:node {name:'MBH_29_YYYYY_N}) with bts, mbh

Получение узлов Vlan БС интерфейса Iub

match (bts)-[:port_attach]->(:port)-[:vlan]->(vlan:vlan)  	with bts as bts,  vlan.vlanid AS vlan_bts   , mbh 

Выбираем узлы ТС на той же площадке с БС, на портах которых прописан VlanID Iub БС

MATCH  ((bts)-->(pl_bts:PL)-->(n:node)-[:port_attach]->(pid:port)-->(v:vlan)) where (v.vlanid=vlan_bts and v.updated > bts.updated - 864000000)  with distinct(v) as v,n,mbh,vlan_bts, bts

по алгоритму Дейкстра находим кратчайший путь от VlanID ТС узла площадки БС до граничного МВН

 CALL apoc.algo.dijkstra(v, mbh, 'port_attach>|port_hosted>|<node_vlan|v_ptp_vlan>|ptp_vlan>|located_at>|to_node>', 'weight',10000000000.0,1) YIELD path as path_pl_mbh 

Из цепочки Vlan получаем список узлов, портов, и связей между портами, который, в итоге, и будет являться путём проключения сервиса Iub от БС до граничного маршрутизатора

WITH FILTER(node in nodes(path_pl_mbh) WHERE  (node:vlan)) as vlans_node , path_pl_mbh, bts ,mbh , vlan_bts unwind vlans_node as vlan_node match (vlan_node)-->(p1:port) match p=(p1)-[:port_hosted|to_port|v_to_port|to_node|located_at]->() return p, bts, mbh

Результат:

Как видно, путь получен, даже несмотря на частичный недостаток данных. В данном случае – отсутствует информация о стыке порта БС с портом радиорелейной станции.

3.1.2. Сегмент РРЛ. Путь по L2 топологии

Допустим, попытка в п. 3.1.1. не удалась по причине полного или частичного отсутствия данных о параметрии VlanID. Другими словами – подобная непрерывная цепочка, доходящая до узла МВН не выстраивается:

Тогда можно попробовать определить проключение сервиса как кратчайший путь до МВН по топологии L2:

match (bts:node {name:'BTS_29_ХХХХ_N}), (mbh:node {name:'MBH_29_YYYYY_N}) with bts, mbh CALL apoc.algo.dijkstra(bts, mbh, 'located_at>|to_node>|to_port>|v_to_port>|port_hosted>|port_attach>', 'weight',1.0,1) YIELD path as p return p

Результат:

Как видно, получен такой же результат. Здесь недостаток информации о стыке БС с РРС восполнен прохождением связи через объект (узел) площадки, на которой они находятся. Разумеется, точность такого метода будет меньше, т.к. в общем случае Vlan может быть прописан не по кратчайшему пути, предполагаемому алгоритмом Дейкстра. Зато запрос состоит из всего двух операций.

3.1.3 Сегмент МВН. Трассировка пути от граничного МВН до контроллера

Здесь так же используем алгоритм Дейкстра.

Один путь с минимальной стоимостью

match (mbh:node {name:’MBH_29_XXX’}), (rnc:node {name:’RNC_YYY’}) CALL apoc.algo.dijkstra(mbh,rnc, 'port_attach>|port_hosted>|<node_vlan|ptp_vlan>|located_at>|to_node>|to_port_mbh>', 'weight',10000000000.0,1) YIELD path as path return path

Топ-2 пути с минимальной стоимостью (основной + альтернатива)

match (mbh:node {name:’MBH_29_XXX’}), (rnc:node {name:’RNC_YYY’}) CALL apoc.algo.dijkstra(mbh,rnc, 'port_attach>|port_hosted>|<node_vlan|ptp_vlan>|located_at>|to_node>|to_port_mbh>', 'weight',10000000000.0,2) YIELD path as path return path

Топ-3 пути с минимальной стоимостью (основной + две альтернативы)

match (mbh:node {name:’MBH_29_XXX’}), (rnc:node {name:’RNC_YYY’}) CALL apoc.algo.dijkstra(mbh,rnc, 'port_attach>|port_hosted>|<node_vlan|ptp_vlan>|located_at>|to_node>|to_port_mbh>', 'weight',10000000000.0,3) YIELD path as path return path

Аналогично – в данном случае отсутствует информация о непосредственных стыках МВН с RNC. Но это не мешает построить путь сервиса, пусть и предполагаемый алгоритмом (об этом — позже).

3.2. Трудозатраты

Реализация Прямой задачи, показанная сейчас, разительно отличается от подхода “разработай алгоритм, программу, способ хранения и извлечения результатов” – здесь всё сводится к “напиши запрос к БД”. Забегая вперёд, отметим, что весь цикл от разработки простой модели графа, загрузки данных в Neo4j из реляционной БД, написания запросов, и до получения результата занял, в общей сложности, один день.

3-4 месяца vs 1 день!!! Это было последним доводом для окончательного ухода в графовую БД.


Часть 4. Графовая БД Neо4j и загрузка данных в неё

4.1. Сравнение реляционных и графовых БД

Сравнительная характеристика Реляционная БД Графовая БД
Хранение данных Данные хранятся в наборе отдельных таблиц, связи между строками которых могут быть определены по ключевым полям через специальные отношения: один к одному, один ко многим, многие ко многим.

Данные хранятся или в виде узлов или в виде отношений (направленных связей/ссылок между узлами). И у тех и у других может быть произвольный набор параметров.

Структура данных Тот, кто строит запросы к БД, должен точно знать структуру хранения данных, и какие связи между данными, помимо определенных через внешние ключи, могут быть. Любые изменения/дополнения в структуре данных требуется соотносить с моделью хранения, при этом заранее оценивая последствия для производительности БД в целом. По этой причине коммерческие системы, использующие для хранения РБД, берут с клиентов деньги за адаптацию потребностей последних к своей модели хранения данных Структура данных (узлов и взаимосвязей между ними) определяется самими данными. Пользователю доступна вся информация о текущей структуре. Отсутствует жесткая фиксированная схема – возможно одновременное существование нескольких вариантов представления данных. Прямое и универсальное моделирование данных пользователем. Любой объект может быть представлен набором из трех сущностей: Узел, Связь, Параметры.
Проблема JOIN Не всегда поля, по которым понадобится сделать объединение данных при запросе – индексированы. Это может значительно снизить быстродействие запроса, т.к. заставляет планировщик прибегать к NESTED-LOOP Связи между узлами определяются на этапе загрузки в БД или на этапах постпроцессинга (вычисления связей). Если угодно – ГБД это как если бы в РБД все нужные JOIN уже были сделаны, причем на уровне отдельных полей отдельных строк.
JOIN chain Чем больше мы сцепляем JOIN операций друг за другом в одном запросе – тем больше падение производительности. Т.е. мы экспоненциально теряем в производительности на каждый вложенный JOIN в запросе. В данной статье приведен пример решения задачи поиска “в глубину” – запросами к РБД Oracle, и к ГБД Neo4j:

Проблемы не существует. Обход графа в глубину – нативное свойство ГБД.
Зависимость от кол-ва записей/размера БД Чем больше записей в объединяемых таблицах, тем большее время требуется от РБД для обработки запроса, даже если количество реально возвращаемых записей неизменно Запрос отсекает именно ту часть графа, которая связана с интересующими узлами/связями и работает только с ней, при этом размер БД графа может быть любым. Например, запрос идет от узла “МВН-Х”, при этом всего в графе может быть как 1000 так и 1 млн узлов МВН – поиск всё равно будет внутри “сегмента” графа, включающего только “МВН-Х”.

4.2. Модель данных

Базовая модель представления ТС до уровня L3 топологии включительно:

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

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

4.3. Загрузка данных

Загрузку данных выполняем из БД параметрии и топологии ТС. Для загрузки в Neo4j из SQL БД используется библиотеки APOC – apoc.load.jdbc, которая принимает на вход строку подключения к RDBMS и текст SQL запроса, и возвращает множество строк, которые через CYHPER –выражения отображаются на узлы, связи, или параметры. Такие операции выполняются слой за слоем для каждого типа объектов модели.

Например, проход для загрузки/обновления узлов, представляющих сетевые элементы (Nodes):

with "jdbc:oracle:thin:usr /passw@IP:1521/db" as url // DB connection string CALL apoc.load.jdbc(url, " select distinct mr,region_code,site_code,node, nodeip,TYPE,VENDOR, coalesce(updated, trunc(localtimestamp-7)) as updated from (     select distinct mr,region_code,site_code,node, nodeip,TYPE,VENDOR, updated from GRAPH_IPMPLS_NE     union     select distinct mr,region_code,site_code,node, nodeip,TYPE,VENDOR, updated from GRAPH_RRN_NE     union     select distinct mr,region_code,site_code,node, nodeip,TYPE,VENDOR, updated from GRAPH_CONTROLLERS_NE ) t where mr is not null and region_code is not null and site_code is not null " ) YIELD row

Вызов процедуры apoc.load.jdbc,
получение набора данных
match (reg:Region {region_code:row.REGION_CODE})-->(pl:PL {SiteCode:row.SITE_CODE})  with pl, row, {updated:row.UPDATED, weight:1000000000000} as conn_params

Для каждой строки из набора данных
по коду региона и сайта ищутся узлы
представляющие соответствующие площадки
	merge (pl)<-[loc:located_at]-(n:node {ip:row.NODEIP}) 	merge (pl)-[to_n:to_node]->(n) 		set n.name=row.NODE 		set n.region_code = row.REGION_CODE 		set n.type = row.TYPE 		set n.updated = row.UPDATED 		set n.vendor = row.VENDOR 		set loc += conn_params 		set to_n += conn_params

Для каждого объекта площадки обновляются
связанные с ней сетевые элементы (node).
Используется инструкция MERGE + SET,
которая обновляет параметры объекта,
если он уже существует в БД, если нет
– то создает объект. Тут же записываются
параметры узла Node и его связей с узлом PL

И так далее – по всем уровням модели ТС.

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


Часть 5. Решаем обратную задачу в Neo4j

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

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

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

Так как, в отличие от коммутируемого сегмента, фактические маршруты сервиса в сегменте mpls определяются динамическими протоколами, нам пришлось принять некоторые…

5.1. Допущения для маршрутизируемых сегментов

Т.к. из данных конфигурации mpls сервисов нет возможности определить их точный путь прохождения через сегменты, управляемые динамическими протоколами маршрутизации (тем более, если используется Traffic Engineering) – для решения используется алгоритм Дейкстры.
Да, есть системы управления, которые могут по NBI-интерфейсу предоставлять актуальный путь сервисных LSP, но пока у нас такой вендор только один, а вендоров на сегменте МВН – больше чем один.

Да, есть системы анализа протоколов маршрутизации внутри AS, которые, слушая обмен IGP протоколов, могут определить текущий маршрут интересующего префикса. Но стоят такие системы — как сбитый Боинг, а учитывая что такую систему нужно развернуть на всех AS того же мобильного бэкхола – стоимость решения вместе со всеми лицензиями составит стоимость Боинга, сбитого чугунным мостом, привязанным к ракете Ангара при полной заправке. И это ещё при том что подобными системами не вполне решены задачи учета маршрутов через несколько AS c использованием BGP.

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

  • Учёт статуса интерфейсов/портов. Отключенный линк повышается в стоимости и идет в конец возможных вариантов пути.
  • Учёт резервного статуса линка. По данным системы Performance Monitoring вычисляется присутствие в mpls канала только трафика keepalive, соответственно, стоимость такого канала также увеличивается.

5.2. Как решить обратную задачу в Neo4j

Напоминание. Обратная задача – получение списка сервисов, зависимых от конкретного канала или узла транспортной сети (ТС).

5.2.1. Коммутируемый L2 сегмент

Для коммутируемого сегмента, где путь сервиса и конфигурация сервиса – это практически одно и то же, задачу ещё можно решить через CYPHER-запросы. Например, для радиолерейного пролета из результатов решения Прямой задачи в п 3.1.1., сделаем запрос от модема радиорелейного линка – “развернем” все цепочки Vlan, которые проходят через него:

match (tn:node {name:'RRN_29_XXXX_1'})-->(tn_port:port {name:'Modem-1'})-->(tn_vlan:vlan) with tn, tn_vlan, tn_port call apoc.path.spanningTree(tn_vlan,{relationshipFilter:"ptp_vlan>|v_ptp_vlan>", maxLevel:20}) yield path as pp with tn_vlan,pp,nodes(pp)[-1] as last_node, tn_port 	match (last_node)-[:vlan]->(:port)-->(n:node) 	return pp, n, tn_port

Красным узлом обозначен модем, Vlan которого разворачиваем. Обведены 3 БС на которые в итоге вывело развертывание транзитных Vlan с Modem1.

У такого подхода есть несколько проблем:

  • Для портов должны быть известны и загружены в модель сконфигурированные Vlan.
  • Из-за возможного фрагментирования, цепочка Vlan не всегда выводит на терминальный узел
  • Невозможно определить – относится ли последний узел в цепочке Vlan к терминальному узлу или сервис, на самом деле, продолжается дальше.

То есть, сервис всегда удобнее трассировать между конечными узлами/точками его сегмента, а не из произвольной “середины”, и с одного уровня OSI.

5.2.2. Маршрутизируемый сегмент

С маршрутизируемым сегментом, как уже описано в п 5.1, выбирать не приходится – для решения обратной задачи на основании данных текущей конфигурации какого-то промежуточного линка MPLS никаких средств нет – конфигурация не определяет в явном виде трассу сервиса.

5.3. Решение

Решение было принято следующее.

  • Проводится полная загрузка модели ТС, включая БС и контроллеры
  • Для всех БС выполняется решение прямой задачи – трассировка сервисов Iub, S1 от БС до граничного МВН, а затем от граничного МВН до соответствующих контроллеров или шлюзов.
  • Результаты трассировки записываются в обычную SQL БД в формате: Наименование БС – массив элементов пути сервиса

Соответственно, при обращении к БД с уловием Узел ТС или Узел ТС + Порт, возвращается список сервисов (БС), в массиве пути которых есть нужный Узел или Узел+Порт.


Часть 6. Результаты и выводы

6.1. Результаты

В итоге система работает следующим образом:

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

Для получения списка сервисов, зависимых от узлов или каналов ТС (решение обратной задачи) разработан API для внешних систем (в частности – Remedy).

6.2. Выводы

  • Оба решения подняли на качественно новый уровень автоматизацию анализа качества сервисов и транспортной сети.
  • Кроме этого, при наличии готовых данных о трассах сервисов БС, стало возможно быстро предоставлять данные для бизнес-подразделений о технической возможности включения В2В клиентов на конкретных площадках — по емкости и качеству трассы.
  • Neo4j показал себя как очень мощный инструмент для решения задач с сетевыми графами. Решение отлично документировано, имеет широкую поддержку в различных сообществах разработчиков, постоянно развивается и улучшается.

6.3. Планы

В планах у нас:

  • расширение технологических сегментов, моделируемых в БД Neo4j
  • разработка и внедрение алгоритмов трассировки сервисов ШПД
  • увеличение производительности серверной платформы

Спасибо за внимание!

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

Microsoft оптимизирует ядро Linux для серверных ARM

На конференции Linux Plumbers Conference 2020 разработчики Microsoft рассказали о своем экспериментальном проекте — оптимизации ядра Linux для серверных ARM-процессоров. С докладом выступил главный менеджер по разработке программного обеспечения Ян Бирман.

По словам специалиста, проект стартовал по внутреннему запросу компании. Linux уже используется в проектах Azure Cloud, Azure Sphere и Windows Subsystem for Linux. Перед командой Бирмана поставили задачу максимизировать производительность облачного сервиса на Linux при использовании процессоров с архитектурой ARM или x86 с 64-битной разрядностью. Разработчикам позволили скомпилировать ядро для операционной системы с собственными параметрами и флагами.

Исходный дистрибутив — Ubuntu 19.10 с предустановленными GCC 9.2.1, binutils 2.33 и kernel 5.3. Процессор сервера — 64-битный ARM Marvell Thunder X2. После мозгового штурма команда решила использовать оптимизацию LTO и PGO для сборки ядра.

Оптимизация профилирования (PGO или FDO) и оптимизация времени связи (LTO или LTCG) существенно замедляют процесс сборки и требует больше оперативной памяти для работы компилятора, но в теории дают прирост скорости выполнения команд на 10-20%. PGO редко используется разработчиками, а LTO не так давно стала применяться для сборки ядер и других пакетов. Ранее разработчики опасались использовать оптимизацию времени связи из-за проблем совместимости в компиляторах GCC и LLVM. Команда Бирмана обратилась за помощью к опытному разработчику ядра Linux Энди Клину, который выпустил патч для корректной работы LTO с ARM-процессорами. Чтобы заставить работать PGO, разработчики изучили документацию и методом проб и ошибок добились стабильной работы.

Завершив сборку ядра, команда протестировала производительность на резидентной системе управления базами данных класса NoSQL с открытым исходным кодом redis. После выполнения различных команд разработчики отчитались о приросте скорости выполнения команд на 5-20%. Данные получены из внутреннего бенчмарк теста redis.

Кстати, не так давно Microsoft выпустила обновление KB4566116 для Windows 10. Апдейт добавляет в 1909 и 1903 версии ОС поддержку подсистемы Windows Subsystem for Linux 2 (WSL 2). Это дает возможность использовать полноценное ядро Linux. Оно в WSL2 не является частью Windows по умолчанию, а загружается динамически и обновляется посредством встроенных в ОС инструментов.

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

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

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

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

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

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



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

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

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

Шаг 1. Выбираем оружие

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

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

Шаг 2. Ищем поле битвы

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

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

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

Более «традиционными» активами можно торговать только в определённые временные промежутки, и часто — только по будним дням. Рынки акций, например, обычно открыты с 9 утра до 4 вечера и по выходным они не работают. Рынки FOREX, хотя и могут работать круглосуточно, обычно закрыты в выходные.

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

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

  1. У вас должна быть законная возможность торговать на выбранной бирже и работать с предлагаемыми ей торговыми инструментами. Если говорить о криптовалютах, то в некоторых странах торговля ими запрещена. Учитывайте это, выбирая инструменты и биржу.
  2. Биржа должна обладать API, который доступен её клиентам. Нельзя создать торгового бота, который не отправляет запросы к бирже и не получает от неё ответов.

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

И ещё, что так же важно, как и всё остальное, я порекомендовал бы оценить объём торгов биржи. Биржи с низкими объёмами имеют свойство «отставать» от ценовых движений. На них, кроме того, сложнее бывает выполнять лимитные заявки (подробнее об этом мы поговорим ниже).

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

Шаг 3. Строим лагерь

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

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

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

Тут у меня есть два предложения:

  1. Роль сервера может выполнять Raspberry Pi (этот подход интереснее).
  2. Сервером может быть некая облачная служба (а этот подход лучше).

Я так думаю, что организация деятельности бота на базе собственного Raspberry Pi-сервера — это интересная и современная идея, поэтому, если и вам эта идея нравится, вы можете претворить её в жизнь.

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

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

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

Шаг 4. Создаём бота

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

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

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

▍Простейший бот

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

У нашего бота будут некоторые ограничения:

  1. Бот сможет пребывать лишь в одном из двух состояний: BUY (покупка) или SELL (продажа). Он не будет постоянно размещать заявки на покупку или на продажу по разным ценам. Если последней операцией была продажа, то следующей операцией, которую попытается выполнить бот, будет покупка.
  2. Бот будет использовать фиксированные пороговые значения для принятия решений о покупке и продаже. Более интеллектуальный бот может быть способен самостоятельно настраивать подобные значения, основываясь на различных индикаторах, но стратегия и ограничения нашего бота будут задаваться вручную.
  3. Он будет торговать только одной валютной парой. Например — BTC/USD.

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

▍Механизм принятия решений

Вот простая диаграмма, дающая общий обзор функционирования нашего бота.

А теперь можно приступать к планированию архитектуры бота.

Нам, для начала, понадобится переменная, в которой будут храниться сведения о том, в каком именно состоянии находится бот в текущий момент. Это либо BUY, либо — SELL. Для хранения подобных сведений хорошо подойдёт логическая переменная или перечисление.

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

Например, если я купил что-то по цене в $100, а в настоящий момент цена составляет $102, то мы имеем дело с увеличением цены на 2%. Если порог для операции SELL установлен на однопроцентное увеличение цены, то бот, увидев эти 2%, продаст актив, так как он уже получил прибыль, превышающую заданное нами пороговое значение.

В нашем случае подобные значения будут константами. Нам понадобится 4 таких значения — по 2 на каждое состояние бота.

▍Пороговые значения для выполнения операции BUY (если бот находится в состоянии SELL)

  • DIP_THRESHOLD: бот выполняет операцию покупки в том случае, если цена уменьшилась на значение, большее, чем задано DIP_THRESHOLD. Смысл этого заключается в реализации стратегии «покупай дёшево, продавай дорого». То есть, бот будет пытаться купить актив по заниженной цене, ожидая роста цены и возможности выгодной продажи актива.
  • UPWARD_TREND_THRESHOLD: бот покупает актив в том случае, если цена выросла на значение, превышающее то, что задано этой константой. Этот ход противоречит философии «покупай дёшево, продавай дорого». Его цель заключается в том, чтобы выявить восходящий тренд и не пропустить возможность покупки до ещё большего роста цены.

Вот иллюстрация, которая может помочь в понимании смысла этих констант.

Если мы выполнили операцию SELL в момент, отмеченный на рисунке красным маркером SELL, то после этого бот, принимая решение о выполнении операции BUY, будет руководствоваться пороговыми значениями DIP_THRESHOLD и UPWARD_TREND_THRESHOLD.

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

▍Пороговые значения для выполнения операции SELL (если бот находится в состоянии BUY)

  • PROFIT_THRESHOLD: бот продаёт актив в том случае, если цена стала выше цены, вычисленной на основе этого значения, так как ранее актив был куплен по более низкой цене. Именно так мы получаем прибыль. Мы продаём актив по цене, которая выше той, что была в момент его покупки.
  • STOP_LOSS_THRESHOLD: в идеальной ситуации мы хотели бы, чтобы бот продавал бы активы только тогда, когда продажа приносит нам прибыль. Но, возможно, произошло сильное движение рынка вниз. В такой ситуации мы решим выйти из сделки до того, как понесём слишком большие убытки, и позже купить актив по более низкой цене. Это пороговое значение используется для закрытия позиции с убытком. Цель этой операции — предотвращение более сильных потерь.

Вот иллюстрация.

Тут показана ситуация, когда там, где стоит маркер BUY, была сделана покупка. После этого цена достигает предела, заданного PROFIT_THRESHOLD, и мы продаём актив с прибылью. Именно так боты зарабатывают.

Теперь, после того, как у нас сформировалось общее понимание того, как функционирует бот, пришло время рассмотреть псевдокод.

▍Вспомогательные функции для работы с API

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

FUNCTION getBalances():     DO: Выполнить GET-запрос к API биржи для получения      сведений о балансах     RETURN: Сведения о балансах  FUNCTION getMarketPrices():     DO: Выполнить GET-запрос к API биржи для получение      текущей цены актива     RETURN: Текущая цена актива  FUNCTION placeSellOrder():     DO:         1. Вычислить количество актива для продажи (на основе         некоего заданного порогового значения, например,          50% общего баланса)         2. Отправить POST-запрос к API биржи для выполнения         операции SELL     RETURN: Цена совершения сделки  FUNCTION placeBuyOrder():     DO:         1. Вычислить количество актива для покупки (на основе         некоего заданного порогового значения, например,          50% общего баланса)         2. Отправить POST-запрос к API биржи для выполнения         операции BUY     RETURN: Цена совершения сделки  // Необязательная функция, которая предназначена для  // получения подтверждения выполнения операций FUNCTION getOperationDetails():     DO: Выполнить GET-запрос к API биржи для получения     сведений об операции     RETURN: Сведения об операции 

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

Часто, например, когда торгуют парой XAU/USD (золото и доллары США), при выполнении запроса можно указать или то, сколько золота нужно купить, или то, сколько долларов нужно продать. При выполнении подобных запросов очень важно чётко понимать смысл производимых действий.

▍Главный цикл бота

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

FUNCTION startBot():     INFINITE LOOP:         attemptToMakeTrade()         sleep(30 seconds) 

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

bool isNextOperationBuy = True  const UPWARD_TREND_THRESHOLD = 1.50 const DIP_THRESHOLD = -2.25  const PROFIT_THRESHOLD = 1.25 const STOP_LOSS_THRESHOLD = -2.00  float lastOpPrice = 100.00  FUNCTION attemptToMakeTrade():     float currentPrice = getMarketPrice()     float percentageDiff = (currentPrice - lastOpPrice)/lastOpPrice*100     IF isNextOperationBuy:         tryToBuy(percentageDiff)     ELSE:         tryToSell(percentageDiff)  FUNCTION tryToBuy(float percentageDiff):     IF percentageDiff >= UPWARD_TREND_THRESHOLD OR percentageDiff <= DIP_THRESHOLD:         lastOpPrice = placeBuyOrder()         isNextOperationBuy = False  FUNCTION tryToSell(float percentageDiff):     IF percentageDiff >= PROFIT_THRESHOLD OR percentageDiff <= STOP_LOSS_THRESHOLD:         lastOpPrice = placeSellOrder()         isNextOperationBuy = True 

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

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

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

Шаг 5. Улучшаем бота

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

▍Журналы

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

Каждый шаг работы программы должен был сопровождаться примерно такими записями:

[BALANCE] USD Balance = 22.15$ [BUY] Bought 0.002 BTC for 22.15 USD [PRICE] Last Operation Price updated to 11,171.40 (BTC/USD) [ERROR] Could not perform SELL operation - Insufficient balance 

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

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

FUNCTION createLog(string msg):     DO:         1. Вывести msg в терминал         2. Записать msg в файл журнала, добавив отметку времени 

▍Идентификация трендов

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

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

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

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

Нам нужно лишь организовать наблюдение за большим количеством ценовых значений, чем раньше. А раньше мы хранили сведения лишь об одном ценовом показателе — о стоимости актива на момент последней операции (lastOpPrice). Можно, например, хранить сведения о ценах за 10 или 20 последних итераций цикла бота и сравнивать с текущей ценой их, а не только lastOpPrice. Это, вероятно, позволит лучше идентифицировать тренды, так как при таком подходе мы можем уловить краткосрочные колебания цены, а не колебания, происходящие за долгое время.

▍База данных?

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

Но что произойдёт в том случае, если, например, бот будет аварийно остановлен? Как ему узнать, без вмешательства человека, о том, каким было значение lastOpPrice?

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

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

В зависимости от того, насколько простой, по вашему мнению, должна быть эта «база данных», вы можете даже решить использовать в таком качестве обычные .txt- или .json-файлы, так как, в любом случае, речь идёт о хранении весьма ограниченного набора данных.

▍Панель управления

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

Это потребует наличия у бота собственного серверного API, предназначенного для управления его функционалом.

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

Существует множество шаблонов панелей управления, а значит вам, если вы решите сделать что-то подобное, даже не придётся создавать такую панель с нуля. Взгляните, например, на Start Bootstrap и Creative Tim.

▍Тестирование стратегий на исторических данных

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

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

▍Дополнительные сведения о пороговых значениях и заявках

При размещении заявок нужно учитывать несколько моментов.

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

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

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

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

Кроме того, к таким заявкам обычно применяются более низкие комиссии, чем к рыночным. Это так из-за того, что к рыночным заявкам обычно применимо то, что называется «taker fee» («комиссия получателя»), а к лимитным заявкам — то, что обычно называется «maker fee» («комиссия создателя»).

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

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

И, завершая разговор о комиссиях, хочу отметить, что задавая значение PROFIT_THRESHOLD нужно учитывать и комиссии.

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

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

Поразмыслим об этом, исходя из предположения о применении комиссий, не зависящих от суммы заявки и от вида операции. Итак, комиссия за покупку актива на $100,00 составляет $0,50. Если этот актив будет продан за $100,75 и при этом будет взята такая же комиссия, то окажется, что валовая прибыль составляет 0,75%. Но, на самом деле, тут мы имеем дело с чистым убытком в 0,25%.

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

Итоги

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

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

Я рассказал вам о разработке торговых ботов всё, что хотел. Надеюсь, теперь вы сможете создать собственного бота.

А вы пользуетесь торговыми ботами?

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