booblik-app
1. Зона ответственности
Запуск. Модуль превращает набор библиотек в процесс: читает конфигурацию, открывает брокер, поднимает сервер, печатает метрики, применяет retention по таймеру и корректно закрывается.
Чем не занимается:
- не реализует ни хранение, ни протокол — только собирает их;
- не демонизируется, не пишет PID-файл, не тянет логгер. Всем этим уже занимается то, что запускает брокер, — systemd, контейнерный рантайм, тест, — и у каждого свои представления. Вывод идёт в stdout, потому что его читают все трое;
- не создаёт топики: их набор фиксируется при старте.
Главный инвариант: невалидная конфигурация — это отказ загрузиться. Подставить умолчание вместо того, что кто-то написал, — способ получить брокер с настройками, которых никто не выбирал.
2. Контракт
Конфигурация — properties-файл первым аргументом плюс переменные окружения. Имя переменной —
ключ заглавными с точками, заменёнными на подчёркивания: booblik.port → BOOBLIK_PORT.
Окружение важнее файла, файл важнее умолчания.
| Ключ | Умолчание | Смысл |
|---|---|---|
booblik.data.dir | data | корень, внутри — каталог на партицию <топик>-<номер> |
booblik.port | 9092 | 0 = любой свободный |
booblik.bind.address | нет | адрес прослушивания; без него — все интерфейсы, см. §1.16 и M-64 |
booblik.topics | default:1 | orders:3,clicks:1 |
booblik.segment.mode | MAPPED | путь записи; FILE_CHANNEL — путь отката, см. Р1 и M-45 |
booblik.segment.capacity.bytes | 512 МиБ | потолок — Int.MAX_VALUE у обоих путей записи |
booblik.index.interval.bytes | 4096 | сколько лога приходится на одну запись индекса |
booblik.flush.every.records | нет | барьер раз в N записей |
booblik.flush.every.millis | нет | барьер раз в T миллисекунд |
booblik.retention.bytes | нет | сколько живого лога держать на партицию |
booblik.retention.millis | нет | по возрасту файла сегмента |
booblik.retention.check.millis | 30000 | как часто применять retention |
booblik.transport | SELECTOR | VIRTUAL_THREADS — линейка для замеров, не рабочий режим |
booblik.fetch.mode | ZERO_COPY | HEAP — контроль в эксперименте M-35 |
booblik.metrics.interval.millis | 10000 | 0 отключает строку метрик |
2а. Ключевые файлы (якоря кода)
| Файл | Что там |
|---|---|
src/main/kotlin/.../app/Main.kt | сборка всего вместе, репортер метрик, таймер retention, shutdown |
src/main/kotlin/.../app/BooblikConfig.kt | чтение и проверка всех ключей |
../ci/smoke.sh | проверка поставки: старт, обмен по проводу, рестарт |
3. Как устроено
Политика сброса — не долговечность. booblik.flush.every.* ограничивает окно потери:
при everyMillis=100 в худшем случае теряются последние сто миллисекунд принятого. Продюсеру,
которому ответили WRITTEN, ответили до всякого барьера, и фоновый сброс этого не меняет.
Ждёт барьера только FORCED. Путать эти две вещи — самый простой способ считать систему
надёжнее, чем она есть; вся история с msync (§1.9) случилась ровно так.
Оба триггера нужны вместе. Счётчик один оставляет простаивающий брокер с несброшенными данными навсегда: последние записи перед тем, как трафик прекратился, — как раз те, до которых счётчик уже не дойдёт. Таймер один игнорирует нагрузку, и всплеск успевает положить под удар больше, чем задумано.
Метрики печатаются скоростями, а не счётчиками. Счётчик, напечатанный раз в десять секунд, — это то, что читателю придётся дифференцировать в уме ровно в тот момент, когда он разбирает инцидент. Сами счётчики остаются в снимке.
Retention применяется отсюда, а не из брокера. У Broker.applyRetention нет часов: он делает
то, что сказали, когда сказали. Так тест двигает время вызовом, а не ожиданием, и здесь —
единственное место, которое решает «когда».
4. Зависимости
| Тип | Имя | Для чего |
|---|---|---|
| Module | :booblik-net | брокер, сервер, метрики |
5. Локальный запуск
./gradlew :booblik-app:run --args="broker.properties"Собрать дистрибутив:
./gradlew :booblik-app:installDistПроверить, что он действительно работает (это же гоняет CI):
./ci/smoke.sh6. Сознательные ограничения / грабли
- Дистрибутив стартует с тем же профилем JVM, что и все замеры (
applicationDefaultJvmArgs). Разойдись они — и каждое число в benchmarking описывало бы не тот процесс, который поставляется. booblik.metrics.interval.millis=0выключает строку метрик молча. Выключенная метрика неотличима от исправной работы, поэтому ноль стоит ставить осознанно.- Порядок остановки: сервер → фоновые задачи → брокер. Брокер закрывается последним и закрывает писателей первыми, так что принятый батч доезжает до диска раньше, чем исчезает лог под ним.
ci/smoke.shнашёл единственный настоящий баг вехи, которого не увидели тесты: писатель терял батч, если таймер сброса срабатывал одновременно с приходом сообщения. Тесты поднимают сервер из кода, а поставку проверяет только это.