2018-04-22

О DynamoDB

Мы — в облаках. Где в облаке взять базу данных?
Можно запустить самую обычную виртуалку, и водрузить на неё какой-нибудь PostgreSQL. Вполне рабочий вариант. Особенно, если это не банальный PostgreSQL, а какая-нибудь редкая БД, которая ещё нигде толком не поддерживается. Свой собственный кластер чего-то экзотичного придётся подымать именно так.
Можно взять тот же PostgreSQL в виде managed ресурса. То, что в амазоновом облаке называется RDS (Relational Database Service). Технически, это будет такая же виртуалка, но чуть дороже. Только установкой СУБД, обновлениями, бэкапами, мониторингом будете заниматься не вы, а облако. Специально обученные киберминьоны, управляемые из облачной консольки. Это очень соблазнительное предложение. Это действительно удобно. Таким образом можно запустить многие популярные реляционные СУБД: MySQL, PosgtreSQL, Oracle, MS SQL Server. И даже парочку популярных кэшей: Memcached и Redis.
Cloud Database
А ещё у нас есть сугубо облачные БД. Они живут где-то на мощностях облака. Они — multitenancy, общие мощности облака делятся между множеством клиентов. Поэтому нельзя сказать, что СУБД запущена на какой-то виртуальной машине. Она запущена там, в облаке.
Так как такие СУБД — масштабные распределённые системы, они, как правило, — нереляционные. То есть, NoSQL. Но встречаются и исключения, СУБД, которые выглядят как SQL, но, на самом деле, являются не совсем SQL.
У Амазона есть Redshift. Штука для аналитики. То, что называется Data Warehouse. Вы туда загружаете данные, а потом делаете SQL запросы по данным. Долго. Дорого.
А недавно у Амазона появилась Aurora. Штуковина с сетевым протоколом MySQL или PostgreSQL на выбор. Но полностью облачная. Я не пробовал, но сам Амазон настойчиво склоняет на её использование вместо обычных инстансов RDS.
Вернёмся к NoSQL. В Azure есть удивительнейшая Cosmos DB. Внизу там некий супер-дупер крутой распределённый транзакционный слой. А поверх можно натянуть несколько разных моделей данных, и разных сетевых протоколов. Можно просто key-value, с интерфейсом, совместимым с другой лазурной облачной NoSQL под названием Table. Можно нечто под названием SQL API, а на самом деле хранилище для JSON документов, просто там запросы на чём-то SQL-подобном делаются. Можно сэмулировать протокол MongoDB, тоже документное хранилище получается. Можно сэмулировать протокол Cassandra, получается колоночная БД. А можно хранить графы, причём со стопочкой стандартных графовых API.
Вся эта многослойная мультимодельная концепция Cosmos DB очень сильно напоминает FoundationDB. Там была такая же крутотень, но её можно было запустить у себя. Три года назад FoundationDB с потрохами купила Apple. А буквально на днях её снова выбросили в опенсорц. Надо потыкать, что после Apple там осталось.
DynamoDB Logo
Пока же я погрузился в пучины облачной DynamoDB. Кажется, это один из самых древнейших представителей облачных NoSQL. Кажется, DynamoDB была в AWS всегда :) Сначала это было просто key-value хранилище, но постепенно оно обрасло фичами.
Модель данных в DynamoDB подозрительно напоминает Cassandra. Ту Кассандру, что доступна через CQL.
Есть таблицы — уникальные именованные сущности в пределах AWS аккаунта. Таблица — это единица доступа и ограничения скорости.
Запись в таблице называется Item. Каждый Item идентифицируется первичным ключом. Первичный ключ может состоять из двух частей.
DynamoDB Hash Keys
Первая часть, обязательная, — это hash key. Это — некоторое примитивное значение (строка, число, blob), от которого будет считаться хэш. Это — partition key. Хэш определяет партицию, куда будут помещены данные. Партиция — вполне физическая сущность с конкретно ограниченными физическими возможностями. Поэтому partition key нужно подбирать так, чтобы имелось достаточное количество различных значений. Ибо это определяет максимально достижимую физическую производительность операций над таблицей.
Hash key, его конкретное значение, никаких диапазонов или больше-меньше, нужно указывать и в операциях записи, и в операциях чтения. Это накладывает определённые ограничения. Значения ключей или алгоритм их формирования нужно где-то знать. Нет эффективного способа узнать набор уже существующих ключей. В худшем случае нужно выдумать какие-то псевдоключи только чтобы сформировать нужное число партиций.
DynamoDB Range Keys
Вторая часть первичного ключа, необязательная, — это sort key. Тоже примитивное значение. Тут возможны уже хитрые запросы по больше, меньше и between. По этому полю, и только по этому полю, можно сортировать. Хорошо, что сортировать можно в обе стороны.
С ключами всё. Выбирать Itemы можно только по этим ключам. Причём partition key — обязателен. Впрочем, есть ещё вторичные индексы, где можно указать другие partition и sort keys по тем же данным. Но по сути, это просто автоматически заполняемая копия данных, проиндексированная по другим полям.
Помимо ключей в Itemах хранятся атрибуты. У атрибутов есть имя — строка. (У ключей, у каждой части, тоже должно быть своё имя). И у атрибутов есть значение. Вот тут интересно.
Можно хранить примитивные типы. Строки, до 400 килобайт. Числа, как в JavaScript подразумевается, что все числа — вещественные. Над числами есть атомарная операция инкремента (на значение, определённое в апдейте), легко делать счётчики. Binary, просто бинарные данные, до 400 килобайт.
Можно хранить множества, set, примитивных значений. Можно добавлять и удалять элементы из множества. Можно хранить списки и мапы. Таким образом можно хранить полноценные JSON документы, только уровень вложенности ограничен 32.
Общий размер Item ограничен теми самыми 400 килобайтами. Всё-таки это не Кассандра. И даже не Монга. Но в рамках этих 400 килобайт можно засунуть сколько угодно атрибутов.
Каждый Item в таблице может иметь свой собственный набор атрибутов, никак не связанный с другими Itemами.
DynamoDB Items
При записи нужно указать первичный ключ и значения атрибутов. Будет сделан upsert, если записей нет, они добавятся, если атрибуты были, они обновятся. Есть операции для модификации чисел, множеств, списков и мапов. Так что можно делать частичные апдейты.
Для чтения есть две операции: Scan и Query.
Scan — это просто последовательный просмотр всей таблицы, с применением фильтров. Scan совершенно никак не оптимизирован и не использует индексы. Поэтому он настоятельно не рекомендуется к использованию. Но он есть.
Query — это уже полноценный запрос. Точное значение partition key. Диапазон sort key. Это ограничит набор просматриваемых данных. Направление сортировки. Проекция, можно выбрать лишь часть атрибутов Itemов. Фильтры, можно ещё ограничить содержимое выборки уже по значениям атрибутов. Равно, не равно, больше, меньше, существует, не существует, содержит подстроку, начинается с подстроки. Много проверок можно сделать. Но фильтры не улучшают производительность запроса, ибо поиск делается только по ключам. Но могут сэкономить немного трафика.
Работать с DynamoDB проще всего через сооветствующее SDK. Под Java там вполне приличное ООП, позволяющее конструировать запросы из объектов. Явовые коллекции совершенно прозрачно кладутся во множества, списки и мапы. Но на низком уровне там API через HTTP. Так что в простеньких случаях можно взять обычный HTTP клиент.
С этой моделью данных можно натворить почти всё, что угодно. Нужно только быть аккуратнее с partition key. Там не должно быть одного-двух значений, тогда будет слишком мало партиций. Туда не стоит помещать время или что-то монотонно возрастающее. Во-первых, при запросе придётся перебирать каждую секунду (или какая у вас там гранулярность). Во-вторых, будет эффект «горячей» партиции, когда вся запись идёт в «сегодня».
DynamoDB Query
Самое интересное: производительность и деньги. В облачных БД одно с другим неразрывно связано.
Платить надо. За «единицы ресурса записи», сколько операций записи в секунду будет разрешено. За «единицы ресурса чтения», сколько операций чтения в секунду будет разрешено. При этом под «операцией» понимается запись чего-то не более 1 килобайта, или чтение чего-то не более 4 килобайт. Чтение значительно (раз в десять, или даже в сорок, если объёмы сравнивать) дешевле записи. За объем хранимых данных, погигабайтно. За передаваемые данные, тоже погигабайтно в месяц. Входящие (то есть запись) — бесплатно. Исходящие (то есть чтение) — нет.
Дабы не мучиться с подсчётом нужных «единиц ресурса» можно настроить автомасштабирование этих параметров. Но, похоже, это может привести к попаданию на бабки при внезапном всплеске активности.
Кстати, помните, что скорость ограничивается для каждой таблицы отдельно, и равномерно пилится между партициями. Опять partition key важен. И хоть производительность — штука платная, она тоже имеет ограничение. Впрочем, текущих десятков тысяч попугаев вроде должно хватить всем.
Cost Comparison
Также отдельно надо платить за репликацию (в том числе и между датацентрами), за бэкапы, за дополнительные инстансы кэша (ухты, есть и такое), за DynamoDB Streams и за триггеры.
Streams — это возможность проиграть все операции записи в БД куда-то ещё. Например, скормить их в Lambda и сделать там что-нибудь полезное.
Триггеры в DynamoDB — это такие же Lambda, которые могут влиять на результат записи. При их использовании придётся платить за Lambda.
Сама DynamoDB неплохо интегрируется с инфраструктурой AWS. Данные из DynamoDB можно скормить в тот же Redshift. Или натравить на таблицы DynamoDB целый Hadoop и делать агрегирующие запросы на HiveQL. (В самой DynamoDB никаких group by нет).
Получается нормальный такой облачный NoSQL. Если уж вы оказались в AWS, и вам нужно довольно быстро или очень много данных, попробуйте начать с DynamoDB. Возможно, её вполне хватит. А если не хватит, данные можно перегрузить во что-нибудь более мощное.

2018-04-08

О CodeFest 2018

Я понял, почему уже который код не хочу ехать на CodeFest, но всё равно еду. И еду именно на CodeFest, а не на какие-нибудь JPoint или HighLoad++.
Не хочу, потому что ну сколько можно уже. Докладчиком не берут, потому что местом проживания и работы не вышел. Сибирские да омские докладчики авторитетом не пользуются. Приглашают только своих. За свои деньги ехать, это надо ещё жабу поуговаривать. Ничего нового обычно не бывает.
А еду, потому что Новосибирск сильно ближе, чем Москва. И, в отличие от кучи московских узкоспециализированных конференций, CodeFest — обо всём и сразу. Всё, чем живёт немосковское российское ИТ, сразу становится видно. А если не видно ничего нового, это же хорошо. Это значит, что я — в тренде, и ничего не упускаю. В этом тоже стоит убедиться.
CodeFest 2018
Итак, CodeFest 2018. Доставлял. Было улётно.
В этот раз, в первый день конференции, был целый поток в большом зале под названием Keynote. И это было шикарно. Лучший поток среди всех потоков всех конференций, где я побывал. Так бы и сидел там весь день, но нужно было разведать некоторые более специфичные области.
Началось всё с выступления голландца с простым именем, но непроизносимой фамилией Sander Hoogendoorn. Рассказывал он, по сути, про бирюзовые организации в ИТ. Делайте не проекты, а продукты. К чёрту оценки и планы. Пусть люди сами самоорганизуются в маленькие динамичные эффективные команды. И всем будет счастье.
Вполне очевидные вещи. Для меня. Я сам мог бы что-нибудь такое задвинуть, если нужно. Но я не живу в Амстердаме, и не курю травку. И я не написал пять книжек про IT на нидерландском. Может, пора?
Потом выступал Григорий Бакунов, тот самый Бобук из Яндекса. Говорил, как изобретать изобретения. И как он сам изобретает. Зачем? Ну, наверное, иначе не может. Похвастался парочкой своих изобретений. Например, как обманывать нейросеточки, распознающие наши лица. Парочка тщательно рассчитаных другими нейросеточками полосок на лице, и вас не узнают. Или даже узнают не вас. Очень просил изобрести телепорт. Показал собранную им статистику, где от момента первого упоминанния какого-нибудь изобретения, где-нибудь в фантастической повести, до момента появления чего-нибудь подобного в реальности проходит в среднем тридцать лет. Впечатлённые дети вырастают и воплощают мечту детства. С телепортом как-то не сложилось :(
Пока на Keynote был перерыв, я успел послушать Михаила Ярийчука про Garbage Collector в .NET. Что-то у меня сложилось впечатление, что в JVM-то этот самый сборщик мусора покруче будет. По крайней мере, я давно не слышал, чтобы куча мелких короткоживущих объектов создавала проблемы. Зато в .NET некоторые объекты можно создавать в стеке. Ну а так, это был доклад не столько про сборщик мусора, сколько про вполне разумные техники экономии памяти. Меньше объектов. Больше локальных примитивов. Никакой LINQ магии. Циклы for — наше всё.
Снова Keynote. Александр Орлов, половинка дружного коллектива Орлова и Панкратова по имени «Стратоплан». Рассказал, как он выгорал на работе. На работе с Панкратовым. Когда всё надоедает, ничего не хочешь делать, начинаешь делать глупости. И отдых не помогает. Указанный выход оказался неожиданным. Нужно пойти к психотерапевту. Казалось бы, если выгораешь, значит, работа виновата? Выходит, не всегда так.
Павел Мочалкин, известный своими глубоко философскими докладами, продолжил Keynote. Про силу ограничений. Но я туда не попал. Ради Котлина.
Дмитрий Грязин расскал про Kotlin/Native. Кто не в курсе, это такой Котлин, который компилируется в нативный код, в первую очередь для того, чтобы можно было на нём писать для iOS. И, оказывается, это уже сейчас действительно возможно.
Во-первых, Kotlin/Native просто очень даже неплохо взаимодействует с C. Нужно взять код на C, прогнать одну утилитку, и получить интерфейсы(?) на Котлине, которые можно использовать из Котлина. Сишные функции вызываются как котлиновые функции. Указатели и прочие прелести представлены соответствующими классами. Гораздо проще JNI. Почти так же легко и удобно, как в Python. Я даже подумал, что, с такой хорошей интероперабильностью с C, Котлин может потеснить Питон в этих наших бигдатах да машинных обучениях. И недавнее интервью с Андреем Бреславом это даже немного подтверждает.
Во-вторых, можно писать проекты на Kotlin, которые будут с одной стороны компилироваться в байткод для JVM, а с другой стороны — в нативную разделяемую библиотеку. Тогда получится этот код использовать и из Android приложения, и из iOS приложения. Это уже работает. Проблема, как я понимаю, пока в том, что пока ещё нет достаточного количества библиотек на Kotlin или pure-Kotlin кода. Например, вам банально нужно сделать GET запрос на некий URL и забрать оттуда какой-нибудь JSON. В JVM вы можете использовать java.net.URL. А в нативном коде что? Можно прибиндиться к libcurl. Но общий котлиновый интерфейс для того и для другого вам пока ещё придётся рисовать самим. Как я понимаю, в этом направлении, всеобщекотлиновом стандартном API, вовсю и работают.
Я не удержался и задал вопрос: «Можно ли, используя какой-нибудь инструмент мобильной кросплатформенной разработки, будь то Kotlin/Native, или React Native, или Xamarin, воплотить в жизнь мечту заказчика об экономии затрат (за счёт кросплатформенной разработки) в два раза?» И целая толпа мобильных разработчиков мне дружно ответила: «Нет!»
Снова Keynote. Иван Ямщиков из ABBYY поведал историю развития искусственного интеллекта. Пытаюсь вспомнить, о чём был доклад, и не могу. Кажется, ничего такого, чего нельзя было бы прочитать в научно-популярных книжках, там не было.
Потом выступал Dylan Beattie. Прикольный дядька, все два дня конференции ходил в ковбойской шляпе и сапогах. А оказался чистокровным британцем. Который к тому же учит русский язык. Обещал через три года выступить на CodeFest на русском. Сделал несколько забавных айтишных каверов на известные песни, всех их можно послушать на его YouTube канале. Видимо, этим и знаменит среди организаторов конференции.
Здесь он рассказал интересные, но банальные вещи. Подробно расписал, как котик, сфотографированный на один телефон, попадает на другой телефон. Включая GSM/3G, TCP/IP, HTTP и прочих. Отлично проиллюстрировал JPEG сжатие с потерями на примере рецепта щи. Если из пятнадцати пунктов рецепта выкинуть треть наименее важных, это всё равно останутся щи.
Хоть всё это и банально, лично мне кажется, что 90% программистов действительно не представляют всех этих многослойных абстракций, которые лежат под обыденными вещами нашей цифровой повседневности. Иногда надо погружать в контекст.
Завершил день киноутов Костантин Осипов. Олег Бартунов не смог приехать. И пришлось Косте отдуваться за будущее баз данных. Копнул он хорошо и глубоко.
Существующие БД никуда не денутся. NoSQL тоже никуда не денется. NewSQL будет процветать, ибо SQL пока что лучший язык запросов к БД. Все будут тырить друг у друга идеи. Опенсорсом денег не заработаешь. Есть угроза со стороны облачных БД, которые вроде те же MySQL, но полностью managed в облаке. Гребут деньги лопатой, но тому же MySQL с этого ничего не перепадает. Но облачные БД не могут захватить весь рынок, потому что есть Edge. Это те же автономные автомобили, которым локально нужно собирать и хранить кучу данных, и они не могут всё перенести в облако. Как-то так.
Первый день конференции закончился. Начался афтепати. Спасибо той неизвестной мне рок-группе, что играла отличную живую музыку в баре «Rock City». На этом про афтепати всё.
CodeFest
На второй день целого потока Keynote не было. Зато было два потока Backend. Один из них открывал снова Костантин Осипов. К сожалению, мы успешно опоздали на первые доклады. И я застал лишь самый конец. Судя по всему, это был отличный обзор различных, применяемых на практике, схем шардирования. Со всеми их преимуществами и недостатками. И о том, что шардирование не заменяет мозги, и всё равно нужно думать, куда и зачем складывать данные. Обязательно надо посмотреть, как только появятся слайды и видео.
Иван Панченко отлично рассказал про PostgreSQL 10. Про новую фичу логической репликации. До этого в Постгресе была отличная потоковая репликация, когда WAL файлы мастера передаются на слейвы и там буквально воспроизводятся. Получается точная (с точностью до задержки репликации) копия мастера. Всей БД целиком. Кроме того, что тут нельзя отреплицировать лишь кусочек БД, есть ещё и проблема с длинными транзакциями на слейве. Пока мы тут что-то долгое на слейве выбираем, с мастера может прийти удаление части данных.
И вот теперь тот же самый поток WAL может более интеллектуально разбираться на слейве. Слейв становится полноценной БД, куда можно писать. Но ещё туда прилетают инсерты и апдейты с мастера. И применяются как обычные инсерты и апдейты. DDL пока не передаётся, так что придётся руками синхронизировать схемы. Зато можно проделывать хитрые фокусы. Например, иметь мастер без индексов, для быстрой вставки. И несколько слейвов, с разным набором тяжёлых индексов для разных отчётов. Или можно сделать частичный мультимастер, чтобы разные таблицы писались на разных узлах, но взаимнореплицировались. Кстати, у Postgres Professional (импортозамещение, помните) есть свой мультимастер.
Иван Круглов рассказал про service mesh в Booking.com. Идея хорошая, и действительно годная, когда у вас много микросервисов. Идея в том, чтобы отделить обязанность поиска других сервисов и связи с ними от самих микросервисов. Не делать это в виде умной библиотеки (на определённом языке), а делегировать прокси, запущенном на localhost.
Каждый сервис, когда ему нужен другой сервис или даже БД, просто обращается к localhost, на том же хосте или даже в том же контейнере, как оно обычно и происходит в девелопменте. А на локалхосте живёт хитрый прокси, который знает, куда запрос переправить, кэширует открытые соединения, делает повторы и балансировку, если нужно. Знания о маршрутах и местоположении других сервисов он берёт из единого центра управления этим хозяйством. В качестве прокси в Booking.com используют Envoy.
Идея вполне здравая, особенно если у вас сервисы написаны совсем на разных языках. Но я также убедился, что discovery и взаимодействие сервисов, которое я напилил в нашем текущем проекте, тоже имеют право на жизнь. Пусть там пока и нет выделенного прокси :)
Ещё один архитектурный доклад был от Andrea Giunta. Он всё правильно рассказал про длинный путь от монолита, через клиент-сервер и трёхслойные архитектуры, до микросервисов и функций в облаке. Но было скучно. Никто даже не родил вопросов по ходу лекции. Немотря на многочисленные «Questions?» докладчика. Может, функции и были бы для меня откровением, но я с ними разобрался двумя неделями ранее :)
А потом я продолжил собственное погружение в мир кросплатформенной мобильной разработки, начатый ранее с Kotlin/Native. Послушал Андрея Оздьона про React Native, Дмитрия Моисеева про Xamarin, Сергея Лагнера про Qt. Ещё сам немного вспомнил про PhoneGap/Cordova.
Глобальных подхода к кросплатформенности у нас получается три.
Номер раз. Берём от платформы что-то переносимое, что позволит там рисовать и реагировать на события. Либо WebView, а в него засовываем почти обычное веб-приложение, это будет Cordova. Либо OpenGL surface, а на нём уже рисуем свои виджеты, это будет Qt.
Номер два. Берём хороший и популярный язык, фреймворк и/или среду выполнения. Тщательно обёртываем нативные возможности каждой платформы в этот наш язык. Как бонус, можно налепить сверху общезнаменательное API, чтобы можно было ваять, не оглядываясь на конкретную платформу. Если языком будет JavaScript, а фреймворком React, получится React Native. Если языком будет C#, а средой выполнения .NET, получится Xamarin.
Номер три. Пишем максимально общий независимый код, бизнес-логику и всё такое, на каком-нибудь языке, который сможет скомпилироваться в библиотеку на любой платформе. Например, на C или, теперь уже, Kotlin. И пишем нативный UI для каждой платформы, который использует эту общую библиотеку.
Особняком ещё стоят игровые движки. Которые вполне можно рассматривать как средство кросплатформенной разработки. Похоже, они изрядно в этом направлении продвинуты.
Лично мне кажется наиболее перспективным и полезным для пользователей подход номер три. Поэтому топим за Котлин :)
Но почему живы и процветают другие подходы? Потому что всё решают ресурсы. Человеческие ресурсы. Где-то завалялись тонны кода на C++, которые никто не будет переписывать. А воткнуть C++ в Android проще через Qt. Где-то есть куча .NET разработчиков, и их можно и нужно утилизировать на мобильную разработку на Xamarin. А где-то развелось фронтендеров, которые, на Reactе-то, научились серьёзным методологиям и подходам, и теперь тоже смогут писать под мобилки с помощью React Native.
Но в любом случае нужны настоящие Android и iOS разработчики. Хоть полчеловека. Чтобы затыкать дыры и дописывать слои совместимости. Вот так.
7bits at CodeFest
Конференцию закрывал Александр Лысковский. Жизнеутверждающим докладом про мощь айтишников. Про то, как ИТ компании приходят в не-ИТ бизнес, и добиваются успеха. Потому что умеют всякий Agile и вообще люди с головой на плечах. Любой айтишник разберётся с тем, как доить кур. Но никакая доярка никогда не сообразит, как настраивать Bitrix. Упоминал Dodo pizza (Фёдор Овчинников закрывал CodeFest в прошлом году), Tinkoff bank (был спонсором CodeFest в этом году), Amazon, Uber и прочих прочих. Жить будем, господа коллеги. Даже если кодеров и верстальщиков заменит нейросеточка, постановщики задач никуда не денутся.
Итак. Кросплатформенная мобильная разработка. Базы данных (PostgreSQL). Микросервисы. Kotlin. Блокчейн. Бизнес. Будущее. Светлое будущее для всех, с информационными технологиями.
И да, англоговорящих докладчиков всё больше, и понимающих их без перевода тоже всё больше.
P.S. Я даю здесь ссылки на доклады на сайте CodeFest. Скоро там появятся презентации. А чуть позднее — видео.