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

Поиск сообщений в 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 ленты.
По всем вопросам о работе данного сервиса обращаться со страницы контактной информации.

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

[Из песочницы] Сборка модуля ядра Linux без точных заголовочных файлов

Понедельник, 19 Июня 2017 г. 12:37 + в цитатник

Представьте, что у вас имеется образ ядра Linux для телефона на базе Android, но вы не располагаете ни соответствующими исходниками, ни заголовочными файлами ядра. Представьте, что ядро имеет поддержку подгрузки модулей (к счастью), и вы хотите собрать модуль для данного ядра. Существует несколько хороших причин, почему нельзя просто собрать новое ядро из исходников и просто закончить на том (например, в собранном ядре отсутствует поддержка какого-нибудь важного устройства, вроде LCD или тачскрина). С постоянно меняющимся ABI ядра Linux и отсутствием исходников и заголовочных файлов, вы можете подумать, что окончательно зашли в тупик.

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

Но больше об этом далее.

Конфигурация ядра


Первый шаг — найти исходники ядра наиболее близкие к тому образу ядра, насколько это возможно. Наверное, получение правильной конфигурации — наиболее сложная составляющая всего процесса сборки модуля. Начните с того номера версии ядра, который может быть прочитан из /proc/version. Если, как я, вы собираете модуль для устройства Android, попробуйте ядра Android от Code Aurora, Cyanogen или Android, те, что наиболее ближе к вашему устройству. В моем случае, это было ядро msm-3.0. Заметьте, вам не обязательно необходимо искать в точности ту же версию исходников, что и версия вашего образа ядра. Небольшие отличия версии, наиболее вероятно, не станут помехой. Я использовал исходники ядра 3.0.21, в то время как версия имеющегося образа ядра была 3.0.8. Не пытайтесь, однако, использовать исходники ядра 3.1, если у вас образ ядра 3.0.x.

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

Предполагая, что arm-eabi-gcc у вас доступен по одному из путей в переменной окружения PATH, и что терминал открыт в папке с исходными файлами ядра, вы можете начать конфигурацию ядра и установку заголовочных файлов и скриптов:

$ mkdir build
$ gunzip config.gz > build/.config # или что угодно, для того, чтобы приготовить .config
$ make silentoldconfig prepare headers_install scripts ARCH=arm CROSS_COMPILE=arm-eabi- O=build KERNELRELEASE=`adb shell uname -r`

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

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

Написание простого модуля


Чтобы создать пустой модуль, необходимо создать два файла: исходник и Makefile. Расположите следующий код в файле hello.c, в некоторой отдельной директории:

#include module.h>       /* Needed by all modules */
#include kernel.h>       /* Needed for KERN_INFO */
#include init.h>         /* Needed for the macros */
static int __init hello_start(void)
{
  printk(KERN_INFO "Hello world\n");
  return 0;
}
static void __exit hello_end(void)
{
  printk(KERN_INFO "Goodbye world\n");
}
module_init(hello_start);
module_exit(hello_end);

Поместите следующий текст в файл Makefile в той же директории:

obj-m = hello.o

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

Сборка модуля


При обычной сборки ядра система сборки ядра создает файл hello.mod.c, содержимое которого может создать различные проблемы:

MODULE_INFO(vermagic, VERMAGIC_STRING);

Значение VERMAGIC_STRING определяется макросом UTS_RELEASE, который располагается в файле include/generated/utsrelease.h, генерируемом системой сборки ядра. По умолчанию, это значение определяется версией ядра и статуса git-репозитория. Это то, что устанавливает KERNELRELEASE при конфигурации ядра. Если VERMAGIC_STRING не совпадает с версией ядра, загрузка модуля приведет к сообщению подобного рода в dmesg:

hello: version magic '3.0.21-perf-ge728813-00399-gd5fa0c9' should be '3.0.8-perf'

Далее, также имеем здесь определение структуры модуля:

struct module __this_module
__attribute__((section(".gnu.linkonce.this_module"))) = {
 .name = KBUILD_MODNAME,
 .init = init_module,
#ifdef CONFIG_MODULE_UNLOAD
 .exit = cleanup_module,
#endif
 .arch = MODULE_ARCH_INIT,
};

Само по себе, это определение выглядит безобидно, но структура struct module, определенная в include/linux/module.h, несет в себе неприятный сюрприз:

struct module
{
        (...)
#ifdef CONFIG_UNUSED_SYMBOLS
        (...)
#endif
        (...)
        /* Startup function. */
        int (*init)(void);
        (...)
#ifdef CONFIG_GENERIC_BUG
        (...)
#endif
#ifdef CONFIG_KALLSYMS
        (...)
#endif
        (...)
(... plenty more ifdefs ...)
#ifdef CONFIG_MODULE_UNLOAD
        (...)
        /* Destruction function. */
        void (*exit)(void);
        (...)
#endif
        (...)
}

Это означает, что для того, чтобы указатель init оказался в правильном месте, CONFIG_UNUSED_SYMBOLS должен быть определен в соответствии с тем, что использует наш образ ядра. Что же насчет указателя exit, — это CONFIG_GENERIC_BUG, CONFIG_KALLSYMS, CONFIG_SMP, CONFIG_TRACEPOINTS, CONFIG_JUMP_LABEL, CONFIG_TRACING, CONFIG_EVENT_TRACING, CONFIG_FTRACE_MCOUNT_RECORD и CONFIG_MODULE_UNLOAD.

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

Далее, определения версий символов:

static const struct modversion_info ____versions[]
__used
__attribute__((section("__versions"))) = {
    { 0xsomehex, "module_layout" },
    { 0xsomehex, "__aeabi_unwind_cpp_pr0" },
    { 0xsomehex, "printk" },
};

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

Каждая такая запись представляет символ, требуемый модулю, и то, какую сигнатуру должен иметь символ. Первый символ, module_layout, зависит от того, как выглядит struct module, то есть, зависит от того, какие опции конфигурации, упомянутые ранее, включены. Второй, __aeabi_unwind_cpp_pr0, — функция, специфичная ABI ARM, и последний — для наших вызовов функции printk.

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

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

hello: disagrees about version of symbol symbol_name

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

Изучаем ядро


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

Ядро использует следующую функцию для поиска в своей таблицы символов (в kernel/module.c):

bool each_symbol_section(bool (*fn)(const struct symsearch *arr,
                                    struct module *owner,
                                    void *data),
                         void *data)
{
        struct module *mod;
        static const struct symsearch arr[] = {
                { __start___ksymtab, __stop___ksymtab, __start___kcrctab,
                  NOT_GPL_ONLY, false },
                { __start___ksymtab_gpl, __stop___ksymtab_gpl,
                  __start___kcrctab_gpl,
                  GPL_ONLY, false },
                { __start___ksymtab_gpl_future, __stop___ksymtab_gpl_future,
                  __start___kcrctab_gpl_future,
                  WILL_BE_GPL_ONLY, false },
#ifdef CONFIG_UNUSED_SYMBOLS
                { __start___ksymtab_unused, __stop___ksymtab_unused,
                  __start___kcrctab_unused,
                  NOT_GPL_ONLY, true },
                { __start___ksymtab_unused_gpl, __stop___ksymtab_unused_gpl,
                  __start___kcrctab_unused_gpl,
                  GPL_ONLY, true },
#endif
        };

        if (each_symbol_in_section(arr, ARRAY_SIZE(arr), NULL, fn, data))
                return true;

        (...)

Структура, используемая в данной функции, определена в include/linux/module.h:

struct symsearch {
        const struct kernel_symbol *start, *stop;
        const unsigned long *crcs;
        enum {
                NOT_GPL_ONLY,
                GPL_ONLY,
                WILL_BE_GPL_ONLY,
        } licence;
        bool unused;
};

Примечание: данный код ядра не изменился значительно за последние четыре года (видимо, с момента рассматриваемого релиза ядра 3.0, — прим. пер.).

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

Данные эти статичны и постоянны, что означает, что они появятся в бинарнике ядра как есть. Сканируя ядро на предмет трех идущих друг за другом последовательностей состоящих из трех указателей в адресном пространстве ядра и следом идущих значений типа integer из определений в each_symbol_section, мы можем определить расположение таблиц символов и сигнатур, и воссоздать файл Module.symvers из бинарника ядра.

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

Я написал скрипт для декомпрессии и извлечения информации о символах ядра в автоматическом режиме. Это должно работать с любой свежей версией ядра, при условии, что ядро не перемещаемое (relocatable) и вы знаете базовый адрес в памяти, куда оно грузится. Скрипт принимает опции для количества и порядка следования битов (endianness) архитектуры, и по умолчанию использует значения, подходящие для ARM. Базовый адрес, однако, должен быть указан. Он может быть найден, на ядрах ARM, в dmesg:

$ adb shell dmesg | grep "\.init"
<5>[01-01 00:00:00.000] [0: swapper]      .init : 0xc0008000 - 0xc0037000   ( 188 kB)

(прим. пер. — однако, не все ядра выводят эти данные в лог, мне довелось встретить один такой практически уникальный случай, когда, видимо, ввиду урезанных опций конфигурации эта информация не выводилась, в таком случае можно обратиться к конфигу PAGE_OFFSET в файле arch/arm/Kconfig и просто надеяться, что вендор использовал одно из дефолтных значений).

Базовый адрес в примере выше — 0xc0008000.

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

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

$ python extract-symvers.py -B 0xc0008000 kernel-filename > Module.symvers

Сборка ядра


Теперь, когда мы имеем правильный файл Module.symvers для ядра, из которого мы хотим загрузить модуль, мы наконец можем собрать модуль (опять, полагая, arm-eabi-gcc доступно из PATH, и что терминал открыт в директории с исходниками):

$ cp /path/to/Module.symvers build/
$ make M=/path/to/module/source ARCH=arm CROSS_COMPILE=arm-eabi- O=build modules

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

$ adb shell
# insmod hello.ko
# dmesg | grep insmod
<6>[mm-dd hh:mm:ss.xxx] [id: insmod]Hello world
# lsmod
hello 586 0 - Live 0xbf008000 (P)
# rmmod hello
# dmesg | grep rmmod
<6>[mm-dd hh:mm:ss.xxx] [id: rmmod]Goodbye world

Данная статья является переводом публикации в блоге Mike Hommey.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331202/


Метки:  

Немного о ServiceNow, ITSM и ServiceDesk в формате подборки полезных материалов

Понедельник, 19 Июня 2017 г. 12:11 + в цитатник
Сегодня мы представляем вашему вниманию дайджест материалов по теме внедрения ServiceNow, ITSM и ServiceDesk. В этой подборке мы использовали только те материалы, которые подготовили самостоятельно и разместили в своем корпоративном блоге.

Изображение Dennis Skley CC

5 шагов для успешного внедрения ServiceNow
  • Как получить одобрение команды? Здесь мы сформировали краткий чеклист, который поможет начать процесс внедрения ITSM и заинтересовать будущих пользователей.

Тактика лучшего внедрения Service Desk — 7 шагов
  • Как не потерять работу, занимаясь внедрением новой системы? Мы собрали простые тактические решения, которые помогут все сделать правильно.

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

6 интересных фактов о компании ServiceNow
  • Интересные «пасхалки» для тех, кто сомневался в чувстве юмора мирового лидера среди производителей облачных ITSM-платформ.

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

Лучшие бесплатные ресурсы для специалиста ServiceNow
  • Быстро разобраться с принципами работы ServiceNow — не проблема. Тематический Slack-канал. сабреддиты, репозитории, официальные сообщества и лучшие практики.

Искусственный интеллект для классификации запросов в ServiceNow
  • Что следует из новостей о покупке системы машинного обучения DxContinuum? Как ServiceNow решит применить технологии этой компании? Об этом в нашем материале.

GRC — управление ИТ, управление рисками и соответствие требованиям в ServiceNow
  • Немного о том, как можно решать «взрослые задачи» по планированию развития и оценке рисков с помощью GRC-треноги (Governance, Risk, Compliance).



Что читать в 2017 году для успешного внедрения ServiceNow
  • С чего начать. Что есть на русском. Самое свежее на английском.

В чем причина популярности ServiceNow
  • PAAS, ITOM, ServiceNow Store и другие интересные особенности, которые позволяют платформе ServiceNow набирает обороты с каждым новым годом.

Инновационные способы использования ServiceNow
  • Интеграция Skype, прием корреспонденции, обслуживание клиентов, управление магазином и… автоматизация автогонок!

Интервью с CTO ServiceNow об инновациях, приоритетах и развитии ИТ
  • Как работает и распределяет свои ресурсы команда Аллана Лейнвана (Allan Leinwand) — насыщенное и краткое интервью в нашем блоге.

ServiceNow — релиз Istanbul
  • Детальный обзор интересных нововведений.



Как не надо внедрять ITSM в компании
  • Разбираемся с путаницей в терминологии, необходимостью планирования отдельного бюджета на внедрение и возможностью самостоятельного внедрения ITSM.

ITSM в облако. 9 преимуществ SaaS-платформы для ITSM
  • Говорим о стоимости сервиса, затратах на обслуживание, доступности, процессе внедрения, надежности и общем удобстве использования для сотрудников компании.

6 различий между Helpdesk и ServiceDesk
  • Кратко затрагиваем тему происхождения данных терминов, приводим обещанные 6 характерных особенностей и немного тематической статистики.

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

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

Правильно внедряем «Управление финансами в ИТ» (ITFM)
  • Смотрим на то, почему необходимо внедрение ITFM и разбираем несколько процессов модели ITIL. Помимо этого мы даем 5 рекомендаций для успешного внедрения проекта.

Что такое Управление портфелем проектов?
  • Знакомимся с понятием рисков в бизнесе и разбираемся с разницей между управлением портфелем проектов (PPM) и управления проектами (PM).



5 причин внедрения управления HR
  • Очевидные выгоды, которые может принести адекватная работа с персоналом. Для этого возможно использовать различные методы автоматизации и накопления знаний.

Как управлять эксплуатацией объекта недвижимости
  • Разбираемся с такими возможностями приложения Facilities Service Management как: каталог услуг, интерактивные карты, управление объектами и отчетностью.

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

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

Как сделать ITIL более клиентоориентированной
  • Ориентирована ли ITIL на клиента, как определить и выбрать клиентов, наладить обратную связь и оценить проделанную работу с точки зрения клиента.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330930/


Метки:  

[Перевод - recovery mode ] Страны Юго-Восточной Азии переходят на гибридную модель хранения данных

Понедельник, 19 Июня 2017 г. 11:50 + в цитатник
В соответствии с социологическим опросом 2017 года «Приоритеты сферы информационных технологий», проведенным компанией TechTarget и опубликованным в Computer Weekly, 40 % руководителей компаний, расположенных в странах Юго-Восточной Азии, в 2017 году планируют реализовать программу перехода на облачное хранение данных, а еще 40 % планируют запустить облачные резервные проекты.

image

Чтобы удовлетворить растущий спрос на облачное хранение данных, новые поставщики облачных решений организовали в регионе центры обработки данных. На рынке облачных технологий Юго-Восточной Азии уже действуют такие крупные игроки, как AWS, Microsoft, IBM, HP, Oracle, а также множество небольших центров обработки данных и провайдеров управляемых ИТ-услуг. Недавно в Сингапуре были созданы компании Alibaba Cloud и Google Cloud для привлечения клиентов из стран Юго-Восточной Азии.

«С выходом компаний Alibaba и Google на рынок облачного хранения данных руководители ИТ-компаний получат более широкий выбор услуг, и это выгодно для тех компаний, которые способны разработать облачную модель, будь то полное погружение компании в облако или внедрение гибридной облачной модели», — отметил Рик Скарфилд, президент компании NetApp APAC.

По словам Энди Кокса, технического директора в компании Dimension Data Asia Pacific, выход провайдеров облачных хранилищ данных на рынок данного региона больше всего повлияет на малые и средние предприятия. «Глядя на некоторых лидирующих поставщиков традиционных хранилищ данных на рынке, можно увидеть, что их рост ограничен рынком, а количество довольно небольшое, — отметил он. — Переход на услуги облачных, гипермасштабных поставщиков, таких как Amazon и Microsoft Azure, а также новых участников рынка, таких как Alibaba Cloud и Google Cloud, окажет значительное влияние на малые и средние предприятия».

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

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

Пол Серрано, главный специалист по пропаганде в компании Nutanix (Азия, страны Тихоокеанского региона и Япония), отметил: «Поскольку в 2017 году отделы информационных технологий предприятий будут оценивать облачные решения открытого доступа и на местах, вероятно, они придут к заключению, что облачные решения открытого доступа лучше подходят для гибкой рабочей нагрузки, то есть нагрузки без определенных требований». Но, по его словам, для многих компаний переход на облачное решение открытого доступа может быть преждевременным.

По мнению Прабхитхы Шитхал Дкруз, старшего рыночного аналитика, проводившего исследование в IDC, организации Азии/Тихоокеанского региона, Юго-Восточной Азии недостаточно быстро переходят на облачные технологии. «Организации в Юго-Восточной Азии довольно медленно принимают облачные технологии, — отметила она. — Рынок Юго-Восточной Азии менее развит, и свойственный ему консерватизм до сих пор ограничивал внедрение компаний AWS, Google и Azure, главным образом их отдельными рабочими операциями, а локальные провайдеры облачных решений должны еще увеличить свой потенциал до уровня, на котором они будут приняты крупными предприятиями».
Но по словам Дкруз, с выходом на рынок таких компаний, как Alibaba Cloud и Google Cloud, клиенты станут перемещать постоянную, второстепенную рабочую нагрузку в облачную инфраструктуру.

Компания Alibaba добилась успеха в Китае


В соответствии с полугодовым анализом IDC публичной облачной среды за первую половину 2016 года, компания Alibaba стала вторым лидирующим провайдером облачных услуг в Азиатско-Тихоокеанском регионе (за исключением Японии), обогнав Microsoft и Google. «Однако успех Alibaba ограничивается Китаем, и отсутствие обширной партнерской экосистемы за пределами Китая означает, что компания не окажет существенного влияния на рынок, за исключением влияния на китайские компании, осуществляющие операции за пределами Китая, и компаний Юго-Восточной Азии, осуществляющих деятельность в Китае, — отметила Дкруз. — Реалии корпоративного рынка отодвинут компанию Alibaba на второй план вместе с ее партнерами, занимающими лидирующее положение в совместной деятельности. Чтобы добиться доверия корпоративного рынка, компании Alibaba необходимо построить партнерскую экосистему для соответствия конкурентам».

Но Нишчал Кхорана, директор облачных технологий и центра обработки данных Азиатско-Тихоокеанского региона компании Frost & Sullivan, не видит таких ограниченных перспектив для компании Alibaba Cloud. «Исходя из долгосрочной перспективы, важно отметить, что рынок облачных хранилищ данных стран Юго-Восточной Азии является очень чувствительным к курсу ценных бумаг, давая возможность компании Alibaba Cloud выступать в качестве основного поставщика в регионе, учитывая ее агрессивную ценовую стратегию», — отметил он.

Однако по прогнозам Кхорана, пройдет некоторое время, прежде чем Alibaba Cloud достигнет успеха. «Индонезия, Малайзия и Филиппины являются быстрорастущими рынками облачной инфраструктуры в Юго-Восточной Азии с инфраструктурой как услугой на рынке, рост которого прогнозируется в размере от 40 до 50 % в год с 2015 по 2022 годы. В то время как Alibaba Cloud и Google находятся в выгодном положении для использования роста рынков облачных хранилищ данных, Amazon Web Services и Microsoft Azure в ближайшем будущем будут удерживать лидирующие позиции благодаря своему устойчивому присутствию».

Уменьшится ли объем рынка традиционных систем хранения данных?


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

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

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

Переход к гибридной модели


По словам Дкруз из компании IDC, организации в странах Юго-Восточной Азии все еще находятся «на незапланированных стадиях развития структуры IDC, зависящих от ситуации». Она добавила, что неоднородное состояние азиатского региона означает то, что не все страны будут следовать одной схеме, некоторые страны могут быстрее других принять решения облачного хранения данных для более сложных вариантов использования.

«Текущая система принятия облачных технологий ограничена резервным копированием, защитой данных или восстановлением в аварийных ситуациях, — отметила она. — Имея большое количество функций и привлекательные цены, облачные технологии хранения данных могут стать заманчивым предложением для многих организаций, но различные законодательные, культурные и политические последствия делают облачные технологии невыгодными для правительств стран Юго-Восточной Азии, которые продвигают внутренние облачные решения».
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330966/


Метки:  

ZFS on Linux: вести с полей 2017

Понедельник, 19 Июня 2017 г. 11:13 + в цитатник
ZFS является одной из самых нафаршированных файловых систем (ФС), а главное — она заботится о сохранности нашей информации.
Да, она не является «серебряной пулей», но в своей области показывает прекрасные результаты.
ZFS

Проект ZFS on Linux изначально был создан для портирования существующего кода из Solaris. После закрытия его исходного кода совместно с сообществом OpenZFS проект продолжил разработку ZFS для Linux. Код может быть собран как в составе ядра, так и в виде модуля.
image
Сейчас пользователь может создать пул с последней совместимой с Solaris версией 28, а также с приоритетной для OpenZFS версией 5000, после которого началось применение feature flags (функциональные флаги). Они позволяют создавать пулы, которые будут поддерживаться в FreeBSD, пост-Sun Solaris ОС, Linux и OSX вне зависимости от различий реализаций.

В 2016 году был преодолён последний рубеж, сдерживавший ZFS на Linux — многие дистрибутивы включили его в штатные репозитории, а проект Proxmox уже включает его в базовую поставку. Ура, товарищи!

Рассмотрим как наиболее важные отличия, так и подводные камни, которые есть в настоящее время в версии ZFS on Linux 0.6.5.10.

Начинать знакомство с ZFS стоит с изучения особенностей CopyOnWrite (CoW) файловых систем — при изменении блока данных старый блок не изменяется, а создается новый. Переводя на русский — происходит копирование при записи. Данный подход накладывает отпечаток на производительности, зато даёт возможность хранить всю историю изменения данных.
image

CoW подход в ZFS даёт огромные возможности: эта ФС не может иметь некорректного состояния, т.к. в случае проблем с последней транзакцией (например при отключении питания) будет использована последняя корректная.

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

Кратко о главных преимуществах ZFS для вашей системы.


Защита данных:
  1. контрольные суммы — гарантия корректности данных;
  2. возможность резервирования как на уровне создания зеркал и аналогов RAID массивов, так и на уровне отдельного диска (параметр copies);
  3. в отличие от многих файловых систем с их fsck на уровне журнала, ZFS проверяет все данные по контрольным суммам и умеет проводить их автоматическое восстановление по команде scrub (если в пуле есть живая копия битых данных);
  4. первая ФС, разработчики которой честно признались во всех возможных рисках при хранении — везде при упоминании ZFS можно встретить требование оперативной памяти с поддержкой ECC (любая ФС имеет риск повреждения при отсутствии ECC памяти, просто все, кроме ZFS, предпочитают не задумываться об этом);
  5. ZFS создавалась с учетом ненадёжности дисков, просто помните это и перестаньте волноваться о вашем WD Green Seagate etc (только, если рядом трудится ещё один выживший диск).


Максимальная гибкость вашего хранилища:
  1. закончилось место? Замените диск на более объёмный, и ваш покорный ZFS сам займёт новоотведённое ему место (по параметру autoexpand);
  2. лучшая реализация снапшотов среди файловых систем для Linux. На это подсаживаешься. Инкрементально по сети, в архив, /dev/null, да хоть раздвойте личность вашего дорогого Linux в реальном времени (clone);
  3. нужно больше золота места? 256 зебибайт хватит всем!


Структура.


В ZFS структура хранилища выглядит следующим образом:
- pool
-- vdev (virtual device) - объединяет носители (в mirror, stripe и др.)
--- block device - диск, массив, файл

В пуле может быть неограниченное количество vdev, что позволяет создать пул из двух и более mirror, RAID-Z или других сочетаний. Также доступны классические RAID10 и т.д.

Типы массивов:


Stripe — обычный RAID0.

Mirror — RAID1 на манер ZFS — реплицируются только занятые блоки, забудьте о синхронизации пустого места.

RAID-Z — создавался как замена RAID5-6, но имеет большие отличия:
— каждый блок данных — аналог отдельного массива (с динамической длинной);
— отсутствует проблема write hole;
— при ребилде создаются только данные (т.е. риск сбоя в этот момент уменьшается). Также в тестовой ветке уже находятся улучшения, которые дополнительно ускорят этот процесс.
Рекомендуется использовать RAID-Z2 (аналог RAID6).
При создании RAID-Z стоит обязательно изучить эту статью, основные нюансы:
— IOPS равен самому медленному диску (создавайте RAID-Z с наименьшим количеством дисков);
— эффективность утилизации места увеличивается при бОльшем количестве дисков в массиве (требуется задать корректный recordsize, см. ссылку выше);
— в существующий массив RAID-Z нельзя добавить ещё один диск (пока), но можно заменить диски на более ёмкие. Эта проблема решается созданием нескольких массивов в рамках одного vdev.

dRAID (в разработке) — базируется на наработках RAID-Z, но при сбое позволяет задействовать на чтение-запись все диски массива.

ARC — умное кеширование в ZFS.


CoW ухудшает производительность. Для сглаживания ситуации был создан adaptive replacement cache (ARC). Его основная особенность в проработанных эвристиках для исключения вымывания кеша, в то время как обычный page cache в Linux к этому очень чувствителен.

Бонусом к ARC существует возможность создать быстрый носитель со следующим уровнем кеша — L2ARC. При необходимости он подключается на быстрые SSD и позволяет заметно улучшить IOPS HDD дисков. L2ARC является аналогом bcache со своими особенностями.

L2ARC стоит использовать только после увеличения ОЗУ на максимально возможный объём.

Также существует возможность вынести запись журнала — ZIL, что позволит значительно ускорить операции записи.

Дополнительные возможности.


Компрессия — с появлением LZ4 позволяет увеличить скорость IO за счёт небольшой нагрузки на процессор. Нагрузка настолько мала, что включение данной опции уже является повсеместной рекомендацией. Также есть возможность воспользоваться другими алгоритмами (для бекапов прекрасно подходит gzip).

Дедупликация — особенности: процесс дедупликации производится синхронно при записи, не требует дополнительной нагрузки, основное требование — ~ 320 байт ОЗУ на каждый блок данных (Используйте команду zdb -S название_пула для симуляции на существующем пуле) или ~ 5гб на каждый 1 тб. В ОЗУ хранится т.н. Dedup table (DDT), при недостатке ОЗУ каждая операция записи будет упираться в IO носителя (DDT будет читаться каждый раз с него).
Рекомендуется использовать только на часто повторяющихся данных. В большинстве случаев накладные расходы не оправданы, лучше включить LZ4 шифрование.

Снапшоты — в силу архитектуры ZFS абсолютно не влияют на производительность, в рамках данной статьи на них останавливаться не будем. Отмечу только прекрасную утилиту zfs-auto-snapshot, которая создаёт их автоматически в заданные интервалы времени. На производительности не отражается.

Шифрование (в разработке) — будет встроенным, разрабатывается с учётом всех недостатков реализации от Oracle, а также позволит штатными send/receive и scrub отправлять и проверять данные на целостность без ключа.

Основные рекомендации (TL;DR):


— Заранее продумайте геометрию массива, в настоящий момент ZFS не умеет уменьшаться, а также расширять существующие массивы (можно добавлять новые или менять диски на более объёмные);
— используйте сжатие:
compression=lz4
— храните расширенные атрибуты правильно, по умолчанию хранятся в виде скрытых файлов (только для Linux):
xattr=sa
— отключайте atime:
atime=off
— выставляйте нужный размер блока (recordsize), файлы меньше recordsize будут записываться в уменьшенный блок, файлы больше recordsize будут записывать конец файла в блок с размером recordsize (при recordsize=1M файл размером 1.5мб будет записан как 2 блока по 1мб, в то время как файл 0.5мб будет записан в блок размером 0.5мб). Больше — лучше для компрессии:
recordsize=128K
— ограничьте максимальный размер ARC (для исключения проблем с количеством ОЗУ):
echo "options zfs zfs_arc_max=половина_ОЗУ_в_байтах" >> /etc/modprobe.d/zfs.conf
echo половина_ОЗУ_в_байтах >> /sys/module/zfs/parameters/zfs_arc_max

— дедупликацию используйте только по явной необходимости;
— по возможности используйте ECC память;
— настройте zfs-auto-snapshot.

Важные моменты:


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

В настоящий момент ZFS on Linux уже является стабильным продуктом, но плотная интеграция в существующие дистрибутивы будет проходить ещё некоторое время.

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

Я, gmelikov, состою в проекте ZFS on Linux и готов с радостью ответить на любые вопросы!
Отдельно хочу пригласить к участию, всегда рады issues и PR, а также готовы помочь вам в наших mailing lists.

Полезные ссылки:
ZFS on Linux github page
FAQ
ZFS Performance tuning
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/314506/


Борьба за время сборки iOS-приложений

Понедельник, 19 Июня 2017 г. 11:12 + в цитатник
Чуть больше месяца назад мы выпустили iOS-приложение «Тинькофф Инвестиции». Приложение полностью написано на языке Swift, но имеет некоторые Objective-C-зависимости. Продукт быстро начал обрастать новой функциональностью, а вместе с тем время сборки проекта существенно увеличивалось. Когда мы пришли к тому, что после clean или значительных правок проект собирался дольше шести минут, мы осознали, что перемены необходимы.

image

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

1. Участки кода, сложные для компиляции.


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

xcodebuild -workspace App.xcworkspace -scheme App clean build OTHER_SWIFT_FLAGS="-Xfrontend -debug-time-function-bodies" | grep .[0-9]ms | grep -v ^0.[0-9]ms | sort -nr > functions_build_analysis.txt

где «App.xcworkspace» — название файла workspace вашего проекта, «App» — название схемы, по которой нужно сделать билд.

Мы передаем флаги "-Xfrontend -debug-time-function-bodies" для отладки процесса компиляции и учета времени на компиляцию каждой функции. С помощью grep мы выбираем строки, содержащие время компиляции, затем выводим отсортированный результат в файл functions_build_analysis.txt.

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

let object = Object(param1: param1Value ?? defaultParam1Value,
  param2: param2Value ?? defaultParam2Value)

Мы вынесли вычисление значения параметра в отдельную строку выше, и проблема была решена — время компиляции функций сократилось до 300 миллисекунд.

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

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

2. Сборка только выбранной архитектуры для Debug-билдов.




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

Поскольку в нашем проекте этот флаг уже был установлен в Yes, мы не добились выигрыша в этом пункте. Но ради эксперимента мы опробовали сборку с флагом, выставленным в No. Для этого пришлось повозиться с Pod’ами, потому что они тоже были готовы предоставить скомпилированный код только для активной архитектуры. Время сборки проекта в итоге составило 10 минут 21 секунду, что действительно почти в два раза больше, чем изначальное.

3. Whole Module Optimization.


У Swift-компилятора есть флаг под названием «-whole-module-optimization». Он отвечает за то, каким образом будут обрабатываться файлы во время компиляции: будут ли они компилироваться по одному или сразу собираться в модуль. В Xcode управлять этим флагом можно с помощью секции «Optimization Level», однако по умолчанию нам доступны только эти опции:



Использование Whole Module Optimization существенно уменьшает время компиляции debug-сборок. Но вместе с этим флагом нам добавляют флаг «-O», который включает SIL-оптимизатор, и возникает проблема — проект перестает поддаваться отладке. В консоли мы видим следующее:

App was compiled with optimization - stepping may behave oddly; variables may not be available.

Чтобы сохранить возможность сборки сразу целого модуля и отключить оптимизацию, можно добавить флаг «-Onone» в секции «Other Swift Flags». В итоге для отладки мы получаем сборку, максимально быстро собирающуюся за счет отключения всякого рода оптимизаций. В нашем проекте это дало поразительные результаты — скорость сборки debug увеличилась почти в 3 раза.

4. Precompiled Bridging Headers.


Есть еще один флаг компилятора, который помогает сократить время компиляции. Но работает он только для сборок без флага «-whole-module-optimization» и, скорее, может быть полезен для Release-сборок. Это флаг «-enable-bridging-pch».



Помогает он не во всех случаях, а только в проектах с Bridging-хедерами от Objective-C. Эффект заключается в том, что каждый раз во время сборки компилятор не перестраивает таблицу бриджинга Objective-C методов в Swift.

Для нашего проекта с выключенным флагом «-whole-module-optimization» и включенным «-enable-bridging-pch» выигрыш во времени составил около 15%.

Итоги


По итогам исследования для ускорения компиляции вашей Debug-сборки можно выделить два основных способа: оптимизация самого кода для компилятора и использование флага «whole-module-optimization». Нам удалось снизить чистое время сборки проекта (clean build) с 6 минут до 1 минуты 20 секунд, половину из которых занимает сборка сторонних зависимостей. Если у вас есть свой опыт борьбы с компилятором Swift, поделитесь в комментариях.

P.S.: железо, на котором проводились тесты:
Mac mini (Late 2012)
2,3 GHz Intel Core i7
16 GB 1600 MHz DDR3
250 GB SSD
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331044/


Метки:  

Частоты и емкость сети — все, о чем вы хотели спросить

Понедельник, 19 Июня 2017 г. 11:03 + в цитатник
Помнится, в школьные годы многие задавались вопросом: «а зачем мне изучать основы физики или математического анализа, если в жизни мне это не пригодится?». Тогда казалось, что во взрослую жизнь можно идти, зная лишь простейшие математические операции (чтобы не ошибиться в магазине с продуктами). Но развитие технологий привело к тому, что рядовым пользователям в руки попали довольно мощные и сложные инструменты. Взять хотя бы мобильную связь. Чтобы грамотно выбирать оператора, понимать, почему где-то мобильная связь есть, а где-то ее нет, приходится вспоминать не только школьные учебники, но и вещи, выходящие далеко за их рамки.

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




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

Немного теории беспроводной передачи данных


Данные (аналоговые или цифровые) «закладываются» в волну при помощи модуляции — процесса, при котором определенные параметры сигнала высокой частоты (несущего) изменяются с низкой частотой. Именно модуляция дает возможность использовать для передачи различной информации весь радиодиапазон, не ограничиваясь лишь частотами, соответствующими нашему голосу.

Модуляция аналогового сигнала


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

Рис. 1. Пример: амплитудная модуляция
 
При передаче аналогового сообщения передатчик использует модуляцию, чтобы «заложить» полезный сигнал в несущую частоту, и передает ее при помощи антенны приемнику. Последний проделывает обратную процедуру — демодуляцию — выделяя изначальный сигнал.
 
Модуляция меняет спектр передаваемого сигнала — с одной единственной частоты он расширяется, а степень и характер этих изменений зависят от типа модуляции. Таким образом, для передачи полезного сигнала без потерь необходима целая полоса частот, ширина которой в простейшем случае модуляции гармоническим сигналом грубо определяется двойной частотой модулирующего сигнала (см. рис. 2).
 

Рис. 2. Простейший пример: высокочастотная несущая модулируется низкочастотным гармоническим сигналом. В спектре суммарного сигнала появляются дополнительные частоты
 

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

Модуляция цифрового сигнала


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

Рис. 4. Амплитудная, частотная и фазовая модуляции дискретного сигнала
 
К ним можно отнести схемы, при которых дискретный сигнал проходит предварительную обработку перед модуляцией для сжатия итоговой спектральной полосы, требующейся для передачи сигнала с минимальными потерями. Хороший пример — используемая в стандарте GSM гаусcовская частотная модуляция с минимальным частотным сдвигом (Gaussian Minimum Shift Keying — GMSK) — разновидность частотной модуляции. Она сокращает спектральную полосу и допускает использование нелинейных усилителей, которые лучше подходят для маленького мобильного аппарата с ограниченной емкостью батареи. Помимо GSM, GMSK-модуляция используется в автоматической идентификационной системе на флоте, в Bluetooth, GPRS, EDGE, CDPD и других приложениях.
 
В сетях LTE используются иные варианты модуляции — OFDM и SC-FDMA, отличающиеся лучшей устойчивостью к помехам. Ранее эти схемы просто не могли быть реализованы из-за дороговизны требуемых вычислительных мощностей.

Радиодиапазон


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

Рис. 8. Положение радиодиапазона на шкале ЭМИ
 
В зависимости от частоты, электромагнитные волны по-разному рассеиваются и отражаются препятствиями. С учетом этого внутри упомянутого отрезка частот выделены диапазоны под различные нужды: радио, телевидение, военные и гражданские фиксированные службы, авиация, морское сообщение и т.п. К примеру, для связи с подводным флотом используются волны, способные проникать в глубь воды (длина волны — десятки километров, глубина проникновения — порядка десятков метров), а для космической связи выбран диапазон миллиметровых волн, проникающих через ионосферу Земли.
 
Упомянутые поддиапазоны сначала «резервировались» под определенные задачи инженерами, а затем их выделенный статус подтверждался международными соглашениями, учитывающими возможность распространения тех или иных сигналов за пределы географических границ (трансграничное согласование частотных присвоений — это тема отдельного долгого разговора). В ходе глобализации определилась и еще одна цель согласованного выделения частот — импорт и экспорт оборудования связи для своего сегмента.
 

Рис. 9. Радиодиапазон
 
С частью радиодиапазона рядовой пользователь не сталкивается ни разу в жизни, но есть определенные частоты, которыми он пользуется чуть ли не ежедневно, например:
  • радиодиапазон, закрепленный за FM-станциями (FM — отсылка к частотной модуляции, принятой в диапазоне) — 87,5 — 108,0 МГц;
  • «гражданский» или Си-Би (Citizen`s Band) диапазон 27 МГц (26,965—27,405 МГц) — известен радиолюбителям; диапазон активно использовался автомобилистами до повсеместного распространения мобильных телефонов;
  • LPD — диапазон для маломощной пользовательской радиосвязи, в частности, пультов сигнализации, радионянь и прочих применений (тут выделено целых 3 диапазона: 403 — 410 МГц, 417 — 422 МГц и 433 — 447 МГц);
  • эфирное телевидение (49,75 — 56,25 МГц для 1 частотного канала и т.п.);
  • мобильная связь стандарта GSM, в частности, 890 — 915/935 — 960 МГц для GSM-900; 1710 — 1785/1805 — 1880 МГц для GSM-1800 (в других странах используются также GSM-450, GSM-850 и GSM-1900);
  • 3G (UMTS: 1885 МГц — 2025 МГц для uplink и 2110 МГц — 2200 МГц для downlink);
  • спутниковое телевидение (Ku-диапазон — 12-18 ГГц).

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

Законодательное регулирование


В России частотным регулированием (в части спектра, не переданной военным) занимается Государственная комиссия по радиочастотам (ГКРЧ) — процесс регламентирует федеральный закон «О связи».
 
Для выделения частоты оператор подает заявку и ждет очередного заседания ГКРЧ. ГКРЧ принимает решение о выделении диапазона, но, если оно положительное, это еще не обещает запуска услуги. С этим решением, а также деталями планируемого строительства (точками размещения базовых станций, мощностями передатчиков и т.п.) оператор идет в ФГУП «ГРЧЦ», где проверяется совместимость стандарта связи, который предполагается использовать на данной частоте, с существующим и планируемым к использованию оборудованием соседних диапазонов. На этом этапе оператор может получить отказ, например, от военных. Процедура, к слову, платная, вне зависимости от результата.
 
Лишь после этого Федеральная служба по надзору в сфере связи, информационных технологий и массовых коммуникаций выдает разрешение. Если на частоту претендует несколько операторов, ресурс распределяется на конкурсной, а в последнее время — на аукционной основе.
 
Существует такая процедура, как расчистка частот — когда по заказу оператора военными или другими заинтересованными организациями высвобождается определенный диапазон частот. Но этот процесс никак не регламентирован — все держится на взаимной договоренности компаний.
 
Частотный диапазон может выделяться на ограниченный срок (10 лет) на всей территории страны или в отдельном регионе (поэтому у федерального оператора может быть разный набор лицензий в разных частях страны). По истечении срока, указанного в разрешении, документы переоформляются, если, конечно, нет причин отказа, например, диапазон запланирован под другую технологию.
 
Получая частоту, оператор берет на себя определенные обязательства: начать предоставлять услуги, под которые выделяется частота, в течение заранее оговоренного срока. Речь в данном случае идет не только о мобильной связи, но о беспроводных услугах вообще — трансляция телевидения, интернет. Если это условие не выполняется, оператор может лишиться диапазона.
 
Политика оплаты использования частот за время существования мобильной связи менялась несколько раз. Сначала операторы платили за каждый объект связи (базовую станцию), затем — за использование частот в отдельном регионе (условия выделения частоты при этом могли содержать пункт о выплате денежной компенсации предыдущему владельцу диапазона, как это было при выделении частот LTE на конкурсе 2012 года). А т.к. разрешения на разные участки спектра в разных регионах оформлялись не единовременно, условия оказались неодинаковыми для отдельных участников рынка, что выливалось в склоки и борьбу компаний между собой за ценный ресурс. В последние годы был принят ряд мер, уравнивающих права компаний на частоты. В частности, с 2015 года начались аукционы (это совершенно не означает, что теперь все частоты выделяются в рамках аукционов, но до 2015 года подобной практики не было), а в 2016 вышло обобщенное решение о распределении частот, уравнивающее условия использования частот (зону покрытия, допустимые технологии для отдельных участков спектра и т.п.).
 
Текущая «картина» распределения частот в Москве (на ноябрь 2016) представлена на рисунке ниже.

Рис. 10. Распределение частот в Москве
 
Лидерами по количеству частот под цифровую мобильную связь в России на данный момент являются МТС и Мегафон.

Диапазоны мобильной связи


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

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

О поколениях мобильной связи
Стандарты современной мобильной связи описаны в спецификации 3GPP (The 3rd Generation Partnership Project) — партнерства ведущих организаций в сфере стандартизации телекоммуникационных технологий. В названии партнерства речь идет о «третьем поколении» связи, но GSM обычно рассматривается в качестве 2 и 2.5 поколения (2G и 2.5G, соответственно). После завершения работы над спецификацией GSM, организация занялась разработкой 3G (UMTS), а затем pre-4G (LTE) и 4G (LTE-Advanced).

 

Рис. 11. Развитие мобильной связи
 
Повсеместно разработанные 3GPP стандарты не заменяют друг друга, а сосуществуют вместе, в рамках сетей одних операторов — новые технологии не одномоментно вытесняют старые.
 
Если рассматривать ситуацию в теории, то все указанные частотные отрезки могут использоваться под связь 4G: сети нового поколения разрабатывались так, чтобы максимально задействовать существующую инфраструктуру. С расчетом на это 3GPP классифицировали возможные диапазоны (bands), присвоив каждому порядковый номер и дав рекомендации по деталям организации передачи (в частности, по способу деления канала между абонентами). Общий список каналов можно найти здесь.
 
На практике некоторые участки спектра закреплены ГКРЧ за определенными технологиями, так что начать там предоставление услуг оператор не может (например, в диапазоне 2100 МГц должны предоставляться услуги 3G, хотя операторы с удовольствием отвели бы его под LTE). Для других же действует принцип технологической нейтральности, согласно которому оператор, владеющий частотой, может использовать ее не только для организации связи по стандарту GSM, но и для технологий следующих поколений (3G, 4G). В итоге у нас же на момент написания данной статьи для 4G используются лишь диапазоны 3 (1800 МГц), 7 (2600 МГц), 20 (800 МГц) и 38 (2600 МГц) в классификации 3GPP.

Учитывая разницу в характере распространения волн каждого из диапазонов в помещении и на открытом пространстве, а также различие в политике операторов относительно поддержки этих диапазонов, пользователям при выборе оборудования приходится превращаться в специалистов по частотному регулированию.
 
Наилучшим вариантом будет аппарат с поддержкой всех используемых у нас диапазонов. Но «минимально рекомендуемый» вариант — это поддержка диапазонов 3 и еще одного: 7 или 38 (в зависимости от оператора).
 
Если не учитывать диапазоны, можно остаться вообще без 4G, как это происходит с владельцами некоторых американских iPhone SE (а именно — модели A1662): в списке диапазонов LTE, поддерживаемых устройством, лишь 20-й как-то развивается в России, и то не во всех регионах (в моделях для международного рынка также присутствует диапазон 7, распространенный у нас, и 38 для TD-LTE).

Оптимизация использования частотного ресурса


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

Общая емкость неизбежно зависит от ширины спектральной полосы (а также ее расположения в радиодиапазоне). Так что операторами востребованы технологии все более эффективного использования доступной спектральной полосы, реализуемые в каждом последующем поколении мобильной связи.
 
В 2G для повышения емкости (на фоне аналоговых стандартов и цифровой связи первого поколения) использовалось сочетание FDMA и TDMA. Во-первых, абонентские устройства были разделены по частотным каналам по принципу FDMA (Frequency Division Multiple Access — множественный доступ с частотным разделением каналов).
 

Рис. 13. TDMA и FDMA
 
Сети третьего поколения используют иной принцип разделения частотных каналов — кодовый или CDMA (Code Division Multiple Access), который позволяет повысить емкость сети при том же используемом частотном диапазоне, а заодно и обеспечить больший уровень безопасности.
В сетях LTE используется либо временное, либо частотное разделение каналов (TDD и FDD, соответственно), но реализованы они иначе, нежели в GSM (2G). TDD (TD-LTE) использует всю ширину спектральной полосы (от 1,4 до 20 МГц) для передачи данных в двух направлениях по очереди; при этом временные отрезки для передачи данных в каждом из направлений могут быть не равны. В FDD (FD-LTE) диапазон разделяется на 2 полосы в общем случае не равных полосы: для каждого из направлений передачи данных. Спецификация рекомендует применять либо FDD, либо TDD для каждого из предписанных для LTE диапазонов (http://en.wikipedia.org/wiki/LTE_frequency_bands#Frequency_bands_and_channel_bandwidths), поскольку метод TDD показал себя лучше на высоких частотах, а FDD, соответственно, на низких. Стоит отметить, что особенность стандарта LTE позволяет сравнительно недорого интегрировать поддержку обоих методов в одном устройстве, поэтому оборудование, поддерживающие и FDD, и TDD не редкость.

Дополнительно пропускная способность доступного спектра в LTE увеличивается за счет технологии многоантенной передачи MIMO (Multiple input-multiple output).

Глазами конечного абонента


Последний момент, о котором хотелось бы поговорить в этой статье — то, как выглядят услуги глазами конечных абонентов.
 
Скорость передачи данных для абонента неизбежно зависит от ширины спектральной полосы, отведенной для его потока информации. Если в поколениях 2G и 3G скорость была ограничена самим стандартом связи, то благодаря нововведениям 4G, скорость в большей степени определяется возможностями устройства.
 
В 4G (а точнее в LTE-Advanced, признанном Международным союзом электросвязи истинным стандартом 4G) появился механизм увеличения абонентской скорости — агрегация частот, в том числе из разных частотных диапазонов. В зависимости от характеристик устройство может задействовать до 4 полос по 20 МГц (в двух столицах на данный момент задействовать можно максимально 3 полосы у «Мегафона»). Для агрегации 4х несущих устройство должно относиться к категории 16 (CAT16). 4х4 MIMO совместно с агрегацией позволяет скачивать данные на таких устройствах со скоростью до 980 Мбит/с. 3 несущие агрегируют устройства категорий 9 и 12 (CAT9 со скростью до 450 Мбит/с и CAT12 с 600 Мбит/с, соответственно), а наиболее простые устройства CAT4 вовсе не агрегируют, достигая скорости не более 150 Мбит/с. Подробнее о непосредственно моделях, поддерживающих ту или иную скорость,здесь.

Работает ли заявленная теорией агрегация на практике в условиях реального радиоприема? В рамках тестов Мегафоном на оборудовании Huawei была продемонстрирована скорость в 1 Гбит/с. Для этого использовалась агрегация трех несущих.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331082/


Метки:  

Индексы в PostgreSQL — 4

Понедельник, 19 Июня 2017 г. 10:41 + в цитатник

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

Btree


Устройство


Индекс btree, он же B-дерево, пригоден для данных, которые можно отсортировать. Иными словами, для типа данных должны быть определены операторы «больше», «больше или равно», «меньше», «меньше или равно» и «равно». Заметьте, что одни и те же данные иногда можно сортировать разными способами, что возвращает нас к концепции семейства операторов.

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

B-деревья обладают несколькими важными свойствами:
  • Они сбалансированы, то есть любую листовую страницу отделяет от корня одно и то число внутренних страниц. Поэтому поиск любого значения занимает одинаковое время.
  • Они сильно ветвисты, то есть каждая страница (как правило, 8 КБ) содержит сразу много (сотни) TID-ов. За счет этого глубина B-деревьев получается небольшой; на практике до 4–5 для очень больших таблиц.
  • Данные в индексе упорядочены по неубыванию (как между страницами, так и внутри каждой страницы), а страницы одного уровня связаны между собой двунаправленным списком. Поэтому получить упорядоченный набор данных мы можем, просто проходя по списку в одну или в другую сторону, не возвращаясь каждый раз к корню.

Вот схематичный пример индекса по одному полю с целочисленными ключами.



В самом начале файла находится метастраница, которая ссылается на корень индекса. Ниже корня расположены внутренние узлы; самый нижний ряд — листовые страницы. Стрелочки вниз символизируют ссылки из листовых узлов на строки таблицы (TID-ы).

Поиск по равенству


Рассмотрим поиск значения в дереве по условию «индексированное-поле = выражение». Допустим, нас интересует ключ 49.



Поиск начинается с корневого узла, и нам надо определить, в какой из дочерних узлов спускаться. Зная находящиеся в корневом узле ключи (4, 32, 64) мы тем самым понимаем диапазоны значений в дочерних узлах. Поскольку 32 <= 49 < 64, надо спускаться во второй дочерний узел. Дальше та же процедура повторяется рекурсивно до тех пор, пока не будет достигнут листовой узел, из которого уже можно получить необходимые TID-ы.

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

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

Поиск по неравенству


При поиске по условию «индексированное-поле <= выражение» ( или «индексированное-поле >= выражение»), сначала находим в индексе значение по условию равенства «индексированное-поле = выражение» (если оно есть), а затем двигаемся по листовым страницам до конца в нужную сторону.

Рисунок иллюстрирует этот процесс для условия n <= 35:



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

Поиск по диапазону


При поиске по диапазону «выражение1 <= индексированное-поле <= выражение2» находим значение по условию «индексированное-поле = выражение1», а затем двигаемся по листовым страницам, пока выполняется условие «индексированное-поле <= выражение2». Или наоборот: начинаем со второго выражения и двигаемся в другую сторону, пока не дойдем до первого.

На рисунке показан процесс для условия 23 <= n <= 64:



Пример


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

demo=# select * from aircrafts;
aircraft_code | model | range
---------------+---------------------+-------
773 | Boeing 777-300 | 11100
763 | Boeing 767-300 | 7900
SU9 | Sukhoi SuperJet-100 | 3000
320 | Airbus A320-200 | 5700
321 | Airbus A321-200 | 5600
319 | Airbus A319-100 | 6700
733 | Boeing 737-300 | 4200
CN1 | Cessna 208 Caravan | 1200
CR2 | Bombardier CRJ-200 | 2700
(9 rows)

demo=# create index on aircrafts(range);
CREATE INDEX

demo=# set enable_seqscan = off;
SET

(Или явно create index on aircrafts using btree(range), но по умолчанию строится именно B-дерево.)

Поиск по равенству:

demo=# explain(costs off) select * from aircrafts where range = 3000;
QUERY PLAN
---------------------------------------------------
Index Scan using aircrafts_range_idx on aircrafts
Index Cond: (range = 3000)
(2 rows)

Поиск по неравенству:

demo=# explain(costs off) select * from aircrafts where range < 3000;
QUERY PLAN
---------------------------------------------------
Index Scan using aircrafts_range_idx on aircrafts
Index Cond: (range < 3000)
(2 rows)

И по диапазону:

demo=# explain(costs off) select * from aircrafts where range between 3000 and 5000;
QUERY PLAN
-----------------------------------------------------
Index Scan using aircrafts_range_idx on aircrafts
Index Cond: ((range >= 3000) AND (range <= 5000))
(2 rows)

Сортировка


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

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

Порядок сортировки


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

demo=# create index on aircrafts(range desc);

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

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

demo=# create view aircrafts_v as
select model,
case
when range < 4000 then 1
when range < 10000 then 2
else 3
end as class
from aircrafts;
CREATE VIEW

demo=# select * from aircrafts_v;
model | class
---------------------+-------
Boeing 777-300 | 3
Boeing 767-300 | 2
Sukhoi SuperJet-100 | 1
Airbus A320-200 | 2
Airbus A321-200 | 2
Airbus A319-100 | 2
Boeing 737-300 | 2
Cessna 208 Caravan | 1
Bombardier CRJ-200 | 1
(9 rows)

И создадим индекс (с использованием выражения):

demo=# create index on aircrafts(
(case when range < 4000 then 1 when range < 10000 then 2 else 3 end), model);
CREATE INDEX

Теперь мы можем использовать этот индекс, чтобы получить данные, отсортированные по обоим столбцам по возрастанию:

demo=# select class, model from aircrafts_v order by class, model;
class | model
-------+---------------------
1 | Bombardier CRJ-200
1 | Cessna 208 Caravan
1 | Sukhoi SuperJet-100
2 | Airbus A319-100
2 | Airbus A320-200
2 | Airbus A321-200
2 | Boeing 737-300
2 | Boeing 767-300
3 | Boeing 777-300
(9 rows)

demo=# explain(costs off) select class, model from aircrafts_v order by class, model;
QUERY PLAN
--------------------------------------------------------
Index Scan using aircrafts_case_model_idx on aircrafts
(1 row)

Точно так же можно выполнить запрос с сортировкой по убыванию:

demo=# select class, model from aircrafts_v order by class desc, model desc;
class | model
-------+---------------------
3 | Boeing 777-300
2 | Boeing 767-300
2 | Boeing 737-300
2 | Airbus A321-200
2 | Airbus A320-200
2 | Airbus A319-100
1 | Sukhoi SuperJet-100
1 | Cessna 208 Caravan
1 | Bombardier CRJ-200
(9 rows)

demo=# explain(costs off)
select class, model from aircrafts_v order by class desc, model desc;
QUERY PLAN
-----------------------------------------------------------------
Index Scan Backward using aircrafts_case_model_idx on aircrafts
(1 row)

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

demo=# explain(costs off)
select class, model from aircrafts_v order by class asc, model desc;
QUERY PLAN
-------------------------------------------------
Sort
Sort Key: (CASE ... END), aircrafts.model DESC
-> Seq Scan on aircrafts
(3 rows)

(Заметьте, что с горя планировщик выбрал сканирование таблицы, даже несмотря на установку enable_seqscan = off, сделанную ранее. Это потому, что на самом деле она не запрещает сканирование таблицы, а только устанавливает ему запредельную стоимость — посмотрите план с «costs on».)

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

demo=# create index aircrafts_case_asc_model_desc_idx on aircrafts(
(case when range < 4000 then 1 when range < 10000 then 2 else 3 end) asc, model desc);
CREATE INDEX

demo=# explain(costs off)
select class, model from aircrafts_v order by class asc, model desc;
QUERY PLAN
-----------------------------------------------------------------
Index Scan using aircrafts_case_asc_model_desc_idx on aircrafts
(1 row)

Порядок столбцов


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

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



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

Из этой схемы понятно, что поиск будет работать эффективно с такими, например, предикатами, как «class = 3» (поиск только по первому полю) или «class = 3 and model = 'Boeing 777-300'» (поиск по обоим полям).

А вот поиск по предикату «model = 'Boeing 777-300'» будет куда менее эффективным: начиная с корня, мы не можем определить, в какой из дочерних узлов спускаться, поэтому спускаться придется во все. Это не значит, что такой индекс не может использоваться в принципе — вопрос только в эффективности. Например, если бы у нас было три класса самолетов и очень много моделей в каждом классе, то нам пришлось бы просмотреть примерно треть индекса, и это могло бы оказаться эффективнее, чем полное сканирование таблицы. А могло бы и не оказаться.

Зато если создать индекс таким образом:

demo=# create index on aircrafts(
model, (case when range < 4000 then 1 when range < 10000 then 2 else 3 end));
CREATE INDEX

то порядок полей поменяется:



И с таким индексом поиск по предикату «model = 'Boeing 777-300'» будет выполняться эффективно, а по предикату «class = 3» — нет.

Неопределенные значения


Метод доступа btree индексирует неопределенные значения и поддерживает поиск по условиям is null и is not null.

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

demo=# create index on flights(actual_arrival);
CREATE INDEX
demo=# explain(costs off) select * from flights where actual_arrival is null;
QUERY PLAN
-------------------------------------------------------
Bitmap Heap Scan on flights
Recheck Cond: (actual_arrival IS NULL)
-> Bitmap Index Scan on flights_actual_arrival_idx
Index Cond: (actual_arrival IS NULL)
(4 rows)

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

demo=# explain(costs off) select * from flights order by actual_arrival nulls last;
QUERY PLAN
--------------------------------------------------------
Index Scan using flights_actual_arrival_idx on flights
(1 row)

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

demo=# explain(costs off) select * from flights order by actual_arrival nulls first;
QUERY PLAN
----------------------------------------
Sort
Sort Key: actual_arrival NULLS FIRST
-> Seq Scan on flights
(3 rows)

Чтобы индекс мог использоваться, надо создать его так, чтобы неопределенные значения шли в начале:

demo=# create index flights_nulls_first_idx on flights(actual_arrival nulls first);
CREATE INDEX
demo=# explain(costs off) select * from flights order by actual_arrival nulls first;
QUERY PLAN
-----------------------------------------------------
Index Scan using flights_nulls_first_idx on flights
(1 row)

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

demo=# \pset null NULL
Null display is "NULL".
demo=# select null < 42;
?column?
----------
NULL
(1 row)

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

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

Свойства


Посмотрим свойства метода доступа btree (запросы приводились ранее).

amname | name | pg_indexam_has_property
--------+---------------+-------------------------
btree | can_order | t
btree | can_unique | t
btree | can_multi_col | t
btree | can_exclude | t

Как мы видели, B-дерево может упорядочивать данные и поддерживает уникальность — и это единственный метод доступа, который обеспечивает такие свойства. Индексы по нескольким столбцам также допустимы; но это умеют и другие методы (хотя и не все). Про поддержку ограничений exclude мы, не без причины, поговорим в следующий раз.

name | pg_index_has_property
---------------+-----------------------
clusterable | t
index_scan | t
bitmap_scan | t
backward_scan | t

Метод доступа b-tree поддерживает оба способа получения значений: и индексное сканирование, и сканирование битовой карты. И, как мы видели, умеет обходить дерево как «вперед», так и в обратном направлении.

name | pg_index_column_has_property
--------------------+------------------------------
asc | t
desc | f
nulls_first | f
nulls_last | t
orderable | t
distance_orderable | f
returnable | t
search_array | t
search_nulls | t

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

Свойство search_array говорит о том, что индекс поддерживает такие конструкции:

demo=# explain(costs off)
select * from aircrafts where aircraft_code in ('733','763','773');
QUERY PLAN
-----------------------------------------------------------------
Index Scan using aircrafts_pkey on aircrafts
Index Cond: (aircraft_code = ANY ('{733,763,773}'::bpchar[]))
(2 rows)

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

Уникальные индексы с дополнительными столбцами


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

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

В нашей компании Анастасия Лубенникова lubennikovaav доработала метод btree так, чтобы в уникальный индекс можно было включать дополнительные — неуникальные — столбцы. Надеемся, что этот патч будет принят сообществом и войдет в PostgreSQL, но это случится уже не в версии 10. Пока патч доступен в Postgres Pro Standard 9.5+, и вот как это выглядит.

Возьмем таблицу бронирований:

demo=# \d bookings
Table "bookings.bookings"
Column | Type | Modifiers
--------------+--------------------------+-----------
book_ref | character(6) | not null
book_date | timestamp with time zone | not null
total_amount | numeric(10,2) | not null
Indexes:
"bookings_pkey" PRIMARY KEY, btree (book_ref)
Referenced by:
TABLE "tickets" CONSTRAINT "tickets_book_ref_fkey" FOREIGN KEY (book_ref) REFERENCES bookings(book_ref)

В ней первичный ключ (book_ref, код бронирования) поддержан обычным btree-индексом. Создадим новый уникальный индекс с дополнительным столбцом:

demo=# create unique index bookings_pkey2 on bookings(book_ref) include (book_date);
CREATE INDEX

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

demo=# begin;
BEGIN
demo=# alter table bookings drop constraint bookings_pkey cascade;
NOTICE: drop cascades to constraint tickets_book_ref_fkey on table tickets
ALTER TABLE
demo=# alter table bookings add primary key using index bookings_pkey2;
ALTER TABLE
demo=# alter table tickets add foreign key (book_ref) references bookings (book_ref);
ALTER TABLE
demo=# commit;
COMMIT

Вот что получилось:

demo=# \d bookings
Table "bookings.bookings"
Column | Type | Modifiers
--------------+--------------------------+-----------
book_ref | character(6) | not null
book_date | timestamp with time zone | not null
total_amount | numeric(10,2) | not null
Indexes:
"bookings_pkey2" PRIMARY KEY, btree (book_ref) INCLUDE (book_date)
Referenced by:
TABLE "tickets" CONSTRAINT "tickets_book_ref_fkey" FOREIGN KEY (book_ref) REFERENCES bookings(book_ref)

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

demo=# explain(costs off)
select book_ref, book_date from bookings where book_ref = '059FC4';
QUERY PLAN
--------------------------------------------------
Index Only Scan using bookings_pkey2 on bookings
Index Cond: (book_ref = '059FC4'::bpchar)
(2 rows)

Создание индекса


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

Дело в том, что при создании btree-индекса используется более эффективная процедура, чем построчная вставка значений в дерево. Грубо говоря, все имеющиеся в таблице данные сортируются и из них формируются листовые страницы индекса; затем на это основание «наращиваются» внутренние страницы до тех пор, пока вся пирамида не сойдется к корню.

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

Семантика сравнения


В прошлый раз мы говорили о том, что PostgreSQL должен знать, какие хеш-функции вызывать для значений разных типов, и что такое соответствие хранится в метода доступа hash. Точно так же системе надо понимать, как упорядочивать значения — это нужно для сортировок, группировок (иногда), соединения слиянием и т. п. PostgreSQL не привязывается к именам операторов (таким, как >, <, =), потому что пользователь вполне может определить свой тип данных и назвать соответствующие операторы как-то иначе. Вместо этого имена операторов определяются семейством операторов, привязанных к методу доступа btree.

Например, вот какие операторы сравнения используются в семействе bool_ops:

postgres=# select amop.amopopr::regoperator as opfamily_operator,
amop.amopstrategy
from pg_am am,
pg_opfamily opf,
pg_amop amop
where opf.opfmethod = am.oid
and amop.amopfamily = opf.oid
and am.amname = 'btree'
and opf.opfname = 'bool_ops'
order by amopstrategy;

opfamily_operator | amopstrategy
---------------------+--------------
<(boolean,boolean) | 1
<=(boolean,boolean) | 2
=(boolean,boolean) | 3
>=(boolean,boolean) | 4
>(boolean,boolean) | 5
(5 rows)

Здесь мы видим пять операторов сравнения, но, как было сказано, не должны ориентироваться на их названия. Чтобы понять, какое сравнение реализовано каким оператором, вводится понятие стратегии. Для btree определены пять стратегий, определяющих семантику операторов:
  • 1 — меньше;
  • 2 — меньше либо равно;
  • 3 — равно;
  • 4 — больше либо равно;
  • 5 — больше.

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

postgres=# select amop.amopopr::regoperator as opfamily_operator
from pg_am am,
pg_opfamily opf,
pg_amop amop
where opf.opfmethod = am.oid
and amop.amopfamily = opf.oid
and am.amname = 'btree'
and opf.opfname = 'integer_ops'
and amop.amopstrategy = 1
order by opfamily_operator;

opfamily_operator
----------------------
<(integer,bigint)
<(smallint,smallint)
<(integer,integer)
<(bigint,bigint)
<(bigint,integer)
<(smallint,integer)
<(integer,smallint)
<(smallint,bigint)
<(bigint,smallint)
(9 rows)

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

Индексная поддержка для нового типа данных


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

Создаем новый составной тип с двумя полями: действительная и мнимая части.

postgres=# create type complex as (re float, im float);
CREATE TYPE

Можно создать таблицу с полем нового типа и добавить в нее каких-нибудь значений:

postgres=# create table numbers(x complex);
CREATE TABLE
postgres=# insert into numbers values ((0.0, 10.0)), ((1.0, 3.0)), ((1.0, 1.0));
INSERT 0 3

Теперь возникает вопрос: как упорядочивать комплексные числа, если в математическом смысле для них не определено отношение порядка?

Как выясняется, операции сравнения уже определены за нас:

postgres=# select * from numbers order by x;
x
--------
(0,10)
(1,1)
(1,3)
(3 rows)

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

postgres=# create function modulus(a complex) returns float as $$
select sqrt(a.re*a.re + a.im*a.im);
$$ immutable language sql;
CREATE FUNCTION

И с ее помощью методично определим функции для всех пяти операций сравнения:

postgres=# create function complex_lt(a complex, b complex) returns boolean as $$
select modulus(a) < modulus(b);
$$ immutable language sql;
CREATE FUNCTION
postgres=# create function complex_le(a complex, b complex) returns boolean as $$
select modulus(a) <= modulus(b);
$$ immutable language sql;
CREATE FUNCTION
postgres=# create function complex_eq(a complex, b complex) returns boolean as $$
select modulus(a) = modulus(b);
$$ immutable language sql;
CREATE FUNCTION
postgres=# create function complex_ge(a complex, b complex) returns boolean as $$
select modulus(a) >= modulus(b);
$$ immutable language sql;
CREATE FUNCTION
postgres=# create function complex_gt(a complex, b complex) returns boolean as $$
select modulus(a) > modulus(b);
$$ immutable language sql;
CREATE FUNCTION

И создадим соответствующие операторы. Чтобы показать, что они не обязаны называться «>», «<» и так далее, дадим им «странные» имена.

postgres=# create operator #<#(leftarg=complex, rightarg=complex, procedure=complex_lt);
CREATE OPERATOR
postgres=# create operator #<=#(leftarg=complex, rightarg=complex, procedure=complex_le);
CREATE OPERATOR
postgres=# create operator #=#(leftarg=complex, rightarg=complex, procedure=complex_eq);
CREATE OPERATOR
postgres=# create operator #>=#(leftarg=complex, rightarg=complex, procedure=complex_ge);
CREATE OPERATOR
postgres=# create operator #>#(leftarg=complex, rightarg=complex, procedure=complex_gt);
CREATE OPERATOR

На этом этапе уже можно сравнивать числа:

postgres=# select (1.0,1.0)::complex #<# (1.0,3.0)::complex;
?column?
----------
t
(1 row)

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

postgres=# create function complex_cmp(a complex, b complex) returns integer as $$
select case when modulus(a) < modulus(b) then -1
when modulus(a) > modulus(b) then 1
else 0
end;
$$ language sql;
CREATE FUNCTION

Теперь мы готовы создать класс операторов (а одноименное семейство будет создано автоматически):

postgresx=# create operator class complex_ops
default for type complex
using btree as
operator 1 #<#,
operator 2 #<=#,
operator 3 #=#,
operator 4 #>=#,
operator 5 #>#,
function 1 complex_cmp(complex,complex);
CREATE OPERATOR CLASS

Теперь сортировка работает так, как мы хотели:

postgres=# select * from numbers order by x;
x
--------
(1,1)
(1,3)
(0,10)
(3 rows)

И, разумеется, она будет поддерживаться индексом btree.

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

postgres=# select amp.amprocnum,
amp.amproc,
amp.amproclefttype::regtype,
amp.amprocrighttype::regtype
from pg_opfamily opf,
pg_am am,
pg_amproc amp
where opf.opfname = 'complex_ops'
and opf.opfmethod = am.oid
and am.amname = 'btree'
and amp.amprocfamily = opf.oid;

amprocnum | amproc | amproclefttype | amprocrighttype
-----------+-------------+----------------+-----------------
1 | complex_cmp | complex | complex
(1 row)

Внутренности


Внутреннюю структуру B-дерева можно изучать, используя расширение pageinspect.

demo=# create extension pageinspect;
CREATE EXTENSION

Метастраница индекса:

demo=# select * from bt_metap('ticket_flights_pkey');
magic | version | root | level | fastroot | fastlevel
--------+---------+------+-------+----------+-----------
340322 | 2 | 164 | 2 | 164 | 2
(1 row)

Самое интересное здесь — глубина индекса (level): для размещения индекса по двум столбцам для таблицы с миллионом строк потребовалось всего 2 уровня (не считая корня).

Статистическая информация о блоке 164 (корень):

demo=# select type, live_items, dead_items, avg_item_size, page_size, free_size
from bt_page_stats('ticket_flights_pkey',164);
type | live_items | dead_items | avg_item_size | page_size | free_size
------+------------+------------+---------------+-----------+-----------
r | 33 | 0 | 31 | 8192 | 6984
(1 row)

И сами данные в блоке (в поле data, которое тут принесено в жертву ширине экрана, находится значение ключа индексирования в двоичном виде):

demo=# select itemoffset, ctid, itemlen, left(data,56) as data
from bt_page_items('ticket_flights_pkey',164) limit 5;
itemoffset | ctid | itemlen | data
------------+---------+---------+----------------------------------------------------------
1 | (3,1) | 8 |
2 | (163,1) | 32 | 1d 30 30 30 35 34 33 32 33 30 35 37 37 31 00 00 ff 5f 00
3 | (323,1) | 32 | 1d 30 30 30 35 34 33 32 34 32 33 36 36 32 00 00 4f 78 00
4 | (482,1) | 32 | 1d 30 30 30 35 34 33 32 35 33 30 38 39 33 00 00 4d 1e 00
5 | (641,1) | 32 | 1d 30 30 30 35 34 33 32 36 35 35 37 38 35 00 00 2b 09 00
(5 rows)

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

Дальше, по доброй традиции, имеет смысл читать документацию, README и исходный код.

И еще одно потенциально полезное расширение: amcheck, которое войдет в состав PostgreSQL 10, а для более ранних версий его можно взять на github. Это расширение проверяет логическую согласованность данных в B-деревьях и позволяет заблаговременно обнаружить повреждения.

Продолжение следует.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330544/


Метки:  

Первая подборка материалов о цифровизации страхования

Понедельник, 19 Июня 2017 г. 10:27 + в цитатник
Привет, Хабр! С этого момента я хотел бы начать вести дайджесты по теме ИТ в страховании. В первой подборке я отдал максимальный приоритет тому, что выходило по теме на Хабре и GT, но и не забыл другие площадки. Англоязычные статьи — материалы с Hacker News, которые набрали хороший рейтинг и показались мне интересными.

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

Фото: GotCredit / CC

Страхование для технологий


Страховка от кибер-рисков
Атаки, вирусы, ИБ-фейлы сотрудников — есть множество причин для утечки критически значимой информации, включающей ПД пользователей. Все эти риски можно компенсировать не только грамотной организацией внутренних процессов, но и страховкой. В этом материале идет речь о продукте CyberEdge, который разработала компания AIG.

Страховые компании и криптовымогатели: новый метод уберечь себя от последствий работы ransomware
Попытка рассуждения на тему наступления такого страхового случая как «кибер-вымогательство». Мнения экспертов, мысли автора и комментарии хабражителей.

Впервые в истории российского венчура: фонд «Росинфокоминвест» застраховал руководство от ошибок
Редакция Хабра пишет о новом кейсе в российском венчуре, который реализовала компания AIG. Ряд сотрудников фонда застрахованы от управленческих ошибок на сумму в 300 миллионов рублей — сюда входят в том числе и расходы на защиту в суде.

Может ли стартап ударить по 20-миллиардному рынку страхования кибер-рисков? перевод
Переводной материал в блоге компании GVA. Здесь рассмотрены основные тренды и новые веяния на страховом рыке. Основной акцент — на страховании ИТ-рисков и потребности в соответствующей экспертизе со стороны страховщиков.

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

Технологии для страхования


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

Компания Bitfury Group поможет рынку страхования
Блокчейн на практике и в сфере страховых услуг — реальность. Основная ниша для начала работ — киберстрахование. Ранее Bitfury уже реализовала блокчейн-проекты для правительства Украины и Грузии (ссылка на блог Bitfury на Хабре).

Блокчейн — будущее страхового рынка
Заметка по теме на Techcrunch. Здесь рассмотрены: P2P-страхование, параметрическое страхование и микрострахование. Помимо общих слов для каждого пункта приведены примеры использования блокчейна.

Как можно применять «большие данные» в страховании: проекты Университета ИТМО
Обсуждение проблем сбора и анализа данных вместе с примерами разработок Университета ИТМО в сфере страхования и транспортной экосистемы города.

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

Индустрия страховых технологий как одна из самых стремительно растущих финтех-вертикалей
Онлайн-агрегаторы, брокеры, что дальше? Компания Wirex подготовила перевод по этой теме и рассказала о будущем сферы Insurtech (тренды Insurtech).

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

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

Фото: franchise opportunities / CC

Электронное ОСАГО, КАСКО и ПТС


Оформление ОСАГО онлайн: Как это работает
Разбор мифов, анализ условий оформления и особенностей Е-ОСАГО, которое появилось еще в 2015 году, но на самом деле — только совсем недавно.

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

Проблемы электронного ОСАГО и страховая экосистема
Экспертная колонка в Forbes. Здесь разобран западный опыт и дана аналитическая оценка того, что будет происходить на российском рынке страховых услуг.

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

Как создавался телематический сервис Smartdriving.io — на 100% российский технологический стартап
История нового тематического стартапа в формате интервью.

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

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



P.S. Еще одна моя подборка по теме: Автомобильный дайджест: Ремонт, страхование и новые технологии
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331182/


Метки:  

Производительность lambda-выражений в Java 8

Понедельник, 19 Июня 2017 г. 10:25 + в цитатник
В середине 2013 с выходом Java 8, язык начал поддерживать lambda-выражения, с тех пор минуло 4 года, было выпущено множество update-ов, грядет уже и выход Java 9 (которую, вероятно, мы сможем увидеть в этом году, не смотря на постоянные переносы сроков), таким образом на стыке времён, хотелось бы подвести итоги и оценить производительность нового в java и старого, как мир инструмента, дав ему количественную оценку.
socmetr.lambda.comparison

Оценки производительности уже неоднократно производились, как в прочем обсуждались достоинства и недостатки lambda-выражений:
к первым можно отнести:
— упрощение и сокращение кода
— возможность реализации функционального стиля
— возможность параллельных вычислений
ко вторым:
— уменьшение производительности
— трудность debug'а

Неплохая методика и тесты были описаны и использованы еще 5 лет назад пользователем dmmm (https://habrahabr.ru/post/146718/), собственно они за основу и были взяты.

Если, в вкратце то сами тесты поставлялись с проектом LambdaJ. dmmm добавил тесты для проекта Guava и откорректировал их после обсуждения с habr-сообществом (2012).

Мною (то бишь blutovi) были переписаны все lambda-тесты (поскольку тестирование проходило на альфа-версиях java, и в текущем состоянии код просто не компилируем), также при помощи Java Mission Control было проанализировано состояние памяти и для каждого теста приложен jfr-файл с результатами.
(Java Mission Control — средство диагностики и мониторинга JVM — доступно начиная с версии java 7 update 40, как результат объединения идей двух JVM: HotSpot от Sun и JRockit от Oracle).

Как тестировалось?


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

Замер времени осуществляется следующим образом: для каждой из ${z}$ итераций, в течении времени ${Y}$, происходит последовательный вызов тестируемого-алгоритма. По его истечении, определяется среднее арифметическое время выполнения алгоритма $\bar{Y}_{z}$:

$\bar{Y}^{z}= \frac{1}{{n}_{z}}\sum_{i=0}^{{n}_{z}}{Y}^{'}_{i}$

путем деления суммарного времени его выполнения ${Y}^{'}$ на количество раз ${n}$, которое он успел выполнится. На основе ${z}$ итераций, находим общее среднее время выполнения алгоритма:

$\bar{Y}= \frac{1}{z}\sum_{i=0}^{z}\bar{Y}^{z}_{i}$

На величины ${z}$ (количество итераций) и ${Y}$ (время в течении, которого происходит вызов тестируемого алгоритма) можно повлиять изменив значения констант в классе ch.lambdaj.demo.AbstractMeasurementTest:

    public static final int WARMUP_ITERATIONS_COUNT = 10;
    public static final int ITERATIONS_COUNT = 10;
    public static final int ITERATION_DURATION_MSEC = 1000;

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

Результаты


в абсолютных величинах (чем значения меньше, тем лучше)
for iterate guava jdk8 lambda
time, ns heap, Mb time, ns heap, Mb time, ns heap, Mb time, ns heap, Mb
Extract cars original cost 220.4 313 200.6 324 188.1 302 266.2 333
Age of youngest who bought for > 50k 6367 260 4245 271 6367 260 6157 278
Find buys of youngest person 6036 270 6411.4 259 6206 260 6235 288
Find most bought car 2356 167 2423 171 5882 193 2971 190
Find most costly sale 49 71 58.1 66 431.6 297 196.1 82
Group sales by buyers and sellers 12144 250 12053 254 8259 206 18447 242
Index cars by brand 263.3 289 275.0 297 2828 226 307.5 278
Print all brands 473.2 355 455.3 365 540.3 281 514.2 337
Select all sales of a Ferrari 199.3 66 265.1 53 210.4 111 200.2 65
Sort sales by cost 1075 74 1075 74 1069 72 1566 124
Sum costs where both are males 67.0 63 72.9 58 215.9 88 413.7 114
в относительных величинах (100% — это база, чем значения меньше, тем лучше)
for iterate guava jdk8 lambda
time heap time heap time heap time heap
Extract cars original cost 117% 104% 107% 107% 100% 100% 142% 110%
Age of youngest who bought for > 50k 150% 100% 100% 104% 150% 100% 145% 107%
Find buys of youngest person 100% 104% 106% 100% 103% 100% 103% 111%
Find most bought car 100% 100% 103% 102% 250% 116% 126% 114%
Find most costly sale 100% 108% 119% 100% 881% 450% 400% 124%
Group sales by buyers and sellers 147% 121% 146% 123% 100% 100% 223% 117%
Index cars by brand 100% 128% 104% 131% 1074% 100% 117% 123%
Print all brands 104% 126% 100% 130% 119% 100% 113% 120%
Select all sales of a Ferrari 100% 125% 133% 100% 106% 209% 100% 123%
Sort sales by cost 101% 103% 101% 103% 100% 100% 147% 172%
Sum costs where both are males 100% 109% 109% 100% 322% 152% 617% 197%

Выводы


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

Таким образом, iterative подход дает возможность сделать акцент на скорости выполнения, а Guava позволяет акцентировать внимание на количестве используемой памяти, сведя ее к минимуму. Использование же lambda-выражений, похоже дает только эстетическое наслаждение (к моему великому удивлению).

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

Ссылки


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

https://habrahabr.ru/post/331030/


Метки:  

Интерактивная кредитка для ввода платежа

Понедельник, 19 Июня 2017 г. 10:21 + в цитатник
Эта статья повествует о не самом сложном способе разработки интерактивных элементов практически сразу в браузере, если вы не разработчик



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

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

Сегодня речь о том как сделать простую интерактивную / анимированную форму ввода платежных данных. Сразу скажу, что создание анимации в Axure не совсем стандартное. Нет привычной шкалы времени с проекцией на слои, как например в After Effects. Есть только последовательность событий, которая запускается при определенном действии. Между ними можно вставлять тайминги “Delay” и указывать паузу в миллисекундах. Анимирование в Axure кажется немного гиковским: вы сможете в нём разобраться, только если глубоко проникнетесь самим процессом.

Посмотрите как это работает:



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

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

План действий:
  • сделать простой и привлекательный дизайн
  • проимитировать определение типа карты после ввода первых 4х цифр (например, Mastercard)
  • автоматизировать перефокусировку между полями ввода разных данных (например, фокус инпута Cardholder после ввода срока действия карты)
  • своевременно предложить ввод CVC кода на обратной стороне, после ввода ФИО
  • попытаться избавиться от возможных лишних действий со стороны пользователя (например, поменьше кликов в очевидных местах)


Общая концепция




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

Дизайн


Для веб интерфейсов я всегда использую 10px сетку — мне так удобнее считать отступы и размерности. Так что старался их делать кратными 10. Логотип временный, не хотелось прибегать к названию существующих банков. Карточка бросает тень вниз под углом 90, чтобы добавить немного ощущения пространства. Параметры тени: x=0, y=25, blur=45, #000000, alpha=0.35

Лицевая сторона (State1)

Содержит графику, скрытый логотип Mastercard, скрытую кнопку разворота карты для ввода CVC кода (8). Эти два объекта будут появляться при определенных условиях. А проверка условий будет завязана с событиями. Например, если длина введенных данных в поле Cardholder name больше или равно 7, то показываем кнопку разворота и ввода CVC с обратной стороны. Конечно в реальной жизни разработчик будет проверять заполненность всех полей, но в моем кейсе это излишний перфекционизм.
Поля ввода (1-7) выполнены двухкомпонентными. Немного странно, но Axure не позволяет особо разгуляться с CSS для html-инпутов. Хорошо, что можно отключить border и придать более современный вид. Поэтому под инпутами проходит дополнительный белый rectangle, а сами они в приоритете поверх и с чекбоксом “Hide border”. Этот rectangle будет менять стиль в момент onFocus’a на инпуте, поэтому никто не догадается об использовании двух связанных объектов.

Обратная сторона (State2)

Здесь всё просто. “Магнитная” полоса проведена для бОльшего реализма с помощью того же rectangle drawer. Из важных контролов здесь только поле CVC. За телом карточки хитро спрятана кнопка подтверждения платежа. Она выезжает с bounce-эффектом (на самом деле простого ease было бы достаточно) только после проверки на условие “Символов в поле CVC >= 3”.

Сторона подтверждения (State3)

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

Определение типа карты


Это имитация распознавания платежного сервиса после ввода первых 4-х цифр. Поскольку это лишь прототип, я использую функцию onLostFocus для первого инпута номера карты + проверка на содержимое. Если “содержимое = true” и фокус переходит на следующие 4-е цифры, то показываем логотип.

Перефокусировка на следующий инпут


Происходит за счёт функции onTextChange. После каждой введенной цифры мы проверяем кол-во и если их уже 4-е, то между ними ставится пробел. Визуально это так и выглядит, но технически всё пришлось сильно усложнить. Почему, сможете узнать ниже в Known bugs. Я думаю тут есть что улучшить, но общий вид не поменяется. Посчитал, что потенциально затраченное время того не стоит. На базе onTextChange выполнены переходы и между остальными полями (например прыжок с даты на ФИО).

Обратная сторона и ввод CVC


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

UX


  • Я отказался от необходимости делать клик по кнопке разворота карты. Считаю, что если пользователь к ней потянулся, значит отдает отчёт, что остальное заполнено корректно. Кнопка сработает при наведении.
  • Аналогично клик не нужен для фокуса на поле CVC. Достаточно навести курсор. Решение не идеальное. Причину описал ниже…
  • Кнопка подтверждения платежа “прилетает” правее карты. Таким образом анимацией показана причинно-следственная связь и меньший путь курсора от инпута CVC до кнопки.


Known bugs


  • Если вбивать номер карты очень быстро, то начинает заедать автофокус на следующие 4-е цифры. Аналогично с удалением. Решением было бы оставить всего один инпут и как-то научить Акшуру ставить пробел после введения каждых 4-х цифр номера карты, но мне это не удалось. Поэтому использовано 4-е независимых инпута только ради удобства ввода номера благодаря разрывам.
  • Я не смог сделать автофокус на CVC при перевороте карточки. У меня никак не получалось связать функцию onPanelStateChange синхронно с проверкой что сейчас мы в состоянии State1 (и только в нём). В идеале я хотел бы сделать так: проверяем, что происходит переворот до State2, ждем delay=100 и потом автофокусируем поле CVC, но увы. В качестве полумеры фокус срабатывает только при onHover. Но тащиться туда мышкой я всё равно обязываю :(


Скачать RP-исходник для Axure 8 @Gumroad

Скачать браузерную версию HTML/CSS/JS
Данная версия распространяется бесплатно, в т.ч. для использования в коммерческих целях. Есть только просьба: если вы успешно интегрировали эту интерактивную форму в свой продукт, оставьте пожалуйста ссылку на проект тут в комментариях. Спасибо.
Скачать @Gumroad
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331176/


Метки:  

[Из песочницы] Занимательная вёрстка с единицами измерения области просмотра

Понедельник, 19 Июня 2017 г. 10:00 + в цитатник

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



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


Между 2011 и 2015 годами в спецификациях CSS, разработанных W3C, в 3-ем уровне модуля Значения и единицы CSS, появились четыре новые единицы, которые связаны непосредственно
с параметрами области просмотра. Новые единицы — vw, vh, vmin, и vmax — работают аналогично существующим единицам длины, таким как px или em, но представляют собой процентные величины от текущей области просмотра браузера.


  • Viewport Width (vw) – это процентная величина от общей ширины области просмотра. 10vw представляет собой 10% от текущей ширины области просмотра, скажем, 48px на телефоне с экраном шириной 480px. Разница между % и vw наиболее сопоставима с отличием между единицами em и rem. Длина в % рассчитывается относительно ширины текущего контекста (контейнера), а длина vw — относительно общей ширины области просмотра браузера.

  • Viewport Height (vh) — это процентная величина от общей высоты области просмотра. 10vh составляет 10% от текущей высоты области просмотра.

  • Viewport Minimum (vmin) — это процентная величина от ширины или высоты области просмотра, независимо от того, которая из двух меньше. 10vmin соответствует 10% от текущей ширины области просмотра в книжной ориентации и 10% от высоты области просмотра в альбомной ориентации.

  • Viewport Maximum (vmax) — это процентная величина от ширины или высоты области просмотра, независимо от того, которая из двух больше. 10vmin будет равняться 10% от текущей высоты области просмотра в книжной ориентации и 10% ширины области просмотра в альбомной ориентации. К сожалению и как бы странно это ни звучало, единица vmax еще не поддерживается браузерами Internet Explorer и Edge.

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


Отзывчивая типографика


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


html {
font-size: 3vw;
margin: .5em;
}

h1 {
font-size: 4vmax;
}

h2 {
font-size: 4vmin;
}

h1, h2 {
font-weight: bold;
}

h1, h2, p {
margin: .5em 0;
}


Такое резкое масштабирование явно не подходит для повседневного использования. Нам нужно что-то более тонкое — минимальные и максимальные значения. Также нужно больше контроля над диапазонами увеличения показателя. Тут нам поможет функция calc(). Для определения базового размера шрифта мы можем использовать более стабильные единицы (скажем, 16px). Мы также можем уменьшить диапазон подстраивания значения под размер области просмотра (0.5vw). Таким образом, браузер будет выполнять следующие математические вычисления: calc(16px + 0.5vw)



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


body {
  // размер шрифта увеличивается на 1px через каждые 100px ширины области просмотра
  font-size: calc(16px + 1vw);
  // междустрочный интервал увеличивается вместе со шрифтом
  // и получает дополнительный прирост на 0.1em + 0.5px через каждые 100px ширины области просмотра
  line-height: calc(1.1em + 0.5vw);
}

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


h1 {
  font-size: calc(1.2em + 3vw);
}

@media (min-width: 50em) {
  h1 {
    font-size: 50px;
  }
}

Тут я поняла, что было бы здорово, если бы существовало такое свойство, как max-font-size.


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





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


Полноэкранные блоки, hero images и прилипающие футеры


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


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



Одно правило для body — height: 100vh — задает высоту вашему приложению равной высоте области просмотра. Убедитесь, что для элементов внутри body заданы значения overflow, чтобы их содержимое не обрезалось. Такой же вёрстки можно добиться, используя flexbox или плавающие элементы. Заметьте, что с вёрсткой в полную высоту в некоторых мобильных браузерах могут возникать проблемы. Есть хороший фикс для Safari на iOS, который мы используем для наиболее часто встречающихся нестандартных случаев.


Прилипающие футеры можно создать аналогичным образом. Все, что нужно — правило для body height: 100vh заменить на min-height: 100vh, и футер будет зафиксирован внизу экрана, до тех пор пока не сместится контентом вниз.



Используйте единицы vh для определения свойств height, min-height или max-height различных элементов и создавайте полноэкранные разделы, hero images и многое другое. В новом редизайне OddBird мы ограничили высоту hero images правилом max-height: 55vh, чтобы они не вытесняли заголовки со страницы. На моем собственном сайте я использовала правило max-height: 85vh, чтобы больше выделить изображения. На других сайтах я применила минимальную высоту — min-height: 90vh — к разделам.


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


Соотношение ширины и высоты для резиновой вёрстки


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


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


/* во всю ширину * соотношение высоты и ширины */
.full-width {
  width: 100vw;
  height: calc(100vw * (9/16));
}

Такие расчеты не обязательно выполнять именно в браузере с поддержкой функции calc. Если вы используете препроцессор, как, например, Sass, того же эффекта можно добиться с помощью подобного расчета: height: 100vw * (9/16). Если вам нужно ограничить максимальную ширину, вы также можете ограничить максимальную высоту:


/* максимальная ширина * соотношение высоты и ширины */
.full-width {
  width: 100vw;
  max-width: 30em;
  height: calc(100vw * (9/16));
  max-height: calc(30em * (9/16));
}

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



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


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



«Разрывая» контейнер


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


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


.full-width {
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
}

Есть более подробные статьи, посвященные данной технике, как на Cloud Four, так и здесь, на CSS Tricks.


Креативные реализации


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



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


Оригинальная статья: Fun with Viewport Units by Miriam Suzanne
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331184/


Метки:  

Программируем в мире Minecraft

Понедельник, 19 Июня 2017 г. 09:54 + в цитатник
Хабр, привет! Пока все обсуждают ИИ в мире Pacman, мы начнем делать свой ИИ в Minecraft с фреймворком Malmo от Microsoft Research. Pacman у нас тоже появится. :) Если вы любите кубический мир, или вам хотелось бы начать изучать искусственный интеллект, или у вас есть дети, с которыми вы не можете найти общие увлечения, или же вас просто заинтересовала тема – прошу под кат.



В этой статье я постараюсь затронуть несколько тем:
  • Выскажу свое мнение о помешательстве детей на кубической игрушке
  • Расскажу об основной идее Malmo
  • Покажу несколько примеров с кодом и дам понимание, куда можно идти дальше
  • Расскажу об идее и результатах Malmo Challenge

Minecraft: моя предыстория


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

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

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



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

Изучая сабж, я случайно узнала, что мир Minecraft не ограничивается игрой, мерчем, летсплеями и фан артами. В игре снимают целые сериалы, и – неожиданно – они являются довольно популярными. На мой взгляд, это забавно. :)

Меня очень обрадовала новость о наличии open source фреймворка для программирования в мире Minecraft. Я твердо уверена, что в будущем в подавляющем числе профессий могут понадобиться базовые навыки программирования. Фреймворк на базе любимой игрушки, на мой взгляд, отличный способ показать ребенку захватывающий мир программирования.

Malmo: основная идея


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

Технические моменты


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

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

Авторы постарались поддержать большое число популярных языков и сделали обвязки для C#, C++, Lua, Python2 и Java. Я выбрала Python.

Как играть программировать в Malmo



Основной процесс выглядит следующим образом: в одном окошке вам необходимо поднять сервер и клиента. Для этого есть скрипт ./Minecraft/launchClient.*. После того, как сервер поднялся, в другом окне вы можете запустить код с основной логикой для управления персонажем. Как узнать, что сервер поднялся? Все крайне логично: вы увидите запущенный экземпляр Minecraft с начальным меню внутри, а в терминале будет гордо красоваться надпись Building 95%.

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

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

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

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

Мой совет: не пытайтесь начинать с нуля, возьмите за базу первый пример. В нем ничего не происходит, мы просто создаем самый простой плоский мир и присоединяемся к персонажу. В цикле while в конце вы можете по своему усмотрению добавить экшена в происходящее. Например, напишите там:
agent_host.sendCommand("move 1")

И насладитесь первыми шагами своего героя. Учтите, что по умолчанию используется т.н. ContinuousMovementCommands. Воспринимайте отдаваемые персонажу команды как изменение положения рычага. Говоря "move 1", вы сделаете не один шаг. Вы будете бежать, пока не дадите команду "move 0". Такой код на практике не сдвинет человечка с места:
agent_host.sendCommand("move 1")
agent_host.sendCommand("move 0")

Команды выполнятся за считанные доли секунды. Не забывайте вставлять периодические строчки "time.sleep(X)". Я уверена, что вы знаете, где брать информацию об остальных командах (хотя, по моему опыту, проще по диагонали просмотреть туториал и затем искать нужное в исходниках).

В xml файле вы можете задать режим игры:
 

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

Вот этот код нарисует вам Пакмана, который поедает шарики и уходит в радужный кратер:


    
    
    
    
    
    
    



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

    
        
        
    

По умолчанию у нас нет возможности осмотреться и получить информацию о ближайших блоках. Тем не менее, мы можем сказать, что хотим знать, что находится вокруг нас. Учтите, что в этом случае нам нужно использовать относительные координаты, отсчитываемые от кубика с ногами героя. В результате выполнения подобной строчки
grid = observations.get(u'floor3x3', 0)

Мы получим массив со строками. Каждая строка – это текстовое представление типа одного из кубиков.
floor3x3: ['lava', 'obsidian', 'obsidian', 'lava', 'obsidian', 'obsidian', 'lava', 'obsidian', 'obsidian']

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

Фичи для ИИ


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

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


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

Кроме этого, исследователи добавили несколько приятных фич для решения задачи обучения с подкреплением (Reinforcement Learning). Алгоритмы этого типа подразумевают постоянное награждение или наказание искусственного интеллекта за те или иные действия. Разработчики продумали этот момент и добавили возможность прописать эти действия/события в xml, избавив код от постоянных одинаковых проверок. Вы также можете задать окончание игры по наступлению некоторого события:

    
    



    
    

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



Malmo: вывод


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

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

Malmo Challenge: история и результаты


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

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



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

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

Я рада поделиться с вами результатами соревнования. Меня очень удивило распределение мест в турнирной таблице.

Первое место занял проект команды из Великобритании. Авторы трезво оценили сильный недостаток времени, поняли, что они вряд ли успеют адаптировать для задачи сложные существующие алгоритмы. Они выбрали Байесовский вывод для определения типа напарника, а также Марковские цепи для непосредственного игрового процесса. И победили.

Участники, занявшие второе место, решили взять самые сложные из существующих решений, они использовали DNN, Reinforcement learning, DQN, A3C model… И это все не помогло им обойти Байеса и Марковские цепи.

Подытожим статью мыслью о том, что нужно быть проще. :)

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

Видео с моим рассказом о Malmo на встрече Петербургского Python митапа уже появилось на моем канале на Youtube. Там также есть записи других моих лекций и прочая болтовня про IT.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331034/


Метки:  

[Перевод] Исходный код Quake III

Понедельник, 19 Июня 2017 г. 09:41 + в цитатник
image

[Примечание переводчика: перевод первой части этой статьи уже есть на Хабре, но её автор почему-то не завершил работу.]

Рендерер Quake III


Рендерер Quake III стал эволюционным развитием рендерера Quake II с аппаратным ускорением: классическая часть построена на архитектуре «двоичного разбиения»/«потенциально видимых наборов», но добавлены два новых заметных ключевых аспекта:

  • Система шейдеров, построенная поверх фиксированного конвейера OpenGL 1.X. Это было большим достижением для 1999 года. Она обеспечивала большое пространство для инноваций в эру до повсеместно распространённых сегодня вершинных, геометрических и фрагментных шейдеров.
  • Поддержка многоядерной архитектуры: клиент-серверная модель OpenGL блокирует некоторые методы и система потоков частично решает эту проблему.

Архитектура


Рендерер полностью содержится в renderer.lib и статично связан с quake3.exe:



Общая архитектура повторяет Quake Classic: в ней используется знаменитое сочетание BSP/PVS/карт освещения:

  • Предварительная обработка:
    1. Дизайнер игры создаёт с помощью QRadiant .map и сохраняет его.
    2. q3bsp.exe разрезает карту двоичным разбиением пространства (BSP). Я писал об этом в обзоре рендерера Quake1.
    3. Из BSP генерируется система порталов: я писал об этом в статье об инструменте Doom3 Dmap.
    4. q3vis.exe использует систему порталов и генерирует PVS (потенциально видимый набор) для каждого листа. Каждый PVS сжимается и хранится в файле bsp, как описано в предыдущей статье.
    5. Система порталов очищается.
    6. q3light.exe вычисляет освещение для каждого полигона на карте и сохраняет результат как текстуры карт освещённости в файле bsp.
    7. На этом этапе все предварительно рассчитанные данные (PVS и карты освещения) хранятся в файле .bsp.
  • Время выполнения:
    1. Движок загружает карту и bsp.
    2. Когда необходима визуализация:
    3. Движок разархивирует PVS для текущего листа и определяет, что видимо на самом деле.
    4. Для каждого полигона он с помощью мультитекстурирования сочетает карту освещения с цветом.

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

Текстура, нарисованная дизайнером уровня/художниками:



Карта освещения, сгенерированная q3light.exe:



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



Архитектура рендеринга была рассмотрена Брайаном Хуком (Brian Hook) на Game Developer Conference в 1999 году. К сожалению, видео с GDC Vault уже недоступно! [Зато оно есть на youtube.]

Шейдеры


Система шейдеров построена поверх фиксированного конвейера OpenGL 1.X, а потому очень затратна. Разработчики могут программировать модификации вершин, но также и добавлять проходы текстур. Это подробно рассмотрено в библии шейдеров Quake 3 Shader bible:


Многоядерный рендерер и SMP (симметричная многопроцессорность)


Многим неизвестно, что Quake III Arena была выпущена с поддержкой SMP с помощью cvariable r_smp. Фронтэнд и бекэнд обмениваются информацией через стандартную схему Producer-Consumer. Когда r_smp имеет значение 1, рисуемые поверхности попеременно сохраняются в двойной буфер, расположенный в ОЗУ. Фронтэнд (который называется в этом примере Main thread (основным потоком)), попеременно выполняет запись в один из буферов, в то время как из другого выполняет чтение бекэнд (в этом примере называемый Renderer thread (потоком рендерера)).

Пример демонстрирует, как всё работает:

t0-t1:
  • Main thread решает, что отрисовывать, и записывает поверхности в surfacebuffer1.
  • Для потока Renderer thread нет данных, поэтому он заблокирован.
  • Поток GPU thread тоже ничего не делает.



t1-t2: повсюду начинаются процессы:
  • Поток Main thread решает, что будет видимо в следующем кадре. Он записывает поверхность в буфер surfacebuffer2: это типичный пример двойной буферизации.
  • Тем временем, поток Renderer thread выполняет вызов OpenGL и терпеливо ждёт, пока поток GPU thread не скопирует всё в надёжное место.
  • Поток GPU thread считывает поверхность оттуда, куда указывает Renderer thread.

Заметьте, что в t2:
  • Renderer thread всё ещё передаёт данные в GPU: используется SurfaceBuffer1.
  • Main thread завершил запись в SurfaceBuffer2… но не может начать запись в SurfaceBuffer1: он заблокирован

Этот случай (когда Renderer thread блокирует Main thread) очень часто возникает при игре в Quake III:
Продемонстрируем ограничение блокировки одного из методов OpenGL API.



После t2:
  • Как только Renderer thread заканчивает с SurfaceBuffer1 (t3), он начинает закачивать поверхности из SurfaceBuffer2.
  • Как только он разблокируется (в t3), Main thread начинает работать в следующем кадре, записывая в SurfaceBuffer1.
  • В такой конфигурации GPU почти никогда не простаивает.



Примечание: синхронизация выполняется через Windows Event Objects в winglimp.c (часть с ускорением SMP внизу).

Сетевая модель


Сетевая модель Quake3 — это, без всяких сомнений, наиболее элегантная часть движка. На низком уровне Quake III по-прежнему абстрагирует обмен данными с модулем NetChannel, впервые появившимся в Quake World. Самое важное, что нужно понять:

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

Поэтому в результате движок использует UDP/IP: в коде нет следов TCP/IP, потому что «надёжная передача» создаёт недопустимую задержку. Сетевой стек был улучшен двумя взаимоисключающими слоями:
  • Шифрование с использованием заранее переданного ключа.
  • Сжатие с помощью заранее вычисленного ключа Хаффмана.



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

Архитектура


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



  • Master Gamestate — это общее, истинное состояние вещей. Клиенты отправляют свои команды в Netchannel. Они преобразуются в event_t, которые изменяют состояние игры при получении сервером.
  • Для каждого клиента сервер хранит 32 последних состояния игры, отправляемых по сети в циклическом массиве: они называются снапшотами. Массив циклически перемещается с использованием знаменитого трюка с двоичной маской, о которой я рассказывал в статье о Quake World Network (элегантные решения).
  • У сервера также есть «пустое» состояние, котором каждое поле имеет значение 0. Оно используется для дельта-снапшотов, у которых нет «предыдущих состояний».

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

Интересный факт: хранение такого количества состояний игры для каждого игрока занимает большой объём памяти: по моим измерениям, 8 МБ для четверых игроков.

Система снапшотов


Чтобы понять систему снапшотов, приведу пример со следующими условиями:
  • Сервер отправляет обновление клиенту Client1.
  • Сервер пытается передать состояние, которое имеет четыре поля, клиенту Client2 (три целочисленных значения для position[X], position[Y], position[Z] и одно целочисленное значение для здоровья).
  • Связь осуществляется через UDP/IP: эти сообщения довольно часто теряются в Интернете.

Кадр 1 сервера:

Сервер получил несколько обновлений от каждого клиента. Они повлияли на общее состояние игры (зелёного цвета). Настало время передать состояние клиенту Client1:



Чтобы сгенерировать сообщение, сетевой модуль ВСЕГДА делает следующее:
  1. Копирует общее состояние игры в следующий слот истории клиента.
  2. Сравнивает его с другим снапшотом.

Именно это мы видим на следующем изображении.

  1. Общее состояние игры (Master gamestate) копируется с индексом 0 в историю Client1: теперь оно называется «Snapshot1».
  2. Поскольку это первое обновление, в истории Client1 правильных снапшотов, поэтому движок использует пустой снапшот «Dummy snapshot», в котором все поля обнулены. Это приводит к ПОЛНОМУ обновлению, потому что каждое поле отправляется в NetChannel.



Важнее всего здесь понять то, что если в истории клиента нет правильных снапшотов, то движок берёт для генерирования дельта-сообщения пустой снапшот. Это приводит к полному обновлению, отправляемому клиенту в 132 битах (каждому полю предшествует битовый маркер): [1 A_on32bits 1 B_on32bits 1 B_on32bits 1 C_on32bits].

Кадр 2 сервера:
Давайте теперь переместимся немного в будущее: вот второй кадр сервера. Как мы видим, каждый клиент отправил команды, и все они повлияли на общее состояние игры Master gamestate: Client2 переместился по оси Y, поэтому теперь pos[1] равно E (синего цвета). Client1 тоже отправил команды, но, что более важно, он подтвердил получение предыдущего обновления, поэтому Snapshot1 был помечен как подтверждённый («ACK»):



Выполняется тот же самый процесс:

  1. Общее состояние игры копируется в следующий слот истории клиента: (индекс 1): это Snapshot2
  2. На этот раз у нас в истории клиента есть правильный снапшот (snapshot1). Сравниваем эти два снапшота

В результате по сети пересылается только частичное обновление (pos[1] = E ). В этом заключается красота такого дизайна: процесс всегда одинаков.



Примечание: поскольку каждому полю предшествует битовый маркер (1=изменилось, 0=не изменилось), для частичного обновления из примера выше используется 36 бит: [0 1 32bitsNewValue 0 0].

Кадр 3 сервера:
Сделаем ещё один шаг вперёд, чтобы посмотреть, как система справляется с утерянными пакетами. Теперь мы находимся в кадре 3. Клиенты продолжают отправлять команды серверу.
Client2 потерпел урон и здоровье теперь равно H. Но Client1 не подтвердил последнее обновление. Возможно, потерялся UDP сервера, возможно, потерялся ACK клиента, но в результате его невозможно использовать.



Несмотря на это, процесс остаётся тем же:
  1. Копируем общее состояние игры в следующий слот истории клиента: (индекс 2): это Snapshot3
  2. Сравниваем последний правильный подтверждённый снапшот (snapshot1).



В результате, сообщение отправляет его частично и содержит сочетание старых и новых изменений: (pos[1]=E и health=H). Заметьте, что snapshot1 может быть слишком устаревшим для использования. В этом случае движок снова использует «пустой снапшот», что приводит к полному обновлению.

Красота и элегантность системы — в её простоте. Один алгоритм автоматически:

  • Генерирует частичное или полное обновление.
  • Повторно отправляет в одном сообщении СТАРУЮ информацию, которая не была получена, и НОВУЮ информацию.

Самоанализ памяти на C


Вы можете задаться вопросом — как Quake3 сравнивает снапшоты самоанализом… ведь в C нет самоанализа.

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

    typedef struct {
        char    *name;
        int     offset;
        int     bits;
    } netField_t; 

    // используем оператор преобразования в строку для сохранения типизации...
    #define	NETF(x) #x,(int)&((entityState_t*)0)->x

    netField_t	entityStateFields[] = 
    {
    { NETF(pos.trTime), 32 },
    { NETF(pos.trBase[0]), 0 },
    { NETF(pos.trBase[1]), 0 },
    ...
    }

Полный код этой части находится в MSG_WriteDeltaEntity из snapshot.c. Quake3 даже не знает, что сравнивает: он слепо использует индекс, смещение и размер entityStateFields и отправляет по сети различия.

Предварительная фрагментация


Углубившись в код, можно увидеть, что модуль NetChannel разрезает сообщения на блоки по 1400 байт (Netchan_Transmit), даже несмотря на то, что максимальный размер датаграммы UDP составляет 65507 байт. Так движок избегает разбивания пакетов роутерами при передаче через Интернет, потому что у большинства сетей максимальный размер пакета (MTU) равен 1500 байтам. Избавление от фрагментации в роутерах очень важно, потому что:

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

Сообщения с надёжной и ненадёжной передачей


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

Такая обязательность абстрагирована модулем NetChannel: я писал об этом в одном из предыдущих постов.

Рекомендуемое чтение


Один из разработчиков, Брайан Хук, написал небольшую статью о сетевой модели.

Автор Unlagged Нил «haste» Торонто (Neil «haste» Toronto) тоже её описывал.

Виртуальная машина


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

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

Более того, её дизайн гораздо более сложен: в нём сочетается защита/портируемость виртуальной машины Quake1 с высокой производительностью нативных DLL Quake2. Это достигается компиляцией на лету байт-кода в команды x86.

Интересный факт: виртуальная машина изначально должна была стать простым интерпретатором байт-кода, но производительность оказалась очень низкой. Поэтому команда разработчиков написала компилятор x86 времени выполнения. Согласно файлу .plan от 16 августа 1999 года, с этой задачей справились за один день.

Архитектура


Виртуальная машина Quake III называется QVM. Постоянно загружены три её части:



  • Сторона клиента: загружены две виртуальные машины. В зависимости от состояния игры сообщения отправляются одной из них:
    • cgame: получает сообщения в фазе боя. Выполняет только отсечение невидимой графики, предсказания и управляет renderer.lib.
    • q3_ui: получает сообщения в режиме меню. Использует системные вызовы для отрисовки меню.

  • Сторона сервера:
    • game: всегда получает сообщения, выполняет игровую логику и использует bot.lib для работы ИИ.

Внутренности QVM


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



quake3.exe и его интерпретатор байт-кода сгенерированы с помощью Visual Studio, но в байт-коде ВМ применяется совершенно другой подход:

  1. Каждый файл .c (модуль трансляции) компилируется отдельно при помощи LCC.
  2. LCC используется со специальным параметром, благодаря которому выполняется вывод не в PE (Windows Portable Executable), а в промежуточное представление, которое является текстовой сборкой стековой машины. Каждый созданный файл состоит из частей text, data и bss с экспортом и импортом символов.
  3. Специальный инструмент id Software под названием q3asm.exe получает все текстовые файлы сборок и собирают их вместе в файл .qvm. Кроме того, он преобразует всю информацию из текстового в двоичный вид (ради скорости, на случай, если невозможно применить нативные преобразованные файлы). Также q3asm.exe распознаёт вызываемые системой методы.
  4. После загрузки двоичного байт-кода quake3.exe преобразует его в команды x86 (не обязательно требуется).

Внутренности LCC


Вот конкретный пример, начинающийся с функции, которую нам нужно запустить в виртуальной машине:

    extern int variableA;
    
    int variableB;
    
    int variableC=0;
    
    int fooFunction(char* string){
	    
        return variableA + strlen(string);
        
    }

Сохранённый в модуле трансляции module.c lcc.exe вызывается со специальным флагом, чтобы избежать генерации объекта Windows PE и выполнить вывод в промежуточное представление. Это файл вывода .obj LCC, соответствующий представленной выше функции C:

    data
    export variableC
    align 4
    LABELV variableC
    byte 4 0
    export fooFunction
    code
    proc fooFunction 4 4
    ADDRFP4 0
    INDIRP4
    ARGP4
    ADDRLP4 0
    ADDRGP4 strlen
    CALLI4
    ASGNI4
    ARGP4 variableA
    INDIRI4
    ADDRLP4 0
    INDIRI4
    ADDI4
    RETI4
    LABELV $1
    endproc fooFunction 4 4
    import strlen
    bss
    export variableB
    align 4
    LABELV variableB
    skip 4
    import variableA

Несколько замечаний:

  • Байт-код разделён на части (text, data и bss): мы чётко видим bss (неинициализированные переменные), data (инициализированные переменные) и code (обычно называемую text)
  • Функции определяются с помощью сендвича из proc, endproc.
  • Промежуточное представление LCC — это стековая машина: все операции выполняются в стеке и никаких допущений о регистрах ЦП не делается.
  • В конце фразы LCC у нас есть группа файлов, импортирующих/экспортирующих переменные/функции.
  • Каждое объявление начинается с типа операции (например, ARGP4, ADDRGP4, CALLI4...). Каждый параметр и результат передаётся в стек.
  • Импорт и экспорт находятся здесь, поэтому ассемблер может «связать» модули трансляции вместе. Заметьте, что используется import strlen, потому что ни q3asm.exe, ни интерпретатор ВМ не обращаются к стандартной библиотеке C, strlen считается системным вызовом и выполняется виртуальной машиной.

Такой текстовый файл генерируется для каждого файла .c в модуле ВМ.

Внутренности q3asm.exe


q3asm.exe получает текстовые файлы промежуточного представления LCC и собирает их вместе в файл .qvm:



Здесь можно заметить следующее:

  • q3asm разбирается в каждом из символов импорта/экспорта в текстовых файлах.
  • Некоторые методы заданы предварительно в текстовом файле системных вызовов. Можно увидеть syscall для клиентской ВМ и для серверных ВМ. У символов системных вызовов есть атрибуты в виде отрицательных целочисленных значений, чтобы их мог распознать интерпретатор.
  • q3asm меняет представление с текстового на двоичное с целью получения пространства и скорости, но ничего более, никаких оптимизаций здесь не выполняется.
  • Первым собираемым методом должен быть vmMain, потому что это диспетчер вводимых сообщений. Кроме того, он должен находиться в 0x2D текстового сегмента байт-кода.

QVM: как она работает


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



Некоторые подробности:

Сообщения (Quake3 -> ВМ) отправляются виртуальной машине следующим образом:

  • Любая часть Quake3 может вызвать VM_Call( vm_t *vm, int callnum, ... ).
  • VMCall может получать до 11 параметров и записывает каждое 4-битное значение в байт-код ВМ (vm_t *vm) с 0x00 по 0x26.
  • VMCall записывает идентификатор сообщения в 0x2A.
  • Интерпретатор начинает интерпретировать опкоды в 0x2D (куда q3asm.exe записал vmMain).
  • vmMain используется для диспетчеризации и маршрутизации сообщения к соответствующему методу байт-кода.

Список сообщений, отправляемых клиентской ВМ и серверной ВМ, представлены в конце каждого файла.

Системные вызовы (ВМ -> Quake3) выполняются так:

  • Интерпретатор один за другим выполняет опкоды ВМ (VM_CallInterpreted).
  • Когда он встречает опкод CALLI4, то проверяет индекс метода в int.
  • Если значение отрицательное, то вызов системный.
  • Вызывается с параметрами указатель функции системного вызова (int (*systemCall)( int *parms )).
  • Функция, на которую указывает systemCall, используется для диспетчеризации и маршрутизации системного вызова к нужной части quake3.exe

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

Интересный факт: параметры всегда имеют очень простые типы, они или примитивные (char,int,float), или являются указателями на примитивные типы (char*,int[]). Подозреваю, что так сделано для минимизации проблем связи struct между Visual Studio и LCC.

Интересный факт: ВМ Quake3 не выполняет динамическое подключение, поэтому разработчик мода QVM не имел доступа ни к каким библиотекам, даже к стандартной библиотеке C (strlen, memset здесь есть, но на самом деле являются системными вызовами). Некоторым удавалось эмулировать их с помощью предварительно заданного буфера: Malloc in QVM.

Беспрецедентная свобода


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

Проблема производительности и её решение


Из-за такого длинного тулчейна разработка кода ВМ была сложной:

  • Тулчейн был медленным.
  • Тулчейн не был интегрирован в Visual Studio.
  • Для сборки QVM требовалось использование инструментов командной строки. Это мешало процессу разработки.
  • Из-за большого количества элементов тулчейна сложно было найти части, ответственные за ошибки.

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



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

  • Интерпретируемого байт-кода
  • Байт-кода, скомпилированного в команды x86
  • Кода, скомпилированного в Windows DLL

Рекомендуемое чтение








Искусственный интеллект


Сообщество моддеров написало системы ботов для всех предыдущих движков idTech. В своё время довольно известными были две системы:

  • Для Quake1 был Omicron.
  • Для Quake2 написали Gladiator.

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

Источник: страница 275 книги «Masters of Doom»:

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

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

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

Архитектура


В результате над ботами работал Жан-Поль ван Ваверен (Mr.Elusive), и это забавно, ведь он написал «Omicron» и «Gladiator». Это объясняет, почему часть серверного кода ботов выделена в отдельный проект bot.lib:



Я мог бы написать об этом, но Жан-Поль ван Ваверен (Jean-Paul van Waveren) сам написал
103-страничный труд с подробным объяснением. Более того, Алекс Шампана (Alex J. Champandard) создал обзор кода системы ботов, в котором описывается местоположение каждого модуля, упомянутого в труде ван Ваверена. Этих двух документов достаточно для понимания ИИ Quake3.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330818/


Метки:  

Механическая Коробка и моя Success Story

Понедельник, 19 Июня 2017 г. 09:31 + в цитатник
Читая Хаб о разработке игр, я часто натыкаюсь на топики в духе «А вот мы делали-делали игру, конечно, она не пошла, но главное опыт, первый блин комом...» и все в таком ключе. Да я и сам грешил этим, чего уж скрывать. И знаете что? К черту это! Хочется прочитать, как у автора все получилось, про миллионы восторженных игроков, про манящие вершины топов, про то, ради чего мы и читаем «постмортемы». Чтобы черпать вдохновение, чтобы с удвоенной энергией преодолевать свои собственные трудности, в конце концов.



Этим мы сегодня и займемся. Это будет рассказ о создании одной моей неоднозначной головоломки, с трудностями, победами, деньгами и прочими пикантными подробностями (для самых нетерпеливых я обвел на КДПВ сумму). Конечно, кто-то только улыбнется такому «успеху», но я считаю, что в современных реалиях, игра, сделанная 2 людьми в свободное от основной работы время, показала себя очень и очень неплохо! Но, обо всем по порядку.

А вот в наше время...


Когда деревья были большими, а я только купил свой первый Android-смартфон (HTC Hero, как будто это было вчера!), все было совсем иначе. Эта мобильная ОС только начинала свое победное шествие и Google был очень заинтересован в появлении новых игр и приложений под нее, пусть даже любительских. Кто-то, как и я, смахнет скупую слезу вспоминая «Топ Новых» — «счастье для всех, даром» от Google. Какой маркетинговый бюджет, какая покупка трафика? Выкладываешь свою игру в магазин (и просто регулярно ее обновляешь) и вот она органика, пользовательская база растет как по волшебству. Делай хорошую игру и не забивай остальным голову — вот и весь секрет! При всем при этом, слабая конкуренция. Можно было буквально на коленке собрать какую-то средненькую игру и заработать, ну скажем… 100 000$, совершенно фантастическая сумма, если вы решите провернуть подобный трюк сейчас.

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

Сейчас, если вы решите заняться мобильной разработкой, запомните горькую правду: ЗДЕСЬ ВАМ НЕ РАДЫ. Теперь рынок повзрослел и Google планомерно выдавливает с него инди (я буду говорить в основном, про Android и Google Play, так как они мне лучше знакомы). Больше нет никакого списка, куда игра могла бы попасть просто потому, что она новая (читай бесплатно). Остался только топ «Набирающие популярность» — игры, у которых есть трафик. Пока вы не купите рекламу (или не возьмете еще откуда-то загрузки) — ваша игра просто не появится ни на одной полке Магазина. Она будет пылиться на складе, как видео на YouTube с доступом «только для тех, у кого есть ссылка».

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

Дает о себе знать и количество ежедневно выпускаемых игр. В этом океане не просто легко, а очень легко затеряться. Если раньше можно было сказать: «Хей, Реддит, я тут сделал игру, зацените!», то сейчас с таким демаршем вам налепят ярлык «self-promotion» и отправят в бан, скорее всего. Модераторы XDA легко шли на контакт и добавляли игру на Главную (или даже делали видео-обзор), просто, по просьбе в личку. Как-то раз, на меня вышли ребята из «App of the day» и предложили сделать одну из моих игр «приложением дня», всего лишь в обмен на раздачу версии без рекламы. А это, на секундочку, 70-80k установок единовременно! Мы с ними потом еще не раз работали… Я интересовался потом, у их конкурентов (загуглите название сами) те же сутки продвижения стоили 15 тыс. евро. Да… Было время…

Если я вас не отговорил


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

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

Второй путь, ведет в страну единорогов, где порхают Флэппи Бёрды и куда мечтает попасть каждый инди. Здесь полная свобода творчества и на аналитику можно, в общем-то, забить. Идея в том, чтобы делать что-то вне мейнстрима, пытаться нащупать относительно свободные ниши (про незанятые я молчу). Главное — зацепить чем-то игрока, вызвать ответную реакцию. Необычная графика, какие-то фишки геймплея, увлекательный сюжет… Все что угодно, что позволило бы рассчитывать на виральность. Честно говоря, это ставка на чистое и незамутненное везение. Этакий современный золотоискатель. Причем шансы на успех я думаю ниже, чем если бы вы в самом деле поехали куда-нибудь на Аляску, копать землю в поисках золота. Такой вот самообман, зато приятный. Я, как вы уже наверное догадались, пытаюсь найти этот путь.

Механическая Коробка


Суть Механической Коробки в двух словах: это набор головоломок. Представьте себе железный кубик, который вы вертите в руках, пытаетесь нажимать на выступы, нащупать какие-то секретные переключатели… Чтобы понять, как это, черт возьми, открывается? Это и будет Механическая Коробка. Она многослойна как луковица, взламывая один слой защиты, под ним вы обнаружите еще один, а под этим — следующий и так далее. Каждый слой защиты — это самостоятельная, авторская головоломка. Никаких повторов.

Ваша задача звучит просто: открыть Коробку. Но только звучит. Тут мы подходим к тому, что я попытался уникального вложить в эту игру. То чем она отличается от всех прочих «100 doors» и «Escape the Room». И это ВЫЗОВ. Если угодно, игру можно назвать недружелюбной к игроку, не будет никаких туториалов, никто не поведет вас за ручку. Вместо этого будут не просто сложные, а часто экстремально сложные головоломки. Я по честному постарался сделать все возможное в рамках правил игры (а иногда, даже немного заступая за них), чтобы вы не смогли открыть эту Коробку. Но в этом-то и есть вся прелесть! Без боя не бывает радости победы.



Кроме всего прочего, я вынужден признать, что сами головоломки… как бы это выразиться… немного нестандартные. Они не только и не столько на логику, сколько на внимательность, умение находить закономерности и мыслить неординарно, «out of the box» как часто пишут в отзывах. Тут либо вам понравится, и вы скажете «Вау! Когда новые уровни?» или (таких комментариев тоже хватает) «Что за бред? Никакой логики! Автор — шизофреник!» Мне реально кто-то написал так, хех. В любом случае, игра вызывает реакцию, то о чем я говорил выше. Это у нас получилось неплохо, я считаю.

Технические детали


Теперь, когда я рассказал вам вкратце об игре, этому топику срочно нужны технические подробности. Механическая Коробка сделана на игровом движке LibGDX. На мой вкус, хороший, бесплатный, кроссплатформенный движок, простой и понятный как молоток — это, собственно, его главное достоинство. Если вы планируете не слишком навороченную игру, работаете с Java и Android Studio — то это вполне себе альтернатива попсовому Unity. Другие плюсы: небольшой размер билда, море информации в Интернете и простая интеграция с чем угодно. Например, рекламу и инаппы подключаем практически так же, как в любом другом нативном приложении, никаких плагинов — не требуется. Билд для iOS создается прямо из Android Studio.

Посмотрел по Bitbucket, между первым коммитом и релизом прошло чуть больше 3 месяцев. Я стремлюсь разработку всех своих игр укладывать примерно в такой промежуток времени, не брать более масштабные идеи, но и не тратить время на более мелкие. Архитектурно, Механическая Коробка выглядит довольно просто: это один игровой экран с одной активной сценой. Кроме момента, когда происходит переход между уровнями, тогда сцены 2: передний и задний план (предыдущий и следующий уровни). Вся графика загружается сразу при старте игры (я предварительно упаковываю её в атласы с помощью TexturePacker). Это плюс и минус одновременно. Плюс — потому что упрощает код и позволяет сделать «бесшовный» переход между уровнями, один уровень раздвигается и под ним мы сразу видим следующий, без необходимости выгружать старые текстуры и загружать новые. Минус — потому что при наращивании количества уровней, игра, рано или поздно, начнет занимать непозволительно много места в памяти.

Не могу не отметить оригинальную графическую часть. Арт и в целом визуальный стиль для Механической Коробки разработал замечательный художник Владимир Акишин, с которым мы познакомились на gamedev.ru. Озвучку я делал сам, подбирая звуки на freesound.org, OpenGameArt и diforb.com. Кстати, еще один инструмент из раздела «маст-хэв» — это бесплатная Audacity для работы со звуком.

Запуск и продвижение


Видя количество загрузок на моем аккаунте, меня часто спрашивают про продвижение. Все думают, что у меня есть какой-то секрет, ага. Но секрет в том, что ложки не существует нет никакого секрета. Прозвучит банально, но лучший совет, который я могу дать: делайте не только интересную игру, но и игру, о которой можно что-то интересное рассказать. Пишите блог, ищите свою аудиторию. Например, на том же iphones.ru можно разместить «dev story» бесплатно. Качественно оформляйте страницу в Сторах, тут, прежде всего поисковая оптимизация и перевод на основные языки, усилий требует относительно немного, а на количестве загрузок сказывается заметно.

Конечно, в 2017 году нужно тратить деньги на маркетинг. Но, спешу вас успокоить, речь не идет о каких-то космических суммах. На продвижение Механической Коробки я потратил порядка 40 тыс. рублей. Это новости на 4pda, включение в обзоры на мелких YouTube-каналах (крупные — не бюджетно), реклама в AdWords и локализация.

Что ж, давайте посмотрим чего нам удалось добиться. Скажу сразу, основные победы Мех. Коробки лежат в пределах категории Puzzle. Да оно и понятно, игра изначально создавалась как нишевая, для любителей хардкорных головоломок. Сначала, максимальные позиции на Google Play:



Крупные страны, где удалось достичь ТОП-5 — это Италия и Испания. Кроме локализации, никаких целенаправленных усилий по продвижению именно в этих странах — я не предпринимал. ТОП-10 — Франция и Германия. Россия — 19 место, в США удалось только-только заглянуть в ТОП-100 Puzzle.

На заметку. Странно, что в России игра получила относительно невысокое место, потому что русских пользователей у нас больше всего (16%), следующие США с 8%. Я думаю, это связано с высокой конкуренцией в русском ТОП-е Головоломок.

В целом, график загрузок выглядит вот так (их полтора миллиона на Google Play):



После марта 2017 он более-менее стабильный, но, конечно же, постепенно падает. Пик в начале декабря 2016 — это пик моих маркетинговых усилий, 1-2 неделя после запуска.

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



Тут долго перечислять страны, скажу что ТОП-1 — это Россия. Правда, мне пришлось снизить цену до минимально возможной — 15 руб. Без этого, первое место не занять никак, там весь ТОП из таких цен. В App Store сейчас балом правит демпинг, да.



Но зато, видеть свою игру ТОП-1, пусть даже только в русском Сторе и только в категории — все-равно дорогого стоит! Именно из-за таких моментов я и занимаюсь разработкой игр.

Монетизация


Наконец-то мы подходим к самому интересному вопросу. Android-версия традиционно бесплатная и монетизированна с помощью рекламы. Делая отступление, продавать на Google Play — глупейшее решение, которое может прийти вам в голову. Так уж исторически сложилось, Play Store — это фритуплей, а App Store все еще заточен на продажу «премиального» контента. Обратите внимание, топ платных у Apple идет перед топом бесплатных, а у Google — наоборот. Нет, конечно, если у вас есть договоренность о фичеринге и деньги на маркетинг — тогда да, попытаться стоит, в других случаях, я бы не стал.

Изначально, в Механической Коробке была одна «межстраничка» AdMob при выходе из игры в главное меню. Хорошо, что я достаточно быстро понял, для такого типа игр идеально подходит видео-реклама с вознаграждением. Если вы застряли на какой-нибудь головоломке, вы можете нажать Помощь, после чего игра предлагает посмотреть 30 сек. ролик в обмен на подсказку. Тут мы убиваем 2 зайцев: стимулируем игрока думать самому и зарабатываем деньги, конечно!

Технически, рекламные ролики — это Unity Ads, через медиацию AdMob. И хочу сказать, что в данной игре, реклама от Unity Ads показала себя очень неплохо!



В абсолютных значениях — это чуть больше 25 000$. Внутриигровая покупка только одна — отключение рекламы. Интересно, что после добавления в игру подсказок есть заметный рост количества покупок отключения рекламы. Я подумал, что будет справедливо давать подсказки без просмотра видео, если игрок уже купил «No ads». То есть, получился такой взаимовыгодный товар — игра без рекламы + не лимитированные подсказки. Как показывает практика, само по себе отключение рекламы — не очень интересно как покупка, проще отключить интернет не на долго, наверное.

Про App Store могу сказать, что для платной игры в русском топе категории, денег почти нет. Мы продали 13 с лишним тысяч копий и заработали около 4 000 долларов.



Если мне не изменяет память, пик — это снижение цены. Эта стратегия все еще работает, ставите цену побольше, а потом улучшаете позиции игры, делая распродажи. Вообще, с App Store у меня не очень складывается, сказывается отсутствие опыта, я все-таки Android-разработчик. Это скорее довесок к тому, что игра неплохо зашла на Google Play.

На данный момент есть небольшой «хвост» и по продажам, и по рекламе, но я не думаю что он будет особо длинным. К тому же я решил сделать Механическую Коробку в App Store бесплатной, насовсем.

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

Послесловие


Совсем недавно, мы сделали Механическую Коробку 2. Ух! Это нечто! Я постарался учесть все пожелания игроков и усвоить уроки первой части. Полностью новый визуальный стиль, ребята из Sevilya Sound сделали крутейший саундтрек и звуковой дизайн. Что осталось по прежнему, так это те самые, на редкость «зубастые» головоломки! И хотя это еще бета по сути, уровней не так много, но я еще не встречал человека, который мог бы открыть Мех. Коробку быстрее, чем за час. Это, пожалуй, первая игра, в которой я не хочу ничего переделывать. Так что, кто знает, может это только начало истории…

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

https://habrahabr.ru/post/330478/


Software Defined Radio руками шестнадцатилетнего подростка

Понедельник, 19 Июня 2017 г. 09:14 + в цитатник

SDR, или программно-определяемая радиосистема – это устройство для работы с радио, в котором работает мини-компьютер со специальным программным обеспечением. Он заменяет традиционные аппаратные компоненты: фильтры, усилители, модуляторы и демоуляторы. Это позволяет создать радиоприемник, работающий с самыми разными протоколами. Вообразите себе радиолу, которая кроме «ХитFM» может принимать аналоговое и цифровое телевидение, связываться по Wi-Fi, Bluetooth и GPS, а также засекать излучение пульсаров.


А теперь представьте себе американского девятиклассника, который решил сделать такую радиолу, заказал через интернет ПЛИС, радиомодуль, развёл шестислойную плату, а потом своими руками смонтировал на неё почти 300 компонентов. И через три ревизии это всё у него заработало!


Что такое SDR


Кому может понадобиться такая радиола? Радиолюбителям, которые здорово эволюционировали! Двадцать лет назад увлеченный человек покупал сложный приёмник и часами сидел в наушниках, вращая частоты в поисках интересных сигналов. В современном мире радиоэфир переполнен информацией, но вся она цифровая. Слушать в наушниках пакеты Wi-Fi не представляет никакого интереса. Сегодня радиолюбитель находит в эфире интересные цифровые радиостанции, а потом подбирает софт, который разбирает протокол передачи и преобразует информацию. К примеру, можно принимать данные телеметрии гражданской авиации – на основе такого рода информации от множества радиолюбителей по всему миру сайт flightradar публикует данные о воздушных судах.


Вы можете прямо сейчас своими глазами увидеть работу Software Defined Radio. Университет Твенте содержит увлекательный проект онлайн SDR-приёмника, который принимает сразу кусок спектра шириной в 29MHz, после чего радиолюбители могут параллельно прослушивать различные несущие этого диапазона. Каталог подобных радиопроектов собран на сайте


Большую роль в популярности любительского SDR играет небольшая стоимость минимального комплекта оборудования. Обнаружились недорогие TV-тюнеры, реализованные на Software-Defined Radio, и в интернете немедленно появились инструкции о том, как перепрашивать такие тюнеры, чтобы прослушивать с их помощью не только телевизионный сигнал. Специализированный комплект на китайском рынке стоит всего 35$ правда, он приходит разобранным (в необходимости предварительно спаять и заключается его шарм) и поддерживает диапазон только 100KHz-1.7GHz. Конечно, аппетит приходит во время еды, и очень скоро радиолюбитель начинает смотреть в сторону оборудования, которое может принимать широкие частотные диапазоны на высокой скорости. Давайте рассмотрим, какие серьёзные приборы сейчас наиболее популярны.


Название Диапазон Макс. ширина канала ADC Sample Rate Цена
hackRF One 1MHz — 6MHz 20MHz 20MSPS $299
bladeRF x40 300MHz — 3.8GHz 28MHz 38.4MSPS $420
USRP B205mini-i 70 MHz — 6 GHz 56MHz 61.44MSPS $750
LimeSDR (coming soon) 100 kHz — 3.8 GHz 61.44MHz 61.44MSPS $299
RTL-SDR (receive only) 22 MHz — 3.8 GHz 3.2MHz 3.2MSPS $10
Per Vices Crimson 0 MHz — 6 GHz 1200MHz 370MSPS $6500

Полный список на Википедии


В двух словах: начинать знакомство с SDR можно с дешёвых вариантов типа RTL-SDR. Когда аппетит исследователя превысит небольшие возможности устройства, придётся искать замену подороже. Устройства типа Per Vices Crimson используются очень серьёзными специалистами, чьи компьютеры достаточно производительны для обработки таких потоков информации. LimeSDR на данный момент только-только закончил сбор средств на Kickstarter. Выглядит очень заманчиво: частота семплирования максимальна для USB3.0, а ширина канала достаточна для поднятия шести 10MHz сот LTE.
Однако, ещё недавно выбор не был так велик, и если не устраивал hackRF за $300, то следующим вариантом был USRP сразу за $750, и никакого компромисса. В связи с этим, шестнадцатилетний Лукас Лао Бейер решил самостоятельно разработать SDR-плату и недавно опубликовал отчёт о своём проекте. Сказать, что мы были поражены – ничего не сказать, лучше просто промолчать.
"Да что эти американские школьники себе позволяют!" — кричат в комментариях к статье Лукаса. Люди годами совершенствуют своё мастерство, а этот мальчишка сделал всё между уроками! Мы решили, что так это оставлять нельзя, и связались с Лукасом. В этой серии статей мы рассмотрим все аспекты создания подобного устройства, чтобы российские школьники перенимали опыт и делали не менее восхитительные вещи. Начнём с перевода на русский язык дневника Лукаса, в котором можно пронаблюдать ход проекта и его переживания в связи с ним. Затем мы разберём выбранные решения и попробуем изготовить такое устройство в российских условиях.


Разработка аппаратной части


Из дневника Лукаса Лао Байер
FreeSRP – доступная программно-определяемая радиосистема. Я ее разработал, потому что не нашел устройств с более высокой пропускной способностью, чем HackRF за 300$, но дешевле более производительной USRP за 700$. Некоторые компоненты еще требуют доработки, но система будет полностью соответствовать философии Open Source.
FreeSRP основана на трансивере Analog Devices AD9364. Ключевые возможности:


  • Полоса в 56MHz
  • Частотный диапазон 70MHz — 6GHz
  • Полнодуплексный режим работы.

Несмотря на то, что есть другие альтернативы типа LimeSDR, я считаю, что FreeSRP будет востребован. Разработка, как и ожидалось, была невероятно познавательной.
Я начал работу над системой два года назад, летом 2014, когда мне было 16. На тот момент у меня не было опыта серьезной работы с железом, не считая низкопроизводительных плат для моего проекта High Altitude Balloon. Поэтому я понимал, что разработка FreeSRP будет непростой во всех аспектах: скоростные шины (100MHz), USB3.0, сигнальные дорожки с производительностью до 6GHz, сложные схемы питания с семью различными напряжениями… Очень хотелось собрать компактную систему на современных компонентах, так что пришлось познакомиться с такими компонентами, как BGA или QFN.



Сравните мою предыдущую плату и нынешнюю
Что и говорить, амбициозность проекта колоссальна. Однако, меня это нисколько не пугало, и я начал с чистого листа, исходя лишь из того, что я точно буду использовать трансивер AD9346, а мост между трансивером и USB3.0 реализую на ПЛИС. Недолгие поиски привели меня к Xilinx Artix 7 и контроллеру Cypress EZ-USB FX3. Эти игрушки показались мне оптимальными рещениями в плане цены.


На основе даташитов и референсных дизайнов я постепенно подготовил принципиальную схему, в которой решил вопросы по всем остальным компонентам. Для разработки я использовал Altium Designer. Хотя он и не open source, для меня это был наиболее интуитивно понятный пакет дизайна печатных плат. Многие его прекрасные функции весьма помогли мне в разработке: жизнь становится гораздо проще, если у тебя есть инструменты для отрисовки параллельных шин или дорожек с конкретным сопротивлением. Впрочем, когда я закончу устранение недочётов в дизайне, я перерисую всё в KiCad, чтобы большему числу людей было удобнее пользоваться моими разработками.


От дизайна к прототипу



Когда схема готова, пора выпускать шаблон платы. Для прототипа очень важна цена изготовления, и в мой бюджет еле-еле умещалась четырёхслойная плата от нашего американского сервиса OSH Park, который славится низким ценником на штучные заказы. Пусть у них есть только четырёхслойки, параметры изготовления весьма хороши — дорожки 5 mil с такими же промежутками, 10 mil для отверстий, а также прекрасный субстрат Isola FR408, от качества которого зависит радиосигнал.


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



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


Изготовление прототипа
После долгих треволнений, я всё же заказал три платы, и в январе 2015 они — УРА! — приехали. Я намеревался самостоятельно собирать плату, поэтому дополнительно заказал шаблон монтажа на пленке для паяльной пасты. Для монтажа я использовал галогеновую печку и контроллер собственной разработки.



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



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



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


Первое включение



Конечно, я невероятно страшился первого включения платы. Хотя цепи питания были проверены на первой плате, я всё равно не исключал, что сейчас мои драгоценные компонентики вспыхнут синим пламенем. Возможно есть какой-то безопасный способ включать не тестированную плату. Мне ничего лучше не пришло в голову, как плавно повышать ток на блоке питания, и молиться, чтобы нигде не пошёл дым.
Тест на дым был пройден успешно, и лампочки загорелись. Ни ПЛИС, ни USB на ощупь не нагревались. Я подключил USB в компьютер, и операционка обнаружила чип Cypress. Затем я запустил приложения Xilinx, и они подключились к ПЛИС через JTAG. Похоже, всё заработало! Рассмотрев детальней, я конечно нашёл ошибку: криво развёл разьём USB3.0, так что заработала только вторая версия. Ничего страшного, начнём тестировать в таком виде, и исправим проблему позже.


Вторая ревизия
Во второй ревизии мне понадобилось устранить проблемы с питанием и разводкой USB3.0. В результате, я получил полностью рабочую цифровую часть платы, и пора было переходить к радиочасти.
Сначала я не стал трогать трансивер, и собрал все остальные компоненты. Параллельно, началась разработка программной части проекта. До этого я никогда не программировал ПЛИС, поэтому мне пришлось изучать Verilog с нуля. На этом этапе я решил реализовать параллельный интерфейс к USB-контроллеру. Хотя все части проекта были не тривиальны, разработка ПЛИС для меня стала самой жуткой частью проекта. Очень сложно найти документацию для чайников по использованию инструментов и IP-блоков. Сообщения, которые писала Vivado Design Suite, были для меня китайской грамотой, а включение готовых IP-блоков приводило к сотням непонятных уведомлений. Скорее всего, я просто не умею пока правильно готовить на этой кухне.Даже самые минимальные изменения в дизайне требовали мучительно долгого обсчёта программой, поэтому всё необходимо симулировать — а это еще больше усложняет вход в чудесный мир ПЛИС. А отладка! Без Integrated Logic Analyzer отлаживать что-либо совершенно невозможно, а он стал бесплатным только в 2016 году– до этого прайс был очень высоким. Поэтому пришлось при отладке передавать часть тестовой информации морганием диода, а часть — на ножки GPIO и смотреть сигнал осциллоскопом.



В вопрос по тактированию я вник до конца не сразу – только к третьей попытке пришло осознание, что тактовый сигнал трансивера нужно было обязательно завернуть в clock-inputs на ПЛИС.
Наигравшись с Verilog, я решил, что самое время впаивать трансивер. Я взял третью плату, вновь установил на неё три сотни компонентов, как и ранее, начав с нижней стороны. Но когда я паял верхнюю сторону, контроллер моей печки объявил забастовку и не выключил печь. Я не мог получать показания по температуре в печи, а контролировать агрегат удавалось только включая-выключая его или открывая дверцу. Никакие мои молитвы не помогли: на дорожках появилось КЗ. Я попытался починить, но тщетно: при включении ПЛИС нагревался. Увы, я только что сжег в печи четыре сотни баксов, и этот факт совсем не придавал мне уверенности.
Тем не менее, я был решительно настроен закончить проект, поэтому разбил копилку, вновь заказал компоненты и через несколько недель предпринял еще одну попытку всё собрать. Вы не представляете, как я потел в этот раз, словно в финале турнира по покеру! К счастью, всё прошло без сюрпризов.



Цифровая часть в новом прототипе работала идеально. А вот трансивер работать не хотел, его конфигурационный порт просто не отвечал. Потом я заметил, что трансивер на ощупь горячий. Почему он так нагрелся, было непонятно, ведь он должен спать без конфигурации. Я безуспешно пытался найти проблемы в питания. Излазил все схемы, перепроверил все на сто раз. И потом я обнаружил следующую вещь.
Оказывается, я по ошибке последовательно включил два резистора — 698Ом и 536ОМ (в сумме 1234Ом) вместо 14.3 килоомного резистора из документации! Я заменил резисторы, и чип перестал греться, но он всё равно не работал. Похоже, я его спалил.



В общем, в этот момент я решил, что сделано уже достаточно много для такого юного специалиста без глубоких знаний электроники, и пора проект отложить. Но у меня осталась работающая ПЛИС, поэтому я стал развлекаться с ней.
В результате долгих экспериментов, я прикрутил драйвер трансивера и справился с генерацией тестовых сигналов. У меня заработала цепочка передачи сигнала от ПЛИС к USB, так что дальше я мог управлять своей SDR с компьютера с помощью библиотеки на более знакомом мне C++. Затем я реализовал совместимость моей платы с GNURadio, так что теперь с этой платой могли работать все полезные программы, реализованные на базе GNURadio.


Третья ревизия



В какой-то момент я нашёл силы на ещё один рывок и сделал третью ревизию. Я исправил досадную ошибку с 14.3 килоомным резистором, соединил clock-inputs с FPGA, и заменил осциллятор трансивера на кристалл, чтобы упростить раздачу тактового сигнала и исключить дальнейшие проблемы.
Конечно, проект вышел за рамки срока и бюджета, но сейчас мне уже кажется, что иметь всего три ревизии до работающей платы — это совсем неплохо!
Также на этой ревизии я перешёл на шестислойную печатную плату. Прототипы стали стоить дороже, но расстояние между сигнальными дорожками значительно увеличились, и я достиг максимальной тактовой частоты в шинах.
Кроме того, я купил отличные шаблоны из нержавейки, которые, в отличие от каптоновых, гораздо проще использовать.



Раз софт у меня уже был готов, я сразу смог запустить трансивер на прием, и вот они долгожданные первые сэмплы в GNURadio!



Наконец-то вся тяжелая работа дала свои плоды. Еще через несколько недель я смог запустить передатчик, и убедился, что полнодуплексный режим у меня взлетел, пусть и не в полную ширину. И тут я нашёл новую проблему с усилком на передаче, поэтому сигнал получился очень слабым.
В любом случае, у меня есть полнофункциональная SDR-плата, ребята! Да, ещё много нужно доделать. Я хочу тщательно измерить производительность приемника и передатчика. Очень хочется запустить мелкосерийное производство, но перед этим мне нужно ещё немного оптимизировать дизайн и быть на 100% уверенным, что я не оставил в плате ещё каких-то сюрпризов.


Постановка задачи
Большое спасибо Лукасу за его подробный отчёт, а сейчас давайте рассмотрим его решения.
Итак, Лукас хотел сделать широкополосную программно-определяемую радиосистему с характеристиками лучше, чем у hackRF, и дешевле USRP. Давайте рассмотрим, как устроено оборудование конкурентов.
USRP




bladeRF



hackRF



Последнее изображение выглядит наиболее лаконично, однако все три устройства имеют одинаковую архитектуру: сигнал принимается из эфира, оцифровывается и передаётся в USB. Есть различия в деталях. В hackRF радиочасть реализована в виде нескольких компонент: сигнал после приёма с помощью миксера сдвигается в промежуточную частоту диапазона 2.3-2.7GHz, затем преобразуется в синфазную и квадратурную составляющую сигнала, которая уже оцифровывется. Другие устройства решают эту задачу одним компонентом — трансивером. Преобразование цифрового сигнала для передачи в USB, а также управление радиотрактом, осуществляется при помощи ПЛИС (FPGA) либо микроконтроллера.
Проектируя систему сверху вниз, мы разделим её на три части: RF, FPGA и USB, и сначала проработаем каждый блок по отдельности, а затем разберёмся, как связать их вместе.


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


Как в hackRF
Майкл Оссманн, кстати говоря, тоже радиолюбитель, а не радиопрофессионал, и единственная причина, почему он не решил радиочасть в своём проекте в виде одного умного кусочка кремния — это доллары, которые для этого потребовались бы. Майкл выбрал компромисс: он использует три кусочка кремния и экономит примерно половину стоимости, что делает hackRF таким доступным по цене. Радиосигнал в hackRF приходит на RFFC5071, который понижает частоту до ~2.5GHz (это называется LO-синтез), затем этот сигнал попадает в узкополосный трансивер MAX2837, превращается в baseband и в таком виде идёт в MAX5864 — это как раз цифро-аналоговый (и обратно) преобразователь.


AD9364
Analog Devices выпускают отличные трансиверы, которые часто используются в различных SDR-проектах. Выше на схеме видно, что такой чип, к примеру, комфортно себя чувствует на устройствах USRP. У производителя можно купить чип на демонстрационной плате AD-FMCOMMS4-EBZ, которая в принципе является готовой примитивной SDR.


LMS6002D
Чипы Lime Micro используются во множестве систем (bladeRF, например), в том числе и в российской SDR-разработке umTRX, а в этом году они замахнулись на собственную SDR-систему и успешно собрали на Kickstarter средства для запуска LimeSDR в продакшн. В целом, Лукас вполне имел право использовать этот чип в своей работе, он прекрасен, и главный его недостаток — диапазон принимаемых частот вполовину уже, чем у AD9364.
Поэтому в итоге Лукас выбрал вариант с AD9364, и немедленно заказал его.


Выбор FPGA
Самое сложное при выборе ПЛИС — это определиться Altera или Xilinx. Эти компании словно Sony и Nintendo производят одинаково крутое железо, и дьявол лишь в деталях. Какая же разница между Altera и Xilinx?
Altera славится очень долгой поддержкой своих микросхем. Среда разработки Xilinx Vivado работает только с последней (седьмой) серией микросхем, тогда как Altera's Quartus поддерживает даже Flex 10K, которому пятнадцать лет исполнилось с момента первого выпуска. На момент старта проекта, софт для отладки Xilinx стоил 700$ (и стал бесплатным только в этом году), а у Altera он бесплатен. IP-блоки (готовые программные библиотеки) в Altera можно попробовать во время демо-периода с ограничениями. В итоге, для новичка-любителя Altera выглядит предпочтительней. Зато в Xilinx умнее DSP часть, в ней есть не только умножение (как в Altera), но и предсложение с аккумулятором, что уменьшает количество необходимых логических блоков для решения задачи.
Но Лукаc выбрал Xilinx. Он утверждает, что из-за цены, но я думаю, что наугад (сравните, Xilinx Aritx-7 и Altera Cyclone V).
Как выбрать конкретную модель микросхемы у Xilinx? Два года назад выбор стоял между Spartan-6 и Artix-7, которые считаются low-cost предложением Xilinx. Spartan-6 отпадает, потому что его не поддерживает программное обеспечение Vivado.
Все BGA семейства Artix-7 совместимы что называется pin-to-pin, поэтому дальше Лукас просто ткнул в модель 50T, решив определиться с конкретной моделью, когда софт будет готов и точно определятся требования к производительности микросхемы.
Какие FPGA используют в других аналогичных проектах?


SDR Модель FPGA Logic Cells
USRP B200 Xilinx Spartan 6 LX150 150k
USRP B210 Xilinx Spartan 6 LX75 75k
bladeRF x40 Altera Cyclone 4 40k
bladeRF x115 Altera Cyclone 4 115k
hackRF CPLD xx

Автор hackRF не стал ставить FPGA, а выбрал более дешёвую технологию — CPLD, что является, скажем так, упрощённой версией FPGA. В результате, он практически ничего полезного не может в ней делать и вообще планирует исключить ПЛИС из своего дизайна, переведя управление трансивером на чип USB-контроллера.


USB3.0
Осталось определиться с решением для USB3.0. Самое популярное решение здесь — микроконтроллер Cypress FX3, и сложно придумать причины не использовать его. Тем не менее, рассмотрим альтернативы.
Первым на ум приходит FTDI FT60x — микроконтроллер в корпусе QFN. Компания FTDI знаменита тем, что любит выпускать драйвера, которые намеренно убивают твой чип, если он является подделкой. Если для USB2.0 чипы этой компании считались стандартом де-факто, то в USB3.0 они, к сожалению, упустили свой рынок таким странным отношением к оборудованию конечного пользователя и низким качеством софта.
Другой вариант — взять трансивер от Texas Instruments TUSB1310A, а MAC-уровень реализовать в ПЛИС. Трансивер стоит на 20$ дешевле, чем микроконтроллер от Cypress FX3, и я затрудняюсь прокомментировать, почему Лукас не сделал именно так.


Изготовление печатной платы
Если вам больше хочется программировать, чем развлекаться с паяльником, я бы рекомендовал делать прототип на готовой плате. Хороший список готовых плат на разных ПЛИС можно найти на специальном сайте. Для этого конкретного проекта есть идеальный вариант готовой платы с USB3.0 и FPGA Artix 7 остаётся только скоммутировать трансивер и можно немедленно приступать к экспериментам.
Однако, Лукасу в этом проекте были интересны все этапы. Более того, он даже монтировать плату хотел сам. Прототипы Лукас изготовил в OSH Park — это очень популярный сервис среди американских студентов. Цена у них идёт от площади платы (10$ за квадратный дюйм), и с учётом расположения в США вся процедура занимает весьма короткий промежуток времени. Однако, сейчас, когда на плату есть заказы и её нужно изготавливать десятками, имеет смысл поискать самый оптимальный вариант для её изготовления. Ниже в таблице я привёл сравнение российских и зарубежных сервисов по изготовлению плат без монтажа на них.
Сравнение цен на изготовление печатной платы. Требования:


  • 5 mil=0,127 мм минимум дорожки
  • 5 mil=0,127 мм минимум промежутки
  • 10 mil=0,254 мм минимальное отверстие
  • Субстрат для платы с хорошими характеристиками
  • Размеры платы: 74 * 108mm

Предприятие Стоимость за пять штук шестислойки Пять штук четырёхслойки
OSH Park Шестислойную не делают 123$ за три штуки, опт — от 150 квадратных дюймов
PCB tech 614$ -
Резонит 153$ -
EasyEDA 284$ -
seeedstudio.com 158$ -
pcbwing 348$ 299$
PCB Offshore 280$ / 4pcs 140$ / 4pcs
PCBCart 191$ 93$

Часть российских заводов ответили отказом или выставили заградительные цены: не хотят связываться с мелкосерийным заказом. Хочу обратить внимание, что при текущем курсе доллара услуги российской компании Резонит оказываются даже предпочтительней китацев. Плюс, они готовы сами смонтировать платы, если вы предоставите им комплектующие. На данный момент, из этого списка я лично работал только с EasyEDA, и нареканий нет. Цены Резонита приятно удивили Лукаса, и сейчас мы планируем разместить там заказ платы по его проекту. Когда у нас всё получится, я обязательно расскажу вам детали взаимодействия с заводом, а также подготовлю статью о процессе проектирования печатной платы и подготовке проекта к изготовлению.


Пишем ПО.


Из дневника Лукаса Лао Байер
Чтобы эта плата начала приносить пользу, необходимо разработать несколько компонент:


  • Логика ПЛИС, которая послужит интерфейсом между AD9364 и USB
  • Прошивку для USB контроллера
  • Драйвер для PC, который выступит интерфейсом между платой и традиционными библиотеками.

Для персонального компьютера я написал C++ библиотеку на основе libusb. Однако, чтобы не изобретать велосипед, я решил интегрироваться в какой-нибудь популярный фреймворк, и очевидным выбором была GNU Radio.
Сначала я собирался просто написать собственный блок для GNU Radio, но затем я натолкнулся на проект gr-osmosdr, который осуществляет поддержку многих популярных SDR. В комплекте с ним идёт анализатор спектра, генератора сигнала. Плюс, эта библиотека уже используется другими приложениями (например, Gqrx, AirProbe/gr-gsm). Соответственно, если я сделаю патч в этот проект, то моя плата автоматически появится в этих приложениях.
Потому я скопировал себе актуальную версию gr-osmosdr, и дальше просто смотрел какие правки делались для поддержки других SDR. В итоге, потребовались очень небольшие правки, чтобы библиотека увидела мою плату. Дальше появились функции для настройки частоты, ширины спектра и т.д. Ключевая функция — work — производит или потребляет данные из потока GNU Radio. Сначала я реализовал простую очередь, чтобы как можно быстрее начать играть с платой, но, конечно, это неэффективно. Сейчас я обновил алгоритм и сделал, как делают все папы: через обратные вызовы и синхронизацию с помощью условных переменных


В общем, теперь для работы с моей платой через gr-osmosdr нужно просто указать аргумент freesrp.


Проверяем корректность потока данных
Я начал баловаться с GNU Radio начиная со второй ревизии моей платы, когда трансивер ещё не очень-то работал. Я просто посылал сигнал и разворачивал его обратно в приёмный тракт. Так я мог проверить, что в цифровой части платы ничего не искажается.
Чтобы проверить частоту дискретизации платы, я гнал сигнал из блока GNU Radio "probe rate", а на ПЛИС собрал простой счётчик:



Сигнал генерируется в ПЛИС и принимается в GNU Radio. Частота дискретизации вбита прямо в код. Получаемая частота дискретизации выводится в отладочное окно.


Дальше тестировал цепь передачи сигнала. Теперь сигнал генерируется в GNU Radio и сливается в (sink block).



Теперь проверяем, что ПЛИС правильно декодирует данные: драйвер должен возвращать 32-битное слово, в котором будет два 12-битных сэмпла (I и Q) и выравнивающая пустота. С помощью программы Integrated Logic Analyzer я мог получить доступ к 12-битным сэмплам в ПЛИС и сравнить их с тем, что я вижу на моём компьютере.



I и Q сигналы на конце цепочки передачи данных в ПЛИС.
GNU Radio генерировал синусы и косинусы, но данные где-то портились. В итоге оказалось, что ошибка была в моей библиотеке freesrp, она неправильно форматировала данные. Когда я её починил, то собрал петлю в ПЛИС:



И всё почти работало. Только некоторые сэмплы терялись и заменялись на нули. На следующей картинке мы видим сгенерированный синий сигнал I, красный Q и сигнал, который прилетел обратно — зелёный I и чёрный Q:



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



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


Весёлые эксперименты с GNU Radio
Теперь мне очень хотелось попробовать декодировать реальные сигналы. Первыми моими жертвами стали GSM и Zigbee, потому что для них есть готовые библиотеки gr-gsm and gr-ieee802-15-4.


GSM
Внешние модули GNU Radio собираются через cmake, потому всё просто:
mkdir build # Creates a blank directory for the build to run in
cd build
cmake… # Load CMake build script in root of the module's directory and run it
make # Run the CMake-generated makefile
sudo make install # Install the module
sudo ldconfig
В пакете gr-gsm идёт некоторое количество пробных приложений. Самые интересные — grgsm_scanner and grgsm_livemon. С помощью первого можно поискать GSM вещание и вычленить из них какие-то идентификаторы, а также получить список базовых станций.



Поглядите, кстати, я в качестве аргумента указываю код своей платы freesrp — и всё работает. Это очень приятное чувство.
Второе приложение позволяет настроиться на один из GSM каналов, расшифровать данные и отправить их в твою локальную сеть, где их можно послушать через Wireshark. Я добавил в программу модуль gr-fosphor, чтобы скриншот стал более красочным:



802.15.4 (Zigbee)
У меня дома было несколько XBee модулей, и я решил с ними взаимодействовать. На этом примере я хотел проверить отправку данных.
Установка модуля настолько же проста, как и в случае с gr-gsm. Примеры, которые идут с библиотекой, сделаны для коммуникационного стека Rime, поэтому я отрезал от него всё, что не касается самого Zigbee, и добавил блок TCP Server, чтобы можно было по локальной сети подключаться и отправлять данные:



Для примера я написал два Python-скрипта: один подключается к XBee через USB, а другой цепляется на TCP порты в GNU Radio. И затем я просто передавал текстовые сообщения через протокол 802.15.4, как в чате.





О разработке драйвера
Дизайн ПЛИС и USB-контроллера
Сейчас моя ПЛИС ничего особого не делает, кроме как служит интерфейсом между трансивером и USB. Из-за простоты реализации, я запустил на MicroBlaze драйвер от AD9364, который производит настройку и калибровку. Драйвер взаимодействует с USB через UART. Вскоре я перенесу этот драйвер на контроллер USB.
AD9364 выдаёт семплы в 12-битный порт чередуя I и Q. Есть ещё один 12-битный порт, куда надо отправлять исходящией I\Q значения. Так же трансивер предоставляет DDR-клок в зависимости от выбранной частоты дискретизации. Во входной сигнальной цепи происходит обратное перемежение и складывание в 24битную очередь.
В контроллере USB есть механизм DMA, куда ПЛИС может напрямую писать (и оттуда же читать) данные через 32битную шину. Поэтому когда в очереди ПЛИС накопилось достаточно данных, а FX3 готова к приёму, конечный автомат перебрасывал данные.
Сейчас я использую только 24 бита из доступных 32. Влезает один I\Q семпл, и остальные 8 бит я просто отбрасываю. Но для полнодуплексной передачи данных нужно будет использовать все 32 бита.
USB контроллер предоставляет следующие контрольные точки:


  • INTERRUPT OUT — отправляет команды в MicroBlaze на драйвер AD9364
  • INTERRUPT IN — принимает ошибки или ответы на эти команды
  • BULK OUT — для отправляемых данных
  • BULK IN — для приёма данных

После включения FPGA можно настроить через INTERRUPT OUT.
Libfreesrp
Библиотека взаимодействия с FreeSRP очень проста. Для приёма и отправки используется интерфейс libusb. Это позволяет накапливать в очередь данные для оптимальной обработки операционной системой. Пользователь указывает колбэк, который будет вызван если поступили новые данные или буферы отправки освободились.


Планы
Дмитрий Стольников из gr-osmosdr уже связался со мной и предложил слить мои изменения в основную ветку библиотеки. Я вскоре закончу её полировать и сделаю это.
Когда я избавлюсь от MicroBlaze и перенесу драйвер на FX3, ПЛИС почти полностью освободится. Я бы хотел воспользоваться этим для экспериментов с обработкой сигналов в реальном времени прямо на ПЛИС.
Очень хочется получить более точные характеристики производительности радиочасти. Я не приблизился к этому ни на шаг, потому что у меня нет приборов, да и других дел полно.


Выпуск продукта





В апреле Лукас запустил краудфандинг для своего продукта и получил первую партию заказов на 20000$ (то есть, порядка пятидесяти экземпляров).


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


Справочные ссылки
Схематика FreeSRP
Исходники FPGA
Исходники USB Контроллера
Сайт проекта

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

https://habrahabr.ru/post/330052/


Метки:  

Наш рецепт отказоустойчивого Linux-роутера

Понедельник, 19 Июня 2017 г. 08:17 + в цитатник


В высоконагруженных проектах всегда повышенные требования к избыточности и надежности. Одним из важнейших звеньев инфраструктуры является маршрутизатор, потому что от его устойчивости зависит доступность сети в целом. Именно на таких узлах мы используем одну из схем реализации отказоустойчивого виртуального роутера на базе GNU/Linux с использованием iproute2, NetGWM, keepalived, ISC DHCPD, PowerDNS. Как мы всё это настраиваем, читайте в этой статье.

Компоненты


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

В общем виде схема (на уровне L2) выглядит так:


Как видно из схемы, нам нужны 2 коммутатора с поддержкой 802.1Q VLAN. Оператор 1 коммутируется в Коммутатор 1 и ему выделяется отдельный VLAN (например, 110). Оператор 2 коммутируется в Коммутатор 2, в другой VLAN (например, 120). Отдельный VLAN (в нашем случае — 200), выделяется под локальную сеть. Между коммутаторами организуется транк, и транком же линкуем оба маршрутизатора, которые и будут «сердцем» нашего виртуального роутера (схема router-on-a-stick).

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

Стек базовых компонентов, которые мы используем в работе роутеров:
  • Ubuntu Linux;
  • NetWGM — утилита приоритезации основного шлюза в решении. Это наша Open Source-разработка, о которой мы готовим отдельную статью (пока предлагаю ознакомиться с базовой документацией);
  • iproute2 — для создания нескольких таблиц маршрутизации;
  • keepalived — для реализации протокола VRRP в Linux;
  • ISC DHCPD — как горизонтально масштабируемый DHCP-сервер;
  • PowerDNS — как DNS-сервер для локальной сети.

Маршрутизаторы настраиваются примерно одинаково, за исключением конфигурации IP-адресов и keepalived.

Настройка интерфейсов


Настраиваем VLAN. Конфигурация /etc/network/interfaces будет выглядеть примерно так:

auto lo
iface lo inet loopback
        post-up bash /etc/network/iprules.sh
        post-up ip route add blackhole 192.168.0.0/16
        dns-nameservers 127.0.0.1
        dns-search dz
 
# lan, wan: trunk dot1q
auto eth0
iface eth0 inet manual
 
# lan
auto vlan200
iface vlan100 inet static
        vlan_raw_device eth0
        address 192.168.1.2
        netmask 255.255.255.0
 
# Operator1
auto vlan110
iface vlan110 inet static
        vlan_raw_device eth0
        address 1.1.1.2
        netmask 255.255.255.252
        post-up   ip route add default via 1.1.1.1 table oper1
        post-up   sysctl net.ipv4.conf.$IFACE.rp_filter=0
        post-down ip route flush table oper1
 
# Operator2
auto vlan120
iface vlan120 inet static
        vlan_raw_device eth0
        address 2.2.2.2
        netmask 255.255.255.252
        post-up   ip route add default via 2.2.2.1 table oper2
        post-up   sysctl net.ipv4.conf.$IFACE.rp_filter=0
        post-down ip route flush table oper2

Основные моменты:
  • настраиваем blackhole — хорошая практика для того, чтобы локальные пакеты не улетали по маршруту по умолчанию в сторону провайдера;
  • net.ipv4.conf.$IFACE.rp_filter=0 — необходим для корректной работы multi-wan;
  • для каждого провайдера настраиваем отдельную таблицу маршрутизации с единственным маршрутом по умолчанию.

Настроим маркинг пакетов для направления в определенные таблицы — добавим в iptables правила:
iptables -t mangle -A PREROUTING -i vlan110 -m conntrack --ctstate NEW,RELATED -j CONNMARK --set-xmark 0x1/0x3
iptables -t mangle -A PREROUTING -i vlan120 -m conntrack --ctstate NEW,RELATED -j CONNMARK --set-xmark 0x2/0x3
iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark --nfmask 0xffffffff --ctmask 0xffffffff
iptables -t mangle -A OUTPUT -o vlan110 -m conntrack --ctstate NEW,RELATED -j CONNMARK --set-xmark 0x1/0x3
iptables -t mangle -A OUTPUT -o vlan120 -m conntrack --ctstate NEW,RELATED -j CONNMARK --set-xmark 0x2/0x3
iptables -t mangle -A OUTPUT -j CONNMARK --restore-mark --nfmask 0xffffffff --ctmask 0xffffffff
iptables -t mangle -A POSTROUTING -o vlan110 -m conntrack --ctstate NEW,RELATED -j CONNMARK --set-xmark 0x1/0x3
iptables -t mangle -A POSTROUTING -o vlan120 -m conntrack --ctstate NEW,RELATED -j CONNMARK --set-xmark 0x2/0x3

И настроим правила маршрутизации для промаркированных пакетов — мы это делаем вызовом скрипта iprules.sh при выполнении ifup lo (смотри выше в /etc/network/interfaces). Внутри скрипта:
#!/bin/bash
 
/sbin/ip rule flush
 
#operator 1
/sbin/ip rule add priority 8001 iif vlan110 lookup main
/sbin/ip rule add priority 10001 fwmark 0x1/0x3 lookup oper1
/sbin/ip rule add from 1.1.1.2 lookup oper1
 
#operator 2
/sbin/ip rule add priority 8002 iif vlan120 lookup main
/sbin/ip rule add priority 10002 fwmark 0x2/0x3 lookup operator2
/sbin/ip rule add from 2.2.2.2 lookup operator2

Эти таблицы маршрутизации необходимо объявить в /etc/iproute2/rt_tables:
# reserved values
255    local
254    main
253    default
0    unspec
# local
110    oper1
120    oper2

Балансировщик основного шлюза


Настроим NetGWM — утилиту для приоритезации основного шлюза. Она будет устанавливать маршрут по умолчанию, выбирая операторов в соответствии с двумя правилами: а) установленным нами приоритетом, б) статусом оператора (жив или нет).

Чтобы установить NetGWM, можно воспользоваться исходниками на GitHub или нашим репозиторием для Ubuntu. Второй способ в случае Ubuntu 14.04 LTS выглядит так:
# Установим репозиторий
$ sudo wget https://apt.flant.ru/apt/flant.trusty.common.list -O /etc/apt/sources.list.d/flant.common.list
# Импортируем ключ
$ wget https://apt.flant.ru/apt/archive.key -O- | sudo apt-key add -
# Понадобится HTTPS-транспорт — установите его, если не сделали это раньше
$ sudo apt-get install apt-transport-https
# Обновим пакетную базу и установим netgwm
$ sudo apt-get update && sudo apt-get install netgwm

Укажем в конфиге /etc/netgwm/netgwm.yml, что у нас 2 оператора, маршруты по умолчанию для каждого из них, приоритезацию и настройки для контроля доступности:
# Описываем маршруты по умолчанию для каждого оператора и приоритеты
# Меньшее значение (число) имеет больший приоритет
gateways:
  oper1: {ip: 1.1.1.1, priority: 1}
  oper2: {ip: 2.2.2.1, priority: 2}
 
# В ситуации, когда более приоритетного оператора начинает «штормить»
# и он то online, то offline, хочется избежать постоянных переключений
# туда-сюда. Этот параметр определяет время (в секундах), после которого
# netgwm будет считать, что связь стабильна
min_uptime: 900
 
# Массив удаленных хостов, которые будут использоваться netgwm для
# проверки работоспособности каждого оператора
check_sites:
  - 192.5.5.241
  - 198.41.0.4


Обратите внимание на имена oper1 и oper2 — это названия таблиц маршрутизации из /etc/iproute2/ip_tables. Рестартнем сервис netgwm, чтобы он начал управлять шлюзом по умолчанию для системы:
$ sudo service netgwm restart

Настройка keepalived


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

На этом этапе мы определяемся, что Маршрутизатор 2 будет играть роль Backup, а Маршрутизатор 1 — роль Master. Настраиваем keepalived, изменяя конфигурационный файл /etc/keepalived/keepalived.conf:
! Глобальный блок можно настраивать под себя
! Configuration File for keepalived
global_defs {
  notification_email {
    admin@fromhabr.ru
  }
  notification_email_from keepalived@example.com
  smtp_server 127.0.0.1
  smtp_connect_timeout 30
  router_id MY_ROUTER
}
 
vrrp_instance VI_1 {
  interface vlan200  # VRRP обслуживает VLAN локальной сети
  virtual_router_id 17 # поставьте любое число, но одинаковое на Master и Backup
  nopreempt # важный параметр, подробнее см. ниже
  state MASTER # на резервном сервере установите state BACKUP
  priority 200 # на резервном сервере число должно быть ниже, например 100
  advert_int 1 # интервал рассылки сообщения “Я жив”
  garp_master_delay 1 
  garp_master_refresh 60 
  authentication {
    auth_type PASS
    auth_pass qwerty # не забудьте поменять пароль
  }
  virtual_ipaddress {
    # Виртуальный адрес, который будет шлюзом по умолчанию в локальной сети и 
       # заодно широковещательный адрес, в который будут рассылаться VRRP-анонсы
    192.168.1.1/24 broadcast 192.168.1.255 dev vlan200
  }
  # Скрипты вызываются при переходе в соответствующее состояние Master, Backup, Fault и 
  # при остановке keepalived; используются нами для передачи уведомлений
  notify_master /etc/keepalived/scripts/master.sh
  notify_backup /etc/keepalived/scripts/backup.sh
  notify_stop   /etc/keepalived/scripts/stop.sh
  notify_fault /etc/keepalived/scripts/fault.sh
}

Так как наш отказоустойчивый роутер — многокомпонентный, мы решили использовать режим, в котором переключение keepalived режимов Backup -> Master происходит только в случае отказа Master-сервера. За это как раз отвечает параметр nopreempt.

Настройка ISC DHCPD


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

Правим конфиг /etc/dhcp/dhcpd.conf:
# Настраиваем DDNS для локальных адресов
ddns-updates on;
ddns-update-style interim;
do-forward-updates on;
update-static-leases on;
deny client-updates;    # ignore, deny, allow
update-conflict-detection false;
update-optimization false;
 
key "update-key" {
        algorithm hmac-md5;
        secret "КЛЮЧ"; # про генерацию ключа см. ниже
};
 
zone    1.168.192.in-addr.arpa. {
        primary 192.168.1.1;
        key "update-key";
}
 
zone    mynet. {
        primary 192.168.1.1;
        key "update-key";
 
# Настраиваем масштабирование
failover peer "failover-partner" {
        primary; # на резервном сервере укажите здесь secondary
        address 192.168.1.3; # адрес резервного сервера
        port 519;
        peer address 192.168.1.2; # адрес основного сервера
        peer port 520;
        max-response-delay 60;
        max-unacked-updates 10;
        load balance max seconds 3;
}
 
default-lease-time 2400;
max-lease-time 36000;
 
log-facility local7;
authoritative;
 
option ntp-servers 192.168.1.1, ru.pool.ntp.org;
 
# Настраиваем пул для нашего сервера
subnet 192.168.1.0 netmask 255.255.255.0 {
  range 192.168.1.51 192.168.1.150; # на 100 адресов, например
  option subnet-mask 255.255.255.0;
  option broadcast-address 192.168.1.255;
  option domain-name-servers 192.168.1.1;
  option routers 192.168.1.1;
  ddns-domainname "mynet.";
# … и пул для резервного. Они не должны пересекаться
  pool {
       failover peer "failover-partner";
       range 192.168.1.151 192.168.1.250;
  }
# … и статические leases
  host printer { hardware ethernet 00:26:73:47:94:d8; fixed-address 192.168.1.8; }
}

Нам понадобится сгенерировать ключ update_key, с помощью которого мы будем обновлять зону mynet. Сгенерируем его и выведем на экран:
$ dnssec-keygen -r /dev/urandom -a HMAC-MD5 -b 64 -n HOST secret_key
Ksecret_key.+157+64663
$ cat Ksecret_key.+*.private | grep ^Key | awk '{print $2}'
bdvkG1HcHCM=

Скопируйте сгенерированный ключ и вставьте в конфигурационный файл вместо слова КЛЮЧ.

Настройка PowerDNS


В качестве DNS-сервера мы предпочли PowerDNS, так как он имеет возможность хранить зоны в СУБД MySQL, которую удобно реплицировать между первым и вторым сервером. Кроме того, PoweDNS — это производительное решение, хорошо функционирующее в высоконагруженном роутере.

Настройку PowerDNS начнем с подготовки базы данных.
# Заходим в MySQL CLI
$ mysql -u root -p
# Создаем БД и назначаем права для пользователя, которым будем к ней подключаться
mysql> CREATE DATABASE IF NOT EXIST powerdns;
mysql> GRANT ALL ON powerdns.* TO 'pdns_admin'@'localhost' IDENTIFIED BY 'pdns_password';
mysql> GRANT ALL ON powerdns.* TO 'pdns_admin'@'localhost.localdomain' IDENTIFIED BY 'pdns_password';
mysql> FLUSH PRIVILEGES;
# Переходим в только что созданную БД и создаем структуру данных
mysql> USE powerdns;

mysql> CREATE TABLE IF NOT EXIST `domains` (
id INT auto_increment,
name VARCHAR(255) NOT NULL,
master VARCHAR(128) DEFAULT NULL,
last_check INT DEFAULT NULL,
type VARCHAR(6) NOT NULL,
notified_serial INT DEFAULT NULL,
account VARCHAR(40) DEFAULT NULL,
primary key (id)
);
mysql> CREATE TABLE `records` (
id INT auto_increment,
domain_id INT DEFAULT NULL,
name VARCHAR(255) DEFAULT NULL,
type VARCHAR(6) DEFAULT NULL,
content VARCHAR(255) DEFAULT NULL,
ttl INT DEFAULT NULL,
prio INT DEFAULT NULL,
change_date INT DEFAULT NULL,
primary key(id)
);
mysql> CREATE TABLE `supermasters` (
ip VARCHAR(25) NOT NULL,
nameserver VARCHAR(255) NOT NULL,
account VARCHAR(40) DEFAULT NULL
);
mysql> CREATE INDEX `domain_id` ON `records`(`domain_id`);
mysql> CREATE INDEX `rec_name_index` ON `records`(`name`);
mysql> CREATE INDEX `nametype_index` ON `records`(`name`,`type`);
mysql> CREATE UNIQUE INDEX name_index` ON `domains`(`name`);

quit;


Теперь нужно настроить PowerDNS и научить его работать с БД. Для этого требуется установить пакет pdns-backend-mysql и изменить конфиг /etc/powerdns/pdns.conf:
# Настраиваем доверенные сети
allow-axfr-ips=127.0.0.0/8,192.168.1.0/24
allow-dnsupdate-from=127.0.0.0/8,192.168.1.0/24
allow-recursion=127.0.0.0/8,192.168.1.0/24
# Базовые настройки демона
config-dir=/etc/powerdns
daemon=yes
disable-axfr=no
dnsupdate=yes
guardian=yes
local-address=0.0.0.0
local-address-nonexist-fail=no
local-port=53
local-ipv6=::1
# На втором маршрутизаторе такие же значения этих параметров
master=yes
slave=no
 
recursor=127.0.0.1:5353
setgid=pdns
setuid=pdns
socket-dir=/var/run
version-string=powerdns
webserver=no
# Настраиваем MySQL
launch=gmysql
# Хост с БД - тот самый, которым управляет keepalived
gmysql-host=192.168.1.1
gmysql-port=3306
# Имя и пароль пользователя, которого мы создавали в БД
gmysql-user=pdns_admin
gmysql-password=pdns_password
gmysql-dnssec=yes

На этом базовая конфигурация PowerDNS закончена. Нам же ещё потребуется настроить рекурсор — обработчик рекурсивных DNS-запросов, который позволяет значительно повысить производительность DNS-сервера. Правим файл /etc/powerdns/recursor.conf:
daemon=yes
forward-zones-file=/etc/powerdns/forward_zones
local-address=127.0.0.1
local-port=5353
quiet=yes
setgid=pdns
setuid=pdns

В файл forward_zones вносим зоны intranet, которые обслуживают соседние серверы:
piter_filial.local=192.168.2.1
2.168.192.in-addr.arpa=192.168.2.1

По окончании настройки перезапускаем сервисы pdns и pdns-recursor.

После запуска настраиваем реплику MySQL между серверами.

Заключение


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

Будем рады, если вы зададите свои вопросы в комментариях или укажите на места в схеме, которые можно улучшить. И, конечно, подписывайтесь на наш хаб, чтобы не пропускать новые полезные материалы! ;-)
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331128/


Pygest #11. Релизы, статьи, интересные проекты из мира Python [6 июня 2017 — 19 июня 2017]

Понедельник, 19 Июня 2017 г. 08:14 + в цитатник
image Всем привет! Это уже одиннадцатый выпуск дайджеста на Хабрахабр о новостях из мира Python.

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

А теперь к делу!


Новости


NumPy получил первые инвестиции в размере 645000$

Релизы


PyPy 5.8
NumPy 1.13.0
Django 1.11.2
Anaconda 4.4.0

Статьи


Instagram Makes a Smooth Move to Python 3
История о том, как Instagram переходит на Python 3.

Understanding Asynchronous Programming in Python
Отличная статья с примерами о том, что же такое асинхронное программирование и как с ним работать.

Embedding Go and groupcache in Python
Крутая статья о том, как внедрить Go-код в код на Python

Introduction to Apache Kafka for Python Programmers
Туториал о том, как начать использовать очередь Apache Kafka в своём проекте на Python.

Building an API with Django REST Framework and Class-Based Views
Хорошая статья о создании API с использованием Django REST Framework'а

5 ways to make Django Admin safer
Небольшая заметка о том, как сделать администраторскую панель в Django безопаснее.

Detecting Fake Videos with Python
Занимательная статья о примере работы с видео в Python

Twitter Advertising
Статья об использовании NLP, Python и Twitter данных для создания рекламных компаний в Twitter.

Microservices with Docker, Flask, and React
Серия статей о создании веб-приложений и микросервисов с использование Docker, Flask и React.js

Go-Flavored Error Handling in Python
Интересная статья об использовании Go-like обработки ошибок в Python.

Why using a context-manager is a better choice?
Об использовании Context Manager в Python

10 awesome features of Python that you can't use because you refuse to upgrade to Python 3
Презентация о том, какие крутые «фичи» есть в Python 3

Predicting Football Results With Statistical Modelling
Об использовании Python для построения статистических моделей и предсказаний на их основе

Records, Structs, and Data Transfer Objects in Python
О разных структурах данных, доступных для использования в Python

Python For Finance: Algorithmic Trading
«Лонгрид» об использовании Python для обработки и анализа финансовых данных

The Evolution of Code Deploys at Reddit
Статья о том, как изменился процесс развертывания Python-приложений на боевых сервера в Reddit

Интересные проекты


Shutit
Библиотека, позволяющая эмулировать любые действия пользователя в терминале

MGC Django
Инструмент для определения жанра музыки на основе машинного обучения

Snaek
Инструмент от создателя Flask, позволяющий создавать библиотеки для Rust, которые можно использовать в Python коде

Molotov
Инструмент для нагрузочного тестирования

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

Gain
Удобный web crawler фреймворк, построенный на asyncio.

Machine Learning Surveys
Обновляемый список различных материалов по машинному обучению

Занимательное


Highest Voted `python-internals` questions
Самые популярные на Stack Overflow вопросы по устройству Python

Шутка о приватных методах в Python

Предыдущий выпуск дайджеста ищете здесь:

Pygest #10. Релизы, статьи, интересные проекты из мира Python [23 мая 2017 — 5 июня 2017]

Спасибо за внимание! Присылайте Ваши предложения для публикации в дайджесте!
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331154/


Метки:  

О лицензиях Qt (и немного о компании)

Понедельник, 19 Июня 2017 г. 01:09 + в цитатник

В предыдущей статье про Qt roadmap я обещал рассказать про Qt 3D Studio и текущую ситуацию с лицензиями. Qt 3D Studio уже было выпущено два (пока писал статью, вышел третий) внутренних релиза, но статьи про неё пока не будет, так что сегодня расскажу про лицензии.


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


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



The Qt Company


Мне показалось важным начать с вводной части, потому что до сих пор есть “серые” места даже в таких простых вещах как правильное произношение (“кьют”) и написание ("Qt"). Что уж тут говорить, если и во внутренней переписке и звонках можно иногда услышать "ку-ти" и увидеть "QT" (от разработчиков — никогда).


История компании


Иногда на выставках задают вопросы вида: “Как, а вы ещё живы?” или “А разве Nokia не того?”. Да, компания вполне жива и не имеет ничего общего с Nokia уже несколько лет.


Вот вся история компании вкратце:


  • 1994: Troll Tech (Trolltech). Разработка Qt началась ещё в 1992, первый коммерческий релиз состоялся в 1995;
  • 2008: Nokia покупает Trolltech;
  • 2011: Финская компания Digia приобретает коммерческую часть Qt у Nokia;
  • 2012: Digia выкупает Qt у Nokia полностью;
  • 2014: Digia начинает выделять Qt в отдельное подразделение (The Qt Company);
  • 01.05.2016: The Qt Company выходит из состава Digia и становится самостоятельной компанией. Также происходит IPO (трекер QTCOM.HE), и соответственно финансовая отчётность находится теперь в открытом доступе — например, за 2016 год компания заработала 32 миллиона евро (кстати, в 2015, ещё в составе Digia, цифра была около 27 миллионов евро).

Вообще, в планах компании сейчас стоит цель достичь прибыли в 100 миллионов евро к 2021 году, потому сейчас идёт активный набор новых сотрудников, и помимо прочих вакансий особенно срочно нужен так называемый sales engineer в берлинский офис. Если кому-то интересно — напишите мне, я расскажу подробнее.


Говоря о Nokia, нельзя не упомянуть её вклад в распространение Qt — ведь именно Nokia сделала Qt доступным также и под лицензией LGPL. По понятным причинам, продажи лицензий её не интересовали — Nokia хотела “популяризировать” Qt, чтобы создавалось больше приложений для её мобильной платформы, а GPL этому очень мешала. И действительно, сразу же после этого начался взрывной рост сообщества Qt, так что спасибо Nokia за это. Но есть и обратная сторона: продавать ПО, лицензируемое одновременно под LGPL и коммерческой лицензией — это довольно непростая задача, так что в этом смысле LGPL-наследие Nokia "fucked up sales big time" (не буду переводить), как сказал сотрудник отдела продаж, пожелавший остаться неизвестным.


Что хочу отметить особо — при всех произошедших сменах владельцев разработчики Qt оставались те же (насколько это возможно за более чем 20 лет). Некоторые, включая нынешнего chief technology officer (CTO) Lars Knoll, работают в Qt и сегодня, а начинали ещё во времена Trolltech.


Вот вкратце об истории всё. Кстати, если будет интересно, расскажу, почему домен — qt.io, а не qt.com (спойлер: киберсквоттинг).


Офисы в разных странах


The Qt Company — международная компания с офисами в нескольких странах:


Офисы The Qt Company


И хотя юридически главный офис сейчас находится в Финляндии, исторически самый большой офис — в Осло (Норвегия). В нём же сидит большинство разработчиков (и CTO).


Российское же представительство The Qt Company одно из самых маленьких (если не самое) — на всю страну только один небольшой офис в Санкт-Петербурге. Кстати говоря, после определённых событий питерский офис однажды получил такое письмо:

В связи с войной между [...] и Россией, для меня в настоящее время неприемлемо общение с российским офисом компании. Пожалуйста, переадресуйте мой запрос в какой-либо европейский или американский офис The Qt Company.
В общем, наличие офисов в разных странах иногда пригождается довольно неожиданным образом.

Релизы Qt


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


Если рассмотреть сроки поддержки релизов, то пока ещё действует “старая” система, по которой минимальный поддерживаемый релиз — 5.4.


По новой же системе начиная с Qt 5.6 релизы теперь будут делиться на обычные и LTS (long-term support):


  • обычные будут сопровождаться в течение одного года;
  • LTS — в течение трёх лет.

Таким образом, текущие поддерживаемые (сопровождаемые) версии:


  • 5.4 — до июля 2017;
  • 5.5 — до марта 2018;
  • 5.6 (LTS) — до марта 2019;
  • 5.7 — до июня 2017 (уже вот-вот);
  • 5.8 — до января 2018;
  • 5.9 (внезапно, тоже LTS) — до июня 2020.

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


Пример с прекращением сопровождения релиза: если вы используете Qt 5.3 и по тем или иным причинам не можете/хотите обновляться до актуальной 5.9, то вы можете продолжать разработку с Qt 5.3 и выпускать свои продукты — но не ожидайте никаких обновлений/исправлений для этой версии. Даже если у вас есть доступ к тех.поддержке — обращаться с вопросами по Qt 5.3 вы не сможете, стандартная поддержка этого релиза также закончилась. Но если вам очень нужно, то есть возможность приобрести расширенную (extended) поддержку для устаревших версий, и тогда сопровождение этой версии будет возобновлено специально для вас.


Двойная лицензия


Qt всегда был доступен под “двойной” (dual-license) лицензией: Open Source и коммерческой. С коммерческой всё понятно: компании нужны деньги, чтобы платить сотрудникам и развивать фреймворк. Но зачем делать свой продукт доступным под лицензиями Open Source?


Вклад Open Source в разработку Qt


На графике показан вклад сторонних компаний в разработку Qt. Нетрудно видеть, что хотя вклад The Qt Company и самый большой, немалая часть разработки ведётся силами Open Source сообщества. А в некоторых модулях вклад сторонних разработчиков даже больше — к примеру, появление Qt 3D является заслугой сервисной компании KDAB.


Поэтому важно, чтобы Qt был и оставался быть доступным не только под коммерческой лицензией, но и под Open Source. Далее ещё будет отдельно про KDE Free Qt Foundation.


Положительную роль играет и такая сторона Open Source — допустим, некоторая компания Chamomile решает использовать Qt в разработке своего нового продукта. Выделяются ресурсы, и разработка ведётся в течение какого-то времени. Затем компания Macrohard неожиданно покупает The Qt Company и, по своему обыкновению, уничтожает её (и продукт). Что это означает для компании Chamomile — проект обречён, все ресурсы потрачены впустую, ведь разработка Qt прекратилась? Нет — его исходники доступны, и разработка будет продолжаться независимо от существования того или иного юридического лица. Конечно, повисает вопрос с лицензиями, но самое главное — Qt как технология останется жив и будет продолжать развиваться.


При всём вышесказанном, неподготовленные сотрудники отдела продаж на ситуацию с Open Source смотрят с плохо скрываемым ужасом. Для них это означает только одно — мы раздаём наш продукт бесплатно! Точно так же на бизнес-модель The Qt Company смотрят и люди со стороны. Но на самом деле всё не так просто, и далее в статье я надеюсь это объяснить.


Продукты Qt


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


Сейчас список продуктов такой:


  • Qt for Application Development — разработка приложений;
  • Qt for Device Creation — разработка встраиваемых (embedded) решений;
  • Automotive Suite — инструментальный кластер (IC) и развлекательная система внутри автомобиля (IVI).

Эти три продукта можно представить так:


Техническая иерархия продуктов Qt


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


Однако кроме технической есть и юридическая составляющая. Например, вы создаёте кофемашину и используете Qt в разработке ПО для неё. По условиям лицензии Qt for Application Development вы не можете распространять/продавать ваши кофемашины — для этого вы должны обладать лицензией Qt for Device Creation, потому как именно она лицензирует такое использование Qt (распространение в составе “устройства”, подробности чуть ниже.


Через некоторое время ожидается появление новых продуктов. Скорее всего, они тоже будут базироваться на Qt for Device Creation и расширять его дополнительным функционалом (и условиями лицензирования), специфичным для определённых индустрий (например, ТВ-приставки, медицина и т.п.).


Есть ещё один, обособленный продукт — лицензия на создание SDK на основе Qt. Этот пакет существует на случай если кто-то захочет взять Qt, внести в него свои изменения (добавить в состав новые библиотеки, расширить Qt Creator дополнительными плагинами, ещё что-то) и распространять/продавать как свой продукт на своих условиях (виртуальный оператор сотовой связи, как аналогия). Такой вариант лицензирования встречается очень редко (и стоит очень дорого).


Отличия между AD и DC


Вероятно, пример с кофемашиной вызвал некоторое недоумение, а может и возмущение, потому хочу рассказать о “юридических“ отличиях между продуктами Qt for Application Development и Qt for Device Creation подробнее.


Qt for Application Development предназначен для разработки приложений на десктопах и мобильных платформах, где такое приложение будет лишь одним из множества других, использующихся в системе. Примеры: Telegram, VLC, VirtualBox и другие — то есть “обычные” приложения, которые могут быть установлены на любой компьютер (смартфон, планшет) или размещены в магазине приложений (App Store, Google Play, Windows Store). Условия этой лицензии покрывают следующие операционные системы: Windows, Linux, Mac OS, iOS, Android, Windows Phone — все они уже включены в стоимость лицензии (выкинуть “ненужные” нельзя).


Qt for Device Creation предназначен для создания “устройств”, когда продукт — это не просто приложение, но комбинация софта и железа, то есть приложение разрабатывается для конкретного устройства, и конечный продукт будет распространяться/продаваться именно в таком виде — устройство и предустановленное (или устанавливаемое позже) на него ПО, без которого устройство просто “не будет работать”. Это может быть графический интерфейс пользователя либо другая существенная функциональность устройства, реализованная с использованием Qt. Условия этой лицензии покрывают только одну операционную систему из списка: Embedded Linux (в общем-то, тот же Линукс, но на embedded платформе), Embedded Windows (UWP, WinRT, Windows EC/WinCE), QNX, VxWorks, INTEGRITY — в стоимость лицензии включена только одна из них, и каждая дополнительная ОС добавляется за дополнительную плату (со скидкой за каждую последующую). Кроме того, есть ещё так называемая “лицензия на распространение” — об этом будет далее.


На всякий случай хочу пояснить, что лицензирование ОС затрагивает только “конечную” (deployment) ОС. Разработку же можно вести в любой ОС, какая нравится (Windows, Linux, Mac OS).


Некоторое проекты могут требовать наличия лицензии Qt for Device Creation даже несмотря на то, что “устройство” представляет собой обычный настольный компьютер на Windows. Например, это может быть рабочая станция на каком-то заводе, на которой работает некоторое приложение для мониторинга каких-нибудь датчиков — и это единственное предназначение этой рабочей станции. С технической точки зрения здесь нет никакой нужды в компонентах из состава Qt for Device Creation (Boot to Qt, виртуальная клавиатура, эмулятор и т.д.), но юридически — это “устройство”, а значит требуется именно эта лицензия. Определение "устройства" дано в условиях и соглашениях.


Может быть и такая ситуация: у некоторой компании два разных проекта: медиа-плеер под Windows и погодная станция на Raspberry Pi и Linux. В этом случае ей нужно приобрести обе лицензии — так называемую “комбо-лицензию”: Qt for Application Development плюс Qt for Device Creation (стоит дешевле этих двух по отдельности). Опять же, с технической точки зрения вполне себе можно работать над проектом медиа-плеера используя версию Qt for Device Creation (ведь она содержит все библиотеки из Qt for Application Development), но “юридически” по условиям лицензии это не разрешается.


Коммерческая лицензия


Для работы над проектом с использованием Qt каждый разработчик должен обладать лицензией. Она именная и привязывается к e-mail адресу (Qt Account). Несмотря на такую привязку, на самом деле лицензия принадлежит вашей компании, и потому когда разработчик с лицензией, например, уволится, вы сможете “переназначить” его лицензию на другого. Однако, это не означает, что у вас в руках “плавающая” лицензия, которую можно переключать между сотрудниками по несколько раз в день — переназначение лицензии регулируется The Qt Company.


Если команда большая, то есть возможность приобрести “массовую” (site license) лицензию на всю компанию, которая не будет зависеть от реального количества разработчиков и, соответственно, обойдётся дешевле.


Свою лицензию каждый разработчик может использовать на неограниченном количестве рабочих станций и операционных систем, при условии что пользоваться ими будет исключительно он. Пример: на работе у меня стоит десктоп с Windows 10 и ноутбук с Ubuntu, а дома я использую Mac — можно установить Qt на все три машины и спокойно работать над проектом на любой из них.


Часто задают вопрос про сервера сборки, нужна ли им отдельная лицензия? Нет, лицензия требуется только для “живых” разработчиков, которые работают с Qt (“touching the Qt code”).


Подписка


Вообще, лицензии для разработчиков являются пожизненными (perpetual), но Qt for Application Development имеет опцию приобретения лицензии по подписке (subscription) (в том числе и “инди”-лицензия для стартапов). Такая лицензия оплачивается за каждый месяц использования.


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


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


Лицензии на распространение


Qt for Device Creation (и все производные продукты, начиная с Automotive Suite) помимо лицензий для разработчиков имеет вторую составляющую — “лицензии на распространение” (distribution licenses или runtimes (не самый удачный термин)). То есть, компания-разработчик, распространяющая/продающая “устройства” с Qt внутри (ПО, разработанное с использованием Qt), должна пробрести эти самые рантаймы по числу распространяемых устройств. Например, пусть та же контора Chamomile продаёт 20 000 кофемашин в год, значит она должна приобрести “рантаймы” для как минимум 20 000 устройств (или сразу 100 000, чтобы на пять лет). Чем больше объём, тем меньше стоимость рантайма за одно устройство (и наоборот).


Более того, существует минимальный порог числа рантаймов — вы должны купить как минимум 5 000 рантаймов независимо от вашего реального плана поставок. Но некоторые компании (и необязательно стартапы) просто не нуждаются в таких объёмах — скажем, производитель МРТ-сканеров продаст от силы 500 сканеров за 10 лет, что ему делать с остальными 4 500 рантаймами? В общем, довольно странное требование (но к счастью не такое "жёсткое").


Продление лицензии


Лицензия для разработчика включает в свою стоимость один год технической поддержки и "получения"" новых версий Qt. Через год у вас есть выбор, “продлить” (renew) поддержку и обновления или нет. Если не продлевать, то вы по-прежнему можете вести разработку (лицензия же “пожизненная”) с последней версией Qt, которая была выпущена в течение этого года, но вы больше не можете обращаться в техническую поддержку а также использовать более новые версии Qt.


У лицензий на распространение (рантаймов) срока действия нет. Вы можете использовать их хоть пять лет, хоть пятьдесят — до тех пор, пока не исчерпаете приобретённый объём. Например, вы приобрели 10 000 рантаймов, и ежегодно вы выпускаете 1 000 единиц вашего продукта (кофемашин) — это означает, что новый пакет рантаймов вам понадобится только через 10 лет.


Пробная версия


Чтобы не покупать кота в мешке, можно запросить “триальную” (evaluation) версию Qt. Это ознакомительный дистрибутив, ограниченный по времени (действует 30 дней) и который содержит все коммерческие компоненты, то есть вы можете собственноручно пощупать образы Boot to Qt, попробовать удалённую отладку и профилирование на устройстве, замерить эффект от использования Qt Quick Compiler, оценить удобство Qt Configuration Tool для Qt Lite и прочее. Также в течение этих 30 дней у вас будет доступ к специалистам тех.поддержки.


Триал доступен как для Qt for Application Development, так и для Qt for Device Creation. Что касается Automotive Suite, то этот продукт ориентирован на “крупных игроков” уровня BMW, Volvo и прочих, потому его заполучить будет не так просто.


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


Техническая поддержка


Одним из важных (а для некоторых — ключевым) отличием коммерческой лицензии от Open Source является наличие технической поддержки.


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


При наличии же технической поддержки вы можете использовать систему тикетов в вашем Qt Account. Вы получаете гарантированное время ответа (48 часов) и доступ к специалистам Qt. Можно даже выйти на разработчика той или иной библиотеки напрямую. Нет никакой “первой линии” с “маринками”, вы общаетесь сразу с техническими специалистами. Задавать можно любые вопросы, даже если они вам кажутся глупыми и "нубскими", без ограничения на их количество. Хотя если у вас всего одна лицензия, но при этом от вас поступают сотни тикетов в день — это вызовет определённые встречные вопросы.


Кроме тех.поддержки, ваши баг-репорты и фича-реквесты получают повышенный приоритет (и помечаются внутренним маркером “коммерческий клиент”).


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


Сервисные услуги


Если и премиум поддержки недостаточно, то The Qt Company также оказывает сервисные (consultancy) услуги. Это вебинары/тренинги в офисе (обучение по стандартным программам или по вашему списку интересующих тем), семинары/воркшопы (анализ архитектуры вашего проекта, оптимизация производительности), изготовление proof-of-concept, срочная реализация фича-реквестов, а также просто аутсорс разработки.


Open Source пользователи тоже могут заказать сервисные услуги у The Qt Company. Однако для них этого будет стоить дороже, чем для обладателей коммерческой лицензии.


Open Source лицензии


Ну и наконец про Open Source лицензии.


GPLv3/LGPLv3


Текущая Open Source версия Qt доступна под условиями и ограничениями GPLv3 или LGPLv3. До Qt 5.7 это были GPLv2.1 и LGPLv2.1.


LGPL является менее “строгой” лицензией по сравнению с GPL, и в подавляющем большинстве компании, решившие пойти путём Open Source, выбирают именно её. Однако, кроме более “мягких” требований LGPL отличается от GPL тем, что не все компоненты Qt доступны под LGPL — например, Qt Charts, Qt Data Visualization и Qt Virtual Keyboard доступны только под GPL, то есть вы не можете использовать их в LGPL-проекте.


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


Вообще, лицензии Open Source не принадлежат The Qt Company, потому она не может предоставить чёткий список требований и ограничений GPL/LGPL по пунктам — это личная ответственность каждой компании, которая хотела бы использовать Qt под той или иной лицензией Open Source. Если юристы компании, изучив текст соответствующей лицензии, выносят вердикт, что продукт компании соответствует требованиям лицензии — это их решение и их ответственность. Потому, если какая-то компания-разработчик заявляет, что им коммерческая лицензия не нужна, и они будут использовать Qt под LGPL, так как полностью ей соответствуют — мы даже не спорим. Может, они и правда соответствуют. Мы не юридическая фирма, и потому не можем консультировать по вопросам использования СПО. The Qt Company отвечает только за свою коммерческую лицензию. Выполнение требований лицензий Open Source регулируется не нами.


Пока что я почти не видел сколько-нибудь крупной компании, которая выбрала бы Qt под Open Source лицензией для своего коммерческого проекта. Если говорить, например, о Германии, то там отдел продаж вообще работает в режиме “алло — сколько, вы говорите, нужно лицензий — отправляю договор”. Мало кто хочет рисковать своим бизнесом, когда текст лицензий попросту не совершенен (переход с GPL/LGPLv2.1 на v3 из-за тивоизации, нечёткое определение “consumer product” и прочие “серые” места), а также когда судебные процессы в этой сфере выдают непредсказуемый результат (GPL внезапно рассматривается как договор).


Я представляю, да, в реалиях какой страны я тут расписываю за Open Source лицензии и их требования. Далеко не отходя за примерами — первые мои работодатели в России, где я начинал как раз-таки разработчиком C++/Qt, имели весьма слабое представление о каких-то там лицензиях-шмицензиях. Вот же страница загрузки, вот ссылка на установщик — всё ставится, ничего не просит, платить не надо, Далее — Далее — Принять — Далее — Готово, можно работать.


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


А ещё вот кстати: одной из метрик анализа данных о посетителях сайта с недавних пор является количество загрузок Open Source версии. То есть, если в каком-то регионе активно грузят “свободный” Qt, то в глазах менеджмента этот регион является очень перспективным, и значит надо усилить в нём присутствие, потому что скоро начнут расти продажи коммерческих лицензий. Лишним будет говорить, что по числу загрузок лидируют Россия, Индия ну и далее по списку. Я пытался объяснять руководству, что цифры эти означают нечто совсем другое, но мне, скажем так, не совсем поверили. Для них это реально невообразимая ситуация — что кто-то может игнорировать текст лицензионного соглашения.


Переход с Open Source на коммерческую


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


Также иногда встречаются ситуации, когда та или иная компания пару лет вела разработку своего проекта под Open Source лицензией, а перед релизом продукта “вдруг” узнала об её ограничениях и захотела приобрести коммерческую лицензию. Вообще, такое не допускается, лицензия должна выбираться на старте проекта, до начала разработки, и если вы взяли Open Source, то и распространение должно осуществляться в соответствии с требованиями GPL/LGPL. Но если такое всё-таки случилось не “вдруг”, а действительно по незнанию — свяжитесь с The Qt Company и опишите ситуацию.


Разница в доступных компонентах по лицензиям


Различия в доступных компонентах есть не только между коммерческой и Open Source версией Qt, но также и между GPL и LGPL (какие-то компоненты доступны только в GPL).


Вот тут надо сказать о KDE Free Qt Foundation. В 1998 году между сообществом KDE и тогда ещё Trolltech было заключено соглашение, что Qt всегда будет доступен как свободное ПО, и это соглашение соблюдалось и соответствующе обновлялось при смене владельцев Qt. Но относительно недавно условия соглашения были, скажем так, нарушены — в составе Qt появился ряд библиотек, которые были доступны только под коммерческой лицензией — это как раз-таки Qt Charts, Qt Data Visualization, Qt Virtual Keyboard и другие. В общем, отношения начали слегка портиться. К счастью, руководство всё-таки приняло решение сделать эти библиотеки доступными и в Open Source, что и произошло в релизе Qt 5.7 — они стали доступны под GPL.


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


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


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


Отличия в компонентах Qt между лицензиями


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


И несколько комментариев по таблице.


Стоимость 0


За Open Source лицензии не нужно платить в явном виде, однако следует понимать, что некоторые расходы всё-таки последуют, пусть они и неочевидны на первый взгляд:


Скрытые расходы с Open Source лицензиями


Charts, Visualization и Virtual Keyboard


Те самые компоненты, которые раньше были доступны только в коммерческой лицензии. Начиная с Qt 5.7 они доступны и под GPL (но по-прежнему недоступны под LGPL).


Qt Quick Compiler


Qt Quick Compiler был (и остаётся) доступным только в коммерческой версии Qt. Его обещали отдать в Open Source с релизом 5.7, потом 5.8, потом 5.9, а сейчас вроде как больше не обещают, только предложили “взамен” механизм кэширования (который всё же не то же самое).


Qt Quick 2D Renderer


Этот модуль был раньше только коммерческий, потом стал доступен и в GPL, а после релиза 5.8 перестал быть отдельным модулем, и теперь интегрирован в Qt Quick и доступен также под LGPL.


Готовые наборы инструментов сборки


Готовые "из коробки" наборы инструментов сборки для кросс-компиляции, отладки, деплоя и профилирования с хост-машины на присоединённом устройстве.


На скриншоте ниже показано меню выбора “таргета” для проекта в Qt Creator — под какую платформу компилировать (кросс-компилировать) и где запустить приложение. Конкретно тут я собираю проект под Raspberry Pi 3 и хочу запустить своё приложение на подключённом по сети устройстве:


Embedded таргеты для Qt проекта


А на этом скриншоте показан полный список устройств, для которых "из коробки" имеются готовые образы и инструменты сборки:


Доступные образы Boot to Qt


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


Лицензия для университетов


Существует также проект "образовательной" лицензии для преподавателей и студентов университетов. Подразумевается, что она будет бесплатной.


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


Проект "образовательной" лицензии всё ещё в пилотном режиме, потому особо не афишируется. Я тоже в этом обзоре не стал её включать в общую лицензионную структуру. Как станет известно больше — добавлю новую информацию.


Ещё раз про виды лицензий


Глядя на весь этот километр текста, думаю, стоит показать лицензионную структуру Qt в виде картинки:


Лицензии Qt


Иногда задают вопрос: “Каковы условия использования Qt без лицензии?”. Ответ содержится на картинке: нет таких условий — невозможно использовать Qt без лицензии. Вы либо приобретаете коммерческую лицензию, либо используете Qt под условиями соответствующей Open Source лицензии (GPL/LGPL).


Заключение


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


Первое — это маркетинговое сотрудничество. Например, у вас классный продукт, вы выходите на рынок и потому заинтересованы в продвижении. The Qt Company, разумеется, тоже заинтересована, чтобы появлялось больше классных продуктов на Qt, и была бы рада объявлять о новых у себя на сайте. На этой взаимовыгодной почве и пополняется галерея Built with Qt. Если же продвижение вам не сильно интересно, зато хотелось бы получить скидку на лицензии — это тоже возможно.


Второе — это compliancy check. Что-то вроде проверки соблюдения условий лицензии. Время от времени The Qt Company может (по условиям договора) проводить такие проверки, и если будут выявлены нарушения, то это чревато последствиями. Пример: вы описали свой проект как “просто приложение под винду” и приобрели Qt for Application Development, а на самом деле у вас хаб для “умного дома” на Windows 10 IoT, поставляемый на рынок в количестве нескольких тысяч устройств ежегодно — это весьма грубое нарушение. Или другой пример: компания заявляет, что в команде проекта будет всего один разработчик, но при этом в LinkedIn от имени этой же компании висит штук десять объявлений поиска программистов Qt — как-то не сходятся цифры.


Надеюсь, теперь система лицензий Qt стала немного понятнее. Если хотите, чтобы я рассказал о чём-то подробнее (например, таки перечислил хотя бы основные ограничения GPL/LGPL), напишите в комментариях — я дополню статью.

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

https://habrahabr.ru/post/331166/


Метки:  

Сравнение систем мониторинга серверов. Заменяем munin на…

Понедельник, 19 Июня 2017 г. 00:31 + в цитатник
Очень долго хотел написать статью, но не хватало времени. Нигде (в том числе на хабре) не нашёл такой простой альтернативы munin, как описанная в этой статье.


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

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


Munin


Он легко устанавливается и имеет небольшие требования. Он написан на perl и использует кольцевую базу данных (RRDtool).
Пример установки
Выполняем команды:
apt-get install munin munin-node
service munin-node start

Теперь munin-node будет собирать метрики системы и писать их в бд, а munin раз в 5 минут будет генерировать из этой бд html-отчёты и класть их в папку /var/cache/munin/www

Для удобного просмотра этих отчётов можно создать простой конфиг для nginx
server {
    listen 80;
    server_name munin.myserver.ru;
    root /var/cache/munin/www;
    index index.html;
}


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

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

Если проект вырастает из одного сервера, тогда на втором сервере достаточно установить munin-node, а на первом — добавить в конфиге одну строчку для сбора метрик со второго сервера. Графики по обоим серверам будут раздельные, что не удобно для просмотра общей картины — на каком сервере заканчивается свободное место на диске, а на каком оперативная память. Эту ситуации можно исправить добавив в конфиг уже десяток строчек для агрегации одного графика с метриками с обоих серверов. Соответственно целесообразно это делать только для самых основных метрик. Если в конфиге сделать ошибку, то придётся долго читать в логах, что именно к ней привело и не найдя информации попытаться исправить ситуацию «методом тыка».
Стоит ли говорить, что для большего количества серверов это превращается в самый настоящий ад. Может это из-за того, что munin был разработан в 2003 году и изначально не был рассчитан на это.

Альтернативы munin для мониторинга нескольких серверов


Определил для себя необходимые качества, которыми должна обладать новая система мониторинга:
  • количество метрик не меньше чем у munin (у него их около 30 базовых графиков и ещё около 200 плагинов в комплекте)
  • возможность написания собственных плагинов на bash (у меня было два таких плагина)
  • иметь небольшие требования к серверу
  • возможность вывода метрик с разных серверов на одном графике без правки конфигов
  • уведомления на почта, в slack и telegram
  • Time Series Database более мощную чем RRDtool
  • простая установка
  • ничего лишнего


Я перечислю, всё что я рассматривал.

Cacti


Почти тоже самое, что munin только на php. В качестве базы данных можно использовать rrdtool как у munin или mysql. Уведомлений «из коробки» найдено не было. Первый релиз: 2001 год.
Интерфейс


Ganglia


Почти тоже самое, что и предыдущие, написана на php, в качестве базы данных — rrdtool. Первый релиз: 1998 год.
Интерфейс


Collectd


Ещё более простая система, чем предыдущие. Написан на c, в качестве базы данных — rrdtool. Первый релиз: 2005 год.
Интерфейс


Graphite


Состоит из трёх компонент, написанных на python:
carbon собирает метрики их записывает их в бд
whisper — собственная rrdtool-подобная бд
graphite-web — интерфейс
Первый релиз: 2008 год.
Интерфейс


Zabbix


Профессиональная система мониторинга, используется большинством админов. Есть практически всё, включая уведомления на почту (для slack и telegram можно написать простой bash-скрипт). Тяжёлая для пользователя и для сервера. Раньше приходилось пользоваться, впечатления, как будто вернулся с jira на mantis.
Ядро написано на c, веб интерфейс — на php. В качестве базы данных может использовать: MySQL, PostgreSQL, SQLite, Oracle или IBM DB2. Первый релиз: 2001 год.
Интерфейс


Nagios


Достойная альтернатива Zabbix. Написан на с. Первый релиз: 1999 год.
Интерфейс


Icinga


Форк Nagios. В качестве бд может использовать: MySQL, Oracle, and PostgreSQL. Первый релиз: 2009 год.
Интерфейс


Небольшое отступление


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

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

Netdata


Вообще не требует базы данных, но может выгружать метрики в Graphite, OpenTSDB, Prometheus, InfluxDB. Написана на c и python. Первый релиз: 2016 год.
Интерфейс


Prometheus


Состоит из трёх компонент, написанных на go:
prometheus — ядро, собственная встроенная база данных и веб-интерфейс.
node_exporter — агент, который может быть установлен на другой сервер и пересылать метрики в ядро, работает только с prometheus.
alertmanager — система уведомлений.
Первый релиз: 2014 год.
Интерфейс


InfluxData (TICK Stack)


Состоит из четырёх компонент, написанных на go которые могут работать со сторонними продуктами:
telegraf — агент, который может быть установлен на другой сервер и пересылать метрики, а также логи в базы influxdb, elasticsearch, prometheus или graphite, а также в несколько серверов очередей.
influxdb — база данных, которая может принимать данные из telegraf, netdata или collectd.
chronograf — веб интерфейс для визуализации метрик из бд.
kapacitor — система уведомлений.
Первый релиз: 2013 год.
Интерфейс


Отдельно хотелось бы упомянуть такой продукт, как grafana, она написана на go и позволяет визуализировать данные из influxdb, elasticsearch, clickhouse, prometheus, graphite, а также отправлять уведомления на почту, в slack и telegram. Первый релиз: 2014 год.
Интерфейс


Выбираем лучшее


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

carbon (агент) -> whisper (бд) -> grafana (интерфейс)
netdata (в качестве агента) -> null / influxdb / elasticsearch / prometheus / graphite (в качестве бд) -> grafana (интерфейс)
node_exporter (агент) -> prometheus (в качестве бд) -> grafana (интерфейс)
collectd (агент) -> influxdb (бд) -> grafana (интерфейс)
zabbix (агент+сервер) -> mysql -> grafana (интерфейс)
telegraf (агент) -> elasticsearch (бд) -> kibana (интерфейс)
… и т.д.
Видел упоминание даже о такой связке:
… (агент) -> clickhouse (бд) -> grafana (интерфейс)

В большинстве случаев в качестве интерфейса использовалась grafana, даже если она была в связке с продуктом, который уже содержал собственный интерфейс (prometheus, graphite-web).
Поэтому (а также в силу её универсальности, простоты и удобства) в качестве интерфейса я остановился на grafana и приступил к выбору базы данных:
prometheus отпал потому что не хотелось тянуть весь его функционал вместе с интерфейсом только из-за одной бд, graphite — бд предыдущего десятилетия, переработанная rrdtool-бд предыдущего столетия, ну и собственно я остановился на influxdb и как выяснилось — не один я сделал такой выбор.
Также для себя я решил выбрать telegraf, потому что он удовлетворял моим потребностям (большое количество метрик и возможность написания своих плагинов на bash), а также работает с разными бд, что может быть полезно в будущем.

Итоговая связка у меня получилась такая:
telegraf (агент) -> influxdb (бд) -> grafana (интерфейс+уведомления)
Все компоненты не содержат ничего лишнего и написаны на go. Единственное, чего я боялся — то что эта связку будет трудна в установке и настройке, но как вы сможете видеть ниже — это было зря.

Итак, короткая инструкция по установке TIG:

influxdb
wget https://dl.influxdata.com/influxdb/releases/influxdb-1.2.2.x86_64.rpm && yum localinstall influxdb-1.2.2.x86_64.rpm #centos
wget https://dl.influxdata.com/influxdb/releases/influxdb_1.2.4_amd64.deb && dpkg -i influxdb_1.2.4_amd64.deb #ubuntu
systemctl start influxdb
systemctl enable influxdb

Теперь можно делать запросы к базе (правда данных там ещё пока нет):
http://localhost:8086/query?q=select+*+from+telegraf..cpu

telegraf
wget https://dl.influxdata.com/telegraf/releases/telegraf-1.2.1.x86_64.rpm && yum -y localinstall telegraf-1.2.1.x86_64.rpm #centos
wget https://dl.influxdata.com/telegraf/releases/telegraf_1.3.2-1_amd64.deb && dpkg -i telegraf_1.3.2-1_amd64.deb #ubuntu
#в случае установки на сервер отличный от того где находится influxdb необходимо в конфиге /etc/telegraf/telegraf.conf в секции [[outputs.influxdb]] поменять параметр urls = ["http://localhost:8086"]:
sed -i 's|  urls = ["http://localhost:8086"]|  urls = ["http://myserver.ru:8086"]|g' /etc/telegraf/telegraf.conf
systemctl start telegraf
systemctl enable telegraf

Telegraf автоматически создаст базу в influxdb с именем «telegraf», логином «telegraf» и паролем «metricsmetricsmetricsmetrics».

grafana
yum install https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-4.3.2-1.x86_64.rpm #centos
wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_4.3.2_amd64.deb && dpkg -i grafana_4.3.2_amd64.deb #ubuntu
systemctl start grafana-server
systemctl enable grafana-server

Интерфейс доступен по адресу http://myserver.ru:3000. Логин: admin, пароль: admin.
Изначально в интерфейсе ничего не будет, потому что графана ничего не знает о данных.
1) Нужно зайти в источники и указать influxdb (бд: telegraf)
2) Нужно создать свой дашборд с нужными метриками (уйдёт очень много времени) или импортировать уже готовый, например:
928 — позволяет видеть все метрики по выбранному хосту
914 — тоже самое
61 — позволяет метрики по выбранным хостам на одном графике
Grafana имеет отличный инструмент для импорта сторонних дашбордов, вы также можете создать свой дашборд и поделиться им с сообществом.
Вот список всех дашбордов, которые могут брать данные из influxdb, которые были собраны с помощь коллектора telegraf.

Акцент на безопасность


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

influxdb
В influxdb по-умолчанию отключена авторизация и кто угодно может делать что угодно. По-этому если на сервере нет файервола, то крайне рекомендую включить авторизацию:
#Создаём базу и пользователей:
influx -execute 'CREATE DATABASE telegraf'
influx -execute 'CREATE USER admin WITH PASSWORD "password_for_admin" WITH ALL PRIVILEGES'
influx -execute 'CREATE USER telegraf WITH PASSWORD "password_for_telegraf"'
influx -execute 'CREATE USER grafana WITH PASSWORD "password_for_grafana"'
influx -execute 'GRANT WRITE ON "telegraf" TO "telegraf"' #чтобы telegraf мог писать метрики в бд
influx -execute 'GRANT READ ON "telegraf" TO "grafana"' #чтобы grafana могла читать метрики из бд

#в конфиге /etc/influxdb/influxdb.conf в секции [http] меняем параметр auth-enabled для включения авторизации:
sed -i 's|  # auth-enabled = false|  auth-enabled = true|g' /etc/influxdb/influxdb.conf

systemctl restart influxdb


telegraf
#в конфиге /etc/telegraf/telegraf.conf в секции [[outputs.influxdb]] меняем пароль на созданный в предыдущем пункте:
sed -i 's|  # password = "metricsmetricsmetricsmetrics"|  password = "password_for_telegraf"|g' /etc/telegraf/telegraf.conf
systemctl restart telegraf


grafana
В настройках источников, нужно указать для influxdb новый логин: «grafana» и пароль «password_for_grafana» из пункта выше.
Также в интерфейсе нужно сменить пароль по-умолчанию для пользователя admin.
Admin -> profile -> change password


P.S.: если я опустил какие-то моменты в описании настройки-установки, то пишите в комментариях и я обновлю статью. Опечатки — в личку.
P.P.S.: конечно этого никто не услышит (исходя из предыдущего опыта написания статей), но я всё равно должен попробовать: не задавайте вопросы в личку на хабре, вк, фб и т.д., а пишите комментарии здесь.
P.P.P.S.: размер статьи и потраченное на неё время сильно выбились из начального «бюджета», надеюсь, что результаты этой работы будут для кого-то полезны.
Что вы используете для мониторинга?

Проголосовало 13 человек. Воздержалось 16 человек.

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

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

https://habrahabr.ru/post/331016/


Метки:  

Нечеткий поиск по названиям

Понедельник, 19 Июня 2017 г. 00:18 + в цитатник

Метки:  

Поиск сообщений в rss_rss_hh_new
Страницы: 1437 ... 1012 1011 [1010] 1009 1008 ..
.. 1 Календарь