İçeriğe geç
academia.sh

Ders 26 / 27

Gerçek Kullanıcı İzleme

Laboratuvar ölçümüyle alan verisinin yanıtladığı farklı sorular, alanda ölçüt toplama ve gönderme biçimi, yüzdelik dilim hesabıyla dağılımın okunması, bölütleme ve örneklem büyüklüğünün etkisi.

İçindekiler

Kararlı bir test paketi, denetim altındaki bir ortamda beklenen davranışın korunduğunu söyler. Söylemediği şey, uygulamanın gerçek kullanıcıların elinde nasıl davrandığıdır. Test makinesi hızlıdır, ağı düzgündür, önbelleği bilinen bir durumdadır. Kuzey Yamaç arayüzünü alanda kullanan gözlemci ise zayıf bir bağlantıda, yaşlı bir aygıtla ve arka planda başka sekmelerle çalışır.

Bu ders iki veri kaynağını yan yana koyar ve aradaki farkı ölçülebilir hâle getirir.

İki Kaynak, İki Soru

Laboratuvar verisi, denetimli bir koşumdan gelir: sabit aygıt profili, sabit ağ koşulları, temiz önbellek. Başarım konusundaki ölçümler bu türdendir. Değerli yanı belirlenimci olmasıdır — iki koşum arasındaki fark, koda yapılan değişikliğe bağlanabilir. Yanıtladığı soru şudur: bu değişiklik neyi bozdu?

Alan verisi, gerçek oturumlardan toplanan ölçümlerdir; toplama yöntemine gerçek kullanıcı izleme (real user monitoring) denir. Tek bir sayı değil, bir dağılım verir. Yanıtladığı soru farklıdır: kullanıcılar gerçekte ne yaşıyor?

İkisi birbirinin yerine geçmez. Laboratuvar ölçümü gerileme tespiti için, alan verisi hedef belirlemek için kullanılır.

Alanda Ne Toplanır

Tarayıcı, ölçütleri kendi başına biriktirir ve bir gözlemciyle sunar. Aşağıdaki kod boyama kayıtlarını ve eşiği aşan etkileşim kayıtlarını toplar, sayfa gizlendiğinde tek bir demet hâlinde gönderir.

// olcut-toplayici.js — alan olcutlerini toplar ve tek demet halinde gonderir
const demet = { yol: location.pathname, surum: '2.4.1', olcutler: {} };

const gozlemci = new PerformanceObserver((liste) => {
  for (const kayit of liste.getEntries()) {
    demet.olcutler[kayit.name] = Math.round(kayit.startTime ?? kayit.duration);
  }
});
gozlemci.observe({ type: 'paint', buffered: true });
gozlemci.observe({ type: 'event', buffered: true, durationThreshold: 40 });

addEventListener('visibilitychange', () => {
  if (document.visibilityState !== 'hidden') return;
  gozlemci.takeRecords();
  navigator.sendBeacon('/olcut', JSON.stringify(demet));
}, { once: true });

Üç karar bu kodun içindedir. buffered seçeneği, gözlemci kurulmadan önce oluşmuş kayıtları da getirir; ölçüm betiği geç yüklendiğinde ilk boyama kaybolmasın diye. Gönderim sayfa kapanışında değil, sayfa gizlendiğinde yapılır: bir sekme kapanmadan arka plana atılıp bir daha öne gelmeyebilir ve o durumda kapanış olayı hiç çalışmaz. Gönderim, sayfa kaldırılırken de tamamlanan bir işaret isteğiyle yapılır.

Demete bağlam alanları eklenir: yol, uygulama sürümü, aygıt sınıfı, bağlantı türü, gezinme türü. Bölütleme bu alanlarla yapılır ve bir sonraki bölümde görüleceği gibi, tek bir sayının gizlediği şey burada ortaya çıkar.

Toplama her oturumda yapılmak zorunda değildir. Örnekleme, oturumların bir bölümünden veri almaktır; oranı düşürmek iletim ve saklama maliyetini düşürür. Seçim oturum başına bir kez yapılmalıdır — sayfa başına yapılırsa aynı oturumun bazı sayfaları örnekleme girer, bazıları girmez ve oturum düzeyindeki sorular yanıtsız kalır.

Dağılımı Okumak

Alan verisi bir dağılımdır ve dağılımı tek sayıya indirmenin birden çok yolu vardır. Aşağıdaki modül belirlenimci bir alan örneklemi üretir — üç aygıt sınıfı, farklı paylarla ve farklı süre aralıklarıyla — ve yüzdelik dilim hesabını verir.

// alan-verisi.mjs — alan olcumlerinin belirlenimci benzetimi ve yuzdelik hesabi
export function uretec(tohum) {
  let s = tohum >>> 0;
  return () => {
    s = (Math.imul(s, 1664525) + 1013904223) >>> 0;
    return s / 4294967296;
  };
}

export const SINIFLAR = [
  { ad: 'hizli', pay: 0.60, taban: 300, yayilim: 200 },
  { ad: 'orta', pay: 0.30, taban: 700, yayilim: 600 },
  { ad: 'yavas', pay: 0.10, taban: 1800, yayilim: 2200 },
];

export function alanOrneklemi(sayi, tohum = 42) {
  const rastgele = uretec(tohum);
  const ornekler = [];
  for (let i = 0; i < sayi; i += 1) {
    const secim = rastgele();
    let birikim = 0;
    const sinif = SINIFLAR.find((s) => (birikim += s.pay) >= secim) ?? SINIFLAR.at(-1);
    ornekler.push({ sinif: sinif.ad, sure: Math.round(sinif.taban + sinif.yayilim * rastgele()) });
  }
  return ornekler;
}

// en yakin siralama yontemi: p yuzdeliginin altinda kalan orneklerin orani en az p'dir
export function yuzdelik(degerler, p) {
  if (degerler.length === 0) return NaN;
  const sirali = [...degerler].sort((a, b) => a - b);
  const sira = Math.ceil((p / 100) * sirali.length);
  return sirali[Math.min(sirali.length, Math.max(1, sira)) - 1];
}

export function ortalama(degerler) {
  return Math.round(degerler.reduce((t, d) => t + d, 0) / degerler.length);
}
// rapor.mjs — laboratuvar olcumu ile alan dagiliminin karsilastirilmasi
import { alanOrneklemi, yuzdelik, ortalama, SINIFLAR } from './alan-verisi.mjs';

const alan = alanOrneklemi(5000);
const sureler = alan.map((o) => o.sure);

// laboratuvar kosumu: hizli aygit, kararli ag, dagilimin ortasi
const hizli = SINIFLAR[0];
const laboratuvar = Math.round(hizli.taban + hizli.yayilim * 0.5);

console.log(`laboratuvar olcumu   ${String(laboratuvar).padStart(5)} ms`);
console.log(`alan ortalamasi      ${String(ortalama(sureler)).padStart(5)} ms`);
for (const p of [50, 75, 90, 95]) {
  console.log(`alan p${String(p).padEnd(2)}             ${String(yuzdelik(sureler, p)).padStart(5)} ms`);
}

console.log('\naygit sinifina gore p75');
for (const s of SINIFLAR) {
  const alt = alan.filter((o) => o.sinif === s.ad).map((o) => o.sure);
  console.log(`  ${s.ad.padEnd(6)} ${String(alt.length).padStart(4)} oturum   p75 = ${yuzdelik(alt, 75)} ms`);
}

console.log('\norneklem buyuklugu ve p75 kararliligi');
for (const n of [20, 100, 1000, 5000]) {
  const p75ler = [0, 1, 2, 3, 4].map((t) => yuzdelik(alanOrneklemi(n, 100 + t).map((o) => o.sure), 75));
  console.log(`  n=${String(n).padStart(4)}  ${p75ler.join('  ')}`);
}
node rapor.mjs
laboratuvar olcumu     400 ms
alan ortalamasi        848 ms
alan p50               471 ms
alan p75              1014 ms
alan p90              1853 ms
alan p95              2971 ms

aygit sinifina gore p75
  hizli  2918 oturum   p75 = 452 ms
  orta   1561 oturum   p75 = 1143 ms
  yavas   521 oturum   p75 = 3473 ms

orneklem buyuklugu ve p75 kararliligi
  n=  20  775  930  837  1073  900
  n= 100  1054  1027  967  1082  1049
  n=1000  978  968  1006  1017  986
  n=5000  985  1001  996  1016  992

Sayıların Söylediği

Laboratuvar ölçümü 400 milisaniye. Alandaki dağılımın ortancası 471, dörtte üçlük dilimi 1014. Yani denetimli koşum, kullanıcıların iyi yarısını temsil ediyor ve kalan yarının gerçeğini hiç göstermiyor. Bu, laboratuvar ölçümünün yanlış olduğu anlamına gelmez; kapsamının dar olduğu anlamına gelir.

Ortalama 848 milisaniye ve hiçbir kullanıcı grubunu tarif etmiyor. Dağılımın kuyruğu uzun olduğunda ortalama, azınlıktaki çok yavaş oturumlar tarafından yukarı çekilir; sonuç ne çoğunluğun deneyimidir ne de en kötü durumun ölçüsü. Süre dağılımlarında ortalama okunmaz.

Yüzdelik dilim seçimi bir denge sorunudur. Medyan kullanıcıların yarısını gizler. p95 ve üstü, tek tük uç oturumlarla — arka planda kalmış bir sekme, aşırı yüklü bir aygıt — oynamaya başlar ve gürültülüdür. p75 ikisinin arasındadır: dörtte üç oranında kullanıcının altında kaldığı değeri verir ve kuyruğa yeterince duyarlıdır. Alan ölçütleri bu yüzden yaygın olarak dörtte üçlük dilimden okunur.

Bölütleme tablosu tek sayının neyi gizlediğini gösteriyor. Aynı uygulamanın p75 değeri hızlı aygıtlarda 452, orta sınıfta 1143, yavaş sınıfta 3473 milisaniye. Genel değer olan 1014, bu üç gerçekten hiçbirine karşılık gelmiyor. İyileştirme kararı ancak bölütlerle verilebilir: yavaş sınıftaki 521 oturum, genel ortalamayı düzeltmeye çalışan her işten daha çok kazanç taşır.

Son tablo örneklem büyüklüğünün etkisidir. Yirmi oturumluk beş ayrı örneklemin p75 değerleri 775 ile 1073 arasında dolaşıyor — aynı dağılımdan gelmelerine rağmen. Bin oturumda aralık 968 ile 1017 arasına daralıyor. Küçük örneklemle ölçülen bir “iyileşme”, çoğu zaman yalnızca örneklem gürültüsüdür. Bir ölçütü bölütlere ayırmak da örneklem büyüklüğünü böler; her bölütün kendi başına yeterli oturumu olmalıdır.

Bütçeye Bağlamak

Başarım konusunda tanımlanan bütçe, alan verisiyle doğrulandığında anlam kazanır. Bütçe denetimi bir teste dönüştürülebilir.

// butce.test.mjs
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { alanOrneklemi, yuzdelik } from './alan-verisi.mjs';

const BUTCE = { p75: 1200, yavasSinifP75: 4000 };

test('genel p75 butcenin altinda', () => {
  const sureler = alanOrneklemi(5000).map((o) => o.sure);
  assert.ok(yuzdelik(sureler, 75) <= BUTCE.p75, `p75 = ${yuzdelik(sureler, 75)} ms`);
});

test('yavas aygit sinifi kendi butcesinin altinda', () => {
  const yavas = alanOrneklemi(5000).filter((o) => o.sinif === 'yavas').map((o) => o.sure);
  assert.ok(yavas.length >= 300, 'yeterli ornek yok');
  assert.ok(yuzdelik(yavas, 75) <= BUTCE.yavasSinifP75, `yavas p75 = ${yuzdelik(yavas, 75)} ms`);
});
node --test butce.test.mjs
✔ genel p75 butcenin altinda (2.985458ms)
✔ yavas aygit sinifi kendi butcesinin altinda (0.718ms)
ℹ tests 2
ℹ suites 0
ℹ pass 2
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 37.70275

İki testin ayrı bütçeleri olması bilinçlidir. Tek bir genel eşik, yavaş sınıfın bozulmasını hızlı sınıfın iyileşmesiyle örtebilir. Bölüt başına bütçe bu takası engeller.

Toplanan verinin kapsamı da bir karardır. Ölçüt demeti kullanıcıyı tanımlayan alan taşımamalıdır; yol bilgisi kimlik içeren parçalardan arındırılır, serbest metin hiç gönderilmez. Ölçüm kodunun kendisinin de bir maliyeti vardır — gözlemci geri çağrıları ana iş parçacığında çalışır ve ölçtüğü şeyi bir miktar yavaşlatır.

Özet

  • Laboratuvar verisi belirlenimcidir ve gerileme tespitine yarar; alan verisi bir dağılımdır ve kullanıcıların gerçekte ne yaşadığını söyler.
  • Ölçütler tarayıcının gözlemcisiyle toplanır ve sayfa gizlendiğinde tek demet hâlinde gönderilir; örnekleme kararı oturum başına bir kez verilir.
  • Süre dağılımlarında ortalama okunmaz; ortanca yarıyı gizler, çok yüksek dilimler gürültülüdür, dörtte üçlük dilim ikisinin arasındadır.
  • Laboratuvar ölçümü 400 milisaniyeyken alan p75 değeri 1014 çıktı; bölütlere ayrıldığında aynı ölçüt 452, 1143 ve 3473 milisaniye oldu.
  • Küçük örneklemde p75 geniş bir aralıkta dolaşır; bölüt başına bütçe, bir sınıftaki bozulmanın bir başkasındaki iyileşmeyle örtülmesini engeller.

Sonraki Adım

Ölçütler uygulamanın ne kadar hızlı olduğunu söyler; çalışıp çalışmadığını söylemez. Bir gözlemci ölçümü kaydetmeye çalışırken bir istisna fırlarsa, o oturumun süre ölçütleri gayet iyi görünmeyi sürdürür. Kullanıcı ise boş bir ekrana bakmaktadır ve çoğu zaman kimseye haber vermez. Son ders bu sessiz başarısızlıkları görünür kılan düzeneği ele alır: istemci hatalarının yakalanması, gönderilmesi ve binlerce olayın tek tek değil, aynı kökene inen gruplar hâlinde okunması.

İ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