İçeriğe geç
academia.sh

Ders 11 / 14

Aşamalı Yayın ve Geri Alma

Aşamalı yayın, yeni bir sürümü kullanıcıların yalnız bir kısmına açar; sorun çıkarsa yayın durdurulur ya da özellik kapatılır. Ders, yayının ulaştığı her kovada özelliğin ne kadar çalıştığını ayrı ayrı ölçer.

Yayın Güncelleme

Bu derste

  • Aşamalı yayını, kovayı ve yayının durdurulmasını mobil bir yayın akışında tanımlar
  • Geri alma ile ileri doğru düzeltmeyi karşılaştırır ve kurulmuş bir sürümün geri çekilemeyeceğini açıklar
  • Yayının her kovasının koşulunu kurup özelliğin işlerliğini kova başına ölçer
  • Yayının ulaştığı aygıt sayısının işlerliği belirlemediğini ölçümle gösterir
İçindekiler

Önceki derste yeni sözleşmeyi isteyen istemci, sunucu henüz hazır değilken yayımlanırsa kullanıcıların bir kısmının özelliği kısıtlı gördüğünü ölçtük. Bu ders o kısmı bilerek ve denetimle belirlemenin yolunu anlatır. Yeni sürüm bütün kullanıcılara birden açılmaz; önce küçük bir gruba açılır, sorun görünmezse grup büyür.

Kursun sorusu aynı kalır: bu koşulda bu özellik ne kadar çalışıyor? Bu derste koşul, aygıtın yayının hangi kovasında olduğudur.

Aşamalı Yayın

Aşamalı yayında bir sürüm mağazada yayımlanır, ama yalnız kullanıcıların bir bölümüne sunulur. Mağaza bölümü kendisi seçer. Android’de ekip yayının hangi aşamaya geçeceğini belirler; iOS’ta aşamalar sabit bir takvimle kendiliğinden ilerler, ekip yalnız yayını duraklatır ya da herkese açar. Aşama genişledikçe sürümü alabilen kullanıcı sayısı artar; son aşamada herkes alır.

Bu düzenin değeri, bir hatanın etkisini sınırlamasıdır. Yeni sürüm beklenmedik bir hata taşıyorsa, hata önce küçük bir grupta görünür. Çökme raporları ve kullanıcı bildirimleri izlenir; işler yolundaysa yayın bir sonraki aşamaya geçer. İzleme ayrı bir dersin konusudur ve bu kursun kapanışında ele alınır.

Aşamalı yayın tek bir mekanizma değildir. Mağazanın kendi aşamalı yayın özelliği sürümü aygıtlara dağıtır. Uygulamanın içindeki bayrak ise sürümü alan aygıtlarda özelliği açıp kapatır. İkisi birlikte kullanılabilir: sürüm mağaza düzeyinde bir kısım aygıta ulaşır, özellik bayrak düzeyinde onların da yalnız bir kısmında açılır.

M12/K02’de bir değişikliğin üretime nasıl ulaştığı anlatıldı. Aşamalı yayında yeni sürüm yalnız bazı kovalara ulaşır; işlerlik ise ulaşılan aygıt sayısını değil, her kovadaki işlerliği sınıflar. Sürümün kaç aygıta ulaştığı yayın planının sorusudur. Ulaştığı kovada özelliğin ne kadar çalıştığı işlerliğin sorusudur.

Kova ve Yayının Durdurulması

Kova, aygıtların kararlı bir kurala göre ayrıldığı gruptur. Kural aygıt kimliğinden bir sayı türetir ve o sayıyı kova sayısına böler; kalan, aygıtın kovasıdır. Aynı aygıt her zaman aynı kovaya düşer. Bu kararlılık önemlidir: yayın genişlediğinde ilk kovadaki aygıt kovasından çıkmaz, açık kovalar listesine yenileri eklenir.

Yayın aşamalarını bir yapılandırma dosyası tutabilir. Aşağıdaki parça yalnız şekli gösterir; ölçülmez.

# Platform kodu: asamali yayin asamalari
rollout:
  - stage: first
    buckets: [2]
  - stage: wider
    buckets: [2, 3]
  - stage: full
    buckets: [0, 1, 2, 3]

Yayını durdurmak, bir sonraki aşamaya geçmemek demektir. Durdurulan yayında sürümü almış aygıtlar onu kullanmaya devam eder. Android’de yeni aygıtlar sürümü almaz; iOS’ta durdurma yalnız otomatik güncellemeyi keser, sürümü mağazadan kendisi indiren kullanıcı onu yine alabilir. Durdurma yeni etkilenen kullanıcı sayısını büyük ölçüde dondurur, ama etkilenmiş olanları iyileştirmez.

Geri Alma ve İleri Düzeltme

Durdurma yetmediğinde iki yol kalır.

Geri alma, kullanıcıyı önceki davranışa döndürmektir. Mobilde kurulmuş bir sürüm geri çekilemez. Mağaza, kullanıcının aygıtındaki uygulamayı eski bir sürüme indirmez; en fazla eski sürümü yeniden sunar, o da bir güncelleme olarak ve yeni bir sürüm numarasıyla. Bu yüzden mobilde geri alma çoğunlukla sürümün değil, özelliğin geri alınması anlamına gelir.

Özelliği geri almanın aracı uzaktan kapatma bayrağıdır: özellik bayrağın arkasında gönderilir, sorun çıkarsa bayrak çekilir ve uygulama eski davranışa döner. Bayrak uzaktan okunuyorsa bunun için yeni bir sürüm gerekmez; bu, mağaza incelemesini beklemeden etkiyi kesmenin tek yoludur. Aşağıdaki iki parça bayrağın okunuşunu gösterir.

// Platform kodu: uzaktan kapatma bayragi okuma
val enabled = config.getBoolean("new_feed_enabled")
if (enabled) showNewFeed() else showLegacyFeed()
// Platform kodu: uzaktan kapatma bayragi okuma
let enabled = config.bool(forKey: "new_feed_enabled")
if enabled { showNewFeed() } else { showLegacyFeed() }

İleri düzeltme, hatayı düzelten yeni bir sürümü yayımlamaktır. Geri alma kadar hızlı değildir, çünkü yeni sürüm mağaza incelemesinden geçer ve kullanıcının onu kurmasını bekler. Ama bayrağın arkasına alınmamış bir özellik için tek yol odur.

İkisinin seçimi, özelliğin bayrağın arkasında olup olmamasına bağlıdır. Bayrağın arkasındaki özellik için önce geri alma, ardından acele etmeden ileri düzeltme gelir. Bayraksız bir özellikte yalnız ileri düzeltme vardır ve etkilenen kullanıcılar düzeltilmiş sürümü kurana kadar sorunla yaşar.

Yayının Koşulunu Ölçmek

Ölçüm için yeni haber akışını ele alalım. NewFeed ağı ve flag:new-feed yeteneğini ister; bayrağın yedeği yoktur. LegacyFeed eski akıştır ve yalnız ağı ister. Yayın açık kovalarda bayrağı sağlar, kapalı kovalarda sağlamaz. Çekirdek ilk dersten tanıdıktır ve her derste aynı biçimde yeniden verilir; ders ona dokunmaz.

// operability.mjs — bir ozelligin bir kosulda ne kadar calistigini siniflandirir
export const LEVELS = ["tam", "kisitli", "ertelenen", "kapali"];
const FALLBACKS = ["kisitli", "ertelenen"];

export function feature(name, needs, fallback = {}) {
  return { name, needs, fallback };
}

export function condition(name, has) {
  return { name, has };
}

function judge(item, cond) {
  const missing = item.needs.filter((need) => !cond.has.includes(need)).sort();
  let level = "tam";
  for (const need of missing) {
    const given = FALLBACKS.includes(item.fallback[need]) ? item.fallback[need] : "kapali";
    if (LEVELS.indexOf(given) > LEVELS.indexOf(level)) level = given;
  }
  return { level, feature: item.name, condition: cond.name, missing };
}

export function assess(features, conditions) {
  const records = [];
  for (const cond of conditions) {
    for (const item of features) records.push(judge(item, cond));
  }
  return records;
}

export function printLevels(records) {
  for (const r of records) {
    const missing = r.missing.length === 0 ? "-" : r.missing.join(",");
    console.log(`${r.level}: ${r.feature} @ ${r.condition} eksik=${missing}`);
  }
}

export function countLevels(records) {
  for (const name of LEVELS) {
    console.log(`${name}: ${records.filter((r) => r.level === name).length}`);
  }
  console.log(`etkilenen: ${records.filter((r) => r.level !== "tam").length}`);
}

Çekirdeğin ardından dersin yardımcı dosyası gelir. bucketOf(deviceId, bucketCount) aygıt kimliğinin karakter kodlarını toplar ve toplamı kova sayısına böler; kalan kovadır. rolloutConditions(fleet, openBuckets, bucketCount) her aygıttan bir koşul üretir: ağ her aygıtta vardır, bayrak yeteneği yalnız kovası açık olanlara eklenir.

// rollout.mjs — aygiti kovasina ayirir, acik kovalardan kosul uretir
import { feature, condition } from "./operability.mjs";

export function bucketOf(deviceId, bucketCount) {
  let sum = 0;
  for (const ch of deviceId) sum += ch.charCodeAt(0);
  return sum % bucketCount;
}

export function rolloutConditions(fleet, openBuckets, bucketCount) {
  return fleet.map((deviceId) => {
    const open = openBuckets.includes(bucketOf(deviceId, bucketCount));
    return condition(deviceId, open ? ["network", "flag:new-feed"] : ["network"]);
  });
}

export const rolloutFeatures = [
  feature("NewFeed", ["network", "flag:new-feed"]),
  feature("LegacyFeed", ["network"]),
];

YI5. Model, yayını sabit bir aygıt listesi ve dört kovayla kurar. Gerçek bir yayında aygıt sayısı sürekli değişir ve kova sayısı çok daha büyüktür; ayrıca mağazanın aşamalı yayını ile uygulamanın bayrağı iki ayrı mekanizmadır ve her biri kendi kovalama kuralını kullanabilir. Model yalnız tek bir kuralı gösterir ve bu işlerliğin kuralını kurar; model çerçevenin kendisi değildir.

İlk ölçüm yayının ilk aşamasını gösterir: yalnız 2 numaralı kova açıktır. Önce dört aygıtın kovası basılır, sonra sekiz kayıt gelir.

// main.mjs
import { assess, printLevels } from "./operability.mjs";
import { bucketOf, rolloutConditions, rolloutFeatures } from "./rollout.mjs";

const fleet = ["device-a", "device-b", "device-c", "device-d"];
for (const deviceId of fleet) {
  console.log(`kova: ${deviceId} ${bucketOf(deviceId, 4)}`);
}
printLevels(assess(rolloutFeatures, rolloutConditions(fleet, [2], 4)));
kova: device-a 2
kova: device-b 3
kova: device-c 0
kova: device-d 1
tam: NewFeed @ device-a eksik=-
tam: LegacyFeed @ device-a eksik=-
kapali: NewFeed @ device-b eksik=flag:new-feed
tam: LegacyFeed @ device-b eksik=-
kapali: NewFeed @ device-c eksik=flag:new-feed
tam: LegacyFeed @ device-c eksik=-
kapali: NewFeed @ device-d eksik=flag:new-feed
tam: LegacyFeed @ device-d eksik=-

Dört aygıt dört ayrı kovaya düşer. Yalnız device-a açık kovadadır ve orada NewFeed tamdır. Öteki üç aygıtta bayrak yoktur; NewFeed kapalıdır, çünkü bayrağın yedeği tanımlı değildir. LegacyFeed dört aygıtta da tamdır. Kapalı olan aygıtın kullanıcısı akışsız kalmaz; eski akışı görür. Yeni akışın kapalı olması ile eski akışın tam olması iki ayrı kayıttır.

Genişletme ve Geri Alma

Yayın genişlediğinde açık kovalar listesine yeni kova eklenir. Geri alındığında liste boşalır. Kural her iki durumda da aynı biçimde çalışır; değişen yalnız koşuldaki yetenektir.

İkinci ölçüm iki aşamayı art arda koyar. Önce 2 ve 3 numaralı kovalar açılır; sonra bayrak çekilir ve açık kova kalmaz. Yalnız NewFeed kayıtları basılır.

// main.mjs
import { assess, printLevels } from "./operability.mjs";
import { rolloutConditions, rolloutFeatures } from "./rollout.mjs";

const fleet = ["device-a", "device-b", "device-c", "device-d"];
const stages = [
  { name: "genisletme", open: [2, 3] },
  { name: "geri-alma", open: [] },
];
for (const stage of stages) {
  console.log(`asama: ${stage.name} acik-kova=${stage.open.length === 0 ? "-" : stage.open.join(",")}`);
  const records = assess(rolloutFeatures, rolloutConditions(fleet, stage.open, 4));
  printLevels(records.filter((r) => r.feature === "NewFeed"));
}
asama: genisletme acik-kova=2,3
tam: NewFeed @ device-a eksik=-
tam: NewFeed @ device-b eksik=-
kapali: NewFeed @ device-c eksik=flag:new-feed
kapali: NewFeed @ device-d eksik=flag:new-feed
asama: geri-alma acik-kova=-
kapali: NewFeed @ device-a eksik=flag:new-feed
kapali: NewFeed @ device-b eksik=flag:new-feed
kapali: NewFeed @ device-c eksik=flag:new-feed
kapali: NewFeed @ device-d eksik=flag:new-feed

Genişletmede device-a ve device-b açık kovalardadır ve NewFeed orada tamdır; device-c ve device-d hâlâ kapalıdır. Geri almada dört aygıtın dördü de kapalıya döner. Bayrağın çekilmesi bir kayıt düzeyinde şunu söyler: yeni akışın ihtiyaç duyduğu yetenek artık hiçbir aygıtta yoktur.

Geri alma bir işlerlik düzeyi değildir. Geri alma, ekibin yaptığı bir iştir; işlerlik ise o işin sonunda koşulun ne olduğunu sınıflar. Kural bayrağı kimin çektiğini, ne zaman çektiğini ya da neden çekildiğini görmez; yalnız çekildikten sonra flag:new-feed yeteneğinin yokluğunu görür.

YI6. Model, bayrağın çekilmesinin her aygıta anında yansıdığını varsayar. Gerçekte aygıtlar yapılandırmayı farklı zamanlarda okur ve çevrimdışı kalmış bir aygıt eski değeri bir süre daha kullanabilir. Geri alma bu yüzden bir anda değil bir dağılım olarak gerçekleşir. Kural bu dağılımı göstermez; her aygıtın okuduğu değere göre ayrı bir koşul kurulmasını ister.

Sınırlayıcı Ölçüm

Bu dersin odak kaydı NewFeed @ device-a’dır; yayının ilk aşamasında açık kovadaki ilk aygıt. Sınırlayıcı ölçüm iki şeyi birlikte gösterir. Birincisi, odak kayıt açık kovada tamdır ve sekiz kaydın üçü etkilenir. İkincisi, yayının ulaştığı aygıt sayısı odak kaydı belirlemez: yayın bir kova daha genişlediğinde device-a’nın kaydı değişmez.

// main.mjs
import { assess, printLevels, countLevels } from "./operability.mjs";
import { rolloutConditions, rolloutFeatures } from "./rollout.mjs";

const fleet = ["device-a", "device-b", "device-c", "device-d"];
const records = assess(rolloutFeatures, rolloutConditions(fleet, [2], 4));
printLevels(records.filter((r) => r.feature === "NewFeed" && r.condition === "device-a"));
countLevels(records);
const reached = records.filter((r) => r.feature === "NewFeed" && r.level === "tam").length;
console.log(`ulasilan aygit: ${reached} toplam: ${fleet.length}`);

const wider = assess(rolloutFeatures, rolloutConditions(fleet, [2, 3], 4));
const pick = (list) => list.find((r) => r.feature === "NewFeed" && r.condition === "device-a");
const same = JSON.stringify(pick(records)) === JSON.stringify(pick(wider));
console.log(`odak kaydi pay degisince ayni: ${same ? "evet" : "hayir"}`);
tam: NewFeed @ device-a eksik=-
tam: 5
kisitli: 0
ertelenen: 0
kapali: 3
etkilenen: 3
ulasilan aygit: 1 toplam: 4
odak kaydi pay degisince ayni: evet

İlk satır dersin işlerliğini taşır: açık kovadaki aygıtta yeni akış tamdır. Sayım satırları sekiz kayıttan beşinin tam, üçünün kapalı olduğunu söyler; etkilenen üçtür. Ulaşılan aygıt sayısı dörtte birdir.

Son iki satır modelin sınırını gösterir. Ulaşılan aygıt sayısı yayın planının sayısıdır; özelliğin her aygıtta ne kadar çalıştığını söylemez. Ulaşılmış aygıtta yeni akışın tam olması, ulaşılmamış aygıtların hiçbirinde bir şeyin bozuk olduğu anlamına gelmez; orada yeni akış hiç sunulmamıştır ve eski akış tam çalışır. Yayın genişleyip ulaşılan sayı ikiye çıksa da device-a’nın kaydı aynı kalır. Pay, hangi aygıtların hangi kayda düştüğünü değiştirir, bir kaydın kendisini değil.

Bu ayrım yayın kararlarında kullanılır. Genişletmeden önce sorulacak soru, ulaşılan aygıt sayısının yeterince büyük olup olmadığı kadar, ulaşılan kovalarda özelliğin tam çalışıp çalışmadığıdır. İkisine de ayrı ayrı bakılır.

Özet

  • Bu dersin işlerliği: tam. NewFeed @ device-a, aygıtın kovası açık olduğu için bayrak yeteneğini sağlar ve yeni akış tam çalışır; kapalı kovalardaki üç aygıtta aynı özellik kapalı kaldı.
  • Aşamalı yayın sürümü kovalara açar; durdurma yayının genişlemesini keser (iOS’ta yalnız otomatik güncellemeyi), ama kurulmuş sürümü geri çekmez.
  • Mobilde geri alma çoğunlukla özelliğin geri alınmasıdır: uzaktan kapatma bayrağı mağaza incelemesini beklemeden etkiyi keser, bayraksız özellikte yalnız ileri düzeltme kalır.
  • Sekiz kayıttan beşi tam, üçü kapalıydı; etkilenen üç. Bayrak çekilince dört aygıtın dördünde yeni akış kapalıya döndü.
  • Yayın bir kova genişleyince odak kayıt değişmedi; işlerlik ulaşılan aygıt sayısını değil, her kovadaki koşulu sınıflar.

Sonraki Adım

Bu derste yeni sürüm bazı kullanıcılara ulaşmadı ve eski sürüm sorunsuz yaşadı. Her zaman böyle olmaz: bazı sürümleri artık desteklemek mümkün değildir. Sıradaki ders, Zorunlu Güncelleme Stratejisi, en düşük desteklenen sürümü, yumuşak ve zorunlu güncelleme istemini ve eski sürümün desteğinin sona ermesini ele alır. Sonra sunucunun istediği en düşük sürümün altında kalan bir istemcide ödeme özelliğinin ne kadar çalıştığını ölçer.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ ↵ Esc gezin · aç · kapat