Cloudflare R2, в чём подвох?
Это сервис типа S3 но без оплаты egress. Не пойму, в чём подвох. Цена за хранение тоже божеская ($15/TB). Что мне мешает сделать клон ютуба и обанкротить клаудфляр?
Это сервис типа S3 но без оплаты egress. Не пойму, в чём подвох. Цена за хранение тоже божеская ($15/TB). Что мне мешает сделать клон ютуба и обанкротить клаудфляр?
Я хочу сделать страницу, которая будет выглядеть максимально похоже на разных браузерах. Идеал - попиксельная идентичность. Понимаю, что идеала не достичь, но хочу достичь что могу.
Ширина и высота у страницы фиксированные.
Шрифты я использую свои.
На что ещё нужно обратить внимание, по крайней мере из очевидного?
Я так понимаю, применять что-то вроде font-size: xx-large не стоит, т.к. это не соответствует конкретному кеглю и лучше применять что-то вроде font-size: 30px.
Хочу писать на C для МК, но так, чтобы ни единого байта не было в бинарнике, не от моего кода.
В целом я понимаю, как это всё собрать и слинковать. Вопрос больше в том, что компилятор C в моём понимании генерирует код, рассчитывая на определённый рантайм, который я у него хочу забрать. К примеру я слыхал, что компилятор может генерировать вызовы функций вроде memcpy, если посчитает нужным. Также я не очень хорошо представляю, что происходит до вызова main и насколько это важно.
Также развитие этого вопроса - тот же вопрос про C++.
Хочу написать приложение, которое будет работать на arm девайсе. Документации не нашёл, делаю по крохам информации, которую нашёл, но ничего не получилось.
Во-первых нужно собрать Qt для хоста.
Хост у меня дебиан. Ставлю пакеты cmake gcc g++ mesa-common-dev ninja-build perl. Собираю командами
../qt-everywhere-src-6.4.3/configure -prefix /mnt/data/qt-host -submodules qtbase
cmake --build . --parallel 4
cmake --install .
Это у меня получилось.
Далее нужно собрать Qt для таргета. Таргет у меня это какая-то китайская плата с i.MX8MM. Есть rootfs для неё.
Первая проблема в том, что не понятно, где брать компилятор. Я поставил таким образом:
dpkg --add-architecture arm64
apt-get update
apt-get install gcc-arm-linux-gnueabi g++-arm-linux-gnueabi
Также пробовал вариации с --add-architecture arm и gnueabhf. Не знаю, чем они отличаются и как понять, какой мне надо.
Далее написал файл imx8mm.cmake со следующими строчками:
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_C_COMPILER arm-linux-gnueabi-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabi-g++)
set(CMAKE_SYSROOT ${INPUT_sysroot})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
и пытаюсь сконфигурировать Qt командой
/mnt/data/qt-everywhere-src-6.4.3/configure \
-prefix /opt/qt \
-extprefix /mnt/data/qt-embedded \
-qt-host-path /mnt/data/qt-host \
-sysroot /mnt/data/rootfs-ok8mm \
-submodules qtbase \
-nomake examples -nomake tests \
-- \
-DCMAKE_TOOLCHAIN_FILE=/home/build/imx8mm.cmake
Это всё кончается ошибкой
ERROR: The OpenGL functionality tests failed! You might need to modify the OpenGL package search path by setting the OpenGL_DIR CMake variable to the OpenGL library's installation directory.
Я не знаю, где посмотреть точно какая ошибка ему помешала.
В файле CMakeError.log есть миллион ошибок, но в том числе одна, которая мне кажется важной и которую я не знаю, как решить:
: && /usr/bin/arm-linux-gnueabi-gcc --sysroot=/mnt/data/rootfs-ok8mm -DCHECK_FUNCTION_EXISTS=XOpenDisplay -fPIE -pie CMakeFiles/cmTC_d6b57.dir/CheckFunctionExists.c.o -o cmTC_d6b57 /mnt/data/rootfs-ok8mm/usr/lib/libX11.so /mnt/data/rootfs-ok8mm/usr/lib/libXext.so /mnt/data/rootfs-ok8mm/usr/lib/libGLESv2.so /mnt/data/rootfs-ok8mm/usr/lib/libEGL.so && :
/mnt/data/rootfs-ok8mm/usr/lib/libX11.so: file not recognized: file format not recognized
collect2: error: ld returned 1 exit status
Как я понимаю, суть ошибки в том, что компилятор не соответствует плате.
Вот вывод readelf -a /mnt/data/rootfs-ok8mm/usr/lib/libX11.so.6.3.0, может быть он чем-то поможет: https://pastebin.com/raw/5t5dQ2qw
Также ещё вижу такие проблемы: в usr/include платы нет заголовков для EGL, но при этом сами библиотеки в usr/lib есть. Пока до ошибок с EGL не дошёл, планировал их решить установкой пакета EGL в хостовую систему и изменением set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) на BOTH, хотя не уверен, что это правильно.
Может быть я зря на Qt 6 это пытаюсь делать и лучше использовать Qt 5? На плате установлена Qt 5 и есть какие-то примеры на Qt 5. Но, как я понимаю, мне всё равно для своей разработки надо собирать локально версию для кросс-компиляции.
Я тут со своей доморощенной виртуализацией экспериментирую. И оказалось, что когда мой ноутбук уснул, в запущенной виртуальной машине время ушло назад на время сна (то бишь не двигалось вперёд). Перезагрузка виртуальной машины проблему решила, но хотелось бы понять, можно ли эту проблему решить другими способами. Я предполагаю, что в запущенном линуксе время отсчитывается средствами процессора, а нужно вероятно вместо этого использовать какие-то аппаратные источники времени (которые, предположительно, в виртуальной машине будут синхронизированы с хостом и будут правильные).
Перемещено hobbit из general
Давно хотел проверить, но никак не доходили руки. Вообще говорят, что и в докер десктопе это есть, я не проверял. В целом запустил федору через Virtualization.Framework на M1 макбуке, в ней поставил докер, а также розетту. И теперь:
% docker run --rm -it --platform linux/amd64 debian:11 uname -a
Linux 3ae5494cbd64 6.1.18-200.fc37.aarch64 #1 SMP PREEMPT_DYNAMIC Sat Mar 11 16:03:54 UTC 2023 x86_64 GNU/Linux
Для меня это важно, мне этого давно не хватало. На qemu эмуляция была, но там такая медленная скорость, что было не юзабельно. А тут ничего так, шустренько.
% time docker run --rm -it --platform linux/amd64 debian:11 bash -c "head -c $((1024 * 1024 * 1024)) /dev/zero | sha256sum"
0.02s user 0.02s system 0% cpu 5.759 total
% time docker run --rm -it --platform linux/arm64 debian:11 bash -c "head -c $((1024 * 1024 * 1024)) /dev/zero | sha256sum"
0.03s user 0.02s system 0% cpu 4.770 total
Если он запускается в виртуалке. Загрузчика вообще нет, сразу ядро и initrd подаётся на вход. Скомпилировать ядро без всего кроме того что надо для виртуалки. Как-то юзерспейс максимально быстро стартануть. Systemd самый быстрый?
У меня сейчас в виртуалке федора с UEFI за несколько секунд грузится. Мне интересно, можно ли это ускорить. Чего она там делает эти несколько секунд - не понятно. dmesg если кому интересно.
Имеется китайская плата на i.mx6ull. Китайцы туда поставили китайский линукс на китайском ядре 4.1.15. Браузера там нет. Я хочу туда засунуть веб приложение. Свое ядро более актуальной версии скомпилять пока не вышло. Посоветуйте как быть.
Имеется такая плата: OKMX6ULL-C
К ней по шлейфу подключил маленький дисплей. При подаче питания грузится какой-то китайский линукс с демо-программами.
Теперь мне надо из этого сделать что-то своё. Я на raspberry собирал свой линукс, но как тут подступиться, пока не понимаю.
Во-первых я не могу подключиться к нему по UART-у, чтобы работать полноценно, а не на крохотном дисплейчике. На выходных пинах есть UART2, …, UART4. Я подключил USB UART к UART2, но дальше соединиться не смог. К распберри я так подключался.
Судя по схеме UART1 разведён на USB-C выход на этой плате через USB-UART микросхему. Не очень понимаю, для чего это сделано. Можно ли подключить этот выход к компьютеру напрямую? Я боюсь спалить что-нибудь.
Во-вторых я не понимаю, как там вообще устроена загрузка. В распберри просто сд-карта, с неё и грузишься. Тут внутри есть emmc память на 8 гигабайтов. Встроенный линукс грузится именно с неё. Там два раздела, один на 500 MB, там ядро и ещё какой-то файл dtb. На втором разделе корень. В принципе слот для сд-карты есть. Пока грузиться с него не пробовал, т.к. вообще не очень понимаю, что туда сувать.
Ещё есть два раздела mmcblk1boot1 4MiB, mmcblk1boot0 4MiB. Они не монтируются, не знаю, что там на них.
В /etc/issue написано Freescale i.MX Release Distro 4.1.15-2.0.1 \n \l
Моя цель: для начала подключить это всё дело через серийный порт, чтобы можно было с компьютера с ним работать по-человечески. Потом скомпилировать минимальный линукс и загрузиться с него. А потом я уже сам разберусь.
Насколько я понимаю, производитель процессора это NXP, компания нормальная, но саму плату сделали китайцы.
У меня есть два гигабайта какой-то мусорной документации, которую они выслали, но я там ничего не понял. Собственно там толком ничего и нет, самое полезное это распиновка самой платы, остальное - тупо несколько десятков даташитов по всем микросхемам, использованным на плате и какой-то «мануал» с putty.exe и ссылками на китайские форумы, откуда предлагается скачать виртуалбокс. В общем такие мануалы мне не нужны.
Я на распи собирал свой линукс через buildroot. Но там был готовый конфиг и человеческие гайды. Как действовать тут - я пока в затруднении.
В связи с последними разработками в сфере ИИ и рассуждениями о том, заменят ли программистов, интересно было бы подумать о том, насколько можно улучшить производительность.
На мой взгляд за последние лет 30 языки программирования не стали выше уровнем. Если взять тот же Haskell, который в каком-то виде в первый раз появился в 1990 году, то я бы не сказал, что Rust последней версии чем-то категорично его превосходит. В целом примерно одни и те же идеи тусуют в разных пропорциях. Я тут говорю исключительно про то, насколько язык помогает программисту писать код.
Мне интересно, как вообще можно совершить качественный скачок в языках программирования, оставаясь в той же парадигме, т.е. мы не будем рассматривать фантастику вроде того, что ты пытаешься там в чате чего-то объяснять роботу. А мы так же пишем формальный строгий текст латинницей, который преобразуется в машинный код. Но при этом то, что сейчас требует месяца работы, будет требовать трёх дней. Там, где сейчас 10 багов, будет 1 баг.
Предполагать, что что-то придёт взамен тексту, я тоже не буду. Текст доказал свою пользу на протяжении тысячелетий. Думаю, что ничего лучше текста не придумать.
Или же программирование в текущем виде достигло своего апогея и никаких принципиально новых идей уже не стоит ожидать?
Хочу поморгать диодом без библиотек. В целом сетап описан тут (linux.org.ru). Процессор STM32F030F4P6. Диод подключен, насколько я могу судить, к ноге PA4.
На текущий момент конфигурация такая:
Makefile:
CC = arm-none-eabi-gcc
AS = arm-none-eabi-as
LD = arm-none-eabi-ld
CFLAGS = -mthumb -mcpu=cortex-m0 -O0
.PHONY: all flash
all: app.bin
crt.o: crt.s
app.elf: linker.ld crt.o blink.o
$(LD) -T linker.ld -o app.elf crt.o blink.o
app.bin: app.elf
arm-none-eabi-objcopy -O binary $< $@
flash: app.bin
st-flash --reset write $< 0x8000000
crt.s:
.cpu cortex-m3
.thumb
.word 0x20005000
.word _reset
.thumb_func
_reset:
bl blink
b .
linker.ld:
MEMORY {
FLASH(rx): ORIGIN = 0x08000000, LENGTH = 16K
RAM (xrw): ORIGIN = 0x20000000, LENGTH = 4K
}
blink.c:
#include <stdint.h>
const uint32_t RCC_BASE = 0x40021000;
const uint32_t GPIOA_BASE = 0x48000000;
const uint32_t RCC_AHBENR_OFFSET = 0x14;
const uint8_t RCC_AHBENR_IOPAEN_BIT = 17;
const uint32_t GPIOx_MODER_OFFSET = 0x00;
const uint8_t GPIOx_MODER_MODE4_BIT_OFFSET = 8;
const uint32_t GPIOx_ODR_OFFSET = 0x14;
const uint8_t GPIOx_ODR_OD4_BIT = 4;
void bit_clear(uint32_t address, uint8_t bit);
void bit_set(uint32_t address, uint8_t bit);
void bit_toggle(uint32_t address, uint8_t bit);
void blink(void) {
bit_set(RCC_BASE + RCC_AHBENR_OFFSET, RCC_AHBENR_IOPAEN_BIT);
bit_set(GPIOA_BASE + GPIOx_MODER_OFFSET, GPIOx_MODER_MODE4_BIT_OFFSET);
bit_set(GPIOA_BASE + GPIOx_ODR_OFFSET, GPIOx_ODR_OD4_BIT);
volatile uint32_t counter = 0;
while (1) {
if (counter % 0x10000 == 0) {
bit_toggle(GPIOA_BASE + GPIOx_ODR_OFFSET, GPIOx_ODR_OD4_BIT);
}
counter++;
}
}
void bit_clear(uint32_t address, uint8_t bit) {
uint32_t mask = 1 << bit;
volatile uint32_t *ptr = (uint32_t *) address;
*ptr &= ~mask;
}
void bit_set(uint32_t address, uint8_t bit) {
uint32_t mask = 1 << bit;
volatile uint32_t *ptr = (uint32_t *) address;
*ptr |= mask;
}
void bit_toggle(uint32_t address, uint8_t bit) {
uint32_t mask = 1 << bit;
volatile uint32_t *ptr = (uint32_t *) address;
*ptr ^= mask;
}
Адреса брал из RM0360:
2.2.2 Memory map and register boundary addresses
AHB2 0x4800 0000 - 0x4800 03FF GPIOA
AHB1 0x4002 1000 - 0x4002 13FF RCC
7.4.6
Reset and clock control (RCC)
AHB peripheral clock enable register (RCC_AHBENR)
Address offset: 0x14
Bit 17: IOPAEN: I/O port A clock enable
8.4.1
GPIO port mode register (GPIOx_MODER)
Address offset:0x00
Bits 9:8 Port configuration bits
01: General purpose output mode
8.4.6
GPIO port output data register (GPIOx_ODR)
Address offset: 0x14
Bit 4: Port output databit
Насколько я понял из чтения документации:
Возможно код на C неправильный, я его знаю плохо, пытался писать максимально просто.
На CubeMX пример с HAL копипастил, он работает, диод моргает. Ниже приведу на всякий случай:
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_4);
HAL_Delay(100);
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
/*Configure GPIO pin : PA4 */
GPIO_InitStruct.Pin = GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
Но я в нём ничего не понимаю, хотелось бы попроще.
Хочу поэкспериментировать с МК. Для этого собрал следующую конструкцию:
Плата Baite STM32F030F4
Далее у меня есть плата Nucleo L073RZ мануал (стр. 16). Я от этой платы отрезал верхний кусок по линии разреза, как я понимаю, там находится программатор. У этого программатора я вытащил два джампера CN2 чтобы переключить его на работу с внешним МК.
Подключил я это всё следующим образом:
1 провод от модуля зарядки TP4056 с пометкой «OUT +» к плате Baite, пину «header 1 pin 5 VIN»
1 провод от модуля зарядки TP4056 с пометкой «OUT -» к плате Baite, пину «header 1 pin 6 GND»
4 провода от Nucleo L073RZ коннектор CN4 пины VDD_TARGET, SWCLK, GND, SWDIO к Baite пинам SWD header pins 3V3, SWCLK, GND, SWDIO
2 провода от Nucleo L073RZ пины TX RX к Baite пинам Serial header pins RX TX
Вообще вчера я подключал всё почти так же, только питание у модуля зарядки брал похоже не с тех разъёмов. В итоге на Baite шло нефильтрованное питание из USB (примерно 4.5В показывал мультиметр). В целом всё заработало, программу я смог залить, но периодически программатор показывал, что соединения с контролером нет.
Сегодня я питание подключил как выше написал, теперь там 4.2В, как я понимаю, более стабильное. Также запитал USB-порт отдельным блоком питания. Пока вроде не отваливается. Вообще допускаю, что я плохо что-то припаял, т.к. паять я не умею, модуль питания и контролер шли без гребёнок, я эту гребёнку к ним припаял и соединил всё на проводках с квадратными разъёмами.
Вопрос 1 - вообще всё правильно?
Вопрос 2 - для чего нужен пин VDD_TARGET? Я сначала подумал, что от него можно запитать контролер, но потом почитав понял, что он питание не даёт а наоборот проверяет.
Вопрос 3 - для чего я подключил TX/RX? Я сам не знаю. Как-то через ST Link можно получить к нему доступ?
Вопрос 4. Можно ли куда-то подключить пин с программатора NRST? Я так понимаю, это удобная штука для перезагрузки контролера, но куда его подключить я не нашёл. Или он не нужен?
Предположим, мне не нравится, что гугл в любой момент может забанить мой username@gmail.com, на который завязана вся моя цифровая жизнь.
Ну как линуксоид я иду и покупаю домен. Настраиваю на этот домен почтовый ящик и вот уже я me@username.com, счастье.
Но есть одно «но». Чтобы купить домен, мне надо зарегистрироваться на каком-нибудь namecheap-е. И для регистрации мне нужна… Правильно, почта.
Если я потеряю доступ к своей исходной почте, любая проблема с аккаунтом и доступ к домену я теряю.
Что же делать?
Пока для себя решил остановиться на варианте - использовать регистратора из своей страны. Есть надежда, что в случае проблем я смогу к ним позвонить, скинуть фото документов и получить возможность, к примеру, сменить забаненную почту.
Альтернативно: можно после покупки домена и настройки почтового сервера у регистратора сменить почту. Рекурсивненько получается. Но опять же это рецепт для проблем. Забыл домен оплатить вовремя, побежал его продлевать - а зайти не можешь и почта не ходит уже.
Я даже думал завести отдельную почту как раз для такой цели - регистрировать на неё самое важное. И желательно не в гугле. Но я не нашёл ни одного крупного почтового сервера, который бы обещал, что он никогда не удалит аккаунт. У всех есть оговорки, что если вы не заходите полгода, мы имеем право удалить аккаунт. Ну я каждого не изучал, только самых крупных, а мелкие и сами закрыться могут.
Имеется постгрес в контейнере в кубе. За несколько дней у него растёт потребление по памяти постепенно. Пока не дорастает до лимита, процесс-коннект не прибивает ООМ-ом и всё заново не происходит. Кажется, что это не совсем хорошо. Хочется навести порядок. Начинал с 60M, уже 300M ему выделил, он сегодня до 200 дорос, как чайный гриб, растёт и всё, при том, что он и на 60M работал - ему 200M явно не надо.
Причём судя по тому, что, скажем, он 3 дня работает нормально, это явно не какие-то там пики и тд, просто память утекает в какие-то кеши или хз куда.
В идеале хочется задать постгресу Xmx60m как жаве и он за пределы этих 60m не вылазил и сам рассчитал там размеры для своих кешей и прочего. А не ронял процессы по ООМ.
Как тут правильно поступить?
Нужно указать в докерфайле какую-нибудь команду, которая ничего не делает. Но чтобы работало завершение по сигналам.
Первое, что пробовал это ENTRYPOINT ["sleep", "infinity"]. Не сработало. sleep игнорирует сигналы. Всякие вариации вроде bash -c "sleep infinity" или bash -c "exec sleep infinity" тоже не работают.
Лучшее, что придумал - ENTRYPOINT ["sh", "-c", "while sleep 1; do true; done"]. Но немного некрасиво - секунду всё равно ждать и крутится там туда-сюда, запускает sleep всё время. И кажись для SIGSTOP не работает, только для SIGINT.
Какой самый классный и короткой способ сделать так, чтобы и по сигналу (SIGINT и SIGSTOP) завершало выполнение, и чтобы в рамках sh работало, и выглядело не монструозно. Через всякие trap-ы и kill-ы и я смогу, но там строк на 10 будет в лучшем случае.
Почему-то коробит, когда делают контейнеры с /data, /app и прочим бредом. Всегда делаю контейнеры с /home/build, /opt/app, /srv/data, /mnt/host и тд, пытаясь хоть как-то в FHS. Для меня создавать рандомный каталог в корне это какое-то кощунство. Вполне могу себе представить, что с таким подходом кто-нибудь смонтирует что-нибудь в /dev, типа среда разработки.
А вы как думаете? Есть в этом смысл?
Пытаюсь подружить реакт с промисами. React Query и прочую муть не предлагать.
Пока родился такой вариант. Думаю, из сигнатур очевидно, как оно должно работать. Не нравится то, что reducer получился «не чистый». Вызывает abortController.abort(). Хотя и идемпотентный но кажется это всё равно не по феншую.
Как сделать нормально - я не придумал. Хотя думал много и это далеко не первая итерация. Буду благодарен помощи от гуру, если у кого будет хорошая идея.
import { DependencyList, useEffect, useReducer } from "react";
type PromiseFunction<T> = (signal: AbortSignal) => Promise<T>;
type Result<T> =
| { status: "pending" }
| { status: "fulfilled"; value: T }
| { status: "rejected"; reason: unknown };
type State<T> =
| { status: "uninitialized" }
| { status: "pending"; id: number; abortController: AbortController }
| { status: "fulfilled"; value: T }
| { status: "rejected"; reason: unknown };
type Action<T> =
| { type: "init"; id: number; abortController: AbortController }
| { type: "resolve"; id: number; value: T }
| { type: "reject"; id: number; reason: unknown }
| { type: "clean" };
function reducer<T>(state: State<T>, action: Action<T>): State<T> {
switch (action.type) {
case "init":
switch (state.status) {
case "uninitialized":
return {
status: "pending",
id: action.id,
abortController: action.abortController,
};
}
break;
case "resolve":
switch (state.status) {
case "uninitialized":
return state;
case "pending":
if (action.id < state.id) {
return state;
}
if (action.id == state.id) {
return { status: "fulfilled", value: action.value };
}
break;
}
break;
case "reject":
switch (state.status) {
case "uninitialized":
return state;
case "pending":
if (action.id < state.id) {
return state;
}
if (action.id == state.id) {
return { status: "rejected", reason: action.reason };
}
break;
}
break;
case "clean":
switch (state.status) {
case "pending":
state.abortController.abort();
return { status: "uninitialized" };
case "fulfilled":
case "rejected":
return { status: "uninitialized" };
}
break;
}
console.error("Unexpected state", state, action);
return state;
}
function loggingReducer<S, A>(
reducer: (state: S, action: A) => S,
): (state: S, action: A) => S {
return (state, action) => {
try {
const nextState = reducer(state, action);
console.log(state, action, nextState);
return nextState;
} catch (e) {
console.log(state, action, e);
throw e;
}
};
}
let nextId = 1;
export default function usePromise<T>(
promiseFunction: PromiseFunction<T>,
deps: DependencyList,
): Result<T> {
const [state, dispatch] = useReducer(loggingReducer(reducer<T>), {
status: "uninitialized",
});
useEffect(() => {
const id = nextId++;
const abortController = new AbortController();
dispatch({ type: "init", id, abortController });
promiseFunction(abortController.signal).then(
(value) => dispatch({ type: "resolve", id, value }),
(reason) => dispatch({ type: "reject", id, reason }),
);
return () => dispatch({ type: "clean" });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, deps);
switch (state.status) {
case "uninitialized":
case "pending":
return { status: "pending" };
case "fulfilled":
return { status: "fulfilled", value: state.value };
case "rejected":
return { status: "rejected", reason: state.reason };
}
}
Хочу начать освоение прометеуса с малого.
К примеру есть адрес someserver.com/metrics
Он выплёвывает кучу всего. Мне из всего этого нужно только одна метрика:
base_gc_time_total_seconds{name="G1 Old Generation"} 0.0
base_gc_time_total_seconds{name="G1 Young Generation"} 0.303
Причём вот этот label мне не нужен, я хочу его убрать. Чтобы в базе лежало только одно значение - сумма этих двух значений.
Как убирать лишние метрики я вроде понял:
metric_relabel_configs:
- source_labels: [ __name__ ]
regex: base_gc_time_total_seconds
action: keep
А вот как убрать лишние label-ы - я не понял. Можно использовать labeldrop, но кажется это не то, он не будет комбинировать получившиеся метрики, а получится какая-то смесь.
То, что можно сумму посчитать в запросе потом это понятно, я в принципе не хочу хранить эту метрику в двух экземплярах.
Также важно, чтобы эта конфигурация применялась локально к конкретной метрике.
В общем по сути хочу включать метрики потихоньку добавляя нужные мне метрики и label-ы, а не всё скопом. Типа добавил base_gc_time_total_seconds, а все label-ы у него убрал. Потом разобрался - что мне нужна более тонкая статистика и добавил этот name конкретно к этой метрике.
Завис сервер. Я рассчитывал, что он отвиснет, когда oom killer что-нибудь прибьёт, а он не отвисает до сих пор. Подожду до завтра, но явно ситуация не нормальная. Поэтому на соседнем сервере пытаюсь разобраться.
Сам я ничего не настраивал специально, свопа у системы нет. Система установлена из облачного образа debian.
Почему создал тему - в интернете на каждом сайте пишут, что оно контролируется через sysctl vm.oom-kill. Но у меня такого нет:
debian@worker-d-3:~$ /usr/sbin/sysctl vm.oom-kill
sysctl: cannot stat /proc/sys/vm/oom-kill: No such file or directory
debian@worker-d-3:~$ ls /proc/sys/vm
admin_reserve_kbytes dirty_ratio max_map_count nr_hugepages overcommit_ratio user_reserve_kbytes
block_dump dirty_writeback_centisecs memory_failure_early_kill nr_hugepages_mempolicy page-cluster vfs_cache_pressure
compact_memory dirtytime_expire_seconds memory_failure_recovery nr_overcommit_hugepages page_lock_unfairness watermark_boost_factor
compact_unevictable_allowed drop_caches min_free_kbytes numa_stat panic_on_oom watermark_scale_factor
compaction_proactiveness extfrag_threshold min_slab_ratio numa_zonelist_order percpu_pagelist_fraction zone_reclaim_mode
dirty_background_bytes hugetlb_shm_group min_unmapped_ratio oom_dump_tasks stat_interval
dirty_background_ratio laptop_mode mmap_min_addr oom_kill_allocating_task stat_refresh
dirty_bytes legacy_va_layout mmap_rnd_bits overcommit_kbytes swappiness
dirty_expire_centisecs lowmem_reserve_ratio mmap_rnd_compat_bits overcommit_memory unprivileged_userfaultfd
Видимо гайды устарели. Как правильно проверить? Ядро 5.10.0-20-amd64
В /usr/lib/systemd/ бинарника systemd-oomd тоже нет и сервиса соответствующего тоже нет, если что.
Есть смысл смотреть на что-то вроде F2FS или сейчас нормальные карты от SSD не отличаются и сами балансируют записи по блокам, то бишь стандартный Ext4 будет предпочтительней?
Помимо прочего крайне необходимо, чтобы не было порчи ФС при выключении питания. Данные хранятся в sqlite, поэтому важно, чтобы sqlite оставалась в работоспособном состоянии.
| ← назад | следующие → |