Открытие файлов слишком много запросов
В SQL Server топ запросов по потреблению ресурсов можно получить из кэша планов запросов или с помощью Query Store.
Первый способ не требует никаких предварительных настроек. DMV sys.dm_exec_query_stats, sys.dm_exec_sql_text и sys.dm_exec_query_plan предоставляют доступ, соответственно, к статистике выполнения, текстам и планам запросов из кэша. К недостаткам этого метода относится то, что в кэше сохраняются не все версии планов запросов, и то, что кэш не предназначен для постоянного хранения и может быть очищен.
Чтобы использовать Query Store его нужно включить, настроить и подождать пока в хранилище накопятся нужные данные.
Коротко рассмотрим оба способа.
Для получения информации о ресурсоемких запросах из кэша планов запросов можно использовать следующий запрос:
Здесь DMV соединяются по идентификатору плана запроса в кэше – plan_handle. Результатом выполнения станет топ запросов по среднему процессорному времени:
Аналогично запросы можно упорядочить и по другим метрикам производительности, таким как логические или физические чтения.
Второй способ – Query Store, который впервые появился в SQL Server 2016. Включить его можно в окне свойств базы данных или с помощью запроса, например:
Помимо прочих возможностей Query Store позволяет просматривать отчет «Основные запросы, потребляющие ресурсы» («Top Resource Consuming Queries»). Откроем отчет и выберем метрику «Время ЦП (мс)»:
Первым в топе мы видим тот же самый запрос, который ранее мы получили из кэша планов запросов с помощью DMV.
В правой части окна мы видим сводку разных вариантов плана этого запроса. Каждая отметка обозначает не единичное выполнение, а обобщенную информацию по выполнениям за интервал времени. Переключившись в табличный формат сводки можно узнать точные значения метрик, а также значение счетчика выполнения запроса. Наш запрос выполняется с высокой периодичностью.
В нижней части окна отчета выводится текст запроса и план его исполнения.
Теперь, когда запрос для оптимизации выбран, выясним, что это за запрос. Для того чтобы определить место вызова запроса в конфигурации, настроим технологический журнал 1С следующим образом:
После того, как запрос в очередной раз выполнится, в технологическом журнале мы найдём следующую запись:
В журнале фиксируется контекст исполнения оператора. В данном случае мы имеем дело с одной из процедур регламентного задания отражения документов в регламентированном учете. Этим и объясняется высокая частота выполнения запроса:
Мы видим, что текст запроса перед выполнением модифицируется. Если посмотреть процедуру ДобавитьВЗапросФильтрОтраженияВРеглУчете(), то можно сказать, что это делается с целью повторного использования кода.
Получим окончательный текст запроса с помощью отладчика:
Теперь выясним, как SQL Server выполняет этот запрос, и почему он входит в топ запросов по потреблению ресурсов.
План исполнения запроса, который мы видим в нижней части отчета Query Store – это предполагаемый план (Estimated Plan), сформированный до выполнения запроса. Чтобы дополнить его информацией времени выполнения, т.е. получить фактический план (Actual Plan), воспользуемся Extended Events.
Сеанс Extended Events можно создать с помощью графических средств, но быстрее и проще это сделать с помощью запроса:
Для события query_post_execution_showplan мы установили отбор по имени базы данных и шаблону текста запроса. В параметрах события мы включили дополнительное поле – sqlserver.sql_text (текст запроса).
Из контекстного меню созданного сеанса запустим сеанс и откроем окно событий – «Наблюдать за данными, передаваемыми в режиме реального времени» («Watch Live Data»).
Мы видим, что наш запрос выполняется за 5,7 секунд (поле duration). Оптимизатор запросов оценил его предполагаемую стоимость как 180 (поле estimated_cost) и, в соответствии с настройками параллелизма, для запроса выбрана параллельная версия плана исполнения (поле dop). Для сравнения, порог стоимости плана запроса для использования параллелизма (cost threshold for parallelism) по умолчанию – 5.
Поле sql_text содержит текст запроса. Скопировав его в редактор запросов SSMS можно получить запрос в отформатированном виде:
Обратите внимание на условие отбора по полю Fld1490 для каждой таблицы. Это поле разделителя с типом "ОбщийРеквизит.ОбластьДанныхОсновныеДанные". Платформа 1С неявно подставляет такие условия в запросы для конфигураций, в которых заложена возможность разделения данных, независимо от того, включено разделение или нет. Это относится ко всем конфигурациям, основанным на современных версиях БСП.
Для того, чтобы узнать каким объектам конфигурации соответствуют таблицы и поля базы данных, нужно воспользоваться функцией глобального контекста ПолучитьСтруктуруХраненияБазыДанных(). Результат её выполнения можно посмотреть в отладчике:
Таким же способом можно получить структуру индексов таблиц базы данных:
Первое, что бросается в глаза в плане исполнения нашего запроса – это толщина стрелок, изображающих потоки данных. Мы видим, что вся таблица регистра сведений ОтражениеДокументовВРеглУчете (InfoRg30933), в которой более 1,3 миллионов записей, попарно соединяется с каждой из основных таблиц трех документов, участвующих в запросе. Если быть точным, соединяются не таблицы, а результаты поиска по некластеризованным индексам, где предикатом является значение поля разделителя Fld1490, которое уже было упомянуто выше. Т.к. разделение в базе отключено, селективность этого предиката равна единице, т.е. возвращаются все строки таблиц.
Во всех трех случаях для соединения используется оператор Hash Match. Оптимизатор обычно использует этот оператор для соединения больших входных данных, если они не отсортированы по полям соединения.
При соединении оператором Hash Match вычисляются хеши полей соединения верхних входных данных, называемых «Build». Таблица со значениями полей соединения и их хешами помещается в оперативную память. После этого выполняется построчное чтение нижних входных данных, называемых «Probe». Для каждой строки вычисляется хеш значений полей соединения и сравнивается с хешами в таблице из оперативной памяти. Для эффективного выполнения в качестве «Build» (верхних входных данных) выбирается меньший из двух потоков.
Поля, по которым выполняется соединение, можно увидеть в свойстве «Hash Keys Probe» оператора Hash Match.
В нашем случае стоимость операторам Hash Match увеличивает ещё и дополнительный предикат, соответствие которому должно быть проверено в ходе соединений. Его можно увидеть в свойстве «Probe Residual» операторов:
Из-за объема данных в нижнем потоке эти три оператора Hash Match наиболее затратны по CPU.
Наш запрос входит в топ по процессорному времени и по той причине, что для его исполнения используется параллелизм. Параллелизм уменьшает время выполнения запроса, но увеличивает потребление ресурсов. Если есть необходимость, параллелизм можно отключить не на уровне экземпляра или базы данных, а для конкретного запроса, добавив к запросу «Хинт» (Hint): OPTION (MAXDOP 1). Т.к с помощью средств платформы 1С мы не можем непосредственно изменять sql-запросы, хинт можно добавить в SSMS с помощью т.н. «Структуры планов» (Plan Guide):
Рассмотрим теперь этот фрагмент плана исполнения:
На плане мы видим, что верхний поток, в котором 1,3 млн. записей (результат соединения регистра сведений с документами), соединяется с таблицей константы «ДатаНачалаВеденияРеглУчета» с помощью оператора Nested Loops. В современных версиях платформы 1С каждой константе соответствует своя отдельная таблица базы данных.
Перед соединением на таблицу константы, как и на все другие таблицы, накладывается отбор по значению разделителя. Чтобы не производить поиск по этому значению на каждой итерации Nested Loops, результат поиска в индексе записывается в tempdb c помощью оператора Table Spool.
При выполнении Nested Loops операторы нижней ветки, в данном случае Table Spool, выполняются столько раз, сколько строк содержит верхний входящий поток, в нашем случае более 1,3 млн. раз. Это неоптимальное использование оператора Nested Loops, который эффективен, только если верхний поток содержит сравнительно малое количество строк.
Оператор Nested Loops проверяет условия соединения одним из двух способов. В нашем случае условия соединения находятся в свойстве «Predicate» оператора. Это значит, что оператор Nested Loops отбирает строки, соответствующие условиям, после того как получит значения из внутреннего цикла (нижняя ветка). Значения из верхнего набора строк в нижний не передаются. Нижние входящие данные в нашем случае статичны и возвращают одни и те же значения при каждом выполнении.
Условия соединения могут также проверятся в нижней ветке (во внутренних циклах). В этом случае мы бы увидели условия не в свойстве «Predicate», а в свойстве «Outer References» оператора Nested Loops.
Если мы посмотрим значение свойства «Predicate» оператора Nested Loops в плане исполнения нашего запроса, то мы увидим там все условия из секции «ГДЕ» запроса.
Способ оптимизации этого запроса достаточно прост. Нужно применить отборы как можно раньше, чтобы уменьшить объем соединяемых данных. При этом поиск данных, соответствующих условиям отбора, по возможности должен выполняться с помощью индексов.
Перепишем запрос следующим образом:
Выполним запрос и посмотрим метрики его производительности в Extended Events:
Мы видим, что на этот раз исполнитель запросов счел запрос достаточно простым, чтобы выполнить его на одном логическом процессоре (estimated_cost=0, dop = 1). При этом измененный запрос выполнился за 0.13 секунд, т.е. в 43 раза быстрее оригинального запроса. Процессорное время, затраченное на выполнение (cpu_time), теперь равно 123870 микросекунд, что в 88 раз меньше, чем у оригинального запроса.
Посмотрим теперь на текст sql-запроса и на план его исполнения:
Для реализации логической операции объединения (Union) оптимизитор использовал физический оператор Merge Join, который требует, чтобы входные данные были упорядочены по полям объединения и не содержали дубликатов. Сам оператор Merge Join (Union) исключает из объединения дубликаты строк, которые есть в обоих наборах, но не учитывает дубликаты, которые могут быть в каждом из наборов по отдельности. Поэтому оптимизатор явным образом удаляет из наборов дубликаты либо с помощью оператора Sort (Distinct Sort), либо с помощью оператора Stream Aggregare (если данные в наборе уже упорядочены по нужным полям):
Посмотрим теперь, как оптимизатор формирует каждый из пяти объединяемых наборов данных, начиная с верхнего.
В секции «ГДЕ» верхнего запроса мы видим условия отбора по ресурсу «Статус» и по измерению «ДатаОтражения» регистра «ОтражениеДокументовВРеглУчете». Значения параметра &СтатусыОтражения передаются в запрос и объединяются с помощью оператора Concatenation. Ресурс «Статус» регистра проиндексирован, и поиск значений статусов выполняется в этом индексе.
Условие по Статусу высокоселективное: из 1.3 млн. строк выбирается 4 тысячи. Далее эти 4 тысячи строк соединяются с таблицей константы с отбором по Дате отражения, уже без использования индексов:
Используя терминологию из
Наконец, для получения результата последнего из пяти запросов, достаточно выполнить поиск по индексу, т.к. все элементы в секции «ГДЕ», несмотря на то, что они объединены оператором «ИЛИ», накладывают отбор по одному и тому же полю – Регистратору.
Таким образом, для применения всех основных условий запроса мы использовали индексы, и избежали неэффективных соединений больших объемов данных. Этим и объясняется значительная разница в количестве процессорного времени, используемого для выполнения запросов.
Оригинальный запрос заменим оптимизированным в расширении конфигурации. В данном случае безопасней всего это сделать, расширив метод «ДобавитьВЗапросФильтрОтраженияВРеглУчете()» следующим образом:
Если после обновления конфигурации оригинальный запрос будет изменен, эта замена автоматически перестанет выполняться.
Я использую модуль запросов для POST нескольких файлов на сервер, это прекрасно работает большую часть времени. Однако, когда загружается много файлов >256, я получаю IOError: [Errno 24] слишком много открытых файлов. Проблема возникает из-за того, что я создаю словарь со многими файлами, которые открываются, как показано в приведенном ниже коде. Поскольку у меня нет ручки, чтобы закрыть эти открытые файлы, мы видим эту ошибку. Это приводит к следующим вопросам
Закрывает ли модуль запросов открытые файлы автоматически?
Обходной путь, который я использую прямо сейчас, - это files.clear() после загрузки < 256 файлов одновременно. Я не уверен, что файлы закрываются при этом, но ошибка исчезает.
2 ответа
Я использую mongo-java2.4jar для связи с сервером mongo. В моем веб-приложении я использую mongo=new Mongo(serverIp,port) там, где это требуется, и как только обработка завершена, я закрываю соединение mongo с помощью mongo.close() . Но через некоторое время я получаю следующее исключение .
я новичок в программировании ios, когда мое приложение работает, я принимаю эти ошибки. Я загружаю 950 + изображений в свое приложение и использую ARC. ImageIO: CGImageRead_mapData 'open' failed '/ Users/apple/Library/Application Support/iPhone.
Самое простое решение здесь-самостоятельно прочитать файлы в память, а затем передать их в запросы. Обратите внимание, что, как говорится в документах , "Если вы хотите, вы можете отправлять строки для получения в виде файлов". Так что сделай это.
Другими словами, вместо того, чтобы создавать диктат, подобный этому:
. постройте его вот так:
Теперь у вас есть только один файл, открытый одновременно, гарантированный.
Это может показаться расточительным, но на самом деле это не так— requests просто будет read во всех данных из всех ваших файлов, если вы этого не сделаете.*
Но пока позвольте мне ответить на ваши реальные вопросы вместо того, чтобы просто говорить вам, что делать.
Поскольку у меня нет дескриптора для закрытия этих открытых файлов, мы видим эту ошибку.
Конечно, знаешь. У вас есть диктант, значениями которого являются эти открытые файлы.
На самом деле, если бы у вас не было ручки для них, эта проблема, вероятно, возникала бы гораздо реже, потому что сборщик мусора (обычно, но не обязательно достаточно надежно/надежно, чтобы рассчитывать на это) заботился бы о вас. Тот факт, что это никогда не происходит, подразумевает, что вы должны иметь с ними дело.
Есть ли способ закрыть эти файлы по частям?
Конечно. Я не знаю, как вы делаете куски, но , по-видимому, каждый кусок-это список ключей или что-то в этом роде, и вы передаете files = , верно?
Итак, после запроса сделайте это:
Или, если вы создаете dict для каждого куска, как это:
. просто сделай это:
Закрывает ли модуль запросов открытые файлы автоматически?
Нет, вы должны сделать это вручную.
Во многих случаях использования вам никогда не удается этого сделать, потому что переменная files исчезает вскоре после запроса, и как только ни у кого нет ссылки на dict, она вскоре очищается (немедленно, с CPython и если нет циклов; просто "soon", если ни один из них не соответствует действительности), что означает, что все файлы вскоре очищаются, и в этот момент деструктор закрывает их для вас. Но вы не должны полагаться на это. Всегда закрывайте свои файлы явно.
И причина, по которой files.clear() , похоже, работает, заключается в том, что он делает то же самое, что и отпускает files : он заставляет диктатора забыть все файлы, что удаляет последнюю ссылку на каждый из них, что означает, что они скоро будут очищены и т. Д.
У меня проблема с ошибкой: PHP не удалось открыть поток: слишком много открытых файлов. Я просмотрел различные ответы здесь, на stackoverflow, но я не могу решить эту проблему. В основном я пытался увеличить лимит макс. открытых файлов: Я отредактировал /etc/security/limits.conf, где я указал это.
Просто реализуйте класс-оболочку для ваших файлов:
Таким образом, каждый файл открывается и закрывается по одному, когда requests повторяет дикт.
Обратите внимание, что, хотя этот ответ и ответ абарнерта в основном делают одно и то же прямо сейчас, requests может в будущем не создавать запрос полностью в памяти, а затем отправлять его, но отправлять каждый файл в потоке, сохраняя низкое использование памяти. В этот момент этот код будет более эффективным для памяти.
Похожие вопросы:
Я наткнулся на ошибку, которую не могу понять, даже после обширных поисков в интернете. Я запускаю проект Maven в Java-SSH в удаленном месте, проект отлично строился в течение прошлой недели, пока я.
Я использую mongo-java2.4jar для связи с сервером mongo. В моем веб-приложении я использую mongo=new Mongo(serverIp,port) там, где это требуется, и как только обработка завершена, я закрываю.
я новичок в программировании ios, когда мое приложение работает, я принимаю эти ошибки. Я загружаю 950 + изображений в свое приложение и использую ARC. ImageIO: CGImageRead_mapData 'open' failed '/.
Я хочу знать точную проблему слишком большого количества файлов, открытых с ошибкой. Я прошел через google для решения, но я не мог понять, почему эта проблема возникает и как решить эту проблему.
У меня проблема с ошибкой: PHP не удалось открыть поток: слишком много открытых файлов. Я просмотрел различные ответы здесь, на stackoverflow, но я не могу решить эту проблему. В основном я пытался.
Мы запускаем веб-сервис в Apache Tomcat в Amazon Linux. Изначально веб-сервис работает нормально. Мы получаем слишком много открытых файлов исключения после того, как сделали более 1000.
Эй, ребята, я застрял в этой ошибке, мне действительно нужна помощь: Ошибка: слишком много открытых файлов. for i in data_files[:8]: try: data_temp = np.load(i) nat_queue +=.
Я использую wildfly (wildfly-10.0.0.Final) в качестве сервера приложений, когда я развернул файл abt 30 wars. каждая война посылает rest api для связи с другими. когда-то я получил ошибку, как.
Анализ и решение Слишком много открытых файлов в Linux
Сегодня в журналах службы появилось большое количество исключений:
Слишком много открытых файлов Эта проблема в основном относится к процессу, пытающемуся открыть файл или дескриптор, но дескриптор, открытый процессом, достиг верхнего предела, и новый дескриптор не может быть открыт.
Как только эта проблема упоминается в Интернете, верхний предел дескриптора должен быть увеличен, и это часто происходит потому, что неправильное использование дескриптора можно назвать утечкой дескриптора. Причина поиска дескриптора для достижения верхнего предела является главной.
Ниже приведено введение в дескрипторы в Linux
Для этих дескрипторов в Linux имеется ограниченное количество, максимальное количество дескрипторов, которые отдельный процесс может открыть по умолчанию, вы можете использовать следующую команду для просмотра:
Результаты приведены ниже:
Одним из открытых файлов является число дескрипторов по умолчанию, в настоящее время количество дескрипторов по умолчанию равно 1024.
Вы также можете установить верхний предел количества дескрипторов процесса.
Результаты приведены ниже:
Также посмотрите на открытые файлы, вы можете увидеть, что верхний предел дескриптора процесса составляет 1024
Количество дескрипторов можно изменить. Чтобы изменить количество дескрипторов по умолчанию, введите следующую команду:
Эта команда может изменить количество дескрипторов по умолчанию на 2000, но значение по умолчанию будет восстановлено после перезапуска системы
Значение по умолчанию этого файла в системе настраивается в файле /etc/security/limits.conf, и добавляется следующая конфигурация:
Жесткая настройка - это фактическое значение по умолчанию, которое является верхним пределом, а мягкая конфигурация используется только для предупреждения. Если мягкое значение будет превышено, появится предупреждение, а третья конфигурация с короткой горизонтальной линией - жесткая. Настраивается одновременно как софт.
Давайте посмотрим, как запросить количество дескрипторов, занятых процессами в системе
Команда lsof - это команда системного мониторинга в Linux. Она может просматривать файлы и порты, открытые процессом. Она мощная. Приведенная выше команда сохраняет количество дескрипторов и PID только после прохождения через серию каналов. Результаты выполнения следующие:
Первый столбец - количество дескрипторов, второй столбец - идентификатор процесса.
Можно видеть, что число дескрипторов первых двух процессов превысило верхний предел, что является исключением из верхней части статьи, о которой сообщают журналы этих двух процессов.
Следующий запрос, какие ручки заняты процессом
Например, чтобы запросить процесс с PID 25950, используется команда
Результаты приведены ниже:
Здесь часть перехвата, смысл каждого столбца следующий:
3. Владелец процесса
4. Файловый дескриптор
Существует несколько типов файлов:
DIR: указывает на каталог.
CHR: указывает тип символа.
BLK: блочный тип устройства.
UNIX: доменный сокет UNIX.
FIFO: очередь первым пришел - первым вышел (FIFO).
IPv4: сокет интернет-протокола (IP).
УСТРОЙСТВО: Укажите название диска
РАЗМЕР: размер файла
NODE: Inode (идентификация файлов на диске)
NAME: точное имя открываемого файла
В процессе, который я рассмотрел, было открыто необычно большое количество файлов типа IPv4, которые можно использовать в качестве подсказки для анализа причины конкретного переполнения дескриптора. В первом примере статьи это произошло потому, что программа продолжала инициировать соединение с другим сервером, что приводило к тому, что дескриптор превышал верхний предел (который также можно анализировать из информации об исключении).
Интеллектуальная рекомендация
[Makefile от более мелких к более глубоким полная запись обучения 4] Переменные и различные методы присвоения
Давайте сегодня узнаем о различных методах присваивания переменных в Makefile! Смысл тяжелой работы, чтобы бедность больше не ограничивать свое воображение! Добавьте QQ, чтобы вместе учиться и обменив.
[Luogu P3147] [BZOJ 4576] [USACO16OPEN]262144
Портал Луогу БЗОЙ Портал Описание заголовка Bessie likes downloading games to play on her cell phone, even though she doesfind the small touch screen rather cumbersome to use with her large hooves. Sh.
Ниже приведены некоторые распространенные типы регулирования, которые могут возникнуть в приложении логики.
Регулирование приложений логики
Служба Azure Logic Apps имеет собственные ограничения пропускной способности. Если приложение логики превышает эти ограничения, то регулируется ресурс этого приложения, а не только конкретного экземпляра или выполнения.
Чтобы найти события регулирования на этом уровне, проверьте панель Метрики приложения логики на портале Azure.
Откройте приложение логики в конструкторе приложений логики на портале Azure.
В меню слева в разделе Мониторинг выберите Метрики.
В разделе Заголовок диаграммы выберите Добавить метрику, чтобы добавить к существующей метрике еще одну.
В первой строке метрики в списке Метрики выберите События, регулируемые действием. Во второй строке метрики в списке Метрики выберите События, регулируемые триггером.
Для управления регулированием на этом уровне доступны следующие варианты.
Ограничьте количество экземпляров приложения логики, которые могут выполняться одновременно.
По умолчанию, если условие триггера приложения логики будет выполняться несколько раз одновременно, то несколько экземпляров триггеров для приложения логики выполняются параллельно, или одновременно. Это означает, что каждый экземпляр триггера срабатывает до завершения выполнения предыдущего экземпляра рабочего процесса.
Хотя количество экземпляров триггеров, которые могут выполняться одновременно, не ограничено, можно ограничить это число, включив параметр параллелизма триггера и при необходимости выбрав ограничение, отличное от значения по умолчанию.
Включение высокой пропускной способности.
Приложение логики имеет ограничение по умолчанию для количества действий, которые могут выполняться в течение 5-минутного интервала. Чтобы увеличить это ограничение до максимального количества действий, включите режим высокой пропускной способности в приложении логики.
Отключите режим депакетирования массива (параметр "Разделить на") в триггерах.
Если триггер возвращает массив для обработки оставшихся действий рабочего процесса, то параметр Разделить на для этого триггера разделяет элементы массива и запускает экземпляр рабочего процесса для каждого элемента массива, фактически выполняя несколько одновременных запусков до ограничения Разделить на. Для управления регулированием отключите поведение Разделить на, пусть приложение логики обрабатывает весь массив одним вызовом, а не по одному элементу за вызов.
Разбивайте действия на меньшие приложения логики.
Как говорилось выше, приложение логики ограничено количеством действий по умолчанию, которые могут выполняться в течение 5-минутного периода. Хотя это ограничение можно увеличить, включив режим высокой пропускной способности, есть также другой вариант — разбить действия приложения логики на более мелкие приложения логики, чтобы количество действий, выполняемых в каждом приложении, было в пределах ограничения. Таким образом вы сократите нагрузку на один ресурс приложения логики, распределив нагрузку между несколькими приложениями логики. Такое решение лучше подойдет для действий, которые обрабатывают большие наборы данных или запускаются для параллельного выполнения множества действий, итераций или действия в каждой итерации цикла, число которых превышает предел выполнения действия.
Например, такое приложение логики выполняет всю работу по получению таблиц из базы данных SQL Server и получает строки из каждой таблицы. Цикл for each параллельно проходит по каждой из таблиц, чтобы действие Получить строки возвращало строки для каждой таблицы. В зависимости от объема данных в таблицах такие действия могут превысить ограничение на количество выполнений.
После рефакторинга приложение логики разделится на родительское и дочернее приложения логики. Родительское приложение получает таблицы из SQL Server, а затем вызывает дочернее приложение логики для каждой таблицы, чтобы получить строки:
Ниже показано дочернее приложение логики, которое вызывается родительским приложением логики для получения строк для каждой из таблиц:
Регулирование соединителя
Каждый соединитель имеет собственные ограничения регулирования, которые можно найти на странице технического справочника по соединителю. Например, соединитель служебной шины Azure имеет ограничение регулирования до 6000 вызовов в минуту, в то время как соединитель SQL Server имеет ограничения регулирования, которые зависят от типа операции.
Чтобы узнать, поддерживает ли триггер или действие политику повтора, проверьте параметры триггера или действия. Чтобы просмотреть количество попыток триггера или действия, перейдите в журнал выполнения приложения логики, выберите запуск, который необходимо просмотреть, и разверните этот триггер или действие, чтобы просмотреть сведения о входных и выходных данных, а также обо всех повторных попытках. Например:
Хотя журнал повторных попыток содержит сведения об ошибках, возможно, это просто проблемы регулирования соединителя и регулирования назначения. В этом случае может потребоваться просмотр данных ответа или выполнение некоторых вычислений интервала регулирования, чтобы выяснить источник.
Для приложений логики в глобальной многоклиентской службе Azure Logic Apps выполняется регулирование на уровне соединения. Например, для приложений логики, выполняемых в среде службы интеграции (ISE), регулирование по-прежнему происходит для соединений, не связанных с ISE, так как они выполняются в глобальной многоклиентской службе Logic Apps. Но подключения ISE, созданные с помощью соединителей ISE, не регулируются, так как они выполняются в интегрированной среде сценариев.
Для управления регулированием на этом уровне доступны следующие варианты.
Настройте несколько подключений для одного действия, чтобы приложение логики секционировало данные для обработки.
Для этого варианта рассмотрите возможность распределения рабочей нагрузки путем разделения запросов действия на несколько соединений к одному назначению с использованием одних и тех же учетных данных.
Предположим, приложение логики получает таблицы из базы данных SQL Server, а затем получает строки из каждой таблицы. В зависимости от количества строк, которые необходимо обработать, можно использовать несколько соединений и несколько циклов for each, чтобы разделить общее количество строк на меньшие наборы для обработки. В этом сценарии используется два цикла for each для разделения общего количества строк пополам. Первый цикл for each использует выражение, которое получает первую половину. В другом цикле for each используется второе выражение, которое получает вторую половину. Например:
Выражение 1. Функция take() возвращает первую часть коллекции. Дополнительные сведения см. по функции take() .
@take(collection-or-array-name, div(length(collection-or-array-name), 2))
Выражение 2. Функция skip() удаляет начало коллекции и возвращает все остальные элементы. Дополнительные сведения см. по функции skip() .
@skip(collection-or-array-name, div(length(collection-or-array-name), 2))
Ниже приведен визуальный пример, демонстрирующий использование этих выражений.
Для каждого действия настраивайте собственное соединение.
Для этого рассмотрите возможность распределения рабочей нагрузки, распределив запросы от каждого из действий по собственному соединению, даже если действия подключаются к одной службе или системе и используют одни и те же учетные данные.
Предположим, приложение логики получает таблицы из базы данных SQL Server, а затем получает строки из каждой из таблиц. Можно разделить соединения так, чтобы для получения таблиц использовалось одно соединение, а для получения строк использовалось другое.
По умолчанию итерации цикла "for each" запускаются одновременно до достижения предела по умолчанию. Если у вас есть соединитель, который регулируется внутри цикла "for each", то можно уменьшить количество итераций цикла, выполняемых параллельно. Дополнительные сведения см. в следующих статьях:
Служба или система назначения
Хотя соединитель имеет собственные ограничения регулирования, целевая служба или система, вызванная соединителем, может также иметь ограничения регулирования. Например, некоторые API в Microsoft Exchange Server имеют более широкие ограничения регулирования, чем соединитель Office 365 Outlook.
По умолчанию экземпляры приложения логики и любые циклы или ветви внутри этих экземпляров выполняются параллельно. Это означает, что несколько экземпляров могут одновременно вызывать одну и ту же конечную точку. Каждый из экземпляров не знает о существовании другого, поэтому попытки повторения неуспешных действий могут привести к состоянию гонки, когда несколько вызовов пытаются выполниться в одно и то же время, однако для их успешного выполнения эти вызовы должны поступить в целевую службу или систему до начала регулирования.
Предположим, имеется массив, содержащий 100 элементов. Для просмотра массива используется цикл "for each", и включение контроля параллелизмом цикла позволит ограничить количество параллельных итераций до 20 или до текущего ограничения по умолчанию. Внутри этого цикла действие вставляет элемент из массива в базу данных SQL Server, которая разрешает всего 15 вызовов в секунду. В этом сценарии возникает проблема регулирования, так как скапливается очередь невыполненных попыток повтора и поэтому выполнение не происходит.
В этой таблице описана временная шкала событий, происходящих в цикле, когда интервал повтора действия равен 1 секунде:
На момент времени | Количество выполненных действий | Количество невыполненных действий | Количество повторных попыток |
---|---|---|---|
T + 0 секунд | 20 вставок | 5 ошибок, из-за ограничения SQL | 5 повторов |
T + 0,5 секунд | 15 вставок, из-за предыдущих 5 попыток в ожидании | Все 15 завершатся ошибкой из-за того, что предыдущее ограничение SQL действует еще 0,5 секунды | 20 повторов (5 предыдущих + 15 новых) |
T + 1 секунда | 20 вставок | 5 ошибок плюс предыдущих 20 повторов, из-за ограничения SQL | 25 повторов (20 предыдущих + 5 новых) |
Для управления регулированием на этом уровне доступны следующие варианты.
Создайте приложения логики таким образом, чтобы каждое из них обрабатывало единственную операцию.
Продолжая пример сценария SQL Server, приведенный в этом разделе, можно создать приложение логики, которое помещает элементы массива в очередь, например очередь служебной шины Azure. А затем создать другое приложение логики, которое будет выполнять только операцию вставки для каждого элемента в этой очереди. Таким образом, только один экземпляр приложения логики будет выполняться в один момент времени, и либо будет завершена операция вставки и переход к следующему элементу в очереди, либо экземпляр получит ошибку 429 и не будет пытаться выполнять бесперспективные повторы.
Создайте родительское приложение логики, которое вызывает дочернее или вложенное приложение логики для каждого действия. Если родительскому приложению необходим вызов различных дочерних приложений исходя из результата, то можно использовать действие условия или переключателя, определяющее, какое дочернее приложение будет вызываться. Это позволит сократить количество вызовов или операций.
Предположим, есть два приложения логики, каждое с триггером опроса, проверяющим учетную запись электронной почты раз в минуту на конкретную тему, например "Успешно" или "Ошибка". Такая установка производит 120 обращений в час. Если вместо этого создать одно родительское приложение логики, которое тоже будет опрашивать раз в минуту, но вызывать дочернее приложение логики в зависимости от темы "Успешно" или "Ошибка", то в этом случае количество обращений удастся сократить вдвое (до 60 в час).
Настройка пакетной обработки.
Используйте версии веб-перехватчика для триггеров и действий, а не опрашивающие версии.
Таким образом, если целевая служба или система поддерживает веб-перехватчики или имеет соединитель с версией веб-перехватчика, то этот вариант является более предпочтительным, чем использование опрашивающей версии. Чтобы определить триггеры и действия веб-перехватчика, убедитесь, что они имеют тип ApiConnectionWebhook или не требуют указания периодичности. Дополнительные сведения см. в статьях Триггер APIConnectionWebhook и Действие APIConnectionWebhook.
Читайте также: