elasticsearch shards что это

Глоссарий ElasticSearch

Примечание переводчика:
Это перевод глоссария ElasticSearch из официальной документации.

Устоявшихся русских терминов для данной предметной области найти не удалось. Пришлось тщательно продумывать как лучше перевести. Кривой термин будет сильно сбивать с толку новичка (а гуру глоссарий неинтересен по определению — и так всё знает). Равно нет никакой пользы от «переводов» вида shard-шард, node-нода, mapping-мэппинг. Тогда уж лучше читать в оригинале. Во избежание путаницы в скобках приведены оригинальные термины.
Явные ошибки и опечатки прошу отправлять в личку. А вот корректность выбора терминов и формулировок определений лучше обсудить в комментариях. Предполагаю, что возможны очень разные мнения. Также, на мой взгляд, кое-что в оригинале написано не сильно удачно и понятно — можно сформулировать лучше, но в переводе старался по возможности обойтись без «отсебятины». Надеюсь на понимание. Спасибо.

Глоссарий ElasticSearch

Примечание переводчика: буквально ElasticSearch означает ГибкийПоиск, но в тексте сохранено оригинальное наименование.

Анализ (analysis)

Анализ – это процесс преобразования (конвертации) обычного текста (full text) в термы (terms). В зависимости от используемого анализатора, фразы: FOO BAR, Foo-Bar, foo, bar скорее всего дадут в результате термы foo и bar. Это термы, которые физически сохранятся в индексе. Полнотекстовый поиск (не запрос терма) для FoO:bAR также будет анализировать термы foo, bar и соответственно подбирать термы запомненные в индексе. Этот процесс анализа (во время индексирования и во время поиска) также позволяет elasticsearch выполнять полнотекстовые запросы. Также см. текст (text) и терм (term).

Кластер (cluster)

Кластер состоит из одного или нескольких узлов (nodes), которые доступны под одним общим наименованием кластера. Каждый кластер имеет один главный (master) узел, который выбирается кластером автоматически и также заменяется в случае отказа.

Документ (document)

Документ – это JSON документ который сохранен в elasticsearch. Это похоже на строку таблицы в реляционной базе данных. Каждый документ сохраненный в индексе (index) имеет тип (type) и идентификатор (id). Документ – это объект JSON (также известный в другой формулировке как хэш (hash) / картотека хэшей (hashmap) / ассоциативный массив (associative array)) который содержит ноль или более полей, или пар ключ-значение (key-value). Оригинальный JSON, который проиндексировали, будет сохранен в поле _source, которое возвращается по умолчанию при получении (getting) или поиске документа.

Идентификатор (id)

Идентификатор (ID) документа (document) идентифицирует документ. Индекс (index)/тип (type)/идентификатор (id) документа должны быть уникальными. Если идентификатор (ID) не задан, он будет создан автоматически. (см. также маршрутизация (routing))

Поле (field)

Документ (document) содержит список полей или пар ключ-значение. Значение может быть простым (скалярным) значением (например, строка, целое число, дата), или вложенной структурой такой как массив или объект. Поле похоже на столбец таблицы в реляционной базе данных. Схема (mapping) для каждого поля содержит поле тип (type) (не путайте с типом документа) которое указывает тип данных которые могут быть сохранены в этом поле, например, целое число (integer), строка (string), объект (object). Схема (mapping) также позволяет вам задавать (помимо прочего) как именно значение поля должно анализироваться.

Индекс (index)

Индекс похож на базу данных (database) в реляционных базах данных. Это схема (mapping) которая определяет несколько типов (types). Индекс – это логическое пространство имен (namespace) которое отображает один или более основных фрагментов (shards) и может иметь один или больше фрагментов-копий (replica shards).

Определение схемы (mapping)

Определение схемы похоже на определение схемы (schema definition) в реляционных базах данных. Каждый индекс (index) имеет схему (mapping), которая определяет каждый тип (type) в индексе, плюс широкий ряд настроек индекса. Схема может быть задана явно или будет создана автоматически при индексации.

Узел (node)

Узел – это работающий экземпляр elasticsearch который принадлежит кластеру (cluster). Множество узлов могут быть запущены на одном сервере для тестовых целей, но обычно на сервере должен быть один узел. При запуске узел будет использовать одноадресную отправку (unicast) (или широковещательную (multicast), если задано) для обнаружения соответствующего ему названия кластера и будет пытаться к нему присоединиться.

Основной фрагмент (primary shard)

Каждый документ хранится в одном основном фрагменте (shard). Когда вы индексируете документ, он сперва индексируется на основном фрагменте, а затем на всех его копиях (replicas). По умолчанию индекс (index) имеет 5 основных фрагментов. Вы можете задать больше или меньше основных фрагментов для масштабирования количества документов (documents) которые индекс сможет обрабатывать. Невозможно изменить количество основных фрагментов, когда индекс уже создан. См. также маршрутизация (routing)

Фрагмент-копия (replica shard)

Маршрутизация (routing)

Когда вы индексируете документ, он сохраняется в одном основном фрагменте (primary shard). Этот фрагмент определяется посредством хэширования некоторого значения для маршрутизации. По умолчанию значение для маршрутизации берется из идентификатора (ID) документа или, если в документе указан родительский документ, из идентификатора (ID) родительского документа (это обеспечивает сохранение дочернего и родительского документа на одном фрагменте). Это значение можно переопределить, указав значение для маршрутизации во время индексирования или поле для маршрутизации (routing field) в сопоставлении (mapping).

Примечание переводчика: в данном случае routing означает процесс определения направления (места, фрагмента) где должен оказаться документ. «Маршрутизация» не самый удачный термин, но это устоявшийся в сфере ИТ перевод «routing»

Фрагмент (shard)

Фрагмент – это единичный экземпляр Lucene (Примечание переводчика: Lucene — свободная библиотека для высокопроизводительного полнотекстового поиска фонда Apache.). Это низкоуровневый обработчик (worker) который управляется elasticsearch автоматически. Индекс – это логическое пространство имен, указывающее на основные фрагменты и фрагменты-копии. Помимо определения количества основных фрагментов и копий, которые должен иметь индекс, вам не нужно указывать фрагменты непосредственно. Вместо этого ваш код должен работать только с индексом. Elasticsearch распределяет фрагменты среди всех узлов кластера и может автоматически перемещать фрагменты с одного узла на другой в случае отказа или при добавлении новых узлов.

Примечание переводчика: буквально «shard» переводится как «осколок». По-русски звучит криво и скорее всего будет вводить в заблуждение. По смыслу sharding это разбиение данных на несколько кусков (частей, секций, фрагментов, разделов), которые могут храниться в разных местах. Из перечисленного «фрагмент» звучит лучше и при этом ближе к оригинальному «осколку».

Читайте также:  Что значит технологический перерыв

Поле исходника (source field)

По умолчанию документ JSON, который вы индексируете, будет храниться в поле _source и будет возвращаться всеми запросами на получение и поиск. Это дает вам доступ непосредственно к исходному объекту сразу в результатах поиска, чтобы избежать второго шага для получения объекта по идентификатору (ID). Примечание. Исходная строка JSON, которую вы проиндексировали, будет возвращена вам, даже если она содержит недопустимый JSON. Содержимое этого поля не говорит ничего о том, как данные в объекте были проиндексированы.

Терм (term)

Терм – это точное значение проиндексированное elasticsearch. Термы foo, Foo, FOO НЕ эквивалентны. Термы (т. е. точные значения) могут быть найдены используя запросы термов (term). См. также текст (text) и анализ (analysis).

Текст (text)

Текст (или полный текст) – это обычный неструктурированный текст, такой как этот параграф. По умолчанию текст будет преобразован (analyzed) в термы (terms), которые фактически хранятся в индексе. Текстовые поля (fields) должны быть преобразованы во время индексирования, чтобы стал возможен полнотекстовый поиск, а ключевые слова в полнотекстовых запросах должны быть проанализированы во время поиска для создания (и поиска) тех же термов, которые были созданы во время построения индекса. См. также терм (text) и анализ (analysis).

Тип (type)

Тип похож на таблицу в реляционных базах данных. Каждый тип имеет список полей, которые могут быть указаны для документов этого типа. Схема (mapping) определяет, как каждое поле в документе будет анализироваться.

Источник

Elasticsearch: сайзинг шардов как завещал Elastic + анонс вебинара + предложения по митапу

Как Elasticsearch работает с шардами

Поисковые запросы обычно попадают в несколько шардов (в продукционных нагруженных средах рекомендуем использовать ноду с ролью coordinating). Каждый шард выполняет поисковый запрос в одном процессорном треде. Если запросов много, пул тредов поиска заканчивается (именно поиска, т.к. есть и другие), что приводит к возникновению очередей, снижению производительности и, как следствие, медленной скорости поиска.

Каждый шард использует ресурсы памяти и процессора. Небольшое количество бóльших по объёму шардов использует меньше ресурсов, чем множество мелких.

Давайте теперь краем глаза взглянем на сегменты (см. картинку ниже). Каждый шард Elasticsearch является индексом Lucene. Максимальное количество документов, которое можно закинуть в индекс Lucene — 2 147 483 519. Индекс Lucene разделен на блоки данных меньшего размера, называемые сегментами. Сегмент — это небольшой индекс Lucene. Lucene выполняет поиск во всех сегментах последовательно. Большинство шардов содержат несколько сегментов, в которых хранятся данные индекса. Elasticsearch хранит метаданные сегментов в JVM Heap, чтобы их можно было быстро извлечь для поиска. По мере роста объёма шарда его сегменты объединяются в меньшее количество более крупных сегментов. Это уменьшает количество сегментов, что означает, что в динамической памяти хранится меньше метаданных (см. также forcemerge, к которому мы вернемся чуть дальше в статье).

Еще стоит сказать о ребалансировке кластера. Если добавляется новая нода или одна из нод выходит из строя, происходит ребалансировка кластера. Ребалансировка сама по себе недешёвая с точки зрения производительности операция. Кластер сбалансирован, если он имеет равное количество шардов на каждой ноде и отсутствует концентрация шардов любого индекса на любой ноде. Elasticsearch запускает автоматический процесс, называемый ребалансировкой, который перемещает шарды между узлами в кластере, чтобы его сбалансировать. При перебалансировке применяются заранее заданные правила выделения сегментов (об allocation awareness и других правилах мы подробнее расскажем в одной из следующих статей). Если вы используете data tiers, Elasticsearch автоматически разместит каждый шард на соответствующем уровне. Балансировщик работает независимо на каждом уровне.

Как заставить Elasticsearch ещё лучше работать с шардами

Правильно удалять данные. Если вы удалили документ, из файловой системы он удалится не сразу. Вместо этого, Elasticsearch помечает документ как удаленный на каждом шарде. Отмеченный документ будет продолжать использовать ресурсы, пока он не будет удален во время периодического слияния сегментов. Если нужно физически освободить место, лучше всего сразу удалять индексы целиком, которые в итоге освободят файловую системы.

Создавать шарды размером от 10 до 50 ГБ. Elastic говорит, шарды размером более 50 ГБ потенциально могут снизить вероятность восстановления кластера после сбоя. Из-за той самой ребалансировки, о которой мы говорили в начале статьи. Ну, и большие шарды накладнее передавать по сети. Предел в 50 ГБ выглядит, конечно, как сферический конь в вакууме, поэтому мы сами больше склоняемся к 10 ГБ. Вот тут человек советует 10 ГБ и смотреть на размер документов в следующем плане:

А теперь посмотрим сколько шардов на каждой ноде и видим, что с нашим тестовым стендов всё в порядке. Жить будет.

Количество шардов на узле можно ограничить при помощи опции index.routing.allocation.total_shards_per_node, но если их уже много, присмотритесь к Shrink API.

Совсем необязательно создавать индексы размером в 1 день. Часто встречали у заказчиков подход, при котором каждый новый день создавался новый индекс. Иногда это оправдано, иногда можно и месяц подождать. Ролловер ведь можно запускать не только с max_age, но и с max_size или max_docs. На Хабре была статья, в которой Адель Сачков, в ту пору из Яндекс Денег (сейчас уже нет), делился полезным лайфхаком: создавал индексы не в момент наступления новых суток, а заранее, чтобы этот процесс не аффектил на производительность кластера, но у него там были микросервисы.

… каждые сутки создаются новые индексы по числу микросервисов — поэтому раньше каждую ночь эластик впадал в клинч примерно на 8 минут, пока создавалась сотня новых индексов, несколько сотен новых шардов, график нагрузки на диски уходил «в полку», вырастали очереди на отправку логов в эластик на хостах, и Zabbix расцветал алертами как новогодняя ёлка. Чтобы этого избежать, по здравому размышлению был написан скрипт на Python для предварительного создания индексов.

С новогодней ёлкой неплохой каламбурчик получился.

Читайте также:  lng tanker что это

Не пренебрегайте ILM и forcemerge. Индексы должны плавно перетекать между соответствующими нодами согласно ILM. В OpenDistro есть аналогичный механизм.

С индексами, в которые уже не ведется запись можно выполнить forcemerge — слияние меньших по размеру сегментов в более крупные. Это в итоге снизит накладные расходы на эксплуатацию шардов и повысит скорость поиска. Forcemerge требует значительных ресурсов, поэтому лучше это делать к какие-то в непиковые часы. Добавим, что forcemerge это фактические создание нового сегмента из двух старых, поэтому свободное место на диске лишним точно не будет.

Приходите в комментарии и расскажите о своём опыте с раскладыванием шардов по нодам. Было бы интересно узнать о том, что работает в вашем случае.

Анонс вебинара. Elastic приглашает посетить 17 марта в 12 часов по московскому времени вебинар Elastic Telco Day: Applications and operational highlights from telco environments. Эксперты расскажут о применении в решений Elastic в телекоме. Регистрация.

Предложения по митапу. Планируем проведение онлайн-митап по Elastic в апреле. Напишите в комментариях или в личку какие темы вам было бы интересно разобрать, каких спикеров услышать. Если бы вы хотели сами выступить и у вас есть что рассказать, тоже напишите. Вступайте в группу Elastic Moscow User Group, чтобы не пропустить анонс митапа.

Канал в телеге. Подписывайтесь на наш канал Elastic Stack Recipes, там интересные материалы и анонсы мероприятий.

Читайте наши другие статьи:

Мы разработали обучающий курс по основам работы с Elastic Stack, который адаптируется под конкретные потребности заказчика. Подробная программа обучения по запросу.

Источник

ElasticSearch: что такое, как работать и где применять

Как раз, ElasticSeach удовлетворяет нас по этим 2 показателям, плюс, он имеет ещё много дополнительных функций и возможностей для того, чтобы сделать нашу жизнь ещё проще.

Что такое Elasticsearch и как он работает

MySQL Базы дынных Таблицы Строки/Колонки
Elasticsearch Индексы Типы Документы со свойствами

Для того, чтобы установить Elasticsearch, рекомендую просмотреть эту статью, в которой были рассмотрены примеры установки на все операционные системы (в том числе, Docker и Homestead Vagrant).

Базовые понятия

Перед началом, хотелось бы рассмотреть подробнее, важные определения.

Фрагмент (Shard)
Elasticsearch поддерживает возможность разделять индексы на фрагменты ( shards ). Каждый из них является полнофункциональным и независимым «индексом», который может быть частью узла внутри кластера. Это полезно, в случаях, когда индекс добавляется в один узел, который не будет занимать больше места, чем ему доступно. Индекс тогда разделяется между несколькими различными узлами. Кроме того, shards позволяют распределять и выполнять параллельные операции между этими фрагментами, повышая при этом производительность.

Какие способы внедрения Elasticsearch в свой проект

При внедрении Elasticsearch в свой проект, существует несколько способов:

Как говорится на их сайте, чем больше ОЗУ, тем лучше работает Elasticsearch.

Добавление документа

Перед тем, как мы разработаем простое PHP-приложение, которое будет взаимодействовать с Elasticsearch, я покажу как добавлять документы в индекс, просто используя REST API, выполняя запросы из обычного HTTP-клиента:

В текущем случае, экранирование кавычек в теле запроса \» должно быть, чтобы на сервер отправился валидный JSON.

Адрес, по которому обращаемся, состоит из таких параметров:

Для демонстрации процесса поиска ниже, добавим ещё несколько записей:

Если вы не используете CURL, а хотите для этого использовать программу Postman, то для этого, нужно настоить удалённый доступ для Elasticsearch и после чего, сможете воспользоваться этим клиентом, указав ему нужные параметры

Поиск документов

Перед тем, как создавать более сложные запросы, удостоверимся, что предыдущие данные были успешно сохранены:

Как можете увидеть, все 3 пользователя были успешно добавлены. И, помимо указанных нами полей, Elasticsearch предоставляет информацию о том, сколько времени занял этот запрос (в миллисекундах), и какое количество результатов было получено, и дополнительные поля документа: индекс, тип и идентификатор.

Подключение и настройка ElasticSearch с PHP

Во второй части той статьи мы рассмотрим пример работы с Elasticsearch из PHP. В результате чего, напишем простой скрипт по добавлению данных в индекс из PHP, и их поиск.

Дальше, вызываем метод поиска, передав нужные параметры:

После чего, пройдёмся по полученному массиву данных, и создадим на его основе свой, содержащий только нужные нам данные:

И, после, можем распечатать результаты в HTML-шаблоне:

В итоге, получился такой результат:

Резюме

В этой статье я рассказал, что такое Elasticsearch, написал небольшой гайд по работе с ним, для чего он нужен, как делать индексы в elasticsearch, описал его базовые понятия и термины для чайников. Так же, показал, как работать с Elasticsearch из PHP, как добавлять документы, искать их, продемонстрировав примеры запросов, и как они строятся. А так, же, как обрабатывать ответ от Elasticsearch в PHP, как делать поиск.
Дальше будут более продвинутые примеры, агрегации, настройка анализаторов, работа с Laravel, массивами, связями и т.д.
А пока что, советую детальнее изучить документация.

Subscribe to Блог php программиста: статьи по PHP, JavaScript, MySql

Get the latest posts delivered right to your inbox

Источник

Осколки и реплики в Elasticsearch

Я пытаюсь понять, что такое осколок и реплика в Elasticsearch, но мне не удалось понять это. Если я загружаю Elasticsearch и запускаю скрипт, то из того, что я знаю, я запустил кластер с одним узлом. Теперь этот узел (мой компьютер) имеет 5 осколков (?) И несколько реплик (?).

Каковы они, у меня есть 5 дубликатов индекса? Если так, то почему? Мне может понадобиться какое-то объяснение.

ОТВЕТЫ

Ответ 1

Я попытаюсь объяснить реальным примером, поскольку ответы и полученные ответы не помогают вам.

Когда вы загружаете и запускаете эластичный поиск, вы создаете узел эластичного поиска, который пытается присоединиться к существующему кластеру, если он доступен, или создает новый. Допустим, вы создали свой новый кластер с одним узлом, который вы только что запустили. У нас нет данных, поэтому нам нужно создать индекс.

Читайте также:  при какой температуре можно опрыскивать фитоспорином

Когда вы создаете индекс (индекс создается автоматически и при индексировании первого документа), вы можете определить, из скольких фрагментов он будет составлен. Если вы не укажете число, у него будет количество шардов по умолчанию: 5 основных цветов. Что это значит?

Это означает, чтоasticsearch создаст 5 первичных осколков, которые будут содержать ваши данные:

Узел 1 будет содержать, например, только три шарда:

Поскольку оставшиеся два осколка были перемещены во вновь запущенный узел:

Каждый индекс эластичного поиска состоит как минимум из одного основного сегмента, начиная с того, где хранятся данные. Однако каждый осколок обходится дорого, поэтому, если у вас один узел и нет ожидаемого роста, просто придерживайтесь одного первичного осколка.

Возвращаясь к нашему примеру, с 1 репликой у нас будет целый индекс на каждом узле, поскольку 3 сегмента реплики будут размещены на первом узле, и они будут содержать точно такие же данные, что и основные цвета на втором узле:

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

При такой настройке, если узел выходит из строя, у вас все еще есть весь индекс. Осколки реплик автоматически становятся первичными, и кластер будет работать правильно, несмотря на сбой узла, следующим образом:

Надеюсь, это прояснит вам.

Ответ 2

Индекс разбивается на осколки, чтобы распределять их и масштабировать.

Реплики являются копиями осколков и обеспечивают надежность, если потеряна node. Часто бывает замешательство в этом числе, потому что количество копий == 1 означает, что кластер должен иметь основную и реплицированную копию осколка, доступную для зеленого.

Для создания реплик в кластере должно быть не менее 2 узлов.

С наилучшими пожеланиями, Пол

Ответ 3

Если вам действительно не нравится видеть его желтым. вы можете установить количество реплик равным нулю:

Обратите внимание, что вы должны сделать это только в своем локальном окне разработки.

Ответ 4

Индекс разбивается на осколки, чтобы распределять их и масштабировать.

A node является запущенным экземпляром упругого поиска, который принадлежит кластеру.

Кластер состоит из одного или нескольких узлов, которые имеют одно и то же имя кластера. Каждый кластер имеет единственный мастер node, который автоматически выбирается кластером и который может быть заменен, если текущий мастер node не работает.

Ответ 5

Осколок:

Реплика:

Ответ 6

Ответ 7

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

Для повышения отказоустойчивости реплики входят в рисунок. По умолчанию упругий поиск создает одну реплику каждого осколка. Эти реплики всегда создаются на другом узле, где основной сегмент не находится. Поэтому для обеспечения отказоустойчивости системы вам может потребоваться увеличить количество узлов в кластере, и это также зависит от количества сегментов вашего индекса. Общая формула для расчета количества узлов, требуемого на основе реплик и сегментов, представляет собой «количество узлов = количество сегментов * (количество реплик + 1)». Стандартная практика заключается в том, чтобы иметь как минимум одну реплику для отказоустойчивости.

Установка количества сегментов является статической операцией, то есть вы должны указать ее при создании индекса. Любое изменение после этого вульфа требует полной переиндексации данных и займет время. Но настройка количества реплик является динамической операцией и может быть выполнена в любое время после создания индекса.

Вы можете настроить количество сегментов и реплик для своего индекса с помощью приведенной ниже команды.

Ответ 8

Elasticsearch великолепно масштабируется со всеми преимуществами его распределенной архитектуры. Это стало возможным благодаря шардингу. Теперь, прежде чем углубляться в это, давайте рассмотрим простой и очень распространенный вариант использования. Предположим, у вас есть индекс, который содержит огромное количество документов, и для простоты рассмотрим, что размер этого индекса равен 1 ТБ (т.е. сумма размеров каждого документа в этом индексе равна 1 ТБ).). Также предположим, что у вас есть два узла с 512 ГБ свободного места для хранения данных. Как ясно видно, весь наш индекс не может храниться ни в одном из двух доступных узлов, и, следовательно, нам необходимо распределить наш индекс по этим узлам.

В подобных случаях, когда размер индекса превышает аппаратные ограничения одного узла, на помощь приходит Sharding. Sharding решает эту проблему, разделяя индексы на более мелкие части, и эти части называются Shards.

Ответ 9

Не ответ, а еще одна ссылка для основных понятий на ElasticSearch, и я думаю, что они довольно понятны как дополнение к ответу @javanna.

Осколки

Индекс может потенциально хранить большой объем данных, которые могут превышать аппаратные ограничения одного узла. Например, один индекс из миллиарда документов, занимающих 1 ТБ дискового пространства, может не уместиться на диске одного узла или может быть слишком медленным, чтобы обслуживать поисковые запросы только от одного узла.

Чтобы решить эту проблему, Elasticsearch предоставляет возможность подразделить ваш индекс на несколько частей, называемых осколками. Когда вы создаете индекс, вы можете просто определить количество сегментов, которое вы хотите. Каждый осколок сам по себе является полнофункциональным и независимым «индексом», который можно разместить на любом узле кластера.

Осколок важен по двум основным причинам:

Реплики

В сетевой/облачной среде, где сбои можно ожидать в любое время, очень полезно и настоятельно рекомендуется иметь механизм аварийного переключения на случай, если осколок/узел каким-либо образом отключится или по какой-либо причине исчезнет. С этой целью Elasticsearch позволяет вам сделать одну или несколько копий ваших индексных сегментов в так называемые фрагменты реплики, или для краткости реплики.

Репликация важна по двум основным причинам:

Источник

Сказочный портал