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

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

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

 

 -Постоянные читатели

 -Статистика

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

Habrahabr








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

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

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

Nuklear+ — миниатюрный кроссплатформенный GUI

Понедельник, 18 Сентября 2017 г. 12:47 + в цитатник
DeXPeriX сегодня в 12:47 Разработка

Nuklear+ — миниатюрный кроссплатформенный GUI

    Nuklear+ (читается как "Nuklear cross", значит "кроссплатформенный Nuklear") — это надстройка над GUI библиотекой Nuklear, которая позволяет абстрагироваться от драйвера вывода и взаимодействия с операционной системой. Нужно написать один простой код, а он потом уже сможет скомпилироваться под все поддерживаемые платформы.


    Я уже писал на хабре статью "Nuklear — идеальный GUI для микро-проектов?". Тогда задача была простой — сделать маленькую кроссплатформенную утилиту с GUI, которая будет примерно одинаково выглядеть в Windows и Linux. Но с тех самых пор меня не отпускал вопрос, а можно ли на Nuklear сделать что-то более-менее сложное? Можно ли целиком на нём сделать какой-нибудь реальный проект, которым будут пользоваться?


    Веб-демо Wordlase


    Именно поэтому следующую свою игру, Wordlase, я делал на чистом Nuklear. И без всякого там OpenGL. Даже фоновые картинки у меня имеют тип nk_image. В конечном итоге это дало возможность выбора драйвера отрисовки, вплоть до чистого X11 или GDI+.


    Ещё в прошлой своей статье я заложил основы Nuklear+ — библиотеки, призванной спрятать всю "грязь" от программиста и дать ему сфокусироваться на создании интерфейса. Библиотека умеет загружать шрифты, картинки, создавать окно операционной системы и контекст отрисовки.


    Полный пример кода есть в Readme на GitHub. Там можно увидеть, что код получается довольно простой. Также я перенёс на Nuklear+ свои проекты dxBin2h и nuklear-webdemo. И сделать это было очень просто — вся инициализация заменяется на один вызов nkc_init, события обрабатываются nkc_poll_events, отрисовка функцией nkc_render, а в качестве деструктора вызывается nkc_shutdown.


    Демо Nuklear


    Но вернёмся к Wordlase, на примере которой и построена данная публикация. С недавних пор у игры есть веб-демо. Я не писал какого-то специфичного веб-кода для игры — это чистое С89 приложение, скомпилированное с помощью Emscripten. И если полностью следовать примеру из Readme Nuklear+ (а именно, использовать nkc_set_main_loop), то веб-версия приложения будет получена абсолютно на халяву, без особых лишних затрат.


    Бэкэнд и фронтэнд


    Самой интересной частью Nuklear+ являются поддерживаемые фронтэнды и бэкэнды. В данном случае под фронтэндом понимается часть, ответственная за взаимодействие с ОС и отрисовку окна. Т.е. непосредственно то, что видит пользователь. Реализации лежат в папке nkc_frontend. Сейчас поддерживаются: SDL, GLFW, X11, GDI+. Они не равносильны. Например, GDI+ использует WinAPI даже для рендера шрифтов и загрузки изображений, т.е. получить ровно такую же картинку в других ОС будет проблематично. Реализация так же не везде одинакова. Например, реализация Х11 пока не умеет изменять разрешение экрана в полноэкранном режиме (буду рад видеть Pull Request)


    Выбрать фронтэнд для своего приложения просто — нужно установить переменную препроцессора NKCD=NKC_x, где x это одно из: SDL, GLFW, XLIB, GDIP. Например: gcc -DNKCD=NKC_GLFW main.c


    Бэкэнд в данном случае выполняет непосредственно отрисовку. Реализация в папке nuklear_drivers. Отрисовка средствами любой версии OpenGL выдаёт примерно одинаковую картинку на всех ОС и фронтэндах. Ведь для загрузки изображений там всегда используется stb_image, а шрифт рендерится стандартными средствами Nuklear (тоже основано на stb). В то же время чистый Х11 драйвер даже не умеет загружать шрифты. Так что не забывайте тестировать своё приложение для выбранной пары бэкэнд+фронтэнд.


    Например: Wordlase, GLFW3, OpenGL 2, Windows
    Wordlase, GLFW3, OpenGL 2, Windows


    Или: Wordlase, SDL2, OpenGL ES, Linux
    Wordlase, SDL2, OpenGL ES, Linux


    В качестве бэкэнда по умолчанию выбран OpenGL2, если доступен. Можно задать NKC_USE_OPENGL=3 для OpenGL 3, и NKC_USE_OPENGL=NGL_ES2 для OpenGL ES 2.0. Для использования чистого Х11 отрисовщика константу NKC_USE_OPENGL указывать не надо. Также OpenGL опции не влияют на GDI+ — там отрисовка всегда идёт своими средствами.


    Вот скриншот с GDI+: Wordlase, GDI+, без OpenGL, Windows


    Wordlase, GDI+, без OpenGL, Windows


    Этот бэкэнд полноценно поддерживает полупрозрачные изображения, картинка близка к оригиналу. Разница в шрифте: хинтинг, сглаживание, да даже размер (также буду рад Pull Request'у для автоматической подстройки размера GDI+ шрифта под размер stb_ttf).


    И самый ужасный случай — чистый Х11 отрисовщик, который до моего pull request даже не умел загружать картинки. Wordlase, X11, без OpenGL, Linux:


    Wordlase, X11, без OpenGL, Linux


    Вот здесь уже довольно много отличий: логотип, солнечные лучи, более острый край девушки, шрифт. Почему? Фон в игре на лету собирается из нескольких полупрозрачных PNG. Но чистый Х11 поддерживает только битовую прозрачность, прямо как GIF. Также отрисовщик Х11 очень медленно работает на больших изображениях с прозрачностью. А если в движке отключить прозрачность, то картинка становится ещё хуже. Wordlase, X11, без OpenGL, без прозрачности:


    Wordlase, X11, без OpenGL, без прозрачности


    Так зачем вообще нужны отрисовщики GDI+ и Х11, если они так уродливы? Потому, что они плохи только для больших изображений с прозрачностью. А если делать маленькую утилиту, где картинки используются только как иконки пользовательского интерфейса, то эти отрисовщики становятся вовсе неплохим вариантом, т.к. имеют минимальное количество зависимостей. Также я пользовался чистым Х11 отрисовщиком на слабых системах, где OpenGL только программный. В таком случае Х11 работает быстрее OpenGL. Подсказка: если вместо кучи полупрозрачных PNG использовать один большой JPEG, то Х11 будет работать быстро и корректно.


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


    Wordlase, X11, gameplay


    Отлично, отрисовщик выбран, окно ОС создаётся. Теперь самое время заняться GUI!


    Фишки Nuklear


    Самым первым в Wordlase показывается экран выбора языка:


    Wordlase, экран выбора языка


    Здесь видны сразу 2 интересных техники: несколько картинок на фоне окна и центрирование виджетов.


    Поместить картинку на фон окна достаточно просто:


    nk_layout_space_push(ctx, nk_rect(x, y, width, height));
    nk_image(ctx, img);

    x и y — позиция на экране, width и height — размеры изображения.


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


    if ( nk_begin(ctx, WIN_TITLE, 
            nk_rect(0, 0, winWidth, winHeight), NK_WINDOW_NO_SCROLLBAR)
    ) {
        int i;
        /* 0.2 are a space skip on button's left and right, 0.6 - button */
        static const float ratio[] = {0.2f, 0.6f, 0.2f};  /* 0.2+0.6+0.2=1 */
    
        /* Just make vertical skip with calculated height of static row  */
        nk_layout_row_static(ctx, 
            (winHeight - (BUTTON_HEIGHT+VSPACE_SKIP)*langCount )/2, 15, 1
        );
    
        nk_layout_row(ctx, NK_DYNAMIC, BUTTON_HEIGHT, 3, ratio);
        for(i=0; i* skip 0.2 left */
            if( nk_button_image_label(ctx, image, caption, NK_TEXT_CENTERED) 
            ){
                loadLang(nkcHandle, ctx, i);
            }
            nk_spacing(ctx, 1); /* skip 0.2 right */
        }
    }
    nk_end(ctx);

    Следующая прикольная штучка — выбор темы оформления в настройках:


    Wordlase, выбор темы оформления


    Реализуется тоже просто:


    if (nk_combo_begin_color(ctx, themeColors[s.curTheme], 
        nk_vec2(nk_widget_width(ctx), (LINE_HEIGHT+5)*WTHEME_COUNT) ) 
    ){
        int i;
        nk_layout_row_dynamic(ctx, LINE_HEIGHT, 1);
        for(i=0; icode>

    Здесь главное понимать, что всплывающее поле combo — это такое же окно, как и главное. И располагать там можно что угодно.


    Самым сложно выглядящим окном является основное игровое окно:


    Wordlase, основное игровое окно


    На самом деле, тут тоже нет ничего сложного. На экране всего 4 ряда:


    1. Верхняя линия с выбором уровня (виджет nk_property_int)
    2. Список слов (nk_group_scrolled)
    3. Кнопки текущего слова
    4. Строка с подсказкой

    Единственный непонятный момент здесь — задание точных размеров элементам. Выполняется это с помощью соотношения ряда:


    float ratio[] = {
        (float)BUTTON_HEIGHT/winWidth, /* square button */
        (float)BUTTON_HEIGHT/winWidth,  /* square button */
        (float)topWordSpace/winWidth, 
        (float)WORD_WIDTH/winWidth
    };
    nk_layout_row(ctx, NK_DYNAMIC, BUTTON_HEIGHT, 4, ratio);

    BUTTON_HEIGHT и WORD_WIDTH — константы, измеряются в пикселях; topWordSpace вычисляется как ширина экрана минус ширины всех остальных элементов.


    И последнее сложно выглядящее окно — статистика:


    Wordlase, статистика


    Расположение элементов регулируется с помощью группировки. Ведь всегда можно сказать Nuklear: "в этом ряду будет 2 виджета". Но группа тоже является виджетом. Т.е. можно просто создать группу с помощью nk_group_begin и nk_group_end, а дальше позиционироваться внутри неё как внутри обычного окна (nk_layout_row и пр.).


    Заключение


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


    Полезные ссылки


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

    https://habrahabr.ru/post/338106/


    [Перевод] PHP жив. PHP 7 на практике

    Понедельник, 18 Сентября 2017 г. 12:42 + в цитатник
    pik4ez сегодня в 12:42 Разработка

    PHP жив. PHP 7 на практике

    • Перевод

    Недавно PHP-проекты Avito перешли на версию PHP 7.1. По этому случаю мы решили вспомнить, как происходил переход на PHP 7.0 у нас и наших коллег из OLX. Дела давно минувших дней, но остались красивые графики, которые хочется показать миру.


    Первая часть рассказа основана на статье PHP’s not dead! PHP7 in practice, которую написал наш коллега из OLX Lukasz Szyma'nski (Лукаш Шиманьски): переход OLX на PHP 7. Во второй части — опыт перехода Avito на PHP 7.0 и PHP 7.1: процесс, трудности, результаты с графиками.


    Часть 1. PHP 7 в OLX


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


    В этом посте расскажем, с какими проблемами пришлось столкнуться и чего удалось получить с переходом на PHP 7. Про переход было рассказано на конференции PHPers Summit 2016.


    Слайды

    Переход


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


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


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


    Memcache


    Отказ от поддержки Memcache в PHP 7 подтолкнул нас к переходу на Memcached. Пришлось поддержать две версии сайта: PHP 5 + Memcache и PHP 7 + Memcached.


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


    https://habrahabr.ru/post/338140/


    Метки:  

    Набор полезных советов для эффективного использования FreeIPA

    Понедельник, 18 Сентября 2017 г. 12:18 + в цитатник
    Vrenskiy сегодня в 12:18 Администрирование

    Набор полезных советов для эффективного использования FreeIPA



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

      Содержание:

      1. FreeIPA агенте в lxc контейнерах
      2. Библиотека для использования API в python
      3. Несколько слов про Ansible модули
      4. FreeIPA агент в debian
      5. Реплика в Амазоне

      FreeIPA агент в lxc контейнерах


      У нас для dev-окружений в некоторых местах используется такая штука, как Proxmox и lxc-контейнеры в нём. Темплейт для контейнера был взят стандартный centos-7-default версии 20170504, который мы кастомизировали. Но при банальной установке агента он отказался работать. После разбора выяснилось, что в этой сборке нет пакетов с sudo и в контейнерах нет SELinux. Итак, по пунктам, что нужно сделать:

      • yum install sudo
      • устанавливаем и конфигурируем
      • в файле /etc/sssd/sssd.conf, в секцию [domain/$DOMAINNAME] добавляем строку selinux_provider=none
      • рестартим sssd systemctl restart sssd

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

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

      ansible_virtualization_role == "guest" and ansible_virtualization_type == "lxc"

      Библиотека для использования API в Python


      В современных версиях FreeIPA появился замечательный API, но вот полноценных библиотек для Python нам найти не удалось. На гитхабе есть репозиторий, но реализованного там нам оказалось мало. Так как решение распространяется под MIT лицензией, мы решили скопировать его и дополнить сами. Наша реализация доступна по этой ссылке.

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

      Несколько слов про Ansible модули


      Оговорюсь сразу, речь пойдёт про версию Ansible 2.3.1.0, установленную через pip. В целом модули добавления юзеров и групп работают нормально. Но при добавлении sudoroles возникли некоторые проблемы. Первая и самая неприятная — они просто не добавляются. Ошибка выглядит вот так:

      get_sudorule_diff() takes exactly 2 arguments (3 given)

      Лечится на скорую руку, это довольно элементарно. В файле модуля ipa_sudorule.py нам нужна строка 307. Вот она:

      diff = get_sudorule_diff(client, ipa_sudorule, module_sudorule)

      Меняем ее на такую:

      diff = get_sudorule_diff(ipa_sudorule, module_sudorule)

      Добавление начинает работать. Прочитать про это можно тут и тут, но нами еще не проверено.

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

      FreeIPA агент в debian


      Установка агента в debian like системы почему-то у некоторых людей вызывает ряд проблем. Я хочу изложить наш вариант развертки агентов на debian подобных системах:

      1. Добавляем репозиторий
      wget -qO - http://apt.numeezy.fr/numeezy.asc | apt-key add -
      echo -e 'deb http://apt.numeezy.fr  jessie main' >> /etc/apt/sources.list
      
      2. Устанавливаем пакеты
      apt-get update
      apt-get install -y freeipa-client
      
      3. Создаём директории
      mkdir -p /etc/pki/nssdb
      certutil -N -d /etc/pki/nssdb
      mkdir -p /var/run/ipa
      
      4. Убираем дефолтный конфиг
      mv  /etc/ipa/default.conf ~/
      
      5. Устанавливаем и настраиваем клиент
      ipa-client-install
      
      6. Включаем создание директорий 
      echo 'session required pam_mkhomedir.so' >> /etc/pam.d/common-session
      
      7. Проверяем, чтобы в /etc/nsswitch.conf был указан sss провайдер
      passwd: files sss
      group: files sss
      shadow: files sss
      
      8. Перезагружаем sssd
      systemctl restart sssd

      Реплика в Amazon


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

      Для решения этой проблемы при установке достаточно на время установки добавить на любой интерфейс внешний IP. Как пример, это можно сделать при помощи ip addr add:

      ip addr add $ADDR  dev $IFace

      После успешной установки и настройки с помощью ip addr del:

      ip addr del $ADDR

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

      В итоге мы получаем, что клиенты в lxc и debian подобных системах вполне реальны и никаких особых проблем не имеют. Все эти решения работают у нас без каких-либо заметных проблем уже довольно длительное время. Управлять полноценно доступами через Ansible не вполне удобно, но можно ускорить и автоматизировать часть рутинной работы. Что касается библиотеки для Python — надо реализовать еще довольно много, но все основные функции там уже имеются. Впрочем, новые идеи тоже приветствуются.
      Original source: habrahabr.ru (comments, light).

      https://habrahabr.ru/post/337454/


      Метки:  

      Zabbix + RocksDB — миграция и первые впечатления

      Понедельник, 18 Сентября 2017 г. 11:37 + в цитатник
      mickvav сегодня в 11:37 Администрирование

      Zabbix + RocksDB — миграция и первые впечатления

        Некоторое время назад я восхитился от команды Facebook-а, запилившей для целей мониторинга специальную базу — RocksDB. При внимательном рассмотрении оказалось, что оно форк более раннего гугловского проекта, оно архивирует данные налету и оно, будучи «в душе» NoSQL, стыкуется к MySQL как storage engine.

        Дальше прилетела новость, что MariaDB включили этот движок в upstream с версии 10.2. Ништяки вроде архивирования на лету и ttl на отдельные строки под капотом так и манили попробовать это на чем-то подходящем…

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

        Ограничения


        Первая проблема, вылезшая при планировании — myrocks не умеет CONSTRAINT FOREIGN KEY. Не умеет, и всё. И не планируется. NoSQL, однако. Казалось бы, на этом можно свернуть всю затею, но внимательный взгляд на схему данных zabbix-а показывает, что самые горячие таблицы — history_uint, history_text, history_log и history_str — куда, собственно, прилетают данные из всех щелей источников, не содержат внешних ключей. Вероятно, команда zabbix сделала это осознанно, чтобы упростить эти таблицы — но нам это только на руку.

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

        Но внимательное разглядывание вывода grep -r 'history_uint' zabbix-3.2.5 приводит к выводу, что хоть zabbix и учиняет транзакции при добавлении значений, внутри этих транзакций он не трогает других таблиц (зачем бы ему, действительно?) — так что пролезаем.

        Ещё нужно поменять collation на табличках, которые мы переносим на rocksdb на latin1_bin или utf8_bin. И вообще — от кодировки latin1 лучше избавиться. В итоге получился вот такой perl-скриптик для преобразования дампа:

        #!/usr/bin/perl
        $tablename='';
        $has_constraints=0;
        
        while(<>) {
          s/CHARACTER SET latin1//;
          if(/CREATE TABLE `(.*)`/) {
            $tablename=$1;
            $has_constraints=0;
          };
          if(/CONSTRAINT/) {
            $has_constraints=1;
          };
          if(/ENGINE=InnoDB/ and $has_constraints==0) {
             s/ENGINE=InnoDB/ENGINE=ROCKSDB/;
             s/CHARSET=([^ ^;]+)/CHARSET=$1 COLLATE=$1_bin/;
          };
          print $_;
        };
        

        Сборка


        Я собирал mariadb из исходников до .deb-пакетов и их уже ставил. Выглядит примерно так (ОС — debian 8.8):

        apt-get update
        apt-get install git g++ cmake libbz2-dev libaio-dev bison zlib1g-dev libsnappy-dev build-essential vim cmake perl bison ncurses-dev libssl-dev libncurses5-dev libgflags-dev libreadline6-dev libncurses5-dev libssl-dev liblz4-dev gdb smartmontools
        
        apt-get install dpkg-dev devscripts chrpath dh-apparmor dh-systemd dpatch libboost-dev libcrack2-dev libjemalloc-dev libreadline-gplv2-dev libsystemd-dev libxml2-dev unixodbc-dev
        apt-get install  libjudy-dev libkrb5-dev libnuma-dev libpam0g-dev libpcre3-dev pkg-config libreadline-gplv2-dev uuid-dev
        
        git clone https://github.com/MariaDB/server.git mariadb-10.2
        cd mariadb-10.2
        git checkout 10.2
        git submodule init
        git submodule update
        ./debian/autobake-deb.sh
        

        Инсталляция


        Не обошлось без дополнительных зависимостей —

        wget http://releases.galeracluster.com/debian/pool/main/g/galera-3/galera-3_25.3.20-1jessie_amd64.deb
        dpkg -i galera-3*.deb
        apt-get install gawk libdbi-perl socat
        dpkg -i mysql-common*.deb  mariadb-server*.deb mariadb-plugin*.deb mariadb-client*.deb libm*.deb
        

        Сборка net-snmp


        По неясным пока причинам, net-snmp из debian приводит к нерабочей сборке zabbix — valgrind ругается на утечки памяти там, где всё должно работать вполне линейно. В итоге заббикс падает.

        Спасает — переборка net-snmp из исходников с наложением почти всех debian-овских патчей.
        У меня собрался net-snmp-code-368636fd94e484a5f4be5c0fcd205f507463412a.zip
        Возможно, более свежие тоже собирутся.
        Ещё понадобится debian-овский архивчик с директорией debian.
        Дальше как-то так:

        version=368636fd94e484a5f4be5c0fcd205f507463412a
        debian_version=net-snmp_5.7.2.1+dfsg-1.debian.tar.xz
        unzip -q net-snmp-code-${version}.zip
        cd net-snmp-code-${version}
        tar -xvJf ../$debian_version
        for i in 03_makefiles.patch 26_kfreebsd.patch 27_kfreebsd_bug625985.patch fix_spelling_error.patch fix_logging_option.patch fix_man_error.patch after_RFC5378 fix_manpage-has-errors_break_line.patch fix_manpage-has-errors-from-man.patch agentx-crash.patch TrapReceiver.patch ifmib.patch CVE-2014-3565.patch; do
          rm debian/patches/$i
          touch debian/patches/$i
        done
        cp ../rules debian/rules
        dpkg-buildpackage -d -b
        cd ..
        dpkg -i *.deb
        

        Фокус с rules-файлом — я в нём выключил --with-mysql (заменил на --without-mysql), чтобы не привязывать net-snmp к mysql — тогда при экспериментах с версиями mariadb не нужно пересобирать net-snmp. Можно и опустить.

        Сборка zabbix


        Сам zabbix приходится собирать уже после установки mariadb, так как он линкуется к динамическим библиотекам, прилетающим с ней. У меня получилось как-то так:

        zabbixversion="3.2.7"
        apt-get install libsnmp-dev libcurl4-openssl-dev python-requests
        if [ ! -f zabbix-${zabbixversion}.tar.gz ]; then
          wget https://downloads.sourceforge.net/project/zabbix/ZABBIX%20Latest%20Stable/${zabbixversion}/zabbix-${zabbixversion}.tar.gz
          tar -xvzf zabbix-${zabbixversion}.tar.gz
        fi
        cd zabbix-${zabbixversion}
        groupadd zabbix
        useradd -g zabbix zabbix
        sed -i 's/mariadbclient/mariadb/' configure
        ./configure --enable-proxy --enable-server --enable-agent --with-mysql --enable-ipv6 --with-net-snmp --with-libcurl --with-libxml2
        make -j5
        make install
        

        Профит — удалось уменьшить аппетиты заббикса к месту, отказаться от ротации табличек по схеме «create partition/drop partition» — теперь housekeeper справляется со своей задачей сам (по крайней мере, на ssd-диске, хех. Тут бы проверить на innodb в свежей сборочке, но пока не успелось) и срок хранения данных вновь стал управляемым для каждого элемента данных по отдельности. При массовых проблемах очередь вычищается теперь в разы быстрее.

        Что не опробовано (ровно потому, что housekeeper завёлся) — добавить в свойства табличек history* и trends* волшебную штуку COMMENT='ttl_duration=864000;ttl_col=clock;' имеющую, насколько я понял, смысл «хранить не более 864000 секунд, чистить на уровне storage engine».

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

        Полезные доки, которые пригодились при написании статьи:


        Разное другое, что вылезало в гугле на те или иные запросы :)
        Спасибо за внимание. Если есть вопросы/замечания — милости прошу в комменты.
        Original source: habrahabr.ru (comments, light).

        https://habrahabr.ru/post/334276/


        Метки:  

        [Перевод] Знакомство с kube-spawn — утилитой для создания локальных Kubernetes-кластеров

        Понедельник, 18 Сентября 2017 г. 11:13 + в цитатник
        shurup сегодня в 11:13 Администрирование

        Знакомство с kube-spawn — утилитой для создания локальных Kubernetes-кластеров

        • Перевод
        Прим. перев.: kube-spawn — достаточно новый (анонсированный в августе) Open Source-проект, созданный в немецкой компании Kinvolk для локального запуска Kubernetes-кластеров. Он написан на Go, работает с Kubernetes версий 1.7.0+, использует возможности kubeadm и systemd-nspawn, ориентирован только на операционную систему GNU/Linux. В отличие от Minikube, он не запускает виртуальную машину для Kubernetes, а значит, что overhead будет минимальным и все процессы, запущенные внутри контейнеров, видны на хост-машине (в т.ч. и через top/htop). Представленная ниже статья — анонс этой утилиты, опубликованный одним из сотрудников компании (Chris K"uhl) в корпоративном блоге.



        kube-spawn — инструмент для простого запуска локального кластера Kubernetes из множества узлов на Linux-машине. Изначально он создавался преимущественно для разработчиков самого Kubernetes, однако со временем превратился в утилиту, которая отлично подходит для того, чтобы попробовать и изучить Kubernetes. Эта статья предлагает общее введение в kube-spawn и показывает, как использовать этот инструмент.

        Обзор


        kube-spawn задаётся целью стать простейшим способом проведения тестов и других экспериментов с Kubernetes в Linux. Этот проект появился из-за сложностей, возникавших при запуске Kubernetes-кластера со множеством узлов на машинах для разработки. Утилиты, предлагающие нужную функциональность, обычно не предоставляют окружения, в которых Kubernetes будет впоследствии запущен, то есть полноценную операционную систему GNU/Linux.

        Запуск кластера Kubernetes с kube-spawn


        Итак, давайте запустим кластер. В kube-spawn достаточно одной команды, чтобы получить образ Container Linux, подготовить узлы (nodes) и развернуть кластер. Эти шаги можно выполнить отдельно с помощью machinectl pull-raw и подкоманд kube-spawn setup и init. Однако подкоманда up сделает всё за нас:

        $ sudo GOPATH=$GOPATH CNI_PATH=$GOPATH/bin ./kube-spawn up --nodes=3

        Когда команда закончит выполняться, вы получите кластер Kubernetes с 3 узлами. Придётся подождать, пока узлы будут готовы для использования.

        $ export KUBECONFIG=$GOPATH/src/github.com/kinvolk/kube-spawn/.kube-spawn/default/kubeconfig
        $ kubectl get nodes
        NAME           STATUS    AGE       VERSION
        kube-spawn-0   Ready     1m        v1.7.0
        kube-spawn-1   Ready     1m        v1.7.0
        kube-spawn-2   Ready     1m        v1.7.0

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

        Демонстрационное приложение


        Работоспособность кластера мы проверим, развернув демонстрационное микросервисное приложение Sock Shop, созданное в Weaveworks. Sock Shop — сложное приложение, состоящее из микросервисов и использующее множество компонентов, которые обычно можно найти в реальных инсталляциях. Таким образом, оно позволяет проверить, что всё действительно работает, и даёт более существенную почву для исследований, чем простое «hello world».

        Клонирование приложения


        Чтобы продолжить, понадобится склонировать репозиторий microservices-demo и перейти в каталог deploy/kubernetes:

        $ cd ~/repos
        $ git clone https://github.com/microservices-demo/microservices-demo.git sock-shop
        $ cd sock-shop/deploy/kubernetes/

        Деплой приложения


        Теперь всё готово для деплоя. Но первым делом необходимо создать пространство имён sock-shop — в deployment предполагается его наличие:

        $ kubectl create namespace sock-shop
        namespace "sock-shop" created

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

        $ kubectl create -f complete-demo.yaml
        deployment "carts-db" created
        service "carts-db" created
        deployment "carts" created
        service "carts" created
        deployment "catalogue-db" created
        service "catalogue-db" created
        deployment "catalogue" created
        service "catalogue" created
        deployment "front-end" created
        service "front-end" created
        deployment "orders-db" created
        service "orders-db" created
        deployment "orders" created
        service "orders" created
        deployment "payment" created
        service "payment" created
        deployment "queue-master" created
        service "queue-master" created
        deployment "rabbitmq" created
        service "rabbitmq" created
        deployment "shipping" created
        service "shipping" created
        deployment "user-db" created
        service "user-db" created
        deployment "user" created
        service "user" created

        После выполнения этих операций надо подождать, пока появятся все поды:

        $ watch kubectl -n sock-shop get pods
        NAME                            READY     STATUS    RESTARTS   AGE
        carts-2469883122-nd0g1          1/1       Running   0          1m
        carts-db-1721187500-392vt       1/1       Running   0          1m
        catalogue-4293036822-d79cm      1/1       Running   0          1m
        catalogue-db-1846494424-njq7h   1/1       Running   0          1m
        front-end-2337481689-v8m2h      1/1       Running   0          1m
        orders-733484335-mg0lh          1/1       Running   0          1m
        orders-db-3728196820-9v07l      1/1       Running   0          1m
        payment-3050936124-rgvjj        1/1       Running   0          1m
        queue-master-2067646375-7xx9x   1/1       Running   0          1m
        rabbitmq-241640118-8htht        1/1       Running   0          1m
        shipping-2463450563-n47k7       1/1       Running   0          1m
        user-1574605338-p1djk           1/1       Running   0          1m
        user-db-3152184577-c8r1f        1/1       Running   0          1m

        Доступ к sock shop


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

        $ kubectl -n sock-shop get svc
        NAME           CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
        carts          10.110.14.144            80/TCP         3m
        carts-db       10.104.115.89            27017/TCP      3m
        catalogue      10.110.157.8             80/TCP         3m
        catalogue-db   10.99.103.79             3306/TCP       3m
        front-end      10.105.224.192          80:30001/TCP   3m
        orders         10.101.177.247           80/TCP         3m
        orders-db      10.109.209.178           27017/TCP      3m
        payment        10.107.53.203            80/TCP         3m
        queue-master   10.111.63.76             80/TCP         3m
        rabbitmq       10.110.136.97            5672/TCP       3m
        shipping       10.96.117.56             80/TCP         3m
        user           10.101.85.39             80/TCP         3m
        user-db        10.107.82.6              27017/TCP      3m

        Видно, что фронтенд (front-end) использует порт 30001 и внешний IP-адрес. Это означает, что мы можем достучаться до его служб через IP-адрес любого рабочего узла (worker) и порт 30001. Узнать IP-адреса всех узлов кластера можно через machinectl:

        $ machinectl
        MACHINE      CLASS     SERVICE        OS     VERSION  ADDRESSES
        kube-spawn-0 container systemd-nspawn coreos 1492.1.0 10.22.0.137...
        kube-spawn-1 container systemd-nspawn coreos 1492.1.0 10.22.0.138...
        kube-spawn-2 container systemd-nspawn coreos 1492.1.0 10.22.0.139...

        Запомните, что первый узел — это мастер, а все остальные — рабочие узлы (workers). В нашем случае достаточно открыть браузер и зайти по адресу 10.22.0.138:30001 или 10.22.0.139:30001, где нас поприветствует магазин, продающий носки.

        Остановка кластера


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

        $ sudo ./kube-spawn stop
        2017/08/10 01:58:00 turning off machines [kube-spawn-0 kube-spawn-1 kube-spawn-2]...
        2017/08/10 01:58:00 All nodes are stopped.

        Демонстрация с инструкциями


        Для тех, кто предпочитает «экскурсии с гидом», смотрите видео на YouTube (около 7 минут на английском языке — прим. перев.).

        Как упомянуто в видео, kube-spawn создаёт в текущей директории каталог .kube-spawn, в котором вы найдёте несколько файлов и директорий в default. Чтобы не ограничиваться размером каждого OS Container, мы монтируем сюда /var/lib/docker каждого узла. Благодаря этому мы можем использовать дисковое пространство хостовой машины. Наконец, на данный момент у нас нет команды очистки (clean). Желающие полностью замести следы деятельности kube-spawn могут выполнить команду rm -rf .kube-spawn/.

        Заключение


        Надеемся, вы тоже найдёте утилиту kube-spawn полезной. Для нас это простейший путь проверить изменения в Kubernetes или развернуть кластер для изучения Kubernetes.

        В kube-spawn всё ещё можно привнести многочисленные улучшения (и некоторые из них весьма очевидны). Очень приветствуем pull requests!

        P.S. от переводчика. Об установке и других особенностях kube-spawn написано в GitHub-репозитории проекта. Читайте также в нашем блоге:

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

        https://habrahabr.ru/post/338132/


        Метки:  

        [Перевод] Знакомство с kube-spawn — утилитой для создания локальных Kubernetes-кластеров

        Понедельник, 18 Сентября 2017 г. 11:13 + в цитатник
        shurup сегодня в 11:13 Администрирование

        Знакомство с kube-spawn — утилитой для создания локальных Kubernetes-кластеров

        • Перевод
        Прим. перев.: kube-spawn — достаточно новый (анонсированный в августе) Open Source-проект, созданный в немецкой компании Kinvolk для локального запуска Kubernetes-кластеров. Он написан на Go, работает с Kubernetes версий 1.7.0+, использует возможности kubeadm и systemd-nspawn, ориентирован только на операционную систему GNU/Linux. В отличие от Minikube, он не запускает виртуальную машину для Kubernetes, а значит, что overhead будет минимальным и все процессы, запущенные внутри контейнеров, видны на хост-машине (в т.ч. и через top/htop). Представленная ниже статья — анонс этой утилиты, опубликованный одним из сотрудников компании (Chris K"uhl) в корпоративном блоге.



        kube-spawn — инструмент для простого запуска локального кластера Kubernetes из множества узлов на Linux-машине. Изначально он создавался преимущественно для разработчиков самого Kubernetes, однако со временем превратился в утилиту, которая отлично подходит для того, чтобы попробовать и изучить Kubernetes. Эта статья предлагает общее введение в kube-spawn и показывает, как использовать этот инструмент.

        Обзор


        kube-spawn задаётся целью стать простейшим способом проведения тестов и других экспериментов с Kubernetes в Linux. Этот проект появился из-за сложностей, возникавших при запуске Kubernetes-кластера со множеством узлов на машинах для разработки. Утилиты, предлагающие нужную функциональность, обычно не предоставляют окружения, в которых Kubernetes будет впоследствии запущен, то есть полноценную операционную систему GNU/Linux.

        Запуск кластера Kubernetes с kube-spawn


        Итак, давайте запустим кластер. В kube-spawn достаточно одной команды, чтобы получить образ Container Linux, подготовить узлы (nodes) и развернуть кластер. Эти шаги можно выполнить отдельно с помощью machinectl pull-raw и подкоманд kube-spawn setup и init. Однако подкоманда up сделает всё за нас:

        $ sudo GOPATH=$GOPATH CNI_PATH=$GOPATH/bin ./kube-spawn up --nodes=3

        Когда команда закончит выполняться, вы получите кластер Kubernetes с 3 узлами. Придётся подождать, пока узлы будут готовы для использования.

        $ export KUBECONFIG=$GOPATH/src/github.com/kinvolk/kube-spawn/.kube-spawn/default/kubeconfig
        $ kubectl get nodes
        NAME           STATUS    AGE       VERSION
        kube-spawn-0   Ready     1m        v1.7.0
        kube-spawn-1   Ready     1m        v1.7.0
        kube-spawn-2   Ready     1m        v1.7.0

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

        Демонстрационное приложение


        Работоспособность кластера мы проверим, развернув демонстрационное микросервисное приложение Sock Shop, созданное в Weaveworks. Sock Shop — сложное приложение, состоящее из микросервисов и использующее множество компонентов, которые обычно можно найти в реальных инсталляциях. Таким образом, оно позволяет проверить, что всё действительно работает, и даёт более существенную почву для исследований, чем простое «hello world».

        Клонирование приложения


        Чтобы продолжить, понадобится склонировать репозиторий microservices-demo и перейти в каталог deploy/kubernetes:

        $ cd ~/repos
        $ git clone https://github.com/microservices-demo/microservices-demo.git sock-shop
        $ cd sock-shop/deploy/kubernetes/

        Деплой приложения


        Теперь всё готово для деплоя. Но первым делом необходимо создать пространство имён sock-shop — в deployment предполагается его наличие:

        $ kubectl create namespace sock-shop
        namespace "sock-shop" created

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

        $ kubectl create -f complete-demo.yaml
        deployment "carts-db" created
        service "carts-db" created
        deployment "carts" created
        service "carts" created
        deployment "catalogue-db" created
        service "catalogue-db" created
        deployment "catalogue" created
        service "catalogue" created
        deployment "front-end" created
        service "front-end" created
        deployment "orders-db" created
        service "orders-db" created
        deployment "orders" created
        service "orders" created
        deployment "payment" created
        service "payment" created
        deployment "queue-master" created
        service "queue-master" created
        deployment "rabbitmq" created
        service "rabbitmq" created
        deployment "shipping" created
        service "shipping" created
        deployment "user-db" created
        service "user-db" created
        deployment "user" created
        service "user" created

        После выполнения этих операций надо подождать, пока появятся все поды:

        $ watch kubectl -n sock-shop get pods
        NAME                            READY     STATUS    RESTARTS   AGE
        carts-2469883122-nd0g1          1/1       Running   0          1m
        carts-db-1721187500-392vt       1/1       Running   0          1m
        catalogue-4293036822-d79cm      1/1       Running   0          1m
        catalogue-db-1846494424-njq7h   1/1       Running   0          1m
        front-end-2337481689-v8m2h      1/1       Running   0          1m
        orders-733484335-mg0lh          1/1       Running   0          1m
        orders-db-3728196820-9v07l      1/1       Running   0          1m
        payment-3050936124-rgvjj        1/1       Running   0          1m
        queue-master-2067646375-7xx9x   1/1       Running   0          1m
        rabbitmq-241640118-8htht        1/1       Running   0          1m
        shipping-2463450563-n47k7       1/1       Running   0          1m
        user-1574605338-p1djk           1/1       Running   0          1m
        user-db-3152184577-c8r1f        1/1       Running   0          1m

        Доступ к sock shop


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

        $ kubectl -n sock-shop get svc
        NAME           CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
        carts          10.110.14.144            80/TCP         3m
        carts-db       10.104.115.89            27017/TCP      3m
        catalogue      10.110.157.8             80/TCP         3m
        catalogue-db   10.99.103.79             3306/TCP       3m
        front-end      10.105.224.192          80:30001/TCP   3m
        orders         10.101.177.247           80/TCP         3m
        orders-db      10.109.209.178           27017/TCP      3m
        payment        10.107.53.203            80/TCP         3m
        queue-master   10.111.63.76             80/TCP         3m
        rabbitmq       10.110.136.97            5672/TCP       3m
        shipping       10.96.117.56             80/TCP         3m
        user           10.101.85.39             80/TCP         3m
        user-db        10.107.82.6              27017/TCP      3m

        Видно, что фронтенд (front-end) использует порт 30001 и внешний IP-адрес. Это означает, что мы можем достучаться до его служб через IP-адрес любого рабочего узла (worker) и порт 30001. Узнать IP-адреса всех узлов кластера можно через machinectl:

        $ machinectl
        MACHINE      CLASS     SERVICE        OS     VERSION  ADDRESSES
        kube-spawn-0 container systemd-nspawn coreos 1492.1.0 10.22.0.137...
        kube-spawn-1 container systemd-nspawn coreos 1492.1.0 10.22.0.138...
        kube-spawn-2 container systemd-nspawn coreos 1492.1.0 10.22.0.139...

        Запомните, что первый узел — это мастер, а все остальные — рабочие узлы (workers). В нашем случае достаточно открыть браузер и зайти по адресу 10.22.0.138:30001 или 10.22.0.139:30001, где нас поприветствует магазин, продающий носки.

        Остановка кластера


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

        $ sudo ./kube-spawn stop
        2017/08/10 01:58:00 turning off machines [kube-spawn-0 kube-spawn-1 kube-spawn-2]...
        2017/08/10 01:58:00 All nodes are stopped.

        Демонстрация с инструкциями


        Для тех, кто предпочитает «экскурсии с гидом», смотрите видео на YouTube (около 7 минут на английском языке — прим. перев.).

        Как упомянуто в видео, kube-spawn создаёт в текущей директории каталог .kube-spawn, в котором вы найдёте несколько файлов и директорий в default. Чтобы не ограничиваться размером каждого OS Container, мы монтируем сюда /var/lib/docker каждого узла. Благодаря этому мы можем использовать дисковое пространство хостовой машины. Наконец, на данный момент у нас нет команды очистки (clean). Желающие полностью замести следы деятельности kube-spawn могут выполнить команду rm -rf .kube-spawn/.

        Заключение


        Надеемся, вы тоже найдёте утилиту kube-spawn полезной. Для нас это простейший путь проверить изменения в Kubernetes или развернуть кластер для изучения Kubernetes.

        В kube-spawn всё ещё можно привнести многочисленные улучшения (и некоторые из них весьма очевидны). Очень приветствуем pull requests!

        P.S. от переводчика. Об установке и других особенностях kube-spawn написано в GitHub-репозитории проекта. Читайте также в нашем блоге:

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

        https://habrahabr.ru/post/338132/


        Метки:  

        [Перевод] Знакомство с kube-spawn — утилитой для создания локальных Kubernetes-кластеров

        Понедельник, 18 Сентября 2017 г. 11:13 + в цитатник
        shurup сегодня в 11:13 Администрирование

        Знакомство с kube-spawn — утилитой для создания локальных Kubernetes-кластеров

        • Перевод
        Прим. перев.: kube-spawn — достаточно новый (анонсированный в августе) Open Source-проект, созданный в немецкой компании Kinvolk для локального запуска Kubernetes-кластеров. Он написан на Go, работает с Kubernetes версий 1.7.0+, использует возможности kubeadm и systemd-nspawn, ориентирован только на операционную систему GNU/Linux. В отличие от Minikube, он не запускает виртуальную машину для Kubernetes, а значит, что overhead будет минимальным и все процессы, запущенные внутри контейнеров, видны на хост-машине (в т.ч. и через top/htop). Представленная ниже статья — анонс этой утилиты, опубликованный одним из сотрудников компании (Chris K"uhl) в корпоративном блоге.



        kube-spawn — инструмент для простого запуска локального кластера Kubernetes из множества узлов на Linux-машине. Изначально он создавался преимущественно для разработчиков самого Kubernetes, однако со временем превратился в утилиту, которая отлично подходит для того, чтобы попробовать и изучить Kubernetes. Эта статья предлагает общее введение в kube-spawn и показывает, как использовать этот инструмент.

        Обзор


        kube-spawn задаётся целью стать простейшим способом проведения тестов и других экспериментов с Kubernetes в Linux. Этот проект появился из-за сложностей, возникавших при запуске Kubernetes-кластера со множеством узлов на машинах для разработки. Утилиты, предлагающие нужную функциональность, обычно не предоставляют окружения, в которых Kubernetes будет впоследствии запущен, то есть полноценную операционную систему GNU/Linux.

        Запуск кластера Kubernetes с kube-spawn


        Итак, давайте запустим кластер. В kube-spawn достаточно одной команды, чтобы получить образ Container Linux, подготовить узлы (nodes) и развернуть кластер. Эти шаги можно выполнить отдельно с помощью machinectl pull-raw и подкоманд kube-spawn setup и init. Однако подкоманда up сделает всё за нас:

        $ sudo GOPATH=$GOPATH CNI_PATH=$GOPATH/bin ./kube-spawn up --nodes=3

        Когда команда закончит выполняться, вы получите кластер Kubernetes с 3 узлами. Придётся подождать, пока узлы будут готовы для использования.

        $ export KUBECONFIG=$GOPATH/src/github.com/kinvolk/kube-spawn/.kube-spawn/default/kubeconfig
        $ kubectl get nodes
        NAME           STATUS    AGE       VERSION
        kube-spawn-0   Ready     1m        v1.7.0
        kube-spawn-1   Ready     1m        v1.7.0
        kube-spawn-2   Ready     1m        v1.7.0

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

        Демонстрационное приложение


        Работоспособность кластера мы проверим, развернув демонстрационное микросервисное приложение Sock Shop, созданное в Weaveworks. Sock Shop — сложное приложение, состоящее из микросервисов и использующее множество компонентов, которые обычно можно найти в реальных инсталляциях. Таким образом, оно позволяет проверить, что всё действительно работает, и даёт более существенную почву для исследований, чем простое «hello world».

        Клонирование приложения


        Чтобы продолжить, понадобится склонировать репозиторий microservices-demo и перейти в каталог deploy/kubernetes:

        $ cd ~/repos
        $ git clone https://github.com/microservices-demo/microservices-demo.git sock-shop
        $ cd sock-shop/deploy/kubernetes/

        Деплой приложения


        Теперь всё готово для деплоя. Но первым делом необходимо создать пространство имён sock-shop — в deployment предполагается его наличие:

        $ kubectl create namespace sock-shop
        namespace "sock-shop" created

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

        $ kubectl create -f complete-demo.yaml
        deployment "carts-db" created
        service "carts-db" created
        deployment "carts" created
        service "carts" created
        deployment "catalogue-db" created
        service "catalogue-db" created
        deployment "catalogue" created
        service "catalogue" created
        deployment "front-end" created
        service "front-end" created
        deployment "orders-db" created
        service "orders-db" created
        deployment "orders" created
        service "orders" created
        deployment "payment" created
        service "payment" created
        deployment "queue-master" created
        service "queue-master" created
        deployment "rabbitmq" created
        service "rabbitmq" created
        deployment "shipping" created
        service "shipping" created
        deployment "user-db" created
        service "user-db" created
        deployment "user" created
        service "user" created

        После выполнения этих операций надо подождать, пока появятся все поды:

        $ watch kubectl -n sock-shop get pods
        NAME                            READY     STATUS    RESTARTS   AGE
        carts-2469883122-nd0g1          1/1       Running   0          1m
        carts-db-1721187500-392vt       1/1       Running   0          1m
        catalogue-4293036822-d79cm      1/1       Running   0          1m
        catalogue-db-1846494424-njq7h   1/1       Running   0          1m
        front-end-2337481689-v8m2h      1/1       Running   0          1m
        orders-733484335-mg0lh          1/1       Running   0          1m
        orders-db-3728196820-9v07l      1/1       Running   0          1m
        payment-3050936124-rgvjj        1/1       Running   0          1m
        queue-master-2067646375-7xx9x   1/1       Running   0          1m
        rabbitmq-241640118-8htht        1/1       Running   0          1m
        shipping-2463450563-n47k7       1/1       Running   0          1m
        user-1574605338-p1djk           1/1       Running   0          1m
        user-db-3152184577-c8r1f        1/1       Running   0          1m

        Доступ к sock shop


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

        $ kubectl -n sock-shop get svc
        NAME           CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
        carts          10.110.14.144            80/TCP         3m
        carts-db       10.104.115.89            27017/TCP      3m
        catalogue      10.110.157.8             80/TCP         3m
        catalogue-db   10.99.103.79             3306/TCP       3m
        front-end      10.105.224.192          80:30001/TCP   3m
        orders         10.101.177.247           80/TCP         3m
        orders-db      10.109.209.178           27017/TCP      3m
        payment        10.107.53.203            80/TCP         3m
        queue-master   10.111.63.76             80/TCP         3m
        rabbitmq       10.110.136.97            5672/TCP       3m
        shipping       10.96.117.56             80/TCP         3m
        user           10.101.85.39             80/TCP         3m
        user-db        10.107.82.6              27017/TCP      3m

        Видно, что фронтенд (front-end) использует порт 30001 и внешний IP-адрес. Это означает, что мы можем достучаться до его служб через IP-адрес любого рабочего узла (worker) и порт 30001. Узнать IP-адреса всех узлов кластера можно через machinectl:

        $ machinectl
        MACHINE      CLASS     SERVICE        OS     VERSION  ADDRESSES
        kube-spawn-0 container systemd-nspawn coreos 1492.1.0 10.22.0.137...
        kube-spawn-1 container systemd-nspawn coreos 1492.1.0 10.22.0.138...
        kube-spawn-2 container systemd-nspawn coreos 1492.1.0 10.22.0.139...

        Запомните, что первый узел — это мастер, а все остальные — рабочие узлы (workers). В нашем случае достаточно открыть браузер и зайти по адресу 10.22.0.138:30001 или 10.22.0.139:30001, где нас поприветствует магазин, продающий носки.

        Остановка кластера


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

        $ sudo ./kube-spawn stop
        2017/08/10 01:58:00 turning off machines [kube-spawn-0 kube-spawn-1 kube-spawn-2]...
        2017/08/10 01:58:00 All nodes are stopped.

        Демонстрация с инструкциями


        Для тех, кто предпочитает «экскурсии с гидом», смотрите видео на YouTube (около 7 минут на английском языке — прим. перев.).

        Как упомянуто в видео, kube-spawn создаёт в текущей директории каталог .kube-spawn, в котором вы найдёте несколько файлов и директорий в default. Чтобы не ограничиваться размером каждого OS Container, мы монтируем сюда /var/lib/docker каждого узла. Благодаря этому мы можем использовать дисковое пространство хостовой машины. Наконец, на данный момент у нас нет команды очистки (clean). Желающие полностью замести следы деятельности kube-spawn могут выполнить команду rm -rf .kube-spawn/.

        Заключение


        Надеемся, вы тоже найдёте утилиту kube-spawn полезной. Для нас это простейший путь проверить изменения в Kubernetes или развернуть кластер для изучения Kubernetes.

        В kube-spawn всё ещё можно привнести многочисленные улучшения (и некоторые из них весьма очевидны). Очень приветствуем pull requests!

        P.S. от переводчика. Об установке и других особенностях kube-spawn написано в GitHub-репозитории проекта. Читайте также в нашем блоге:

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

        https://habrahabr.ru/post/338132/


        Метки:  

        [Перевод] OO VS FP

        Понедельник, 18 Сентября 2017 г. 11:02 + в цитатник
        marshinov сегодня в 11:02 Разработка

        OO VS FP

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

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

        Эти точки зрения игнорируют саму суть ООП и ФП парадигм. Вставлю свои пять копеек.

        ООП не про внутреннее состояние


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

        Функциональные программы, как и объектно-ориентированные являются композицией функций преобразования данных. В ООП принято объединять данные и поведение. И что? Это действительно так важно? Есть огромная разница между f(o), o.f() и (f o)? Что, вся разница в синтаксисе. Так в чем же настоящие различия между ООП и ФП? Что есть в ООП, чего нет в ФП и наоборот?

        ФП навязывает дисциплину в присвоение (immutability)


        В «тру фп» нет оператора присвоения. Термин «переменная» вообще не применим к функциональным ЯП, потому что однажды присвоив значение его нельзя изменить.
        Да. Да. Апологеты ФП часто указывают на то что функции – объекты первого класса. В Smalltalk функции – тоже объекты первого класса. Smaltalk – объектно-ориентированный, а не функциональный язык.
        Ключевое отличие не в этом, а в отсутствии удобного оператора присваивания. Значит ли это, в ФП вообще нет изменяемого состояния? Нет. В ФП языках есть всевозможные уловки, позволяющие работать с изменяемым состоянием. Однако, чтобы сделать это, вам придется совершить определенную церемонию. Изменение состояния выглядит сложным, громоздким и чужеродным в ФП. Это исключительная мера, к которой прибегают лишь изредка и неохотно.

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


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

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

        Если вы хотите использовать полиморфизм в C вам придется работать с указателями вручную и это сложно. Хотите полиморфизм в Lisp: придется передавать функции в качестве аргументов самостоятельно (кстати, это называется паттерном стратегия). Но в объектно-ориентированных языках все это есть из коробки: бери и пользуйся.

        Взаимоисключающие?


        Являются две эти дисциплины взаимоисключающими? Может ли ЯП навязывать дисциплину в присваивании и при работе с указателями на функции. Конечно может! Эти вещи вообще не связаны. Эти парадигмы – не взаимоисключающие. Это значит, что можно писать объектно-ориентированные функциональные программы.

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

        Преимущества полиморфизма


        У полиморфизма всего одно преимущество, но оно значительно. Это инверсия исходного кода и рантайм-зависимостей.

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

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

        Преимущества неизменяемости


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

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

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

        Занудные философствования


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

        Так что там про принципы и паттерны?


        Что вызвало у меня такое раздражение? Первые слайды намекают на то что все принципы и паттерны, разработанные нами за десятилетия работы применимы только для ООП. А в ФП все решается просто функциями.
        Вау, и после этого вы что-то говорите про редукционизм? Идея проста. Принципы остаются неизменными, независимо от стиля программирования. Факт, что вы выбрали ЯП без удобного оператора присвоения, не значит, что вы можете игнорировать SRP или OCP, что эти принципы будут каким-то образом работать автоматически. Если паттерн «Стратегия» использует полиморфизм, это еще не значит, что он не может применяться в функциональном ЯП (например Clojure).

        Итого, ООП работает, если вы знаете, как его готовить. Аналогично для ФП. Функциональные объектно-ориентированные программы – вообще отлично, если вы действительно понимаете, что это значит.
        Original source: habrahabr.ru (comments, light).

        https://habrahabr.ru/post/338136/


        Метки:  

        [Перевод] OO VS FP

        Понедельник, 18 Сентября 2017 г. 11:02 + в цитатник
        marshinov сегодня в 11:02 Разработка

        OO VS FP

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

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

        Эти точки зрения игнорируют саму суть ООП и ФП парадигм. Вставлю свои пять копеек.

        ООП не про внутреннее состояние


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

        Функциональные программы, как и объектно-ориентированные являются композицией функций преобразования данных. В ООП принято объединять данные и поведение. И что? Это действительно так важно? Есть огромная разница между f(o), o.f() и (f o)? Что, вся разница в синтаксисе. Так в чем же настоящие различия между ООП и ФП? Что есть в ООП, чего нет в ФП и наоборот?

        ФП навязывает дисциплину в присвоение (immutability)


        В «тру фп» нет оператора присвоения. Термин «переменная» вообще не применим к функциональным ЯП, потому что однажды присвоив значение его нельзя изменить.
        Да. Да. Апологеты ФП часто указывают на то что функции – объекты первого класса. В Smalltalk функции – тоже объекты первого класса. Smaltalk – объектно-ориентированный, а не функциональный язык.
        Ключевое отличие не в этом, а в отсутствии удобного оператора присваивания. Значит ли это, в ФП вообще нет изменяемого состояния? Нет. В ФП языках есть всевозможные уловки, позволяющие работать с изменяемым состоянием. Однако, чтобы сделать это, вам придется совершить определенную церемонию. Изменение состояния выглядит сложным, громоздким и чужеродным в ФП. Это исключительная мера, к которой прибегают лишь изредка и неохотно.

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


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

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

        Если вы хотите использовать полиморфизм в C вам придется работать с указателями вручную и это сложно. Хотите полиморфизм в Lisp: придется передавать функции в качестве аргументов самостоятельно (кстати, это называется паттерном стратегия). Но в объектно-ориентированных языках все это есть из коробки: бери и пользуйся.

        Взаимоисключающие?


        Являются две эти дисциплины взаимоисключающими? Может ли ЯП навязывать дисциплину в присваивании и при работе с указателями на функции. Конечно может! Эти вещи вообще не связаны. Эти парадигмы – не взаимоисключающие. Это значит, что можно писать объектно-ориентированные функциональные программы.

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

        Преимущества полиморфизма


        У полиморфизма всего одно преимущество, но оно значительно. Это инверсия исходного кода и рантайм-зависимостей.

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

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

        Преимущества неизменяемости


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

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

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

        Занудные философствования


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

        Так что там про принципы и паттерны?


        Что вызвало у меня такое раздражение? Первые слайды намекают на то что все принципы и паттерны, разработанные нами за десятилетия работы применимы только для ООП. А в ФП все решается просто функциями.
        Вау, и после этого вы что-то говорите про редукционизм? Идея проста. Принципы остаются неизменными, независимо от стиля программирования. Факт, что вы выбрали ЯП без удобного оператора присвоения, не значит, что вы можете игнорировать SRP или OCP, что эти принципы будут каким-то образом работать автоматически. Если паттерн «Стратегия» использует полиморфизм, это еще не значит, что он не может применяться в функциональном ЯП (например Clojure).

        Итого, ООП работает, если вы знаете, как его готовить. Аналогично для ФП. Функциональные объектно-ориентированные программы – вообще отлично, если вы действительно понимаете, что это значит.
        Original source: habrahabr.ru (comments, light).

        https://habrahabr.ru/post/338136/


        Метки:  

        [Перевод] OO VS FP

        Понедельник, 18 Сентября 2017 г. 11:02 + в цитатник
        marshinov сегодня в 11:02 Разработка

        OO VS FP

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

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

        Эти точки зрения игнорируют саму суть ООП и ФП парадигм. Вставлю свои пять копеек.

        ООП не про внутреннее состояние


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

        Функциональные программы, как и объектно-ориентированные являются композицией функций преобразования данных. В ООП принято объединять данные и поведение. И что? Это действительно так важно? Есть огромная разница между f(o), o.f() и (f o)? Что, вся разница в синтаксисе. Так в чем же настоящие различия между ООП и ФП? Что есть в ООП, чего нет в ФП и наоборот?

        ФП навязывает дисциплину в присвоение (immutability)


        В «тру фп» нет оператора присвоения. Термин «переменная» вообще не применим к функциональным ЯП, потому что однажды присвоив значение его нельзя изменить.
        Да. Да. Апологеты ФП часто указывают на то что функции – объекты первого класса. В Smalltalk функции – тоже объекты первого класса. Smaltalk – объектно-ориентированный, а не функциональный язык.
        Ключевое отличие не в этом, а в отсутствии удобного оператора присваивания. Значит ли это, в ФП вообще нет изменяемого состояния? Нет. В ФП языках есть всевозможные уловки, позволяющие работать с изменяемым состоянием. Однако, чтобы сделать это, вам придется совершить определенную церемонию. Изменение состояния выглядит сложным, громоздким и чужеродным в ФП. Это исключительная мера, к которой прибегают лишь изредка и неохотно.

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


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

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

        Если вы хотите использовать полиморфизм в C вам придется работать с указателями вручную и это сложно. Хотите полиморфизм в Lisp: придется передавать функции в качестве аргументов самостоятельно (кстати, это называется паттерном стратегия). Но в объектно-ориентированных языках все это есть из коробки: бери и пользуйся.

        Взаимоисключающие?


        Являются две эти дисциплины взаимоисключающими? Может ли ЯП навязывать дисциплину в присваивании и при работе с указателями на функции. Конечно может! Эти вещи вообще не связаны. Эти парадигмы – не взаимоисключающие. Это значит, что можно писать объектно-ориентированные функциональные программы.

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

        Преимущества полиморфизма


        У полиморфизма всего одно преимущество, но оно значительно. Это инверсия исходного кода и рантайм-зависимостей.

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

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

        Преимущества неизменяемости


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

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

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

        Занудные философствования


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

        Так что там про принципы и паттерны?


        Что вызвало у меня такое раздражение? Первые слайды намекают на то что все принципы и паттерны, разработанные нами за десятилетия работы применимы только для ООП. А в ФП все решается просто функциями.
        Вау, и после этого вы что-то говорите про редукционизм? Идея проста. Принципы остаются неизменными, независимо от стиля программирования. Факт, что вы выбрали ЯП без удобного оператора присвоения, не значит, что вы можете игнорировать SRP или OCP, что эти принципы будут каким-то образом работать автоматически. Если паттерн «Стратегия» использует полиморфизм, это еще не значит, что он не может применяться в функциональном ЯП (например Clojure).

        Итого, ООП работает, если вы знаете, как его готовить. Аналогично для ФП. Функциональные объектно-ориентированные программы – вообще отлично, если вы действительно понимаете, что это значит.
        Original source: habrahabr.ru (comments, light).

        https://habrahabr.ru/post/338136/


        Метки:  

        Wi-Fi сети в ритейле: типовые сценарии и подбор оборудования

        Понедельник, 18 Сентября 2017 г. 10:39 + в цитатник
        TP-Link сегодня в 10:39 Администрирование

        Wi-Fi сети в ритейле: типовые сценарии и подбор оборудования

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

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





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

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

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

          Auranet


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


          Точки доступа CAP300 и EAP225

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





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

          Типовая инфраструктура на оборудовании TP-Link


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

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

          Кстати, в ближайшее время в нашем ассортименте продуктов появится точка доступа CAP1200, поддерживающая протоколы бесшовного роуминга  802.11k и 802.11v, а позже будет добавлена и поддержка  802.11r. С новой точкой доступа подключения станут еще стабильнее, а работа – удобнее.

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

          Среди моделей коммутаторов высоким спросом пользуется TL-SG1008PE, имеющий восемь гигабитных портов с поддержкой PoE+ (до 30 Вт на порт). Эта модель заслужила популярность благодаря невысокой цене, отличному качеству, а также достаточному количеству портов для применения на небольших складах и магазинах. В целом коммутаторы с поддержкой PoE – один из основных компонентов, спрос на которые постоянно растет. Повышенная стоимость PoE-коммутаторов компенсируется  отсутствием необходимости прокладки кабелей питания во все, даже самые далекие места, где устанавливается оборудование, например точки доступа. PoE также используется для питания камер видеонаблюдения, IP-телефонов и множества других устройств, но об этом в другой раз.


          PoE-коммутатор TL-SG1008PE

          Выбор точек доступа и контроллеров


          Основные параметры, которые учитываются при выборе точек доступа, отличаются от проекта к проекту. Первоочередными являются способ подключения питания и поддержка стандартов беспроводной передачи данных. Так, в торговых центрах предпочтительнее выбирать модели с поддержкой PoE и беспроводной сети в диапазоне 5 ГГц. Кроме того, иногда возникают ситуации, когда оборудование 2,4 ГГц мешает уже имеющемуся оборудованию, работающему в этом же диапазоне, например сети датчиков, используемых для отслеживания состояний складских помещений. Тогда приходится ограничиваться использованием сетевого оборудования с поддержкой сети в диапазоне 5 ГГц.

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

          Выбор контроллеров в какой-то степени проще. Здесь либо выбирается программное решение для серии EAP, которое бесплатно и позволяет управлять сотнями точек доступа, либо аппаратные контроллеры серии CAP (AC500 или AC50, поддерживающие до 500 или до 50 точек доступа соответственно).


          Программный контроллер EAP

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


          Wi-Fi контроллер Auranet AC500

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

          Реализованные проекты у наших клиентов


          Не сегодняшний день многие ритейловые компании используют в своих торговых зонах и логистических комплексах наше оборудование, о чем нам периодически сообщают партнеры. Среди них Zenden, Nanolek (склады), Лэтуаль, МЮЗ, Магнит, Перекресток и ряд других. Некоторые из них, опробовав оборудование в пилотных проектах на одной или нескольких собственных площадках, переходят к масштабному внедрению на всех своих точках присутствия.

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

          В одном из недавних проектов пришлось серьезно вложиться в разработку структуры сети именно с учетом непростых условий и геометрии помещений. К счастью, складские зоны, в которых преимущественно располагалась сеть, не везде требовали использования оборудования для наружного размещения, поскольку на складах заказчика поддерживается температура около 20 градусов, хотя есть и холодильные камеры с температурным режимом 4 или 8 градусов. При этом условия по влажности везде были благоприятные и не требовали наличия влагозащиты. В итоге для развертывания сети были выбраны точки доступа EAP225 и ЕАР контроллер для центрального управления. При этом первоначально были опробованы точки ЕАР115, но от них пришлось отказаться из-за работы другого оборудования в том же частотном диапазоне (2,4 ГГц). Компанией использовались различные датчики и устройства для контроля температуры на складе, которые, после установки точек доступа EAP115 стали работать нестабильно.

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

          Другой удачный пример связан с использованием технологии PoE. В одном из недавних проектов наши партнеры столкнулись с ситуацией, когда потолочное расположение точки доступа оказалось возможным лишь при использовании питания по кабелям Ethernet, поскольку подведение отдельной линии питания потребовало бы множества согласований и дополнительных работот. Благодаря PoE удалось существенно ускорить завершение пилотного проекта и значительно упростить дальнейшее обслуживание такого решения. В настоящий момент оборудование по аналогичной схеме установлено уже в 30 магазинах этого заказчика. В ближайшее время они планируют развернуть Wi-Fi сети еще в нескольких сотнях торговых помещений по всей России, используя опыт пилотного проекта, выполненного на точках доступа EAP115 и EAP245 и коммутаторах PoE TL-SG1008PE.


          Точка доступа EAP-115 Wall

          В целом это достаточно простые примеры, которые мы привели скорее для того, чтобы показать, что наш офис также принимает активное участие в работе с клиентами и партнерами. Чаще всего мы консультируем, принимаем фидбек и даже добавляем новые функции в прошивки по отдельным запросам. О чем мы подробно расскажем в одном из следующих постов.
          Original source: habrahabr.ru (comments, light).

          https://habrahabr.ru/post/338010/


          Метки:  

          Wi-Fi сети в ритейле: типовые сценарии и подбор оборудования

          Понедельник, 18 Сентября 2017 г. 10:39 + в цитатник
          TP-Link сегодня в 10:39 Администрирование

          Wi-Fi сети в ритейле: типовые сценарии и подбор оборудования

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

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





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

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

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

            Auranet


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


            Точки доступа CAP300 и EAP225

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





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

            Типовая инфраструктура на оборудовании TP-Link


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

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

            Кстати, в ближайшее время в нашем ассортименте продуктов появится точка доступа CAP1200, поддерживающая протоколы бесшовного роуминга  802.11k и 802.11v, а позже будет добавлена и поддержка  802.11r. С новой точкой доступа подключения станут еще стабильнее, а работа – удобнее.

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

            Среди моделей коммутаторов высоким спросом пользуется TL-SG1008PE, имеющий восемь гигабитных портов с поддержкой PoE+ (до 30 Вт на порт). Эта модель заслужила популярность благодаря невысокой цене, отличному качеству, а также достаточному количеству портов для применения на небольших складах и магазинах. В целом коммутаторы с поддержкой PoE – один из основных компонентов, спрос на которые постоянно растет. Повышенная стоимость PoE-коммутаторов компенсируется  отсутствием необходимости прокладки кабелей питания во все, даже самые далекие места, где устанавливается оборудование, например точки доступа. PoE также используется для питания камер видеонаблюдения, IP-телефонов и множества других устройств, но об этом в другой раз.


            PoE-коммутатор TL-SG1008PE

            Выбор точек доступа и контроллеров


            Основные параметры, которые учитываются при выборе точек доступа, отличаются от проекта к проекту. Первоочередными являются способ подключения питания и поддержка стандартов беспроводной передачи данных. Так, в торговых центрах предпочтительнее выбирать модели с поддержкой PoE и беспроводной сети в диапазоне 5 ГГц. Кроме того, иногда возникают ситуации, когда оборудование 2,4 ГГц мешает уже имеющемуся оборудованию, работающему в этом же диапазоне, например сети датчиков, используемых для отслеживания состояний складских помещений. Тогда приходится ограничиваться использованием сетевого оборудования с поддержкой сети в диапазоне 5 ГГц.

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

            Выбор контроллеров в какой-то степени проще. Здесь либо выбирается программное решение для серии EAP, которое бесплатно и позволяет управлять сотнями точек доступа, либо аппаратные контроллеры серии CAP (AC500 или AC50, поддерживающие до 500 или до 50 точек доступа соответственно).


            Программный контроллер EAP

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


            Wi-Fi контроллер Auranet AC500

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

            Реализованные проекты у наших клиентов


            Не сегодняшний день многие ритейловые компании используют в своих торговых зонах и логистических комплексах наше оборудование, о чем нам периодически сообщают партнеры. Среди них Zenden, Nanolek (склады), Лэтуаль, МЮЗ, Магнит, Перекресток и ряд других. Некоторые из них, опробовав оборудование в пилотных проектах на одной или нескольких собственных площадках, переходят к масштабному внедрению на всех своих точках присутствия.

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

            В одном из недавних проектов пришлось серьезно вложиться в разработку структуры сети именно с учетом непростых условий и геометрии помещений. К счастью, складские зоны, в которых преимущественно располагалась сеть, не везде требовали использования оборудования для наружного размещения, поскольку на складах заказчика поддерживается температура около 20 градусов, хотя есть и холодильные камеры с температурным режимом 4 или 8 градусов. При этом условия по влажности везде были благоприятные и не требовали наличия влагозащиты. В итоге для развертывания сети были выбраны точки доступа EAP225 и ЕАР контроллер для центрального управления. При этом первоначально были опробованы точки ЕАР115, но от них пришлось отказаться из-за работы другого оборудования в том же частотном диапазоне (2,4 ГГц). Компанией использовались различные датчики и устройства для контроля температуры на складе, которые, после установки точек доступа EAP115 стали работать нестабильно.

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

            Другой удачный пример связан с использованием технологии PoE. В одном из недавних проектов наши партнеры столкнулись с ситуацией, когда потолочное расположение точки доступа оказалось возможным лишь при использовании питания по кабелям Ethernet, поскольку подведение отдельной линии питания потребовало бы множества согласований и дополнительных работот. Благодаря PoE удалось существенно ускорить завершение пилотного проекта и значительно упростить дальнейшее обслуживание такого решения. В настоящий момент оборудование по аналогичной схеме установлено уже в 30 магазинах этого заказчика. В ближайшее время они планируют развернуть Wi-Fi сети еще в нескольких сотнях торговых помещений по всей России, используя опыт пилотного проекта, выполненного на точках доступа EAP115 и EAP245 и коммутаторах PoE TL-SG1008PE.


            Точка доступа EAP-115 Wall

            В целом это достаточно простые примеры, которые мы привели скорее для того, чтобы показать, что наш офис также принимает активное участие в работе с клиентами и партнерами. Чаще всего мы консультируем, принимаем фидбек и даже добавляем новые функции в прошивки по отдельным запросам. О чем мы подробно расскажем в одном из следующих постов.
            Original source: habrahabr.ru (comments, light).

            https://habrahabr.ru/post/338010/


            Метки:  

            Wi-Fi сети в ритейле: типовые сценарии и подбор оборудования

            Понедельник, 18 Сентября 2017 г. 10:39 + в цитатник
            TP-Link сегодня в 10:39 Администрирование

            Wi-Fi сети в ритейле: типовые сценарии и подбор оборудования

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

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





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

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

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

              Auranet


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


              Точки доступа CAP300 и EAP225

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





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

              Типовая инфраструктура на оборудовании TP-Link


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

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

              Кстати, в ближайшее время в нашем ассортименте продуктов появится точка доступа CAP1200, поддерживающая протоколы бесшовного роуминга  802.11k и 802.11v, а позже будет добавлена и поддержка  802.11r. С новой точкой доступа подключения станут еще стабильнее, а работа – удобнее.

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

              Среди моделей коммутаторов высоким спросом пользуется TL-SG1008PE, имеющий восемь гигабитных портов с поддержкой PoE+ (до 30 Вт на порт). Эта модель заслужила популярность благодаря невысокой цене, отличному качеству, а также достаточному количеству портов для применения на небольших складах и магазинах. В целом коммутаторы с поддержкой PoE – один из основных компонентов, спрос на которые постоянно растет. Повышенная стоимость PoE-коммутаторов компенсируется  отсутствием необходимости прокладки кабелей питания во все, даже самые далекие места, где устанавливается оборудование, например точки доступа. PoE также используется для питания камер видеонаблюдения, IP-телефонов и множества других устройств, но об этом в другой раз.


              PoE-коммутатор TL-SG1008PE

              Выбор точек доступа и контроллеров


              Основные параметры, которые учитываются при выборе точек доступа, отличаются от проекта к проекту. Первоочередными являются способ подключения питания и поддержка стандартов беспроводной передачи данных. Так, в торговых центрах предпочтительнее выбирать модели с поддержкой PoE и беспроводной сети в диапазоне 5 ГГц. Кроме того, иногда возникают ситуации, когда оборудование 2,4 ГГц мешает уже имеющемуся оборудованию, работающему в этом же диапазоне, например сети датчиков, используемых для отслеживания состояний складских помещений. Тогда приходится ограничиваться использованием сетевого оборудования с поддержкой сети в диапазоне 5 ГГц.

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

              Выбор контроллеров в какой-то степени проще. Здесь либо выбирается программное решение для серии EAP, которое бесплатно и позволяет управлять сотнями точек доступа, либо аппаратные контроллеры серии CAP (AC500 или AC50, поддерживающие до 500 или до 50 точек доступа соответственно).


              Программный контроллер EAP

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


              Wi-Fi контроллер Auranet AC500

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

              Реализованные проекты у наших клиентов


              Не сегодняшний день многие ритейловые компании используют в своих торговых зонах и логистических комплексах наше оборудование, о чем нам периодически сообщают партнеры. Среди них Zenden, Nanolek (склады), Лэтуаль, МЮЗ, Магнит, Перекресток и ряд других. Некоторые из них, опробовав оборудование в пилотных проектах на одной или нескольких собственных площадках, переходят к масштабному внедрению на всех своих точках присутствия.

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

              В одном из недавних проектов пришлось серьезно вложиться в разработку структуры сети именно с учетом непростых условий и геометрии помещений. К счастью, складские зоны, в которых преимущественно располагалась сеть, не везде требовали использования оборудования для наружного размещения, поскольку на складах заказчика поддерживается температура около 20 градусов, хотя есть и холодильные камеры с температурным режимом 4 или 8 градусов. При этом условия по влажности везде были благоприятные и не требовали наличия влагозащиты. В итоге для развертывания сети были выбраны точки доступа EAP225 и ЕАР контроллер для центрального управления. При этом первоначально были опробованы точки ЕАР115, но от них пришлось отказаться из-за работы другого оборудования в том же частотном диапазоне (2,4 ГГц). Компанией использовались различные датчики и устройства для контроля температуры на складе, которые, после установки точек доступа EAP115 стали работать нестабильно.

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

              Другой удачный пример связан с использованием технологии PoE. В одном из недавних проектов наши партнеры столкнулись с ситуацией, когда потолочное расположение точки доступа оказалось возможным лишь при использовании питания по кабелям Ethernet, поскольку подведение отдельной линии питания потребовало бы множества согласований и дополнительных работот. Благодаря PoE удалось существенно ускорить завершение пилотного проекта и значительно упростить дальнейшее обслуживание такого решения. В настоящий момент оборудование по аналогичной схеме установлено уже в 30 магазинах этого заказчика. В ближайшее время они планируют развернуть Wi-Fi сети еще в нескольких сотнях торговых помещений по всей России, используя опыт пилотного проекта, выполненного на точках доступа EAP115 и EAP245 и коммутаторах PoE TL-SG1008PE.


              Точка доступа EAP-115 Wall

              В целом это достаточно простые примеры, которые мы привели скорее для того, чтобы показать, что наш офис также принимает активное участие в работе с клиентами и партнерами. Чаще всего мы консультируем, принимаем фидбек и даже добавляем новые функции в прошивки по отдельным запросам. О чем мы подробно расскажем в одном из следующих постов.
              Original source: habrahabr.ru (comments, light).

              https://habrahabr.ru/post/338010/


              Метки:  

              Индексы в PostgreSQL — 6

              Понедельник, 18 Сентября 2017 г. 10:39 + в цитатник
              erogov сегодня в 10:39 Разработка

              Индексы в PostgreSQL — 6


                Мы уже рассмотрели механизм индексирования PostgreSQL, интерфейс методов доступа и три метода: хеш-индекс, B-дерево и GiST. В этой части речь пойдет о SP-GiST.

                SP-GiST


                Вначале немного о названии. Слово «GiST» намекает на определенную схожесть с одноименным методом. Схожесть действительно есть: и тот, и другой — generalized search trees, обобщенные деревья поиска, предоставляющие каркас для построения разных методов доступа.

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

                SP-GiST подходит для структур, в которых пространство рекурсивно разбивается на непересекающиеся области. В этот класс входят деревья квадрантов (quadtree), k-мерные деревья (k-D tree), префиксные деревья (trie).


                Устройство


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

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

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

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

                Листовые узлы SP-GiST содержат значение индексированного типа и ссылку на строку таблицы (TID). В качестве значения могут использоваться сами индексированные данные (ключ поиска), но не обязательно: может храниться и сокращенное значение.

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

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

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

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

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

                Пример: дерево квадрантов


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

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


                Сначала делим плоскость на четыре квадранта...


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


                И так далее, пока не получим итоговое разбиение.

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



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



                Точки, лежащие на границах, относятся к квадранту с меньшим номером.

                postgres=# create table points(p point);
                CREATE TABLE

                postgres=# insert into points(p) values
                  (point '(1,1)'), (point '(3,2)'), (point '(6,3)'),
                  (point '(5,5)'), (point '(7,8)'), (point '(8,6)');
                INSERT 0 6

                postgres=# create index points_quad_idx on points using spgist(p);
                CREATE INDEX

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

                postgres=# select amop.amopopr::regoperator, amop.amopstrategy
                from pg_opclass opc, pg_opfamily opf, pg_am am, pg_amop amop
                where opc.opcname = 'quad_point_ops'
                and opf.oid = opc.opcfamily
                and am.oid = opf.opfmethod
                and amop.amopfamily = opc.opcfamily
                and am.amname = 'spgist'
                and amop.amoplefttype = opc.opcintype;
                     amopopr     | amopstrategy
                -----------------+--------------
                 <<(point,point) |            1  строго слева
                 >>(point,point) |            5  строго справа
                 ~=(point,point) |            6  совпадает
                 <^(point,point) |           10  строго сверху
                 >^(point,point) |           11  строго снизу
                 <@(point,box)   |            8  содержится в прямоугольнике
                (6 rows)

                Рассмотрим, например, как будет выполняться запрос select * from points where p >^ point '(2,7)' (найти все точки, лежащие выше заданной).



                Начинаем с корневого узла и выбираем, в какие дочерние узлы надо спускаться с помощью функции согласованности. Для оператора >^ эта функция сравнивает точку (2,7) с центральной точкой узла (4,4) и выбирает квадранты, в которых могут находиться искомые точки — в данном случае первый и четвертый.

                В узле, соответствующем первому квадранту, снова определяем дочерние узлы с помощью функции согласованности. Центральная точка (6,6), и нам снова требуется просмотреть первый и четвертый квадранты.



                Первому квадранту соответствует список листовых узлов (8,6) и (7,8), из которых под условие запроса подходит только точка (7,8). Ссылка на четвертый квадрант пуста.

                У внутреннего узла (4,4) ссылка на четвертый квадрант также пуста, и на этом писк завершен.

                postgres=# set enable_seqscan = off;
                SET
                postgres=# explain (costs off) select * from points where p >^ point '(2,7)';
                                   QUERY PLAN                  
                ------------------------------------------------
                 Index Only Scan using points_quad_idx on points
                   Index Cond: (p >^ '(2,7)'::point)
                (2 rows)

                Внутри


                Внутреннее устройство индексов SP-GiST можно изучать с помощью расширения gevel, про которое мы уже говорили ранее. Плохая новость: из-за ошибки расширение некорректно работает на современных версиях PostgreSQL. Хорошая новость: мы планируем перенести функциональность gevel в pageinspect (обсуждение). И ошибка там уже исправлена.

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

                demo=# create index airports_coordinates_quad_idx on airports_ml using spgist(coordinates);
                CREATE INDEX

                Об индексе можно, во-первых, узнать некоторую статистическую информацию:

                demo=# select * from spgist_stats('airports_coordinates_quad_idx');
                           spgist_stats          
                ----------------------------------
                 totalPages:        33           +
                 deletedPages:      0            +
                 innerPages:        3            +
                 leafPages:         30           +
                 emptyPages:        2            +
                 usedSpace:         201.53 kbytes+
                 usedInnerSpace:    2.17 kbytes  +
                 usedLeafSpace:     199.36 kbytes+
                 freeSpace:         61.44 kbytes +
                 fillRatio:         76.64%       +
                 leafTuples:        5993         +
                 innerTuples:       37           +
                 innerAllTheSame:   0            +
                 leafPlaceholders:  725          +
                 innerPlaceholders: 0            +
                 leafRedirects:     0            +
                 innerRedirects:    0
                (1 row)

                И во-вторых, вывести само дерево индекса:

                demo=# select tid, n, level, tid_ptr, prefix, leaf_value
                from spgist_print('airports_coordinates_quad_idx') as t(
                  tid tid,
                  allthesame bool,
                  n int,
                  level int,
                  tid_ptr tid,
                  prefix point,    -- тип префикса
                  node_label int,  -- тип метки (в данном случае не используется)
                  leaf_value point -- тип листового значения
                )
                order by tid, n;
                   tid   | n | level | tid_ptr |      prefix      |    leaf_value
                ---------+---+-------+---------+------------------+------------------
                 (1,1)   | 0 |     1 | (5,3)   | (-10.220,53.588) |
                 (1,1)   | 1 |     1 | (5,2)   | (-10.220,53.588) |
                 (1,1)   | 2 |     1 | (5,1)   | (-10.220,53.588) |
                 (1,1)   | 3 |     1 | (5,14)  | (-10.220,53.588) |
                 (3,68)  |   |     3 |         |                  | (86.107,55.270)
                 (3,70)  |   |     3 |         |                  | (129.771,62.093)
                 (3,85)  |   |     4 |         |                  | (57.684,-20.430)
                 (3,122) |   |     4 |         |                  | (107.438,51.808)
                 (3,154) |   |     3 |         |                  | (-51.678,64.191)
                 (5,1)   | 0 |     2 | (24,27) | (-88.680,48.638) |
                 (5,1)   | 1 |     2 | (5,7)   | (-88.680,48.638) |
                 ...

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

                Пример: k-мерные деревья


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

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

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

                Метод легко обобщается на k-мерные пространства, поэтому и деревья в литературе называются k-мерным (k-D tree).

                На примере аэропортов:


                Сначала делим плоскость на верх и низ...


                Затем каждую часть на лево и право...


                И так далее, пока не получим итоговое разбиение.

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

                postgres=# create index points_kd_idx on points using spgist(p kd_point_ops);
                CREATE INDEX


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

                Внутри


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

                demo=# select tid, n, level, tid_ptr, prefix, leaf_value
                from spgist_print('airports_coordinates_kd_idx') as t(
                  tid tid,
                  allthesame bool,
                  n int,
                  level int,
                  tid_ptr tid,
                  prefix float,    -- тип префикса
                  node_label int,  -- тип метки (в данном случае не используется)
                  leaf_value point -- тип листового значения
                )
                order by tid, n;
                   tid   | n | level | tid_ptr |   prefix   |    leaf_value
                ---------+---+-------+---------+------------+------------------
                 (1,1)   | 0 |     1 | (5,1)   |     53.740 |
                 (1,1)   | 1 |     1 | (5,4)   |     53.740 |
                 (3,113) |   |     6 |         |            | (-7.277,62.064)
                 (3,114) |   |     6 |         |            | (-85.033,73.006)
                 (5,1)   | 0 |     2 | (5,12)  |    -65.449 |
                 (5,1)   | 1 |     2 | (5,2)   |    -65.449 |
                 (5,2)   | 0 |     3 | (5,6)   |     35.624 |
                 (5,2)   | 1 |     3 | (5,3)   |     35.624 |
                 ...


                Пример: префиксное дерево


                С помощью SP-GiST можно реализовать и префиксное дерево (radix tree) для строк. Идея префиксного дерева в том, что индексируемая строка не хранится целиком в листовом узле, а получается конкатенацией значений, хранящихся в узлах вверх от данного до корня.

                Допустим, надо проиндексировать адреса сайтов: «postgrespro.ru», «postgrespro.com», «postgresql.org» и «planet.postgresql.org».

                postgres=# create table sites(url text);
                CREATE TABLE

                postgres=# insert into sites values ('postgrespro.ru'),('postgrespro.com'),('postgresql.org'),('planet.postgresql.org');
                INSERT 0 4

                postgres=# create index on sites using spgist(url);
                CREATE INDEX

                Дерево будет иметь следующий вид:



                Во внутренних узлах дерева хранятся префиксы, общие для всех дочерних узлов. Например, в дочках узла «stgres» значения начинаются на «p» + «o» + «stgres».

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

                Класс операторов text_ops поддерживает операторы, традиционные для b-tree: «равно», «больше», «меньше»:

                postgres=# select amop.amopopr::regoperator, amop.amopstrategy
                from pg_opclass opc, pg_opfamily opf, pg_am am, pg_amop amop
                where opc.opcname = 'text_ops'
                and opf.oid = opc.opcfamily
                and am.oid = opf.opfmethod
                and amop.amopfamily = opc.opcfamily
                and am.amname = 'spgist'
                and amop.amoplefttype = opc.opcintype;
                     amopopr     | amopstrategy
                -----------------+--------------
                 ~<~(text,text)  |            1
                 ~<=~(text,text) |            2
                 =(text,text)    |            3
                 ~>=~(text,text) |            4
                 ~>~(text,text)  |            5
                 <(text,text)    |           11
                 <=(text,text)   |           12
                 >=(text,text)   |           14
                 >(text,text)    |           15
                (9 rows)

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

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

                Рассмотрим запрос: select * from sites where url like 'postgresp%ru'. Он может быть выполнен с помощью индекса:

                postgres=# explain (costs off) select * from sites where url like 'postgresp%ru';
                                                  QUERY PLAN                                  
                ------------------------------------------------------------------------------
                 Index Only Scan using sites_url_idx on sites
                   Index Cond: ((url ~>=~ 'postgresp'::text) AND (url ~<~ 'postgresq'::text))
                   Filter: (url ~~ 'postgresp%ru'::text)
                (3 rows)

                Фактически по индексу находятся значения, большие или равные «postgresp» и в то же время меньшие «postgresq» (Index Cond), а затем из результата отбираются подходящие значения (Filter).

                Сначала функция согласованности должна решить, в какие дочерние узлы корня «p» нужно спуститься. Есть два варианта: «p» + «l» (не подходит, даже не заглядывая дальше) и «p» + «o» + «stgres» (подходит).

                Для узла «stgres» снова требуется обращение к функции согласованности, чтобы проверить «postgres» + «p» + «ro.» (подходит) и «postgres» + «q» (не подходит).

                Для узла «ro.» и всех его дочерних листовых узлов функции согласованности ответит «подходит», так что индексный метод вернет два значения: «postgrespro.com» и «postgrespro.ru». Из них — уже на этапе фильтрации — будет выбрано одно подходящее значение.



                Внутри


                При просмотре структуры дерева надо учесть типы данных:

                postgres=# select * from spgist_print('sites_url_idx') as t(
                  tid tid,
                  allthesame bool,
                  n int,
                  level int,
                  tid_ptr tid,
                  prefix text,         -- тип префикса
                  node_label smallint, -- тип метки
                  leaf_value text      -- тип листового значения
                )
                order by tid, n;

                Свойства


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

                 amname |     name      | pg_indexam_has_property
                --------+---------------+-------------------------
                 spgist | can_order     | f
                 spgist | can_unique    | f
                 spgist | can_multi_col | f
                 spgist | can_exclude   | t


                Индксы SP-GiST не могут использоваться для сортировки и поддержки уникальности. Кроме того, такие индексы нельзя строить по нескольким столбцам (в отличие от GiST). Использование для поддержки ограничений исключения допускается.

                Свойства индекса:

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

                Здесь отличие от GiST состоит в отсутствии возможности кластеризации.

                И, наконец, свойства уровня столбца:

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

                Поддержки сортировки нет, что понятно. Операторы расстояния для поиска ближайших соседей в SP-GiST пока не доступны; скорее всего такая поддержка появится в будущем.

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

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


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

                postgres=# explain (costs off)
                select * from sites where url is null;
                                  QUERY PLAN                  
                ----------------------------------------------
                 Index Only Scan using sites_url_idx on sites
                   Index Cond: (url IS NULL)
                (2 rows)

                Однако неопределенное значение для SP-GiST — нечто чужеродное. Все операторы, входящие в класс операторов метода spgist, должны быть строгими: для неопределенных параметров они должны возвращать неопределенный результат. Это обеспечивает сам метод; неопределенные значения просто не передаются операторам.

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

                Другие типы данных


                Помимо точек и префиксных деревьев для строк, в PostgreSQL реализованы и другие методы на основе SP-GiST:

                • Дерево квадрантов для прямоугольников обеспечивает класс операторов box_ops.
                  Каждый прямоугольник представляется точкой в четырехмерном пространстве, так что число квадрантов равно 16. Такой индекс может выиграть у GiST по производительности, когда среди прямоугольников много пересечений: в GiST невозможно провести границы так, чтобы отделить пересекающиеся объекты друг от друга, а вот с точками (пусть и четырехмерными) таких проблем нет.
                • Дерево квадрантов для диапазонов предоставляет класс операторов range_ops.
                  Интервал представляется двумерной точкой: нижняя граница становится абсциссой, а верхняя — ординатой.


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

                https://habrahabr.ru/post/337502/


                Метки:  

                Индексы в PostgreSQL — 6

                Понедельник, 18 Сентября 2017 г. 10:39 + в цитатник
                erogov сегодня в 10:39 Разработка

                Индексы в PostgreSQL — 6


                  Мы уже рассмотрели механизм индексирования PostgreSQL, интерфейс методов доступа и три метода: хеш-индекс, B-дерево и GiST. В этой части речь пойдет о SP-GiST.

                  SP-GiST


                  Вначале немного о названии. Слово «GiST» намекает на определенную схожесть с одноименным методом. Схожесть действительно есть: и тот, и другой — generalized search trees, обобщенные деревья поиска, предоставляющие каркас для построения разных методов доступа.

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

                  SP-GiST подходит для структур, в которых пространство рекурсивно разбивается на непересекающиеся области. В этот класс входят деревья квадрантов (quadtree), k-мерные деревья (k-D tree), префиксные деревья (trie).


                  Устройство


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

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

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

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

                  Листовые узлы SP-GiST содержат значение индексированного типа и ссылку на строку таблицы (TID). В качестве значения могут использоваться сами индексированные данные (ключ поиска), но не обязательно: может храниться и сокращенное значение.

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

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

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

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

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

                  Пример: дерево квадрантов


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

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


                  Сначала делим плоскость на четыре квадранта...


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


                  И так далее, пока не получим итоговое разбиение.

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



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



                  Точки, лежащие на границах, относятся к квадранту с меньшим номером.

                  postgres=# create table points(p point);
                  CREATE TABLE

                  postgres=# insert into points(p) values
                    (point '(1,1)'), (point '(3,2)'), (point '(6,3)'),
                    (point '(5,5)'), (point '(7,8)'), (point '(8,6)');
                  INSERT 0 6

                  postgres=# create index points_quad_idx on points using spgist(p);
                  CREATE INDEX

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

                  postgres=# select amop.amopopr::regoperator, amop.amopstrategy
                  from pg_opclass opc, pg_opfamily opf, pg_am am, pg_amop amop
                  where opc.opcname = 'quad_point_ops'
                  and opf.oid = opc.opcfamily
                  and am.oid = opf.opfmethod
                  and amop.amopfamily = opc.opcfamily
                  and am.amname = 'spgist'
                  and amop.amoplefttype = opc.opcintype;
                       amopopr     | amopstrategy
                  -----------------+--------------
                   <<(point,point) |            1  строго слева
                   >>(point,point) |            5  строго справа
                   ~=(point,point) |            6  совпадает
                   <^(point,point) |           10  строго сверху
                   >^(point,point) |           11  строго снизу
                   <@(point,box)   |            8  содержится в прямоугольнике
                  (6 rows)

                  Рассмотрим, например, как будет выполняться запрос select * from points where p >^ point '(2,7)' (найти все точки, лежащие выше заданной).



                  Начинаем с корневого узла и выбираем, в какие дочерние узлы надо спускаться с помощью функции согласованности. Для оператора >^ эта функция сравнивает точку (2,7) с центральной точкой узла (4,4) и выбирает квадранты, в которых могут находиться искомые точки — в данном случае первый и четвертый.

                  В узле, соответствующем первому квадранту, снова определяем дочерние узлы с помощью функции согласованности. Центральная точка (6,6), и нам снова требуется просмотреть первый и четвертый квадранты.



                  Первому квадранту соответствует список листовых узлов (8,6) и (7,8), из которых под условие запроса подходит только точка (7,8). Ссылка на четвертый квадрант пуста.

                  У внутреннего узла (4,4) ссылка на четвертый квадрант также пуста, и на этом писк завершен.

                  postgres=# set enable_seqscan = off;
                  SET
                  postgres=# explain (costs off) select * from points where p >^ point '(2,7)';
                                     QUERY PLAN                  
                  ------------------------------------------------
                   Index Only Scan using points_quad_idx on points
                     Index Cond: (p >^ '(2,7)'::point)
                  (2 rows)

                  Внутри


                  Внутреннее устройство индексов SP-GiST можно изучать с помощью расширения gevel, про которое мы уже говорили ранее. Плохая новость: из-за ошибки расширение некорректно работает на современных версиях PostgreSQL. Хорошая новость: мы планируем перенести функциональность gevel в pageinspect (обсуждение). И ошибка там уже исправлена.

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

                  demo=# create index airports_coordinates_quad_idx on airports_ml using spgist(coordinates);
                  CREATE INDEX

                  Об индексе можно, во-первых, узнать некоторую статистическую информацию:

                  demo=# select * from spgist_stats('airports_coordinates_quad_idx');
                             spgist_stats          
                  ----------------------------------
                   totalPages:        33           +
                   deletedPages:      0            +
                   innerPages:        3            +
                   leafPages:         30           +
                   emptyPages:        2            +
                   usedSpace:         201.53 kbytes+
                   usedInnerSpace:    2.17 kbytes  +
                   usedLeafSpace:     199.36 kbytes+
                   freeSpace:         61.44 kbytes +
                   fillRatio:         76.64%       +
                   leafTuples:        5993         +
                   innerTuples:       37           +
                   innerAllTheSame:   0            +
                   leafPlaceholders:  725          +
                   innerPlaceholders: 0            +
                   leafRedirects:     0            +
                   innerRedirects:    0
                  (1 row)

                  И во-вторых, вывести само дерево индекса:

                  demo=# select tid, n, level, tid_ptr, prefix, leaf_value
                  from spgist_print('airports_coordinates_quad_idx') as t(
                    tid tid,
                    allthesame bool,
                    n int,
                    level int,
                    tid_ptr tid,
                    prefix point,    -- тип префикса
                    node_label int,  -- тип метки (в данном случае не используется)
                    leaf_value point -- тип листового значения
                  )
                  order by tid, n;
                     tid   | n | level | tid_ptr |      prefix      |    leaf_value
                  ---------+---+-------+---------+------------------+------------------
                   (1,1)   | 0 |     1 | (5,3)   | (-10.220,53.588) |
                   (1,1)   | 1 |     1 | (5,2)   | (-10.220,53.588) |
                   (1,1)   | 2 |     1 | (5,1)   | (-10.220,53.588) |
                   (1,1)   | 3 |     1 | (5,14)  | (-10.220,53.588) |
                   (3,68)  |   |     3 |         |                  | (86.107,55.270)
                   (3,70)  |   |     3 |         |                  | (129.771,62.093)
                   (3,85)  |   |     4 |         |                  | (57.684,-20.430)
                   (3,122) |   |     4 |         |                  | (107.438,51.808)
                   (3,154) |   |     3 |         |                  | (-51.678,64.191)
                   (5,1)   | 0 |     2 | (24,27) | (-88.680,48.638) |
                   (5,1)   | 1 |     2 | (5,7)   | (-88.680,48.638) |
                   ...

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

                  Пример: k-мерные деревья


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

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

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

                  Метод легко обобщается на k-мерные пространства, поэтому и деревья в литературе называются k-мерным (k-D tree).

                  На примере аэропортов:


                  Сначала делим плоскость на верх и низ...


                  Затем каждую часть на лево и право...


                  И так далее, пока не получим итоговое разбиение.

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

                  postgres=# create index points_kd_idx on points using spgist(p kd_point_ops);
                  CREATE INDEX


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

                  Внутри


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

                  demo=# select tid, n, level, tid_ptr, prefix, leaf_value
                  from spgist_print('airports_coordinates_kd_idx') as t(
                    tid tid,
                    allthesame bool,
                    n int,
                    level int,
                    tid_ptr tid,
                    prefix float,    -- тип префикса
                    node_label int,  -- тип метки (в данном случае не используется)
                    leaf_value point -- тип листового значения
                  )
                  order by tid, n;
                     tid   | n | level | tid_ptr |   prefix   |    leaf_value
                  ---------+---+-------+---------+------------+------------------
                   (1,1)   | 0 |     1 | (5,1)   |     53.740 |
                   (1,1)   | 1 |     1 | (5,4)   |     53.740 |
                   (3,113) |   |     6 |         |            | (-7.277,62.064)
                   (3,114) |   |     6 |         |            | (-85.033,73.006)
                   (5,1)   | 0 |     2 | (5,12)  |    -65.449 |
                   (5,1)   | 1 |     2 | (5,2)   |    -65.449 |
                   (5,2)   | 0 |     3 | (5,6)   |     35.624 |
                   (5,2)   | 1 |     3 | (5,3)   |     35.624 |
                   ...


                  Пример: префиксное дерево


                  С помощью SP-GiST можно реализовать и префиксное дерево (radix tree) для строк. Идея префиксного дерева в том, что индексируемая строка не хранится целиком в листовом узле, а получается конкатенацией значений, хранящихся в узлах вверх от данного до корня.

                  Допустим, надо проиндексировать адреса сайтов: «postgrespro.ru», «postgrespro.com», «postgresql.org» и «planet.postgresql.org».

                  postgres=# create table sites(url text);
                  CREATE TABLE

                  postgres=# insert into sites values ('postgrespro.ru'),('postgrespro.com'),('postgresql.org'),('planet.postgresql.org');
                  INSERT 0 4

                  postgres=# create index on sites using spgist(url);
                  CREATE INDEX

                  Дерево будет иметь следующий вид:



                  Во внутренних узлах дерева хранятся префиксы, общие для всех дочерних узлов. Например, в дочках узла «stgres» значения начинаются на «p» + «o» + «stgres».

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

                  Класс операторов text_ops поддерживает операторы, традиционные для b-tree: «равно», «больше», «меньше»:

                  postgres=# select amop.amopopr::regoperator, amop.amopstrategy
                  from pg_opclass opc, pg_opfamily opf, pg_am am, pg_amop amop
                  where opc.opcname = 'text_ops'
                  and opf.oid = opc.opcfamily
                  and am.oid = opf.opfmethod
                  and amop.amopfamily = opc.opcfamily
                  and am.amname = 'spgist'
                  and amop.amoplefttype = opc.opcintype;
                       amopopr     | amopstrategy
                  -----------------+--------------
                   ~<~(text,text)  |            1
                   ~<=~(text,text) |            2
                   =(text,text)    |            3
                   ~>=~(text,text) |            4
                   ~>~(text,text)  |            5
                   <(text,text)    |           11
                   <=(text,text)   |           12
                   >=(text,text)   |           14
                   >(text,text)    |           15
                  (9 rows)

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

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

                  Рассмотрим запрос: select * from sites where url like 'postgresp%ru'. Он может быть выполнен с помощью индекса:

                  postgres=# explain (costs off) select * from sites where url like 'postgresp%ru';
                                                    QUERY PLAN                                  
                  ------------------------------------------------------------------------------
                   Index Only Scan using sites_url_idx on sites
                     Index Cond: ((url ~>=~ 'postgresp'::text) AND (url ~<~ 'postgresq'::text))
                     Filter: (url ~~ 'postgresp%ru'::text)
                  (3 rows)

                  Фактически по индексу находятся значения, большие или равные «postgresp» и в то же время меньшие «postgresq» (Index Cond), а затем из результата отбираются подходящие значения (Filter).

                  Сначала функция согласованности должна решить, в какие дочерние узлы корня «p» нужно спуститься. Есть два варианта: «p» + «l» (не подходит, даже не заглядывая дальше) и «p» + «o» + «stgres» (подходит).

                  Для узла «stgres» снова требуется обращение к функции согласованности, чтобы проверить «postgres» + «p» + «ro.» (подходит) и «postgres» + «q» (не подходит).

                  Для узла «ro.» и всех его дочерних листовых узлов функции согласованности ответит «подходит», так что индексный метод вернет два значения: «postgrespro.com» и «postgrespro.ru». Из них — уже на этапе фильтрации — будет выбрано одно подходящее значение.



                  Внутри


                  При просмотре структуры дерева надо учесть типы данных:

                  postgres=# select * from spgist_print('sites_url_idx') as t(
                    tid tid,
                    allthesame bool,
                    n int,
                    level int,
                    tid_ptr tid,
                    prefix text,         -- тип префикса
                    node_label smallint, -- тип метки
                    leaf_value text      -- тип листового значения
                  )
                  order by tid, n;

                  Свойства


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

                   amname |     name      | pg_indexam_has_property
                  --------+---------------+-------------------------
                   spgist | can_order     | f
                   spgist | can_unique    | f
                   spgist | can_multi_col | f
                   spgist | can_exclude   | t


                  Индксы SP-GiST не могут использоваться для сортировки и поддержки уникальности. Кроме того, такие индексы нельзя строить по нескольким столбцам (в отличие от GiST). Использование для поддержки ограничений исключения допускается.

                  Свойства индекса:

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

                  Здесь отличие от GiST состоит в отсутствии возможности кластеризации.

                  И, наконец, свойства уровня столбца:

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

                  Поддержки сортировки нет, что понятно. Операторы расстояния для поиска ближайших соседей в SP-GiST пока не доступны; скорее всего такая поддержка появится в будущем.

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

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


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

                  postgres=# explain (costs off)
                  select * from sites where url is null;
                                    QUERY PLAN                  
                  ----------------------------------------------
                   Index Only Scan using sites_url_idx on sites
                     Index Cond: (url IS NULL)
                  (2 rows)

                  Однако неопределенное значение для SP-GiST — нечто чужеродное. Все операторы, входящие в класс операторов метода spgist, должны быть строгими: для неопределенных параметров они должны возвращать неопределенный результат. Это обеспечивает сам метод; неопределенные значения просто не передаются операторам.

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

                  Другие типы данных


                  Помимо точек и префиксных деревьев для строк, в PostgreSQL реализованы и другие методы на основе SP-GiST:

                  • Дерево квадрантов для прямоугольников обеспечивает класс операторов box_ops.
                    Каждый прямоугольник представляется точкой в четырехмерном пространстве, так что число квадрантов равно 16. Такой индекс может выиграть у GiST по производительности, когда среди прямоугольников много пересечений: в GiST невозможно провести границы так, чтобы отделить пересекающиеся объекты друг от друга, а вот с точками (пусть и четырехмерными) таких проблем нет.
                  • Дерево квадрантов для диапазонов предоставляет класс операторов range_ops.
                    Интервал представляется двумерной точкой: нижняя граница становится абсциссой, а верхняя — ординатой.


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

                  https://habrahabr.ru/post/337502/


                  Метки:  

                  Индексы в PostgreSQL — 6

                  Понедельник, 18 Сентября 2017 г. 10:39 + в цитатник
                  erogov сегодня в 10:39 Разработка

                  Индексы в PostgreSQL — 6


                    Мы уже рассмотрели механизм индексирования PostgreSQL, интерфейс методов доступа и три метода: хеш-индекс, B-дерево и GiST. В этой части речь пойдет о SP-GiST.

                    SP-GiST


                    Вначале немного о названии. Слово «GiST» намекает на определенную схожесть с одноименным методом. Схожесть действительно есть: и тот, и другой — generalized search trees, обобщенные деревья поиска, предоставляющие каркас для построения разных методов доступа.

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

                    SP-GiST подходит для структур, в которых пространство рекурсивно разбивается на непересекающиеся области. В этот класс входят деревья квадрантов (quadtree), k-мерные деревья (k-D tree), префиксные деревья (trie).


                    Устройство


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

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

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

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

                    Листовые узлы SP-GiST содержат значение индексированного типа и ссылку на строку таблицы (TID). В качестве значения могут использоваться сами индексированные данные (ключ поиска), но не обязательно: может храниться и сокращенное значение.

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

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

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

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

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

                    Пример: дерево квадрантов


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

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


                    Сначала делим плоскость на четыре квадранта...


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


                    И так далее, пока не получим итоговое разбиение.

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



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



                    Точки, лежащие на границах, относятся к квадранту с меньшим номером.

                    postgres=# create table points(p point);
                    CREATE TABLE

                    postgres=# insert into points(p) values
                      (point '(1,1)'), (point '(3,2)'), (point '(6,3)'),
                      (point '(5,5)'), (point '(7,8)'), (point '(8,6)');
                    INSERT 0 6

                    postgres=# create index points_quad_idx on points using spgist(p);
                    CREATE INDEX

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

                    postgres=# select amop.amopopr::regoperator, amop.amopstrategy
                    from pg_opclass opc, pg_opfamily opf, pg_am am, pg_amop amop
                    where opc.opcname = 'quad_point_ops'
                    and opf.oid = opc.opcfamily
                    and am.oid = opf.opfmethod
                    and amop.amopfamily = opc.opcfamily
                    and am.amname = 'spgist'
                    and amop.amoplefttype = opc.opcintype;
                         amopopr     | amopstrategy
                    -----------------+--------------
                     <<(point,point) |            1  строго слева
                     >>(point,point) |            5  строго справа
                     ~=(point,point) |            6  совпадает
                     <^(point,point) |           10  строго сверху
                     >^(point,point) |           11  строго снизу
                     <@(point,box)   |            8  содержится в прямоугольнике
                    (6 rows)

                    Рассмотрим, например, как будет выполняться запрос select * from points where p >^ point '(2,7)' (найти все точки, лежащие выше заданной).



                    Начинаем с корневого узла и выбираем, в какие дочерние узлы надо спускаться с помощью функции согласованности. Для оператора >^ эта функция сравнивает точку (2,7) с центральной точкой узла (4,4) и выбирает квадранты, в которых могут находиться искомые точки — в данном случае первый и четвертый.

                    В узле, соответствующем первому квадранту, снова определяем дочерние узлы с помощью функции согласованности. Центральная точка (6,6), и нам снова требуется просмотреть первый и четвертый квадранты.



                    Первому квадранту соответствует список листовых узлов (8,6) и (7,8), из которых под условие запроса подходит только точка (7,8). Ссылка на четвертый квадрант пуста.

                    У внутреннего узла (4,4) ссылка на четвертый квадрант также пуста, и на этом писк завершен.

                    postgres=# set enable_seqscan = off;
                    SET
                    postgres=# explain (costs off) select * from points where p >^ point '(2,7)';
                                       QUERY PLAN                  
                    ------------------------------------------------
                     Index Only Scan using points_quad_idx on points
                       Index Cond: (p >^ '(2,7)'::point)
                    (2 rows)

                    Внутри


                    Внутреннее устройство индексов SP-GiST можно изучать с помощью расширения gevel, про которое мы уже говорили ранее. Плохая новость: из-за ошибки расширение некорректно работает на современных версиях PostgreSQL. Хорошая новость: мы планируем перенести функциональность gevel в pageinspect (обсуждение). И ошибка там уже исправлена.

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

                    demo=# create index airports_coordinates_quad_idx on airports_ml using spgist(coordinates);
                    CREATE INDEX

                    Об индексе можно, во-первых, узнать некоторую статистическую информацию:

                    demo=# select * from spgist_stats('airports_coordinates_quad_idx');
                               spgist_stats          
                    ----------------------------------
                     totalPages:        33           +
                     deletedPages:      0            +
                     innerPages:        3            +
                     leafPages:         30           +
                     emptyPages:        2            +
                     usedSpace:         201.53 kbytes+
                     usedInnerSpace:    2.17 kbytes  +
                     usedLeafSpace:     199.36 kbytes+
                     freeSpace:         61.44 kbytes +
                     fillRatio:         76.64%       +
                     leafTuples:        5993         +
                     innerTuples:       37           +
                     innerAllTheSame:   0            +
                     leafPlaceholders:  725          +
                     innerPlaceholders: 0            +
                     leafRedirects:     0            +
                     innerRedirects:    0
                    (1 row)

                    И во-вторых, вывести само дерево индекса:

                    demo=# select tid, n, level, tid_ptr, prefix, leaf_value
                    from spgist_print('airports_coordinates_quad_idx') as t(
                      tid tid,
                      allthesame bool,
                      n int,
                      level int,
                      tid_ptr tid,
                      prefix point,    -- тип префикса
                      node_label int,  -- тип метки (в данном случае не используется)
                      leaf_value point -- тип листового значения
                    )
                    order by tid, n;
                       tid   | n | level | tid_ptr |      prefix      |    leaf_value
                    ---------+---+-------+---------+------------------+------------------
                     (1,1)   | 0 |     1 | (5,3)   | (-10.220,53.588) |
                     (1,1)   | 1 |     1 | (5,2)   | (-10.220,53.588) |
                     (1,1)   | 2 |     1 | (5,1)   | (-10.220,53.588) |
                     (1,1)   | 3 |     1 | (5,14)  | (-10.220,53.588) |
                     (3,68)  |   |     3 |         |                  | (86.107,55.270)
                     (3,70)  |   |     3 |         |                  | (129.771,62.093)
                     (3,85)  |   |     4 |         |                  | (57.684,-20.430)
                     (3,122) |   |     4 |         |                  | (107.438,51.808)
                     (3,154) |   |     3 |         |                  | (-51.678,64.191)
                     (5,1)   | 0 |     2 | (24,27) | (-88.680,48.638) |
                     (5,1)   | 1 |     2 | (5,7)   | (-88.680,48.638) |
                     ...

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

                    Пример: k-мерные деревья


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

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

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

                    Метод легко обобщается на k-мерные пространства, поэтому и деревья в литературе называются k-мерным (k-D tree).

                    На примере аэропортов:


                    Сначала делим плоскость на верх и низ...


                    Затем каждую часть на лево и право...


                    И так далее, пока не получим итоговое разбиение.

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

                    postgres=# create index points_kd_idx on points using spgist(p kd_point_ops);
                    CREATE INDEX


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

                    Внутри


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

                    demo=# select tid, n, level, tid_ptr, prefix, leaf_value
                    from spgist_print('airports_coordinates_kd_idx') as t(
                      tid tid,
                      allthesame bool,
                      n int,
                      level int,
                      tid_ptr tid,
                      prefix float,    -- тип префикса
                      node_label int,  -- тип метки (в данном случае не используется)
                      leaf_value point -- тип листового значения
                    )
                    order by tid, n;
                       tid   | n | level | tid_ptr |   prefix   |    leaf_value
                    ---------+---+-------+---------+------------+------------------
                     (1,1)   | 0 |     1 | (5,1)   |     53.740 |
                     (1,1)   | 1 |     1 | (5,4)   |     53.740 |
                     (3,113) |   |     6 |         |            | (-7.277,62.064)
                     (3,114) |   |     6 |         |            | (-85.033,73.006)
                     (5,1)   | 0 |     2 | (5,12)  |    -65.449 |
                     (5,1)   | 1 |     2 | (5,2)   |    -65.449 |
                     (5,2)   | 0 |     3 | (5,6)   |     35.624 |
                     (5,2)   | 1 |     3 | (5,3)   |     35.624 |
                     ...


                    Пример: префиксное дерево


                    С помощью SP-GiST можно реализовать и префиксное дерево (radix tree) для строк. Идея префиксного дерева в том, что индексируемая строка не хранится целиком в листовом узле, а получается конкатенацией значений, хранящихся в узлах вверх от данного до корня.

                    Допустим, надо проиндексировать адреса сайтов: «postgrespro.ru», «postgrespro.com», «postgresql.org» и «planet.postgresql.org».

                    postgres=# create table sites(url text);
                    CREATE TABLE

                    postgres=# insert into sites values ('postgrespro.ru'),('postgrespro.com'),('postgresql.org'),('planet.postgresql.org');
                    INSERT 0 4

                    postgres=# create index on sites using spgist(url);
                    CREATE INDEX

                    Дерево будет иметь следующий вид:



                    Во внутренних узлах дерева хранятся префиксы, общие для всех дочерних узлов. Например, в дочках узла «stgres» значения начинаются на «p» + «o» + «stgres».

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

                    Класс операторов text_ops поддерживает операторы, традиционные для b-tree: «равно», «больше», «меньше»:

                    postgres=# select amop.amopopr::regoperator, amop.amopstrategy
                    from pg_opclass opc, pg_opfamily opf, pg_am am, pg_amop amop
                    where opc.opcname = 'text_ops'
                    and opf.oid = opc.opcfamily
                    and am.oid = opf.opfmethod
                    and amop.amopfamily = opc.opcfamily
                    and am.amname = 'spgist'
                    and amop.amoplefttype = opc.opcintype;
                         amopopr     | amopstrategy
                    -----------------+--------------
                     ~<~(text,text)  |            1
                     ~<=~(text,text) |            2
                     =(text,text)    |            3
                     ~>=~(text,text) |            4
                     ~>~(text,text)  |            5
                     <(text,text)    |           11
                     <=(text,text)   |           12
                     >=(text,text)   |           14
                     >(text,text)    |           15
                    (9 rows)

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

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

                    Рассмотрим запрос: select * from sites where url like 'postgresp%ru'. Он может быть выполнен с помощью индекса:

                    postgres=# explain (costs off) select * from sites where url like 'postgresp%ru';
                                                      QUERY PLAN                                  
                    ------------------------------------------------------------------------------
                     Index Only Scan using sites_url_idx on sites
                       Index Cond: ((url ~>=~ 'postgresp'::text) AND (url ~<~ 'postgresq'::text))
                       Filter: (url ~~ 'postgresp%ru'::text)
                    (3 rows)

                    Фактически по индексу находятся значения, большие или равные «postgresp» и в то же время меньшие «postgresq» (Index Cond), а затем из результата отбираются подходящие значения (Filter).

                    Сначала функция согласованности должна решить, в какие дочерние узлы корня «p» нужно спуститься. Есть два варианта: «p» + «l» (не подходит, даже не заглядывая дальше) и «p» + «o» + «stgres» (подходит).

                    Для узла «stgres» снова требуется обращение к функции согласованности, чтобы проверить «postgres» + «p» + «ro.» (подходит) и «postgres» + «q» (не подходит).

                    Для узла «ro.» и всех его дочерних листовых узлов функции согласованности ответит «подходит», так что индексный метод вернет два значения: «postgrespro.com» и «postgrespro.ru». Из них — уже на этапе фильтрации — будет выбрано одно подходящее значение.



                    Внутри


                    При просмотре структуры дерева надо учесть типы данных:

                    postgres=# select * from spgist_print('sites_url_idx') as t(
                      tid tid,
                      allthesame bool,
                      n int,
                      level int,
                      tid_ptr tid,
                      prefix text,         -- тип префикса
                      node_label smallint, -- тип метки
                      leaf_value text      -- тип листового значения
                    )
                    order by tid, n;

                    Свойства


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

                     amname |     name      | pg_indexam_has_property
                    --------+---------------+-------------------------
                     spgist | can_order     | f
                     spgist | can_unique    | f
                     spgist | can_multi_col | f
                     spgist | can_exclude   | t


                    Индксы SP-GiST не могут использоваться для сортировки и поддержки уникальности. Кроме того, такие индексы нельзя строить по нескольким столбцам (в отличие от GiST). Использование для поддержки ограничений исключения допускается.

                    Свойства индекса:

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

                    Здесь отличие от GiST состоит в отсутствии возможности кластеризации.

                    И, наконец, свойства уровня столбца:

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

                    Поддержки сортировки нет, что понятно. Операторы расстояния для поиска ближайших соседей в SP-GiST пока не доступны; скорее всего такая поддержка появится в будущем.

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

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


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

                    postgres=# explain (costs off)
                    select * from sites where url is null;
                                      QUERY PLAN                  
                    ----------------------------------------------
                     Index Only Scan using sites_url_idx on sites
                       Index Cond: (url IS NULL)
                    (2 rows)

                    Однако неопределенное значение для SP-GiST — нечто чужеродное. Все операторы, входящие в класс операторов метода spgist, должны быть строгими: для неопределенных параметров они должны возвращать неопределенный результат. Это обеспечивает сам метод; неопределенные значения просто не передаются операторам.

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

                    Другие типы данных


                    Помимо точек и префиксных деревьев для строк, в PostgreSQL реализованы и другие методы на основе SP-GiST:

                    • Дерево квадрантов для прямоугольников обеспечивает класс операторов box_ops.
                      Каждый прямоугольник представляется точкой в четырехмерном пространстве, так что число квадрантов равно 16. Такой индекс может выиграть у GiST по производительности, когда среди прямоугольников много пересечений: в GiST невозможно провести границы так, чтобы отделить пересекающиеся объекты друг от друга, а вот с точками (пусть и четырехмерными) таких проблем нет.
                    • Дерево квадрантов для диапазонов предоставляет класс операторов range_ops.
                      Интервал представляется двумерной точкой: нижняя граница становится абсциссой, а верхняя — ординатой.


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

                    https://habrahabr.ru/post/337502/


                    Метки:  

                    Мой опыт съемки панорамы 360o на фотопленку

                    Понедельник, 18 Сентября 2017 г. 10:00 + в цитатник

                    Метки:  

                    Мой опыт съемки панорамы 360o на фотопленку

                    Понедельник, 18 Сентября 2017 г. 10:00 + в цитатник

                    Метки:  

                    Мой опыт съемки панорамы 360o на фотопленку

                    Понедельник, 18 Сентября 2017 г. 10:00 + в цитатник

                    Метки:  

                    Проекции? Hет, спасибо

                    Понедельник, 18 Сентября 2017 г. 07:02 + в цитатник
                    zzeng сегодня в 07:02 Разработка

                    Проекции? Hет, спасибо


                      Под катом будет небольшая заметка о применении пространственного индекса
                      на основе zcurve для индексации точечных данных, расположенных на сфере.
                      А так же bencmark-и для PostgreSQL и сравнение с таким же (но совсем другим)
                      индексом на R-дереве.

                      В развитие темы (1, 2, 3, 4, 5, 6).
                      Собственно, возвращаемся к самому началу — идее индексировать географические координаты, размещая их на поверхности сферы. Обычная индексация пары широта/долгота приводит к искажениям вдали от экватора, работа с проекциями не универсальна. Поэтому мысль переводить географические координаты в трехмерное пространство выглядит довольно изящно.

                      Сама по себе идея эта не нова, аналогично работает, например, расширение PostgreSQL — PGSphere, которое использует для индексации 3-мерное R-дерево. С ним и будем сравнивать.

                      Подготовка данных.


                      PGSphere


                      • Для начала придётся выкачать, собрать и инсталлировать расширение (автор использовал текущую версию 1.1.5)
                        gmake USE_PGXS=1 PG_CONFIG=/usr/bin/pg_config
                        sudo gmake USE_PGXS=1 PG_CONFIG=/usr/bin/pg_config install
                        
                      • Далее загрузить его (psql)
                        CREATE EXTENSION pg_sphere;
                      • Создадим таблицу для тестовых данных
                        CREATE TABLE spoint_data (sp spoint);
                      • Нам потребуется источник случайных данных.
                        Первый параметр программы — радиус, второй — число результатов.
                        Единственная тонкость — данные равномерно распределены внутри шара с заданным радиусом, иначе не получится равномерного распределения на сфере
                      • Случайные данные пропустим через скрипт awk чтобы превратить в геокоординаты
                        # --- gendata.awk ------
                        BEGIN{
                        	pi=3.1415926535897932;
                        	degra=pi/180.0;
                        	rad=180.0/pi;
                        	Grad = 1000000.;
                        }
                        {
                        	x = $1;	y = $2;	z = $3;
                        	r3 = sqrt(x*x + y*y + z*z);
                        	x *= Grad / r3;
                        	y *= Grad / r3;
                        	z *= Grad / r3;
                        
                        	r2 = sqrt(x*x + y*y);
                        	lat = atan2(z, r2) * rad;
                        	lon = 180. + atan2(y, x) * rad;
                        
                        	printf ("(%14.10fd, %14.10fd)\n", lon, lat);
                        }
                      • Собственно создание данных, здесь радиус не важен, важно чтобы и pgsphere и zcurve получили одни и те же данные. Сортировка весьма желательна для ускорения индексации.
                        ./random 1000000 100000000 | gawk -f gendata.awk | sort > pgsphere.txt
                      • Заливаем данные в нашу таблицу
                        COPY spoint_data (sp) FROM  '/home/.../pgsphere.txt';
                      • Индексируем
                        CREATE INDEX sp_idx ON spoint_data USING gist (sp);

                      ZORDER


                      • Для начала придётся выкачать, собрать и инсталлировать расширение
                        gmake USE_PGXS=1 PG_CONFIG=/usr/bin/pg_config
                        sudo gmake USE_PGXS=1 PG_CONFIG=/usr/bin/pg_config install
                        
                      • Создадим таблицу для тестовых данных
                        create table test_points_3d (x integer,y integer, z integer);
                      • Нам потребуется тот же источник случайных данных.
                      • Случайные данные пропустим через скрипт awk чтобы разместить их внутри куба со стороной в 2 000 000
                        #--- gendata2.awk ------
                        BEGIN{
                        	pi=3.1415926535897932;
                        	degra=pi/180.0;
                        	rad=180.0/pi;
                        	Grad = 1000000.;
                        }
                        {
                        	x = $1;	y = $2;	z = $3;
                        	r3 = sqrt(x*x + y*y + z*z);
                        	x *= Grad / r3;
                        	y *= Grad / r3;
                        	z *= Grad / r3;
                        
                        	ix = int(x+0.5+Grad);
                        	iy = int(y+0.5+Grad);
                        	iz = int(z+0.5+Grad);
                        	print ix"\t"iy"\t"iz;
                        }
                      • Собственно создание данных, здесь радиус важен. Сортировка не обязательна.
                        ./random 1000000 100000000 | gawk -f gendata2.awk > zcurve.txt
                      • Заливаем данные в нашу таблицу
                        COPY test_points_3d FROM '/home/.../zcurve.txt';
                      • Индексируем
                        create index zcurve_test_points_3d on test_points_3d(zcurve_num_from_xyz(x,y,z));

                      Подготовка тестов


                      PGSphere


                      Для тестирования потребуется вот такой awk скрипт
                      #--- gentest.awk -------
                      BEGIN{
                      	pi=3.1415926535897932;
                      	degra=pi/180.0;
                      	rad=180.0/pi;
                      	Grad = 1000000.;
                      }
                      {
                      	x = $1;	y = $2;	z = $3;
                      	r3 = sqrt(x*x + y*y + z*z);
                      	x *= Grad / r3;
                      	y *= Grad / r3;
                      	z *= Grad / r3;
                      
                      	r2 = sqrt(x*x + y*y);
                      
                      	lat = atan2(z, r2) * rad;
                      	lon = 180. + atan2(y, x) * rad;
                      
                      #	EXPLAIN (ANALYZE,BUFFERS) 
                        printf ("select count(1) from spoint_data where sp        @'<(%14.10fd,%14.10fd),.316d>'::scircle;\n", lon, lat);
                      }

                      Этот скрипт вполне симметричен тому, с помощью которого мы подготавливали данные. Стоит обратить внимание на число .316, это радиус сферы с центром в вычисленной случайной точке, в которой мы ищем данные
                      Подготовка серии запросов делается так:
                      ./random 1000000 100 1023 | gawk -f gentest.awk >tests1.sql

                      Здесь 100 — размер тестовой серии, 1023 — seed рандомизатора.

                      ZCURVE


                      Для тестирования тоже потребуется awk скрипт
                      #--- gentest2.awk -------
                      BEGIN{
                      	pi=3.1415926535897932;
                      	degra=pi/180.0;
                      	rad=180.0/pi;
                      	Grad = 1000000.;
                      }
                      {
                      	x = $1;	y = $2;	z = $3;
                      	r3 = sqrt(x*x + y*y + z*z);
                      	x *= Grad / r3;
                      	y *= Grad / r3;
                      	z *= Grad / r3;
                      
                      	ix = int(x+0.5+Grad);
                      	iy = int(y+0.5+Grad);
                      	iz = int(z+0.5+Grad);
                      #	EXPLAIN (ANALYZE,BUFFERS) 
                      	lrad = int(0.5 + Grad * sin(.316 * degra));
                      	print "select count(1) from zcurve_3d_lookup_tidonly('zcurve_test_points_3d',   "ix-lrad","iy-lrad","iz-lrad","ix+lrad","iy+lrad","iz+lrad");";
                      }

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

                      Подготовка серии запросов делается так:
                      ./random 1000000 100 1023 | gawk -f gentest2.awk >tests2.sql

                      Здесь 100 — размер тестовой серии, 1023 — seed рандомизатора, лучше, если он совпадает с оным от pgsphere.

                      Benchmark


                      Как и раньше, замеры проводились на скромной виртуальной машине с двумя ядрами и 4 Гб ОЗУ, поэтому времена не имеют абсолютной ценности, а вот числам прочитанных страниц по прежнему можно доверять.
                      Времена показаны на вторых прогонах, на разогретом сервере и виртуальной машине. Количества прочитанных буферов — на свеже-поднятом сервере.
                      Radius AVG NPoints Nreq Type Time(ms) Reads Hits
                      .01° 1.17
                      0.7631
                      (0.7615)
                      10 000 zcurve
                      rtree
                      .37
                      .46
                      1.4397
                      2.1165
                      9.5647
                      3.087
                      .0316° 11.6
                      7.6392
                      (7.6045)
                      10 000 zcurve
                      rtree
                      .39
                      .67
                      2.0466
                      3.0944
                      20.9707
                      2.7769
                      .1° 115.22
                      76.193
                      (76.15)
                      1 000 zcurve
                      rtree
                      .44
                      2.75 *
                      4.4184
                      6.073
                      82.8572
                      2.469
                      .316° 1145.3
                      758.37
                      (760.45)
                      1 000 zcurve
                      rtree
                      .59
                      18.3 *
                      15.2719
                      21.706
                      401.791
                      1.62
                      1.° 11310
                      7602
                      (7615)
                      100 zcurve
                      rtree
                      7.2
                      94.5 *
                      74.9544
                      132.15
                      1651.45
                      1.12
                      где
                          Radius — размер поисковой области в градусах
                          Npoints — среднее число точек в выдаче, в скобках — теоретически ожидаемое число
                           (в сфере 41252.96 кв. градусов, 100 000 000 точек, ~2424 точки на кв. градус)

                          Nreq — число запросов в серии
                          Type
                            ‘zcurve’ — оно и есть
                            ’rtree’- PGSphere
                          Time(ms) — среднее время выполнения запроса
                          Reads — среднее число чтений на запрос
                          Hits — число обращений к буферам

                          * в какой-то момент производительность R-tree начинает резко
                          проседать, связано это с тем, это дерево читает заметно больше
                          страниц и его рабочий набор перестаёт помещаться в кэше (по-видимому).

                      Отметим, что zcurve находит больше данных, что логично т.к. он ищет внутри куба, а не сферы как PGSphere. Поэтому требуется пост-фильтрация в духе HAVERSINE. Но здесь мы сравниваем только производительности индексов.

                      Попробуем оценить разницу. Вообще, задача найти площадь куска сферы, попавшей внутрь куба нетривиальна. Попробуем сделать оценку.
                      • Предположим, что наш куб в среднем вырезает из сферы ту же площадь, что и сфера равного объема
                      • Объем единичной сферы 1.33*3.14=4.19
                      • Объем куба со стороной 2 = 8.
                      • Тогда корень третьей степени из 8/4.19 = 1.24 — это отношение радиусов мнимой сферы к настоящей
                      • соотношение площадей мнимой сферы к настоящей 1.24*1.24=1.54
                      • имеем из экспериментальных данных 1.17/0.7631= 1.5332
                        Bingo!
                      Original source: habrahabr.ru (comments, light).

                      https://habrahabr.ru/post/338088/


                      Метки:  

                      Поиск сообщений в rss_rss_hh_full
                      Страницы: 1824 ... 1536 1535 [1534] 1533 1532 ..
                      .. 1 Календарь