Распределенный блог - Т3

Оглавление

  1. Постановка задачи
  2. Идеальное решение
  3. Решение на основе существующих технологий
    1. Использование foaf
    2. Использование Atom
  4. Задачи, для которых существующих технологий недостаточно
    1. Протокол распределенного комментирования
    2. Реализация записей ограниченного доступа на основе OpenID

Постановка задачи

Крупные blog-сайты вроде livejournal, обеспечивают существенно большую степень интеграции социальной сети, чем standalone блоговые движки.

Основными преимуществами этих сайтов, на мой взгляд, являются:

  1. Наличие интегрированной ленты интересных для чтения блогов (френдленты)
  2. Узнаваемость людей, комментирующих твой блог или дискутирующих в комментарии какого-то другого блога. Сюда включается как то, что пользователь идентифицируется именем своего блога, так и наличие легко запоминающихся аватаров(юзерпиков)
  3. Развитые возможности управления доступом. Существует возможность ограничения комментирования (только для друзей, для определенной группы) и ограничения видимости)
  4. Достаточно высокая устойчивость к нагрузкам и надежность сервиса. Все мы знаем, что ЖЖ периодически падает, но обеспечить аналогичную доступность standalone блога, размещенного, например на хостинге какого-нибудь мелкого провинциального провайдера - задача нетривиальная.

Тем не менее, крупные блог-сайты обладают и рядом недостатков:

  1. Практически полное отсутствие контроля пользователя над функциональностью своего блога - никогда не знаешь когда там сапгрейдят софт и у твоего блога непредсказуемо изменится look & feel.
  2. Отсутствие реальных стимулов к развитию. Основной ценностью сервиса является не техническое превосходство его движка, а уже сформировавшееся коммьюнити. Поэтому компания - владелец сервиса практически не имеет стимулов к удовлетворению потребностей пользователя. Все равно не разбегутся, куда они от своих друзей денутся.
  3. Неизбежно возникающие неоправданные ограничения на контент. Компании с миллионом пользователей, пусть даже платных, проще отказаться от одного клиента, чем брать на себя защиту его интересов в конфликте. Поэтому голословное обвинение в hate speech, распространении порнографии etc приводит к закрытию блога. И уже пользователю приходится доказывать, что он не верблюд. Презумпции невиновности в квазимонопольном коммерческом сервисе нет и быть не может.

Каким может быть решение этой проблемы? На мой взгляд, наиболее естественным решением является создание набора протоколов (и нескольких реализаций) которые обеспечивают связность социальной сети, сравнимой с ЖЖ-шной в случае расположения блогов на независимых серверах. Что это дает?

  1. Первое и самое главное - меняя провайдера сервиса ты не покидаешь коммьюнити. Все остальные преимущества следуют из этого.
  2. Становится возможной конкуренция реализаций в пределах одного коммьюнити. Соответственно, ценность конкретного провайдера сервиса для пользователя определеяется в первую очередь его техническими характеристиками - доступностью (availability) сайта, наличием каких-то интерфейсных усовершенствований etc. Начинается здоровая конкуренция.
  3. Провайдер сервиса становится заинтересованным в том, чтобы выступать как представитель интересов клиента в случае (необоснованных) обвинений в публикации чего-либо противозаконного. Клиента на его сервисе теперь держит именно уровень сервиса, а не коммьюнити. Переплюнуть соседей по техническому уровню сервиса будет довольно непросто, а юридическая поддержка - тоже сервис. Тем более что в большинстве случаев для этой поддержки нет необходимости быть грамотным адвокатом. Достаточно просто упереться и сказать: нет, с нашей точки зрения этот человек ничего противозаконного не сделал. Не согласны - подавайте в суд. (Лучше, конечно иметь возможность реально оценить перспективы иска).
  4. Если все плохо, то можно всех сервис-провайдеров послать, и поднять блог-движок на собственной машине. В развитых странах и регионах broadband-каналы нынче весьма распространены, да часто еще имеются и конкурирующие канальные провайдеры (что возвращает нас к предыдущему пункту). Тем более что канальный провайдер часто может прикрыться статусом Common Carrier (в тех юрисдикциях где он бывает). А вот наехать на частное лицо, которое на диске принадлежащего ему компьютера держит какую-то информацию и публикует её по протколу HTTP, гораздо сложнее, чем наехать на провайдера. Тут возмущенным письмом или звонком от куратора неограничишься, надо начинать с получения ордера.
  5. Опять же в мире существуют под две сотни разных юрисдикций с разными законами относительно интеллектуальной собственности, запрещенных видов пропаганды etc. Если мы можем свободно перемещать наш блог по интернету, то мы можем и юрисдикцию его хостинга выбирать.

Соответственно, требуется обеспечить возможность интеграции блогов на независимых движках, со степенью интеграции, сравнимой с интеграцией разных блогов на движке ЖЖ. Для этого необходимы стандартные протоколы для:

Что самое смешное, все эти стандарты уже существуют и более того, где-то как-то поддерживаются существующими крупными блог-площадками.

Чего можно добиться с помощью только этих протоколов? Да почти всего, что требуется. Если предположить, что интернет функционирует на 100% надежно, то в любой момент блог-сайт может аутентифицировать пользователя любого другого блог-сайта, получить его юзерпик, получить свеженькие посты и сформировать френдленту. Ну а если захотелось откомментировать чужой пост - пойди на родной для него сайт и откомментируй. Тот сайт тоже узнает тебя по OpenID и получит необходимую для своих пользователей информацию о тебе через foaf.

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

Более правильное решение предлагает lj.rossia.org при кросс-постах в ЖЖ. В ссылку вставляется картинка, которая запрашивается с оригинального сайта, и изображает текущее число комментариев. Это решение сделано исходя из предпосылки, что сайт, куда мы кросспостим, не принимает специальных мер для кооперации с нами. Если такие меры принимает либо сервер (вставляя в страницу client-side скрипт), либо пользователь (устанавливая скрипт в браузер через какой-нибудь greasemonkey), то можно существенно сэкономить ресурсы сервера, отдавая просто число комментариев в текстовом формате. Не нужно ни рендирить картинку, ни отдавать её.

Сложности начинаются, когда мы вводим предположение о том, что интернет работает не на 100% надежно. Вот пошли мы комментировать чужой блог, а наш блог-сайт в этот момент недоступен, и не может подтвердить нашу идентичность по OpenID. Впрочем, это как раз не самое страшное.

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

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

А уж возможность отправки комментария, да так, чтобы он расползся по всем известным копиям данного блога, а рано или поздно попал и на родной сайт, вообще пока не представляется возможным.

Хотя сходная задача - распространение по сложной сети серверов сообщений, с провязыванием между этими сообщениям связей вида "В ответ на" (In-Reply-To) вполне успешно решена в NNTP еще в 1986 году (если не раньше, учитывая доинтернетовские времена UUCP-шного Usenet).

Идеальное решение

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

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

Использование криптографии также позволит вспомнить о намеренно упущенном выше явлении записей с ограниченным доступом.

Но, к сожалению, уровень поддержки криптографии в современных браузерах не позволяет реализовать такую систему непосредственно в браузере. А если мы начинаем настаивать на применении специальных программ-клиентов, то это уже не блоггинг (ибо слово blog это сокращение от web-log). Существенной особенностью блоггинга является принципиальная доступность записей в блогах и дискуссий по ним для любого пользователя интернета, у которого есть только браузер. Если нам требуется специальный клиент, то почему бы не вернуться в usenet, где S/MIME и PGP уже давно поддерживаются существующими клиентами?

Поэтому эту возможность мы пока из рассмотрения исключим.

Решение на основе существующих технологий

Использование foaf

Корнем решения на базе существующих технологий должно стать активное использование возможностей foaf. Именно foaf, гибкий и расширяемый формат информации о действующем лице (не обязательно человеке - можно организации, программном агенте etc) позволяет превратить отдельные сайты, общего между которыми только то, что они поддерживают протокол HTTP и имеют имена в DNS, в социальную сеть.

Существующая спецификация foaf имеет некоторые ограничения, крайне критичные для реализации distributed blog. Например, элемент foaf:knows в ЖЖ описывает список френдов (тех, кого я читаю), но не список friends-of (тех, кто читает меня). А последний список крайне важен для того чтобы знать, где искать более свежую кэшированную копию блога, если вдруг при очередном обращении к RSS мы обнаружили, что сайт недоступен.

Кроме того, в foaf же можно обговорить политику комментирования - явный список людей, которые не могут комментировать данный блог (ban-list), можно ли комментировать анонимам, можно ли комментировать, людям не указанным в foaf:knows и т.д.

Но foaf сам по себе является расширением RDF. Например, в foaf-файле, отдаваемом ЖЖ перечислено целых 6 namespaces. Соответственно, можно определить еще одно, которое будет содержать необходимую нам информацию.

Сюда должна входить следующая информация:

known-by
Список foaf-персон, которые читают нас. Вернее, список публично доступных RSS/Атом-агрегаторов, которые имеют копию нашей ленты.
has-comments
Тэг, который помещается в known-by, если известно, что на этом сайте кэшируется копия не только постов, но и дискуссий по ним
introduce
URL, по которой другой сайт может сообщить, что он внес наш блог в свой список foaf:knows (и мы должны его внести в свой список known-by
non-grata
Список персон, комментарии от которых мы не хотим видеть в нашем блоге, и ни в одной из его копий
comment-policy
Набор элементов allow и disallow указывающий на то, кто имеет право постить комментарии. Для большей пущести можно использовать XPath-запрос, который, при применении к данному foaf-файлу будет возвращать список персон. Ну плюс еще специальные значения anybody (в смысле любой зарегистрированный пользователь) и anonymous.

Естественно, что из результата любого запроса вычитается список non-grata. По умолчанию предполагается <allow>anybody</allow>

Этот кусочек неймспейса может потребоваться импортировать не только в foaf, но и в atom - чтобы задавать политику комментирования для отдельных постов.

foaf следует агрессивно кешировать. Пришел к нам Open-Id пользователь, для того чтобы комментарий оставить - выкачиваем его foaf (чтобы юзерпик показать), и сохраняем у себя. Пришел к нам чужой блог-сервер, отметиться, что хочет читать наш RSS, и его foaf сохраняем. А вдруг кроме нашего rss у него есть еще какие-то, которые внезапно (когда их оригинальный сервер ляжет) окажутся интересным нам.

Закэшированные foaf надо периодически проверять на актуальность. Раз в сутки, по-моему, достаточно. Поэтому крайне рекомендуется при отдаче своего foaf поддерживать HTTP-загловок If-Modified-Since и интерпретировать его именно как "если информация была содержательно изменена".

Тогда, если нам понадобился какой-нибудь блог, основной сайт которого недоступен, мы, весьма вероятно, сможем найти ссылку на его живую копию в нашей базе данных foaf - сначала проверть known-by в foaf этого блога, потом (или если этот блог не размещает информацию о своих читателях в своем foaf), все knows в других foaf. И есть шанс, что хотя бы на одном из этих сайтов окажется более свежая копия, чем у нас.

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

Использование Atom

Естественно, если мы хотим, чтобы наши посты пользователи могли читать в своих агрегаторах, даже если наш сервер не доступен, мы должны раздавать в виде atom feed полный текст этих постов.

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

В atom feed стоит включать информацию о том, где смотреть информацию о количестве комментариев (даже если мы не поддерживаем распределенного комментирования).

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

Задачи, для которых существующих технологий недостаточно

Протокол распределенного комментирования

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

Поэтому для этой цели не подходит AtomPub. Расширения RSS вроде WFW тоже не подходят.

Нужно что-то что использует механизм, подобный NNTP-шному IHAVE/SENDME. Причем, в отличие от NNTP, где обычно соседи, с которыми идет обмен, конфигурируются вручную, администратором сервера, здесь децентрализованная сеть обмена комментариев должна формироваться динамически, на основе анализа закэшированных foaf-файлов.

Именно для этой цели предназначен описанный мной несколько дней назад Distributed Comments protocol.

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

Реализация записей ограниченного доступа на основе OpenID

Теоретически возможно решение, когда при скачивании фида по RSS/Atom агрегатор аутентифицируется по OpenID. В норме OpenID предполагает взаимодействие трех сторон - пользователя с браузером, сервера, подтверждающего его идентичность, и сервера принимающего эту идентичность. Но в случае RSS-агрегатора, встроенного в блог-сервер, "пользователь" и сервер, подтверждающий идентичность совпадают. Поэтому вполне можно реализовать OpenID в неинтерактивном процессе.

На пальцах это выглядит так: сервер, получивший запрос на скачивание фида ограниченного доступа, переспрашивает у сервера по известной ему URL: "Это действительно ты пришел?" и тот ему отвечает:"Да, это я.".

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

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