...

суббота, 9 апреля 2016 г.

The dangers of not looking ahead

Tracert vs Traceroute

В чем отличие маршрута пакета от его пути?
Стандартный механизм маршрутизации пакетов в интернете — per hop behavior — то есть каждый узел в сети принимает решение куда ему отправить пакет на основе информации, полученной от протоколов динамической маршрутизации и статически указанных администраторами маршрутов.

Маршрут — это интерфейс, в который нам надо послать пакет для достижения какого то узла назначения и адрес следующего маршрутизатора (next-hop):

R1#sh ip rou | i 40.  
         40.0.0.0/8 is variably subnetted, 2 subnets, 2 masks
O        40.0.0.0/31 [110/3] via 20.0.0.0, 00:01:54, FastEthernet0/0
O        40.1.1.1/32 [110/4] via 20.0.0.0, 00:00:05, FastEthernet0/0


Что такое путь? Путь — это список узлов, через которые прошел (пройдет) пакет:
 1  10.0.0.1  16.616 ms  16.270 ms  15.929 ms
 2  20.0.0.0  15.678 ms  15.157 ms  15.071 ms
 3  30.0.0.1  26.423 ms  26.081 ms  26.744 ms
 4  40.0.0.0  48.979 ms  48.674 ms  48.384 ms
 5  100.0.0.2  58.707 ms  58.773 ms  58.536 ms


Путь пакета можно посмотреть с помощью утилит tracert в OC Windows и traceroute в Unix-подобных системах. (другие команды, типа tracepath мы не рассматриваем).
Многие считают что этих утилит один и тот же принцип работы, но это не так. Давайте разберемся.

Итак, утилита tracert.
В основе работы данной утилиты лежит протокол icmp. Рассмотрим вот такую схему:

Host отправляет по указанному в его таблице маршрутизации маршруту ICMP Echo-Request с ttl 1. Router1, получив такой пакет, проверит адрес назначения — может быть пакет ему. Так как данный пакет адресован другому хосту, то Router1 считает себя транзитным узлом, декрементирует ttl пакета и отбрасывает его, так как время жизни пакета становится равным 0. Так как пакет был дропнут, Router1 отправляет источнику пакета icmp сообщение с указанием причины дропа — Time Exceeded. Утилита tracert, получив данное icmp сообщение, указывает Router1 как первый хоп (информация об адресе указана в icmp сообщении). Далее процесс повторяется с инкрементированием ttl, пока ttl icmp запроса не будет равен количеству хопов между узлом-отправителем и узлом получателем. В данном примере Server1 является узлом назначения. Получив пакет, он проверит адрес назначения, увидит, что запрос адресован ему и отправит ICMP Echo-Reply, что и будет являться для утилиты tracert триггером к окончанию трассировки.

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

Traceroute — данная утилита работает по иному принципу, хоть и вывод команды похож на вывод предыдущей.
Traceroute основана не на ICMP Echo-Request, а на отправке udp фрагментов и получения сообщения о доступности/недостижимости порта. Вернемся к прошлой схеме. Host генерирует udp фрагмент, инкапсулирует его в IP пакет и выставляет ttl=1. Router1, являясь транзитным узлом, ответит на данный пакет icmp сообщением об окончании времени жизни пакета. Утилита traceroute, получив данное сообщение, указывает адрес источника icmp пакета (Router1) как адрес первого хопа. Далее процесс повторяется с инкрементированием ttl пакета. Всё практически так же, как и в tracert. Но ведь мы не отправляем ICMP Echo-Request, как утилита traceroute поймет, что трассировка закончена? Все просто — в udp заголовке есть поля source и destination порт. Логично, что source порт будет любым портом выше 1023. А каким указать destination порт? Как было сказано выше, работа утилиты traceroute основана на получении сообщения о недостижимости или доступности порта назначения. То есть мы отправляем udp фрагмент с порта 45000 ( к примеру) на порт 33434 (именно этот порт используется по умолчанию). Как и в предыдущем случае, Server1 является узлом назначения. Получив пакет, он распаковывает его и должен передать его протоколам высшего уровня. Но так как порт 33434 по умолочанию будет закрыт на сервере, то Server1 формирует icmp сообщение о недостижимости порта назначения (ICMP Type 3 «Destination Unreachable» Code 3 «Port Unreachable»). Получив данное сообщение, утилита traceroute считает трассировку законченной. В процессе трассировки номер порта назначения будет инкрементироваться при каждой попытке ( 33434, 33435 и т д). Может получится так, что порт назначения будет открыт. В данном случае сервер отправит на хост-инициатор например TCP ACK, что тоже будет являться триггером к окончанию трассировки.

Вывод:
Утилита traceroute позволяет сделать трассировку с указанием порта назначения.

Для этого разберем пример ниже:

Возьмем предыдущую схему и сделаем трассировку:

С использованием TCP SYN пакетов:

bormoglots@ubuntu-server-s1:~$ sudo traceroute -T -p 22 -w 1 -n 100.0.0.2
traceroute to 100.0.0.2 (100.0.0.2), 30 hops max, 60 byte packets
 1  10.0.0.1  16.616 ms  16.270 ms  15.929 ms
 2  20.0.0.0  15.678 ms  15.157 ms  15.071 ms
 3  30.0.0.1  26.423 ms  26.081 ms  26.744 ms
 4  40.0.0.0  48.979 ms  48.674 ms  48.384 ms
 5  100.0.0.2  58.707 ms  58.773 ms  58.536 ms


C использованием UDP пакетов:
bormoglots@ubuntu-server-s1:~$ sudo traceroute -U -p 22 -w 1 -n 100.0.0.2
traceroute to 100.0.0.2 (100.0.0.2), 30 hops max, 60 byte packets
 1  10.0.0.1  7.102 ms  6.917 ms  6.680 ms
 2  20.0.0.0  17.021 ms  16.838 ms  17.051 ms
 3  30.0.0.1  31.035 ms  30.859 ms  30.658 ms
 4  40.0.0.0  41.124 ms  40.941 ms  40.728 ms
 5  100.0.0.2  51.291 ms  51.045 ms  50.720 ms


Как видите трассировка прошла успешно. Мы видим путь до указанного хоста.

А теперь повесим на интерфейс Router4 фильтр на in (как указано на рисунке):

R4#sh run int fa0/0
Building configuration...

Current configuration : 121 bytes
!
interface FastEthernet0/0
 ip address 40.0.0.0 255.255.255.254
 ip access-group deny-to-server in
 duplex half
 !
end

R4#sh access-lists deny-to-server
Extended IP access list deny-to-server
    10 deny tcp any host 100.0.0.2 log (32 matches)
    20 deny udp any host 100.0.0.2 log (29 matches)
    30 permit ip any any (128 matches)


Снова сделаем трассировку:
bormoglots@ubuntu-server-s1:~$ sudo traceroute -T -p 22 -w 1 -n 100.0.0.2
traceroute to 100.0.0.2 (100.0.0.2), 30 hops max, 60 byte packets
 1  10.0.0.1  4.575 ms  4.490 ms  4.367 ms
 2  20.0.0.0  18.431 ms  18.359 ms  29.573 ms
 3  30.0.0.1  30.579 ms  30.690 ms  30.722 ms
 4  40.0.0.0  52.518 ms !X  62.977 ms !X  62.898 ms !X


bormoglots@ubuntu-server-s1:~$ sudo traceroute -U -p 22 -w 1 -n 100.0.0.2
traceroute to 100.0.0.2 (100.0.0.2), 30 hops max, 60 byte packets
 1  10.0.0.1  5.614 ms  5.523 ms  5.689 ms
 2  20.0.0.0  18.364 ms  18.629 ms  18.556 ms
 3  30.0.0.1  42.289 ms  42.225 ms  42.143 ms
 4  40.0.0.0  41.984 ms !X  41.898 ms !X  41.815 ms !X


Теперь трассировка закончилась на предпоследнем хопе и в выводе появились знаки! Х. Почему это произошло? Router4 получив пакет к Server1 дропает его, так как он попадает под запрещающее правило на входящем интерфейсе и отправляет хосту-инициатору сообщение о том, что пакет был зафильтрован (ICMP Type 3 «Destination Unreachable» Code 13 — «Communication Administratively Prohibited»). Это тоже сообщение о недостижимости порта назначения. Поэтому утилита traceroute получив такое сообщение, заканчивает свою работу так не добравшись до хоста назначения. В данном случае в выводе важно понять, что пакеты были именно зафильрованы, о чем нам подсказывает знак !X (в Unix) или знак !A (в Cisco):
R1#traceroute 100.0.0.2

Type escape sequence to abort.
Tracing the route to 100.0.0.2

  1 20.0.0.0 24 msec 24 msec 16 msec
  2 30.0.0.1 16 msec 36 msec 40 msec
  3 40.0.0.0 !A  !A  !A

Примечание: Возможен случай, когда пакеты будут дропаться без отправки ICMP сообщений ( отправка в Null-интерфейс в Cisco/Huawei или discard в Juniper). В данном случае трассировка будет идти пока не кончится максимальное TTL, указанное в утилите traceroute (по умолчанию максимум 30 хопов, но можно задать вручную до 255, правда обычно достаточно 15-18 хопов) или ее не прервет администратор, а в выводе будут звездочки.

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

Собственно говоря, утилита traceroute может работать как и утилита tracert с использованием ICMP Echo-Request. Для этого ее следует запустить с ключом -I. В примеры выше фильтр не блокирует ICMP, поэтому трассировка с использованием данного протокола покажет нам весь путь пакета:

bormoglots@ubuntu-server-s1:~$ sudo traceroute -I -w 1 -n 100.0.0.2
traceroute to 100.0.0.2 (100.0.0.2), 30 hops max, 60 byte packets
 1  10.0.0.1  4.073 ms  3.986 ms  3.890 ms
 2  20.0.0.0  19.474 ms  19.389 ms  19.294 ms
 3  30.0.0.1  30.147 ms  30.276 ms  30.826 ms
 4  40.0.0.0  42.316 ms  42.240 ms  42.145 ms
 5  100.0.0.2  52.705 ms  52.622 ms  52.521 ms


Надеюсь мы разобрались в работе данных утилит. Если надо сделать трассировку по какому то порту в Windows системах, можно использовать сторонние утилиты, к примеру tcptrace.

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

Комментарии (0)

    Let's block ads! (Why?)

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

    В нашем блоге на Хабре мы не только рассказываем о развитии своего продукта — биллинга для операторов связи «Гидра», но и публикуем материалы о работе с инфраструктурой и использовании технологий.

    Недавно мы писали об использовании Clojure и MongoDB, а сегодня речь пойдет о плюсах и минусах денормализации баз данных. Разработчик баз данных и финансовый аналитик Эмил Дркушич (Emil Drkušić) написал в блоге компании Vertabelo материал о том, зачем, как и когда использовать этот подход. Мы представляем вашему вниманию главные тезисы этой заметки.

    Что такое денормализация?


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

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

    Рассмотрим нормализованную модель для простейшей CRM-системы:

    Пробежимся по имеющимся здесь таблицам:

    • Таблица user_account хранит данные о пользователях, зарегистрированных в приложении (для упрощения модели роли и права пользователей из нее исключены).
    • Таблица client содержит некие базовые сведения о клиентах.
    • Таблица product — это список предлагаемых товаров.
    • Таблица task содержит все созданные задачи. Каждую из них можно представить в виде набора согласованных действий по отношению к клиенту. Для каждой есть список звонков, встреч, предложенных и проданных товаров.
    • Таблицы call и meeting хранят данные о заказах и встречах с клиентами и связывают их с текущими задачами.
    • Словари task_outcome, meeting_outcome и call_outcome содержат все возможные варианты результата звонков, встреч и задания.
    • product_offered хранит список продуктов, которые были предложены клиентам;
    • product_sold — продукты, которые удалось продать.
    • Таблица supply_order хранит информацию обо всех размещенных заказах.
    • Таблица writeoff содержит перечень списанных по каким-либо причинам товаров.

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

    Когда полезно использовать денормализацию


    Прежде чем браться разнормализовывать то, что уже однажды было нормализовано, естественно, нужно четко понимать, зачем это нужно? Следует убедиться, что выгода от применения метода перевешивает возможные негативные последствия. Вот несколько ситуаций, в которых определенно стоит задуматься о денормализации.
    1. Сохранение исторических данных. Данные меняются с течением времени, но может быть нужно сохранять значения, которые были введены в момент создания записи. Например, могут измениться имя и фамилия клиента или другие данные о его месте жительства и роде занятий. Задача должна содержать значения полей, которые были актуальны на момент создания задачи. Если этого не обеспечить, то восстановить прошлые данные корректно не удастся. Решить проблему можно, добавив таблицу с историей изменений. В таком случае SELECT-запрос, который будет возвращать задачу и актуальное имя клиента будет более сложным. Возможно, дополнительная таблица — не лучший выход из положения.
    2. Повышение производительности запросов. Некоторые запросы могут использовать множество таблиц для доступа к часто запрашиваемым данным. Пример — ситуация, когда необходимо объединить до 10 таблиц для получения имени клиента и наименования товаров, которые были ему проданы. Некоторые из них, в свою очередь, могут содержать большие объемы данных. При таком раскладе разумным будет добавить напрямую поле client_id в таблицу products_sold.
    3. Ускорение создания отчетов. Бизнесу часто требуется выгружать определенную статистику. Создание отчетов по «живым» данным может требовать большого количества времени, да и производительность всей системы может в таком случае упасть. Например, требуется отслеживать клиентские продажи за определенный промежуток по заданной группе или по всем пользователям разом. Решающий эту задачу запрос в «боевой» базе перелопатит ее полностью, прежде чем подобный отчет будет сформирован. Нетрудно представить, насколько медленнее все будет работать, если такие отчеты будут нужны ежедневно.
    4. Предварительные вычисления часто запрашиваемых значений. Всегда есть потребность держать наиболее часто запрашиваемые значения наготове для регулярных расчетов, а не создавать их заново, генерируя их каждый раз в реальном времени.

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

    Не все так гладко


    Очевидная цель денормализации — повышение производительности. Но всему есть своя цена. В данном случае она складывается из следующих пунктов:
    • Место на диске. Ожидаемо, поскольку данные дублируются.
    • Аномалии данных. Необходимо понимать, что с определенного момента данные могут быть изменены в нескольких местах одновременно. Соответственно, нужно корректно менять и их копии. Это же относится к отчетам и предварительно вычисляемым значениям. Решить проблему можно с помощью триггеров, транзакций и хранимых процедур для совмещения операций.
    • Документация. Каждое применение денормализации следует подробно документировать. Если в будущем структура базы поменяется, то в ходе этого процесса нужно будет учесть все прошлые изменения — возможно, от них вообще можно будет к тому моменту отказаться за ненадобностью. (Пример: в клиентскую таблицу добавлен новый атрибут, что приводит к необходимости сохранения прошлых значений. Чтобы решить эту задачу, придется поменять настройки денормализации).
    • Замедление других операций. Вполне возможно, что применение денормализации замедлит процессы вставки, модификации и удаления данных. Если подобные действия проводятся относительно редко, то это может быть оправдано. В этом случае мы разбиваем один медленный SELECT-запрос на серию более мелких запросов по вводу, обновлению и удалению данных. Если сложный запрос может серьезно замедлить всю систему, то замедление множества небольших операций не отразится на качестве работы приложения столь драматических образом.
    • Больше кода. Пункты 2 и 3 потребуют добавления кода. В то же время они могут существенно упростить некоторые запросы. Если денормализации подвергается существующая база данных, то потребуется модифицировать эти запросы, чтобы оптимизировать работу всей системы. Также понадобится обновить существующие записи, заполнив значения добавленных атрибутов — это тоже потребует написания некоторого количества кода.

    Денормализация на примере


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

    Что изменилось и почему?

    Единственное нововведение в таблице product — строка units_in_stock. В нормализованной модели мы можем вычислить это значение следующим образом: заказанное наименование — проданное — (предложенное) — списанное (units ordered — units sold — (units offered) — units written off). Вычисление повторяется каждый раз, когда клиент запрашивает товар. Это довольно затратный по времени процесс. Вместо этого можно вычислять значение заранее так, чтобы к моменту поступления запроса от покупателя, все уже было наготове. С другой стороны, атрибут units_in_stock должен оновляться после каждой операции ввода, обновления или удаления в таблицах products_on_order, writeoff, product_offered и product_sold.

    В таблицу task добавлено два новых атрибута: client_name и user_first_last_name. Оба они хранят значения на момент создания задачи — это нужно, потому что каждое из них может поменяться с течением времени. Также нужно сохранить внешний ключ, который связывает их с исходным пользовательским и клиентским ID. Есть и другие значения, которые нужно хранить — например, адрес клиента или информация о включенных в стоимость налогах вроде НДС.

    Денормализованная таблица product_offered получила два новых атрибута: price_per_unit и price. Первый из них необходим для хранения актуальной цены на момент предложения товара. Нормализованная модель будет показывать лишь ее текущее состояние. Поэтому, как только цена изменится, изменится и «ценовая история». Нововведение не просто ускорит работу базы, оно улучшает функциональность. Строка price вычисляет значение units_sold * price_per_unit. Таким образом, не нужно делать расчет каждый раз, как понадобится взглянуть на список предложенных товаров. Это небольшая цена за увеличение производительности.

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

    Таблица statistics_per_year (статистика за год) в тестовой модели — абсолютно новый элемент. По сути, это денормализованная таблица, поскольку все ее данные могут быть рассчитаны из других таблиц. Здесь хранится информация о текущих задачах, успешно выполненных задачах, встречах, звонках по каждому заданному клиенту. В данном месте также хранится общая сумма проведенных начислений за каждый год. После ввода, обновления или удаления любых данных в таблицах task, meeting, call и product_sold приходится пересчитывать эти данные для каждого клиента и соответствующего года. Так как изменения, скорее всего, касаются лишь текущего года, отчеты за предыдущие годы теперь могут оставаться без изменений. Значения в этой таблице вычисляются заранее, поэтому мы сэкономим время и ресурсы, когда нам понадобятся результаты расчетов.

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

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

    Наш опыт


    Мы в Латере много занимаемся оптимизацией производительности нашей биллинговой системы «Гидра», что неудивительно, учитывая объемы наших клиентов и специфику телеком-отрасли.

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

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

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

    Другие технические статьи в нашем блоге:


    Комментарии (0)

      Let's block ads! (Why?)

      Security Week 14: опасная уязвимость в Adobe Flash, WhatsApp включает шифрование, Пентагон платит за баги

      История о споре между Apple и ФБР показала нам как политика может повлиять на технологии. На этой неделе все обсуждают обратный пример — тему об утечке данных из панамской юридической фирмы Mossack Fonseca. Не касаясь политической стороны этого события, не могу не отметить важный момент: резонансная история, скорее всего, началась с кибератаки и кражи данных. Об этом говорят в самой компании и есть косвенные доказательства того, что взломать инфраструктуру фирмы было не так уж сложно. В частности, внешний доступ к документам клиентов работал на версии Drupal трехлетней давности с минимум двумя критическими уязвимостями (впрочем, достаточно было одной этой).

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

      — Не бывает неважных корпоративных данных. Не исключено, что в Mossack Fonseca даже не подозревали, какой резонанс могут вызвать хранящиеся у них документы. Это приводит к недооценке рисков и неадекватным затратам на защиту.
      — Шифрование данных — это эффективная мера. Об этом говорит иная часть данной истории: десятки журналистов по всему миру анализировали полученные документы больше года, используя облачные системы и различные формы передачи данных в зашифрованном виде (начиная с VeraCrypt, форка TrueCrypt для шифрования жестких дисков). За это время не произошло ни одной утечки, несмотря на огромное количество участников проекта и отсутствие серьезных обязательств между ними.
      — Объем утечки превышает 2,5 терабайта. Нужна система, которая поможет компаниям фиксировать такие события. Неважно по какой причине с серверов компании утекает огромный объем данных — специалист по безопасности должен об этом знать.

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

      Adobe закрывает критическую уязвимость в Flash, которая уже используется для распространения криптолокеров
      Новость. Advisory.

      Очередных, внеочередных и прочих патчей для Adobe Flash за последнее время было так много, что очередной апдейт вряд ли бы удостоился внимания, если бы не активное использование критической уязвимости. До того, как апдейт был выпущен. Не так уж часто киберпреступники получают информацию о свежих уязвимостях до того, как они закрываются. Это им, впрочем, не мешает заражать пользователей незащищенных ПК и после патча, так как не всегда и не везде софт обновляется вовремя. Как выяснилось в четверг, критическая уязвимость Adobe Flash затрагивала версии для всех платформ, вызывала сбой в работе плагина и могла привести к выполнению произвольного кода. Уязвимость использовали в эксплойт-паках Magnitude и Nuclear для распространения криптолокеров Cerber и Locky.

      Locky — это тот самый троян-шифровальщик, который недавно наделал шума после инцидента с заражением медицинских учреждений. Уверен, что данное событие послужит еще одним аргументом в пользу полного и окончательного отказа от Flash — ведь получается, что даже устанавливая самые последние апдейты нельзя быть уверенным в безопасности системы. Но оказывается своевременный апдейт все же помогает и в этом случае. Проанализировав эксплойт-пак, эксперт компании Proofpoint заметил, что он таргетирует пользователей совсем старых версий Flash. Новый эксплойт, который какое-то время (минимум 3 дня до патча) мог успешно атаковать даже самые свежие релизы плагина, почему-то использовался только для устаревших версий. Судя по всему, создатели эксплойт-пака не до конца поняли, что именно попало им в руки.

      Whatsapp внедрил сквозное шифрование сообщений для всех пользователей
      Новость. Пост в блоге Whatsapp.

      Создатели мессенджера Whatsapp в последней версии клиента для всех мобильных платформ включили полное сквозное шифрование сообщений. Причем это касается всех видов передаваемых данных: в личных и групповых чатах, текст и картинки, для голосовых сообщений и звонков. Для шифрования используется открытый протокол Signal. Если шифрование реализовано корректно, и оно действительно сквозное, то по идее прочитать сообщения можете только вы и ваш собеседник (или собеседники). Именно это в Whatsapp и обещают. Именно поэтому данное событие называют куда более важным, чем спор между Apple и ФБР: сотни миллионов пользователей на этой неделе получили бесплатный, надежный и защищенный канал связи.

      Или нет? Мы собрали комментарии экспертов в этой новости. В частности, протокол может быть идеальным, но в конечном счете за реальную защиту данных отвечает владелец системы, то есть в данном случае Facebook. По мнению независимого эксперта Джонатана Здярски, приватность и сам Facebook — вещи малосовместимые. Уверен, что так думает не только он. Более аргументированный довод: даже если сообщения будет невозможно расшифровать, метаданные (IP-адреса и другая информация) все равно раскрывают слишком многое, чтобы можно было говорить о полной приватности или анонимности. Наконец, зашифрованная передача данных не отменяет уязвимости информации на конечном устройстве. Впрочем, это мы уже проходили недавно, с кейсом о взломе телефона Apple. Уверен, довольно скоро дебаты на тему конфликта между приватностью и необходимостью отслеживать коммуникации, конечно с благой целью (но и не только) будут продолжены. И обсуждать на них будут как устройства, так и протоколы и сети: две ключевых точки перехвата информации.

      Про абсолютную приватность недавно высказался глава ФБР, читайте в этой новости. Если коротко, то он против.

      Пентагон открывает собственную bug bounty программу Hack The Pentagon
      Новость.

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

      Программа реализована на платформе компании HackerOne, предоставляющей компаниям инфраструктуру для работы с исследователями. Впрочем, прогресс-прогрессом, но без особенностей не обошлось. Предъявлять определенные требования к найденным уязвимостям — это вполне нормально, но Пентагон довольно серьезно фильтрует и самих исследователей. Нужно иметь гражданство США, а особым счастливчикам еще придется пройти security check, включая проверку на наличие судимостей. Отказаться от проверки можно, но и премию тогда не выплатят, даже если исследование будет соответствовать всем правилам.

      Что еще произошло:
      На Филиппинах украли базу данных избирателей, 55 миллионов записей.

      ФБР в рамках судебного разбирательства попросили рассказать, как именно они взламывают коммуникации в сети Tor. ФБР вежливо ответило отказом.

      Опасная уязвимость в сетевых экранах Cisco.

      Древности:
      Семейство «Protect»

      Опасные резидентные вирусы, стандартно поражают COM- и EXE-файлы при из запуске на выполнение. Перехватывают int 21h и int 1Ch или int 33h в зависимости от версии. Содержат текст: «File protection». «Protect-1157» снимает атрибуты файлов и блокирует работу мыши. «Protect-1355» проявляется на EGA и VGA мониторах мелким и очень противным дрожанием экрана.

      Цитата по книге «Компьютерные вирусы в MS-DOS» Евгения Касперского. 1992 год. Страницa 44.

      Disclaimer: Данная колонка отражает лишь частное мнение ее автора. Оно может совпадать с позицией компании «Лаборатория Касперского», а может и не совпадать. Тут уж как повезет.

      Комментарии (0)

        Let's block ads! (Why?)

        Кюветы Android, Часть 2: SDK и Libraries

        Разрабатывая под Android, всегда нужно быть начеку. Шаг влево / шаг вправо — и вот прошел ещё один час за дебагом. Кюветы могут быть какие угодно: начиная от обычных багов в SDK и заканчивая неочевидными именами методов с контекстно зависимым результатом (да-да, Fragment.getFragmentManager(), это я о тебе).

        В предыдущей статье были описаны кюветы «на поверхности» SDK, в которые угодить очень легко. На этот же раз кюветы будут поглубже, помудрёнее и поспецифичнее. Также будет несколько моментов, связанных с Retrofit 2 & Gson.
        image

        1. GridLayout не реагирует на layout_weight


        Ситуация

        Иногда так случается, что обычный способ создания объекта с кучей не подходит:
        Обычная форма
        image

        Такой ситуацией может быть, например, landscape отображение формы. Хотелось бы в таком случае иметь нечто вроде такого:
        Форма для landscape
        image

        Как сделать такое же выравнивание 50 на 50? Существует несколько основных подходов:

        Однако они все имеют свои недостатки:
        • Обилие LinearLayout приводит к монструозности xml'ки, а она приводит к смерте котиков.
        • RelativeLayout усложняет изменение в будущем (поменять местами несколько строк в форме или добавить разделитель будет той ещё задачкой. Про View.setVisibility(View.GONE) я и вовсе молчу).
        • Ну а TableLayout вообще никто не использует… или используют, но редко. Я таких людей не знаю.

        Более того, довольно часто необходимо использовать магию числа 0dp & weight=1, чтобы добиться гибкого дизайна. Ни TableLayout, ни RelativeLayout тут вам не помогут. При первой же попытке использовать что-то вроде TextView.setEllipsize(), начнутся проблемы и боль.
        И тут вы наверное подметили, что я пропустил ещё один элемент. Казалось бы, на помощь приходит GridLayout, но и тот оказывается бесполезен из-за того, что не поддерживает свойство layout_weight. Так что же делать?
        Решение

        До некоторых пор делать было действительно нечего — либо мучайся с RelativeLayout, либо применяй LinearLayout , либо заполняй всё программный путем (для особо извращенных).
        Однако с 21 версии GridLayout наконец-то начал поддерживать свойство layout_weight и, что самое важное, это изменение было добавлено в AppCompat в виде android.support.v7.widget.GridLayout!
        К моменту когда я узнал об этом (и вообще о том, что обычный GridLayout чхать хотел на мой weight), я потратил по меньшей мере неделю, пытаясь понять почему мой layout поплыл вправо (как здесь). Пожалуй, это одно из самых важных нововведений, которое, почему-то, осталось без должного внимания. К счастью, ответы на stackoverflow (1, 2) уже начинают дописывать.
        Также советую заглянуть на страничку к новым PercentRelativeLayout и PercentFrameLayout — это действительно бомба. Название говорит само за себя и позволяет сделать крайне адаптивный дизайн. iOS'ники оценят. И ах да, оно есть в AppCompat.

        2. Fragment.isRemoving() и Acitivity.isFinishing() равны?


        Ситуация

        Как-то раз захотел я написать свой PresenterManager в виде синглтона (привет от MVP). Чтобы вовремя удалять Presenter'ов, я использовал Activity.isFinishing(), собирая id Presenter'ов фрагментов в активити и удаляя их вместе с ним. Естественно, такой способ плохо работал в случае с NavigationView — фрагменты менялись через FragmentTransaction.replace(), Presenter'ы копились и всё шло коту под хвост.
        Погуглив смальца, был найден метод Fragment.isRemoving(), который вроде бы делает то же самое, но для фрагментов. Я переписал код PresenterManager'а и был доволен. Конец…
        Решение

        … наступил моей спокойной жизни, когда я пытался заставить это работать. Честно, я пытался и так, и эдак, но поведение этого метода вкорне отличается от Activity.isFinishing(). Гугл был неправ. Если у вас когда-нибудь возникнет подобная задача, подумайте трижды прежде чем использовать Fragment.isRemoving(). Я серьезно. Особенно уделите внимание логам при повороте экрана.

        Кстати с Acitivity.isFinishing() тоже не всё так гладко: сверните приложение с >1 активити в стэке, дождитесь ситуации нехватки памяти, вернитесь обратно и воспользуйтесь Up Navigation и *вуаля*!.. Это был простой рецепт того, как поиметь Activity.isFinishing() == false для активити, которые вы больше никогда не увидите.

        3. Header/Footer в RecyclerView


        Ситуация

        Обычная задача при реализации пагинации — необходимо отображать ProgressBar на время загрузки новых данных.
        В отличие от ListView, RecyclerView обладает куда большими возможностями — чего только стоит RecyclerView.Adapter.notifyItemRangeInserted() по сравнению с той самой головной болью ListView.
        Однако попробовав использовать его в проекте вместо ListView, сразу же натыкаешься на множество нюансов: где свойство ListView.setDivider()? Где нечто вроде ListView.addHeaderView()? Что ещё за RecyclerView.Adapter.getItemViewType() и т.д., и т.п.
        Разобраться то со всей этой свалкой новой информации несложно, однако кое-что неприятное всё равно остается. Добавление Divider/Header заствляет писать тучи кода. Что уж и говорить о сложных layout'ах? Довеча доводилось делать RecyclerView с 4-мя различными Header'ами и Footer'ом с контроллами. Скажем так, опечаленным и удрученным я ходил очень долго.
        Решение

        На самом деле всё не так плохо, если знать, что искать. Самая основная проблема RecyclerView (и оно же его основное преимущество) — с ним можно делать всё, что угодно. Нет практически никаких рамок. Отсюда и вытекает проблема: хочешь Header — сделай сам. Но к счастью, «сделай сам» уже сделали за нас другие, так что давайте пользоваться.
        Типичные проблемы и их решения:
        • Заголовки для групп элементов (например, в словаре «А» будет являться заголовком для всех слов, начинающихся с этой буквы) — проще всего сделать через единственный item-layout, не добавляя 2-ой ненужный тип ViewHolder'а. Добавьте проверку на то, что текущий элемент ознаменует переход от одной буквы к другой и включите спрятанный в layout заголовок через View.VISIBLE.
        • Простой divider — копи-паст этого кода в проект. Никаких лишних махинаций. Работает через RecyclerView.addItemDecoration()
        • Добавлените Header / Footer / Drag&Drop и т.д. — если делать ручками, то либо заводить новый тип на каждый новый ViewHolder (не советую), либо делать WrapperAdapter (куда приятнее). Но ещё лучше посмотреть тут и выбрать понравившуюся либу. Лично мне нравятся сразу две: FastAdapter и UltimateRecyclerView
        • Нужна пагинация, но лень возиться с Header / Footer для ProgressBar'ов — библиотека Paginate от одного из разработчиков твиттера.

        Хотя для меня всё равно остается загадкой — почему нельзя было сделать какие-нибудь SimpleDivider / SimpleHeaderAdapter и т.д. сразу в SDK?

        4. Ускорение с RecyclerView.Adapter.setHasStableIds()


        Что с ним не так?

        Нестолько проблема, сколько недостаток документации. Вот что там написано:
        Returns true if this adapter publishes a unique long value that can act as a key for the item at a given position in the data set. If that item is relocated in the data set, the ID returned for that item should be the same.

        И тут люди делятся на два типа. Первые: всё ж ясно. Вторые: чо это вообще значит то?
        Проблема в том, что даже если вы отнесли себя к первым людям, вас может поставить в тупик вопрос: а зачем этот метод? Да-да, чтобы вернуть уникальный ID! Я знаю. Но зачем оно надо? И нет, ответ «гугл пишет, что так быстрее скроллиться будет!» меня не устроит.
        А вот в чём дело

        Ускорение от RecyclerView.Adapter.setHasStableIds() действительно можно получить, но только в одном случае — если вы повсеместно используете RecyclerView.Adapter.notifyDataSetChanged() (а тут они соизволили написать, зачем нужны stable id). Если вы имеете статичные данные, то вам этот метод не даст ровным счетом ничего, а возможно даже и немного замедлит из-за внутренних проверок ID. Узнал я об этом только после чтения исходников, а чуть позже случайно наткнулся на эту статью.

        5. WebView


        Ситуация

        Задача — получить html-текст от сервера и вывести его на экран. Текст сервером отдается в виде "& lt;html& gt;". Всё. Это вся задача. Сложно? Существует же WebView, который может отобразить html в пару строк. Да что там, даже TextView может это сделать! Раз-два и готово… да?.. нет?.. ну должно же?!
        Решение

        К сожалению, тут всё не так гладко:
        • Начнём с того, что нет метода типа HtmlUtils.unescape() в Android SDK. Если хочешь "& lt;" превратить в "<", то самый простой способ (кроме прописывания regex'а ручками) — подключить apache с его StringUtils.unescapeHtml4().
        • Следующей проблемой будут артефакты при прокрутке. Совершенно внезапно (да, Android SDK?), WebView будет мигать черным цветом. Что делать — рассказывается тут и тут. Лично мне помогла только комбинация этих подходов.
        • И если вас ещё не удивило обилие проблем от столь простой задачи, то вот добивалочка: нужно отобразить ProgressBar, пока html-страничка не отрендерилась. И тут всё плохо. То есть реально плохо. Все представленые на stackoverflow решения работают через раз или не работаю вовсе (тык, тык). Единственный работающий доселе способ был с применением WebView.setPictureListener (), однако тот теперь объявлен deprecated и тут уже ничего не попишешь.
          В итоге, единственное, что можно посоветовать — отказаться от ProgressBar'а. Либо, если уж совсем-совсем-совсем приспичит — добавить его прямо в html-код, проверяя через javascript готовность страницы. Но это уже для клуба элитных мазахистов.

        6. Gson: битовая маска в виде EnumSet


        Когда/Где/Зачем?

        (Ситуация специфична и напрямую к проблемам Android'а не относится, но в качестве затравки перед следующим кюветом решил добавить)
        В ответ на один из api-запросов приходит битовая маска прав доступа в виде int'а. Нужно обрабатывать элементы этой маски.
        Первое, что приходит в голову — int'овые константы и битовые операциями для проверок. Несомненно, оно всегда работает. Но что если хочется большего? Как насчет EnumSet?
        «Без проблем» — ответит проггер-бородач и разобьет архитектуру моделей ещё на несколько уровней: POJO, Model, Entity, UiModel и чем ещё чёрт не шутит. Но если лень и хочется без доп. классов? Что тогда?
        Решение

        Создаём нужный нам enum, позаботившись о «битовости» имён в @SerializedName:
        enum Access
        public enum Access {
            @SerializedName("1")
            CREATE,
            @SerializedName("2")
            READ;
            @SerializedName("4")
            UPDATE;
            @SerializedName("8")
            DELETE;
        }
        
        


        Определяем JsonDeserializer для десериализации из json в EnumSet:
        EnumMaskConverter
        public class EnumMaskConverter<E extends Enum<E>> implements JsonDeserializer<EnumSet<E>> {
                Class<E> enumClass;
        
                public EnumMaskConverter(Class<E> enumClass) {
                        this.enumClass = enumClass;
                }
        
                @Override
                public EnumSet<E> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
                        long mask = json.getAsLong();
                        EnumSet<E> set = EnumSet.noneOf(enumClass);
        
                        for (E bit : enumClass.getEnumConstants()) {
                                final String value = EnumUtils.GetSerializedNameValue(bit);
                                assert value != null;
        
                                long key = Integer.valueOf(value);
                                if ((mask & key) != 0) {
                                        set.add(bit);
                                }
                        }
                        return set;
                }
        }
        
        


        И добавляем его в Gson:
        GsonBuilder
        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.registerTypeAdapter((new TypeToken<EnumSet<Access>>() {}).getType(), new EnumMaskConverter<>(Access.class));
        Gson gson = gsonBuilder.create();
        
        


        В результате:
        Использование
        class MyModel {
                @SerializedName("mask")
                public EnumSet<Access> access;
        }
        
        /* ...some lines later... */
        
        if (myModel.access.containsAll(EnumSet.of(Access.READ, Access.UPDATE, Access.DELETE))) { 
                /* do something really cool */ 
        }
        
        

        7. Retrofit: Enum в @GET запросе


        Ситуация

        Начнём с настройки. Gson формируется также, как и ранее. Retrofit создаётся вот так:
        new Retrofit.Builder()
        retrofit = new Retrofit.Builder()
                        .baseUrl(ApiConstants.API_ENDPOINT)
                        .client(httpClient)
                        .addConverterFactory(GsonConverterFactory.create(gson))
                        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                        .build();
        
        


        А данные выглядят так:
        enum Season
        public enum Season {
            @SerializedName("3")
            AUTUMN,
            @SerializedName("1")
            SPRING;
        }
        
        


        Благодаря возможности Gson к прямому парсингу enum через обычный @SerializedName, стало возможным избавиться от необходимости создавать всякие дополнительные классы-прослойки. Все данные будут сразу идти из запросов в Model. Всё прекрасно:
        Retrofit Service
        public interface MonthApi {
                @GET("index.php?page[api]=selectors")
                Observable<MonthSelector> getPriorityMonthSelector();
        
                @GET("index.php?page[api]=years")
                Observable<Month> getFirstMonth(@Query("season") Season season);
        }
        
        


        Применение
        class MonthSelector {
                @SerializedName("season")
                public Season season;
        }
        
        /* ...some mouses later... */
        MonthSelector selector = monthApi.getPriorityMonthSelector();
        Season season = selector.season;
        
        /* ...some cats later... */
        Month month = monthApi.getFirstMonth(season);
        
        


        А теперь, уважаемые знатоки, внимание вопрос! Что пошло не так и почему оно не работает?
        Решение

        Я специально опустил информацию о том, что именно здесь не работает. Дело в том, что если посмотреть в логи, то запрос monthApi.getFirstMonth(season) будет обработан, как index.php?page[api]=years&season_lookup=AUTUMN… «ээээ, что за дела?» — скажу я. А каков ваш ответ? Почему такой результат? Ещё не догадались? Тогда вы попали.
        Когда я столкнулся с этой задачей, мне потребовалось несколько часов поисков в исходниках, чтобы понять одну вещь (или скорее даже вспомнить): да не используется Gson при отправке @GET / @POST и других подобных _запросов_ вообще! Ведь действительно, когда вы последний раз видели нечто вроде index.php?page[api]=years&season_lookup={a:123; b:321}? Это не имеет смысла. Retrofit 2 использует Gson только при конвертации Body, но никак не для самих запросов. В итоге? используется просто season.toString() — отсюда и результат.
        Однако, если уж ооочень хочется (а я из таких) использовать enum с конвертацией через Gson в запросе, то вам сюда — ещё один конвертор, всё как всегда.

        8. Retrofit: передача auth-token


        И напоследок, хотелось бы сказать одну вещь тем, кто пишет так:
        Любой Retrofit Service
        public interface CoolApi {
            @GET("index.php?page[api]=need")
            Observable<Data> 
            just(@Header("auth-token") String authToken);
            //           ^шлём auth-token
        
            @GET("index.php?page[api]=more")
            Observable<Data> 
            not(@Header("auth-token") String authToken);
            //           ^шлём auth-token ещё раз
        
            @GET("index.php?page[api]=gold")
            Observable<Data> 
            doIt(@Header("auth-token") String authToken);
            //           ^шлём auth-token в 101ый раз!
        }
        
        


        Начните уже использовать Interceptor'оры! Я понимаю, что Retrofit использовать очень просто и поэтому никто не читает документацию, но когда 3 часа сидишь и вычищаешь код не только от auth-token, но и ото всяких специфических current_location, battery_level, busy_status — настигает великая печалька (не спрашивайте, зачем передавать battery_level в каждый запрос. Сам в шоке). Почитать об этом можно тут.

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


        Что ж, на этот раз вышло куда больше текста, чем я планировал. Некоторые менее интересные кюветы пришлось выкинуть, другие же я решил оставил для следующего раза.
        Вопреки посылу предыдущей части, в этот раз я старался заставить вас не «гуглить в первую очередь», а прежде всего подумать «а зачем я это делаю?». Иногда проблему создает не SDK или библиотека, а сам программист и, к сожалению, в этом случае всё куда плачевнее. Не стоит недооценивать выбранный инструментарий, как и не стоит переоценивать его.
        В общем, если вам нравится андроид и/или вы планируете им заняться — всегда держите себя в курсе мировых трендов. Ну или поищите здесь более удобный для себя новостной ресурс. Там же вы можете найти много информации об Android SDK, популярных библиотеках и т.д., и т.п.

        Комментарии (0)

          Let's block ads! (Why?)

          [Перевод] Почти полное руководство по flexbox (без самих flexbox)

          пятница, 8 апреля 2016 г.

          Sipnet WebRTS

          Комментарии (0)

            Let's block ads! (Why?)

            SonataAdminBundle: создание объекта из List View (часть 2)

            IoT-решение за 1,5 часа

            Компьютерное зрение и мобильные роботы. Часть 1 — V-REP, Python, OpenCV

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

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

            Так и возникла идея серии статей, про решение простейшей задачи ориентации робота в пространстве — от виртуальной симуляции, до воплощения в реальном мобильном роботе:

            Часть 1. Настройка виртуальной среды, интеграция с python и OpenCV для распознавания образов из виртуального мира.
            Часть 2. Создание виртуального мобильного робота, алгоритм автономного перемещения (поиск объекта)
            Часть 3. Создание реального робота, перенос логики на него.

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

            Мозгом робота будет микрокомпьютер RaspberryPi2 — на котором без проблем работает и python, и OpenCV. Таким образом необходимо состыковать систему виртуальной робототехники V-REP — с Python и OpenCV. Вот про это и будет первая часть — данная публикация.

            Видео, что получилось (поиск зеленого объекта)

            На верхнем окне — прямое изображение с видео-камеры в 3д виртуальном мире, на нижнем окне — результат выполнения python скрипта, что получает изображение передаёт её OpenCV и рисует маркер, вокруг найденного объекта.

            Нарисуем архитектуру нашего мобильного робота.

            Архитектура мобильного робота
            Реальный робот, будет выглядит примерно так (ещё камеру добавим)

            Архитектурно:

            Как мы видим — «мозг» робота получает изображение, распознаёт (посредством OpenCV) и передаёт управляющие команды на колеса. И заменив изображение с камеры на 3д изображение, а управление колесами — на управление виртуальными колесами 3д робота в виртуальном мире — мы получим стенд для отработки логики.

            Получаем, такую архитектуру для виртуального стенда:

            В нашей сегодняшней первой части — нам необходимо решить задачу связки V-REP с внешним python скриптом, который выполняет распознавание образов с помощью OpenCV, и выводит маркер вокруг найденного объекта.

            Получается такая архитектура:

            Установка V-REP

            Про бесплатную систему робо-моделирования V-REP — было несколько русскоязычных публикаций:

            Поэтому установку и первые шаги — можно посмотреть в них.
            Сцена

            Считаем что V-REP установлен и работает. Нам необходимо создать сцену.

            На сцене будет камера, что просматривает область, на которой есть разные 3д объекты, это изображение необходимо транслировать внешнему python скрипту, который должен вызывать OpenCV для распознавания, и формирования маркера, и возврат данного изображения обратно в V-REP — для контроля.

            К счастью среди примеров который поставляются с V-REP был подобный пример, правда он использовал ROS (что для текущих задач не требовался):

            На базе этого демо появилась следующая сцена:

            • подвижный штатив, что вращается
            • на этом штативе закреплена камера v0 (vision sensor)
            • размещён v1 сенсор, данные на который передаются из внешней системы

            Сцену scene.ttt можно скачать отсюда.
            Python API

            Считаем, что Python у вас установлен (тестировалось на 2.7.6)

            При запуске V-REP автоматически загружается плагин обеспечивающий связку Python API. Для работы с API через python скрипт необходимо наличие трёх файлов в папке:

            • remoteApi.so (или remoteApi.dll)
            • vrep.py
            • vrepConst.py

            Их можно скопировать из V-REP каталога (programming/remoteApiBindings/python/python, programming/remoteApiBindings/lib/lib/). После этого можно импортировать модуль V-REP:
            import vrep
            
            

            Простейший скрипт, что подключается к API, выглядит так:
            import vrep
            
            vrep.simxFinish(-1) # just in case, close all opened connections
            
            clientID = vrep.simxStart('127.0.0.1', 19997, True, True, 5000, 5)
            
            if clientID!=-1:
              print 'Connected to remote API server'
            
              while (vrep.simxGetConnectionId(clientID) != -1):
                print "some work"
            else:
              print "Failed to connect to remote API Server"
              vrep.simxFinish(clientID)
            
            

            На нашей сцене есть два объекта — v0 и v1 — это Visual Sensor — с первого мы считываем картинку, на второй мы должны записывать результат. Поэтому мы должны получить эти объекты в контексте нашего python скрипта, делается это с помощью API команды vrep.simxGetObjectHandle

              res, v0 = vrep.simxGetObjectHandle(clientID, 'v0', vrep.simx_opmode_oneshot_wait)
              res, v1 = vrep.simxGetObjectHandle(clientID, 'v1', vrep.simx_opmode_oneshot_wait)
            
            

            Обращаем внимание, что все функции доступные через API — так же доступны и через внутренние скрипты (Lua), единственное отличие что в названии вместо simx — sim, то есть в нашем случае вызов функции на Lua будет «simGetObjectHandle».

            Для получения из Vision Sensor картинки и записи — есть две функции: vrep.simxGetVisionSensorImage и vrep.simxSetVisionSensorImage соответственно.

            И в python коде это будет выглядеть так (где v0 и v1 — соответствующие объекты):

                # получение изображения из сенсора v0
                err, resolution, image = vrep.simxGetVisionSensorImage(clientID, v0, 0, vrep.simx_opmode_buffer)
                # запись изображения в сенсор v1
                vrep.simxSetVisionSensorImage(clientID, v1, image, 0, vrep.simx_opmode_oneshot)
            
            

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

            Таким образом сейчас мы можем сделать python скрипт, что через V-REP API берёт изображение с видео-сенсора и ретранслирует его:
            simple_image_retranslate.py
            # simple_image_retranslate.py
            
            import vrep
            import time
            
            vrep.simxFinish(-1)
            
            clientID = vrep.simxStart('127.0.0.1', 19997, True, True, 5000, 5)
            
            if clientID!=-1:
              print 'Connected to remote API server'
            
              # get vision sensor objects
              res, v0 = vrep.simxGetObjectHandle(clientID, 'v0', vrep.simx_opmode_oneshot_wait)
              res, v1 = vrep.simxGetObjectHandle(clientID, 'v1', vrep.simx_opmode_oneshot_wait)
            
            
              err, resolution, image = vrep.simxGetVisionSensorImage(clientID, v0, 0, vrep.simx_opmode_streaming)
              time.sleep(1)
            
              while (vrep.simxGetConnectionId(clientID) != -1):
                err, resolution, image = vrep.simxGetVisionSensorImage(clientID, v0, 0, vrep.simx_opmode_buffer)
                if err == vrep.simx_return_ok:
                  vrep.simxSetVisionSensorImage(clientID, v1, image, 0, vrep.simx_opmode_oneshot)
                elif err == vrep.simx_return_novalue_flag:
                  print "no image yet"
                else:
                  print err
            else:
              print "Failed to connect to remote API Server"
              vrep.simxFinish(clientID)
            
            

            Для проверки мы должны стартовать сцену (кнопка «Play» вверх), и после этого в командной строке запустить файл simple_image_retranslate.py

            И вот результат (v1 — отображает изображение из python скрипта):

            Ок, базовая заготовка есть, теперь необходимо подключить распознавание образов (компьютерное зрение)

            Компьютерное зрение, OpenCV

            Думаю все слышали про открытую систему компьютерного зрения, OpenCV, которую разработал
            Gary Bradski

            Gary Bradski посетил стенд нашего хакспейса на иннопроме 2014

            Во первых OpenCV надо установить, установка opencv2 на Linux Mint (Ubuntu) выглядела достаточно просто:
            sudo apt-get install libopencv-dev python-opencv

            После этого появилась возможность подключать библиотеку в python коде:

            import cv2
            
            

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

            Появилась функция def track_green_object(image), что возвращает координаты зелёного объекта, если найден.

            И так же надо отметить маркером вокруг найденного объекта, для этого мы воспользуемся базовой OpenCV функцией для рисования прямоугольника: cv2.rectangle.

            И наш фрагмент кода, что:

            1. получает изображение (из v0)
            2. находит объект (что-то зелёное)
            3. добавляет маркер (желтый прямоугольник)
            4. возвращает изображение (в v1)

            выглядит так:
                # get image from vision sensor 'v0'
                err, resolution, image = vrep.simxGetVisionSensorImage(clientID, v0, 0, vrep.simx_opmode_buffer)
                if err == vrep.simx_return_ok:
                  image_byte_array = array.array('b', image)
                  image_buffer = I.frombuffer("RGB", (resolution[0],resolution[1]), image_byte_array, "raw", "RGB", 0, 1)
                  img2 = numpy.asarray(image_buffer)
            
                  # try to find something green
                  ret = track_green_object(img2)
            
                  # overlay rectangle marker if something is found by OpenCV
                  if ret:
                    cv2.rectangle(img2,(ret[0]-15,ret[1]-15), (ret[0]+15,ret[1]+15), (0xff,0xf4,0x0d), 1)
            
                  # return image to sensor 'v1'
                  img2 = img2.ravel()
                  vrep.simxSetVisionSensorImage(clientID, v1, img2, 0, vrep.simx_opmode_oneshot)
            
            

            Результат

            Теперь осталось запустить всё вместе: стартуем сцену, запускаем скрипт и смотрим, что происходит:

            Исходный код проекта можно найти на github.

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

            Комментарии (0)

              Let's block ads! (Why?)

              Сборка мусора в персистентной модели: от терабайта и дальше

              Honda усовершенствовала управление силовой установкой автомобиля Формулы 1 при помощи IBM Watson IoT

              Ближайшее будущее облачных технологий и виртуализации

              Hypermedia — то без чего ваше API не совсем REST

              Пятничный формат: Как работает Netflix

              В нашем блоге на Хабре мы рассказываем не только про технологические аспекты работы облачного сервиса 1cloud, но и затрагиваем вопросы огранизации рабочего процесса. Например, совсем недавно мы обсуждали работу тех. поддержки.

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

              Компания Netflix была основана в 1997 году Марком Рэндольфом (Marc Randolph) и Ридом Гастингсом (Reed Hastings) в Скотс-Вэлли, штат Калифорния. Поначалу в ней работали 30 сотрудников, занимавшихся предоставлением 925 фильмов и сериалов по подписке. Сегодня Netflix является ведущей мировой сетью интернет-телевидения, обслуживающей десятки миллионов клиентов.

              Компания достаточно активно выкладывает в Сеть информацию о применяемых технологиях, инфраструктуре и необычных решениях. Например, в своем блоге сотрудники Netflix рассказали о том, что компания делает, чтобы предоставляемый контент всегда был качественным. Для этого ими была разработана целая методология. Сеть доставки контента (CDN) компании учитывает то, какими устройствами пользуются ее клиенты, и поддерживает широкий диапазон интернет-соединений – от мобильного интернета со скоростью менее 0,5 Мб/с до высокоскоростного интернета (более 100 Мб/с).

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

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

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

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

              Если исходный файл не удовлетворяет требованиям, система автоматически уведомляет партнеров компании о проблеме и запрашивает новый исходник. Если все в порядке, к файлу прикрепляются метаданные для кодирования. Чтобы повысить эффективность работы с крупными файлами (например, видео с разрешением 4K), их фрагментируют – файл условно разбивается на небольшие части, проверка которых осуществляется параллельно.

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

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

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

              До того как в систему Netflix был интегрирован контроль качества, все ошибки «всплывали», когда клиенты обращались в службу технической поддержки. Чаще всего пользователи были сильно недовольны, а это сказывалось на финансовом положении компании. После введения системы контроля качества команда Netflix стала своевременно выявлять все ошибки, а надежность кодирования исходника, прошедшего проверку, сегодня составляет более 99,99%. Если компания сталкивается с проблемой, которую не удалось выявить с помощью алгоритмов автоматизации, сотрудники приступают к разработке новых механизмов проверки, чтобы не допускать подобного в будущем.

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

              Сеть доставки контента Netflix Open Connect предоставляет свои услуги более крупным интернет-провайдерам, имеющим более 100 000 клиентов. Специальное встроенное оборудование с низкой мощностью и высокой плотностью записи за определенную плату может передать с сайта Netflix контент, хранящийся в дата-центах интернет-провайдеров, тем самым сокращая затраты на передачу данных из Сети. Это оборудование работает на операционной системе FreeBSD, используя сервер nginx и службу маршрутизации BIRD.

              Мониторинг неисправных серверов


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

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

              В представленном ниже видео Коди Риу (Cody Rioux) рассказывает о том, что подтолкнуло компанию заниматься этими проблемами, а также делится техническими подробностями используемых алгоритмов (с примерами).

              Компанией широко используется так называемый кластерный анализ, который является методом машинного «обучения без учителя». Выбирая кластерный алгоритм, парни из Netflix остановили свой выбор на алгоритме кластеризации пространственных данных с присутствием шума DBSCAN (Density-Based Spatial Clustering of Applications with Noise).

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

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

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

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

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

              Рекомендательные алгоритмы


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

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

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

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

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

              Крайне важно при генерации страницы каким-либо алгоритмом оценить её качество. Придумывая метрики оценки, сотрудники Netflix черпали идеи в такой области деятельности, как информационный поиск. Например, компания нашла применение величине, называемой «полнота» (Recall), которая является отношением числа релевантных объектов (фильмов, которые выбрал клиент) в выборке, к общему числу релевантных объектов.

              Было принято решение использовать величину Rec[m;n], которая являет собой число релевантных объектов в первых m строках и n колонках на странице, разделенное на общее число релевантных объектов. Таким образом, Rec[3;4] – это качество видеозаписей (для конкретного пользователя), представленных на устройстве, дисплей которого позволяет отобразить всего 3 строки по 4 видео в каждой. Достоинством такой метрики является то, что, зафиксировав одну из величин (m или n) и изменяя другую, можно увидеть, как меняется значение полноты при прокрутке страницы.

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

              Что же касается разнообразия жанров, то это целая отдельная история. Если вы – пользователь Netflix, то, скорее всего замечали, что бывает вам предлагаются фильмы странных, порой абсурдных, жанров. Документальные драматические фильмы про борцов с системой? Пьеса про королевскую семью, основанная на реальных событиях? Зарубежные истории про сатанистов 80-х?

              И вот что интересно, оказывается, Netflix имеет 76897 разных способов описания фильмов. Компания создала специальные команды, члены которых помечали метатегами каждый предложенный им фильм. Этот процесс оказался настолько сложен, что участникам выдали 36-страничное руководство, в котором было расписано, как оценивать фильмы по наличию сексуального содержания, количеству крови, как определить романтичность фильма и оценить уровень актерской игры. Оценивалась даже нравственность персонажей.

              Журналист издания The Atlantic Алексис Мадригал (Alexis Madrigal) решил разобраться в ситуации поподробнее и обнаружил, что у Netflix абсурдно большое количество жанров (их количество превышало 90000). Чтобы пролить немного света на ситуацию, Алексис написал скрипт, который «вытянул» все существующие жанры с сайта компании.

              «Я сразу обратил внимание, что на сайте есть фильмы не всех представленных жанров», – отмечает Мадригал. – Наличие жанра в базе означает, что, по данным алгоритма, такие фильмы могут появиться позже, или уже есть материалы, которые подпадают под описание, но еще не добавлены на сайт». Например, категория №91300 называлась «Добрые романтические ТВ-шоу на испанском языке» и была пустой, категория №91307 носила заголовок «Красивые латиноамериканские комедии» и содержала два фильма, а в категории №6307 «Красивые романтические драмы» были представлены 20 фильмов.

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

              Оказалось, что для каждого дескриптора существует строгая иерархия. Короче говоря, жанр формируется по установленному паттерну:

              Откуда + Прилагательные + Существительное + Основан на … + Снят в … + От режиссера … + О… + Для возрастов от X до Y

              Все 76897 жанров, которые нашел бот Мадригала, были созданы из этих основных компонентов. Подробнее о процессе формирования «микрожанров» рассказал вице-президент Netflix Тодд Йеллин. В 2006 году Йеллин с командой инженеров начал работу над документацией, получившей название «Квантовая теория Netflix». В этом контексте квант – это небольшой «пакет энергии» (микро-тег), являющийся частью каждого фильма.

              Йеллин сказал, что жанры ограничиваются тремя основными факторами:

              • Название жанра не должно превышать 50 знаков из-за особенностей пользовательского интерфейса.
              • Чтобы алгоритм сформировал жанр, должна накопиться «критическая масса» контента, который бы подошел под его описание.
              • Регистрируемые жанры – синтаксически правильные.

              В мире Netflix нет жанров, состоящих из более чем пяти дескрипторов. Четыре дескриптора очень редки, но их можно встретить: «Культовые ужастики про безумных ученых 1970-х годов». Три дескриптора встречаются достаточно часто: «Добрые зарубежные комедии для неисправимых романтиков». Два дескриптора используются очень часто: «Фильмы, насыщенные загадками». Очень часто встречаются одиночные дескрипторы: «Необычные фильмы».

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

              Комментарии (0)

                Let's block ads! (Why?)

                Мобильная связь и интернет за рубежом: особенности и опасности

                Boomstarter в облаке — кто помогает запускать новые проекты?

                Привет!

                Сегодня с нами Руслан Тугушев, основатель компании Boomstarter, уже 3.5 года разрабатывающей краудфандинговую платформу и консультирующей авторов проектов, как привлекать деньги на свои деньги. На момент марта 2016 года проекты привлекли уже больше 210 миллионов рублей, и Руслан рассказывает, как Microsoft Azure поддерживает платформу возможностями уже инфраструктурными. Как раз недавно Бумстартер помог собрать космическому проекту «Маяк» без семи тысяч два миллиона рублей — самый успешный проект о космосе за всю историю Boomstarter! Под катом — подробности.



                Про старт Boomstarter

                Boomstarter запустился очень успешно, так как мы были одной из первых платформ краудфандинга, нацеленной на русскоязычную аудиторию. С технологической точки зрения запуск прошёл плавно, без неприятных сюрпризов, благодаря тому, что мы сделали ставку на проверенные технологии. Хотя аппаратное обеспечение иногда подкидывало сюрпризы (мы запускали проект на арендованных выделенных серверах), но чаще всего мы были к ним готовы. Сейчас мы являемся одной из лидирующих платформ краудфандинга в России, нас ежемесячно посещают 300.000 уникальных посетителей, и в основном мы нацелены на русскоязычный сегмент интернета. Мы знаем, что Хабр любит космос, и у нас есть проекты, которые напрямую с ним связаны. Один из последних успешно завершившихся таковых проектов — космический спутник «Маяк», который привлёк 1 993 146 рублей на испытание и создание лётного варианта малого космического аппарата (МКА) «Маяк», который будет выведен на орбиту Земли на ракете-носителе «Союз-2» в середине 2016 года. Проект «Маяк» — самый успешный проект о космосе за всю историю Boomstarter!

                Автор проекта — Александр Шаенко — дал небольшой отзыв о работе с Boomstarter: «Самое приятное, что Бумстартер – это не площадка, это сервис, где есть люди, готовые помочь советом и делом. Многие советы были услышаны и воплощены. В рамках этого проекта мы убедились в том, как много среди нас энтузиастов, инженеров и любителей космоса, что тема популяризации космонавтики интересна людям. Что люди готовы объединиться и помочь в борьбе с проблемой космического мусора.

                Мы получили много полезных контактов, партнеров, которые помогают нашему проекту.
                Ну и, конечно, мы получили возможность реализовать проект, о котором узнает весь мир уже в этом году!»

                Про выбор облака

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

                Про технологии и миграцию

                За исключением переноса файлового хранилища, миграция прошла неожиданно легко. Технический департамент проекта воспринял миграцию и облачную платформу с энтузиазмом. В основном были временные затраты, особенно сложной частью стал перенос файлов из Amazon S3 в хранилище Azure. Наши объёмы не позволяли осуществить перенос с хоть каким-то приемлемым даунтаймом, поэтому мы были вынуждены переносить данные инкрементально. Что хотелось бы иметь, и чего не было, так это готового инструмента для этих задач. На самом деле даже вытащить список файлов из S3 оказалось нетривиальной задачей: готовые инструменты не справлялись с нашими объёмами. Когда мы всё-таки добыли список файлов и запустили наш самописный инструмент миграции, нас ждало разочарование: оценочные расчёты времени превысили полтора месяца! Нам пришлось научить нашу утилиту распараллеливаться, в том числе для запуска на нескольких машинах. Здесь нам и помогла возможность облака быстрого введения в строй дополнительных машин.

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

                Архитектурно наш проект представляет собой вполне стандартное веб-приложение, в том числе для мобильных клиентов, с трёхзвенной архитектурой. В качестве основного инструмента используется Ruby On Rails. Большое количество логики вынесено на фронтенд.

                Для кэширования используется отказоустойчивый Azure Redis Cache, реализация Microsoft Redis как сервиса у себя в облаке. Данные хранятся в PostgreSQL, для фоновых задач — resque. Все вполне традиционно для Ruby On Rails, да и решения, проверенные временем.

                Заключение

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

                Комментарии (0)

                  Let's block ads! (Why?)

                  Паять или не паять? Интернет вещей для начинающих

                  Я ничего не смыслю в электронике, никогда не работала с платами и микроконтроллерами, не паяла, но посмотрев The Maker Show, я уже подумываю, а не заказать ли мне Arduino или Raspberry Pi.
                  Рекомендую это шоу тем, кто только начинает изучать тему Интернета вещей. Для вас я сделала обзор основных выпусков шоу.

                  1. Введение в электронику

                  Как заставить светодиод светиться с помощью лимона?

                  Технологический евангелист Microsoft Дэвид Крук проводит несколько экспериментов, иллюстрирующих основы электроники.

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

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

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

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

                  2. Мигающие светодиоды… А теперь что?

                  В этом выпуске The Maker Show лимонов не будет. Он посвящен мигающим светодиодам и микроконтроллерам Arduino UNO.

                  Технологический евангелист Microsoft Брайан Шеруин рассказывает, из чего состоит микроконтроллер Arduino UNO, и показывает, как его запрограммировать.

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

                  3. Arduino и серводвигатели

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

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

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

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

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

                  4. Создание и печать 3D-моделей, соответствующих по размеру реальным компонентам

                  В этом выпуске с нами Джереми Фостер. Он рассказывает о 3D-моделировании и 3D печати на примере контроллера Xbox One.

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

                  Джереми использует программу Fusion 360 от Autodesk, которая позволяет очень просто спроектировать 3D модель. Еще больше упрощает задачу онлайн-сервис GrabCAD. В нем собраны уже готовые 3D модели.

                  5. Как установить Windows 10 на Raspberry Pi 2?

                  В следующем выпуске технологический евангелист Microsoft Кенни Спэйд пошагово рассказывает, как установить Windows 10 IoT Core на Raspberry Pi 2.

                  Эта операционная система помогает запускать универсальные приложения Windows на Raspberry Pi. Все, что рассказывает Кенни, также актуально для Raspberry Pi 3.

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

                  6. Основы пайки

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

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

                  В The Maker Show регулярно выходят новые выпуски, последние, например, посвящены носимым устройствам, шаговым двигателям и многому другому.

                  Следить за выпусками шоу вы можете на Channel 9.

                  Паять или не паять? Однозначно, паять!

                  Комментарии (0)

                    Let's block ads! (Why?)