Pull to refresh
50
0
Дмитрий @StraNNikk

Python / PHP / JavaScript developer

Send message
Вы не совсем меня поняли, да и наверное я объяснил не совсем правильно. Все почему-то набросились на 15ть секунд таймаута, хотя это тут вообще дело 10ое.

Основная проблема в эксепшенах типа AutoReconnect. Эти эксепшены происходят из-за проблем с сетью, не важно работаете ли вы на репликсете или шардированной конфигурации или же на одном сервере монги без ничего. Т.е. если драйвер pymongo в какой-то момент работы не получает ответ от сервера, то он райзит такой эксепшен. Один из частных случаев, как это воспроизвести — это отрубание primary в репликсете из 3х машин.

Проблема pymongo (и возможно MongoDB тоже) в том, что он не может проконтролировать, добавился ли документ в момент insert-а или же нет. Т.е. вы должны контролировать это сами в своем коде.
не, ну я к тому, что для начала надо понять почему нельзя сделать нормальный ресторе. Т.е. локализовать проблему — т.е. это проблема утилиты mongorestore или проблема схемы данных или проблема что дамп при помощи утилиты mongodump делается как-то неправильно. Т.е. один раз руками расковырять, разобраться, решить проблему, а потом автоматизация и пр.
По поводу бага 2 — вы какую версию mongo используете (с которой дамп снимаете)? случаем не 2.4? а в какую версию восстанавливаете — 2.6-3.0?
Просто интерсный баг был в версии 2.4. Вот например есть у нас коллекция со следующей структурой:

>db.entites.findOne()
{
        "_id" : ObjectId("54837b27bf0a898b0cbb3b78"),
        "path" : "/home/foo/bar/",
        "owner_id" : 42,
        "some_value_1" : 1,
        "some_value_2" : 2,
        "some_value_3" : 3
}

>db.entites.ensureIndex({"path": 1, “owner_id”: 1})


Т.е. поле path — хранит путь — строку произвольной длины. И вот, допустим, пользователь создает документ, где поле path длиной более 1024 символов:

>db.entites.insert({path: new Array(1025).join('x'), owner_id: 42, "some_value_1" : 1, "some_value_2" : 2, "some_value_3" : 3})


И все. Документ пропал. Выполняя запрос:

>db.entites.find({path: new Array(1025).join('x'), owner_id: 42}).count()
0

вы его не найдете. А все потому-то:
http://docs.mongodb.org/manual/reference/limits/#Index-Key-Limit
The total size of an index entry, which can include structural overhead depending on the BSON type, must be less than 1024 bytes.

То есть монга 2.4 разрешает документ создать, но не добавляет его в индекс, потому что поле path больше максимально возможной длины.
Кстати вот такой запрос-таки найдет пропавший документ:

>db.entites.find({path: new Array(1025).join('x'), owner_id: 42}).hint({_id: 1}).pretty()


А вот монга 2.6 такой документ создавать не разрешает и на моменте insert-а кидает эксепшен:

> db.entites.insert({path: new Array(1025).join('x'), owner_id: 42, "some_value_1" : 1, "some_value_2" : 2, "some_value_3" : 3})
WriteResult({
        "nInserted" : 0,
        "writeError" : {
                "code" : 17280,
                "errmsg" : "insertDocument :: caused by :: 17280 Btree::insert: key too large to index, failing test.entites.$path_1_owner_id_1 1037 { : \"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...\" }"
        }
})


В любом случае, я бы посоветовал бы вам делать mongorestore c ключиками --drop (чтобы на всякий пожарный удалить существующую коллекцию если она есть) и --noIndexRestore (чтобы при восстановлении восстановить без индексов, а потом их нагнать руками)
Дык я и не говорю, что «Монго — это зло, давайте дружно переходить на MySQL» :-)
Репликация и шардинг из коробки вообще как киллер фича монги, очень подкупают.
Про эти 15ть секунд, как я и писал выше в комментариях, тоже не так страшно.
Основная траббла, в подвисании воркеров, ошибках AutoReconnect и в том, что pymongo не знает, удалось ли ему создать документ или не удалось. А самому руками генерить ObjectId в коде на каждый insert — далеко нетривиальная штука.
Про общее затраченное время — в случае MySQL оно составляет в районе 18ти секунд на один проход количеством N (1..30) процессов по всем юзерам и практически не меняется при нарастани числа воркеров. В случае MongoDB оно составляет в районе 40секунд:
вывод консоли тут
(mongodb-performance-tests)[foo@ip-10-0-0-158 tool]$ python run_test.py --adapter mongodb --name mongodb_3_0_wt
Running «mongodb_3_0_wt» test
Prepare database

Create user documents
Full time: 97.6963868141
OK! Users were created!

Run test with 1 proceses
Test is finished! Save results

Full time: 145.417565107

Run test with 2 proceses
Test is finished! Save results

Full time: 72.3193061352

Run test with 3 proceses
Test is finished! Save results

Full time: 56.4604640007

Run test with 4 proceses
Test is finished! Save results

Full time: 43.2622559071

Run test with 5 proceses
Test is finished! Save results

Full time: 38.1150348186



Run test with 10 proceses
Test is finished! Save results

Full time: 40.7822709084

Run test with 11 proceses
Test is finished! Save results

Full time: 39.3015518188

Run test with 12 proceses
Test is finished! Save results

Full time: 37.2085850239

Run test with 13 proceses
Test is finished! Save results

Full time: 42.0286569595

Run test with 14 proceses
Test is finished! Save results

Full time: 40.7457239628

Run test with 15 proceses
Test is finished! Save results

Full time: 45.9798600674



Run test with 20 proceses
Test is finished! Save results

Full time: 44.4311590195

Run test with 21 proceses
Test is finished! Save results

Full time: 46.1173479557



Run test with 25 proceses
Test is finished! Save results

Full time: 43.7823390961



Run test with 29 proceses
Test is finished! Save results

Full time: 42.1524219513

Run test with 30 proceses
Test is finished! Save results

Full time: 43.6515491009

Finish!


По поводу обновления большого количества документов — ну вот не факт. Например, если ваша структура данных аля древовидная (каталоги, подкаталоги, подподкаталоги и т.п.), то без массовых обновлений не обойтись
Ненене, всего в реплик сете должно быть четное количество машин (минимум 3). У меня в тесте — как раз 3 машины. То, что третья машина — арбитр или просто ещё один secondary — это уже не принципиально. Если мощностей достаточно и хочется более надежной реплизкации, то делаем его еще одной репликой, если мощностей мало — то только под арбитр. При голосовании их голоса равноценны.
А в какой инфраструктуре смотрели? В Amazon/DigitalPcean/VPS или прям на железках?
У меня стабильно воспроизводится на Amazon-е для версии MongoDB 2.6.x (3ку не смотрел).
Кстати, а как проверяли? Просто описанная траббла с подвисанием особенно актуальна для процессов-демонов, которые держат коннект постоянно.

Но казалось бы и фик с этой проблемой, в конце концов 45сек-1минуту даунтайма может и можно себе позволить в случае аварии, в конце концов сервера тоже не каждый день вылетают. Меня больше смущают эксепшены типа AutoReconnect, дубликаты и неоднозначное поведение python-драйвера
Да на двух машинах отказоустойчивость тестировать смысла особо нет. Надо как минимум 3 машины для кворума, ну или любое нечетное число больше 3х.
Ни в коем разе не хотел этой статьёй сказать «как все плохо и близко не подходите».
Когда на рынке появляется новая технология, которая при этом еще и активно раскручивается, то хочешь-не хочешь по началу люди начинают исполюзовать её везде, где только можно и где нельзя. Смысл этой статьи как раз в том, чтобы поделиться сложностями и своим видением на то, когда эту базу лучше использовать.
Это очень-очень частный случай, когда отсутствие схемы действительно выгоднее, но возвращаясь к контексту MongoDB — большинство идеологов монги проповедуют отсутствие схемы несколько в ином ключе — в духе что мол код писать быстрое, не надо проектировать схему — самое то для стартапов. Поставил базу и побежали.
Собственно в статье основная претензия к монге в плане отсутствия схемы — что приходится логику приложения усложнять. И это действительно так. Без схемы и правда получается быстрее на каких-то ранних этапах развития некоторого абстрактного проекта в вакууме. Но в последствии это преимущество сводится на нет фиксом всяких нетривиальных багов. Да и самый частый кейс — программист уволился/заболел/ушел в астрал, и пади там разбери без схемы, что происходит в базе на 20 млн. документов. Конечно идеологи монги могут сказать — «смотри в код», но тут надо понимать что чтобы понять что происходит в базе нужно смотреть не только текущий код но и все ревизии кода с самого начала, потому что хрен его знает как там база менялась на протяжении жизни проекта.
Конечно можно использовать всякие mongoid или там mongoengine (в python), но зачем? Если в этом действительно появилась потребность, то лучше чтобы за целостность схемы отвечала БД, а не приложение. Так что на мой взгляд претензии к shemaless, описанные в статье, вполне себе обоснованные.
Но кейс, описанный вами, оправданный.
Это все ОК, но почему в тегах присутствует «Amazon Web Services»? :-)
Не совсем согласен с автором по поводу пункта «Документация». Точнее как — быть может документация на сайте MySQL и правда уступает документации PostgreSQL (хотя это весьма спорное утверждение), но вот в принципе в интернетах информационных ресурсов по MySQL в десятки раз больше чем по PostgreSQL. Взять хотя бы stackoverflow — 298,085 тредов против 35,063.

Ещё не указан один из весомейших на мой взгляд плюсов PostgreSQL — это PL/SQL. В MySQL-е с этим все очень и очень плохо, и сами разработчики не стесняются признаваться в этом. К этому же пункту можно отнести специализированные геоиндексы, JSONB и т.п.

И отсюда по-моему не совсем правильный вывод в финале статьи. Я бы сказал так — если вы точно, знаете, что собираетесь использовать все эти специализированные фичи (в особенности PL/SQL), то выбор в пользу PostgreSQL — однозначен. В остальных случаях — выбор в пользу того, с какой из БД больше всего знакома команда. И про «серьезные амбиции» и «большой проект» — считаю вообще не аргумент. Опыт таких гигантов как Google, Facebook, VK, twitter, badoo показал, что на MySQL можно более чем успешно разрабатывать вполне себе «большие проекты».

P.S. К слову, коль в статье была упомянута percona с их собственными тулами, то помимо их решений так же есть весьма неплохие патчи от Google code.google.com/p/google-mysql/.
RPM собирается по спекам при помощи rpmbuild-а
Вопрос: как устроена система хранения и анализа логов в Badoo?

Насколько я знаю, для сбора информации по времени выполнения запросов вы используете Pinba, но это скорее к мониторингу и профилированию. Меня больше интересуют такие кейсы: например у некоторого юзера проблемы с тем, что он выполнил такие-то такие-то действия, а в итоге получил не то, что хотел, и надо разобраться, почему так получилось. Собственно, если вы ведете логи пользовательских действий, то как вы их храните и как осуществляете поиск по ним? Может быть используете какие-то специализированные решения или же просто пишете текстовые логи и потом grep-ете по ним?

У нас на проекте мы используем связку logstash + elasticsearch + kibana. Каждый из API backend-ов пишет логи в формате JSON в rsyslog, который переправляет их на специализированный сервер, где они парсятся logstash-ем и пишутся в индекс поискового движка elasticsearch. Проблемы большого количества логов решаются встроенным механизмом автоматического шардирования индексов. Для каждого запроса на nginx-е генерится некий уникальный идентификатор запроса, который затем проталкивается на API backend (если backend создает какую-то отложенную background задачу — то проталкиваем этот идентификатор в эту задачу), и потом через интерфейс kibana собираем все реакции системы на некий запрос по его идентификатору.
В корне не согласен с автором
Мой будущий коллега потом объяснил, что целью этого тестового задания было определить, как я буду работать в условиях жёсткой нехватки времени.

B зачем такое надо? Мне просто интересно зачем при поиске кандидатов делать основную ставку на стрессоустойчивость? Если в компании данная ситуация постоянного ASAP-а и дедлайна в порядке нормы, то это ни разу не круто. Очевидно, что в компании явно что-то не в порядке с менеджментом, и такого рода собеседование должно быть первым звоночком соискателю — а стоит ли вообще идти в эту компанию? Не, ну правда, нервы-то дороже. Да и решение, которое человек выдает в условиях неоправданно лимитированного времени, вряд ли будет хоть сколько-нибудь поддерживаемым и расширяемым. Непонятно зачем это надо компании, если она занимается более-менее серьезными проектами, а не клепает сайты-однодневки?

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

Единственное с чем я могу согласиться с автором — это нафиг не нужные логические задачи аля «канализационные люки», «как сдвинуть гору Фудзи» и пр. По-моему даже Google, который ввел моду на них, уже признал бессмысленность такого подхода.
В остальном же мне кажется автору не следует путать кислое с пресным — наследование через прототип и замыкания это как бы основы основ. Как же вы код пишете, не зная этих вещей? Взять вот хотя бы замыкания — если вы будете копаться во внутренностях большинства JS-фреймворков, то там сплошь и рядом замыкания. А ведь если вы позиционируете себя как javascript ninja, то заглядывать под капот так или иначе придется.
И вот как раз-таки не соглашусь, что с ростом числа библиотек все эти знания теряют смысл — зависимость совершенно обратная. Чем больше библиотек, тем лучше человек должен уметь ориентироваться в том, что у них происходит под капотом. Иначе можно всю жизнь быть jQuery-программистом и под любую задачу 2+2 искать плагин.
Я имел ввиду именно что полнотекстовый поиск. Но это лишь предположение — я не копался во внутренностях, поэтому не могу сказать ничего конкретного. Может быть там делается полнотекстовый поиск, а может быть просто что-то на подобии like %...%. В любом случае если не выносить искомые значения в кастомные предопределенные поля, то «сложный» поиск по телу сообщения при больших объемах логов будет работать медленно — у нас по крайне мере так было
На самом деле MongoDB в случае LogAnalyzer позиционируется как альтернативное хранилище данных, а не как хранилище, которое даст improvement производительности. То есть по принципу «Вот у нас в проекте одна монга — зачем нам ещё MySQL? Коль уж используем монгу, то давайте и логи туда складировать.»
Объясняю основную причину, почему нас не устроил ни MySQL, ни MongoDB. Вот у нас есть, скажем, логи от сервера приложений, и разработчики обязуются слать логи в формате JSON, проталкивая при этом параметр user_id в каждом из логов. Благодаря этому мы сможем легко и непринужденно получить информацию об активности пользователя за прошедшее время. А такое зачастую очень даже надо. Например в случае багфикса. Так вот, в принципе в LogAnalyzer можно задавать кастомные поля для выборки логов, но так, как это так реализовано, нам показалось далеко не юзер-френдли. То ли дело в logstash, где данная задача решается на уровне встроенных фильтров. А если искать значение тупо по регулярке по телу message-а, то насколько я понимаю на уровне базы данных делается что-то на подобии Full-Text Search, и база просто настолько долго делает скан, что веб-интерфейс не дождавшись ответа умирает с ошибкой. И тут дело не в MySQL или MongoDB, тут скорее вопрос, идет запрос в индекс или нет.
Настраивали в основном по официальной документации logstash.net/docs/1.3.3/ и плюс немного по статьям с хабра
Какое-то непродолжительное время мы тоже использовали связку rsyslog+mysql+LogAnalyzer и в итоге оказались от неё в пользу rsyslog+logstash+elasticsearch+kibana.
Причины собственно две:
1. В LogAnalyzer уууужасный web-интерфейс. Это по-моему что-то даже более доисторическое, чем web 1.0. А ещё очень сильно раздражает popup, который всплывает на каждую строку лога в листинге.
2. MySQL из коробки банально не справляется при большом количестве логов и хитрой выборке данных. То есть банальный листинг и pagination всех имеющихся логов конечно не тормозит, но вот если надо выбрать например только логи nginx-а и только за определённый период времени, и только те, где встречается определенный user-agent, то тут и начинаются проблемы.

Связка rsyslog+logstash+elasticsearch+kibana решила эти две проблемы.
1. Logstash позволяет осуществлять парсинг и нормализацию логов. При помощи фильтров можно выдрать из логов по определенному шаблону конкретные кастомные значения для того, чтобы в дальнейшем добавить их в поисковый индекс.
2. Kibana няшка demo.kibana.org/, даст 100 очков форы LogAnalyzer-у
3. Elasticsearch — поисковый сервер на основе Apache Lucene. Масштабируемый из коробки. Одна из частных задач, которую он решает вкупе с logstash — организация хранения логов
1. Нажимаем на кнопку в Jenkins-е -> Делается git clone репозитория, нагоняется buildout (buildout т.к. проекта на python-е, в случае php для этих целей мы используем phing), билдится rpm-ка проекта и кладется в rpm-репозиторий
2. Даем команду salt-у (cм. SaltStack), который раскатывает собранную rpm-ку по серверам, вносит на каждом из серверов необходимые изменения в файлы конфигураций, после чего выполняется миграция БД и делается синхронный рестарт веб-серверов

Information

Rating
Does not participate
Location
Нижний Новгород, Нижегородская обл., Россия
Date of birth
Registered
Activity