-Поиск по дневнику

Поиск сообщений в rss_rss_hh_new

 -Подписка по e-mail

 

 -Статистика

Статистика LiveInternet.ru: показано количество хитов и посетителей
Создан: 17.03.2011
Записей:
Комментариев:
Написано: 51

Habrahabr/New








Добавить любой RSS - источник (включая журнал LiveJournal) в свою ленту друзей вы можете на странице синдикации.

Исходная информация - http://habrahabr.ru/rss/new/.
Данный дневник сформирован из открытого RSS-источника по адресу http://feeds.feedburner.com/xtmb/hh-new-full, и дополняется в соответствии с дополнением данного источника. Он может не соответствовать содержимому оригинальной страницы. Трансляция создана автоматически по запросу читателей этой RSS ленты.
По всем вопросам о работе данного сервиса обращаться со страницы контактной информации.

[Обновить трансляцию]

Ядро автоматизации тестирования в микросервисной архитектуре

Четверг, 20 Июля 2017 г. 10:59 + в цитатник
Привет, Хабр! Меня зовут Дмитрий Химион, я руковожу отделом обеспечения качества в Avito. Cегодня я хочу рассказать про автоматизацию тестирования в рамках работы с микросервисной архитектурой. Что мы можем предложить разработке для того, чтобы облегчить контроль качества? Читайте под катом.



Вместо вступления


“An implementation should be conservative in its sending behavior, and liberal in its receiving behavior”.
Jonathan Bruce Postel, computer scientist


Что такое микросервисная архитектура?


Чтобы мой рассказ был полным, начнем с основ. Если упростить, микросервисная архитектура — это способ организации сервера приложений. Как он работает? По сути, это просто ответ сервис-ориентированной архитектуры на появление такой практики, как DevOps. Если в SOA не регламентированы размеры сервисов и то, что именно они должны делать, то в рамках микросервисной архитектуры есть некоторые умозрительные ограничения. Микросервис — это некоторая сущность, которая заключает в себе одну небольшую функциональность, которой она заведует и предоставляет внешним сервисам какие-то данные.

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

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

Переход к микросервисам


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



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

Контракты для микросервисной архитектуры


Взаимодействия микросервисов между собой реализуются посредством контрактов. Что это значит для сервис-ориентированной архитектуры? Контракт — это некоторое соглашение, которое разработчики сервиса создают для взаимодействия между собой внешних пользователей. Разработчики сервиса сами решают, что вы можете запросить у них “X”, а они вам предоставят “Y”. Сервис может предоставлять внешним пользователям яблоки, помидоры, плутоний, продавать детскую одежду или телевизоры — ему не декларируется чёткий фокус на функционал. Внутреннее наполнение регламентируется только на уровне здравого смысла. И соответственно, это сервис диктует внешним пользователям то, что они будут получать, и как к нему необходимо обращаться.

Если увеличивать комплексность этой задачи, когда сервисов будут не десятки (10-20-50), а сотни (200, 400…2000), то традиционные, “классические” контракты перестают работать в функциональном смысле. И тогда уже возникает необходимость модернизации контрактов под микросервисную архитектуру. Разработан шаблон работы для разработчиков, в котором они и “конечные пользователи” микросервиса меняются местами — этот подход называется consumer driven contacts. Теперь запросы делают внешние пользователи. Это можно представить как такого рода беседу:
Пользователь 1: “Я слышал, вы поставляете яблоки. Мне нужны маленькие и зелёные”.
Пользователь 2: “А мне нужны огромные красные яблоки”.
Пользователь N: “А мне нужно, чтобы вы привезли три тонны яблок”.

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



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

Предикаты для CDC-testing (Consumer Driven Contracts)


Без чего нельзя начать работать по принципам CDC-testing? Первое. У нас не получится помочь, если мы видим что у нас в разработке не соблюдается процесс работы по контрактам. Вторая вещь более техническая: это система post-commit (post-PR, если хотите) hook-ов, которая обрабатывает этот поток общения между девелоперами с помощью контрактов и сигнализирует нашей системе тестирования об их обновлении, удалении, появлении новых. Соответственно, заводятся соответствующие таски в Jira, чтобы автоматизаторы успели это все “переварить”. К этому базовому процессу можно добавить еще все что угодно — дополнительные проверки, процессные примочки, но без контроля изменения контрактов взаимодействия между микросервисами жить будет достаточно сложно. Выполнив в каком-то виде эти два пункта, мы можем приступить к имплементации.

Имплементация автоматизации под CDC


В основу нашей системы автоматизации тестирования ляжет такое решение, как PACT-фреймворки. Что нужно о них знать? Это протокольное взаимодействие с API: JSON over HTTP, в этом нет ничего сложного. Эти решения взаимодействуют с нашими микросервисами и дают некоторый дополнительный функционал для изоляции и организации тестирования. Что сказать еще? Я видел, как это реализовано в том или ином виде на семи языках программирования (Java, Javascript, Ruby, Python, Go, .NET, Swift). Но если вашего нет в этом списке, не пугайтесь: можно взять базовую библиотеку и сделать свой велосипед, или написать что-то подобное тому, что уже реализовано.

Что ещё нас ждёт почти в 100% случаев? Первое — это мокирование внешних сервисов. Проблема в том, что сложно поддерживать релевантность того, как себя ведет внешний сервис, и поддерживать это во всех заглушках. Как решать эту проблему? Это зависит от вас. Скорее всего, потребуется направить на это больше ресурсов или ограничить покрытие тестами. И второе: сэмплированные базы данных. Понадобится нарезать боевые базы данных в облегченном виде так, чтобы в них были все необходимые данные для тестирования в рамках нашей системы. Тогда получится наглядный релевантный результат.



Идем далее. Первое, что я сразу захотел сделать в этом проекте — это информативное логирование. Всегда необходима репрезентативность итогов тестирования. Простая истина: если результаты невозможно прочитать и понять — их никто не будет смотреть. Надо сказать, что базовое логирование в PACT-фреймворках реализовано очень убого.

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

Следующий, возможно, “капитанский” момент — это Config Reader. Но в рамках тестирования микросервисной архитектуры это может быть немного заковыристой вещью. Для Config Reader у нас есть два источника. Первый — это PACT-файлы, а второй — State.



Что это такое PACT-файл? Это не какой-то шифрованный бинарник, а обычный JSON-файл, который имеет специфичную структуру. В нем выделяется consumer, provider (т.е. кто именно и с кем взаимодействует в рамках этого контракта и в какой роли). Далее описываются взаимодействия (это делают разработчики): я — consumer, и хочу от этого сервиса (provider), чтобы он отдавал мне “маленькие зеленые яблоки”; жду такой-то код ответа, статус, header, body и так далее. Есть поле description — это просто описание, повод напомнить разработчикам о чём шла речь в контракте, какой смысл в него вкладывался.

И самое интересное — это State Provider. Что это? По сути, это состояние, в котором должен пребывать тестируемый микросервис на момент обращений к нему по конкретной итерации тестирования, по конкретному запросу. В States могут описываться как SQL-запросы (или другие механизмы приведения сервиса в некоторое состояние), так и создание каких-то данных в нашей сэмплированной базе. States — это сложный модуль, который может содержать в себе всякого рода сущности, приводящие наш сервис в нужное надлежащее состояние.

Важно отметить, что здесь появляется Suite runner (см. схему ниже). Это — та сущность, которая будет отвечать за запуск и конфигурирование тестов в удобном для разработчика/тестировщика виде. Её можно и не писать, но я бы все-таки выделил этот момент, так как сложно предвидеть какие тесты необходимо будет прогонять в тот или иной момент времени на проекте. В итоге у нас получается вот такое ядро автоматизации тестирования под микросервисную архитектуру:



Теперь самое важное — внедрение. Мы должны предоставить эту схему с требованиями по наличию описанных контрактов разработчикам. Что мы получаем после?



У нас есть информация по каждому сервису: о том, что он выдает и то, что он запрашивает у своих “соседей”. Соответственно, с помощью нашей системы автоматизации тестирования, с помощью PACT-файлов мы изолируем наш микросервис для обеспечения изоляции его тестирования вне зависимости от внешних сервисов, с которыми он интегрирован. И предоставляем states через моки, заглушки, сэмплированные базы данных, или напрямую как-то изменяем сервис. Получаем, соответственно, изолированное тестирование. Вуаля: у нас есть ответ на вопрос, что делать с автоматизацией тестирования во время перехода от монолита к микросервисной архитектуре.



Что учесть при имплементации?


Что же нужно учесть при имплементации? Первое — это использование контейнеризации и виртуализации в процессе сборки/деплоя микросервиса. И наша система автоматизации тестирования точно так же закручивается в контейнер. Как будете обеспечивать взаимодействие микросервиса и системы автоматизации тестирования — это уже не столь важно: как удобнее, так и делайте.

Второе — актуализация файлов требований по контрактам. Есть такая проблема, что требования консьюмеров к провайдеру начинают копиться, а разработчики занимаются только тем, что им насущно необходимо сейчас. Здесь нужно на уровне тест-менеджмента или управления продуктом ставить задачу разработчикам: например, час в неделю работать с этим “хвостом”, чтобы он не разрастался. Конечно, эти тесты быстрые, они могут проходить за несколько секунд. Но если их количество будет измеряться тысячами, это будет осложнять актуализацию тестирования. А мы со своей стороны, через систему commit hook-ов будем получать информацию и убирать ненужные автотесты. По сути, CDC — это documentation-driven development, если так можно выразиться.

Третье: нужно ввести обязательно ввести в эту работу процесс актуализации states и data suites. Что такое data suites? Девелоперы в процессе разработки пишут некоторые базовые сценарии взаимодействия. К примеру: “мне нужен такой запрос и такой ответ”. А обо всем остальном — в каких рамках он должен существовать, какие значения параметров возможны, а какие — нет, забывают. Это необходимо проверять. И сюда мы должны входить с нашим data-driven подходом к тестированию, реализуя это в нашем конфигураторе: позитивные, пограничные и негативные тесты, для того, чтобы обеспечить отказоустойчивость работы нашей микросервисной архитектуры на продакшене. Без этого она вряд ли будет работать, любой шаг вправо/влево — и ошибка взаимодействия.

Соответственно при появлении новых pact-файлов, через hook мы получаем таски и наполняем новые/изменённые взаимодействия большим количеством наборов данных в interactions, что равно целому ряду проведенных тестов. Мы можем наполнять и редактировать interactions вручную, а можем делать генераторы, которые будут параметризировать их и гнать тесты.
Что касается States: если брать автоматизацию тестирования веба, то это preconditions, setUps, FixTure; для микросервисов есть проблема — готового механизма нет: надо продумать то, как вы будете сопрягать изменение названия States в PACT-файлах в этом модуле. Самый простой из механизмов — использовать Aliases, по сути KDT (keyword driven testing), говоря на языке автоматизации тестирования. Рассказать сейчас про более красивое и элегантное решение не готов: пока что его не придумал.



Итоги


  1. То, что касается post-commit-hooks, автоматизации мониторинга, появления и изменения, удаления контрактов между сервисами — это все необходимо автоматизировать, это часть системы. Я бы сказал, что это кусочек ядра, который стоит на уровне репозиториев.
  2. CDC-паттерн для разработчиков обязателен. Это фундамент, без него ничего работать не будет.
  3. Вы заметите снижение склонности системы к появлению дефектов. По сути, у нас все её части окутаны изолирующим тестированием. Мы быстро локализуем дефекты, их быстро исправляют, мы располагаем высоким тестовым покрытием. Если будут появляться дефекты на уровне системного тестирования, они, скорее всего, будут связаны с фронт-эндом или какими-то внешними сервисами.
  4. Вы имеете возможность уйти от ручного тестирования изменений. Ключевые моменты: быстрое и изолированное тестирование. Тогда мы получим профит от того, что мы можем хорошо локализовать проблему или дефект.


P.S.


Если вы больше любите не читать, а смотреть видео, то эта информация доступна в формате доклада по ссылке. А в конце августа у нас в Avito пройдет тематический митап для профессионалов в области тестирования. Поговорим о векторах развития систем автоматизации в целом, обсудим применение прикладных инструментов и их влияние на изменение инфраструктуры тестирования. Если интересно — следите за обновлениями на нашей странице в FB, или напишите в комментариях: дадим знать, когда будут подробности о мероприятии.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333644/


Метки:  

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

Четверг, 20 Июля 2017 г. 10:48 + в цитатник

Лето 2017 года выдалось богатым на ураганы. А вот у нас тоже был случай. Ровно 7 лет назад наш первый дата-центр на Боровой пережил ураган, который похоронил чиллеры под слоем 10 тонн железа, прилетевшего с соседней крыши. Душещипательные фотографии искореженных чиллеров разошлись по интернету уже давно, а история про восстановление ЦОДа, оставшегося без холода, никогда не публиковалась. Решил поднять архивы и восполнить пробел.


В 2010 году DataLine был начинающим оператором дата-центров. На площадке OST успели запустить только три зала на 360 стоек, на севере Москвы (NORD) был один корпус с одним залом на 147 стоек.



Вот как изменились масштабы нашей инфраструктуры с 2010 года.


Хотя мы сами проектировали и строили, тогда у нас не было выделенной службы эксплуатации. Не было, как сейчас, отдельных специалистов по ДГУ, кондиционерам, электриков – отдавали все по максимуму подрядчикам. Объемы инфраструктуры были небольшие, как, впрочем, и наш опыт. За инженерку тогда отвечали директор по производству, главный энергетик и я, технический директор. На подхвате были еще дежурные инженеры (трое в смене), но они занимались клиентскими запросами и мониторингом.



Один из первых залов дата-центра OST-1 в конце 2009 года.



Так выглядят новые залы в OST сегодня.


Три зала на Боровой были заполнены только наполовину. Клиентов было немного, для пересчета хватило бы пальцев одной руки.
На площадке работала чиллерная схема на этиленгликоле с тремя чиллерами Emicon в схеме резервирования 2+1. Надо сказать, эти чиллеры так и не вышли на заявленную производителем мощность, но, поскольку нагрузка была небольшая, одного чиллера почти хватало на все три зала.


День первый


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



Кровельное железо свисало с проводов, как белье.


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






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





На видео часы отстают. Когда все произошло, было уже 18.18.


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



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



Искореженные вентиляторы одного из чиллеров.


Из пробитых теплообменников фрикулинга хлестал гликоль. Давление в системе холодоснабжения резко упало. Насосы остановились по защите от сухого хода, вырубился последний рабочий чиллер, и вся система холодоснабжения встала (времени было 18:32, две минуты как закончился рабочий день). Несколько секунд мы пребывали в ступоре и не знали, что делать. Потом позвонили подрядчику по холодоснабжению и вызвали аварийную бригаду. По телефону подрядчик посоветовал перекрыть внешний контур, объяснил, где находятся нужные вентили и краны системы подпитки. Мы перекрыли вентили, питающие внешние теплообменники, гликоль перестал течь.


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


В 18:51 начали дозаправлять гликолевые контуры водопроводной водой и постепенно довели давление в системе до рабочего.
В 19.45 приехала аварийная бригада.
В 19.53 насосы запустились, но заработал только один чиллер из трех. У другого были повреждены вентиляторы, а у третьего – еще и фреоновый контур.
Пока мы проделывали все эти упражнения, температура гликоля успела вырасти с рабочих значений (7–12° С) до 20 градусов. Один живой чиллер работал с перегрузкой, и периодически один из двух его контуров останавливался по ошибке. После этого нужно было вручную сбросить ошибку на пульте, и через пять минут (защитный интервал) компрессор запускался. Или не запускался. Тогда помогало полное обесточивание чиллера с перезагрузкой.


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



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


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


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



Сообщение об ошибке, которое нам по очереди показывали то один, то другой чиллер.


Глубокой ночью случилось то, чего мы боялись: по аварии одновременно остановились оба чиллера и завести их вместе больше не удавалось. Из четырех юнитов первого и второго чиллеров работало один-два, остальные по очереди пребывали в коматозном состоянии по случаю перегрузки. Температура в залах остановилась на уровне около 30 градусов. Все двери в машинные залы были открыты. Это позволяло хоть как-то избавиться от накопившегося тепла.
Мы вместе с подрядчиками пошли изучать схемы чиллеров. После долгих и тяжких раздумий они предложили под нашу ответственность сделать то, чего делать нельзя: обойти защиту, поставив перемычки, т.е. накоротко замкнуть реле тепловой защиты. Это был прямой путь к тому, чтобы окончательно убить компрессоры, но других вариантов не было. В три часа ночи чиллеры завелись и больше не останавливались. Температура в холодных коридорах начала приходить в соответствие с SLA.



Изменение температуры в холодных коридорах с начала аварии и до ее устранения.
1 — время первой остановки всех чиллеров; 2 — время запуска первого чиллера; 3 — время запуска второго чиллера; 4 — повторная остановка чиллеров; 5 — запуск чиллеров с отключенной тепловой защитой.


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


День второй


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



А вот исторический кадр: чиллеры спасает дежурный сетевой инженер Григорий Атрепьев, ныне руководитель отдела комплексных проектов.


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



Замена вентиляторов на третьем чиллере. Чиллер Emicon RAH1252F с опцией фрикулинга (свободного охлаждения) состоит из двух модулей, в каждом из которых стоит 8 осевых вентиляторов и компрессор Bitzer.









Заправка фреоном.



Вид на задний двор на следующий день. Еще долго вывозили металлолом.


Что было дальше


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


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


Поскольку чиллеры так и не выдавали заявленной холодильной мощности (а ИТ-нагрузка росла по мере заполнения ЦОДа), приходилось и дальше поливать их в жару. Теплообменники не пережили водных процедур: с годами они обросли известковыми отложениями, а в зазор между теплообменником фрикулинга и фреоновым конденсатором набилась всякая грязь, удалить которую конструкция не позволяла. Через несколько лет мы планово заменили два из трех чиллеров (про это тоже будет увлекательная история, на этот раз без жертв), а на оставшемся срезали теплообменники фрикулинга. Сейчас на площадке OST работает 4 чиллера: два Stulz, Hiref (добавился, когда дата-центр подрос) и один старый Emicon.



Чиллеры на площадке OST в 2017 году.


Клиенты. Несмотря на этот кошмар эксплуататора, клиенты отнеслись с нашей беде с пониманием и даже никто от нас не съехал.


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


Оргвыводы


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


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


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


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


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


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


  6. Настроили удаленное управление чиллерами из центра мониторинга.


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


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

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


А какие стихийные бедствия пришлось пережить вашей серверной/дата-центру и какие полезные выводы вы для себя сделали?

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333578/


Метки:  

Дели — сокращай, или как мы делали мобильный 2ГИС Онлайн

Четверг, 20 Июля 2017 г. 09:19 + в цитатник


Мобильный веб развивается семимильными шагами. На дворе 2017 год. Мобильный трафик превысил десктопный — больше половины всех страниц теперь открываются через телефоны или планшеты. В 2015 году Google объявил о предпочтении mobile-friendly сайтов при ранжировании выдачи, а в 2016 это сделал Яндекс. Юзеры проводят в интернете 60-70 часов в месяц с мобильных устройств и не готовы идти на компромисс и пользоваться неадаптивными сайтами. И 2ГИС — не исключение. За 2 года рост мобильного трафика 2ГИС Онлайн составил 74%, а месячная аудитория превысила 6 миллионов человек.


17 апреля мы зарелизили новый мобильный онлайн («Монлайн») — одностраничное приложение, доступное по адресу m.2gis.ru. Приложение запущено в двух городах: Уфе и Новосибирске, а в ближайшее время планируется релиз на всю Россию.


Мы знали, что при мобильной разработке столкнемся с тремя проблемами:


Мобильный интернет
Мобильный интернет (2G, 3G, 4G) или Wi-Fi медленнее и не такой стабильный, как кабельный.


Мобильные устройства
Проблема мобилок — слабый процессор. Это влияет на парсинг JS, рендеринг и анимации.


Мобильные браузеры
Некоторые популярные мобильные браузеры не поддерживают часть CSS-свойств или методов JS API. Иногда мы думали, что вернулись в темные времена разработки под IE8. Мобильный интернет и процессор не позволяли использовать полифилы, а значит, приходилось выкручиваться самостоятельно.


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


Дели — сокращай


В мире мобильного веба JS-разработчик следует одному кредо: дели — сокращай. Конечный бандл мобильного приложения должен мало весить и быть разбит на куски.


Выбор фреймворка и библиотек


Главным и единственным фреймворком фронтенда является Preact. Это не опечатка. Preact — легковесная альтернатива React, использующая тот же API и работающая с Virtual DOM. Преимуществами фреймворка является небольшой вес (3 kB gzip против 45 kB у React) и более высокая скорость рендеринга. Благодаря использованию Preact вместо React размер нашего вендора сократился на 90%.


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


Кроме того, мы стараемся писать самостоятельно и не подключать сторонние полифилы и тяжелые библиотеки. Необходимые полифилы грузятся асинхронно через require.ensure и не попадают в бандл. Каждый полифил подключается только в зависимости от условий. Например, в случае с полифилом для Android Browser — мы сэкономили 5 kB кода в gzip.


Ленивая загрузка


image

JS сформирован. Теперь пришло время его разбить. JS код делится на 3 группы:


  • вендор — сторонние библиотеки;
  • app-бандл, в котором хранится главный код приложения;
  • либы и полифилы, подключаемые в зависимости от условий, таких как версия браузера;

Вендор минимизировали через выбор Preact, либы и полифилы подключаем асинхронно и по потребности. Остался последний герой. Гзипнутый app-бандл весом в 143 килобайта в gzip. Это роскошь для мобильной разработки. Так, если пользователь зашел в карточку организации, нет смысла моментально грузить код, отвечающий за рендеринг карточки метро или достопримечательности. Чтобы уменьшить размер app-бандла и доставлять клиенту как можно меньше кода, мы сделали ленивую загрузку.


Требования к коду № 1 в Монлайне гласит: «Код должен быть максимально простым и не знать или делать лишнего». На этом правиле базируется структура UI. В проекте 11 контейнеров и 85 «глупых» компонентов. «Глупые» компоненты не знают о существовании друг друга. Контейнеры объединяют компоненты в структуры и передают данные через пропсы. Карточка организации или отзыва, выдача зданий — примеры контейнеров. 6 контейнеров из 11 не связаны друг с другом, что позволяет разбить app-бандл на… интрига… 6 дополнительных чанков. При восстановлении браузер загружает app-бандл и нужный чанк, а затем асинхронно подгружаются остальные JS-файлы, отвечающие за неактивные контейнеры. Это не блокирует работу приложения. После релиза ленивой загрузки вес app-бандла сократился на 38%.


Хранение и нормализация данных на клиенте


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


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


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


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


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


Облегчаем себе разработку


В создании Монлайна поучаствовали 34 разработчика. В мастер слили 2 000 коммитов, написали 77 000 строк кода и создали 1425 файлов. В проекте участвовали люди из других команд, ребята приходили на стажировки. Мы хотели ускорить процесс разработки, сделать код понятным и документированным. Поэтому решили отказаться от динамической типизации в JavaScript.


Статическая типизация


Клиентская часть приложения написана на TypeScript. Статическая типизация — главное преимущество TypeScript над JS. Она бьет по рукам в случае ошибок при компиляции, документирует код изнутри и облегчает рефакторинг и отладку.


Для управление состоянием приложения в проекте используется Redux. Redux сочетается с TypeScript. Разработчик знает, что передается в payload или meta и, соответственно, что приходит в редьюсер. Например:


export const setScrollTop = (payload: number) => ({
  type: APPCONTEXT_CHANGE_SCROLL_TOP,
  payload
});

export const setErrorToFrame = (errorCode: ErrorCodeType) => ({
  type: APPCONTEXT_SET_ERROR_TO_FRAME,
  payload: { errorCode }
});

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


export default function (state: AppContext = defaultState, action: AppAction): AppContext {
  switch (action.type) {
    case APPCONTEXT_ADD_FRAME:
      return appAddFrame(state, action.payload);
    case APPCONTEXT_REMOVE_ACTIVE_FRAME:
      return appRemoveActiveFrame(state);
   ....
    case APPCONTEXT_HIDE_MENU:
      return { ...state, isSideMenuShown: false };
    default:
      return state;

Избежать путаницы с набором экшнов в редьюсере и данными в payload или meta помогает Discriminated Unions. В коде выше видно, что аргумент action описан типом AppAction, который выглядит так:


export type AppAction = AppAddFrameAction | AppRemoveActiveFrame | AppChangeFramePos | AppChangeMode | AppChangeLandscape…

AppAction объединяет в себя 60 интерфейсов (appAddFrameAction, AppRemoveActiveFrame и т. д.). Каждый интерфейс описывает экшн. Тип (type) экшна — строковый литерал — это дискриминант. Он определяет наличие и содержание внутренностей объекта, таких как payload или meta.


export interface AppAddFrameAction {
  type: 'APPCONTEXT_ADD_FRAME';
  payload: Frame;
}

export interface AppRemoveActiveFrame {
  type: 'APPCONTEXT_REMOVE_ACTIVE_FRAME';
}

export interface AppChangeFramePos {
  type: 'APPCONTEXT_CHANGE_FRAME_POS';
  payload: FramePos;
}

Так TypeScript понимает, что для экшна с дискриминантом 'APPCONTEXT_ADD_FRAME' нужно передать payload с интерфейсом Frame, а в случае 'APPCONTEXT_REMOVE_ACTIVE_FRAME' ничего передавать не нужно.


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


export interface IconProps {
  icon: SVGIcon;
  width?: number;
  height?: number;
  color?: string;
  className?: string;
}

export class Icon extends React.PureComponent {
  constructor(props: IconProps) {
    super(props);
  }

  public render() {
    const { color, icon } = this.props;
    const iconStyle = color ? { color: this.props.color } : undefined;

    return (
      
        
      
    );
  }
}

TypeScript задокументирован и имеет песочницу. Разумеется, язык не всесилен, на июль 2017 года открыто 2200 issues. Продукт Microsoft не поддерживает часть нововведений в ES6. Но медленно и верно эти проблемы решаются в каждом новом релизе.


Создание и тестирование верстки


В мобильном онлайне — 85 «глупых» компонентов. «Глупые» компоненты — визуальные сущности, отвечающие за представление полученных данных. В первую очередь мы хотели разделить верстку и интеграцию этих компонентов в приложении. Это позволило бы ускорить code review и тестирование ресурсом разработчиков. Для достижения этих целей используется Makeup.
Makeup — графический интерфейс для быстрого и комфортного ручного регрессионного тестирования верстки. Подробно почитать об инструменте можно здесь, а потрогать — здесь.


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


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


image

А так мы проверяем «одиннадцатиклассницу» и видим, что ничего не поехало:


image

Заключение


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


В планах разбить «жирные» модули в зависимости от контекста (например, карточку фирмы или геообъекта разделить на отдельные чанки) и попробовать разбить редьюсеры.


Статья посвящена JS-коду. Но разработческое кредо «дели — сокращай» распространяется и на CSS-бандл. В будущем мы также планируем заняться и сплиттингом стилей.

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333016/


Метки:  

[Перевод] Мировые рынки: как добиться успеха в Индии и Бразилии

Четверг, 20 Июля 2017 г. 08:36 + в цитатник

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

Переведено в Alconost

В цифрах



Индия


Сейчас в Индии более 1 миллиарда пользователей мобильной связи. На конец 2016 года около 200 миллионов из них — пользователи со смартфонами (больше только в Китае), и это, на самом-то деле, только начало.

Планшетофоны (мобильные устройства с экраном с диагональю от 5 до 7 дюймов) занимают 61% рынка, намного больше, чем в США. И хотя самая популярная категория устройств ясна, на рынке присутствует как минимум десяток производителей, включая лидера, Samsung (с долей в 40%), а также менее известные бренды, вроде Redmi и Micromax.

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

Пик использования мобильных устройств в Индии в личных целях в приходится на 9 часов вечера. Индийцы не очень активны утром. Мобильные пользователи Индии заботятся о своей конфиденциальности, и, на сегодняшний день, не очень часто пользуются мобильными платежами (примерно 360 миллионов долларов в  2016, лишь малая толика от 27 миллиардов долларов мобильных платежей только в США), но в ближайшие месяца и годы эта цифра будет быстро расти по мере распространения смартфонов среди населения, снижения цен на мобильный Интернет и распространения эффектов демонетизации.

Бразилия


Последние несколько лет экономика Бразилии находилась в состоянии спада, но сейчас видны признаки того, что ситуация изменится. На самом деле, уже предсказано, что спад закончился и в 2017 году экономика Бразилии снова будет расти.
Страсть бразильцев к мобильных технологиям может быть одной из причин этого роста. Около 64 миллионов из 208 миллионов пользователей мобильной связи владеют смартфонами, это более трети всех пользователей в Латинской Америке. Как и в Индии, это цифра растет — к 2018 году ожидается, что проникновение смартфонов достигнет 48%, на 10 пунктов выше, чем в 2015. Это отличная новость для торговли и рынка мобильной рекламы, поскольку бразильцы — поистине ненасытные потребители цифрового контента.

Бразилия уже является самым большим розничным рынком в Латинской Америке, несмотря на экономический спад. Электронная коммерция в Бразилии уже на первом месте среди стран Латинской Америки и объемы ее продолжат расти  примерно на 12,5% в год. Одной из важных причин такого роста является высокое проникновение кредитных карт (50%) и альтернативных методов оплаты, предлагаемых местными компаниями, включая Boleto Bancario, работающую при поддержке правительства систему электронных платежей, через которую проходит примерно четверть цифровых платежей в стране.

Бразильцы относятся к рекламе куда спокойнее, чем индийцы, и рекламодатели тратят 50% рекламных бюджетов всей Латинской Америки в одной только Бразилии — а прогноз на 2019 год составляет 5,8 миллиарда долларов. Помимо этого, в Бразилии самый высокий процент полного просмотра видеорекламы в мире.

Тенденции в использовании приложений


Индия


Использование приложений в Индии растет почти в четыре раза быстрее, чем по всему миру (Индия = 43% год от года; весь мир = 11%). Это создает взрывной спрос пропускной способности и доступности мобильного Интернета. А пока инфраструктура не может удовлетворить потребности рынка, индийские потребители используют UC Browser от Softonic, очень маленькое приложение, способное отфильтровывать более 80% трафика и снижать расходы на связь.

Android доминирует в Индии (97% по состоянию на второй квартал 2016 года), здесь доступны несколько магазинов приложений, включая Amazon и Opera, а также местные магазины, вроде GetJar, самый большой из открытых магазинов приложений в мире. UC Browser с огромным отрывом лидирует среди браузеров в Индии, являясь 6 по популярности приложением в Топ 10 приложений Индии, по порядку: WhatsApp, YouTube, Google, Gmail, SHAREit, UC, Google Maps, MX Player, Facebook и Facebook Messenger. Интересно, что Индия — единственная страна, в топе которой находятся сразу два видеоприложения (YouTube и MX Player): для издателей и рекламодателей это очевидный намек на эффективность и потенциал видеорекламы на этом огромном и растущем рынке.

В 2016 году категория «Музыка, мультимедиа и развлечения» похвасталась самым большим приростом объемов использования (188%), на втором месте была категория «Бизнес и финансы» (176%), на третьем — «Утилиты и продуктивность» (99%). Еще одной особенностью индийского рынка является популярность приложений для здоровья и фитнеса (рост в 27%), которые очень нравятся индийским потребителем, вместе с носимыми устройствами для отслеживания состояния здоровья и достижения фитнес-целей.

Бразилия


В Бразилии очень социальная культура и это находит свое отражение в рейтинге — на первых местах Top 10 социальные приложения и мессенджеры (YouTube, WhatsApp, Google, Facebook, Facebook Messenger, Chrome, Google Maps, Hangouts, Gmail chat, Google+).

На самом деле, 92% пользователей Интернета в Бразилии, как мобильного, так и в целом, пользуются социальными сетями. Бразильцы — это 10% всего социального трафика в мире. Такая социализация создает огромное количество трафика: целых 34% сессий приложений во всей Латинской Америке исходят из Бразилии, намного больше, чем из любой другой страны, включая Мексику. Конфиденциальность зачастую не важна, реклама, которая подстраивается под тон социальных бесед, обычно достигает успеха.

Как и в Индии, Android доминирует с примерно 90% рынка (тут, конечно, помогает тот факт, что iPhone в Бразилии дороже, чем где бы то ни было). Помимо Google Play, популярными вариантами для поиска и скачивания приложений, рингтонов и другого контента являются местные маркеты Aptoide, Mobile9 и Mobogenie. Требования к мобильному Интернету — не проблема в Бразилии, где все гораздо лучше, чем в Индии. Примерно 20% пользователей смартфонов имеют постоянный доступ к сетям 4G, а WiFi (любимый способ бразильцев выходить в сеть) доступен повсеместно.

Активные игроки этих рынков


Индия


Прогноз проникновения смартфонов в 66% в 2018 — огромный скачок на 40 пунктов по сравнению с 2015 годом — говорит о том, что мобильный рынок Индии чрезвычайно активен. В сфере телекоммуникаций ведущим инноватором является Jio, в то время как Vodafone и Airtel начали процесс консолидации рынка через серию сделок по поглощению и объединению.

Если посмотреть на общественные процессы, стоит отметить вложение правительством 3 миллиардов долларов в создание национальной оптической сети National Fiber Optic Network, а также планы по организации бесплатного WiFi-доступа в более чем 1000 отдаленных деревень. Эти и другие смелые инициативы индийский предпринимателей, конечно же, лишь ускоряют распространение приложений.
Lookup, стартап из Бангалора, который с помощью чата связывает покупателей с магазинами поблизости, один из потенциальных лидеров рынка. Получившая посевные инвестиции от таких источников как Vinod Khosla и Biz Stone от Twitter, компания быстро была куплена NowFloats.

Бразилия


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

Несмотря на то, что большая часть из 208 миллионов граждан Бразилии живет в городах, целых 40% жителей Бразилии не являются частью традиционной банковской системы. Но как вы помните, в Бразилии очень широко распространены (и продолжают распространяться) смартфоны. Поэтому финансовые технологии, а в особенности мобильные финансовые технологии — очень горячая отрасль. Бренды и издатели приложений идут на все, чтобы создать надежное и доступное финансовое приложение, которое бы завлекало бразильских потребителей и отвечало их уникальным потребностям.

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

Прогнозы


К 2020 на растущих рынках будет более 2,5 миллиардов пользователей смартфонов, а потребности в мобильном Интернете возрастут почти в 10 раз.

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

В Бразилии, где к 2019 году смартфоны будут почти у 80 миллионов человек (половина из них с доступом к 4G), стимулами роста будут даже не развлечения и коммерция, а полезные и практичные приложения. Бразильцы, очень социальные по своей натуре, быстро принимают и распространяют новые технологии,  (включая мобильные финансовые технологии), и чатботы, внедренные в невероятно популярные по всей стране мессенджеры, станут обычным делом в жизни бразильских потребителей.

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


О переводчике

Перевод статьи выполнен в Alconost.

Alconost занимается локализацией приложений, игр и сайтов на 68 языков. Переводчики-носители языка, лингвистическое тестирование, облачная платформа с API, непрерывная локализация, менеджеры проектов 24/7, любые форматы строковых ресурсов, перевод технических текстов.

Мы также делаем рекламные и обучающие видеоролики — для сайтов, продающие, имиджевые, рекламные, обучающие, тизеры, эксплейнеры, трейлеры для Google Play и App Store.

Подробнее: https://alconost.com

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333752/


Deep Learning, теперь и в OpenCV

Четверг, 20 Июля 2017 г. 08:28 + в цитатник


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

Пожалуй, многие согласятся, что OpenCV является наиболее известной библиотекой компьютерного зрения. За долгое время своего существования она приобрела обширную аудиторию пользователей и стала, де-факто, стандартом в области компьютерного зрения. Множество алгоритмов, работающих «из коробки», открытость исходного кода, замечательная поддержка, большое сообщество пользователей и разработчиков, возможность пользоваться библиотекой на языках C, C++, Python (а также Matlab, C#, Java) под различными операционными системами — это далеко не полный список того, что позволяет OpenCV оставаться востребованной. Но OpenCV не стоит на месте — постоянно добавляется функционал. И сегодня я хочу рассказать о новых возможностях OpenCV в области Deep Learning. Загрузка и получение результатов (предсказаний) с помощью моделей, созданных в любом из трех популярных фреймворков (Caffe, TensorFlow, Torch), быстрая работа на CPU, поддержка основных слоев нейронных сетей и, как всегда, кроссплатформенность, открытость исходного кода и поддержка — об этом я собираюсь рассказать в данной статье.

Прежде всего, хотелось бы представиться. Меня зовут Рыбников Александр. Я являюсь инженером компании Intel и занимаюсь реализацией функциональности Deep Learning в библиотеке OpenCV.

Пару слов о том, как устроена OpenCV. Эта библиотека представляет собой набор модулей, каждый из которых связан с определенной областью компьютерного зрения. Существует стандартный набор модулей — так сказать, «must have» для любой задачи компьютерного зрения. Реализуя известные алгоритмы, данные модули хорошо проработаны и протестированы. Все они представлены в основном репозитории OpenCV. Также существует репозиторий с дополнительными модулями, реализующими экспериментальную или новую функциональность. Требования к экспериментальным модулям, по понятным причинам, мягче. И, как правило, когда какой-то из таких модулей становится достаточно развитым, сформировавшимся и востребованным, он может быть перенесен в основной репозиторий.

Данная статья связана с одним из модулей, совсем недавно занявшим почетное место в основном репозитории — с модулем dnn (далее просто dnn).

(N+1)-й фреймворк для deep learning, это вообще зачем?


Зачем вообще понадобился Deep Learning в OpenCV? В последние годы во многих областях глубокое обучение (в некоторых источниках глубинное обучение) показывает результаты, значительно превосходящие аналогичные у классических алгоритмов. Это касается и области компьютерного зрения, где масса задач решается с применением нейронных сетей. В свете данного факта кажется логичным дать пользователям OpenCV возможность работы с нейросетями.

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

Во-первых, так можно добиться легковесности решения. Оставляя только возможность выполнения прямого прохода (forward pass) по сети, можно упростить код, ускорить процесс установки и сборки.

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

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

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

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

Основные возможности


Основная возможность dnn заключается, конечно же, в загрузке и запуске нейронных сетей (inference). При этом модель может быть создана в любом из трех фреймворков глубокого обучения — Caffe, TensorFlow или Torch; способ ее загрузки и использования сохраняется независимо от того, где она была создана.

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

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

Поддерживаются все основные слои: начиная от базовых (Convolution и Fully connected) и заканчивая более специализированными — всего более 30.
Список поддерживаемых слоев
AbsVal
AveragePooling
BatchNormalization
Concatenation
Convolution (with dilation)
Crop
DetectionOutput
Dropout
Eltwise
Flatten
FullConvolution
FullyConnected
LRN
LSTM
MaxPooling
MaxUnpooling
MVN
NormalizeBBox
Padding
Permute
Power
PReLU
PriorBox
ReLU
RNN
Scale
Shift
Sigmoid
Slice
Softmax
Split
TanH

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

Кроме поддержки отдельных слоев, важна также и поддержка конкретных архитектур нейронных сетей. Модуль содержит примеры для классификации (AlexNet, GoogLeNet, ResNet, SqueezeNet), сегментации (FCN, ENet), детектирования объектов (SSD); многие из указанных моделей проверены на исходных датасетах, но об этом позднее.

Сборка


Если вы — опытный пользователь OpenCV, то можете смело пропустить этот раздел. Если нет, то я постараюсь максимально кратко рассказать о том, как же получить работающие примеры из исходного кода для Linux или Windows.
Краткая инструкция по сборке
Предварительно потребуется установить git (либо Git Bash для Windows), [cmake](http://cmake.org) и компилятор С++ (Visual Studio под Windows, Xcode на Mac, clang либо gcc под Linux). Если вы собираетесь использовать OpenCV из Python, то нужно также установить сам Python (подойдут последние версии 2.7.x или 3.x) и соответствующую ему версию numpy.

Начнем с клонирования репозитория:

mkdir git && cd git
git clone https://github.com/opencv/opencv.git


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

cd ..
mkdir build && cd build
cmake ../git/opencv -DBUILD_EXAMPLES=ON


(для Windows здесь и далее нужно заменить cmake на полный путь до запускаемого файла cmake, например на «C:\Program Files\CMake\bin\cmake.exe» или использовать cmake GUI)

Теперь непосредственно сборка:

make -j5 (Linux)
cmake --build . --config Release -- /m:5 (Windows)


После этого dnn готов к использованию.
Приведенная выше инструкция достаточно краткая, поэтому приведу также ссылки на пошаговые инструкции по установке OpenCV на Windows и Linux.


Примеры использования


По хорошей традиции, каждый модуль OpenCV включает в себя примеры использования. dnn — не исключение, примеры на С++ и Python доступны в поддиректории samples в репозитории с исходным кодом. В примерах присутствуют комментарии, да и в целом все достаточно просто.
Приведу здесь краткий пример, выполняющий классификацию изображений с помощью модели GoogLeNet. На языке Python наш пример будет выглядеть следующим образом:

import numpy as np
import cv2 as cv

# read names of classes
with open('synset_words.txt') as f:
    classes = [x[x.find(' ') + 1:] for x in f]

image = cv.imread('space_shuttle.jpg')
# create tensor with 224x224 spatial size and subtract mean values (104, 117, 123) 
# from corresponding channels (R, G, B)
input = cv.dnn.blobFromImage(image, 1, (224, 224), (104, 117, 123))

# load model from caffe
net = cv.dnn.readNetFromCaffe('bvlc_googlenet.prototxt', 'bvlc_googlenet.caffemodel')
# feed input tensor to the model
net.setInput(input)
# perform inference and get output
out = net.forward() 
# get indices with the highest probability
indexes = np.argsort(out[0])[-5:] 
for i in reversed(indexes):
    print('class:', classes[i], ' probability:', out[0][i])


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

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

Выглядит несложно, не так ли? Если записать то же самое на C++, код получится немного более длинным. Однако, самое главное — имена функций и логика работы с модулем — останутся одними и теми же.

Точность


Как понять, что одна натренированная модель лучше другой? Необходимо сравнить метрики качества для обеих моделей. Очень часто борьба на вершине рейтинга лучших моделей идет за доли процентов качества. Поскольку dnn читает и преобразует модели из различных фреймворков в свое внутреннее представление, возникают вопросы сохранения качества после преобразования модели: не «испортилась» ли модель после загрузки? Без ответов на эти вопросы, а значит без проверки сложно говорить о полноценном использовании dnn.
Я провел тестирование моделей из имеющихся примеров для различных фреймворков и различных задач: AlexNet (Caffe), GoogLeNet (Caffe), GoogLeNet (TensorFlow), ResNet-50 (Caffe), SqueezeNet v1.1 (Caffe) для задачи классификации объектов; FCN (Caffe), ENet (Torch) для задачи семантической сегментации. Результаты приведены в Таблицах 1 и 2.
Модель (исходный фреймворк)
Опубликованное значение acc@top-5
Измеренное значение acc@top-5 в исходном фреймворке
Измеренное значение acc@top-5 в dnn
Средняя разница на элемент между выходными тензорами фреймворка и dnn
Максимальная разница между выходными тензорами фреймворка и dnn
AlexNet (Caffe)
80.2%
79.1%
79.1%
6.5E-10
3.01E-06
GoogLeNet (Caffe)
88.9%
88.5%
88.5%
1.18E-09
1.33E-05
GoogLeNet (TensorFlow)
89.4%
89.4%
1.84E-09
1.47E-05
ResNet-50
(Caffe)
92.2%
91.8%
91.8%
8.73E-10
4.29E-06
SqueezeNet v1.1
(Caffe)
80.3%
80.4%
80.4%
1.91E-09
6.77E-06
Таблица 1. Результаты оценки качества для задачи классификации. Измерения проводились на валидационном наборе ImageNet 2012 (ILSVRC2012 val, 50000 примеров).
Модель (фреймворк)
Опубликованное значение mean IOU
Измеренное значение mean IOU в исходном фреймворке
Измеренное значение mean IOU в dnn
Средняя разница на элемент между выходными тензорами фреймворка и dnn
Максимальная разница между выходными тензорами фреймворка и dnn
FCN (Caffe)
65.5%
60.402874%
60.402879%
3.1E-7
1.53E-5
ENet (Torch)
58.3%
59.1368%
59.1369%
3.2E-5
1.20
Таблица 2. Результаты оценки качества для задачи семантической сегментации. Объяснение большой максимальной разницы для ENet далее в тексте.

Результаты для FCN вычислены для валидационного набора сегментационной части PASCAL VOC 2012 (736 примеров). Результаты для ENet вычислены на валидационном наборе Cityscapes (500 примеров).

Следует сказать несколько слов о том, какой смысл имеют указанные выше числа. Для задач классификации общепринятой метрикой качества моделей является точность для топ-5 ответов сети (accuracy@top-5, [1]): если правильный ответ имеется среди 5 ответов сети с максимальными показателями уверенности (confidence), то данный ответ сети засчитывается как верный. Соответственно, точность — это отношение числа верных ответов к числу примеров. Данный способ измерения позволяет учесть не всегда корректную разметку данных, когда, например, отмечается объект, занимающий далеко не центральное положение на кадре.

Для задач семантической сегментации используются несколько метрик — попиксельная точность (pixel accuracy) и среднее по классам отношение пересечения к объединению (mean intersection over union, mean IOU) [5]. Попиксельная точность — это отношение количества правильно классифицированных пикселей к количеству всех пикселей. mean IOU — более сложная характеристика: это усредненное по классам отношение правильно отмеченных пикселей к сумме числа пикселей данного класса и числа пикселей, отмеченных как данный класс.

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

Разницу между опубликованными и полученными в экспериментах числами можно объяснить тем, что авторы моделей проводят все вычисления с использованием GPU, в то время как я использовал CPU-реализации. Также было замечено, что различные библиотеки могут по-разному декодировать формат jpeg. Это могло сказаться на результатах для FCN, так как датасет PASCAL VOC 2012 содержит изображения именно данного формата, а модели для семантической сегментации оказываются достаточно чувствительны к изменению распределения входных данных.

Как вы заметили, в Таблице 2 присутствует аномально большая максимальная разница выходов dnn и Torch для модели ENet. Меня также заинтересовал данный факт и далее я кратко расскажу о причинах его возникновения.
Почему возникает большое различие между dnn и Torch для ENet?
Модель ENet использует несколько операций MaxPooling. Данная операция выбирает максимальный элемент в окрестности каждой позиции и записывает в выходной тензор это максимальное значение, а также передает далее индексы выбранных максимальных элементов. Эти индексы далее используются операцией, в некотором смысле обратной данной — MaxUnpooling. Эта операция записывает элементы входного тензора в позиции выходного, соответствующие тем самым индексам. В этом месте и возникает большая ошибка: в определенной окрестности операция MaxPooling выбирает элемент с неправильным индексом; при этом разница между правильным выходом Torch и выходом dnn для данного слоя лежит в пределах вычислительной погрешности (10E-7), а разница в индексах соответствует соседним элементам окрестности. То есть, в результате небольшой флуктуации соседний элемент стал несколько больше, чем элемент с правильным индексом. Результат операции MaxUnpooling, при этом, зависит не только от выхода предыдущего слоя, но и от индексов соответствующей операции MaxPooling, которая располагается намного раньше (в начале вычислительного графа модели). Таким образом, MaxUnpooling записывает элемент с правильным значением в неверную позицию. В результате, накапливается ошибка.

К сожалению, устранить данную ошибку не представляется возможным, так как первопричины ее появления связаны, скорее всего, с немного различающимися реализациями алгоритмов, использованных при тренировке и при inference и не связаны с наличием ошибки в реализации.
Однако, справедливо отметить, что средняя ошибка на элемент выходного тензора остается низкой (см. Таблицу 2) — то есть ошибки в индексах возникают достаточно редко. Более того, наличие данной ошибки не приводит к ухудшению качества работы модели, о чем свидетельствуют числа в той же Таблице 2.


Производительность


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

Я провел замеры времени работы для различных моделей при их использовании — результаты в Таблице 3.
Модель (исходный фреймворк)
Разрешение изображения
Производительность исходного фреймворка, CPU (библиотека акселерации); потребление памяти
Производительность dnn, CPU (ускорение относительно исходного фреймворка); потребление памяти
AlexNet (Caffe)
227x227
23.7 мс (MKL); 945 МБ
14.7 мс (1.6x); 713 МБ
GoogLeNet (Caffe)
224x224
44.6 мс (MKL); 197 МБ
20.1 мс (2.2x); 172 МБ
ResNet-50 (Caffe)
224x224
70.2 мс (MKL); 386 МБ
58.8 мс (1.2x); 224 МБ
SqueezeNet v1.1
(Caffe)
227x227
12.4 мс (MKL); 113 МБ
5.3 мс (2.3x); 38 МБ
GoogLeNet (TensorFlow)
224x224
17.9 мс (Eigen); 310 МБ
21.1 мс (0.8x); 135 МБ
FCN (Caffe)
различное (500x350 в среднем)
3873.6 мс (MKL);
4453 МБ
1229.8 мс (3.1x);
1332 МБ
ENet (Torch)
1024x512
1105.0 мс; 828 МБ
218.7 мс (5.1x); 190 МБ
Таблица 3. Результаты замеров времени работы различных моделей. Эксперименты проводились с использованием Intel Core i7-6700k.

Замеры времени производились с усреднением по 50-ти запускам и выполнялись следующим образом: для dnn использовался встроенный в OpenCV таймер; для Caffe использовалась утилита caffe time; для Torch и TensorFlow использовались существующие функции замера времени.

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

Дальнейшие планы


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

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

Что касается производительности, то несмотря на многие выполненные оптимизации, у нас все еще есть идеи, как улучшить результаты. Одна из таких идей — уменьшить разрядность вычислений. Данная процедура носит название квантизации. Грубо говоря, выкинуть часть разрядов у входа и весов слоя перед вычислением сверток (fp32->fp16), либо вычислить масштабирующие коэффициенты, переводящие диапазон входных чисел в диапазон int или short. При этом возрастет скорость (за счет использования более быстрых операций с целыми числами), но, возможно, немного пострадает точность. Однако публикации и эксперименты в этой области показывают, что даже достаточно сильная квантизация в определенных случаях не приводит к заметному падению качества.

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

Сейчас к релизу готовится нечто достаточно интересное. Думаю, немногие слышали о языке программирования Halide. Он не является Тьюринг-полным — некоторые конструкции реализовать на нем не получится; возможно поэтому он и не пользуется популярностью. Однако указанный недостаток является одновременно и его преимуществом — написанный на нем исходный код может быть автоматически превращен в высокооптимизированный под разные «железки»: CPU, GPU, DSP. При этом нет нужды быть гуру оптимизации — специальный компилятор все сделает за вас. Уже сейчас Halide позволяет получить ускорение некоторых моделей — и, например, семантическая сегментация с моделью ENet работает 25 fps для разрешения 512x256 на Intel Core i7-6700k (против 22 fps у dnn без Halide). И, что самое приятное, без переписывания кода можно задействовать интегрированную в процессор GPU, получив дополнительно еще пару кадров в секунду.

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

Заключение


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

Если у вас есть вопросы, появились предложения, возникли проблемы или вы хотите внести свой вклад путем подачи pull request — добро пожаловать в github-репозиторий, а также на наш форум, где я и мои коллеги постараемся вам помочь. Если ни один из указанных способов не подошел, на нашем сайте можно найти дополнительные пути коммуникации. Я всегда буду рад сотрудничеству, конструктивным замечаниям и предложениям. Спасибо за внимание!

P.S. Выражаю огромную благодарность моим коллегам за помощь в работе и написании данной статьи.

Ссылки


  1. ImageNet Classification with Deep Convolutional Neural Networks
  2. Going deeper with convolutions
  3. Deep Residual Learning for Image Recognition
  4. SqueezeNet: AlexNet-level accuracy with 50x fewer parameters and <0.5MB model size
  5. Fully Convolutional Networks for Semantic Segmentation
  6. ENet: A Deep Neural Network Architecture for Real-Time Semantic Segmentation
  7. SSD: Single Shot MultiBox Detector
  8. Deep Compression: Compressing Deep Neural Networks with Pruning, Trained Quantization and Huffman Coding
  9. OpenCV github
  10. Официальный сайт OpenCV
  11. Форум OpenCV
  12. Halide
  13. Caffe
  14. TensorFlow
  15. Torch
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333612/


Метки:  

ICO: основные юрисдикции и вопросы

Четверг, 20 Июля 2017 г. 05:45 + в цитатник


Где-то год назад я начал изучать тему ICO (кто не в курсе — это первичное размещение токенов: аналогия взята из аббревиатуры IPO): как оказалось — не зря. На сегодня рынок ICO вышел (уже вышел — а год ещё не закончился) за 1 000 000 000 долларов. При этом рынок crypto по объёму выходил за 100 000 000 000 (но сейчас — колеблется возле цифры в 85 миллиардов). Это, конечно, не триллионы, но уже серьёзно.

В этой заметке хотелось бы ответить на три вопроса:

  1. ICO — это пузырь или нет?
  2. В каких юрисдикция и почему регистрируются те, кто проводят ICO?
  3. Есть ли у ICO будущее и каково оно?

Ответ на первый вопрос прост: да. Да, ICO — это пузырь и тому есть несколько причин:

  1. Большинство сервисов (на сегодня плотно проанализировал — 54, всего просматривал — 117) не имеют под собой чёткой технологической основы и порой — даже проработанного концепта: создатели ограничиваются Белой книгой и Дорожной картой, сбивая на ICO деньги на разработку и маркетинг;
  2. Спекулянтом слишком сильны, потому как рынок очень мелкий и манипулировать ценой — весьма просто (ниже будет несколько примеров).
  3. Если сравнивать доткомы или тюльпаноманию с ICO — то найдётся очень много общего: большое количество того, что растёт; огромные спекуляции на этом; вера в том, что это никогда не закончится и т.д.
  4. Команды, которые выходят на ICO, — очень молодые и это на запуске видится положительным фактором, но, когда возникают операционные сложности, — трудности возрастают троекратно. И я даже не про Matchpool и иже с ним, когда кто-то похищает средства, а о том, что слаженность команды — это не тот фактор, которым можно пренебречь. В блокчейне, возможно, даже сильнее он себя проявляет, так сфера строится как сверх-технологичная, а значит — риск от человеческого фактора только возрастает, как это ни парадоксально: думаю, пример The DAO всем знаком.

Безусловно, это не всё: но даже этих критериев при оценке хватит, чтобы понять всю зыбкость первичного накопления капитала в ICO. К тому же, сейчас (в 2017 году в смысле) этот инструмент стал просто хайповым: деньги от банков, инвесторов и того же IPO стоят не мало, а вот деньги от краудфандинга (не будем сейчас вдаваться в подробный анализ, так как явлений, поясняющих ICO — несколько: всё зависит от правового статуса токена).

Ответ на второй вопрос не так прост: в 2014 году ещё bitnovosti проводили исследование данного рынка. И вот какая картинка нарисовалась:



Чтобы исследование было совсем «чистым», отмечу, что речь в материале всё же шла в первую очередь о bitcoin-стартапах. А вот как выглядит ситуация на сегодня (за основу взял собственные наработки, статистику можно также собирать из источников, указанных ниже) в ТОП-30:


Добавлю, что для рассмотрения я взял только те проекты, у которых:
  1. Было именно ICO (например, его не было у Bitcoin'а и Ripple — хоть и по разным причинам, но не было);
  2. Данные о компаниях не закрыты: есть в Белой книги и/или на сайте: и в этот раз я нарочно не копал глубоко, чтобы встать на место рядового пользователя и увидеть данные фирмы, если для этого не нужно делать каких-то жутких запросов в формате СПАРК;
  3. Капитализация позволяет делать обобщающие выводы.
  4. По списку coinmarketcap я дошёл до 41 места, но не включал: btc, ltc (хотя у этой монеты есть и Litecoin Association из США, и Litecoin Foundation из Сингапура), monero; EOS, т.к. компания уже была организована ранее, как, скажем и Ardor (производная от NXT); Byteball — потому что платформа не предполагает ICO в принципе;
  5. Кроме того, китайские проекты я тоже не трогал, так как нужно быть очень… неожиданным инвестором, чтобы создавать компанию под ICO в Поднебесной.

Конечно, совсем немного порывшись в Сети можно найти данные и других проектов: Waves, Golem (Golem Factory GmbH is a Swiss LLC established in 2017.) и так далее.

Вопрос в том, что немногие это до сих пор делают.

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

Регистрация в Сингапуре (по ней, кстати, пошёл и ещё один недавний проект — SONM) объяснима: за 6000-10 000 долларов вы получаете компанию в технологически развитой стране, где Правительство дружелюбно (подробней читайте здесь) в целом настроено к блокчейн-стартапам. К тому же — вывод в фиат, полученных на ICO средств здесь не сравним, скажем, с Россией (если с этой юрисдикцией вообще что-то уместно в этом аспекте сравнивать). В этом плане Гонконг — вполне логичная альтернатива Сингапуру: подробней почитать об отношении к «крипте» можно в книге, скажу лишь, что в обеих странах оно нейтрально-позитивное.

США — родина стартапов, поэтому зарождающиеся там проекты не меняют юрисдикцию. Швейцария, а конкретнее — Цуг, считается Криптодолиной (Эфириум В. Бутерина «тому виной» в первую очередь). Великобритания в этом смысле — хороша для российских стартапов.

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

Сводно это звучит так:
  1. Англия, Шотландия — примерно 1000-1500 долларов
  2. Сингапур — (см. выше) около 10 000
  3. Гонконг — 2 000
  4. Швейцария — 11 000 — 15 000

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

Но, что дозволено Юпитеру, но позволено быку: выход на ICO не уникальных сервисов, разного рода проектов из реального сектора или проектов без огромного маркетингового бюджета (а он составляет у ТОПовых ICOшников от 100 000 до 500 000 вечнозелёных и даже более).

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

Ещё один частый вопрос — это налоги, но тут проще:
  1. Сингапур
  2. Гонконг
  3. Великобритания
  4. Швейцария
  5. США

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

Чтобы было понятно — напомню: Ripple — компанию, которая изначально на США завязана, в своё время оштрафовали на 700 000 мёртвых президентов, т.к. " ...Ripple Labs не смогла зарегистрироваться в качестве компании, оказывающей финансовые услуги, но тем не менее продавала XRP, цифровое средство для проведения платежей в сети Ripple". Опять же — примеры есть и в книге по ICO.

Поэтому США — хорошая юрисдикция, но: 1) лишь на первый взгляд; 2) для резидентов США в первую очередь.

Наконец, чтобы ответить на последний вопрос, скажу следующее: у ICO есть будущее, но падение — неизбежно. И на то есть ряд причин:
  1. Ужесточение государственного регулирования
  2. Разочарование в проектах после не выхода из alfa- & beta-версий
  3. Абсолютная (и об этом будет отдельный материал) неподготовленность проектов с юридической точки зрения: этот гром будет одним из самых слышимых;
  4. Технологическое несовершенство.

Локально это уже видим на рынках:


Или на самом ярком примере — на Эфириуме:


Впрочем, у последнего проблемы сейчас связаны не только со спекуляциями (формата: «Виталик умер — мы все умрём), но и с принципиальными как раз вещами, когда запуск очередного ICO кладёт (на) Сеть полностью. И вот такие проблемы в ближайший год-два неизбежны для многих блокчейн-стартапов, которые почувствовали запах лёгких денег.

Таким образом, на мой взгляд выбор юрисдикции — это лишь один из шагов по оптимизации рисков. И он абсолютно не поможет, а то и навредит, если проект не просто не выстрелит, но и „что-то пойдёт совсем не так“.

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

И да: график — напоминание…


P.S. Прошу поучаствовать в опросе: нужен срез мнений по юрисдикция.
Где бы вы открыли юр. лицо для ICO?

Проголосовал 1 человек. Воздержавшихся нет.

Когда лопнет пузырь ICO (не криптовалют!)?

Проголосовал 1 человек. Воздержавшихся нет.

Вы участвовали уже в ICO?

Проголосовал 1 человек. Воздержавшихся нет.

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

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333748/


Метки:  

Как писать на Spring в 2017

Четверг, 20 Июля 2017 г. 01:28 + в цитатник

Метки:  

Критическая уязвимость в multisig кошельке Parity, хакерами выведен $31 миллион в ethereum

Четверг, 20 Июля 2017 г. 00:16 + в цитатник
Из-за уязвимости в коде смарт-контракта multisig кошелька Parity (1.5 и более поздний) хакер смог вывести монет ethereum в эквиваленте 31 миллиона долларов.

Кошелёк хакера: etherscan.io/address/0xb3764761e297d6f121e79c32a65829cd1ddb4d32

White-hat группа смогла вывести эфира в 76 миллион долларов (и ещё 80 миллионов в различных токенах) с уязвимых кошельков для защиты средств
etherscan.io/address/0x1dba1131000664b884a1ba238464159892252d3a

Были украдены деньги с кошельков следующих ICO:
  • Edgeless Casino
  • Swarm City
  • Aeternity blockchain

"Edgeless casino, swarm city, and aeternity have all been drained" --CF Slack #parityhack

— CoinFund (@coinfund_io) July 19, 2017

В white-hat кошельке на данный момент, например, находятся токены eos криптовалютного инвестиционного фонда satoshi.fund в размере $1,5 млн.

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

Оповещение об уязвимости в блоге Parity
Официальное заявление Swarm City

invested in Aeternity
lol
and they lost like 18million
f#$@ morons…

It likes like it will be a eternity until you get your money back ;)

The DAO 2.0. Только хард-форка эфира для спасения средств в этот раз не ожидается. Твит Виталика Бутерина в ответ на вопрос, почему был произведен хард-форк цепи ethereum в случае с The DAO, а здесь его не будет:

1. Ecosystem less mature then
2. More at stake then as % of all ETH
3 [most impt]. Today's attacker can just move funds, so HF is impossible

— Vitalik Buterin (@VitalikButerin) July 19, 2017

  1. Менее зрелая экосистема в то время
  2. Тогда на кону был больший % от всего ЕТН
  3. (самое важное) Хакер может просто перевести средства, поэтому хард-форк невозможен
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333754/


Метки:  

DevOps Days Riga 2017

Среда, 19 Июля 2017 г. 21:34 + в цитатник

DevOps Days Riga 2017 — это организованная сообществом техническая конференция, которая пройдет в Риге с 18-19 Сентября для более 200 участников из стран Прибалтики и за ее пределами.

Основная тематика конференции — использование DevOps практик и инструментов в различных ИТ компаниях.

Место проведения — Tallink Hotel Riga.
Ранняя регистрация со скидкой до 26.07


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

Организаторы приглашают принять участие DevOps, Tech Team Leads, Engineers, а так же Project Managers and Innovation Team Leads из ИТ-компаний, кто уже знаком с тем, что такое DevOps.

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

Официальная страница мероприятия
Билеты на конференцию уже доступны

Ссылки на аккаунт мероприятия в социальных сетях

Присоединиться в Facebook
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333740/


Метки:  

Укрощаем мультимедиа с помощью ffmpeg

Среда, 19 Июля 2017 г. 20:59 + в цитатник

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





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


Библиотека ffmpeg и обработка видео


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


Конвертировать один формат аудио и видео файлов в другой


ffmpeg -i file. [options] file.

Уменьшаем видео, записанное на фотоаппарате:


ffmpeg -i MVI_4703.MOV MVI_4703.avi

То же самое, но с контролем качества.


ffmpeg -i MVI_4703.MOV -q:v 4 MVI_4703.avi

Размер изображения уменьшился более чем в 5 раз без ощутимой потери качества. Опция -qscale:v n, сокращенно -q:v n позволяет установить уровень качества генерируемого видеопотока, где n принимает значения в интервале от 1 до 31. Значение 1 соответствует самому лучшему качеству, а 31 — самому худшему.


-rw-r--r-- 1 mig users 124M июл 18 23:29 foto/MVI_4703.avi
-rw-r--r-- 1 mig users 686M июн 27 21:38 foto/MVI_4703.MOV

Указать кодек


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


ffmpeg -i video.mp4 -c:v vp9 -c:a libvorbis video.mkv

Увидеть все поддерживаемые кодеки можно командой ffpmeg -codecs.


Поменять контейнер файла


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


ffmpeg -i video.m4v -c:av copy video.mkv

Если же нужно поменять только звук, а видео оставить как есть, запускаем эту команду. Почему-то телевизоры Филипс понимают только форматы звука AAC/AC3.


ffmpeg -i video.m4v -c:v copy -c:a aac video.mkv

Добавить звуковую дорожку


Просто перечисляем файлы ввода и задаем вывод.


ffmpeg -i video.mp4 -i audio.ogg video_sound.mp4

Извлечь звуковую дорожку


Если нужно просто извлечь звук, то можно так.


ffmpeg -i video.MOV -vn audio.ogg

Задаем формат извлекаемой звуковой дорожки.


ffmpeg -i video.MOV -vn -c:a flac audio.flac

Указывает приемлемый битрейт, по умолчанию будет записано 128k.


ffmpeg -i video.MOV -vn -c:a flac -b:a 192k audio.flac

Делаем слайд-шоу из картинок


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


ffmpeg -r .3 -pix_fmt rgba -s 1280x720 -pattern_type glob -i "*.JPGЭ video.mkv

Требуются некоторые пояснения.


  • -r number — частота кадров в секунду.
  • -pix_fmt — Пиксельный формат, список из команды ffmpeg -pix_fmts. Не со всему форматами получается выставить нужный размер кадра.
  • -pattern_type glob — Для того, чтобы использовать совпадение по шаблону как в командной оболочке. Альтернативой является использование формата C printf, например image%03d.png для всех image0001.png, image0002.png и т. д.

Изменить видеопоток


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


ffmpeg -i video_full.m4v -c:av copy -ss 00:01:00 -t 10 video_short.m4v

Как повысить качество потоков аудио или видео? Для этого используется ключ битрейта -b.


ffmpeg - video.webm -c:a copy -c:v vp9 -b:v 2M final.mkv

Захват экрана


Для захвата экрана используется устройство x11grab, а ffmpeg должен быть собран с опцией --enable-x11grab.


ffmpeg -f x11grab -framerate 25 -video_size 4cif -i :0.0 out.mpg

  • -video_size word — Размер захвата, cif = 352x288, 4cif = 704x576. Подробнее в info ffmpeg-utils.

Бонусная дорожка


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


mogrify -resize 60% *.png

Аккуратное повышение резкости изображения, наподобие Smart Sharpen с помощью Perl скрипта, использующего convert и composite из набора утилит ImageMagick.


Ссылки по теме


  1. Хабрапост про ffmpeg, много полезных команд, однако синтаксис для большинства уже успел поменяться.
  2. A quick guide to using FFmpeg to convert media files
  3. Настройка качества кодировки в FFmpeg: переменный и постоянный битрейт для Mpeg4
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333664/


Метки:  

Текущая активность вокруг MIPSfpga и не только

Среда, 19 Июля 2017 г. 20:27 + в цитатник

КДПВ


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


  • релиз MIPSfpga 2.0;
  • процессор schoolMIPS и Летняя школа юных программистов в Новосибирске;
  • школа-семинар по цифровому дизайну и компьютерной архитектуре в Томске;
  • запуск ванильного ядра Linux на MIPSfpga-plus;
  • поддержка АЦП Altera MAX10 в MIPSfpga-plus;
  • логотип MIPSfpga-plus.

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


Релиз MIPSfpga 2.0


Спустя 2 года после первого релиза MIPSfpga компания Imagination Technologies выпустила вторую версию пакета: MIPSfpga 2.0 [L1].
На что следует обратить внимание:


  • как и прежде MIPSfpga преподносится не только как открытые под академической лицензией исходные коды промышленного процессорного ядра, а еще и как набор образовательных материалов, включающий также документацию и лабораторные работы. И это прекрасно, потому что в комплекте с не так давно переведенной на русский язык книгой "Цифровая схемотехника и архитектура компьютера" (H&H) [L2] мы получаем очень качественный и доступный набор теории и практики, преподносимый на примере архитектуры MIPS;
  • на недавно прошедшем в Торонто симпозиуме [L3] Сара Харрис (один из авторов H&H) представила коллективную статью [L14], в которой приводится достатовно подробное описание MIPSfpga 2.0, а также анализ распространения образовательной инициативы Imagination Technologies по ВУЗам. И (вау!) там даже упоминается мое имя в связи с активностью в проекте MIPSfpga-plus.
  • если первый релиз был в основном сконцентрирован на том, как собрать систему на кристалле (СнК) на базе MIPSfpga, то втором акцент смещен именно на работу самого процессора:

Список лабораторных работ

1 Create a Project in Vivado or Quartus-II
2 Learn how to compile, debug and run C programs
3 Learn MIPS Assembly Programming system
4 More C Programming Practice (optional)
5 Expand the system to add 7-segment displays
6 Expand the system to add a counter
7 Expand the system to add a buzzer
8 Expand the system to add an SPI-Light Sensor
9 Expand the system to add a SPI-LCD
10 Interact with peripherals using interrupts
11 Build a DMA engine for transfers between peripherals
12 Build a Data Encryption Standard (DES) engine
13 Learn how to use the Performance Counters
14 Execution of ADD and other arithmetic instruction
15 Execution of AND and other logic instructions
16 Execution of LW and other related instructions
17 Execution of BEQ and other related instructions
18 Learn how the Hazard Unit is implemented
19 Learn how to use the CorExtend interface
20 Introduction to the caches available in MIPSfpga
21 Analyze the D$ and implement new configurations
22 Cache Controller: Analyze a cache hit and miss
23 Cache Controller: Analyze D$ management policies
24 Cache Controller: Analyze the Store and Fill Buffers
25 Implement an Instruction Scratchpad RAM


  • само ядро по предварительной информации особых изменений не претерпело, это все то же MIPS microAptiv UP, на базе которого построен, к примеру, Microchip PIC32MZ;
  • неизменной осталась и ориентированность на Xilinx при построение СнК в лабораторных работах. Так, общая схема используемой в лабораторных работах СнК выглядит следующим образом, что несколько ограничивает запуск на Altera-based платах:
    MIPSfpga Linux SoC

Если учесть, что компания Digilent искуственно ограничивает поставки своих плат на без ПЛИС Xilinx в Россию и на Украину, то картина получается не очень приятная. Но тут нам на помощь приходит MIPSfpga-plus — opensource проект по построению СнК на базе MIPSfpga с платформонезависимой периферией [L4]. Для корректного взаимодействия с MIPSfpga 2.0 его, возможно, придется немного доработать.


schoolMIPS и Летняя школа юных программистов


Сегодня в Новосибирске открылась Летняя школа юных программистов [L5]. Учебная программа школы предполагает разделение на мастерские [L6], одна из которых ориентирована на преподавание Verilog и архитектуры микросхем. Преподавателем у ребят будет Юрий Панчул YuriPanchul, который специально ради этого дела прилетел из Штатов.


Мастерская архитекторов микросхем

Мастер: Юрий Панчул


Цифровое железо, от логических элементов до собственного процессора


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


Мы начнем с трех ключевых кирпичиков цифровой электроники — логического элемента, тактового сигнала и D-триггера, памяти для одного бита информации. Для наглядности мы освоим их старомодным способом, соединяя проводами микросхемы малой степени интеграции на макетной плате.


Затем мы повторим построенные схемы на языке описания аппаратуры SystemVerilog и промоделируем их на программе-симуляторе. Но как мы можем воплотить их в микросхемы? Ведь заказ коммерческой микросхемы на фабрике очень дорогой? К счастью, существуют “перестраиваемые” программируемые логические интегральные схемы (ПЛИС), платы с которыми которые мы и будем использовать для наших занятий.


Помимо упражнений с арифметическими блоками и конечными автоматами, мы попробуем построить простой процессор, похожий по микроархитектуре на процессор Mongoose-V внутри космического корабля New Horizons, который год назад пролетел мимо Плутона.


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


Это круто, и я, если честно, немного завидую этим школьникам — в моем детстве такого не было.
Специально для данного мероприятия мы написали небольшой процессор MIPS-архитектуры: schoolMIPS [L6], который планируется использовать в образовательном процессе. Он построен путем упрощения процессора Сары Харрис, описанного в H&H [L2]. Основные особенности:


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

В комплекте идет небольшая инструкция и слайды, описывающие построение процессорного ядра в стиле аналогичном H&H [L2].
Помимо написания процессора был выполнен достаточно масштабный перевод на русский язык различных образовательных материалов. Эту тему я затрагивать не буду, т.к. не участвовал, полагаю, что Юрий YuriPanchul в будущем об этом еще напишет.


Школа-семинар по цифровому дизайну и компьютерной архитектуре в Томске


С 18 по 22 сентября на базе Томского государственного университета пройдет Школа–семинар по цифровому дизайну и компьютерной архитектуре в эпоху систем на кристалле (SoC) и интернет технологий (IoT). Предварительная программа школы и список участников опубликованы на сайте [L8]. Там будет выступать и ваш покорный слуга: планирую рассказать про AHB-Lite, подключение периферии к MIPSfpga, работу с SDRAM — это со сцены. А неофициально можем обсудить Linux, подключение отладчика и любой код, который я принес в MIPSfpga-plus. Приходите!


Запуск Linux на MIPSfpga-plus


Лабораторные работы MIPSfpga описывают запуск Linux на СнК, построенной с использованием Xilinx-специфических периферийных модулей. Вкупе с уже упомянутой выше проблемой с доступом к платам это создавало некоторые трудности. Необходимым минимумом для запуска ОС Linux являются: MMU (есть в составе MIPS fpga), достаточный объем памяти и UART. При этом большая часть работ по портированию системы уже выполнена Imagination Technologies, соответствующий код включен в основную ветку ядра [L9]. Буквально неделю назад у меня получилось запустить Linux на Terasic DE10-Lite и не скажу, что необходимый для этого патч получился очень сложным.
Основные особенности:


  • конфигурация системы: ПЛИС Altera MAX10, SDRAM 64Мб,MIPSfpga-plus, UART16550;
  • ядро загружается в память с помощью EJTAG [L10];
  • mmc/sdcard пока не поддерживаются, поэтому о загрузке с карты памяти говорить не приходится. С другой стороны, в лабораторных работах MIPSfpga о загрузки с флешки речь также не идет.

Лог загрузки
Linux version 4.12.2+ (stas@ubuntu) (gcc version 4.9.2 (Codescape GNU Tools 2016.05-03 for MIPS MTI Linux) ) #67      Wed Jul 19 00:07:19 MSK 2017
CPU0 revision is: 00019e60 (MIPS M14KEc)
MIPS: machine is terasic,de10lite
Determined physical RAM map:
 memory: 04000000 @ 00000000 (usable)
Initrd not found or empty - disabling initrd
Primary instruction cache 4kB, VIPT, 2-way, linesize 16 bytes.
Primary data cache 4kB, 2-way, VIPT, no aliases, linesize 16 bytes
Zone ranges:
  Normal   [mem 0x0000000000000000-0x0000000003ffffff]
Movable zone start for each node
Early memory node ranges
  node   0: [mem 0x0000000000000000-0x0000000003ffffff]
Initmem setup node 0 [mem 0x0000000000000000-0x0000000003ffffff]
Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 16256
Kernel command line: console=ttyS0,115200
PID hash table entries: 256 (order: -2, 1024 bytes)
Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
Memory: 60512K/65536K available (1827K kernel code, 97K rwdata, 320K rodata, 948K init, 184K bss, 5024K reserved     , 0K cma-reserved)
NR_IRQS:8
clocksource: MIPS: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 38225208935 ns
sched_clock: 32 bits at 50MHz, resolution 20ns, wraps every 42949672950ns
Console: colour dummy device 80x25
Calibrating delay loop... 10.81 BogoMIPS (lpj=21632)
pid_max: default: 32768 minimum: 301
Mount-cache hash table entries: 1024 (order: 0, 4096 bytes)
Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes)
devtmpfs: initialized
clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns
futex hash table entries: 256 (order: -1, 3072 bytes)
clocksource: Switched to clocksource MIPS
random: fast init done
workingset: timestamp_bits=30 max_order=14 bucket_order=0
Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
console [ttyS0] disabled
b0400000.serial: ttyS0 at MMIO 0xb0401000 (irq = 0, base_baud = 3125000) is a 16550A
console [ttyS0] enabled
Freeing unused kernel memory: 948K
This architecture does not have kernel memory protection.
mount: mounting devpts on /dev/pts failed: No such device
mount: mounting tmpfs on /dev/shm failed: Invalid argument
mount: mounting tmpfs on /tmp failed: Invalid argument
mount: mounting tmpfs on /run failed: Invalid argument
Starting logging: OK
Initializing random number generator... done.
Starting network: ip: socket: Function not implemented
ip: socket: Function not implemented
FAIL

Welcome to MIPSfpga
mipsfpga login: root
Jan  1 00:00:09 login[43]: root login on 'console'
# uname -a
Linux mipsfpga 4.12.2+ #67 Wed Jul 19 00:07:19 MSK 2017 mips GNU/Linux
# free -m
             total       used       free     shared    buffers     cached
Mem:            60          3         56          0          0          2
-/+ buffers/cache:          0         59
Swap:            0          0          0

В ближайшее время планирую подготовить небольшое HOWTO о том, как воспроизвести эти результаты. А большую статью, наверное, напишу после добавления в MIPSfpga-plus модуля для работы с mmc/sdcard, допиливания загрузчика и отладки всего, что необходимо для автономного запуска. Если кому-то нужно "вот прямо сейчас" — дайте знать.


MIPSfpga-plus и АЦП Altera MAX10


В июне закончил работу по интеграции АЦП, который есть на борту Altera MAX10, в MIPSfpga-plus. Соответствующий код добавлен в основную ветку проекта [L11], с документацией [L12] и примером [L13]. Модуль, фактически, является конвертером между шиной AHB-Lite и Avalon-ST, выполненный учетом специфики конкретного АЦП. Он очень прост по архитектуре — старался сделать его программный интерфейс максимально похожим на АЦП микроконтроллера Atmel ATmega88.
Не обошлось, конечно, и без подводных камней, так на используемой в Terasic DE10-Lite ПЛИС доступно 2 канала АЦП (с независимым наборов вводов на каждом), при разводке этих вводов второй канал оказался целиком заземлен, т.о. параллельная работа каналов на DE10-Lite — невозможна:


Terasic DE10-Lite ADC pins


Хочется верить, что в академических проектах будет чуть чаще использоваться MIPSfpga-plus там, где до этого ради встроенного АЦП нужно было брать микроконтроллер или конфигурацию MAX10 + NIOS-II.
Опять же, нужна ли отдельная статья, где детально разбирается работа с АЦП? Или для того, чтобы разобраться, вам достаточно уже приведенных мной ссылок на исходный код модуля, примера и документацию?


Логотип MIPSfpga-plus


Как вы считаете, проект MIPSfpga-plus достаточно созрел для того, чтобы у него появился свой узнаваемый логотип? Мне, наверное, потратив на него не один десяток часов, уже хочется, чтобы он ассоциировался с какой-нибудь позитивной картинкой. Почему-то в голову приходит только Большой Ух из одноименного мультика (см. КДПВ), возможно, что из-за его конфедератки, которая хорошо ассоциируется с изначально образовательной направленностью проекта. Да и в принципе данный персонаж мне глубоко симпатичен.
Что думаете на эту тему? Может быть вы сможете предложить какой-то альтернативный вариант или, вдруг, среди читателей есть художник, который может изобразить "мультипликационного персонажа, отдаленно напоминающего Большого Уха, но не до степени смешения"?


Благодарности


Автор выражает благодарность коллективу переводчиков учебника Дэвида Харриса и Сары Харрис «Цифровая схемотехника и архитектура компьютера» [L2], компании Imagination Technologies [L1] за академическую лицензию на современное процессорное ядро и образовательные материалы, а также персонально Юрию Панчулу YuriPanchul за его работу по популяризации MIPSfpga. Отдельное большое спасибо Александру Романову (ВШЭ) [L15] за дельный и скрупулезный подход к микроархитектуре schoolMIPS, а также всем участникам списка рассылки Young Russian Chip Architects, принявшим участие в обсуждении.


Ссылки


[L1] — Пресс-релиз о выходе MIPSfpga 2.0;
[L2] — Цифровая схемотехника и архитектура компьютера;
[L3] — Workshop on Computer Architecture Education (Toronto);
[L4] — Проект MIPSfpga-plus на github;
[L5] — Летняя школа программистов (Новосибирск);
[L6] — Летняя школа программистов (Новосибирск). Учебная программа;
[L7] — Проект schoolMIPS на github;
[L8] — Школа–семинар по цифровому дизайну и компьютерной архитектуре (Томск);
[L9] — Поддержка MIPSfpga в ядре Linux;
[L10] — MIPSfpga и внутрисхемная отладка;
[L11] — MIPSfpga-plus. Модуль поддержки АЦП Altera MAX10;
[L12] — MIPSfpga-plus. Модуль поддержки АЦП Altera MAX10. Документация;
[L13] — MIPSfpga-plus. Модуль поддержки АЦП Altera MAX10. Пример;
[L14] — Practical experiences based on MIPSfpga;
[L15] — Профиль Александра Романова на сайте ВШЭ.

О чем написать в следующий раз

Никто ещё не голосовал. Воздержавшихся нет.

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

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333722/


Метки:  

Visual Tcl. Разработка графического пользовательского интерфейса для утилит командной строки (Продолжение)

Среда, 19 Июля 2017 г. 20:26 + в цитатник
В предыдущей статье в качестве инструментария для создания графического интерфейса для утилит командной строки на базе Tcl/Tk был рассмотрен конструктор tkBuilder. Конструктор хорош, но как было отмечено в статье обладает и рядом недостатков, главный из которых нет поддержки UTF-8, а следовательно, и русского алфивита. Еще один недостаток был отмечен пользователем merlin-vrn. Это поддержка на сегодняшний день только Tcl/Tk версии 8.4.

Но вот в комментарии от пользователя svk28 был упомянут конструктор Visual Tcl на базе Tck/Tk:
image

После предварительного ознакомления было решено использовать его в деле, тем более что предыдущий материал фактически остался незавершенным, если смотреть на него с точки зрения объявленной цели – дать графическую оболочку утилитам командной строки с помощью которых можно получить доступ к облачному криптографическому токену PKCS#11. Поэтому настала пора разработать графический интерфейс и для второй утилиты, а именно ls11cloud_config:
bash-4.3$ /usr/local/bin64/ls11cloud_config
LS11CLOUD User Utility 
usage:  /usr/local/bin64/ls11cloud_config  [-p ] [-n ]    
Commands:
   register    - register new user on the server 
        duplicate    - duplicate user account on other computer 
        change_pswd - change SESPAKE authentication password 
        status      - display current configuration data 
        log         - display server log file 
        recreate    - re-create token to initial empty state 
        unregister  - remove all user files from the server 
NB: Don't use non-latin letters to avoid encoding problems! 
Copyright(C) Ltd (http://soft.lissi.ru) 2017 
bash-4.3$

Первым делом было проверено какую версию Tcl/Tk поддерживает Visual Tcl. Оказалось, что версия 8.6, которая установлена на моем компьютере, поддерживается конструктором Visual Tcl:

bash-4.3$ cd ../vtcl.vtcl-8.6-master
bash-4.3$ ./configure 
Using /bin/wish8.6
bash-4.3$

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

image

Но осмотревшись оказалось что пару окон (новостную ленту – Visual Tcl News и знаете ли вы это – Did you know)можно закрывать без всякого ущерба для работы. И оказывается, что окон уже и не так много и при необходимости их можно периодически скрывать.
Приятной неожиданностью стало наличие своего мольберта для для каждой виджеты класса toplevel:

image

В нашем проекте потребовалось три виджеты класса toplevel и соответственно в нашем распоряжении было три мольберта:

1. Виджета GUICloudConfig, основное окно с функциями утилиты ls11cloudconfig (см. выше);
2. Виджета Password, которая так или иначе задействована во всех функциях:

image

3. Виджета CloudToken, которая задействуется в функциях Регистрации и Дублирования облачного криптографического токена:

image

И никаких проблем с «великим, могучим, правдивым и свободным русским языком!» (И.С. Тургенев).
Отметим одну особенность дизайнера Visual Tcl. Она связана с редактированием функций. Изменения, вносимые в функции, не попадут в проект до тех пор, пока не будет закрыто окно, в котором редактируется функция:

image

Отметим также, что проект в понимании Visual Tcl сохраняется как файл Tcl/Tk (*.tcl) и его в любой момент можно выполнять самостоятельно без дополнительных преобразований. Обратное не верно, далеко не каждый файл Tcl/Tk конструктор будет рассматривать как свой проект.
На еще одну очень полезную вещь навел проект Visual Tcl – возможность сохранения проекта в бинарном коде. Для этой цели задействуется утилита freewrap , которая превращает скрипты Tcl / Tk в однофайловые исполняемые программы. Так и мы оба скрипта, реализующих графический интерфейс для утилит p11conf и ls11cloudconfig преобразовали в исполняемые программы:

bash-4.3$ ls 
GUITKP11Conf.tcl  LS11CLOUD_CONFIG.tcl 
bash-4.3$
bash-4.3$ freewrap GUITKP11Conf.tcl
bash-4.3$ freewrap LS11CLOUD_CONFIG.tcl
bash-4.3$ ls 
GUITKP11Conf      LS11CLOUD_CONFIG      
GUITKP11Conf.tcl  LS11CLOUD_CONFIG.tcl 
bash-4.3$


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

Большое спасибо пользователю svk28 за его подсказку!
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333742/


Метки:  

Локализацию можно автоматизировать: опыт использования Lokalise в боевых условиях

Среда, 19 Июля 2017 г. 20:17 + в цитатник
Lokalise — это сервис по локализации проектов, который позволяет автоматизировать процесс перевода элементов UI в мобильных приложениях, ПО и на вебе. Обычно в качестве первого шага вы загружаете свои файлы локализации на наш сервис, а дальше тексты правятся менеджерами продукта и переводятся либо вашими переводчиками, либо наемной командой уже на стороне Lokalise.

image

После редактирования и перевода вы можете скачать файлы через веб-интерфейс или интегрировать с помощью мобильных SDK, API или утилиты CLI. В случае веба возможна вставка, например, html-ключей, которые будут «подтягивать» локализованный текст в ваш проект. Платформа удобна для команд, которые не готовы постоянно влезать в проекты «на живую» ради правок в локализации, видоизменяя лишь конкретные метки (их ещё называют ключами) на стороне Lokalise.

В этой статье мы расскажем о применении Lokalise для локализации и перевода проектов компанией-разработчиком блокчейн-продуктов Ambisafe. Опытом использования Lokalise с нами поделился Алексей Матиасевич – менеджер проектов Ambisafe.

Команда Ambisafe занимается разработкой web-проектов и программного обеспечения с 2010 года. С этого же времени в недрах команды озаботились вопросом локализации на пару-тройку базовых языков, отличных от английского.

Изначально команда использовала ручную локализацию, идя по пути наименьшего сопротивления. «Да, мы использовали ручную локализацию», — говорит Алексей, «многие веб-разработчики до сих пор так делают, и будут делать еще долгое время». Но каждый, кто сталкивался с вопросами локализации, понимает, насколько нестройным и трудоемким является этот процесс, выполняемый вручную. В какой-то момент команда Ambisafe перешла на использование Lokalise, причем настолько давно, что по утверждению Алексея «хвостов уже не найти».

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

Однако в портфолио команды есть и проекты, которые они локализовали на десяток языков. Среди них Polybius — проект по созданию регулируемого банка для цифрового поколения, который в рамках ICO собрал эквивалент $31 млн в различных фиатных и криптовалютах. В общей сложности проект был локализован на десять основных языков.

Сильные стороны Lokalise


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


Скриншот системы управления переводчиками

Но не обходится и без подводных камней. Так, использование Lokalise требует определенной сноровки и опыта от Front-end разработчиков.

«Для перевода нескольких абзацев нужно либо разбивать тексты на блоки и переводить их отдельно, либо использовать специальное форматирование текста для перевода — вставки html-тегов», — приводит пример из практики Алексей. «Опять же, далеко не у всех Front-end разработчиков с первого раза получается работать с сайтами, локализованными через этот сервис, так как в коде используются специальные конструкции для определения «ключей». Как показывает наш опыт, в некоторых случаях код просто ломают, и восстанавливать корректную работу переводов приходится более опытным коллегам».

Процесс, о котором говорит Алексей, и есть создание файлов локализации. При в­­­­ёрстке простых веб-страниц разработчики действительно могут хардкодить тексты, и для дальнейшей интеграции с любой платформой их будет необходимо сегментировать. А вот для сложных веб-страниц и веб-приложений использование файлов локализации изначально — это единственный грамотный подход. Надо сказать, что Ambisafe не единственная компания, которая борется с захардкоденными текстами, поэтому сейчас мы отлаживаем наш новый инструмент для автоматического «заворачивания» текста в метки (ключи).


Панель управления блоками для вставки фронт-эндерами

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

«Этот сервис, прежде всего, экономит время на самом процессе перевода и прикручивания их к сайту. Нужно сказать, что стоимость переводов на сервисе не самая демократичная (около половины команд переводят сами или приглашают своих переводчиков, а остальные заказывают у нас — прим. Lokalise), однако это компенсируется экономией на параллельных активностях», — утверждает менеджер Ambisafe. Например, экономия возникает на поддержке сайта — нет необходимости делать несколько версток для отдельных языков, контент меняется централизованно, проще управлять изменениями, так как переводы централизованы.

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


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

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

Что дальше


В ближайших статьях мы расскажем о теории и практике локализации iOS- и Android- приложений, где мультиплатформенность, универсальные маркеры вставки и мобильные Lokalise SDК творят небольшие чудеса.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333744/


[Из песочницы] Аудит ИТ-инфраструктуры — как быть новичку

Среда, 19 Июля 2017 г. 18:21 + в цитатник

Привет, %username%! Готов поспорить, что рано или поздно все сисадмины относительно небольших компаний сталкиваются с такой волшебной задачей от руководства, как составление проекта развития ИТ-инфраструктуры компании. Особенно если тебе предложили должность и сразу же попросили составить план развития и бюджетирования. Вот и мне однажды поставили такую задачу. О всех подводных камнях, с которыми можно столкнуться, я и напишу. Всем заинтересовавшимся велкам под кат!


Сразу поясню, что вы тут не найдете советов о том, какое оборудование выбирать для тех или иных решений, какие программные продукты выбирать, open source или платное ПО, с какими интеграторами общаться стоит, а с какими нет. Это все полностью индивидуально и будет напрямую зависеть от вас и того, что в итоге вы хотите — залатать дыры в текущем корыте или построить ИТ-инфраструктуру таким образом, чтобы любая задача сводилась к нажатию кнопки “СДЕЛАТЬ ХОРОШО” (да я ленивый).


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


Вот собственно примерный список проблем, с которыми можно столкнуться при проведении аудита ИТ-инфраструктуры:


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


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


3. Отсутствие четкого (документированного) описания текущей инфраструктуры — увы (!) этого не было никогда ранее. Никто и никогда не составлял банальную карту сети офиса. Не описывал как организована связь между филиалами (коих более 10 штук по всей стране). Я уже не говорю про банальную маркировку кабелей на маршрутизаторах.


4. Полное отсутствие документации — вообще! Абсолютно никакой документации не велось в отделе никогда. И это категорически печально. Ведь банальные копии договоров (на телефонию, интернет, обслуживание 1С, аренду хостинга и прочее) хотя бы в электронном виде должны быть в отделе. И это одно из обязательных условий, ведь любой сотрудник отдела ИТ должен знать, к кому обратиться в случае если упал интернет в другом регионе (где время +3 к Москве).


5. Отсутствие общей базы паролей — все пароли были разные и менялись от случая к случаю. Весь этот ворох приходилось держать в голове, т.к. “все что записано однажды — может быть и считано”. Для того, чтобы предоставить новому сотруднику определенный доступ, необходимо переписать в почте (или на бумажке) все логины и пароли и передать их лично ему. А если ты еще не правильно пароль вспомнил… Ужас!


6. Отсутствие информации о том, как все организованно в регионах — имелась информация лишь о том, сколько там человек, кто руководитель и… всё! Т.е. имелась просто абстракция под названием “Региональное представительство в городе Мухосранске, где сидит 15 человек”. Никто никогда не задавался вопросом, как там устроена сеть, какие у нее слабые места, как происходит доступ сотрудников представительства в сеть Интернет, как организован доступ сотрудников к сетевым ресурсам центрального офиса.


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


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


А теперь подробнее о том, как я советовал бы преодолевать все трудности


Я не стану напоминать о том, что необходимо сделать инвентаризацию для того, чтобы понимать с чем работаешь, что является устаревшим, что можно заменить на более производительное. Это обязательное мероприятие. А вот о том, что после переписи всего оборудования надо все разделить всё на категории (активное сетевое, workstaion, bussiness-critical servers and service) напомню. При наличии доступа к административной панели сделать бэкапы конфигураций, описать “что”, “зачем” и “для чего” настроено в конкретной железке, переписать все сетевые адреса серверов, управляемых железок (да простят меня господа сетевики), сетевых хранилищ, принтеров и всего, что имеет доступ к сети (ну кроме рабочих станций).


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


Анализ железячной составляющей это одно из важных мероприятий. Необходимо понимать, насколько актуально на текущий момент времени используемое железо (как сетевое и серверное, так и пользовательские ПК). Обычно на этом этапе выясняется (с поддержкой от бухгалтерии, а так же коммерческих отделов), что вся bussiness-critical информация хранится в виде документов Excell на сервере, у которого жесткие диски работают уже третий гарантийный срок (!) и все удивляются тому, что “файлы по сети медленно открываются” и сам сервер шумит дисками как больной психиатрии стучащий ложкой по кастрюле. А сетевые железки сняты с производства еще за год до того, как их купили в компанию и по отзывам они ужасны. Или например wi-fi в офисе поднят на точках доступа, которые по всем отзывам считаются такой дрянью, которую врагу не пожелаешь.


Далее, необходимо оценить текущие серверные мощности


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


Виртуализируйте все!


Когда парк ваших серверов и сервисов достигает критической массы и вы вынуждены заходя в серверную смотреть, что это за систменик или тыкаться по KVM в поисках нужного сервера, то вам явно требуется виртуализация. Все системы, которые можно запустить на виртуалке необходимо перевести в виртуальную среду (всяческие СКУДы, сервер корпоративного портала, корпоративное облако, etc). Современных, а главное удобных инструментов для этого предостаточно (VMware, Proxmox, Xen, Hyper-V). Просто определитесь с тем, что вам нужно/нравится/можно купить и запускайте в работу.


Виртуализацию в топку! Даешь только хардвер!


Не виртуализируйте критичные вещи — такие как шлюзы, маршрутизаторы, VPN-сервера используемые для аварийного доступа в сеть, сервера 1С (тут в меня могу полететь тухлые помидоры). Важно здраво оценивать все факторы, руководствуясь которыми вы принимаете решение о том, что загонять в виртуальную среду, а что нет. Идеальных решений не существует.


Организация сетей между филиалами


Вопрос довольно обширный и имеет множество решений. От самого простого — выделять каждому удаленному сотруднику логин и пароль для VPN, дорогого — арендовать L2-сеть у одного провайдера и до безумного — наставить самых различных сетевых железок от разных вендоров, с помощью которых организовать доступ в сеть на местах и доступ к сетевым ресурсам внутри компании (сетевые хранилища и т.п.). Оцените все “за” и “против” и примите верное и лучшее решение в конкретно вашем случае. Для простоты и понимания “что делать” и “как делать” смело приглашайте системных интеграторов и консультируйтесь с ними. За спрос не дадут по шее, а дадут понять как можно решить одну и ту же проблему разными способами (дешево и дорого). Уже после пары-тройки таких встреч вы сможете более точно и более четко описать для себя самого все свои хотелки и возможные способы их решения.


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


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


Правильно организуйте работу вашего отдела, особенно когда вас в отделе больше двух человек. Никогда не создавайте такую ситуацию, в которой какие-то вещи завязаны на одно человека. Это ваша точка отказа!


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


И запомните две вещи:


  1. Идеальной инструкции не существует!
  2. Идеальной защиты не существует!

P.S.: На этом все. Жду ваших комментариев и здравой критики.

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333732/


Метки:  

[Из песочницы] Пошаговый мануал как ввезти технику, на которую отсутствует нотификация ФСБ

Среда, 19 Июля 2017 г. 18:03 + в цитатник

Заметил, что на Хабре (да и в Рунете), практически нет инструкций о том, что делать, если на технику, заказанную из-за рубежа, отсутствует нотификация ФСБ. Хотел бы поделиться опытом, приобретенным в процессе доставки ноутбука из Америки. Инструкция под катом.


Краткая предыстория

Мой брат, решив сменить свой старый ноутбук, обратился ко мне за помощью в подборе модели. В одном из обзоров на сайте, в комментариях проскользнуло такое чудо инженерной мысли как LG Gram. Имея диагональ 15 дюймов, данный ноутбук весит меньше килограмма, имеет неплохую начинку и выглядит очень неплохо. В России данный ноутбук не продается, поэтому поиски продолжились на сайте Amazon. Изначально модель стоила около 1100 долларов, но я, имея годы опыта покупок за рубежом, решил подождать. В итоге цена упала до 830 долларов и решено было брать. Ноутбук успешно пришел на склад одного из mail-forward сервисов и был готов к отправке. Но тут начинается самое интересное. На почту приходит такое письмо:


Добрый день, %username%!

На предварительном согласовании данных о пересылаемых посылках с таможней, последняя не одобрила к отправке ноутбук из вашей посылки #****** из-за отсутствия на него нотификации ФСБ РФ. Поэтому мы не сможем отправить такую посылку методом ***.

Мы готовы отправить такую посылку только методами USPS Express/Priority без страховки. Однако важно понимать, что в таком случае есть риск возврата товара с таможни из-за отсутствия нотификации на устройство.

Советуем отменить отправку в разделе личного кабинета «Пакуется». После отмены отправки можно будет переоформить декларацию на USPS и создать новую исходящую посылку USPS Express/Priority.

Возможно, одним из решений в данный момент будет вернуть товар продавцу.

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


  1. Отправка обычной почтой в надежде, что мне повезет и посылку выборочно не просветит таможня
  2. Возврат товара и получение денег
  3. Получение нотификации и ввоз легально
  4. На май 2017 года появился еще один способ — сервисы, которые позволяют ввезти товары через туристов, заказав доставку на их адрес. Я такими не пользуюсь, но возможно кто то найдет полезным

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


Была рассмотрена куча вариантов, типа отправки через Беларусь, Украину с последующим привозом знакомыми и даже такие экзотические варианты как отправка контейнером с запчастями, но все они были неосуществимы. Например в РБ и на Украине таможенные лимиты ниже 100 долларов.


Итак, как ввезти технику на территорию РФ официально? Существует 2 способа:


  1. Получить нотификацию ФСБ
  2. Ввезти как юридическое лицо для личных нужд

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


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


Следующим был звонок в ФСБ, а именно ЦЛСЗ ФСБ России. Сразу хочу сказать, там работают достаточно вменяемые люди, которые все подробно объяснят и помогут правильно составить документы. Там мне сказали, что ИП действительно могут получить разрешение на ввоз техники для личного пользования. Порядок описан в данном документе. Для этого требуется отправить письмо на адрес канцелярии ЦЛСЗ ФСБ России (г.Москва. 107031, ул.Большая Лубянка, дом 1/3).


В письмо необходимо вложить:


  1. Заявление на имя начальника ЦЛСЗ ФСБ России
  2. Распечатка технических характеристик техники
  3. Ксерокопия паспорта
  4. Ксерокопия свидетельства о регистрации ИП и ИНН
  5. Заполненное заключение (Приложение № 1 к Решению Коллегии Евразийской экономической комиссии от 16 мая 2012 г. № 45)

Возможно список неполный, происходило это больше полугода назад, я что то мог упустить. Лучше все же позвонить в ЦЛСЗ ФСБ России и уточнить.


Заявление пишется в свободной форме, вот то, что писал я:


Заявление

Начальнику Центра по лицензированию, сертификации
и защите государственной тайны ФСБ России
Васюкову Юрию Константиновичу


Заявление


Я, индивидуальный предприниматель Иванов Иван Иванович, ИНН XXXX, ОГРНИП XXXX, ПАСПОРТНЫЕ ДАННЫЕ, на основании приложения №9 к решению коллегии Евразийской экономической комиссии от 21 апреля 2015г №30, для собственных нужд в качестве индивидуального предпринимателя в интернет-магазине Amazon приобрел ноутбук LG Gram 15" (модель 15Z960). В связи с тем, что производитель не дал нотификацию на данную модель, прошу дать разрешение на его ввоз. Данный ноутбук, исходя из спецификации на сайте производителя, содержит средства шифрования, входящие в WiFi модуль, модуль Bluetooth (характеристики прилагаются) и операционную систему Windows XX (указать номер нотификации с сайта ЕЭК). Других функций шифрования ноутбук не имеет. Полный список технических характеристик прилагается. Данный ноутбук необходим мне для решения личных задач в качестве индивидуального предпринимателя. Обязуюсь использовать его только для личных целей без предоставления услуг шифрования третьим лицам. Прошу выдать разрешение мне на руки (либо его пришлют по почте на адрес регистрации ИП). Контактный телефон XXXX


30.06.2017 Иванов Иван Иванович


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


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


В моем случае положительный ответ пришел через 3 недели. Дальше вы едете на ул. Ярцевская, д. 30 и получаете разрешение. Скан разрешения вкладывается в посылку mail-forward сервисом и освобождает вас от проблем с таможней.


Хотел бы посоветовать всем (то же мне сказали в ФСБ), кто хочет воспользоватся данным способом, сделать это до момента покупки, чтобы избежать длительного ожидания. В моем случае я купил ноутбук в конце ноября 2016, а получил его только в конце марта 2017.


Надеюсь данный мануал будет полезен.

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333730/


Метки:  

[Перевод] Starbucks следует открыть публичный доступ к своим API

Среда, 19 Июля 2017 г. 18:02 + в цитатник
Мобильное приложение Starbucks — один из самых известных кейсов в ecommerce. Автор материала — программист опытным путем доказывающий, почему стоит открыть API этого приложения.

image

Мотивация


Стоит отдать должное приложению Starbucks — оно просто отличное. Я использую его (как минимум) раз в день. В нем есть все, что мне нужно от отличного мобильного сервиса — кофе, плейлисты хитов 80-х в Spotify и возможность избежать живого общения с другими людьми. Я явно не одинок в своих предпочтениях, так как 20% операций Starbucks в США сейчас производится через мобильные телефоны.

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

Однако я не мог ждать и поэтому решил взять дело в свои руки.

Было нелегко


Приложение Starbucks оказалось крепким орешком. Несмотря на URL-адрес «openapi.starbucks.com», пришлось пробираться через серьезные дебри, прежде чем начать анализировать вызовы, совершаемые приложением. Как и для любого другого приложения, обрабатывающего платежи, Starbucks предпринял многочисленные меры безопасности для защиты API, используемых своим приложением, от несанкционированного использования. Вот некоторые из них:

  • SSL certificate pinning
  • Создание цифрового отпечатка атрибутов вашего мобильного телефона, чтобы понять, используете ли вы смартфон
  • Шифрование этого отпечатка с использованием AES, 256-битным ключом и псевдослучайным вектором инициализации
  • Подписание запросов с меткой текущего времени

Наблюдение за запросами сети


Для начала мне нужен был способ наблюдать за запросами и ответами, которыми обменивались приложение Starbucks и его сервера. Обычно я просто настраивал свой iPhone на Charles (или mitmproxy), и этого было достаточно.

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

image

Муахаха

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

image
Результат запроса о ближайшем магазине. Теперь вы знаете, где я работаю. Упс.

«Это легко», — думал я, — «Я просто размещу заказ, подключившись к прокси-серверу, и потом воспроизведу запросы!»

А вот и нет.

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

Вход в систему


Конечная точка OAuth, используемая приложением, перед выдачей токена проверяет три параметра:

  • Параметр строки запроса sig. Исследователь проблем безопасности Райан Пикрен выяснил, что это клиентский ключ, клиентский секретный ключ и текущая временная метка UNIX, конкатенированные вместе и прогнанные через функцию MD5-хэширования.
  • Параметр формы «deviceFingerprint». Это список различных атрибутов устройства в кодировке base64 и зашифрованный AES-256. Он также регулярно изменяется, поскольку текущее время и аптайм устройства включены в отпечаток.
  • HTTP-заголовок «X-Cbt». Еще одна строка секретного ключа в кодировке base64.

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

image

www.youtube.com/watch?v=o8ZnCT14nRc

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

image

Аналогичным образом удалось выяснить, как генерировать заголовок «X-Cbt». Для краткости изложения, я оставлю эту задачу вам :)

Заключение


После того, как я смог подписать и снять отпечатки со своих запросов на вход, я объединил все в небольшой модуль Node.js, который позволяет использовать некоторые основные функции API Starbucks. Хорошие новости: он (в основном) размещен здесь на GitHub!

Вуаля! Программируемый кофе.

image
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/322800/


Метки:  

[Перевод] XBRL: Просто о сложном - Глава 2. Что такое XBRL?

Среда, 19 Июля 2017 г. 17:53 + в цитатник

Метки:  

Летняя школа Wolfram 2017: рассказ участника

Среда, 19 Июля 2017 г. 17:32 + в цитатник

Обмен валюты: фиксируем курс для оффлайна в онлайне. Опыт ВТБ24

Среда, 19 Июля 2017 г. 17:32 + в цитатник
Обмен валюты – скучный и стандартный процесс, через который по тем или иным причинам проходит каждый. Кажется, технически там делать уже особо и нечего. ВТБ24 так не считает – мы как банк знаем о нескольких не лежащих на поверхности проблемах валютного обмена, с которыми можно столкнуться внезапно и в самый неподходящий момент. И решили их с помощью IT. Какие проблемы и как именно решили – читайте под катом.



ВТБ24 придумал новый сервис по обмену валюты – зафиксировав курс обмена в онлайне, можно прийти в офис и обменять валюту. Курс можно фиксировать на сайте банка или в чат-боте в мессенджере Фейсбук. Сервис позволяет клиентам зафиксировать курс обмена валюты на два рабочих дня, не считая день заказа, и совершить обмен наличной валюты, даже если курс на рынке изменится.

Сервис доступен клиентам с картой любого российского банка как для покупки, так и для продажи наличной валюты с фиксированием курса онлайн в режиме 24/7.

Как мы пришли к такой идее


Было несколько предпосылок к формированию идеи и создании нового сервиса.
Это самые распространенные вопросы в сезон отпусков у населения: «Где поменять валюту? Где лучший курс? Как поменять выгодно?», а также динамические изменения курсов валют и желание большей определенности со стороны клиентов.  

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

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

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

Таким образом новый сервис решает две проблемы: 

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

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

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

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

Технически процесс выглядит так. Пользователь заходит на сайт obmen.vtb24.ru или в чат-бот в Facebook и видит курс обмена, который он может зафиксировать на 2 дня.

Далее он вводит свои данные – фамилию, имя, при желании отчество и контактный телефон — и обязательно e-mail. Чат-бот сохраняет эти параметры для новых заказов — до момента, пока пользователь не попросит его удалить их. После ввода суммы валюты бот прописывает в чате срок, до которого нужно обменять валюту, и сумму (10% от суммы сделки), зарезервированную на счету клиента в качестве гарантии обмена до момента сделки — в случае отказа или просрочки банк удерживает ее.  Похожее резервирование делают путешественники, бронируя отели в интернете или арендуя автомобиль, предоставляя при этом средства на карте в качестве страхового депозита.

После подтверждения оформления заказа клиент переходит на платежную страницу, вводит реквизиты карты, и в случае, если операция резервирования средств пройдет успешно, на следующей странице получит подтверждение заказа (номер и параметры). Квитанция о заказе будет направлена на e-mail.




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



Как мы с этим справились?


Для разработки сайта и чат-бота мы привлекли партнёров из EPAM и InspiredGames и
попросили их прокомментировать технические особенности проекта.

Слово InspiredGames:

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

Однако:

  • банк даёт очень динамичные курсы. В рабочие часы они real-time отражают котировки на бирже, ночью (а сервис, естественно, круглосуточный) они тоже корректные. Банк передает в «движок» бота эти котировки, используя свой уникальный сервис.

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

При этом хоть бот и является интерфейсом, но реализованы и функции, обычно связываемые с back-end частью (указанное чуть выше получение актуальных курсов из банка, АРМ для его уполномоченных сотрудников, обсчёт данных по заказам, транзакционные действия с платежной системой, напоминания, аудит…).

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

Итак, прежде всего встал выбор – использовать ли какие-то фреймворки или конструкторы? Microsoft Bot Framework – замечательно, но нет коннектора к Viber и уж тем более к ВКонтакте. Другие конструкторы (по крайней мере, те, что мы нашли) не обладали нужной нам гибкостью. Поэтому приняли решение сделать всё самим. Что касается инфраструктурного решения, то посчитали, то лучше всего будет наше обычное и привычное использование RESTful Web API, соответственно – IIS, а для удобства – и MS SQL как СУБД (со всеми представлениями, разделением доступа, парой хранимых процедур и триггеров).

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

Первая: модульность.

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

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

Взаимодействие модулей, кстати, — тоже посредством REST API.

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

  • вынести всю специфику и настройки работы с разными мессенджерами на уровень коннекторов. Viber, в отличие от Facebook Messenger, позволяет менять шрифт и цвета кнопок в клавиатуре? Отлично, «покрасим» их в цвета в соответствии с brand book прямо в настройках коннектора. В Facebook Messenger есть «карусели»? Очень хорошо, настроим коннектор к нему так, чтобы в ответе с показом отделений эти отделения были представлены именно каруселью. А ядру бота «знать» об этих особенностях необязательно;
  • в случае необходимости — распространять бот на другие мессенджеры, только лишь разработав новый (новые) коннектор и добавив его в пул, не трогая ничего другого;
  • -если потребуется, разнести коннекторы и другие модули на разные хосты.

Вторая: концепция «текст-контекст-подтекст».

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

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

Пользователь шлет боту сообщение «заказ». Текст = «заказ», но мало знать текст. Ядро обращается к сервису данных и получает текущий контекст этого пользователя. (Справочно – у нас сейчас чуть более 200 контекстов, и они могут быть настроены без программирования).

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

Если же полученный контекст – «главное меню», то нужен еще и подтекст. А именно, ядро получает от сервиса данных подтекст, состоящий из совокупности формальных (как в паспорте) фамилии, имени, отчества и адреса электронной почты этого пользователя. И теперь ответ бота зависит от подтекста. Если такой подтекст непуст (а это означает, что пользователь ранее его боту сообщил), то бот предложит использовать его (или изменить в случае необходимости) и сделать заказ. Если же такой подтекст пуст, то бот как условие для того, чтобы сделать заказ, выдаст необходимость сообщить эти данные. И когда данные будут получены, появится и нужный подтекст, и заказ можно будет сделать. Следующий контекст – «все данные пользователя получены, продолжаем заказ». Ясно, что при всём этом накапливается история (которая, в свою очередь, будет использована для получения нового подтекста).

Отлично, но где же NLP? Верно, NLP (Natural Language Processing, обработка естественного языка) сейчас очень модная аббревиатура. Но вот только пока даже здесь, на Habrahabr, иногда обработку естественного языка путают с нейролингвистическим программированием. И, как и NLP — «программирование», NLP – обработка русского сейчас работает не так хорошо, как хотелось бы. Вдобавок есть ещё одна тонкость – по нашему мнению (и по мнению других экспертов), пользователь не хочет общаться с ботом как с человеком. Он понимает, что это – программа, и хочет получить UI как с программой – кнопки, цвета, картинки…

Но если у Вас есть лимон, то можно из него сделать лимонад. Именно поэтому мы:
— предпочли сделать «командный» (а не в чистом виде чат-) бот;
— используем сервис NLP как модуль (сервис для ядра, как было описано выше), позволяющий вместе с контекстом и подтекстом разобрать по тексту, чего же хочет пользователь. Этот модуль (в зависимости от контекста!) нам возвращает массив объектов, которые анализируются ядром. Простой пример – если контекст «оформление заказа на стадии выбора основных параметров обмена», то на текст «500 долларов» именно этот сервис выдаст массив:

{  
   "deal_candidates":  
   [
 {
"direction": "buy", 
"amount":500,
"ISOCode": "USD"},
{
"direction": "sell", 
"amount":500,
"ISOCode": "USD"}
]
}

А уже по этому массиву ядро бота спросит «выберите, что хотите».

Итог нашего опыта:

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

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

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

ВТБ24 в дальнейшем планирует выпустить чат-боты во всех доступных мессенджерах (добавим Вайбер и Вконтакте, а также надеемся дождемся открытия API WhatsApp).

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

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

Фиксирование оффлайнового курса в онлайне — это новый важный канал предоставления услуг населению.

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

Для ВТБ24 это также отличная возможность поиграть и протестировать новые технологии, чтобы определить вектор дальнейшего развития.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333724/


Метки:  

Динамическая инструментация — не просто, а тривиально*: пишем yet another инструментацию для American Fuzzy Lop

Среда, 19 Июля 2017 г. 17:26 + в цитатник

(*) На самом деле, не совсем.
Наверное, многие слышали про Valgrind — отладчик, который может сказать, где в вашей нативной программе утечка памяти, где ветвление зависит от неинициализированной переменной и многое другое (а ведь кроме memcheck, у него есть и другие режимы работы). Внутри себя эта чудо-программа перемалывает нативный код в некий промежуточный байткод, инструментирует его и генерирует новый машинный код — уже с run-time проверками. Но есть проблема: Valgrind не умеет работать под Windows. Когда мне это понадобилось, поиски привели меня к аналогичной утилите под названием DrMemory, также с ней в комплекте был аналог strace. Но речь не столько о них, сколько о библиотеке динамической инструментации, на базе которой они построены, DynamoRIO. В какой-то момент я заинтересовался этой библиотекой с точки зрения написания собственной инструментации, начал искать документацию, набрёл на большое количество примеров и был поражён тем, что простенькую, но законченную инструментацию вроде подсчёта инструкций вызова можно написать буквально в 237 строк сишного кода, 32 из которых — лицензия, а 8 — описание. Нет, это, конечно не "пишем убийцу Valgrind в 30 строк кода на JavaScript", но сильно проще, чем то, что можно представить для подобной задачи.


В качестве примера давайте напишем уже четвёртую реализацию инструментации для фаззера American Fuzzy Lop, о котором недавно уже писали на Хабре.


Что такое AFL


AFL — это инструмент для поиска багов и уязвимостей на основе guided fuzzing, собранный из железобетонных костылей эвристик, реализованных максимально тривиальным и эффективным способом. Вот так смотришь на инструмент, способный, наблюдая за поведением libjpeg, синтезировать валидные джипеги, и поражаешься, что всё это сделано на основе не такой уж и заумной механики. Вкратце, для полноценной работы AFL целевой бинарник должен быть инструментирован таким образом, чтобы в процессе выполнения собирать рёберное покрытие: представим себе каждый базовый блок (basic block, что-то вроде последовательности инструкций от метки и до ближайшей инструкции перехода) в качестве вершины графа. Рёбра — это возможные пути передачи управления между ББ. Соответственно, AFL интересует то, какие переходы и в каком примерно количестве происходили между базовыми блоками программы.


Основной способ инструментации в AFL — статическая на этапе компиляции с помощью обёрток afl-gcc / afl-g++ или их аналогов для clang. Что забавно, afl-gcc подменяет вызываемую команду as на обёртку, переписывающую ассемблерный листинг, сгенерированный компилятором. Есть и более продвинутый вариант, называемый llvm mode, который честно встраивается в процесс компиляции (производимой с помощью LLVM, естественно) и, теоретически, должен поэтому давать большую производительность генерируемого кода. Наконец, для фаззинга уже скомпилированных бинарников есть qemu mode — патч к QEMU в режиме эмуляции одного процесса, добавляющий необходимую инструментацию (изначально этот режим работы QEMU предназначался, чтобы запускать отдельные процессы, собранные для другой архитектуры, используя хостовое ядро).


Что такое DynamoRIO


DynamoRIO — это система динамической инструментации (то есть она инструментирует уже скомпилированные бинарники прямо во время выполнения), работающая на Windows, Linux и Android на архитектурах x86 и x86_64, а также ARM (поддержка AArch64 есть в release candidate версии 7.0). В отличие от QEMU, она предназначена не для исполнения программ "близко к тексту" на чужой архитектуре, а для лёгкого создания собственных инструментаций, модифицирующих поведение программы на родной архитектуре. При этом ставится цель по возможности не портить оптимизированный код. К сожалению, я так и не нашёл способ, при котором клиенты (так называются пользовательские библиотеки инструментации) могли бы не знать о целевом наборе инструкций (кроме каких-то тривиальных случаев, где достаточно кроссплатформенных обёрток для базовых инструкций), поскольку не происходит конверсии "машинный код -> байткод — [инструментация] -> новый байткод -> инструментированный машинный код". Вместо этого на каждый транслируемый базовый блок происходит передача клиенту списка декодированных инструкций, который он может изменять и дополнять с помощью удобных функций и макросов. То есть в машинных кодах программировать не нужно, но набор инструкций x86 (или другой платформы) знать, скорее всего, придётся.


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


DRK is DynamoRIO as a loadable Linux Kernel module. When DRK is loaded, all kernel-mode execution (system calls, interrupt & exception handlers, kernel threads, etc.) happens under the purview of DynamoRIO whereas user-mode execution is untouched — the inverse of normal DynamoRIO, which instruments a user-mode process and doesn't touch kernel-mode execution.

Тестовая программа


Для начала посмотрим, на что в принципе способен AFL. Нет, мы не будем брать уязвимую версию какой-нибудь библиотеки и ждать часы или сутки. Для теста напишем максимально тупую программу, которая разыменовывает нулевой указатель, если на stdin подать ей строку, начинающуюся с букв NULL. Это, конечно, не синтез джипега из ниоткуда, но зато и ждать почти не нужно.


Итак, скачаем AFL отсюда и соберём его. Как вы уже, наверное, догадались, собирать будем под GNU/Linux. Впрочем, другие Unix-like системы и Юниксы вроде Mac OS X тоже должны работать. Возьмём небольшую программку:


#include 
#include 

volatile int *ptr = NULL;
const char cmd[] = "NULL";

int main(int argc, char *argv[]) {
    char buf[16];
    fgets(buf, sizeof buf, stdin);
    if (strncmp(buf, cmd, 4)) {
        return 0;
    }
    *ptr = 1;
    return 0;
}

Скомпилируем её и запустим фаззинг:


$ export AFL_PATH=~/tmp/build/afl-2.42b/
$ # Запустим стандартную обёртку, которая статически добавит инструментацию
$ $AFL_PATH/afl-gcc example-bug-libc.c -o example-bug-libc
$ # Создадим какой-нибудь пример входного файла (можно несколько)
$ mkdir input
$ echo test > input/1
$ # Запустим фаззер
$ $AFL_PATH/afl-fuzz -i input -o output -- ./example-bug-libc

И что же мы видим:



Как-то оно не работает… Обратите внимание на строчку last new path: AFL ругается, что по прошествии 91 тысячи запусков он так и не нашёл новый путь. На самом деле это вполне логично: напомню, мы использовали статическую инструментацию на этапе вызова ассемблера. Основное же сравнение делает функция из libc, которая не инструментирована, и поэтому не получится посчитать количество совпавших символов. Так я думал, пока не решил это проверить, но оказалось, что наш бинарник не импортирует функцию strncmp. Судя по выводу objdump -d, компилятор просто сгенерировал на месте strncmp инструкцию с префиксом вместо цикла, куда можно было бы впихнуть инструментацию.


Инструментированная функция main со strncmp
00000000000007f0 <.plt.got>:
 7f0:   ff 25 82 17 20 00       jmpq   *0x201782(%rip)        # 201f78 <getenv@glibc_2.2.5>
 7f6:   66 90                   xchg   %ax,%ax
 7f8:   ff 25 8a 17 20 00       jmpq   *0x20178a(%rip)        # 201f88 <_exit@GLIBC_2.2.5>
 7fe:   66 90                   xchg   %ax,%ax
 800:   ff 25 8a 17 20 00       jmpq   *0x20178a(%rip)        # 201f90 <write@glibc_2.2.5>
 806:   66 90                   xchg   %ax,%ax
 808:   ff 25 8a 17 20 00       jmpq   *0x20178a(%rip)        # 201f98 <__stack_chk_fail@GLIBC_2.4>
 80e:   66 90                   xchg   %ax,%ax
 810:   ff 25 8a 17 20 00       jmpq   *0x20178a(%rip)        # 201fa0 <close@glibc_2.2.5>
 816:   66 90                   xchg   %ax,%ax
 818:   ff 25 8a 17 20 00       jmpq   *0x20178a(%rip)        # 201fa8 <read@glibc_2.2.5>
 81e:   66 90                   xchg   %ax,%ax
 820:   ff 25 92 17 20 00       jmpq   *0x201792(%rip)        # 201fb8 <fgets@glibc_2.2.5>
 826:   66 90                   xchg   %ax,%ax
 828:   ff 25 9a 17 20 00       jmpq   *0x20179a(%rip)        # 201fc8 <waitpid@glibc_2.2.5>
 82e:   66 90                   xchg   %ax,%ax
 830:   ff 25 a2 17 20 00       jmpq   *0x2017a2(%rip)        # 201fd8 <shmat@glibc_2.2.5>
 836:   66 90                   xchg   %ax,%ax
 838:   ff 25 a2 17 20 00       jmpq   *0x2017a2(%rip)        # 201fe0 <atoi@glibc_2.2.5>
 83e:   66 90                   xchg   %ax,%ax
 840:   ff 25 aa 17 20 00       jmpq   *0x2017aa(%rip)        # 201ff0 <__cxa_finalize@GLIBC_2.2.5>
 846:   66 90                   xchg   %ax,%ax
 848:   ff 25 aa 17 20 00       jmpq   *0x2017aa(%rip)        # 201ff8 <fork@glibc_2.2.5>
 84e:   66 90                   xchg   %ax,%ax

...

0000000000000850 
: 850: 48 8d a4 24 68 ff ff lea -0x98(%rsp),%rsp 857: ff 858: 48 89 14 24 mov %rdx,(%rsp) 85c: 48 89 4c 24 08 mov %rcx,0x8(%rsp) 861: 48 89 44 24 10 mov %rax,0x10(%rsp) 866: 48 c7 c1 04 6a 00 00 mov $0x6a04,%rcx 86d: e8 9e 02 00 00 callq b10 <__afl_maybe_log> 872: 48 8b 44 24 10 mov 0x10(%rsp),%rax 877: 48 8b 4c 24 08 mov 0x8(%rsp),%rcx 87c: 48 8b 14 24 mov (%rsp),%rdx 880: 48 8d a4 24 98 00 00 lea 0x98(%rsp),%rsp 887: 00 888: 53 push %rbx 889: be 10 00 00 00 mov $0x10,%esi 88e: 48 83 ec 20 sub $0x20,%rsp 892: 48 8b 15 77 17 20 00 mov 0x201777(%rip),%rdx # 202010 <stdin@@glibc_2.2.5> 899: 48 89 e7 mov %rsp,%rdi 89c: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax 8a3: 00 00 8a5: 48 89 44 24 18 mov %rax,0x18(%rsp) 8aa: 31 c0 xor %eax,%eax 8ac: e8 6f ff ff ff callq 820 <.plt.got+0x30> 8b1: 48 8d 3d dc 06 00 00 lea 0x6dc(%rip),%rdi # f94 8b8: b9 04 00 00 00 mov $0x4,%ecx 8bd: 48 89 e6 mov %rsp,%rsi 8c0: f3 a6 repz cmpsb %es:(%rdi),%ds:(%rsi) 8c2: 75 45 jne 909 8c4: 48 8d a4 24 68 ff ff lea -0x98(%rsp),%rsp 8cb: ff 8cc: 48 89 14 24 mov %rdx,(%rsp) 8d0: 48 89 4c 24 08 mov %rcx,0x8(%rsp) 8d5: 48 89 44 24 10 mov %rax,0x10(%rsp) 8da: 48 c7 c1 2d 5b 00 00 mov $0x5b2d,%rcx 8e1: e8 2a 02 00 00 callq b10 <__afl_maybe_log> 8e6: 48 8b 44 24 10 mov 0x10(%rsp),%rax 8eb: 48 8b 4c 24 08 mov 0x8(%rsp),%rcx 8f0: 48 8b 14 24 mov (%rsp),%rdx 8f4: 48 8d a4 24 98 00 00 lea 0x98(%rsp),%rsp 8fb: 00 8fc: 48 8b 05 1d 17 20 00 mov 0x20171d(%rip),%rax # 202020 903: c7 00 01 00 00 00 movl $0x1,(%rax) 909: 0f 1f 00 nopl (%rax) 90c: 48 8d a4 24 68 ff ff lea -0x98(%rsp),%rsp 913: ff 914: 48 89 14 24 mov %rdx,(%rsp) 918: 48 89 4c 24 08 mov %rcx,0x8(%rsp) 91d: 48 89 44 24 10 mov %rax,0x10(%rsp) 922: 48 c7 c1 8f 33 00 00 mov $0x338f,%rcx 929: e8 e2 01 00 00 callq b10 <__afl_maybe_log> 92e: 48 8b 44 24 10 mov 0x10(%rsp),%rax 933: 48 8b 4c 24 08 mov 0x8(%rsp),%rcx 938: 48 8b 14 24 mov (%rsp),%rdx 93c: 48 8d a4 24 98 00 00 lea 0x98(%rsp),%rsp 943: 00 944: 31 c0 xor %eax,%eax 946: 48 8b 54 24 18 mov 0x18(%rsp),%rdx 94b: 64 48 33 14 25 28 00 xor %fs:0x28,%rdx 952: 00 00 954: 75 40 jne 996 956: 66 90 xchg %ax,%ax 958: 48 8d a4 24 68 ff ff lea -0x98(%rsp),%rsp 95f: ff 960: 48 89 14 24 mov %rdx,(%rsp) 964: 48 89 4c 24 08 mov %rcx,0x8(%rsp) 969: 48 89 44 24 10 mov %rax,0x10(%rsp) 96e: 48 c7 c1 0a 7d 00 00 mov $0x7d0a,%rcx 975: e8 96 01 00 00 callq b10 <__afl_maybe_log> 97a: 48 8b 44 24 10 mov 0x10(%rsp),%rax 97f: 48 8b 4c 24 08 mov 0x8(%rsp),%rcx 984: 48 8b 14 24 mov (%rsp),%rdx 988: 48 8d a4 24 98 00 00 lea 0x98(%rsp),%rsp 98f: 00 990: 48 83 c4 20 add $0x20,%rsp 994: 5b pop %rbx 995: c3 retq 996: 66 90 xchg %ax,%ax 998: 48 8d a4 24 68 ff ff lea -0x98(%rsp),%rsp 99f: ff 9a0: 48 89 14 24 mov %rdx,(%rsp) 9a4: 48 89 4c 24 08 mov %rcx,0x8(%rsp) 9a9: 48 89 44 24 10 mov %rax,0x10(%rsp) 9ae: 48 c7 c1 a8 dc 00 00 mov $0xdca8,%rcx 9b5: e8 56 01 00 00 callq b10 <__afl_maybe_log> 9ba: 48 8b 44 24 10 mov 0x10(%rsp),%rax 9bf: 48 8b 4c 24 08 mov 0x8(%rsp),%rcx 9c4: 48 8b 14 24 mov (%rsp),%rdx 9c8: 48 8d a4 24 98 00 00 lea 0x98(%rsp),%rsp 9cf: 00 9d0: e8 33 fe ff ff callq 808 <.plt.got+0x18> 9d5: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 9dc: 00 00 00 9df: 90 nop

То же, но без инструментации
0000000000000630 <.plt.got>:
 630:   ff 25 82 09 20 00       jmpq   *0x200982(%rip)        # 200fb8 <strncmp@glibc_2.2.5>
 636:   66 90                   xchg   %ax,%ax
 638:   ff 25 8a 09 20 00       jmpq   *0x20098a(%rip)        # 200fc8 <__stack_chk_fail@GLIBC_2.4>
 63e:   66 90                   xchg   %ax,%ax
 640:   ff 25 92 09 20 00       jmpq   *0x200992(%rip)        # 200fd8 <fgets@glibc_2.2.5>
 646:   66 90                   xchg   %ax,%ax
 648:   ff 25 aa 09 20 00       jmpq   *0x2009aa(%rip)        # 200ff8 <__cxa_finalize@GLIBC_2.2.5>
 64e:   66 90                   xchg   %ax,%ax

...

0000000000000780 
: 780: 55 push %rbp 781: 48 89 e5 mov %rsp,%rbp 784: 48 83 ec 30 sub $0x30,%rsp 788: 89 7d dc mov %edi,-0x24(%rbp) 78b: 48 89 75 d0 mov %rsi,-0x30(%rbp) 78f: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax 796: 00 00 798: 48 89 45 f8 mov %rax,-0x8(%rbp) 79c: 31 c0 xor %eax,%eax 79e: 48 8b 15 6b 08 20 00 mov 0x20086b(%rip),%rdx # 201010 <stdin@@glibc_2.2.5> 7a5: 48 8d 45 e0 lea -0x20(%rbp),%rax 7a9: be 10 00 00 00 mov $0x10,%esi 7ae: 48 89 c7 mov %rax,%rdi 7b1: e8 8a fe ff ff callq 640 <.plt.got+0x10> 7b6: 48 8d 45 e0 lea -0x20(%rbp),%rax 7ba: ba 04 00 00 00 mov $0x4,%edx 7bf: 48 8d 35 ce 00 00 00 lea 0xce(%rip),%rsi # 894 7c6: 48 89 c7 mov %rax,%rdi 7c9: e8 62 fe ff ff callq 630 <.plt.got> 7ce: 85 c0 test %eax,%eax 7d0: 74 07 je 7d9 7d2: b8 00 00 00 00 mov $0x0,%eax 7d7: eb 12 jmp 7eb 7d9: 48 8b 05 40 08 20 00 mov 0x200840(%rip),%rax # 201020 7e0: c7 00 01 00 00 00 movl $0x1,(%rax) 7e6: b8 00 00 00 00 mov $0x0,%eax 7eb: 48 8b 4d f8 mov -0x8(%rbp),%rcx 7ef: 64 48 33 0c 25 28 00 xor %fs:0x28,%rcx 7f6: 00 00 7f8: 74 05 je 7ff 7fa: e8 39 fe ff ff callq 638 <.plt.got+0x8> 7ff: c9 leaveq 800: c3 retq 801: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 808: 00 00 00 80b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)

Что интересно, похоже, AFL сам включил оптимизацию, потому что в неинструментированном коде честно вызывается strncmp. Что же до разбухшей PLT в коде, собранном afl-gcc, то, судя по всему, мы видим функции, вызываемые forkserver-ом — его мы тоже напишем, но обо всём по порядку. Хорошо, сделаем вид, что этого не видели, и попробуем наивным образом переписать наш пример без библиотечных функций:


#include 

volatile int *ptr = NULL;
const char cmd[] = "NULL";

int main(int argc, char *argv[]) {
    char buf[16];
    fgets(buf, sizeof buf, stdin);
    for (int i = 0; i < sizeof cmd - 1; ++i) {
        if (buf[i] != cmd[i])
            return 0;
    }
    *ptr = 1;
    return 0;
}

Компилируем, запускаем и… тадам!



Пишем свой forkserver


Как я уже говорил, AFL предполагает наличие инструментации, собирающей информацию о переходах между базовыми блоками исследуемой программы. Но есть и ещё одна оптимизация, добавляемая afl-gcc: forkserver. Смысл её в том, чтобы не перезапускать программу с помощью связки fork-execve, каждый раз выполняя динамическую линковку и т. д., а один раз внутри процесса фаззера сделать fork, потом execve в инструментированную программу. Как же мы будем перезапускать исследуемую программу? Смысл в том, что тестировать мы будем не этот запущенный процесс. Вместо этого в нём запускается код, который в бесконечном цикле ждёт команды от фаззера, делает fork, ждёт завершения дочернего процесса и отзванивается о результате. А вот отпочковавшийся процесс уже реально обрабатывает входные данные и собирает информацию о рёберном покрытии. В случае afl-gcc, если я правильно понимаю его логику, forkserver запускается при первом обращении к инструментированному коду. В случае же llvm mode также поддерживается режим deferred forkserver — таким образом можно пропустить не только динамическую линковку, но и стандартную для исследуемого процесса инициализацию, что потенциально может ускорить весь процесс на порядки, но нужно учитывать некоторые нюансы:


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

Также в llvm mode поддерживается persistent mode, в котором несколько тестовых примеров подряд выполняются внутри одного отпочкованного процесса. Наверное, это ещё больше снижает накладные расходы, но при этом есть опасность, что результат выполнения программы на очередном тестовом примере будет зависеть не только от текущего примера, но и от истории запусков. Кстати, уже после начала написания статьи я наткнулся на информацию о том, что порт AFL на Windows тоже использует DynamoRIO для инструментации, и он как раз использует persistent mode. Ну а что ему ещё остаётся без поддержки fork?


Итак, нужно написать свой forkserver на DynamoRIO, но для начала нужно понять требуемый протокол его взаимодействия с процессом фаззера. Что-то можно почерпнуть по указанной выше ссылке на блог автора AFL, но проще найти в каталоге фаззера файл llvm_mode/afl-llvm-rt.o.c. В нём есть много интересного, но для начала посмотрим на функцию __afl_start_forkserver — там всё подробно описывается, даже с комментариями. Persistent mode нас не интересует, в остальном всё довольно понятно: нам дано два файловых дескриптора с известными номерами — из одного читаем, в другой пишем. Нам нужно:


  1. Цитата из исходника: Phone home and tell the parent that we're OK. Записываем любые 4 байта.
  2. Читаем 4 байта. Поскольку похоже, что в нашем случае (без persistent mode) мы имеем инвариант child_stopped == 0, то что именно мы прочитали, значения не имеет.
  3. Отпочковываем дочерний процесс и закрываем в нём файловые дескрипторы для связи с фаззером.
  4. Пишем 4 байта с PID дочернего процесса в файловый дескриптор и ожидаем его (процесса) завершения.
  5. Дождавшись, пишем ещё 4 байта с кодом возврата и переходим к пункту 2.

И вот мы, собственно, подошли к написанию своего клиента. Тут нужно сделать лирическое отступление о том, что хотя примеры из документации и занимают всего пару сотен строчек, но документацию почитать всё-таки стоит. Начать можно, например, отсюда, где, в частности, написано о том, чего делать не стоит. Например, перефразировав известного литературного персонажа, можно сказать, что "клиент инструментации — это очень уж странный предмет: вроде он есть, но его как бы нет", что в документации именуется client transparency: в частности, нужно пользоваться своими копиями системных библиотек (в чём поможет private loader), либо пользоваться API DynamoRIO (выделение памяти, разбор опций командной строки и многое другое). Также важная информация есть в документации на функции API: например, в описании функции dr_register_bb_event указан краткий список из 11 пунктов, чему должна удовлетворять получившаяся последовательность инструкций после инструментации.


Для управления сборкой клиентов для DynamoRIO рекомендуется использовать CMake — им мы и воспользуемся. О том, как это сделать, можно прочитать в документации, мы же перейдём к более интересным вопросам. Например, для того, чтобы сделать deferred forkserver, нам нужно как-то пометить место его запуска в исследуемой программе, а потом найти эту пометку в DynamoRIO (впрочем, вроде бы ничто не мешает сделать forkserver просто в виде вызова обычной функции внутри исследуемой программы, но ведь так же не интересно, правда?), К счастью, подобная функциональность встроена в DynamoRIO и называется аннотациями. Разработчик клиента должен собрать специальную статическую библиотеку, которую нужно прилинковать к исследуемой программе, и в требуемом месте вызвать функцию из этой библиотеки, последовательность инструкций в которой не делает ничего интересного при обычном исполнении, но при запуске под DynamoRIO распознаётся им и заменяется на определённую константу или вызов функции.


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


По поводу реализации forkserver-а всё тоже довольно прямолинейно, за исключением того, что, вероятно, не очень правильно вызывать fork из нашей копии libc: например, автор AFL в указанной выше статье про особенности реализации forkserver говорил о том, что libc кеширует PID. В случае же вызова fork из копии libc исследуемого приложения и оно будет знать про произошедший вызов fork, и DynamoRIO это, хочется верить, тоже заметит. Поэтому пришлось написать что-то вроде


module_data_t *module = dr_lookup_module_by_name("libc.so.6");
EXIT_IF_FAILED(module != NULL, "Cannot lookup libc.\n", 1)
fork_fun_t fork_ptr = (fork_fun_t)dr_get_proc_address(module->handle, "fork");
EXIT_IF_FAILED(fork_ptr != NULL, "Cannot get fork function from libc.\n", 1)
dr_free_module_data(module);

Поэтому, чтобы поддержать традиционный режим запуска forkserver-а при старте программы, нужно убедиться, что к этому моменту уже доступна libc.


Когда я попытался это протестировать, я столкнулся со странным поведением: тестируемая программа запускалась, а forkserver — нет. Я добавил в dr_client_main печать на консоль — её тоже не появилось. Переключился на сборочный каталог чернового варианта кода. Хм… работает. Сравнил вывод nm -D на рабочей и нерабочей библиотеке инструментации: и там, и там есть функция dr_client_main. Сравнил ещё раз — действительно есть… Указал для drrun опции -verbose -debug. В общем, после некого количества экспериментов выяснилось, что дело было не в библиотеке клиента, и даже не в тестовой программе. Просто для чернового сборочного каталога QtCreator создал путь .../build-afl-dr-Desktop_3fb6e5-Выпуск, а для "рабочего" — .../build-afl-dr-Desktop-По умолчанию. Ну вы поняли, во втором был пробел. Нет, я понимаю, что некоторые программы не работают, когда в пути есть пробелы, но втихаря выкинуть библиотеку инструментации, это, конечно, креативненько… (Да, я отправил баг-репорт.)


Тестируем:


$ ~/soft/DynamoRIO-Linux-6.2.0-2/bin64/drrun -c libafl-dr.so -- ./example-bug
Running forkserver...
Cannot connect to fuzzer.
1
$ ~/soft/DynamoRIO-Linux-6.2.0-2/bin64/drrun -c libafl-dr.so -- ./example-bug 198<&0 199>/dev/null
Running forkserver...
xxxx
1
Incorrect spawn command from fuzzer.

Ну, более-менее работает. Проверим, как отнесётся к нему AFL. Для этого запустим его в dumb mode (не собирать рёберное покрытие), но попросим его всё-таки использовать forkserver:


$ AFL_DUMB_FORKSRV=1 $AFL_PATH/afl-fuzz -i input -o output -n -- ./example-bug
... что-то там про Fork server handshake failed -- правильно, инструментации нет ...
$ AFL_DUMB_FORKSRV=1 $AFL_PATH/afl-fuzz -i input -o output -n -- ~/soft/DynamoRIO-Linux-6.2.0-2/bin64/drrun -c libafl-dr.so -- ./example-bug
... что-то там про Timeout while initializing fork server (adjusting -t may help)
$ # изучаем логи strace-а и...
$ AFL_DUMB_FORKSRV=1 $AFL_PATH/afl-fuzz -i input -o output -n -m 2048 -- ~/soft/DynamoRIO-Linux-6.2.0-2/bin64/drrun -c libafl-dr.so -- ./example-bug
... всё работает, если дать больше памяти (опция -m)


Впрочем, скорость не ахти. Но речь пока о работе на качественном уровне.


И тут обнаружилась проблема: хотя с тестовой программой такой forkserver работает нормально, некоторые программы с ним просто рушатся по SIGSEGV. После некого времени, потраченного на отладку, ответа так и не появилось, однако оказалось, что в качестве обходного пути можно вызывать fork из копии libc, принадлежащей клиенту, а не приложению. Ну что же, это повод познакомиться с extension под названием droption. Чтобы его использовать, нужно всего лишь объявить статическую переменную типа dr_option_t, в параметрах указав имя опции, описание и значение по умолчанию, а в начале dr_client_main вызвать droption_parser_t::parse_argv(...) (да, клиент теперь у нас получается на C++). Внезапно оказалось, что документация на сайте относится к версии 7.0 RC1, а в 6.2.0-2 документация на это расширение отсутствует, и стандартным способом через CMake именно droption почему-то не подключается. Но само расширение есть. Впрочем, нам нужен лишь путь к заголовочным файлам, поэтому просто подключим другое расширение с тем же путём, например, drutil.


В итоге получились следующие реализации:


afl-annotations.h
// Based on dr_annotations.h from DynamoRIO sources

#ifndef _AFL_DR_ANNOTATIONS_H_
#define _AFL_DR_ANNOTATIONS_H_ 1

#include "annotations/dr_annotations_asm.h"

/* To simplify project configuration, this pragma excludes the file from GCC warnings. */
#ifdef __GNUC__
# pragma GCC system_header
#endif

#define RUN_FORKSERVER() \
    DR_ANNOTATION(run_forkserver)

#ifdef __cplusplus
extern "C" {
#endif

DR_DECLARE_ANNOTATION(void, run_forkserver, ());

#ifdef __cplusplus
}
#endif

#endif

afl-annotations.c
#include "afl-annotations.h"

DR_DEFINE_ANNOTATION(void, run_forkserver, (), );

afl-dr.c
#include 
#include 

#include 
#include 
#include wait.h>

#include "afl-annotations.h"

static const int FROM_FUZZER_FD = 198;
static const int TO_FUZZER_FD   = 199;

typedef int (*fork_fun_t)();

#define EXIT_IF_FAILED(isOk, msg, code) \
    if (!(isOk)) { \
        dr_fprintf(STDERR, (msg)); \
        dr_exit_process((code)); \
    }

static droption_t opt_private_fork(DROPTION_SCOPE_CLIENT, "private-fork", false,
                                         "Use fork function from the private libc",
                                         "Use fork function from the private libc");

static void parse_options(int argc, const char *argv[]) {
    std::string parse_err;
    if (!droption_parser_t::parse_argv(DROPTION_SCOPE_CLIENT, argc, argv, &parse_err, NULL)) {
        dr_fprintf(STDERR, "Incorrect client options: %s\n", parse_err.c_str());
        dr_exit_process(1);
    }
}

static void start_forkserver() {
    // For references, see https://lcamtuf.blogspot.ru/2014/10/fuzzing-binaries-without-execve.html
    // and __afl_start_forkserver in llvm_mode/afl-llvm-rt.o.c from AFL sources

    static bool forkserver_is_running = false;

    uint32_t unused_four_bytes = 0;
    uint32_t was_killed;

    if (!forkserver_is_running) {
        dr_printf("Running forkserver...\n");
        forkserver_is_running = true;
    } else {
        dr_printf("Warning: Attempt to re-run forkserver ignored.\n");
        return;
    }

    if (write(TO_FUZZER_FD, &unused_four_bytes, 4) != 4) {
        dr_printf("Cannot connect to fuzzer.\n");
        return;
    }

    fork_fun_t fork_ptr;
    // Lookup the fork function from target application, so both DynamoRIO
    // and application's copy of libc know about fork
    // Currently causes crashes sometimes, in that case use the private libc's fork.
    if (!opt_private_fork.get_value()) {
        module_data_t *module = dr_lookup_module_by_name("libc.so.6");
        EXIT_IF_FAILED(module != NULL, "Cannot lookup libc.\n", 1)
        fork_ptr = (fork_fun_t)dr_get_proc_address(module->handle, "fork");
        EXIT_IF_FAILED(fork_ptr != NULL, "Cannot get fork function from libc.\n", 1)
        dr_free_module_data(module);
    } else {
        fork_ptr = fork;
    }

    while (true) {
        EXIT_IF_FAILED(read(FROM_FUZZER_FD, &was_killed, 4) == 4, "Incorrect spawn command from fuzzer.\n", 1)
        int child_pid = fork_ptr();
        EXIT_IF_FAILED(child_pid >= 0, "Cannot fork.\n", 1)

        if (child_pid == 0) {
            close(TO_FUZZER_FD);
            close(FROM_FUZZER_FD);
            return;
        } else {
            int status;
            EXIT_IF_FAILED(write(TO_FUZZER_FD, &child_pid, 4) == 4, "Cannot write child PID.\n", 1)
            EXIT_IF_FAILED(waitpid(child_pid, &status, 0) >= 0,     "Wait for child failed.\n", 1)
            EXIT_IF_FAILED(write(TO_FUZZER_FD, &status, 4) == 4,    "Cannot write child exit status.\n", 1)
        }
    }
}

DR_EXPORT void dr_client_main(client_id_t id, int argc, const char *argv[]) {
    parse_options(argc, argv);
    EXIT_IF_FAILED(
        dr_annotation_register_call("run_forkserver", (void *)start_forkserver, false, 0, DR_ANNOTATION_CALL_TYPE_FASTCALL),
        "Cannot register forkserver annotation.\n", 1);
}

Собираем рёберное покрытие


И вот, наконец, настало время приступить к полноценному перекорёживанию машинного кода. Как и в прошлый раз, не будем изобретать велосипед, а посмотрим в исходниках AFL, как делается существующая инструментация. А именно, изменения вносимые afl-gcc описаны в afl-as.c, а сам вписываемый ассемблерный код находится в виде строковых литералов в afl-as.h. Подробности работы AFL и, в частности, используемая инструментация, описаны в официальном документе technical details. По сути, в места ветвления программы вписывается код эквивалентный


cur_location = ;
shared_mem[cur_location ^ prev_location]++;
prev_location = cur_location >> 1;

(псевдокод нагло позаимствован из документации AFL). Каждая локация помечается случайным идентификатором, а ребру в графе переходов соответствует байт в карте с номером, состоящим из поксоренных идентификаторов текущей и предыдущей локации, причём один из идентификаторов сдвигается на 1 — это позволяет сделать рёбра ориентированными. Для взаимодействия с процессом фаззера программе через переменную окружения передаётся ссылка на 64-килобайтную карту в shared memory, пример работы с которой можно посмотреть всё в том же файле llvm_mode/afl-llvm-rt.o.c.


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


// Внутри dr_client_main:

lock = dr_mutex_create();
dr_register_thread_init_event(event_thread_init);
dr_register_thread_exit_event(event_thread_exit);
dr_register_bb_event(event_basic_block);
dr_register_exit_event(event_exit);

Обработчики создания и удаления потоков довольно бесхитростны:


typedef struct {
    uint64_t scratch;
    uint8_t map[MAP_SIZE];
} thread_data;

static void event_thread_init(void *drcontext) {
    void *data = dr_thread_alloc(drcontext, sizeof(thread_data));
    memset(data, 0, sizeof(thread_data));
    dr_set_tls_field(drcontext, data);
}

static void event_thread_exit(void *drcontext) {
    thread_data *data = (thread_data *) dr_get_tls_field(drcontext);

    dr_mutex_lock(lock);
    for (int i = 0; i < MAP_SIZE; ++i) {
        shmem[i] += data->map[i];
    }
    dr_mutex_unlock(lock);
    dr_thread_free(drcontext, data, sizeof(thread_data));
}

… а удаление мьютекса я даже приводить не буду. Из интересного в этом коде стоит обратить внимание, во-первых, на то, что DynamoRIO имеет собственные функции и для выделения памяти, и для примитивов синхронизации, причём есть вариант аллокатора с thread-specific memory pool. Во-вторых, здесь мы видим создание глобальных-на-уровне-потока структур thread_data, чей адрес мы заносим в tls field.


И вот, мы подошли к сути происходящего: функции event_basic_block(void *drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating), которая и занимается переписыванием машинного кода. Как я и обещал, нам не придётся ворочать шестнадцатиричные коды инструкций и высчитывать байты — инструкции придут к нам уже в декодированном виде в параметре instrlist_t *bb. Есть даже несколько макросов для кроссплатформенной (в плане архитектуры процессора) генерации наиболее типичных инструкций, но, увы, нам всё же придётся разбираться с ассемблером amd64 aka x86_64. Читать документацию по используемым функциям DynamoRIO вообще полезно, а в случае с dr_register_bb_event это полезно вдвойне. Например, вот что понимается под basic block:


DR constructs dynamic basic blocks, which are distinct from a compiler's classic basic blocks. DR does not know all entry points ahead of time, and will end up duplicating the tail of a basic block if a later entry point is discovered that targets the middle of a block created earlier, or if a later entry point targets straight-line code that falls through into code already present in a block.

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


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


static dr_emit_flags_t event_basic_block(void *drcontext, void *tag, instrlist_t *bb,
                                         bool for_trace, bool translating) {
    instr_t *where = instrlist_first(bb);
    reg_id_t tls_reg = DR_REG_XDI, offset_reg = DR_REG_XDX;

    dr_save_arith_flags(drcontext, bb, where, SPILL_SLOT_1);
    dr_save_reg(drcontext, bb, where, tls_reg, SPILL_SLOT_2);
    dr_save_reg(drcontext, bb, where, offset_reg, SPILL_SLOT_3);

    dr_insert_read_tls_field(drcontext, bb, where, tls_reg);

    // здесь будет дописываться инструментация

    dr_restore_reg(drcontext, bb, where, offset_reg, SPILL_SLOT_3);
    dr_restore_reg(drcontext, bb, where, tls_reg, SPILL_SLOT_2);
    dr_restore_arith_flags(drcontext, bb, where, SPILL_SLOT_1);

    return DR_EMIT_DEFAULT;
}

В tls_reg тут же положим адрес нашей структуры с временной картой для текущего потока. Также в приведённом выше псевдокоде из документации фигурирует COMPILE_TIME_RANDOM. Проблема с использованием случайных идентификаторов в том, что наш event_basic_block может вызываться несколько раз: обратите внимание на аргументы for_trace и translating. Дело в том, что, кроме трансляции отдельных блоков, наиболее часто встречающиеся цепочки блоков DynamoRIO собирает в трейсы. Перед тем, как добавить блок в трейс, ещё раз вызываются зарегистрированные обработчики трансляции базового блока, но уже с for_trace = true, в которых можно сгенерировать специальную инструментацию для помещения блока в трейс. Также иногда возникает необходимость понять, какому реальному адресу кода соответствует кешированный, на котором произошло некое событие, тогда наш обработчик вызывается с translating = true — тут уже, конечно, нужно повторить ровно те же преобразования, как с translating = false. Впрочем, можно вернуть из обработчика DR_EMIT_STORE_TRANSLATIONS вместо DR_EMIT_DEFAULT, и адреса будут запомнены за нас, но на это потребуются дополнительные ресурсы. Даже, если бы никаких повторных вызовов не предполагалось бы by design, всё равно пришлось бы хитро координировать наши случайные метки с учётом того, что часть будет создана уже после форка процесса. Поэтому просто будем давать идентификатор как функцию от адреса кода, где лежит basic block.


void *app_pc = dr_fragment_app_pc(tag);
uint32_t cur_location = ((uint32_t)(uintptr_t)app_pc * (uint32_t)33533) & 0xFFFF;

Если уже после форка будут загружены дополнительные динамические библиотеки, то ASLR испортит нам планы, но будем считать это редким случаем. Кстати, "если припрёт", рандомизацию можно временно отключить для всей системы с помощью sysctl -w kernel.randomize_va_space=0.


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


 instrlist_meta_preinsert(bb, where,
    XINST_CREATE_load(drcontext,
                      opnd_create_reg(offset_reg),
                      OPND_CREATE_MEM64(tls_reg, offsetof(thread_data, scratch))));
instrlist_meta_preinsert(bb, where,
    INSTR_CREATE_xor(drcontext,
                     opnd_create_reg(offset_reg),
                     OPND_CREATE_INT32(cur_location)));
instrlist_meta_preinsert(bb, where,
    XINST_CREATE_store(drcontext,
                       OPND_CREATE_MEM32(tls_reg, offsetof(thread_data, scratch)),
                       OPND_CREATE_INT32(cur_location >> 1)));
instrlist_meta_preinsert(bb, where,
    INSTR_CREATE_inc(drcontext,
                     opnd_create_base_disp(tls_reg, offset_reg, 1, offsetof(thread_data, map), OPSZ_1)));

Кстати, если вы ошибётесь с инструкциями, то вместо подробного сообщения о том, что ай-ай-ай такие операнды задавать этой инструкции, вы получите просто Segmentation fault. Например, заменим в первой инстукции XINST_CREATE_load на XINST_CREATE_store и запустим:


$ ~/soft/DynamoRIO-Linux-6.2.0-2/bin64/drrun -c libafl-dr.so --private-fork -- ./example-bug
Cannot get SHM id from environment.
Creating dummy map.
Running forkserver...
Cannot connect to fuzzer.
^C
$ # Поменяли load на store
$ ~/soft/DynamoRIO-Linux-6.2.0-2/bin64/drrun -c libafl-dr.so --private-fork -- ./example-bug
Cannot get SHM id from environment.
Creating dummy map.
path/to/example-bug (5058).  Tool internal crash at PC 0x00005605e72bbeaa.  Please report this at your tool's issue tracker.  Program aborted.
Received SIGSEGV at pc 0x00005605e72bbeaa in thread 5058
Base: 0x00005605e71c5000
Registers:eax=0x0000000000000001 ebx=0x00007ff6dfa12038 ecx=0x0000000000000048 edx=0x0000000000000000
        esi=0x0000000000000049 edi=0x0000000000000005 esp=0x00007ff6dfa0ebb0 ebp=0x00007ff6dfa0ebc0
        r8 =0x0000000000000003 r9 =0x0000000000000005 r10=0x0000000000000000 r11=0x00005605e72b70ef
        r12=0x0000000000000000 r13=0x0000000000000000 r14=0x000000000000000c r15=0x00005605e7368c50
        eflags=0x0000000000010202
version 6.2.0, build 2
-no_dynamic_options -client_lib '/path/to/libafl-dr.so;0;"--private-fork"' -code_api -stack_size 56K -max_elide_jmp 0 -max_elide_call 0 -early_inject -emulate_brk -no_inline_ignored_syscalls -native_exec_default_list '' -no_native_exec_managed_code -no_indcall2direct
0x00007ff6dfa0ebc0 0x0000020803000000>

Что делать? Можно по одной комментировать инструкции, пока не перестанет падать. Можно задать опции командной строки вроде -debug -loglevel 1 -logdir /tmp/dynamorio/ и тогда вместо невразумительного падения на консоль будет написано о невозможности закодировать инструкцию, а в логе будет что-то вроде:


ERROR: Could not find encoding for: mov    (%rdi)[8byte] -> %rdx
SYSLOG_ERROR: Application /path/to/example-bug (5192) DynamoRIO usage error : instr_encode error: no encoding found (see log)
SYSLOG_ERROR: Usage error: instr_encode error: no encoding found (see log) (/dynamorio_package/core/arch/x86/encode.c, line 2417)

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


Что же, инструментация готова, можно запускать:


$ $AFL_PATH/afl-fuzz -i input -o output -m 2048 -- ~/soft/DynamoRIO-Linux-6.2.0-2/bin64/drrun -c libafl-dr.so -- ./example-bug
afl-fuzz 2.42b by <lcamtuf@google.com>
[+] You have 4 CPU cores and 1 runnable tasks (utilization: 25%).
[+] Try parallel jobs - see docs/parallel_fuzzing.txt.
[] Checking CPU core loadout...
[+] Found a free CPU core, binding to #0.
[] Checking core_pattern...
[] Checking CPU scaling governor...
[] Setting up output directories...
[+] Output directory exists but deemed OK to reuse.
[] Deleting old session data...
[+] Output dir cleanup successful.
[] Scanning 'input'...
[+] No auto-generated dictionary tokens to reuse.
[] Creating hard links for all input files...
[] Validating target binary...

[-] Looks like the target binary is not instrumented! The fuzzer depends on
    compile-time instrumentation to isolate interesting test cases while
    mutating the input data. For more information, and for tips on how to
    instrument binaries, please see docs/README.

    When source code is not available, you may be able to leverage QEMU
    mode support. Consult the README for tips on how to enable this.
    (It is also possible to use afl-fuzz as a traditional, "dumb" fuzzer.
    For that, you can use the -n option - but expect much worse results.)

[-] PROGRAM ABORT : No instrumentation detected
         Location : check_binary(), afl-fuzz.c:6894

Но… У нас же есть инструментация… Неужели она не работает? На самом деле ситуация ещё смешнее: если посмотреть на лог strace для этой команды, то мы увидим, что drrun даже не запускался. И что же это за телепатия, как afl-fuzz видит отсутствие инструментации, даже не запуская программу? Помните, я говорил о том, что AFL — это подборка железобетонных эвристик? Так вот, идём куда послали, ну, в смысле, в afl-fuzz.c:6894, и видим:


f_data = mmap(0, f_len, PROT_READ, MAP_PRIVATE, fd, 0);
// ...
if (!qemu_mode && !dumb_mode &&
    !memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
    // ...
    FATAL("No instrumentation detected");
}

Да-да, именно так: AFL ищет в бинарнике строчку __AFL_SHM_ID — имя переменной окружения, через которую инструментированная программа получает идентификатор общей памяти. Теперь-то всё ясно, echo -ne "__AFL_SHM_ID\0" >> /path/to/drrun впрочем, нет, не повторяйте моих ошибок: если посмотреть в исходнике чуть выше, то окажется, что можно просто задать переменную окружения AFL_SKIP_BIN_CHECK и отключить проверку:


$ # Опция -d заставляет пропустить детерминированные шаги фаззинга
$ AFL_SKIP_BIN_CHECK=1 $AFL_PATH/afl-fuzz -i input -o output -m 2048 -d -- ~/soft/DynamoRIO-Linux-6.2.0-2/bin64/drrun -c libafl-dr.so -- ./example-bug


Ура, AFL признал нашу инструментацию, но что это, Бэрримор, total paths: 12, а раньше было только 4-5. Точно сказать сложно, но подозреваю, что это овсяlibc. Ведь теперь инструментации подвергается не только наш код из example-bug, но и всё, что исполняется в процессе (ну, кроме DynamoRIO, конечно). Да и скорость не ахти… Поэтому самое время начать делать


Оптимизации


… и первой будет выбор, какие модули процесса мы хотим инструментировать. Точнее, пока просто будем ограничивать инструментацию главным модулем программы, и сделаем опцию "сделать как раньше". Для этого я заведу глобальную переменную типа module_data_t *, в dr_client_main проинициализирую её информацией о главном модуле программы, а в event_basic_block буду сразу прерывать обработку, если код "не наш":


module_data_t *main_module;

// В dr_client_main:
main_module = dr_get_main_module();

// В event_basic_block:
if (!opt_instrument_everything.get_value() && !dr_module_contains_addr(main_module, pc)) {
    return DR_EMIT_DEFAULT;
}

Для тестового примера это увеличило скорость фаззинга до 80 запусков в секунду (приблизительно в 2 раза), а в output/queue строка test за пару минут уже превратилась в NU — медленно, но как будто бы работает.


Далее, у DynamoRIO есть опция -thread_private, при указании которой он будет использовать отдельные кеши кода для каждого потока. В этом случае значение из tls field фактически становится константой, поэтому, хотя выкинуть использование регистра у меня не получилось, но инициализировать его можно immediate-константой:


if (dr_using_all_private_caches()) {
    instrlist_meta_preinsert(bb, where,
        INSTR_CREATE_mov_imm(drcontext,
                             opnd_create_reg(tls_reg),
                             OPND_CREATE_INTPTR(dr_get_tls_field(drcontext))));
} else {
    dr_insert_read_tls_field(drcontext, bb, where, tls_reg);
}

Запускаем с опцией -thread_private (но эта опция должна идти до -c libafl-dr.so, поскольку она принадлежит самому DynamoRIO, а не нашему клиенту), и получаем приблизительно на 5 запусков в секунду больше. Впрочем, даже если написать if (0 && dr_using_all_private_caches()), то результат идентичный — видимо, DynamoRIO просто эффективнее работает в таком режиме. :)


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


Напоследок скажу, что ещё чуть улучшить производительность можно, если "прогреть" тестируемую программу перед запуском forkserver-а: добавим в example-bug.c код


ungetc('1', stdin);
char ch;
fscanf(stdin, "%c", &ch);

RUN_FORKSERVER();

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


За сим разрешите откланяться. В этом небольшом проекте ещё есть над чем подумать:


  • можно не тратиться на инструментацию безусловных переходов, как это и сделано в afl-as
  • можно попытаться научиться пересоздавать запущенные потоки после форка (такой функциональности в текущих реализациях, вроде бы, нет)
  • можно по аналогии с патчем для QEMU отправлять в сторону forkserver информацию о транслированных адресах, чтобы он их также транслировал у себя и последующие его потомки уже не тратили на это время (но, видимо, в лучшем случае придётся допиливать DynamoRIO. Хотя, надо отдать должное гитхабовским телепатам: не успел я отправить feature request, полез смотреть существующие issues, а они это уже две недели назад закоммитили...)

… но это уже совсем другая история. И помните, все врут: не стоит на вопрос "А правда ли эту функцию API / ассемблерную инструкцию можно так использовать?" отвечать, "Да, конечно, я так вон в той статье видел!" — сложно сказать, сколько разнокалиберных неожиданностей ещё предстоит вычистить из этого небольшого кода. Впрочем, надеюсь, вы убедились, что написание несложной, но полезной динамической инструментации — задача намного более выполнимая, чем кажется на первый взгляд.


Ссылки:


  • Этот проект на Github.
  • WinAFL — ещё одна реализация подобного на DynamoRIO (для Windows).
  • Ещё размышления и эксперименты по поводу неофициальных реализаций инструментации: раз, два.
  • Dynamic Binary Instrumentation в ИБ — статья 2012 года про другую систему динамической инструментации, PIN
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/332076/


Метки:  

Поиск сообщений в rss_rss_hh_new
Страницы: 1437 ... 1057 1056 [1055] 1054 1053 ..
.. 1 Календарь