Nebula Blogs https://blogs.nebulasrv.net Типо блох Fri, 17 Dec 2021 20:29:39 +0000 en-US hourly 1 https://wordpress.org/?v=6.3.5 https://blogs.nebulasrv.net/wp-content/uploads/2019/01/cropped-favicon_bl-1-32x32.png Nebula Blogs https://blogs.nebulasrv.net 32 32 Удаляем назойливое “меню SIM” https://blogs.nebulasrv.net/2019/07/%d1%83%d0%b4%d0%b0%d0%bb%d1%8f%d0%b5%d0%bc-%d0%bd%d0%b0%d0%b7%d0%be%d0%b9%d0%bb%d0%b8%d0%b2%d0%be%d0%b5-%d0%bc%d0%b5%d0%bd%d1%8e-sim/ Mon, 08 Jul 2019 17:42:00 +0000 https://blogs.nebulasrv.net/?p=832 С момента покупки смартфона, жутчайший бомбеж у меня вызывало всплывающее окно “еле-два“, постоянно вылезающее после перезагрузки телефона, либо вообще в случайное время. Причем вылазило оно настолько невовремя, что у меня даже получалось ненароком подключить парочку платных услуг.

Кроме как паскудством все это дело не назвать, но мне всё было лень изучить вопрос как следует.

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

Расчехляем adb, врубаем отладку по USB и приступаем.

Просто для интереса можно посмотреть полный список установленных пакетов:

adb shell cmd package list packages

Но нам нужен конкретный. Смотрим путь до его apk:

adb shell pm path com.android.stk

На всякий случай бэкапим:

adb pull /путь/из/результата/прошлой/команды.apk /локальный/путь/куда/бэкапить

И удаляем гавно:

adb shell pm uninstall -k --user 0 com.android.stk

Готово. Как пишут в интернетах, может не работать автополучение настроек APN, но и нахер оно не надо, ибо:

  • Можно настроить руками
  • Если все уже давно настроено, то может сбиться только после резета телефона, ну а после этого приложение все равно вернётся.

]]>
Мониторинг влажности растений, комплексный подход (на самом деле, на коленке) https://blogs.nebulasrv.net/2019/06/plantmonitor/ Sun, 30 Jun 2019 08:22:53 +0000 https://blogs.nebulasrv.net/?p=697
Небольшое предисловие
Этот пост мало того что писался очень долго (около трех месяцев, и все из-за моей лени, естественно), и при этом сильно позже того, как я закончил конструировать и тестировать концепт. Некоторые идеи весьма устарели, код требует доработки, где-то просто сместились приоритеты. Но, все же, я не думаю что имеет смысл “обновлять” статью по мере этих изменений, а лучше каждый следующий этап (если они будут) отражать в новых постах.

Как-то так всегда получилось, что я не был приучен к своевременному поливу цветов, и этим всегда занимался кто-то другой. В какой-то момент, отсутствие внимания к поливу растений стало критичным для их принципиального существования, поэтому мне пришлось вырабатывать у себя соответствующие привычки – проверять землю по приходу домой, обращать внимание на пожухлось листвы и прочее. И уже тогда в моем жидком мозге появился некий пунктик – нужно срочно мониторить сухость растений!

Это было, что называется, inception, после которого мой план-перехват медленно зрел в глубинах сознания. Где-то в этот же период я решил для себя что нужно перестать трусливо поджимать уши когда речь заходит об электронике, и начал поднимать общий уровень образования относительно ее теории.

Кстати, советую сайт-блог-учебник Easyelectronics, лучшее из того что я нагуглил. Хотя, опережая возможный гнев читателя, безусловно:
А) надо было бы читать школьные учебники!
Б) нужно было нормально учиться в школе!
В) как такого не знать, работая по инженерной специальности!

Таким вот образом, практически незаметно для себя, я набрел на arduino. Хайп относительно DIY на этих микропроцах уже давно прошел, а я вот только созрел. Изучив ютаб, документацию, и несколько чужих проектов, пришло понимание, что собирать поделки на ардуине действительно просто и не требует знаний какого-либо серьезного порядка, при этом позволяет воплощать свои фантазии без серьезных финансовых затрат, или поисков каких-то суперспециальных железяк на алиекспрессе.

В интернете тысяча и одна штука проектов “умных теплиц”, всяких автополивочных и прочего, но я не встретил ни одного варианта интеграции в существующую систему умного дома и, как следствие, проектирования системы с максимально простым и удобным масштабированием. В общем-то, у меня сразу появилось стойкое ощущение что энтузиасты с ютуба делают свои наработки по большей части в стиле proof of concept: свою идею достаточно реализовать в хоть сколько-то работающем виде, показать что она функционирует, после чего интерес к ней угасает и проект разбирается\пылиться на полке. Я для себя решил сразу – чтобы собственный проект считать хоть чего-то стоящим, я должен ответить себе на несколько вопросов:

  • Готов ли я реализовать проект для кого-то другого человека, не опасаясь за то, что придется каждый раз беспокоится за его работу? Не случится ли так, что поддержка такого проекта будет занимать больше сил чем его разработка? Это самый ужаснейший из исходов – когда проклинаешь себя что вообще взялся за создание чего-то подобного.
  • Безопасен ли проект? Если оставить его без присмотра на месяц\год, есть хоть малейшая вероятность пожара\потопа\лягушек с неба? Если да – взрослый адекватный человек (хотелось бы считать себя таковым) таким пользоваться не станет.
  • Можно ли рассчитать MTBF (наработку на отказ)? Срок до “капиталки” должен быть или очень большим или рассчитываемым. Нужно знать, что вот такая-то часть проекта потребует технического обслуживания примерно раз в год. Вот такая вот часть не должна ломаться. Третья часть, теоретически, может выйти из строя при некоторых условиях, но наличие одной запасной детали будет оптимально.

Чего греха таить – на момент написания этих строк, мой проект находится не в том положении – концептуально работает, но ни на один из вышеперечисленных вопросов я не могу ответить утвердительно. Поэтому этот пост – просто затравка, некий фундамент, на котором при должном усердии можно собрать что-то хоть немного полезное.

Итак, первоначальный концепт проекта был таков:

К ардуине подключается максимальное возможное количество датчиков влажности почвы. Показания с датчиков отправляются на устройство способное запускать полноценную ОС, я выбрал для этого Raspberry Pi 2. На ней должен производиться сбор данных, их хранение и отображение. В идеале, должен быть пользовательский интерфейс, через который можно было увидеть все датчики. Каждому датчику можно будет сопоставить растение, со детальным описанием, к которому можно выставить границы предупреждений высыхания, диапазоны “красных”, “жёлтых” и “зелёных” областей, в зависимости от типа растения. Примерно, как-то так.

К сожалению, так просто я не смог подобрать инструментарий для полного осуществления плана (что неудивительно), и начал подозревать что для такого функционала нужны самописные решения. Так как писать приложения я не умею, то у меня было два варианта: таки научиться писать приложения или подобрать некий заменитель. Немного поразмыслив и решив что всему свое время, я выбрал заменитель.

И вот к чему я в итоге пришел.

Общий вид

Базовый механизм таков: арудины заняты тем что собирают информацию с датчиков, которые запрашивает raspberry по протоколу i2c.

i2c (Inter-Integrated Circuit) – протокол обмена данными между устройствами на одной шине, использует две линии передачи: линия данных (SDA) и линия тактов (SCL). Он достаточно хитро работает, я ограничился прочтением статьи на педивикии, но даже она оказалась для меня не очень простой.

Схема подключения

На картиночке мы можем наблюдать основные элементы системы. На самом деле, ими являются только три электронных компоненты – raspberry, arduino и гигрометры (датчики влажности) для почвы. Помимо них, на схеме присутствуют rgb светодиод, и кнопка. Они нужны для дебага, но об этом подробнее позже.

Также, в данной схеме используется arduino nano – как самая маленькая и дешевая (из популярных) версия ардуины. Но использовать можно абсолютно любую – я лично тестов не проводил, но логично было бы посоветовать arduino Micro, у них больше аналоговых пинов при тех же размерах платы, а SDA и SCL занимают цифровые выходы. Но плата гораздо менее распространенная, поэтому проблемой может быть не только ее приобрести, но и заставить правильно работать. Если все растения находятся в непосредственной близости друг к другу, то можно обратить внимание и на arduino Mega (16 аналоговых пинов), хотя, вероятно, дешевле будет воспользоваться платой-экстендером или мультиплексором, хотя для этого придется видоизменять код. Вариантов очень много, и подобрать наиболее подходящую плату – задача выходящая за рамки стадии сборки концепта.

Также, из того что я смог попробовать из подручных средств – увеличил шину i2c по длине до 2,5 метров, каких-то изменений не обнаружил, данные не начали “гулять” из-за наводок.

Настройка ардуины

Стандартный датчик влажности представляет собой анод и катод, с минимальной электрической обвязкой. Ток идёт от одного зубца к другому, и делает это наиболее хорошо в максимально проводимой среде. На полное замыкание (проводом, к примеру) он не рассчитан, и предполагает что электрическая проводимость между зубьями всегда будет достаточно низкая.

У датчика который я купил (самый дешёвый и популярный вариант), есть 4 контакта: плюс, земля, цифровой выход и аналоговый. Работает он от 5 вольт (от 3,3 в принципе тоже), а полярность не имеет значения. Примерное энергопотребление 3 миллиампера, что, учитывая максимальных выходной ток пинов на арудине в 40 мА, дает возможность питать 10 таких датчиков с небольшим запасом.

Если цифровому выходу сложно придумать применение, то с аналогового можно получать значения в 10 бит, от 0 до 1023, где (если подключать через INPUT_PULLUP) 1023 это полная сухость. При опускании в воду оба моих датчика показывают значения около 400.
В целом, этого уже достаточно чтобы собрать простой тестовый стенд – подключаем датчик к ардуине, плюсы и землю ясно куда, а аналоговый пин датчика к любому аналоговому пину на плате. Переводим этот пин в INPUT_PULLUP (питание через резистор, позволяет избегать наводок и паразитных токов) и снимаем значения в Serial.println.

На самом деле, отдельный подтягивающий резистор все равно не помешает – возможно, в будущем, придется переделать под него код (а лучше с переменной, в которой можно будет выставить работу с резистором\без оного).

Также, я попробовал удлинить провода от “обвязки” где установлен подстроечный резистор до самой “вилки” до ~20 см и не заметил изменений. Но удлинение проводов от обвязки до платы ардуины вызвало странные флуктуации показателей с датчика. Хотя это не являлось корректным экспериментом, и требует качественной проверки.

Но, как я говорил, тестовый стенд очень сильно далек от “промышленного” варианта, и не представляет собой ничего стоящего. Все сложности начинаются тогда, когда появляется потребность организовать хорошую, надежную и адекватную работу.

Итак, коротко о логике работы программы. Ниже представлена абы-какая блок-схема, которая, скорее всего, не соответствует нормативам, но должна отразить суть:

В первую очередь стоит обратить внимание на то, что основа программы – три “ожидания”. Два из них последовательно выполняются в основном цикле void loop, это настриваемый таймер и нажатие кнопки. А одно идет параллельно модулем Wire, активируясь при получении запроса по i2c.
Таким образом, при включении ардуины, без получения управляющего сигнала, она ничего делать вообще не будет. И есть два варианта как ее можно активировать: нажать кнопочку в течении секунды, которая активирует нулевой датчик (подключенный к A0), либо отправить по i2c запрос с номером датчика, информацию с которого хотелось бы получить. В этом случае, этот датчик будет помечен как активный внутренней логикой программы, и, с цикличностью равной period, с него будут собираться показатели.

Помимо запросов по датчикам, управляющий элемент (raspberry pi) может отправлять и другие запросы. Любой запрос, отличный от номера датчика, считается служебным и должен обрабатываться в соответствии с этим, например менять на ходу переменные (типа period) или сбрасывать флаги. Этот механизм предусмотрен, но я его еще не реализовал :).

Дальше я хочу выложить код арудины, донести его логику и попутно объяснить те или иные решения. Сразу нужно оговориться – я нисколько не программист, поэтому у Вас наверняка будет бомбить как от содержательной части кода так и его форматирования (по большей части его просто нет).

Код ардуины
/*
Bydlo code for moisture sensors

*/
#include <Wire.h> //i2c module
#include <JC_Button.h> //easy button module

//#define HardwareSerial_h //disable serial port, significally reduces code size
#define buttonPin 3 //button pin
#define ledRedPin 9 //led pins for testing
#define ledGreenPin 10
#define ledBluePin 11
#define SLAVE_ADDRESS 0x04 // arduino will have that i2c address in slave mode
#define powerPin 5


//timers
unsigned long timing; //timer for collecting cycle
unsigned long fadeTiming; //timer for collecting cycle
unsigned long period; //period for collector in seconds
//data
byte reqType; //request data, input from raspberry
byte countCollects; //number of collects for median calculation
int* dataArray; //data storage for sensors
int* collectArray; //pointer for dynamic array of sensor values creation
bool* sensorArray; //store flags if sensor is requested and must be used in collect function
//pins
const uint8_t analog_pins[] = {A0,A1,A2,A3,A6};
byte sensorPins; //count of sensors calculating from analog_pins, 7 analog pins on nano (used in loops, so starts with zero) minus 2 for i2c (see above)
//debug
bool debugSerial = false; //change to true to enable serial port messages. !!WARNING makes i2c proto almost unusable (dont know why)
//LED
byte ledBrightness; //from 0 to 10
Button ledButton(buttonPin,50); //set button type on buttonPin, with 50 debounce time, input_pullup (JC_button functionality)
byte ledActive; //active led var
byte fadeBrightness = 0; // how bright the LED is
byte fadeAmount = 5; // how many points to fade the LED by
bool fadeOn; // does fading to be used

void setup() {
//set default values:
ledBrightness = 1;
countCollects = 5;
period = 60;
//initialization
Wire.begin(SLAVE_ADDRESS); // I2C start on hard-coded address
Wire.onReceive(receive); //When raspberry sends data, do receive function
Wire.onRequest(send); //response function for answer
ledButton.begin(); //button module init
sensorPins = sizeof(analog_pins); //count of sensor pins calculation
ledActive = sensorPins; //default status for led is off (pins starts with 0, so last pin is (sizeof(analog_pins) - 1).
pinMode(ledRedPin, OUTPUT); // color led init
pinMode(ledGreenPin, OUTPUT);
pinMode(ledBluePin, OUTPUT);
pinMode(powerPin, OUTPUT); //Enable Power pin mode
//creating dynamic arrays:
dataArray = new int [sensorPins]; //creating dynamic array for data storage
collectArray = new int [countCollects]; //creating dynamic array for median calculating
sensorArray = new bool [sensorPins]; //creating dynamic array for flags
//zeroing arrays:
for (byte i = 0; i < sensorPins; i++) { //or i <= 4
pinMode(analog_pins[i],INPUT_PULLUP);
dataArray[i] = 0;
sensorArray[i] = 0;
}
if (debugSerial == true) {
Serial.begin(9600);
Serial.println("Ready!");
}
}

void loop() {
ledButton.read();
if (millis() - timing > (period * 1000 )){ // period of collecting data
timing = millis();
delay(500); //warming sensor for some time
for (byte i = 0; i < sensorPins; i++) {
digitalWrite(powerPin, HIGH);
if (sensorArray[i] == 1 ) { //check array of flags if sensor is used
collect(i); //send to function what sensor need to be processed
if (debugSerial == true) {
Serial.print ("sensorPins = ");
Serial.println (sensorPins);
Serial.print ("Sensor ");
Serial.print (i);
Serial.print (" collected data = ");
Serial.println (dataArray[i]); //debug
Serial.print ("sensorFlag = ");
Serial.println (sensorArray[i]);
}
}
digitalWrite(powerPin, LOW); //collect ended. power off
}
}
//wait for input from button
if (ledButton.wasReleased()) {
if (ledActive < sensorPins) {
ledActive++;
led();
}
else {
ledActive = 0;
led();
}
}
else if (ledButton.pressedFor(1000))
if (digitalRead(buttonPin) == LOW) { //"low" because of pullup
sensorArray[0] = 1;
digitalWrite(powerPin, HIGH);
collect(0); //collecting 0 button for test
delay(500);
digitalWrite(powerPin, LOW); //collect ended. power off
}
if (debugSerial == true) {
Serial.print ("ledActive = ");
Serial.println (ledActive);
Serial.print (" collected data = ");
Serial.println (dataArray[ledActive]); //debug
}
fader();
}
void receive() {
while (Wire.available()) {
reqType = Wire.read();
if (debugSerial == true) {
Serial.print("Get request, type = ");
Serial.println(reqType);
Serial.println(sensorArray[reqType]);
}
if (reqType <= sensorPins) { //check request if it lower than number of maximum available sensors, this is sensor number. Another is service codes
if (sensorArray[reqType] == 0) { //check if flag not set
sensorArray[reqType] = 1; //set flag of sensors array (enable sensor)
if (debugSerial == true) {
Serial.print("Sensor ");
Serial.print(reqType);
Serial.println(" activated");
}
collect(reqType); //collect data from newly activated sensor *!! COMMENT THIS LINE on debug process it is not working with enabled serial port, dont know why*
}
}
else {
if (debugSerial == true) {
Serial.println("Service code received");
}
}
}
}

int collect(byte sensNumber) {
//Here goes loop for calculating median of value
for (byte i = 0; i < countCollects; i++) { //do countCollect number of sensor requests
collectArray[i] = analogRead(sensNumber);
// Serial.println(collectArray[i]); //detailed debug
delay(150); //delay between requests
}
sortArray();
if ( (countCollects % 2) == 0) { //even number of elements
dataArray[sensNumber] = ((collectArray[countCollects/2] + collectArray[(countCollects/2)+1]) / 2);
}
else { //odd number of elements
dataArray[sensNumber] = collectArray[countCollects/2];
}

//send();
led();
}


void send () {
byte metric;
if (debugSerial == true) {
Serial.print("Raw data for sensor ");
Serial.print(reqType);
Serial.print(" is ");
Serial.println(dataArray[reqType]);
}
metric = map(dataArray[reqType], 0, 1023, 0, 255);
metric = constrain(metric, 0, 255);
Wire.write(int(metric));
if (debugSerial == true) {
Serial.print("Sensor ");
Serial.print(reqType);
Serial.print(" data sent = ");
Serial.println(metric);
}
}

void sortArray() {
int out, in, swapper;
for(out=0 ; out < countCollects; out++) { // outer loop
for(in=out; in<(countCollects-1); in++) { // inner loop
if( collectArray[in] > collectArray[in+1] ) { // out of order?
// swap them:
swapper = collectArray[in];
collectArray[in] = collectArray[in+1];
collectArray[in+1] = swapper;
}
}
}
}


void led () {
if (ledActive == sensorPins) {
fadeOn = 0;
analogWrite(ledRedPin, 0);
analogWrite(ledGreenPin, 0);
analogWrite(ledBluePin, 0);
}
else if (dataArray[ledActive] > 900 ) {
fadeOn = 0;
analogWrite(ledRedPin, 25 * ledBrightness);
//Serial.println(50 * ledBrightness);
analogWrite(ledGreenPin, 0);
analogWrite(ledBluePin, 0);
}
else if ((dataArray[ledActive] < 900) && (dataArray[ledActive] > 750)) {
fadeOn = 0;
analogWrite(ledRedPin, 25 * ledBrightness);
analogWrite(ledGreenPin, 15 * ledBrightness);
analogWrite(ledBluePin, 0);
}
else if (dataArray[ledActive] < 750 && (dataArray[ledActive] > 15)) {
fadeOn = 0;
analogWrite(ledRedPin, 0);
analogWrite(ledGreenPin, 25 * ledBrightness);
analogWrite(ledBluePin, 0);
}
else if (dataArray[ledActive] < 15) {
fadeOn = 1;
analogWrite(ledGreenPin, 0);
analogWrite(ledBluePin, 0);
}
}

void fader() {
if ( fadeOn == 1 ) {
if (millis() - fadeTiming > 10 ) { // wait for 30 milliseconds to see the dimming effect
fadeTiming = millis();
analogWrite(ledRedPin, fadeBrightness);
// change the brightness for next time through the loop:
fadeBrightness = fadeBrightness + fadeAmount;
// reverse the direction of the fading at the ends of the fade:
if (fadeBrightness <= 0 || fadeBrightness >= 255) {
fadeAmount = -fadeAmount;
}
}
}
}

Код я постарался максимально прокомментировать, но все же хочу разобрать его по блокам, просто чтобы у Вас была возможность понять из чего он состоит, и, возможно, воспользоваться им в своих каких-то начинаниях.

На второй странице будет исключительно разбор кода ардуины, если он вам неинтересен, можно сразу переходить на 3-ю.

]]>
Интересное за май https://blogs.nebulasrv.net/2019/06/interesting-may/ Sun, 02 Jun 2019 04:00:56 +0000 https://blogs.nebulasrv.net/?p=693 Наступают летние месяцы, а вместе с ними, так уж сошлось, сильно отвлеченные от ИТ-тусовки жизненные задачи и приоритеты. Поэтому список интересностей в этом месяце выдался крайне скромный, и, весьма вероятно, либо актуальными станут вещи далекие от этих ваших люмиксов, либо будет царить пустота и тишина. Вот по мелочи:


Карта молний. Либо так: сайт-оригинал.

Изучил вопрос сбора данных – присутствует возможность присоединится к проекту, но нужно заказать непростое устройство (тем не менее даются схемы как сделать его самому), чтобы передавать наблюдамые показания в ДЦ. Как-то наблюдал грозу совсем неподалеку, но на карте не смог ее обнаружить. Обидно.


Поиграйте в симулятор роскомнадзора.


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

]]>
Интересное за апрель https://blogs.nebulasrv.net/2019/04/interesting-april/ Tue, 30 Apr 2019 10:00:11 +0000 https://blogs.nebulasrv.net/?p=511 Некоторые сайты могут возвращать вам заголовок X-clacks-overhead, в значении которого будет указано “GNU Terry Pratchett” автор юмористического фэнтези, вскользь упоминаемый в прошлой части интересного за месяц. Полезной нагрузки заголовок, само собой, не несет, так что, похоже, является простым способом помянуть автора. В RFC такие шуточные заголовки не внесены и не стандартизованы (в отличие от знаменитого и любимого мной протокола “IP over голубиная почта“, например). Впрочем, существует дофига и больше других забавных rfc.


Статейка на швабре, как небольшой крик души на тему такой единицы измерения энергии как КВт*ч. В действительности, самому стыдно было столько времени ошибаться как в написании, так и в физическом понимании этой величины. Если лень читать\тыкать ссылку\там не понятно, то краткий ликбез от меня:
Есть физическая величина Ватт. Она уже отображает количество энергии в единицу времени, и равна 1 Дж/с. Теперь посмотрите на КВт*ч. Между КВт и ч стоит знак умножения, что неправильно произносить как “киловатт в час” или “киловатт за час”. И если мы, собственно, произведем эту операцию умножения, то обнаружим что единицы времени должны просто сократиться, и результатом получится некий коэффициент и Дж – единица измерения энергии (работы).
Итого, то что нам показывает счетчик, это:
выполненная работа (КВт*ч) всеми домашними приборами за неизвестное (вопреки интуитивному понятию) время, и никак не отображающая мощность ваших приборов, пока не известно то самое время, за которое эта работа была выполнена.


Для жителей Омска отличная находка, превосходный магазинчик с ардуино. Уж не помню как я на него наткнулся в инете, но почему-то мне сразу он показался что надо. Мне всегда казалось что предприниматели должны очень охотно закупать китайский электронный ширпотреб, но найти соответствующие точки продажи достаточно сложно, если только активно курсировать по подземным переходам города. В этом магазе я обнаружил практически полный ассортимент того что можно найти на алиэкспрессе, причем наценка настолько небольшая, что это получается не только “мгновенно”, в отличие от полуторамесячной почтовой пересылки, но и дороже чем китайская стоимость + доставка с треком всего процентов на 10-15. Все товары есть на витрине (правда в коробочках и пакетиках, но достать и посмотреть\пощупать можно), неисправные детали можно без проблем вернуть. В общем, советую.


Разработчики OpenBSD к выпускам релизов записывают песни! Что ж, никогда не сомневался, что истинный BSDшник талантлив во всем. Там же опубликованы тексты песен, во основном они на тему разработки, опенсорса и прочего рилейтед. Веселые обложки. Внизу песни на пробу!

Winter of 95

Planet of the Users

Games

Blob!


В дубльгисе появилась карта Вестероса из “Игры престолов”. Народ оставляет отзывы о разных городах, местами очень забавно.

]]>
Разбираемся с тормозной файловой системой, часть 3: базовые инструменты. https://blogs.nebulasrv.net/2019/04/rtfs-3/ Tue, 30 Apr 2019 04:20:20 +0000 https://blogs.nebulasrv.net/?p=331

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

Когда я только начал замечать проблемы и полез в гугл за ответами, со всех сторон начали сыпаться советы по тестированию скорости диска с помощью утилиты dd.


dd


Отгадайте пословицу: dd if=/dev/zero of=/dev/null

Как написано в man’е, производит конвертирование и копирование файла. Описание очень скудное и не дает представления о том на что способна эта замечательная программа.
Это не сильно соотносится сейчас с нашей темой, но принцип устройства VFS предполагает что буквально все в системе должно быть представлено как “файл”, в том числе и устройства. С этим связано одно из самый популярных применений dd – возможность побайтово склонировать целый диск, раздел, или какую-то их часть.

dd if=/dev/sda of=/dev/sdb

Команда выше полностью скопирует информацию с одного диска на другой со всеми “потрохами”: идентификаторами разделов, файловыми системами, метаданными и полезной нагрузкой.
Добавив status=progress можно будет наблюдать за течением сего процесса.

Также, например, если не указывать куда перенаправлять вывод (без директивы of=), то вывод просто получим на экран (stdout).

dd if=/etc/os-release

Впрочем, в мане или на просторах сети полно информации о дэдэшечке, не будем повторяться.

Вернемся лучше к нашим баранам, мы собирались измерить скорость работы дисков. Как правило самые ходовые тесты заключаются в копировании файлов с места на место или копирование нулей в файл.
Вот мы типо пишем 1 гигабайт:

> dd if=/dev/zero of=/tmp/testfile bs=1G count=1

1073741824 bytes (1,1 GB, 1,0 GiB) copied, 10,0035 s, 107 MB/s

Теперь пробежимся по значимым опциям.

bs = размер блока. Т.к dd работает именно поблочно, то это будет размером его атомарной операции, считать n байт => записать n байт, ни больше ни меньше. Поддерживается указание арифметических операций, например bs=2x80x18b (размер дискеты). По умолчанию bs равен 512b

count = тут понятно, это просто счетчик.

status = progress – периодически отписываться в stderr о прогрессе.

iflag \ oflag = чтение или запись может производится особым образом.

  • direct – отправлять запросы минуя кэш (direct I/O)
  • dsync – использовать синхронное I/O (synchronized I/O), т.е. каждое последующее IO только после завершения предыдущего.

conv = обработка, которая происходит между in и out. В основном используется директива noerror, остальные весьма специфичны, и редко встречались или требовались мне на практике.

Таким образом, можно проводить тесты линейной записи или чтения.
Можно регулировать размер блока, который будет записан\прочитан.
Есть возможность писать, с просьбой ядру не использовать кэш.
Можно использовать синхронное I/O.

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

А нам надо видеть чем занимаются диски. Разбираемся дальше.


iotop

Аналог top, только типо для дисков.

Можно наблюдать список процессов, и различные показатели по столбцам: thread ID, IO приоритет, пользователя, интенсивность свопа и некий процент IO.

IO priority – be\rt\id означают класс процесса (best-effort, real-time, idle), а значение от 0 до 7 приоритет относительно других процессов (меньшие значения подразумевают больший приоритет). Эти значения можно изменить с помощью утилиты ionice, но помните, что приоритеты смотрит I/O scheduler, упоминаемый в предыдущей статье. И умеют это только “весовые” виды планировщиков, т.е. CFQ, BFQ и Kyber (насчет него неточно). Также, приоритеты не работают для асинхронной записи.
Swap – так как процессу отводится некоторая часть всей очереди на ввод-вывод, то процент от этой части, являющийся свопингом будет отображен в этом значении.
I/O – работает по тому же принципу что и swap, но отображает время затрачиваемое на ожидание ввода-вывода.

Также в верхней части экрана есть значения {Total,Actual} DISK {READ,WRITE}. Как написано в мане, Total read\write подразумевает весь обмен между процессами и дисковой подсистемой ядра.

Немного аналитики
Мне показалось непонятной формулировка “kernel block device subsystem” я решил хотя бы минимально, так сказать, прощупать границы. Выяснилось, что это точно не уровень VFS, т.к. запись в tmpfs c o_direct не отображается в iotop. Так что судя по всему подразумевается bio.

Actual read\write – обмен между дисковой подсистемой ядра и драйверами оборудования.
Таким образом значения Total и Actual могут ощутимо отличаться как раз таки из-за кэша и планировщика.

Ключи
-a – iotop будет показывать аккумулированные данные с момента своего запуска. В таком режиме информация получается более наглядной.
-o – показывать только те процессы, у которых есть активность.
-d – интервал обновления.
-P – показывать не треды а процессы.

На самом деле, каких-то действительно полезных аналитических данных через iotop у меня не получалось добыть. Главное причина тому – нет разделения по блочным устройствам, показываются данные по всей системе целиком. Но в роли подспорья утилита однозначно хороша.


iostat

Является частью пакета sysstat.

Тулза для мониторинга блочных устройств.
Если просто просто ее запустить без ключей, то получим средние значения по всем дискам с момента загрузки системы.

Если же запускать в формате iostat число1 число2, то механизм работы будет следующим: число1 – это как часто опрашивать статистику, число2 – количество опросов. iostat 2 10 – опросить каждые 2 секунды,
всего 10 раз .

В верхней строчке идет статистика по CPU.
В принципе, все это можно увидеть в top:
%user – загрузка процессами выполняющимися в userpspace.
%nice – тот же userspace, но то что выполняется с настройками nice – определяющими приоритет у дискового шедулера
%system – то что кушают ядерные процессы
%iowait – процент времени которые CPU ждет ответа от дисковой подсистемы
%steal (может отсутствовать) – как правило, встречается в виртуализации, когда виртуальные машины бьются друг с другом за ресурсы
%idle – CPU отдыхает

Значения:

tps – количество I/O запросов устройству. Судя по ману, здесь отображаются запросы уже после их комбинирования планировщиком.
Без дополнительных ключей, остальные столбцы, думаю, понятны – запись и чтение в секунду, и сколько всего было записано\прочитано.

Другое дело с ключиком :
rrqm/s и wrqm/s – количество объединенных запросов чтения и записи соответственно.
r/s и w/s – количество i/o на чтение и запись в секунду.
rkB/s и wkB/s – чтение и запись в КБ\сек.
avgrq-sz – средний размер отправленных запросов (в секторах).
avgqu-sz – средняя длина очереди.
await, r_await, w_await – время запроса в очереди, плюс время на его обслуживание.
util – время в течении которого блочное устройство занято запросами на I/O в процентах.

В новых версиях iostat слегка изменились некоторые столбцы.
Добавились %rrqm и %wrqm – процент объединенных запросов.
areq-sz – средний размер запросов (бывший avgrq-sz, но в отличие от него не в секторах, а в килобайтах).
aqu-sz – средняя длина очереди (бывший avgqu-sz)
rareq-sz, wareq-sz – средний размер запроса для чтения\записи.

Кратко о ключах:

  • с – только статистика по CPU.
  • d – убрать статистику по CPU, только диски.
  • g – позволяет группировать диски и отображать по ним суммарные значения. например: iostat -g my_disk_group sda sdb sdc. Получим статистику по трем дискам и их сумму в группе my_disk_group.
  • H – вместе с -g уберет из вывода отдельные диски, оставив только суммарные значения по группе.
  • h – human readable, но, как по мне, удобств не добавляет.
  • j { ID | LABEL | PATH | UUID | … } – вывести название диска в указанном формате, по умолчанию LABEL.
  • k и m – отображать значения в килобайтах или мегабайтах соответственно.
  • N – использовать имена для device mapper томов. Удобно для LVM.
  • p – отображать разделы
  • t – штамп времени каждого отчета
  • x – расширенная статистика.
  • y – не показывать первый отчет, который показывает общую статистику с момента загрузки.
  • z – не показывать устройства с неизменными значениями (типо неактивные).

/proc/sys/vm/block_dump

Можно включить отладку сброса dirty pages на диск.

echo 1 > /proc/sys/vm/block_dump

Сообщения о том, данные какого процесса сбрасываются можно увидеть в dmesg или логах ядра (количество сообщений пропорционально интенсивности записи, будьте готовы к срачу в логах)


Домашняя работа

А теперь на основании теоретических знаний из первой статьи и практических инструментов из текущей, попробуйте понять что происходит с линейной записью в этих четырех случаях, и почему получаются именно такие результаты? Какое узкое место системы в данном случае проявляется? Запись производится на один диск, файловая система XFS.

> dd if=/dev/zero of=/tmp/testfile bs=4k count=200000 
...
819200000 байт (819 MB, 781 MiB) скопирован, 5,26288 s, 156 MB/s 
> dd if=/dev/zero of=/tmp/testfile bs=781M count=1 oflag=direct
...
818937856 байт (819 MB, 781 MiB) скопирован, 8,7302 s, 93,8 MB/s
> dd if=/dev/zero of=/tmp/testfile bs=4k count=200000 oflag=direct 
...
819200000 байт (819 MB, 781 MiB) скопирован, 39,5175 s, 20,7 MB/s
> dd if=/dev/zero of=/tmp/testfile bs=4k count=2000 oflag=dsync 
...
8192000 байт (8,2 MB, 7,8 MiB) скопирован, 60,7651 s, 135 kB/s

В последнем примере специально количество блоков меньше в сто раз, потому что иначе очень долго ждать 🙂

Попробуйте эти команды у себя (на ext4 результаты отличаться не будут), удостоверьтесь что результат не из головы.

Ответ будет в отдельном посте или в следующей части. Всех благ!

]]>
Разбираемся с тормозной файловой системой, часть 2: взгляд со стороны ОС https://blogs.nebulasrv.net/2019/04/rstfs-2/ https://blogs.nebulasrv.net/2019/04/rstfs-2/#comments Tue, 30 Apr 2019 04:15:51 +0000 https://blogs.nebulasrv.net/?p=539
Предисловие
Так получилось, что я решил переработать прошлую версию статьи РСТФС-2 и разделить ее на две отдельные части. Теперь здесь снова только теоретическая часть, а обзор базовых инструментов (когда-нибудь будут еще и продвинутые) в третьей части. Как мне видится, так материал получился более последовательным и понятным, надеюсь, так оно и есть.

О секторах, блоках и адресации

Мне показалось очень нужным рассмотреть на низком уровне работу механических дисков (хотя и все равно поверхностно, как ни крути). Дело в том, что можно легко запутаться во всех этих секторах и блоках разных калибров. И у этого есть исторические аспекты. Маленько разберемся:

Сектор приз на барабане.

Сектором называется минимальная область диска, которая имеет адрес. Раньше дефолтным размером было 512 байт. Теперь современный стандарт – 4096 байт, известный как advanced format. Если коротко – на картинке выше изображен физический сектор. Логический сектор – это “виртуальный” размер сектора о котором может сообщать вам диск. Можно пронаблюдать через команду fdisk -l /dev/$device.

Кластер или блок.

Эти слова часто имеют очень путанное использование. Вроде как в линуксе слово “cluster” не применяется, либо можно считать его синонимичным определению блока. А вот блок… С ним часто происходят разночтения.
В первую очередь нужно закрепить понимание, что это просто абстракция, логическое представления единицы обрабатываемых данных. Порой, блоками называют как логические так и физические секторы диска, только подразумевая взгляд со стороны ОС. Как бы для диска это сектор, но для самой операционки это всего лишь некий абстрактный блок, который диск соизволил отдать (в случае SSD или некоторых SCSI это действительно “фиктивный” сектор). А иногда, слегка поднявшись по структуре блочных устройств, так называют структурные единицы уровня файловой системы. Это все является блоками, но без контекста можно запутаться. Я постараюсь не создавать двусмысленности в статьях, и не использовать слово “кластер” касательно файловой системы, и писать “физический сектор” или “логический сектор” там, где подразумевается именно соответствующий сектор.

Выравнивание разделов.

Как я уже упоминал, слово “блок” может использоваться при использовании различных сущностей: блок как логический сектор на диске, блок как структурная единица файловой системы, менеджера томов, RAID-массива. А ведь все это может вполне себе работать в связке. А теперь представьте, что внезапно каждая из этих сущностей считает блоком совсем не то, что считает другая. Это породило бы массу неприятностей…

На самом деле, такой исход маловероятен, но теоретически возможен. Впрочем, механизмы создания логических томов, RAIDов, ZFS пулов и прочего, автоматизировано умеют выравниваться вдоль разделов или всего диска или может даже друг друга (почему нет?). Но во-первых, так было не всегда, а во-вторых, иногда тоже есть нюансы. Итак зачем нужно выравнивание?

Запустив fdisk -l /dev/$device обратите внимание на размер логического и физического сектора и стартовый сектор. Скорее всего, у вас все в порядке, и будет такая картина:

Sector size (logical/physical): 512 bytes / 4096 bytes
Device       Start
/dev/sda1      2048

Проблема возникает, когда первым логическим сектором у вас является 63й.

Device       Start
/dev/sda1      63

Но почему именно 63?
Стандартной схемой всегда считалось начинать раздел сразу после окончания первой дорожки или цилиндра (track, cylinder).

А при старом типе адресации CHS (cylinders, heads, sectors) адрес сектора в дорожке мог кодироваться только 6 битами (0-63).
На смену CHS пришел LBA (logical block address), добавляющий дополнительный уровень абстракции между адресацией диска и драйвера ОС. С тех пор напрямую с геометрией диска работать не принято, и используются уже много раз упомянутые логические секторы\блоки.


Двойственность понятия сектора

А теперь быстренько вернемся к недавней теме о секторах. Ведь с точки зрения окружности, нумерованный сектор, тот что выделен зеленым, это набор состоящий из уникальных физических секторов с каждого цилиндра и головки. И каждый раз, в нумерации CHS (цилиндр, головка, сектор), он отображает один и тот же номер физического сектора, с координатой (x,y,1), где x- номер цилиндра, y – номер головки, 1 – первый сектор (только нумерация секторов идет с единицы, всего остального с нуля).
Возможно, именно на границе перехода с CHS на LBA так сильно перемешались понятия логических\физических\блоков\секторов, ведь, как только появился дополнительный слой абстракции, пропала эта явная связь между сектором окружности и адресом, а его логический адрес перестал отображать физическое расположение.

Если вернуться к Advanced Format, при котором физический сектор больше логического, то по нашему “блинчику” это выглядит так:


Логический сектор 512 байт, физический 4096 байт

Теперь к сути выравнивания.
И если как-то сошлись звезды, и у вас “недоехал” раздел до 2048-го сектора (кстати, или любого другого, кратного 4 килобайтам, пусть даже 64-го), то ситуация будет выглядеть следующим образом:

Видно что 4k блоки файловой системы съехали на 512 байт относительно 4k блоков диска. Такая ситуация порождает дополнительные накладные расходы, когда при работе с одним блоком, диску, по факту, приходится оперировать двумя.

В утилите parted есть даже команда проверки выравнивания.

# проверяем 1 раздел на выравнивание по начальному и конечному сектору 
parted /dev/sda align-check optimal 1

/sys/block/device

sysfs – виртуальная файловая система, в которой отражены значения различных переменных ядра.

В директории /sys/block будут все Ваши блочные устройства, а в директории устройства и в файле stat – статистика работы с этим устройством. Для начала, поглядим на них.

/sys/block/$device/stat

Информация взята из документации, где также присутствуют значения “discard” для ядер 4.19 и выше. На текущий момент такие ядра по дефолту есть только в rolling-release дистрибутивах, и потому здесь их не включил, тем паче, discard-операции применимы только для SSD и thin-provision устройств.

Получив значения (например командой cat) мы сможем наблюдать 11 цифр, разделенных табуляцией. Каждый “столбик” отображает свое значение.

  1. read I/Os
  2. read merges
  3. read sectors
  4. read ticks
  5. write I/Os
  6. write merges
  7. write sectors
  8. write ticks
  9. in-flight
  10. io-ticks
  11. time-in-queue

read и write I/O – количество завершенных I/O операций.
read и write merges – значение увеличивается, при присоединении нового I/O запроса к запросу в очереди. (вспоминаем, например readahead из прошлой части)
read и write sectors – количество прочитанных или записанных секторов
read и write ticks – произведение времени нахождения и количества запросов ожидающих в очереди или суммарное время ожидания I/O за секунду, в миллисекундах. Так, если в 60 запросов, в среднем, ждут 30 миллисекунд, то значение будет 30*60=1800ms
in_flight – I/O отправленные драйверу, но еще не выполненные. Сюда не входят те запросы, которые стоят в очереди.
io_ticks – время за секунду, при котором устройство имеет в очереди запросы. Что-то вроде утилизации.
time_in_queue – По документации это read + write ticks, но на практике я заметил что такая арифметика не выходит.

time_in_queue
Я посмотрел в исходники ядра, но все равно не смог понять почему цифры таки не сходятся. Единственная догадка на текущий момент: это происходит из-за округлений подсчетов в единицу времени.
Эх, если бы я умел в С…

“Руками” эти метрики смотреть не очень информативно, а вот собирать системами мониторинга – очень даже.

/sys/block/$device/queue

В директории queue содержится большая часть интересностей.

Опять же, не хочется в тупую заниматься переводом документации, поэтому постараюсь привести только максимально полезные данные. Полный список в доках по ссылке выше. Также часть параметров есть в русских доках по redhat 6.

Итак, в директории /sys/block/$device/queue можно найти следующие файлы, cat’нув которые, получим значения:

add_random (RW) – (RW означает что параметр доступен для перезаписи, RO – только чтение). Забавно, но есть так называемая “энтропия диска“, которую используют для генерации случайных чисел. Этим параметром можно ее включать (1)\выключать (0).

physical_block_size (RO) – размер физического сектора на диске. Как видите, в названии параметра написано блок, то есть по-сути это размер сектора о котором сообщает нам диск.

logical_block_size (RO) – размер логического сектора диска.

max_hw_sectors_kb (RO) – несмотря на слово “сектор”, это максимальный возможный размер переданных за один запрос данных в килобайтах. Т.е. по-сути это максимальный размер чего? Надеюсь, вы догадались, это максимальный размер I\O.

max_sectors_kb (RW) – здесь как раз мы задаем ограничение на размер I/O. Я всегда по умолчанию наблюдал значение 1280 кб, но оно вроде может и варьироваться, но не знаю по каким критериям. Это значение, что логично, нельзя выставить больше чем max_hw_sectors_kb.

minimum_io_size (RO) – минимальный размер I/O. Ожидаемо, следует из размера логического сектора.

nomerges (RW) – объединение запросов. 0 – алгоритмы работают на полную катушку, 1 – только простые, 2- полностью отключено.

nr_requests (RW) – Число запросов чтения или записи в очереди. Если очередь переполнилась, процесс будет ждать ее освобождения.

optimal_io_size (RO) – некоторые устройства умеют сообщать оптимальный размер I/O для себя.

read_ahead_kb (RW) – размер упреждающего чтения (было в первой части цикла).

rotational (RW) – параметр, определяющий является ли диск механическим или нет. Если выставить значение вручную, то можно превратить обычный HDD в SSD для диска будут использоваться соответствующие оптимизации.

write_cache (RW) – режим работы write back (запись в кэш) или write through (мимо кэша ОС). Хоть значение и RW, его лучше не изменять, так как оно изменяет лишь видение ситуации со стороны ядра, но не диска. WriteThrough подразумевается тогда, когда кэшированием занимается другое устройство, например RAID-контроллер.


Грязный гарри (Dirty Pages)

Dirty pages – специальных механизм отложенной записи на диск, при котором хранящиеся в памяти данные помечаются “грязными”, то есть ожидающими записи на диск. По-сути, является одной из структурных частей механизма дискового кэширования. Учтем это, и пойдем дальше.

/proc/sys/vm/

По отработанной схеме, переведу только описание параметров имеющих корреляцию с темой работы дисков.

dirty_background_bytes и dirty_background_ratio – Отражает ограничение по количеству памяти с “грязными” страницами, превышение которого обязывает ядро начать сбрасывать страницы на диск. Может быть, соответственно задано жестко в байтах либо в процентном отношении от доступной памяти системы. Обнуляют значения друг друга.

Если что, “доступная память” не равно “вся память системы”. Доступную память, как и dirty pages можно пронаблюдать в /proc/meminfo.

grep -e "Dirty\|MemAvailable" /proc/meminfo

Подробнее про meminfo в доках редхат.

dirty_bytes и dirty_ratio – Это лимит на количество dirty pages которое не должно быть превышено. Так же, либо в байтах , либо в процентах от MemAvailable.

dirty_writeback_centisecs – время “протухания” dirty pages, это максимальное время, которое они могут хранится в памяти до сброса на диск. Указано в сотых долях секунды.

dirty_writeback_centisecs – как часто просыпается поллер pdflush, чтобы выполнить сброс dirty-bytes на диск.

Таким образом, dirty pages у нас имеют право без проблем накапливаться до значения dirty_background_ratio либо пока не истечет время их нахождения в памяти равное dirty_writeback_centisecs, после чего они начинают сбрасываться на диск. При этом они могут продолжать накапливаться, покуда не достигнут своего предела dirty_ratio.

Ррряяя!
На тостере есть вопрос на тему этих дёрти-ратио, и человек достаточно доходчиво с примерами объясняет как оно работает. А вот вопрошающий, родив, практически, новый мем “как правильно вычислять dirty_ratio”, вызвал у меня бурю негодования своими попытками парирования, лаконичными самоповторами, непониманием исчерпывающих ответов, и своим профилем дивопсика-смузихлёба.

laptop_mode – интересный режим, подразумевает что если на текущий момент ОС загружена на устройстве с аккумулятором и не подключена к питанию, то нужно использовать специальный механизм сброса dirty pages. Суть режима заключается в следующем: раз на первый план вынесено энергопотребление, то нужно максимально сократить время работы механической части диска – его вращения и раскрутки. Для этого категорически не подходит обычная логика работы сброса кэшей (описанная выше), так как она способствует “размазыванию” нагрузки на диск во времени. Следовательно, для компоновки и разнесения обращений к диску, сброс dirty pages производится только если диск уже находится в движении, например, после read i/o. Время жизни dirty pages возрастает до 10 минут (можно изменить). Присутствует много интересностей, типо возможности сильно задрать readahead или сменить частоту CPU. Подробнее, как обычно, в документации.


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


Доп информация:

Хорошая презенташка от Christoph Anton Mitterer, взято отсюда: https://www.dcache.org


]]>
https://blogs.nebulasrv.net/2019/04/rstfs-2/feed/ 1
Интересное за март https://blogs.nebulasrv.net/2019/04/interesting-march/ Mon, 01 Apr 2019 11:01:02 +0000 https://blogs.nebulasrv.net/?p=367 Кто бы мог подумать, но в знаменитом пакмане (или правильнее: пэкмане) у каждого преследующего вас привидения свой неповторимый AI.
Обладая простенькой логикой, цветные паршивцы очень неплохо умеют обступать бедного “колобка” со всех сторон. На русском статья тут.


Милый и очень круто нарисованный комикс под названием перчик и морковка Pepper and Carrot. Действие происходит в мире, очень похожем на “Плоский Мир” Терри Пратчетта, а главная героиня и другие перонажи на конкретную повесть “Творцы заклинаний” (Equal Rites). Мне очень приглянулась рисовка и внимание к деталям.


Это поначалу может показаться диким, но все популярные ФС имеют файловый атрибут, в котором хранится ссылка по которой был скачан файл.
Весьма интересно ознакомиться.


Хана-Монтана линукс. Он существует! Причем уже много лет.
Хотя чему удивляться, если есть RebeccaBlack OS… Которая работает только по пятницам.


Неплохие комиксы на программистскую тематику.


На сайте NASA есть интерактивная карта солнечной системы с актуальным положением большого количества небесных тел, включая искусственные спутники. Интересненько полетать.


Неожиданно открыл для себя такую вещь как текстовые квесты (более продвинутый термин – интерактивная литература). К сожалению, еще не успел как следует изучить вопрос, но, по крайней мере опробовал местную классику “Дядя, который работает в Нинтендо“, открыв все концовки.
Вполне очевидно, что отчасти из-за свежести жанра, отчасти от специфики, но большинство произведений пишутся начинающими мастерами пера и много ожидать от них, думаю, не стоит. Тем не менее, можно заметить некое сходство с инди-играми, когда сам концепт произведения оказывается достаточно новым и необычным, из-за чего вызывает гораздо больше интереса чем классическая “линейная” проза.

Собственно, релевантные ресурсы:
kril.ifiction.ru
ifhub.club
instead-games.ru


]]>
Интересное за февраль https://blogs.nebulasrv.net/2019/02/interesting-february/ Thu, 28 Feb 2019 06:51:36 +0000 https://blogs.nebulasrv.net/?p=178 Мой первый пулл-реквест (на битбакет, так уж вышло), принятый в мастер! Касался он, правда, не кода, а орфографии, но все равно, настоящий вклад в открытое программное обеспечение. 19.02.2019 пришло обновление через F-Droid, уже с моими фиксами. Круть!

На этой волне даже форкнул шаблон мониторинга метрик с ИБП для Zabbix на гитхабе, и доработал под свои нужды.


Снова на тему слежки в интернете. Насколько вы анонимны?

Наведите чтобы увидеть спойлер…

Способов идентифицировать вас – миллион и одна штука. Легко убедиться здесь.  В разделе WebGL, вероятно, узнаете собственную видеокарту. WebRTC покажет внутренний айпишник. Canvas fingerprint докажет, что выделить Вас среди остальных – совсем не сложная задача.


Выпадающий терминал для KDE – yakuake. Подтягивает внешний вид konsole, по умолчанию выезжает сверху по нажатию клавиши f12. Крайне удобненько!


Смотрите как клево реализована история в браузере vivaldi!

Искать одно удовольствие, не то что в фигефоксе

Между прочим, разработчики Vivaldi – отчасти те самые люди, что делали любимую многими старую Оперу, ту что была еще на движке Presto. Сделан на WebKit (хром), open-source. Есть куча приятных фич, например цвет основного окна меняется в зависимости от превалирующего цвета favicon (как я понял), можно в один клик отключать картинки и анимацию, применять цветофильтры и включать интересные настройки для веб-разраба. Группировка кладок, разделение экрана. Отлично встают дополнения от chrome, а что еще нужно? Могут встречаться баги, так как проект развивается, и не имеет гор золота как, например, гугл. Но однозначно советую ознакомиться. Видос про фичи

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


Ну и пока что все.

]]>
Разбираемся с тормозной файловой системой, часть 1: теория https://blogs.nebulasrv.net/2019/02/rtfs-1/ Wed, 27 Feb 2019 05:34:23 +0000 https://blogs.nebulasrv.net/?p=182
Заметка
Эта статья достаточно непростая технически, и в ней запросто может быть много неточностей и ошибок. Сообщите о них пожалуйста, так как очень не хочется распространять дезинформацию. Сама статья будет исправляться и дополнятся по мере появления новых знаний.

Так уж получилось, что я любитель пробовать все самое новенькое и продвинутое. И когда я планировал миграцию домашнего сервачка с убунты на proxmox, то решил что хочу попробовать что-то экстравагантное. У меня уже был небольшой опыт пользования BTRFS и ZFS, да и LVM2, а хотелось попробовать все. Хотя история с развалившейся ext4, которой не помог журнал, еще не успела меня подкосить, я все же уже был повернут лицом к таким важным технологиям как soft-RAID, volume management, snapshots и, непосредственно, регулярный бекап. Так как я нищеброд, то в распоряжении у меня было очень мало дисковых ресурсов, а распределить место хотелось максимально эффективно. Пришлось как следует поколхозить!

Под систему и сервисы я смог выделить два однотерабайтных HDD и один на 500Gb. Логика подсказывает, с дисками разного размера много каши не сваришь: зазеркалить не получится (да и зачем зеркало из трех дисков?), сделать RAID5 тоже.

Но линкусовый софт-рейд mdadm работает с разделами – собственно чтобы собрать к примеру raid1 из двух дисков, нужно создать на каждом из них соответствующий раздел с меткой “Linux RAID” и уже из этих разделов дальше собирать зеркало. К тому же, это в моем случае было обязательно еще и просто потому, что загрузчику UEFI нужно увидеть на диске раздел fat32, на котором уже загрузить grub а потом kernel + initramfs. Если этот efi-раздел будет с неправильной меткой, то загрузчик его не воспримет.

В итоге собрать все это непотребство я решил таким образом:

Получился раздел /dev/md0 на 500 Гб, состоящих из двух зеркалируемых разделов sda2 и sdb2, а также раздел /dev/md5 на 1ТБ состоящий из трех разделов по 500 Гб: sda3, sdb3, sdc1.

К слову сказать, все эти sda, sdb, sdc самому mdadm’у до лампочки: при создании массива всю служебную информацию он записывает в специальный суперблок и при загрузке системы сам собирает все диски как надо. Независимо от уровня рейда, достаточно иметь суперблок от одного диска, чтобы знать к какому массиву он принадлежит, сколько в нем всего должно быть дисков и т.п.

На md0 (все же следовало бы назвать его md1) создана группа томов LVM sysvg, а в ней логические тома: rootlv (для самой системы) swaplv (понятно, раздел подкачки) и thinlv (специальный тонкий том).

На md5 также создана volume group с двумя томами, один тоже под системные контейнеры, один для пользователей.

Рядом из трех дисков был собран raidz, представляющий собой нечто похожее на RAID5, только средствами ZOL (ZFS on linux). На схеме его нет, возможно речь о нем пойдет в другой статье.

Все это было успешно развернуто и работало, хотя и попахивало тормозами. Обрастало контейнерами и виртуалками, как-то, в общем, жило. В то, как это работало без тормозов, вносил свой вклад еще и тот самый raidz, с которого были смонтированы файловые системы, на которых хранится, непосредственно, полезная нагрузка. Он как раз работает без нареканий, быстро и качественно.

Когда пришло время хоть сколько-нибудь значимых нагрузок на системные сервисы, и когда их просто стало достаточно много (они же все еще и логи пишут) то начались проблемы – отзывчивость сервака упала до совсем низких пределов – спасало только то, что не использовался swap, иначе бы система была практически в лежачем состоянии.

И я начал изучать теорию.

Продолжение на следующей странице

]]>
Обходим прокси на работе https://blogs.nebulasrv.net/2019/02/my-little-dissident/ Sun, 10 Feb 2019 03:05:56 +0000 https://blogs.nebulasrv.net/?p=117 Данный способ не несет в себе каких-то открытий, по-сути являет собой всего лишь использование универсальных средств. К тому же в вашем распоряжении должно быть некое очень редкое устройство!

Итак, что мы имеем?

  • Компуктер на шиндовс 10, без прав админа.
  • Выход в интернет через корпоративный прокси, естественно, жестко ограниченный (как и те, кто это ограничение придумал)

Что нам нужно?

  • Возможность подключаться по ssh к домашним серверам.
  • Возможность заходить на веб-интерфейс своих серверов.
  • Как следствие возможность загрузки и выгрузки файлов домой (не связанных с работой, зачем нам головняки)
  • Ну и неограниченный интернет как бонус 🙂

Собственно напрашивается самый простой вариант – почему бы не принести с собой обычный 3Г-модем? Но тут нас должно остановить несколько вещей:

  • Сразу становится понятно зачем мы его приперли на работу.
  • В системе он будет видеться, в том числе, как сетевой интерфейс и это тоже палево.
  • Чтобы соединения через него могли работать, должны быть изменены настройки сети в системе, маршруты. А сие нельзя делать без прав админа.

Хорошо, но что нам тогда вообще остается, если нам недоступны сетевые настройки? Но это не тупик.

Так уж случилось, что благодаря хорошему другу у меня в распоряжении оказался nexus 5 hammerhead прошитый в ОС под названием Ubuntu Touch. Её раньше пыталась пилить Cannonical, но когда оной стало плохо, перешла сообществу. Голубая мечта иметь полноценный линукс на телефоне стала совсем близка. Этим надо пользоваться.

Единственный способ, как мы можем увязать в нашей ситуации ПК и смартфон – это кабель USB. Cобственно, в Ubuntu touch для Nexus 5 используется ядро под андроид, вернее Cyanogenmod (ныне известный как lineage OS):

phablet@ubuntu-phablet:~$ uname -r
3.4.0-cyanogenmod-g2669fa0

Это все потому что в нем болтаются проприетарные блобы, позволяющие работать всяческим устройствам под которые нету свободных драйверов, например Bluetooth или Wi-Fi.

Поэтому успешно используем ADB – Android Device Bridge, позволяющий общаться с вашим устройством посредством USB – подключения.

Но славный adb оказывается не простенькой утилитой для получения доступа к shell на телефоне или для передачи на него файлов: это реальный комбайн, легко и просто работающий (без прав админа, да!).

PS C:\%path-to-adb% > adb.exe forward tcp:6100 tcp:22

Таким нехитрым образом, мы как бы соединяем удаленный порт на устройстве (телефон) и локальный порт на системе (виндовс) поверх USB-подключения.

> netstat -a | Select-String 6100
 TCP    127.0.0.1:6100         %COMPUTERNAME%:0        LISTENING

В системе открывается порт (в данном случае 6100), подключившись на который по ssh, adb нас перебросит на 22 порт телефона. Сам телефон нас не впустит, потому что он настроен пускать только по ключу. Это можно поменять, а можно сгенерировать ключ в puttygen и добавить в known-hosts на смартфоне. Есть в мануале.

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

Точек монтирования, внимание, оказалось 85 (!) штук.

phablet@ubuntu-phablet:~$ mount | wc -l
85

Корень и еще пачка путей смонтированы в рид-онли, скорее всего для сохранения целостности вашей ОС.

Разработчики предлагают следующий вариант установки ПО в ваш телефон: если для нужной вам программы есть специальная сборка и ее можно найти в местном магазине приложений OpenStore, то она ставится в вашу основную систему и, интегрируясь в оболочку, вроде как, успешно работает. Но если появляется потребность в неадаптированной программе, то ее установку следует устанавливать в специальный chroot-контейнер, избегая неожиданного поведения вашей системы.

Поэтому я зашел в shell на трубке, создал там контейнер и установил самый обычный прокси-сервер сквид.

# Создаем контейнер
libertine-container-manager create -i squid -n "squid proxy"
# Ставим в него кальмара (параметр -i Containername опущен, т.к. без него будет использоваться контейнер по умолчанию, а он у нас в принципе всего один).
libertine-container-manager install-package -p squid
# Заходим в консоль контейнера 
libertine-container-manager exec -c "/bin/bash"
# И стартуем squid
root@ubuntu-phablet:/# squid

На самом деле, этим вполне себе можно ограничиться, squid запустится и будет слушать запросы на порту 3128 и проксировать их вовне, будь то wi-fi или мобильная сеть (в моем случае вообще в openvpn).

Дело осталось за малым, как-то сделать так, чтобы браузер мог достучаться до этого самого порта и отправить запрос.

Тот же adb нам помощник:

.\adb.exe forward tcp:12345 tcp:3128

Скачиваем портабельный браузер и настраиваем на нем прокси на 127.0.0.1, порт 12345.

Пользуемся.

Как бонус, с помощью ssh туннеля можно нагло подключаться по VNC к домашнему компу (опять же, у меня был настроен openvpn):

phablet@ubuntu-phablet:~$ ssh -L 5900:127.0.0.1:5900 192.168.100.11 -l user "x11vnc"

На рабочем ПК:

.\adb.exe forward tcp:5900 tcp:5900

Через TightVNC подключаемся:

Собственно, такой вот способ диссиденствовать на работе!

]]>