Здравствуй!
На момент публикации этого поста на Хабре найдено только три аналога по ключу «рыбалка» и пару дней назад мой коллега рассказал про картографический сервис для рыболовов.
Разумеется, не все гики рыболовы, скорее даже наоборот, но вот как-то так сложилось, что в нашей команде стремление оторваться от компьютера и отдыхать на свежем воздухе пересилило лень, в результате мы сделали «очередную социалку», так и не оторвались от компьютера и нашли себе лишнюю головную боль по поводу безуспешной раскрутки узкотематического проекта.
Под катом нет решений для высоконагруженных приложений, да и в принципе нет никакого описания технологий, скорее здесь мы пытаемся сформировать общее описание проекта, а если кому-то будут интересны детали – напишем вторым постом ответы на вопросы.
Введение
Буду честным, частично это все же пиар, но искренне надеюсь, что кому-нибудь наш опыт будет полезен. Также заранее оговорюсь, ни один участник проекта не пожалел о том, что взялся за него, помимо конечной цели какой-либо монетизации, нам всем просто нравилось и продолжает нравится поддерживать хоть и медленно, но растущий сайт в интересной нам тематике.
Итак, первая простая версия сайта (который по нынешним временам никому не был бы интересен) появилась в 2008 году. Простой информационный ресурс-библиотека, никакого интерактива, только редакторские статьи и немного публикаций из рыболовной периодики.
Сайт был сделан и успешно заброшен ввиду отсутствия времени у создателей. Внешний вид этого детища можно найти в вебархиве, но он явно не достоин того, чтобы показывать его общественности.
К середине 2011 года появилось время и главное желание создать нечто «грандиозное» и обязательно с нуля (думаю многие проходили этот этап, когда что-то делается не ради конечной цели, а потому, что от грандиозности планов захватывает дух и процесс интереснее результата). К тому времени в команде создателей было три человека – верстальщик/программист, дизайнер и профессиональный копирайтер. Все трое увлекались рыбалкой (по крайней мере мы продолжаем думать, что ей увлекаемся :)).
Вторая версия сайта в виде «очередной социалки» рождалась полгода. Дизайн, платформа с нуля (PHP, Smarty, MySQL, jQuery) и многие бессонные ночи.
Благо у нас со фрилансерских времен была своя CMS, на которой можно было пилить узкозаточенные задачи без излишнего коробочного объема.
Мы много и долго анализировали аналоги и пришли к неутешительному выводу: подавляющее большинство проектов в этой тематике – форумы. Более того, пользователи настолько «приучены» к ним, что формат true-social им чужд. Впоследствии это сказалось на скорости количества регистраций и даже в общении со сложившимся костяком сайта выяснялось, что рыбакам приходилось переучиваться работе с выкладкой материалов в блог-формате. Все стремились использовать хостинги изображений и бб-теги (хотя мы сразу реализовали ajax-upload и правку материалов в режиме одной страницы с удобным управлением). Тем не менее, мы отбросили сомнения и продолжили развиваться в режиме социалки и хоть и есть форум, он всегда был вторичен.
Разумеется, ничего приципиально нового мы не придумали, как и любая социальная сеть, Фиш-Хук обладает системой рейтингов пользователей, возможностью комментировать любые материалы, выкладывать посты, фото, видео с популярных видео-хостингов.
Первой отличительной особенностью проекта стал режим модерации. В отличие от аналогов, на Фиш-Хуке никто не знает модераторов. Т.е. есть служба поддержки проекта, но её сотрудники не являются публичными пользователями. И это ключевая особенность, т.к. на всех без исключения сайтах, которые мы анализировали, есть одна не очень приятная составляющая: модераторы могут активно продавливать свою точку зрения и управлять сообществом как таковым. Мы же строили систему, в которой модерация пассивна (до момента нарушения правил пользователями) и является корректировочной (все без исключения материалы в фоне проходят редакторскую корректировку, в основном постмодерация, за исключением постов в блогах), но жизнь сообщества регулируется самими пользователями на базе рейтингов и голосований. И это за уже 3 года существования проекта в существующем виде привело к полному отсутствию троллинга и войн в комментариях. Пользователи просто сами останавливают подобные неурядицы.
С такими посылами появилось вот это (оглядываясь, сейчас сами ужасаемся :)):
Затем была работа над ошибками, сбор мнений сотен пользователей, внутренние дебаты, множественные правки промежуточных версий и появилась обновленная версия с ajax-пейджерами, информерами и т.д.:
В последней версии мы уже допиливаем интерфейсы поблочно, по большей степени последним дизайном довольны почти все зарегистрированные пользователи.
Сервер
На данный момент проект справляется с текущей посещаемостью на
- Платформа XEN;
- Процессор: 2x2.40 GHz;
- Память: 4096Mb;
- Диск: 75GB (RAID 10);
- Трафик: неограничен;
- Порт: 100Mbit.
Не Бог весть что, но вполне хватает, еще и запас пока есть.
Производительность, кэширование
Еще во время создания первой версии мы заложили блочное кэширование для большинства страниц сайта. Сначала оно было реализовано полностью на возможностях Smarty. Кэширование автоматически управляемое на уровне ядра и модулей системы — при обновлении контента сбрасывается связанный кэш. Разумеется есть и ручной сброс.
Уже под «реальной нагрузкой» (если так можно было назвать посещаемость в тысячу уников в сутки) в сочетании с тестами мы уперлись в ограничения файловой системы. Поскольку кэшировались блоки страниц, а не сами страницы, в папке кэша могло возникнуть несколько десятков тысяч файлов. Скорость доступа в таком случае известна коллегам, поэтому не буду заострять внимание. В Smarty есть возможность включить в кэшировании разделение файлов по директориям, но и это не лучшее для нас решение, поскольку (по нашим тестам) после генерации 2-3х тысяч файлов кэша, скорость генерации страниц падала в 2-3 раза. Дальше только хуже. При этом, мы получали время генерации страницы до 0,5-0,6 сек. по тестам на генерацию тысячи страниц. Средний расход памяти на страницу – до 7 Mb.
Не дожидаясь неминуемого решили добавить Memcache. После допиливания необходимого плагина для Smarty мы полностью увели поблочный кэш страниц в оперативную память. В файловом кэше остались стили и js в подготовленном gz и ряд служебных файлов. Результат оправдал все наши надежды, при общем количестве кэшированных блоков 45-50 тысяч, скорость генерации страниц не поднимается выше 0,2 секунд. Оптимизация кода привела и к уменьшению памяти на генерацию страниц до 3-4 Mb.
На этом пока остановились.
Хранение файлов
На стадии создания сайта была заложена архитектура хранения пользовательских файлов в их персональных директориях. Все пользователи были поделены на тысячу, по принципу создания не более 1000 директорий внутри другой директории. Также был создан механизм, при котором при достижении 1000 файлов в пользовательской директории, для пользователя создавалась новая директория по общей структуре:
users_1_1000000 users_1_1000 user_1 dir_1 dir_2 ... dir n ... user_1000 users_1001_2000 и т.д.
Казалось бы такая структура вполне подходит, но смущали лишние траты на отслеживание кол-ва файлов и папок и неравномерность распределения плотности: у активных пользователей за год появлялись десятки тысяч файлов. Кроме того, рано или поздно появились бы пользователи, у которых в корневой папке количество вложенных перевалило бы за 1000, а мы для себя это число избрали критерием предела (разумеется после многократных тестов). В результате мы пришли к файловой структуре, построенной по принципу MD5 хэша от имени файла с дальнейшей уникализацией и управляемой глубиной вложенности двухсимвольных папок. Получалась комбинация из 36х36 папок в одной корневой папке и более-менее равномерное распределение благодаря алгоритму md5. Кроме того, маниакальное стремление к безопасности подтолкнуло к уникализации имени файла еще до хэширования и обработки (т.е. на сервере в принципе нельзя предугадать имя загружаемого файла).
Контент
Картинки
В первые месяцы существования мы столкнулись с ограничением GD библиотеки на обработку картинок налету. Например, пользователи при написании отчета с рыбалки могут в одновременно выкладывать с десяток фотографий сразу с фотоаппарата (по статистике мегабайт по 8 объемом). Картинки грузятся аяксом, а пользователь тем временем продолжает редактирование своего поста. В таких случаях при обработке скриптами (выпиливание exif, ресайзинг, создание разноразмерных копий) всего 2-3 фотографий могло тратиться до 2Gb памяти. Поскольку одновременно материалы редактирует не один пользователь – все плачевно могло упасть, пользователь продолжил бы видеть безрезультатно крутящийся прелоадер загрузки.
Так на
Предметы снаряжения
Любой пользователь может сформировать собственную базу снаряжения, распределяя ее по тегам, формируя таблицы параметров и загружая произвольные картинки и тексты. Все остальные пользователи могут прокомментировать любой предмет и проголосовать за него.
Интерфейс правки пошаговый, пользователь может создавать абзацы, заголовки, списки, добавлять фото/видео и т.д.
Посты
Текстовые посты (статьи) — основной вид наполнения сайта. Посты включают в себя произвольный текст, загружаемые картинки, импортируемые видео-ролики, Яндекс карты.
Интерфейс стандартизован:
Например при вставке карт пользователю достаточно выбрать место, масштаб и указать точку, можно добавить описание:
На клиентской части карта отобразится уже с балуном, а в списке карт даже в балуне сохраняется функциональность сайта (на скрине показаны голосования):
Аналогично предметам снаряжения, в постах все комментируется, за них можно голосовать, они могут автоматически причисляться к конкурсам.
Как все это связано
Все элементы контентного наполнения связаны друг с другом. Помимо возможности загружать фото и импортировать видео в посты и в предметы снаряжения, пользователи могут одновременно постить картинки и в фотогалерею, а видео в видеогалерею. При этом каждый объект будет редактируемым, комментируемым и за него можно будет голосовать. Впрочем этим мало кого можно удивить, хотя подобный функционал не сильно распространен на сайтах подобной тематики.
Псевдоаккаунты и накрутка голосований
Поскольку мы регулярно проводим конкурсы и вручаем призы, на этапе запуска столкнулись с желанием некоторых пользователей быстро накрутить себе рейтинги и выиграть в конкурсах путем приглашений «проголосуй за меня» или с помощью множественных регистраций с последующим голосованием за себя. Последовательно шаг за шагом мы вводили ограничения.
- для начала ограничили возможность голосования новых пользователей, пока не набирался необходимый минимальный рейтинг;
- ввели систему, которая отслеживала cookie и не позволяла повторно регистрироваться;
- для «продвинутых» пользователей ввели серверное отслеживание похожести профилей (по ряду идентификационных признаков);
- для «суперпродвинутых» пользователей (способных пользоваться файрбагами и прочими средствами) со временем ввели систему фонового выявления псевдопользователей, которая успешно работает и по сей день.
Таким образом мы получили вторую «фишку» проекта: к щадящей модерации/корректуре добавилась чистота пользовательской базы. Флудеры и тролли, помучавшись немного, просто уходят.
Кроме того, система e-mail рассылок/уведомлений позволяет нам контролировать актуальность почтовых ящиков пользователей: при наличии ответа 550 после отправки письма, профиль пользователя может блокироваться с различным набором опций.
Комментарии
Тут тоже все относительно просто – ajax публикация/редактирование и обновление комментариев, информер новых с якорным переходом.
Конкурсы
Третья особенность проекта – конкурсы, полностью управляемые сообществом. Поскольку накрутку голосований мы исключили (ну или почти исключили), грех был бы не дать пользователям возможность самим решать, кто должен победить в том или ином конкурсе. При этом вмешательство админстрации должно было быть лишь контролирующим, не более того. В результате мы создали систему, которая автоматически стартует и заканчивает конкурсы по расписанию, сохраняет результаты и формирует очередь уведомлений пользователям, занявшим призовые места.
Почему «особенность» – все просто. Все, как правило, проводят конкурсы в режиме форумной ветки с ручным награждением по факту завершения конкурса. Мы ленивы и хотели, чтобы все знали результат конкурса через секунду после его окончания.
Уведомления и рассылки
На сайте довольно много событий, при которых необходимо рассылать пользователям уведомления: начиная от подписок в личных настройках, заканчивая уведомлениями об изменении рейтингов, личных сообщениях, поздравлениях с днем рождения, победой в конкурсе и т.д.
Рассылки организованы по принципу очередей с помощью cron скриптов. Для каждого пользователя формируется сводное письмо с интересными ему событиями и изменениями в его профиле и отправляется раз в сутки. Кроме того есть «мгновенные» уведомления и поздравления. Админы получают соответствующие рассылки о необходимости модерации или вмешательства различного уровня. В общей сложности за день с сайта успешно рассылается 2-3 тысячи писем.
Яндекс.Маркет не дает покоя
Какой рыболовный сайт без рыболовных товаров? После создания основной функциональности, наигравшись с полностью контентным сайтом, мы начали поглядывать в сторону каталога товаров с его возможными моделями монетизации. Торговать товарами мы не собирались, а делать очередной Маркет изначально казалось безумной затеей.
Причин безумности было две:
- специфика товаров крайне сложной структуры (от мелочевки до крупных вещей), которые сложно классифицировать по разделам и у которых могут быть десятки параметров, меняющихся от категории к категории;
- количество товаров для (по актуальному на сегодняшний день состоянию), доступных для продажи в странах СНГ по нашим исходным оценкам — несколько миллионов (у официальных брендов, еще пару сотен тысяч позиций производят артели в глубинках и частные мастера).
Но была статистика, которую собирали как по российским источникам, так и по иностранным. Мы пересмотрели несколько десятков бизнес-планов (от магазинов до социалок) из которых получили примерное понимание рыночной ситуации. В отличие от ситуации зарубежом, рынок рыболовных товаров в России практически никто никогда не пытался оценивать. Если в США можно видеть данные об оборотах в $110-130 млрд, при доле населения, увлекающегося рыбалкой, в 24%, то в России рыночный оборот в разы меньше, а доля увлекающихся рыбалкой доходит до трети населения. Другими словами рынок не перенасыщен, а информационный рынок вовсе на стадии 90х и по дизайну и по функциональности.
Ради смеха дизайнеру была поставлена задача, а программист начал строить структуру базы данных, способную вместить в себя все разнообразие необъятной тематики. Несколько месяцев разработки в свободное время и мы получили каталог товаров, который сейчас только на начальной стадии заполнения. Тем не менее, мы его выкатили на продакшн и уже подключили с десяток магазинов. При нынешней посещаемости это не более чем тест и проба собственных сил.
Да, мы долго мучались с идентификацией товаров в прайсах магазинов и уже разрабатывая свой механизм поняли, почему на маркете так много женских бус в рыболовных товарах :), но начало положено и при должном упрямстве в сочетании с модерацией можно говорить об успешном построении маленького, но рыболовного агрегатора товарных предложений.
Разумеется, всем товарам в каталоге можно присваивать рейтинг, их можно комментировать, оставлять отзывы и фильтровать по параметрам как в «серьезном магазине». Фильтрация товаров построена на ajax с сохранением критериев поиска для каждого раздела каталога в локальном хранилище.
Поиск
Пока нам хватает псевдо-полнотекстового поиска по заранее подготовленному индексу (который создается автоматически) с использованием морфологии на базе phpMorphy. Вероятно в будущем понадобится переход на Сфинкс, но пока наши объемы контента вполне успешно «обыскиваются» существующим решением.
Привлечение аудитории
После запуска проекта и по сей день мы почти не давали никакой рекламы. Было несколько робких попыток «слить» по 300$ в рекламе на Директе, в ВК и даже на Фейсбуке, но эффективность была крайне низкой. Основной упор сделали на привлечение пользователей с помощью регулярно проводимых конкурсов. В данный момент продвижение проекта можно сказать пущено на самотек. В день в среднем мы имеем несколько новых регистраций.
Были также попытки преглашений пользователей на других ресурсах, но мы выяснили крайне высокую инертность аудитории, как правило с насиженных ресурсов уходят только по факторам несовместимости с модераторами, в остальных случаях людям хватает форумных сайтов, на которых они привыкли сидеть.
Учтенные и упущенные моменты
Еще при проектировании пользовательских интерфейсов (добавление статей и других материалов) мы учли особенность аудитории — далеко не айтишники, не всегда на быстром интернете. Это было плюсом, поскольку после регистрации многие «прописывались» на сайте из-за простоты и удобства.
Но мы не учли факт привычек и нежелания их менять: мы считали и продолжаем считать, что форумный формат крайне сложен для поиска информации и её структурирования, в результате интерфейс отпугивал и продолжает отпугивать часть аудитории, которая привыкла к бесчисленным топикам и тысячам флудо-страниц. Тут до сих пор разводим руками и видим тенденцию: в возрастной составляющей регистрирующихся пользователей, львиная доля аудитории в диапазоне 20-35 лет, в то время как по анализу «форумных» сайтов — на них смещение к границе в 40-50 лет наиболее распространено.
Вероятно мы ориентированы на молодых пользователей, близко знакомых с ЖЖ, ВК, ФБ и т.д., но этот путь рискован, т.к. нет исследований, насколько падает процент заинтересованных рыбалкой со снижением возрастной границы.
Выводы
Создание тематической социальной сети интересно и приносит дополнительный опыт. Однако если создавать полностью коммерческий проект (мы не будем учитывать наш случай, когда работа переросла из хобби в сайт, который создавался все же как прототип) необходимо в начале полностью оценивать аудиторию, её интересы и загруженность ниши в целом.
И речь даже не о том, что рыболовы не хотят делиться «закрытой» информацией (как места ловли или свои секреты мастерства), видимо сказывается просто общая инертность аудитории. За время нашего развития мы следили за еще одним проектом, в котором участвовал сторонний инвестор. Полгода назад проект закрылся несмотря на довольно активную рекламу в ВК и на Директе.
Нельзя отбрасывать также фактор региональности. Мы на собственном опыте узнали, что пользователи могут быть приверженцами того или иного сайта не за его удобства (чаще даже наоборот, готовы мириться с допотопностью интерфейсов), а за его региональную принадлежность. Например, многие пользователи не хотят пользоваться сайтами, которые явно не привязаны к их региону (т.е. не являются местными).
Ну и конечно есть факторы лени и недоверия. Возрастная аудитория не регистрируется по причине боязни за свои персональные данные (нам даже звонили некоторые пользователи с целью пообщаться перед регистрацией :)), а многие не регистрируются потому, что читают, но не хотят писать. И по нашей статистике читателей гораздо больше половины общей аудитории.
Несмотря на все факторы медленного роста мы не унываем и будем продолжать поддерживать и развивать проект. Есть вера в потенциал, силы и стремление достичь результата, а это важно (наверное) :).
В заключение, с вашего позволения оставлю ссылку на проект, рискуя положить его под хаброэффектом – Фиш-Хук.
Всем спасибо!
Автор: izelenyuk