Использование Лиспа в производство

Использование Лиспа в производство

655

На данный момент движок обрабатывает наиболее тыщи предложений в секунду, масштабируется горизонтально и накрепко служит нам в производстве в течение практически 3 лет. В это лежит в базе нашего бизнеса — Центральный языке движок написан в коммон Лиспа.
Во время выполнения и среды программирования lisp предоставляет несколько неповторимых и незначительно не по привычке, способности для поддержки производственных систем (для нетерпеливых — они описаны в крайней части). Мы увидели, что практически нет постов о развертывании Лисп программного обеспечения на современные пасмурные инфраструктуры, потому мы решили поделиться нашим опытом было бы неплохой идеей.
Вту Лисп?!!

Вопреки всераспространенному мнению, lisp-это неописуемо практичный язык для сотворения производственных систем. Фактически говоря, вокруг нас много Лисп-систем: раз вы ищете авиакассу на Hipmunk либо ездить на метро в Лондоне, употреблял Лисп.
Наш Лисп-сервисы концептуальных являются классическим ИИ приложение, которое работает на большой куче познаний, сделанных языковедами и исследователями. Его главным используемым ресурсом является процессор, и это один из огромнейших потребителей вычислительных ресурсов в нашей сети.
Один из приятных качеств при помощи lisp — у вас есть выбор из пары развитых реализаций с разными плюсы и минусы: в нашем случае, мы улучшали скорость сервера и скорость компиляции во время разработки (почему это принципиально для нас описано ниже). Система работает на обыкновенной Linux-системы, развернутые в aws. Мы используем для производства SBCL и ccl в большинстве машин разрабов.
Чужак в чужой земле

Этот подход имеет определенную стоимость в сервис, но мы ценим выбор и свобода-это больше, чем правила и структуры. Следует инкапсуляции услуг дозволяет нам применять язык либо платформу, которая лучше всего подступает для задачки. На это, мы используем разные языки программирования для развития наших услуг: кроме языков для jvm и javascript, мы также писать на erlang, Python и идти.
Мы также стараемся опираться на обыкновенные, не привязаны к языкам инфраструктуры ЖКХ. К примеру, statsd является красивым примером неописуемо обычная и нужная услуга, которая чрезвычайно проста в использовании. Вот весь код, который нужен (и практически все это просто подстрочный перевод спецификации): Остальные Graylog2, она обеспечивает стильный Спецификация для журнальчика, и невзирая на то, что существует готовая библиотека для работы с ним из ЛЧ, это было чрезвычайно просто собрать из того, что доступно в Лиспе экосистемы. Таковой подход высвобождает нас от почти всех заморочек в ходе интеграции всего зоопарка технологий в нашей платформе.
Как вы сможете созидать, 5 библиотек, используемых в этом примере, за такие вещи, как кодирование, сжатие, получение времени в Unix, и в сокетное соединение. (defun graylog (сообщение &главный уровень след строчка файла-нет)
(пусть ((мсг (salza2:сжатие данных
(Бабель:строчки в октетах
(в формате json:кодировки-преобразования json-строчки #{
:Версия «1.0»
:объект «лисп»
:хоста *имя хоста*
:|short_message| сообщение
:|full_message| след
:отметка времени (по местному-время:метка времени в Unix (по местному времени:на данный момент))
:уровень уровень
:файл файл
:линия линия-нет
})
:Шифровка :utf-8)
‘salza2:сжатия zlib-компрессор)))
(usocket:патрубок-отправьте (usocket:сокет-подключения
*graylog-хоста* *graylog-порт*
:протокол :дейтаграммы :элемент-Тип ‘(беззнаковый б 8))
мсг (длина сбщ))))

Отсутствие библиотек в экосистему — одна из нередких жалоб о Лиспе.
К счастью, посодействовал один вопросец на stackoverflow — мы интегрировали ее в свою свою библиотеку тест должен инспектировать. Лисп библиотеки есть, но, как и во всех интеграций библиотек, мы сталкиваемся с неуввязками. К примеру, чтоб соединить непрерывной интеграции jenkins, мы должны были применять xUnit и это было не чрезвычайно просто отыскать в спецификации для него.
Иным примером является внедрение HDF5 для обмена модели машинного обучения: мы провели некое время, чтоб приспособиться низкоуровневые библиотеки hdf5-cffi для наших реалий, но нам пришлось издержать намного больше времени, чтоб обновить наш АМИ (Амазонка машинки изображения) для поддержки текущей версии C-библиотек.
Таковым образом, мы не должны взаимодействовать с базами данных в критически принципиальных частях наши сервисы лингвистического ядра. Тем не наименее, мы используем MySQL, и postgres, redis и Монго для внутреннего хранения, и мы удачно используются CLSQL, постмодерн, ХЛ-с redis и CL-монго, чтоб получить к ним доступ из Лиспа. Иной принцип, которому мы следуем в платформу grammarly представляет наибольшее разложение разных услуг для обеспечения горизонтальной масштабируемости и многофункциональной независимости этот пост моей коллеги.
Мы используем Quicklisp для управления наружными зависимостями и обычная система упаковки начальный код библиотеки проекта для собственных библиотек и вилки. В Quicklisp репозиторий содержит наиболее 1000 Лисп библиотек: не супер большой, но полностью достаточное, чтоб удовлетворить все потребности нашего производства.
Для развертывания в производстве мы используем всепригодный стек: приложение тестируется и собирается с Дженкинс, доставляется на сервер по Rundeck там и начал применять выскочка как обыденный процесс ОС Unix.
Раз вы желаете применять Лисп в создание и испытывать наслаждение от написания программы на Лиспе, нет никаких настоящих технических обстоятельств этого не делать! В общем, трудности, с которыми мы сталкиваемся при интеграции lisp-приложений в облаке мире, конструктивно не различается от тех, которые мы встречаем во почти всех остальных технологий.
Тяжелейшая ошибка я когда-или отлажен

Какой бы совершенной эта история все не про радугу и единорогов.
Мы сделали эзотерические приложения (даже по меркам мира Лиспа) и в процессе столкнулся с некими ограничениями платформы. Невзирая на это, существует известное общее решение, стиль звонка-с -*, что дозволяет nemovitosti эффективность для наилучшей модульности (что оказалось решающим в нашем случае) и ollivetti. Мы в значимой степени полагаемся на макросы, и величайший из их, раскрываются в тыщи строк кода низкого уровня. Оказалось, что компилятор SBCL реализует множество оптимизаций, благодаря которым мы можем наслаждаться достаточно быстро сгенерированный код, но некие требуют экспоненциального времени и памяти. Одним из таковых сюрпризом стало исключению нехватки памяти во время компиляции. К огорчению, нет никакого метода, чтоб выключить его либо настроить их.
SBCL обеспечивает неплохой сборщик мусора, основанный на поколениях, хотя и не так непростая, как в jvm. Еще один параметр, который мы должны были сделать, еще наименее разумеется, был пуск программного обеспечения ГХ каждые N минут. Наименее неожиданный, чем приручение компилятор настроить сборщик мусора, чтоб уменьшить задержки и повысить эффективность использования ресурсов в нашей системе. Наш подход с повторяющейся ГК привел систему в наиболее стабильное состояние с фактически неизменным потреблением памяти. Нам пришлось скорректировать размеры поколений и нашли, что наилучшим вариантом является применять увеличенный Размер кучи: наше приложение потребляет 2-4 гб памяти, но мы прогнали его с кучей 25г на, что автоматом привело к повышению размера первого поколения. Слева показано, как работает система Без наших опций, а справа — эффект повторяющегося ГК. С увеличенным лотом, мы увидели постепенное повышение памяти в течение 10-ов минут, за которые больше времени было потрачено на ГК и понижение производительности приложений.

От всех этих проблем, худшая ошибка я когда-или встречал, был сетевой глюк. Как традиционно бывает в таковых ситуациях, ошибка была не в заявке и базисной платформы (в этот раз — SBCL). И, наиболее того, я столкнулся с ним два раза в 2-ух различных сервисах, но в 1-ый раз я не сумел это узнать, так что нам пришлось обойти его.
Это было чрезвычайно маловероятно гонки, так это проявлялось лишь в высоконагруженных сетевых услуг, когда эта функция вызывается с 10-ки тыщ раз. Опосля долгого расследования с подозрением на входные данные, мы нашли, что неувязка была в гонке низкого уровня сетевого кода для SBCL, в частности в методе вызова функции в сокет getprotobyname, что был не нацелен на многопотоковое выполнение. Он выбил один рабочий поток за иным, равномерно вводя систему в кому. Когда мы начали пуск нашего сервиса для главных нагрузок в производстве, опосля некого времени обычной работы всех серверах вдруг начал замедляться и в конце концов перестает отвечать на запросы.
(Баг был выслан в команду SBCL и была Исправлена, но мы по-прежнему применять этот хак, на всякий вариант 🙂 Вот это поправить, где мы останавливались, к огорчению, она не может быть применена в наиболее широком контексте в качестве библиотеки.
#+Юникс
(defun ШБ-внедрение BSD-сокетов:получить-протоколом по имени (имя)
(вариант (mkeyw имя)
(ПТС 6)
(:УДП 17)))
Назад в будущее

Вот власть этого вооруженного до зубов и оперативных боевую станцию в действии. Пока ветвь ожидает созревания приложения lighttable и подобные инструменты, Лисп программеры тихо радуясь таковой способности в слизи в течение почти всех лет. Система коммон Лиспа воплотить почти все идеи знаменитого Лисп-машинки. Одним из более узнаваемых является интерактивная среда слизь.
Java-программеры могут мыслить о инструмент jconsole, но тогда Вы не скованы предопределенный набор операций и может произвести хоть какой интроспекции либо поменять то, что вы желаете. Но слизь-это не просто сюсюкает подход к IDE. Будучи клиент-серверных приложений, она дозволяет запускать серверной части на удаленной машине и подключиться к нему из локальной редактора emacs (либо vim, раз у вас нет выбора, с SLIMV). Мы не смогли изловить гонку в гнездо функций без этих способностей.
Как почти все IDE он имеет возможность ориентироваться в начальном коде функции, но в отличие от java либо Python, мой кар имеет начального кода для SBCL, потому я нередко просматривает начальные коды реализации, и это помогает выяснить, что происходит еще лучше. Наиболее того, в удаленной консоли-это не лишь нужная утилита, предоставленная слизь. Для варианта с гнездом баг этот был также принципиальной частью процесса отладки.
Она была инвентарем в поиске нашего противный баг. Она на сто процентов изменила мой подход к отладке: от кислых местных обратиться к analysera картину в целом. В конце концов, еще один супер нужный инструмент для самоанализа и отладки, мы используем след.
проследить это как печать на стероиды, что дозволяет быстро просачиваться в толщу код случайной трудности и контролировать сложные пути выполнения. С трассировки , задания функции проследить, выполнить код, и Лисп печатает все вызовы данной функции и ее Аргументы, и все результаты его возвращает. Это что-то вроде трассировки стека, но для вас не нужен полный стек динамически и вы получите поток следов, без остановки приложения. Единственный недочет — Вы не сможете транзитного макросы.
Вот фрагмент трассировки, которые я сделал сейчас, чтоб убедиться в том, что json-запроса в одном из наших услуг формируется верно и возвращает верный итог:
И когда мне позвонили и произнесли, что никогда не возвратился — это был он. 0: (ПОЛУЧИТЬ-ДЭПАМИ
(«вы думаете, что это плохо, хе-хе, я помню когда у меня был старенькый 100МГЦ Делл блока я употреблял в качестве сервера в моей комнате»))
1: (ФОРМАТ JSON:Кодировки-ПРЕОБРАЗОВАНИЯ JSON-Строчки
#<ХЭШ-ТАБЛИЦА :ТЕСТ ОКУ :ГРАФА 2 {1037DD9383}>)
2: (Формат json:кодировки-преобразования json-строчку «действие»)
2: json для:кодировки-преобразования json-строчку, возвращаемую «»действие»»
2: (Формат json:кодировки-преобразования json-строчку «предложения»)
2: json для:кодировки-преобразования json-строчку, возвращаемую «»предложений»»
1: json для:кодировки-преобразования json-строчку, возвращаемую
«{«действие»:»зависимости»,»предложений»:[«вы думаете, что это плохо, хе-хе, я помню когда у меня был старенькый 100МГЦ Делл блока я употреблял в качестве сервера в моей комнате»]}»
0: получи-ДЭПАМИ возвратился
(((«nsubj» 1 0) («ccomp» 9 1) («nsubj» 2 3) («ccomp» 1 3) («acomp» 3 4)
(«punct» 9 5) («людей с типом личности intj» 9 6) («punct» 9 7) («nsubj» 8 9) («корень» -1 9)
(«advmod» 9 10) («nsubj» 12 11) («ccomp» 9 12) («дет» 17 13)
(«амод» 17 14) («НН» 16 15) («НН» 17 16) («dobj» 12 из 17)
(«nsubj» 20 18) (ОКС 20 19) («rcmod» 17 из 20) («прэп» 20 из 21)
(«дет» 23 22) («pobj» 21 23) («прэп» 23 из 24)
(«посс» 26 25) («pobj» 24 26)))
((<вы из 0.3> <придумать 4.9> <10,14 что> < » ы 14,16> <17,20 плохо> <, 20,21>
<хе-хе 22,26> <, 26,27> <28,29 я> <помню 30,38> <раз 39,43>
<я 44,45> <было 46,49> <собой 50,52> <старенькые 53,56> <100МГЦ 57,63>
<Делл 64,68> <единица 69,73> <я 74,75> <был 76,79> <a внедрение для 80.85>
<как 86,88> и <A 89,90> <сервер 91,97> <в 98,100> <мой 101,103>
<номер 104,108>))

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

habrahabr.ru Ок. Надеюсь, прочитав эту статью, кто-то направит внимание на этот недооцененный технологии. переводчик:
Мне вдвойне приятно о использовании общего Лиспа в создание, написание, и даже пишут люди из СНГ, поэтому что мы практикуем этот стек фактически нет.