• «No space left on device» и inodes by Ast

    Честно говоря, я тоже не знаю. Это был всего лишь термин, который мы начали использовать. Из-за немного необычной структуры файловой системы, при которой информация о доступе к файлам хранится в виде плоского (двумерного) массива на диске, отдельно от всей информации об иерархии каталогов, лучшее, что я могу предположить (для «и») - это «индекс». Таким образом, и-номер являлся индексом в этом массиве, и-нод - выбираемым элементом массива. (Приставка «и-» использовалась в первой версии руководства; со временем дефис перестали употреблять).
    Деннис Ритчи

    Я был очень удивлен, когда получил ошибку следующего содержания при попытке открытия сессии:

    PHP Warning:  Unknown: open(/tmp/sess_e34ad6u6f51gum3htmqkd7ldn6, O_RDWR) failed: No space left on device (28)
    

    Ведь при этом df -h показывал такую картину, что свободного пространства много:

    df -h
    
    
    Filesystem          1K-blocks     Used Available Use% Mounted on
    /dev/sda2            19091584  3784332  14314332  21% /
    udev                  8192628        8   8192620   1% /dev
    tmpfs                 3280992      284   3280708   1% /run
    none                     5120        4      5116   1% /run/lock
    none                  8202472       92   8202380   1% /run/shm
    /dev/mapper/vg0-var  47926152 24100456  21368096  54% /var
    

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

    df -i
    

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

  • «Strangler Application» и SSI by Ast

    When Cindy and I went to Australia, we spent some time in the rain forests on the Queensland coast. One of the natural wonders of this area are the huge strangler vines. They seed in the upper branches of a fig tree and gradually work their way down the tree until they root in the soil. Over many years they grow into fantastic and beautiful shapes, meanwhile strangling and killing the tree that was their host.
    Martin Fowler, «Strangler application»

    strangler vines

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

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

    В такой ситуации может оказаться полезной такая технология, как SSI. Она позволяет осуществлять пост-процессинг тела ответа, например, применять условные функции или делать дополнительные запросы. При реализации «Strangler Application» это может пригодиться следующим образом: старое приложение загружается как обычно, но вместо какого-то отдельного блока на странице происходит обращение к новому приложению. Веб-сервер, получив такие инструкции, делает дополнительный запрос по указанному адресу и вместо инструкции SSI размещает полученный ответ. Можно сравнить это с загрузкой блока посредством AJAX-запроса, но только значительно быстрее и совершенно прозрачно для пользователя, т.к. вся магия происходит еще на сервере, до отправки ответа клиенту.

    Такая строка в коде сайта заставит сервер сделать запрос по адресу «/my-new-application-url» и «вклеить» его результат в код сайта:

    <!--# include virtual="/my-new-application-url" -->
    

    В конфиге nginx следует разрешить такие запросы:

    location / {
            ...
            ssi on;
            ...
    }
    

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

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

  • Удаление слешей из урла в nginx by Ast

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

    http://mysite.com//page//1.htm/ --> http://mysite.com/page/1.htm

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

    set $test_uri $scheme://$host$request_uri;
    if ($test_uri != $scheme://$host$uri$is_args$args) {
        rewrite ^ $scheme://$host$uri$is_args$args? permanent;
    }
    

    И с конца:

    rewrite ^/(.*)/$ /$1 permanent;
    
  • Событийная архитектура веб-приложения by Ast

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

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

    function add(item_id, quantity) {
        $.ajax({
            type: "POST",
            url: "/api/cart/add",
            dataType: 'json',
            data: {item_id: item_id, quantity: quantity}
        }).done(function (data) {
            $('body').trigger('QuantityChanged', [data.item_id, data.quantity]);
            $('body').trigger('PriceChanged', [data.item_id, data.sum]);
        });
    };
    

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

    /**
     * Обновить количество товара в корзине
     */
    $('body').on('QuantityChanged', function (e, item_id, quantity) {
        $('[data-item-quantity="' + item_id + '"]').html(quantity);
    });
    
    /**
     * Обновить цену товара в корзине
     */
    $('body').on('PriceChanged', function (e, item_id, sum) {
        $('[data-item-sum="' + item_id + '"]').html(sum);
    });
    

    Никто теперь не мешает нам расширить систему, добавив на какой-то отдельной странице дополнительное действие при добавлении товара в корзину. И это всё без изменения API, без изменения старых событий и без условных операторов.

  • Пакет для балансировки запросов к статическим файлам by Ast

    Url Balancer

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

    • Поддержка Composer (через packagist)
    • Поддержка Silex
    • Расширяемость стратегий балансировки

    Установка

    Рекомендуется установка через Composer:

    {
        "require": {
            "astartsky/url-balancer": "1.1.2"
        }
    }
    

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

    $urlBalancer = new \Astartsky\UrlBalancer\UrlBalancer();
    $urlBalancer->setStrategy(new \Astartsky\UrlBalancer\Strategy\HashStrategy())
    $urlBalancer->addBucket(new \Astartsky\UrlBalancer\Domain("s1.myawesomesite.com"));
    $urlBalancer->addBucket(new \Astartsky\UrlBalancer\Domain("s2.myawesomesite.com"));
    $urlBalancer->addBucket(new \Astartsky\UrlBalancer\Domain("s3.myawesomesite.com"));
    
    $url = $urlBalancer->getUrl("/images/my_impressive_content.png");
    

    Ссылки

    На Packagist.org: пакет

    На Bitbucket.org: репозитарий

  • Как команда технарей свою студию создавала by Ast

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

    Команда

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

    Читать дальше...

  • Minecraft by Ast

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

  • А вот и я, всем привет by Ast

    Dragon

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

    Что ж у меня нового?

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

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

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

    В общем, я всегда где-то здесь. Может, еще что-то расскажу скоро.

  • Ветка git в командной строке by Ast

    Если активная работа над проектом идет над несколькими ветками сразу, всегда полезно знать, на какой ветке в текущий момент находится указатель HEAD репозитария. Чтобы не полагаться на память, можно добавить отображение названия ветки в приглашение командной строки. Для этого откроем на редактирование ~/.bashrc

    export PS1='\u@\h: \w\[\033[01;33m\]$(__git_ps1) \$\[\033[00m\] '
    

    Любуемся результатом:

    Но, по хорошему, лучше просто поставьте zsh — оно того стоит.