Русский
Русский
English
Статистика
Реклама

Хранение данных

Шифрование диска с помощью VeraCrypt на Windows для неискушенных пользователей

19.05.2021 18:19:31 | Автор: admin

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

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

Этот материал вдохновлен статьёй Олега Афонина "Как укрепить Веру. Делаем шифрованные контейнеры VeraCrypt неприступными". Если вы хотите углубиться в тему ИБ, то можете задонатить и подписаться на него.

Важно

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

Узнать заранее поддерживает ли ваш данную технологию можно на официальном сайте вендора. Например Intel:

Или проверить можно на сторонних сайтах, пример здесь.

Также можно проверить наличие данной технологии с помощью самой программы VeraCrypt. После установки зайдите в Сервис > Тест скорости... Нас интересует показатель в правом нижнем углу.

Показатель "Да" будет означать наличие ускорения, показатель "Н/П" ее отсутствие.

Установка

Скачивайте с официального сайта. Заходим на вкладку Downloads, выбираем версию (Installer for) для своей операционной системы, я выбрал Windows.

Далее открываем скачанный файл и начинаем установку. Тут все просто, подтверждаем все пункты пока не установим программу.

VeraCrypt в конце процедуры может пожаловаться на функцию быстрого запуска ОС. В этом случае, отключаем ее:

Перезагружаем компьютер.

Эксплуатация

После перезагрузки открываем VeraCrypt и создаем новый том. В открывшемся мастере создания томов мы делаем следующее:

  1. Выбираем "Зашифровать раздел или весь диск с системой"

  2. Тип шифрования обычный

  3. Область шифрования на выбор два варианта, "Зашифровать системный раздел Windows" или "Зашифровать весь диск". Если у вас доступен второй, то выбираем его.

  4. Число операционных систем "Одиночная загрузка", если у вас на машине только одна ОС.

Шифрование

И тут мы переходим к самому интересному, методам шифрования.

В качестве алгоритма мы выбираем проверенный временем AES, а вот с хэшированием уже посложнее.

В первую очередь злоумышленники отрабатывают самые распространенные сценарии, AES и SHA-512, которые стоят по умолчанию. По возможности отказываемся от стандартных настроек: усложняем задачу хакерам, чтобы им пришлось дольше угадывать какой комбинацией вы шифруетесь.

Лично я выберу Whirlpool.

Внимание, ни при каких условиях не выбирайте Streebog, данный алгоритм содержит дыру в безопасности (разработан Центром защиты информации и специальной связи ФСБ России с участием ОАО "ИнфоТеКС")

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

Ставим галочку "Использовать PIM" и идем дальше.

PIM (Personal Iterations Multiplier)

Нас попросят ввести PIM, там же приводится описание данного термина. Чем больше тем безопаснее, но вместе с тем медленнее. Подождать лишние секунды при загрузке несложно, а нам полезнее.

Если вам интересны конкретные цифры, то ниже будут представлены картинки с тестами:

Настройки PIM по умолчанию (485):

500:

1000:

Чтобы у вас сложилось понимание почему мы должны его использовать, представим, что даже если злоумышленник знает пароль, ему придется перебирать все вариации PIM, то есть (1,2,3 ... n) чтобы расшифровать диск. И если не знать точного числа, то можно застрять надолго, что играет нам на руку.

Но даже при высоком значении стоит выбирать номер очень аккуратно. То есть комбинации 1234 / 2012 / 1939 / год рождения ребенка / поступления / совершеннолетия сразу отбрасываем. Число никак не должно быть связано с вами, и при этом не быть слишком тривиальным.

Итак, PIM должен быть большим, анонимным и неординарным. Например 1709.

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

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

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

Пре-тест

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

Для особых случаев в ходе пре-теста (например если вы резко забыли пароль и PIM придуманные 5 минут назад) существует механизм обхода ввода пароля. Нажимаем на ESC и загружаемся в Windows. VeraCrypt уведомит нас что пре-тест провалился и предложит пройти его снова. Мы от предложения отказываемся.

Заходим в Система > Окончательно расшифровать системный раздел/диск. Убеждаемся что ничего не зашифровано и повторяем весь процесс шифрования с начала.

В случае успешного входа нас встретит VeraCrypt с оповещением, что пре-тест выполнен успешно, и нам остается лишь зашифровать диск, что мы и делаем, нажав Encrypt, после чего ждем около 15 минут.

Вы сделали это. Вы - Молодец.

Дальше ответы на вопросы:

За раз шифруется только 1 диск ?

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

Разве увеличение длины пароля на два-три знака из расширенного набора символов не даст схожий или даже лучший результат чем PIM?

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

Подробнее..

Небезопасный сервис про безопасность

02.06.2021 10:16:01 | Автор: admin

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

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

Мы делали продукт о безопасности. Эдакая народная карта противоправных действий, на которой пользователи могли отметить подозрительные события и подписаться на уведомления в интересующих районах.

Продукт включал в себя приложения Android/iOS, фронт и бэк. Я писала мобилки, двое моих коллег занимались фронтом и бэком соответственно.

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

Утро перед пресс-конференцией. Заблаговременно выпущены релизы в AppStore и Google Play, фронт и бэк задеплоены. Боевая база данных потихоньку набирает пользователей - наша команда, тестировщики, представители заказчика и случайные люди, которые сами нашли продукт, хотя реклама еще не давалась.

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

Согласовав с заказчиком маневр, мы очистили базу. Началась пресс-конференция, а вместе с ней начали появляться первые регистрации.

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

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

Выстрелили два фактора - целочисленный id у пользователей и вечный токен, который генерировался однозначно из этого id.

Поясню подробнее на примере.

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

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

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

За годы работы в IT я убедилась - любой практический опыт, а тем более опыт ошибок, со временем перерастает в профессиональное чутье. А теоретические знания без практики быстро меркнут, поэтому важно действовать и не бояться оступиться. Люди ошибаются, это нормально. Не нормально - не анализировать свои ошибки.

Подробнее..

Обучающие вебинары Dell Technologies новые серверы, VDI, хранение и защита данных, модернизация ЦОД, удалённая работа

04.06.2021 14:18:19 | Автор: admin

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

Интересно будет специалистам разного профиля, причём не только техническим. На наш взгляд, про VDI и организацию удалённой работы наверняка полезно будет послушать руководителям и владельцам бизнеса. Как и всегда, заранее можно зарегистрироваться на любое количество вебинаров, участие в них бесплатное. Если тема заинтересовала, то лучше не откладывать регистрацию на потом после неё мы пришлём уведомление ближе к началу сессии. Все даты, подробности и ссылки под катом.


Новая линейка серверов Dell EMC PowerEdge

Вебинар доступен в записи

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


Dell Hybrid Client: новая ступень в развитии VDI

10 июня, 11:00 (МСК)

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


Решения Dell Technologies для хранения и защиты данных

24 июня, 11:00 (МСК)

Это самый большой вебинар из всех, запланированных на текущий квартал, в нём будет сразу четыре выступления. Все посвящены современным подходам к хранению и защите данных. Сначала мы посмотрим на серверы PowerEdge в обозначенном контексте: поговорим об оптимизации производительности, использующихся хранилищах данных и масштабировании. Затем изучим Dell EMC PowerScale лидирующее на рынке решение для работы с файловыми и объектными задачами. После этого перейдём к PowerProtect комплексному программно-аппаратному решению для защиты данных. После этого расскажем о SmartFabric, сервисе автоматизации сетевой фабрики Dell EMC для PowerStore и PowerScale.


Модернизация сети ЦОД с решением Dell EMC SmartFabric Director и VMware NSX-T

8 июля, 11:00 (МСК)

На технической сессии эксперты Dell Technologies расскажут, как упростить автоматизацию сетевой фабрики ЦОД и виртуализацию сети на всех этапах во время развёртывания, обслуживания и мониторинга. Особый акцент сделаем на платформе VMware NSX-T: изучим её архитектуру и компоненты, рассмотрим преимущества и сценарии применения, в которых она будет наиболее эффективна. В качестве вишенки на торте мы приготовили разбор реального сценария модернизации сети ЦОД одного из наших заказчиков на основе сети Dell EMC и VMware NSX-T.


Современные подходы к организации удалённых рабочих мест: собственный опыт Dell Technologies

22 июля, 11:00 (МСК)

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

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


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

Подробнее..

Автоматизация или смерть как управлять тысячами единиц игрового контента с помощью гугл-таблиц

10.06.2021 18:12:02 | Автор: admin

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

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

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

Баланс в онлайн-шутере крайне важная штука. Нужно, чтобы геймплей нравился всем игрокам не было тех, кто не может вообще никого убить или, наоборот, тех, кто доминирует и фрустрирует всех остальных.

На первых годах жизни Pixel Gun 3D использовалась простая схема: весь контент добавлялся и редактировался вручную. Нужно поменять урон пушке? Заходишь в Unity, открываешь нужный файл и правишь руками. Дело на пару минут.

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

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

Нужно было глобально что-то менять.

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

Из гугл-таблиц в Unity

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

Для получения данных с таблиц мы используем Google Apps Script. Первое время заводили отдельные скрипты на каждую таблицу, в которых обрабатывали данные в JSON. Затем, получая в редакторе JSON, применяли их по назначению.

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

Так выглядит наш скрипт:
function doGet(e){ if (e === undefined || e.parameter === undefined) {   return FailWithMessage("nullable parameters"); } var tableId = e.parameter["table"]; var listName = e.parameter["list"]; if (listName !== undefined && listName !== "" && listName !== "null") {   var startRow = parseInt(e.parameter["startRow"]);   var startColumn = parseInt(e.parameter["startColumn"]);   var numRow = parseInt(e.parameter["numRow"]);   var numColumn = parseInt(e.parameter["numCol"]);   return GetSigleList(tableId, listName, startRow, startColumn, numRow, numColumn); } else {   return GetAllTable(tableId); }}  function GetSigleList(tableId, listName, startRow, startColumn, numRow, numColumn){ var ss = SpreadsheetApp.openById(tableId); if (ss == null) {   return FailWithMessage("table with name: " + tableId + "not found"); } var sheet = ss.getSheetByName(listName); if (sheet == null) {   return FailWithMessage("list with name: " + listName + "not found"); }  if (numRow < 1) numRow = sheet.getLastRow(); if (numColumn < 1) numColumn = sheet.getLastColumn(); var range = sheet.getRange(startRow, startColumn, numRow, numColumn); var data = range.getValues(); var str = JSON.stringify(data);  var resultObject = {   "resultCode": 2,   "message": str }; var result = JSON.stringify(resultObject); return ContentService.createTextOutput(result);}  function GetAllTable(tableId){ var ss = SpreadsheetApp.openById(tableId); if (ss == null) {   return FailWithMessage("table with name: " + tableId + "not found"); }  var result = {};  var listModes = ss.getSheets(); for(var i = 0; i< listModes.length; i++) {   var sheet = listModes[i];   var sheetName = sheet.getSheetName();     var range = sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn());   var data = range.getValues();   result[sheetName] = data; }  var str = JSON.stringify(result);  var resultObject = {   "resultCode": 2,   "message": str };  var result = JSON.stringify(resultObject); return ContentService.createTextOutput(result);} function FailWithMessage(message){ var result = {   "resultCode": 1,   "message": message };   var str = JSON.stringify(result);  return ContentService.createTextOutput(str);}

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

После публикации получится ссылка такого формата:

https://script.google.com/macros/s/WwlCZODTDRXJaHhdjfwFRcKtHRQOHqzYisjndduZzDihMpXehLrNxdi/exec

Ее нужно использовать для запуска скрипта. Чтобы скрипт знал, с какой таблицы нужны данные, в get-запрос подставляем ID таблицы. Получить его можно из URL таблицы. Например, в https://docs.google.com/spreadsheets/d/example_habr/edit#gid=0, ID будет example_habr.

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

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

https://script.google.com/macros/s/WwlCZODTDRXJaHhdjfwFRcKtHRQOHqzYisjndduZzDihMpXehLrNxdi/exec?table=example_habr&list=MyList&startRow=1&startColumn=2&numRow=10&numCol=5

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

Теперь большинство параметров контента редактируется не внутри проекта, а во вне. Движок просто получает данные из таблицы в реальном времени. Например, нужно всем пушкам добавить 5 урона: вбиваем в ячейку, протягиваем по столбцу и нажимаем загрузить. Готово все данные ушли в клиент. По сути, мы с помощью нескольких гугл-таблиц управляем всей игрой.

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

Но мы пошли дальше.

Из Unity в гугл-таблицы

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

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

Начали с простеньких задачек. Например, мы часто превышали лимит в 500 символов на описание апдейта в Google Play. Стор такое отклоняет, нужно переписывать и отправлять заново. Задались вопросом, а есть ли формула для подсчета символов в ячейке? Разумеется, в гугл-таблицах большой перечень базовых формул, которые можно комбинировать как угодно и решать практически любые задачи. Написали в ячейке, чтобы описание апдейта автоматически проверялось на количество символов =ДЛСТР(номер ячейки). Теперь проблемы нет.

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

В гугл-таблицах огромное количество функций, ознакомиться со всеми можно на сайте саппорта Google.

Например, решили составить коллекции для галереи оружия (это такие подборки оружия по схожим признакам: цвет, сеттинг, сезон). Чтобы составить одну коллекцию, нужно оценить визуал, смотрятся ли они вместе, схожий ли у них класс и другие детали. Для этого сделали таблицу, в которую из базы данных выгрузили список всех пушек, написали формулу и подгрузили превьюшки, с которыми можно визуально работать. А уже из таблиц по балансу подтягиваем названия, теги и остальную информацию.

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

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

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

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

Где используем автоматизацию

Мы применяем ее практически везде, где это возможно. И всегда ищем новые способы, чтобы сделать себе жизнь проще и переложить часть работы на формулы.

Балансировка контента

Самые базовый способ применения, о котором уже упоминали выше. Так мы ищем проблемные места, добавляем новый контент, не ломая старый, нерфим или бафаем оружие и так далее.

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

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

Генерация сущностей

Автоматизацию можно использовать не только для баланса, но и для генерации нового контента. Так, в каждом батлпассе у нас есть порядка 140 разных челленджей (например, сыграть 10 игр в определенном режиме или убить 30 противников из пистолета). Каждый раз придумывать это вручную долго и нудно, поэтому сделали генерацию. Собрали подробный список условий и прямо из гугл-таблицы создаем квесты теперь одна формула придумывает нам все задачи на каждый сезон.

Естественно, со сгенерированным пулом работает уже человек и настраивает кривую сложности. Игрок должен плавно войти в ивент, тем самым повысив конвертацию в платеж или в более длинную игровую сессию.

Подобным образом мы генерируем задачи и для клановых войн.

Пример формулы:

=ifs(I2="EndMatch";ifs(AE2<=TasksData!$O$34+TasksData!$N$34;"TeamDuel";AE2<=TasksData!$O$34+TasksData!$N$34+TasksData!$M$34;ЕСЛИ(A2=0;"TeamDuel";"Spleef");AE2<=TasksData!$O$34+TasksData!$N$34+TasksData!$M$34+TasksData!$L$34;"Duel";AE2<=TasksData!$O$34+TasksData!$N$34+TasksData!$M$34+TasksData!$L$34+TasksData!$K$34;ЕСЛИ(A2=0;"Duel";"BattleRoyale");AE2<=TasksData!$O$34+TasksData!$N$34+TasksData!$M$34+TasksData!$L$34+TasksData!$K$34+TasksData!$J$34;ЕСЛИ(A2=0;"TeamFight";"DeadlyGames");AE2<=TasksData!$O$34+TasksData!$N$34+TasksData!$M$34+TasksData!$L$34+TasksData!$K$34+TasksData!$J$34+TasksData!$I$34;"CapturePoints";AE2<=TasksData!$O$34+TasksData!$N$34+TasksData!$M$34+TasksData!$L$34+TasksData!$K$34+TasksData!$J$34+TasksData!$I$34+TasksData!$H$34;"FlagCapture";AE2<=TasksData!$O$34+TasksData!$N$34+TasksData!$M$34+TasksData!$L$34+TasksData!$K$34+TasksData!$J$34+TasksData!$I$34+TasksData!$H$34+TasksData!$G$34;"Deathmatch";AE2>TasksData!$O$34+TasksData!$N$34+TasksData!$M$34+TasksData!$L$34+TasksData!$K$34+TasksData!$J$34+TasksData!$I$34+TasksData!$H$34+TasksData!$G$34;"TeamFight"); I2="killPlayer";ifs(AE2<=TasksData!$N$35;"TeamDuel";AE2<=TasksData!$N$35+TasksData!$L$35;"Duel";AE2<=TasksData!$N$35+TasksData!$L$35+TasksData!$K$35;ЕСЛИ(A2=0;"TeamFight";"BattleRoyale");AE2<=TasksData!$N$35+TasksData!$L$35+TasksData!$K$35+TasksData!$J$35;"DeadlyGames";AE2<=TasksData!$N$35+TasksData!$L$35+TasksData!$K$35+TasksData!$J$35+TasksData!$I$35;"CapturePoints";AE2<=TasksData!$N$35+TasksData!$L$35+TasksData!$K$35+TasksData!$J$35+TasksData!$I$35+TasksData!$H$35;"FlagCapture";AE2<=TasksData!$N$35+TasksData!$L$35+TasksData!$K$35+TasksData!$J$35+TasksData!$I$35+TasksData!$H$35+TasksData!$G$35;"Deathmatch";AE2>TasksData!$N$35+TasksData!$L$35+TasksData!$K$35+TasksData!$J$35+TasksData!$I$35+TasksData!$H$35+TasksData!$G$35;"TeamFight"); I2="killPet";ifs(AE2<=TasksData!$G$36;"Deathmatch";AE2>TasksData!$G$36;"TeamFight"); I2="killPlayerThroughWall";ifs(AE2<=TasksData!$I$37;"CapturePoints";AE2<=TasksData!$I$37+TasksData!$H$37;"FlagCapture";AE2<=TasksData!$I$37+TasksData!$H$37+TasksData!$G$37;"Deathmatch";AE2>TasksData!$I$37+TasksData!$H$37+TasksData!$G$37;"TeamFight"); I2="killPlayerFlying";ifs(AE2<=TasksData!$I$38;"CapturePoints";AE2<=TasksData!$I$38+TasksData!$H$38;"FlagCapture";AE2<=TasksData!$I$38+TasksData!$H$38+TasksData!$G$38;"Deathmatch";AE2>TasksData!$I$38+TasksData!$H$38+TasksData!$G$38;"TeamFight");I2="ramEscort";"Siege";I2="escortDestroyGate";"Siege";I2="winBrNoChest";"BattleRoyale";I2="crashChest";"BattleRoyale";I2="winBrInParty";"BattleRoyale";I2="flagCapture";"FlagCapture";I2="pointCapture";"CapturePoints")

Пример таблицы с вводными для генератора:

Пример формулы (в ней представлена часть с генерацией описаний задач, Key_номер это ключи локализаций, из которых составляются задачи):

=IFS(I2="endMatch";(ЕСЛИ(T2=0;"Key_7220";"Key_7234"));I2="killPet";ЕСЛИ(W2="None";"Key_7228";"Key_7224");I2="killPlayer";ЕСЛИ(Q2=1;"Key_7227";(ЕСЛИ(W2="NONE";ЕСЛИ(R2=1;"Key_7232";ЕСЛИ(S2=1;"Key_7233";"Key_7221"));"Key_7216")));I2="killPlayerFlying";"Key_7225";I2="killPlayerThroughWall";"Key_7226";I2="ramEscort";"Key_7235";I2="escortDestroyGate";"Key_7236";I2="winBrNoChest";"Key_7229";I2="crashChest";"Key_7230";I2="winBrInParty";"Key_7231";I2="flagCapture";"Key_7237";I2="pointCapture";"Key_7238";I2="";"")

И еще более эпичная, уже проходящая через ячейки параметров и рандомайзеров:

=ifs(L3="DeadlyGames";0;L3="BattleRoyale";0;L3="TeamDuel";0;1=1;ЕСЛИ(I3="killPlayer";ifs(A3=0;ЕСЛИ(СЧЁТЕСЛИ($I$2:I2;"killPlayer")>=(TasksData!$B$34+TasksData!$B$36+TasksData!$B$38)*6;ЕСЛИ(СЧЁТЕСЛИ($I$2:I2;"killPlayer")<(TasksData!$B$34+TasksData!$B$36+TasksData!$B$38+TasksData!$B$47)*6;1;0);0);A3=1;ЕСЛИ(СЧЁТЕСЛИ($I$2:I2;"killPlayer")>=(TasksData!$B$34+TasksData!$B$36+TasksData!$B$38+TasksData!$B$47+TasksData!$B$48+TasksData!$C$34+TasksData!$C$36+TasksData!$C$38)*6;ЕСЛИ(СЧЁТЕСЛИ($I$2:I2;"killPlayer")<(TasksData!$B$34+TasksData!$B$36+TasksData!$B$38+TasksData!$C$34+TasksData!$C$36+TasksData!$C$38+TasksData!$B$47+TasksData!$B$48+TasksData!$C$47)*6;1;0);0);A3=2;ЕСЛИ(СЧЁТЕСЛИ($I$2:I2;"killPlayer")>=(TasksData!$B$34+TasksData!$B$36+TasksData!$B$38+TasksData!$B$47+TasksData!$B$48+TasksData!$C$34+TasksData!$C$36+TasksData!$C$38+TasksData!$C$47+TasksData!$C$48+TasksData!$D$34+TasksData!$D$36+TasksData!$D$38)*6;ЕСЛИ(СЧЁТЕСЛИ($I$2:I2;"killPlayer")<(TasksData!$B$34+TasksData!$B$36+TasksData!$B$38+TasksData!$B$48+TasksData!$C$34+TasksData!$C$36+TasksData!$C$38+TasksData!$D$34+TasksData!$D$36+TasksData!$D$38+TasksData!$B$47+TasksData!$C$47+TasksData!$C$48+TasksData!$D$47)*6;1;0);0));0))

Симуляция процессов

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

Пример части вводных данных:

Пример использованных формул в ячейках:

=СЛУЧМЕЖДУ(1;100)
=СРЗНАЧ(13;15)*6
=СУММ(B4:F4)
=IFS($A32<=G32;"Mythic";$A32<=F32;"Legend";$A32<=E32;"Epic";$A32<=D32;"Rare";$A32<=C32;"Common")

Сами по себе формулы простые, но при правильном построении связей ячеек и порядка выполнения действий получается нужный результат.

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

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

Воркфлоу создания таблицы

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

Расскажу подробнее по шагам (цифры в примере изменены в рамках конфиденциальности):

Эти же данные можно брать из таблицы баланса. Разница в том, что таблица баланса дает актуальные параметры (и не дает метрики), а на сервере информация хранится с пометкой даты ее можно выгрузить за нужный период (и вместе с метриками).

2. Затем создается гугл-таблица, в которой будет происходить основная работа. И в нее загружается полученный CSV-файл.

3. Для удобства из другой таблицы с помощью формулы подтягиваются картинки пушек. Арты предварительно загружены на сервис для получения прямой ссылки в формате (важно именно расширение в конце ссылки):

http://адрес_сервиса/путь/номер/имя картинки.jpg

Для добавления в таблицу используем простую функцию:

=IMAGE("https://files.fm/u/wdrhemgnk#/view/special_offer_pixelman_reward_big.png")

Пример формулы для подтягивания артов с перебором:

=ЕСЛИ(ЕНД(ВПР(A4;importrange(имя_таблицы;Лист1!B:F);5;ЛОЖЬ))=ЛОЖЬ;ВПР(A4;importrange(имя_таблицы;Лист1!B:F);5;ЛОЖЬ); ЕСЛИ(ЕНД(ВПР(A4;importrange(имя_таблицы;Лист1!C:F);4;ЛОЖЬ))=ЛОЖЬ;ВПР(A4;importrange(имя_таблицы;Лист1!C:F);4;ЛОЖЬ); ЕСЛИ(ЕНД(ВПР(A4;importrange(имя_таблицы;Лист1!D:F);3;ЛОЖЬ))=ЛОЖЬ;ВПР(A4;importrange(имя_таблицы;Лист1!D:F);3;ЛОЖЬ); ЕСЛИ(ЕНД(ВПР(A4;importrange(имя_таблицы;Лист1!E:F);2;ЛОЖЬ))=ЛОЖЬ;ВПР(A4;importrange(имя_таблицы;Лист1!E:F);2;ЛОЖЬ);НИМА ТАКОГО))))

Теперь можно работать не с абстрактными строками, а наглядно. Если пушек 30 штук, можно зайти в игру и посмотреть, но когда их 700 так уже не сделаешь.

Важный момент: после подгрузки данных мы их вырезаем (ctrl+x) и вставляем без привязки к формуле (ctrl+x+v). Формулу затем удаляем, иначе после каждого обновления страницы она будет пересчитывать все строки. В данном случае более 800.

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

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

5. Также используем форматирование ячеек. Оно может выполнить множество полезных преобразований. Например, покрасить ячейки, в которых значение больше 2 или меньше 1.

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

6. Добавляем столбец с категориями оружия (у нас их 6) и прибегая к тому же условному форматированию красим каждый в свой цвет. Стало видно, что в топе нет пушек категории Special, что уже наталкивает на анализ механик этой категории оружия.

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

Теперь можно сортировать, строить графики, добавлять продажи или другую информацию, чтобы быстро и обоснованно сделать нужные выводы или проверить теории.

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

График популярности оружияГрафик популярности оружия

Жизнь после автоматизации

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

Теперь легче что-то поменять, перезалить или вообще обновить целый класс оружия, в котором 100+ позиций. Достаточно вбить новые параметры все автоматически и с учетом механик пересчитается под норму (а часть параметров пересчитаются сами под новые вводные).

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

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

P.S. Данный подход меняет сам принцип работы с различными инструментами. Например, в том же Slack можно видеть BB-коды наглядно с помощью простой команды #:

Полезные ссылки

Подробнее..

Восстановление погибших дискет с осциллографом

22.05.2021 10:07:56 | Автор: admin

Greaseweazle F7 Plus

Есть много хороших современных решений для чтения данных со старых дискет и жёстких дисков. Пожалуй, одно из лучших Greaseweazle: очень функциональная система с открытым железом, исходным кодом, недорогая. На форумах вам с радостью помогут дружелюбные фанаты. Плата подключается напрямую к дисководу, заменяя собой флоппи-контроллер и считывает данные в малейших деталях. Работает на дискетах с любой защитой от чтения.

Но что делать, если Greaseweazle не может прочитать биты на магнитной поверхности и сообщает о повреждённых данных? Что, если на дискете материал исторической важности, исходный код в единственном экземпляре или культовая игра? Неужели всё потеряно?

Совсем нет. Известный хакер Крис Эванс с инженером Филом Пембертоном протестировали новый способ восстановления данных с флоппи-дискет, используя осциллограф. В частности, они вернули к жизни игру Ферма старого Макдональда для BBC Micro.

В 1980-е годы руководства пользователя и руководства для обслуживания для компьютерных накопителей были гораздо информативнее, чем сейчас. Например, вот страничка из технического мануала для TEC FB-50x:



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

Концептуально алгоритм считывания довольно простой. Однако инженеры прошлого всё же придумали несколько схем кодирования (и раскодирования) сигнала: MFM(использовались в PC, Amiga, BBC Micro ADFS) и GCR (использовались в Apple II и Commodore 64). Дискеты BBC Micro DFS работали по самой простой схеме FM. В ней дисковод вообще не отягощал себя какой-то схемой кодирования, а просто выдавал импульсы по счётчику (таймеру).

Данные:  0 0 1 0 1 1 0 1 0 0 0 1 1 0Код:    1010111011111011101010111110Таймер: 1 1 1 1 1 1 1 1 1 1 1 1 1 1

Восстановление исходного кода


Крис Эвансом с Филом Пембертоном смогли восстановить исходный код культовой игры Repton 3, игру Ферма старого Макдональда (Old Macdonald's Farm) а также ещё несколько ценных файлов для компьютера BBC Micro.

Они получили дискеты от нескольких хранителей исторических ценностей, но все они были повреждены временем. Greaseweazle выдавал ошибки CRC:


Скрин из эмулятора HxC Floppy Drive Emulator

Чёрные горизонтальные полосы это тайминги между импульсами с дискеты. Чем они тоньше, тем более чёткий сигнал. Здесь видим, что качество отличное, то есть дегенерация дискеты ещё не дошла до такой стадии, когда всё сливается в кашу. Тут просто проблема с единственным участком. Что там может быть?


А вот и проблема

Визуальная инспекция показала, что кто-то неудачно помял дискету.

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



Ничего не оставалось, как применить научное оборудование, которое Крис Эванс использует в своих цифровых расследованиях. На фотографии любительский осциллограф Siglent SDS 1104X-E, подключённый к плате Greaseweazle. Она считывает данные с дисковода TEC FB-50x, в котором крутится дискета с исходным кодом Repton3.



Тут Greaseweazle только для управления, но не для анализа. Он просто включает движок дисковода, а считывание данных происходит напрямую на осциллограф по проводам, подключённым к дисководу на тестовые точки TP3 и TP4, как указано в техническом мануале (см. скан страницы в начале статьи).

Производительности этого осциллографа начального уровня достаточно, чтобы загрузить целую дорожку с дискеты (время считывания 200мс) во внутреннюю память на частоте 25Мсэмплов/с. Чувствительности 500uV/div хватает, чтобы различить пики в записи. Пара пиков по 4 микросекунды обычно соответствует "1", а пик на 8 микросекунд это "0".

Конечно, без проблем не обошлось. Оказалось, что разные дисководы выдают разный аналоговый сигнал: например, у Mitsubishi сигнал более чистый, у TEAC присутствует странный высокочастотный шум. А лучше всех проявил себя дисковод TEC FB-502, хотя он был старше Mitsubishi и остальных.


ASCII-символ "1" (00110001), первый символ в названии диска (1187V1.0)

Чтобы усилить магнитный сигнал с дискеты, Фил поставил резистор для управления скоростью вращения, и дискеты разгоняли со стандартной скорости 300 RPM до 400 FPM. Естественно, прочитать данные становилось легче законы физики!

Звук записи на дискету 5,25", замедленный примерно в 100 раз (20 секунд вместо реальных 0,2секунды)

Но вернёмся к осциллографу. Получив аналоговый сигнал с дисковода, хотелось бы применить какой-то алгоритм для автоматической расшифровки этого сигнала. Инженеры решили попробовать такой вариант: найти начало сектора, и непрерывно отсчитывать от него по 8 микросекунд аналогового потока. Если напряжение растёт или снижается на протяжении всего участка, это "0". Если напряжение изменяется сначала в одном направлении, а потом в другом, то это "1". Затем повторная синхронизация к ближайшему пику.



Несмотря на хаотичные волновые формы, алгоритм восстановил все биты в потерянном секторе с той дискеты:



В самых трудных случаях форму сигнала с осциллографа исправляли вручную в редакторе FloppyControlApp. Немного похоже на то, как ретушируют (восстанавливают) старые фотографии:



Этот инновационный метод позволил получить исходный код, который безуспешно пытались восстановить разными методами несколько лет! С помощью осциллографа прочитано 100% кода со всех дискет! В том числе игра Ферма старого Макдональда. Это безусловная удача для цифровых археологов.

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

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

В общем, Крис с Филом ждут ваших дискет! И старый Макдональд тоже :)





Облачные VDS от Маклауд быстрые и безопасные.

Зарегистрируйтесь по ссылке выше или кликнув на баннер и получите 10% скидку на первый месяц аренды сервера любой конфигурации!

Подробнее..

Нагрузочное тестирование СХД на Эльбрусе на базе нового ядра Линукс версии 5.4

31.05.2021 06:09:55 | Автор: admin


Тестирование СХД Аэродиск Восток на базе процессоров Эльбрус 8С на новом ядре 5.4 показало крайне позитивный результат: 1,4 миллиона IOPS! Пока оптимисты верили и надеялись, а пессимисты снисходительно улыбались, программисты работали писали код. В итоге новая версия ядра Линукс v5.4 для архитектуры Эльбрус позволила в разы улучшить производительность подсистемы ввода-вывода и полностью реализовать процессора Эльбрус 8С/СВ для систем хранения данных.


По этому прекрасному поводу мы в Аэродиске, предварительно обновив боевую версию встроенного Альт-Линукса в СХД ВОСТОК до ядра 5.4, повторно выполнили нагрузочное тестирование СХД, которое мы публиковали полгода назад. С прошлым отчетом можно ознакомиться по данной ссылке.


Новые тесты проводились на долгожданном ядре Линукс для e2k версии 5.4, которое появилось начале 2021 года, за что хотим сказать огромное спасибо коллективам разработчиков МЦСТ, Базальт СПО, а также Михаилу Шигорину лично.


В ядре 5.4 изменений много, но нас интересуют только основные изменения с точки зрения СХД, а их можно разделить на следующие группы:


Общие обновления:


  • переработан планировщик ввода-вывода, что позволяет лучше параллелить IO между дисками;
  • много мелких оптимизаций под скоростные твердотельные накопители;
  • и самое главное изменение новый компилятор от МЦСТ (LCC версии 1.25).

Обновления от Аэродиска:


  • обновлённый таргет-драйвер, который позволяет лучше параллелить IO между процессорными ядрами;
  • обновление логики работы связки ядро процессора диск для систем на Эльбрусе.

Тестовый стенд


Тестирование мы выполняли на том же железе, что и в прошлый раз. Стенд состоит из сервера с Линуксом, подключенного через FC-коммутатор к двум контроллерам СХД Восток, в которой установлено 12 SAS SSD дисков.


Конфигурация оборудования следующая:


  • Linux-сервер (2xIntel Xeon E5-2603 v4 (6 cores, 1,70Ghz), 64 GB DDR4, 2xFC-адаптер 16G 2 порта) 1шт.
  • Коммутатор FC 16G 1 шт.
  • СХД Аэродиск Восток 2-Э12 (2xЭльбрус 8С (8 cores, 1,20Ghz), 32 GB DDR3, 2xFE FC-adaptor 16G 2 port, 12xSAS SSD 960 GB) 1 шт

Ниже схема стенда.



Методика тестирования


Также как и в прошлый раз для нагрузочных тестов мы использовали популярную и проверенную временем программу Flexible IO (FIO).


СХД сконфигурирована исходя из наших рекомендаций к высокой производительности на блочном доступе или просто настройки для ALL-Flash систем. Поэтому используем не менее двух дисковых пулов DDP (Dynamic Disk Pool). Чтобы не бить в одну точку и максимально реализовать вычислительный потенциал платформы создаем несколько LUN-ов в RAID-10 (8 шт. по 500 ГБ каждый).


Все LUN-ы презентуем двум контроллерам (пополам, по 4 каждому), чтобы максимально утилизировать все ресурсы СХД.


В ходе тестирование будут выполняться следующие популярные сценарии использования СХД, в частности:


Последовательная нагрузка маленькими блоками 4k


  • 100%_read_4k_sequential
  • 100%_write_4k_sequential

Случайная нагрузка маленькими блоками 4k


  • 100%_read_4k_random
  • 100%_write_4k_random

Последовательная нагрузка большими блоками 128k


  • 100%_read_128k_sequential
  • 100%_write_128k_sequential

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


Во всех тестах мы, чтобы не искажать результаты тестирования, намеренно отключаем RAM-кэш СХД, который используется для ускорения ввода-вывода, компрессии и дедупликации. Забежим вперед и отдельно скажем про утилизацию оперативной памяти СХД в целом (чтобы к этому вопросу больше не возвращаться). Во всех тестах RAM утилизируется практически одинаково, т.е. слабо, т.к RAM-кэш, дедуп и компрессия отключены. Вся утилизация RAM это внутренние системные операции СХД. Если бы мы включили RAM-кэш, то результаты были бы заметно лучше, но тогда тест был бы не совсем честным. При этом график утилизации оперативки мы для порядка все-равно приводим в отчете ниже.


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


100%_read_4k_sequential

[global]
blocksize=4k
size=80%
direct=1
buffered=0
ioengine=libaio
iodepth=128
group_reporting
rw=read
numjobs=16
runtime=2400
time_based=1
per_job_logs=0
log_avg_msec=30000
write_bw_log=./logs/read-iodepth-128-numjobs-16
write_iops_log=./logs/read-iodepth-128-numjobs-16
write_lat_log=./logs/read-iodepth-128-numjobs-16
[job-1]
filename=/dev/sdj
[job-2]
filename=/dev/sdc
[job-3]
filename=/dev/sdd
[job-4]
filename=/dev/sde
[job-5]
filename=/dev/sdf
[job-6]
filename=/dev/sdg
[job-7]
filename=/dev/sdh
[job-8]
filename=/dev/sdi


100%_write_4k_sequential

[global]
blocksize=4k
size=80%
direct=1
buffered=0
ioengine=libaio
iodepth=128
group_reporting
rw=write
numjobs=16
runtime=2400
time_based=1


write_bw_log=./logs/4k-seq-write.results


write_iops_log=./logs/4k-seq-write.results


write_lat_log=./logs/4k-seq-write.results


[job-1]
filename=/dev/sdj
[job-2]
filename=/dev/sdc
[job-3]
filename=/dev/sdd
[job-4]
filename=/dev/sde
[job-5]
filename=/dev/sdf
[job-6]
filename=/dev/sdg
[job-7]
filename=/dev/sdh
[job-8]
filename=/dev/sdi


100%_read_4k_random

[global]
blocksize=4k
size=80%
direct=1
buffered=0
ioengine=libaio
iodepth=64
group_reporting
rw=randread
numjobs=2
runtime=2400
time_based=1
per_job_logs=0
log_avg_msec=30000
write_bw_log=./logs/4k-rand-read.results
write_iops_log=./logs/4k-rand-read.results
write_lat_log=./logs/4k-rand-read.results
[job-1]
filename=/dev/sdc
[job-2]
filename=/dev/sdd
[job-3]
filename=/dev/sde
[job-4]
filename=/dev/sdf
[job-5]
filename=/dev/sdg
[job-6]
filename=/dev/sdh
[job-7]
filename=/dev/sdi
[job-8]
filename=/dev/sdj


100%_write_4k_random

[global]
blocksize=4k
size=80%
direct=1
buffered=0
ioengine=libaio
iodepth=16
group_reporting
rw=randwrite
numjobs=2
runtime=2400
time_based=1
per_job_logs=0
log_avg_msec=30000
write_bw_log=./logs/4k-rand-write.results
write_iops_log=./logs/4k-rand-write.results
write_lat_log=./logs/4k-rand-write.results
[job-1]
filename=/dev/sdc
[job-2]
filename=/dev/sdd
[job-3]
filename=/dev/sde
[job-4]
filename=/dev/sdf
[job-5]
filename=/dev/sdg
[job-6]
filename=/dev/sdh
[job-7]
filename=/dev/sdi
[job-8]
filename=/dev/sdj


100%_read_128k_sequential

[global]
blocksize=128k
size=80%
direct=1
buffered=0
ioengine=libaio
iodepth=128
group_reporting
rw=read
numjobs=16
runtime=2400
time_based=1
per_job_logs=0
log_avg_msec=30000
write_bw_log=./logs/128k-seq-read.results
write_iops_log=./logs/128k-seq-read.results
write_lat_log=./logs/128k-seq-read.results
[job-1]
filename=/dev/sdj
[job-2]
filename=/dev/sdc
[job-3]
filename=/dev/sdd
[job-4]
filename=/dev/sde
[job-5]
filename=/dev/sdf
[job-6]
filename=/dev/sdg
[job-7]
filename=/dev/sdh
[job-8]
filename=/dev/sdi


100%_write128k_sequential

[global]
blocksize=128k
size=80%
direct=1
buffered=0
ioengine=libaio
iodepth=16
group_reporting
rw=write
numjobs=2
runtime=2400
time_based=1
per_job_logs=0
log_avg_msec=30000
write_bw_log=./logs/128k-seq-write.results
write_iops_log=./logs/128k-seq-write.results
write_lat_log=./logs/128k-seq-write.results
[job-1]
filename=/dev/sdj
[job-2]
filename=/dev/sdc
[job-3]
filename=/dev/sdd
[job-4]
filename=/dev/sde
[job-5]
filename=/dev/sdf
[job-6]
filename=/dev/sdg
[job-7]
filename=/dev/sdh
[job-8]


Результаты тестов


Последовательная нагрузка маленькими блоками 4k


100%_read_4k_sequential
График загрузки CPU СХД и RAM СХД


Ввод-вывод СХД, IOPS и latency


100%_write_4k_sequential
График загрузки CPU СХД и RAM СХД


Ввод-вывод СХД, IOPS и latency


Результат:


Результаты теста с использованием последовательного характера нагрузки небольшими блоками 4k нас впечатлили, получилось !1,4 миллиона! IOPS на чтение и 700k на запись. Если сравнивать это с предыдущим нашим тестом на ядре 4,19 (371k и 233k IOPS), то это скачек в четыре раза при том, что железо мы не меняли.


Также отмечаем довольно небольшую утилизацию CPU, она примерно на 20% ниже предыдущего теста (69/71% против 76/92%).
Задержки при этом остались на том же уровне, что и полгода назад, это не значит, что с этим мы думаем мириться, это значит, что над этим мы ещё будем работать. В конце статьи, будет итоговая таблица сравнения с тестом полугодовой давности на ядре 4,19.


Случайная нагрузка маленькими блоками 4k


100%_read_4k_random
График загрузки CPU СХД и RAM СХД


Ввод-вывод СХД, IOPS и latency


100%_write_4k_random
График загрузки CPU СХД и RAM СХД


Ввод-вывод СХД, IOPS и latency


Результат:


Показатели случайной нагрузки маленькими блоками, характерной для транзакционных СУБД остались практически без изменений по сравнению с прошлым тестом. СХД Восток на Эльбрусе вполне нормально справляется с подобными задачами, выдавая 118k IOPS на чтение и 84k IOPS на запись при довольно высокой утилизации CPU.


Отмечаем, что для Эльбруса в отличии от других процессоров работа в режиме постоянной загрузки близкой к 100% является штатной ситуацией (он для этого создавался). Мы это проверяли, оставляя СХД Восток с нагруженным процессором под 95% на несколько дней и результат был следующий: 1) процессор был холодный; 2)процессор и система в целом работали в нормальном режиме. Поэтому к высокому уровню утилизации процессоров Эльбрус следует относиться спокойно.


Также с прошлого ядра сохранилась приятная особенность. Если посмотреть на задержки при случайной нагрузке маленькими блоками, то внимание привлекает то, что задержки на запись ниже, чем на чтение (3 мс против 8 мс), когда мы все привыкли, что должно быть наоборот. Эльбрус с точки зрения случайного характера нагрузки по-прежнему любит запись больше чем чтение, что несомненно является отличным преимуществом, которое грех не использовать.


Последовательная нагрузка большими блоками 128k


100%_read_128k_sequential
График загрузки CPU СХД и RAM СХД


Ввод-вывод СХД, IOPS и latency


100%_write_128k_sequential
График загрузки CPU СХД и RAM СХД


Ввод-вывод СХД, IOPS и latency


Результат:


Ещё полгода назад СХД Восток на базе процессоров Эльбрус показала отличный результат в тесте последовательной нагрузки большими блоками, что актуально для видеонаблюдения или трансляций. Особой фишкой Эльбруса были ультранизкие задержки при работе с большими блоками (0,4-0,5 мс против 5 6 мс у аналогичного процессора архитектуры x-86).


При чтении данных большими блоками данное преимущество удалось не только закрепить, но и развить. Максимальную скорость на новом ядре удалось поднять в два раза (5,7 ГБ/с на ядре 5.4 против 2,6 ГБ/с на ядре 4.19) при задержках 0,3 мс! Также нагрузка на процессор при данном тесте тоже выглядит лучше (52% на 5,4 против 75% на 4,19).


А вот с записью не так все радужно. К сожалению, в новой версии ядра получить ультранизкие задержки на запись уже не удается, во всяком случае пока. Они находятся на уровне 11 мс (а было 0,5 мс), что в целом не плохо, т.к. примерно такой же уровень задержек при таком тесте мы видим на процессорах других архитектур. Так или иначе это наше домашнее задание, над которым мы будем работать. При этом позитивный момент все-таки есть. Как и в других тестах утилизация процессора значительны снижена (74% против 95%).


Итоговые результаты тестирования АЭРОДИСК ВОСТОК на базе процессоров Эльбрус 8 С, ядро 5.4


Улучшение в 5.4 зеленые, ухудшения 5.4 оранжевые


Для сравнения, результаты тестирования АЭРОДИСК ВОСТОК на базе процессоров Эльбрус 8С, ядро 4.19


Улучшение в 5.4 зеленые, ухудшения в 5.4 оранжевые


Прогресс виден не вооруженным глазом! Новая версия ядра 5.4 для архитектуры Эльбрус позволила выжать практические максимумы из совсем не нового процессора Эльбрус 8С (2016 г. выпуска). На данный момент даже у самых ярых пессимистов уже не повернется язык назвать процессор Эльбрус медленным, все таки полтора миллиона IOPS это много.


В очередной раз мы убедились в отличной работе СХД на Эльбрусе среде, где преобладает последовательная нагрузка, а это аналитические СУБД, онлайн-трансляции, видеонаблюдение, обработка больших данных и т.п.


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


Безусловно есть ещё над чем работать (те же задержки при записи больших потоков), но за прошедшие полгода коллектив МЦСТ проделал титаническую работу, и она дала видимый результат, что не может не радовать.


В конце этого 21-ого года мы ожидаем новый процессор Эльбрус 16С, который, кроме того что будет намного быстрее, ещё будет поддерживать аппаратную виртуализацию, а это значит что у нас в России наконец-то появится полностью отечественные не только СХД, но и системы виртуализации, и гиперконвергентные системы (кто сказал АИСТ и vAIR?))).


Кстати о птичках! В течение этой недели мы определимся с датами следующего технического вебинара ОколоИТ про нашу систему виртуализации АИСТ и гиперконвергентную систему vAIR, ссылка на регистрацию появится в этой статье (следите за обновлением), а также в нашем телеграмм-чате.
Ну и само собой, не можем не напомнить о бесплатных курсах по системам Аэродиск, на которые можно записаться тут.


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

Подробнее..

Chia Coin, или сказка о том, как Флешки выжили в войне криптовалют

07.06.2021 12:06:42 | Автор: admin
Привет, Хабр! USB-флешки единственные, кто не пострадал в спекуляциях на тему цен вокруг носителей информации. Благодаря монете Chia спрос на носители HDD, SSD взлетел за месяц до невиданных высот. С полок магазинов пропали HDD емкостью выше 1-2 ТБ, SSD емкостью более 0,5 ТБ, но потребности в переносе данных еще остались.



Будем откровенны, ажиотаж вокруг видеокарт и жестких дисков фактически парализовал IT сектор. Не хватает нам только монет, добываемых на CPU, и о компьютерах можно будет только мечтать, рассматривая буклеты интернет-магазинов.

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



В этот ответственный момент компания Kingston выпустила на рынок две привлекательные модели USB Flash: DataTraveler Kyson и DataTraveler Exodia. Благодаря отсутствию ажиотажного спроса на данный тип носителей модели располагает большой емкостью для перемещения данных, распространенным разъемом USB и приличными скоростями. К тому же цена на них вполне демократичная, точнее 1/25 от мейнстрим видеокарт GTX 3060 Ti.

DataTraveler Exodia



Самобытное устройство, выпускаемое в четырех емкостях и четырех цветах. Оснащена пластиковым колпачком и не имеет ни единого светодиода.



Очень легкая (11 г) благодаря пластиковому корпусу. Разъем подключения USB Type A, поддерживаемый протокол USB 3.2 Gen 1. Доступна в размере 32, 64, 128 и 256 ГБ. Стиль и исполнение флешки напоминают старую школу просто и со вкусом, без лишней иллюминации и с возможностью привязать устройство к шнурку или связке ключей. Стоит помнить, что колпачок хоть и фиксируется плотно, да и к тому же легкий, но в кармане может слететь. Следите за ним внимательно.



Из коробки DataTraveler Exodia 256G отформатирована в системе FAT32 и доступный для пользователя размер составляет 230 ГБ в системе исчисления Windows 10.

DataTraveler Kyson



Полная противоположность выше рассмотренной флешке, т.к. выполнена в современном и стильном дизайне: лишена колпачка, металлический корпус, минималистичный вид. В отличие от Exodia производитель гарантирует высокую скорость чтения (до 200 МБ/сек) и приличную скорость записи (до 60 МБ/сек). Цветовых вариаций нет, зато можно выбрать из четырех размеров: 32, 64, 128 и 256 ГБ.



Компактные размеры и смешной вес (39x12,6x4,9 мм, 4 г) не будут оттягивать карман хозяина. Крупное кольцо позволяет привязать флешку буквально к любому предмету. По спецификации флешка совместима с разъемом USB Type A и протоколом USB 3.2 Gen 1.



В заводском исполнении предварительно отформатирована в FAT32, доступный для пользователя системы Windows 10 объем составляет ровно 230 ГБ.

Новые горизонты





Раз речь зашла о недоступности устройств хранения и переноса информации из-за тотального шествия новой криптовалюты, то не стоит думать, что флешки больше ни на что не сгодятся. Более тонкий тех. процесс производства памяти сделал из них почти полную замену внешним жестким дискам и SATA SSD с оговоркой на ресурс и скорость. Естественно, ни в какое сравнение не идет и разница в стоимости устройств. На столь емких флешках будет удобно брать с собой различную информацию больших (в рамках типичного пользователя ПК) размеров будь то фильмы, дистрибутивы, фотографии и многое другое. На 256 ГБ действительно влезет пару десяткой рипов фильмов или несколько сезонов популярного сериала, а посмотреть их можно будет, просто воткнув флешку в телевизор или приставку. Благо TV 2017 и более поздних годов выпуска оснащаются как раз USB Type A разъемами.

По ряду профессий емкие флешки с высокой скоростью чтения удобны для системных администраторов: храня и разворачивая образы различных систем, начиная от ESXi и заканчивая Windows Server 2019. В конце концов 256 ГБ позволяют переносить на сервера образы готовых систем заранее оптимизированные и сконфигурированные в VMware Workstation Pro путем конвертирования их в программе VMware Converter.



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

Благодаря доступному объему можно легко отказаться от принятия решений, что хранить на флешке и ничем не жертвовать из-за нехватки места.

Методика тестирования


Так как флешки в первую очередь предназначены для ПК и ноутбуков, то процесс измерения производительности будет проведен на ПК с интерфейсом USB 3.2 Gen 2 и скоростью 10 Гбит/с.

Типичный сценарий использования USB Flash это более 80% времени работы тратится на чтение данных. Запись обычно происходит реже, либо записываются сжатые архивы/образы. В повседневном использовании флешки должны отрабатывать различные не серверные задачи и тем более нет смысла использовать потребительские USB Flash в качестве места долгого хранения, или считать их местом для создания бекапов. Поэтому в списке приложений мы отдаем предпочтение распространенным программам для тестирования. Это AS SSD Benchmark, CrystalDiskMark, HD Tune Pro 5.75, PCMark 10 Storage, H2Test и другие. В качестве бонуса проведем тесты записи и чтения папки с образами, фото и фильмами, имитируя типичную работу пользователя с устройствами.

Используемая конфигурация ПК:
Maximus XI Hero (Wi-Fi), процессор Intel Core i7 9900K, встроенная видеокарта Intel, 64-Гб памяти DDR4-3200 и операционная система Windows 10 x64. Для проверки совместимости флешки подключались к raspberry, ноутбукам с чипсетами Intel, AMD, а также NAS накопителю.

Результаты тестирования



AS SSD Benchmark


Copy Benchmark оценивает скорость работы и затраченного на это времени при копировании разных групп файлов (ISO образ, папка с программами, папка с играми).

DataTraveler Exodia



DataTraveler Kyson



CrystalDiskMark


Тестирование проводилось с 5 повторениями, каждый объемом 16 ГБ и 1 ГБ.
Последовательное чтение/запись с глубиной 8.
Последовательное чтение/запись с глубиной 1.
Случайное чтение/запись блоками по 4 кб с глубиной 32 и 16 потоков.
Случайное чтение/запись блоками по 4 кб с глубиной 1.

DataTraveler Exodia



DataTraveler Kyson



HD Tune Pro 5.75


Линейная скорость чтения и записи блоками 512 Кбайт.
Время доступа.
Расширенные тесты чтения и записи.

DataTraveler Exodia



DataTraveler Kyson



PCMark 10 Storage


Quick System Drive Benchmark: короткий тест, эмулирующий легкую нагрузку на систему хранения. Используются наборы тестов, повторяющие реальные действия системы и программ с накопителем;
Data Drive Benchmark: повторяет нагрузку на систему хранения в виде наборов тестов для NAS, (хранение и использование файлов различного типа).

DataTraveler Exodia



DataTraveler Kyson



H2Test


Позволяет оценить среднюю скорость чтения и записи на диск, выдавая информацию в Мбайт/сек.

DataTraveler Exodia



DataTraveler Kyson



USB Flash Benchmark


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

DataTraveler Exodia



DataTraveler Kyson



Натуральный тест


И последний, натуральный тест на копирование образа Windows 10 x64.iso плюс папка с распакованным образом Windows 10, а также Windows Server 2019 x64 iso и папка с распакованным образом Windows Server 2019. Добавляем сюда 5 крупных фрагментов сериала и 77 RAW фотографий. По папкам:
Фильмы 29,1 ГБ (5 крупных фрагментов);
ISO 17,6 ГБ (смешанные файлы большого, среднего и маленького размера);
Фото 5,4 ГБ (77 RAW фотографий);


Запись фильмов, ISO, фото размером 53453 МБ за 1339 сек или 40 МБ/сек


Чтение фильмов, ISO, фото размером 53453 МБ за 447 сек или 120 МБ/сек

DataTraveler Kyson


Запись фильмов, ISO, фото размером 53453 МБ за 1236 сек или 43,2 МБ/сек


Чтение фильмов, ISO, фото размером 53453 МБ за 214 сек или 250 МБ/сек

Выводы


Kingston DataTraveler Kyson



Серия Kyson это универсальные и доступные флеш-карты для любых видов файлов. Они прекрасно работают с мелкими, средними и крупными файлами. Сильной стороной Kyson стала именно универсальность использования в любых видах перемещения данных. Заявленная скорость чтения даже превысила паспортные характеристики и достигает половины производительности хорошего SATA SSD, ведь в тестах на чтение флешка показала от 250 до 270 МБ/сек. Если обратить взгляд на запись, то кажется будто 40 с хвостиком МБ/сек не такая и большая цифра. Но Kingston DataTraveler Kyson не пасует перед мелкоблочными данными, развивая гарантированную скорость более 44 МБ/сек. Еще одним достоинством стал температурный режим и стабильность работы. После часовых тестов флешка не нагревается выше 40С и не впадает в анабиоз. Ее совместимость с различными контроллерами (Intel, AMD, VLI, ASM) подтвердилась на практике. Одним словом, если вам нужна универсальная и скоростная флешка для чтения и постоянная скорость на запись с любыми видами данных, то Kyson отлично подходит на эту роль.

Kingston DataTraveler Exodia



Бюджетно не значит плохо! Kingston DataTraveler Exodia относится к Entry Level флеш-устройству. У нее нет индикации, а корпус пластиковый. Большая емкость, легкий вес, защитный колпачок и доступная цена вот ее основные достоинства. Наилучшей стороной Exodia стали тесты с копированием и записью файлов размером больше 512 Кб. Все, что больше это ее родная стихия. На мелкоблочных операциях чтения и записи скорость падает, но как только вы решите записать большие файлы, то результат под 60 МБ/сек на запись вас впечатлит в разрезе стоимости малышки. Фактический результат с учетом особенностей: до 125 МБ/сек чтения и до 60 МБ/сек на запись.

Дополнительную информацию о новинках DataTraveler Kyson и DataTraveler Exodia ищите на официальном сайте Kingston.



Для получения дополнительной информации о продуктах Kingston Technology обращайтесь на официальный сайт компании.
Подробнее..

Тестирование производительности и краткий обзор HPE Nimble Storage Adaptive Flash HF60

13.06.2021 08:21:39 | Автор: admin

Хочется пролить свет на интересную линейку систем хранения данных HPE Nimble Storage Adaptive Flash и попытаться раскрыть вопрос почему маркетологи решили его назвать Adaptive Flash, а не более традиционно - Hybrid Flash. Судя по поиску, существует не так много обзоров и статей, посвященных Nimble, поэтому надеюсь, что этот материал будет полезен интересующимся данной темой.

В мое распоряжение попал массив с флагманскими контроллерами - HF60. Это СХД 5-го поколения (Nimble Gen5), но уже по состоянию на 04.05.2021 компания HPE анонсировала (пока только AllFlash) 6-е поколение (Nimble Gen6), которое будет называться Allerta 6000. Adaptive Flash 6-го поколения - анонс ожидается летом 2021. Так что пока наш подопытный последнего (актуального) поколения.

Итак, чем же интересен HPE Nimble Adaptive Flash?

Давайте начнем издалека. Компания Nimble Storage берет свое начало в 2008 году и уже в 2014 наделала много шуму, объявив о революционном достижении (на тот момент) доступность систем хранения данных превысила 99,999%. В 2016 году этот показатель уже составлял 99,999928%. Традиционно, столь успешные стартапы поглощаются более крупными компаниями. Так и случилось с Nimble - в 2017 году компания влилась в ряды Hewlett Packard Enterprise. За счет чего им удалось получить такие цифры доступности (причем это не лабораторные, а реальные данные)? Если совсем коротко: архитектура и надстройка в виде аналитической платформы InfoSight. Давайте остановимся на каждом пункте чуть подробнее.

Архитектура

Если Вам лень читать, можете посмотреть видео (на англ.):

СХД Nimble в своей основе использует архитектуру CASL (Cache Accelerated Sequential Layout). В основу архитектуры заложено:

  1. Active/Standby контроллеры. Большинство других систем с двумя контроллерами Active/Active демонстрируют производительность с нулевым запасом мощности, поэтому, если один из контроллеров недоступен - вы уведёте половину скорости...

  2. Функционал редупликации/компрессии/шифрования в режиме онлайн (на лету). Подробнее как это работает ниже в описании операций чтения и записи.

  3. RAID Tripple Parity+ с фиксированным стартовым набором дисков 21шт HDD + 6шт SSD. Массив выдерживает выход из строя 3 любых дисков из одной RAID группы. Но лучшее качество Triple+ RAID не в том, что он защищает от потери любых 3 дисков. Крутая часть это +. Это позволяет системе не иметь проблем с целостностью данных, даже если на каждом отдельном диске в системе возникают ошибки параллельного чтения секторов и три диска были потеряны. Это уровень устойчивости к коррелированным по времени ошибкам, который ни один другой массив в мире даже близко не может предложить.

  4. Защита данных через каскадные многоступенчатые контрольные суммы.

  5. Память с защитой по питанию NVRAM.

  6. SSD кэш на чтение (в случае с Adaptive Flash). Важно отметить, что RAID для SSD не используется, т. к. задача кэша дать максимальную скорость. Насчет надежности можно не беспокоиться, поскольку данные в кэш копируются с защищенных RAID-ом TripleParity+ HDD (об этом ниже).

Рассмотрим алгоритмы чтения и записи

Процесс записи на массивы Adaptive FlashПроцесс записи на массивы Adaptive Flash

Распишем процесс записи:

  1. Запись от разных приложений разными блоками;

  2. NimbleOS принимает запись на NVDIMM активного контроллера;

  3. NimbleOS зеркалирует NVDIMM активного контроллера в NVDIMM Standby контроллера;

  4. NimbleOS подтверждает запись хосту;

  5. Блоки копируются в DRAM, где и происходит магия архитектуры CASL, а именно:

    a. Дедупликация с переменным блоком;

    b. Сжатие с переменным блоком;

    c. Блоки собираются в страйпы размером 10 Мбайт;

    d. Страйпы последовательно пишутся на HDD;

  6. Достойные кэша блоки или блоки из Pinned томов копируются на SSD кэш + блоки индексируются (индекс пишется на SSD и HDD в фоне). Есть 3 настройки кеширования которые можно выставить на каждый том:

    Default данные кэшируются в автоматическом режиме по выбору NimbleOS;

    Pinned настройка, которая по умолчанию копирует все данные тома на SSD диски и мы получаем All Flash на чтение;

    OFF - выключенное кеширование, т. е. SSD диски не задействованы вообще. Полезно для томов, где нет необходимости ускорять чтение;

Какие преимущества имеет такая запись?

Во-первых: количество операций Random write в бэкенде системы минимизировано. По сути, большинство операций происходит в оперативной памяти кэша контроллеров, компрессия выполняется после дедупликации, таким образом число операций ввода-вывода на дисках SSD/HDD сведено к минимуму.

Во-вторых: последовательная запись помогает избежать задержек на механических дисках. Иными словами, благодаря такой архитектуре используется максимум выгоды от обычных HDD дисков.

Процесс чтения в массивах Adaptive FlashПроцесс чтения в массивах Adaptive Flash

Рассмотрим, что происходит при чтении:

  1. Запрашиваем блок в NVDIMM. Если данные там отдаем хосту;

  2. Если блока нет, читаем из DRAM;

  3. Если блока нет, читаем с SSD:

    a. Если блок есть, проверяем контрольную сумму, разжимаем;

    b. Регидрируем и отдаем хосту;

  4. Если блока нет, читаем с HDD, блок ищем через индекс;

    a. Если блок есть, проверяем контрольную сумму, разжимаем;

    b. Регидрируем и отдаем хосту;

  5. Если блок достоин кэша, копируем на SSD;

Какие преимущества дает такой алгоритм чтения?

Во-первых: скорость ограничена не производительностью дисков, а скоростью памяти NVDIMM (которая существенно быстрее SSD дисков) т. е. контроллерами.

Во-вторых: согласно живой статистике, массив больше 95% попадает в кэш. Иными словами, имея в запасе всего 1020% SSD дисков, массив будет обеспечивать скорость All Flash больше 95% времени. Важно отметить, что это не означает что оставшиеся 5% времени данные будут читаться медленно с механических дисков. Дисков в стартовом наборе - 21 шт., при чтении их скорость суммируется. Будет иметь место то, что при чтении с HDD дисков задержка будет немного больше чем 1мс. Но не забываем, что этого легко избежать настройкой кэширования индивидуально для каждого тома.

Резюмируя по архитектуре:

  1. Данные защищены от выхода из строя 3-х любых накопителей;

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

  3. Данные пишутся быстро: благодаря алгоритму архитектуры CASL;

  4. Данные читаются быстро: кэшируются на SSD диски для ускорения чтения и здесь нет никакого тирринга данных как в традиционных гибридах;

  5. Данные можно дополнительно защищать шифрованием;

  6. Гибкие настройки. Можно вкл/выкл индивидуально для каждого тома: дедуп; компрессия; шифрование; кеширование; ограничение по IOPS или пропускной способности (или того и другого) и прочее;

  7. Гибкие возможности масштабирования емкости/производительности:

  • возможность масштабировать емкость (добавлять дисковые полки);

  • емкость и производительность (добавлять еще один массив в кластер, до 4 шт);

  • производительность (заменить контроллеры на более производительные).

InfoSight

Тезисы:

  • HPE InfoSight это передовая в отрасли платформа облачной аналитики InfoSight. Передовая - поскольку начала работать гораздо раньше, чем у других вендоров. А здесь важна наработка системы по времени. Чем дольше она работает, тем больше данных собирает, тем больше проблем может предотвратить. Об этом ниже.

  • Доступность СХД HPE Nimble 99,9999%, достигается благодаря применению InfoSight.

  • Миссия HPE InfoSight: сохранять маниакальный фокус на предоставлении заказчику такой поддержки, чтобы все завидовали!

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

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

По данным HPE, при использовании InfoSight 86% проблем разрешаются без участия ИТ-службы. Сюда входят инциденты как с самой СХД, так и с окружающей инфраструктурой.

InfoSight позволяет значительно сократить время на поиск проблемных узлов инфраструктуры в случае деградации производительности. Система в удобном графическом виде показывает текущее время отклика и статистику задержек за определенный период по проблемной ВМ не только относительно самой СХД, но и сети передачи данных SAN, а также приложений гипервизора. Отклонение каких-либо показателей в кратчайшие сроки позволит определить узкое место инфраструктуры. Не нужно переключаться между несколькими системами мониторинга, все показатели доступны в едином портале, так как InfoSight интегрируется с VMware VCenter. В процессе диагностики собирается только служебная информация, собственные данные заказчика не затрагиваются. Информация передается по защищенному SSL каналу.

Некоторые примеры передаваемых данных:

  • Серийный номер массива.

  • Базовая информация о работоспособности (health check).

  • Системные журналы событий.

  • Параметры настроек системы.

  • Статистика работы системы.

Самое вкусное на десерт - тестирование

Тестовая конфигурация:

  • СХД Nimble HPE Nimble Storage Adaptive Flash HF60 / 21x2TB HDD / 5.76TB (6x960GB) SSD Cache / 4x16GB FC на каждый контроллер;

  • Хост 1: Сервер HPE DL160 Gen10 / 1x Xeon 4210R / 6x16GB DDR4-R / 2xSN1100Q 16Gb 2p FC / 2x500W;

  • Хост 2: Сервер HPE DL325 Gen10 / 1x EPYC 7551P / 8x16GB DDR4-R / 2xSN1100Q 16Gb 2p FC / 2x500W;

  • Подключение серверов напрямую к СХД, т. к. под рукой не было коммутаторов Fibre Channel. Поэтому в серверах по 2шт двухпортовых карточки, чтоб загрузить все 4 порта на каждом контроллере СХД;

  • VMware vSphere 7;

  • Тестирование с помощью HCIbench 2.5.3;

Для начала нам было интересно сравнить наш Adaptive Flash HF60 с протестированным All Flash AF40:

Нагружаем наш массив аналогичными параметрами и в конце сводим результаты.

Первый тест: 384 потока/100%, получаем результаты:

Второй тест: 192 потока/100% чтение, получаем результаты:

Третий тест: 192 потока/100% запись, получаем результаты:

Сравниваем результаты Adaptive Flash HF60 vs All Flash AF40:

Пару слов о полученных результатах

Получаем то, что СХД с медленными 7,2k дисками дает большую производительность и меньшое время отклика чем All Flash массив. Как так? Все дело в контроллерах и архитектуре. В нашем случает стоят более производительные контроллеры и за счет магии архитектуры CASL гибриды Adaptive Flash показывают производительности сопоставимую с All Flash (контролеры используются одинаковые HF20=AF20, HF40=AF40, HF60=AF60, разница HF и AF только в конфигурации дисках). Причем скорость и задержки HF60 выигрывает при записи, где в Adaptive Flash никак не задействованы SSD.

За то время что у нас был массив мы смогли сравнить еще с одной конфигурацией All Flash XS5226D СХД QSAN. К нам попал такой результат тестирования:

Единственное, что мы не смогли повторить 464 потока при 32-х виртуалках. Поэтому сделали 448 и 480.

448/480 одновременных потоков серьезная нагрузка. Можно отметить, что здесь массив вполне играет наравне с дешевым All Flash. У QSAN очень много непонятных пиков и провалов по задержке. Поэтому Nimble существенно выигрывает по 95-му перцентилю.

Эксперименты с дудепликацией и компрессией

При 100% записи производительность проседает некритично ~ 20%. При 100% чтении почти ничего не меняется, что вполне логично. Гораздо интереснее 70/30. При наличии нулевых блоков операции чтения ускоряются при включенной компрессии.

Итого: почему его назвали Adaptive Flash а не Hybrid Flash?

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

Могу еще добавить, что наши инженеры скептически относились к данному массиву до тестирования. После первых предварительных результатов (~94k IOPS и задержки 5мс) на 100% чтение Возник спор, т. к. 94k полученных и 300k теоретических сильно отличались. Инженеры стояли на том, что невозможно получить больше на дисках 7200. После проверки конфигурации оказалось, что для тестовых машин было выключено кеширования и чтение не ускорялось вообще. После правильной настройки все взлетело. И как только они не пытались убить скорость массива не получалось (в рамках разумного естественно). В итоге лишь в условиях личного опыта у них поменялось мнение. К чему это? К тому что очень полезно брать железяку на тест, когда ее предлагают (да еще и бесплатно).

Подробнее..

Как мы внедрили свою модель хранения данных highly Normalized hybrid Model. Доклад Яндекса

26.05.2021 12:10:08 | Автор: admin
Общепринятый и проверенный временем подход к построению Data Warehouse (DWH) это схема Звезда или Снежинка. Такой подход каноничен, фундаментален, вотрфоллен и совсем не отвечает той гибкости, к которой призывает Agile. Чтобы сделать структуру DWH гибкой, существуют современные подходы к проектированию: Data Vault и Anchor modeling похожие и разные одновременно. Задавшись вопросом, какую из двух методологий выбрать, мы в Яндекс Go пришли к неожиданному ответу: выбирать надо не между подходами, а лучшее из двух подходов.

Темы доклада, который вместе со мной прочитал Николай Гребенщиков:
DV и AM: в чем разница и где точки соприкосновения
Гибридный подход к построению хранилища
Сильные и слабые стороны этого подхода
Примеры кода
Дальнейший вектор развития hNhM

Меня зовут Евгений Ермаков, я руководитель Data Warehouse в Яндекс Go.

Я расскажу историю о том, как два руководителя объединились и сделали нечто крутое как минимум, по мнению этих двух руководителей. Расскажу про наш подход к хранению данных в детальном слое. Мы его называем highly Normalized hybrid Model. Надеюсь, что корректно произнес по-английски, я тренировался.

Мы это сокращаем до hNhM не пугайтесь, если услышите эту странную аббревиатуру. Можно еще гибридная модель или двухстульная модель. А почему двухcтульная, я обязательно расскажу на примере одного мема.



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

Также я расскажу про архитектуру хранилища Яндекс Go в целом, вместе с детальным слоем, где как раз эта модель и применяется. Потом сравню Data Vault и якорное моделирование так, как мы у себя их сравнивали, и объясню, почему мы из этого сравнения сделали вывод, что нужно создавать нечто свое. И расскажу базисные основы про hNhM.



А во второй главе я передам слово Коле.

Николай Гребенщиков:
Я расскажу о нашем фреймворке, который позволяет нам описывать сущности и загружать данные. Покажу, как мы с ним работаем, как загружаем используем и строим витрины над нашим детальным слоем.

В конце мы подведем итоги, самое главное, что можно из этого доклада почерпнуть. посмотрим, куда мы пришли, что сделали и как это можно переиспользовать.



Итак, архитектура Data Warehouse (DWH) в Яндекс Go. Расскажу об архитектуре слоев данных, какая она у нас, какие инструменты хранения и обработки информации есть, и покажу место детального слоя во всей этой архитектуре.



По моему мнению, архитектура слоев данных в нашем хранилище максимально классическая. Мы шли от глаголов действий над данными, которые происходят с хранилищами. Что мы делаем с данными?

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

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

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



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

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

Дальше детальный слой. Ядро хранилища. Здесь мы храним детальную историю изменений и консолидируем данные между всеми источниками.



На базе этого детального слоя есть слой витрин Common Data Marts.



Здесь мы уже формируем плоские, удобные для аналитиков витрины и оптимизируем доступ на чтение.



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



В итоге классика, все по слоям, от RAW до REP. Данные протекают в хранилище, все как завещали Кимбалл и Инмон в своих подходах.

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



RAW, ODS это такой Data Lake. Здесь у нас полуструктурированные данные, каркас MapReduce и всевозможные внутренние аналоги экосистемы Hadoop.

Центр хранилища это непосредственно Data Warehouse. Здесь у нас слои ODS, DDS, CDM.



Основные цели давать ответ на всевозможные ad-hoc-запросы наших аналитиков, выдерживать большое количество Join и достаточно малое время отклика на всевозможные вопросы.

И витрины. Помимо того, что они служат Data Warehouse, мы еще отгружаем их содержимое в системы анализа и визуализации данных. Это кубы данных, отчеты, дашборды, Tableau.



Если мы эти слои разложим по системам, то получится приблизительно такая картина.

То есть RAW, ODS и части CDM-слоя на супербольших данных это у нас Data Lake.



Маленькая ремарка: в Яндексе много внутренних инструментов, которые мы делаем сами. У нас есть своя собственная платформа, есть такие внутренние инструменты, как YT. Можно проводить аналоги: YT это как Hadoop. И в принципе, есть всевозможные аналоги Hadoop-стека.

На Greenplum у нас находятся часть слоя ODS, детальный слой и витрины. Построенные в Greenplum витрины мы затем отгружаем в MS SSAS или ClickHouse для ряда пользователей. Некоторым удобно пользоваться кубами данных, некоторым широкимb плоскими таблицами, и ClickHouse здесь прямо идеален.

Часть витрин доступно для биосистем, или мы делаем из них агрегаты, доступные для нашего BI. BI у нас это Tableau.

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

Смотреть доклад Владимира

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

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



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

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

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

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

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

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

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



Пойдем дальше. Следующий подход классическая звезда и снежинка. Нормализация до третьей нормальной формы, то, что описывал у себя Билл Инмон. Это можно использовать с минимальной подготовкой нужно понимать, что такое первичный ключ, внешний ключ, join-таблички, SCD2, если мы говорим про измерения. И понимать, какие SCD вообще существуют.

Это может быть неудобно перестраивать при изменении кардинальности. Например, есть клиент и заказ. У одного клиента может быть много заказов, но у одного заказа только один клиент. Бизнес поменялся, у одного заказа теперь может быть несколько клиентов, и клиенты могут делить между собой заказ, как это, например, реализовано в такси. Перестраивать все это крайне больно.

При этом минимальное дублирование информации, если мы используем SCD. И какое-то приемлемое количество join. Если аналитики работают с SQL, они должны уметь работать и с этим.

Следующие походы Data Vault и Anchor modeling. Почему я их вывел одновременно? Потому что они предлагают, на самом деле, нечто очень похожее. Это достаточно строгая нормализация, их сложно использовать без подготовки, без понимания, какие таблицы и какие правила они накладывают.



Обе методологии обещают, что их не надо перестраивать. Для Data Vault это работает с ограничениями, я дальше проговорю, какими. Здесь ультрабольшое количество join. При этом обе методологии относительно современны и обещают гибкость.

Посмотрим на эксплуатацию. Все, что справа, Data Vault и якорное моделирование достаточно сложно эксплуатировать из-за большого количества join. Чем больше join, тем сложнее писать SQL-запросы и в целом получать отсюда информацию. При этом проще вносить изменения в модель. Во всяком случае, обе методологии это обещают.

И наоборот, если у нас никакого подхода нет и мы всё вкладываем в плоскую табличку или нормализуем, то эксплуатировать проще. join или вообще нет, или их приемлемо малое количество. Но при этом вносить изменения, перестраивать сложно.

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



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

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

Сперва стоит спрогнозировать требования, а потом подумать, согласовать, подумать еще. Я уверен, что все, кто работал с классическими DWH, которые построены не по Data Vault или по якорю, понимают, что DWH это не быстро.

Но здесь классический дэвэхашник сталкивается с проблемой: заказчик не знает, чего хочет. Готов смотреть на результат, а потом уточнять, что ему хочется. Его желания постоянно меняются.

И вообще, у нас Agile, мы гибкие, давайте все переделывать максимально быстро. Желательно, завтра. Примерно так выглядит классический дэвэхашник, когда попадает в Agile-среду, в которой невозможно использовать Waterfall.

Логичные вопросы: откуда родились методологии Data Vault и якорь; может ли DWH быть agile; можно ли подходить к разработке хранилища гибко?

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



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



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

Data Vault вводит и регламентирует несколько основных тип таблиц. Ключевые это Hub, Link и Satellite, дальше я буду о них говорить. Hub хранит сущности, Link обеспечивает связь между хабами, Satellite предоставляет атрибуты и описания Data Vault.

Data Vault 2.0 я не буду касаться. Есть еще специальные таблицы типа bridge и point-in-time. Они упрощают или соединение данных через несколько связей, или получение информации из сателлитов с разной частотой обновления. Это скорее расширяющие, упрощающие модель сущности. Ключевые таблицы это все-таки Hub, Link и Satellite.

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



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

Satellite или сателлит это описательная информация хаба, обычно с историзмом по SCD2. Здесь есть информация о ключе связи или хаба, в зависимости от описательных характеристик того, что находится в этом сателлите, сама информация и технические записи: SCD2, временная отметка даты загрузки, код источника данных.

Если на это посмотреть с точки зрения третьей нормальной формы, то есть вот такая неплохая картинка из презентации самого автора Data Vault:


Ссылка со слайда

Посмотрим на третью нормальную форму. Видно, что бизнес-ключи мигрируют в хабы. Все внешние ключи мигрируют и фактически являются связями. А все описательное, все наши поля, которые несут какой-то смысл, уходят в сателлиты. Сателлитов может быть несколько. Нет явных правил, как правильно разбить атрибуты на сателлит. Есть разные подходы: можно бить по частоте изменений, по источнику, по чтению это такой творческий момент в Data Vault.



Если мы посмотрим на якорное моделирование, то я бы его сформулировал как такую крайнюю форму Data Vault, когда у нас правила еще строже и нормализация еще выше.

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

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



Tie связь многих ко многим, один в один как в Data Vault. Внешние таблицы это принципиальный момент, даже если кардинальность связи другая. Но в якорном моделировании есть отличие у связи принципиально не может быть атрибутов.

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

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

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



Если мы рассмотрим нашу таблицу в третьей нормальной форме, то суррогатные ключи находятся в якорях. Это не тот суррогатный ключ, который нам приходит, а которые мы сгенерировали в хранилище.



Внешние ключи находятся в наших связях.


Ссылка со слайдов

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

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

Посмотрим на стандартный тест TPC-H. Я уверен, что многие из вас знают, что это такое, но кратко напомню: это стандартный тест для проверки аналитических хранилищ, внизу на слайде есть ссылка на одну из его версий.


Ссылка со слайда

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

Если мы эту схему преобразуем в Data Vault, то видно, насколько больше таблиц становится, появляются отдельные хабы, отдельные Link. Причем Link сделаны в виде таблиц многие-ко-многим.


Ссылка со слайда

У нас вешаются сателлиты как на Link, так и на отдельные хабы. И в целом, таблица становится больше.

Если мы это конвертируем в якорную модель, получится нечто подобное.



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

В чем же схожести и различия, если их в лоб сравнивать?



И в Data Vault, и в якоре создается специальная таблица на сущность. В Data Vault это Hub, в якоре это якорь. Разница в том, что в хабе есть бизнес-ключ, а в якоре бизнес-ключ это атрибут.

В Data Vault атрибуты группируются в таблицы-сателлиты. В якоре все строже: один атрибут одна таблица, шестая нормальная форма, все раскладываем на отдельные кубики-элементы.

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

И есть специальные таблицы, в Data Vault point in time и bridge, в якоре knot.

Когда мы вот так, в лоб, их сравнили, ощущение было что выбрать? В чем-то лучше якорь, в чем-то Data Vault. У каждого достаточно цельная методология. Якорь построже, но, с другой стороны, возникает меньше вопросов и больше пространства для автоматизации.


В общем, как-то так. Яндекс славится тем, что создает свои инструменты. Почему бы нам не создать свою модель?

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



Из этой идеи и родилась наша гибридная модель highly Normalized hybrid Model, hNhM. Здесь я кратко расскажу ключевые идеи модели. (...)



Ключевая идея выбирать оптимальный формат хранения. Мы не ограничиваем себя ни Data Vault, ни строгостью якоря. Но при этом позволяем выбрать либо одно, либо другое. А если мы позволяем это выбрать, то с точки зрения методологии классно было бы разделить логическое и физическое моделирование.

Еще есть требование, которое мы сами себе ставили: параллельная загрузка из разных источников, идемпотентность при повторной загрузке тех же данных. Стандартная для Data Vault и якоря устойчивость к изменению в бизнесе, модульность и масштабируемость.

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

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



У нас есть слои, про которые я рассказывал, RAW. ODS это наш Data Lake. В RAW мы захватили данные, они лежат как есть. В ODS мы их чуть почистили, но это операционные данные, без истории. В детальном слое мы фактически разложили это все на маленькие кубики-сущности. С точки зрения логического проектирования это сущности-связи между ними. С точки зрения физического хранения на нашем Greenplum это скрыто с точки зрения использования.

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

То есть мы сначала разбираем все на кубики, а потом из этих кубиков собираем что-то красивое. Во всяком случае, мы себе так это рисовали на старте. К концу доклада вы сможете понять, получилось у нас сделать это так, как мы это изначально планировали, или нет.

Про разделение логического и физического уровня. Мы хотели на старте их разделить явным образом.

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

Логический уровень когнитивно сложная часть проектирования. Он не зависит от СУБД в общем виде и достаточно сложен. Трудно выделить сущности и домены в бизнесе, особенно если ты его не знаешь так, как основатели этого бизнеса.



Физический уровень это скрипты DDL. Здесь выполняется партицирование сущностей, объединение атрибутов в группы, дистрибьюция в системах MPP. И индексы для ускорения запросов. Все перечисленное мы хотели скрыть. Во-первых, оно зависит от СУБД и технических ограничений, которые у нас есть. Во-вторых, нам хотелось сделать так, чтобы этот физический уровень был невидим, чтобы мы могли переключаться между Data Vault и якорем, если захотим.



Разделяя так логический и физический уровень, мы фактически делим задачи между нашими ролями. У нас есть две роли:

  • Партнер по данным, Data Partner. Мы так переименовали Data steward. Да, слово steward имеет здравое значение в переводе: распорядитель чего-то чужого, а данные в этом смысле чужие. Но все равно партнер по данным звучит гораздо лучше.

    Партнер по данным на логическом уровне должен ответить на вопрос концептуальной модели: какие вообще направления бизнеса и взаимосвязи между ними у нас есть, как часто будут меняться атрибуты. И из этого построить логическую модель, прямо по классике.
  • И инженер данных, здесь все классически. Он отвечает на вопросы физической модели: как хранить атрибуты, нужны ли партиции, нужно ли закрытие SCD2. И обеспечивает сам расчет данных по инкременту, а также пересчет истории, то есть фактически ETL-процесс.

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



В итоге, базируясь на ER-диаграммах, мы используем сущность и связь. Сущность базовый кубик любого описания домена. Здесь, на логическом уровне, мы хотели сделать так, чтобы сущности описывались наименованием и комментарием; именем сущности и его описанием; бизнес-ключом, который обязателен для любой сущности, чтобы понимать, что его определяет; и каким-то набором атрибутов.

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

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

Атрибут это таблица. Она содержит информацию об одном атрибуте, может содержать историю, а может не содержать. Group это группа атрибутов, как сателлит в Data Vault. Она может содержать информацию о нескольких атрибутах. Важное ограничение на уровне модели: все атрибуты должны приходить в эту группу сателлита из нового источника и иметь один тип историзма.



Связь. На уровне ER-диаграммы понятно, что это такое. С точки зрения логического уровня это список связанных сущностей и кардинальность связи. Здесь мы пошли по жесткой модели якоря и не позволили хранить у связи никаких атрибутов. Если хочется повесить на связь атрибут, то для этого должна быть отдельная сущность.

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

Итого мы получаем примерно такую картинку: На логическом уровне рисуем ER-диаграмму или описываем нашу сущность.



А на физическом уровне получаем вот такой набор таблиц. Видно, что тут есть и группы атрибутов, и просто атрибуты, и связи. Хотелось бы, чтобы все это было скрыто. Причем на обоих уровнях работы с DDS: и на загрузке данных, и на построении витрин.



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

Мы хотим скрыть сложности загрузки SCD2. Если приходят данные, то мы в этом месте требуем, чтобы в слое DDS обязательно помимо ключа была еще дата, актуальная с точки зрения бизнеса, по которой мы простраиваем SCD2 в детальном слое.

На уровне построения витрин скрываем сложность групп, связей, хабов. Мы работаем с сущностями на логическом уровне, а они с таблицами на физическом уровне. Это нам позволяет скрыть сложности исторической обработки записей и максимизировать простоту работы с инкрементом.

Всего тут есть три концептуальные идеи:

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

Если возвращаться к Data Vault и якорю, то фактически из Data Vault мы взяли сателлиты и назвали их у себя группой атрибутов. Позволили отойти от этой строгости якоря, где один атрибут одна таблица.

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



Но с точки зрения простоты внедрения проще не думать, вешать ли атрибут на связь, а сразу знать: если на связь потребуется выделить атрибуты создай новую сущность. Или подумай, что за сущность с этими атрибутами должна существовать.

Из Data Vault мы взяли специальные таблицы point in time и bridge для упрощения своей собственной внутренней работы с hNhM.

И если подводить итог, этим всем категорически невозможно управлять без фреймворка. Если вы попробуете все это воссоздать полуавтоматически или DDL-скриптами, то можно буквально убиться об количество таблиц и весь объем данных, метаданных, которыми надо управлять.



Поэтому мы разработали так называемый hNhM-фреймворк. Здесь я передаю слово Коле. Он подробно расскажет, что мы конкретно разработали и как мы этим пользуемся у себя внутри.

Да, я расскажу о нашем фреймворке что сделали, как храним и как с этим работаем.

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

Смотреть доклад Владимира

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



В центральной части находится наш Data Lake, который хранится на YT. Это аналог экосистемы Hadoop, в нем мы храним слои RAW и ODS. Сейчас у нас объем данных около двух петабайт.

И само хранилище на Greenplum, в котором находится частично ODS за очень небольшое количество времени и слой DDS. Сейчас Greenplum у нас весит, по-моему, около пол-петабайта. На каждом слое мы умеем вычислять инкремент, что позволяет ускорить загрузку, избавиться от лишней работы по чтению и обработке данных.

Детальный слой основной элемент хранилища на Greenplum. На его основе мы строим все наши витрины.



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



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

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



Далее необходимо описать технические параметры layout. С помощью трех полей Layer, Group и Name мы определяем путь до места хранения объекта в нашем хранилище. Неважно, будет ли это YT, Greenplum или что-то еще в будущем.



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

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



Сейчас у нас есть три типа. Ignore это когда пришедшее значение записывается, а мнение с большей бизнес-датой игнорируется. Update когда при изменении значение перезаписывается. New исторический атрибут.

Атрибуты с Ignore и Update не хранят историю изменений и отличаются тем, что в Ignore предпочтение отдается значению с меньшей бизнес-датой, а в Update с большей.



Также для каждой сущности мы указываем логический ключ.

На слайде видно, во что физически превращается каждая сущность.





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

Также в каждой таблице есть поля, в которых хранятся даты действия атрибута.





Если у данного атрибута историчность New, то это два столбца utc_valid_from_dttm и utc_valid_to_dttm. То есть это метка во времени, с которой определяется действие конкретной записи.

Для атрибутов типа историчности Update и Ignore действует только один столбец: utc_valid_from. Это бизнес-дата, с которой мы узнали, что атрибут имеет текущее значение.





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

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



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

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

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

Структура после объединения части атрибутов в группы выглядит уже гораздо более компактно.





Например, все флаги мы объединили в группу flg, общую информацию в группу info, ключевые атрибуты в группу key.

Теперь поговорим про объявление связей. Каждая связь тоже описывается в отдельном классе.



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

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

В этом примере мы делаем Link между департаментом и сотрудником. В данном случае ключом Link является сотрудник.



На слайде мы видим, как это физически реализовано.



Видно, что у Link нет суррогатного ключа, потому что его суррогатным ключом являются все те сущности, которые входят в ключ Link.

Теперь мы обсудим, как загружаем сущности.

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



В самом простом случае этот кубик выглядит так.



В самом начале мы описываем источник. Это stage-таблица, для которой есть точно такой же класс, написанный отдельно в платформе.

Также мы указываем поле, в котором хранится бизнес-дата и система-источник.

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



Как мы видим, в качестве таргета указана таблица Person. Дальше следует маппинг атрибутов. Это самый простой вариант описания. В реальной жизни все выглядит гораздо сложнее. Например, так.



Мы видим, что из одной stage-таблицы данные грузятся в несколько сущностей. Одна сущность может грузиться несколько раз. Это в данном случае e-mail, он может быть в stage-таблице и персональным, и рабочим.

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

А если нет, то, скорее всего, это ошибка и мы об этом сообщаем пользователю.



Но в ряде случаев мы не можем автоматически этого сделать. Например, в stage-таблицу приходит и персональный почтовый ящик, и рабочий. Но и в обоих Link используется одна и та же сущность e-mail. Мы их специально не разделяем, потому что в реальном мире e-mail единая сущность. В то же время нам надо понять, какое здесь поле, какой Link грузить. Мы добавили специальный параметр, который позволяет определить, какое поле куда идет.

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



Все задачи внутри графа выполняются параллельно, в зависимости от типа изменений. Это либо Insert\Update по SCD2, либо Insert. Данные из разных источников также могут загружаться параллельно.



Дальше я расскажу, как мы используем наш hNhM.

На основе DDS мы строим витрины. Пользователи напрямую могут обращаться к нашим сущностям и просматривать данные.



У нас есть два основных типа потребления данных DDS: ad-hoc-запросы от бизнес-пользователей и построение витрин. ad-hoc-запрос реализован двумя способами либо view, либо через функции. И то и то скрывает реализацию от пользователей.

Витрины мы строим с помощью нашего фреймворка и тоже полностью скрываем реализацию.

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

После изменения описания сущности все витрины, которые использует тот или иной атрибут, теоретически могут развалиться, потому что атрибут был исторический, стал не исторический, и это изменит структуру таблицы.

В конце концов, это просто очень сложно написать что-то с select, где будет 20-30 join.

Как у нас происходит доступ к сущностям из Python?



Было разработано несколько классов, которые позволяют сформировать SQL-запрос к определенной сущности и затем использовать его в построении витрины. Как это выглядит?



Мы описываем CTE. Оно может быть либо историческое, либо актуальное.



В первую очередь мы указываем сущность, которую хотим использовать.



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



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

А так выглядит SQL-запрос для построения витрины. Есть переменные постановки, которые полностью скрывают реализацию. Потом идет сам запрос, который их использует. При этом можно использовать переменные как в визе, так и во временных таблицах. Это уже зависит от объема данных.



Как происходит доступ к сущностям из СУБД?



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

И вторая процедура это когда мы от entity к существующей таблице через Link добавляем дополнительную сущность и расширяем нашу табличку. Теоретически ключ у нее даже может поменяться.

А сейчас чуть более подробно покажу, как это работает.



Мы вызываем специальную функцию.



Указываем сущность.



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



Дальше указываем временную таблицу, в которую надо положить данные.

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



Примерно так же выглядит добавление сущности к уже созданной таблице.



Мы указываем таблицу, в которой уже есть сущность.



Указываем Link, через который мы хотим подключить дополнительную сущность.



Указываем саму сущность, которую мы хотим добавить.



И столбцы этой новой сущности. При этом мы можем как положить данные в уже существующую таблицу, так и создать новую.



Дальше мы расскажем, какие задачи оптимизации мы решали. Тут я передам слово Жене.

Спасибо. Расскажу про оптимизацию и атрибуты против групп. Задача, на мой взгляд, очень интересная.

Посмотрим на объявление класса. Например, на объявление сущности Person.



В физическом мире мы можем представить ее в виде один атрибут одна табличка.





Это будет вполне нормально с точки зрения якорной модели. А можем ли мы сгруппировать атрибут? Здесь часть сгруппирована: флаги отдельно, информация о персоне отдельно, ключи отдельно, атрибуты отдельно.





Какая схема лучше? С точки зрения загрузки данных все то же самое. С точки зрения чтения данных все это скрыто, Коля про это рассказал. И с точки зрения использования будет одинаково.Не можем ли мы сделать так, чтобы эта физическая модель выбиралась наилучшим, оптимальным образом?



Мы постарались это свести к оптимизационной задаче. У нас буквально стояла проблема с объемом данных на Greenplum. Сейчас она не стоит. У нас действительно полупетабайтовый кластер на Greenplum, это достаточно много. Но еще буквально год-полтора назад даже такого не было.

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

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

Будем минимизировать занимаемое место на диске. Вот такую задачу мы себе поставили. Как мы ее решали?



Прежде всего мы формализовали и стандартизовали операции, меняющие схему, но не меняющие логику. Они совсем простые и очевидные. Можем объединять группы атрибутов в какую-нибудь еще группу, еще более крупную. Можем разъединять набор групп или вообще разъединить до атрибутов.

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

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



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

Дальше все просто. Мы из нашего состояния генерим новое мутациями атомарными преобразованиями. Чтобы не обходить все, мы ограничиваем выборку и оцениваем каждое состояние.

Берем лучшие, скрещиваем их между собой, проводим новые мутации и так далее, классический генетический алгоритм.

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

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

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



К чему мы пришли, зачем мы сюда пришли и стоит ли вообще повторять наш путь?

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



Мы провели сравнение и сделали вывод: можно взять лучшее из каждой методологии. Не стоит слепо идти по одной из них и разрезать, например, clickstream на отдельные атрибуты. Стоит взять лучшее из Data Vault и из якоря.


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

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

На слайде показано, что мы взяли из Data Vault, а что из якоря.

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



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

Этот путь мы не советуем повторять. Если у вас нет свободной горы разработчиков, которые настолько круто прокачаны в Python, что готовы все это повторить и аккуратно сделать так же, как у нас, лучше не вступать на этот скользкий путь. Вы просто убьете очень много времени и не получите того бизнес-результата, который можно получить, используя Data Vault, якорь или гибридную модель, как мы.



Что же делать? У нас есть большой roadmap развития. Можно добавить больше гибкости например, я говорил, что на связь мы не вешаем ни атрибуты, ни группы. Но здесь можно это реализовать и воссоздать все типы таблиц Data Vault и якоря.

В нашем коде мы сейчас сильно завязаны на Greenplum. Хотелось бы от этого оторваться, сделать так, чтобы можно было применять модель где угодно именно с точки зрения фреймворка.

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

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

Что делать, если у вас нет разработчиков? Дождаться, когда мы это заопенсорсим. У нас есть такие мечты. Вполне возможно, что мы свои фантазии осуществим и заопенсорсим этот продукт.

Следите за обновлениями или, если не хотите следить, приходите к нам и создавайте гибридную модель вместе с нами. На этом все. Спасибо за внимание.
Подробнее..

Транзакции. Часть 2. Конспект книги Designing Data-Intensive Applications

23.05.2021 14:09:40 | Автор: admin

Эта статья является конспектом книги Designing Data-Intensive Applications.

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

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

Асимметрия записи и фантомы

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

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

Рис. 1 - Пример асимметрии записи, вызванной ошибкой в коде приложенияРис. 1 - Пример асимметрии записи, вызванной ошибкой в коде приложения

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

Такая аномалия носит название асимметрии записи (write skew). Это не грязная операция записи и не потеря обновления, поскольку две наши транзакции обновляют два различных объекта. Наличие конфликта тут менее заметно, но это, безусловно, состояние гонки:если две транзакции выполнялись бы одна за другой, то второй врач не получил быотгула.

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

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

BEGIN TRANSACTION;SELECT * FROM doctorsWHERE on_call = trueAND shift_id = 1234 FOR UPDATE;UPDATE doctorsSET on_call = falseWHERE name = 'Alice'AND shift_id = 1234;COMMIT;

Предложение FOR UPDATE указывает базе установить блокировкуна все возвращенные данным запросом строки.

В примере с дежурными врачами измененная строка была одной из строк,возвращенных в первом запросе, так что можно было обезопасить транзакцию и избежатьасимметрии записи, блокируя строки (SELECT FOR UPDATE). Однако если выполняется проверка на отсутствиеудовлетворяющих определенному условию поиска строк, а операция записи вставляет соответствующую этому же условию строку, то первый запрос на получения данных не вернетничего и SELECT FOR UPDATE не на что будет устанавливать блокировки.

Такой эффект, при котором операция записи в одной транзакции меняет результатзапроса на поиск в другой, называется фантомом (phantom).

Для предотвращения таких ситуация в большинстве случаев предпочтительнее использоватьизоляцию уровня сериализуемости.

Сериализуемость

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

Но если сериализуемость настолько лучше более слабых уровней изоляции, почему бы не использовать ее повсеместно? Для ответа на данный вопрос рассмотримвероятные реализации сериализуемости и их производительность. Большинство современных БД, обеспечивающих сериализуемость, применяют один из трех методов:

  • действительно последовательное выполнение транзакций;

  • двухфазную блокировку;

  • методы оптимистического управления конкурентным доступом, например,сериализуемую изоляцию снимков состояния (SSI).

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

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

Хотя эта идея довольно очевидна, создатели баз данных только относительнонедавно решили, что однопоточный цикл выполнения транзакцийоправдывает себя. Как случилось, что однопоточное выполнение стало считаться допустимым?

Этот пересмотр концепции был вызван двумя факторами.

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

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

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

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

  • Набор данных должен помещаться в памяти целиком. Потенциально можнопереместить на диск редко используемые данные, но, если понадобится обратиться к ним в однопоточной транзакции, система способна очень сильнозамедлиться.

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

Двухфазная блокировка (2PL). В течение долгого времени в базах данных широко использовался только один алгоритм сериализуемости: двухфазная блокировка (two-phase locking, 2PL).

Обратите внимание, что, хотя название двухфазной блокировки (2PL) оченьсхоже с названием двухфазной фиксации транзакций (2PC), это две совершенно разные вещи.

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

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

Из-за столь большого количества блокировок часто встречается ситуация, когдатранзакция A ждет снятия блокировки транзакции B и наоборот. Такая ситуацияназывается взаимной блокировкой (deadlock). База данных автоматически обнаруживает взаимные блокировки между транзакциями и прерывает одну из них, чтобыостальные могли продолжить работу.

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

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

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

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

Очень многообещающим представляется алгоритм под названиемсериализуемая изоляция снимков состояния (serializable snapshot isolation, SSI).Он обеспечивает полную сериализуемость за счет лишь небольшого сниженияпроизводительности по сравнению с обычной изоляцией снимков состояния. SSI относительно новый метод: он был впервые описан в 2008 году.

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

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

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

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

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

База данных не знает, как приложение использует результаты выполняемыхк ней запросов. Ради безопасности она предполагает, что любые изменения в результатах запроса означают потенциальную неправильность выполненных текущей транзакцией операций записи. Другими словами, возможна причинно-следственнаясвязь между запросами и выполняемыми транзакцией операциями записи. Для обеспечения сериализуемости БД должна выявлять ситуации, когда транзакция могла выполнять действия на основе устаревших исходных условий, и прерыватьтакие транзакции. Рассмотрим дваслучая:

  • выявление операций чтения устаревших версий MVCC-объектов (перед чтением произошла незафиксированная операция записи);

  • выявление операций записи, влияющих на предшествующие операции чтения(операция записи произошла после чтения).

Выявление операций чтения устаревших версий MVCC объектов. Изоляция снимков состояния обычно реализуется с помощьюMVCC.Транзакция, читающая из согласованного снимка состояния в базе данных MVCC,игнорирует все операции записи, которые были выполнены транзакциями, ещене зафиксированными на момент получения снимка состояния. На рис. 2 транзакция 43 видит, что Алиса находится на дежурстве (on_call = true), посколькутранзакция 42 не зафиксирована. Однако на моментфиксации транзакции 43 транзакция 42 уже зафиксирована. Это значит, что операция записи, проигнорированная при чтении из согласованного снимка состояния,теперь уже вступила в силу и исходные условия транзакции 43 более не соответствуют действительности.

Рис. 2 - Выявление чтения транзакцией устаревших значений из снимка состояния MVCCРис. 2 - Выявление чтения транзакцией устаревших значений из снимка состояния MVCC

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

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

Рис. 3 - Выявление при сериализуемой изоляции снимков состояния случаев модификации транзакцией данных, прочитанных другой транзакциейРис. 3 - Выявление при сериализуемой изоляции снимков состояния случаев модификации транзакцией данных, прочитанных другой транзакцией

На рис. 3 обе транзакции, 42 и 43, выполняют поиск дежурящих в смену 1234 врачей. При наличии индекса по shift_id база может воспользоваться его записью 1234, чтобы отметить факт чтения транзакциями 42 и 43 этих данных (еслииндекса нет, информацию можно отслеживать на уровне таблицы). Сама информация требуется только временно: после завершения выполнения транзакции(ее фиксации или прерывания) и завершения всех конкурентных транзакций БДможет спокойно забыть о том, какие данные читались этой транзакцией.

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

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

Вывод

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

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

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

  • Грязные операции чтения. Клиент читает записанные другим клиентомданные до их фиксации. Уровень изоляции чтения зафиксированных данныхи более сильные предотвращают грязные операции чтения.

  • Грязные операции записи. Клиент перезаписывает данные, которые другойклиент записал, но еще не зафиксировал. Практически все реализации транзакций предотвращают грязные операции записи.

  • Асимметрия чтения (невоспроизводимое чтение). Клиент видит различные части базы данных по состоянию на разные моменты времени. Чаще всего такуюпроблему предотвращают с помощью изоляции снимков состояния, при которойтранзакция читает данные из согласованного снимка состояния, соответствующего определенному моменту времени. Обычно это реализуется благодарямноговерсионному управлению конкурентным доступом (MVCC).

  • Потерянные обновления. Два клиента выполняют в конкурентном режиме циклчтения изменения записи. Один переписывает записанные другим данныебез учета внесенных им изменений, так что данные оказываются потеряны.Некоторые реализации изоляции снимков состояния предотвращают эту аномалию автоматически, а в других требуется установка блокировки вручную(SELECT FOR UPDATE).

  • Асимметрия записи. Транзакция читает какие-либо данные, принимает наоснове прочитанного значения решение о дальнейших действиях и выполняетоперацию записи в базу данных. Однако на момент ее выполнения исходныеусловия, на основе которых принималось решение, более не соответствуютдействительности. Эту аномалию предотвращает только сериализуемость.

  • Фантомные чтения. Транзакция читает объекты, соответствующие определенному условию поиска. Другой клиент выполняет операцию записи, котораякаким-то образом влияет на результаты этого поиска. Изоляция снимков состояния предотвращает непосредственно фантомные чтения, но фантомы в контексте асимметрии записи требуют отдельной обработки, например, блокировокпо диапазону значений индекса.

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

  • По-настоящему последовательное выполнение транзакций. Если вы можетесделать отдельные транзакции очень быстрыми, причем количество транзакций,обрабатываемых за единицу времени на одном ядре CPU, достаточно невелико,то для обработки этот вариант окажется простым и эффективным.

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

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

Ссылки на все части

Подробнее..

Аптайм 500 дней перезагрузка падение собираем бэкап по частям

09.06.2021 10:16:43 | Автор: admin

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

Все началось с того, что сервер статистики контактного центра заказчика (на тот момент ещё потенциального) сбросил все пользовательские сессии и перестал отвечать на запросы. Соответственно к нему подкатили тележку с монитором и перезагрузили. Это обычно надо делать раз в 90 дней по инструкции от вендора, но тут это не делалось больше 500 дней. В общем, сервер отметил юбилей аптайма.

Дальше быстро выяснилось, что на рестарте посыпалась база и пропали конфиги. Но главное, что сервер стартанул, бэкапы куда-то писались. Всё хорошо, железо работает, диски в порядке, надо просто накатить бэкап.

Но после накатывания бэкапа система просто легла.

В этот момент нас позвали отмечать день рождения сервера. Без него не работала балансировка нагрузки на операторов внутри КЦ.

Что это была за система?

Система Avaya Call Management System (CMS). Это кусок колл-центра, который собирает статистику по звонкам, операторам, нагрузке исторические и реал-тайм данные. На этом же сервере каждое утро собираются отчёты о работе. В реальном времени сервер говорит, какие операторы сейчас в каких статусах находятся, какие звонки обрабатываются, сколько звонков висит в очереди. В целом система нужна, чтобы следить за группами операторов, за колл-центром, чтобы правильно распределять нагрузку, потому что можно переносить операторов из ненагруженных линий в нагруженные и так далее. Обычно там просто сидят супервизоры и следят за всем происходящим. Прямых аналогов нет, обычно используются самописные решения или же всё вообще делается вручную. Аваевскую систему выбирают за надёжность и многофункциональность.

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

Сбои со статистикой ведут к тому, что маркетологи не знают, как идут рекламные кампании, и это означает, что они сидят в неизвестности.

Первый день пятница

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

Приезжаем на место (напомню, что сервер лёг и удалённого доступа нет), подключаемся с монитором и клавиатурой, ещё раз смотрим, как система не стартует.

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

У нас условно есть три части системы: железный сервер, который входит в ПАК, поставляемый сразу с софтом в виде чёрного ящика от вендора, CMS и база данных. Бэкапы CMS (конфигураций) и базы делаются в разные места.

ОК, система запустилась, но только база пустая данных никаких нет.

Уже дальше мы узнали и историю про юбилей, и про рестарт, и про всё остальное. Вообще-то для серверов такого класса нормально работать месяцами и годами без перерыва, но у Аваи есть регламент. Там в зависимости от нагрузки системы перезагрузка делается раз в 90 или раз в 180 дней. Очевидно, что регламент пять-шесть раз уже не соблюли. Это тоже нормально, до этого места инструкции дочитывают далеко не все, а если дочитывают, то считают, что это перестраховка вендора. Потому что это и есть перестраховка вендора.

Итак, у нас на руках железный оракловский сервер, с которым что-то не то (но это не посыпавшийся раньше времени диск), на нём Solaris c базjq Informix от IBM + пакет CMS от вендора. Решение продаётся как программно-аппаратный комплекс, то есть всё там как поставил вендор, так никто и не трогал.

Бэкапы БД делались. Итерации были по 180 дней, бэкапирование настроено в планировщике системы. Логи бэкапов никто особо не читал, консистентность не проверяли, назад до этого юбилея сервака накатывать не пытались.

Складировались бэкапы прямо на этот же сервер.

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

Дальнейшее исследование

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

К утру мы всё ещё думали, что справимся быстро (в КЦ уже начались проблемы). Решили не трогать бренную земную оболочку сервера, а сразу снять с него образ и развернуть на виртуалке. Это стандартная процедура и для форензики, и для восстановления чего-то, где может посыпаться дальше диск, и вообще очень удобно в конечном итоге в плане не навреди ещё.

Сначала мы развернули виртуалку на стенде прямо у заказчика и начали препарировать там. Фактически Авая сделала больше, чем должна была, подарив лицензию на виртуальную систему. Ну, точнее, заказчику. Выяснили, что бэкап встаёт с ошибкой устройства, но в остальном норм, правда, система пустая. Довольно быстро стало понятно, что бэкап битый полностью.

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

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

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

В лаборатории

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

Сразу стало понятно, что свежий бэкап неконсистентен и вообще похож на записанный прямо из /dev/random. То есть последний месяц (который не бэкапился) пропал просто в силу того, что его никто никуда не резервировал. Следующие полгода пропали из-за битого бэкапа. И только в следующей итерации нашлись таблицы, где были реальные данные. То есть минус семь месяцев от момента аварии, и, как позже выяснилось, целых данных там было не очень много, не больше года, а часто по некоторым показателям и меньше.

Вручную с таблицы перенесли данные в базу данных и скормили всё это нашей виртуалке.

То есть в итоге оставили систему в рабочем режиме со старыми данными, руками настраиваем всё то, что не удалось восстановить из бэкапа системы (пользовательские учётки, коннекторы к другим системам, скрипты).

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

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

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

Выводы

История на самом деле печальная: да, мы частично восстановили систему (вендор был готов в рамках своих сервисных соглашений только поднять с нуля чистую систему). Да, запустили колл-центр в понедельник со сбором статистики очень оперативно (по меркам проблемы).

Выводы достаточно очевидные: запишите где-нибудь процедуры обслуживания серверов, чтобы их не пропустили, раз. И проверяйте бэкапы два. Если у вас есть что-то критичное или держите это в виртуальной среде, или имейте второе железное решение для бесшовных перезагрузок (ну или готовьтесь к простою). Складируйте бэкапы не на сам сервер, который надо бэкапить. Имейте партнёра со SLA на такие поломки ну или хотя бы просто проверенные контакты, потому что, когда что-то падает, обычно надо решать сразу. Повезло, что это было перед выходными и что на выходных КЦ под минимальной нагрузкой.

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

Подробнее..

Перевод Система хранения данных на основе ДНК реально ли это и как работает?

16.06.2021 16:13:28 | Автор: admin

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

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

Подробнее о проблемах


Разрабатываемые системы хранения данных в ДНК предусматривают добавление определенных меток последовательностей (sequence tags) к участкам ДНК, которые содержат данные. Для получения необходимой информации в молекулу добавляются участки, которые способны образовывать пары оснований с нужными метками. Все это используется для амплификации полной последовательности. Примерно как пометить каждое изображение в коллекции собственным ID, а затем настроить все так, чтобы амплифицировался один конкретный ID.

Метод достаточно эффективен, но у него есть два ограничения. Во-первых, этап амплификации, который выполняется при помощи процесса полимеразной цепной реакции (ПЦР), имеет ограничения на размер амплифицируемой последовательности. При этом каждый тег занимает часть и так ограниченного пространства, поэтому добавление подробных меток сокращает объем пространства для хранения данных.

Еще одно ограничение заключается в том, что ПЦР, амплифицирующая определенные фрагменты ДНК с данными, потребляет часть исходной библиотеки ДНК. То есть каждый раз, когда мы считываем данные, часть их уничтожается. Ученые сравнивают такой способ поиска информации со сжиганием стога сена для обнаружения иголки. Если это делать часто, в итоге можно потерять вообще всю базу данных. Правда, есть способы восстанавливать потерянные участки, но этот метод не идеален, поскольку при его использовании увеличивается вероятность появления ошибки в ДНК и участках данных.


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

Новая система


Основа технологии капсулы из диоксида кремния, в которых хранятся отдельные файлы. К каждой капсуле прикрепляются ДНК-метки, которые показывают, что в файле. Размер каждой капсулы составляет около 6 микрометров. Благодаря такой системе ученым удалось научиться извлекать отдельные изображения с точностью 100%. Набор файлов, который они создали, не очень велик их всего 20. Но если учитывать возможности ДНК, то масштабировать такую систему можно до секстиллиона файлов.

Закодированы эти 20 файлов были во фрагменты ДНК длиной около 3000 нуклеотидов, это около 100 байт данных. В одну капсулу из кремнезема можно поместить файл размером до гигабайта. После того, как файл помещен в оболочку, на его поверхность помещаются метки из одноцепочечной ДНК. К одной оболочке можно прикрепить несколько меток, которые служат ключевыми словами. Например, рыжий, кот, животное.

Помеченные таким образом капсулы из кремнезема объединяются в единую библиотеку данных. Она не так компактна, как хранилище из чистой ДНК, но зато данные в этом случае не повреждаются.

Поиск файлов


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

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

При этом остальная часть библиотеки затрагиваться не будет, а значит, не пострадают данные. Стог сена ради поиска одной иголки сжигать уже не требуется. Дополнительный плюс в возможности логического поиска с разными критериями. Например, условия запроса могут быть сложными: true для кот, false для домашний, true для черный и т.п.

Не только поиск


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

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

Подробнее..

Что нам стоит дом построить? (часть 2)

21.06.2021 12:17:59 | Автор: admin

Привет, Хабр. В прошлой статье я рассказал о начальном анализе предметной области и базовом проектировании нашей новой ECM-системы. Теперь я расскажу о первой практической задаче, которую мы решили. А именно - о выборе способа организации структуры хранилища бизнес-атрибутов объектов.

Напомню, что в результате анализа мы пришли к следующей структуре объекта:

Системные и интеграционные поля содержат техническую информацию и редко подвержены модификациям. А вот бизнес-поля - искомые атрибуты объектов - могут и будут различаться для разных типов документов, которых у нас на входе предполагается около 1000. Проанализировав возможность повторного использования полей, мы пришли к выводу, что у разных типов документов может быть не более 15% общих свойств. И при этом всё равно придется скрепя сердце согласиться на неполное соответствие названия и содержания.

Таким образом, есть большое количество сущностей с разнообразным атрибутивным составом, который нужно хранить, тратя как можно меньше ресурсов, и расширять который хотелось бы также с минимальными усилиями.

Какие есть варианты?

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

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

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

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

А впоследствии могут начать возникать проблемы с восприятием. Если поля данных добавляются в одну общую таблицу, то растет размер впустую выделяемых ячеек. Если для каждой сущности добавляется отдельная таблица со специфичными для нее данными, то со временем структура хранилища начинает напоминать примерно такой "одуванчик".

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

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

А что у нас?

Второй вариант - это использование специализированных документоориентированных (или документных, как больше нравится) баз данных, реализующих NoSQL-подход к хранению и обработкенеструктурированной или слабоструктурированной информации. Наиболее часто данные хранятся в виде JSON объектов, но с предоставлением производителями СУБД инструментария для доступа к данным внутри этих структур.

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

  • можем управлять структурой объектов без программирования, в том числе в реальном времени, путем администрирования. Администратор сможет зайти в некий интерфейс справочника полей и задать новые.

  • ограничиваем ситуации случайного воздействия на данные - модифицировать json объект гораздо сложнее, чем данные в колонке.

  • проще описывать объекты в коде - иногда можно вообще не описывать структуру документа в коде, а работать прямо с полями в JSON.

Но есть и минусы:

  • невозможно нативно реализовать проверки данных при размещении в хранилище.

  • валидацию данных придется проводить в коде.

  • невозможно организовать внутреннюю связность подчиненных данных, например, справочников.

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

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

Делаем прототип

Возьмем гипотезу, что NoSQL-подход для нашей системы применим как минимум не хуже, чем классический. Для ее проверки создадим прототип, в рамках которого реализуем оба подхода. В качестве СУБД возьмем Postgre, который уже давно умеет хорошо работать с JSON полями.

Создадим следующие таблицы:

Для описания объектов в табличном виде:

  • r_objects, базовые данные по объектам: тип, дата создания и ссылка на хранилище атрибутов.

  • r_attributes. атрибуты, во всех возможные колонки для всех объектов. В идеале конечно же хранилища атрибутов для разных объектов лучше разбить по разным таблицам, но для прототипа это не критично.

Для описания объектов в виде JSON:

  • objects. Данные по объектам, где в поле data формата jsonb хранятся искомые атрибуты.

Остальные таблицы - это различные вспомогательные хранилища.

Реализуем в коде 5 разных типов объектов, для каждого из них описав программную структуру, механизм извлечения данных из хранилища и наполнения этими данными самих объектов.

Методика тестирования

Для тестирования обоих подходов хранения данных используем следующие методы:

  • добавление данных по объекту. Критерий успешности: объект с данными появился в хранилище, метод вернул в ответе его идентификатор.

  • обновление данных по объекту. Критерий успешности: данные в хранилище были изменены, метод вернул отметку об успехе. Удаление данных в системе не предусматривается, поэтому удаление объекта является операцией, аналогичной обновлению.

  • извлечение данных по объекту. Критерий успешности: объект с данными возвращен в ответе на запрос. Извлечение объекта происходит по конкретному идентификатору, по критериям поиска и постранично (пагинация).

Генерация запросов будет происходить в 20 параллельных потоков по 50 запросов в каждом потоке. Для того, чтобы тестирование было действительно показательным с точки зрения производительности, предварительно наполним базу 200 млн. объектов.

Тестирование показало следующие результаты:

График по тестированию табличного хранилищаГрафик по тестированию табличного хранилищаГрафик по тестированию NoSQL-хранилищаГрафик по тестированию NoSQL-хранилища

Первая (высокая) часть графика - это получение объектов по случайной странице - пагинация. Здесь в обоих случаях пришлось применить небольшой трюк - так как Postgres не агрегирует точное число строк в таблице, то узнать, сколько всего записей на объеме данных теста простым count - это долго, и для получения количества записей пришлось брать статистику данных по таблице. Также время получения данных на страницах свыше 10000-й неприлично велико, поэтому верхняя планка для получения случайного номера страницы была установлена в 10000. Учитывая специфику нашей системы, получение пагинированных данных не будет частой операцией, и поэтому такое извлечение данных применяется исключительно в целях тестирования.

Вторая (средняя) часть графика - вставка или обновление данных.

Третья (низкая) часть графика - получение данных по случайному идентификатору.

В случае табличной структуры данных - линий на графике больше, потому что с точки зрения программной структуры, получение данных для каждого типа объекта идет по разным методам, тогда как для NoSQL - по одинаковым.

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

Результаты тестов на 40000 запросов приведу в виде таблицы:

Табличная

NoSQL

Объем хранилища

74

66

Среднее количество операций в секунду

970

1080

Время тестирования, секунды

42

37

Количество запросов

40000

40000

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

Что получилось?

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

Подробнее..

VSS для самых маленьких

02.06.2021 10:16:01 | Автор: admin

Снятие снапшота - именно с этого начинается любой бекап. До тех пор, пока мы не знаем, как сбросить все буфера на диск и привести файлы с данными в консистентное состояние, мы не бекапы делаем, а занимаемся копированием файлов с непредсказуемым содержимым внутри. Понимая важность снапшотов, все вендоры стараются дать нам если не полностью готовую функцию (типа Time Mashine в MacOS), то хотя бы набор ручек, за которые можно подёргать (вроде модуля dm-snap в ядре Linux).

Но сегодня речь пойдёт про самую распространённую ОС - Microsoft Windows, где эта задача решается с помощью Volume Shadow Copy сервиса, известного в народе под аббревиатурой VSS (Volume Snapshot Service). А нашего внимания он удостоился из-за того, что, несмотря на всю популярность своего материнского корабля, сам он окутан вуалью из тайн и мистических слухов. Давайте уже как-то разберёмся с этой штукой.

А, собственно, что с ним за проблема? Вот есть документация, где вполне адекватно и красиво описано, как всё работает. Есть утилита vssadmin, позволяющая вполне годно создавать и удалять снапшоты. Что не так-то, и где сложности?

Но проблема в том, что более лучшая документация, намного правильнее отражающая происходящие процессы, несколько сложна для понимания. Microsoft вообще написал по этой теме какое-то неслыханное количество документов. Но даже когда вам как-то удаётся выстроить в голове работу этого алгоритма, вы сразу сталкиваетесь с тем, что на практике многие вещи работают совершенно не так, как описаны. Или вообще не работают. А что-то не описано совсем, хотя этому мы уже давно не удивляемся. Но не хвататься же сразу за дебагер и дизассемблер, да?

Хотя упомянутый выше vssadmin как-то вроде и работает, и снапшоты даже делает, и вообще молодец. Но это всё до того момента, пока ты не начинаешь вникать в тонкости, где может выясниться, что репорт об успешно созданном снапшоте - это репорт о чём угодно, только не об успешно созданном снапшоте.

Вот поэтому и захотелось немного поговорить о том, как же на самом деле работает VSS. И да, строго говоря, результатом работы VSS является созданная shadow copy. Но дабы не ломать язык и не мучить вас транслитом, давайте просто писать снапшот.

Какова роль VSS

Не сомневаюсь, что 90% читающих прекрасно понимают, зачем нужны снапшоты, но ради оставшихся 10% потерпите несколько предложений. Или сразу идите в следующий раздел.

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

Сами снапшоты ничего не знают про ваши файлы и папки. Они работают на уровень ниже файловой системы - с блочными устройствами и блоками данных. Если придерживаться терминологи Microsoft, то снапшот - это место, именуемое Shadow Storage, куда записываются изменённые блоки данных и откуда их можно извлекать с целью переписать данные на оригинальном диске. Тут можно запомнить для себя два нюанса. Первый - только что сделанный спапшот занимает ровно ноль байт. Это просто пре-алоцированное место, куда файловая система может копировать измененные блоки (или наоборот, новые блоки, но не суть). И второй - теневая копия суть есть дифференциальный бекап. Все данные, которые вы изменили, не удаляются, а отправляются на хранение в этой зоне.

Где найти VSS

Обнаружить следы VSS можно двумя классическими способами: через GUI или в консоли. В зависимости от конкретной версии системы пути могут немного отличаться, но суть будет одинакова. Итак, есть у меня в лабе Windows Server 2019, и если сделать ПКМ на любом диске в проводнике, мы увидим два пункта: Configure Shadow Copies и Restore previous versions.

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

После того,как вы всё настроите на свой вкус, появляется смысл в пункте Restore previous versions. Чисто технически туда и до этого можно было зайти, однако внутри, скорее всего, будет только гнетущая пустота.

Но всё это баловство с графическим интерфейсом, и как мы знаем, до добра это не доводит, поэтому открываем powershell (или даже cmd, почему нет) - и там у нас имеется два варианта из коробки: vssadmin и diskshadow. Первая утилита есть практически на любой системе, начиная с WinXP/Win2003. Нет её только на Windows 8. По какой-то таинственной причине из восьмёрки вырезали инструменты управления теневыми копиями, но потом осознали свою неправоту и вернули всё на место. А вот diskshadow доступен только на серверных вариантах Windows. Это уже более продвинутый вариант vssadmin, позволяющий работать не только в интерактивном режиме, но и выполнять целые скрипты, написанные на понятном этому интерпретатору языке. Да и просто это более адекватный и поддающийся контролю инструмент.

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

Вот отличный пример: мы создали снимок в diskshadow и пытаемся удалить его с помощью vssadmin. Сам снимок мы видим, но он не в нашем контексте, поэтому сорян, у нас нет здесь власти.Вот отличный пример: мы создали снимок в diskshadow и пытаемся удалить его с помощью vssadmin. Сам снимок мы видим, но он не в нашем контексте, поэтому сорян, у нас нет здесь власти.

Технически ничего не мешает одновременно делать снимки с помощью vssadmin и diskshadow. Хотя есть вероятность, что получите сообщение типа Another shadow copy is in progress. Но это так, к слову пришлось. Не надо пытаться одновременно делать несколько снапшотов разными программами.

Как появился VSS

Итак, судя по написанному выше, всё просто: нам надо просто брать появляющиеся блоки и сохранять их куда-то в сторонку, чтобы при необходимости вынимать обратно. Сразу возникает первый вопрос: а что именно надо сохранять в нашем теневом хранилище? Ведь действительно, можно просто писать в него все приходящие новые блоки и сохранять в метаданные, на какое место они (блоки) должны были быть записаны. А можно поступить чуть сложнее и записывать новые блоки сразу на полагающееся им место, а в хранилище отправлять содержимое перезаписываемых блоков. Что лучше и как выбрать? На самом деле право на жизнь имеют оба варианта, и какой выбрать - зависит исключительно от воли вендора. Первый подход (redirect-on-write, RoW, если оперировать грамотными терминами) быстро пишется, но долго читается. Зато если надо откатиться на первоначальное состояние, это делается моментально - мы просто удаляем наше теневое хранилище. Второй подход (copy-on-write, CoW) пишется медленней, читается быстрее и моментально удаляет копии предыдущих состояний. VSS, к слову, придерживается парадигмы CoW, а в снапшотах VMware реализован RoW.

Но на самом деле этот вопрос не самый важный из тех, которые стоит себе задать перед тем, как начать перехватывать появляющиеся блоки и складывать их в сторонке. Главный вопрос - в какой именно момент надо осуществлять перехват?

Давайте рассмотрим хрестоматийную ситуацию с файлом базы данных. (И если у вас уже заскрипел песок на зубах, смело пропускайте следующие два абзаца.) Итак: у нас есть банальная SQL Server база данных в виде mdf файла, и тут к нам прилетает какой-то запрос. SQL, как порядочное приложение, начинает старательно вносить изменения в файл, а мы старательно перехватываем каждый новый блок данных падающих на диск и пишем в нашу теневую копию. Всё хорошо и здорово, но тут выключили свет. Потом свет включили, сервер запустили и мы даже базу восстановили из нашей теневой копии, но тут оказывается, что SQL не запускается. Говорит - база в не консистентном состоянии. Это значит следующее: во время нормальной работы завершение каждой транзакции помечается специальным флагом. Сервер его видит и знает, что всё хорошо. А тут сервер загружается, видит, что из его базы торчит какой-то кусок данных, флага нет и, следовательно, что с этим всем делать - он понятия не имеет. То ли удалить, то ли дописать, то ли ещё что-то. Но у нас тут не угадайка, а всё должно быть однозначно и консистентно. Поэтому он принимает решение выключиться, дабы не поломать базу ещё сильнее.

Хорошо, но как избежать подобных приключений? Отличным вариантом будет подождать, пока SQL сервер допишет свою транзакцию, пометит её как завершённую, и потом мы быстренько заберём все появившиеся новые блоки. Отличный вариант, который надо срочно реализовывать! Вот только есть небольшая проблема: до этого мы говорили про одно приложение и один файл, с которым оно работает. Научиться общаться с условным SQL Server много ума не надо, но что делать с остальными миллиардами существующих приложений? А что делать, в конце концов, с самой ОС, у которой внутри огромное количество своих процессов и открытых файлов? Вот примерно с такими проблемами и столкнулись учёные мужи из Microsoft, когда пришли к выводу, что надо реализовать некий общий интерфейс, через который можно будет сразу всем прокричать нечто вроде: Сейчас мы будем делать снапшот, так что быстренько сворачиваемся и сбрасываем буфера на диск! Приостанавливайте свою кипучую деятельность и приводите данные в консистентный вид!. Ну а назвать эту штуку они решили, как вы уже догадались, Volume Snapshot Service. Или просто VSS.

И тут можно воскликнуть - но ведь в Windows 2008 был представлен Kernel Transaction Manager! Это разве не то же самое? Он же как раз занимается тем, что приводит файлы на диске в консистентное состояние. А вот и нет! То есть да, KTM приводит, но отвечает только за дисковые операции, а что там происходит с приложениями - его мало волнует. А ведь многим из этих приложений важна не просто целостность файлов, но и что в них записано. Классический пример - это Exchange и Active Directory. И тут мы подошли к важной теме:

Как устроен VSS

Чтобы не прыгать с места в карьер громады страшных терминов и процессов, начнём с высокоуровневого описания. Поэтому ограничимся таким списком компонентов:

  • VSS Writer. В кириллическом простонародье известен как просто райтер, поэтому так и будем его называть в дальнейшем, вызывая праведный гнев ненавистников англицизмов.

    Райтер занимается тем, что выстраивает мостик взаимодействия между VSS подсистемой и конкретным приложением. Поэтому а) в любой системе их будет достаточно много (проверьте у себя с помощью vssadmin list writers) б) райтер всегда пишется поставщиком приложения, ибо кроме него никто не знает, что там и как должно происходить во время создания снапшота.

    Соответственно, райтер по своей сути выполняет роль регулировщика: сначала он говорит приложению подготовиться к снапшоту, затем даёт отмашку VSS сервису делать снапшот. Или не даёт, если приложение не смогло за установленный промежуток времени подготовить свои файлы.

    Также хочется отметить, что райтеры - это какие-то невероятно нежные ребята, которые зачастую ломаются без каких-либо внешних признаков. Поэтому если в выводе vssadmin list writers в поле State вы увидите что-то, отличающееся от Stable, это надо чинить, ибо сделать консистентный бекап, увы, не получится.

  • VSS Provider. Тот самый парень, который занимается созданием и управлением снапшотами. Известен тем, что бывает софтовый или хардовый. Список установленных в системе провайдеров можно посмотреть с помощью команды vssadmin lisrt providers. По дефолту, с системой идет Microsoft Software Shadow Copy provider. Он даже отлично и замечательно работает, но до тех пор, пока вы не подключите к системе брендовую СХД. Хорошие вендоры всегда снабжают свои железки управляющим софтом, в составе которого находится и родной провайдер к этой железяке. Благодаря этому можно уже делать всякие хитрые трюки, которые реализованы в вашем оборудовании, и именно поэтому мы в Veeam так гордимся списком интеграций с железом.

  • VSS Requestor. Участник процесса, который инициирует создание VSS снапшота или восстановление данных. Можно сказать, что реквестор - это бекапное приложение, которое общается с райтерами и провайдерами. Может показаться, что его роль незначительна, однако от грамотности реализации реквестора зависит качество получаемого результата. То есть VSS не будет за вас думать, что и в каком виде надо сделать. Чем более чёткие инструкции выдаст реквестор, тем более предсказуемым будет результат.

Как в итоге всё выглядит на самом высоком уровне: реквестор стучится в Volume Shadow Copy сервис, тот отдаёт команду райтерам предупредить приложения о надвигающемся снапшоте, райтеры рапортуют об успехе, а сервис отдаёт команду провайдерам делать снапшоты. О результатах докладывается реквестору.

Но на деле, очевидно, всё несколько сложнее. На первом шаге реквестор проверяет, что вообще есть в наличии и с кем предстоит общаться. Затем после составления списка райтеров он обращается к провайдеру, объясняя, что он хочет заснапшотить и где должен располагаться снапшот. Это называется SnapshotSet. В большинстве случаев он будет располагаться на том же вольюме, что и оригинальный диск. А меньшинство случаев - это те самые хардварные провайдеры, которые поставляются вместе с СХД. Для них нормой считается создавать отдельный вольюм для снапшота, который называется storage snapshot. А в определённых случаях можно так и вообще перемещать снапшот на другое физическое устройство, чтобы выкачивать данные уже оттуда, а не с прода. Без хардварных провайдеров сделать такое не выйдет.

Следом начинается стадия, именуемая Prepare for backup. На этом этапе мы должны уже не просто изучить метаданные райтеров, а запросить их реальные статусы и приготовиться к самой жаркой поре: все райтеры должы будут отработать один за другим. Причём каждый должен уложиться в отведённое ему время, которое по умолчанию равно 60 секундам. Так решили в Microsoft, забыв уточнить причины. Но есть ещё приложения-чемпионы, например, Exchange. Его авторы посчитали, что 20 секунд более чем достаточно, и остановились на таком лимите. А чем чревато невыполнение этого этапа, который в документации называется OnFreeze? Тем, что райтер вернёт сообщение об ошибке, и снапшот не будет сделан. После чего в интерфейсе Veeam появится одна из каноничных ошибок вроде VSSControl: Failed to freeze guest, wait timeout". Тут радует одно: в логах VSS всегда будет написано, какой именно райтер завалил задание. А по самим ошибкам уже столько KB написано, что вспоминать страшно. Но если вы вдруг сомневаетесь, то точно вам говорю - написанному в них можно смело верить. И если после всего получается, что у вас слишком медленное хранилище, и за отведённое время не получается сбросить все кэши на диск, ну, значит, так оно и есть. Физику не обманешь, а вот железо надо хоть иногда обновлять.

Но это был пессимистичный вариант (прошу понять меня правильно, но беды с VSS - это очень частная причина обращений в сапорт), а в оптимистичном можно начинать самый важный этап. Как только райтеры рапортуют, что всё, вся деятельность в системе заморожена, а кеши сброшены на диск, у нас есть десять(!!!) секунд на создание снапшота, после чего райтеры будут принудительно разморожены, и всё закрутится вновь. И можно сказать, что на этом процесс бекапа заканчивается, и всё что нужно - это просто импортировать наш снапшот и скачать его куда-то к себе, чтобы сохранить под семью замками. Однако есть одно важное Но - log truncate. Фундаментально это вообще не связанные операции и транкейт зависит только от бекапа логов, но как все мы понимаем - на пользовательском уровне эти вещи связаны в единый процесс. То есть, прежде чем выкачивать снапшот, надо не забыть выдать команду backup log, которая запустит операцию транкейта. И после этого совесть наша чиста.

Но что дальше происходит с данными? Если мы действительно используем какое-то приложение для бекапов, которое запустило весь этот процесс, дождалось его завершения и скачало данные в своё хранилище, то снимок можно просто удалить одной командой. Поскольку VSS пропагандирует CoW подход, то речь здесь действительно о банальном удалении нашей аллоцированной зоны, ведь все новые данные сразу пишутся на оригинальный диск. Это называется non-persistent shadow copy, и она не имеет никакого смысла без оригинального диска.

Чтобы пройти этот путь вручную, достаточно открыть консоль и набрать:

PS C:\Windows\system32> diskshadowMicrosoft DiskShadow version 1.0Copyright (C) 2013 Microsoft CorporationOn computer:  VEEAM,  17.05.2021 19:18:44DISKSHADOW> add volume c: # добавляем в задание диск СDISKSHADOW> create# создаём снапшотAlias VSS_SHADOW_1 for shadow ID {a1eef71e-247e-4580-99bc-ee62c42221d6} set as environment variable.Alias VSS_SHADOW_SET for shadow set ID {cc9fab4d-3e7d-44a5-9a4d-0df11dd7219c} set as environment variable.Querying all shadow copies with the shadow copy set ID {cc9fab4d-3e7d-44a5-9a4d-0df11dd7219c}        * Shadow copy ID = {a1eef71e-247e-4580-99bc-ee62c42221d6}               %VSS_SHADOW_1%                - Shadow copy set: {cc9fab4d-3e7d-44a5-9a4d-0df11dd7219c}       %VSS_SHADOW_SET%                - Original count of shadow copies = 1                - Original volume name: \\?\Volume{7fd0c79d-0000-0000-0000-602200000000}\ [C:\]                - Creation time: 17.05.2021 19:19:45                - Shadow copy device name: \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy2                - Originating machine: veeam.university.veeam.local                - Service machine: veeam.university.veeam.local                - Not exposed                - Provider ID: {b5946137-7b9f-4925-af80-51abd60b20d5}                - Attributes:  Auto_Release DifferentialNumber of shadow copies listed: 1

Здесь мы видим, что успешно создался снапшот со своим Shadow copy ID, и для удобства ему сразу присвоили алиас VSS_SHADOW_1. Этими данными вполне можно оперировать, если возникает такое желание. Однако не будем уходить в сторону и попробуем прочитать содержимое этого снимка. Для чего подмонтируем его в качестве диска.

DISKSHADOW> expose {a1eef71e-247e-4580-99bc-ee62c42221d6} Z:The shadow copy is a non-persistent shadow copy. Only persistent shadow copies can be exposed.

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

DISKSHADOW> delete shadows all # или только нужный IDDeleting shadow copy {a1eef71e-247e-4580-99bc-ee62c42221d6} on volume \\?\Volume{7fd0c79d-0000-0000-0000-602200000000}\ from provider {b5946137-7b9f-4925-af80-51abd60b20d5} [Attributes: 0x00420000]...Number of shadow copies deleted: 1

И начинаем всё заново, только теперь укажем, что нам нужна персистентная копия, чтобы мы могли использовать её как полноценный диск.

DISKSHADOW> add volume C:DISKSHADOW> set context persistent # вот этот моментDISKSHADOW> createAlias VSS_SHADOW_1 for shadow ID {346d896b-8722-4c01-bf01-0f38b9abe20a} set as environment variable.Alias VSS_SHADOW_SET for shadow set ID {785983be-e09d-4d2a-b8b7-a4f722899896} set as environment variable.Querying all shadow copies with the shadow copy set ID {785983be-e09d-4d2a-b8b7-a4f722899896}        * Shadow copy ID = {346d896b-8722-4c01-bf01-0f38b9abe20a}               %VSS_SHADOW_1%                - Shadow copy set: {785983be-e09d-4d2a-b8b7-a4f722899896}       %VSS_SHADOW_SET%                - Original count of shadow copies = 1                - Original volume name: \\?\Volume{7fd0c79d-0000-0000-0000-602200000000}\ [C:\]                - Creation time: 17.05.2021 19:38:45                - Shadow copy device name: \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy3                - Originating machine: veeam.university.veeam.local                - Service machine: veeam.university.veeam.local                - Not exposed                - Provider ID: {b5946137-7b9f-4925-af80-51abd60b20d5}                - Attributes:  No_Auto_Release Persistent DifferentialNumber of shadow copies listed: 1

Как мы видим: Attributes: No_Auto_Release Persistent Differential. Поэтому если теперь вы сделаете expose, то снапшот примаунтится как полноценный диск, по которому можно перемещаться и копировать с него файлы. Диск, само собой, виртуальный и состоит из блоков оригинального диска, плюс блоки изменившихся данных, читая которые, мы можем видеть состояние оригинального диска на момент снапшота. Всё просто.

Только учтите, пожалуйста, такой момент, если вдруг решите, что нашли святой грааль: в таком режиме нельзя занимать данными больше 50% места на диске. Один блок свыше - и всё, диск переполнился.

Что тут хочется ещё сказать, а вернее, спросить: если всё так просто, то почему же я говорю, что всё так сложно? Проблема в том, что, отдавая на боевом сервере команду vssadmin create shadow, мы, конечно, создаём какой-то снимок, но как себя будут чувствовать приложения после отката на этот снимок, мы предсказать не можем. Это не шутка: команда create признаёт наличие ошибок при выполнении как вариант нормы. Райтер не вернул вовремя Ок от приложения? Да кому это надо, го делать снапшот, я создал.

Поэтому когда за дело берётся настоящее бекапное приложение вроде Veeam Backup & Replication, то речь идёт не об одной команде, а о целой россыпи предварительных запросов, в результате которых формируется огромнейшая команда (это не метафора для красного словца, а реальность), в которой учитываются состояния райтеров и приложений на целевой системе, с жестким требованием соответствия всех статусов необходимым. Словом, количество мест, где что-то может пойти не так, вырастает на порядок. Ведь нам главное - не снапшот создать, закрыв глаза на сопутствующие потери, а гарантировать консистентность данных внутри него.

Как лечить VSS

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

Другая проблема - это железо. Помните про временные рамки для райтеров? Про десять секунд на снапшот? Для многих это ограничение становится проблемой из-за того, что СХД физически не успевает сделать требуемые действия за отведённое время. Как это лечится? А вот никак. Или покупаем более мощное железо, или ищем пути снижения нагрузки, чтобы операция была проведена за выделенный промежуток времени.

Если посмотрите одно из самых популярных KB1680: VSS Timeout when backing up Exchange VM, то легко обнаружите, что первые три шага для решения всех проблем с VSS - сделайте снапшот вручную и посмотрите чтобы это заняло менее 20 секунд, перезагрузитесь и попробуйте снизить нагрузку. Вот так и живём, да.

И что же делать, если VSS падает, в ивентах ничего нет, а понять, что происходит надо? Тут я могу порекомендовать три хороших статьи:

  • КВ от Veeam, посвящённое анализу поведения VSS с помощью diskshadow.

  • Другое KB от Veeam, посвящённое сбору информации с помощью vsstrace из Windows SDK. Но скажу сразу, это уже не для слабых духом.

  • И видео от моего коллеги, где он наглядно показывает, как работать с информацией из первых двух пунктов =) Рассказывает он действительно хорошо, но с непривычки голова у вас от объёма информации заболит, это я вам обещаю.

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

А на сегодня всё. Я и так хотел кратенько, но получилось больше десяти страниц текста. Поэтому самое время закругляться. Если хочется раскрытия какой-то другой темы или углубиться в детали VSS, то обязательно пишите об этом в комментариях.

Подробнее..

Как мы запустили документооборот в Telegram и что из этого вышло? Да, это не сон

24.05.2021 12:21:25 | Автор: admin

Разбираем аргументы за и против. В конце также можно ознакомиться с моим мнением на этот счет.

С чего все начиналось?

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

Немного обо мне: я Python разработчик, архитектор, тимлид. В программировании с 2009 года. Ранее опубликовал эту статью на vc.ru.

В реализации проекта мне помогал аналитик от заказчика, и в общем-то всё.

Итак, к кейсу

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

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

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

Как решить проблему потери времени? У сотрудника должна быть возможность коннектиться с CRM-системой с планшета или телефона.

Как осуществить задуманное?

Выход нашёлся быстро: создать чат-бот в Telegram.

И на это решение можно посмотреть с двух сторон: с позиции управленцев и со стороны айтишников.

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

Если рассуждать со стороны управленцев, соединение CRM-системы с чат-ботом Telegram значительно снижает энергозатраты и финансовые расходы компании. И вот, почему:

  • Не нужно обучать большой штат новым программам-интеграторам CRM с телефоном.

  • Тем более, стоимость таких программ значительно выше, чем стоимость написания и поддержания работоспособности чат-бота для Telegram.

  • Это удобно. Сейчас у каждого есть возможность скачать Telegram, который не занимает много места в памяти телефона.

  • Работает Telegram-бот действительно быстрее, чем сложная программа. Кроме того, чат-бот помогает сотруднику сориентироваться во внутреннем документообороте фирмы.


Но со стороны безопасности и сохранности данных такое внедрение в электронный документооборот крупной компании нужно считать неприемлемым. Здесь на арену выходят возможные доводы IT-отдела.

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

  • Если изменить процесс документооборота, например, ввести отправку редактированных вариантов, то решение рассыпается. В таком случае сотруднику необходимо будет сначала отредактировать документ, а потом отправить его в чат с ботом.

С точки зрения офисного сотрудника это легко выполнимая задача. А со стороны полевого человека, это сильно усложняет процесс работы с документами.

  • Ещё один весомый аргумент: данные будут храниться в разных системах. Telegram-бот может быть напрямую привязан к CRM или ERP-системе, но в большинстве случаев он имеет свое хранилище, в котором агрегирует данные и обрабатывает их.

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

А что я думаю по этому поводу?

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

Тем более, если говорить об удобстве главных героев этой эпопеи - полевых работниках, то загрузить документ и отправить его на дальнейшее согласование, получить нужное уведомление гораздо проще через бот в Telegram, чем через специализированную программу, типа 1C, Диадок и т.д.

По моему мнению, идея с созданием чат-бота в Telegram является довольно простой с точки зрения использования и реализации. Да, он имеет интеграции с другими системами, но мы решили проблему удобства и оперативности получения информации.

Даже удивительно, почему другие компании не используют подобные методы. А может и использует, кто их знает?

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

О технической стороне вопроса

Идея была реализована на основе Telegram API на вебхуках. Для разработки был использован любимый python, данные хранятся на базе postgresql. Для ускорения работы и асинхронности задач применили связку redis + celery, в качестве серверной операционной системы использована Ubuntu 18 Server.

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

А вы на стороне программистов или управленцев? Делитесь своим мнением, задавайте вопросы!

Подробнее..

Может поменять способ хранения?

24.05.2021 20:06:11 | Автор: admin

Собрались однажды 2 разработчика. И нужно было им новую HTTP API реализовать для игрового магазина. Дошло дело до выбора БД, которую стоит применить в проекте:

- Слушай, а как мы выберем? Реляционную БД использовать или NoSQL. В частности, может нужна документоориентированная?

- Сперва нужно понять какие данные будут в нашей предметной области!

- Да, вот я уже набросал схемку:

Для построения каталога нам потребуются все данные У каждой игры свой каталог, отличать будем по game_id.

- Выглядит так, что у нас уже есть четко описанная структурированная модель, да и опыт использования MySQL есть в компании. Предлагаю использовать его!


И реализовали разработчики успешно свою задумку. Аккуратно нормализовали данные, использовали ORM для работы с БД из приложения. Написали красивый и аккуратный код.

Начали интегрироваться партнеры, и тут начались проблемы Оказывается, API работает очень медленно и совсем не держит нагрузки! Масштабирование дает смехотворный прирост, подключение кэшей всевозможных уровней дает профит, но зависимость запросов от параметров пользователей (сегментирование и атрибутирование) снижают его практически до ноля.

Корнем проблемы являлось большое (очень) количество запросов к БД - на каждое отношение между сущностями ORM генерировала дополнительный запрос.

Разработчики опустили руки и приуныли. Что же делать? Повезло им, ведь нашли они мудрость, увековеченную на бумажном носителе (милая книга с кабанчиком от Клеппмана).

А книга и порекомендовала еще раз внимательно взглянуть на свою предметную область... Ведь отношения между сущностями образуют дерево! А дерево можно уместить в одном документе (или представить с помощью одного JSON), что позволит избежать такого количества запросов.

Вооружились идеей разработчики и просто сериализовали сущность в JSON и сложили в 1 столбец MySQL (+ несколько генерируемых столбцов с индексами, для поиска):

95 перцентиль уменьшилась более чем в 3 раза, пропорционально увеличился и выдаваемый rps одного инстанса приложения.

А ведь просто поменяли формат хранимых данных, никак не затрагивая инфраструктуру и конфигурацию приложения

Какой вывод можно сделать?

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

  • Важнее понимать какие концепты помогут достичь требуемого качества, а затем выбирать технологии, реализующие их, нежели просто выбирать между технологиями

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

Подробнее..

Recovery mode Как ускорить сайт в 4 раза, просто перенастроив сервер

02.06.2021 12:04:43 | Автор: admin

Если вы работаете с сайтом, который постепенно растет, - увеличивается количество товаров, трафик с рекламы - то рано или поздно придется перейти в режим работы highload, высоких нагрузок на сервер. Но что делать, если ваш сайт не растет, а сервер все чаще не выдерживает, и происходит блокировка данных? Именно с этой проблемой мы столкнулись, дорабатывая сайт для интернет-магазина светового оборудования с ассортиментом более чем 100 000 товаров.

Исходная ситуация

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

Поиск проблемы

Мы провели аудит настроек сервера и сайта, разделив работы на два этапа: анализ back-end и front-end, и обнаружили низкую скорость загрузки страниц на back-ende - порядка 80 секунд на самых посещаемых страницах, что в итоге приводило к существенному снижению конверсии.

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

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

Решение

Шаг 1. Настройка баз данных

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

Шаг 2. Смена типа хранения на InnoDB

Почему мы выбрали InnoDB?

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

Главное преимущество InnoDB заключается в скорости работы при выполнении запроса к базе InnoDB происходит блокировка только строки, при выполнении же запроса к базе MyISAM блокируется вся таблица. Дело в том, что пока запрос не будет выполнен, никакие другие обращения к таблице/строке будут невозможны. А поскольку строки значительно меньше целых таблиц, InnoDB обрабатывает запросы быстрее.

Также была произведена оптимизация работы самой базы данных InnoDB. Например, были оптимизированы параметры:

# InnoDB parameters

innodb_file_per_table

innodb_flush_log_at_trx_commit

innodb_flush_method

innodb_buffer_pool_size

innodb_log_file_size

innodb_buffer_pool_instances

innodb_file_format

innodb_locks_unsafe_for_binlog

innodb_autoinc_lock_mode

transaction-isolation

innodb-data-file-path

innodb_log_buffer_size

innodb_io_capacity

innodb_io_capacity_max

innodb_checksum_algorithm

innodb_read_io_threads

innodb_write_io_threads

Промежуточные результаты

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

Это в свою очередь привело к уменьшению потребляемой оперативной памяти.

Шаг 3. Перенастройка Nginx и установка модулей кэширования brotli, pagespeed, proxy_buffering

Nginx позиционируется как простой, быстрый и надежный сервер, неперегруженный функциями. Уже длительное время Nginx обслуживает серверы многих высоконагруженных российских сайтов, например, Яндекс, Mail.Ru, ВКонтакте и Рамблер. Для улучшения производительности при использовании дополнительных серверов, Nginx поддерживает буферизацию (proxy_buffering) и кеширование (proxy_cache), чем мы и воспользовались.

Не обошлось и без курьезов настроек Nginx. У клиента был обычный интернет-магазин с товарами, тогда как настройки буферизации, которые мы обнаружили во время аудита, позволяли ему быть чуть ли ни стриминговым сервисом. Мы существенно уменьшили значения в параметре client_max_body_size, что в совокупности с перенастройкой Nginx еще больше снизило потребление памяти.

Шаг 4. Оптимизация настроек PHP-FPM и Memcache и отключение Apache

PHP-FPM нередко используется в паре с веб-сервером Nginx. Последний обрабатывает статические данные, а обработку скриптов отдает PHP-FPM. Такая реализация работает быстрее, чем распространенная модель Nginx + Apache.

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

Необходимым шагом стал перевод работы PHP-FPM на unix socket. Зачем это понадобилось? Nginx сам по себе довольно быстрый веб-сервер, однако самостоятельно он не может обрабатывать скрипты. Для этого необходим бэкенд в виде PHP-FPM. Чтобы вся эта связка работала без потери скорости, мы использовали unix socket способ подключения к PHP-FPM, позволяющий избегать сетевые запросы и дающий значительный прирост в скорости работы сайта.

Результаты работ

1. Время отклика главной страницы уменьшилось с 24 секунд до чуть более 3 секунд, внутренних до 5-8 сек.

2. Уменьшилось потребление серверных ресурсов.

3. Стабилизировалось поведение сервера - он перестал зависать.

4. Глубина просмотров увеличилась на 30%, и как следствие, это дало улучшение в SЕО, а также последующих продаж: растут поведенческие показатели => растут позиции сайта в выдаче => растет трафик => растут продажи.

5. Клиенту были даны рекомендации по оптимизации front-end части сайта для ускорения работы сайта. Например:

  • оптимизировать графики и настройку выдачи изображений в формате webp;

  • настроить lazyload-загрузки данных;

  • вынести все некритические для отображения страницы скрипты в конец страницы.

Вывод

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

Подробнее..

Перевод Эксклюзив США по словам чиновника, взломы с помощью программ-вымогателей надо приравнять к терроризму

04.06.2021 16:20:58 | Автор: admin
image

Вашингтон (Рейтер) Министерство юстиции США считает расследования атак с использованием программ-вымогателей таким же важным, как и терроризм. После взлома Colonial Pipeline и увеличения ущерба, нанесенного киберпреступниками, сообщил Reuters высокопоставленный чиновник ведомства.

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

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

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

По словам представителей компании, Colonial Pipeline решила заплатить хакерам, вторгшимся в их системы, почти 5 миллионов долларов за восстановление доступа.
В руководстве Министерства юстиции конкретно упоминается Colonial как пример растущей угрозы, которую представляют для страны программы-вымогатели и цифровое вымогательство.

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

По словам официальных лиц США, решение Министерства юстиции о включении программ-вымогателей в этот специальный процесс демонстрирует, как проблема становится приоритетной.

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

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

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

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

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

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

Хакеры создают, покупают и сдают в аренду бот-сети для совершения киберпреступлений, начиная от рекламного мошенничества и заканчивая крупными кибератаками.

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

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

Что нам стоит загрузить JSON в Data Platform

16.06.2021 16:13:28 | Автор: admin

Всем привет!

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

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

Схема из прошлой нашей статьи.Схема из прошлой нашей статьи.

Напомним, что в нашей компании более 350 реляционных баз данных. Естественно, не все они уникальны и многие представляют собой по сути разные экземпляры одной и той же системы, установленной во всех магазинах торговой сети, но все же зоопарк разнообразия присутствует. Поэтому без какого-либо Frameworkа, упрощающего и ускоряющего интеграцию источников в Data Platform, не обойтись.

Общая схема доставки данных из источников в ODS-слой Greenplum посредством разработанного нами frameworkа приведена ниже:

Общая схема доставки данных в ODS-слой Greenplum Общая схема доставки данных в ODS-слой Greenplum
  1. Данные из систем-источников пишутся в Kafka в AVRO-формате, обрабатываются в режиме реального времени Apache NiFi, который сохраняет их в формате parquet на S3.

  2. Затем эти файлы с сырыми данными с помощью Sparkа обрабатываются в два этапа:

    1. Compaction на данном этапе выполняется объединение для снижения количества выходных файлов с целью оптимизации записи и последующего чтения (то есть несколько более мелких файлов объединяются в несколько файлов побольше), а также производится дедубликация данных: простой distinct() и затем coalesce(). Результат сохраняется на S3. Эти файлы используются затем для parsing'а , а также являются своеобразным архивом сырых необработанных данных в формате как есть;

    2. Parsing на этой фазе производится разбор входных данных и сохранение их в плоские структуры согласно маппингу, описанному в метаданных. В общем случае из одного входного файла можно получить на выходе несколько плоских структур, которые в виде сжатых (как правило gzip) CSV-файлов сохраняются на S3.

  3. Заключительный этап загрузка данных CSV-файлов в ODS-слой хранилища: создается временная external table над данными в S3 через PXF S3 connector, после чего данные уже простым pgsql переливаются в таблицы ODS-слоя Greenplum

  4. Все это оркестрируется с помощью Airflow.

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

  • создать в ODS-слое Хранилища таблицы-приемники данных;

  • в репозитории метаданных в Git согласно принятым стандартам прописать в виде отдельных YAML-файлов:

    • общие настройки источника (такие как: расписание загрузки, входной и выходной формат файлов с данными, S3-бакет, имя сервисного пользователя, имя и email владельца для нотификации в случае сбоя загрузки и т.п.);

    • маппинг данных объектов источника на таблицы слоя ODS (при этом поддерживаются как плоские, так и вложенные структуры и массивы, а также есть возможность данные из одного объекта раскладывать в ODS-слое по нескольким таблицам). То есть описать, как необходимо сложную вложенную структуру разложить в плоские таблицы;

До недавнего времени такой подход удовлетворял текущие наши потребности, но количество и разнообразие источников данных растет. У нас стали появляться источники, которые не являются реляционными базами данных, а генерируют данные в виде потока JSON-объектов. Кроме того на горизонте уже маячила интеграция источника, который под собой имел MongoDB и поэтому будет использовать MongoDB Kafka source connector для записи данных в Kafka. Поэтому остро встала необходимость доработки нашего frameworkа для поддержки такого сценария. Хотелось, чтобы данные источника сразу попадали на S3 в формате JSON - то есть в формате "как есть", без лишнего шага конвертации в parquet посредством Apache NiFi.

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

df = spark.read.format(in_format) \               .options(**in_options) \               .load(path) \               .distinct()    new_df = df.coalesce(div)new_df.write.mode("overwrite") \             .format(out_format) \            .options(**out_options) \            .save(path)

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

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

рассматривать файлы с JSON-объектами как DataFrame с одной колонкой, содержащей весь JSON-объект.

Попробуем сделать это. Допустим, мы имеем следующий файл данных:

file1:

{productId: 1, productName: ProductName 1, tags: [tag 1, tag 2], dimensions: {length: 10, width: 12, height: 12.5}}{productId: 2, price: 10.01, tags: [tag 1, tag 2], dimensions: {length: 10, width: 12, height: 12.5}}

Обратите внимание на формат этого файла. Это файл с JSON-объектами, где 1 строка = 1 объект. Оставаясь, по сути, JSON-ом, он при этом не пройдет синтаксическую JSON-валидацию. Именно в таком виде мы сохраняем JSON-данные на S3 (есть специальная "галочка в процессоре Apache NiFi).

Прочитаем файл предлагаемым способом:

# Читаем данныеdf = spark.read \          .format("csv") \          .option("sep", "\a") \          .load("file1.json")# Схема получившегося DataFramedf.printSchema()root |-- _c0: string (nullable = true)# Сами данныеdf.show()+--------------------+|                 _c0|+--------------------+|{"productId": 1, ...||{"productId": 2, ...|+--------------------+

То есть мы тут читаем JSON как обычный CSV, указывая разделитель, который никогда заведомо не встретится в наших данных. Например, Bell character. В итоге мы получим DataFrame из одного поля, к которому можно будет также применить dicstinct() и затем coalesce(), то есть менять существующий код не потребуется. Нам остается только определить опции в зависимости от формата:

# Для parquetin_format = "parquet"in_options = {}# Для JSONin_format = "csv"in_options = {"sep": "\a"}

Ну и при сохранении этого же DataFrame обратно на S3 в зависимости от формата данных опять применяем разные опции:

df.write.mode("overwrite") \           .format(out_format) \.options(**out_options) \  .save(path)  # для JSON     out_format = "text" out_options = {"compression": "gzip"}  # для parquet   out_format = input_format out_options = {"compression": "snappy"}

Следующей точкой доработки был шаг Parsing. В принципе, ничего сложного, если бы задача при этом упиралась в одну маленькую деталь: JSON -файл, в отличии от parquet, не содержит в себе схему данных. Для разовой загрузки это не является проблемой, так как при чтении JSON-файла Spark умеет сам определять схему, и даже в случае, если файл содержит несколько JSON-объектов с немного отличающимся набором полей, корректно выполнит mergeSchema. Но для регулярного процесса мы не могли уповать на это. Банально может случиться так, что во всех записях какого-то файла с данными может не оказаться некоего поля field_1, так как, например, в источнике оно заполняется не во всех случаях. Тогда в получившемся Spark DataFrame вообще не окажется этого поля, и наш Parsing, построенный на метаданных, просто-напросто упадет с ошибкой из-за того, что не найдет прописанное в маппинге поле.

Проиллюстрирую. Допустим,у нас есть два файла из одного источника со следующим наполнением:

file1 (тот же что и в примере выше):

{productId: 1, productName: ProductName 1, tags: [tag 1, tag 2], dimensions: {length: 10, width: 12, height: 12.5}}{productId: 2, price: 10.01, tags: [tag 1, tag 2], dimensions: {length: 10, width: 12, height: 12.5}}

file2:

{productId: 3, productName: ProductName 3, dimensions: {length: 10, width: 12, height: 12.5, package: [10, 20.5, 30]}}

Теперь прочитаем Sparkом их и посмотрим данные и схемы получившихся DataFrame:

df = spark.read \          .format("json") \          .option("multiline", "false") \          .load(path)df.printSchema()df.show()

Первый файл (схема и данные):

root |-- dimensions: struct (nullable = true) |    |-- height: double (nullable = true) |    |-- length: long (nullable = true) |    |-- width: long (nullable = true) |-- price: double (nullable = true) |-- productId: long (nullable = true) |-- productName: string (nullable = true) |-- tags: array (nullable = true) |    |-- element: string (containsNull = true)+--------------+-----+---------+-------------+--------------+|    dimensions|price|productId|  productName|          tags|+--------------+-----+---------+-------------+--------------+|[12.5, 10, 12]| null|        1|ProductName 1|[tag 1, tag 2]||[12.5, 10, 12]|10.01|        2|         null|[tag 1, tag 2]|+--------------+-----+---------+-------------+--------------+

Второй файл (схема и данные):

root |-- dimensions: struct (nullable = true) |    |-- height: double (nullable = true) |    |-- length: long (nullable = true) |    |-- package: array (nullable = true) |    |    |-- element: double (containsNull = true) |    |-- width: long (nullable = true) |-- productId: long (nullable = true) |-- productName: string (nullable = true)+--------------------+---------+-------------+|          dimensions|productId|  productName|+--------------------+---------+-------------+|[12.5, 10, [10.0,...|        3|ProductName 3|+--------------------+---------+-------------+

Как видно, Spark корректно выстроил схему отдельно для каждого файла. Если в какой-либо записи не было обнаружено поля, имеющегося в другой, то в DataFrame мы видим корректное проставление null (поля price и productName для первого файла).

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

root |-- price: double (nullable = true) |-- productId: long (nullable = true) |-- productName: string (nullable = true)

а во входных данных у нас присутствуют только файлы а-ля file2, где поля price нет ни у одной записи, то Spark упадет с ошибкой, так как не найдет поля price для формирования выходного DataFrame. С parquet-файлами такой проблемы как правило не возникает, так как сам parquet-файл генерируется из AVRO, который уже содержит полную схему данных и, соответственно, эта полная схема есть и в parquet-файле.

Еще надо отметить, что, естественно, мы хотели по максимум переиспользовать уже существующий и зарекомендовавший себя код нашего frameworkа, а не городить какую-то полностью отдельную ветку для обработки JSONов то есть все изменения хотелось сделать на этапе чтения JSON-файлов с S3.

Таким образом очевидно, что для корректной загрузки данных из JSON-файлов необходимо предопределить схему JSON-файла с данными и читать файлы уже с применением этой схемы. Тогда у нас даже если в JSONе нет какого-то поля, то в самом DataFrame это поле будет, но его значение подставится как null:

df = spark.read \          .format("json") \          .option("multiline","false") \          .schema(df_schema) \          .load(path)

Первая мысль была использовать для хранения схемы имеющийся сервис метаданных - то есть описать схему в YAML-формате и сохранить в имеющемся репозитории. Но с учетом того, что все данные источников у нас проходят через Kafka, решили, что логично для хранения схем использовать имеющийся Kafka Schema Registry, а схему хранить в стандартном для JSON формате (другой формат, кстати говоря, Kafka Schema Registry не позволил бы хранить).

В общем, вырисовывалась следующая реализация:

  • Читаем из Kafka Schema Registry схему

  • Импортируем ее в pyspark.sql.types.StructType что-то типа такого:

# 1. получаем через Kafka Schema Registry REST API схему данных # 2. записываем ее в переменную schema и далее:df_schema = StructType.fromJson(schema)
  • Ну и с помощью полученной схемы читаем JSON-файлы

Звучит хорошо, если бы Давайте посмотрим на формат JSON-схемы, понятной Sparkу. Пусть имеем простой JSON из file2 выше. Посмотреть его схему в формате JSON можно, выполнив:

df.schema.json()  
Получившаяся схема
{    "fields":    [        {            "metadata": {},            "name": "dimensions",            "nullable": true,            "type":            {                "fields":                [                    {"metadata":{},"name":"height","nullable":true,"type":"double"},                    {"metadata":{},"name":"length","nullable":true,"type":"long"},                    {"metadata":{},"name":"width","nullable":true,"type":"long"}                ],                "type": "struct"            }        },        {            "metadata": {},            "name": "price",            "nullable": true,            "type": "double"        },        {            "metadata": {},            "name": "productId",            "nullable": true,            "type": "long"        },        {            "metadata": {},            "name": "productName",            "nullable": true,            "type": "string"        },        {            "metadata": {},            "name": "tags",            "nullable": true,            "type":            {                "containsNull": true,                "elementType": "string",                "type": "array"            }        }    ],    "type": "struct"}

Как видно, это совсем не стандартный формат JSON-схемы.

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

как сохранить схему уже прочитанного DataFrame в JSON, затем использовать повторно

либо на репозиторий https://github.com/zalando-incubator/spark-json-schema, который нам бы подошел, если мы использовали Scala, а не pySpark

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

К счастью, у нас уже был один источник, генерирующий данные в формате JSON. Как временное решение схема его интеграции в DataPlatform была незамысловата: NiFi читал данные из Kafka, преобразовывал их в parquet, использую прибитую гвоздями в NiFi схему в формате AVRO-schema, и складывал на S3. Схема данных была действительно непростой и с кучей вложенных структур и нескольких десятков полей - неплохой тест-кейс в общем-то:

Посмотреть длинную портянку, если кому интересно :)
root |-- taskId: string (nullable = true) |-- extOrderId: string (nullable = true) |-- taskStatus: string (nullable = true) |-- taskControlStatus: string (nullable = true) |-- documentVersion: long (nullable = true) |-- buId: long (nullable = true) |-- storeId: long (nullable = true) |-- priority: string (nullable = true) |-- created: struct (nullable = true) |    |-- createdBy: string (nullable = true) |    |-- created: string (nullable = true) |-- lastUpdateInformation: struct (nullable = true) |    |-- updatedBy: string (nullable = true) |    |-- updated: string (nullable = true) |-- customerId: string (nullable = true) |-- employeeId: string (nullable = true) |-- pointOfGiveAway: struct (nullable = true) |    |-- selected: string (nullable = true) |    |-- available: array (nullable = true) |    |    |-- element: string (containsNull = true) |-- dateOfGiveAway: string (nullable = true) |-- dateOfGiveAwayEnd: string (nullable = true) |-- pickingDeadline: string (nullable = true) |-- storageLocation: string (nullable = true) |-- currentStorageLocations: array (nullable = true) |    |-- element: string (containsNull = true) |-- customerType: string (nullable = true) |-- comment: string (nullable = true) |-- totalAmount: double (nullable = true) |-- currency: string (nullable = true) |-- stockDecrease: boolean (nullable = true) |-- offline: boolean (nullable = true) |-- trackId: string (nullable = true) |-- transportationType: string (nullable = true) |-- stockRebook: boolean (nullable = true) |-- notificationStatus: string (nullable = true) |-- lines: array (nullable = true) |    |-- element: struct (containsNull = true) |    |    |-- lineId: string (nullable = true) |    |    |-- extOrderLineId: string (nullable = true) |    |    |-- productId: string (nullable = true) |    |    |-- lineStatus: string (nullable = true) |    |    |-- lineControlStatus: string (nullable = true) |    |    |-- orderedQuantity: double (nullable = true) |    |    |-- confirmedQuantity: double (nullable = true) |    |    |-- assignedQuantity: double (nullable = true) |    |    |-- pickedQuantity: double (nullable = true) |    |    |-- controlledQuantity: double (nullable = true) |    |    |-- allowedForGiveAwayQuantity: double (nullable = true) |    |    |-- givenAwayQuantity: double (nullable = true) |    |    |-- returnedQuantity: double (nullable = true) |    |    |-- sellingScheme: string (nullable = true) |    |    |-- stockSource: string (nullable = true) |    |    |-- productPrice: double (nullable = true) |    |    |-- lineAmount: double (nullable = true) |    |    |-- currency: string (nullable = true) |    |    |-- markingFlag: string (nullable = true) |    |    |-- operations: array (nullable = true) |    |    |    |-- element: struct (containsNull = true) |    |    |    |    |-- operationId: string (nullable = true) |    |    |    |    |-- type: string (nullable = true) |    |    |    |    |-- reason: string (nullable = true) |    |    |    |    |-- quantity: double (nullable = true) |    |    |    |    |-- dmCodes: array (nullable = true) |    |    |    |    |    |-- element: string (containsNull = true) |    |    |    |    |-- timeStamp: string (nullable = true) |    |    |    |    |-- updatedBy: string (nullable = true) |    |    |-- source: array (nullable = true) |    |    |    |-- element: struct (containsNull = true) |    |    |    |    |-- type: string (nullable = true) |    |    |    |    |-- items: array (nullable = true) |    |    |    |    |    |-- element: struct (containsNull = true) |    |    |    |    |    |    |-- assignedQuantity: double (nullable = true) |-- linkedObjects: array (nullable = true) |    |-- element: struct (containsNull = true) |    |    |-- objectType: string (nullable = true) |    |    |-- objectId: string (nullable = true) |    |    |-- objectStatus: string (nullable = true) |    |    |-- objectLines: array (nullable = true) |    |    |    |-- element: struct (containsNull = true) |    |    |    |    |-- objectLineId: string (nullable = true) |    |    |    |    |-- taskLineId: string (nullable = true)

Естественно, я не захотел перебивать руками захардкоженную схему, а воспользовался одним из многочисленных онлайн-конвертеров, позволяющих из Avro-схемы сделать JSON-схему. И тут меня ждал неприятный сюрприз: все перепробованные мною конвертеры на выходе использовали гораздо больше синтаксических конструкций, чем понимала первая версия конвертера. Дополнительно пришло осознание, что также как и я, наши пользователи (а для нас пользователями в данном контексте являются владельцы источников данных) с большой вероятностью могут использовать подобные конвертеры для того, чтобы получить JSON-схему, которую надо зарегистрировать в Kafka Schema Registry, из того, что у них есть.

В результате наш SparkJsonSchemaConverter был доработан появилась поддержка более сложных конструкций, таких как definitions, refs (только внутренние) и oneOf. Сам же парсер был оформлен уже в отдельный класс, который сразу собирал на основании JSON-схемы объект pyspark.sql.types.StructType

У нас почти сразу же родилась мысль, что хорошо бы было поделиться им с сообществом, так как мы в Леруа Мерлен сами активно используем продукты Open Source, созданные и поддерживаемые энтузиастами со всего мира, и хотим не просто их использовать, но и контрибьютить обратно, участвуя в разработке Open Source продуктов и поддерживая сообщество. В настоящий момент мы решаем внутренние орг.вопросы по схеме выкладывания данного конвертера в Open Source и, уверен, что в ближайшее время поделимся с сообществом этой наработкой!

В итоге благодаря написанному SparkJsonSchemaConverterу доработка шага Parsing свелась только к небольшому тюнингу чтения данных с S3: в зависимости от формата входных данных источника (получаем из сервиса метаданных) читаем файлы с S3 немного по-разному:

# Для JSONdf = spark.read.format(in_format)\            .option("multiline", "false")\            .schema(json_schema) \            .load(path)# Для parquet:df = spark.read.format(in_format)\            .load(path)

А дальше отрабатывает уже существующий код, раскрывающий все вложенные структуры согласно маппингу и сохраняющий данные DataFrameа в несколько плоских CSV-файлов.

В итоге мы смогли при относительном минимуме внесенных изменений в код текущего frameworkа добавить в него поддержку интеграции в нашу Data Platform JSON-источников данных. И результат нашей работы уже заметен:

  • Всего через месяц после внедрения доработки у нас на ПРОДе проинтегрировано 4 новых JSON-источника!

  • Все текущие интеграции даже не заметили расширения функционала frameworkа, а значит, мы точно ничего не сломали произведенной доработкой.

Подробнее..

Дата-центрическая архитектура волшебная пуля от интеграционных проблем

16.06.2021 18:22:08 | Автор: admin

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

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

А что, если найдется способ избавиться от всех интеграционных проблем разом? Такая "волшебная пуля" существует, и называется она - дата-центрическая архитектура. Ее основная идея состоит в том, чтобы сделать центральным элементом корпоративной ИТ-архитектуры не бизнес-приложения, а данные. Этот принцип изложен в Манифесте дата-центрической архитектуры.

Представьте, что в компании существует единое виртуальное хранилище данных, в котором каждый бизнес-объект или событие существует в единственном экземпляре. Для наглядности можно вообразить, что идея системы MDM (Master Data Management) доведена до логически полного воплощения, и именно MDM является хранилищем всех корпоративных данных; бизнес-приложения не имеют собственных СУБД и работают только с объектами данных из MDM. Преимущества такой архитектуры очевидны:

  • Раз и навсегда отменяется необходимость в интеграционных процедурах.

  • Снижаются затраты на хранение данных за счет избавления от множества копий каждого бизнес-объекта в разных системах.

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

  • Повышается качество данных за счет избавления от неполных, не актуальных представлений бизнес-объектов.

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

"Это какая-то фантастика", скажут некоторые. Нельзя же выбросить все существующие бизнес-приложения и начать с чистого листа, вывернув наизнанку всю корпоративную ИТ-архитектуру?

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

Итак, если на первом этапе построить платформу, работающую в режиме логической витрины данных, способную предоставить "прозрачный" доступ ко всем (или хотя бы ко многим) данным из существующих корпоративных систем, а затем постепенно мигрировать эти данные в виртуальное корпоративное облако - плавный переход к дата-центрической архитектуре будет успешным. Уже на первом этапе появится возможность создавать новые, дата-центрические приложения.

Чем такой подход отличается от создания "обычного" корпоративного облака данных (corporate data cloud) или озера данных (data lake)? Прежде всего - методологией использования платформы, особым вниманием к структуре данных и некоторой функциональной спецификой. Если обычный data lake часто представляет собой коллекцию наборов данных, созданных кем-то для решения конкретных задач и заведомо содержащих копию уже существующей где-то информации, то для дата-центрической архитектуры принципиально соблюдение принципа "один объект в реальном мире - один объект данных". И никаких физических срезов, по крайней мере персистентных...

Управление структурой корпоративных данных - отдельный и очень важный вопрос, которому часто уделяется слишком мало внимания. Задача описания структуры всей информации, с которой работает предприятие, может показаться настолько сложной, что никто и не думает ее решать; вместо этого создается множество структур данных под конкретные бизнес-задачи, что влечет очевидные последствия. Мы утверждаем, что эта задача может и должна решаться; она успешно решается на практике в конкретных проектах, нужно лишь использовать подходящие для этого технологии. Одним из возможных вариантов является описание структуры корпоративной информации с помощью онтологий (см. спецификацию OWL консорциума W3C).

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

Когда вся корпоративная информация становится структурированной и логически связной, она приобретает свойства корпоративного графа знаний (corporate knowledge graph), который открывает предприятию новый уровень аналитических возможностей и позволяет гораздо эффективнее монетизировать накопленную информацию.

Какими функциональными свойствами должна обладать платформа, являющаяся ядром дата-центрической архитектуры? Она должна:

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

  • Хранить непрерывную историю модели (структуры) данных. Структура данных столь же изменчива, как и сами данные. Платформа должна иметь возможность представлять объекты данных в соответствии с любой версией структуры. Структура должна формально описывать смысл каждого элемента данных.

  • Поддерживать множество API для работы с данными, включая REST, GraphQL, SPARQL.

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

  • Иметь развитые инструменты управления доступом к данным и защиты конфиденциальной информации.

  • Поддерживать инструменты прослеживания происхождения данных (data provenance), контроля их качества (data quality), описания степени доверия к данным.

Построение подобных платформ с использованием онтологических моделей открывает и другие возможности. В онтологической модели можно описать в машинно-читаемой и автоматически исполняемой форме не только структуру данных, но и алгоритмы их обработки - правила контроля целостности, арифметических вычислений, дополнения информации (см. спецификации SHACL и SHACL Advanced Functions). Это позволяет по-новому взглянуть и на принцип low code: если в единой корпоративной платформе управления данными хранятся не только данные и описание их структуры, но и машинно-читаемое описание алгоритмов обработки данных, то новые бизнес-приложения, ориентированные на использование таких описаний, станут еще гибче и смогут изменять свое поведение "на лету" без вмешательства не только в код, но и в настройки приложений.

Платформы, отвечающие таким требованиям, уже существуют и применяются и на российском, и на зарубежном рынке.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru