Как надо устроить распределенный блог-сервер

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

1. Функции изолированного узла-бэкенда

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

Комментарий имеет атрибуты в виде ссылки на комментарий уровнем выше и ссылки на все отвечающие комментарии (для удобства чтения по тредам).

Узел-бэкенд отвечает, после проверки авторизации, на различные запросы; такие, как "выдать все записи пользователя, датированные такими-то датами", "выдать список пользователей, соответствующих такому-то запросу (по интересам, подписке на чью-то ленту и так далее)", "выдать все записи пользователя, модифицированные после такой-то даты", "выдать комментарии с n-го по (n+k)-й к данной записи или в данном треде". Все эти функции реализованы в LJ (или должны быть реализованы, но почему-то не реализованы).

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

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

2. Узел-фронтэнд

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

Фронтэнд есть динамический WWW-сайт, размещенный на сервере, поддерживающем узел-бэкенд. Он сообщается только со своим бэкендом, изображая пользовательскую информацию, ленты для чтения и локальные блоги в виде удобочитаемого HTML. В идеале, юзерские функции и настройки фронтенда должны быть приближены к таковым у LJ, а изолированный узел (фронтенд+бэкенд) должен повторять функциональность LJ-сервера.

Узлы, не желающие поддерживать фронтенд, могут этого и не делать. Дневники, размещенные на таких узлах, можно будет читать только клиентом. Сам по себе бэкенд должен требовать весьма мало ресурсов (кроме дискового пространства, конечно же). Идеальным решением было бы написать его как модуль для Apache.

В дальнейшем слово "узел" обозначает узел-бэкенд.

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

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

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

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

Наконец, тот факт, что проект чрезвычайной культурной значимости (де-факто монопольный блог-сервер и СМИ колоссальной массовости и влияния) окажется в руках людей незаинтересованных (или того хуже - имеющих свои политические и цензурные интересы) представляет колоссальную опасность для общественного механизма. Поэтому надо любой ценой избегать монополии, то есть строить распределенный сервер. Благо на описанной мною архитектуре (фронтенд+бэкенд) это нетрудно осуществить.

4. Механизм авторизации удаленного узла

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

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

После занесения в базу данных узла, удаленному узлу проставляется "уровень доверия". Минимальный (проставленный по дефолту) - возможность идентификации комментариев. Следующий уровень - использование удаленного узла в качестве кэширующего сервера (для открытых записей). Следующий уровень - разрешение удаленному узлу кэширования защищенных записей с локального узла, при условии, что на удаленном узле есть пользователь, авторизованный хозяином локального блога на чтение. Следующий уровень - кэширование всех записей, авторизованных для группы (то есть friends-only, но не private). Максимальное доверие - возможность кэширования всех вообще записей, в том числе приватных (для отзеркаливания сервера, например). Этот уровень лучше не включать, кроме случаев миграции дневников на новый сервер.

Для кэширования потребуется следующая система авторизации: сервер A дает серверу B авторизацию на загрузку записей из A, идущих через промежуточные сервера (C и D), сервера C и D имеют публичную часть секретного кода для A, и сличают ее с разрешением, которое демонстрируется B. Нужно сие, чтобы в случае недоступности A можно было осуществлять распространение кэшируемых записей с этого сервера.

5. Кэширование: опыт NNTP

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

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

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

6. Поддержка кэширования

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

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

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

Вместе с каждым архивом отдаленного блога локально сохраняются также адреса всех нисходящих серверов, сгрузивших кэш этого блога с локального сервера. Это нужно для оповещения нисходящего сервера об изменении статуса кэша (об этом ниже).

С исходящим сервером осуществляется регулярная (каждые 15 минут, например) проверка связи. Если исходящий сервер становится недоступен, локальный сервер оповещает нисходящие сервера, а затем ищет другой удаленный сервер, готовый предоставить ему архивы этого блога, и договаривается с ним об этом. Если исходящий сервер найти не удалось, статус обновления кэша заменяется на "не активный с такого-то момента". Об изменении пути кэширования к удаленному блогу, а также об изменении статуса с активного на не активный и наоборот кэширующий сервер оповещает все нисходящие кэши.

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

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

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

В принципе, можно было бы обойтись цепочками длины 1 или 2 (грузить все от исходного сервера, либо из промежуточного сервера, занимающегося аггрегацией отдельных блогов). Система с распределенным кэшированием хороша тем, что легко переносится на p2p-протоколы, и устойчивее работает в ситуации, когда все узлы - маленькие и ненадежные; а приори, подобную сеть можно поднимать на домашних компьютерах, где установлен, например, Apache (в предположении, что бэкенд реализован как модуль к Apache, либо как отдельная программа, простая в установке).

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

7. Составление френд-ленты: подсчеты

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

Будем исходить из системы в 5 миллионов активных пользователей (имеющих свой дневник и френд-ленту), и 1000 серверов, поддерживающих каждый по 5 тысяч пользователей. При этом типичный пользователь читает по 50 блогов (700 блогов - верхний предел по-любому). Будем считать, что в среднем френд-лента состоит из 200 пользователей. Итого - каждый сервер должен держать в кэше не больше миллиона блогов (реально гораздо меньше, поскольку френд-ленты будут пересекаться). За месяц пользователь пишет в среднем килобайт 30-40, в любом случае не больше 300. Будем исходить из 100 кил, и поддержку в кэше архивов за последний месяц.

Итого, архивы кэша будут составлять не больше 100 гигабайт (реально же в 1000 раз меньше). Это вполне реально - нормальный веб-сервер имеет сейчас по 300-500 гиг веб-пространства, при цене в 1000 долларов, и свободные 100 гиг на нем найти ничего не стоит. Соответствующий траффик (те же 100 гиг, реально ж опять-таки в 1000 раз меньше) стоит копейки.

8. Социальный контракт

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

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

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

Необходимо составить социальный контракт, набор добровольно взятых на себя обязательств хостинга.

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

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

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

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

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

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

Миша Вербицкий

комментарии



Advertisement on IMPERIUM.LENIN.RU:
Хаким-Бей: ОБУЧЕНИЕ КАЛИ-ЮГЕ | Путин над всей землей | Навсегда голодный дедушка Хайдер
Розовый Слонъ: литературный альманахъ | Измена Родине себя не окупает