LINUX.ORG.RU

Быстрое локальное блобохранилище

 , ,


0

2

Есть у меня, джентельмены, BLOBы, числом до миллиона. Размером примерно 36 кБ каждый. У каждого из них имеет свой идентификатор, а кроме того, каждый из них имеет одну или несколько категорий.

Надо мне делать следующее:

1) Уметь выгружать такие BLOBы на диск, потому как память не резиновая.

2) Уметь подгружать с диска BLOBы, соответствующие конкретной категории. С хорошей производительностью.

Я пытался сделать это через SQLite, подгружая BLOBы каждой категории через список IDшек, относящихся к ней (создавая временную табличку в памяти). Однако скорость получилась очень небольшой.

Можете ли что-нибудь посоветовать?


Уметь подгружать с диска BLOBы, соответствующие конкретной категории. С хорошей производительностью.

т.е. вся категория при этом будет целиком в памяти, вместе с блобами? Если так, то лучше делать самому.

Выгрузка и загрузка категории это простые операции линейного обхода индекса в памяти и чтения с диска соответственно. На диске будут кортежи типа (ключ, блоб), каждая категория свой отдельный файл. Осталось только решить когда какие категории должны быть в памяти. Можно начать с LRU.

mashina ★★★★★
()
Ответ на: комментарий от mashina

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

Yak
() автор топика

Не льсти себе - это даже и близко не bigdata.

Я пытался сделать это через SQLite, подгружая BLOBы каждой категории через список IDшек, относящихся к ней (создавая временную табличку в памяти).

Из этой фразы даже не понятно, хранятся блобы в sqlite или ФС.

tailgunner ★★★★★
()

man mmap. Он по-умолчанию в Линуксе ленивый, поэтому пока страничку не тронешь, её в памяти нет. Индекс сам придумай. Ну и там всякие madvise можно делать.

Если данные не статичны, то нагугли какой-нибудь простенький сишечный buddy allocator и используй его на области замапленного файла.

mv ★★★★★
()
Ответ на: комментарий от Yak

Ещё одна проблема — одной записи может соответствовать несколько категорий.

вот теперь нифига не понятно, т.е. не ясна структура твоих данных.

mashina ★★★★★
()
Ответ на: комментарий от tailgunner

Разумеется, в SQLITE.

CREATE TABLE 'docBlobs' ('docId' INTEGER, 'featureIndexes' BLOB, 'featureWeights' BLOB );

CREATE INDEX 'docIdIndex_docBlobs' ON 'docBlobs' ('docId' ASC);
Yak
() автор топика
Ответ на: комментарий от mashina

Есть куча текстов, из котороых выдраны некоторые фичи (для каждого текста создаётся 2 BLOBа: индексы этих фич - и их веса в тексте).

Каждому тексту присвоен 1 или более тег (это и есть категорий.)

Yak
() автор топика
Ответ на: комментарий от tailgunner

Списки документов, относящиеся к каждой категории, я храню в памяти, они там вполне помещаются.

Yak
() автор топика
Ответ на: комментарий от Yak

Не знаю насчет остальных, а для меня твоя задача так и осталась невнятной.

tailgunner ★★★★★
()
Ответ на: комментарий от Yak

Всё лучше, чем создавать миллион файлов, n'est-ce pas?

Не факт даже в случае однопоточной работы. И очевидно хуже — в случае многопоточной.

В sqlite, вообще, ключевое слово — «lite».

KRoN73 ★★★★★
()
Ответ на: комментарий от Yak

Есть куча текстов, из котороых выдраны некоторые фичи (для каждого текста создаётся 2 BLOBа: индексы этих фич - и их веса в тексте).

выходит, что доступ к блобам относительно рандомный, потому совсем хорошо не сделаешь. Ориентироваться стоит на скорость линейного чтения всех данных с диска. Для твоих объёмов это около 4-5 минут на типичном hdd. Если SQLite укладывается в это время, то стоит забить.

Либо стоит срараться сделать всю работу за один проход по блобам.

mashina ★★★★★
()
Ответ на: комментарий от mashina

Пока что доступ к 10K случайных документов из 1M получается примерно столько же по времени, сколько и чтение всех документов подряд.

Около 8 минут.

Yak
() автор топика
Ответ на: комментарий от mashina

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

Yak
() автор топика
Ответ на: комментарий от Yak

А для типичного hdd это пара минут. Т.е. если по 10к грузить, то есть смысл избавиться от SQLite и сделать всё на k/v хранилище типа bdb, gdbm или самописном.

mashina ★★★★★
()

Можете ли что-нибудь посоветовать?

А почему ещё никто не посоветовал Berkeley DB? Или какое-нибудь другое key-value хранилище. Tokyo Cabinet, Kyoto Cabinet считаются быстрыми.

i-rinat ★★★★★
()
Последнее исправление: i-rinat (всего исправлений: 1)
Ответ на: комментарий от Yak

Всё лучше, чем создавать миллион файлов

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

vtVitus ★★★★★
()
Ответ на: комментарий от vtVitus

мне просто интересно, чем лучше?

у ФС большой оверхед на мелкие файлы, медленные операции доступа, засорение кэша от 1M ненужных объектов (ФС она почти одна на всё).

хранение большого кол-ва блобов/клобов в базе данных, априори не правильная архитектура приложения.

это какой-то неправильный обобщённый стереотип, выросший из историй хранения больших блобов (мегабайты и более) в рСУБД разработчиками из мира офтопика.

mashina ★★★★★
()

индексы и прочие метаданные хранить как и прежде в sqlite, «blob» ы вынести в ФС как обычные файлы или в key-value базу а-ля berkeley db,gdbm/ndbm.

MKuznetsov ★★★★★
()
Ответ на: комментарий от mashina

у ФС большой оверхед на мелкие файлы, медленные операции доступа, засорение кэша от 1M ненужных объектов (ФС она почти одна на всё).

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

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


при чём тут офтопик не понял в принципе.

vtVitus ★★★★★
()
Ответ на: комментарий от Yak

Около 8 минут.

Что-то многовато. Я из любопытства проверил. SQLite, 1M записей, в записи ид и 40к рандомного блоба. Диск какой-то совсем обычный.

Выбираем 10к записей со случайным ид:

real	1m43.405s
user	0m1.528s
sys	0m1.404s

10к записей последовательно:

real	0m1.794s
user	0m0.836s
sys	0m0.584s

Deleted
()
Ответ на: комментарий от vtVitus

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

дававай не будешь заниматься обобщением особенностей работы с блобами какой-то определённой рСУБД на все БД? Твои обобщения неверны даже среди реляционок, не говоря уже про KV БД.

mashina ★★★★★
()
Ответ на: комментарий от Deleted

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

10к записей, сброшенный дисковый кеш и случайный доступ:

real	0m26.659s
user	0m0.008s
sys	0m0.236s

Кешированное:

real	0m0.119s
user	0m0.008s
sys	0m0.112s

Deleted
()
Ответ на: комментарий от Deleted

как-то слишком бодро вышло для обычного диска и случайного доступа. Мб 10к выбираешь не из всего 1M? Обычный диск это примерно 100 IOPS, т.е. нормальный порядок на 40гб будет около 100 сек.

mashina ★★★★★
()

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

note173 ★★★★★
()
Ответ на: комментарий от mashina

как-то слишком бодро вышло для обычного диска и случайного доступа.

разрыв шаблона. надо же, но ты продолжай хранить блобы в бд, а не править архитектуру.

такого же эффекта добивались храня по файлово в /u/id % 1000/id в рейзер 3.6, тоже теоретики сидели и доказывали, как хорошо хранить в бд, нет чтоб потратить 30 минут времени на проверку своего теоретизма...

vtVitus ★★★★★
()
Ответ на: комментарий от mashina

Мб 10к выбираешь не из всего 1M?

        for (i=0; i<10000; i++) {
                uint64_t off;

                off = (rand() % 1000000) * sizeof(buf);
                fseek(f, off, SEEK_SET);
                fread(buf, 1, sizeof(buf), f);
        }

нормальный порядок на 40гб будет около 100 сек.

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

$ sudo echo 3 > /proc/sys/vm/drop_caches 
$ time ./fetch_test 

real	0m42.409s
user	0m0.004s
sys	0m0.340s
$ time ./fetch_test 

real	0m0.131s
user	0m0.008s
sys	0m0.124s

Возможно, это префетчинг помогает?

Deleted
()

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

{ категория:[(имя файла, смещение блоба), ...], ... }
до какой нить БД если очень хочется.

ЗЫ можно даже сразу сгруппировать по файлам:

{ категория: {имя файла: [смещение блоба, ...], ... }, ... }

AIv ★★★★★
()
Последнее исправление: AIv (всего исправлений: 4)
Ответ на: комментарий от Deleted

fseek(f, off, SEEK_SET);

Ха-ха. Я _FILE_OFFSET_BITS=64 выставил, а fseek оставил 32-битный. Надо fseeko

real	1m18.051s
user	0m0.028s
sys	0m0.392s

78 секунд. Ну, недалеко от 100.

Кешированное:

real	0m0.133s
user	0m0.000s
sys	0m0.132s

Deleted
()
Ответ на: комментарий от Deleted

78 секунд. Ну, недалеко от 100.

около 120-130 IOPSов, уже нормально, подходит под хороший обычный диск

mashina ★★★★★
()
Ответ на: комментарий от vtVitus

разрыв шаблона. надо же, но ты продолжай хранить блобы в бд, а не править архитектуру.

ты какой-то тупой. Попробуй сначала разобраться о чём здесь вообще разговор.

mashina ★★★★★
()

У меня нечто подобное сделано для хранения данных с железки. Там категорий мало, поэтому я тупо в id отвел несколько бит под категорию. В итоге получилась таблица id, blob которая лежит в SQLite. Блобы жмутся, поэтому у них у всех разная длина, а городить самописный формат мне было лень. Вариант много файлов рассматривался, но очень неудобно для пользователя. Так одно измерение — одно файло, таскай как хош.

ebantrop
()

Храни в файловой системе. Имя файла - ID блоба, по директории на категорию, хардлинк если категорий больше одной. Делается это быстро и просто. Если будет тормозить - тогда начнёшь оптимизировать. Нормальные ФС (ext3, ext4, reiserfs) без проблем держат миллионы файлов даже в одной директории.

legolegs ★★★★★
()
Ответ на: комментарий от legolegs

Есть проблема: эта доброштука должна неплохо работать и под Windows, а NTFS с миллиона файлов таки начинает тормозить.

Yak
() автор топика

Быстрое локальное блобохранилище

только я прочитал «баблохранилище»?

q11q11 ★★★★★
()
Ответ на: комментарий от legolegs

Нормальные ФС (ext3, ext4, reiserfs) без проблем держат миллионы файлов даже в одной директории.

ext3

Ню-ню.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.