]> www.wagner.pp.ru Git - sites/home_page.git/blob - articles/dblog.html
Исправлена опечатка в аннотации к Детям Пространства
[sites/home_page.git] / articles / dblog.html
1 <HTML><HEAD>
2 <META HTTP-EQUIV="Content-Type" "text/html; charset=utf-8">
3 <META NAME="description" CONTENT="Описание реализации тесно
4 интегрированной социальной сети, подобной LiveJournal в виде множества независимых
5 друг от друга сайтов.">
6 <TITLE>Распределенный блог, ТЗ</TITLE>
7 </HEAD><BODY>
8 <h1>Распределенный блог - Т3</h1>
9 <h2>Оглавление</h2>
10 <!--CONTENTS NUMBERED NESTED BACKREFS--><OL>
11 <LI><A NAME="toc_entry0"></A><A HREF="#toc_section0">Постановка задачи</A>
12 <LI><A NAME="toc_entry1"></A><A HREF="#toc_section1">Идеальное решение</A>
13 <LI><A NAME="toc_entry2"></A><A HREF="#toc_section2">Решение на основе существующих технологий</A>
14 <OL>
15 <LI><A NAME="toc_entry3"></A><A HREF="#toc_section3">Использование foaf</A>
16 <LI><A NAME="toc_entry4"></A><A HREF="#toc_section4">Использование Atom</A>
17 </OL>
18 <LI><A NAME="toc_entry5"></A><A HREF="#toc_section5">Задачи, для которых существующих технологий недостаточно</A>
19 <OL>
20 <LI><A NAME="toc_entry6"></A><A HREF="#toc_section6">Протокол распределенного комментирования</A>
21 <LI><A NAME="toc_entry7"></A><A HREF="#toc_section7">Реализация записей
22 ограниченного доступа на основе OpenID</A>
23 </OL>
24 </OL>
25 <!-- END CONTENT -->
26
27
28 <A NAME="toc_section0"></A><A HREF="#toc_entry0"><h2>Постановка задачи</h2></A>
29 <p>
30 Крупные blog-сайты вроде livejournal, обеспечивают существенно большую
31 степень интеграции социальной сети, чем standalone блоговые движки.
32 </p>
33 <p>
34 Основными преимуществами этих сайтов, на мой взгляд, являются:
35 </p>
36 <ol>
37 <li>Наличие интегрированной ленты интересных для чтения блогов
38 (френдленты)
39 <li>Узнаваемость людей, комментирующих твой блог или дискутирующих в
40 комментарии какого-то другого блога. Сюда включается как то, что
41 пользователь идентифицируется именем своего блога, так и наличие легко
42 запоминающихся аватаров(юзерпиков)
43 <li>Развитые возможности управления доступом. Существует возможность
44 ограничения комментирования (только для друзей, для определенной группы)
45 и ограничения видимости)
46 <li>Достаточно высокая устойчивость к нагрузкам и надежность сервиса.
47 Все мы знаем, что ЖЖ периодически падает, но обеспечить аналогичную
48 доступность standalone блога, размещенного, например на хостинге
49 какого-нибудь мелкого провинциального провайдера - задача нетривиальная. 
50 </ol>
51 <p>
52 Тем не менее, крупные блог-сайты обладают и рядом недостатков:
53 <ol>
54 <li>Практически полное отсутствие контроля пользователя над
55 функциональностью своего блога - никогда не знаешь когда там сапгрейдят
56 софт и у твоего блога непредсказуемо изменится look &amp; feel.
57 <li>Отсутствие реальных стимулов к развитию. Основной ценностью сервиса
58 является не техническое превосходство его движка, а уже сформировавшееся
59 коммьюнити. Поэтому компания - владелец сервиса практически не имеет
60 стимулов к удовлетворению потребностей пользователя. Все равно
61 не разбегутся, куда они от своих друзей денутся.
62 <li>Неизбежно возникающие неоправданные ограничения на контент. Компании
63 с миллионом пользователей, пусть даже платных, проще отказаться от
64 одного клиента, чем брать на себя защиту его интересов в конфликте.
65 Поэтому голословное обвинение в hate speech, распространении порнографии etc
66 приводит к закрытию блога. И уже пользователю приходится доказывать, что
67 он не верблюд. Презумпции невиновности в квазимонопольном коммерческом сервисе нет и быть не может.
68 </ol>
69 <p>
70 Каким может быть решение этой проблемы? На мой взгляд, наиболее
71 естественным решением является создание набора протоколов (и нескольких
72 реализаций) которые обеспечивают связность социальной сети, сравнимой с
73 ЖЖ-шной в случае расположения блогов на независимых серверах. Что это
74 дает?
75 </p>
76 <ol>
77 <li>Первое и самое главное - меняя провайдера сервиса ты не покидаешь
78 коммьюнити. Все остальные преимущества следуют из этого.
79 <li>Становится возможной конкуренция реализаций в пределах одного
80 коммьюнити. Соответственно, ценность конкретного провайдера сервиса для
81 пользователя определеяется в первую очередь его техническими характеристиками -
82 доступностью (availability) сайта, наличием каких-то интерфейсных
83 усовершенствований etc. Начинается здоровая конкуренция.
84 <li>Провайдер сервиса становится заинтересованным в том, чтобы выступать
85 как представитель интересов клиента в случае (необоснованных) обвинений
86 в публикации чего-либо противозаконного. Клиента на его сервисе теперь
87 держит именно уровень сервиса, а не коммьюнити. Переплюнуть соседей по
88 техническому уровню сервиса будет довольно непросто, а юридическая
89 поддержка - тоже сервис. Тем более что в большинстве случаев для этой
90 поддержки нет необходимости быть грамотным адвокатом. Достаточно просто
91 упереться и сказать: нет,  с нашей точки зрения этот человек ничего
92 противозаконного не сделал. Не согласны - подавайте в суд. (Лучше,
93 конечно иметь возможность реально оценить перспективы иска). 
94 <li>Если все плохо, то можно всех сервис-провайдеров послать, и поднять
95 блог-движок на собственной машине. В развитых странах и регионах
96 broadband-каналы нынче весьма распространены, да часто еще имеются и
97 конкурирующие канальные провайдеры (что возвращает нас к предыдущему
98 пункту). Тем более что канальный провайдер часто может прикрыться
99 статусом Common Carrier (в тех юрисдикциях где он бывает). А вот наехать
100 на частное лицо, которое на диске принадлежащего ему компьютера держит
101 какую-то информацию и публикует её по протколу HTTP, гораздо сложнее,
102 чем наехать на провайдера. Тут возмущенным письмом или звонком от
103 куратора неограничишься, надо <b>начинать</b> с получения ордера.
104 <li>Опять же в мире существуют под две сотни разных юрисдикций с разными
105 законами относительно интеллектуальной собственности, запрещенных видов
106 пропаганды etc. Если мы можем свободно перемещать наш блог по интернету,
107 то мы можем и юрисдикцию его хостинга выбирать.
108 </ol>
109 <p>
110 Соответственно, требуется обеспечить возможность интеграции блогов на
111 независимых движках, со степенью интеграции, сравнимой с интеграцией
112 разных блогов на движке ЖЖ. Для этого необходимы стандартные протоколы
113 для:
114 </p>
115 <ul>
116 <li>Кросс-сайтовой аутентификации пользователя
117 <li>Получения доостаточной информации о пользователе, другого сайта,
118  чтобы читатель нашего блога легко его узнал.
119 <li>Получения информации о новых постах в других блогах.  
120 </ul>
121 <p>
122 Что самое смешное, все эти стандарты <b>уже существуют</b> и более того,
123 где-то как-то поддерживаются существующими крупными блог-площадками.
124 </p>
125 <ul>
126 <li>Кросс-сайтовая аутентификация - <a
127 href="http://openid.net/">OpenID</a>
128 <li>Получение информации о пользователе - <a
129 href="http://xmlns.com/foaf/spec/">FOAF</a>.
130 <li>Получение информации о новых постах RSS/Atom (см <a
131 href="http://tools.ietf.org/html/rfc4287">RFC 4287</a>)
132 </ul>
133 <p>
134 Чего можно добиться с помощью <i>только</i> этих протоколов? Да почти
135 всего, что требуется. Если предположить, что интернет функционирует на
136 100% надежно, то в любой момент блог-сайт может аутентифицировать
137 пользователя любого другого блог-сайта, получить его юзерпик, получить
138 свеженькие посты и сформировать френдленту. Ну а если захотелось
139 откомментировать чужой пост - пойди на родной для него сайт и
140 откомментируй. Тот сайт тоже узнает тебя по OpenID и получит необходимую
141 для своих пользователей информацию о тебе через foaf.
142 </p>
143 <p>
144 Единственое, чего нельзя - это оперативно обновлять во френдленте
145 информацию о количестве комментариев. <a
146 href="http://web.resource.org/rss/1.0/modules/slash/">slash
147 extension</a> тут не лучший вариант - выкачивать заново весь RSS только
148 для того, чтобы узнать что число комментов  в посте месячной давности
149 обновилось - не самое эффективное решение.
150 </p>
151 <p>
152 Более правильное решение предлагает <a
153 href="http://lj.rossia.org">lj.rossia.org</a> при кросс-постах в ЖЖ. В
154 ссылку вставляется картинка, которая запрашивается с оригинального
155 сайта, и изображает текущее число комментариев. Это решение сделано
156 исходя из предпосылки, что сайт, куда мы кросспостим, не принимает
157 специальных мер для кооперации с нами. Если такие меры принимает либо
158 сервер (вставляя в страницу client-side скрипт), либо пользователь
159 (устанавливая скрипт в браузер через какой-нибудь greasemonkey), то
160 можно существенно сэкономить ресурсы сервера, отдавая просто число
161 комментариев в текстовом формате. Не нужно ни рендирить картинку, ни
162 отдавать её.   
163 </p>
164 <p> Сложности начинаются, когда мы вводим предположение о том, что
165 интернет работает не на 100% надежно. Вот пошли мы комментировать чужой
166 блог, а наш блог-сайт в этот момент недоступен, и не может подтвердить
167 нашу идентичность по OpenID. Впрочем, это как раз не самое страшное.
168 </p>
169 <p>Как правило, сайты кэшируют OpenID-аутентификацию, отдавая
170 пользователю собственную куку. Так что в течение какого-то времени
171 (которе скорее всего будет больше времени даунтайма нашего сервера)
172 комментировать на чужих серверах нам позволят. 
173 </p>
174 <p>Теперь рассмотрим ситуацию, когда недоступен чужой блог, который мы
175 хотим прочитать. Скорее всего сами посты мы прочитаем - они уже
176 закэшированы через RSS/Atom агрегацию в нашей френдленте. Но вот
177 прочитать дискуссию уже сложнее. Существуют расширения RSS, позволяющие
178 раздавать комментарии, но, поскольку RSS не оптимизирован под
179 минимизацию траффика, их мало кто реализует.
180 </p>
181 <p>А уж возможность отправки комментария, да так, чтобы он расползся по
182 всем известным копиям данного блога, а рано или поздно попал и на родной
183 сайт, вообще пока не представляется возможным.
184 </p>
185 <p>Хотя сходная задача - распространение по сложной сети серверов
186 сообщений, с провязыванием между этими сообщениям связей вида &quot;В
187 ответ на&quot; (In-Reply-To) вполне успешно решена в <a
188 href="http://www.ietf.org/rfc/rfc3977.txt">NNTP</a> еще в 1986
189 году (если не раньше, учитывая доинтернетовские времена UUCP-шного
190 Usenet).
191 </p>
192 <A NAME="toc_section1"></A><A HREF="#toc_entry1"><h2>Идеальное решение</h2></A>
193 <p>
194 Идеальным решением проблемы, конечно же была бы система, которая
195 позволяла аутентифицировать пользователей и надеждно определять
196 авторство постов и комментариев, независимо от наличия в сети серверов,
197 и даже выпадения из сети целых стран.
198 </p>
199 <p>
200 Теоретически, такое решение возможно, с использованием криптографических
201 методов аутентификации (электронной подписи) с выстраиванием цепочек
202 доверия. Тогда можно с определенной уверенностью говорить об
203 идентичности пользователя, даже если недоступен не только его
204 собственный блог, но и все блоги его друзей, но доступен хотя бы один
205 блог кого либо из друзей его друзей.
206 </p>
207 <p>
208 Использование криптографии также позволит вспомнить о намеренно
209 упущенном выше явлении записей с ограниченным доступом.
210 </p>
211 <p>
212 Но, к сожалению, уровень поддержки криптографии в современных браузерах
213 не позволяет реализовать такую систему непосредственно в браузере. А
214 если мы начинаем настаивать на применении специальных программ-клиентов,
215 то это уже не блоггинг (ибо слово blog это сокращение от web-log).
216 Существенной особенностью блоггинга является принципиальная доступность
217 записей в блогах и дискуссий по ним для любого пользователя интернета, у
218 которого есть только браузер. Если нам требуется специальный клиент, то
219 почему бы не вернуться в usenet, где S/MIME и PGP уже давно
220 поддерживаются существующими клиентами?
221 </p>
222 <p>
223 Поэтому эту возможность мы пока из рассмотрения исключим.
224 </p>
225 <A NAME="toc_section2"></A><A HREF="#toc_entry2"><h2>Решение на основе существующих технологий</h2></A>
226 <A NAME="toc_section3"></A><A HREF="#toc_entry3"><h3>Использование foaf</h3></A>
227 <p>
228 Корнем решения на базе существующих технологий должно стать активное
229 использование возможностей foaf. Именно foaf, гибкий и расширяемый
230 формат информации о действующем лице (не обязательно человеке - можно
231 организации, программном агенте etc) позволяет превратить отдельные
232 сайты, общего между которыми только то, что они поддерживают протокол
233 HTTP и имеют имена в DNS, в социальную сеть.
234 </p>
235 <p>
236 Существующая спецификация foaf имеет некоторые ограничения, крайне
237 критичные для реализации distributed blog. Например, элемент foaf:knows
238 в ЖЖ описывает список френдов (тех, кого я читаю), но не список
239 friends-of (тех, кто читает меня). А последний список крайне важен для
240 того чтобы знать, где искать более свежую кэшированную копию блога, если
241 вдруг при очередном обращении к RSS мы обнаружили, что сайт недоступен.
242 </p>
243 <p>
244 Кроме того, в foaf же можно обговорить политику комментирования - явный список
245 людей, которые не могут комментировать данный блог (ban-list), можно ли
246 комментировать анонимам, можно ли комментировать, людям не указанным в
247 foaf:knows и т.д.
248 </p>
249 <p>
250 Но foaf сам по себе является расширением RDF. Например, в foaf-файле,
251 отдаваемом ЖЖ перечислено целых 6 namespaces. Соответственно, можно
252 определить еще одно, которое будет содержать необходимую нам информацию.
253 </p>
254 <p>Сюда должна входить следующая информация:</p>
255 <dl><dt>known-by</dt>
256 <dd>Список foaf-персон, которые читают нас. Вернее, список публично
257 доступных RSS/Атом-агрегаторов, которые имеют копию нашей ленты.
258 </dd>
259 <dt>has-comments</dt>
260 <dd>Тэг, который помещается в <b>known-by</b>, если известно, что на
261 этом сайте кэшируется копия не только постов, но и дискуссий по ним
262 </dd>
263 <dt>introduce</dt>
264 <dd>URL, по которой другой сайт может сообщить, что он внес наш блог в
265 свой список <b>foaf:knows</b> (и мы должны его внести в свой список
266 <b>known-by</b>
267 </dd>
268 <dt>non-grata</dt>
269 <dd>Список персон, комментарии от которых мы не хотим видеть в нашем
270 блоге, и ни в одной из его копий
271 </dd>
272 <dt>comment-policy</dt>
273 <dd>Набор элементов <b>allow</b> и <b>disallow</b> указывающий на то,
274 кто имеет право постить комментарии. Для большей пущести можно
275 использовать XPath-запрос, который, при применении  к данному foaf-файлу
276 будет возвращать список персон. Ну плюс еще специальные значения
277 <b>anybody</b>
278 (в смысле любой зарегистрированный пользователь) и <b>anonymous</b>.
279 <p>
280 Естественно, что из результата любого запроса вычитается список
281 <b>non-grata</b>. По умолчанию предполагается
282 <b>&lt;allow&gt;anybody&lt;/allow&gt;</b>
283 <p> Этот кусочек неймспейса может потребоваться импортировать не только в foaf, но
284 и в atom - чтобы задавать политику комментирования для отдельных постов.
285 </dd>
286 </dl>
287 <p>foaf следует агрессивно кешировать. Пришел к нам Open-Id
288 пользователь, для того чтобы комментарий оставить - выкачиваем его foaf
289 (чтобы юзерпик показать), и сохраняем у себя. Пришел к нам чужой
290 блог-сервер, отметиться, что хочет читать наш RSS, и его foaf сохраняем. 
291 А вдруг кроме нашего rss у него есть еще какие-то, которые внезапно
292 (когда их оригинальный сервер ляжет) окажутся интересным нам.
293 </p>
294 <p>
295 Закэшированные foaf надо периодически проверять на актуальность. Раз в
296 сутки, по-моему, достаточно. Поэтому крайне рекомендуется при отдаче
297 своего foaf поддерживать HTTP-загловок If-Modified-Since и
298 интерпретировать его именно как &quot;если информация была содержательно
299 изменена&quot;.
300 </p>
301 <p>Тогда, если нам понадобился какой-нибудь блог, основной сайт которого
302 недоступен, мы, весьма вероятно, сможем найти ссылку на его живую копию
303 в  нашей базе данных foaf - сначала проверть known-by в foaf этого
304 блога, потом (или если этот блог не размещает информацию о своих
305 читателях в своем foaf), все knows в других foaf. И есть шанс, что хотя
306 бы на одном из этих сайтов окажется более свежая копия, чем у нас.
307 </p>
308 <p>
309 Юзерпики тоже надо кэшировать. Чтобы внешний вид дискуссии не портился
310 от того, что сервер, пользователь которого год назад оставил у нас
311 комментарий, давно сдох и оживать не собирается.
312 </p>
313 <A NAME="toc_section4"></A><A HREF="#toc_entry4"><h3>Использование Atom</h3></A>
314 <p>
315 Естественно, если мы хотим, чтобы наши посты пользователи могли читать в
316 своих агрегаторах, даже если наш сервер не доступен, мы
317 должны раздавать в виде atom feed полный текст этих постов.
318 </p>
319 <p>Если в постах встретились изображения, их тоже стоило бы кэшировать.
320 Правда, не совсем понятно, как отличить изображение, являющееся
321 интегрированной частью блога и изображение с внешнего по отношению к
322 блогу сайта.
323 </p>
324 <p>
325 В atom feed стоит включать информацию о том, где смотреть информацию о
326 количестве комментариев (даже если мы не поддерживаем распределенного
327 комментирования).
328 </p>
329 <p>Выкачанные atom feed других блогов стоит реэкспортировать, при
330 необходимости добавляя информацию об URL копии. На предмет обеспечения
331 доступности резервной копии.
332 </p>
333 <A NAME="toc_section5"></A><A HREF="#toc_entry5"><H2>Задачи, для которых существующих технологий недостаточно</H2></A>
334 <A NAME="toc_section6"></A><A HREF="#toc_entry6"><h3>Протокол распределенного комментирования</h3></A>
335 <p>
336 С реализацией распределенного комментирования стоит связываться только
337 если мы твердо рассчитываем на то, что дискуссия может активно идти при
338 недоступности основного сайта, причем комментарии будут публиковаться
339 одновременно на нескольких сайтах и автоматически распространяться по
340 всем заинтересованным сайтам. Повторяю, в отсутствие в сети основного
341 сайта. Иначе он не нужен.
342 </p>
343 <p>Поэтому для этой цели не подходит <a
344 href="http://bitworking.org/projects/atom/rfc5023.html">AtomPub</a>.
345 Расширения RSS вроде <a
346 href="http://wellformedweb.org/news/wfw_namespace_elements/">WFW</a>
347 тоже не подходят.
348 </p>
349 <p>Нужно что-то что использует механизм, подобный NNTP-шному
350 IHAVE/SENDME. Причем, в отличие от NNTP, где обычно соседи, с которыми
351 идет обмен, конфигурируются вручную, администратором сервера, здесь
352 децентрализованная сеть обмена комментариев должна формироваться
353 динамически, на основе анализа закэшированных foaf-файлов.
354 </p>
355 <p>Именно для этой цели предназначен описанный мной несколько дней назад
356 <a href="http://vitus.wagner.pp.ru/distributed-comments.txt">Distributed
357 Comments protocol</a>.
358 <p>
359 В случае, когда исходный блог доступен, можно ограничиться схемой
360 &quot;звезда&quot;  - комментарий, запощенный в определенный блог,
361 отправляется на исходный сервер, а уже оттуда распространяется на все
362 остальные. В случае схемы &quot;звезда&quot; расширения от WFW оказываются вполне
363 работоспособны. 
364 </p>
365 <A NAME="toc_section7"></A><A HREF="#toc_entry7"><H3>Реализация записей
366 ограниченного доступа на основе OpenID</h3></A>
367 <p>Теоретически возможно решение, когда при скачивании фида по RSS/Atom
368 агрегатор аутентифицируется по OpenID. В норме OpenID предполагает
369 взаимодействие трех сторон - пользователя с браузером, сервера,
370 подтверждающего его идентичность, и сервера принимающего эту
371 идентичность. Но в случае RSS-агрегатора, встроенного в блог-сервер, 
372 &quot;пользователь&quot; и сервер, подтверждающий идентичность
373 совпадают. Поэтому вполне можно реализовать OpenID в неинтерактивном
374 процессе.
375 </p>
376 <p>На пальцах это выглядит так: сервер, получивший запрос на скачивание
377 фида ограниченного доступа, переспрашивает у сервера по известной ему URL:
378 &quot;Это действительно ты пришел?&quot; и тот ему отвечает:&quot;Да,
379 это я.&quot;. 
380 </p>
381 <p>
382 Тут возникает вопрос о том, можно ли доверять блог-серверу пользователя
383 в той же степени, как самому пользователю. Но этот вопрос надо решать
384 индивидуально. В конце концов, доверяем же мы крупным блог-площадкам,
385 что они не раскроют информацию, которую мы пометили как подзамочную,
386 другим своим пользователям, кроме тех, которым мы это разрешили.
387 </p>
388 <p>Для уменьшения траффика, вероятно, стоит раздавать открытые посты и
389 посты ограниченного доступа разными фидами.
390 </p>
391
392 </BODY>
393 </HTML>