Yvision.kz
kk
Разное
Разное
399 771 постов41 подписчиков
Всяко-разно
0
00:37, 27 июля 2011

Архитектура и история i-News.kz

Всем привет! Я долго собирался с мыслями и в итоге решился описать архитектуру своего сайта - i-news.kz. Но для начала немного истории.

В далёком 2008 году я, вместе с товарищем Сашей Малым (Prankster) делал многообещающий (и ныне покойный) проект - uno.kz и в его рамках нам очень хотелось запустить новостной сайт. Останавливал нас тот факт, что новости эти кто-то должен размещать на сайте. Т.е. нужен человек, который будет заниматься скучной монотонной работой (примерно так, как сделано на www.zakon.kz).

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

Прошло время и наши с Сашей пути разошлись не самым добрым образом, а чуть позже uno.kz умер. Я взял тот движок и развернул под именем i-news.kz на дешёвом shared-хостинге, где i-news.kz проживал до декабря 2010 года. За это время в базе скопилось более 300 тыс. новостей.

Изначально все новости целиком хранились в базе MySQL и для поиска использовался полнотекстовый индекс. Пока новостей и посетителей было мало всё было супер. Потом в один из выходных мой аккаунт отключили за большую нагрузку на процессор.

Здесь появилась первая оптимизация - тексты новостей я перелил в файлы, а для поиска стал использовать xml.yandex.ru. Из базы были удалены тексты и полнотекстовый индекс, таблица с новостями похудела с 2Гб до 800Мб, сайт задышал свободнее. Плюс кеши и прочие мелочи - можно жить.

Однако через примерно полгода хостер опять взбунтовался, заявив, что мой сайт тормозит весь сервер - ведь "в линуксе начинает тормозить файловая система, когда количество файлов в одном каталоге превышает 50 тыс., а у вас их 300 тыс.". И плевать, что файлы разложены по директориям - "мы сказали много, значит много". В этот момент тексты переехали из файлов в SQLite-базы, разбитые по файлам понедельно и по годам. Хранилище новостей и по сей день организовано в виде структуры DataStorage/2011/12.db - данные за 12-ю неделю 2011 года. К слову, это решение также подсказал Никита (правда, предложив за имя файла брать первые/последние 2 символа из md5($news_id)). За что ему низкий поклон.

В конце-концов, в ноябре 2010 года хостер безапелляционно попросил меня уйти, сославшись на высокие нагрузки. Всё, что мне оставалось - арендовать выделенный реальный сервер и разместиться там. Пока суть да дело проект несколько недель жил на моём компьютере, постоянно включенном и подключенном через 512кб/с канал Алма-ТВ. Потом он переехал на довольно слабую машинку с двухъядерным Athlon'ом и 2 Гб памяти.

Поскольку на своём сервере я сам себе хозяин, я смог использовать PHP 5.3 (на хостинге была версия 5.2), заменить MySQL на Percona Server, для поиска использовать Sphinx. Неизменным осталось лишь хранилище - это SQLite, разбитый по неделям.

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

Последней оптимизацией, резко повысившей скорость работы сайта в целом и практически каждой страницы в отдельности стал практически полный уход от MySQL (Percona Server) в пользу моего хранилища на SQLite и Sphinx'а. Теперь все [служебные] данные новостей лежат в SQLite и поэтому мне не нужно вытаскивать их из MySQL'я, а вместо индексов используются атрибуты Sphinx'а. Т.е. чтобы выбрать первые 30 новостей в определённой категории я раньше делал как-то так:

  1. $news = $db->findAll(array("cat_id" => 1));
  2. $news = $dataStorage->load_multi($news);

а теперь делаю как-то так:

  1. $sphinxClient->setFilter("cat_id", 1);
  2. $result = $sphinxClient->query("", "*");
  3. $news = $dataStorage->load_from_sphinx_result($result);

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

Таким образом, ныне зоопарк используемых технологий выглядит следующим образом:
- MySQL (Percona Server) для хранения информации про источники новостей, для ведения auto_increment и хранения дат новостей (для нахождения новости в DataStorage нужны id и дата, поскольку новости разбиты по неделям), для хранения очереди отправки почты и очереди публикации новостей (это была вынужденная мера, поскольку писать в SQLite можно только в один поток), для хранения комментариев
- PHP 5.3, никакие специфичные фичи не используются, не 5.2 исключительно из-за нового сборщика мусора и умения лучше разруливать цикличные ссылки
- SQLite для хранения основного - текстов новостей, id их категорий, id фидов и всей прочей информации
- Sphinx для поиска, сортировки, группировки и т.д.
- MongoDB для хранения количества просмотров новостей и их рейтингов
- memcached для кеширования редко изменяющихся данных (на длинное время до 10 мину)
- xcache для оптимизации и кеширования кода, а также для кеширования оперативных данных (на короткое время до 1 минуты)
- lighttpd в качестве веб-сервера (никаких апачей я на своём сервере не терплю)
- Ubuntu Server в качестве ОС

Стоит отметить, что на этом же сервере располагается мой проект internets.kz, в состав которого входит счётчик посещений, генерирующий в сутки порядка 100К хитов (отдельно от самого сайта internets.kz и сайта i-news.kz). Загрузка сервера по графикам Munin не превышает 3.5%

В плане кода i-news.kz содержит под капотом самопальный каркас (фреймворком это назвать нельзя) для разделения кода и представления. Для отправки почты используется Zend_Mail, а для кеширования Zend_Cache. Для общения с MySQL используется PDO, для разбора HTML - DomDocument+DomXPath.

В целом, я очень благодарен всем, кто [не всегда] по своей воле помогал мне с проектом. Я очень многому научился и, уверен, ещё научусь.

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

0