Pull to refresh
15
0
Николай Андрейчук @Youkai

Пользователь

Send message

Про потери данных не совсем верно. Вопрос был про производительность.
Мы Clickhouse не по назначению использовали. Пытались одной базой решить две проблемы:
1. Уметь считать статистику для отчетов (например, сколько каких переходов на сайт за день было)
2. Уметь вытаскивать данные по конкретному человеку (в момент, когда идентифицируем человека надо все данные по его переходам из сервиса на Clickhouse перенести в другой микросервис).

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

В итоге для доступа в разрезе по конкретному человеку заюзали Cassandra, а данные для отчетов храним в DataLake хранилище поверх S3 файлов.
Для несложных отчетов в принципе и Clickhouse подошел бы. А вот для ML нужно выгружать большой объем данных и тут Clickhouse тоже не очень подходит. DataLake закрывает как кейсы с аналитикой (в том числе сложной, которую нельзя SQL-запросом описать), так и кейсы ML.

Раньше на Planing Poker звали менеджера, который общался с клиентом. Иногда оказывалось, что менеджер тоже до конца не знает, чего хочет клиент. Тогда оценку задачи откладывали.

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

Сейчас за любой историей закрепляются продукт оунер и архитектор, которые выясняют все требования и продумывают решение в общих чертах. Так что команде приходит задача, по которой уже нет вопросов к клиентам. Но все равно остаются нюансы, которые полезно продумать до оценки, и разбиение истории на части помогает их выявить.
Один разработчик может слишком много упустить, разбивая историю на подзадачи. Даже тимлид от этого не застрахован. Команда на оценке может увидеть, что что-то не учтено или планируется сделать неправильно. Командная оценка — это в первую очередь ревью того, как спроектировано решение. Можно сократить этап совместной оценки оценки так: вместо Planning Poker'а команда просто указывает, какие задачи точно нельзя сделать за день и нужно разбить. Оценку каждой задачи уже дает один человек. Но такая оценка будет не качественной. Более самоуверенный программист будет недооценивать, а осторожные — переоценивать. Полноценная оценка всей командой помогает решить эту проблему.

Для удобства при оценке можно считать, что 1 story point — это 1 час. Важно помнить, что это не реальный час и не путать этим клиентов или менеджеров. Реальный размер story point'а надо вычислять исходя из статистики. У кого-то это будет 2 рабочих часа, а у кого-то и все 4. Мы разбиваем до подзадач, которые по нашей оценке занимают 3-4 часа. Но с учетом рисков, приемки, ревью и отвлечений на общение с менеджерами, один программист делает только 3 story point'а в неделю.
Да, такой подход тоже можно использовать. Так проще разбивать истории на подзадачи и точно не будет возникать эффекта привязки. Но тогда надо будет оценивать каждую подзадачу с помощью Planning Poker и это достаточно долго.

Важный момент: 1 день, пол дня и 2 часа стоит использовать только для того, чтобы программистам было проще прийти к одинаковому пониманию размер story point'а. Здесь 5 story point'ов — это 1 идеальный день. Чаще всего люди не укладываются в оценку, которую они дали в абсолютных величинах. С относительной оценкой получается лучше. Реальный размер story point'а нужно определять исходя из статистики.

На скачки графика такой подход не повлияет. График скачет в основном из-за того, что по окончании месяца остаются наполовину сделанные большие истории. Их в скорости мы не учитываем. Учитываем только принятые. Можно по другому учитывать, чтобы график меньше скакал, но это спорный вопрос.
Вместо экспертной оценки рисков, мы разбиваем истории на подзадачи настолько мелко, чтобы нивелировать риски. Они, конечно, все равно остаются, но в среднем мы не учитываем только 20% подзадач.
Ну я так понял детально проработанные истории на следующий спринт — это уже Sprint Backlog (http://www.scrumguides.org/scrum-guide.html#artifacts-sprintbacklog). Но это уже нюансы, конечно.
Посмотрите в Scrum Guide: Product Backlog refinement (http://www.scrumguides.org/scrum-guide.html#artifacts-productbacklog) — в статье вы описываете вашу реализацию этого процесса.
Не совсем. Наш способ оценки слишком дорогой, чтобы использовать его для оценки бэклога. Хотя и Planning Poker для этого мне кажется слишком затратным. Для оценки задач в бэклоге мы используем экспертную оценку одного-двух человек. Этого достаточно для приоритезации и при этом мы не тратим много времени на поддержку бэклога.

Делим историю на подзадачи и оцениваем мы непосредственно перед тем как брать их в спринт.
В Planning Poker историям дают относительные оценки. Например, от 0,5 до 40.

Можно разбивать истории до задач поменьше и оценивать их с помощью Planning Poker.

Мы же разбиваем истории до подзадач размером 1. Каждую подзадачу мы не оцениваем по какой-то шкале. Просто отвечаем на вопрос — она занимает ровно 1 story point или нет.
Вы за 30 минут должны весь объём спринта оценить, добрый вечер.

Когда мы оценивали с помощью Planning Poker на оценку 2-ух недельного спринта уходило не меньше полутора часа. Слишком много возникает вопросов к реализации и требованиям клиента. Пара дней уходит на большие истории, чтобы разобраться в том, что нужно делать и спроектировать решение. Так что это выходит за рамки оценки.
А сколько тикетов вы успеваете за пол часа оценить? Какого размера? Как часто во время работы над тикетом оказывается, что тикет сильно недооценен?
Насколько я понимаю, html-шаблон у Angular все равно будет не строго типизированным. Эту проблему, к сожалению, никто кроме разработчиков tsx не решил.
Ну да, с тем, что транзакция могла быть не завершена — это я погорячился)

Вариант с ROWCOUNT мы уже подробно обсудили веткой выше.
Мы делали похожим образом (правда там был email, а не FacebookId). Если точнее, мы создавали во время транзакции отдельную транзакцию (в другом connection'е) с уровнем изоляции read uncomitted. В итоге мы получали потребителя по email и, так как он уже есть, вместо добавления пытались его отредактировать, но в другой транзакции оказывалось, что потребителя в базе нет, потому что:
  • либо транзакция, добавившая потребителя, еще не была завершена
  • либо она была откачена
  • либо потребитель успел поменять email

Если использовать read comitted транзакцию, для проверки есть ли потребитель в БД, то останется только проблема с параллельным редактированием потребителя, но с ней все равно надо как-то бороться.

Вообще, можно использовать read uncomitted транзакцию, для быстрой предварительной проверки данных, но после нее все равно надо повторно проверить эти данные в транзакции изменяющей их. Тут описан пример, когда такой подход полезен.
Не уверен, что за счет такого подхода можно ощутимо выиграть в скорости (хотя, это, конечно, зависит от конкретной ситуации). Подход с update блокировкой как-то проще.
Боюсь, в этом случае больше проблем будет из-за того, что сервисный поток при обработке буферной таблицы будет блокировать вставку в нее потоками отправки. В принципе это все решаемо, конечно, но подход с лишней записью как-то проще.
У нас сложная гибко настраиваемая логика импорта с выводом подробных валидационных сообщений. Поддерживать ее на процедурах было бы слишком сложно. Поэтому мы используем ORM и serializable транзакции, хотя и жертвуем при этом скоростью в пользу гибкости.
Хотя, можно выполнить с помощью RAW SQL только запрос
UPDATE BonusPool 
SET RemainingCount -= 1
WHERE BonusID = @BonusID AND RemainingCount > 0

И выполнять дальше с помощью ORM любую логику, если @@ROWCOUNT > 0. Это будет практически полностью аналогично подходу с использованием update блокировки. Разве что, в момент транзакции между наложением update блокировки и изменением RemainingCount, могут выполнятся транзакции, которым нужно только прочитать из таблицы BonusPool, а в случае с update'ом будет наложена эксклюзивная блокировка и любые транзакции, обращающиеся к призу с этим Id, будут ждать.
Да, так тоже можно. Но при использовании ORM такой подход не получится использовать, пожалуй (сделать RAW SQL запрос в начале транзакции — это еще приемлемо, а переводить всю транзакцию на RAW SQL — это уже перебор). К тому же у нас более сложная логика и запись о типе приза нам в любом случае нужно вытащить, чтобы проверить другие ограничения на выдачу приза.
Ну SQL мы тоже не считаем 100% надежным. Мы не стремимся обработать запрос пользователя в 100% случаев. Но если одна из операций упала (SQL транзакция или отправка в очередь), то другую операцию мы должны откатить.
Да это вроде рабочий вариант. Хочу только уточнить пару нюансов:
  1. Воркер, переотправляющий сообщения, должен вытаскивать только старые сообщения (например, отправленные более минуты назад), причем скорее всего придется использовать уровень изоляции ReadUncomitted. Иначе SELECT всех сообщений будет блокировать обработку текущих.
  2. Этот подход, как и наш, может добавлять дубли сообщений в очередь.

На мой взгляд вариант с промежуточной очередью все-таки проще, а также обладает следующими преимуществами:
  1. Можно обойтись без дополнительной таблицы, если в SQL транзакции и так создается сущность с уникальным ключом.
  2. Его можно использовать и для отправки писем о регистрации.
Жертвуем гарантированностью мы на этапе обработки сообщения (отправки email). И это частный случай. При отправке платежей, например, мы можем гарантировать 100% отправку, так как сервисы ОСМП идемпотенты.

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

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

Information

Rating
Does not participate
Registered
Activity