?

Log in

No account? Create an account

Стой под стрелой

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

Категория: еда

Zookeeper
усы2
tonsky

Поручили наркоману черепах в зоопарке стеречь. Он открыл дверь в загон, а они КАААААААК ломанутся!
Я точно не знаю, для кого и кем создавался ZooKeeper и как его правильно готовят, но если верить хайпу, то это такая система для обеспечения мутабельного стейта в кластере. Сервис, обеспечивающий всем нодам согласованное и постоянно-доступное (available) представление о происходящем.

Идея была такая, что они очень много усилий вложили в то, чтобы это работало, один раз сделали и теперь все могут выдохнуть. Версия 3.4.5, уж не знаю что там было в 1.0 или 2.0, страшно. Да что там, еще в 3.3.3 важные смысловые баги были, а вплоть до 3.4.0 он логами засирал диск вусмерть.

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

Протестировать это, естественно, непросто, ведь тестировать надо на ситуации вроде падения, замедления, протухания серверов и коннектов до кластера Зукипера. И всё это нужно умудряться вставить в нужные места своего приложения, например, вот тут прячется рейс:
  (when-not (exists? zk "/path")
    (create zk "/path))
Для системы, обещающей вам согласованное состояниие, не дать метода вытащить поддерево за один вызов — это грустно. Если я сначала получу `children "/path"`, а потом начну вытаскивать каждого child, то пока я это делаю, их состав может поменяться. В итоге у меня будет размазанный по времени, несогласованный view поддерева, если кто-то в это время туда писал. Я согласен, что можно придумать задачи, когда это perfectly ok, но иногда ведь и нет.

Есть еще концепция watchers, это когда ты говоришь Зукиперу что тебя интересует (детишки вот этого пути, существование вот этой ноды) и он вроде как присылает тебе нотификацию, если по интересующему объекту что-то изменится. Так вот, он пришлет такую нотификацию один раз, и нужно взводить нотификацию снова. Нотификации надо привязывать к каждому узлу, никаких рекурсивных нотификаций, что вы. Поскольку я хочу следить за целым поддеревом, надо пройти на каждый узел дерева, взвести там нотификацию, и внимательно пересоздавать ее каждый раз, как что-то дернулось. Да, если попросить создать нотификацию дважды, придет две нотификации, надо быть ОЧЕНЬ внимательным. Короче, это нехилая такая стейт-машина, а стейт-машины обычно делают когда хотят внести в систему сложное багоопасное место. А, да, если коннект сдохнет и его пересоздать, или, например, к другому Зукиперу в кластере подключиться (availability же), ВСЕ установленные нотификации прости-прощай, обнулятся. Еще один интересный стейт.

Исходный java-клиент это вообще труба, надо сразу идти за Netflix Curator (его недавно забрал Апач и теперь даже исходники хрен скачаешь), но и с ним жизнь не сахар. В исходном клиенте ссылка на Zookeeper могла в любой момент перестать быть валидной (коннект сдох), и надо было как-то идти и всем во всех местах, кто ее уже использует, дружно ее пересоздавать. А, или вот, если вы сделали connect, нельзя сразу начинать его использовать, надо асинхронно подождать события sync-connected. В кураторе просто нужно следить за переходами между стейтами и аккуратно их обрабатывать (стейт-машина, да). Ох.

Есть и совсем глупые баги. Например, есть понятие эфемерных znodes, они ассоциируются с tcp-коннектом и стираются, если клиент сдох. Для service discovery хорошо, вот мол я, используйте меня по такому-то адресу, а если я пропал, нода сама удалится. Так вот, z-нода удаляется после таймаута, и если клиент сдох, а потом перезапустился и создал z-ноду еще раз (мол, я снова живой), то z-нода все равно удалится, когда первая сессия протухнет. То есть я живой и вот он, ноду создал, а она потом возьми и исчезни.

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

А чего душа просит? В первую очередь, умного клиента. Идея о том, что нужно предоставлять максимально кондовое API и клиента, состоящего из сгенеренных thrift-заглушек, она иногда правильная (потому что гибкая), но только не в случае распределенной системы. В распределенной системе клиент сам является компонентом, и рассчитывать на то, что юзеры понапишут правильных стейт-машин по переключению коннектов и обработке исключений — не стоит. Они скорее будут страдать от собственной тупости (а мы все неидеальны), отсутствия времени и нефундаментального подхода (все-таки не все FoundationDB пишут), чем обработают все случаи взаимодействия с API правильно.

Во-вторых, хочется получать consistent view одной фиксированной версии. Пусть она уже десять раз устарела, пока я ее скачивал, но она хотя бы будет непротиворечива блин. Это все делается на иммутабельности и merkle trees, what’s the problem?

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

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

В-пятых, больше стабильности и декларативности в клиенте. В конце концов, если мы декларируем себя как «последнее и окончательное решение проблемы шареного стейта», то не должно возникать ситуаций, когда существование моей эфемерной ноды зависит от того, правильно ли я обработал все ситуации потери коннекта и переподключения. Нет, если я сказал, что вот он я и я предоставляю сервис, то все должны меня видеть независимо от того, как и когда колбасит моё соединение, сколько раз я переподключался, перезапускался или не успевал ответить на heartbeat. Если я сказал, что мне интересно поддерево /jobs, я хочу получать новую информацию об этом дереве независимо от того, существует оно в момент моей просьбы, или будет создано позже, или его двадцать раз добавят-удалят, или Зукипер грохнут, остановят и всю память ему сотрут. У нас же и клиент, и сервер — все умные, почему я вообще по регэкспу не могу на множество путей подписаться? Этот пункт вроде бы решается на уровне умного клиента и даже оформляется как recipe к текущему zookeeper.

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

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

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

Вот, вместо того, чтобы google reader клиентов переписывать или революцию в todo листах делать, может замутил бы кто, а? Там, глядишь, и Апач купит за бусы и ракушки, всё-таки стартап.

Что я нашел, что я нашел, местами это прекрасно
tonsky
ironichna-osoba:
две параллельные прямые
живут в эвклидовом мирке
и бегают пересекаться
в мир лобачевского тайком

yapavlik:
олег за всё берётся смело
всё превращается в говно
а если за говно берётся
то просто тратит меньше сил

nik-aragua:
висит на сцене в первом акте
бензопила ведро и ёж
заинтригован станиславский
боится выйти в туалет

tequilaman:
купил айфон а чо с ним делать
где кнопки чтобы нажимать
и как мне позвонить сереге
а вот и он звонит и чо

оман:
она спросила хочешь хлеба
я тут же понял это шифр
но что же должен я ответить
хочу я хлеба или нет

rimearien:
о подозрительных предметах
я машинисту сообщил
два бильбоке одна клепсидра
жабо спирограф и бювар

sonyushka:
олег работал на границе
он охранял добро от зла
свет ото тьмы а бесконечность
от ограниченных людей

vera:
а город даже не заметил
что я уехал навсегда
и продолжал писать мне письма
про свет про воду про тепло

the axy:
с утра сорокин сел за книгу
но написал лишь слово хуй
уж вечер близится сорокин
никак не разовьёт сюжет

дядюшКаа:
семен задумался о жызни
грустит и пъёт десятый день
а николай веселый ходит
все время думает про смерть

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


Короче ссылко: http://www.perashki.ru/piro/best/
Метки:

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

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

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

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