Управление релизами - публикация для группы пользователей - как это будет работать на общедоступном веб-сайте - PullRequest
20 голосов
/ 15 ноября 2011

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

Я работаю в основном со стеком Microsoft (TFS для контроля исходного кода, IIS, asp.net, SQL Server с огромными данными).Разумеется, публичные сайты, поэтому они должны быть размером 24x7x365.Хотя я могу представить себе выпуск моих api / dll только на одном из серверов (в веб-ферме) и его тестирование, как мне это сделать, если есть БД (сохраненные подписи процедур, изменения схемы таблиц)?В настоящее время мы работаем с версиями SP (новые будут mySPNameV2, где в качестве старого будет mySPNameV1 - оба принимают другой набор параметров, следовательно, переименование), а новые API будут использовать SP-V2, где старый API будет продолжать работу с SP-V1.

Я вижу какой-то запах дизайна, но есть ли лучший способ сделать это?

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

Ответы [ 7 ]

5 голосов
/ 24 ноября 2011

В моей компании мы почти всегда делаем любые крупные релизы в шахматном порядке. Мы достигаем этого, добавляя флаг для каждой новой функции в таблице пользователей. По умолчанию этот флаг имеет значение false; и когда мы внедряем эту функцию для большего количества пользователей, мы просто переключаем флаг в таблице БД.

Это означает, что на уровне приложения мы должны убедиться, что во всех местах мы проверяем наличие этого флага. Нажатие кода распространяется на все серверы. Внесены изменения в БД; но только некоторые пользователи видят новую функцию.

На уровне базы данных мы гарантируем, что любые изменения в SP "обратно совместимы". Это делается по следующим простым правилам:

  1. Любые новые параметры, добавленные в SP, должны идти в конец списка параметров.
  2. Новые параметры должны иметь значение по умолчанию. Это сделано для того, чтобы существующие вызовы SP не прерывались.
  3. Если необходимо изменить существующие параметры для SP (или если должен быть изменен порядок параметров), то очевидно, что все вызовы для SP изменены. Но SP закодирован таким образом, что он поддерживает пользователей, у которых эта функция включена, а также пользователей, у которых она не включена.
  4. Большинство изменений в таблице связаны с добавлением новых столбцов. Это действительно редко, когда мы должны изменить существующий столбец. Все новые столбцы добавляются со значением по умолчанию или разрешенными значениями NULL.

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

Кроме того, для каждого пользователя мы храним версию API, которую он использует. В зависимости от версии пользователи переходят на разные URL-адреса API. Поэтому, в основном, когда пользователи совершают первый вызов API для аутентификации, мы передаем новый URL-адрес API (в зависимости от версии API для пользователя). Для всех последующих вызовов они должны вызывать новый URL. Salesforce.com также следует за их вызовами API.

3 голосов
/ 30 ноября 2011

Я был на QCon в прошлом году, когда парень из веб-команды Facebook говорил об этом подходе.Вы на 100% правы, что для реализации этого будут запахи кода.Но это занимает гораздо больше, чем просто запахи кода (на самом деле они называют эти запахи кода Gate Keepers:).

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

Что выможно сделать это, добавив хранители ворот (если (пользователь из Новой Зеландии) {использовать затем новую версию с новыми классами} иначе {прикрепить старую}).

Вы, вероятно, можете представить, какой кодэто приведет к дублированию в случае структурированной модели (например, вам потребуется 2 пользователя, 2 заказа, 2 заказа).Оставляя это в стороне, я думаю, что много регрессии также будет иметь место, если вы не будете предельно осторожны.

Насколько я помню - они выпускают намного чаще, чем только по вторникам.Я думаю, что у них непрерывное развертывание, и код запускается каждый день, просто они очищают старые Gate Gateers / изменения схемы по вторникам, когда к тому времени они переключили всех пользователей на новую функциональность.1012 *

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

Я понимаю, что этот ответ может не соответствоватьбыть достаточно полным, чтобы претендовать на ответ, но я услышал это от их парня и подумал, что стоит поделиться.

1 голос
/ 30 ноября 2011

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

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

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

То же самое относится и к хранимым процедурам - все нестандартные параметры должны иметь значения по умолчанию и т. Д. *

0 голосов
/ 30 ноября 2011

Может быть, я упрощаю здесь, но почему бы просто не создать экземпляр базы данных дальше?

Когда вы проводите подгруппу пользователей для «тестирования», будь то внутреннее, подмножество внешних или окружающих, разве вы не проводите что-то вроде бета-теста? Разве это не вызвало бы другой экземпляр базы данных, который имеет бета-версию хранимых процедур по сравнению с текущей версией / экземпляром? Просто вопрос указания строк подключения в веб-конфигах на этом этапе, не так ли?

Может быть, ограничением здесь является стоимость серверов и «огромных данных», находящихся на них, на которые, я признаю, я заглядываю или вопрос действительно о версии хранимых процедур и т. Д.? Разве они не могут контролироваться как источником, так и изменениями схемы?

Я, вероятно, спросил больше, чем ответил.

0 голосов
/ 30 ноября 2011

Я действительно думал, что этот вопрос получил бы намного больше внимания. Учитывая то, что вы сказали, и существующие ответы, я думаю, что ваше существующее решение является наиболее простым и простым в управлении. Как вы сказали, есть некоторый «запах дизайна» (мне нравится эта фраза), но это имеет смысл.

Возможно, сделаем еще один шаг и объединим некоторые небольшие изменения с вашими собственными:

  • Сохранить существующее соглашение о версии базы данных
  • Выпускать конкретные версии-кандидаты либо на поддоменещатель 01.yoururl.com, либо на конкретный сервер, если у вас есть ферма серверов
  • Используйте флаг в вашей таблице пользователей / участников, чтобы указать, на какой рабочий сервер или поддомен пользователь должен быть направлен
    • Предоставляет возможность перенаправлять некоторых пользователей на сервер-кандидат на выпуск.
    • Не требует количества кода, которое указывал бы вариант ответа для каждой функции, упомянутый в ответе DK (вы можете пойти любым путем, хотя в зависимости от того, какой целью вы хотите быть, но я думаю, что наименее сложный маршрут будет лучше здесь и будет направлять пользователей к конкретным версиям приложения, а не пытаться включать / отключать отдельные функции для каждого пользователя)

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

0 голосов
/ 29 ноября 2011

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

Create Table Features
    (
    Code varchar(10) not null Primary Key
    , StartPage nvarchar(max) not null
    , Description nvarchar(max) not null
    )

Create Table UserFeatures 
    ( 
    UserId ... not null
    , FeatureCode varchar(10) References Features ( Code )
    )

Во-первых, причина, по которой я бы использовал текстовый код для первичного ключа функции, а не суррогатный ключ, такой как столбец IDENTITY или guid, заключается в том, что только система будет запрашивать функции. Пользователи никогда не смогут произвольно добавить функцию. Таким образом, он делает ваш код намного чище и проще для чтения для запроса ...Where FeatureCode = 'AdvancedEntry', чем ...Where FeatureId = 13.

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

Таким образом, если функции тесно интегрированы в существующую кодовую базу и уровень представления (что, кстати, является причиной того, что управление версиями так сложно), альтернативным подходом будет сохранение имени хранимой процедуры, которая должна использоваться в Features таблица Ваш код запросит присоединение к вышеуказанным таблицам и вернет имя хранимой процедуры, которое следует использовать. Для аргументов вы можете сохранить параметризованный вызов в базе данных (например, exec Schema.Foo @bar, @gamma, @beta), и при выполнении запроса просто проверить, содержит ли эта строка заданный параметр, и, если это так, добавить значение этого параметра:

if ( ProcTemplate.Contains( "@bar")
    commandInstance.Parameters.AddWithValue( "@bar", barValue );
if ( ProcTemplate.Contains( "@gamma")
    commandInstance.Parameters.AddWithValue( "@gamma", gammaValue );
...

Если вы сопоставляете объекты с ролями или группами пользователей, вам нужно будет разработать «превентивные» правила, определяющие, какой объект следует использовать в случае возвращения нескольких объектов. При таком подходе вы бы оставили существующие хранимые процедуры без изменений в схеме, которые требовали изменения хранимой процедуры (например, удаление столбца). Бонусным результатом этого подхода является то, что вы можете добавить дату в таблицу Features, чтобы определить, когда новая функция должна появиться в сети.

0 голосов
/ 15 ноября 2011

Вариант 1:

(sub) домен для (полу) (public?) Devsite. Некоторые пользователи принимаются на сайте разработчика на основе файлов cookie, установленных вручную (сотрудники и т. Д.) <Личное тестирование </p>

Основной домен, который устанавливает файлы cookie для определенных пользователей (файлы cookie устанавливаются, когда время находится между временем X и временем Y) <в зависимости от вашего трафика. Если вы получаете 1000 (уникальных) посетителей каждый час и хотите получить 10% от домена dev, вы должны убедиться, что время разницы составляет 6 минут. Вы можете просто удалить файлы cookie, если хотите, чтобы пользователи перенаправлялись на обычный сайт (убедитесь, что вы перенаправили весь входящий URL-адрес, чтобы предотвратить потерю закладок. </p>

Вариант 2:

Распределение нагрузки на определенный процент трафика на серверах, на которых выполняется новое приложение.

База данных

1: Взаимодействие с действующей базой данных при разработке <регулярных резервных копий + обычных опытных разработчиков = безопасно </p>

2: посмотрите репликацию master-slave, чтобы создать «живую» теневую копию вашей БД

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