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

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

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

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

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

8 ответов

Решение

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

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

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

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

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

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

На уровне базы данных мы гарантируем, что любые изменения в 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.

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

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

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

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

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

Итак, в основном:

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

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

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

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

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

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

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

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

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

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

мой ответ очень прост: пусть трафик приходит, бросьте [F5 -балансировщик нагрузки] идет к недавно развернутому пакету (для пользователей подмножества) только на одном производственном сервере (на этом сервере есть новый пакет), и он подключается к другой клонированной БД из производственная среда

Самым простым подходом 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 таблица, чтобы определить, когда новая функция должна выходить в интернет.

Опция 1:

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

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

Вариант 2:

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

База данных

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

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

Другие вопросы по тегам