Статья оставила двоякое впечатление... С одной стороны - достаточно интересная тема... А с другой - осталось впечатление, что просто в рабочем проекте, "на коленках", поиграли с технологией, что-то получили, и решили по-быстрому оформить в виде статьи.
Отсюда странный выбор технологий - использовали просто то, что и так было в проекте и под рукой в целом (подозреваю, что изначально просто junit-тест был написан для пробы).
Зачем тут spring? Main-класса было бы достаточно. Инъекция зависимостей ради пары зависимостей? Зачем lombok? Пару геттеров-сеттеров можно и руками написать. Чем обусловлен выбор testcontainers для БД? Есть полноценные встраиваемые БД. А то и просто в RAM/файлах можно было хранить.
Как бы да, это все "лучшие практики" в Java, но в таком маленьком проекте они просто избыточны - руками все сделать не сильно сложнее, а то и проще было бы.
Ну и главное - а где собственно семантический поиск? Получили просто индекс близости статей к друг другу.
Для полноценного же поиска не хватило малости - просто строки ввода, которую надо было через embedding прогнать и вывести список статей по близости к запросу (опционально - перевести через LLM текст запроса).
P.S. ну или просто кто-то с ИИ для кодинга игрался - что тоже нельзя исключать. Ну или лабораторная работа какая...
В процессе чтения статьи возникла мысль, что добавь в LLM возможность редактировать свой же системный промт - и LLM сразу же превратится в сильный ИИ, потому как появится опыт, целеполагание и прочие элементы сильного ИИ.
10А на батарею не означает, что сборка только 10А тянет. Разные типы батарей имеют разную токоотдачу, не говоря уже про разные схемы подключения батарей в сборке.
У меня LiFePo4 сборка до 25А выдает (1 акб), что урезало ИБП на 450VA примерно вдвое (если очень грубо считать). Но мне пиковые показания и не нужны были - так что я мало что потерял в итоге.
Вроде читал что и работу с неполным зарядом они переносят хорошо, но за это не подпишусь.
Да, хорошо (как и все литий-ионные), другое дело что при полном заряде они деградируют быстрее, но с LiFePo4 это не так критично вроде )
И с LiFePo4 есть другой нюанс - из-за ровной кривой разряда нельзя определить (по напряжению) степень заряда батареи (только "полностью заряжено" и "полностью разряжено") - для этого надо считать "сколько ушло" и "сколько пришло". Поэтому при неполном заряде расчетные показания могут уплывать со временем. Но для подобного подсчета надо и продвинутую BMS иметь.
если напряжение ЗУ ИБП предназначенного для свинца окажется выше чем рекомендуемое для LiFePo4
Для свинца (на 12В) напряжение чуть ниже чем у сборки с LiFePo4 (на 12В) - так что замена безопасной должна быть. Как раз поэтому LiFePo4 и используют активно как простую замену свинцовым батареям.
Пиковая отдача - да, свинцовые впереди будут. Хотя LiFePo4 и тут хороши (если речь про кратковременную нагрузку).
Но ни кто не мешает параллельно батареи цеплять - и 10А превращаются в 20А, 30А и т.д. Правда с BMS могут возникнуть нюансы - не всегда допустимы параллельные или последовательные соединения сборок батарей.
Можно подумать, что реально все 3kVA используются. В предельных режимах ИБП обычно держит считанные минуты - если ИБП не просто для "успеть сохраниться", то и смысла в пиковом потреблении нет.
Да и большой вопрос к состоянию свинцовых батарей - не факт, что все 3kVA выдадут даже на несколько минут.
Ноутбук + док-станция - довольно неплохая замена ПК. Когда нужно - в режиме ПК работаешь, со всеми удобствами (клавиатура, мышь, мониторы и т.д.). Когда нужно - появляется портативность и компактность.
Перешел со свинцовых на LiFePO4 в своих ИБП (для ПК и сетевого оборудования). Да, дороже. Да, емкость меньше. Да, токоотдача меньше (ограничение из-за дешевой BMS). Но пиковую нагрузку все равно не использовал, а надежность важнее - поставил и забыл. Играть в лотерею с покупкой свинцового не захотел - отзывы практически у всех от "работает годами" до "не проработал и пары месяцев".
Это безопасная замена - сборки LiFePO4 имеют схожую вольт-амперную характеристику со свинцовыми. Пиковый вольтаж у сборки LiFePO4 чуть выше свинцовых, но на емкость это не критично сказывается - кривая разряда у LiFePO4 практически плоская (так что когда ИБП сообщит о низком заряде - счет уже на секунды идет, так у меня во всяком случае).
Но размеры сборки могут быть чуть выше свинцового аккумулятора для ИБП - надо это учитывать (разница в несколько мм). В итоге я взял меньшей емкости, но с гарантированно "правильными" размерами - и не прогадал, лишнего места в ИБП не было.
P.S. свинцовые при работе могут выделять кислоту в воздух. Даже герметичные, необслуживаемые и специальные для ИБП - у них просто выделяется меньше и реже. Так что с переходом на LiFePO4 ушел и характерный запах работы ИБП.
Думаю причина сухого глаза в частоте предыдущих экранов в 60 Гц. А на новом 144 Гц, отсюда и повышение удобства.
И второй фактор - VA-матрица. VA-матрицы считаются комфортнее для глаз за счет более глубокого черного цвета и высокой контрастности. Но темные объекты могут сливаться с черным - особенности матрицы.
Даже если без девайса с экраном не обойтись - старый телефон может заменить весь девайс, если приложение написать подобное (не уверен, что уже нет таких). Да, не так стильно, не так красиво, не так удобно - но почему бы и нет?
P.S. впрочем, это хороший подарок для тех, у кого "все уже есть" )
P.P.S. если сделать стильный эмулятор устройства под мобильный - то популярность устройства (и сценариев использования) может сильно возрасти. А главное - каждый запущенный эмулятор будет бесплатной рекламной площадкой. При такой цене не думаю, что реальное устройство будет конкурировать с эмулятором )
Масштабирование бывает двух видов: горизонтальное и вертикальное. Горизонтальное также делится на два типа:
репликация, которая отвечает за масштабирование вычислений;
шардинг, который используется для масштабирования данных.
Оригинальное определение репликации и шардингу.
Репликация - это несколько серверов, работающих над одними и теми же данным. Если что и масштабируется что, то только операции чтения. Но зато повышается отказоустойчивость.
Шардинг - разделение данных по разным серверам. Да, данные масштабируются, но и операции чтения/записи тоже масштабируются. Отказоустойчивость если и повышается, то только в виде "стали недоступны не все данные, а только часть".
Я бы еще добавил, что алгоритмы консенсуса распределенных систем (тот же Raft) хорошо на CQRS+Event Sourcing ложатся - что может быть полезно для повышения отказоустойчивости.
Ну и горизонтальное масштабирование на чтение можно получить до кучи (но не запись - пишут все узлы параллельно).
А почему нет? Event Sourcing упоминается в контексте CQRS как способ организации и масштабирования сервиса - выделяем отдельные микросервисы для записи и отдельные микросервисы для чтения (причем можно несколько и разных по функционалу).
Да, Golang прост для чтения и понимания. Но это не мешает мне считать не самым удачным решением бесконечные err != nil в коде. Но да, это просто для чтения, спору нет.
И да, Rust сложен для чтения. Не понимаю, причем тут TypeScript - это C#/Java только чуть сбоку. Мне вообще показалось, что TypeScript упоминается как средство запуска WebAssembly-модуля, написанного на Rust )
В контексте TypeScript скорее NodeJS есть за что критиковать - все крайне быстро развивается и устаревает, зачастую статьи полу-годовой давности уже не работают как надо.
В абсолютном большинстве случаев этого достаточно. Контекст вызова есть в месте логгирования, если этого мало для диагностики - всегда можно дополнить ошибку.
Если же каждый чих проверять - то это называется не "приходится думать", а "заниматься ерундой микроменеджментом". Высокоуровневые языки нужны для упрощения рутины.
Если так хочется думать и контролировать каждый чих - можно и к assembler-у вернуться. Контроль всего и вся на 100%.
Можно подумать, с Go-шных return nil, err будет больше информации. Получение нормального контекста ошибок всегда требует определенной работы. Что в Golang, что в Java, что в Rust-е.
Но факт в том, что с Golang практически каждая строчка кода сопровождается проверкой err != nil. И это бесит. В Java с try-catch все-таки кода меньше на выходе. Даже если это просто проброс ошибки дальше, а не вдумчивая обработка. В Rust с его Result вообще отдельно от метода можно преобразование ошибок сделать - чисто на описании типа и его конвертациях. Сам метод еще чище будет. Но читаемость страдает, на мой взгляд.
Я знаю, что такое отказоустойчивость, как считается и т.д. Но также я и знаю, что это заслуга не просто "запустили 2-3 сервера вместо одного", но и софта, умеющего в распределенном режиме работать.
И основной камень преткновения - именно в софте, а не в железе.
Гугл, Яндекс, Амазон имеют нужные компетенции и ресурсы для работы в подобном режиме. И то бывает всплывают нюансы.
Статья оставила двоякое впечатление... С одной стороны - достаточно интересная тема... А с другой - осталось впечатление, что просто в рабочем проекте, "на коленках", поиграли с технологией, что-то получили, и решили по-быстрому оформить в виде статьи.
Отсюда странный выбор технологий - использовали просто то, что и так было в проекте и под рукой в целом (подозреваю, что изначально просто junit-тест был написан для пробы).
Зачем тут spring? Main-класса было бы достаточно. Инъекция зависимостей ради пары зависимостей?
Зачем lombok? Пару геттеров-сеттеров можно и руками написать.
Чем обусловлен выбор testcontainers для БД? Есть полноценные встраиваемые БД. А то и просто в RAM/файлах можно было хранить.
Как бы да, это все "лучшие практики" в Java, но в таком маленьком проекте они просто избыточны - руками все сделать не сильно сложнее, а то и проще было бы.
Ну и главное - а где собственно семантический поиск? Получили просто индекс близости статей к друг другу.
Для полноценного же поиска не хватило малости - просто строки ввода, которую надо было через embedding прогнать и вывести список статей по близости к запросу (опционально - перевести через LLM текст запроса).
P.S. ну или просто кто-то с ИИ для кодинга игрался - что тоже нельзя исключать. Ну или лабораторная работа какая...
Это немного другой прикол с defer - изменение возвращаемых значений:
https://go.dev/play/p/oCpFl6trX_6
В процессе чтения статьи возникла мысль, что добавь в LLM возможность редактировать свой же системный промт - и LLM сразу же превратится в сильный ИИ, потому как появится опыт, целеполагание и прочие элементы сильного ИИ.
10А на батарею не означает, что сборка только 10А тянет. Разные типы батарей имеют разную токоотдачу, не говоря уже про разные схемы подключения батарей в сборке.
У меня LiFePo4 сборка до 25А выдает (1 акб), что урезало ИБП на 450VA примерно вдвое (если очень грубо считать).
Но мне пиковые показания и не нужны были - так что я мало что потерял в итоге.
Да, хорошо (как и все литий-ионные), другое дело что при полном заряде они деградируют быстрее, но с LiFePo4 это не так критично вроде )
И с LiFePo4 есть другой нюанс - из-за ровной кривой разряда нельзя определить (по напряжению) степень заряда батареи (только "полностью заряжено" и "полностью разряжено") - для этого надо считать "сколько ушло" и "сколько пришло". Поэтому при неполном заряде расчетные показания могут уплывать со временем. Но для подобного подсчета надо и продвинутую BMS иметь.
Для свинца (на 12В) напряжение чуть ниже чем у сборки с LiFePo4 (на 12В) - так что замена безопасной должна быть. Как раз поэтому LiFePo4 и используют активно как простую замену свинцовым батареям.
Пиковая отдача - да, свинцовые впереди будут. Хотя LiFePo4 и тут хороши (если речь про кратковременную нагрузку).
Но ни кто не мешает параллельно батареи цеплять - и 10А превращаются в 20А, 30А и т.д.
Правда с BMS могут возникнуть нюансы - не всегда допустимы параллельные или последовательные соединения сборок батарей.
Можно подумать, что реально все 3kVA используются. В предельных режимах ИБП обычно держит считанные минуты - если ИБП не просто для "успеть сохраниться", то и смысла в пиковом потреблении нет.
Да и большой вопрос к состоянию свинцовых батарей - не факт, что все 3kVA выдадут даже на несколько минут.
Ноутбук + док-станция - довольно неплохая замена ПК.
Когда нужно - в режиме ПК работаешь, со всеми удобствами (клавиатура, мышь, мониторы и т.д.). Когда нужно - появляется портативность и компактность.
Перешел со свинцовых на LiFePO4 в своих ИБП (для ПК и сетевого оборудования).
Да, дороже. Да, емкость меньше. Да, токоотдача меньше (ограничение из-за дешевой BMS). Но пиковую нагрузку все равно не использовал, а надежность важнее - поставил и забыл. Играть в лотерею с покупкой свинцового не захотел - отзывы практически у всех от "работает годами" до "не проработал и пары месяцев".
Это безопасная замена - сборки LiFePO4 имеют схожую вольт-амперную характеристику со свинцовыми. Пиковый вольтаж у сборки LiFePO4 чуть выше свинцовых, но на емкость это не критично сказывается - кривая разряда у LiFePO4 практически плоская (так что когда ИБП сообщит о низком заряде - счет уже на секунды идет, так у меня во всяком случае).
Но размеры сборки могут быть чуть выше свинцового аккумулятора для ИБП - надо это учитывать (разница в несколько мм). В итоге я взял меньшей емкости, но с гарантированно "правильными" размерами - и не прогадал, лишнего места в ИБП не было.
P.S. свинцовые при работе могут выделять кислоту в воздух. Даже герметичные, необслуживаемые и специальные для ИБП - у них просто выделяется меньше и реже. Так что с переходом на LiFePO4 ушел и характерный запах работы ИБП.
И второй фактор - VA-матрица. VA-матрицы считаются комфортнее для глаз за счет более глубокого черного цвета и высокой контрастности. Но темные объекты могут сливаться с черным - особенности матрицы.
Даже если без девайса с экраном не обойтись - старый телефон может заменить весь девайс, если приложение написать подобное (не уверен, что уже нет таких). Да, не так стильно, не так красиво, не так удобно - но почему бы и нет?
P.S. впрочем, это хороший подарок для тех, у кого "все уже есть" )
P.P.S. если сделать стильный эмулятор устройства под мобильный - то популярность устройства (и сценариев использования) может сильно возрасти. А главное - каждый запущенный эмулятор будет бесплатной рекламной площадкой. При такой цене не думаю, что реальное устройство будет конкурировать с эмулятором )
Туда бы еще встроить мониторинг качества воздуха )
Оригинальное определение репликации и шардингу.
Репликация - это несколько серверов, работающих над одними и теми же данным. Если что и масштабируется что, то только операции чтения. Но зато повышается отказоустойчивость.
Шардинг - разделение данных по разным серверам. Да, данные масштабируются, но и операции чтения/записи тоже масштабируются. Отказоустойчивость если и повышается, то только в виде "стали недоступны не все данные, а только часть".
btop - bpytop переписанный на плюсах )
Отличная статья!
Я бы еще добавил, что алгоритмы консенсуса распределенных систем (тот же Raft) хорошо на CQRS+Event Sourcing ложатся - что может быть полезно для повышения отказоустойчивости.
Ну и горизонтальное масштабирование на чтение можно получить до кучи (но не запись - пишут все узлы параллельно).
А почему нет? Event Sourcing упоминается в контексте CQRS как способ организации и масштабирования сервиса - выделяем отдельные микросервисы для записи и отдельные микросервисы для чтения (причем можно несколько и разных по функционалу).
Да, Golang прост для чтения и понимания. Но это не мешает мне считать не самым удачным решением бесконечные
err != nil
в коде. Но да, это просто для чтения, спору нет.И да, Rust сложен для чтения. Не понимаю, причем тут TypeScript - это C#/Java только чуть сбоку. Мне вообще показалось, что TypeScript упоминается как средство запуска WebAssembly-модуля, написанного на Rust )
В контексте TypeScript скорее NodeJS есть за что критиковать - все крайне быстро развивается и устаревает, зачастую статьи полу-годовой давности уже не работают как надо.
Типичная обработка ошибки - залогировали ошибку, откатили транзакцию, работаем дальше.
В абсолютном большинстве случаев этого достаточно. Контекст вызова есть в месте логгирования, если этого мало для диагностики - всегда можно дополнить ошибку.
Если же каждый чих проверять - то это называется не "приходится думать", а "заниматься
ерундоймикроменеджментом". Высокоуровневые языки нужны для упрощения рутины.Если так хочется думать и контролировать каждый чих - можно и к assembler-у вернуться. Контроль всего и вся на 100%.
Можно подумать, с Go-шных
return nil, err
будет больше информации.Получение нормального контекста ошибок всегда требует определенной работы.
Что в Golang, что в Java, что в Rust-е.
Но факт в том, что с Golang практически каждая строчка кода сопровождается проверкой
err != nil
. И это бесит.В Java с try-catch все-таки кода меньше на выходе. Даже если это просто проброс ошибки дальше, а не вдумчивая обработка.
В Rust с его Result вообще отдельно от метода можно преобразование ошибок сделать - чисто на описании типа и его конвертациях. Сам метод еще чище будет. Но читаемость страдает, на мой взгляд.
Я знаю, что такое отказоустойчивость, как считается и т.д.
Но также я и знаю, что это заслуга не просто "запустили 2-3 сервера вместо одного", но и софта, умеющего в распределенном режиме работать.
И основной камень преткновения - именно в софте, а не в железе.
Гугл, Яндекс, Амазон имеют нужные компетенции и ресурсы для работы в подобном режиме. И то бывает всплывают нюансы.
Стесненный в средствах стартап - сомневаюсь.