Прим. перев.: на прошлой неделе сбой одного из сервисов AWS привёл к проблемам в доступности/корректном функционировании целого ряда облачных услуг этого крупного провайдера. В официальной публикации, оперативно размещённой инженерами интернет-компании, рассказывается о подробностях инцидента, его причинах и — главное — уроках, которые были извлечены из случившегося. Представляем вашему вниманию её перевод.
В этом материале мы хотели бы рассказать подробности о перебоях в обслуживании, случившихся в регионе Northern Virginia (US-EAST-1) 25 ноября 2020.
Amazon Kinesis позволяет в реальном времени собирать, обрабатывать и анализировать потоковые данные. Помимо непосредственного использования клиентами, он задействован в ряде сервисов AWS. Эти сервисы также пострадали от сбоя. Триггером (но не основной причиной) данного события стало относительно небольшое добавление мощностей к сервису, начавшееся в 2:44 утра PST и завершившееся в 3:47.
В Kinesis используется большое число «бэкендовых» кластеров-ячеек (cells), обрабатывающих потоки данных. Это рабочие лошадки Kinesis. Именно они отвечают за распределение, доступ и масштабирование при потоковой обработке. Потоки распределяются фронтенд-серверами по бэкенд-серверам с помощью шардинга. Бэкенд-кластер «владеет» множеством шардов и обеспечивает согласованное масштабирование и изоляцию при сбоях. Работа фронтенда в нашем случае невелика, но важна. Он отвечает за аутентификацию, троттлинг и маршрутизацию запросов к правильным шардам потоков на бэкенд-кластерах.
Мы добавляли новые мощности в парк фронтенд-машин. Каждый фронтенд-сервер формирует кэш данных, включая сведения о членстве и владельцах шардов (среди бэкенд-кластеров), формирующие так называемую шард-карту (shard-map). Эту информацию он получает, посылая запросы сервису, предоставляющему информацию о членстве, и извлекая данные о конфигурации из DynamoDB.
Кроме того, каждый сервер непрерывно обрабатывает сообщения от других фронтенд-серверов Kinesis. Для этого в ОС каждой фронтенд-машины создаются потоки для каждого из фронтенд-серверов. При добавлении новых мощностей серверы, которые уже работают в составе фронтенд-парка, узнают о новых участниках и создают соответствующие потоки. На то, чтобы каждый существующий фронтенд-сервер узнал о новых машинах, уходит до часа времени.
В 5:15 PST появились первые сообщения об ошибках при записи и получении записей Kinesis. Наши команды незамедлительно приступили к изучению логов. Подозрение сразу пало на новые мощности, однако часть ошибок была никак не связана с новыми машинами и, скорее всего, никуда бы не делась, даже если бы мы убрали все новые мощности.
Тем не менее, из предосторожности, мы все же начали их удалять, попутно пытаясь установить причину других ошибок. Их большое разнообразие замедляло нашу диагностику. Мы наблюдали ошибки, связанные со всеми аспектами всевозможных вызовов, совершаемых существующими и новыми членами парка фронтенд-машин, и это изрядно осложняло отделение побочных эффектов от основной причины.
По состоянию на 7:51 PST мы сузили круг подозреваемых до нескольких кандидатов и определили, что любая из наиболее вероятных причин потребует полного перезапуска фронтенда. Команда Kinesis отлично знала, что процесс этот должен быть неспешным и обстоятельным.
Дело в том, что наполнение шард-карты конкурирует с обработкой входящих запросов за ресурсы фронтенд-сервера. Таким образом, слишком быстрое возвращение фронтенд-серверов в рабочий режим создаст конфликт между этими двумя процессами и приведет к тому, что на обработку входящих запросов останется слишком мало. Итог предсказуем: увеличение частоты ошибок и рост задержек (latencies). Кроме того, медленная работа фронтенд-серверов может восприниматься как признак их нездоровья (unhealthy), из-за чего они могут удаляться из списка доступных серверов, что, в свою очередь, дополнительно замедлит процесс восстановления.
Все возможные решения предусматривали изменение конфигурации каждого фронтенд-сервера и его перезапуск. В то время как наш основной кандидат на источник наших бед (проблема, которая, похоже, оказывала давление на память) выглядел вполне перспективно, в случае неправоты мы рисковали удвоить время восстановления, поскольку пришлось бы повторно все исправлять и перезапускать. Чтобы ускорить перезапуск, параллельно с расследованием, мы начали вносить в конфигурацию фронтенд-серверов изменения, позволяющие получать данные непосредственно из хранилища метаданных во время начальной загрузки, а не от фронтенд-соседей.
В 9:39 PST мы, наконец, смогли подтвердить главную причину сбоя. Оказалось, что она не связана с памятью. Добавление новых мощностей привело к тому, что на всех фронтенд-серверах число потоков превысило максимально возможное, разрешенное конфигурацией системы. Поскольку предел был превышен, кэш (шард-карты) не удавалось создать. В результате фронтенд-серверы оказались неспособны пересылать запросы в бэкенд-кластеры.
Нам не хотелось увеличивать лимит потоков в ОС без предварительного тестирования, и, поскольку дополнительные мощности на тот момент уже были удалены, мы решили, что риск превышения системного лимита на число потоков минимален и продолжили перезапуск серверов. Первая группа «свежих» фронтендов начала принимать трафик Kinesis в 10:07 PST.
Парк фронтенд-машин состоит из многих тысяч серверов, и по причинам, описанным выше, мы могли добавлять серверы со скоростью не более нескольких сотен в час. Мы продолжали медленно добавлять трафик во фронтенд, отмечая неуклонное снижение ошибок сервиса Kinesis, начавшееся с полудня. Сервис полностью пришел в норму в 22:23 PST.
Из происшествия с Kinesis мы извлекли несколько уроков и в ближайшее время планируем внести соответствующие исправления.
Сбой также затронул некоторые сервисы, использующие Kinesis.
Amazon Cognito с помощью Kinesis Data Streams собирает и анализирует паттерны доступа к API. В то время как эта информация чрезвычайно полезна для работы сервиса Cognito, ее доставка не гарантируется (best effort). Данные буферизуются локально, что помогает сервису справляться с задержками или короткими периодами недоступности сервиса Kinesis Data Streams.
К сожалению, затянувшаяся недоступность Kinesis Data Streams проявила скрытую ошибку в коде буферизации, которая привела к тому, что веб-серверы Cognito начали блокировать буферы Kinesis Data Stream. В результате потребители Cognito столкнулись со сбоями API и повышением задержек для Cognito User Pools и Identity Pools. Внешние пользователи не могли пройти процедуру аутентификации или получить временные учетные данные AWS.
На ранних стадиях сбоя команда Cognito постаралась смягчить воздействие ошибок Kinesis, подключив дополнительные мощности и, тем самым, увеличив возможности по буферизации вызовов к Kinesis. Сначала это благоприятно сказалось на работе сервиса, однако к 7:01 PST частота ошибок значительно возросла. Параллельно команда работала над снижением зависимости Cognito от Kinesis. В 10:15 это решение было развернуто и частота ошибок начала снижаться. К 12:15 количество ошибок значительно уменьшилось, и в 14:18 PST Cognito функционировал нормально. Чтобы предотвратить повторное возникновение этой проблемы, мы модифицировали веб-серверы Cognito. Теперь они могут переносить ошибки API Kinesis, не исчерпав свои буферы (что привело к проблемам с пользователями).
CloudWatch использует Kinesis Data Streams для обработки метрик и логов. Начиная с 5:15 утра CloudWatch столкнулся с ростом числа ошибок и увеличением задержек (latencies) для API PutMetricData и PutLogEvents, а оповещения перешли в состояние
В 5:47 PST появились первые признаки восстановления на фоне улучшения ситуации с Kinesis Data Stream, и к 22:31 метрики CloudWatch и оповещения полностью восстановились. В последующие часы продолжилась обработка задержанных метрик и логов. Пока CloudWatch боролся с ошибками, внутренние и внешние клиенты не могли поставлять данные метрик в CloudWatch. В результате в данных метрик CloudWatch появились пробелы.
На данный момент сервис CloudWatch зависит от Kinesis в деле сбора метрик и логов, однако его команда в скором времени собирается реализовать изменение, после которого CloudWatch будет хранить данные за три часа в локальном хранилище. Это изменение откроет пользователям и сервисам, завязанным на метрики CloudWatch (включая AutoScaling), прямой доступ к недавно собранным метрикам (в локальном хранилище данных CloudWatch). Такая идея уже была реализована в регионе US-EAST-1, а в ближайшие недели мы планируем развернуть ее глобально.
Еще два сервиса оказались заложниками проблем с метриками CloudWatch:
CloudWatch Events и EventBridge столкнулись с ростом числа ошибок API и задержками в обработке событий начиная с 5:15 утра по восточному времени. После улучшения доступности Kinesis EventBridge возобновил доставку новых событий адресатам, попутно обрабатывая накопившиеся события.
Elastic Container Service (ECS) и Elastic Kubernetes Service (EKS) используют EventBridge в своих внутренних рабочих процессах для управления кластерами клиентов и задачами. Это повлияло на подготовку новых кластеров, задержало масштабирование существующих и сказалось на de-provisioning задач. К 16:15 PST большинство из этих проблем были решены.
Кроме сложностей с сервисами, в самом начале происшествия мы столкнулись с определенными задержками при доведении информации о статусе сервисов до клиентов.
У нас два способа связи с клиентами во время эксплуатационных событий:
Во время событий, подобных этому, мы обычно публикуем информацию в Service Health Dashboard. Однако в данном случае в самом начале сбоя мы не смогли обновить информацию в Service Health Dashboard, поскольку инструмент, который используется для публикации обновлений, применяет в работе пострадавший от сбоя Cognito.
У нас имеется резервный способ обновления Service Health Dashboard с минимальными зависимостями от сервисов. Он сработал, как и задумывалось, однако при публикации сведений в Service Health Dashboard с его помощью в начале события мы столкнулись с некоторыми задержками. Дело в том, что этот запасной инструмент гораздо меньше автоматизирован и хуже знаком операторам службы поддержки.
Чтобы обеспечить своевременную доставку обновлений всем пострадавшим клиентам, команда поддержки воспользовалась Personal Health Dashboard и уведомила их о возможных проблемах с сервисами. Мы также вывесили в Service Health Dashboard глобальный баннер с актуальной информацией, чтобы обеспечить максимальную информированность пользователей о происшествии. До окончания сбоя продолжалось применение комбинации из Service Health Dashboard (с краткими итогами на глобальных баннерах и подробностями о работе конкретных сервисов) и Personal Health Dashboard, где мы старались держать в курсе происходящего клиентов, пострадавших от проблем с сервисами. Исходя из полученного опыта, мы ввели обязательные упражнения с резервной системой публикации сообщений в Service Health Dashboard в регулярные тренинги инженеров службы поддержки.
Наконец, хотелось бы извиниться за то негативное воздействие, которое это происшествие оказало на наших клиентов. Мы гордимся высокими показателями доступности Amazon Kinesis и прекрасно осознаем, насколько этот и другие сервисы AWS важны для наших клиентов, их приложений/конечных пользователей и их бизнеса. Мы сделаем все возможное, чтобы извлечь уроки из данного происшествия и использовать его для дальнейшего повышения уровня доступности.
Читайте также в нашем блоге:
В этом материале мы хотели бы рассказать подробности о перебоях в обслуживании, случившихся в регионе Northern Virginia (US-EAST-1) 25 ноября 2020.
Amazon Kinesis позволяет в реальном времени собирать, обрабатывать и анализировать потоковые данные. Помимо непосредственного использования клиентами, он задействован в ряде сервисов AWS. Эти сервисы также пострадали от сбоя. Триггером (но не основной причиной) данного события стало относительно небольшое добавление мощностей к сервису, начавшееся в 2:44 утра PST и завершившееся в 3:47.
Об устройстве Kinesis
В Kinesis используется большое число «бэкендовых» кластеров-ячеек (cells), обрабатывающих потоки данных. Это рабочие лошадки Kinesis. Именно они отвечают за распределение, доступ и масштабирование при потоковой обработке. Потоки распределяются фронтенд-серверами по бэкенд-серверам с помощью шардинга. Бэкенд-кластер «владеет» множеством шардов и обеспечивает согласованное масштабирование и изоляцию при сбоях. Работа фронтенда в нашем случае невелика, но важна. Он отвечает за аутентификацию, троттлинг и маршрутизацию запросов к правильным шардам потоков на бэкенд-кластерах.
Мы добавляли новые мощности в парк фронтенд-машин. Каждый фронтенд-сервер формирует кэш данных, включая сведения о членстве и владельцах шардов (среди бэкенд-кластеров), формирующие так называемую шард-карту (shard-map). Эту информацию он получает, посылая запросы сервису, предоставляющему информацию о членстве, и извлекая данные о конфигурации из DynamoDB.
Кроме того, каждый сервер непрерывно обрабатывает сообщения от других фронтенд-серверов Kinesis. Для этого в ОС каждой фронтенд-машины создаются потоки для каждого из фронтенд-серверов. При добавлении новых мощностей серверы, которые уже работают в составе фронтенд-парка, узнают о новых участниках и создают соответствующие потоки. На то, чтобы каждый существующий фронтенд-сервер узнал о новых машинах, уходит до часа времени.
Диагностика и решение проблемы
В 5:15 PST появились первые сообщения об ошибках при записи и получении записей Kinesis. Наши команды незамедлительно приступили к изучению логов. Подозрение сразу пало на новые мощности, однако часть ошибок была никак не связана с новыми машинами и, скорее всего, никуда бы не делась, даже если бы мы убрали все новые мощности.
Тем не менее, из предосторожности, мы все же начали их удалять, попутно пытаясь установить причину других ошибок. Их большое разнообразие замедляло нашу диагностику. Мы наблюдали ошибки, связанные со всеми аспектами всевозможных вызовов, совершаемых существующими и новыми членами парка фронтенд-машин, и это изрядно осложняло отделение побочных эффектов от основной причины.
По состоянию на 7:51 PST мы сузили круг подозреваемых до нескольких кандидатов и определили, что любая из наиболее вероятных причин потребует полного перезапуска фронтенда. Команда Kinesis отлично знала, что процесс этот должен быть неспешным и обстоятельным.
Дело в том, что наполнение шард-карты конкурирует с обработкой входящих запросов за ресурсы фронтенд-сервера. Таким образом, слишком быстрое возвращение фронтенд-серверов в рабочий режим создаст конфликт между этими двумя процессами и приведет к тому, что на обработку входящих запросов останется слишком мало. Итог предсказуем: увеличение частоты ошибок и рост задержек (latencies). Кроме того, медленная работа фронтенд-серверов может восприниматься как признак их нездоровья (unhealthy), из-за чего они могут удаляться из списка доступных серверов, что, в свою очередь, дополнительно замедлит процесс восстановления.
Все возможные решения предусматривали изменение конфигурации каждого фронтенд-сервера и его перезапуск. В то время как наш основной кандидат на источник наших бед (проблема, которая, похоже, оказывала давление на память) выглядел вполне перспективно, в случае неправоты мы рисковали удвоить время восстановления, поскольку пришлось бы повторно все исправлять и перезапускать. Чтобы ускорить перезапуск, параллельно с расследованием, мы начали вносить в конфигурацию фронтенд-серверов изменения, позволяющие получать данные непосредственно из хранилища метаданных во время начальной загрузки, а не от фронтенд-соседей.
Главная причина
В 9:39 PST мы, наконец, смогли подтвердить главную причину сбоя. Оказалось, что она не связана с памятью. Добавление новых мощностей привело к тому, что на всех фронтенд-серверах число потоков превысило максимально возможное, разрешенное конфигурацией системы. Поскольку предел был превышен, кэш (шард-карты) не удавалось создать. В результате фронтенд-серверы оказались неспособны пересылать запросы в бэкенд-кластеры.
Нам не хотелось увеличивать лимит потоков в ОС без предварительного тестирования, и, поскольку дополнительные мощности на тот момент уже были удалены, мы решили, что риск превышения системного лимита на число потоков минимален и продолжили перезапуск серверов. Первая группа «свежих» фронтендов начала принимать трафик Kinesis в 10:07 PST.
Парк фронтенд-машин состоит из многих тысяч серверов, и по причинам, описанным выше, мы могли добавлять серверы со скоростью не более нескольких сотен в час. Мы продолжали медленно добавлять трафик во фронтенд, отмечая неуклонное снижение ошибок сервиса Kinesis, начавшееся с полудня. Сервис полностью пришел в норму в 22:23 PST.
Чему мы научились
Из происшествия с Kinesis мы извлекли несколько уроков и в ближайшее время планируем внести соответствующие исправления.
- Прежде всего, мы перейдем на серверы с большим количеством CPU и объемом памяти. Число серверов упадет, следовательно, сократится количество потоков, необходимое каждому серверу для связи с другими. Это обеспечит нам приличный запас по потокам, поскольку их количество прямо пропорционально числу серверов в парке. Меньшее число серверов означает, что на каждом сервере будет задействовано меньшее количество потоков.
- Также мы планируем создать подробную систему оповещений о проблемах с потоками в сервисе.
- Кроме того, заканчивается тестирование работы системы с увеличенным лимитом ОС на потоки. По нашему мнению, это обеспечит значительный задел по числу потоков на каждый сервер и придаст дополнительный запас прочности всей системе.
- Также будет внесен ряд изменений для значительного сокращения времени холодного запуска фронтенд-серверов. Мы переносим кэш фронтенд-серверов на выделенные машины и намерены перевести несколько крупных сервисов AWS (вроде CloudWatch) на отдельный, обособленный парк фронтенд-машин.
- В среднесрочной перспективе мы планируем значительно ускорить процесс перехода (cellularization) фронтенда к ячеистой структуре (по типу той, которую мы сделали для бэкенда). Мы используем этот подход для изоляции последствий сбоя внутри сервиса и для поддержания компонентов сервиса (в данном случае кэша шард-карты) в работоспособном состоянии в ранее проверенном и привычном диапазоне. Некоторое время мы занимаемся переводом Kinesis на подобную структуру, но, к сожалению, эта задача весьма обширна и на данный момент не завершена. Ячеистая структура не только позволит фронтенду работать стабильно и в привычном/хорошо проверенном диапазоне в плане общего числа используемых потоков, но и обеспечит лучшую защиту от любых других неизвестных пределов, связанных с масштабированием.
Связанные сервисы
Сбой также затронул некоторые сервисы, использующие Kinesis.
Amazon Cognito с помощью Kinesis Data Streams собирает и анализирует паттерны доступа к API. В то время как эта информация чрезвычайно полезна для работы сервиса Cognito, ее доставка не гарантируется (best effort). Данные буферизуются локально, что помогает сервису справляться с задержками или короткими периодами недоступности сервиса Kinesis Data Streams.
К сожалению, затянувшаяся недоступность Kinesis Data Streams проявила скрытую ошибку в коде буферизации, которая привела к тому, что веб-серверы Cognito начали блокировать буферы Kinesis Data Stream. В результате потребители Cognito столкнулись со сбоями API и повышением задержек для Cognito User Pools и Identity Pools. Внешние пользователи не могли пройти процедуру аутентификации или получить временные учетные данные AWS.
На ранних стадиях сбоя команда Cognito постаралась смягчить воздействие ошибок Kinesis, подключив дополнительные мощности и, тем самым, увеличив возможности по буферизации вызовов к Kinesis. Сначала это благоприятно сказалось на работе сервиса, однако к 7:01 PST частота ошибок значительно возросла. Параллельно команда работала над снижением зависимости Cognito от Kinesis. В 10:15 это решение было развернуто и частота ошибок начала снижаться. К 12:15 количество ошибок значительно уменьшилось, и в 14:18 PST Cognito функционировал нормально. Чтобы предотвратить повторное возникновение этой проблемы, мы модифицировали веб-серверы Cognito. Теперь они могут переносить ошибки API Kinesis, не исчерпав свои буферы (что привело к проблемам с пользователями).
CloudWatch использует Kinesis Data Streams для обработки метрик и логов. Начиная с 5:15 утра CloudWatch столкнулся с ростом числа ошибок и увеличением задержек (latencies) для API PutMetricData и PutLogEvents, а оповещения перешли в состояние
INSUFFICIENT_DATA
. Хотя некоторые метрики CloudWatch продолжали обрабатываться во время сбоя, их основная часть пала жертвой многочисленных ошибок и возросших задержек.В 5:47 PST появились первые признаки восстановления на фоне улучшения ситуации с Kinesis Data Stream, и к 22:31 метрики CloudWatch и оповещения полностью восстановились. В последующие часы продолжилась обработка задержанных метрик и логов. Пока CloudWatch боролся с ошибками, внутренние и внешние клиенты не могли поставлять данные метрик в CloudWatch. В результате в данных метрик CloudWatch появились пробелы.
На данный момент сервис CloudWatch зависит от Kinesis в деле сбора метрик и логов, однако его команда в скором времени собирается реализовать изменение, после которого CloudWatch будет хранить данные за три часа в локальном хранилище. Это изменение откроет пользователям и сервисам, завязанным на метрики CloudWatch (включая AutoScaling), прямой доступ к недавно собранным метрикам (в локальном хранилище данных CloudWatch). Такая идея уже была реализована в регионе US-EAST-1, а в ближайшие недели мы планируем развернуть ее глобально.
Еще два сервиса оказались заложниками проблем с метриками CloudWatch:
- Во-первых, политики AutoScaling, опирающиеся на метрики CloudWatch, демонстрировали задержки до 17:47 — момента, когда сервис CloudWatch начал приходить в норму.
- Во-вторых, пострадал сервис Lambda. Лямбда-функции при вызове публикуют метрики в CloudWatch. Агенты Lambda, которые за это отвечают, могут в течение некоторого времени сохранять данные метрик в локальный буфер, если CloudWatch недоступен. В 6:15 PST эти буферы разрослись до такой степени, что возникла нехватка памяти на базовых хостах, использующихся для вызова лямбда-функций. Итог очевиден: рост числа ошибок. В 10:36 PST инженеры предприняли меры по устранению нехватки памяти, тем самым решив проблему ошибок при вызове функций.
CloudWatch Events и EventBridge столкнулись с ростом числа ошибок API и задержками в обработке событий начиная с 5:15 утра по восточному времени. После улучшения доступности Kinesis EventBridge возобновил доставку новых событий адресатам, попутно обрабатывая накопившиеся события.
Elastic Container Service (ECS) и Elastic Kubernetes Service (EKS) используют EventBridge в своих внутренних рабочих процессах для управления кластерами клиентов и задачами. Это повлияло на подготовку новых кластеров, задержало масштабирование существующих и сказалось на de-provisioning задач. К 16:15 PST большинство из этих проблем были решены.
Уведомление клиентов
Кроме сложностей с сервисами, в самом начале происшествия мы столкнулись с определенными задержками при доведении информации о статусе сервисов до клиентов.
У нас два способа связи с клиентами во время эксплуатационных событий:
- Service Health Dashboard – общедоступная панель для оповещения о масштабных проблемах в эксплуатации;
- Personal Health Dashboard — для прямого уведомления клиентов, затронутых проблемой.
Во время событий, подобных этому, мы обычно публикуем информацию в Service Health Dashboard. Однако в данном случае в самом начале сбоя мы не смогли обновить информацию в Service Health Dashboard, поскольку инструмент, который используется для публикации обновлений, применяет в работе пострадавший от сбоя Cognito.
У нас имеется резервный способ обновления Service Health Dashboard с минимальными зависимостями от сервисов. Он сработал, как и задумывалось, однако при публикации сведений в Service Health Dashboard с его помощью в начале события мы столкнулись с некоторыми задержками. Дело в том, что этот запасной инструмент гораздо меньше автоматизирован и хуже знаком операторам службы поддержки.
Чтобы обеспечить своевременную доставку обновлений всем пострадавшим клиентам, команда поддержки воспользовалась Personal Health Dashboard и уведомила их о возможных проблемах с сервисами. Мы также вывесили в Service Health Dashboard глобальный баннер с актуальной информацией, чтобы обеспечить максимальную информированность пользователей о происшествии. До окончания сбоя продолжалось применение комбинации из Service Health Dashboard (с краткими итогами на глобальных баннерах и подробностями о работе конкретных сервисов) и Personal Health Dashboard, где мы старались держать в курсе происходящего клиентов, пострадавших от проблем с сервисами. Исходя из полученного опыта, мы ввели обязательные упражнения с резервной системой публикации сообщений в Service Health Dashboard в регулярные тренинги инженеров службы поддержки.
…
Наконец, хотелось бы извиниться за то негативное воздействие, которое это происшествие оказало на наших клиентов. Мы гордимся высокими показателями доступности Amazon Kinesis и прекрасно осознаем, насколько этот и другие сервисы AWS важны для наших клиентов, их приложений/конечных пользователей и их бизнеса. Мы сделаем все возможное, чтобы извлечь уроки из данного происшествия и использовать его для дальнейшего повышения уровня доступности.
P.S.
Читайте также в нашем блоге: