- Деятельность:Итоги салона технологий 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. Отказ от ответственности
- Записи/слайды принадлежат авторам, авторские права конечно принадлежат им
- Расшифровка из Zoom.Quiet, все проблемы с текстом по моей вине, к оригиналу отношения не имеют
- Из-за моих ограниченных технологий я использую только слайды и записи, я несу ответственность за любые ошибки в моей памяти и не имею никакого отношения к оригинальному автору.
- Любое недовольство и комментарии, пожалуйста, свяжитесь со мной напрямую для улучшения
- zoomquiet+nginx@gmail.com
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
- Другие совсем плохие,Самая большая проблема апача - его модель ввода/вывода, которая не может дать очень эффективного ответа, но плюсы: интерфейс разработки обычный, и на его основе очень удобно писать моды; Lighttpd как раз наоборот, его ввод-вывод очень эффективен, но интерфейс разработки не очень удобен; и Nginx сочетает в себе преимущества обоих ;-)
- С одной стороны, используется модель 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 локально представляет собой небольшой язык, например:
Эта конфигурация также знакома пользователям Apache.location = '/hello' { set_unescape_uri $person $arg_person; set_if_empty $person 'anonymous'; echo "hello, $person!"; }
- Сначала мы используем форму, похожую на регулярные выражения, чтобы согласовать 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
- Выше это преобразование из utf-8 в gbk
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