Media is too big
VIEW IN TELEGRAM
С пятницей, коллеги!
Сегодня разбавляем серьезный контент... наболевшим🤯
В новом эпизоде нашего подкаста IT ToLк by EvApps системный аналитик Олег и мобильный разработчик Андрей разгоняют про боли и слёзы айтишников.
▶️ Четвертый эпизод уже в ВК - https://vk.cc/cPE3fD
Сегодня разбавляем серьезный контент... наболевшим🤯
В новом эпизоде нашего подкаста IT ToLк by EvApps системный аналитик Олег и мобильный разработчик Андрей разгоняют про боли и слёзы айтишников.
▶️ Четвертый эпизод уже в ВК - https://vk.cc/cPE3fD
🔥5😁1
Привет, друзья 👋
В этом посте завершаем нашу серию и рассмотрим два последних паттерна, которые могут быть полезны в ситуациях, когда требуется особая защита и автономность для контекстов.
Open-Host Service 🌐🔐
Этот паттерн противоположен Anticorruption Layer. Здесь Supplier создает защитный слой, чтобы обезопасить своих пользователей от изменений в своей системе. Он использует публичные контракты (published language), которые помогают изолировать изменения внутри Supplier и позволить ему развиваться автономно от нижележащих контекстов.
Separate Ways 🛑🚶♂️
Последний тип взаимодействия, по сути, исключает само взаимодействие между командами. Этот паттерн применяется в случаях, когда команды не могут или не хотят взаимодействовать по различным причинам.
Такая ситуация может возникнуть, если из-за организационных или политических факторов достижение согласия между командами занимает много времени и значительно увеличивает стоимость разработки. Также, если затраты на дублирование и поддержку функциональности (чаще всего это касается generic subdomains) ниже, чем на разработку общего решения и интеграцию между контекстами.
Иногда модели ограниченных контекстов настолько отличаются друг от друга, что использование паттернов типа Customer-Supplier становится слишком дорогим в реализации и обслуживании. В таких случаях проще и выгоднее просто продублировать функциональность, чем пытаться интегрировать её в рамках общего контекста.
Примечание: ⚠️ Следует избегать паттерна Separate Ways в реализации core subdomains.
#development #паттерны #openhostservice #separateways #boundedcontext
В этом посте завершаем нашу серию и рассмотрим два последних паттерна, которые могут быть полезны в ситуациях, когда требуется особая защита и автономность для контекстов.
Open-Host Service 🌐🔐
Этот паттерн противоположен Anticorruption Layer. Здесь Supplier создает защитный слой, чтобы обезопасить своих пользователей от изменений в своей системе. Он использует публичные контракты (published language), которые помогают изолировать изменения внутри Supplier и позволить ему развиваться автономно от нижележащих контекстов.
Separate Ways 🛑🚶♂️
Последний тип взаимодействия, по сути, исключает само взаимодействие между командами. Этот паттерн применяется в случаях, когда команды не могут или не хотят взаимодействовать по различным причинам.
Такая ситуация может возникнуть, если из-за организационных или политических факторов достижение согласия между командами занимает много времени и значительно увеличивает стоимость разработки. Также, если затраты на дублирование и поддержку функциональности (чаще всего это касается generic subdomains) ниже, чем на разработку общего решения и интеграцию между контекстами.
Иногда модели ограниченных контекстов настолько отличаются друг от друга, что использование паттернов типа Customer-Supplier становится слишком дорогим в реализации и обслуживании. В таких случаях проще и выгоднее просто продублировать функциональность, чем пытаться интегрировать её в рамках общего контекста.
Примечание: ⚠️ Следует избегать паттерна Separate Ways в реализации core subdomains.
#development #паттерны #openhostservice #separateways #boundedcontext
Привет 👋
💡 Сегодня разбираем базовую, но важную тему в Git — три способа интеграции изменений между ветками: Merge, Rebase и Fast-Forward.
Каждый из них влияет на историю коммитов и рабочий процесс команды.
🔀Merge
Объединяет изменения из одной ветки в другую, создавая отдельный merge-коммит.
Вид ветки: сохраняет полную и разветвлённую структуру — видно, где ветки расходились и сходились.
Когда использовать: при объединении фич в main ветку, когда важно сохранить контекст разработки, особенно в командной работе.
♻️Rebase
Переносит коммиты ветки на новую, обычно на актуальное состояние main ветки.
Вид ветки: становится линейной, без merge-коммитов — будто работа шла поверх main ветки.
Когда использовать: удобно для локальных веток, чтобы очистить историю перед слиянием.
⏩ Fast-Forward Merge
Происходит, если основная ветка не расходилась с твоей. В этом случае Git перемещает указатель вперёд без создания нового коммита.
Вид ветки: полностью линейная, как после rebase.
Когда использовать: если в целевой ветке не было других изменений. Можно указать флаг --ff-only.
📚Отличия:
Структура ветки: git merge сохраняет разветвлённую структуру с merge-коммитами; git rebase создаёт линейную структуру, переписывая коммиты; fast-forward даёт линейную структуру, перемещая указатель.
ID коммитов: git merge сохраняет оригинальные ID коммитов; git rebase создаёт новые ID для перебазированных коммитов.
Безопасность: git merge обычно безопаснее для общих веток, так как не переписывает историю; git rebase следует использовать с осторожностью на общих ветках из-за переписывания истории.
Выбирайте учитывая ваши рабочие процессы и приоритеты команды — что важнее: чистая история или точное сохранение контекста разработки.
🖥 Попрактиковаться с ветками и коммитами можно на интерактивном тренажёре: Learn Git Branching
#git #development #merge #rebase #fastforward #workflow
💡 Сегодня разбираем базовую, но важную тему в Git — три способа интеграции изменений между ветками: Merge, Rebase и Fast-Forward.
Каждый из них влияет на историю коммитов и рабочий процесс команды.
🔀Merge
Объединяет изменения из одной ветки в другую, создавая отдельный merge-коммит.
Вид ветки: сохраняет полную и разветвлённую структуру — видно, где ветки расходились и сходились.
Когда использовать: при объединении фич в main ветку, когда важно сохранить контекст разработки, особенно в командной работе.
♻️Rebase
Переносит коммиты ветки на новую, обычно на актуальное состояние main ветки.
Вид ветки: становится линейной, без merge-коммитов — будто работа шла поверх main ветки.
Когда использовать: удобно для локальных веток, чтобы очистить историю перед слиянием.
⏩ Fast-Forward Merge
Происходит, если основная ветка не расходилась с твоей. В этом случае Git перемещает указатель вперёд без создания нового коммита.
Вид ветки: полностью линейная, как после rebase.
Когда использовать: если в целевой ветке не было других изменений. Можно указать флаг --ff-only.
📚Отличия:
Структура ветки: git merge сохраняет разветвлённую структуру с merge-коммитами; git rebase создаёт линейную структуру, переписывая коммиты; fast-forward даёт линейную структуру, перемещая указатель.
ID коммитов: git merge сохраняет оригинальные ID коммитов; git rebase создаёт новые ID для перебазированных коммитов.
Безопасность: git merge обычно безопаснее для общих веток, так как не переписывает историю; git rebase следует использовать с осторожностью на общих ветках из-за переписывания истории.
Выбирайте учитывая ваши рабочие процессы и приоритеты команды — что важнее: чистая история или точное сохранение контекста разработки.
🖥 Попрактиковаться с ветками и коммитами можно на интерактивном тренажёре: Learn Git Branching
#git #development #merge #rebase #fastforward #workflow
learngitbranching.js.org
Learn Git Branching
An interactive Git visualization tool to educate and challenge!
👍5
Сегодня нейросетям всё чаще доверяют писать и править код, чтобы ускорить разработку.
Но нередко результат — день, потраченный на устранение хаоса.
Этот кейс — не обвинение ИИ, а напоминание: важно понимать, с чем мы работаем
💡 Почему нейросети ломают код?
Нейросеть — не разработчик, а языковая модель.
Она не понимает код — она предсказывает, что выглядит как правильный ответ.
Ее цель — звучать уверенно, а не быть точной.
Поэтому она может предложить «исправление», которое в итоге ломает всё.
Она видит не систему, а текст — и делает то, что статистически похоже на решение.
📘 1. Оптимизирован не под правду, а под уверенность.
Модель обучена звучать убедительно, даже если ошибается.
Её «награда» — не корректность, а ощущение правильности.
💻 2. Не тестируют и не исполняют.
Разработчик проверяет код, запускает тесты, видит окружение и файлы проекта.
AI-ассистенты, даже встроенные в редактор, могут «видеть» файлы и окружение, но не запускают код и не проверяют его работу.
Они просто предсказывают, как может выглядеть «фикс» — не зная, сработает ли он на самом деле.
🧠 3. Не помнит, а делает вид, что помнит.
Контекст диалога ограничен — старые детали теряются.
Но вместо того чтобы признаться, ИИ «достраивает» логику самостоятельно, будто всё под контролем.
⚙️ Нейросети не ломают системы специально.
Они делает это, потому что не понимают, что такое система.
Они не видят ваших дедлайнов, пользователей, окружения — только текст.
А когда текст становится единственной мерой истины, реальность перестаёт иметь значение.
ИИ не должен заменять разработчиков — ему нужны разработчики, которые помнят, как выглядит реальность.
Используйте его, чтобы усиливать свои навыки, а не подменять их.
Потому что в тот момент, когда вы отдаёте ему свой код — вы отдаёте ему контроль.
#ai #development #code #workflow #risk #vibe_coding
Но нередко результат — день, потраченный на устранение хаоса.
Этот кейс — не обвинение ИИ, а напоминание: важно понимать, с чем мы работаем
💡 Почему нейросети ломают код?
Нейросеть — не разработчик, а языковая модель.
Она не понимает код — она предсказывает, что выглядит как правильный ответ.
Ее цель — звучать уверенно, а не быть точной.
Поэтому она может предложить «исправление», которое в итоге ломает всё.
Она видит не систему, а текст — и делает то, что статистически похоже на решение.
📘 1. Оптимизирован не под правду, а под уверенность.
Модель обучена звучать убедительно, даже если ошибается.
Её «награда» — не корректность, а ощущение правильности.
💻 2. Не тестируют и не исполняют.
Разработчик проверяет код, запускает тесты, видит окружение и файлы проекта.
AI-ассистенты, даже встроенные в редактор, могут «видеть» файлы и окружение, но не запускают код и не проверяют его работу.
Они просто предсказывают, как может выглядеть «фикс» — не зная, сработает ли он на самом деле.
🧠 3. Не помнит, а делает вид, что помнит.
Контекст диалога ограничен — старые детали теряются.
Но вместо того чтобы признаться, ИИ «достраивает» логику самостоятельно, будто всё под контролем.
⚙️ Нейросети не ломают системы специально.
Они делает это, потому что не понимают, что такое система.
Они не видят ваших дедлайнов, пользователей, окружения — только текст.
А когда текст становится единственной мерой истины, реальность перестаёт иметь значение.
ИИ не должен заменять разработчиков — ему нужны разработчики, которые помнят, как выглядит реальность.
Используйте его, чтобы усиливать свои навыки, а не подменять их.
Потому что в тот момент, когда вы отдаёте ему свой код — вы отдаёте ему контроль.
#ai #development #code #workflow #risk #vibe_coding
🏆1
Forwarded from Двач
This media is not supported in your browser
VIEW IN TELEGRAM
ChatGPT, когда в очередной раз выдал говёный код с ошибкой:
Всем привет🖐
Недавно, у нас возникла идея рассмотреть lazy loading не только как инструмент оптимизации, но и как возможный способ защиты чувствительного кода.
Lazy-loading — это способ загружать модули, компоненты или шаблоны только тогда, когда они действительно нужны, а не при первом запуске приложения.
В React и других фреймворках это реализуется через:
- разделение модулей,
- конфигурацию роутов,
- отложенную загрузку компонентов.
Преимущества стандартны:
⚡️ быстреее начальная загрузка
📉 меньше трафика
🚀 выше производительность
В React это реализуется через React.lazy() и Suspense:
Такое разбиение кода уменьшает размер бандла и повышает скорость загрузки.
Во время разбирательств, мы заметили странную вещь — почти ни один фреймворк не упоминает lazy-loading в контексте безопасности. Только как оптимизацию.
Но если задуматься:
В серверно-рендеримых приложениях чувствительный код не возвращается клиенту, пока пользователь не прошёл аутентификацию.
В SPA всё иначе — весь код загружается сразу, даже тот, что должен быть доступен только после входа.
Lazy-loading позволяет решить это:
мы можем не загружать части приложения с чувствительной логикой до тех пор, пока пользователь не авторизован.
Вот пример с использованием OAuth2-библиотеки для клиентской аутентификации:
Вместо простого текста здесь может быть целый <ComplexApp /> — с десятками килобайт JS, потенциально раскрывающих уязвимости.
Решение: оборачивать такие блоки в <Suspense> и загружать их только после подтверждённой аутентификации.
Классическое SPA грузит всё и сразу, включая закрытый функционал.
Lazy-loading — загружает только то, что нужно конкретному пользователю в данный момент.
Это не «панацея» для безопасности, но важный слой защиты:
Чем меньше кода попадает в браузер, тем меньше поверхность атаки.
- Должны ли мы использовать lazy-loading не только ради скорости, но и ради защиты кода?
- Да. Определённо должны.
🧠 А вы что думаете? Встречали такой способ использования lazy-loading?
#webdev #security #architecture #frontend #development
Недавно, у нас возникла идея рассмотреть lazy loading не только как инструмент оптимизации, но и как возможный способ защиты чувствительного кода.
Lazy-loading — это способ загружать модули, компоненты или шаблоны только тогда, когда они действительно нужны, а не при первом запуске приложения.
В React и других фреймворках это реализуется через:
- разделение модулей,
- конфигурацию роутов,
- отложенную загрузку компонентов.
Преимущества стандартны:
⚡️ быстреее начальная загрузка
📉 меньше трафика
🚀 выше производительность
В React это реализуется через React.lazy() и Suspense:
const OtherComponent = React.lazy(() => import('./OtherComponent'));
function MyComponent() {
return (
<Suspense fallback={<div>Loading...</div>}>
<OtherComponent />
</Suspense>
);
}Такое разбиение кода уменьшает размер бандла и повышает скорость загрузки.
Во время разбирательств, мы заметили странную вещь — почти ни один фреймворк не упоминает lazy-loading в контексте безопасности. Только как оптимизацию.
Но если задуматься:
В серверно-рендеримых приложениях чувствительный код не возвращается клиенту, пока пользователь не прошёл аутентификацию.
В SPA всё иначе — весь код загружается сразу, даже тот, что должен быть доступен только после входа.
Lazy-loading позволяет решить это:
мы можем не загружать части приложения с чувствительной логикой до тех пор, пока пользователь не авторизован.
Вот пример с использованием OAuth2-библиотеки для клиентской аутентификации:
<AuthenticatedTemplate>
<p>Вход выполнен как: {user?.username}</p>
</AuthenticatedTemplate>
Вместо простого текста здесь может быть целый <ComplexApp /> — с десятками килобайт JS, потенциально раскрывающих уязвимости.
Решение: оборачивать такие блоки в <Suspense> и загружать их только после подтверждённой аутентификации.
Классическое SPA грузит всё и сразу, включая закрытый функционал.
Lazy-loading — загружает только то, что нужно конкретному пользователю в данный момент.
Это не «панацея» для безопасности, но важный слой защиты:
Чем меньше кода попадает в браузер, тем меньше поверхность атаки.
- Должны ли мы использовать lazy-loading не только ради скорости, но и ради защиты кода?
- Да. Определённо должны.
🧠 А вы что думаете? Встречали такой способ использования lazy-loading?
#webdev #security #architecture #frontend #development
❤3🔥3
Представьте: утро, обычный рабочий день.
Открываешь приложение — и что-то не так.
База не поднимается. Файлы повреждены. Или какой-то баг просто всё удалил.
В голове сразу мысль: «Ладно, не страшно — есть же бэкапы».
Но при попытке восстановить — тишина.
Архивы пустые, повреждённые или восстанавливаются бесконечно.
Горькая правда:
бэкап ничего не стоит, пока ты не попробовал его восстановить.
Недавно у одной из команд случилась такая история.
Меняли схему базы данных в одном из проектов, и во время миграции что-то пошло не так — SQLite база повредилась.
Попробовали развернуть резервную копию — но и она оказалась битой.
Позже выяснилось, что копирование шло в тот момент, когда приложение ещё писало данные.
Система месяцами создавала битые бэкапы — и никто не знал, потому что восстановление ни разу не проверялось.
К счастью, это были тестовые данные. Но если бы прод?
Пользовательские данные, проект, репутация — всё под угрозой.
Часто живёшь в иллюзии, что раз бэкап есть — значит, всё под контролем.
На деле это копия, которая может не сработать в тот момент, когда она нужна.
Что важно бэкапить:
🧠 Код — GitHub, GitLab
🗄 Базу — Postgres, MySQL, Supabase, SQLite
🖼 Файлы пользователей — изображения, документы
🔐 Конфиги и секреты — .env, API-ключи, настройки деплоя
Главная ошибка:
ты не знаешь, работает ли бэкап, пока не попробуешь восстановление.
Без этого — он как кот Шрёдингера, запертый в коробке.
Как делают большие компании:
— GitLab ежедневно тестирует восстановление и следит за метриками
— Basecamp проводит «тесты катастроф» — симулирует исчезновение датацентра
Типовая схема:
• Делать бэкапы автоматически (ночные дампы, снапшоты)
• Восстанавливать в тестовую среду
• Проверять: база поднимается, файлы читаются, логин работает (плюс smoke-тесты)
• Отправлять алерты при сбоях
• Периодически симулировать сбой и измерять скорость восстановления
Что и как проверять:
💻 Код: Push в GitHub/GitLab (с 2FA) → клонировать в новую папку и собрать проект
🗄 База данных: pg_dump / .backup / PITR → восстановить в тестовую БД и проверить данные
🖼 Файлы пользователей: S3 / B2 / GCS → случайно скачать несколько файлов и открыть
🔐 Конфиги и секреты: 1Password / Bitwarden / VeraCrypt → запустить проект, используя только эти конфиги
💡 Для SQLite:
копирование живой .db может её повредить.
Используй:
sqlite3 mydb.db "VACUUM INTO backup.db"
Так создаётся чистая копия без ошибок.
Когда тестировать восстановление:
— Раз в месяц: локально проверить случайный бэкап
— Раз в квартал: полный тест — база + файлы + приложение
— Раз в год: симулировать потерю устройства и попробовать вернуть
Почему это важно:
Один сбой может уничтожить проект, если вы не проверяли восстановление.
Теперь бэкапы делаются не ради спокойствия,
а ради уверенности, что смогу восстановиться.
Потому что бэкапы — это не паранойя.
Это способ быть уверенным, что завтра твой проект не исчезнет. ❤️
#backup #development #risk #code
Открываешь приложение — и что-то не так.
База не поднимается. Файлы повреждены. Или какой-то баг просто всё удалил.
В голове сразу мысль: «Ладно, не страшно — есть же бэкапы».
Но при попытке восстановить — тишина.
Архивы пустые, повреждённые или восстанавливаются бесконечно.
Горькая правда:
бэкап ничего не стоит, пока ты не попробовал его восстановить.
Недавно у одной из команд случилась такая история.
Меняли схему базы данных в одном из проектов, и во время миграции что-то пошло не так — SQLite база повредилась.
Попробовали развернуть резервную копию — но и она оказалась битой.
Позже выяснилось, что копирование шло в тот момент, когда приложение ещё писало данные.
Система месяцами создавала битые бэкапы — и никто не знал, потому что восстановление ни разу не проверялось.
К счастью, это были тестовые данные. Но если бы прод?
Пользовательские данные, проект, репутация — всё под угрозой.
Часто живёшь в иллюзии, что раз бэкап есть — значит, всё под контролем.
На деле это копия, которая может не сработать в тот момент, когда она нужна.
Что важно бэкапить:
🧠 Код — GitHub, GitLab
🗄 Базу — Postgres, MySQL, Supabase, SQLite
🖼 Файлы пользователей — изображения, документы
🔐 Конфиги и секреты — .env, API-ключи, настройки деплоя
Главная ошибка:
ты не знаешь, работает ли бэкап, пока не попробуешь восстановление.
Без этого — он как кот Шрёдингера, запертый в коробке.
Как делают большие компании:
— GitLab ежедневно тестирует восстановление и следит за метриками
— Basecamp проводит «тесты катастроф» — симулирует исчезновение датацентра
Типовая схема:
• Делать бэкапы автоматически (ночные дампы, снапшоты)
• Восстанавливать в тестовую среду
• Проверять: база поднимается, файлы читаются, логин работает (плюс smoke-тесты)
• Отправлять алерты при сбоях
• Периодически симулировать сбой и измерять скорость восстановления
Что и как проверять:
💻 Код: Push в GitHub/GitLab (с 2FA) → клонировать в новую папку и собрать проект
🗄 База данных: pg_dump / .backup / PITR → восстановить в тестовую БД и проверить данные
🖼 Файлы пользователей: S3 / B2 / GCS → случайно скачать несколько файлов и открыть
🔐 Конфиги и секреты: 1Password / Bitwarden / VeraCrypt → запустить проект, используя только эти конфиги
💡 Для SQLite:
копирование живой .db может её повредить.
Используй:
sqlite3 mydb.db "VACUUM INTO backup.db"
Так создаётся чистая копия без ошибок.
Когда тестировать восстановление:
— Раз в месяц: локально проверить случайный бэкап
— Раз в квартал: полный тест — база + файлы + приложение
— Раз в год: симулировать потерю устройства и попробовать вернуть
Почему это важно:
Один сбой может уничтожить проект, если вы не проверяли восстановление.
Теперь бэкапы делаются не ради спокойствия,
а ради уверенности, что смогу восстановиться.
Потому что бэкапы — это не паранойя.
Это способ быть уверенным, что завтра твой проект не исчезнет. ❤️
#backup #development #risk #code
❤7
🚀 Почему dev-серверы часто запускаются на localhost:3000 (и сейчас ещё на 5173)
Когда ты запускаешь сервер localhost:3000 или localhost:5173, это не случайность.
За этими портами — история веб-разработки: от Ruby on Rails и Java до Node.js и Vite.
💡 Что такое порт?
Порт — это номер, по которому на компьютере слушает сервис.
Представь, что твой компьютер — это здание, а порты — двери с номерами.
Когда ты заходишь на localhost:3000, ты буквально открываешь дверь № 3000, чтобы увидеть своё приложение.
Всего таких дверей 65 535:
🔹 0–1023 — системные (HTTP 80, HTTPS 443, SSH 22)
🔹 1024–49151 — пользовательские (3000, 8000, 8080 и др.)
🔹 49152–65535 — временные (используются ОС)
Так что 3000 — просто одно из множества возможных значений.
⚙️ Порт 3000 — путь от Rails к Node.js
В Ruby on Rails по умолчанию сервер разработки запускался на 3000.
Позже, с ростом Node.js и Express, в официальных примерах часто встречалась строка:
Эта привычка закрепилась: её копировали в туториалах, курсах и шаблонах.
React, Next.js и другие фреймворки просто продолжили эту традицию.
Сегодня 3000 — неофициальный “Hello World” порт веб-разработки.
🐍 Порт 8000 — классика Python
Ещё до Node, Python-разработчики поднимали локальные HTTP-сервера командой:
По умолчанию сервер слушал 8000 — безопасный номер, не требующий прав администратора.
Фреймворк Django тоже выбрал этот порт.
Со временем 8000 стал синонимом “запустил и проверил локально”.
☕️ Порт 8080 — наследие Java
В 90-х порты ниже 1024 требовали root-прав.
Java-разработчики из Apache Tomcat и Jetty придумали обход:
80 → 8080
Выглядит похоже, но работает без повышенных прав.
С тех пор 8080 стал стандартом для “серьёзных” серверов вроде Spring Boot.
⚡️ Порт 5173 — современный штрих от Vite
Когда появился Vite, авторы выбрали порт с пасхалкой:
51 = VI
73 = TE
👉 5173 = VITE 😎
Теперь каждый npm run dev открывает localhost:5173 — фирменный почерк нового поколения фронтенда.
🧠 Можно ли использовать другие порты?
Конечно!
Многие привыкают к 3000 и паникуют, увидев:
Но свободных портов тысячи.
Попробуй:
И никаких конфликтов 😄
🕰 Заключение
8080 — обход ограничений Java
8000 — прагматичный выбор Python
3000 — наследие Rails и Node.js
5173 — фирменный порт Vite
Эти цифры — не просто числа.
Это часть истории веб-разработки с 90-х годов.
Когда в следующий раз запустишь:
👉 http://localhost:3000/
вспомни — за этим числом десятилетия привычек и технологий.
Если порт занят — не убивай процесс.
Просто выбери другое число.
Сделай его своим фирменным портом 😉
Безопасный диапазон: 1024–49151
И когда будешь запускать сервер — делай это с уважением😁
А вы оставляете порт по умолчанию или меняете на свой?
#development #webdev #frontend #backend
Когда ты запускаешь сервер localhost:3000 или localhost:5173, это не случайность.
За этими портами — история веб-разработки: от Ruby on Rails и Java до Node.js и Vite.
💡 Что такое порт?
Порт — это номер, по которому на компьютере слушает сервис.
Представь, что твой компьютер — это здание, а порты — двери с номерами.
Когда ты заходишь на localhost:3000, ты буквально открываешь дверь № 3000, чтобы увидеть своё приложение.
Всего таких дверей 65 535:
🔹 0–1023 — системные (HTTP 80, HTTPS 443, SSH 22)
🔹 1024–49151 — пользовательские (3000, 8000, 8080 и др.)
🔹 49152–65535 — временные (используются ОС)
Так что 3000 — просто одно из множества возможных значений.
⚙️ Порт 3000 — путь от Rails к Node.js
В Ruby on Rails по умолчанию сервер разработки запускался на 3000.
Позже, с ростом Node.js и Express, в официальных примерах часто встречалась строка:
app.listen(3000, () => console.log('Server running on port 3000'));Эта привычка закрепилась: её копировали в туториалах, курсах и шаблонах.
React, Next.js и другие фреймворки просто продолжили эту традицию.
Сегодня 3000 — неофициальный “Hello World” порт веб-разработки.
🐍 Порт 8000 — классика Python
Ещё до Node, Python-разработчики поднимали локальные HTTP-сервера командой:
python3 -m http.server
По умолчанию сервер слушал 8000 — безопасный номер, не требующий прав администратора.
Фреймворк Django тоже выбрал этот порт.
Со временем 8000 стал синонимом “запустил и проверил локально”.
☕️ Порт 8080 — наследие Java
В 90-х порты ниже 1024 требовали root-прав.
Java-разработчики из Apache Tomcat и Jetty придумали обход:
80 → 8080
Выглядит похоже, но работает без повышенных прав.
С тех пор 8080 стал стандартом для “серьёзных” серверов вроде Spring Boot.
⚡️ Порт 5173 — современный штрих от Vite
Когда появился Vite, авторы выбрали порт с пасхалкой:
51 = VI
73 = TE
👉 5173 = VITE 😎
Теперь каждый npm run dev открывает localhost:5173 — фирменный почерк нового поколения фронтенда.
🧠 Можно ли использовать другие порты?
Конечно!
Многие привыкают к 3000 и паникуют, увидев:
Error: Port 3000 already in use
Но свободных портов тысячи.
Попробуй:
npm run dev -- --port=42069
vite --port=13337
И никаких конфликтов 😄
🕰 Заключение
8080 — обход ограничений Java
8000 — прагматичный выбор Python
3000 — наследие Rails и Node.js
5173 — фирменный порт Vite
Эти цифры — не просто числа.
Это часть истории веб-разработки с 90-х годов.
Когда в следующий раз запустишь:
👉 http://localhost:3000/
вспомни — за этим числом десятилетия привычек и технологий.
Если порт занят — не убивай процесс.
Просто выбери другое число.
Сделай его своим фирменным портом 😉
Безопасный диапазон: 1024–49151
И когда будешь запускать сервер — делай это с уважением😁
А вы оставляете порт по умолчанию или меняете на свой?
#development #webdev #frontend #backend
👍5🔥1
🚀 Наши друзья из Intelsy проводят вебинар для тех, кто руководит ИТ и хочет навести порядок в хаосе 1С-проектов - а мы такое всецело поддерживаем!
Тема: Будни ИТ-директора: стабильность, быстродействие, борьба с 1С
Дата: 6 ноября в 11:00 по мск
Формат: открытый разговор без маркетинговых лозунгов
О чем поговорим:
– какие вопросы тянет на себе ИТ-директор;
– зачем нужны внешние спецы при собственном штате;
– к кому обращаться за ресурсами и как не ошибиться;
– как работает обращение к внешним ресурсам и что остается за кадром.
📍 Регистрация — по ссылке, без спама и рассылок.
Вебинар
Вебинар
Вебинар
🔥 Залетай, если хочешь меньше хаоса и больше стабильности в своих 1С-проектах.
Тема: Будни ИТ-директора: стабильность, быстродействие, борьба с 1С
Дата: 6 ноября в 11:00 по мск
Формат: открытый разговор без маркетинговых лозунгов
О чем поговорим:
– какие вопросы тянет на себе ИТ-директор;
– зачем нужны внешние спецы при собственном штате;
– к кому обращаться за ресурсами и как не ошибиться;
– как работает обращение к внешним ресурсам и что остается за кадром.
📍 Регистрация — по ссылке, без спама и рассылок.
Вебинар
Вебинар
Вебинар
🔥 Залетай, если хочешь меньше хаоса и больше стабильности в своих 1С-проектах.
🚀 Почему спор про Tailwind vs CSS до сих пор живет?
И причина не в том, что один инструмент «лучше».
Просто веб-разработка изменилась, а подходы к стилям — нетривиальны и оба имеют вес.
Сегодня Tailwind часто выбирают там, где важна скорость.
Командам проще двигаться, когда шрифты, отступы и цвета уже определены.
Разработчикам удобно — пишешь классы, видишь результат сразу.
Дизайн получается единообразным, а адаптивность решается прямо в разметке, без дополнительных медиа запросов.
Но обратная сторона тоже очевидна.
Разметка становится перегруженной.
В инструмент добавляется зависимость от сборки, конфигурации, среды.
Отладка усложняется: чтобы понять, почему элемент выглядит так, приходится разбираться в наборе utility-классов, а не открывать небольшой фрагмент CSS.
Пример привычного Tailwind-фрагмента:
Работает. Быстро. Но выглядит не всегда читаемо.
С другой стороны, классический CSS постепенно переживает второе дыхание .
Никаких дополнительных инструментов, чистая структура проекта, читаемость.
Современные возможности языка закрывают задачи, которые раньше требовали Tailwind или препроцессоры: container queries, nesting, cascade layers, :has(), переменные — всё это теперь доступно нативно.
Пример варианта на чистом CSS:
Читается. Легко рефакторится. Но требует самодисциплины, принятой методологии и аккуратности, иначе проект быстро теряет структуру.
🎯 И в итоге вопрос уже не звучит как «что лучше».
Tailwind — это про темп, единообразие и скорость вывода продукта.
CSS — про прозрачность, контроль и устойчивость без зависимостей.
В реальных командах в 2026-м всё выглядит проще:
часть задач удобно решать utility-классами, часть — обычными стилями.
Tailwind часто используют как систему отступов и цветов, а более сложные компоненты пишут вручную.
Настоящий сдвиг — в том, что разработчики наконец начали изучать сам CSS глубже. Tailwind помог ускорить работу, но современные возможности языка вернули интерес к фундаменту.
Скорость важна, но и понятный код никто не отменял.
Поэтому и Tailwind, и CSS останутся. Не как конкуренты — как инструменты для разных ситуаций.
А на чьей стороне ты, Tailwind или CSS❓
#frontend #web #development #clear_code #чистый_код
И причина не в том, что один инструмент «лучше».
Просто веб-разработка изменилась, а подходы к стилям — нетривиальны и оба имеют вес.
Сегодня Tailwind часто выбирают там, где важна скорость.
Командам проще двигаться, когда шрифты, отступы и цвета уже определены.
Разработчикам удобно — пишешь классы, видишь результат сразу.
Дизайн получается единообразным, а адаптивность решается прямо в разметке, без дополнительных медиа запросов.
Но обратная сторона тоже очевидна.
Разметка становится перегруженной.
В инструмент добавляется зависимость от сборки, конфигурации, среды.
Отладка усложняется: чтобы понять, почему элемент выглядит так, приходится разбираться в наборе utility-классов, а не открывать небольшой фрагмент CSS.
Пример привычного Tailwind-фрагмента:
<button
class="px-4 py-2 rounded-md bg-indigo-600 text-white font-medium
transition hover:bg-indigo-700 hover:-translate-y-1">
Button
</button>
Работает. Быстро. Но выглядит не всегда читаемо.
С другой стороны, классический CSS постепенно переживает второе дыхание .
Никаких дополнительных инструментов, чистая структура проекта, читаемость.
Современные возможности языка закрывают задачи, которые раньше требовали Tailwind или препроцессоры: container queries, nesting, cascade layers, :has(), переменные — всё это теперь доступно нативно.
Пример варианта на чистом CSS:
<button class="btn">Button</button>
.btn {
padding: .5rem 1rem;
background: #4f46e5;
color: #fff;
border-radius: .5rem;
font-weight: 500;
transition: .2s;
}
.btn:hover {
background: #4338ca;
transform: translateY(-4px);
}
Читается. Легко рефакторится. Но требует самодисциплины, принятой методологии и аккуратности, иначе проект быстро теряет структуру.
🎯 И в итоге вопрос уже не звучит как «что лучше».
Tailwind — это про темп, единообразие и скорость вывода продукта.
CSS — про прозрачность, контроль и устойчивость без зависимостей.
В реальных командах в 2026-м всё выглядит проще:
часть задач удобно решать utility-классами, часть — обычными стилями.
Tailwind часто используют как систему отступов и цветов, а более сложные компоненты пишут вручную.
Настоящий сдвиг — в том, что разработчики наконец начали изучать сам CSS глубже. Tailwind помог ускорить работу, но современные возможности языка вернули интерес к фундаменту.
Скорость важна, но и понятный код никто не отменял.
Поэтому и Tailwind, и CSS останутся. Не как конкуренты — как инструменты для разных ситуаций.
А на чьей стороне ты, Tailwind или CSS❓
#frontend #web #development #clear_code #чистый_код
Всем привет!
Стартуем линейку постов про транзакции.
🔍 Зачем нужны транзакции и что такое ACID в MySQL + Laravel
Когда проект растёт, главное — не код, а данные.
Если данные кривые → бизнес страдает, деньги теряются, пользователи бесятся.
И вся эта история держится на одной штуке — транзакции.
🔥 Что такое транзакция
Транзакция — это группа операций, которая должна выполниться как одно целое.
Либо всё выполняется, либо ничего.
Представь последовательность:
- списать деньги
- создать заказ
- уменьшить остатки
Если один шаг упал → откатываем всё назад, как будто ничего не было.
Это и спасает от «битых» данных.
🎯 ACID — 4 принципа надёжных транзакций
A — Atomicity (атомарность)
Все изменения — как один выстрел.
Если внутри что-то упало → откат всей пачки.
Пример: списали деньги, но заказ не создался — Atomicity не даст оставить данные в полурежиме.
C — Consistency (согласованность)
Данные обязаны соблюдать правила БД:
- внешние ключи
- ограничения
- уникальность
- валидность значений
Если до транзакции данные были норм — после тоже должны быть.
Это защита от «сломал базу случайно».
I — Isolation (изолированность)
Параллельные запросы не должны портить друг другу картину мира.
Без Isolation возможны ситуации:
- два человека покупают последний товар одновременно
- два процесса списывают деньги по старому балансу
- кто-то читает недописанные данные
Изоляция не допускает такого.
D — Durability (надёжность)
Если транзакция зафиксировалась — данные не пропадут даже при:
- падении сервера
- сбое питания
- перезапуске MySQL
InnoDB пишет всё в журнал, чтобы восстановить изменения.
🧩 Итог
Транзакции — базовый предохранитель реальных продуктов.
Они не дают платежам списаться дважды, заказам зависнуть в «полусозданном» состоянии, а бронированиям ломать расписание.
Многошаговая операция либо проходит полностью, либо откатывается — и бизнес работает без сюрпризов.
Следите за серией постов — дальше будем развивать эту тему😊
#transactions #db #development #webdev #mysql #laravel
Стартуем линейку постов про транзакции.
🔍 Зачем нужны транзакции и что такое ACID в MySQL + Laravel
Когда проект растёт, главное — не код, а данные.
Если данные кривые → бизнес страдает, деньги теряются, пользователи бесятся.
И вся эта история держится на одной штуке — транзакции.
🔥 Что такое транзакция
Транзакция — это группа операций, которая должна выполниться как одно целое.
Либо всё выполняется, либо ничего.
Представь последовательность:
- списать деньги
- создать заказ
- уменьшить остатки
Если один шаг упал → откатываем всё назад, как будто ничего не было.
Это и спасает от «битых» данных.
🎯 ACID — 4 принципа надёжных транзакций
A — Atomicity (атомарность)
Все изменения — как один выстрел.
Если внутри что-то упало → откат всей пачки.
Пример: списали деньги, но заказ не создался — Atomicity не даст оставить данные в полурежиме.
C — Consistency (согласованность)
Данные обязаны соблюдать правила БД:
- внешние ключи
- ограничения
- уникальность
- валидность значений
Если до транзакции данные были норм — после тоже должны быть.
Это защита от «сломал базу случайно».
I — Isolation (изолированность)
Параллельные запросы не должны портить друг другу картину мира.
Без Isolation возможны ситуации:
- два человека покупают последний товар одновременно
- два процесса списывают деньги по старому балансу
- кто-то читает недописанные данные
Изоляция не допускает такого.
D — Durability (надёжность)
Если транзакция зафиксировалась — данные не пропадут даже при:
- падении сервера
- сбое питания
- перезапуске MySQL
InnoDB пишет всё в журнал, чтобы восстановить изменения.
🧩 Итог
Транзакции — базовый предохранитель реальных продуктов.
Они не дают платежам списаться дважды, заказам зависнуть в «полусозданном» состоянии, а бронированиям ломать расписание.
Многошаговая операция либо проходит полностью, либо откатывается — и бизнес работает без сюрпризов.
Следите за серией постов — дальше будем развивать эту тему😊
#transactions #db #development #webdev #mysql #laravel
👍2
Media is too big
VIEW IN TELEGRAM
💥 Врываемся в твой понедельник с новым эпизодом подкаста IT ToLк!
На этот раз расспросили нашего CEO Альфреда Столяровао галерах об аутстаффинге - и всех самых страшных мифах про это дело 👀
➡️ Смотри скорее по ссылке
На этот раз расспросили нашего CEO Альфреда Столярова
➡️ Смотри скорее по ссылке
И снова всем привет)
Продолжаем линейку постов про транзакции.
🔧 Транзакции в MySQL: нюансы▶️ MySQL / InnoDB
Если хочешь, чтобы транзакции работали как надо, таблицы должны быть в InnoDB.
Почему:
- построчные блокировки, а не блокировка всей таблицы
- поддержка внешних ключей
- нормальная атомарность и откаты
- корректная работа уровней изоляции
MyISAM — не подходит, он использует устаревший движок без поддержки транзакций, использующий блокировки всей таблицы.
В продакшене его применение создаёт серьёзные ограничения и повышает риски некорректной работы с данными.
▶️ Уровень изоляции
В MySQL (InnoDB) уровень изоляции по умолчанию — REPEATABLE READ.
Он обеспечивает работу транзакции со стабильным снимком данных: все повторные SELECT внутри одной транзакции возвращают одну и ту же версию строк, даже если параллельные транзакции их уже изменили.
❗️Каждый уровень изоляции определяет, какие аномалии конкурентного доступа возможны:
- Dirty reads — чтение незакоммиченных данных другой транзакции.
- Non-repeatable reads — одна и та же строка возвращает разные значения в рамках одной транзакции.
- Phantom reads — при повторном запросе появляются новые строки, которых не было в первой выборке.
В InnoDB dirty reads исключены автоматически (READ UNCOMMITTED фактически не используется).
REPEATABLE READ блокирует non-repeatable reads, но фантомы сохраняются, что на нагруженных системах может приводить к гонкам в логике проверки и вставки данных.
При необходимости максимально строгой модели используют SERIALIZABLE.
Этот уровень устраняет фантомы, но делает все операции чтения потенциально блокирующими, что резко снижает производительность.
Поэтому его применяют точечно, только там, где фантомы действительно критичны для корректности
▶️ DDL и транзакции: почему MySQL делает implicit commit
В MySQL операции изменения структуры данных (DDL) автоматически вызывают commit до и после выполнения.
Этот механизм встроен в движок и не зависит ни от приложения, ни от фреймворка.
Какие команды вызывают implicit commit:
- CREATE TABLE
- ALTER TABLE
- DROP TABLE / DROP INDEX
- TRUNCATE
- RENAME TABLE
- CREATE/DROP VIEW
- SET AUTOCOMMIT = 1
Как только выполняется любая из этих команд:
1.MySQL выполняет скрытый commit текущей транзакции.
2.Выполняет DDL.
3.Делает ещё один скрытый commit после DDL.
Это означает, что откатить изменения, выполненные до DDL, невозможно — они уже зафиксированы.
Пример сценария:
1. START TRANSACTION;
2. Вставляем данные.
3. Выполняем ALTER TABLE.
4. MySQL автоматически коммитит всё, что было до команды.
5. Попытка ROLLBACK уже не влияет на вставленные данные.
Это критичное поведение, которое разработчик обязан учитывать.
Laravel или любой ORM не могут перехватить или отменить implicit commit, потому что решение принимает сам MySQL на уровне протокола.
⚠️Последствия использования DDL внутри бизнес-операций:
- невозможность гарантировать атомарность операций
- риск частично записанных данных
- неконтролируемые состояния при сбоях
- нарушение инвариантов бизнес-логики
Поэтому DDL строго отделяют от обычных транзакций:
- применяют только через миграции
- выполняют в отдельные деплой-этапы
- не допускают вызовов в runtime
Это базовое правило эксплуатации MySQL в продакшене.
#transactions #db #development #webdev #mysql #DDL #innoDB
Продолжаем линейку постов про транзакции.
🔧 Транзакции в MySQL: нюансы▶️ MySQL / InnoDB
Если хочешь, чтобы транзакции работали как надо, таблицы должны быть в InnoDB.
Почему:
- построчные блокировки, а не блокировка всей таблицы
- поддержка внешних ключей
- нормальная атомарность и откаты
- корректная работа уровней изоляции
MyISAM — не подходит, он использует устаревший движок без поддержки транзакций, использующий блокировки всей таблицы.
В продакшене его применение создаёт серьёзные ограничения и повышает риски некорректной работы с данными.
▶️ Уровень изоляции
В MySQL (InnoDB) уровень изоляции по умолчанию — REPEATABLE READ.
Он обеспечивает работу транзакции со стабильным снимком данных: все повторные SELECT внутри одной транзакции возвращают одну и ту же версию строк, даже если параллельные транзакции их уже изменили.
❗️Каждый уровень изоляции определяет, какие аномалии конкурентного доступа возможны:
- Dirty reads — чтение незакоммиченных данных другой транзакции.
- Non-repeatable reads — одна и та же строка возвращает разные значения в рамках одной транзакции.
- Phantom reads — при повторном запросе появляются новые строки, которых не было в первой выборке.
В InnoDB dirty reads исключены автоматически (READ UNCOMMITTED фактически не используется).
REPEATABLE READ блокирует non-repeatable reads, но фантомы сохраняются, что на нагруженных системах может приводить к гонкам в логике проверки и вставки данных.
При необходимости максимально строгой модели используют SERIALIZABLE.
Этот уровень устраняет фантомы, но делает все операции чтения потенциально блокирующими, что резко снижает производительность.
Поэтому его применяют точечно, только там, где фантомы действительно критичны для корректности
▶️ DDL и транзакции: почему MySQL делает implicit commit
В MySQL операции изменения структуры данных (DDL) автоматически вызывают commit до и после выполнения.
Этот механизм встроен в движок и не зависит ни от приложения, ни от фреймворка.
Какие команды вызывают implicit commit:
- CREATE TABLE
- ALTER TABLE
- DROP TABLE / DROP INDEX
- TRUNCATE
- RENAME TABLE
- CREATE/DROP VIEW
- SET AUTOCOMMIT = 1
Как только выполняется любая из этих команд:
1.MySQL выполняет скрытый commit текущей транзакции.
2.Выполняет DDL.
3.Делает ещё один скрытый commit после DDL.
Это означает, что откатить изменения, выполненные до DDL, невозможно — они уже зафиксированы.
Пример сценария:
1. START TRANSACTION;
2. Вставляем данные.
3. Выполняем ALTER TABLE.
4. MySQL автоматически коммитит всё, что было до команды.
5. Попытка ROLLBACK уже не влияет на вставленные данные.
Это критичное поведение, которое разработчик обязан учитывать.
Laravel или любой ORM не могут перехватить или отменить implicit commit, потому что решение принимает сам MySQL на уровне протокола.
⚠️Последствия использования DDL внутри бизнес-операций:
- невозможность гарантировать атомарность операций
- риск частично записанных данных
- неконтролируемые состояния при сбоях
- нарушение инвариантов бизнес-логики
Поэтому DDL строго отделяют от обычных транзакций:
- применяют только через миграции
- выполняют в отдельные деплой-этапы
- не допускают вызовов в runtime
Это базовое правило эксплуатации MySQL в продакшене.
#transactions #db #development #webdev #mysql #DDL #innoDB
🔥1
Forwarded from Julia Reznichenko
Внимание, у нас важная новость - мы запустили пилотную программу по системному анализу! 🚀
И это не очередной «курс» на просторах интернета - это безопасное пространство, чтобы попробовать, ошибиться, разобраться и увидеть, как все устроено изнутри.
Мы сделали упор на практику и живую поддержку наставников.
Что будем делать?
🔹 Погрузимся в основы, которые реально работают в проектах.
🔹 Разберем живую систему и создадим настоящую документацию.
🔹 Проведем авторские мастер-классы - на них можно будет потрогать технологии руками и увидеть, как они работают изнутри.
🤗 Учимся без перегруза: в формате индивидуальных разборов, небольших встреч и лёгких игр. И, конечно, даём обратную связь по каждому заданию.
Это пилот, и в будущем мы планируем набирать только маленькие группы до 5 человек. Нам важен результат и реальный опыт каждого 💪
Мы долго готовились, чтобы поделиться тем, что проверили годами практики!
Первый поток ведет лично наш руководитель отдела системного анализа Оксана Соболевская ❤️
У Оксаны за плечами многолетний опыт в анализе и целый отдел аналитиков, который она создала с нуля!
Следите за обновлениями: обязательно расскажем, как все проходит, и о следующих наборах тоже сообщим - у нас уже открыт лист ожидания😉
❗️Если ты тоже хочешь в нем оказаться, пиши нам на почту hr@evapps.ru
И это не очередной «курс» на просторах интернета - это безопасное пространство, чтобы попробовать, ошибиться, разобраться и увидеть, как все устроено изнутри.
Мы сделали упор на практику и живую поддержку наставников.
Что будем делать?
🔹 Погрузимся в основы, которые реально работают в проектах.
🔹 Разберем живую систему и создадим настоящую документацию.
🔹 Проведем авторские мастер-классы - на них можно будет потрогать технологии руками и увидеть, как они работают изнутри.
🤗 Учимся без перегруза: в формате индивидуальных разборов, небольших встреч и лёгких игр. И, конечно, даём обратную связь по каждому заданию.
Это пилот, и в будущем мы планируем набирать только маленькие группы до 5 человек. Нам важен результат и реальный опыт каждого 💪
Мы долго готовились, чтобы поделиться тем, что проверили годами практики!
Первый поток ведет лично наш руководитель отдела системного анализа Оксана Соболевская ❤️
У Оксаны за плечами многолетний опыт в анализе и целый отдел аналитиков, который она создала с нуля!
Следите за обновлениями: обязательно расскажем, как все проходит, и о следующих наборах тоже сообщим - у нас уже открыт лист ожидания😉
❗️Если ты тоже хочешь в нем оказаться, пиши нам на почту hr@evapps.ru
❤1
Сегодня завершим нашу линейку постов про транзакции.
🚨 1) Внешние действия внутри транзакции = проблемы
Любой внешний вызов внутри транзакции может выполниться два и более раз, потому что Laravel автоматически повторяет транзакцию при дедлоках и таймаутах.
DB::transaction($callback, $attempts) сам делает retry, если произошёл:
- дедлок
- lock wait timeout
- потеря блокировки
И важно: При повторе он запускает весь callback с нуля.
Он не понимает, что там было «одноразовым», а что идемпотентным.
Что под раздачу попадает:
- отправка писем
- пуши
- внешние HTTP-запросы
- интеграции (CRM, платёжки)
Если транзакция упала и Laravel её перезапустил → действие повторится, потому что MySQL откатывает только свои изменения, а внешние вызовы уже произошли и не откатываются.
Как избежать:
- всё внешнее — только после commit
- использовать afterCommit() у моделей или dispatch(fn)->afterCommit() — так действие выполняется один раз, после успешной фиксации данных.
🔒 2) Дедлоки из-за порядка блокировок
Дедлок (deadlock) — ситуация, когда две и более транзакций ожидают друг друга бесконечно, и MySQL вынужден прервать одну из них, чтобы система продолжила работать.
Чаще всего дедлоки возникают не из-за MySQL как такового, а из-за разного порядка, в котором код блокирует строки или ресурсы.
Пример типичной ситуации:
- Транзакция A начинает и лочит строки 5 → 10
- Транзакция B начинает и лочит строки 10 → 5
MySQL обнаруживает тупик и прерывает одну транзакцию с ошибкой Deadlock found.
Как снизить риск:
1. Всегда блокировать строки в одном порядке
Обычно по возрастанию ID, чтобы исключить циклические ожидания.
2. Использовать блокировки корректно
- FOR UPDATE — эксклюзивная блокировка для изменения
- sharedLock() — блокировка для чтения без мешающих других читателей
3. Минимизировать время удержания блокировок
Чем быстрее транзакция завершится, тем ниже шанс дедлока.
4. Разделять независимые операции
Операции по разным таблицам или сущностям лучше выполнять в отдельных транзакциях, чтобы не увеличивать зону возможного конфликта.
🌐 3) Когда транзакции не работают вообще
Стандартные транзакции работают только в рамках одной базы данных и одного соединения.
Если операция затрагивает:
- несколько сервисов (например, микросервисы с разной логикой),
- несколько БД (разные инстансы, разные схемы),
- внешние API (CRM, платёжные системы, сторонние интеграции),то гарантировать атомарность стандартной транзакцией невозможно.
Причина: транзакция контролирует только изменения внутри конкретного движка базы данных.
Внешние действия, например HTTP-запросы или вызовы другой БД, не могут быть откатаны автоматически при ошибке — их состояние уже “зафиксировано” в сторонней системе.
🔹4) Стандартный подход — Saga pattern
Saga pattern — это архитектурный паттерн для управления распределёнными транзакциями.
Его идея проста:
1.Каждый шаг — независимый
Каждое действие выполняется как отдельная транзакция, которая гарантированно сохраняет свои изменения в локальной БД.
2. Компенсирующие действия
Для каждого шага создаётся обратная операция, которая может откатить изменения, если последующий шаг не удался.
Например, для биллинга:
Шаг 1: резервируем средства на счёте клиента (локальная транзакция)
Шаг 2: создаём заказ в системе (локальная транзакция)
Шаг 3: уведомляем склад о сборкеЕсли шаг 2 падает, шаг 1 компенсируется: средства возвращаются на счёт клиента.
Преимущества Saga pattern:
- Нет необходимости в глобальной межсервисной транзакции, которая блокировала бы все сервисы.
- Процесс становится устойчивым к сбоям: каждая ошибка обрабатывается локально и компенсируется.
- Подходит для систем с высокой нагрузкой и распределённой архитектурой: очереди, биллинг, бронирования, логистика.
❓ Есть ли у вас интересные кейсы, когда Saga pattern спасала систему от ошибок?
#laravel #mysql #transactions #webdev #db #devops #saga #aftercommit
🚨 1) Внешние действия внутри транзакции = проблемы
Любой внешний вызов внутри транзакции может выполниться два и более раз, потому что Laravel автоматически повторяет транзакцию при дедлоках и таймаутах.
DB::transaction($callback, $attempts) сам делает retry, если произошёл:
- дедлок
- lock wait timeout
- потеря блокировки
И важно: При повторе он запускает весь callback с нуля.
Он не понимает, что там было «одноразовым», а что идемпотентным.
Что под раздачу попадает:
- отправка писем
- пуши
- внешние HTTP-запросы
- интеграции (CRM, платёжки)
Если транзакция упала и Laravel её перезапустил → действие повторится, потому что MySQL откатывает только свои изменения, а внешние вызовы уже произошли и не откатываются.
Как избежать:
- всё внешнее — только после commit
- использовать afterCommit() у моделей или dispatch(fn)->afterCommit() — так действие выполняется один раз, после успешной фиксации данных.
🔒 2) Дедлоки из-за порядка блокировок
Дедлок (deadlock) — ситуация, когда две и более транзакций ожидают друг друга бесконечно, и MySQL вынужден прервать одну из них, чтобы система продолжила работать.
Чаще всего дедлоки возникают не из-за MySQL как такового, а из-за разного порядка, в котором код блокирует строки или ресурсы.
Пример типичной ситуации:
- Транзакция A начинает и лочит строки 5 → 10
- Транзакция B начинает и лочит строки 10 → 5
MySQL обнаруживает тупик и прерывает одну транзакцию с ошибкой Deadlock found.
Как снизить риск:
1. Всегда блокировать строки в одном порядке
Обычно по возрастанию ID, чтобы исключить циклические ожидания.
$rows = DB::table('accounts')
->whereIn('id', [$id1, $id2])
->orderBy('id')
->lockForUpdate()
->get();2. Использовать блокировки корректно
- FOR UPDATE — эксклюзивная блокировка для изменения
- sharedLock() — блокировка для чтения без мешающих других читателей
3. Минимизировать время удержания блокировок
Чем быстрее транзакция завершится, тем ниже шанс дедлока.
4. Разделять независимые операции
Операции по разным таблицам или сущностям лучше выполнять в отдельных транзакциях, чтобы не увеличивать зону возможного конфликта.
🌐 3) Когда транзакции не работают вообще
Стандартные транзакции работают только в рамках одной базы данных и одного соединения.
Если операция затрагивает:
- несколько сервисов (например, микросервисы с разной логикой),
- несколько БД (разные инстансы, разные схемы),
- внешние API (CRM, платёжные системы, сторонние интеграции),то гарантировать атомарность стандартной транзакцией невозможно.
Причина: транзакция контролирует только изменения внутри конкретного движка базы данных.
Внешние действия, например HTTP-запросы или вызовы другой БД, не могут быть откатаны автоматически при ошибке — их состояние уже “зафиксировано” в сторонней системе.
🔹4) Стандартный подход — Saga pattern
Saga pattern — это архитектурный паттерн для управления распределёнными транзакциями.
Его идея проста:
1.Каждый шаг — независимый
Каждое действие выполняется как отдельная транзакция, которая гарантированно сохраняет свои изменения в локальной БД.
2. Компенсирующие действия
Для каждого шага создаётся обратная операция, которая может откатить изменения, если последующий шаг не удался.
Например, для биллинга:
Шаг 1: резервируем средства на счёте клиента (локальная транзакция)
Шаг 2: создаём заказ в системе (локальная транзакция)
Шаг 3: уведомляем склад о сборкеЕсли шаг 2 падает, шаг 1 компенсируется: средства возвращаются на счёт клиента.
Преимущества Saga pattern:
- Нет необходимости в глобальной межсервисной транзакции, которая блокировала бы все сервисы.
- Процесс становится устойчивым к сбоям: каждая ошибка обрабатывается локально и компенсируется.
- Подходит для систем с высокой нагрузкой и распределённой архитектурой: очереди, биллинг, бронирования, логистика.
❓ Есть ли у вас интересные кейсы, когда Saga pattern спасала систему от ошибок?
#laravel #mysql #transactions #webdev #db #devops #saga #aftercommit
#️⃣ClickHouse (Часть 1)
🔥 Запускаем серию постов про ClickHouse — одну из самых быстрых колонночных баз для аналитики.
Её придумали в Яндексе, а сейчас используют Facebook, Uber и многие другие компании, когда нужно крутить миллиарды строк за секунды.
Что такое ClickHouse:
Это open‑source СУБД, заточенная под OLAP.
Работает с SQL‑подобным языком, умеет шардинг, репликацию, распределённые запросы и масштабирование без единой точки отказа.
Чем она крута:
🗂 Колонночное хранение
В отличие от классических СУБД, где данные лежат построчно, ClickHouse хранит их по столбцам.
Это даёт сразу несколько преимуществ:
📑Сжатие: каждый столбец хранится в отдельном файле и может быть отсортирован. Благодаря этому алгоритмы компрессии (zstd, LZ4) работают эффективнее, и таблицы занимают в десятки раз меньше места.
⚡️Быстрые аналитические запросы: для range‑запросов система обращается только к нужным столбцам, а не ко всей таблице. Если столбцы отсортированы (sort keys), поиск и агрегации выполняются значительно быстрее.
🖥 Параллельная обработка: при работе с большими объёмами данных ClickHouse умеет распараллеливать операции на многоядерных процессорах, ускоряя загрузку и вычисления.
📈 Масштабируемость
ClickHouse отлично масштабируется как «вверх», так и «вширь»:
🔀 Горизонтально — добавляем новые шарды и реплики, распределяем нагрузку между узлами.
🏢 Между дата‑центрами — поддерживается асинхронная multi‑master репликация, все узлы равноправны, нет единой точки отказа.
💡 Вертикально — можно увеличивать ресурсы отдельного сервера (CPU, RAM, диски), и ClickHouse будет использовать их максимально эффективно.
Но есть нюансы:
- Нет полноценного UPDATE/DELETE ClickHouse не рассчитан на частые модификации данных.
Такие операции выполняются медленно и неэффективно, поэтому для сценариев с постоянными изменениями таблиц он не лучший выбор.
- OLTP‑запросы не его сильная сторона
Если нужны точечные запросы (например, быстро достать одну строку по ключу), классические реляционные базы вроде MySQL или PostgreSQL справятся заметно лучше.
Аналоги:
- Druid
- ElasticSearch
- SingleStore
- Snowflake
- TimescaleDB
У каждого свои плюсы, но ClickHouse — топ именно для аналитики.
Установка
В этом гайде я показываю только вариант через Docker — самый быстрый способ «поднять» ClickHouse без лишних танцев с бубном.
За другими способами и нюансами - как и всегда, лучше обратиться к официальной доке
Загрузка образа
Запуск:
Подключение к нему из нативного клиента
Первые шаги
➕ Вставка данных
🔍 Чтение данных
📌 Мы разобрали основы ClickHouse и базовый сетап.
Впереди — движки таблиц, ключи, индексы и сравнение с MySQL.
Следите за апдейтами!
#clickhouse #database #tutorial
🔥 Запускаем серию постов про ClickHouse — одну из самых быстрых колонночных баз для аналитики.
Её придумали в Яндексе, а сейчас используют Facebook, Uber и многие другие компании, когда нужно крутить миллиарды строк за секунды.
Что такое ClickHouse:
Это open‑source СУБД, заточенная под OLAP.
Работает с SQL‑подобным языком, умеет шардинг, репликацию, распределённые запросы и масштабирование без единой точки отказа.
Чем она крута:
🗂 Колонночное хранение
В отличие от классических СУБД, где данные лежат построчно, ClickHouse хранит их по столбцам.
Это даёт сразу несколько преимуществ:
📑Сжатие: каждый столбец хранится в отдельном файле и может быть отсортирован. Благодаря этому алгоритмы компрессии (zstd, LZ4) работают эффективнее, и таблицы занимают в десятки раз меньше места.
⚡️Быстрые аналитические запросы: для range‑запросов система обращается только к нужным столбцам, а не ко всей таблице. Если столбцы отсортированы (sort keys), поиск и агрегации выполняются значительно быстрее.
🖥 Параллельная обработка: при работе с большими объёмами данных ClickHouse умеет распараллеливать операции на многоядерных процессорах, ускоряя загрузку и вычисления.
📈 Масштабируемость
ClickHouse отлично масштабируется как «вверх», так и «вширь»:
🔀 Горизонтально — добавляем новые шарды и реплики, распределяем нагрузку между узлами.
🏢 Между дата‑центрами — поддерживается асинхронная multi‑master репликация, все узлы равноправны, нет единой точки отказа.
💡 Вертикально — можно увеличивать ресурсы отдельного сервера (CPU, RAM, диски), и ClickHouse будет использовать их максимально эффективно.
Но есть нюансы:
- Нет полноценного UPDATE/DELETE ClickHouse не рассчитан на частые модификации данных.
Такие операции выполняются медленно и неэффективно, поэтому для сценариев с постоянными изменениями таблиц он не лучший выбор.
- OLTP‑запросы не его сильная сторона
Если нужны точечные запросы (например, быстро достать одну строку по ключу), классические реляционные базы вроде MySQL или PostgreSQL справятся заметно лучше.
Аналоги:
- Druid
- ElasticSearch
- SingleStore
- Snowflake
- TimescaleDB
У каждого свои плюсы, но ClickHouse — топ именно для аналитики.
Установка
В этом гайде я показываю только вариант через Docker — самый быстрый способ «поднять» ClickHouse без лишних танцев с бубном.
За другими способами и нюансами - как и всегда, лучше обратиться к официальной доке
Загрузка образа
docker pull clickhouse/clickhouse-server
Запуск:
docker run -d --name some-clickhouse-server --ulimit nofile=262144:262144 clickhouse/clickhouse-server
Подключение к нему из нативного клиента
docker run -it --rm --network=container:some-clickhouse-server --entrypoint clickhouse-client clickhouse/clickhouse-server
# ИЛИ \{#or}
docker exec -it some-clickhouse-server clickhouse-client
Первые шаги
CREATE DATABASE ecommerce;
CREATE TABLE ecommerce.users
(
UserID UUID,
Username String,
Email String,
RegistrationDate Date,
LastLogin DateTime64(3, 'UTC'),
Age UInt8,
Salary Decimal(10, 2),
IsPremium Bool,
Settings JSON,
Tags Array(String),
Metadata Map(String, String)
)
ENGINE = MergeTree
PRIMARY KEY (UserID, RegistrationDate)
ORDER BY (UserID, RegistrationDate, Username)
PARTITION BY toYYYYMM(RegistrationDate);
➕ Вставка данных
INSERT INTO ecommerce.users VALUES
(
generateUUIDv4(), -- Автоматическая генерация UUID
'anna_sidorova',
'anna.s@company.com',
'2024-02-20',
'2024-03-19 09:15:30.500',
32,
62000.00,
false,
'{"theme": "light", "email_notifications": false}',
['new_user'],
map('city', 'Saint Petersburg', 'department', 'Sales')
);
🔍 Чтение данных
SELECT * FROM ecommerce.users;
📌 Мы разобрали основы ClickHouse и базовый сетап.
Впереди — движки таблиц, ключи, индексы и сравнение с MySQL.
Следите за апдейтами!
#clickhouse #database #tutorial
А есть ли здесь представители компаний-аутстафферов, которые одним глазком наблюдают за нашей бурной деятельностью?😎
На всякий случай делимся новостью - мы запустили конкурс на предоставление услуг IT-разработчиков в аутстафф.
У нас большой штат собственных аналитиков и разработчиков, но иногда клиентам нужна команда еще больше - или требуется специфичный стек. Тогда мы идем к нашим любимым партнерам, список которых все время пополняется надежными поставщиками IT-услуг💪
⚡️ Так что, если здесь среди разрабов затесался поставщик IT-ресурсов, который давно хотел поработать с нами - есть отличная возможность принять участие в открытом отборе партнеров на 2026 год.
📄 Подача заявок, а также подробные условия тендера и требования - на нашей площадке: https://business.roseltorg.ru/lk/orders/all/94251
⏰ Принимаем заявки до 18:00 19 декабря - успевайте, возможно, мы ищем именно вас😉
На всякий случай делимся новостью - мы запустили конкурс на предоставление услуг IT-разработчиков в аутстафф.
У нас большой штат собственных аналитиков и разработчиков, но иногда клиентам нужна команда еще больше - или требуется специфичный стек. Тогда мы идем к нашим любимым партнерам, список которых все время пополняется надежными поставщиками IT-услуг💪
⚡️ Так что, если здесь среди разрабов затесался поставщик IT-ресурсов, который давно хотел поработать с нами - есть отличная возможность принять участие в открытом отборе партнеров на 2026 год.
📄 Подача заявок, а также подробные условия тендера и требования - на нашей площадке: https://business.roseltorg.ru/lk/orders/all/94251
⏰ Принимаем заявки до 18:00 19 декабря - успевайте, возможно, мы ищем именно вас😉
🔥1
В этой части мы поговорим о движке таблиц ClickHouse.
Как и в любой другой базе данных, ClickHouse использует движки для определения методов хранения, репликации и работы с параллельными запросами для таблиц.
У каждого движка есть свои плюсы и минусы, и выбирать их следует исходя из ваших задач.
Более того, движки сгруппированы в семейства, объединённые общими ключевыми характеристиками.
Итак, начнём с первого и самого популярного семейства:
Семейство MergeTree
Это основной и наиболее мощный движок ClickHouse. Если вы создаете таблицу и не знаете, что выбрать — начинайте с MergeTree или его модификаций.
Основная идея — оптимизация для интенсивной записи данных (INSERT).
Под капотом используется структура LSM-дерево (Log-Structured Merge-Tree).
В отличие от B-деревьев в классических базах данных (MySQL, PostgreSQL), LSM сначала буферизирует записи в памяти, а затем крупными, отсортированными "пакетами" записывает на диск.
Это дает огромный выигрыш в скорости вставки и уменьшает фрагментацию.
Теперь рассмотрим ключевых представителей семейства.
1. MergeTree (базовый)Пример создания таблицы:
Как работает?
Данные разбиваются на части (parts) и сортируются по ORDER BY.
Каждая часть делится на гранулы (блоки данных).
Для гранул создаются засечки (marks) — "отметки" по первичному ключу. Это разреженный индекс.
При запросе с условием по первичному ключу ClickHouse быстро находит нужные гранулы через бинарный поиск по засечкам и загружает только их.Правило: Первичный ключ (PRIMARY KEY) должен быть префиксом или совпадать с ключом сортировки (ORDER BY). Если PRIMARY KEY не указан, вместо него используется ORDER BY.
2. ReplacingMergeTree (для дедупликации)
DDL
В этом движке строки с одинаковыми ключами сортировки заменяются последней вставленной строкой.
Рассмотрим пример:
Предположим, вы вставляете строку в эту таблицу:
Теперь вставим другую строку с теми же ключами сортировки:
Теперь последняя строка заменит предыдущую. Обратите внимание: если вы выполните выборку, то можете увидеть обе строки:
Это происходит потому, что ClickHouse выполняет процесс замены во время слияния частей (merge), которое происходит в фоновом режиме асинхронно, а не мгновенно. Чтобы сразу увидеть финальный результат, вы можете использовать модификатор FINAL:
Примечание: Вы можете указать столбец в качестве версии при определении таблицы, чтобы управлять логикой замены строк.
Применение
ReplacingMergeTree широко используется для дедупликации.
Поскольку ClickHouse не очень эффективен при частых обновлениях, вы можете обновить столбец, вставив новую строку с такими же ключами сортировки, и ClickHouse удалит устаревшие строки в фоновом режиме.
Конечно, обновление самих ключей сортировки является проблемой, поскольку в этом случае старые строки не будут удалены.
В следующей части мы продолжим разбор семейства MergeTree и рассмотрим:
CollapsingMergeTree — для контролируемых обновлений и удалений
AggregatingMergeTree — для предварительной агрегации данных
А также затронем более легковесные семейства Log и Integration для работы с внешними системами.
#ClickHouse #БазыДанных #Аналитика #MergeTree #Оптимизация
Как и в любой другой базе данных, ClickHouse использует движки для определения методов хранения, репликации и работы с параллельными запросами для таблиц.
У каждого движка есть свои плюсы и минусы, и выбирать их следует исходя из ваших задач.
Более того, движки сгруппированы в семейства, объединённые общими ключевыми характеристиками.
Итак, начнём с первого и самого популярного семейства:
Семейство MergeTree
Это основной и наиболее мощный движок ClickHouse. Если вы создаете таблицу и не знаете, что выбрать — начинайте с MergeTree или его модификаций.
Основная идея — оптимизация для интенсивной записи данных (INSERT).
Под капотом используется структура LSM-дерево (Log-Structured Merge-Tree).
В отличие от B-деревьев в классических базах данных (MySQL, PostgreSQL), LSM сначала буферизирует записи в памяти, а затем крупными, отсортированными "пакетами" записывает на диск.
Это дает огромный выигрыш в скорости вставки и уменьшает фрагментацию.
Теперь рассмотрим ключевых представителей семейства.
1. MergeTree (базовый)Пример создания таблицы:
CREATE TABLE users
(
`user_id` Int32,
`name` String,
`age` Int32,
`city` String
)
ENGINE = MergeTree
PRIMARY KEY (user_id, city)
ORDER BY (user_id, city, name)
Как работает?
Данные разбиваются на части (parts) и сортируются по ORDER BY.
Каждая часть делится на гранулы (блоки данных).
Для гранул создаются засечки (marks) — "отметки" по первичному ключу. Это разреженный индекс.
При запросе с условием по первичному ключу ClickHouse быстро находит нужные гранулы через бинарный поиск по засечкам и загружает только их.Правило: Первичный ключ (PRIMARY KEY) должен быть префиксом или совпадать с ключом сортировки (ORDER BY). Если PRIMARY KEY не указан, вместо него используется ORDER BY.
2. ReplacingMergeTree (для дедупликации)
DDL
В этом движке строки с одинаковыми ключами сортировки заменяются последней вставленной строкой.
Рассмотрим пример:
CREATE TABLE user_sessions
(
`user_id` Int32,
`session_id` String,
`status` String,
`last_activity` DateTime
)
ENGINE = ReplacingMergeTree
ORDER BY (user_id, session_id);
Предположим, вы вставляете строку в эту таблицу:
INSERT INTO user_sessions VALUES (101, 's1', 'active', '2024-01-15 10:00:00');
Теперь вставим другую строку с теми же ключами сортировки:
INSERT INTO user_sessions VALUES (101, 's1', 'inactive', '2024-01-15 11:30:00');
Теперь последняя строка заменит предыдущую. Обратите внимание: если вы выполните выборку, то можете увидеть обе строки:
Это происходит потому, что ClickHouse выполняет процесс замены во время слияния частей (merge), которое происходит в фоновом режиме асинхронно, а не мгновенно. Чтобы сразу увидеть финальный результат, вы можете использовать модификатор FINAL:
SELECT * from user_sessions FINAL WHERE user_id=101;
Примечание: Вы можете указать столбец в качестве версии при определении таблицы, чтобы управлять логикой замены строк.
Применение
ReplacingMergeTree широко используется для дедупликации.
Поскольку ClickHouse не очень эффективен при частых обновлениях, вы можете обновить столбец, вставив новую строку с такими же ключами сортировки, и ClickHouse удалит устаревшие строки в фоновом режиме.
Конечно, обновление самих ключей сортировки является проблемой, поскольку в этом случае старые строки не будут удалены.
В следующей части мы продолжим разбор семейства MergeTree и рассмотрим:
CollapsingMergeTree — для контролируемых обновлений и удалений
AggregatingMergeTree — для предварительной агрегации данных
А также затронем более легковесные семейства Log и Integration для работы с внешними системами.
#ClickHouse #БазыДанных #Аналитика #MergeTree #Оптимизация
Продолжаем разбор движков ClickHouse!
3. CollapsingMergeTree (для контролируемых изменений)
Этот движок позволяет явно управлять обновлениями и удалениями через специальный столбец-признак (sign):
sign = 1 — добавить/актуальная версия строки
sign = -1 — удалить/старая версия строки
Пример таблицы для отслеживания статусов заказов:
Как работает изменение статуса:
Важно:
Как и в ReplacingMergeTree, схлопывание происходит в фоне. Для немедленного результата используйте FINAL.
Особенности:
CollapsingMergeTree позволяет более контролируемо обрабатывать обновления и удаления.
Например, вы можете обновить ключи сортировки, вставив старую строку с sign=-1 и новую строку с новыми ключами сортировки и sign=1.
4. AggregatingMergeTree
Этот движок автоматически вычисляет агрегаты при вставке данных, значительно ускоряя аналитические запросы.
Пример — дневная статистика пользователей:
Как использовать агрегированные данные:
Этот движок помогает сократить время отклика на сложные, фиксированные аналитические запросы, рассчитывая их во время записи.
Семейство Log: минималистичное хранение
Эти движки максимально просты и быстры для записи, но не имеют индексов.
TinyLog — для временных данных:
Применение: Промежуточные данные ETL, кэши, временные логи.
Семейство Integration: работа с внешними системами
MySQL Engine — доступ:
Теперь можно выполнять запросы к MySQL через ClickHouse:
Очевидно, что ClickHouse предлагает широкий спектр вариантов движков для различных сценариев использования. MergeTree является движком по умолчанию и подходит для большинства ситуаций, но при необходимости его можно заменить другими движками, правильный выбор движка для вашей конкретной задачи может значительно повысить производительность и эффективность работы с данными. Поэтому стоит потратить время на то, чтобы понять сильные и слабые стороны каждого движка и выбрать тот, который лучше всего соответствует вашим потребностям.
Ну и будем продолжать тему Clickhouse в следующих постах, дальше интересней :)
#ClickHouse #БазыДанных #Аналитика #MergeTree #CollapsingMergeTree #AggregatingMergeTree
3. CollapsingMergeTree (для контролируемых изменений)
Этот движок позволяет явно управлять обновлениями и удалениями через специальный столбец-признак (sign):
sign = 1 — добавить/актуальная версия строки
sign = -1 — удалить/старая версия строки
Пример таблицы для отслеживания статусов заказов:
CREATE TABLE order_statuses
(
`order_id` Int32,
`status` String,
`updated_at` DateTime,
`sign` Int8
)
ENGINE = CollapsingMergeTree(sign)
ORDER BY (order_id, updated_at);
Как работает изменение статуса:
-- Первоначальный статус
INSERT INTO order_statuses VALUES (5001, 'pending', '2024-01-15 10:00:00', 1);
-- Обновление статуса: удаляем старый, добавляем новый
INSERT INTO order_statuses VALUES
(5001, 'pending', '2024-01-15 10:00:00', -1),
(5001, 'shipped', '2024-01-15 14:00:00', 1);
Важно:
Как и в ReplacingMergeTree, схлопывание происходит в фоне. Для немедленного результата используйте FINAL.
Особенности:
CollapsingMergeTree позволяет более контролируемо обрабатывать обновления и удаления.
Например, вы можете обновить ключи сортировки, вставив старую строку с sign=-1 и новую строку с новыми ключами сортировки и sign=1.
4. AggregatingMergeTree
Этот движок автоматически вычисляет агрегаты при вставке данных, значительно ускоряя аналитические запросы.
Пример — дневная статистика пользователей:
-- Исходная таблица с активностью
CREATE TABLE user_activity
(
`user_id` Int32,
`action` String,
`duration` UInt32,
`event_date` Date
) ENGINE = MergeTree
ORDER BY (user_id, event_date);
-- Материализованное представление с агрегатами
CREATE MATERIALIZED VIEW user_daily_stats
ENGINE = AggregatingMergeTree()
ORDER BY (user_id, event_date)
AS SELECT
user_id,
event_date,
countState() as action_count,
sumState(duration) as total_duration,
uniqState(action) as unique_actions
FROM user_activity
GROUP BY user_id, event_date;
Как использовать агрегированные данные:
-- Вставка детальных данных
INSERT INTO user_activity VALUES
(1001, 'login', 120, '2024-01-15'),
(1001, 'view', 300, '2024-01-15'),
(1001, 'purchase', 60, '2024-01-15');
-- Получение агрегированных результатов
SELECT
user_id,
event_date,
countMerge(action_count) as actions,
sumMerge(total_duration) as total_time,
uniqMerge(unique_actions) as different_actions
FROM user_daily_stats
WHERE user_id = 1001
GROUP BY user_id, event_date;
Этот движок помогает сократить время отклика на сложные, фиксированные аналитические запросы, рассчитывая их во время записи.
Семейство Log: минималистичное хранение
Эти движки максимально просты и быстры для записи, но не имеют индексов.
TinyLog — для временных данных:
CREATE TABLE temp_metrics
(
`metric_id` UUID,
`value` Float64,
`collected_at` DateTime
) ENGINE = TinyLog;
Применение: Промежуточные данные ETL, кэши, временные логи.
Семейство Integration: работа с внешними системами
MySQL Engine — доступ:
CREATE TABLE remote_products
(
`id` Int32,
`noscript` String,
`category` String
)
ENGINE = MySQL('mysql-server:2206', 'shop', 'products', 'admin', 'password');
Теперь можно выполнять запросы к MySQL через ClickHouse:
SELECT * FROM remote_products WHERE category = 'electronics';
Очевидно, что ClickHouse предлагает широкий спектр вариантов движков для различных сценариев использования. MergeTree является движком по умолчанию и подходит для большинства ситуаций, но при необходимости его можно заменить другими движками, правильный выбор движка для вашей конкретной задачи может значительно повысить производительность и эффективность работы с данными. Поэтому стоит потратить время на то, чтобы понять сильные и слабые стороны каждого движка и выбрать тот, который лучше всего соответствует вашим потребностям.
Ну и будем продолжать тему Clickhouse в следующих постах, дальше интересней :)
#ClickHouse #БазыДанных #Аналитика #MergeTree #CollapsingMergeTree #AggregatingMergeTree
А тем временем в новом эпизоде ITToLкового подкаста наши бессменные ведущие вывели на чистую воду человека, который привык оставаться за кадром (но у истоков💪) всех наших PR-активностей😎
Поговорили с CMO EvApps Юлией Резниченко о том, как продвигать IT-компанию, сколько дают "на маркетинг" и причем здесь тульские пряники😉
🚀Что выяснили?
🔗 Смотри скорее по ссылке: https://vkvideo.ru/video-78780379_456239303
Поговорили с CMO EvApps Юлией Резниченко о том, как продвигать IT-компанию, сколько дают "на маркетинг" и причем здесь тульские пряники😉
🚀Что выяснили?
🔗 Смотри скорее по ссылке: https://vkvideo.ru/video-78780379_456239303
VK Видео
IT ToLк by EvApps. Маркетинг, сексизм и пряники
Расспросили нашего CMO Юлию Резниченко, откуда она берет такие красивые показатели, что работает, а что не работает в маркетинге и PR IT-компаний - и причем здесь, собственно, пряники. "Ссылочки в описании", как и обещали: ✅ Это наш официальный ВК (https…
👍1