Экосистема Nginx, склеенная Lua

HTTP Nginx API Lua
  • Деятельность:Итоги салона технологий Tech-Club (февраль 2012 г.)
  • Слайд-шоу:ngx_openresty: an Nginx ecosystem glued by Lua
  • запись:120306_ngx_openresty.mp3
  • Стенограмма: Zoom.Quiet nginx@gmail.com>
  • Chnangelog:
    • 131213 fixed losted vdisk.weibo.com/s/2Qcon
    • 120312 fixed as s/hhttp/http/g ,thanx muxueqz
    • 120309 fixed kindel->kindle, thanx for milel liu;
    • 120308 fixed ahcking->hacking,thanx weakish
    • 120306 fixed agentzh ID name,thanx himself alert
    • 120305 finished
    • 120301 init.

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

1. Отказ от ответственности

  1. Записи/слайды принадлежат авторам, авторские права конечно принадлежат им
  2. Расшифровка из Zoom.Quiet, все проблемы с текстом по моей вине, к оригиналу отношения не имеют
  3. Из-за моих ограниченных технологий я использую только слайды и записи, я несу ответственность за любые ошибки в моей памяти и не имею никакого отношения к оригинальному автору.
  4. Любое недовольство и комментарии, пожалуйста, свяжитесь со мной напрямую для улучшения

2. Экосистема Nginx, связанная с Lua

Гао Гао поделится с вами сегодня.Раньше у нас был связанный обмен в Пекине.Сегодня наша тема Nginx или Lua.Мы представим нашу работу за последние 3 года.Название проекта openresty, которое можно проследить до 2007 года. , когда я только пришел в Yahoo! China, моей первой задачей было создание открытой платформы, собственной открытой платформы Yahoo!, и система постепенно отклонялась от первоначального замысла. Мы начали делать некоторые проекты для крупных интернет-компаний. для работы с веб-интерфейсом;

Я проработал в Yahoo! и TaoBao два года соответственно, а потом уволился, основная причина в том, что все больше и больше людей используют наши разработки с открытым исходным кодом, и с одной стороны, я должен удовлетворять так называемые потребности бизнеса, а с другой стороны, я должен реагировать на внутренние и внешние требования активных разработчиков или ошибок; поэтому я уволился с работы, чтобы сосредоточиться на своей работе; изначально я хотел переехать в Сямэнь, но моя жена нашла работу в Фучжоу , так что теперь мне не платят, и я обязан служить миру, созданному любителями ;-) Сейчас я в Фучжоу уже 7 месяцев, это фото моя жена сделала, я привык писать код сначала на бумаге, а потом набираешь в комп.

Тот, что спереди, это Kindle, интересно происхождение этого Kindle,

  • Когда я был в TaoBao, я собирался переписать openresty, потому что он с самого начала был написан на Perl.
  • В Yahoo!, несмотря на то, что для унификации функции поиска использовался openresty, производительность действительно средняя.
  • В то время я хотел переписать его на основе Apache, но один мастер сказал мне: "Ты можешь просто написать это на C, у написания на Apache нет будущего!"
  • Я был очень подавлен, поэтому я спросил, как это исправить?Мастер ответил, вы должны изучить исходный код nginx, а затем игнорировать меня, и смотреть на код очень утомительно, поэтому я купил киндел, как только я приехал в TaoBao.код...

2.1. openresty

Как я только что упомянул, openresty отклоняется от первоначального плана в процессе разработки, позже, столкнувшись с более конкретным бизнесом компании, в это время можно увидеть, что так называемый Ajax/Servise уже используется. тенденция, то есть:

    对看起来是个整体的web 应用
    习惯在后台拆成很多 Service
    有些Service 是供給客户端发起請求来访问的,
    而有些Service 根本就是为其它服务而服务的,也使用了 http 协议进行发布

Эта структура приводит к тому, что вся система становится очень децентрализованной.

  • Часть системы внедряется несколькими отделами
  • И каждый отдел, открытый для других отделов, представляет собой просто интерфейс в виде http-протокола, resful

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

      Поскольку протокол http настолько распространен, нам нужна прочная основа для реализации; nginx — наименее плохая среди различных платформ, которые мы исследовали!
      • Другие совсем плохие,Самая большая проблема апача - его модель ввода/вывода, которая не может дать очень эффективного ответа, но плюсы: интерфейс разработки обычный, и на его основе очень удобно писать моды; Lighttpd как раз наоборот, его ввод-вывод очень эффективен, но интерфейс разработки не очень удобен; и Nginx сочетает в себе преимущества обоих ;-)

        <<< 5:11

  • С одной стороны, используется модель I/O мультиплексирования lighttpd.
  • С другой стороны, он опирается на поддержку разработки модулей Apache.

    Во время (openresty) разработки люди часто спрашивают, почему nginx такой быстрый?
  • Мы знаем, что nginx однопоточный,
  • А однопоточная модель, почему она может выдерживать десятки тысяч или даже сотни тысяч одновременных запросов?!Из-за того, как работает nginx, как показано на анимации, это простая анимация git, которую я только что сгенерировал с помощью perl:
  • На самом деле это то, что делают потоки операционной системы.
  • Первые три соответствуют разным http запросам
  • Каждый квадрат представляет собой операцию чтения или записи.
  • Последний epoll_wait — самый эффективный интерфейс событий в системе Linux.

    То есть nginx на самом деле является механизмом, управляемым событиями.
  • Конкретные данные обрабатываются только тогда, когда происходит соответствующее событие
  • Если в текущем интерфейсе нет данных, он немедленно отключится и обработает другие запросы.
  • Поэтому, несмотря на то, что существует только один поток, он может обрабатывать запросы многих потоков одновременно Таким образом, эта форма веб-системы может легко полностью загрузить процессор, даже если полоса пропускания не заполнена. многопоточная модель процесса, сложно полностью загрузить процессор:
    • Потому что, когда параллелизм достигает определенной суммы
    • память кончится первой
    • Поскольку в системе Linux количество потоков ограничено, каждый поток должен предварительно выделять стек размером 8 м, независимо от того, используется он или нет!
    • Таким образом, при увеличении числа потоков узким местом в первую очередь становится память.
    • Даже если он переживет проблему с памятью, когда будет достаточно одновременных запросов, проблема планирования потоков конкуренции за процессор снова станет узким местом системы.

      <<< 8:31

      Таким образом, простая однопоточная модель с одним входом, такая как nginx, устанавливается в качестве модели ввода-вывода высокопроизводительными системами, такими как memcached; тогда что мы сделали?
    • В основном для nginx Предоставить множество патчей и исправлений
    • В то же время, используя интерфейс разработчика, предоставляемый nginx, внесли множество модулей
    • Мы также встраиваем ранее упомянутый Lua в nginx, чтобы сделать его полностью интерактивным.
    • Также поместите в него несколько общих библиотек Lux.
    • Затем создайте большой пакет и назовите его openresty... Это случайная домашняя страница, созданная с помощью Tiddlywiki:openresty.org

2.2. Настройка маленького языка

Сам nginx имеет очень важную функцию, которая также выделена в статье Википедии:

  • Его нотация файла конфигурации очень гибкая и читабельная.
  • Конфигурационный файл nginx.conf локально представляет собой небольшой язык, например:

    location = '/hello' {
           set_unescape_uri $person $arg_person;
           set_if_empty $person 'anonymous';
           echo "hello, $person!";
       }

    Эта конфигурация также знакома пользователям Apache.
  • Сначала мы используем форму, похожую на регулярные выражения, чтобы согласовать URL-адрес ответа.
  • Затем вы можете использовать различные директивы nginx для выполнения ряда операций с внутренними переменными.
  • Переменные также являются частью файла конфигурации, подобно языку программирования.
  • Например, здесь мы присваиваем переменной person значение arg_person.
  • Затем используйте «анонимный» в качестве значения по умолчанию для $person, когда он пуст.
  • Наконец, используйте echo для прямого вывода результата Таким образом, мы можем использовать curl для имитации доступа к браузеру, предоставить строковое значение в кодировке utf8 для /hello и использовать переменную метода GET ?person= для получения ожидаемой обратной связи: привет, Чжан Ичунь. Если параметры не указаны, анонимное использование только сейчас будет работать;

    Итак, в целом, мы ожидаем реализовать интерфейс сервиса в nginx, просто напишите такую ​​конфигурацию, вам не нужно писать какой-то серьезный код на C ;-) и он работает как летающий, потому что, чтобы написать так, это практично и c Реальность не имеет значения;

    На самом деле, разработчики по всему миру используют интерфейс разработки nginx, пытаясь обогатить словарный запас этого небольшого языка конфигурационных файлов!
  • И что действительно определяет его выразительную способность, так это: «словарный запас».
  • Например, давайте посмотрим на этот пример, это то, что я написал во 2-й или 3-й модуль nginx:
    • Так называемые upstream-модули для прямого доступа к memcached
    • nginx имеет свой собственный набор терминов, после которого различные сервисы, такие как memcached, являются вышестоящими с точки зрения nginx.
    • Соответственно, такие клиенты, как браузеры, которые обращаются к nginx, считаются нижестоящими.

      # (not quite) REST interface to our memcached server
      #  at 127.0.0.1:11211
      location = /memc {
          set $memc_cmd $arg_cmd;
          set $memc_key $arg_key;
          set $memc_value $arg_val;
          set $memc_exptime $arg_exptime;
          memc_pass 127.0.0.1:11211;
          }

    • Эта простая конфигурация сопоставляет различные параметры URL-адреса с несколькими переменными через set,
    • Затем подключитесь к удаленному сервису memcached через memc_pass, конечно, это может быть и кластер позади
    • Сразу же получаем интерфейсный сервис, о котором следует сказать, что это псевдо restfulle memcached.
    • Мы можем использовать curl для управления целевым memcached.
    • Например, известную команду flush_all можно выполнить прямо через URL-адрес.

  • В таком виде мы можем быстро расшириться до простого сервиса управления memcached-кластером и выполнять различные операции
  • Преимущество этого заключается в том, что:
    • Независимо от того, какие другие связанные приложения написаны на php или любом другом запутанном языке, все они могут быть упакованы как http-интерфейсы.
    • Превратите всю бизнес-систему в протокол http, чтобы можно было эффективно уменьшить сложность системы.
  • Таким же образом можно упаковать и другие кластерные службы, такие как MySQL.
  • Включая известный кластер taobao для внешней разработки, похоже, это сервис, выпущенный для внешней экспансии.
    • По сути, различные сервисы внутри таобао тоже объединены в две формы.
    • Всем известно, что таобао — это система Java, и многие из его сервисов дополняются настройкой jvm.
    • Поэтому для исходного бизнеса али, бизнеса партнера и бизнеса нашего отдела статистики данных его нельзя использовать напрямую для jvm.
    • Что делать?Поэтому, благодаря бизнесу открытой платформы, различные внутренние сервисы инкапсулированы в серию http-интерфейсов для удобства использования.
    • Включая логин таобао, на самом деле он также инкапсулирован в http-интерфейс, который предоставляется для использования приложениями поддоменов таобао.
  • Независимо от того, какой язык разработки используется, всегда можно получить доступ к протоколу http.
    • А сам протокол http очень прост
    • Мы можем легко получить множество готовых инструментов для отладки/трассировки/оптимизации.
    • К тому же за счет выбора nginx стоимость http очень и очень низкая
  • Помните Qunar.com, первоначальный бизнес использовал десятки серверов MySQL.
    • Внешний интерфейс использует jodb Java для подключения
    • А поскольку код написан плохо, потому что бизнес-отдел при написании не обращает внимания на эффективность пула соединений,
    • Итак, нагрузка на каждый хост очень и очень высока.
    • Однако позже мы перешли на nginx в качестве внешнего интерфейса, и в результате один nginx может противостоять бизнесу десятков java-хостов раньше.
    • Инкапсулируя его в http-интерфейс, бизнес-код можно подключить для длинного/короткого соединения, что бы это ни было, оно может выдержать!
    • Итак, то, что их java-программисты назвали невыполнимой задачей, было решено хостом nginx.

  • Поскольку база данных инкапсулирована в http-интерфейс, мы используем внутренний пул соединений.
  • Эффективный пул соединений с базой данных, который был оптимизирован, и инженерам общего профиля не нужно обращать внимание на навыки создания пула соединений, просто сосредоточьтесь на завершении бизнес-кода, и не так просто сделать ошибки.
  • Кроме того, использование промежуточного программного обеспечения для конкретного языка связано с другими проблемами:
    • Является ли промежуточное ПО стабильным?Высокоэффективным?
    • Легко ли расширять и поддерживать промежуточное ПО?
    • Ряд задач и т.п. далеко не унифицированы в приложениях http Serve, реализованных на всех языках просто и лаконично
  • Даже позже мы представили полный язык Lua, который в основном достаточно совершенен, чтобы помочь нам завершить наш бизнес напрямую.
    • Куб данных Taobao собирается напрямую в nginx с помощью скрипта
    • По сравнению с исходной версией php один только этот пункт улучшает скорость отклика на порядок!
  • Таким образом, независимо от memcached или любой базы данных, мы можем объединиться в одно промежуточное ПО.
    • Промежуточное программное обеспечение протокола http имеет то преимущество, что его можно напрямую использовать извне.
    • Потому что контроль доступа на http легко сделать, а сложность невелика
    • Наша квантовая статистика напрямую интегрирована с мастер-сервисом taobao через http.
    • Может быть выпущен снаружи или внутри для безопасного использования с помощью простого обработчика с одним параметром.

2.3. ngx_drizzle

Через модули мы можем установить неблокирующую связь между приложением и MySQL.

  • Этот момент очень важен!
  • Потому что, когда передняя часть получает доступ к большому кластеру данных в задней части, ее собственные возможности параллелизма становятся узким местом.
  • Когда предполагается, что в бэкэнде около 100 MySQL, параллелизм самого бэкэнда уже очень велик.
  • Тем не менее, аналогичная технология php для внешнего интерфейса просто не может использовать возможности всех серверных хостов.
  • Итак, нам отчаянно нужны неблокирующие технологии
  • Прокси базы данных необходим, как и высокопроизводительный шлюз, чтобы стимулировать возможности всех серверов MySQL в бэкенде.
  • Вместо того, чтобы ожидать, что клиентские приложения будут выполнять параллельное планирование самостоятельно, основываясь на вышеуказанных знаниях, мы разработали неблокирующие восходящие модули для различных данных:
    • Включая поддержку MySQL/Postgres/redis и т. д.
    • Я также пробовал Oracole, но его официальный драйвер c имеет некоторые ограничения.Хотя он также обеспечивает неблокирующий интерфейс, он не является полным.
    • При установлении соединения и разрушении соединения это можно сделать только блокирующим способом, поэтому это очень запутано.
    • Официальный драйвер c для MySQL поддерживает только режим блокировки!
    • Потом пришлось искать сторонний драйвер, мы выбрали драйвер Drizzle и интегрировали его в модуль ngx_drizzle.

      upstream my_mysql_backend {
                 drizzle_server 127.0.0.1:3306 dbname=test
                             password=some_pass user=monty
                             protocol=mysql;
                 # a connection pool that can cache up to
                 #   200 mysql TCP connections
                 drizzle_keepalive max=200 overflow=reject;
             }

  • Мы просто настраиваем это так:
    • Настройте пароль и протокол подключения через drizzle_server, поскольку модуль может подключаться как к источникам данных MySQL, так и к источникам данных drizzle, поэтому режим протокола должен быть объявлен
    • Используйте drizzle_keepalive для создания пула соединений с верхним пределом 200. Когда лимит соединений будет превышен, он будет отклонен, что является довольно простой защитой для базы данных.
    • Затем определите интерфейс кошки, подобный этому

      location ~ '^/cat/(.*)' {
             set $name $1;
             set_quote_sql_str $quoted_name $name;
             drizzle_query "select *
                 from cats
                 where name=$quoted_name";
             drizzle_pass my_mysql_backend;
             rds_json on;
         }

    • После cat идет имя кота, которое получается с помощью set, являющегося функцией самого nginx
    • Затем используйте set_quote_sql_str, чтобы выйти из оператора запроса, чтобы предотвратить атаки SQL-инъекций.
    • Объединено в оператор запроса через drizzle_query
    • drizzle_pass для завершения запроса к серверному кластеру данных, потому что предыдущий drizzle_server может объявить группу серверов MySQL.
    • Даже мы настроили формат для набора результатов, возвращаемого запросом, который называется rds_json.
      • Этот формат предназначен для различных реляционных баз данных.
      • Для этого формата мы разработали серию фильтров для свободного вывода в формате csd или json.
      • Таким образом реализованы почти все интерфейсы отчетов
      • Taobao Express использует формат csd, потому что они используют его в качестве промежуточного программного обеспечения.
      • А мы напрямую через json в виде аякса
    • Таким образом, запрашивая Джерри, обращаясь к интерфейсу кота через curl, вы можете получить соответствующие данные кота по имени Джерри.
    • Вывод json здесь можно свободно настроить несколькими способами.
    • Например, некоторые требуют, чтобы каждая строка данных была в формате ключ/значение, некоторые требуют компактного формата, после того, как первая строка содержит ключ, все последующие являются данными и т. д.,

2.4. ngx_postgres

Тогда имя модуля интерфейса доступа к портам будет следующим: ngx_postgres.

  • Это делает польский хакер на основе нашего ngx_drizzle.
  • потому что он имитирует форму нашего интерфейса
  • Официальный модуль pg недоступен, поэтому потратил два месяца на прохождение этого модуля
  • Qunar.com, есть много мест, где используется этот модуль
  • Мы можем видеть, как использовать Lua для вызова этого стандартного модуля, потому что в веб-разработке с каждым уровнем скорость будет уменьшаться на один уровень, однако функция будет намного богаче.
  • Однако при использовании для этого модуля nginx штраф за скорость ограничен.

    upstream my_pg_backend {
           postgres_server 10.62.136.3:5432 dbname=test
                   user=someone password=123456;
           postgres_keepalive max=50 mode=single overflow=ignore;
       }

    • Здесь настраиваем переполнение. При игнорировании игнорируем, то есть когда соединение превышает лимит, сразу входим в режим короткого соединения
      location ~ '^/cat/(.*)' {
             set $name $1;
             set_quote_pgsql_str $quoted_name $name;
             postgres_query "select *
                 from cats
                 where name=$quoted_name";
             postgres_pass my_pg_backend;
             rds_json on;
         }

    • Это определяет pg-версию интерфейса cat.
    • Обратите внимание, что set_quote_pgsql_str запрашивается при выполнении экранирования SQL, потому что экранирование SQL pg отличается от других.

2.5. ngx_redis2

Затем, в прошлом году, я написал для развлечения модуль Redis: ngx_redis2.

  • Это по-прежнему 100% неблокирующий модуль, и Кунар и Тианья также часто используют этот модуль.

    upstream my_redis_node {
           server 127.0.0.1:6379;
           keepalive 1024 single;
       }
    • Также используйте восходящий поток для определения одного или нескольких пулов соединений.
    • Используйте keepalive для определения стратегии параллелизма.В этом сценарии потребление TCP-соединения в http очень низкое

      # multiple pipelined queries
         location /foo {
             set $value 'first';
             redis2_query set one $value;
             redis2_query get one;
             redis2_pass my_redis_node;
         }
    • Здесь я определил два запроса, используя redis2_query.
    • Через конвейерную форму в одном запросе отправляются две команды, а при получении ответа есть два ответа, которые возвращаются последовательно

2.6. ngx_srcache

ngx_srcache — интересный модуль кэширования общего назначения.

  • Я уже писал несколько модулей для apache, один из наиболее интересных — написать модуль memcached для модуля mod_cache, который может кэшировать любой ответ в apache через memcached!
  • Этот модуль изначально был разработан для системы извлечения поисковых роботов в поисковом бизнесе Yahoo!.
  • Я конечно обнаружил что при блокировке доступа к memcached в апаче он немного не в фокусе?По мере увеличения числа параллелизма скорость отклика быстро падает
  • Поэтому в nginx такой проблемы нет и гарантированно вся обработка не блокируется!В том числе доступ к memcached
  • Итак, мы можем решить, какой бэкенд использовать для хранения кеша в файле конфигурации.

    location /api {
           set $key "$uri?$args";
           srcache_fetch GET /memc key=$key;
           srcache_store PUT /memc key=$key&exptime=3600;
           # proxy_pass/drizzle_pass/postgres_pass/etc
       }
    • Здесь мы определяем два вида вызовов, так называемый fetch — это шаблон в apache, вызов c-level, но техника такая же, как и у get из http.
    • С местоположением, объявленным таким образом, мы можем одновременно обеспечивать звонки во внешний мир, а также мы можем звонить в другие местоположения внутри конфигурации!
      location /memc {
            internal;
            set_unescape_uri $memc_key $arg_key;
            set $memc_exptime $arg_exptime;
            set_hashed_upstream $backend my_memc_cluster $memc_key;
            memc_pass $backend;
        }
    • Таким образом, фактически, когда запрос получен, интерфейс /memc фактически вызывается для доступа к внутреннему кешу.
    • Получив результат, используйте интерфейс srcache_store, чтобы отсортировать место записи возвращенного запроса и установить соответствующий формат.
    • Интерфейс /memc помечается как внутренний и становится интерфейсом только для внутренних служб.
    • Позже мы передаем ряд инструкций, начиная с параметра url ;-)
      • Даже если это внутренний вызов, это все равно стандартный интерфейс HTTP-запроса.
    • Затем используйте set_hashed_upstream для кластеризации memcached.Выполните хэш по модулю на основе ключа и поместите результат в $backend
    • Наконец, используйте memc_pass для завершения запроса в кластере.
    • Как здесь определяется my_memc_cluster?

      upstream memc1 {
             server 10.32.126.3:11211;
         }
         upstream memc2 {
             server 10.32.126.4:11211;
         }
         upstream_list my_memc_cluster memc1 memc2;
  • Определите две службы, используя upstream, и объявите их как кластер, используя upstream_list.
  • На самом деле здесь есть ограничения:
    • Когда мы динамически добавляем хост
    • Мы хотим восстановить файл конфигурации, а затем использовать команду touch, чтобы сообщить nginx о перезагрузке.
    • И этого ограничения, как мы увидим, нет в реализациях на основе Lua ;-)

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

      <<< 29:51

2.7. ngx_iconv

В реальном использовании еще одним важным требованием является кодирование строк:

  • Потому что некоторые бизнесы основаны на gbk, а некоторые на utf-8.
  • Как правило, мы можем обрабатывать его на уровне базы данных.
  • Однако для некоторых продуктов с более слабыми функциями, таких как memcache/redis и т. д., нет возможности
  • Итак, мы завершили собственный модуль преобразования динамической кодировки:
    ngx_iconv
    
  • Независимо от того, какой способ вы используете для доступа к MySQL, например, обычный обратный прокси-сервер или что-то в этом роде.
  • Оба могут кодировать тело ответа через iconv_filter!
  • И это потоковое преобразование, то есть буфер не требуется, и преобразование завершается сразу с небольшим количеством данных.

    location /api {
           # drizzle_pass/postgres_pass/etc
           iconv_filter from=UTF-8 to=GBK;
       }
    • Выше это преобразование из utf-8 в gbk

      <<< 30:54

2.8 Встраивание Lua

Позже мы приложили много усилий, чтобы встроить Lua внутрь:

  • Это дает возможность реализовать любой сложный бизнес

    # nginx.conf
       location = /hello {
           content_by_lua '
               ngx.say("Hello World")
           ';
       }

    • Итак, мы завершили привет мир
    • ngx.say — это интерфейс, который lua предоставляет модулям.
  • Кроме того, конечно, вы также можете вызывать внешние скрипты
  • Так же, как когда мы пишем php-приложения, мы привыкли организовывать бизнес-скрипты отдельно в .php-файлах.
# nginx.conf
   location = /hello {
       content_by_lua_file conf/hello.lua;
   }

  • Вызов внешних файлов через content_by_lua_file:

    -- hello.lua
       ngx.say("Hello World")

  • Скрипты здесь могут быть сколь угодно сложными, либо вы можете использовать собственные библиотеки Lua

    Ранее мы в значительной степени полагались на подзапросы ngninx для повторного использования модуля запроса nginx:
  • Например, у нас есть модуль, которому требуется одновременный доступ ко многим бэкендам, таким как memcached/mysql/pg.
  • Что мне делать в это время? Вот оно:
location = /memc {
       internal;
       memc_pass ...;
   }
   location = /api {
       content_by_lua '
           local resp = ngx.location.capture("/memc")
           if resp.status ~= 200 then
               ngx.exit(500)
           end
           ngx.say(resp.body)
       ';
   }
  • Сначала установите соединение с memcache в /memc и объявите его внутренним интерфейсом.
  • Затем используйте ngx.location.capture в /api, чтобы инициировать запрос местоположения.
  • Точно так же, как сделать законный http-запрос, запросите его, но нет HTTP-накладных расходов, потому что это внутренний вызов c-уровня!
  • И это асинхронный вызов, хотя мы пишем его синхронно
  • Затем мы можем проверить, является ли ответ 200, иначе доступ к 500
  • Наконец, тело ответа может быть выведено

2.8.1 Асинхронное выполнение в синхронной форме!

Почему здесь можно писать синхронно?

  • Друзья, которые писали клиентские программы на javascript, должны знать, что для достижения асинхронных эффектов мы часто используем обратные вызовы.
  • И в Lua мы можем это сделать, потому что Lua поддерживает сопрограммы, то есть параллельные
  • Таким образом, мы можем разделить несколько логических потоков Lua уровня пользователя в один поток Lua.
  • Этот псевдопоток может обеспечить гораздо более высокий параллелизм, чем операционная система, потому что системные накладные расходы очень малы.
  • В последние годы появились некоторые технологии, которые также поддерживают параллельную технологию, которая может быть написана в том же порядке, что и HTTP-запрос.
  • Вам не нужно писать задом наперёд, как js-программистам, когда вам нужны последовательные операции, вам приходится заимствовать некоторые приёмы, а код для применения приёмов действительно уродлив и к нему невозможно привыкнуть.

    Поэтому очень важной причиной, по которой мы выбрали Lua, была поддержка сопрограмм.
  • Здесь мы предполагаем, что несколько источников данных должны быть доступны одновременно.
  • Более того, запрос не имеет зависимостей, тогда мы можем делать запросы одновременно
  • Таким образом, моя общая задержка — это самое медленное время всех моих запросов, а не суперпозиция всех исходных запросов!
  • Таким образом, время отклика заменяется параллелизмом.

    location = /api {
           content_by_lua '
               local res1, res2, res3 =
                   ngx.location.capture_multi{
                       {"/memc"}, {"/mysql"}, {"/postgres"}
                   }
               ngx.say(res1.body, res2.body, res3.body)
           ';
       }

    • Здесь мы делаем 3 запроса одновременно
    • Также в memcached/mysql/pg
    • Затем после нового ответа результаты возвращаются в три переменные res1/2/3, поэтому в этой модели также очень удобно реализовать параллельный доступ ;-)

      <<< 35:20

2.9. lua_shared_dict

Это модуль словаря общей памяти nginx, над которым я усердно работал в прошлом году: lua_shared_dict

  • Поскольку nginx — это модель с несколькими рабочими процессами, процессов может быть несколько.
  • Однако на самом деле количество воркеров не имеет никакого отношения к concurrency, который отличается от apache.
  • Цель nginx multi-worker — заполнить процессор, потому что это единый процесс
  • nginx на самом деле запускает только один поток операционной системы, поэтому в многоядерном хосте, если есть 8 ядер, мы обычно запускаем 8 рабочих процессов.
  • Если в бизнесе есть операции ввода-вывода с жестким диском, мы обычно запускаем немного большее количество рабочих процессов, чем количество ядер.
    • Потому что в Linux трудно выполнять неблокирующие операции на диске.
    • Хотя есть модель аио, но есть много других проблем
    • Итак, по сути, у nginx есть много рабочих процессов для полной загрузки процессора.
  • Затем, когда есть несколько процессов, возникает множество проблем сосуществования.
    • Например, мы хотим, чтобы конфигурация/бизнес-данные сосуществовали в нескольких процессах.
    • Поэтому, основываясь на сосуществующей памяти,

      lua_shared_dict dogs 10m;
         server {
             location = /set {
                 content_by_lua '
                     local dogs = ngx.shared.dogs
                     dogs:set("Tom", ngx.var.arg_n)
                     ngx.say("OK")
                 '
             }
             location = /get {
                 content_by_lua '
                     local dogs = ngx.shared.dogs
                     ngx.say("Tom: ", dogs.get("Tom"))
                 ';
             }

  • Вот пример:
    • Во-первых, используйте lua_shared_dict, чтобы выделить 10 МБ пространства.
    • Затем используйте ООП для определения двух интерфейсов: один /set и один /get
    • Затем, независимо от того, какой worker конкретно вызывает какую операцию
    • Но результат всегда один
  • Используйте curl, чтобы сначала установить, а затем получить его становится 59, потому что выполняется внутреннее самоинкрементирование
    • Реализация сосуществования достигается через красно-черное дерево + спинлок:
      • Поиск красно-черного дерева аналогичен алгоритму поиска по хеш-таблице.
      • Чтобы обеспечить согласованность данных при чтении и записи, используйте спин-блокировку, чтобы гарантировать
      • Поэтому при увеличении параллелизма или увеличении количества обновлений могут возникнуть проблемы со спин-блокировкой.В будущем мы планируем дополнительно модифицировать модель, сообщающую о грей.
    • На самом деле метод с общей памятью очень эффективен, когда накладные расходы на блокировку очень малы: запустить 200 000 одновременно на одной машине Tencent тривиально;

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

    -- api.lua
    -- asynchronous emit data as a response body part
    ngx.say("big data chunk")
    -- won`t return until all the data flushed out
    ngx.flush(true)
    -- ditto
    ngx.say("another big data chunk")
    ngx.flush(true)
    • Например, здесь мы сначала ngx.say выводим данные асинхронно
    • Эти данные не обязательно перелистываются, если сетевая карта не успеет вывести данные, они будут закэшированы в процессе nginx.
    • Если я хочу дождаться вывода данных, прежде чем продолжить, используйте ngx.flush. В настоящее время, только после того, как данные будут фактически сброшены в системный буфер, он вернется
    • Это гарантирует, что наш кеш nginx не низкий, а затем мы обрабатываем следующий сегмент данных
    • Таким образом реализуется потоковый вывод больших данных

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

2.10 Форма гнезда

Однако есть также некоторые медленные соединения, которые являются вредоносными атаками:

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

    <<< 40:50

    Таким образом, мне не нужно обращаться к http-запросам через восходящий модуль nginx:
  • Мы можем позволить Lua получить доступ к любой серверной службе напрямую через http или протокол сокетов unix.

    local sock = ngx.socket.tcp()
    sock:settimeout(1000)   -- one second
    local ok, err = sock:connect("127.0.0.1", 11211)
    if not ok then
       ngx.say("failed to connect: ", err)
       return
    end

  • Таким образом устанавливается порт сокета, и можно установить тайм-аут.
  • Мы можем осуществлять неблокирующий контроль доступа, по истечении которого nginx может автоматически приостановить работу и переключиться на другие сопрограммы для обработки.
  • Если все соединения неактивны, я также могу дождаться вызова системы epoll вместо того, чтобы оставаться там полностью.

    local bytes, err = sock:send("flush_all\r\n")
    if not bytes then
        ngx.say("failed to send query: ", err)
        return
    end
     
    local line, err = sock:receive()
    if not line then
        ngx.say("failed to receive a line: ", err)
        return
    end
     
    ngx.say("result: ", line)

  • Или используйте sock:send для возврата напрямую, вы можете продолжить другие запросы
  • Используйте получение, чтобы получить результат запроса. Если чтение завершилось неудачей, значит, с ним не удастся справиться. Если оно удастся, оно будет распечатано. Все в естественном порядке.

    local ok, err = sock:setkeepalive(60000, 500)
    if not ok then
        ngx.say("failed to put the connection into pool "
            .. "with pool capacity 500 "
            .. "and maximal idle time 60 sec")
        return
    end

  • Это вызов пула соединений
  • Через sock:setkeepalive модуль Lua поместит текущее соединение в другой пул соединений для повторного использования другими запросами.
  • То есть, если к тому же URL-адресу будут отправлены другие запросы, nginx напрямую передаст его исходному соединению, экономя потребление при открытии нового соединения.
  • keepalive имеет меньше параметров:
    • Первый — это максимальное время простоя, то есть максимальное время, в течение которого соединение помещается в пул соединений, когда его никто не использует.
      • Вот 60 секунд, потому что поддерживать соединение все равно очень дорого, если минуту никто не воспользуется, я активно закрою вас для экономии ресурсов
      • Для приложений с большими нагрузками это может уменьшить количество отходов.
    • Второй параметр — максимальное количество соединений,
      • Здесь 500. Если количество подключений превысит лимит, он автоматически перейдет в режим передачи подключений.

        Сокеты домена Unix — это уникальные интерфейсы процессов для систем Linux/Unix.
  • Хотя он не соответствует протоколу http, форма вызова полностью аналогична сокету tcp.

    local sock = ngx.socket.tcp()
    local ok, err = sock:connect("/tmp/some.sock")
    if not ok then
        ngx.say("failed to connect to /tmp/some.sock: ", err)
        return
    end

  • Таким же образом установить соединение через ngx.socket.tcp
  • Затем используйте sock:connect, чтобы указать специальный файл для подключения к сокету.
  • Можно выполнять различные ежедневные операции

2.11. concurrent ~ "cosocket"

Этот модуль основан на параллельном:

  • Запись идет последовательно, а выполнение не блокируется!Это очень важно!
  • Технология сопрограмм родилась несколько лет назад.
  • Тем не менее, 99,9% веб-приложений на сегодняшний день все еще блокируют
  • Потому что в первые годы разработка приложений на основе блоков была слишком привычна для
  • А асинхронная разработка требует от инженеров слишком много мыслительных способностей, поэтому инженеры Node.js являются основной головной болью в разработке.
  • Потому что требуется изменить образ мышления для рассмотрения проблемы, большинство наших программистов - php, и очень больно просить их изменить свое мышление.

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

      Однако есть еще одна очень важная причина, по которой мы выбрали Lua:
  • производительность процессора
  • Когда ваш режим параллелизма уже экстремальный
  • Процессор может легко стать узким местом!

    В нормальных условиях сначала пропускной способности не хватает, а потом процессор переполняется
  • Однако в модели apache памяти сначала не хватает
  • Часто бывает 24 процесса, своп 8G/24G продолжает расти, и он зависает и не может ничего воспроизвести.
  • А процессор там выполняет только переключение контекста, не делая ничего осмысленного, то есть так называемое внутреннее потребление

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

    Тем не менее, вы должны быть быстрыми, когда дело доходит до расчетов!
  • И насколько далеко продвинулись компиляторы Lua за последние годы?
  • Существует компилятор, который может динамически генерировать машинный код во время выполнения.
  • В наших тестах выше, чем gpc без включенных оптимизаций
  • А с включенным оптимизированным gpc потребление ресурсов выше, чем у Lua

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

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

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

    local sock, err = ngx.req.socket()
    if not sock then
        ngx.say("failed to get request socket: ", err)
        return
    end
    sock:settimeout(10000)  -- 10 sec timeout
     
    while true do
        local chunk, err = sock:receive(4096)
        if not chunk then
            if err == "closed" then
                break
            end
            ngx.say("faile to read: ", err)
            return
        end
        process_chunk(chunk)
    end

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

2.12. Реализация на высоком уровне

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

  • Мне потребовалось несколько лет, чтобы реализовать модуль подключения к MySQL на чистом Lua.
  • Теперь это реализовано с помощью нескольких сотен строк Lua-скрипта: lua-resty-mysql
    • И это очень полная реализация
    • Расширенные функции, такие как поддержка нескольких результатов/хранимых процедур
  • И производительность очень близка к модулю, написанному на чистом C. После моей оценки ответ хуже только на 10~20%.
  • Если в будущем я буду использовать C для перезаписи модуля обработки, требующего больших вычислительных ресурсов, производительность может быть значительно улучшена!

    lua-resty-memcached имеет длину чуть более 500 строк!
  • полная поддержка протокола memcached

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

    Сам протокол Redis очень продуман, несмотря на множество команд, базовый протокол передачи очень прост.
  • Итак, я реализовал его чуть более чем из 200 строк: lua-resty-redis

    Последние два модуля относительно грубы и инкапсулируют только протокол передачи, поэтому эффективность выполнения выше, чем у их официальных эквивалентов реализации c ;-)

    lua-resty-upload — упомянутый модуль загрузки больших файлов
  • Однако этот модуль написан относительно грубо.
  • API не выставлен достаточно изящно,

3. abt.

  • я здесьgithub.com/agentzhОтправляйте код каждый день;
  • Также листайте Weibo:weibo.com/agentzh/Однако в последнее время меньше чистил,

    <<< 53:00

QA:

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

  • Какую проблему openresty в основном решает с nginx, это дефект nginx?
    • Подумайте об этом двумя способами:
    • 1. Как дополнение к nginx, многие используют и так, например доступ под нагрузкой, упрощение настройки фронтенда F5, логическое управление доступом,
    • 2. Непосредственно служить механизмом для веб-приложений, напрямую реализовывать все приложения, выводить веб-страницы, публиковать веб-сервисы и т. д.

  • В чем основная разница в производительности с apache?
    • В основном существенная разница в модели ввода/вывода
    • nginx + Lua может добиться улучшения на порядок
    • И, как приложение или как httpd, он может одновременно выполнять двойную функцию!

  • t2t визуализировать::2013-12-13 02:41:34
  • Питаться от::txt2tags