Diary Spirit @дневники: изнутри

четверг, 27 октября 2005

Администратор

10:50 И еще немного о ленте избранного
Кому интересно - формирование ленты происходит примерно так.



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

Затем у обнаруженных избранных выбираются записи, сделанные после даты Х. При этом проверяется еще и право доступа к кажой конкретной записи.

Наконец все это разбивается на страницы (учитывая выбранное число вывода для конкретного юзера).



В часы пик сервер, мягко скажем, не радуется.



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

29.10.2005 в 21:18

29.10.2005 в 21:18
Dr0n сервер - MySQL 4 / MySQL 5, протокол - соединения клиент-сервер, данные - собственно результат SQL запроса



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

29.10.2005 в 21:27

29.10.2005 в 21:27
ymik, странно, но ты сказал делать таблицы именно для постов и комментов. как тут получится брать ПРЯМО - я не пердставляю.

проще говоря - ты гонишь, чувак. сначала сказал одно, теперь говоришь совсем другое.
URL

29.10.2005 в 21:32

29.10.2005 в 21:32
.silent конкретно задачу скажи, какую страничку собрать - напишу SQL запрос.
URL

29.10.2005 в 21:34

29.10.2005 в 21:34
ymik немного не понял я про большие объемы данных и откуда они берутся.

А вот теперь лови мою мысль:

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

А вот что будет творится в соответствии с твоей стуктурой - это ужас.

Ну во-первых, вполне возможно, что у ОС просто не хватит файловых дескрипторов для открытия очередной таблицы (имеется ввиду MyISAM и все же немгновенное исполнение sql запроса). Затем ОС будет заниматься lookup`ми в свои системных таблицах, для того чтобы вычислить расположение файла с таблицей, проверять права доступа, открывать его, отдавать дескриптор процессу mysqld, потом закрывать. Это ж какой системный оверхед будет???
URL

29.10.2005 в 21:35

29.10.2005 в 21:35
ymik, ну, напиши просмотр избранного, раз уж о ней речь.
URL

29.10.2005 в 22:05

29.10.2005 в 22:05
Dr0n ок. отвечаю попунктно:



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



смотрим в голову и видим:

Идет обращение к базе - выбирается группа тех, кто есть в избранном у данного пользователя (с проверкой права на доступ к дневнику). Причем проверка шарашит по всей базе пользователей. Затем у обнаруженных избранных выбираются записи, сделанные после даты Х. При этом проверяется еще и право доступа к кажой конкретной записи.



Таким образом получаем, что только для того, чтобы составить список избранных нужно шарить по всей БД пользователей. Это раз. Далее нужно сделать выборку из постов, принадлежащих этим пользователям до даты X и отсортировать найденые записи в порядке добавления. Это два. Далее нужно (почему только на этом этапе?!) проверить права доступа к этим записям. Это три. И, наконец, выдать их. соответственно ни о какой выборке по ключам тут и речи нет - шерстится по полной БД потому что выбираются записи, сделанные после даты Х.



Теперь смотрим, что предлагаю я:

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



Теперь о данных.

Имеются ввиду тексты самих сообщений. К примеру моя френд-лента в чистом тексте в битовой кодировке занимает порядка 60-90 кб (в зависимости от активности участников, естественно без форматирования и всяких картинок - только текст). При пересылке между клиентом и сервером это превратится в полновесные 200 кб, тогда как сопроводительная служебная информация (выборки по другим столбцам и т.д.) - килобайт 30, не больше. Таким образом очевидно, что при создании моего "избранного" сервер более 3/4 всего времени потратит на пересылку текстов постов. А пока приём этого куска не закончен этот коннекшин не может быть разорван. Так же очевидно, что кол-во слотов для коннекшинов ограничено сверху какой-то цифрой. А когда забиты все слоты и новое соединение просто не может быть создано, то сервер нам и отдаёт сообщение про "попытайтесь через 20 секунд". Соответственно, если разгрузить пересылку данных, то с миру по нитке, но очередь реально идёт быстрее и время ожидания в ней сокращается.



теперь о количестве файлов:

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

29.10.2005 в 22:07

29.10.2005 в 22:07
.silent см. выше, кажется довольно подробно описал алгоритм.
URL

29.10.2005 в 22:56

29.10.2005 в 22:56
я предлагаю хранить данные об избранных прямо в записи самого пользователя в виде ключей, потому запрос френд-ленты будет выглядеть как выборка из объединения заранее указанных таблиц с одновременной сортировкой результатов и отсечением ненужных данных.

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

не врубаюсь просто, видимо я идиот :)

и еще больший идиот из-за того что не понимаю сути миллионов таблиц 8)))



прикольно было бы посмотреть работу в phpMyAdmin с такой базой.

базы так не строятся, поверь мне. я хоть и работаю с MSSQL больше чем с MySQL, но принципы реляционных баз данных представляю отлично.



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

29.10.2005 в 23:27

29.10.2005 в 23:27
.silent

> прикольно было бы посмотреть работу в phpMyAdmin с такой базой

О, не только у меня родилась такая мысль :)
URL

30.10.2005 в 00:02

30.10.2005 в 00:02
Neiru, сейчас он нам ответит, что профы phpMyAdmin не пользуются ;)
URL

30.10.2005 в 02:06

30.10.2005 в 02:06
ymik наблюдатели ждут продолжения
URL

30.10.2005 в 05:41

30.10.2005 в 05:41
ymik : пара миллионов таблиц - это пара миллионов подкаталогов в одном каталоге (верно для MySQL/UNIX). FS в UNIX'е не предназначена для быстрого поиска по такому каталогу.
URL

30.10.2005 в 05:43

30.10.2005 в 05:43
Dr0n : да, про системные таблицы я не подумал...
URL

30.10.2005 в 07:30

30.10.2005 в 07:30
интуиция подсказывает, что когда чего-то намного больше чем всего остального именно на этом "чего-то" и будет замедление.



миллион таблиц - это миллион операций открытия/закрытия файла ? :upset: тоже не быстрая операция кстати..
URL

30.10.2005 в 15:14

30.10.2005 в 15:14
Оранжевый Удав +1 :)

URL

30.10.2005 в 18:09

30.10.2005 в 18:09
не, ну предложение для каждого дневника создать таблицу, я бы еще понял, но на каждый пост/комментарий - наверно я тоже чего-то недопонимаю :)
URL

30.10.2005 в 20:21

30.10.2005 в 20:21
.silent

не понимаю сути миллионов таблиц

А кто сказал, что таблиц будет миллионы? Посчитаем? Допустим, человек написал за всё время 1000 постов, так чтобы по предложеному методу образовался хотя бы 1 миллион таблиц нужно 300000 человек + порядка 1000 таблиц некоторое кол-во отдельных таблиц для кэширования активных дискуссий, тобишь минус 1 человек из этих 300000.



tarkhil

пара миллионов таблиц - это пара миллионов подкаталогов в одном каталоге (верно для MySQL/UNIX). FS в UNIX'е не предназначена для быстрого поиска по такому каталогу.

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



Оранжевый Удав

миллион таблиц - это миллион операций открытия/закрытия файла?

Рассмотрим схему работы мускула с табличками: вот файл, мы храним там данные, мы читаем frm файл, грузим описание таблицы в память, читаем индексный файл, грузим описание, всё это сохраняем в куче. А теперь обращаемся к данным. Что происходит? Мучкул открывает файл данных, берёт данные, закрывает файл. Сколько обращений, столько и операций открытия - закрытия файла таблицы. Чтобы амортизировать данный эффект создаются синхронизированные дескрипторы файла, хранящие хэндлер файла. Но время жизни этого дискриптора - до закрытия соединения - соединение закрыто - закрывается файл. Итак, принципиально разница между 100000 обращений к одной таблицей и 100000 к 100000 таблиц - лишь в глубине кучи и во времени поиска файла в FS. Чтобы оценить разницу можно написать элементарный бенчмарк, который покажет, что на этих самых 100000 запросах производительность падает не более 20%. С учётом того, что отработка запроса на поиск по 100000 записей (поиск по 2м полям, одно - ключ, второе - варчаровое, выбирается поле, равное, к примеру "A") занимает бОльшее время, чем отработка 100000 запросов по 100 уже предварительно найденым таблицам в 3 РАЗА, то экономию на таком чуть усложнённом бенче я, лично, получил у себя на машинке в 80%. Вопросы?



Проверьте мои результаты, если так интиресно... И опять же - откуда вы взяли миллионы таблиц?
URL

30.10.2005 в 20:42

30.10.2005 в 20:42
ymik,



Зарегистрировано:

Пользователей - 104 421

Дневников - 79 867



у большинства больше 10 записей все же.
URL

30.10.2005 в 20:43

30.10.2005 в 20:43
ymik миллионы таблиц — экстраполяция твоего предложения держать комменты к каждому посту в отдельной таблице. там выше был пример увеличения числа таблиц за один средний день работы сервера.



> Допустим, человек написал за всё время 1000 постов

Положим, каждый десятый пользователь написал уже 1000 постов. Тогда таблиц с комментами будет 1000 постов с человека * (58000/10) человек = 5 800 000 таблиц.



Это если я дошёл до сути твоего предложения. Или же всё-таки одна таблица для постов, одна для комментов невзирая на ID юзера?





@дминистраторам:

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

Но вдруг поможет? ;)
URL

30.10.2005 в 20:57

30.10.2005 в 20:57
Neiru ну я же сказал выше, что пожалуй для каждого поста по таблице - черезчур, но вот штук 1000 активных дискуссий, которые ведутся в данный момент, можно было бы и вынести в отдельную БД, чтобы ускорить сборку тредов. Такое своеобразное кэширование данных. А для остального - следующая схема:



на один дневник - две таблицы

первая - для всех постов дневника

вторая - для всех комментариев ко всем постам дневника



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

30.10.2005 в 21:15

30.10.2005 в 21:15
ymik, ты реально не догоняешь. твое предложение на помойке лежит.
URL

30.10.2005 в 22:59

30.10.2005 в 22:59
Завтра будет запущена новая версия скриптов, работающих с лентой избранного. Может не все сразу учтено, но оно будет постепенно доработано и в результате должно работать в несколько раз быстрее.

URL

31.10.2005 в 04:20

31.10.2005 в 04:20
нос :hlop:

Ваша оперативность приятно удивляет)
URL

31.10.2005 в 10:36

31.10.2005 в 10:36
Neiru, спасибо ))

Оно уже работает с утра! По нашим замерам самый тормозной запрос выполняется в 5,3 раза быстрее, а сама лента избранного формируется в 2,5 раза быстрее. Это утром, на малозагруженной системе, когда было 1100 посетителей.



По нешему мнению при большой нагрузке разница должна стать более существенной. Пока здесь небольшое число людей - 2300. Посмотрим дальше.

URL

31.10.2005 в 10:48

31.10.2005 в 10:48
нос : хотя бы вкратце - что сделали?
URL

31.10.2005 в 10:48

31.10.2005 в 10:48
нос дык, что сделали то?
URL

31.10.2005 в 10:51

31.10.2005 в 10:51
При 2300 юзеров на сайте время формирования ленты моего избранного уменьшилось в 16 раз!

Что сделали — расскажут программисты. Идею выдвинул Dr0n, а реализовал gluker.



URL

31.10.2005 в 15:27

31.10.2005 в 15:27
В общем, задача была решена так:

Мы создали memory disk , положили туда таблицу с постами за последние 3 дня и делаем выборки по ней. Все апдейты идут параллельно в две таблицы: в большую и в 3-х дневную. Таблица в памяти периодически очищается с устаревшими постами. И все дела.
URL

31.10.2005 в 15:31

31.10.2005 в 15:31
Dr0n так вот в связи с чем ограничение в три дня на избранном :)
URL

31.10.2005 в 15:35

31.10.2005 в 15:35
Dr0n : хм. А temporary table не прокатила?
URL