Тёмный
Сергей Петрелевич
Сергей Петрелевич
Сергей Петрелевич
Подписаться
Знакомство с Micronaut
21:59
5 месяцев назад
Java virtual Thread
27:11
5 месяцев назад
Знакомство с Armeria
42:20
6 месяцев назад
TCP Log-appender на java (NIO)
20:50
9 месяцев назад
TCP Log-сервер на java (NIO)
22:23
9 месяцев назад
reactor kafka
1:29:10
Год назад
Кто такие дженерики?
50:17
2 года назад
Serializer и Deserializer в Kafka
6:32
2 года назад
Kafka consumer. Метод poll
27:43
2 года назад
Основы Java collections
1:40:18
2 года назад
Reactor Netty
20:42
2 года назад
Пример бота Telegram на java
1:36:46
3 года назад
Введение в Gradle
1:02:10
3 года назад
Комментарии
@alexandr6055
@alexandr6055 20 дней назад
Отличная лекция, спасибо. Но мне кажется лучше просто в записи кидать. И было бы не плохо, если б немного больше теории. В частности здесь в целом что такое ThreadLocal, для чего он, а затем уже код.
@miraclechina1301
@miraclechina1301 Месяц назад
Одно непонятно что делать если у нас две разные базы данных для финансов и для бд с сохранением состояния Кафки тогда завернуть в транзакцию не получится и нужно будет табличку з записями про обработку данных из портиции тащить в базу з платежами.
@petrelevich
@petrelevich Месяц назад
Т.е. надо консистентно вставить в две базы данных? Для этого надо использовать или распределенные транзакции или сагу.
@vrazovsky
@vrazovsky Месяц назад
как-то все очень душно, я не могу такое смотреть
@aleksey2793
@aleksey2793 Месяц назад
А как лучше работать с кешем? Использовать абстракцию в виде аннотаций типа @Cacheble и др? Или работать с помощью методов напрямую, как у вас в примере?
@petrelevich
@petrelevich Месяц назад
Это дело вкуса и принятых на проекте практик. Я больше люблю работать напрямую без лишних посредников.
@СергейВячеслаев
@СергейВячеслаев 2 месяца назад
Спасибо, как всегда очень доходчиво и наглядно
@МаксМакс-ч8к
@МаксМакс-ч8к 2 месяца назад
Мне далеко не все уроки Сергея нравятся, но этот прям хорош!!! Спасибо!!!
@southhorizons5894
@southhorizons5894 2 месяца назад
а мне все нравятся
@itlife8792
@itlife8792 2 месяца назад
братик, спасибо тебе
@RuslanMurzin-uz8fj
@RuslanMurzin-uz8fj 2 месяца назад
Спасибо за лекцию. А как Вы запускали docker-compose.yml ? Правильно я понимаю, что мне надо установить docker desktop (под windows) и там уже есть docker compose ? P.S. в указанном чате отсутсnвует данная лекция.
@BoringCoder
@BoringCoder 2 месяца назад
Что будет, если ожидаемое событие для перехода между состояниями не произойдет? Как обрабатывать такие случаи?
@petrelevich
@petrelevich 2 месяца назад
Если надо ограничивать время перехода, то стоит добавить таймауты.
@luyt2
@luyt2 3 месяца назад
Спасибо, доступно. Я бы ещё добавил про особенности пересборки проекта при использовании api/implementation
@rainqirimli5457
@rainqirimli5457 3 месяца назад
Так а в чем прикол? Томкат чтобы обработать 200 реквестов запустит 200 трэдов. А нэтти если прилетят 200 риквестов одновременно - что сделает? Эвент лупом примет эти 200 реквествов, а затем запустит 200 трэдов, которые будут обрабатывать их... я не прав?
@petrelevich
@petrelevich 3 месяца назад
Netty все эти 200 запросов будет обрабатывать ограниченным числом потоков, в соответствии с конфигурацией. Скорее всего, их будет столько, сколько доступно ядер. Т.е. для обработки 200 запросов, надо будет не 200 потоков, а порядка 5-10. Но эти запросы должны быть неблокирующие.
@rainqirimli5457
@rainqirimli5457 3 месяца назад
@@petrelevich спасибо за быстрый ответ. Но немного не ясно. Представим вэб приложение, которое обращается к базе, выполняет сиквел, отдает ответ клиенту. И вот это приложение получило 200 риквестов, и соответственно должно сделать 200 запросов в базу. Т.е. если моё понимание верно, то вот эти обращения к базе будут выполнены не эвент луп трэдом, а другими трэдами, назовём их воркер трэдами. Если предположить что,запросы к базе долго играющие и их одновременно 200, не значит ли это, что система помимо 5-10 эвент луп трэдов запустит ещё 200 трэдов для коммуникации с базой данных? Заранее спасибо
@petrelevich
@petrelevich 3 месяца назад
@@rainqirimli5457 работа с базой - дело особое. 200 сессий может и не выдержать. Да и connection pool обычно настроен на более скромные лимиты. Далее вопрос: база данных на блокирующем драйвере или реактивном. Если на блокирующем, как пример, jdbc, то все 200 запросов уйдут в очередь, у которой кол-во поток будет равно кол-ву connection-ов в пуле. Если база данных реактивная, то все равно, скорее всего образуется очередь, т.к. все равно будет какой-то connection pool и на нем будет ограничение кол-ва подключений.
@artemromanov5346
@artemromanov5346 3 месяца назад
воды много - все умещается в 20м-30м от силы
@alex45788
@alex45788 4 месяца назад
Сергей, у Вас нет в планах сделать видео с разбором популярных и нетривиальных операторов Project Reator ? Как бы это было бы круто 🥺
@petrelevich
@petrelevich 4 месяца назад
Сейчас готовлю доклад про замену webflux на virtual thread. В нем как раз будут такие операторы. Т.е. про случаи, когда заменить будет трудно.
@alex45788
@alex45788 4 месяца назад
Вопрос по коду. Создание KafkaReceiver (класс ReactiveReceiver) KafkaReceiver.create(options) .receiveAutoAck() .concatMap(consumerRecordFlux -> { log.info("consumerRecordFlux done, commit"); return consumerRecordFlux; }) .retryWhen(Retry.backoff(3, Duration.of(10L, ChronoUnit.SECONDS))); 1. Почему выбран метод concatMap? Какая его логика? Мы могли бы использовать например doOnNext для логирования очередного элемента потока. 2. Почему используется backoff в retryWhen, а не fixedDelay например?
@petrelevich
@petrelevich 4 месяца назад
1. concatMap преобразует Flux<Flux<ConsumerRecord<K, V>>> receiveAutoAck() в Flux<ConsumerRecord<K, V>>, doOnNext не подойдет 2. backoff реализует exponential backoff strategy, т.е. каждая следующая попытка будет выполняться с большим интервалом, а fixedDelay задает интервал фиксированный.
@gderuki
@gderuki 4 месяца назад
+
@levaryazan
@levaryazan 5 месяцев назад
Отличное объяснение!! Спасибо.
@sergglav
@sergglav 5 месяцев назад
Спасибо! Стало быть, у Micronaut Reactor под капотом? Или его надо специально подключать?
@petrelevich
@petrelevich 5 месяцев назад
reactor приезжает транзитивно с другими зависимостями.
@mitruslatovous6
@mitruslatovous6 5 месяцев назад
Спасибо за просветительскую работу!
@exes5282
@exes5282 5 месяцев назад
Спасибо!!!!!!
@ivanstrelka3448
@ivanstrelka3448 5 месяцев назад
Спасибо!
@wildjoe6259
@wildjoe6259 5 месяцев назад
Спасибо!
@mitruslatovous6
@mitruslatovous6 5 месяцев назад
Спасибо! Понятное объяснение. Было очень интересно)
@sergglav
@sergglav 5 месяцев назад
Сергей, огромное спасибо за видео! Как всегда всё познавательно и внятно, как на курсах)
@MrRomanvideo
@MrRomanvideo 5 месяцев назад
Спасибо, интересно и полезно. Пример со Спринг Бута тоже было бы классно вместе посмотреть)
@ЛеонидПескин-з7ы
@ЛеонидПескин-з7ы 5 месяцев назад
Сори, не смог до конца досмотреть, такое монотонное объяснение, тяжело очень для восприятия, несколько раз перематывал, так как терял логическую цепочку, что происходит. Ужасное объяснение, хотя структура прекрасная абсолютно
@alex45788
@alex45788 5 месяцев назад
Жду шестую серию сериала)
@АлександрТеплых-э7о
@АлександрТеплых-э7о 5 месяцев назад
Я думаю, что стоило хоть разок запустить приложение и показать как оно работает)))
@petrelevich
@petrelevich 5 месяцев назад
да, это было бы полезно
@972gmailcom1
@972gmailcom1 5 месяцев назад
Интересно, но к сожалению "плохой звук": через наушники слышно нормально, а вот на средних динамиках не слышно.
@konstantinchvilyov9602
@konstantinchvilyov9602 5 месяцев назад
Спасибо. Без базы данных нельзя обойтись?.. Это же потеря скорости.
@petrelevich
@petrelevich 5 месяцев назад
Можно обойтись, если не требуется гарантия exectly-once. Такая гарантия действительно редко нужна.
@konstantinchvilyov9602
@konstantinchvilyov9602 5 месяцев назад
@@petrelevich Странно, такая гарантия всегда была нужна на моих работах.
@petrelevich
@petrelevich 5 месяцев назад
@@konstantinchvilyov9602 Например, exectly-once точно не надо в логгировании, телеметрии, социальных сетях и т.е., когда что-то иногда можно потерять. И exectly-once почти всегда обязателен в платежах.
@AlexSmile-y2x
@AlexSmile-y2x 6 месяцев назад
Классный проект (особенно порадовал production-ready подход к разработке). Очень интересно будет следить за его развитием в полноценную систему. Такие видеосериалы с постепенным построением готовой неучебной платформы, на мой взгляд, как раз лучшие для обучения начинающего: позволяют понять для чего каждый элемент и чем отличаются подходы P.S. кстати, не понял, почему в качестве мапперов для таких объемных дто не использовался mapstruct, он легковесный и одной строкой заменяет все эти полотна кода?
@petrelevich
@petrelevich 6 месяцев назад
>кстати, не понял, почему в качестве мапперов для таких объемных дто не использовался mapstruct, он легковесный и одной строкой заменяет все эти полотна кода? да, можно его использовать. И это еще один вопрос - а нужно ли тут вообще dto.
@AlexSmile-y2x
@AlexSmile-y2x 6 месяцев назад
@@petrelevich ну сами по себе иммутабельные ДТО часто бывают полезны (помогают при формализации необходимого контракта для клиента, и полезны для его документирования, помогают при валидации данных, если модель анемична, могут часто помочь при дальнейших доработках, уменьшая связанность между моделью и интерфейсом клиента и т.п.), и при этом они "есть не просят" особо, как говорится, поэтому лично я полагаю, что лучше с ними, чем без них
@sequ3nce515
@sequ3nce515 6 месяцев назад
Хорошее видео, спасибо :) Нет ли в планах создания полноценного курса по какой-либо из тем? Или если есть может кто-то сказать название и где можно приобрести?
@petrelevich
@petrelevich 6 месяцев назад
Пока таких планов нет, но все возможно в будущем :)
@972gmailcom1
@972gmailcom1 7 месяцев назад
Спасибо. Посмотрел позже. Было интересно и полезно.
@v.volkau
@v.volkau 7 месяцев назад
Отличное видео, пересмотрел второй раз спустя время и всё понял. Замечательный пример про бармена. Пожалуйста, продолжайте использовать такие бытовые примеры для объяснения - очень хорошо запоминается.
@v.volkau
@v.volkau 7 месяцев назад
Спасибо, отличное видео!
@immortal-spirit-13
@immortal-spirit-13 7 месяцев назад
Петрелевич очень умный парень, хорошо доносит
@markostr
@markostr 7 месяцев назад
Очень хорошо объяснили ! Спасибо !
@root924
@root924 7 месяцев назад
Если guava есть в classpath, то по какой причине libApiUse ее не видит?
@petrelevich
@petrelevich 7 месяцев назад
не видит, если используется scope - implementation
@Сергей-и8ж7в
@Сергей-и8ж7в 8 месяцев назад
Из разряда "как нарисовать сову": 1. рисуем три кружка; 2. дорисовываем до совы. Отус такой ценник за свои курсы лупит, а лайф-кодинг поленился сделать даже на вводном уроке. Смотрите - это парсер, ну парсер и парсер, ничего особенного 😅 Спринг так же объясняете?) Это бин, ну бин и бин, ничего особенного, поехали дальше))
@petrelevich
@petrelevich 8 месяцев назад
Что именно не понятно и требует детального пояснения?
@takezo_kyiv
@takezo_kyiv 8 месяцев назад
Спасибо большое за видео! Очень познавательно
@Евгений-1
@Евгений-1 9 месяцев назад
откуда при раскладе 3 сек на источник и 2 сек на обработчик может возникнуть очередь? источник генерит медленнее чем обработчик обрабатывает. 1,2,3 источник 4,5 обработчик 4,5,6 источник 7,8 обработчик 7,8,9 источник
@petrelevich
@petrelevich 9 месяцев назад
какую очередь имеете в виду?
@Евгений-1
@Евгений-1 9 месяцев назад
@@petrelevich вот тут: 1 час 20 минут
@petrelevich
@petrelevich 9 месяцев назад
@@Евгений-1 Пересмотрел, начиная с этого момента ru-vid.com/video/%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE-UDGZV0tzPQ8.htmlsi=WwyOF8Sv5okuUib_&t=4743 Ничего не услышал про "очередь".
@Евгений-1
@Евгений-1 9 месяцев назад
​@@petrelevich там в комментах задан вопрос и вот текстовая расшифровка: 1:20:57 у вас есть некий некая задержка а на 1:21:15 звучит "и в итоге тут должно больше наплодиться.... чем больше работаем тем больше накапливается разница" это где будет накопление? и откуда возьмется накопление учитывая что генерация медленнее чем обработка?
@petrelevich
@petrelevich 9 месяцев назад
@@Евгений-1 Теперь понятно, в чем вопрос. В классе DataProducerStringReactor данные генерируются без ограничения скорости, но потом добавляется задержка delayElements(Duration.ofSeconds(3)). Чтобы согласовать быстрый источник и медленный обработчик включается механизм backpressure. Это приводит к тому, что данные создаются в генераторе и буферизируются (накапливаются) пока потребитель не сможет их обработать. После обработки создается новая порция данных и они буферизируются, пока не обработаются. Понятно пояснил? Надо, наверное, видос на эту тему записать?
@sromankov6102
@sromankov6102 9 месяцев назад
спасибо очень информативно, только вот вопрос, как скажем из CI задать выбор энва? Определить две configMap и как-то выбирать между ними или же как-то по другому ?
@petrelevich
@petrelevich 9 месяцев назад
Второй configMap делать не надо. Лучше применить шаблонизатор типа Helm
@wildjoe6259
@wildjoe6259 9 месяцев назад
Спасибо!
@anjelomanoranjan
@anjelomanoranjan 9 месяцев назад
Сергей, спасибо за то, что предоставили исходный код) Это очень важно для новичков)
@anjelomanoranjan
@anjelomanoranjan 9 месяцев назад
Спасибо огромное) шикарное видео! Честно говоря, не помню чтобы встречал разорванное текстовое сообщение. Насколько знаю, текстовые сообщения передаются по протоколу TCP, а этот протокол должен ГАРАНТИРОВАТЬ целостность отправленных пакетов.
@petrelevich
@petrelevich 9 месяцев назад
Пакеты придут полностью, но длинные сообщения могут прийти по частям или наоборот вместе. Посмотрите предыдущее видео про нагрузочное тестирование. Там всплывали подобные моменты. И еще момент - в этом видео речь идет уже о "бизнес - логике", тут получение по частям максимально вероятно из-за буферизации на стороне "tcp-сервера".
@anjelomanoranjan
@anjelomanoranjan 9 месяцев назад
@@petrelevich благодарю за развёрнутый ответ
@wildjoe6259
@wildjoe6259 9 месяцев назад
Спасибо! Довольно познавательный цикл получился. Не так давно, нечто подобное у себя на проекте реализовывали с командой. За идею с применением концепции конечных автоматов в кейсе с парсингом, прям большой респект!
@MaximBodrov
@MaximBodrov 9 месяцев назад
Вопрос к Сергею, не первый раз уже слышу его мысль о важности groupID для консьюмера, т.е. если скопировать код из другого проекта и не изменить имя группы, то он (консьюмер) будет "красть" не свои сообщения. И вот тут у меня непонятки: ведь мы при настройке консюмера указываем еще и имя топика, на который он подписан. Я так понимал, для того чтобы он забирал по ошибке сообщения из другого проекта, нужно чтобы и имя группы, и имя топика совпало, а это еще более малый шанс
@petrelevich
@petrelevich 9 месяцев назад
Да, имя топика должно быть то же. И конечно, тот же инстанс kafka. Вероятность "кражи" зависит от характера приложения. Представьте, что это очередь заказов в магазине и куча систем работают с этой очередью: кто-то аналитику делает, кто-то отправку организует, кто-то уведомления рассылает. Для kafaka типовая ситуация, когда с одним топиком работает много систем.
@ekaterinagalkina7303
@ekaterinagalkina7303 10 месяцев назад
Смущает фраза из доки "that max.poll.records does not impact the underlying fetching behavior". Т.е. звучит так, что сетевые запросы - это одно, а poll() - другое, и на сетевые запросы к кафке настройка не влияет. Т.е. запрошенный объем данных где-то еще кэшируется, а that max.poll.records - всего лишь размер массива. max.poll.records The maximum number of records returned in a single call to poll(). Note, that max.poll.records does not impact the underlying fetching behavior. The consumer will cache the records from each fetch request and returns them incrementally from each poll. А для fetch другие настройки есть - максимальный размер в байтах и т.д. Но тогда непонятно, как по poll кафка определяет, что консьюмер упал. Правда, есть еще другая настройка heartbeat.interval.ms для пинга от консьюмера.
@petrelevich
@petrelevich 10 месяцев назад
Параметры запроса к брокеру определяются конфигом: package org.apache.kafka.clients.consumer.internals; public class FetchConfig<K, V> { final int fetchSize; final int maxPollRecords; где this.fetchSize = config.getInt(ConsumerConfig.MAX_PARTITION_FETCH_BYTES_CONFIG); this.maxPollRecords = config.getInt(ConsumerConfig.MAX_POLL_RECORDS_CONFIG); сам запрос формируется тут: package org.apache.kafka.clients.consumer.internals; public abstract class AbstractFetch<K, V> один из его параметров .setMaxBytes(fetchConfig.maxBytes) а fetchSize используется в вычитывании из внутреннего буфера. Вот с этим буфером еще надо поразбираться.
@evgenykuznetsov7490
@evgenykuznetsov7490 10 месяцев назад
топ как всегда, крутая тема👍
@qreol136
@qreol136 10 месяцев назад
Житель из деревни
@LighterDos
@LighterDos 10 месяцев назад
Спасибо! Очень понятно и доходчиво, супер