Блог:Виталий Филиппов

Материал из YourcmcWiki
Перейти к: навигация, поиск

Технические вопросы и вменяемые заметки от меня, Виталика.

У меня, конечно, уже есть блог Ljuser.gifsimply_a_man.

2024-04-25 Как покрасить лаком стол!

Внезапное! Для тех, кто давно хотел, но стеснялся спросить, как!

Уроки, вынесенные из покраски лаком стола! Что делать, если хочется получить идеальное гладкое зеркально-глянцевое покрытие. В интернете такой инструкции ни фига не нашёл…

  1. Кисточка должна быть ЧИСТАЯ. На финишный слой — НОВАЯ. Благо цена ей 100 рублей. Ибо каждая пылинка на кисточке — это будущий дефект на лаке.
  2. Для алкидного лака нужна кисточка с натуральной щетиной, для водной основы — с искусственной. Но лаком на водной основе лучше вообще не красить, так как идеальный результат получить сложнее. Да, воняет, ну и что! Зато идеальный результат получить гораздо легче! Ну и даже вкусно воняет, вообще-то ]:->
  3. Кисточку перед покраской промять и продрать рукой, чтобы все волосины, которые могут легко выпасть, выпали ДО покраски, а не в процессе.
  4. Яхтный лак FARBITEX PROFI WOOD разбавить на 30% уайт спиритом. Он тогда становится более текучим и легче прощает ошибки. Да, красьте именно яхтным лаком — идеал получить гораздо легче. Само собой, для получения глянцевой поверхности лак тоже должен быть глянцевым!
  5. Красить надо не таким уж и тонким слоем, лака на поверхности должно быть ощутимое количество! Чтобы было, чему натягиваться под действием поверхностного натяжения. Но, конечно, и слишком толстым слой быть не должен.
  6. Кисточку до почти сухого состояния в процессе покраски не вымазывать! Кисточка всегда должна быть мокрая. Как только с кисточки перестает «течь» лак на поверхность при движении, её надо мочить снова.
  7. На кисточку не надо давить, практически вообще! Если давить, из неё выдавливаются пузырьки. Если не давить, тоже лезут пузырьки, но только чуть-чуть и почти все сами лопаются.
  8. Красить равными мазками в одном направлении, вдоль волокон древесины, потом в идеале по каждой покрашенной полоске проходиться одним проходом по всей, чтобы выровнять покрытие.
  9. Сразу после покраски проверить на дефекты. В первую очередь — обязательно проверить на предмет отвалившихся от кисточки волосин! Аккуратно убрать их, поддев кисточкой же. Далее, где остались непрокрасы (почти сухие визуально места) — можно аккуратно докапать лака кисточкой, где пузырьки — можно их аккуратно полопать уголком кисточки. Хотя 99% пузырьков в норме лопаются сами, под действием поверхностного натяжения. Также обязательно проверить края, подтёки снять.
  10. Сушить надо ДОЛГО. Лак сохнет быстро, но окончательно застывает и превращается в «стекло» — очень долго (вплоть до месяца), особенно, если его слой толстый. Если в это время на него что-то поставить, это что-то в нём отпечатается. Возможно, есть какие-то способы ускорить процесс (обдувать горячим воздухом?), но это скорее актуально для условий покрасочной камеры, чем для домашних… Также, возможно, быстрее сохнут другие виды лака, например 2-х компонентный полиуретановый, но опять же х-з, надо тестировать.
  11. Как мыть кисточку: берем баночку, наливаем туда чуть-чуть растворителя, моем в нём кисточку, отжимаем об стенку банки и дальше вытираем кисточку насухо об картон, как бы крася его. Растворитель выливаем, наливаем чуть-чуть нового, повторяем. И так раза 4-5. Останавливаемся, когда растворитель уже почти не «пачкается» кисточкой. Итог — абсолютно чистая кисточка.
  12. Красить надо в 3 слоя, перед каждым слоем — обязательно шкурить! Особенно после первого слоя, так как после первой покраски «поднимается ворс» и дерево становится шершавее, чем было! Просто берём брусок и 320-ю наждачную бумагу, и шлифуем весь стол до гладкого матового состояния. Не волнуйтесь, после следующего слоя лак зальёт все микронеровности и стол опять станет зеркально-глянцевым!
  13. Каждый лак уникален! Любой новый лак в идеале сначала нужно запрототипировать — попробовать на ненужной детали. Особенно какой-нибудь «акриловый на водной основе», так как г#на среди них встречается гораздо больше.
  14. В идеале лак брать не прямо из основной банки, а наливать в промежуточную банку и красить из неё. Либо хотя бы использовать небольшие банки лака (по литру). Чтобы в лаке не накапливались пылинки с кисточки. Лайфхак: если вы разбавляете лак, это получится само собой!
  15. Перед покраской лак размешать палочкой, не взбалтывая, чтобы не порождать дополнительные пузырьки воздуха.

И да пребудет с тобой сила, Люк…

2024-04-25 Как покрасить лаком стол! 2024-04-25 00-36-57 image0.png

2024-01-22 Как чучуть переназначить клавиши на Xiaomi Mi Notebook

На Xiaomi Mi Notebook клавиатура отличная, почти идеальная.

Есть вертикальный ряд кнопок home/end/pageup/pagedown, ход клавиш приятный, стрелочки полноразмерные.

Единственное извращение - в углу клавиатуры стоит уникальная кнопка, которая ни за что не отвечает - по задумке ты на неё должен назначить что-то своё, Delete сдвинут влево, а Insert находится на Fn+F12. Ну и ряд вертикальный хочется home/pageup/pagedown/end, а не home/end/pageup/pagedown.

Но всё это очень легко поправимо.

# remap del -> ins
setkeycodes e053 110
# remap xiaomi key -> del
setkeycodes e072 111
# remap home end pgup pgdown -> home pgup pgdown end
setkeycodes e04f 104
setkeycodes e049 109
setkeycodes e051 107

И всё, каеф.

2021-06-09 Blender, OpenCL и Radeon ProRender

Есть у меня такая традиция — раз примерно в год с блендером и каким-нибудь радеоном трахаться.

В этот раз меня, в принципе, ждал успех. Получилось, во-первых, завести Cycles на OpenCL с Radeon RX 5500M (Navi 14) под Linux-ом, а во-вторых, даже получить расчётные показатели производительности! Расчётные — это немного быстрее нивидии GTX 1660 Ti и примерно на уровне GTX 1080 (да, она быстрее 1660), именно так, как и заявляется про данный GPU.

Бонусом завёлся и Radeon ProRender, но на конкретном демо-файле толку от него оказалось мало.

Итак, что я сделал…

→ продолжить чтение…

2020-08-22 Полноэкранная цветокоррекция, KWin и драйвер Intel Iris

Недавно на ноуте словил багов с Intel-овскими дровами, которые под Linux раньше были самые беспроблемные. Все полечил, хочу запротоколировать.

В общем, суть такая: я использую нетривиальный ноутбук Samsung, у дисплея которого очень упоротая цветопередача. В остальном ноутбук отличный, поэтому я попереживал, что цвета не очень и написал себе свой собственный цветокорректор для KDE — в виде эффекта для оконного менеджера KWin.

KWin вообще уже очень давно работает гораздо лучше Compiz-а и подобных, при этом умеет все те же самые эффекты. Как вспомню, как я прикручивал Compiz к Gnome 2 — о боже, какой это был глюкодром… А сейчас в KWin просто включаешь эффекты и всё — всё работает. Никаких тебе артефактов, никаких тебе падений.

Ну, собственно, KDE вообще на порядок лучше гнома. До выхода гномощели (Gnome 3 / Gnome Shell) они шли примерно ноздря в ноздрю и я переходил то на гном, то обратно на KDE, но гномощель отбросила гном назад лет на 20, поэтому теперь — только KDE.

В общем вот. Я использую собственный эффект для KDE, который делает полноэкранную ICC-цветокоррекцию через шейдер: https://github.com/vitalif/kwin

И вдруг на тебе! Обновляю систему, пересобираю свой плагин для KWin 5.17 (до этого был 5.14) и вместо эффектов весь экран в каких-то диких артефактах.

Чешу репу, лезу пробовать настраивать драйвер intel в Xorg. В общем все похождения описывать не буду — задолбаюсь — но прихожу к тому, что опция AccelMethod=UXA помогает, с ней эффект работает нормально. Успокаиваюсь.

Через некоторое время начинает проявляется ещё один баг — ИНОГДА подвисает отрисовка (картинка на экране). При этом можно переключиться в консоль (Ctrl-Alt-F1) и обычно даже переключиться обратно, и всё отлипает. Нахожу какой-то баг с GPU Lockup-ами, который кто-то обходил через опцию ядра i915.enable_psr=0, прописываю, подвисания уходят. Успокаиваюсь снова.

В итоге обнаруживается ещё более прикольная вещь — тормозит GTK. Если открыть любое GTK-приложение, например, Gimp, процесс Xorg начинает жрать 100 % CPU, а отрисовка дико тормозить. Особенно заметно это, если в Gimp сделать квадратное выделение, нагрузку на иксы создаёт ползущий пунктирчик выделения.

В общем, да — оказывается, GTK тормозит при AccelMethod=UXA. Выключаю AccelMethod=UXA, эффекты отваливаются обратно. Тогда решаю проверить под новым, тестовым, пользователем на том же ноутбуке — опа, обнаруживаю, что эффекты работают. Обнуляю свой конфиг KWin (kwinrc) и настраиваю эффект заново — опа, и под моим пользователем работает. Виновата была какая-то опция, оставшаяся от прошлых времён. Окончательно радуюсь — эффекты работают, GTK не тормозит.

Но не даёт покоя вопрос: а из-за чего вообще-то произошёл такой геморрой?

А оказалось всё просто. С обновлениями системы приехала Mesa 20, а в ней для интела включили по умолчанию новый драйвер iris_dri. Когда я это понял, конечно, сразу его отключил переменной окружения MESA_LOADER_DRIVER_OVERRIDE=i965. А отключил бы сразу — и всего вышеупомянутого бы не было :-).

В общем, вот такая ситуация. Iris всё ещё сыроват.

2020-08-14 mdadm shrink

Пипец, чуть с ума щас не сошёл. Вроде такая простая задача, а протрахался… :)

Дано: mdadm RAID1 (зеркало) из /dev/sda2 и /dev/sdb2, и это rootfs. Надо немного уменьшить разделы на диске. Ну, я думаю — что тут сложного:

  1. Перезагружаемся в initramfs (в Debian опция ядра break=mount), прихватив с собой busybox, resize2fs и sfdisk (и нужные им библиотеки), ну или делаем извращение типа такого, но перезагрузиться проще
  2. Уменьшаем ФС — resize2fs /dev/md0 <SIZE>K
  3. Уменьшаем RAID — mdadm --grow --size=<SIZE> /dev/md0
  4. Останавливаем RAID — mdadm --stop /dev/md0
  5. Меняем размеры разделов sfdisk-ом — sfdisk --dump /dev/sda > sda.txt; vi sda.txt; sfdisk /dev/sda < sda.txt; sfdisk /dev/sdb < sdb.txt — конечно, правильно их рассчитав по mdadm --examine /dev/sda сложением Data Offset + 2*Array Size (он в килобайтах).
  6. Запускаем RAID обратно — mdadm --assemble --scan

И вот на последнем этапе схема даёт сбой:

/ # mdadm --assemble --scan
mdadm: failed to add /dev/sdb2 to /dev/md/0: Invalid argument
mdadm: failed to add /dev/sda2 to /dev/md/0: Invalid argument
mdadm: failed to RUN_ARRAY /dev/md/0: Invalid argument

Причём я априори в курсе, что старые версии суперблока mdadm хранятся в конце раздела и изменение раздела не переживают — но в данном случае версия суперблока изначально 1.2, так что этой проблемы быть не должно.

Разгадка: эта тварь хранит размер каждого устройства в его суперблоке, и отказывается запускаться, когда реальный размер не соответствует сохранённому. Но есть способ его обновить — для этого на последнем этапе надо просто сказать mdadm --assemble -U devicesize /dev/md0 /dev/sda2 /dev/sdb2.

2020-01-14 Про "эффективные" "надёжные" микросервисы

На хайлоад в этом году не ходил, но услышал от коллеги про доклад … про вот этот вот доклад (на хайлоаде был он же):

https://2019.jokerconf.com/2019/talks/4wj9og0tij3wpxe3ourovr/

Вкратце: выходит дядька и говорит, что вот, в типичной веб-архитектуре с БД, memcached и stateless приложением очень большие затраты на маршалинг и демаршалинг [дядя реальный олд, раз сериализация у него маршалинг — но на это забьём]. Конкретно, до 85 % времени на это дело якобы уходит.

Поэтому они взяли Кассандру, засунули её прямо в Java процесс с приложением, и общаются с ней локально. Типа она распределённая, поэтому всё остаётся отказоустойчиво — она синхронизируется с другими нодами. И типа поэтому всё хорошо.

И вот с чего я тут охреневаю — это с 85 % затрат на сериализацию. Ну треш же какой-то! Ладно, ява, ну и что — https://github.com/fabienrenaud/java-json-benchmark - вот бенч разных библиотек JSON для явы. Самая быстрая даёт ~800 тысяч разборов и ~1.5 млн кодирований по 1 КБ в секунду, да и банальный Jackson не сильно отстаёт: ~500к / ~1 м.

Оказывается, 85 % это ссылка на статью: https://research.google/pubs/pub48030/. Статья тоже кривая. Не объясняя, ЧТО они тестировали, они действительно приводят цифры в оверхед сериализации в 45 % CPU и 85 % передачи лишних данных по сети и на основании этого агитируют за написание stateful бэкенда.

Если присмотреться внимательнее, там, правда, есть пометка:

Finally, our experiments in Section 3 show that if only part of the record is needed (10 %), RInK stores incur both extra CPU (46 %) and network (85 %) costs

For example, consider anapplication that caches the address books for all online usersin aRInKstore: for each user, the address book is stored as asingle key-value pair. If a request arrives from Alice to readBob’s phone number from her address book, all of Alice’scontacts must be fetched and unmarshalled, even thoughonly a small portion of the data is needed.

Б**дь! Ну так не надо так писать, чтобы для чтения 1 номера телефона приложение читало всю адресную книгу!!!

А к дядьке этому у меня один вопрос — он сам вообще что-то сравнивал? Или как всегда — «потому что можем»?

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

Ну ладно. «Ночью через лес», когда файловое хранилище на postgresql изобретал, тоже сначала бодрый был.

2019-02-06 Ночью через лес

Про доклад «Ночью через лес»… https://youtu.be/oMQLR-BhnJU

…по болоту на тандемном велосипеде с крыльями.

Ко мне тут (4.02.2019) однокурсник обратился с вопросом — типа он там щас работает в этой конторе. У них хранилище ФАЙЛОВ (30-50 тб, правда, в основном мелких) в Кассандре. Было то ли на 4 то ли на 8 серверах, диски в RAID-ах и поверх bcache.

Щас они этот кластер — внимание! — переместили в один сервер в докеры, оставив 16 дисков и 16 узлов (но убрав bcache), то есть теперь 16 кассандр в одном сервере (зачем? потому что так дешевле).

И вот короче встал вопрос: извне всего ~137 rps, объекты по <= 64 кб. 64кб*137 = всего где-то ~9 мбайт/с. Но при этом 16 дисков (HDD) загружены по самое не балуйся, на каждом чтение >= 100 мбайт/с. Вопрос: какогохуя?)))

Я его спросил — а на#уя в кассандре? — а он мне скинул ссылку на этот доклад — я открыл, начал смотреть и думаю — б#я! я же помню этого мужика!

И точно — он в 2012 году на highload рассказывал, как пи#дато файлы в postgres-е хранить: Highload-2012: Отчёт Виталия Филиппова#Спасение 6 млн файлов в условиях полного Хецнера / Даниил Подольский, Дмитрий Симонов (Setup.ru)

То есть типа сначала у них всё типа было просто в локальных ФС на двух серверах и синхронизировалось rsync-ом. Потом у них кончилось место на серверах, обход дерева директорий стал занимать очень много времени (8 часов), и они засунули файлы в postgresql с мастер-мастер репликацией.

Потом оказалось, что крупные файлы неудобно хранить просто в поле и они их засунули в блобы. А потом обнаружили, что блобы не попадают в репликацию! Ну и в целом, что всё это грузит постгрю. Тогда они вынули из postgresql всё, что было больше 64к и сунули в LeoFS. LeoFS — это такая попытка сделать Ceph, но очень хреновая.

Потом в leofs кончилось место, они попробовали добавить пару серверов… и leofs развалился на хрен. Они позвонили японцам-авторам, те их час послушали и сказали «простите, у нас кончилось время, до свидания».

Они с помощью видимо такой-то матери убрали добавленные сервера обратно — и оно опять работало, пока в leofs не кончилось место окончательно.

И тут… им пришла свежая мысль — засунуть это всё в aerospike. Засунули, на 8 серверов. И оно вроде опять заработало, да ещё и кластеризация автоматическая появилась. Про это был доклад уже в 2015 году.

Продолжение я знаю уже из вопроса однокурсника: Aerospike их, видимо, тоже не устроил и сейчас у них всё это уже в кассандре!

И вот этот дядя на Highload нам рассказывает, что Ceph, который под это идеален, они пробовали и им было медленно (да ещё и «ребаланс по каждому чиху, при котором кластер вообще нельзя эксплуатировать»)… Жопой чую — у них там и сеть была 1G, конечно, какой уж тут ребаланс…

И это всё на продакшне. Эпично. Там ещё гениальный вопрос в конце доклада есть — типа, а вот когда у вас кончилось место в 2 серверах — почему вы… просто не добавили ещё 2?))))))) — «а чо, так можно было?…»

Просто плотно проработав последние несколько лет с Ceph-ом слушать это мегаржачно! Это вот Ceph значит медленный, а кассандра, которая грузит все диски на 100 % — быстрая? И это у них ещё записи нет. Была бы запись, было бы примерно как с KVStore-ом, когда 80 % i/o занимал compaction (KVStore — это промежуточная попытка апгрейда хранилки в ceph между filestore и bluestore).

Бэкапы он тоже не делает — ну, типа, реплика же есть, да и откуда ещё 30 тб взять.

Третья серия — это второй доклад 2015 года — https://youtu.be/bOqSexPzSIE?t=1702 - в нём он уже не такой весёлый и просто рассказывает, как всё сложно с этими вашими файловыми хранилищами.

2018-06-27 Тестирование различных способов подключения SSD для Ceph

Задача: проверить гипотезу, что дешёвые SSD без конденсаторов можно подключать к системе через RAID контроллер с батарейкой для получения приличных IOPS-ов в Ceph (хотя это и извращение).

TL;DR: похоже, можно. IOPS-ы растут, а данные потерять не удалось. Но, конечно, это всё равно в некоторой мере стрельба в ногу, поэтому лучше просто купить недорогие Enterprise SSD с «advanced power loss protection» типа Micron 5100/5200.

UPD: Предложенную идею официально считать дичью, делать так не надо.

→ продолжить чтение…

2018-06-26 Пенсионная математика

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

Можно заюзать вот такую математику.

Если предположить, что:

  • пенсии субсидируются исключительно налогом с зарплат
  • средняя зарплата в стране 36000 руб
  • средняя пенсия в стране 14000 руб
  • количество пенсионеров 30 %
  • количество работающих 54 %

(все цифры взяты из интернетов, предположим что близки к реальности)

Тогда налог будет 14/36*30/54 = 21,6 %

Что характерно, весьма близко к реальности — реальность 22 %.

С одной стороны, правда, в среднем в реальности меньше, так как всякие льготы и «регрессивная» шкала налога. С другой стороны, вроде и ПФР субсидируется не только налогом с зп. Ну и сам очевидно жрёт — но поисследовать сколько он жрёт вопрос к исследователям типа ФБК ну и не знаю,… ФСБ там.

В общем, если так смотреть — то вроде:

  • по мне как-то не видно явной необходимости повышать возраст.
  • реальная проблема России в низких зарплатах. из-за низких зарплат и пенсии низкие.

А, да, и ещё соответственно накопительная система была в принципе тоже логичным решением проблемы — тогда типа убралось бы «усреднение» — у кого зп большая, была бы и пенсия большая (в теории), а у кого маленькая — была бы и пенсия маленькая. Но «получилось как всегда», так как у будущих бабушек в усть-задрищенске зарплата мизерная, а содержать их надо (ну в принципе логично что надо — вроде там это… помощь незащищённым слоям населения и всё такое). Вот и закопали её видимо.

Но по сути правильное решение — постараться обеспечить рост средней з/п по стране + оптимизировать нецелевые расходы ПФР (в России же живём, наверняка там их можно найти) + продолжать сколько-то субсидировать, наверное.

И ещё на самом деле сам этот налог — для мелкого бизнеса идиотский совершенно. Вот допустим ты ИП и работаешь на себя — платишь только фиксированный взнос 28000 в год в ПФР и 6 % налога с выручки.

А потом вдруг хочешь нанять ОДНОГО сотрудника и хренак!!! Сразу 43 % налога!!! Из которых 22 % это ПФР, 8 % прочее и 13 % НДФЛ. И ещё твои 6 % тоже ведь никуда не деваются.

Как-то это тупо, разрыв слишком огромный. Выходит либо никого не оформляй и работай в чёрную, либо оформляй на 10000 руб оклад и снижай ту самую среднюю з/п по стране, либо ищи где-то лишних 43 % бабла, что для мелкого бизнеса весьма проблематично.

Какой-то более мягкий переход должен быть, тогда мелочь повылезает из чёрных/серых окладов и небось и средняя з/п тоже повысится и фактические отчисления в ПФР…

2018-01-01 Всё-таки Redux - отстой

Всё-таки Redux кривоват.

Ну просто вот пример — есть там, не знаю, в приложении таблица «города», и надо сделать компонент подсказки городов — автокомплит.

Есть библиотечный автокомплит, поверх к нему, соответственно, надо дописать функцию, которая подгружает сами данные, чтобы дальше использовать в ДВУХ и более местах приложения БЕЗ копипастинга. Например просто два поля подряд даже вставить — ну типа город1, город2, или город юзера / город компании, или ещё что-нибудь.

Состояние у автокомплита — это:

  1. введённый текст (не обязательно совпадающий с выбранным значением)
  2. текущие подгруженные опции
  3. выбранное значение (но оно, по идее — не его личное состояние, а кусок тех данных, которые собственно редактируются в этом поле)

И действия:

  1. обработать изменение введённого текста (подождать 200мс, отправить запрос на подгрузку опций)
  2. обработать ответ на запрос подгрузки — залить опции в состояние
  3. обработать событие выбора опции — залить выбранное значение в состояние

Вопрос: КУДА всё это пихать?

Если Redux, то Redux говорит, что вроде как ВСЁ пихать в Store. Но Store глобальный => получается, что когда ты вставляешь в ДВА или более места свой компонент, ты должен:

  1. заставить его брать данные из РАЗНЫХ мест из стора
  2. заставить его отправлять Reducer’у какие-то ДРУГИЕ действия (по-другому именованные видимо — типа «field1_load_autocomplete», «field2_load_autocomplete»)
  3. потом ещё и заставить Reducer(ы) их обрабатывать

Получается, что по идее ради 1 и 2 ты, как минимум, занимаешься копипастингом mapStateToProps/mapDispatchToProps/connect(), а ради 3 ты ещё и копипастишь обработчик action’а, или подключение обработчика, возможно через combineReducers(), но всё равно тебе как минимум один action в нём придётся как-то переопределить — чтобы значение-то итоговое сохранять туда, куда нужно.

Вопрос: НА#УЯ всё это надо?

Если с голым React’ом ты просто все эти обработчики ляпнешь прямо в компоненте, и стейт будет там же, а значение наружу будет передаваться колбэком.

И в этом случае чтобы повторно использовать компонент ты как бы да, просто напишешь <CityAutocomplete value=... onChange=... />.

Не, я понимаю, что ВРОДЕ типа кажется круто полностью отделить работу с данными от рендера, ВРОДЕ типа круто при серверсайд рендеринге (подгрузил состояние и продолжил с того же момента), при извращениях типа живой отладки с сохранением состояния при изменении кода…

Но если при этом теряется переиспользуемость компонентов — это какое-то фуфло.

Короче, резюме: React, похоже, надо юзать голый, БЕЗ Redux’а.

2017-12-14 История одного просветления, произошедшего пару лет назад

Надо запротоколировать — прикольная история.

Когда я на это напоролся, у меня было, собственно, открытие — я полностью прочувствовал, что PHP по дефолту не умеет обрабатывать 2 параллельных запроса от одного юзера.)))

Суть такая: в PHP сделано тупое, но надёжное решение для исключения параллельной записи данных одной сессии двумя процессами — сессия тупо блокируется на весь период от её открытия до закрытия. А открывается она обычно в начале запроса — а закрывается в конце.))

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

Оно понятно, зачем сделано — если не блокировать, то что окажется в итоге в сессии — неизвестно — два процесса могут писать в сессию параллельно и один может перезаписать данные другого. И оно обычно как бы не страшно, так как да, действительно сайтики редко кто так насилует, а если и насилует, то типа нефиг же — типа, тоже мне кулхацкер, у нас тут и так 100500 юзеров параллельно, а ты ещё и свои запросы хочешь в параллель пускать, падла?!

И видимо, когда народ в PHP переключает сессию на redis и говорит, что всё стало «летать» — летать оно начинает именно потому, что redis хранилище сессий в пхп не делает блокировку — не то что это его фича — просто не умеет оно в блокировки :)

А вот теперь история, как я на это напоролся:

Ставил я VisualEditor (визуальный редактор для MediaWiki) и хотел его подружить с нашими правами (IntraACL). Для справки — в VisualEditor википеды же тоже прилично извратились — конфигурация там такая — сама вики на PHP, но рядом, чисто для VisualEditor’а, на сервер ставится node.js.

В котором выполняется parsoid, служащий бэкендом к VisualEditor’у. Parsoid — это частично переписанный на js парсер медиавики — полностью не осилили и не осилят никогда, уж больно там говнокода много на него завязано.

И запросы идут через такую жопу: браузер -> PHP -> node.js -> (а дальше нода же хочет получить текст страницы, которую правишь) -> обратно запрос в PHP.

И по дефолту на втором запросе к PHP они его сессионную Cookie ему обратно не передавали. Соответственно, у нас из-за прав доступа отредактировать страницу не удавалось — но зато эта конструкция вообще работала! :)

А когда я включил передачу куки юзера на этом запросе, чтобы нода читала текст страницы с учётом прав — вся эта конструкция стала радостно повисать. Я чуть башку не сломал, а оказывается, это была как раз блокировка сессии. Второй запрос же «вложен» в первый и запускается в той же сессии => 2 ждёт, пока кончится 1, а 1 ждёт, когда закончится 2. Дедлок.

Вот тогда у меня и случилось просветление.))

А после внедрения в медиавики неблокирующей работы с сессией, естественно, попёрли гонки и стала иногда отваливаться авторизация. Причём, почему-то, в том числе при вызове из скрипта репликации, который вообще однопоточный — там до сих пор гонка бывает, я так и не понял пока, откуда она там — для обычных-то юзеров поправили, конечно.

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

Короче: какая-то, с*ка, светлая голова в SemanticMediaWiki впилила для пересчёта какой-то очередной внутренней хрени обработчик очереди. Стандартной медиавиковской очереди — есть у неё в ядре очередь задач, и можно туда свои задачи пихать.

Но так как стандартная обработка заданий идёт в том числе потихоньку в конце каждого запроса, после отдачи страницы юзеру (ну, типа, чтобы работало даже там, где демона не запустишь) — эта, с*ка, светлая голова решила, что это же будет тормозить! И реализовала обработку самого задания через дополнительный запрос с сервера на самого себя, к URLу который фактически обрабатывает задание.

И оно как-то большей частью даже прокатывало… пока пользователь не открывал 2 вкладки одновременно — после чего висло нафиг 2 процесса сервера, а после N повторов висли все доступные процессы сервера и вики переставала отзываться. Причём все такие спокойные — загрузки CPU нет, никто ничем не занят, а вики висит — все в дедлоках.

Сами википеды на свои сессии тоже вроде потом напоролись, но уже после меня (после 1.26) — и то ли в 1.27, то ли в 1.28, вроде, переосмыслили своё поведение.

2016-09-23 Thin RAID5

Блин. А есть в Linux’е что-нибудь такое, чтобы сделать RAID5, но без необходимости полного resync’а? То есть что-то типа thin provision, чтобы блоки под RAID выделялись по запросу. В идеале — чтобы оно при этом поддерживало извращённые схемы расположения, то есть например 3-дисковый (2 данные, 1 чётность) рейд на 4-х дисках 3+3+2+2 тб.

Это кстати очень даже возможно — 3+3+2+2 нарезать на 6.66 тб RAID5! Схема такая: сначала кладём по 2тб на первые 3 диска, остаётся свободных 2*1тб и 1*2тб, кладём на них ещё по 1тб, остаётся 1тб свободный. Дальше забираем 0.33тб из первой группы с 1-го диска и 0.33тб из второй группы со второго диска и перекладываем на свободный 1тб, и на освободившееся место дописываем новую группу 3*0.33тб.

То есть вот так схема выглядит:

111422333
114222333
111222
333214

Вот. ceph так умеет, но он сетевой и распределённый, локально не поюзаешь. ZFS… «thin raid» умеет, но не умеет его расширять — то есть ещё диск не добавишь.

А с LVM, например, нельзя так извратиться?

2016-09-08 Тестирование скорости дешёвого SSD Silicon Power Slim S55 120Гб

Спойлер: Чтение приличное, а вот скорость записи — не очень (устоявшаяся 95 Мб/с).

Отчёт о реальных скоростях данного SSD. Тестировал утилитой fio, под Linux. Глубина очереди везде 128, планировщик noop, слияние запросов в очереди для теста отключено. При снижении глубины очереди производительность сильно проседает; ну, так и не надо её снижать.

  1. Последовательное чтение в идеальном случае (блоками >= 256кб) — 550 Мб/с
  2. Последовательное чтение блоками по 4к — в среднем 190 Мб/с, но прилично колеблется в пределах 170—280 Мб/с
  3. Последовательное чтение блоками по 8к — 370 Мб/с; по 16к — 450 Мб/с; по 32к — 500 Мб/с; по 64к — 530 Мб/с; по 128к — 540 Мб/с. Тут уже все цифры абсолютно стабильны, не колеблются.
  4. Случайное чтение блоками по 4к — 170 Мб/с (~41000 iops), тоже колеблется в пределах 120—220 Мб/с.
  5. Случайное чтение блоками по 8к — 305 Мб/с. По 16к — 340 Мб/с. По 32к — 380 Мб/с. По 64к — 440 Мб/с. По 128к — 510 Мб/с. По 256к — 535 Мб/с (это уже фактически последовательное чтение, а не случайное). Тут скорость опять стабильна, практически без колебаний.
  6. Есть «псевдо-SLC кэш». Последовательная запись первых 2.4 Гб блоками по 4к — 244 Мб/с. Крупными блоками (>= 256к) — 490 Мб/с.
  7. После 2.4 гб запись устаканивается на уровне 95 Мб/с, независимо от размера блока (SLC кэш кончается).
  8. Скорость случайной записи абсолютно идентична скорости последовательной записи.
  9. Скорость записи сохраняется постоянно, в том числе после полной перезаписи всего диска без TRIM.
  10. 30 секунд простоя достаточно, чтобы SLC кэш сбросился и запись вернулась к 490 Мб/с.

Наибольший «физический смысл» имеют случайные чтение/запись блоками 4к (стандартный размер блока ФС как в винде, так и в линуксе), а также последовательное чтение/запись блоками по 16к (так будет, если программа читает по 4к, а драйвер будет объединять соседние запросы), ну либо уже максимальными блоками (если программа копирует данные крупными блоками).

В общем, с чтением всё ок, но огорчает устоявшаяся скорость записи, 95 Мб/с — для SSD мало. Хотя, наверное, за эти деньги ожидать чего-то сильно лучшего и не приходится.

2016-09-07 ФС для флешек

Давно уже люблю на всяких мелких/тестовых серверках / с флешек монтировать. Удобно — места под rootfs много не надо, а скорость чтения — что случайного, что последовательного — вполне адекватная.

Другое дело, что случайная запись с обычными ФС типа ext4 очень медленная, флешки — это не SSD, гигагерцовых контроллеров и гигабайтов оперативки у них внутри нет — потому и Translation Layer внутри тупой, всё, что он обычно умеет — это «открыть» (стереть) и держать «открытыми» 2-3-4 блока стирания (обычно по 2 мб) и поддерживать в них последовательную запись. То есть, случайную запись мелкими блоками флешки не переваривают вовсе — iops на запись при этом обычно ограничивается 3-4 запросами в секунду.

Стандартно это решается лог-структурированными ФС, которые никогда не перезаписывают файлы «на месте», а всегда дописывают новую версию «в конец», одновременно постепенно освобождая место от старых блоков «в начале». То есть такие ФС чем-то похожи на кольцевой буфер :). И такие ФС под linux есть, я их ещё раньше уже тестировал: ubifs, jffs2, yaffs, logfs, nilfs2… фиг кстати знает почему, но в прошлый раз я почему-то остановился на ubifs, хотя она (как и jffs2, и yaffs) предназначена для MTD (голой флеш-памяти, не блочных устройств) и монтировать её одно извращение, и после краша она ещё не восстанавливается потом.

На самом деле из этих лучше брать nilfs2 — вроде самая живая и для блочных устройств подходит. Правда есть у неё как минимум один «нюанс» — на пустой ФС можно получить ошибку «нет свободного места», потому что она защищает (отказывается удалять) часть недавно созданных снапшотов. Время защиты вроде бы задаётся параметром `-o pp` при монтировании, но что-то я даже с pp=1 эту ошибку всё равно время от времени (при интенсивной записи) получал. Да и в общем в стабильность её работы у меня, честно говоря, особой веры нет. Экзотика, в общем.

Ещё отдельный юмор — это самсунговская F2FS (Flash-Friendly FS). Фиг знает, в каком она месте friendly и зачем она вообще создана — случайную запись она не ускоряет вообще.

Вот… некуда казалось бы податься любителю флешек. Но вчера возникла у меня идея — есть же btrfs! А в нём cow по дефолту для всех данных! Это ж как раз то, что нужно! И популярная, и по стабильности — не ext4, конечно, но я думаю уж точно получше экзотических nilfs’ов.

И таки точно! Берём обычную флешку (5 мб/с скорость последовательной записи), бенчмаркаем случайное чтение+запись блоками по 4-16кб (с помощью fio, в 8 потоков). Получаем суммарно (чтение+запись):

  • ext4=7.15 iops
  • f2fs=7.38 iops
  • nilfs2=160.8 iops (лог-структурированная ФС)
  • btrfs=128 iops (круто, почти не хуже чем nilfs2)

Короче всё, я на флешках буду btrfs теперь юзать.

2016-08-27 Математическое наблюдение на тему MTBF и AFR

Есть такой параметр, заявляемый производителями жёстких дисков — MTBF (Mean Time Before Failure), среднее время наработки на отказ. Ясно, что он чисто маркетинговый, так как очевидно, что невозможно честно определить его для новой модели. И фигурируют там обычно миллионы часов, самое меньшее 800000 — аж 91 год с гаком.

И вот непонятно — а какого чёрта харды вообще мрут при такой оценке надёжности? :-) ну как же, он 91 год в среднем прожить должен?

Ответ кроется в математике. Есть более осмысленный параметр — AFR (Annualized Failure Rate), вероятность выхода из строя в течение года. По статистике Backblaze (кроме них никто её по ходу не публикует) реальный AFR у дисков Seagate и WD как минимум процентов 5-10, у некоторых «особо надёжных» моделей аж 25-28 %, и даже у дисков HGST не ниже 0,8 % (а в основном 1-1.5 %).

А давайте попробуем по AFR посчитать MTBF? Если предположить, что AFR диска не меняется со временем, то MTBF в годах = 1*(1-AFR) + 2*(1-AFR)² + 3*(1-AFR)³ + … (матожидание числа лет). Разворачиваем формулу дважды в сумму геометрической прогрессии (так как это по сути сумма геометрических прогрессий, начинающихся с 1… 2… 3… и т. п. членов), и получаем MTBF в годах = (1-AFR)/AFR². Можно записать это и наоборот, решив квадратное уравнение, и получить AFR = (-1 + sqrt(1+4*MTBF)) / (2*MTBF).

По этой формуле MTBF 800000 часов = 9,93 % AFR, MTBF 1400000 часов = 7,6 % AFR, MTBF 2000000 часов = 6,4 % AFR. А 1 % AFR соответствует MTBF аж 86724000 часов! То есть, в принципе, MTBF 800000 часов не так уж и много, так как на самом деле он означает, что 10 % дисков выйдет из строя в первый же год :-).

Упс. В вычисления закралась досадная ошибка — правильная формула MTBF в годах = AFR + 1*AFR*(1-AFR) + 2*AFR*(1-AFR)² + 3*AFR*(1-AFR)³ + … = AFR + (1-AFR)/AFR. Соответственно AFR = (MTBF+1 — sqrt((MTBF+1)²-4)) / 2.

И, соответственно, никаких впечатляющих % там не будет — 800000 MTBF = 1.08% AFR, 1400000 MTBF = 0.62% AFR, 2000000 MTBF = 0.44% AFR. Ну ладно, тогда да, MTBF — просто ничего не значащая маркетинговая цифра :). Даже 1.08% — абсолютно нереально реально, современные HGST так и живут. Но когда я это писал, было таки нереально.

UPD: Вторая версия формулы, по-моему, тоже была неправильной, но, что удивительно, численные результаты получились верными. Правильно так:

MTBF = 1*AFR*(1-AFR) + 2*AFR*(1-AFR)^2 + ... = Sum_{i=0..+inf}((1-AFR) * (1-AFR)^i) = (1-AFR) / AFR
1 - AFR = MTBF * AFR  <=>  AFR = 1/(1+MTBF)

По этой формуле MTBF 800000 часов = 1.08% AFR, MTBF 1400000 часов = 0.62% AFR, MTBF 2000000 часов = 0.44% AFR.

А, и ещё картина по идее может зависеть от распределения отказов — интуиция подсказывает, что вряд ли оно равномерное. Но сильно, наверное, это вряд ли повлияет, так как вот тут http://www.cs.cmu.edu/~bianca/fast/ есть статья, из которой видно, что, по-видимому, лет где-то до 5 каждый год вероятность отказа неуклонно возрастает, а потом даже немного снижается.


2016-08-21 Паттерн бэд блоков в ddrescueview

Короче прогнал ddrescue на своём сдохшем Seagate Constellation ES.3 3 тб (ST3000NM0033). Вот такая картина (ddrescueview):

Ddrescue1.png

Если поближе, то вот:

Ddrescue2.png

О чём нам говорит такой паттерн? Судя по всему, об одной полностью сдохшей головке. Если посмотреть на цифры, то становится чётко видно, что картина по всему диску следующая — в начале диска идёт 50мб читаемых, 50мб нечитаемых, потом 600мб читаемых, потом примерно 50мб нечитаемых, 100мб читаемых, 50мб нечитаемых и дальше так и повторяется — 600-50-100-50… 600мб ближе к концу диска (к центру пластин), на самом деле, превращается в ~265мб, но соотношение всё время сохраняется чётко — 12:1:2:1 (где-то 11.8, где-то 12.2, но суть одна).

Блина у этой модели 4, головок 8. Потеряна как раз 1/8 данных. Логично, что это как раз и должно означать мёртвую головку. Единственным непонятным для меня моментом был паттерн — я думал, раз головок 8, хард с них должен читать по порядку — 12345678 12345678 и т. п. Но тогда картина читаемых-нечитаемых областей выглядела бы как 7-1-7-1-7-1…, а не 12-1-2-1-12-1-2-1…, как у меня.

Ответ, оказывается, простой — вместо традиционной схемы диски сейчас применяют также схемы «Cylinder Serpentine», «Surface serpentine» и их комбинации. В моём случае это как раз «Cylinder serpentine»: 12345678 87654321 12345678 87654321…, и плохая тут, видимо, как раз 2-я головка: 1(2)345678876543(2)11(2)345678876543(2)1…

Такой вот получился «RAID 0» из одного диска — сдохла одна головка, а потеряется почти всё, так как все данные дырявые, максимальный размер неповреждённой области — 614 мб.

Интересные ссылки по теме:

2016-07-30 Корпус Aerocool - наедалово

Твою мать! Козлы! https://market.yandex.ru/product/9275336, https://market.yandex.ru/product/9275333 - написано, что безвинтовое крепление HDD, в отзывах кто-то подтверждает — да, безвинтовое крепление, да, удобно.

А там оно не то что безвинтовое! Там и винтового-то не очень! Схема крепления через дикую жопу. Какие салазки, вы о чём! Крепления хардов просто какой-то суперизвращенец придумывал:

  • два 3.5" в самом низу на винтах, вставляются со стороны материнки.
  • один 2.5" плашмя на отведённом месте + с ОДНОЙ стороны крепится винтами.
  • один 2.5" аж вертикально, крепится к панели внутри корпуса 4 винтами.
  • один 3.5" плашмя на отведённом месте под 5.25" отсеками и крепится винтами.
  • и один 3.5" прикручивается к специальной 5.25" панельке-переходнику, к ней же по желанию под хард лепится доп.вентилятор (если докупишь) и этот страшный бутерброд ставится в 5.25" отсек.

И ещё остаётся пара свободных 5.25" отсеков (нафиг они вообще нужны в 21 веке). ЖЕСТЬ.

Повёлся блин на описание товара. Заказал, теперь возвращать буду.

2016-07-21 Опа! В связи с законом о перс данных Seagate гарантии больше нет

За#бцааааа…

Гарантия производителя на диски Seagate Constellation ES.3 — 5 лет, но похоже, что теперь в связи с законом о персональных данных ей невозможно воспользоваться: http://www.seagate.com/ru/ru/support/russia-law/

Типа мы же иностранная компания, гарантийные запросы обрабатываем за рубежом. А они включают персональные данные.)). запретили обрабатывать персональные данные — вот и идите со своей гарантией в жопу в магазин, где покупали. :-))

Это у меня такой хард дуба дал. производство 2013, купил либо в 2013, либо в 2014, гарантия в магазинах обычно года 2-3, но главное чек не могу найти и не помню где брал…

2016-07-21 Helvetica Neue Condensed

Всегда считал, что Helvetica — это тот же Arial, а так как Arial не люблю, считал, что и Helvetica — отстой. Потом, правда, понял, что в мелких размерах Arial выглядит неплохо, но уже было не важно).

А недавно открыл для себя, что Helvetica Neue ещё бывает Condensed и вот это классный шрифт. Правда, в теории платный, но кого ж это волнует на самом деле, он настолько похож на свободный Roboto Condensed, что фактически можно юзать его (хотя субъективно гельветика чуть поаккуратней). Ещё один похожий шрифт — PT Sans Narrow (но он-то точно покривей). Вот все три:

Condensed.png


Посередине Helvetica, сверху Roboto, внизу PT Sans.

2016-06-27 Минутка юмора nodejs

Задача: вытащить часть пути до первой части, содержащей glob-паттерн (glob — это стандартные шаблоны имён файлов: * ? [] {}).

Решение: один регэксп, да? Нееееет!

Для node.js есть целая библиотека glob-parent. Очень содержательная:

var path = require('path');
var isglob = require('is-glob');
 
module.exports = function globParent(str) {
	str += 'a'; // preserves full path in case of trailing path separator
	do {str = path.dirname(str)} while (isglob(str));
	return str;
};

Не, ну наверно там парсинг сложный, да? Давайте посмотрим, как написан is-glob:

var isExtglob = require('is-extglob');
 
module.exports = function isGlob(str) {
  return typeof str === 'string'
    && (/[*!?{}(|)[\]]/.test(str)
     || isExtglob(str));
};

Гм. Ну что ж, может вся хитрость в is-extglob?

module.exports = function isExtglob(str) {
  return typeof str === 'string'
    && /[@?!+*]\(/.test(str);
};

Это весь код этих 3-х библиотек, ну за исключением всяких README и package.json, конечно… которые там в 5 раз больше.

Alice-facepalm.jpg

« новейшие ‹ 20 более новых старейшие »