Задать вопрос
  • Почему Redis обрабатывает запрос в 5 раз дольше, чем запрос напрямую в бд?

    Eugene-Usachev
    @Eugene-Usachev
    Так в Postgres ты производишь выборку на стороне СУБД, а в случае с Redis выгружаешь всё по сети. Если в среднем строка весит 100 байт (а ты JSON используешь, так что там и больше быть может), то ты гоняешь по сети 10 000 * 100 байт, то есть примерно мегабайт памяти. Так и потом ты этот JSON разбираешь в JS (в нём же, да?), в то время как Postgres разбирает таблицу в C++.
    Ответ написан
    Комментировать
  • Архитектура кластера баз данных для географически распределенного проекта?

    Eugene-Usachev
    @Eugene-Usachev
    Если "чат/мессенджер/что-то подобное", будет лежать очень много данных. То есть профили можно сохранить хоть в Postgres + Redis (шардированный по регионам), и иметь вполне себе хорошую производительность. Проблема будет именно с сообщениями.

    Если решать проблему по логике "почему бы не стремиться к 8 млрд пользователей", для профилей можно взять Aerospike или Tarantool. Оба решения имеют возможность шардирования по вторичным ключам, так что их можно разнести по разным регионам. Причём надо именно шардироваться, а не только реплицироваться. Таким образом, можно избежать "узких горлышек". В этом случае оба решения будут выдавать более миллиона запросов в секунду на один кластер с маленькой задержкой (скорее всего двухзначной в медиане) и не иметь единой точки отказа.

    С сообщениями сложнее, так как их будут петабайты. Тут советую не "изобретать велосипед" и взять ScyllaDB, как это сделал Discord. ScyllaDB работает с огромными массивами данных довольно быстро и прекрасно масштабируется. Ради двухзначных чисел задержки в медиане достаточно шардироваться по регионам.

    Выводы очень простые. Если "стремиться к 8 млрд пользователей" надо
    1 - использовать нереляционные СУБД
    2 - шардировать БД по регионам (тогда можно отказаться от очередей)
    3 - использовать кэширование "горячих" данных
    4 - использовать Write-Optimized СУБД для больших массивов данных.

    Если у Вас "8 млрд пользователей" Вы можете позволить себе по датацентру в каждом регионе, поэтому основной задачей является правильное шардирование. И ещё один совет. Если гнаться за производительностью, надо использовать не очереди сообщений, а многопоточные асинхронные серверы, которые "кучкуют" сообщения пачками, чтобы как можно реже обращаться по сети.
    Ответ написан
    1 комментарий
  • Почему асинхронный блок поверх асинхронного асинхронного блока удваивает память?

    Eugene-Usachev
    @Eugene-Usachev Автор вопроса
    Я поднял этот вопрос на официальном форуме. Мне ответили, что пока что в async Rust есть несколько мест, в которых память используется неэффективно. Это будет исправлено в скором времени.
    Ответ написан
    1 комментарий
  • Как вытащить поля из запроса в pgx?

    Eugene-Usachev
    @Eugene-Usachev
    struct User {
        id int
        name string
        level int
        currentExp int
        maxExp int
    }
    
    var user User
    
    row := ... // Ваш запрос
    if err := row.Scan(&user.id, &user.name, &user.level, &user.currentExp, &user.maxExp); err != nil {
        // обработайте ошибку
    }
    
    // тут поля у user заполнены


    Вы не приложили структуру, поэтому мне пришлось её выдумать. Используйте метод Scan у row. Он принимает ссылки на переменные для вставки значений. Значения вставляет в том порядке, в котором они возвращаются, за этим нужно следить.

    Также уберите картинку или спрячьте её в спойлер. Я уже не помню номер правила, но Вы его нарушаете. У некоторых людей слабый интернет.
    Ответ написан
    Комментировать
  • Как написать такой макрос?

    Eugene-Usachev
    @Eugene-Usachev Автор вопроса
    Это частично возможно. Почему частично? Невозможно нормально обработать try-expression (он же знак вопроса) и макросы, которые держат в себе return. В остальном это возможно, но у меня ушло на это 164 строчки кода, а я всё ещё не уверен, что обработал все случаи (неявный возврат может придти из любого блока, находящегося в любом другом блоке; а я не уверен, что моей фантазии хватило на все случаи). Я не нашёл способа сделать это готовой функцией и парсил почти "в лоб руками", используя syn. Если кому интересно, решение кроется в рекурсивной обработке всех syn::Block и всех syn::Expr + syn::Local в нём.

    Я не буду прикладывать свой код здесь, так как он, вероятно, не обрабатывает все случаи и работает в худшем случаи за O(2*N) по скорости, но если реализация совсем не идёт в голову, пишите в комментарии этого ответа.
    Ответ написан
    Комментировать
  • Redis кеш под Wordpress сожрал всю память, что делать?

    Eugene-Usachev
    @Eugene-Usachev
    Не понимаю вашей проблемы. Redis будет удалять самые старые записи, если он заполнен. Если ничего не делать, он всё ещё будет хорошо работать в качестве кэша.

    1 ГБ - это слабая загруженность, на самом деле. Такой объём можно полностью уместить в Redis или Tarantool.
    Ответ написан
    Комментировать
  • Как динамически отправлять данные на клиент с golang сервера?

    Eugene-Usachev
    @Eugene-Usachev
    Способов много. Можно использовать или SSE, или http2, или long Polling, или short Polling или Websockets. Причём последний вариант самый предпочтительный почти всегда, так как является очень популярным и шустрым. Замеры я не проводил, но на бумаге протокол Websockets имеет наименьший оверхед из всех способов. Реализаций Websocket очень много для Go.

    Если проект маленький, берите Gorilla-websocket, или fiber-websocket или fasthttp-websocket (зависит от того, какую библиотеку вы используете). Эти технологии очень простые и удовлетворяют почти всем требованиям. В крупных проектах я бы предложил использовать или centrifuge, или centrifugo. centrifuge - это хорошо оптимизированная библиотека, а centrifugo - готовое решение. Они посложнее, но уже оптимизированы и предоставляют fallbacks, если клиент не способен установить websocket.

    Если у вас есть специфичные требования, вам следует указать это, потому что сейчас приходится "тыкать в небо".
    Ответ написан
    Комментировать
  • Проверка пользователя online/offline socket.io?

    Eugene-Usachev
    @Eugene-Usachev
    Во-первых, эта система не масштабируется. Надо сохранять подписки для каждого пользователя, чтобы не отсылать всем пользователям событие онлайна каждого пользователя. Во-вторых, вы пишите только тому, кто открыл соединение.
    Ответ написан
    Комментировать
  • Как запустить сервер nodejs без порта?

    Eugene-Usachev
    @Eugene-Usachev
    Под запустил фронт вы имеете в виду React в режиме dev или что-то подобное? Если так, то вам стоит ввести константу, например, domain, в которой сейчас будет адрес поднятого сервера (сейчас на другом порту). Перед релизом приложения, вам нужно выполнить сборку, таким образом вы получите статичные файлы. Дальше вы меня domain на "/" и раздаёте эти файлы с сервера. Таким образом и ваш клиент и ваш сервер будут на одном домене. Если под клиентом вы имели в виду что-то иное, напишите это.
    Ответ написан
  • Обязателен ли web-server (NGINX) для Actix Web?

    Eugene-Usachev
    @Eugene-Usachev
    Обязательным nginx не будет, но он рекомендован большинству веб-проектам. Очень многие проблемы на себя берёт nginx, и вообще странно брать высокопроизводительный инструмент (Actix Web) и не позаботься о балансировке нагрузки (или вы хотите сами писать балансировщик?).
    Ответ написан
    Комментировать
  • В каком приложении программировать на Python?

    Eugene-Usachev
    @Eugene-Usachev
    Я перебрал много редакторов кода, в частности для Python. Если кратко, берите Pycharm (там есть бесплатная версия, в которой только Python, но раз вы только учитесь, вам её хватит), если у вас есть хотя бы 8 ГБ ОЗУ, так как в проектах средней величины IDE начинает потреблять неприлично много (под 2 с половиной ГБ), если у вас нет такого запаса ОЗУ, берите VSCode.

    А теперь чуть подробнее. Когда я начанал учить программирование, я писал около месяцев 2 в стандартным редактором кода Python (я уже не вспомню, откуда она, но с установкой Python появляется грубое подобие блокнота с подсветкой синтаксиса и возможность стартовать программы на f5). Думаю этот абзац не нуждается в пояснении, насколько это удобно, но я к тому, что даже так можно писать код.

    Дальше я перешёл на Sublime text. Я писал на нём около месяца и не понял, за что его так хвалят. Может, я просто не смог настроить его под себя, но мне он показался, конечно, удобнее стандартного редактора кода Python, но я не понял, за что его хвалят.

    Дальше я решил попробовать VSCode и около полугода писал в этом редакторе кода. Ощущения были бесподобными после Sublime text. Этот редактор кода имеет множество расширений, которые ставятся меньше, чем за минуту. Без расширений очень тяжко программировать (может, в Sublime text есть все нужные, но я не уверен), так что это очень важный плюс. Также VSCode помогает набирать код (начинаешь набирать название переменой / метода / функции / класса и так далее и VSCode начинает подбирать похожие элементы из кода), что ускоряет процесс написания кода раза в полтора. Так же VSCode самый популярный редактор кода, так что в интернете легко найти гайды по настройке и легко найти исправления багов редактора кода. ИМХО, VSCode на голову лучше Sublime text.

    Затем я опробовал VS. Тоже бесплатная и предоставляет тот же функционал, но менее популярный (не на много). Для Python проще использовать VSCode.

    Затем я попробовал IDE от JetBrains (по типу PyCharm). И я ощутил то же самое, что при переходе с Sublime text на VSCode. Багов почти нет, удобная официальная документация, так же популярна и легко ставить расширения. Но расширений тут гораздо больше и выходят они сначала именно для этих IDE. Кастомизация этих IDE гораздо проще, чем кастомизация в VSCode. IDE подсказывает ощутимо лучше, так ещё и подсвечивает некоторый кривой код (написанный не по стандарту или содержащий прочие ошибки не связанные с логикой программы). И из приятного, все инструменты для разработки идут из коробки (для Python идёт из коробки пакетный менеджер). Так же порадовали авто-импорты (в других редакторах кода их можно поставить только с помощью расширений).

    ИМХО, писать код можно и в блокноте (как в первом абзаце), но я не вижу смысла заставлять себя использовать неудобные инструменты. Так что я бы посоветовал установить или PyCharm или VSCode. Не забудьте сразу загуглить hotkeys для соответствующего редактора кода и список самых популярных расширений для них. Это сразу ускорит работу и упростит её. По субъективным ощущениям, правильные расширения и hotkeys + "умный" редактор кода ускоряют разработку раза в 2 относительно Sublime text.
    Ответ написан
    Комментировать
  • В чем преимущества MobX?

    Eugene-Usachev
    @Eugene-Usachev
    Вы пытаетесь сравнивать не сравнимые вещи. Главное преимущество MobX в том, что он позволяет создать глобальный store. Глобальный store позволяет описать в себе множество различных состояний и обращаться к ним из любого компонента.

    В вашем случае нет нужды использовать MobX, вы это и сами заметили, однако давайте представим ситуацию, в которой этот ваш таймер нужен не в этом же компоненте, то есть создаётся в этом, но прокидывается дочерним компонентам. Это может привезти к увеличению кода в программе и может затруднить её чтение. В вашем случае выше, вы могли бы использовать export const myTimer и использовать его в любой компоненте.
    Ответ написан
    3 комментария
  • Почему скорость чтения из файла резко деградирует?

    Eugene-Usachev
    @Eugene-Usachev Автор вопроса
    Чёрная магия, не иначе. Несколько раз возвращался к коду на неделе и так и не исправил эту ошибку. Решил выписать все теории и проверить залпом.

    Проблема не Оперативной Памяти. Как вы могли заметить, я держу в памяти все ключи и значения. Начал их генерировать на ходу, стало хуже.

    Проблема не в том, что размер данных слишком большой. Поставил 100 байт, но 30 000 000 повторов, стало ещё хуже (оно и логично).

    Дальше я заметил крайне странную ситуацию. Сначала я прогнал тест на Windows и получил 2.5 секунды на вставку и 17 секунд на получение (при 100 байт), однако проблема этого теста в том, что IDE пытается заиндексировать новые файлы, так что я и не стал проверять на Windows неделю назад (работал в Docker), но тут решил проверить. Получилось (на 1000 байт) 10.8 секунд на запись и 24 секунды на получение. Этот тест вызвал у меня ещё больше вопросов.

    Я программист с учебным опыт около полутора лет и не могу это объяснить. Может кто-нибудь объяснить такую ситуацию?
    Ответ написан
  • Какая база данных подходит для частых UPDATE и сортировки?

    Eugene-Usachev
    @Eugene-Usachev
    Если я правильно понял суть вопроса, вам подойдёт любая KV СУБД. Вынесите только эту таблицу в какой-нибудь Tarantool или Redis (я имею в виду использовать хранимые процедуры для вашей задачи). 1-3 млн записей - относительно немного. Даже если одна запись весит 4 КБ, все данные займут 4-12 ГБ ОЗУ, что не так уж и много. Если использовать батчинг, что Redis, что Tarantool дадут вам на 16 ядрах свыше 100к RPS на такие сложные запросы.

    Можете так же глянуть AerospikeDB (хранит данные на диске, но с индексами в памяти, где один индекс стоит 64 байт), но я не уверен, что вам хватит его функционала. Если вы дадите больше контекста, возможно, я смогу предложить вам другие идеи.

    UPD: AerospikeDB тоже позволяет сохранить готовые процедуры, так что его функционала хватит для вышеуказанной задачи.
    Ответ написан
    1 комментарий
  • Как сделать много вставок в HashMap за минимальное время?

    Eugene-Usachev
    @Eugene-Usachev Автор вопроса
    Должен отметить, что Василий Банников дал прекрасный ответ. Дальше я пошёл в увеличение количества map (срез содержит срез map, который содержат другие map) и добился скорости записи 3 000 000 элементов на моём компьютере за 180 миллисекунд (вместо 4 секунд).

    И вот сейчас я наткнулся на замечательную статью от DragonflyDB https://github.com/dragonflydb/dragonfly/blob/main.... Там подход схожий с моим, советую к ознакомлению всем, кто хочет масштабировать map вертикально (за счёт числа ядер).
    Ответ написан
    Комментировать
  • О чем на самом деле идет речь в single-responsibility principle?

    Eugene-Usachev
    @Eugene-Usachev
    Я приведу обратный пример.

    Вот есть у нас разработчик Вася. Он пишет embedded систему. И у него есть датчик, у которого есть встроенный таймер и который измеряет температуру. Ну Вася посмотрел на это и написал класс TimeTemp, который имеет поля ,относящиеся к таймеру, и имеет поля, относящиеся к температуре. То же самое с методами.

    Приходит Петя со словами: "Вась, я помню ты классный класс писал, который умеет работать с временем, у меня есть датчик который умеет работать со временем, давай я буду его переиспользовать." Вася подумал и сказал, что не может дать целый класс отвечающий за время и температуру. Тогда Петя взял и вырезал части кода отвечающие за таймер.

    Потом пришёл Георгий и позаимствовал части кода с температурой.

    Проходит время и в классе TimeTemp находят ошибку, Вася сразу её правит. Вот только в других классах ошибка всё ещё есть и её теперь надо искать там и править, если вообще Вася скажет, что у него была ошибка Пете или Георгию.

    Так же ошибку могли найти у Георгия, и тогда не факт, что в классе TimeTemp её сразу исправят. Это я молчу про то, что кода стало в два раза больше.

    Всех этих последствий можно было бы избежать, если бы Вася написал один класс для работы со временем и другой класс для работы с температурой. SPR про то, что один класс должен использоваться только для одной цели, так как иначе код начинает множиться и отлаживать его становится трудно.
    Ответ написан
    Комментировать
  • Почему Redis PUB/SUB передаем сообщения хуже чем http tcp?

    Eugene-Usachev
    @Eugene-Usachev
    Я не знаток Redis и по его исходникам не лазил, но все адаптеры, что я смотрел и писал используют TCP, отсюда я делаю вывод, что Redis использует TCP под капотом. Следовательно вы поменяли структуру с
    бек сервер - TCP -> бек сервер
    на
    бек сервер - TCP -> СУБД (не сервер, у неё своих забот хватает) - TCP -> бек сервер.
    - TCP -> второй бек сервер.

    Теперь про советы:
    1 - PUB/SUB у Redis очень производительный, но вы неправильно его используете для этих целей. Я не знаток python и не очень хорошо знаю node, но не вижу у вас ни batching, ни pipelining. Я недавно проводил тесты на Go и пришёл к выводу, что pipelining для PUB/SUB даёт рост скорости более, чем в 4 раза. В документации к Redis очень хорошо описан подход pipeling и большинство адаптеров его так или иначе предлагают, советую провести тесты с ним.
    2 - Вы не по назначению используете PUB/SUB. Для обмена между двумя серверами обычно используют gRPC или TCP или голые сокеты. PUB/SUB используется для масштабирования (я не вижу у вас его в коде, но я не знаток python или node).
    Ответ написан
    9 комментариев
  • Как сделать preloader в Next.js v.13 с app dir?

    Eugene-Usachev
    @Eugene-Usachev
    Если я вам нужен preloader для всей странице, поместите в папку с вашим page.tsx файл loading.tsx и оформите в нём preloader как вам угодно. Если для одного компонента, используйте useEffect.
    Ответ написан
    Комментировать
  • Где делать запросы на РЕАКТЕ?

    Eugene-Usachev
    @Eugene-Usachev
    Есть простое решение, которое изучают все новички React, оно подразумевает использовать useState в верхних компонентах, через useEffect с пустым массивом зависимостей заполнить этот state и пробросить его ниже.
    Однако лучше использовать стейт менеджер. Я не смогу описать их в одном ответе, но советую вам погуглить про них. Самый популярный (с большим отрывом) - Redux (смотрите так же Redux-thunk и Redux-saga). Однако я бы посоветовал использовать MobX или Zustand так как они тоже популярны, но значительно удобнее. Судя по вашему запросу, я бы посоветовал начать с useState и useEffect.
    Не относится к теме вопроса, но вам стоит посмотреть плейлист "Мощнейшая практика" от uldi TV, так как автор не просто показывает, как использовать React, но и делает акцент на лучших паттернах и структуре.
    Ответ написан
    Комментировать