{
    "version": "https:\/\/jsonfeed.org\/version\/1.1",
    "title": "Yuriy Gavrilov: posts tagged Ray",
    "_rss_description": "Welcome to my personal place for love, peace and happiness 🤖 Yuiry Gavrilov",
    "_rss_language": "en",
    "_itunes_email": "yvgavrilov@gmail.com",
    "_itunes_categories_xml": "",
    "_itunes_image": "https:\/\/gavrilov.info\/pictures\/userpic\/userpic-square@2x.jpg?1643451008",
    "_itunes_explicit": "no",
    "home_page_url": "https:\/\/gavrilov.info\/tags\/ray\/",
    "feed_url": "https:\/\/gavrilov.info\/tags\/ray\/json\/",
    "icon": "https:\/\/gavrilov.info\/pictures\/userpic\/userpic@2x.jpg?1643451008",
    "authors": [
        {
            "name": "Yuriy Gavrilov - B[u]g - for charity.gavrilov.eth",
            "url": "https:\/\/gavrilov.info\/",
            "avatar": "https:\/\/gavrilov.info\/pictures\/userpic\/userpic@2x.jpg?1643451008"
        }
    ],
    "items": [
        {
            "id": "334",
            "url": "https:\/\/gavrilov.info\/all\/raspredelyonnye-vychisleniya-s-ray-i-otchetiki\/",
            "title": "Распределённые вычисления с Ray и отчетики",
            "content_html": "<h3>Введение в распределённые вычисления с Ray<\/h3>\n<p>ПредположенИИе 🤖<\/p>\n<p>Ray — это унифицированный фреймворк с открытым исходным кодом для масштабирования AI- и Python-приложений. Он предоставляет простой API для создания распределённых приложений, которые могут масштабироваться от одного ноутбука до целого кластера без изменения кода. Ray эффективно обрабатывает разнообразные рабочие нагрузки: от пакетной обработки данных и распределённого обучения моделей до гиперпараметрической оптимизации и serving-а инференса моделей в продакшене. Ray не ограничивается только задачами ML: он также предоставляет Ray Data и потоковые примитивы для эффективных входных пайплайнов, пакетной обработки и онлайн-инференса.<\/p>\n<h4>Ключевые возможности Ray<\/h4>\n<ul>\n<li><b>Единый фреймворк<\/b>: Одна кодовая база охватывает все этапы жизненного цикла AI — от обработки данных до развёртывания моделей, устраняя сложность интеграции разнородных систем.<\/li>\n<li><b>Масштабируемость<\/b>: Бесшовный переход от локальной разработки к кластеру из тысяч ядер без переписывания кода.<\/li>\n<li><b>Производительность<\/b>: На некоторых ML-задачах Ray показывает результаты лучше, чем Spark и Dask, а на одном узле — на ~10% быстрее стандартной многопроцессорной обработки Python.<\/li>\n<li><b>Гибкость<\/b>: Поддержка как stateful (сохраняющих состояние), так и stateless (не сохраняющих состояние) рабочих нагрузок с помощью задач (tasks) и акторов (actors).<\/li>\n<\/ul>\n<h3>Фронтенд для дашбордов: Streamlit и Marimo<\/h3>\n<p>Для визуализации данных и создания интерактивных дашбордов на Python сегодня доступны два мощных инструмента: проверенный временем Streamlit и современный Marimo.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/gavrilov.info\/pictures\/Snimok-ekrana-2026-04-23-v-08.46.41.png\" width=\"2130\" height=\"1370\" alt=\"\" \/>\n<\/div>\n<h4>Streamlit: Классика для data-приложений<\/h4>\n<p>Streamlit — это open-source Python-библиотека, которая позволяет превратить скрипты анализа данных в полноценные веб-приложения за считанные минуты, без необходимости писать HTML, CSS или JavaScript. Streamlt поддерживает:<\/p>\n<ul>\n<li><b>Виджеты<\/b>: Слайдеры, кнопки, текстовые поля для создания интерактивных интерфейсов.<\/li>\n<li><b>Кэширование<\/b>: Декораторы `st.cache_data` и `st.cache_resource` для оптимизации загрузки данных и управления тяжёлыми объектами (моделями, подключениями к БД).<\/li>\n<li><b>Многозатраничность<\/b>: Возможность создавать приложения с несколькими страницами через папку `pages\/`.<\/li>\n<\/ul>\n<h4>Marimo: Реактивная альтернатива<\/h4>\n<p>Marimo — это реактивный Python-ноутбук нового поколения, который также можно использовать для создания веб-приложений. Главное отличие от Streamlit — реактивная модель выполнения: при изменении одной ячейки или взаимодействии с UI-элементом автоматически пересчитываются только зависимые ячейки, а не весь скрипт. Marimo подходит для сложного исследовательского анализа и интерактивных дашбордов, где важна производительность и детальный контроль выполнения.<\/p>\n<h4>Сравнение Streamlit и Marimo<\/h4>\n<ul>\n<li><b>Подход<\/b>: Streamlit — это фреймворк для data-приложений, тогда как Marimo — ноутбук-среда, которую можно запускать как приложение.<\/li>\n<li><b>Производительность<\/b>: Marimo часто показывает лучшую производительность, так как перезапускает только зависимые части, в отличие от Streamlit, который выполняет весь скрипт заново при каждом взаимодействии.<\/li>\n<li><b>Сценарии использования<\/b>: Streamlt идеален для быстрой разработки надёжных бизнес-дашбордов, а Marimo — для исследовательских задач и сложной аналитики.<\/li>\n<\/ul>\n<h3>Архитектура системы: Ray как бэкенд для дашбордов<\/h3>\n<p>Рассмотрим практический пример построения масштабируемой системы отчётности, где Ray выступает в роли мощного бэкенда для обработки и serving-а данных, а Streamlit (или Marimo) — в роли фронтенда для визуализации. Код визуализаций хранится в Git, что упрощает версионирование, совместную работу и развёртывание.<\/p>\n<h4>Основные компоненты<\/h4>\n<ol start=\"1\">\n<li><b>Бэкенд (Ray)<\/b>: Распределённое приложение (деплоймент) на Ray Serve, которое подключается к источнику данных (например, Trino), выполняет сложные агрегации и возвращает результат.<\/li>\n<li><b>Фронтенд (Streamlit\/Marimo)<\/b>: Веб-приложение, которое отправляет HTTP-запросы к Ray-бэкенду, получает данные и отображает их в интерактивных дашбордах.<\/li>\n<li><b>Внешнее хранилище состояния (опционально)<\/b>: Redis или база данных для хранения состояния сессий пользователей.<\/li>\n<li><b>Git<\/b>: Репозиторий для хранения кода фронтенда (Streamlit-скрипты, Marimo-ноутбуки) и конфигураций.<\/li>\n<\/ol>\n<h4>Пример кода: Бэкенд на Ray Serve<\/h4>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/gavrilov.info\/pictures\/Snimok-ekrana-2026-04-23-v-08.47.14.png\" width=\"2478\" height=\"1666\" alt=\"\" \/>\n<\/div>\n<pre class=\"e2-text-code\"><code class=\"\">import ray\nfrom ray import serve\nfrom fastapi import FastAPI, HTTPException\nimport trino\nimport pandas as pd\n\napp = FastAPI()\n\n@serve.deployment(\n    ray_actor_options={&quot;num_cpus&quot;: 0.5},\n    autoscaling_config={&quot;min_replicas&quot;: 1, &quot;max_replicas&quot;: 2},\n)\n@serve.ingress(app)\nclass TrinoQuery:\n    def __init__(self):\n        self.conn = trino.dbapi.connect(\n            host=&quot;192.168.0.125&quot;,\n            port=9999,\n            user=&quot;jupyter&quot;,\n            catalog=&quot;test_warehouse&quot;,\n            schema=&quot;test_schema&quot;,\n            http_scheme=&quot;http&quot;,\n        )\n        print(&quot;Соединение с Trino установлено.&quot;)\n\n    @app.get(&quot;\/query&quot;)\n    async def execute_query(self, query: str):\n        if not query:\n            raise HTTPException(status_code=400, detail=&quot;Query parameter is required.&quot;)\n        try:\n            cursor = self.conn.cursor()\n            cursor.execute(query)\n            rows = cursor.fetchall()\n            col_names = [desc[0] for desc in cursor.description]\n            df = pd.DataFrame(rows, columns=col_names)\n            return df.to_dict(orient=&quot;records&quot;)\n        except Exception as e:\n            raise HTTPException(status_code=500, detail=str(e))\n\nray.init(ignore_reinit_error=True)\nserve.start(http_options={&quot;host&quot;: &quot;0.0.0.0&quot;, &quot;port&quot;: 8000})\nserve.run(TrinoQuery.bind(), blocking=True)<\/code><\/pre><h4>Пример кода: Фронтенд на Streamlit<\/h4>\n<pre class=\"e2-text-code\"><code class=\"\">import streamlit as st\nimport pandas as pd\nimport requests\n\nBACKEND_URL = &quot;http:\/\/127.0.0.1:8000\/query&quot;\n\nst.set_page_config(page_title=&quot;Аналитическая панель&quot;, layout=&quot;wide&quot;)\nst.title(&quot;Дашборд данных из Trino через Ray&quot;)\n\nwith st.sidebar:\n    st.header(&quot;Параметры запроса&quot;)\n    query = st.text_area(\n        &quot;SQL-запрос:&quot;,\n        value=&quot;SELECT nationkey, COUNT(*) as cnt FROM test_warehouse.test_schema.my_table1 GROUP BY nationkey&quot;,\n        height=200,\n    )\n    execute_button = st.button(&quot;Выполнить запрос&quot;, type=&quot;primary&quot;)\n\nif execute_button:\n    if not query:\n        st.warning(&quot;Введите SQL-запрос.&quot;)\n    else:\n        with st.spinner(&quot;Выполняется запрос через Ray Serve...&quot;):\n            try:\n                response = requests.get(BACKEND_URL, params={&quot;query&quot;: query}, timeout=30)\n                response.raise_for_status()\n                data = response.json()\n                if data:\n                    df = pd.DataFrame(data)\n                    st.success(f&quot;Запрос выполнен. Получено строк: {len(df)}&quot;)\n                    st.dataframe(df, use_container_width=True)\n                    if df.select_dtypes(include='number').shape[1] &gt; 0:\n                        st.subheader(&quot;Статистика по числовым колонкам&quot;)\n                        st.dataframe(df.describe(), use_container_width=True)\n                else:\n                    st.info(&quot;Запрос вернул пустой результат.&quot;)\n            except Exception as e:\n                st.error(f&quot;Ошибка: {e}&quot;)<\/code><\/pre><h4>Хранение визуализаций в Git<\/h4>\n<p>Код фронтенда (Streamlit-скрипты или Marimo-ноутбуки) должен храниться в Git-репозитории. Это обеспечивает:<\/p>\n<ul>\n<li><b>Версионирование<\/b>: Возможность отслеживать изменения, откатываться к предыдущим версиям.<\/li>\n<li><b>Совместную работу<\/b>: Команда разработчиков может одновременно работать над разными частями дашборда.<\/li>\n<li><b>Автоматизацию развёртывания<\/b>: CI\/CD пайплайны могут автоматически деплоить новую версию дашборда на сервер при пуше в определённую ветку.<\/li>\n<\/ul>\n<p>Репозиторий может иметь следующую структуру:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">.\n├── app.py                 # Основной файл Streamlit-приложения\n├── pages\/                 # Дополнительные страницы (если используются)\n├── marimo_notebooks\/      # Marimo-ноутбуки (если используются)\n├── requirements.txt       # Зависимости\n├── .gitignore\n└── README.md<\/code><\/pre><h3>Управление состоянием: как построить систему отчётов<\/h3>\n<p>В распределённой системе, где множество пользователей одновременно обращаются к дашборду, а сам бэкенд масштабируется на множество реплик, управление состоянием (state management) становится критически важным. Ошибка может привести к тому, что пользователь увидит чужие данные или потеряет свой прогресс в сессии.<\/p>\n<h4>Stateless vs. Stateful: Основной выбор<\/h4>\n<p>Ray поддерживает оба подхода:<\/p>\n<ul>\n<li><b>Stateless бэкенд (рекомендуемый)<\/b>: Бэкенд не хранит состояние пользователей. Вся сессионная информация (например, результаты фильтрации, текущая страница) хранится во фронтенде или во внешнем хранилище. Любая реплика Ray может обработать любой запрос. Это делает систему простой и отказоустойчивой, но требует, чтобы состояние было “лёгким” (например, хранилось в cookies или `session_state`).<\/li>\n<li><b>Stateful бэкенд<\/b>: Бэкенд хранит состояние в своей памяти. В этом случае необходимо обеспечить, чтобы все запросы от одного пользователя направлялись на одну и ту же реплику (sticky sessions).<\/li>\n<\/ul>\n<h4>Рекомендуемая архитектура: Stateless бэкенд + Session State во фронтенде<\/h4>\n<p>Для большинства BI-дашбордов идеальна следующая схема:<\/p>\n<ol start=\"1\">\n<li><b>Бэкенд (Ray)<\/b>: Полностью stateless. Он принимает запрос, выполняет вычисления и возвращает результат. Он не помнит, какие запросы делал пользователь ранее.<\/li>\n<li><b>Фронтенд (Streamlit\/Marimo)<\/b>: Хранит состояние сессии локально. В Streamlit для этого используется `st.session_state`. Например, вы можете сохранить в `session_state` фильтры, выбранные пользователем, чтобы они применялись при каждом взаимодействии.<\/li>\n<li><b>Внешнее хранилище<\/b>: Для кэширования результатов тяжёлых запросов или для хранения общего состояния (например, результатов обучения модели) используйте Redis или базу данных.<\/li>\n<\/ol>\n<h4>Если требуется Stateful бэкенд (например, кэш в памяти реплики)<\/h4>\n<p>Иногда возникает необходимость, чтобы бэкенд хранил какое-то состояние для повышения производительности. Например, каждая реплика может загружать большую модель машинного обучения в свою память. В таком случае используется подход <b>Soft Session Affinity<\/b>: все запросы от одного пользователя направляются на одну и ту же реплику, используя уникальный ключ (`X-SERVE-SHARD-KEY`).<\/p>\n<h4>Сценарий: Долгоживущий отчёт (Report as a Service)<\/h4>\n<p>Рассмотрим сценарий, где бизнес-пользователь хочет “заказать” отчёт, который генерируется 10 минут, и вернуться за ним через час. Stateless архитектура здесь не подойдёт, так как бэкенд “забудет” о задаче.<\/p>\n<ol start=\"1\">\n<li><b>Stateful бэкенд (Ray Actor)<\/b>: Используется долгоживущий Ray Actor (актор), который хранит состояние задачи и её результат.<\/li>\n<li><b>Хранилище задач<\/b>: База данных (например, PostgreSQL) используется для хранения информации о задаче (статус, результат). Актор периодически обновляет статус.<\/li>\n<li><b>Фронтенд<\/b>: Пользователь запускает задачу, получает её `task_id`, а затем периодически опрашивает эндпоинт `GET \/task\/{task_id}\/status`, который возвращает статус и, при готовности, результат.<\/li>\n<\/ol>\n<h3>Преимущества использования Ray в архитектуре отчётов<\/h3>\n<ol start=\"1\">\n<li><b>Масштабируемость под нагрузку<\/b>: Ray может автоматически масштабировать количество реплик бэкенда в зависимости от количества запросов. Если вашим дашбордом пользуется 10 или 10 000 человек, Ray адаптируется.<\/li>\n<li><b>Производительность<\/b>: Ray оптимизирован для параллельных вычислений и может обрабатывать большие объёмы данных быстрее, чем традиционные инструменты.<\/li>\n<li><b>Единая кодовая база<\/b>: Вы можете использовать Ray не только для serving-а данных, но и для их предварительной обработки, обучения моделей и т.д. Это упрощает инфраструктуру.<\/li>\n<li><b>Отказоустойчивость<\/b>: Ray автоматически перезапускает упавшие реплики, обеспечивая высокую доступность ваших дашбордов.<\/li>\n<li><b>Гибкость управления ресурсами<\/b>: Вы можете точно указать, сколько CPU и GPU нужно выделить для каждого компонента системы.<\/li>\n<\/ol>\n<h3>Заключение<\/h3>\n<p>Ray, Streamlit и Marimo образуют мощный тандем для построения современных систем отчётности и аналитики. Ray обеспечивает масштабируемый и производительный бэкенд, способный обрабатывать большие объёмы данных. Streamlit и Marimo предоставляют удобные средства для создания интерактивных и красивых дашбордов, а Git гарантирует контроль версий и простоту развёртывания. Ключом к успешной архитектуре является правильный выбор стратегии управления состоянием: в большинстве случаев подходит stateless бэкенд с хранением состояния во фронтенде, что обеспечивает простоту и отказоустойчивость. Для более сложных сценариев (долгие задачи, кэширование моделей) можно использовать stateful подход с Ray акторами и внешним хранилищем.<\/p>\n<p>Если вы хотите увидеть полный рабочий пример с кодом, архитектурной схемой и инструкцией по развёртыванию, дайте знать — я подготовлю подробный гайд.<\/p>\n",
            "date_published": "2026-04-23T08:49:14+03:00",
            "date_modified": "2026-04-23T08:48:38+03:00",
            "tags": [
                "BI",
                "big data",
                "Data",
                "Ray"
            ],
            "image": "https:\/\/gavrilov.info\/pictures\/Snimok-ekrana-2026-04-23-v-08.46.41.png",
            "_date_published_rfc2822": "Thu, 23 Apr 2026 08:49:14 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "334",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "highlight\/highlight.js",
                    "highlight\/highlight.css"
                ],
                "og_images": [
                    "https:\/\/gavrilov.info\/pictures\/Snimok-ekrana-2026-04-23-v-08.46.41.png",
                    "https:\/\/gavrilov.info\/pictures\/Snimok-ekrana-2026-04-23-v-08.47.14.png"
                ]
            }
        }
    ],
    "_e2_version": 4171,
    "_e2_ua_string": "Aegea 11.4 (v4171e)"
}