Как мы в Яндекс Лавке работаем с большим объемом данных. Интеграция 1С и YTsaurus

05.08.25

База данных - HighLoad оптимизация

Open Source технология для работы с большими данными YTsaurus внутри Яндекса применяется давно и очень активно. Какие задачи она решает, как развернуть ее внутри своей компании и использовать в связке с 1С, какие готовые модули есть для интеграции с ней и какие подходы рекомендуется применять к проектированию 1С с учетом ее наличия, рассказали разработчики YTsaurus и команды 1С Яндекс Лавки.

Меня зовут Звонков Кирилл, я являюсь руководителем сектора ERP-разработки Яндекс Лавки. Мой соавтор Ривкин Андрей руководит группой продуктового развития YTsaurus.

Эта статья о нашей работе с большими объемами данных в Яндекс Лавке и об интеграции системы 1С с системой YTsaurus. Сначала мы расскажем о проблеме, которую решаем. Затем объясним, что такое система YTsaurus. В заключении поговорим о сценариях интеграции 1С и YTsaurus. Такая структура обусловлена тем, что без понимания платформы YTsaurus сложно будет понять, почему мы используем именно такие сценарии интеграции.

 

Какую проблему решаем

Давайте ненадолго вернемся в прошлое – к проблеме, с которой мы столкнулись. В 2021 году в Яндекс Лавке использовалась конфигурация 1С:Управление торговлей 11. Объем нашей базы данных PostgreSQL увеличивался на 400 гигабайт ежемесячно. Важно отметить, что основной проблемой была не столько величина базы данных, сколько темпы ее роста. Мы уже тогда использовали облачный PostgreSQL в Яндекс Облаке, максимальный размер кластера которого составлял 4 терабайта. Возможности расширения существовали, но требовали значительных усилий, и мы не хотели этим заниматься.

Кроме того, BI-аналитики активно использовали данные из нашей 1С, но делали это посредством прямых запросов, что было для них непростой задачей. Важно отметить, что ребята из аналитики мало что знают об 1С, и при прямом чтении данных из 1С им было сложно что-либо понять. В то время как наш бизнес активно рос на фоне пандемии, объем данных продолжал увеличиваться и вскоре мог достичь 500, 600 гигабайт и более. В итоге мы бы просто исчерпали объем кластера.

 

Какие были варианты

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

Второй вариант состоял в полном отказе от использования 1С:Предприятия в нашем контуре. В Яндексе есть Oracle, у него есть свои недостатки, включая скорость разработки, которая нас не совсем устраивала. Поскольку мы ценим возможности 1С, этот вариант также не казался нам привлекательным.

Третий вариант предполагал использование шардирования средствами 1С, то есть разделение одной базы на части для распределения нагрузки. Однако сама платформа не предоставляет подходящего инструмента для шардирования, который бы соответствовал нашим требованиям и использовался в других технологиях.

Четвертый вариант, который мы рассматривали, заключался в использовании внешней базы данных и ее интеграции с 1С не как внешнего источника, который обычно используется в 1С, а как чего-то более продвинутого.

К счастью, в Яндексе уже была система, которая называется YTsaurus. В дальнейшем мы будем называть ее YT.

 

Система YTsaurus

YTsaurus является основной корпоративной системой Яндекса для хранения и обработки данных. Она поддерживает два основных сценария: OLAP и OLTP, реализуя оба в одной системе. Далее мы расскажем, каким образом это происходит.

Эта система отлично масштабируется, так как изначально была создана для обработки объемов данных на уровне петабайт, и наши терабайты данных не представляют для нее никакой проблемы. Кроме того, она обладает возможностью интеграции с 1С по REST API.

 

Как сейчас

На текущий момент размер основной базы данных у нас составляет 2 терабайта, а размер данных в кластере YT – 25 терабайт.

Здесь приведен пример таблицы внутри YT. Вверху указано количество строк в этой таблице. В таблице содержится 19 миллиардов строк, а общий объем таблицы составляет 10 терабайт. При этом скорость чтения из данной таблицы никак не снижается при росте объема. Мы можем добавить туда еще 20 миллиардов строк, и в целом ничего не изменится.

 

 

YTsaurus

Когда нас спрашивают, что такое YTsaurus, мы обычно говорим, что это платформа для хранения и обработки больших данных. Если кто-то знает, что такое Hadoop, то можно провести аналогию, так как это очень похоже на всю экосистему Hadoop. Представьте себе базу данных, в которой можно совместить OLAP и OLTP. При этом она масштабируется и может достигать огромных объемов.

Размер одного из наших кластеров – это экзабайты места, которое можно использовать. Это миллионы ядер, множество графических процессоров и порядка 20 тысяч серверов. Это один из кластеров Яндекса, в котором хранится основной набор данных компании. Мы предоставляем эту платформу внутри как сервис для разных подразделений, таких как Яндекс Такси, Яндекс Маркет, беспилотные автомобили и Яндекс Лавка. Разные команды работают в ней и сожительствуют.

Почему мы вообще можем про это рассказывать? Потому что мы выложили платформу в открытый доступ (open source), и теперь ей можно воспользоваться. Мы понимаем, что такие огромные объемы нужны не всем. Тем не менее, начинать можно с пяти серверов и потихоньку наращивать мощности и масштабироваться.

Система не является каким-то форком или копией. Она полностью написана на C++, создана для целей самого Яндекса и для наших объемов более 10 лет назад. Мы продолжаем систему эксплуатировать и использовать с высокой нагрузкой. Наверное, самый большой наш пользователь – это реклама Яндекса. Когда вы заходите на главную страницу Яндекса, вы видите рекламу, и мы ее показываем из этой системы.

 

Преимущества платформы

При помощи одного большого кластера вы можете решать довольно широкий спектр задач. Вы можете использовать его для ETL обработки, делать быстрые запросы для построения аналитики, графиков, подключать BI-инструменты. Вы можете использовать ее для OLTP сценариев. Это не так удобно, как в PostgreSQL, но возможно, и этот сценарий будет масштабироваться. Также вы можете использовать ее для ML-обучения, если у вас есть такие задачи.

За счет того, что система одна, вам не надо данные никуда копировать, не надо делать синхронизацию. Когда одни люди научились что-то делать, они могут своими наработками поделиться с другими. И мы от этого, как Яндекс, очень много выигрываем.

 

Архитектура YTsaurus

На изображении представлена высокоуровневая архитектура.

 

 

В основе системы лежит распределенная файловая система с поддержкой транзакций, называемая Cypress. По сути, ее можно представить как обычную файловую систему на любом ноутбуке, но с расширенными возможностями. Отличие заключается в том, что помимо файлов, она хранит таблицы (представьте себе Excel). Система масштабируется, и вы можете добавлять узлы для хранения большего количества данных.

Таблицы бывают двух типов:

  1. Статические таблицы – обеспечивают очень дешевое хранение исторических данных.

  2. Динамические таблицы – напоминают таблицы в PostgreSQL. Их можно легко обновлять, изменять и удалять данные.

Далее, у нас есть разнообразные движки для обработки данных. Они используют единое хранилище, и у всех движков общие данные.

  • YQL (SQL-интерфейс) – позволяет писать ETL-процессы и выполнять задачи по обработке больших объемов данных (терабайты и петабайты).

  • CHYT (ClickHouse движок) – позволяет обращаться к данным, хранящимся в этом едином большом хранилище.

  • SPYT (Apache Spark движок) – классический инструмент для аналитиков, для машинного обучения и выполнения обработки данных в памяти.

В верхней части архитектуры находится SDK на четырех языках, удобный пользовательский интерфейс и инструмент командной строки. Это все, что существует на верхнем уровне системы.

Что такое YTsaurus

Давайте вернемся к Cypress. Он выглядит как некоторая древовидная файловая система с папками и таблицами.

 

 

Здесь есть несколько интересных особенностей:

  1. Транзакционность – система поддерживает транзакции. Вы можете атомарно переименовывать таблицу, создавать новую и коммитить транзакцию.

  2. Атрибуты таблиц – каждая таблица имеет набор атрибутов. Эти атрибуты бывают системные, такие как дата создания и количество строк, и пользовательские. Вы можете указать ответственного или описать процесс, породивший эту таблицу. Во время обработки вы получаете как таблицу, так и ее метаданные, что позволяет выполнять обработку в зависимости от доступных метаданных.

Система поддерживает различные типы хранилищ: HDD, SSD, NVMe и даже оперативную память. Вы можете выбирать тип хранилища в зависимости от требований к скорости доступа к данным и желаемой задержки. Это просто атрибут, и система сама переместит данные в фоновом режиме.

 

Интерфейс

Вот пример интерфейса. Это Navigation (навигация). Здесь вы видите папки и две таблицы. Они немного различаются. На изображении виден документ и метаинформация. Также есть вкладки с атрибутами, блокировками, поскольку система транзакционная, и управление доступом к данным, которое определяет, кто может читать и кто может писать.

 

 

Основной объект системы – таблица

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

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

 

 

На следующем изображении представлена эта таблица в интерфейсе. Здесь можно увидеть количество строк, информацию о создателе таблицы, ее тип (поколоночная или посрочная). И есть даже кнопочка YQL – это возможность написать SQL-запрос прямо к этой таблице, прямо в этом интерфейсе.

 

 

Как уже было сказано, таблицы бывают двух типов.

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

Динамические таблицы. Это распределенное key-value хранилище с поддержкой транзакций. Сейчас их также называют NewSQL. Под капотом у них используется LSM-дерево, есть поддержка in-memory хранения, поддержка кросс-табличных транзакций и модель изоляции MVCC. Такие системы существуют.

 

 

Основное преимущество динамических таблиц заключается в их тесной интеграции с движками обработки и MapReduce. Это значит, что если у вас есть история, которая лежит и занимает гигабайты или терабайты в статической таблице, и есть какие-то активно меняемые данные, которые лежат в динамической таблице, вы можете их объединить. Вы можете подготовить в движке снапшот ваших новых данных, атомарно вставить их в технологические таблицы и начать их использовать, например, в интернет-магазине или в 1С.

Это довольно редкая возможность, потому что хорошо совмещать OLTP и OLAP нагрузку сложно. Нужны определенные механизмы. Внутри системы мы научились это делать. Существует довольно большое количество разных конфигураций: вы можете выбирать, где вы храните ваши данные и каким движком вы их обрабатываете.

 

Scheduler

Возвращаемся к обработке. У нас есть такая функция, как Scheduler (шедулер). Это пространство вычислительных ресурсов, которое вы распределяете между командами или пользователями. Например, вы можете сказать: «Вот этому человеку 100 ядер, этому 200, а вот этот пусть работает на негарантируемых ресурсах, используя то, что осталось от продакшена». У нас есть структура пулов – это контейнер, в котором распределяются ресурсы. У каждого пула есть ACL (Access Control List), который определяет, кому можно запускать задачи в этом пуле. Например, в одном пуле работает продакшен, а в другом – тестовые задачи.

 

 

Предположим, у вас есть кластер с тысячами ядер, и вы их как-то распределяете. Шедулер отвечает за это разделение. Далее внутри пулов вы можете запускать разные задачи и передавать данные между ними.

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

 

 

YQL

Внутри пула вы можете запускать разные задачи. Одна из таких задач – это YQL. Это SQL-движок, который позволяет обрабатывать данные. Это классический SQL. Его ограничение заключается в том, что он не очень быстрый. Он отлично подходит для обработки больших объемов данных, но у него низкая задержка, порядка единиц секунд. Тем не менее, он эффективно использует кластер, сохраняет промежуточные результаты, не боится сбоев и имеет разные аналитические возможности. Например, можно внутри SQL-запроса использовать Python или вызывать функции для машинного обучения, которые уже встроены, писать свои UDF (User Defined Functions). Но если вы хотите посчитать данные или построить дашборд, это может быть медленно.

 

 

ClickHouse over YT (CHYT)

Мы взяли базу ClickHouse, тоже разработанную в Яндексе, отрезали у нее нижнюю часть и сказали: «А теперь смотри на данные, которые лежат у нас в кластере». Вы можете поднять несколько таких маленьких баз ClickHouse в рамках YTsaurus и дальше с ними работать из любого BI-инструмента, писать быстрые запросы, если объем данных позволяет.

 

 

Преимущества. Данные у вас одни и те же. Они лежат на месте, и вы их обрабатываете. Вы запустили ETL, подготовили какую-то витрину данных и захотели построить дашборд над теми же данными. Вы подняли себе ClickHouse over YT instance и начали писать запросы через него. Данные копировать не нужно. Если ночью вам эта штука не нужна, вы ее остановили и запустили ETL на тех же самых ресурсах.

 

Spark over YT (SPYT)

Ситуация в Spark похожая. Любите писать на Python, знаете Spark, у вас много процессов на нем написано, любите in-memory обработку? Хорошо, подняли себе Spark-кластер, написали, запустили над теми же данными. Хотите, записали их в статические таблицы, хотите – в динамические. В общем, делайте все, что угодно, с вашими данными, которые лежат в этом хранилище.

 

 

На скриншоте примера из интерфейса видно, как можно написать запрос на синтаксисе ClickHouse SQL и какой получить результат. Можно взять ссылку и поделиться с коллегой, чтобы он посмотрел на результат и проанализировал его.

 

 

SDK

Наша команда делает довольно неплохие SDK на четырех основных языках программирования: Java, Python, C++ и Go.

 

 

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

 

Интеграция 1С и YTsaurus

У нас есть пять основных сценариев работы:

  1. Репликация объектов 1С в YT – репликация объектов в динамические таблицы.

  2. Замена табличных частей документов, справочников и некоторых регистров динамическими таблицами в реальном времени.

  3. Отказ от формирования отчетов внутри 1С – перенос всей отчетности в BI.

  4. Обработка данных с помощью YQL-запросов – активное применение YQL в 1С.

  5. Хранение и обработка логов в YT – использование YQL для обработки логов и хранение их в виде таблиц.

Теперь более подробно о первом сценарии. Это основной сценарий, с которого мы начинали работу с YT.

 

Сценарий 1. Репликация объектов в динамические таблицы

Какова наша архитектура 1С в целом? Мы проектируем систему таким образом, чтобы все исторические данные и большие объемы данных хранить в YT, а в PostgreSQL внутри 1С сохранять текущий условно-актуальный период. При этом данные задним числом мы не изменяем. Все процессы – расчет себестоимости, закрытие месяца, взаиморасчеты, складские остатки – у нас делаются текущей датой. Это позволяет нам безболезненно удалять данные.

Этот механизм содержит в себе две вещи: репликацию и архивацию. Они работают вместе. И механизм архивации решил нашу проблему с объемом базы.

 

Механизм репликации

Мы фиксируем универсальную дату изменения для всех объектов, которые хотим реплицировать. У нас есть курсорные выборки из регистра сведений, откуда данные выгружаются. Затем мы написали механизм, который выгружает данные в YT через API.

Первоначально мы просто писали код на 1С, выгружали данные из таблицы и реплицировали их в YT. Когда у нас появились десятки таких реплик, мы поняли, что нужен универсальный механизм. Мы создали систему, которая позволяет пользователям настраивать репликацию в интерфейсе, аналогично тому, как это сделано в конвертации данных 3.0, в соответствии с полями объекта 1С и объекта YT. Затем система работает автоматически.

Например, выгрузка какого-нибудь документа у разработчика занимает примерно 5-10 минут, в зависимости от сложности документа. Этот сценарий позволяет встраивать туда постобработчики и писать сложный код, который не просто реплицирует данные в YT, но и обогащает их. Механизм расчета себестоимости у нас работает именно таким образом. Мы в 1С считаем транзакции, а когда выгружаем их в YT, обогащаем большим количеством данных. Это сильно экономит место в 1С, но дает более расширенные возможности для аналитики.

 

Шардирование данных

У нас есть не только эта база, но и другие базы 1С. Также есть сценарий, когда поднято несколько инстансов одной и той же базы. Например, их три, и нам нужно предоставить данные в едином виде, в одной таблице. Мы реплицируем данные из трех баз 1С в одну таблицу. Там есть разделитель, условно ID базы, и таким образом задача решается. Это понятный механизм условного шардирования, который позволяет легко предоставлять данные внешним пользователям.

 

Также мы реализовали механизм, когда нужно получить архивные данные из YT, если они уже удалены в 1С. Это тоже можно сделать понятным образом из YT. Это первый сценарий, и он основной.

 

Сценарий 2. Замена табличных частей и регистров динамическими таблицами

Данный сценарий более сложный. Это случай, когда мы отказываемся от хранения данных в 1С. Например, создаем документ, но не делаем табличные части, а сразу проектируем табличную часть так, чтобы она хранилась в YT. В YT динамическая таблица, ее особенность в том, что это key-value хранилище, у нее есть ключ, и 1С может легко работать с таким форматом. Есть ключ GUID документа, и он является ключом динамической таблицы. Операция вставки в динамическую таблицу умеет обновлять данные по ключу. Когда пользователь или робот записывает объект в базу, мы одновременно транзакционно можем вставлять данные во внешнюю систему.

При этом можно сделать транзакционно несколько таблиц, так как YT поддерживает транзакции. В YT реализована поддержка транзакций, когда мы можем несколько запросов транзакционно сохранить в YT с гарантиями.

Мы также реализовали еще один сценарий, когда нужно отдавать данные во внешнюю систему по API. К нам приходит внешний запрос в сервис, и мы данные читаем не из PostgreSQL, а напрямую из YT. При этом, если нам нужно увеличить скорость отдачи данных, мы просто ставим галочку на таблице, что таблица in-memory, и больше ничего делать не нужно. Поставили галочку, и таблица средствами YT сама автоматически стала in-memory. Конечно, не стоит терабайтную таблицу засовывать в память, там есть ограничения, но адекватные таблицы можно сделать in-memory. Это позволяет сильно увеличить скорость доступа к данным, до десятков миллисекунд.

Это довольно сложный алгоритм, и его нужно много программировать внутри 1С. Но он довольно перспективен для нас, и мы в него верим.

Важный момент заключается в том, что внутри YT данные можно хранить в виде JSON в поле. Есть поле product, в котором хранятся данные табличной части. Когда выполняются запросы в YT, мы используем одну таблицу, а не несколько. Это позволяет удобнее хранить данные, и средствами YQL такую структуру можно развернуть в понятную плоскую таблицу.

 

 

Сценарий 3. Отказ от формирования отчетов в 1С

Когда мы проектируем документы, регистры и другие элементы, мы изначально исходим из того, что отчеты внутри 1С создавать не будем. Это позволяет нам избежать высокой нагрузки, связанной с формированием отчетов в 1С. И экономит время на разработку, так как наши разработчики 1С в основном не занимаются созданием отчетов, хотя в мире 1С это довольно распространенная задача. Это также снимает значительную нагрузку с платформы и кластеров, включая утечки памяти. Основной инструмент визуализации внутри Яндекса, который мы используем, – это DataLens.

 

Сценарий 4. Использование YQL-запросов

Следующий сценарий – использование YQL-запросов для обработки данных вне 1С. Например, если нам нужно объединить большой объем исторических данных, таких как продажи за год по всем складам, добавить туда остатки и взять данные из внешней системы (например, из FMS – Financial Management System) или из третьей системы (например, от аналитиков), мы просто пишем YQL-запрос в YT, который объединяет данные и обрабатывает их. В YQL можно встроить обработчики на Python, что значительно расширяет возможности обработки данных. На выходе этот алгоритм дает готовую таблицу, которую мы загружаем в 1С и используем в своих задачах, если это необходимо, или показываем в интерфейсе. Сложные расчеты внутри 1С мы не выполняем, а используем YQL.

 

Использование готовых данных

Похожий сценарий – это когда внешние команды предоставляют нам готовые данные, которые мы используем в своих алгоритмах. Например, команда аналитиков рассчитала что-то и отдала нам. Мы просто берем, читаем таблицу в YT, загружаем ее себе или используем в реальном времени, если это возможно и объем позволяет.

 

Сценарий 5. Хранение логов

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

 

 

Готовые инструменты

Готовые инструменты, которые мы планируем выложить в Open Source:

  1. Модуль интеграции YTsaurus с 1С. Там реализованы все методы, такие как insert, select, и есть метод, который позволяет отправить кастомный запрос. Вы просто пишете текст запроса, вызываете его по API, и вам возвращаются данные. Есть метод, который позволяет выполнить транзакцию транзакционно.

  2. Модуль репликации данных, который был показан на скриншоте. Он позволяет в пользовательском режиме удобным образом настроить репликацию.

Мы показали один из способов, как можно обрабатывать большие данные в 1С, используя внешнюю технологию. На наш взгляд, это довольно ценно, потому что не все задачи можно и нужно решать в 1С. Обработка терабайтных данных в 1С – не самая лучшая идея, и есть инструменты, которые позволяют делать это проще.

 

*************

Статья написана по итогам доклада (видео), прочитанного на конференции INFOSTART TECH EVENT.

Вступайте в нашу телеграмм-группу Инфостарт

См. также

HighLoad оптимизация Программист 1С v8.3 1C:ERP Бесплатно (free)

Приведем примеры использования различных в динамических списках и посмотрим, почему это плохо.

18.02.2025    5761    ivanov660    39    

59

HighLoad оптимизация Технологический журнал Системный администратор Программист Бесплатно (free)

Обсудим поиск и разбор причин длительных серверных вызовов CALL, SCALL.

24.06.2024    8353    ivanov660    13    

60

HighLoad оптимизация Программист 1С v8.3 Бесплатно (free)

Метод очень медленно работает, когда параметр приемник содержит намного меньше свойств, чем источник.

06.06.2024    13717    Evg-Lylyk    67    

45

HighLoad оптимизация Программист 1С v8.3 1C:Бухгалтерия Бесплатно (free)

Анализ простого плана запроса. Оптимизация нагрузки на ЦП сервера СУБД используя типовые индексы.

13.03.2024    6635    spyke    29    

52

HighLoad оптимизация Программист 1С v8.3 Бесплатно (free)

Оказывается, в типовых конфигурациях 1С есть, что улучшить!

13.03.2024    9798    vasilev2015    22    

45

HighLoad оптимизация Инструменты администратора БД Системный администратор Программист 1С v8.3 1C:Бухгалтерия Абонемент ($m)

Обработка для простого и удобного анализа настроек, нагрузки и проблем с SQL сервером с упором на использование оного для 1С. Анализ текущих запросов на sql, ожиданий, конвертация запроса в 1С и рекомендации, где может тормозить.

5 стартмани

15.02.2024    16424    317    ZAOSTG    100    

123
Оставьте свое сообщение