📡 Протокол WebSocket — двусторонняя связь в реальном времени
Классический HTTP работает по принципу «запрос-ответ»: клиент (браузер) просит данные, сервер их отдает, и соединение закрывается. Но что делать, если вам нужно построить чат, онлайн-игру или живой график котировок криптовалют? Заставлять браузер каждую секунду слать HTTP-запросы — дико неэффективно. Для таких задач используют протокол WebSocket.
В отличие от HTTP, WebSocket создает одно постоянное, открытое соединение между клиентом и сервером. Обе стороны могут отправлять друг другу данные в любой момент времени без лишних заголовков и задержек.
Как устроен жизненный цикл WebSocket:
— Handshake (Рукопожатие): Клиент отправляет обычный HTTP-запрос с особыми заголовками, говоря серверу: «Давай перейдем на WebSocket».
— Upgrade: Если сервер согласен, соединение «апгрейдится» (статус код
— Двусторонний обмен: Канал открыт. Теперь данные летают туда и обратно в виде легких фреймов.
— Закрытие: Любая сторона может закрыть соединение в любой момент.
Зачем это инженеру? Ради мгновенной реакции и экономии ресурсов. В HTTP каждый запрос тянет за собой кучу служебной информации (куки, заголовки браузера, тип контента), которая может весить больше, чем полезные данные. В WebSocket после установки соединения накладные расходы составляют всего несколько байт на сообщение.
В экосистеме Python работать с WebSocket невероятно удобно через фреймворк FastAPI. Он из коробки предоставляет простой синтаксис для управления такими соединениями.
Пример простейшего WebSocket-сервера на FastAPI:
WebSocket — это незаменимый инструмент для создания интерактивных интерфейсов в 2026 году. Однако стоит помнить, что постоянные соединения требуют много оперативной памяти на сервере, так как он обязан держать открытым сокет для каждого активного пользователя. Поэтому для эффективного масштабирования таких приложений бэкенд часто комбинируют с асинхронными инструментами и брокерами сообщений.
🚪 Bash Ready | #практика
Классический HTTP работает по принципу «запрос-ответ»: клиент (браузер) просит данные, сервер их отдает, и соединение закрывается. Но что делать, если вам нужно построить чат, онлайн-игру или живой график котировок криптовалют? Заставлять браузер каждую секунду слать HTTP-запросы — дико неэффективно. Для таких задач используют протокол WebSocket.
В отличие от HTTP, WebSocket создает одно постоянное, открытое соединение между клиентом и сервером. Обе стороны могут отправлять друг другу данные в любой момент времени без лишних заголовков и задержек.
Как устроен жизненный цикл WebSocket:
— Handshake (Рукопожатие): Клиент отправляет обычный HTTP-запрос с особыми заголовками, говоря серверу: «Давай перейдем на WebSocket».
— Upgrade: Если сервер согласен, соединение «апгрейдится» (статус код
101 Switching Protocols).— Двусторонний обмен: Канал открыт. Теперь данные летают туда и обратно в виде легких фреймов.
— Закрытие: Любая сторона может закрыть соединение в любой момент.
Зачем это инженеру? Ради мгновенной реакции и экономии ресурсов. В HTTP каждый запрос тянет за собой кучу служебной информации (куки, заголовки браузера, тип контента), которая может весить больше, чем полезные данные. В WebSocket после установки соединения накладные расходы составляют всего несколько байт на сообщение.
В экосистеме Python работать с WebSocket невероятно удобно через фреймворк FastAPI. Он из коробки предоставляет простой синтаксис для управления такими соединениями.
Пример простейшего WebSocket-сервера на FastAPI:
from fastapi import FastAPI, WebSocket
app = FastAPI()
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept() # Принимаем соединение
while True:
# Ждем сообщение от клиента
data = await websocket.receive_text()
# Тут же отправляем ответ назад
await websocket.send_text(f"Сервер получил: {data}")
WebSocket — это незаменимый инструмент для создания интерактивных интерфейсов в 2026 году. Однако стоит помнить, что постоянные соединения требуют много оперативной памяти на сервере, так как он обязан держать открытым сокет для каждого активного пользователя. Поэтому для эффективного масштабирования таких приложений бэкенд часто комбинируют с асинхронными инструментами и брокерами сообщений.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7
Не крипта, не мемкоины, не казино ❌
🥇 Твой пассивный доход должен строиться на понятных активах
А не на СКАМерских проектах-однодневках.
Notal 📈 — канал о том, как зарабатывать на автоматической торговле золотом и серебром без вечной жизни на графиках.
Начните с простого: получите БЕСПЛАТНУЮ версию робота с доходностью до 25% годовых. Без подписок. Без настроек.
🤖 SilentGain
Как возможны 25% годовых? Узнай⤵️
https://t.me/+SZaP3SGi1uZjNzYy
🥇 Твой пассивный доход должен строиться на понятных активах
А не на СКАМерских проектах-однодневках.
Notal 📈 — канал о том, как зарабатывать на автоматической торговле золотом и серебром без вечной жизни на графиках.
Начните с простого: получите БЕСПЛАТНУЮ версию робота с доходностью до 25% годовых. Без подписок. Без настроек.
🤖 SilentGain
Как возможны 25% годовых? Узнай⤵️
https://t.me/+SZaP3SGi1uZjNzYy
😁3👍1
🥒 Кэширование на стероидах — зачем использовать Redis Hash?
Когда разработчики начинают работать с Redis, они обычно используют его как простое хранилище строк: записывают объект пользователя в виде JSON-строки по ключу
Хэши в Redis — это полноценные словари внутри базы данных. Они позволяют хранить под одним ключом множество пар «поле-значение». Вы получаете структуру вида
Основные команды для работы с Хэшами:
— Записать объект:
— Получить конкретное поле:
— Получить весь объект:
— Увеличить числовое поле:
— Удалить одно поле:
Зачем это инженеру? Ради колоссальной экономии памяти и процессорного времени. Когда вы используете Redis Hash, бэкенду на Python или JS больше не нужно тратить ресурсы на постоянный парсинг строк туда-обратно. Вы можете обновить статус пользователя одной быстрой командой, не трогая остальные данные.
Кроме того, под капотом Redis оптимизирует хранение маленьких хэшей с помощью структуры ziplist (компактный список). Это позволяет хранить миллионы объектов, тратя на них в разы меньше оперативной памяти, чем если бы каждый из них был отдельной JSON-строкой.
Использование хэшей — это стандартный паттерн для хранения профилей пользователей, настроек конфигурации, корзин товаров в интернет-магазинах или текущего состояния игровых сессий.
Переход от обычных строк к хэшам — простой способ оптимизировать кэш-слой вашего приложения, снизить нагрузку на сеть и сделать работу с динамическими структурами данных элегантной и быстрой.
🚪 Bash Ready | #практика
Когда разработчики начинают работать с Redis, они обычно используют его как простое хранилище строк: записывают объект пользователя в виде JSON-строки по ключу
user:100 через команду SET. Но если вам нужно обновить всего одно поле (например, статус или баланс), приходится доставать всю строку, десериализовать её, менять значение, собирать обратно в JSON и перезаписывать. Это медленно и неэффективно. Для работы со сложными объектами в Redis есть идеальная структура — Hash (Хэш).Хэши в Redis — это полноценные словари внутри базы данных. Они позволяют хранить под одним ключом множество пар «поле-значение». Вы получаете структуру вида
Ключ -> [Поле1: Значение1, Поле2: Значение2], которой можно управлять точечно.Основные команды для работы с Хэшами:
— Записать объект:
HSET user:100 username "alex" status "active" age 25— Получить конкретное поле:
HGET user:100 status— Получить весь объект:
HGETALL user:100— Увеличить числовое поле:
HINCRBY user:100 age 1 (идеально для счетчиков)— Удалить одно поле:
HDEL user:100 ageЗачем это инженеру? Ради колоссальной экономии памяти и процессорного времени. Когда вы используете Redis Hash, бэкенду на Python или JS больше не нужно тратить ресурсы на постоянный парсинг строк туда-обратно. Вы можете обновить статус пользователя одной быстрой командой, не трогая остальные данные.
Кроме того, под капотом Redis оптимизирует хранение маленьких хэшей с помощью структуры ziplist (компактный список). Это позволяет хранить миллионы объектов, тратя на них в разы меньше оперативной памяти, чем если бы каждый из них был отдельной JSON-строкой.
Использование хэшей — это стандартный паттерн для хранения профилей пользователей, настроек конфигурации, корзин товаров в интернет-магазинах или текущего состояния игровых сессий.
Переход от обычных строк к хэшам — простой способ оптимизировать кэш-слой вашего приложения, снизить нагрузку на сеть и сделать работу с динамическими структурами данных элегантной и быстрой.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
📬 Брокеры сообщений — зачем вашему проекту Celery и RabbitMQ?
Когда пользователь нажимает кнопку «Зарегистрироваться», ваш бэкенд должен сделать много дел: создать запись в базе данных, сгенерировать тяжелый PDF-договор, загрузить аватарку в облако и отправить приветственное письмо на почту. Если делать всё это в основном потоке веб-запроса, пользователь будет секунд 10 смотреть на крутящийся лоадер. Чтобы этого избегать, тяжелые задачи уводят в фоновый режим с помощью очередей задач.
---
Для реализации такой схемы нужна связка из двух компонентов: Брокера сообщений (например, RabbitMQ или Redis) и Воркера (в мире Python это чаще всего Celery).
Как устроена эта цепочка:
— Веб-приложение (Producer): Быстро сохраняет юзера в базу, кидает короткую задачу вроде «отправь письмо юзеру №42» в брокер и тут же возвращает пользователю ответ
— Брокер сообщений (RabbitMQ): Принимает эту задачу, складывает её в очередь и хранит, пока освободится исполнитель.
— Воркер (Celery Worker): Постоянно слушает брокер, забирает задачу из очереди и спокойно выполняет её на фоне, не мешая основному сайту.
Зачем это инженеру? Это кардинально повышает живучесть и скорость системы. Если сторонний сервис отправки писем вдруг «приляжет», ваше приложение не упадет. RabbitMQ сохранит задачу в очереди, а Celery будет пытаться отправить её снова и снова, пока сервис не оживет. Пользователь об этих проблемах даже не узнает.
Пример кода на Python с использованием Celery:
В основном коде FastAPI или Django вы вызываете эту функцию не напрямую, а через специальный метод:
Использование Celery и RabbitMQ — это стандарт построения масштабируемых и отказоустойчивых систем. Это позволяет легко распределять нагрузку: если задач стало слишком много, вы можете просто запустить еще несколько воркеров Celery на соседних серверах, не меняя ни единой строчки в коде самого сайта.
Когда пользователь нажимает кнопку «Зарегистрироваться», ваш бэкенд должен сделать много дел: создать запись в базе данных, сгенерировать тяжелый PDF-договор, загрузить аватарку в облако и отправить приветственное письмо на почту. Если делать всё это в основном потоке веб-запроса, пользователь будет секунд 10 смотреть на крутящийся лоадер. Чтобы этого избегать, тяжелые задачи уводят в фоновый режим с помощью очередей задач.
---
Для реализации такой схемы нужна связка из двух компонентов: Брокера сообщений (например, RabbitMQ или Redis) и Воркера (в мире Python это чаще всего Celery).
Как устроена эта цепочка:
— Веб-приложение (Producer): Быстро сохраняет юзера в базу, кидает короткую задачу вроде «отправь письмо юзеру №42» в брокер и тут же возвращает пользователю ответ
200 OK. Для юзера всё произошло мгновенно.— Брокер сообщений (RabbitMQ): Принимает эту задачу, складывает её в очередь и хранит, пока освободится исполнитель.
— Воркер (Celery Worker): Постоянно слушает брокер, забирает задачу из очереди и спокойно выполняет её на фоне, не мешая основному сайту.
Зачем это инженеру? Это кардинально повышает живучесть и скорость системы. Если сторонний сервис отправки писем вдруг «приляжет», ваше приложение не упадет. RabbitMQ сохранит задачу в очереди, а Celery будет пытаться отправить её снова и снова, пока сервис не оживет. Пользователь об этих проблемах даже не узнает.
Пример кода на Python с использованием Celery:
from celery import Celery
# Инициализируем Celery и указываем RabbitMQ в качестве брокера
app = Celery('tasks', broker='amqp://guest@localhost//')
@app.task
def send_welcome_email(user_id):
# Тут логика генерации PDF и отправки тяжелого письма
print(f"Письмо для пользователя {user_id} успешно отправлено!")
В основном коде FastAPI или Django вы вызываете эту функцию не напрямую, а через специальный метод:
send_welcome_email.delay(user_id). Слово .delay() как раз и дает команду не выполнять код здесь и сейчас, а упаковать аргументы в сообщение и забросить их в RabbitMQ.Использование Celery и RabbitMQ — это стандарт построения масштабируемых и отказоустойчивых систем. Это позволяет легко распределять нагрузку: если задач стало слишком много, вы можете просто запустить еще несколько воркеров Celery на соседних серверах, не меняя ни единой строчки в коде самого сайта.
❤2
🛡️ Мидлвары — как фильтровать веб-запросы на подлете к коду?
Представьте, что у вас в приложении на FastAPI, Django или Node.js есть 50 разных эндпоинтов. Для каждого из них нужно проверять, авторизован ли пользователь, логировать время обработки запроса и добавлять защитные заголовки. Писать этот код вручную внутри каждой функции — кошмар для поддержки. Чтобы решать такие сквозные задачи в один клик, используют Middleware (промежуточное ПО).
Мидлварь — это специальный слой-перехватчик, который встает прямо на пути сетевого запроса от клиента к вашему основному коду (роутам) и на обратном пути ответа от сервера к клиенту.
через мидлварь проходит абсолютно каждый запрос. Вы можете выстроить целую цепочку из таких фильтров, где каждый слой отвечает за свою задачу.
Как устроен жизненный цикл запроса с Middleware:
— Клиент отправляет запрос к серверу.
— Middleware 1 (Логирование): Записывает время старта и IP-адрес клиента, передает запрос дальше.
— Middleware 2 (Авторизация): Достает токен из заголовков. Если токен битый — мидлварь сразу разворачивает запрос назад и отдает ошибку
— Ваш код (Роут): Если всё ок, выполняется логика приложения (например, выдача списка товаров) и формируется ответ.
— Обратный путь: Ответ снова летит через все мидлвари в обратном порядке. Например, слой безопасности может прикрепить к нему CORS-заголовки.
Зачем это инженеру? Это идеальное воплощение принципа DRY (Don't Repeat Yourself). Вместо дублирования проверок безопасности, вы выносите их на глобальный уровень.
Пример кастомной мидлвари для подсчета времени запроса на FastAPI:
Встроенные мидлвари есть во всех популярных фреймворках. Самый частый пример — CORSMiddleware, который разрешает или запрещает вашему фронтенду, запущенному на другом домене, делать запросы к бэкенду. Без него браузер просто заблокирует любые попытки забрать данные.
Использование Middleware позволяет держать ваш основной код чистым, фокусируясь только на бизнес-логике. Все системные задачи — проверка токенов, сжатие ответов (Gzip), защита от атак и сбор метрик — делегируются этим невидимым стражам на входе в систему.
🚪 Bash Ready | #практика
Представьте, что у вас в приложении на FastAPI, Django или Node.js есть 50 разных эндпоинтов. Для каждого из них нужно проверять, авторизован ли пользователь, логировать время обработки запроса и добавлять защитные заголовки. Писать этот код вручную внутри каждой функции — кошмар для поддержки. Чтобы решать такие сквозные задачи в один клик, используют Middleware (промежуточное ПО).
Мидлварь — это специальный слой-перехватчик, который встает прямо на пути сетевого запроса от клиента к вашему основному коду (роутам) и на обратном пути ответа от сервера к клиенту.
через мидлварь проходит абсолютно каждый запрос. Вы можете выстроить целую цепочку из таких фильтров, где каждый слой отвечает за свою задачу.
Как устроен жизненный цикл запроса с Middleware:
— Клиент отправляет запрос к серверу.
— Middleware 1 (Логирование): Записывает время старта и IP-адрес клиента, передает запрос дальше.
— Middleware 2 (Авторизация): Достает токен из заголовков. Если токен битый — мидлварь сразу разворачивает запрос назад и отдает ошибку
401 Unauthorized, даже не беспокоя основной код приложения.— Ваш код (Роут): Если всё ок, выполняется логика приложения (например, выдача списка товаров) и формируется ответ.
— Обратный путь: Ответ снова летит через все мидлвари в обратном порядке. Например, слой безопасности может прикрепить к нему CORS-заголовки.
Зачем это инженеру? Это идеальное воплощение принципа DRY (Don't Repeat Yourself). Вместо дублирования проверок безопасности, вы выносите их на глобальный уровень.
Пример кастомной мидлвари для подсчета времени запроса на FastAPI:
import time
from fastapi import FastAPI, Request
app = FastAPI()
@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
start_time = time.time()
# Передаем запрос дальше по цепочке к роуту
response = await call_next(request)
# Этот код выполнится уже на обратном пути ответа
process_time = time.time() - start_time
response.headers["X-Process-Time"] = str(process_time)
return response
Встроенные мидлвари есть во всех популярных фреймворках. Самый частый пример — CORSMiddleware, который разрешает или запрещает вашему фронтенду, запущенному на другом домене, делать запросы к бэкенду. Без него браузер просто заблокирует любые попытки забрать данные.
Использование Middleware позволяет держать ваш основной код чистым, фокусируясь только на бизнес-логике. Все системные задачи — проверка токенов, сжатие ответов (Gzip), защита от атак и сбор метрик — делегируются этим невидимым стражам на входе в систему.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4
📡 Веб-хуки — как заставить сервер самому звонить вашему коду?
Когда вы создаете Telegram-бота, парсер или платежную систему, вашему коду нужно оперативно узнавать о новых событиях: пользователь отправил сообщение, пришла оплата на криптокошелек или обновилась котировка. У вас есть два пути: постоянно спамить чужой сервер запросами в цикле (Polling) или настроить Webhook (веб-хук).
---
Polling — это когда ваш скрипт каждые две секунды спрашивает: «Ну что, есть новые данные? А сейчас? А теперь?». Это дико перегружает процессор, тратит сетевой трафик и создает кучу пустых запросов.
Webhook работает ровно наоборот (принцип *Don't call us, we'll call you*). Вы один раз говорите стороннему сервису: «Вот адрес моего сервера (URL). Как только что-то произойдет — сам пришли мне данные».
Как устроен процесс работы через Webhook:
— Вы поднимаете простейший веб-сервер (например, на FastAPI) и создаете эндпоинт, готовый принимать
— Регистрируете этот URL в стороннем сервисе (через настройки API Telegram, платежки или GitHub).
— Когда происходит событие, сторонний сервис сам формирует HTTP-запрос с JSON-пакетом внутри и отправляет его на ваш адрес.
— Ваш код мгновенно ловит этот запрос, обрабатывает данные и возвращает статус
Зачем это инженеру? Ради моментальной реакции и тишины в логах. С веб-хуками бот отвечает пользователю за миллисекунды, потому что он не ждет следующего цикла проверки, а реагирует на входящий триггер здесь и сейчас. Ваш сервер отдыхает, пока нет реальной активности.
Пример обработки веб-хука на FastAPI:
Однако у веб-хуков есть важный нюанс: ваш сервер должен иметь публичный IP-адрес и работать по защищенному протоколу HTTPS (то, что мы как раз настраивали с помощью Nginx и Certbot). Если вы ведете разработку локально на домашнем компьютере, сторонний сервис не сможет достучаться до вашего
Для тестирования веб-хуков на локальной машине используют инструменты туннелирования вроде ngrok или LocalTunnel. Они создают временный публичный HTTPS-адрес и перенаправляют весь входящий трафик прямиком в ваш локальный порт.
Использование Webhooks — это стандарт для построения событийно-ориентированных (Event-Driven) систем. Это избавляет инфраструктуру от лишней работы и позволяет вашему коду мгновенно реагировать на любые изменения во внешнем мире.
🚪 Bash Ready | #практика
Когда вы создаете Telegram-бота, парсер или платежную систему, вашему коду нужно оперативно узнавать о новых событиях: пользователь отправил сообщение, пришла оплата на криптокошелек или обновилась котировка. У вас есть два пути: постоянно спамить чужой сервер запросами в цикле (Polling) или настроить Webhook (веб-хук).
---
Polling — это когда ваш скрипт каждые две секунды спрашивает: «Ну что, есть новые данные? А сейчас? А теперь?». Это дико перегружает процессор, тратит сетевой трафик и создает кучу пустых запросов.
Webhook работает ровно наоборот (принцип *Don't call us, we'll call you*). Вы один раз говорите стороннему сервису: «Вот адрес моего сервера (URL). Как только что-то произойдет — сам пришли мне данные».
Как устроен процесс работы через Webhook:
— Вы поднимаете простейший веб-сервер (например, на FastAPI) и создаете эндпоинт, готовый принимать
POST-запросы (например, /api/v1/telegram-webhook).— Регистрируете этот URL в стороннем сервисе (через настройки API Telegram, платежки или GitHub).
— Когда происходит событие, сторонний сервис сам формирует HTTP-запрос с JSON-пакетом внутри и отправляет его на ваш адрес.
— Ваш код мгновенно ловит этот запрос, обрабатывает данные и возвращает статус
200 OK, подтверждая, что всё получено.Зачем это инженеру? Ради моментальной реакции и тишины в логах. С веб-хуками бот отвечает пользователю за миллисекунды, потому что он не ждет следующего цикла проверки, а реагирует на входящий триггер здесь и сейчас. Ваш сервер отдыхает, пока нет реальной активности.
Пример обработки веб-хука на FastAPI:
from fastapi import FastAPI, Request, Response
app = FastAPI()
@app.post("/webhook/payment")
async def receive_payment_webhook(request: Request):
# Получаем JSON с данными о транзакции
payload = await request.json()
event_type = payload.get("event")
amount = payload.get("amount")
if event_type == "payment.success":
print(f"Зачислено {amount}$! Начисляем баланс пользователю...")
# Тут ваша логика обработки (например, запись в базу)
return Response(status_code=200)
Однако у веб-хуков есть важный нюанс: ваш сервер должен иметь публичный IP-адрес и работать по защищенному протоколу HTTPS (то, что мы как раз настраивали с помощью Nginx и Certbot). Если вы ведете разработку локально на домашнем компьютере, сторонний сервис не сможет достучаться до вашего
localhost.Для тестирования веб-хуков на локальной машине используют инструменты туннелирования вроде ngrok или LocalTunnel. Они создают временный публичный HTTPS-адрес и перенаправляют весь входящий трафик прямиком в ваш локальный порт.
Использование Webhooks — это стандарт для построения событийно-ориентированных (Event-Driven) систем. Это избавляет инфраструктуру от лишней работы и позволяет вашему коду мгновенно реагировать на любые изменения во внешнем мире.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍2🔥2
🛠️ Идемпотентность API — как защитить систему от дубликатов запросов?
Представьте ситуацию: пользователь в мобильном приложении нажимает кнопку «Оплатить заказ». Клик улетает на бэкенд, списываются деньги, но в этот самый момент на телефоне на секунду пропадает связь. Приложение не получает ответ от сервера, считает, что произошел сбой, и автоматически отправляет запрос повторно. Если ваш бэкенд не обладает свойством идемпотентности, у пользователя спишутся деньги дважды.
Идемпотентность в программировании — это свойство метода или всей системы выдавать один и тот же результат при многократных идентичных запросах. Сколько бы раз вы ни отправили один и тот же запрос, состояние системы изменится только один раз, а все последующие ответы будут точной копией первого успешного ответа.
В стандартном REST API некоторые HTTP-методы идемпотентны по определению:
— GET: сколько раз ни запрашивай профиль пользователя, он не изменится.
— PUT / DELETE: если вы обновили имя на конкретное значение или удалили пост с
— POST: не идемпотентен. Каждый новый вызов по умолчанию пытается создать новую запись в базе данных. Именно с ним и возникают проблемы при дублировании сетевых пакетов.
Как это правильно реализовать на практике:
Самый надежный способ защитить неидемпотентные операции (например, создание транзакции или отправку сообщения) — использование специального ключа идемпотентности (
— Генерация ключа: Перед отправкой POST-запроса фронтенд (или клиент) генерирует уникальный UUID для этой операции и прикрепляет его в заголовки:
— Проверка на бэкенде: Когда запрос приходит на сервер, бэкенд первым в цепочке (например, через Middleware) проверяет, есть ли такой ключ в быстром кэше (идеально подходит Redis со временем жизни ключа в 24 часа).
— Если ключа нет: Сервер понимает, что это уникальный запрос. Он сохраняет ключ в Redis со статусом «в обработке» (
— Если ключ уже есть: Сервер видит, что этот запрос дубликат. Если статус еще «в обработке», он просит клиента подождать. Если статус «выполнено» — сервер просто берет готовый ответ из Redis и возвращает его клиенту, вообще не трогая основную базу данных и не выполняя код повторно.
Зачем это инженеру? Это критически важный стандарт при работе с любыми финансовыми шлюзами, внешними интеграциями и распределенными системами. Сетевые сбои, повторные нажатия кнопок пользователями или автоматические ретраи (retries) в очередях задач — обычное дело для продакшена.
Реализация идемпотентности гарантирует предсказуемость и стабильность данных. Вы можете спать спокойно, зная, что даже при сотне одинаковых сетевых запросов система отработает ровно один раз, сохранив целостность базы данных и нервы ваших пользователей.
🚪 Bash Ready | #практика
Представьте ситуацию: пользователь в мобильном приложении нажимает кнопку «Оплатить заказ». Клик улетает на бэкенд, списываются деньги, но в этот самый момент на телефоне на секунду пропадает связь. Приложение не получает ответ от сервера, считает, что произошел сбой, и автоматически отправляет запрос повторно. Если ваш бэкенд не обладает свойством идемпотентности, у пользователя спишутся деньги дважды.
Идемпотентность в программировании — это свойство метода или всей системы выдавать один и тот же результат при многократных идентичных запросах. Сколько бы раз вы ни отправили один и тот же запрос, состояние системы изменится только один раз, а все последующие ответы будут точной копией первого успешного ответа.
В стандартном REST API некоторые HTTP-методы идемпотентны по определению:
— GET: сколько раз ни запрашивай профиль пользователя, он не изменится.
— PUT / DELETE: если вы обновили имя на конкретное значение или удалили пост с
id=5, повторные вызовы дадут тот же результат (пост останется удаленным).— POST: не идемпотентен. Каждый новый вызов по умолчанию пытается создать новую запись в базе данных. Именно с ним и возникают проблемы при дублировании сетевых пакетов.
Как это правильно реализовать на практике:
Самый надежный способ защитить неидемпотентные операции (например, создание транзакции или отправку сообщения) — использование специального ключа идемпотентности (
Idempotency-Key).— Генерация ключа: Перед отправкой POST-запроса фронтенд (или клиент) генерирует уникальный UUID для этой операции и прикрепляет его в заголовки:
Idempotency-Key: 7b9e84b2-a42e-4e1b-b461-9f9361ad2a48.— Проверка на бэкенде: Когда запрос приходит на сервер, бэкенд первым в цепочке (например, через Middleware) проверяет, есть ли такой ключ в быстром кэше (идеально подходит Redis со временем жизни ключа в 24 часа).
— Если ключа нет: Сервер понимает, что это уникальный запрос. Он сохраняет ключ в Redis со статусом «в обработке» (
In Progress) и начинает выполнять код. После успешного завершения статус меняется на «выполнено» (Completed), а рядом сохраняется тело ответа (Response Body).— Если ключ уже есть: Сервер видит, что этот запрос дубликат. Если статус еще «в обработке», он просит клиента подождать. Если статус «выполнено» — сервер просто берет готовый ответ из Redis и возвращает его клиенту, вообще не трогая основную базу данных и не выполняя код повторно.
Зачем это инженеру? Это критически важный стандарт при работе с любыми финансовыми шлюзами, внешними интеграциями и распределенными системами. Сетевые сбои, повторные нажатия кнопок пользователями или автоматические ретраи (retries) в очередях задач — обычное дело для продакшена.
Реализация идемпотентности гарантирует предсказуемость и стабильность данных. Вы можете спать спокойно, зная, что даже при сотне одинаковых сетевых запросов система отработает ровно один раз, сохранив целостность базы данных и нервы ваших пользователей.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3❤1
🔄 Пул соединений (Connection Pool) — как не положить базу данных при нагрузке
Когда ваш Python-скрипт или веб-сервер делает запрос к базе данных (PostgreSQL, MySQL), под капотом происходит сложный процесс: приложение стучится к серверу базы по сети, проходит авторизацию, открывает сетевой сокет, выполняет SQL-запрос и закрывает соединение. Если на каждый клик пользователя открывать новое соединение с нуля, сервер моментально захлебнется. Решение этой проблемы — Connection Pool.
Открытие нового соединения — это одна из самых «дорогих» и медленных операций в работе с базами данных. Приложении тратит драгоценное время процессора и сети еще до того, как выполнит сам SQL-код.
Пул соединений работает по принципу кэширования: при старте приложения создается фиксированное количество готовых, уже авторизованных сетевых подключений к базе (например, 10–20 штук), которые удерживаются в памяти в активном состоянии.
Как устроен жизненный цикл запроса с Connection Pool:
— Запрос к базе: Когда вашему коду нужно вытянуть данные, он не создает новое подключение, а просит пул выдать одно из свободных.
— Выполнение кода: Приложение мгновенно получает готовый сокет, выполняет SQL-запрос и забирает результат.
— Возврат в пул: Вместо закрытия соединения (
Зачем это инженеру? Чтобы защитить базу от падения и ускорить приложение в разы. У любой СУБД (например, PostgreSQL) есть жесткий лимит на максимальное количество одновременных подключений (
В экосистеме Python при работе с асинхронным бэкендом (FastAPI / SQLAlchemy) пул соединений настраивается автоматически прямо при создании движка (Engine).
Пример настройки пула в SQLAlchemy:
Если ваше приложение разрастается на несколько серверов или Docker-контейнеров, локального пула внутри кода может не хватить (ведь каждый контейнер заберет себе по 20 подключений, и лимит базы снова исчерпается). В таких масштабах перед PostgreSQL ставят специализированные внешние прокси-пулеры — PgBouncer или Odyssey, которые умеют эффективно делить подключения между тысячами независимых процессов.
Использование Connection Pool превращает хаотичные сетевые запросы в упорядоченный, предсказуемый поток данных, снижая нагрузку на сервер и обеспечивая стабильную работу проекта даже в моменты жесткого хабраэффекта.
🚪 Bash Ready | #практика
Когда ваш Python-скрипт или веб-сервер делает запрос к базе данных (PostgreSQL, MySQL), под капотом происходит сложный процесс: приложение стучится к серверу базы по сети, проходит авторизацию, открывает сетевой сокет, выполняет SQL-запрос и закрывает соединение. Если на каждый клик пользователя открывать новое соединение с нуля, сервер моментально захлебнется. Решение этой проблемы — Connection Pool.
Открытие нового соединения — это одна из самых «дорогих» и медленных операций в работе с базами данных. Приложении тратит драгоценное время процессора и сети еще до того, как выполнит сам SQL-код.
Пул соединений работает по принципу кэширования: при старте приложения создается фиксированное количество готовых, уже авторизованных сетевых подключений к базе (например, 10–20 штук), которые удерживаются в памяти в активном состоянии.
Как устроен жизненный цикл запроса с Connection Pool:
— Запрос к базе: Когда вашему коду нужно вытянуть данные, он не создает новое подключение, а просит пул выдать одно из свободных.
— Выполнение кода: Приложение мгновенно получает готовый сокет, выполняет SQL-запрос и забирает результат.
— Возврат в пул: Вместо закрытия соединения (
connection.close()), код просто возвращает его обратно в пул. Оно остается открытым и ждет следующего пользователя.Зачем это инженеру? Чтобы защитить базу от падения и ускорить приложение в разы. У любой СУБД (например, PostgreSQL) есть жесткий лимит на максимальное количество одновременных подключений (
max_connections). Если 500 пользователей одновременно зайдут на сайт без пула, база выдаст ошибку Too many connections и сайт упадет. Пул выступает в роли умного диспетчера.В экосистеме Python при работе с асинхронным бэкендом (FastAPI / SQLAlchemy) пул соединений настраивается автоматически прямо при создании движка (Engine).
Пример настройки пула в SQLAlchemy:
from sqlalchemy.ext.asyncio import create_async_engine
DATABASE_URL = "postgresql+asyncpg://user:password@localhost/mydb"
# Настраиваем пул соединений
engine = create_async_engine(
DATABASE_URL,
pool_size=10, # Базовое количество соединений, удерживаемых всегда
max_overflow=20, # Сколько максимум можно создать сверх нормы при пиковой нагрузке
pool_timeout=30, # Сколько секунд ждать свободное соединение из пула, прежде чем выкинуть ошибку
pool_recycle=1800 # Сбрасывать соединения каждые 30 минут, чтобы они не застаивались
)
Если ваше приложение разрастается на несколько серверов или Docker-контейнеров, локального пула внутри кода может не хватить (ведь каждый контейнер заберет себе по 20 подключений, и лимит базы снова исчерпается). В таких масштабах перед PostgreSQL ставят специализированные внешние прокси-пулеры — PgBouncer или Odyssey, которые умеют эффективно делить подключения между тысячами независимых процессов.
Использование Connection Pool превращает хаотичные сетевые запросы в упорядоченный, предсказуемый поток данных, снижая нагрузку на сервер и обеспечивая стабильную работу проекта даже в моменты жесткого хабраэффекта.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
⚙️ Графическое вычисление (GPU) против Центрального процессора (CPU) — когда бэкендеру нужны видеокарты?
Когда речь заходит об ускорении работы скриптов или сервисов, первая мысль разработчика — оптимизировать алгоритм или разложить задачи по ядрам процессора (CPU). Но бывают задачи, где даже самый мощный серверный процессор начинает безбожно тормозить. В этот момент тяжелые вычисления переносят на видеокарты (GPU).
---
CPU (Центральный процессор) — это «мозг» компьютера, спроектированный для решения общих и сложных последовательных задач. У него относительно мало ядер (обычно от 4 до 64), но каждое ядро невероятно мощное, имеет высокую тактовую частоту и огромный кэш. CPU отлично справляется с ветвлением логики (
GPU (Графический процессор) — устроен совершенно иначе. Он создавался для отрисовки графики и работы с 3D, где нужно одновременно просчитывать цвет миллионов пикселей на экране. Для этого вместо нескольких мощных ядер в него упаковали тысячи мелких, простых ядер, работающих параллельно.
Главные отличия в архитектуре вычислений:
— Параллелизм: CPU обрабатывает задачи последовательно (или в несколько мощных потоков). GPU берет массив данных и обрабатывает тысячи элементов одновременно по одной и той же инструкции (архитектура SIMD — *Single Instruction, Multiple Data*).
— Сложность операций: Ядро GPU не умеет эффективно выполнять сложную логику со множеством ветвлений. Его стихия — простая, однотипная математика: умножение матриц и работа с векторами.
Зачем это инженеру? Чтобы понимать, в какой момент архитектуру проекта нужно дополнить видеокартами. Если вы пишете стандартное REST API или парсер — GPU вам ничем не поможет. Но есть три сферы, где без видеокарт проект просто не запустится:
— Искусственный интеллект и Нейросети (AI/ML): Обучение моделей и генерация (будь то текст в LLM или картинки в Stable Diffusion) — это чистая линейная алгебра и гигантские матрицы. На GPU (например, с использованием ядер Nvidia CUDA или Тензорных ядер) эти процессы ускоряются в 100–1000 раз по сравнению с CPU.
— Обработка медиаданных: Сжатие «на лету» потокового видео, кодирование аудио высокого разрешения или рендеринг 3D-сцен на сервере.
— Криптография и Хэширование: Перебор паролей (брутфорс при аудите безопасности) или работа с блокчейн-сетями.
В экосистеме Python для работы с GPU бэкенд-разработчики используют библиотеки вроде PyTorch, TensorFlow или CuPy (аналог NumPy для видеокарт). Они позволяют перенести массив данных из обычной оперативной памяти (RAM) в видеопамять (VRAM) одной командой:
🚪 Bash Ready | #практика
Когда речь заходит об ускорении работы скриптов или сервисов, первая мысль разработчика — оптимизировать алгоритм или разложить задачи по ядрам процессора (CPU). Но бывают задачи, где даже самый мощный серверный процессор начинает безбожно тормозить. В этот момент тяжелые вычисления переносят на видеокарты (GPU).
---
CPU (Центральный процессор) — это «мозг» компьютера, спроектированный для решения общих и сложных последовательных задач. У него относительно мало ядер (обычно от 4 до 64), но каждое ядро невероятно мощное, имеет высокую тактовую частоту и огромный кэш. CPU отлично справляется с ветвлением логики (
if/else), управлением операционной системой, работой баз данных и выполнением стандартного кода вашего приложения.GPU (Графический процессор) — устроен совершенно иначе. Он создавался для отрисовки графики и работы с 3D, где нужно одновременно просчитывать цвет миллионов пикселей на экране. Для этого вместо нескольких мощных ядер в него упаковали тысячи мелких, простых ядер, работающих параллельно.
Главные отличия в архитектуре вычислений:
— Параллелизм: CPU обрабатывает задачи последовательно (или в несколько мощных потоков). GPU берет массив данных и обрабатывает тысячи элементов одновременно по одной и той же инструкции (архитектура SIMD — *Single Instruction, Multiple Data*).
— Сложность операций: Ядро GPU не умеет эффективно выполнять сложную логику со множеством ветвлений. Его стихия — простая, однотипная математика: умножение матриц и работа с векторами.
Зачем это инженеру? Чтобы понимать, в какой момент архитектуру проекта нужно дополнить видеокартами. Если вы пишете стандартное REST API или парсер — GPU вам ничем не поможет. Но есть три сферы, где без видеокарт проект просто не запустится:
— Искусственный интеллект и Нейросети (AI/ML): Обучение моделей и генерация (будь то текст в LLM или картинки в Stable Diffusion) — это чистая линейная алгебра и гигантские матрицы. На GPU (например, с использованием ядер Nvidia CUDA или Тензорных ядер) эти процессы ускоряются в 100–1000 раз по сравнению с CPU.
— Обработка медиаданных: Сжатие «на лету» потокового видео, кодирование аудио высокого разрешения или рендеринг 3D-сцен на сервере.
— Криптография и Хэширование: Перебор паролей (брутфорс при аудите безопасности) или работа с блокчейн-сетями.
В экосистеме Python для работы с GPU бэкенд-разработчики используют библиотеки вроде PyTorch, TensorFlow или CuPy (аналог NumPy для видеокарт). Они позволяют перенести массив данных из обычной оперативной памяти (RAM) в видеопамять (VRAM) одной командой:
import torch
# Проверяем, доступна ли видеокарта от Nvidia
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# Создаем тяжелую матрицу и отправляем её на вычисление в GPU
x = torch.randn(10000, 10000, device=device)
y = torch.randn(10000, 10000, device=device)
# Мгновенное матричное умножение силами ядер видеокарты
result = torch.matmul(x, y)
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤2😁1
Проверка времени отклика сервисов
Когда сервис работает, но пользователи жалуются на медлительность, нужно мерить не аптайм, а отклик. Это легко сделать обычным curl.
▪️ Самый простой замер
Показывает общее время выполнения запроса и быстро понять, тормозит или нет.
▪️ Точнее: только сетевое время
Полезные метрики:
Пример:
▪️ Проверка нескольких сервисов
▪️ Таймаут обязателен
Без таймаута любой мониторинг бесполезен.
Когда сервис работает, но пользователи жалуются на медлительность, нужно мерить не аптайм, а отклик. Это легко сделать обычным curl.
time curl -s https://bashtex.com > /dev/null
Показывает общее время выполнения запроса и быстро понять, тормозит или нет.
curl -s -o /dev/null -w "time_total: %{time_total}\n" https://bashtex.com
Полезные метрики:
time_namelookup
time_connect
time_starttransfer
time_totalПример:
curl -w "DNS:%{time_namelookup} CONNECT:%{time_connect} TTFB:%{time_starttransfer} TOTAL:%{time_total}\n" \
-o /dev/null -s https://bashtex.com
for url in https://a.ru https://b.ru; do
curl -o /dev/null -s -w "$url %{time_total}\n" "$url"
done
curl --connect-timeout 3 --max-time 5 https://bashtex.com
Без таймаута любой мониторинг бесполезен.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍4
This media is not supported in your browser
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7😁1
Руководитель группы продукта «Поиск и Рекомендации» Яндекс Маркета Любовь Горбунова считает, что необходимость в предельно точных формулировках снижается: нейросеть все лучше понимает запросы и в перспективе с ней можно будет общаться как с консультантом в магазине — в свободной форме и с уточнениями по ходу диалога.
Еще один тренд — использование ИИ вместе с VR/AR-технологиями. Уже сейчас такие решения улучшают сценарии виртуальной примерки одежды. А в будущем подход может распространиться и на другие категории, например, на «примерку» мебели в интерьере.
Please open Telegram to view this post
VIEW IN TELEGRAM
В новом исследовании изучили Spotify и выяснили, что 93% нейротреков не набирают даже 1000 прослушиваний.
Авторы называют это music slop. Тысячи композиций заливают пачками в разные жанры, надеясь случайно попасть в рекомендации. Дистрибьюторы почти этому не мешают, а детекторы пока легко обходятся.
А как часто вам попадается в реках нейрохрючево?
• Источник
Please open Telegram to view this post
VIEW IN TELEGRAM
😁5
Поиск забытых .ssh директорий
После чистки пользователей в системе нередко остаются их .ssh-каталоги. Это мусор + потенциальная дыра: старые ключи могут лежать годами.
▪️ Быстрый поиск по системе
Найдет все .ssh, включая:
нестандартные каталоги
▪️ Проверяем, существует ли владелец
Если владелец:
UNKNOWN
или пользователь отсутствует в
то каталог подозрительный.
▪️ Поиск .ssh без пользователя
⚠️ Перед удалением лучше сделать архив
После чистки пользователей в системе нередко остаются их .ssh-каталоги. Это мусор + потенциальная дыра: старые ключи могут лежать годами.
find / -type d -name .ssh 2>/dev/null
Найдет все .ssh, включая:
/home/*/.ssh
/root/.sshнестандартные каталоги
find / -type d -name .ssh -exec stat -c '%U %n' {} \;
Если владелец:
UNKNOWN
или пользователь отсутствует в
/etc/passwdто каталог подозрительный.
while read user path; do
id "$user" &>/dev/null || echo "Лишний: $path"
done < <(find / -type d -name .ssh -exec stat -c '%U %n' {} \;)
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Циклы while vs for - где что правильно
В bash оба цикла нужны, но для разных задач. Путаница между ними - источник проблем.
▪️ for - перебор готового списка. Используй, когда список уже есть.
файлы;
аргументы "$@";
элементы массива.
⚠️ Пример ошибок:
▪️ while - поток данных. Идеален для чтения ввода.
строки с пробелами;
вывод команд;
большие файлы.
⚠️ Частая ошибка:
(цикл в subshell!)
В bash оба цикла нужны, но для разных задач. Путаница между ними - источник проблем.
for f in *.log; do
echo "$f"
done
файлы;
аргументы "$@";
элементы массива.
for f in $(ls *.log); do # ломается на пробелах
while IFS= read -r line; do
echo "$line"
done < file.txt
строки с пробелами;
вывод команд;
большие файлы.
cat file | while read line; do
count=$((count+1)) # переменная пропадёт
done
(цикл в subshell!)
for не является универсальным, а while безопаснее для данных. Перед созданием цикла нужно задавать себе вопрос: список или поток.Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤1
🧠 Быстрый просмотр SSL-сертификата домена
Нужно быстро проверить срок действия SSL-сертификата у удалённого сайта без браузера?
📌 Покажет строки вида:
🔒 Хочешь только дату окончания? Добавь
📦 Убедись, что установлен
💡 Подходит для мониторинга и ручной проверки валидности сертификатов.
Нужно быстро проверить срок действия SSL-сертификата у удалённого сайта без браузера?
echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null | openssl x509 -noout -dates
📌 Покажет строки вида:
notBefore=Jun 1 00:00:00 2024 GMT
notAfter=Aug 30 23:59:59 2024 GMT
🔒 Хочешь только дату окончания? Добавь
| grep notAfter📦 Убедись, что установлен
openssl💡 Подходит для мониторинга и ручной проверки валидности сертификатов.
❤3
KubePlumber проверяет работу сети Kubernetes изнутри кластера, тестируя:
* внутренний DNS,
* трафик между подами,
* внешний DNS,
* пропускную способность между нодами.
➤ https://github.com/David-VTUK/KubePlumber
* внутренний DNS,
* трафик между подами,
* внешний DNS,
* пропускную способность между нодами.
➤ https://github.com/David-VTUK/KubePlumber
This media is not supported in your browser
VIEW IN TELEGRAM
Как обученная AI-модель превращается в production API в Kubernetes?
KServe — это проект CNCF на стадии Incubating для развёртывания и обслуживания AI-моделей в Kubernetes.
Проще говоря, KServe берёт обученную модель и превращает её в масштабируемый inference-сервис в Kubernetes.
Он берёт на себя деплой, сеть, автоскейлинг и health checks модели.
Важно понимать, что KServe уже давно работает не только с классическими ML-моделями.
Как inference-платформа, он поддерживает две категории AI/ML-нагрузок:
- Predictive AI (классический ML): например, модели на scikit-learn, XGBoost, модели, упакованные через MLflow, и другие.
- Generative AI (LLM): например, запуск и обслуживание LLM через backend vLLM с поддержкой GPU.
Если хотите разобраться, как устроена inference-платформа KServe, можно прочитать свежий выпуск MLOps-рассылки.
В нём разбираются:
- Model Servers и runtimes в KServe
- Как KServe разворачивает AI-модели в Kubernetes
- Деплой MLflow-модели в KServe на практике
- Как выкатывать новые версии моделей
- Rolling Updates, Canary, A/B Testing и Shadow Deployments
И многое другое.
Читать здесь: https://newsletter.devopscube.com/p/kserve
KServe — это проект CNCF на стадии Incubating для развёртывания и обслуживания AI-моделей в Kubernetes.
Проще говоря, KServe берёт обученную модель и превращает её в масштабируемый inference-сервис в Kubernetes.
Он берёт на себя деплой, сеть, автоскейлинг и health checks модели.
Важно понимать, что KServe уже давно работает не только с классическими ML-моделями.
Как inference-платформа, он поддерживает две категории AI/ML-нагрузок:
- Predictive AI (классический ML): например, модели на scikit-learn, XGBoost, модели, упакованные через MLflow, и другие.
- Generative AI (LLM): например, запуск и обслуживание LLM через backend vLLM с поддержкой GPU.
Если хотите разобраться, как устроена inference-платформа KServe, можно прочитать свежий выпуск MLOps-рассылки.
В нём разбираются:
- Model Servers и runtimes в KServe
- Как KServe разворачивает AI-модели в Kubernetes
- Деплой MLflow-модели в KServe на практике
- Как выкатывать новые версии моделей
- Rolling Updates, Canary, A/B Testing и Shadow Deployments
И многое другое.
Читать здесь: https://newsletter.devopscube.com/p/kserve
Многие ли знают, что Helm хранит информацию о релизах в Kubernetes Secrets?
Когда вы запускаете
В Secret хранится, например:
- имя релиза;
- статус деплоя;
- применённые манифесты;
- использованные values;
- информация о chart и другие данные.
Данные в Secret сжимаются с помощью gzip, а затем кодируются в base64.
Имя Secret создаётся по следующему шаблону:
Когда вы запускаете
Helm не нужна внешняя база данных.
Вся информация хранится прямо в вашем кластере в виде нативных Kubernetes Secrets.
Примечание: также можно настроить внешнюю SQL-базу данных для хранения релизов, но эта возможность пока находится в beta
Когда вы запускаете
helm install или helm upgrade, Helm сохраняет данные о релизе в K8s Secrets в том же namespace.В Secret хранится, например:
- имя релиза;
- статус деплоя;
- применённые манифесты;
- использованные values;
- информация о chart и другие данные.
Данные в Secret сжимаются с помощью gzip, а затем кодируются в base64.
Имя Secret создаётся по следующему шаблону:
sh.helm.release.v1.[release-name].v[revision]Когда вы запускаете
helm rollback, Helm читает эти Secrets, чтобы восстановить приложение до предыдущей версии.Helm не нужна внешняя база данных.
Вся информация хранится прямо в вашем кластере в виде нативных Kubernetes Secrets.
Примечание: также можно настроить внешнюю SQL-базу данных для хранения релизов, но эта возможность пока находится в beta
❤2
VPN, который просто работает.
RuSolv — подключение за несколько минут, 50+ серверов и современные протоколы для стабильного доступа к интернету.
✓ 10 ГБ каждый месяц бесплатно
✓ Без привязки карты
✓ Без логов
✓ Телефон, компьютер и другие устройства
Попробуйте бесплатно → https://rusolv.com
RuSolv — подключение за несколько минут, 50+ серверов и современные протоколы для стабильного доступа к интернету.
✓ 10 ГБ каждый месяц бесплатно
✓ Без привязки карты
✓ Без логов
✓ Телефон, компьютер и другие устройства
Попробуйте бесплатно → https://rusolv.com
👍2👎1