31 Ekim 2025 Cuma

Ubuntu 24.04’te Rootless Podman: Kurulum, Güvenlik ve Performans İpuçları (Güncel Kılavuz)

Rootless Podman Nedir?

Podman, Docker benzeri bir konteyner motorudur ancak arka planda daemon gerektirmez ve root yetkisi olmadan çalışabilir. Rootless (köksüz) kurulumlar, tekil kullanıcıların sistem genelinde yetki almadan konteyner çalıştırmasına izin vererek saldırı yüzeyini daraltır. Ubuntu 24.04 LTS ile gelen güncel çekirdek ve kullanıcı alanı araçları, rootless Podman kullanırken güvenlik ve performans açısından önemli avantajlar sunar.

Önkoşullar ve Kurulum

Başlamadan önce sisteminizin güncel olduğundan emin olun. Ubuntu 24.04 ile Podman 4.x/5.x depolarda hazır gelir. Kurulum için sudo apt update && sudo apt install -y podman uidmap fuse-overlayfs slirp4netns komutu yeterlidir. Bu paketler, köksüz ağ ve depolama katmanları için gereklidir. Gerekirse buildah ve podman-compose de ekleyebilirsiniz.

Kullanıcı adınız için kullanıcı ve grup eşlemesi (subuid/subgid) tanımlı olmalıdır. Bunu /etc/subuid ve /etc/subgid dosyalarında kullaniciadi:100000:65536 biçiminde kontrol edin. Eksikse ekleyin ve oturumu yeniden başlatın. Bu sayede rootless Podman, kullanıcı ad alanlarını güvenle izole eder.

Kullanıcı oturumunuzda Podman’ı ilk kez çalıştırdığınızda, podman info ile köksüz modun aktif olduğunu doğrulayın. graphRoot ve runRoot yollarının ~/.local/share/containers ve /run/user/<uid> gibi kullanıcı alanına işaret etmesi gerekir.

Rootless Ağ ve DNS

Köksüz ağ, slirp4netns ile sağlanır. Varsayılan ayarlar çoğu senaryoda yeterli olsa da yüksek throughput gereken durumlarda --network slirp4netns:mtu=65520,tap=true gibi iyileştirmeler deneyebilirsiniz. DNS tarafında, /etc/resolv.conf içeriği konteyner içerisine geçirildiğinden sıkı DNS politikalarınız varsa özel bir --dns parametresi belirtmek bağlantı sorunlarını azaltır.

Depolama: fuse-overlayfs ve Katman Önbelleği

Rootless modda overlay sürücüsü, fuse-overlayfs üzerinden çalışır. Performansı iyileştirmek için Podman otomatik algılama yapar; yine de podman info ile store.graphDriverName değerinin overlay olduğunu doğrulayın. Büyük imajlarda build sürelerini kısaltmak için podman build --layers=true --cgroup-manager=cgroupfs --jobs=4 gibi parametreler kullanabilirsiniz. --jobs, bağımsız katmanların eşzamanlı derlenmesini teşvik eder.

Sık kullanılan baz imajları yerel olarak güncel tutmak önbelleği güçlendirir. podman pull ile düzenli çekim yapın ve podman image prune ile atık katmanları temizleyin. Geliştirme sırasında bağımlılıkları ayrı katmanlara taşımak (ör. pip install -r requirements.txt adımını kod kopyalamadan önce yapmak) build tekrarlarında büyük fark yaratır.

Güvenlik Sertleştirmeleri

Rootless Podman zaten güçlü bir izolasyon sağlar; yine de ek sertleştirme önerilir. Çalıştırma sırasında gereksiz yetkileri bırakmak için --cap-drop=ALL ile başlayın ve yalnızca gerekliyse spesifik yetkileri ekleyin. Dosya sistemi bütünlüğü için --read-only ve yazma gereken yollar için -v /yol:rw yaklaşımı tercih edin.

Ubuntu’da AppArmor profilleri varsayılan olarak etkindir. Profil saptamak ve sorun yaşarsanız geçici olarak rahatlatmak için --security-opt apparmor=unconfined denenebilir; ancak kalıcı çözüm için minimal özel profil oluşturmanız önerilir. Ek olarak, seccomp filtreleri varsayılandır; özel çağrılar gerekiyorsa --security-opt seccomp=dosya.json ile dar kapsamlı izin verin.

Konteyner başlatırken kullanıcıyı düşürmek kritik önem taşır. İmajda USER app tanımlayın veya çalıştırmada -u 1000:1000 kullanın. Böylece rootless üzerinde ek bir güvenlik katmanı oluşturmuş olursunuz.

Geliştirici İş Akışı: Compose, Build ve SBOM

Takım çalışması için podman-compose ile docker-compose.yml dosyalarını büyük ölçüde uyumlu biçimde kullanabilirsiniz. Rootless ortamda bağlanan portları -p 8080:80 gibi kullanıcı alanı NAT üzerinden yayınlayın. Geliştirme/test ayrımı için --env-file ile yapılandırma yönetimi düzenli tutulmalıdır.

Build süreçlerinde buildah ve Podman birlikte çalışır. Tek Dockerfile ile çok aşamalı imajlar (multi-stage) oluşturmak, final katmanı küçük tutar. Tedarik zinciri görünürlüğü için podman build --sbom=true ve podman manifest ile çok mimarili imajlar üretmeyi düşünün. İmaj imzalama için sigstore/notation entegrasyonları güveni artırır.

Hizmet Olarak Çalıştırma ve Sistem Entegrasyonu

Sunucu uygulamalarını kullanıcı oturumundan bağımsız başlatmak için systemd user ünitelerini kullanın. loginctl enable-linger <kullanici> komutu, oturum kapalıyken bile user systemd’nin çalışmasını sağlar. Podman, podman generate systemd --new --files --name servis ile servis dosyaları üretir; bunları ~/.config/systemd/user altına koyup systemctl --user enable --now ile etkinleştirin.

Sorun Giderme İpuçları

Ağ erişimi yavaşsa slirp4netns’in yeni sürümünü deneyin veya MTU değerini düşürüp tekrar test edin. Cgroups v2’nin etkin olduğundan emin olun; değilse kapsayıcı kaynak sınırlamaları beklediğiniz gibi çalışmayabilir. Disk alanı hızla doluyorsa podman system df ile katmanları analiz edip podman system prune çalıştırın. Yetki hatalarında çoğunlukla /etc/subuid//etc/subgid eksik veya dar aralık tanımlıdır; aralığı genişletmek çözüm sağlar.

Sonuç

Ubuntu 24.04 üzerinde rootless Podman, güvenliği artırırken geliştirici hızını düşürmeden modern konteyner iş akışlarını mümkün kılar. Doğru ağ, depolama ve sertleştirme ayarlarıyla hem yerel geliştirme hem de kullanıcı bazlı servislerde verimli, izole ve izlenebilir bir ortam kurabilirsiniz. Bu kılavuzdaki pratik ayarları uygulayarak konteynerlerinizi daha güvenli ve performanslı çalıştırabilirsiniz.

30 Ekim 2025 Perşembe

Jetson Orin Nano’da Llama.cpp ile 7B LLM Çalıştırma ve Optimize Etme Rehberi

Giriş: Neden Jetson Orin Nano’da Yerel LLM?

Gizlilik, gecikme ve maliyet avantajları nedeniyle büyük dil modellerini (LLM) uçta çalıştırmak giderek daha cazip hale geliyor. Nvidia Jetson Orin Nano; CUDA hızlandırması, kompakt form faktörü ve yeterli bellek bant genişliğiyle, 7B sınıfı LLM’leri makul hızlarda çalıştırmak için güçlü bir aday. Bu rehberde, llama.cpp ile 7B bir modeli Jetson Orin Nano’da kurup çalıştırmayı, ardından performans ve stabiliteyi iyileştirmek için yapabileceklerinizi adım adım anlatıyorum.

Önkoşullar ve Donanım Notları

Jetson’unuzda JetPack’in güncel bir sürümü kurulu olmalı (CUDA/cuBLAS bu pakette gelir). Orin Nano 8 GB ile 16 GB bellek arasında fark hissedilir; 8 GB’de 7B model çalışır ama bağlam penceresi büyükse (ör. 4K) bellek baskısı artar. Uzun oturumlarda throttling’i önlemek için iyi bir soğutma ve yeterli güç adaptörü şart. Kartı microSD ile kullanıyorsanız, mümkünse UHS-I hızlı bir kart ya da NVMe tercih edin. Sistem kararlılığı için 2–4 GB swap da hayat kurtarıcı olabilir.

Gerekli Paketler ve Derleme

llama.cpp, Jetson’da cuBLAS üzerinden GPU hızlandırmayı destekler. Önce temel araçları kuralım:

Komutlar:
sudo apt update && sudo apt upgrade -y
sudo apt install -y build-essential git cmake ninja-build

Kaynak kodu alın ve CUDA destekli derleyin:

git clone https://github.com/ggerganov/llama.cpp.git
cd llama.cpp
make LLAMA_CUBLAS=1 -j6

Derleme tamamlandığında klasörde main ikilisini göreceksiniz. Bu ikiliyi kullanarak modeli çalıştıracağız.

Model Dosyası (GGUF) ve Boyut Seçimi

llama.cpp, GGUF formatındaki modelleri kullanır. 7B bir modelin Q4_K_M gibi agresif bir quantization’ı genellikle 4–5 GB civarındadır ve Jetson Orin Nano 8 GB için iyi bir başlangıçtır. Q5 tipleri biraz daha çok bellek ister, karşılığında doğruluk artar. GGUF dosyasını örneğin ~/models içine koyduğunuzu varsayalım. Büyük bağlam pencereleri (ör. 4096 token) KV önbelleği nedeniyle bellek kullanımını ciddi artırır; ilk denemelerde 2048 civarı daha güvenlidir.

İlk Çalıştırma: Doğru Bayraklarla Başlayın

Aşağıdaki örnek, 7B bir modeli Q4_K_M ile, GPU’ya katman offload ederek başlatır. -ngl GPU’ya atılacak katman sayısını, -t CPU iş parçacığı sayısını, -c bağlam penceresini belirler.

./main -m ~/models/your-7b.Q4_K_M.gguf \
-ngl 20 -t 4 -c 2048 -n 200 \
--temp 0.7 --repeat-penalty 1.1 \
-p "Türkçe olarak, Jetson Orin Nano’da yerel LLM çalıştırmanın avantajlarını anlat."

İlk denemede -ngl 20 ile başlayın. Bellek yeterliyse 24–32 aralığına kademeli çıkabilirsiniz. Jetson’un birleşik belleği nedeniyle ekran, tarayıcı gibi uygulamalar açıkken OOM (out-of-memory) hatası alabilirsiniz; gereksiz süreçleri kapatın.

Performans İpuçları: nvpmodel, jetson_clocks ve Isıl Yönetim

Orin’in performans modunu en yükseğe almak için şunları uygulayın:

sudo nvpmodel -m 2
sudo jetson_clocks

Bu iki komut, güç bütçesini ve saat hızlarını maksimuma yaklaştırır. Uzun oturumlarda sıcaklıklar yükselebilir; iyi bir fan profili ve havalandırma şarttır. Aksi halde GPU/CPU termal kısıtlamaya girip tokens/s değeriniz düşer.

Doğru Ayarları Bulmak: Denge Sanatı

- Quantization seçimi: Q4_K_M genelde iyi bir başlangıç; daha iyi kalite istiyorsanız Q5 seçeneklerini deneyin ancak bellek kullanımına dikkat edin.
- Bağlam penceresi: 2048→4096’a çıkmak kaliteyi artırır ama KV önbelleği büyür. Bellekte zorlanıyorsanız 1536–2048 aralığı iyi dengedir.
- İş parçacığı (-t): Orin Nano’da 4–6 aralığını test edin. Her zaman maksimum çekirdek sayısı en iyi sonuç vermez; ısı ve bellek bant genişliği sınırlayıcı olabilir.
- GPU katmanları (-ngl): Değer yükseldikçe hız artar ama VRAM/birleşik bellek tüketimi de artar. OOM görürseniz önce -ngl’yi, sonra -c’yi düşürün.
- Ön ısıtma (warm-up): İlk birkaç istekte hız düşük görünebilir; oturum uzadıkça derleyici ve önbellek etkileriyle stabil hale gelir.

Swap/ZRAM ve Kararlılık

8 GB’lık sistemlerde büyük bağlamlarda swap faydalıdır. ZRAM etkinleştirmek için sisteminizdeki servis mevcutsa aşağıdaki komut işinizi görebilir:

sudo systemctl enable nvzramconfig
sudo systemctl start nvzramconfig

Klasik bir swap dosyası da oluşturabilirsiniz; fakat swap’ın SSD ömrü ve performansı etkileyebileceğini unutmayın. Hedefiniz OOM’u önlemek için “emniyet kemeri” sağlamaktır, sürekli swap tüketmek değil.

Sorun Giderme

- CUDA out of memory: -ngl ve/veya -c değerlerini azaltın, diğer uygulamaları kapatın. Q4 yerine daha küçük bir quantization da deneyebilirsiniz.
- Düşük tokens/s: Güç modu ve saatlerin açık olduğundan emin olun; soğutmayı güçlendirin; -t ve -ngl kombinasyonlarını test edin.
- Derleme hataları: make temizleyip yeniden derleyin: make clean && make LLAMA_CUBLAS=1 -j6. Gerekirse cmake ile taze bir build klasörü kullanın.

Sonuç: Uçta LLM, Pratikte Mümkün

Jetson Orin Nano üzerinde llama.cpp ile 7B bir LLM’i çalıştırmak, doğru quantization ve ayarlarla gayet mümkün. Gizlilik hassasiyetleri olan uygulamalarda, internet bağlantısının zayıf olduğu senaryolarda veya düşük gecikmeli etkileşim gereken robotik/kontrol projelerinde yerel LLM büyük fark yaratır. Bu rehberdeki adımlar ve ince ayar ipuçlarıyla, hem stabil hem de tatmin edici hızlarda bir kurulum elde edebilirsiniz. Geriye kalan, kullanım amacınıza uygun prompt mühendisliği ve model seçimi ile deneyimi zenginleştirmek.

29 Ekim 2025 Çarşamba

OpenTelemetry ile Node.js Mikroservislerde Uçtan Uca Gözlemlenebilirlik: Adım Adım Kurulum

OpenTelemetry Nedir ve Neden Önemlidir?

OpenTelemetry (OTel), uygulamalarınızdan metrik, iz (trace) ve log verilerini standart bir formatla toplayıp farklı arka uç (backend) sistemlerine göndermenizi sağlayan, CNCF çatısı altındaki açık kaynak bir çatı projedir. Mikroservis mimarilerinde bir isteğin hangi servislerde gezdiğini, nerede yavaşladığını veya hata verdiğini anlamak için dağıtık izleme, performans metrikleri ve log korelasyonu kritik öneme sahiptir. OTel; SDK’lar, otomatik enstrümantasyon modülleri, Collector (aracı) ve OTLP adlı açık protokol ile bu süreci basitleştirir.

Hedef Mimari ve Bileşenler

Bu makalede bir Node.js (Express) servisinden izleri OpenTelemetry Collector’a, oradan da Grafana Tempo’ya taşıyacağız. Görselleştirme için Grafana kullanılacak. Metrikler için Prometheus veya Grafana Cloud tercih edilebilir; ancak odak noktamız uçtan uca izleme (tracing) kurulumu olacak. Basitçe akış şöyle: Uygulama (OTel SDK) → OTLP (gRPC) → OTel Collector → Tempo → Grafana.

Ön Koşullar

Node.js 18+ sürümü, Docker ve Docker Compose kurulu olmalı. Yerel ortamda çalışıyorsanız 4317 (OTLP gRPC) ve 3000 (Grafana) portlarının boş olduğundan emin olun. Örnekler Linux ve macOS için benzer; Windows’ta da WSL ile rahatça yürütülebilir.

1) Node.js Projesini Hazırlama

Önce basit bir Express API oluşturalım ve OpenTelemetry paketlerini ekleyelim. Yeni bir klasör açın ve terminalde şu komutları çalıştırın: npm init -y ardından npm i express @opentelemetry/sdk-node @opentelemetry/auto-instrumentations-node @opentelemetry/exporter-trace-otlp-grpc @opentelemetry/resources. Bu paketler sırasıyla temel OTel SDK, otomatik enstrümantasyon, OTLP gRPC exporter ve kaynak (service.name vb.) tanımları için gereklidir.

2) OpenTelemetry Yapılandırması (tracing.js)

Projenizin köküne tracing.js adlı bir dosya ekleyin ve aşağıdaki içeriği yerleştirin. Bu dosya Collector’a giden OTLP gRPC bağlantısını kurar ve otomatik enstrümantasyonu aktif eder: const { NodeSDK } = require('@opentelemetry/sdk-node'); const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-grpc'); const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node'); const { Resource } = require('@opentelemetry/resources'); const exporter = new OTLPTraceExporter({ url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4317' }); const sdk = new NodeSDK({ resource: new Resource({ 'service.name': process.env.OTEL_SERVICE_NAME || 'orders-api', 'service.namespace': 'example', }), traceExporter: exporter, instrumentations: [getNodeAutoInstrumentations()], }); sdk.start().then(() => console.log('OTel tracing started')).catch(err => console.error(err)); process.on('SIGTERM', () => sdk.shutdown());

3) Express Uygulaması (app.js)

Express sunucusunu başlatmadan önce tracing’i import etmek önemlidir; aksi halde otomatik enstrümantasyon bazı modülleri kaçırabilir. app.js dosyası için örnek: require('./tracing'); const express = require('express'); const app = express(); app.get('/health', (req, res) => res.send('ok')); app.get('/orders/:id', async (req, res) => { // İş mantığı simülasyonu await new Promise(r => setTimeout(r, 50)); res.json({ id: req.params.id, status: 'ready' }); }); const port = process.env.PORT || 3001; app.listen(port, () => console.log('API listening on ' + port));

4) OpenTelemetry Collector ve Tempo

Collector, üretim ortamlarında veriyi merkezileştirip birden fazla hedefe yönlendirmek için idealdir. Aşağıdaki basit collector.yaml Tempo’ya iz aktarmaya yeter. Docker ile kullanırken dosyayı aynı klasöre koyun ve mount edin: receivers: otlp: protocols: grpc: exporters: otlp: endpoint: tempo:4317 tls: insecure: true service: pipelines: traces: receivers: [otlp] exporters: [otlp] Bu yapı, Collector’ın 4317 portundan OTLP gRPC ile aldığı izleri, aynı docker ağı içindeki tempo servisine yine OTLP ile iletir.

Basit bir docker-compose.yaml ile Tempo ve Collector’ı ayağa kaldırabilirsiniz. Özetle, otel-collector servisini otel/opentelemetry-collector:latest imajı ile çalıştırıp 4317 portunu publish edin; tempo için grafana/tempo imajını kullanın. Grafana’yı grafana/grafana ile 3000 portunda başlatın. Grafana içinden “Add data source” menüsünde Tempo’yu ekleyip Collector/Tempo adresini işaret edin.

5) Test ve Doğrulama

Node.js uygulamanızı node app.js ile başlatın. Ardından birkaç istek atın: curl http://localhost:3001/orders/123. Grafana’da Tempo veri kaynağını açıp “Explore” sekmesinde hizmet adınızla (ör. orders-api) arama yapın. Trace grafında isteklerin gecikme dağılımını, otomatik enstrümantasyon sayesinde HTTP client/server span’lerini ve hata durumlarını görebilirsiniz. Trace ayrıntılarında attributes altında http.method, http.route gibi alanlar hazır gelir.

Gelişmiş İpuçları ve En İyi Uygulamalar

Üretimde örnekleme (sampling) oranını dikkatle seçin. Başlangıç için parentbased_traceidratio ile %5–10 iyi bir denge sağlar. Node tarafında OTEL_TRACES_SAMPLER=parentbased_traceidratio ve OTEL_TRACES_SAMPLER_ARG=0.1 gibi değişkenler kullanabilirsiniz. Ağ ve depolama maliyetlerini kontrol altında tutmak için gereksiz etiketleri (attributes) azaltın, sadece iş değeri yüksek etiketleri aktarın.

Servisler arası çağrılarda bağlam aktarımı (context propagation) hayati önem taşır. Varsayılan W3C Trace Context çoğu senaryo için yeterlidir. Gateway veya API proxy katmanınız varsa, traceparent ve tracestate başlıklarının bozulmadığından emin olun. Mikroservis zincirlerinde bu başlıkların taşınmaması, izlerin kopuk görünmesine neden olur.

Metrik ve log’larla korelasyon kurmak için aynı resource attributes değerlerini (ör. service.name, service.namespace, deployment.environment) hem uygulama hem Collector tarafında tutarlı kullanın. Log yönünde OTel Logger ile Grafana Loki entegrasyonu, bir trace ID’sinden ilgili log satırına tek tıkla geçiş imkanı verir. Bu, MTTR’ı ciddi biçimde düşürür.

Güvenlik açısından üretimde OTLP trafiğini TLS ile şifreleyin ve Collector’ı egress katmanı olarak konumlandırın. Kubernetes’te DaemonSet veya sidecar modeliyle dağıtım yapabilir, her node’da yerel Collector çalıştırarak ağ gecikmesini azaltabilirsiniz. SLO takibi için kritik endpoint’lerinizde özel span adları ve durum kodu etiketleri kullanmak; hata bütçesi yönetimi ve kök neden analizlerinde büyük kolaylık sağlar.

Sonuç

OpenTelemetry, Node.js mikroservislerinizde gözlemlenebilirliği standart, taşınabilir ve ölçeklenebilir hale getirir. Collector ve Tempo ile kuracağınız hafif mimari hem yerelde hem de bulutta hızlıca devreye alınabilir. Bu rehberle temel taşıyıcıları ayağa kaldırdıktan sonra, metrik ve log entegrasyonlarını ekleyerek tam üç sütunlu gözlemlenebilirlik elde edebilir, üretim ortamında güvenle iterasyon yapabilirsiniz.

28 Ekim 2025 Salı

PostgreSQL + pgvector ile Semantik Arama ve RAG: Kurulum, İndeks ve Performans Rehberi

Giriş

Semantik arama ve RAG (Retrieval-Augmented Generation) uygulamaları, yalnızca bir metnin kelimelerine değil, anlamına göre sonuç döndürerek daha isabetli yanıtlar verebiliyor. Bu yaklaşımı uygulamak için vektör veritabanı şart. Pek çok ekip, halihazırda kullandıkları PostgreSQL üzerinde pgvector eklentisiyle bu ihtiyacı karşılıyor. Bu yazıda, PostgreSQL + pgvector kombinasyonuyla semantik arama altyapısını nasıl kuracağınızı, indekslemeyi nasıl yapacağınızı ve performansı nasıl optimize edeceğinizi adım adım anlatıyorum.

Neden pgvector?

Pgvector, PostgreSQL’e vektör veri tipi (vector) ve benzerlik aramaları (cosine, L2, inner product) kazandırır. Ayrı bir veritabanı yönetmek yerine tek bir Postgres kümesi üzerinde hem ilişkisel verilerinizi hem de embedding’lerinizi saklayabilirsiniz. Bu, devops maliyetini azaltırken güçlü ACID garantileri ve yedekleme stratejilerinden de yararlanmanızı sağlar.

Önkoşullar

PostgreSQL 14+ önerilir; performans ve özellikler için 15/16 daha iyi. Sunucuda en az 4 CPU, 8 GB RAM başlamak için konfor sağlar. Ayrıca embedding üretmek için bir model (örneğin OpenAI text-embedding-3-small, Instructor, E5-large veya yerel bir model) gereklidir.

Kurulum (Docker ve Yerel)

Docker ile hızlı kurulum: Resmi Postgres imajı yerine pgvector içeren bir imaj kullanabilirsiniz. Örnek:

docker run -d --name pg -e POSTGRES_PASSWORD=secret -p 5432:5432 ankane/pgvector

Yerel kurulum (Ubuntu/Debian): Paket yöneticinizde pgvector olmayabilir. Kaynaktan kurulum tipik akış:

sudo apt-get update && sudo apt-get install -y postgresql postgresql-server-dev-all git make gcc

git clone https://github.com/pgvector/pgvector.git && cd pgvector && make && sudo make install

Veritabanını Hazırlama

Postgres’e bağlandıktan sonra eklentiyi etkinleştirin ve şemanızı oluşturun:

CREATE EXTENSION IF NOT EXISTS vector;

CREATE TABLE documents (id bigserial PRIMARY KEY, title text, body text, embedding vector(1536));

Burada vector(1536) embedding boyutunu temsil ediyor. Kullanacağınız modele göre bu değeri değiştirin (örn. 768, 1024, 1536).

Embedding Üretme ve Veri Ekleme

Embedding’leri uygulama katmanında üretip Postgres’e yazmak en yaygın yaklaşım. Basit akış: metni temizle, cümlelere/segmentlere böl, embedding modeline gönder, sonuç vektörünü tabloya ekle.

Örnek bir ekleme akışı:

INSERT INTO documents (title, body, embedding) VALUES ('KVKK Özeti', 'Kişisel verilerin korunması...', '[0.012, -0.034, ...]');

Not: pgvector, köşeli parantezle vektör alır. Uygulama dilinizde (Python/Node/Go) embedding dizisini string’e çevirip eklemek pratik bir yöntemdir.

Benzerlik İndeksleri: IVFFlat ve HNSW

Büyük veri kümelerinde ham tarama yavaştır. Bu nedenle IVFFlat veya HNSW indeksleri kullanılır. IVFFlat için önce tabloyu kabaca küme merkezlerine göre “eğitmek” gerekir.

-- Koşul: önce yeterince satır eklenmiş olmalı

CREATE INDEX ON documents USING ivfflat (embedding vector_cosine) WITH (lists = 100);

HNSW, eğitime gerek duymaz ve bazı veri setlerinde daha iyi gecikme/kalite dengesi sunabilir:

CREATE INDEX ON documents USING hnsw (embedding vector_cosine) WITH (m = 16, ef_construction = 128);

Metrik seçimi kritiktir: embedding modeliniz cosine ile eğitildiyse vector_cosine seçin. Performans için lists (IVFFlat) ve ef_search (HNSW) değerlerini iş yükünüze göre ayarlayın.

Semantik Arama Sorguları

Arama anında, sorgu metnini embedding’e çevirin ve en yakın komşuları çekin:

-- sorgu_embedding uygulama katmanından parametre olarak gelir

SELECT id, title, body FROM documents ORDER BY embedding <#> :sorgu_embedding LIMIT 5;

<#> operatörü cosine distance’dır. En iyi sonuçları almak için LIMIT’i ve filtre koşullarını (ör. kategori, tarih aralığı) birlikte kullanın.

RAG İçin Basit Bir Akış

- Kullanıcı sorusunu alın ve embedding’e dönüştürün.

- PostgreSQL’den en alakalı 5–10 dokümanı semantik aramayla çekin.

- Cevaplayıcı LLM’e, bu parçaları bağlamsal ek metin (context) olarak verin.

- Kaynakları (title ve id) cevapla birlikte kullanıcıya gösterin. Bu yaklaşım, halüsinasyonları azaltır ve izlenebilirlik sağlar.

Performans ve Ölçek İpuçları

1) İndeks ısınması: Sık aranan sorgu türleri için sistem başladığında birkaç “ısınma” araması yapın. Bu, sayfa önbelleğini doldurur.

2) Paralelleştirme: Toplu embedding üretiminde çoklu iş parçacığı ya da job queue kullanın. Veritabanına batch insert (ör. 100–1000 satır) performans sağlar.

3) Tablo tasarımı: Metin gövdeleri büyükse, embedding’leri ayrı bir tabloda (documents_vec) tutup body’yi object storage’a koymayı değerlendirin; Postgres’te sadece referans saklayın.

4) Bakım: Yoğun yazma/indeks güncellemelerinde VACUUM (ANALYZE) planlayın. Autovacuum ayarlarını (naptime, cost_limit) iş yükünüze göre iyileştirin.

5) IVFFlat ayarları: lists değerini veri büyüklüğüne göre artırmak hatırlama oranını iyileştirir; sorgu anında SET ivfflat.probes = X; ile daha fazla liste tarayıp isabet oranını yükseltebilirsiniz (gecikme artar).

6) HNSW ayarları: SET hnsw.ef_search = 64/128/256 gibi değerlerle kalite/gecikmeyi dengeleyin. Daha yüksek ef_search, daha iyi sonuç ama daha fazla CPU demektir.

7) Sharding/Partitioning: Konu veya müşteri bazlı PARTITION BY LIST ile arama alanını daraltmak ciddi kazanç sağlar.

Güvenlik ve Versiyonlama

Embedding uzayı model güncellemeleriyle değişebilir. Model versiyonunu tabloda saklayın (örn. model_version text) ve farklı versiyonlar için ayrı indeks tutun. Erişim tarafında Row Level Security (RLS) ile müşteri/veri bölümlendirmesini zorunlu kılın.

Hata Ayıklama ve Sık Karşılaşılan Sorunlar

- ERROR: type "vector" does not exist: CREATE EXTENSION vector; komutunun ilgili veritabanında çalıştığından ve eklentinin kurulu olduğundan emin olun.

- IVFFlat “not enough tuples”: İndeksi kurmadan önce yeterli sayıda satır eklenmiş olmalı; aksi halde eğitim yapılamaz.

- Yüksek gecikme: İndeks kullanılmıyor olabilir; EXPLAIN (ANALYZE, BUFFERS) ile planı inceleyin. probes veya ef_search değerlerini ayarlayın.

Sonuç

Pgvector, PostgreSQL’i güçlü bir vektör arama motoruna dönüştürüyor. Doğru indeks ve ayarlarla milyonlarca embedding üzerinde milisaniyeler içinde semantik arama yapılabiliyor. RAG senaryolarında ise hem kaynak yönetimini sadeleştiriyor hem de mevcut Postgres ekosisteminin güvenilirliğinden yararlanmanızı sağlıyor. Küçük bir POC ile başlayıp indeks parametrelerini kademeli ayarlayarak en iyi maliyet/performans noktasını yakalayabilirsiniz.

27 Ekim 2025 Pazartesi

WebGPU ile Tarayıcıda Yapay Zeka: onnxruntime-web ile Hızlı Görüntü Sınıflandırma (Adım Adım Rehber)

WebGPU nedir ve neden önemli?

WebGPU, modern tarayıcılarda yerel GPU erişimi sunan yeni nesil bir web standardıdır. WebGL’in mirasını devralırken, daha düşük seviyeli ve verimli bir API sağlar. Bu sayede tarayıcı içinde yapay zeka modellerini, özellikle de tensör hesaplamalarını GPU üzerinde çalıştırarak ciddi performans artışları elde edebilirsiniz. Bu yazıda, WebGPU ve onnxruntime-web kullanarak basit bir görüntü sınıflandırma örneğini nasıl hayata geçirebileceğinizi adım adım anlatacağım. Amaç, “kodu kopyala-çalıştır” değil; mantığı kavrayıp kendi projenize uyarlayabilmeniz.

Destekleyen tarayıcılar ve ön koşullar

WebGPU, Chrome 113+ ve Edge gibi Chromium tabanlı tarayıcılarda genel olarak desteklenirken, bazı sistemlerde bayrak (flag) açmanız gerekebilir. Adres çubuğuna chrome://flags/#enable-unsafe-webgpu yazıp etkinleştirip tarayıcıyı yeniden başlatın. Donanım olarak modern bir entegre veya ayrık GPU, güncel sürücüler ve mümkünse 8 GB+ RAM önerilir. Ayrıca, proje dizininde basit bir HTTP sunucu (örneğin live-server veya vite) kullanmanız yerel dosya erişim sorunlarını önler.

Proje iskeleti ve kurulum

Temiz bir klasör oluşturun ve bir paket yöneticisiyle başlangıç yapın. Örnek: “npm init -y” ile bir Node projesi başlatın. Ardından “npm i onnxruntime-web” komutuyla tarayıcı sürümünü ekleyin. Statik dosyalar için index.html, model ve etiket dosyaları için “/public” klasörü, mantık kodu için main.js gibi basit bir yapı işinizi görür. Geliştirme sunucusu için “npx vite” gibi bir araç tercih edebilirsiniz; aksi durumda “npx http-server” da yeterli.

Model seçimi: ONNX ve boyut optimizasyonu

Tarayıcı için düşük gecikme ve sınırlı bellek kritik. Bu nedenle küçük ve verimli görüntü sınıflandırma modelleri (MobileNetV2/V3, EfficientNet-Lite) iyi başlangıç noktalarıdır. ONNX formatında bir model indirin veya dönüştürün. Eğer PyTorch veya TensorFlow modeliniz varsa, ONNX’a export edin. Ardından boyutu ve bellek kullanımını azaltmak için quantization uygulayın. Örnek komut akışı: “pip install onnxruntime-tools” ardından dinamik quantization ile “python -m onnxruntime.quantization.quantize_dynamic model.onnx model-int8.onnx”. Tarayıcıda indirme süresini kısaltmak için 8-bit tamsayı (INT8) genellikle iyi bir dengedir.

WebGPU ile oturum başlatma mantığı

onnxruntime-web, birden fazla çalışma sağlayıcısı (execution provider) sunar. Varsayılan WASM’tan maksimum hız beklemiyorsanız WebGPU sağlayıcısını açın. Temel akış şöyledir: 1) Tarayıcıda navigator.gpu mevcut mu kontrol edin. 2) onnxruntime-web’i import edin. 3) “InferenceSession.create(‘model.onnx’, { executionProviders: [‘webgpu’] })” ile oturumu başlatın. 4) Girdiyi (örneğin 224x224 RGB) ön işleyin: yeniden boyutlandırma, normalize etme (mean/std) ve tensör şeklini NHWC veya NCHW’ye uygun hazırlama. 5) “session.run(feeds)” ile çıkarım yapıp çıktıdan en yüksek olasılıklı sınıfı alın. Çıktıları etiket dosyanızla eşleştirerek kullanıcıya dostu bir sonuç sunun.

Veri ön işleme ve performans nüansları

Tarayıcı tarafında piksel işlemleri için OffscreenCanvas ve ImageBitmap kullanmak, ana iş parçacığını (main thread) bloklamadan dönüşüm yapmanıza yardım eder. Mümkünse işlemleri Web Worker içine taşıyın. Normalize (ör. 0-1 aralığına çekme) ve kanal düzeni dönüşümleri (HWC’den CHW’ye) pahalı olabilir; bu adımları GPU ile yapacak eklentiler henüz yaygın olmasa da, yapılabildiği durumlarda dramatik hızlanma sağlar. Ayrıca “warm-up” için ilk çağrıda boş bir tensörle veya düşük çözünürlüklü bir örnekle modeli çalıştırmak, JIT derlemelerini önden tetikleyerek ilk gecikmeyi azaltır.

Hafıza yönetimi ve kullanıcı deneyimi

Model dosyanız büyükse, indirme süresini iyileştirmek için HTTP/2, CDN ve gzip/br sıkıştırmayı aktif edin. Yükleme sırasında aşamalı geri bildirim (yüzde barı, “model yükleniyor”) sağlayın. Mobil cihazlarda bellek sınırlı olduğu için giriş çözünürlüğünü 160-192 gibi daha küçük değerlere düşürmeyi ve modelin INT8 sürümünü varsayılan yapmayı düşünebilirsiniz. Uzun süren işler için kullanıcıya iptal butonu vermek, UI’ın donduğu algısını ortadan kaldırır.

Geriye dönüş (fallback) stratejisi

Her cihaz WebGPU’yu desteklemeyebilir. Bu nedenle oturum açılışı başarısız olduğunda otomatik olarak WASM sağlayıcısına düşmek iyi bir uygulamadır. Mantık basit: “navigator.gpu” yoksa veya adapter alınamadıysa, “executionProviders: [‘wasm’]” ile yeniden dene. Kullanıcıya küçük bir uyarı vererek performansın sınırlı olabileceğini belirtin. Progressive enhancement yaklaşımıyla en iyi olanı kullanıp, geri kalanları zarifçe destekleyin.

Sık karşılaşılan hatalar

“navigator.gpu is undefined”: Tarayıcınız veya platformunuz WebGPU’yu desteklemiyor; bayrakları kontrol edin, tarayıcıyı güncelleyin veya Edge/Chrome deneyin. “Adapter not found” veya “RequestDevice failed”: Sürücüler eski olabilir, GPU erişimi politikalarla kısıtlanmış olabilir. “Out of memory”: Model boyutu büyük; INT8’e geçin, giriş çözünürlüğünü düşürün, arka planda çalışan sekmeleri kapatın. “CORS hataları”: Model dosyalarını aynı origin’den servis edin veya doğru CORS başlıklarını etkinleştirin.

Gizlilik, offline ve güvenlik boyutu

Tarayıcı içinde yerel çıkarım, verinin cihazi terk etmeden işlenmesini sağlar. Bu, özellikle sağlık veya kişisel görsellerin sınıflandırılması gibi senaryolarda mahremiyet avantajı sunar. Doğru Cache-Control ve Service Worker stratejileriyle model dosyalarını offline kullanılabilir hale getirebilir, ilk kurulumdan sonra çevrimdışı sınıflandırma deneyimi sunabilirsiniz. Güvenlik tarafında ise sadece güvenilir kaynaklardan model ve betik dosyaları alın; tedarik zinciri risklerini azaltmak için bütünlük (integrity) ve imza kontrollerini değerlendirin.

Sonuç ve ileri adımlar

WebGPU, tarayıcıda yapay zekayı pratik ve hızlı kılıyor. onnxruntime-web ile birkaç adımda GPU hızlandırmalı görüntü sınıflandırma çalıştırabilir, küçük cihazlarda dahi akıcı bir deneyim sağlayabilirsiniz. Bir sonraki adım olarak, metinle yönlendirilen görsel arama, gerçek zamanlı kamera akışı üzerinde nesne tespiti veya WebAssembly + WebGPU karma stratejileriyle daha Karmaşık modelleri denemeyi düşünebilirsiniz. Performansı daha da artırmak için model mimarilerini küçültmek, katman füzyonu uygulamak ve akıllı önbellekleme teknikleri kullanmak, projelerinizi üretime hazır hale getirir.

26 Ekim 2025 Pazar

Tarayıcıda Yapay Zeka: ONNX Runtime Web ve WebGPU ile YOLOv8 Nesne Tespiti (Adım Adım)

Giriş

Tarayıcıda çalışan yapay zeka uygulamaları son iki yılda WebGPU’nun yaygınlaşmasıyla ciddi ivme kazandı. Sunucu maliyeti olmadan, gecikmeyi düşürerek ve veriyi cihazda tutarak gerçek zamanlı deneyimler kurmak artık mümkün. Bu yazıda, ONNX Runtime Web ve WebGPU kullanarak tarayıcıda YOLOv8 tabanlı nesne tespiti nasıl çalıştırılır adım adım anlatıyorum. Amacımız, sade bir JavaScript projesinde model dosyasını yüklemek, WebGPU hızlandırmalı çıkarım yapmak ve olası performans tuzaklarını aşmak.

Neden Tarayıcıda Nesne Tespiti?

- Gizlilik: Görselleri veya kamera akışını sunucuya göndermeden cihazda işlemek, KVKK ve benzeri regülasyonlara uyumu kolaylaştırır.

- Düşük gecikme: Ağ gecikmesi ortadan kalktığı için özellikle gerçek zamanlı iş akışlarında (ör. kalite kontrol, interaktif demolar) deneyim belirgin şekilde iyileşir.

- Ölçeklenebilirlik: Her kullanıcı kendi cihaz kaynağını kullanır; sunucu GPU’su tahsis etme ihtiyacı azalır.

Gereksinimler

- Güncel bir Chromium tabanlı tarayıcı (Chrome/Edge 113+ sürümleri veya muadilleri) ya da WebGPU destekli Safari. Bazı eski sürümlerde deneysel bayraklar gerekebilir.

- Node.js ve bir paket yöneticisi (npm veya pnpm).

- onnxruntime-web paketi ve YOLOv8’in ONNX formatında bir sürümü (tercihen küçük bir varyant: yolov8n.onnx).

Proje Kurulumu

1) Hızlı bir iskelet için Vite ile başlangıç oluşturun: npm create vite@latest yolo-webgpu -- --template vanilla

2) Projeye girin ve bağımlılığı kurun: cd yolo-webgpu && npm i onnxruntime-web

3) Model dosyasını (ör. yolov8n.onnx) public/models/ klasörüne koyun. Geliştirme sırasında dosyaya /models/yolov8n.onnx yolu ile erişeceğiz.

4) Geliştirme sunucusunu başlatın: npm run dev. Modeli dosya sistemi üzerinden (file://) çağırmayın; tarayıcı CORS kısıtları nedeniyle engelleyebilir.

Modeli Hazırlama

Eğer hazır bir ONNX modeli kullanmıyorsanız, Ultralytics YOLOv8’i ONNX biçimine dışa aktarabilirsiniz. Tipik dışa aktarma, PyTorch modelinden .onnx üretir. Tarayıcı tarafı için küçük boyutlu (n veya s serisi) ve mümkünse nicemlenmiş (INT8) modeller performans ve bellek açısından avantaj sağlar. ONNX Runtime Web, QLinear tabanlı nicemlenmiş modelleri destekleyebilir; ancak operatör kapsaması modele göre değiştiğinden küçük bir varyantla başlamak mantıklıdır.

InferenceSession Oluşturma

Tarayıcı tarafında ONNX Runtime Web’i yükleyip WebGPU sağlayıcısıyla bir oturum açacağız. Güncel sürümlerde WebGPU kullanılabilir değilse otomatik olarak WASM arka ucuna düşecek şekilde bir dizi sağlayıcı tanımlamak iyi bir pratiktir:

import * as ort from 'onnxruntime-web';

const session = await ort.InferenceSession.create('/models/yolov8n.onnx', { executionProviders: ['webgpu', 'wasm'], graphOptimizationLevel: 'all' });

Bu yapılandırma, WebGPU uygunsa GPU hızlandırmayı kullanır; değilse WASM ile çalışmaya devam eder. WASM tarafında çok çekirdek ve SIMD faydası görmek için sayfanın Cross-Origin-Opener-Policy ve Cross-Origin-Embedder-Policy başlıklarıyla izole sunulması gerekir; Vite ve çoğu modern dev sunucu buna uygundur.

Ön İşleme ve Çıkarım

YOLOv8, girdi olarak tipik biçimde [1, 3, H, W] boyutunda, float32 normalleştirilmiş tensör bekler. Tarayıcıda bir <canvas> üzerinden görüntüyü 640×640’a yeniden boyutlandırıp RGB kanallarını alarak tensöre dönüştürebilirsiniz. Kanal sıralamasını (HWC → CHW) unutmayın ve 0–1 aralığına ölçekleyin.

Örnek çağrı akışı şu şekildedir: const feeds = { images: inputTensor }; ardından const output = await session.run(feeds);. Çoğu YOLOv8 ONNX dışa aktarımında çıktı, kutular ve sınıf skorlarını içeren tek bir tensördür. Bu tensörü NMS (Non-Maximum Suppression) ile filtreleyip skor ve sınıf eşikleri ile sonuçları çizmeniz gerekir.

Sonuçların Görselleştirilmesi

Nesne tespiti sonuçlarını çizmek için ikinci bir <canvas> katmanı kullanın. Her kutu için [x1, y1, x2, y2] koordinatlarını orijinal çözünürlüğe geri ölçekleyin. Sınıf adına göre renk paleti oluşturmak, kullanıcı deneyimini iyileştirir. Yüksek kare hızları elde etmek için çizimi requestAnimationFrame döngüsüyle eşleştirin ve her karede gereksiz bellek tahsisinden kaçının.

Performans İpuçları

- Küçük model seçin: yolov8n veya yolov8s web için daha uygundur.

- İlk çağrı ısınması: Uygulama açılışında küçük bir “boş” çıkarım tetikleyerek WebGPU shader derlemelerini önceden yaptırabilirsiniz; bu, ilk gerçek karedeki gecikmeyi düşürür.

- Nicemleme: INT8 veya dinamik nicemlenmiş modellerin boyutu küçülür ve bant genişliği ihtiyacı azalır. Doğruluk-hız dengesini ürün gereksinimlerinize göre ölçün.

- Asenkron iş akışı: Kamera karesini işlerken UI’ı kilitlememek için çıkarımı bir Web Worker içinde yürütmeyi değerlendirin. OffscreenCanvas desteklenen tarayıcılarda çizimi de iş parçacığına taşıyabilirsiniz.

Yayına Alma ve Güvenlik

Üretime alırken modeli bir CDN üzerinden cache-control başlıklarıyla servis etmek yükleme süresini iyileştirir. Model dosyalarınız büyükse gzip veya brotli sıkıştırmayı etkinleştirin. Gizlilik açısından, tüm çıkarımın cihazda kalması önemli bir artıdır; sunucuya yalnızca analitik metrikleri veya anonimleştirilmiş telemetri göndermek yeterli olabilir. Kamera erişimi gerekiyorsa kullanıcıya net bir izin akışı ve kapatma seçeneği sunun.

Sorun Giderme

- navigator.gpu undefined: Tarayıcı WebGPU’yu desteklemiyor olabilir. Sağlayıcı sırasına 'wasm' eklediğinizden emin olun.

- CORS/ERR_BLOCKED_BY_RESPONSE: Modeli file:// üzerinden değil bir HTTP sunucusundan yükleyin; yerelde Vite dev sunucusu yeterlidir.

- Out of memory: Modeli küçültün, çözünürlüğü düşürün (ör. 640 → 512) ve gereksiz kopyaları engellemek için tensörleri tekrar kullanın.

Sonuç

ONNX Runtime Web ve WebGPU kombinasyonu, tarayıcıda gerçek zamanlı nesne tespiti için pratik ve çağdaş bir yaklaşım sunuyor. Doğru model seçimi, düzenli ön işleme ve akıllı görselleştirme ile sunucu maliyeti olmadan yüksek kaliteli deneyimler oluşturabilirsiniz. Küçükten başlayın, performansı ölçerek iterasyon yapın ve kademeli olarak daha gelişmiş modellere geçin. Böylece hem kullanıcı gizliliğini korur hem de modern web’in sunduğu GPU gücünden en iyi şekilde yararlanmış olursunuz.

25 Ekim 2025 Cumartesi

OpenTelemetry ile Node.js Mikroservislerinde Uçtan Uca İzleme: Adım Adım Kurulum ve İpuçları

Giriş

Mikroservis mimarisi yaygınlaştıkça, bir isteğin sistem içinde hangi servislerden geçtiğini net olarak görmek kritik hale geldi. Tam bu noktada OpenTelemetry (OTel), izleme (tracing), metrik ve log sinyallerini standart bir şekilde toplayıp farklı arka uçlara gönderebilmenizi sağlayan, satıcıdan bağımsız bir çatı sunuyor. Bu yazıda, Node.js tabanlı mikroservislerde OpenTelemetry ile uçtan uca izlemeyi nasıl kuracağınızı, OpenTelemetry Collector’ı nasıl konumlandıracağınızı ve Jaeger/Grafana gibi araçlarla nasıl görünürlük elde edeceğinizi adım adım anlatıyorum.

Neden OpenTelemetry?

OpenTelemetry; W3C TraceContext ile uyumlu bağlam taşıma, otomatik enstrümantasyon paketleri ve güçlü bir Collector katmanı sayesinde uygulamaya minimum müdahale ile geniş görünürlük sağlar. Tek bir SDK ile farklı hedeflere (Jaeger, Tempo, Zipkin, OTLP uyumlu APM’ler) veri gönderebilir, kolektör üzerinde örnekleme (sampling), maskeleme ve yönlendirme politikaları kurabilirsiniz. Özellikle ölçek büyüdüğünde, kolektör katmanında merkezi yönetim büyük avantaj sağlar.

Mimari ve Gereksinimler

Önerilen basit topoloji şu şekilde: Node.js servisleri OpenTelemetry SDK ile izleri OTLP (HTTP veya gRPC) üzerinden OpenTelemetry Collector’a yollar. Collector, gelen veriyi batch’ler ve seçilen bir arka uca (ör. Jaeger veya Grafana Tempo) aktarır. Görselleştirme için Jaeger UI veya Grafana kullanılabilir. Üretimde TLS ve kimlik doğrulama (ör. mTLS, token) eklemeniz güvenlik açısından önemlidir.

Adım 1: OpenTelemetry Collector Kurulumu

Collector’ı Docker veya Kubernetes üzerinde çalıştırabilirsiniz. Temel bir yapılandırmada otlp alıcısını (receiver) hem HTTP hem gRPC için etkinleştirir, batch işlemcisini performans için eklersiniz. Çıkış tarafında jaeger ya da otlp exporter ile Tempo/OTLP hedefinize gönderim yapabilirsiniz. Üretime geçerken limitler, kuyruklar ve hata tekrar denemeleri için memory_limiter ve retry işlemcilerini de eklemeniz önerilir.

Adım 2: Node.js Uygulamasında OpenTelemetry’yi Etkinleştirme

Node.js tarafında @opentelemetry/sdk-node ve @opentelemetry/auto-instrumentations-node paketleriyle hızlıca başlayabilirsiniz. Önerim, uygulama giriş noktasından önce çalışacak bir tracing-bootstrap dosyası oluşturmak ve süreç başında SDK’yı başlatmaktır. Exporter olarak @opentelemetry/exporter-trace-otlp-http veya gRPC sürümünü seçebilirsiniz. Çevresel değişkenlerle (OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_SERVICE_NAME, OTEL_TRACES_SAMPLER, OTEL_RESOURCE_ATTRIBUTES) yapılandırma esnekliğini koruyun. Örneğin servis adını, ortamı (prod/stage), sürümü ve k8s etiketlerini kaynak (resource) niteliklerine eklemek aramada büyük kolaylık sağlar.

Adım 3: Bağlam Taşıma ve Enstrümantasyon

Dağıtık izleme için en kritik konu, isteklerin bağlamının doğru taşınmasıdır. OpenTelemetry varsayılan olarak W3C TraceContext başlıklarını kullanır (traceparent, tracestate). HTTP istemcileriniz (axios, fetch, got) ve sunucu tarafı (Express, Fastify, NestJS) için otomatik enstrümantasyon paketlerini aktif ettiğinizde, gelen isteğin bağlamı çıkarılır ve giden isteklere eklenir. API ağ geçitleri, CDN’ler veya servis mesh bileşenleri (Envoy/Linkerd/Istio) üzerinde bu başlıkların korunmasını sağlayın.

Adım 4: Metrikler ve Loglar

İzler başlangıç için idealdir; ancak gecikme ve hata oranlarını anlık izlemek için metrikleri de açın. Node.js’te bir MeterProvider ile sayaç, histogram ve gözlemci ölçümlerini üretebilir, OTLP veya Prometheus’a gönderebilirsiniz. Log tarafında, uygulama loglarını bir log yönlendirici (örn. Promtail, Vector) üzerinden kolektöre veya doğrudan hedef sisteme iletmek pratik bir yaklaşımdır. İzlerle logları korele etmek için log satırına trace_id ve span_id eklemek altın değerdedir.

Adım 5: Görselleştirme ve Analiz

Jaeger ile başlangıç hızlıdır: Servis adınıza, işlem adlarına ve hata etiketlerine göre izleri filtreleyebilirsiniz. Grafana + Tempo kullanıyorsanız, izler ile metrikler arasında geçiş yaparak (exemplar’lar) sorunlu zaman dilimindeki istekleri yakalamak çok güçlü bir yöntemdir. Yavaş isteklerin hangi mikroserviste takıldığını, dış bağımlılıkların (veritabanı, cache, üçüncü parti API’ler) gecikmeye etkisini birkaç tıkla görürsünüz.

İleri Düzey: Sampling, Güvenlik ve Kubernetes

Üretimde her isteği izlemek pahalı olabilir. Başlangıçta parentbased_traceidratio ile yüzde bazlı head sampling kullanın; daha sonra Collector üzerinde tail_sampling ile hata kodlarına veya gecikmeye göre akıllı örnekleme kurun. Hassas verileri maskelemek için Collector’ın attributes işlemcisiyle veri temizleme ekleyin. Kubernetes’te resource algılayıcılarıyla pod/namespace etiketleri otomatik gelir; ayrıca auto-instrumentation için init container yaklaşımıyla uygulama imajlarınızı değiştirmeden OTel’i devreye alabilirsiniz.

Sorun Giderme İpuçları

İzler görünmüyorsa önce Collector loglarını kontrol edin; OTLP uç noktasına ulaşabildiğinizi ve doğru protokol (HTTP vs gRPC) kullandığınızı doğrulayın. Node.js tarafında SDK’yı uygulama kodundan önce başlattığınızdan emin olun. Reverse proxy veya API gateway APM başlıklarını siliyor olabilir; başlık geçiş kurallarını gözden geçirin. Gecikme yüksekse, Collector’da batch ayarlarını ve kuyruk limitlerini optimize edin.

Sonuç

OpenTelemetry, Node.js mikroservislerinizde uçtan uca görünürlük sağlayarak kök neden analizini hızlandırır, müşteri etkisini azaltır ve ekipler arası ortak bir gözlem dili sunar. Küçükten başlayın: Collector + izler + Jaeger, ardından metrikler, log korelasyonu ve akıllı örnekleme ile olgunlaştırın. Doğru etiketleme ve bağlam taşıma kurulduğunda, karmaşık bir dağıtık sistemde bile “ne, nerede, neden yavaş?” sorularının yanıtı birkaç dakika uzaklıkta olacaktır.

24 Ekim 2025 Cuma

Yerel LLM ile RAG: Ollama + LangChain + ChromaDB ile Türkçe Soru-Cevap Sistemi Kurulumu (2025 Rehberi)

RAG nedir, neden yerel?

RAG (Retrieval-Augmented Generation), büyük dil modellerini (LLM) kendi verinizle güçlendirmenin en pratik yollarından biridir. Model, önce vektör veritabanından ilgili pasajları arar (retrieval), ardından yanıtı bu pasajları referans alarak üretir (generation). Bu yaklaşım, hem doğruluk hem de güncellik sağlar. Yerel (on-prem/edge) kurulum ise hassas veriyi dışarı çıkarmadan çalıştığı için KVKK uyumu, gecikme ve maliyet açısından avantajlıdır.

Mimari genel bakış

Ollama yerel LLM’i (ör. Qwen2.5 7B) çalıştırır, LangChain iş akışını yönetir, ChromaDB vektör veritabanı olarak belgeleri tutar, Sentence-Transformers ise Türkçe uyumlu gömme (embedding) üretir. Sorgu akışı: Kullanıcı sorusu → Embedding → Chroma’dan benzer parçaların bulunması → Seçilmiş LLM ile bağlamsal yanıt.

Gereksinimler ve ortam

- İşletim sistemi: macOS, Linux veya WSL2’li Windows
- Python 3.10+
- 16 GB RAM önerilir (8 GB ile quantize modeller çalışır).
- GPU hızlandırma varsa avantajlı; yoksa 4-bit quantize modelleri tercih edin.

Kurulum adımları

1) Ollama’yı kurun ve modeli çekin:
curl -fsSL https://ollama.com/install.sh | sh
ollama pull qwen2.5:7b
Qwen2.5 çok dilli yapısıyla Türkçe’de başarılıdır. Daha hafif bir seçenek gerekiyorsa qwen2.5:3b veya llama3.1:8b-instruct da tercih edilebilir.

2) Python ortamını hazırlayın:
python -m venv .venv && source .venv/bin/activate
pip install langchain langchain-community chromadb sentence-transformers pypdf fastapi uvicorn
Embedding için Türkçe’de güçlü bir seçenek: intfloat/multilingual-e5-base veya sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2.

Veri hazırlama ve indeksleme

Belgelerinizi data/ klasörüne koyun (PDF, TXT, MD). PDF’ler için pypdf ile metin çıkarabilirsiniz. Amaç, büyük belgeleri 500–1000 karakterlik, 50–100 karakter örtüşmeli parçalara ayırmaktır. Bu sayede arama daha isabetli olur ve bağlam penceresini verimli kullanırsınız.

Örnek akış (özet):
- Belgeleri yükle: PDF/TXT okuma
- Parçala: 800 karakter, 120 örtüşme
- Embedding üret: multilingual-e5-base
- ChromaDB’ye yaz: kalıcı (persist) bir dizinde tut

Basit bir betik iskeleti:
from langchain_community.document_loaders import PyPDFLoader, TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
from langchain_community.embeddings import HuggingFaceEmbeddings

loader = PyPDFLoader("data/rapor.pdf")
docs = loader.load()

splitter = RecursiveCharacterTextSplitter(chunk_size=800, chunk_overlap=120)
chunks = splitter.split_documents(docs)

emb = HuggingFaceEmbeddings(model_name="intfloat/multilingual-e5-base")
vect = Chroma.from_documents(chunks, emb, persist_directory="chroma_store")
vect.persist()

Arama + üretim zinciri

LangChain ile basit bir RAG zinciri kurabilirsiniz. Retriever’ı Chroma’dan oluşturun, Ollama LLM’i bağlayın ve istem (prompt) şablonu ile bağlamı enjekte edin. MMR (Maximal Marginal Relevance) ve top_k gibi ayarlarla oynayarak tekrar eden içerikleri azaltın ve çeşitliliği artırın.

Örnek sorgulama iskeleti:
from langchain_community.llms import Ollama
from langchain.prompts import PromptTemplate

vect = Chroma(persist_directory="chroma_store", embedding_function=emb)
retriever = vect.as_retriever(search_type="mmr", search_kwargs={"k": 5, "fetch_k": 20})

llm = Ollama(model="qwen2.5:7b", temperature=0.2)
template = ("Aşağıdaki bağlama dayanarak Türkçe, kaynaklara sadık ve kısa bir yanıt ver. "
"Bağlam:\n{context}\n\nSoru: {question}\nYanıt:")
prompt = PromptTemplate.from_template(template)

docs = retriever.get_relevant_documents("2024 finansal özet nedir?")
context = "\n\n".join([d.page_content for d in docs])
print(llm.invoke(prompt.format(context=context, question="2024 finansal özet nedir?")))

Doğruluk ve optimizasyon

- Chunk boyutu: 600–1000 karakter arası pratik. Daha küçük parça daha hassas arama, daha fazla parçayı LLM’e göndermek demektir. Bağlam penceresiyle dengeleme yapın.
- Reranker: GPU’nuz varsa bge-reranker-large gibi çapraz-encoder modeller ekleyerek bağlam kalitesini artırın.
- Top-k: 3–8 arası iyi bir başlangıç. Soru karmaşıksa artırın.
- Sıcaklık (temperature): 0.1–0.3 arası daha tutarlı, kaynaklara sadık yanıt sağlar.
- GYS/Değerlendirme: Küçük bir altın veri kümesi ile doğruluk ölçün. RAGAS gibi metriklerle bağlamsal doğruluğu takip edin.

Üretimde çalıştırma

Basit bir API için FastAPI idealdir. İsteğe göre streaming açarak ilk token’ı daha hızlı iletebilirsiniz. Chroma’yı kalıcı dizinle (persist_directory) başlatın ve yalnızca “okuma” modunda koşturun. Döküman güncellemeleri için zamanlanmış yeniden indeksleme (ör. günlük) stratejisi belirleyin.

Örnek uç nokta iskeleti:
from fastapi import FastAPI
app = FastAPI()

@app.get("/ask")
def ask(q: str):
  docs = retriever.get_relevant_documents(q)
  ctx = "\n\n".join(d.page_content for d in docs)
  ans = llm.invoke(prompt.format(context=ctx, question=q))
  return {"answer": ans}

uvicorn main:app --reload

Güvenlik, maliyet ve lisans notları

- Veri gizliliği: PII içeren alanları maskeleyin; loglarda ham sorgu ve belgeleri tutmayın. Diskte Chroma klasörünü şifreli bir birimde saklayın.
- Lisans: Kullandığınız model ve embedding lisansını kontrol edin; ticarî kullanımlarda kısıtlar olabilir.
- Maliyet: Yerel kurulum bulut token maliyetini düşürür, ancak donanım kaynağına ihtiyaç duyar. 4-bit quantize modeller düşük RAM’de dengeli performans sağlar.

Sorun giderme

- Yavaş yanıt: Embedding modelini daha hafife çekin (MiniLM), top_k’yı düşürün, quantize LLM kullanın.
- Alakasız bağlam: Chunk boyutunu artırın, MMR’ı açın, gerekirse reranker ekleyin.
- Bozuk indeks: chroma_store klasörünü temizleyip yeniden indeksleyin; gömme modelini değiştirdiyseniz indeksin de değişmesi gerekir.
- Hallüsinasyon: Prompt’a “Kaynak verilmeyen bilgiyi üretme” kuralını ekleyin, temperature’ı düşürün ve bağlamı zenginleştirin.

Sonuç

Bu rehberde Ollama + LangChain + ChromaDB ve çok dilli embedding’lerle yerel bir Türkçe RAG sistemi kurmanın hızlı yolunu gördünüz. Doğru chunking, iyi bir retriever ve tutarlı istem tasarımıyla, Türkçe dokümanlarınıza dayalı güvenilir bir soru-cevap deneyimi sağlayabilirsiniz. İhtiyaca göre model boyutunu, indeks ayarlarını ve dağıtım mimarisini optimize ederek sistemi üretim kalitesine taşıyın.

23 Ekim 2025 Perşembe

Docker Distroless ile Node.js API’nizi Hafif ve Güvenli Hale Getirme (Multi-Stage Build Rehberi)

Giriş

Üretim ortamında konteyner imaj boyutu, güvenlik yüzeyi ve başlatma hızı kritik öneme sahiptir. Geleneksel Node.js tabanlı imajlar (ör. Debian/Alpine) paket yöneticileri, shell ve gereksiz araçlar içerdiğinden hem büyük olur hem de CVE yüzeyi genişler. Bu yazıda, Docker Multi-Stage Build ve Distroless yaklaşımını birleştirerek, Node.js 20 tabanlı bir API’yi onlarca megabayta düşürüp, saldırı yüzeyini minimize etmeyi gösteriyorum.

Neden Distroless?

Distroless imajlar, uygulamanızı çalıştırmak için gerekli en minimal dosyaları içerir; shell, paket yöneticisi veya gereksiz araçlar yoktur. Bu sayede: (1) İmaj boyutu küçülür, (2) Potansiyel güvenlik açıkları azalır, (3) Soğuk başlatma hızlanır, (4) Tedarik zinciri şeffaflığı artar. Dezavantajı ise hata ayıklamanın klasik yöntemlerle (bash, curl) yapılamamasıdır; ancak doğru loglama ve metrikler bu ihtiyacı büyük ölçüde ortadan kaldırır.

Ön Koşullar

- Docker 24+ (BuildKit aktif önerilir)
- Node.js 20 LTS ile uyumlu bir proje (ör. Express, Fastify, NestJS)
- Üretim derlemesi yapan bir betik: npm run build (ör. TypeScript için tsc)

Multi-Stage Dockerfile Mantığı

Amaç, bağımlılıkları ve derlemeyi ağır bir builder evresinde yapmak, ardından sadece çalışması gereken artefaktları Distroless evresine kopyalamaktır. Aşağıda örnek bir Dockerfile yapısı yer alır:

# 1) Bağımlılıklar
FROM node:20-bookworm-slim AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci

# 2) Derleme
FROM deps AS build
COPY . .
RUN npm run build && npm prune --production

# 3) Distroless (final)
FROM gcr.io/distroless/nodejs20-debian12 AS runner
WORKDIR /app
ENV NODE_ENV=production
# Distroless'ta yerleşik 'nonroot' kullanıcısı mevcut
USER nonroot
COPY --from=build /app/dist ./dist
COPY --from=build /app/package*.json ./
COPY --from=build /app/node_modules ./node_modules
EXPOSE 3000
# Distroless nodejs imajı 'node' ENTRYPOINT'i ile gelir
CMD ["dist/index.js"]

Adım Adım Kurulum

1) package.json’ı hazırlayın: Üretim derlemesi için "build" komutunuz olsun (ör. "build": "tsc"). Sunucuyu relative path ile başlatabileceğinizden emin olun (ör. "start": "node dist/index.js").

2) Dockerfile’ı ekleyin: Yukarıdaki örneği kök dizine Dockerfile adıyla koyun. TypeScript kullanıyorsanız dist klasörünün üretildiğinden emin olun.

3) İmajı derleyin: docker build -t api:distroless . komutuyla derleyin. Build cache’i hızlandırmak için package*.json dosyalarını erken kopyaladığımıza dikkat edin.

4) Konteyneri çalıştırın: docker run -p 3000:3000 api:distroless komutuyla ayağa kaldırın. Uygulamanız http://localhost:3000 üzerinden yanıt vermelidir.

Güvenlik ve İyileştirme İpuçları

Non-root çalıştırma: Distroless imajlarda USER nonroot kritik bir adımdır. Bu, olası bir ihlalde yetkileri sınırlar.

ENV ve gizli bilgiler: Üretimde sırları ENV ile bake etmeyin. Orkestratör (Kubernetes Secrets, ECS, Swarm) üzerinden enjekte edin. Yerel testte --env-file kullanabilirsiniz.

SBOM ve tarama: Tedarik zinciri görünürlüğü için Syft ile SBOM çıkarın (syft packages docker:api:distroless) ve Grype/Trivy ile tarayın. Distroless, raporlanan CVE sayısını anlamlı biçimde azaltır.

Boyut ve performans: Tipik bir Node imajı 300–900 MB olabilirken distroless ile 70–150 MB bandı sık görülür. Daha küçük imaj, daha hızlı pull ve daha hızlı ölçekleme demektir.

Healthcheck: Distroless’ta shell olmadığından curl yoktur. Sağlık kontrolünü uygulama içi /health endpoint’i ile orkestratörden yapın. Alternatif olarak Node ile bir komut yazabilirsiniz (ör. HEALTHCHECK CMD ["node","-e","require('http').request({host:'127.0.0.1',port:3000,path:'/health'},r=>process.exit(r.statusCode===200?0:1)).on('error',()=>process.exit(1)).end()"]).

Sık Yapılan Hatalar

COPY sırası: COPY . . satırını npm ci’dan önce yazmak, her değişimde cache’i bozar ve build’i yavaşlatır. Önce package*.json, sonra bağımlılıklar, en sonda kaynak kod.

Gereksiz dev bağımlılıkları: Üretim imajına devDependencies taşımayın. npm prune --production veya npm ci --omit=dev kullanın.

Shell beklentisi: Distroless’ta /bin/sh yoktur. Debug için logs, structured logging (JSON) ve APM/Tracing (OpenTelemetry) tercih edin. İhtiyaç halinde aynı artefaktlarla ikinci bir “debug” imajı üretebilirsiniz (ör. Alpine tabanlı).

Güncel Pratikler

- Node 20 LTS kullanın ve düzenli güvenlik güncellemelerini takip edin.
- İmajınızı cosign ile imzalayıp politikalar aracılığıyla doğrulayın.
- Read-only root filesystem ve drop capabilities (Kubernetes) gibi kısıtlamalarla koşun.
- ROOTLESS Docker ya da Pod Security Standartlarıyla ek sertleştirme sağlayın.

Sonuç

Distroless ve Multi-Stage Build, Node.js servislerinizi hem hafif hem de güvenli hale getirmenin pratik bir yoludur. Daha küçük imajlar, daha hızlı dağıtım ve daha düşük saldırı yüzeyi anlamına gelir. Üretime geçerken non-root kullanıcı, SBOM, tarama ve gözlemlenebilirlik (logs/metrics/traces) gibi temel prensipleri uyguladığınızda, bakım maliyeti düşer ve ölçeklenebilirlik artar. Mevcut Dockerfile’ınızı yukarıdaki adımlarla iyileştirerek ilk günden somut kazanım elde edebilirsiniz.

22 Ekim 2025 Çarşamba

WebAuthn ve Passkey ile Parolasız Kimlik Doğrulama: Next.js + Node.js ile Uçtan Uca Kurulum

Giriş

Parolalar bitmek bilmeyen bir güvenlik ve kullanıcı deneyimi sorunu. WebAuthn ve Passkey (FIDO2) standartları, hem güvenliği artıran hem de kullanıcıyı zahmetten kurtaran parolasız kimlik doğrulama sunuyor. Bu yazıda, Next.js ve Node.js kullanarak uçtan uca bir WebAuthn akışını nasıl kuracağınızı adım adım anlatıyorum. Hem modern tarayıcı desteğini, hem de üretim ortamında dikkat edilmesi gerekenleri ele alacağız.

WebAuthn ve Passkey Nedir?

WebAuthn, W3C ve FIDO Alliance tarafından geliştirilen, tarayıcı üzerinden güvenli anahtar tabanlı kimlik doğrulama standardıdır. Passkey ise kullanıcıların cihazlarında saklanan ve bulut üzerinden senkronize olabilen (Apple iCloud, Google Password Manager vb.) WebAuthn kimlik bilgileridir. Kısaca: kullanıcı, parolaya gerek duymadan cihaz biyometrisi (Face ID, Touch ID, Windows Hello) veya güvenlik anahtarı (YubiKey) ile giriş yapar.

Kavramsal olarak iki akış var: Kayıt (Registration) ve Giriş (Authentication). Sunucu, benzersiz bir challenge üretir; tarayıcıda navigator.credentials.create() veya navigator.credentials.get() çağrıları yapılır; elde edilen yanıt sunucu tarafından doğrulanır. Doğrulama sonrası, kullanıcı artık parolasız giriş yapabilir.

Mimari Özeti

- Relying Party (RP): Uygulamanızın alan adıyla tanımlanır (ör. rpId: "ornek.com"). Bu değer kök alan adınız olmalıdır.

- Attestation ve Assertion: Kayıtta attestation, girişte assertion doğrulanır. Üretimde çoğunlukla attestation: "none" kullanılır.

- Depolama: Kamu anahtarı, credential ID ve counter gibi veriler sunucuda saklanır. Challenge için kısa süreli bir önbellek (Redis) önerilir.

Ön Koşullar

- Next.js 14+ (App Router önerilir), Node.js 18+.

- HTTPS zorunlu (geliştirmede localhost hariç). Üretimde gerçek bir alan adıyla test edin.

- Kütüphaneler: @simplewebauthn/server ve @simplewebauthn/browser. Bu ikili, challenge üretimi ve doğrulama işini hataya yer bırakmadan kolaylaştırır.

Adım 1: Projeyi Hazırlayın

Next.js projesini oluşturun ve bağımlılıkları kurun: npm i @simplewebauthn/server @simplewebauthn/browser. App Router ile app/api altında dört endpoint planlayın: /webauthn/register/options, /webauthn/register/verify, /webauthn/login/options, /webauthn/login/verify.

Sunucu tarafında yapılandırma için değişkenleri belirleyin: rpName, rpID (alan adınız), origin (ör. https://app.ornek.com). Bu üçü birbirine tam uyumlu olmalıdır; aksi halde tarayıcı doğrulamayı reddeder.

Adım 2: Kayıt (Registration) Akışı

1) Options üretimi: Sunucu, oturumu açık kullanıcının (ör. user.id, user.name) bilgileriyle generateRegistrationOptions çağırır. attestation: "none", authenticatorSelection için residentKey: "preferred" ve userVerification: "preferred" yeterlidir.

2) Challenge saklama: Dönen options.challenge değerini kullanıcının oturumuna veya Redis’e yazın. Bu değer tek kullanımlık ve kısa ömürlü olmalıdır.

3) İstemci işlem: Tarayıcıda startRegistration(options) veya yerel API ile navigator.credentials.create({ publicKey: options }) çağırın. Kullanıcı, cihaz biyometrisiyle onaylar ve bir attestation yanıtı oluşur.

4) Doğrulama: Yanıt sunucuya gönderilir ve verifyRegistrationResponse ile doğrulanır. Başarılıysa credentialID, publicKey, counter, transports gibi alanları veritabanına kaydedin.

Not: Binary verilerin JSON’a taşınmasında base64url dönüşümleri gerekir. @simplewebauthn bu dönüşümleri kolaylaştırır; farklı bir yaklaşım kullanıyorsanız, ArrayBuffer ↔ base64url dönüşümleri için tutarlı yardımcı fonksiyonlar geliştirin.

Adım 3: Giriş (Authentication) Akışı

1) Options üretimi: Sunucu generateAuthenticationOptions ile yeni bir challenge üretir. Dilerseniz sadece kullanıcıya ait allowCredentials listesi dönebilir veya passkey’lerin “discovered” kullanımına izin vermek için boş da bırakabilirsiniz.

2) İstemci işlem: Tarayıcıda startAuthentication(options) ya da navigator.credentials.get({ publicKey: options }) çağrılır. Kullanıcı biyometrik onayı verir.

3) Doğrulama: Sunucu, verifyAuthenticationResponse ile yanıtı doğrular; counter değerini günceller ve başarılıysa oturum veya token üretir (HTTP only, SameSite=Strict bir çerez önerilir).

Güvenlik ve Üretim İpuçları

- Origin ve rpID eşleşmesi: origin tam URL, rpID kök alan adı olmalı. https://login.ornek.com ile rpID: "ornek.com" uyumludur.

- HTTPS zorunlu: Geliştirme dışında güvenli olmayan kökenlerde WebAuthn çalışmaz.

- Attestation politikası: Kurumsal cihaz kökenini doğrulamak gerekmiyorsa none en pratik seçenek.

- Kullanıcı doğrulaması: userVerification: "required" güvenliği artırır; deneyim açısından “preferred” daha esnek olabilir.

- Passkey senkronizasyonu: Çok cihazlı deneyim için kullanıcıya aynı ekosistemde (iCloud / Google) senkronizasyonu etkinleştirmesini anlatın.

- Conditional UI: Chrome’da parolasız “otomatik” akış için navigator.credentials.get({ mediation: "conditional" }) ve ilgili bayrakları düşünün.

- Geri dönüş: İlk aşamada SMS/e-posta yedek yöntem bulundurun ancak uzun vadede phishing’e dayanıklı seçeneklere yönelin.

Sık Karşılaşılan Hatalar

- NotAllowedError: Kullanıcı akışı iptal etti veya tarayıcı UI zaman aşımına uğradı. Zaman aşımını düşürün ve açık geri bildirim gösterin.

- InvalidStateError: Aynı cihazda aynı kullanıcı için tekrar kayıt yapılmak isteniyor olabilir. Kayıt öncesi kullanıcıya mevcut passkey’leri gösterip yönetin.

- RP ID uyuşmazlığı: Alt alan adı/Origin ve rpID yanlış ayarlandığında doğrulama başarısız olur. Üretim alan adınızla birebir test edin.

Dağıtım ve Sonuç

Uygulamayı dağıtırken, ters proxy (Nginx) üzerinden HTTP → HTTPS zorlaması yapın. Load balancer arkasında gerçek istemci IP’sini günlüğe almak için X-Forwarded-For başlığını doğru iletin. CDN veya WAF kullanıyorsanız WebAuthn isteklerinin gövde boyutu ve header’larını kısıtlamadığından emin olun.

Sonuç olarak, WebAuthn ve Passkey ile Next.js + Node.js üzerinde parolasız kimlik doğrulama kurmak düşündüğünüzden daha erişilebilir. Doğru rpID/origin eşleşmesi, sağlam challenge saklama, güvenli çerez ayarları ve iyi bir kullanıcı akışı ile hem güvenlik seviyenizi yükseltir hem de dönüşüm oranlarını artırırsınız. Bugün basit bir kayıt/giriş prototipi hazırlayıp ekibinizle birlikte deneyin; parolaları geride bırakma vakti geldi.

3.

21 Ekim 2025 Salı

Yerel LLM Kurulumu: Ollama ve Open WebUI ile Hızlı ve Güvenli Yapılandırma Rehberi

Giriş: Neden Yerel LLM?

Gizlilik, düşük gecikme ve maliyet kontrolü, büyük dil modellerini (LLM) yerelde çalıştırmanın en önemli avantajları. Bu rehberde, açık kaynak ekosistemde hızla popülerleşen Ollama ile modelleri nasıl indireceğinizi ve Open WebUI üzerinden nasıl yöneteceğinizi adım adım göstereceğim. Amaç, teknik bariyeri düşük tutarak pratik bir kurulum sağlamak ve GPU hızlandırma, belge tabanlı arama (RAG) gibi ileri kullanım senaryolarına hızlıca geçebilmek.

Ön Koşullar ve Mimari

Ollama; macOS’ta Metal, Linux’ta CUDA/ROCm, Windows’ta DirectML/CUDA (uyum durumuna göre) ile çalışır. Open WebUI, Ollama’nın sunduğu yerel API’ye (varsayılan http://localhost:11434) bağlanarak tarayıcı tabanlı bir arayüz sunar. İkisini tek makinede koşturabilir, Docker ile izole edebilir veya sunucuya taşıyabilirsiniz.

Kurulum: Ollama

macOS: Homebrew ile brew install ollama komutunu çalıştırın. Ardından ollama serve ile servisi başlatın. Apple Silicon’da GPU hızlandırma otomatik devreye girer.

Linux: Terminalde curl -fsSL https://ollama.com/install.sh | sh komutunu çalıştırın. NVIDIA GPU için sürücü ve CUDA kurulumu yaptığınızdan emin olun. Servisi systemctl enable --now ollama ile kalıcılaştırabilirsiniz.

Windows: Resmi .msi yükleyicisiyle kurulum yapın. Ollama Tray ile servis başlatılabilir. GPU hızlandırma için güncel sürücüler ve desteklenen backend gereklidir.

İlk Modeli İndirme ve Çalıştırma

Popüler ve hızlı bir başlangıç için ollama pull llama3:8b veya ollama pull mistral:7b komutlarını kullanın. Ardından ollama run llama3:8b diyerek etkileşime geçin. Soruları terminalden yazabilir veya REST API ile programatik çağrılar yapabilirsiniz.

API örneği: curl http://localhost:11434/api/generate -d '{"model":"llama3:8b","prompt":"Merhaba, bugünün tarihi?"}'. Yanıtlarda gecikme görürseniz daha düşük quantizasyon (ör. q4_K_M) indirmeyi değerlendirin.

Open WebUI ile Grafik Arayüz

Open WebUI, sohbet geçmişi, çoklu model, belge ekleme ve RAG gibi özellikleri tek ekranda sunar. Docker ile hızlı kurulum için iki konteyner yeterlidir.

Ollama (Docker): docker run -d --name ollama -p 11434:11434 --gpus all -v ollama:/root/.ollama ollama/ollama

Open WebUI: Linux’ta Ollama’ya erişim için host gateway ekleyin: docker run -d --name open-webui -p 3000:8080 --add-host=host.docker.internal:host-gateway -e OLLAMA_API_BASE_URL=http://host.docker.internal:11434 -v open-webui:/app/backend/data open-webui/open-webui:latest

Windows/macOS’ta genellikle host.docker.internal otomatik çalışır. Tarayıcıdan http://localhost:3000 adresine giderek arayüze ulaşabilirsiniz.

RAG: Belgelerle Akıllı Yanıtlar

Open WebUI içinde “Knowledge” veya “Documents” bölümünden PDF, Markdown, TXT gibi belgeleri ekleyebilir ve indeksleyebilirsiniz. Ardından sohbet penceresinde ilgili bilgi tabanını seçtiğinizde model, cevaplarını bu içeriklere dayandırır. Küçük veri kümelerinde arama oldukça hızlıdır; büyük koleksiyonlarda bellek yükünü azaltmak için daha düşük boyutlu modeller ve hafif embedding’ler tercih edin.

Performans ve İnce Ayar

- Quantization: q4 varyantları RAM ve VRAM kullanımını düşürür; kalite/akıcılık dengesi için q5 veya q6 deneyin.
- İş Parçacığı: OLLAMA_NUM_PARALLEL ile eşzamanlı istek sayısını, --num-ctx ile bağlam penceresini ayarlayın.
- GPU Paylaşımı: Birden fazla model kullanıyorsanız aynı anda çalıştırmak yerine sıraya almayı tercih edin. GPU belleği dolarsa CPU’ya düşerek performans keskin biçimde azalabilir.
- Model Seçimi: Kod tamamlama için “Coder” varyantları; uzun bağlam gerektiren işlerde “Instruct” ve geniş context pencereli sürümler daha verimlidir.

Güvenlik ve Ağ Erişimi

Ollama’nın API’sini dış dünyaya açacaksanız bir ters vekil (ör. Caddy, Nginx) arkasında temel kimlik doğrulama uygulayın. Ev ağı senaryosunda sadece localhost’a bağlayın ve 11434 portunu yönlendirmeyin. Open WebUI kullanıcı hesapları oluşturmanıza izin verir; rol tabanlı erişimle modellerin kimler tarafından kullanılabileceğini sınırlayın.

Sorun Giderme

- Yavaş yanıt: Daha küçük modeli veya düşük quantizasyonu deneyin; CPU moduna düşmediğinizden emin olun.
- GPU tanınmıyor: Sürücü/CUDA güncellemelerini kontrol edin. Docker’da --gpus all bayrağı ve NVIDIA Container Toolkit gereklidir.
- Bağlantı hatası: Open WebUI’de OLLAMA_API_BASE_URL değerini ve ağ köprüsünü doğrulayın; Linux’ta --add-host parametresini eklemeyi unutmayın.
- Disk doluyor: Kullanmadığınız modelleri ollama rm model-adı ile kaldırın; hacim boyutlarını düzenli izleyin.

Sonuç

Ollama + Open WebUI ikilisiyle yerel LLM deneyimi, hem bireysel üretkenlik hem de kurumsal prototipleme için güçlü bir zemin sunuyor. Kurulum basit, yönetim pratik ve maliyet öngörülebilir. Başlangıçta hafif bir modelle ilerleyip ihtiyaçlara göre ölçeklendirmek, GPU kaynaklarını dikkatle planlamak ve güvenlik katmanlarını erken eklemek uzun vadede en sağlıklı yaklaşım olacaktır.

20 Ekim 2025 Pazartesi

Traefik v3 ile Docker Compose Üzerinde Çoklu Alan Adı ve Otomatik SSL: Adım Adım Rehber

Bir sunucuda birden fazla web uygulamasını farklı alan adlarıyla güvenli (HTTPS) şekilde yayınlamak istiyorsanız, modern bir ters proxy çözümü olan Traefik v3 harika bir seçenek. Bu rehberde, Docker Compose kullanarak Traefik v3 ile otomatik Let’s Encrypt sertifika yönetimini, HTTP’den HTTPS’e yönlendirmeyi ve birden fazla alan adını tek yapılandırmada yönetmeyi adım adım göstereceğim.

Traefik v3 nedir ve neden tercih edilmeli?

Traefik v3, konteyner tabanlı mimariler için optimize edilmiş, otomatik keşif ve sade etiketleme (label) mantığıyla çalışan bir ters proxy ve yük dengeleyicidir. Docker, Kubernetes ve diğer sağlayıcılarla derin entegrasyon sunar. v3 sürümü, performans ve yapılandırma deneyiminde iyileştirmeler getirirken, Let’s Encrypt ile otomatik TLS/SSL sertifikalandırmayı pratik hale getirir.

Ön koşullar ve DNS

- Bir Linux sunucu (Ubuntu/Debian/CentOS vb.)

- Docker ve Docker Compose kurulu

- Alan adınızda, sunucunuzun IP adresine işaret eden A/AAAA kayıtları (örnek: app.example.com ve traefik.example.com)

İpucu: Cloudflare kullanıyorsanız ve HTTP-01 doğrulaması yapacaksanız, ilgili DNS kaydını “DNS only” (turuncu bulut kapalı) olarak ayarlayın; aksi halde Let’s Encrypt doğrulaması başarısız olabilir.

Adım 1: Docker ağı ve klasörler

Aşağıdaki ağ, farklı Compose dosyaları arasında servisleri paylaşmanızı sağlar. Oluşturun:

docker network create web
mkdir -p traefik/letsencrypt
touch traefik/letsencrypt/acme.json
chmod 600 traefik/letsencrypt/acme.json

Adım 2: Traefik v3 için docker-compose.yml

Aşağıdaki dosya, Traefik’i 80/443 portlarına bağlar, Let’s Encrypt’i HTTP-01 ile etkinleştirir, HTTP’yi otomatik olarak HTTPS’e yönlendirir ve güvenli bir kontrol paneli kurar. E-postayı ve alan adlarını kendinize göre düzenlemeyi unutmayın.

version: "3.8"

services:
  traefik:
    image: traefik:v3.0
    container_name: traefik
    command:
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - --entrypoints.web.http.redirections.entrypoint.to=websecure
      - --entrypoints.web.http.redirections.entrypoint.scheme=https
      - [email protected]
      - --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
      - --certificatesresolvers.letsencrypt.acme.httpchallenge=true
      - --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
      - --api.dashboard=true
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./traefik/letsencrypt:/letsencrypt
    networks:
      - web
    labels:
      - "traefik.enable=true"
      # Dashboard için güvenli router
      - "traefik.http.routers.api.rule=Host(`traefik.example.com`)"
      - "traefik.http.routers.api.service=api@internal"
      - "traefik.http.routers.api.entrypoints=websecure"
      - "traefik.http.routers.api.tls.certresolver=letsencrypt"
      # Basit BasicAuth middleware (parolayı hashleyip $$ ile kaçırın)
      - "traefik.http.middlewares.basicauth.basicauth.users=admin:$$2y$$12$$REPLACE_WITH_YOUR_BCRYPT_HASH"
      - "traefik.http.routers.api.middlewares=basicauth@docker"

  # Örnek uygulama
  whoami:
    image: traefik/whoami
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`app.example.com`)"
      - "traefik.http.routers.whoami.entrypoints=websecure"
      - "traefik.http.routers.whoami.tls.certresolver=letsencrypt"
    networks:
      - web

networks:
  web:
    external: true

Bu dosyada iki önemli nokta var: “exposedbydefault=false” etiketsiz konteynerların dış dünyaya açılmasını engeller; “http redirections” ise tüm HTTP trafiğini otomatik olarak HTTPS’e taşır. Dashboard’ı traefik.example.com üzerinden basit bir BasicAuth ile koruyoruz. Parola hash’ini üretmek için şu komutlardan birini kullanabilirsiniz:

# OpenSSL ile bcrypt:
htpasswd -nbB admin SIFRENIZ

# Ya da Python:
python3 -c "import bcrypt; print(b'admin:' + bcrypt.hashpw(b'SIFRENIZ', bcrypt.gensalt()))"

Elde ettiğiniz hash’i compose dosyasına yapıştırırken $ karakterlerini $$ ile kaçırın; aksi halde Compose bunu çevresel değişken sanacaktır.

Adım 3: Servis ekleme ve çoklu alan adı

Yeni bir servis eklemek için ilgili konteynere “traefik.enable=true” etiketi ve “rule=Host(`sub.example.com`)" kuralı tanımlayın. Her servis için ayrı router, entrypoint ve TLS resolver atayabilirsiniz. Örneğin bir Node.js uygulaması için:

myapp:
  image: node:20-alpine
  working_dir: /app
  command: ["node", "server.js"]
  volumes:
    - ./myapp:/app
  labels:
    - "traefik.enable=true"
    - "traefik.http.routers.myapp.rule=Host(`api.example.com`)"
    - "traefik.http.routers.myapp.entrypoints=websecure"
    - "traefik.http.routers.myapp.tls.certresolver=letsencrypt"
  networks:
    - web

Statik dosya sunucuları, PHP-FPM arkasındaki Nginx veya Go/Rust uygulamaları da benzer şekilde etiketlenir. Tüm servisler aynı “web” ağına bağlı oldukça Traefik onları otomatik keşfeder.

Güvenlik ve en iyi uygulamalar

- Dashboard’ı mutlaka alt alan adı ve BasicAuth (veya IP kısıtlaması) ile koruyun.

- “acme.json” dosyasını 600 izinleriyle saklayın; sertifika anahtarları bu dosyada tutulur.

- Gereksiz portları açmayın; yalnızca 80 ve 443 çoğu kurulum için yeterlidir.

- Üretimde otomatik yeniden başlatma politikası (“restart: unless-stopped”) kullanabilirsiniz.

Sık karşılaşılan hatalar ve çözümler

- Sertifika alınamadı: DNS kayıtlarınız doğru mu? Cloudflare “proxied” açık mı? HTTP-01 için kapalı olmalı. Alternatif olarak DNS-01 challenge kullanarak wildcard (*.example.com) alabilirsiniz.

- 80/443 dinlenemiyor: Sunucuda bu portları kullanan farklı bir servis (ör. Nginx) çalışıyor olabilir. Kapatın veya taşıyın.

- Rate limit: Let’s Encrypt test sırasında üretim yerine staging sunucularını deneyin. Traefik için “acme.caserver” parametresiyle staging’e geçebilirsiniz.

- “acme.json permission denied”: Dosya izinlerini 600 yapın ve doğru mount yolunu kontrol edin.

Sonuç

Traefik v3 ve Docker Compose ile çok sayıda servisi tek bir sunucu üzerinde, otomatik SSL ve modern yönlendirme yetenekleriyle dakikalar içinde yayına alabilirsiniz. Etiket tabanlı mimari, CI/CD süreçlerine rahatça entegre olurken, yeniden başlatma ihtiyacı olmadan konfigürasyon değişikliklerini devreye almanızı sağlar. Üstelik ölçeklenebilir ve gözlemlenebilir bir altyapının temelini atmış olursunuz.

19 Ekim 2025 Pazar

Tarayıcıda Python Çalıştırma Rehberi: WebAssembly ve Pyodide ile Adım Adım

WebAssembly (WASM) ve Pyodide sayesinde Python kodunu doğrudan tarayıcıda, sunucuya ihtiyaç duymadan çalıştırmak artık mümkün. Bu yazıda, Pyodide nedir, nasıl entegre edilir, paket yönetimi ve performans ipuçları nelerdir gibi sorulara adım adım yanıt veriyorum. Hedefimiz, hem modern web uygulamalarına Python gömmenin pratik yolunu göstermek hem de gerçek hayatta işinize yarayacak optimizasyon önerilerini sunmak.

Pyodide Nedir?

Pyodide, CPython yorumlayıcısını ve birçok bilimsel Python paketini WebAssembly’ye derleyerek tarayıcıda çalıştırmanıza olanak tanır. NumPy, Pandas, Matplotlib gibi kütüphanelerin “pure-Python” olanlarını veya WASM’a derlenmiş varyantlarını tarayıcıya getirir. Ağ bağlantısı olmasa bile, gerekli dosyalar indirildikten sonra kodunuzu yerel olarak işletir. Bu da interaktif eğitim içerikleri, gömülü veri görselleştirme, offline notebook deneyimleri ve güvenli istemci tarafı prototipleme için güçlü bir zemin sunar.

Hızlı Başlangıç: Basit Entegrasyon

Aşağıdaki minimal örnekle tarayıcıda Python çalıştırabilirsiniz. Kodu bir HTML dosyasına koyup açmanız yeterli.

<!-- Pyodide yükleyici -->
<script src="https://cdn.jsdelivr.net/pyodide/v0.26.0/full/pyodide.js"></script>
<script>
(async () => {
const pyodide = await loadPyodide({ indexURL: "https://cdn.jsdelivr.net/pyodide/v0.26.0/full/" });
await pyodide.runPythonAsync(`import sys; print(sys.version)`);
const result = await pyodide.runPythonAsync("sum(range(10))");
console.log("Python sonucu:", result);
})();
</script>

Burada loadPyodide ile WASM tabanlı Python ortamı yükleniyor, ardından runPythonAsync ile kod yürütülüyor. Konsolda Python sürümü ve örnek bir hesaplamanın sonucu görünecektir.

Paket Yönetimi: micropip ve Yerleşik Paketler

Pyodide, birçok popüler kütüphaneyi hazır olarak getirir. Ek bir pakete ihtiyaç duyduğunuzda micropip ile pure-Python paketleri (C uzantısı gerektirmeyenler) kolayca kurulabilir.

await pyodide.runPythonAsync(`import micropip; await micropip.install("requests")`);

NumPy veya Pandas gibi ağır paketler için Pyodide’ın yerleşik kaynaklarını kullanmak daha verimlidir. Bunlar çoğunlukla pyodide.loadPackage ile önceden yüklenebilir:

await pyodide.loadPackage(["numpy", "pandas"]);

Paket yüklemelerini sayfa ilk açılışında toplu yapmak, kullanıcı etkileşimi sırasında gecikmeleri azaltır. İlk kez yüklemede CDN’den indirme yapılırken, sonraki sayfa yenilemelerinde tarayıcı önbelleğinden faydalanılır.

Tarayıcı Dosya Sistemi ve Veri Paylaşımı

Pyodide, Emscripten’in sanal dosya sistemini (MEMFS) kullanır. JavaScript tarafındaki veriyi Python tarafına aktarmak için dosya sistemine yazmak pratik bir yöntemdir:

const csv = "a,b\\n1,2\\n3,4";
pyodide.FS.writeFile("/tmp/data.csv", csv);
await pyodide.runPythonAsync(`import pandas as pd; df = pd.read_csv("/tmp/data.csv"); print(df.sum().to_dict())`);

Alternatif olarak, doğrudan JS-Python köprüsünden yararlanabilir ve pyodide.toPy / pyodide.toJs ile veri alışverişi yapabilirsiniz. Büyük verilerde kopyalamayı en aza indirmek için bu köprüleri tercih edin.

Performans İpuçları

- Lazy yükleme yapın: İlk ekranda gerekmeyen büyük paketleri, kullanıcı etkileşimiyle tetiklenen aşamada yükleyin.
- runPython yerine runPythonAsync kullanın: Uzun süren işlemler UI’ı kilitlemesin.
- Ön ısıtma (warm-up): Sayfa yüklenir yüklenmez küçük bir Python ifadesi çalıştırmak, JIT yoksa bile modül başlatmalarını önceden yaparak ilk gerçek görevde gecikmeyi azaltır.
- Önbellekleme: CDN varlıklarını (pyodide.js, .wasm, paket indeksleri) Service Worker ile cache-first stratejisiyle saklayın. Böylece offline veya zayıf ağda bile hızlı açılış sağlanır.
- Veri boyutunu sınırlayın: Tarayıcı belleği kısıtlıdır. Tek seferde işlenen veri setlerini makul boyutta tutun ve gereksiz kopyalardan kaçının.

Güvenlik ve Sandbox

Pyodide, tarayıcının güvenli çalışma alanında koşar. Varsayılan olarak yerel dosya sistemine erişemez ve ağ istekleri tarayıcı CORS kurallarına tabidir. Üçüncü taraf paketleri yüklerken yalnızca güvendiğiniz kaynakları kullanın. Kullanıcıdan gelen Python kodunu çalıştıracaksanız, suistimali azaltmak için zaman sınırı, bellek sınırı ve izinli API listesi (allowlist) gibi korumalar düşünün.

Ne Zaman Pyodide? Ne Zaman Sunucu?

- Pyodide’ı tercih edin: Hızlı prototip, eğitim içerikleri, etkileşimli dokümantasyon, gizlilik gerektiren istemci tarafı analizler, offline kullanım senaryoları.
- Sunucuyu tercih edin: Büyük veri işlemleri, yoğun CPU bellek kullanımı, kurumsal paket bağımlılıkları, kalıcı depolama ve erişim kontrolünün kritik olduğu projeler.

Örnek Kullanım: Mini Veri Görselleştirme

Aşağıdaki örnek, küçük bir veri kümesiyle Matplotlib’i kullanır. İlk etapta paketi yükleyin, ardından grafiği base64 olarak üretip bir <img> etiketine atayabilirsiniz. (Bu yazıda görsel eklemiyoruz, ancak yaklaşım bu şekildedir.)

await pyodide.loadPackage(["matplotlib", "numpy"]);
const png = await pyodide.runPythonAsync(`import matplotlib.pyplot as plt, io, base64, numpy as np
x = np.linspace(0, 2*np.pi, 200)
y = np.sin(x)
plt.figure(figsize=(3,2), dpi=150)
plt.plot(x, y)
buf = io.BytesIO()
plt.savefig(buf, format="png", bbox_inches="tight")
base64.b64encode(buf.getvalue()).decode()`);
// document.getElementById("plot").src = "data:image/png;base64," + png;

Sonuç

Pyodide ve WebAssembly, Python’u tarayıcıya taşıyarak ön uç geliştirmeye yeni kapılar açıyor. Doğru paket yönetimi, akıllı önbellekleme ve verimli veri paylaşımıyla hem akıcı bir kullanıcı deneyimi hem de sürdürülebilir performans elde edebilirsiniz. Küçük başlayın, ihtiyaç duydukça paketleri ve optimizasyonları ekleyin. Böylece ister eğitim amaçlı mini bir laboratuvar, ister ürününüze gömülü etkileşimli bir analiz modülü geliştirin; modern webin olanaklarından en iyi şekilde yararlanırsınız.

18 Ekim 2025 Cumartesi

Rust ve WebAssembly ile Tarayıcıda Yüksek Performanslı Görüntü Filtresi Geliştirme (Adım Adım)

Giriş

Tarayıcıda yüksek performanslı görüntü işleme yapmak çoğu zaman JavaScript ile zorlayıcı olabilir. Rust ve WebAssembly (WASM) ikilisi sayesinde, CPU yoğun işlemleri güvenli ve hızlı biçimde web tarafına taşıyabilirsiniz. Bu rehberde, Rust ile basit bir gri tonlama filtresi yazacak, wasm-bindgen ve wasm-pack kullanarak WebAssembly’ye derleyecek ve sonucu bir web projesinde çağıracağız. Amaç sade, pratik ve SEO uyumlu bir anlatımla sizi hızlıca üretken hale getirmek.

Neden Rust + WebAssembly?

WebAssembly, tarayıcıda neredeyse yerel hızda çalışabilen bir bayt kod formatıdır. Rust ise bellek güvenliği, sıfır maliyetli soyutlamalar ve modern dil özellikleriyle WebAssembly hedefi için biçilmiş kaftandır. Bu kombinasyon sayesinde, görüntü işleme, ses işleme, veri sıkıştırma gibi CPU yoğun iş yüklerini JavaScript’in tek iş parçacıklı darboğazından çıkarır ve kullanıcıya akıcı bir deneyim sunarsınız.

Önkoşullar ve Kurulum

Başlamadan önce sisteminizde Rust (stable), wasm-pack ve bir paket yöneticisi (npm veya pnpm) kurulu olmalı. Kurulum komutları: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh ve cargo install wasm-pack. Web tarafı için basit bir Vite veya React projesi işinizi görecektir.

Rust Kütüphanesini Oluşturma

Yeni bir Rust kütüphanesi oluşturun: cargo new --lib image_filter_wasm. Ardından Cargo.toml dosyanızı aşağıdaki gibi düzenleyin:

[package]
name = "image_filter_wasm"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
wasm-bindgen = "0.2"

Gri Tonlama Filtresi Yazımı

Temel yaklaşımımız, bir Uint8Array içindeki RGBA piksel verisini alıp, gri tonlama uygulayarak yine Uint8Array olarak geri döndürmek. src/lib.rs içeriği örneği:

use wasm_bindgen::prelude::*;
use js_sys::Uint8Array;

#[wasm_bindgen]
pub fn grayscale(input: Uint8Array) -> Uint8Array {
  let mut data = input.to_vec();
  let len = data.len();
  let mut i = 0;
  while i + 3 < len {
    let r = data[i] as u32;
    let g = data[i + 1] as u32;
    let b = data[i + 2] as u32;
    // Luma (BT.709) yaklaşımı
    let y = (0.2126 * r as f32 + 0.7152 * g as f32 + 0.0722 * b as f32) as u8;
    data[i] = y;
    data[i + 1] = y;
    data[i + 2] = y;
    i += 4;
  }
  Uint8Array::from(&data[..])
}

Yukarıdaki örnekte wasm-bindgen ile Uint8Array türünü kullanarak kopyalama maliyetini yönetilebilir düzeyde tutuyoruz. Daha ileri optimizasyonlar için tek seferlik bellek ayırma ve işaretçi tabanlı API’ler de tercih edilebilir.

WebAssembly’ye Derleme

Klasör kökünde wasm-pack build --target web çalıştırın. Bu komut pkg klasöründe tarayıcı uyumlu JS wrapper ve .wasm dosyasını üretir. Alternatif olarak --target bundler ile bundler tabanlı projelere uygun çıktı alabilirsiniz.

Web Projesine Entegrasyon (React Örneği)

Bir React projesinde, canvas üzerinden ImageData elde edip pikselleri WASM fonksiyonuna aktaracağız. Basit bir akış şu şekilde olabilir:

import init, { grayscale } from "./pkg/image_filter_wasm.js";

async function runFilter(ctx, width, height) {
  await init();
  const imageData = ctx.getImageData(0, 0, width, height);
  const input = new Uint8Array(imageData.data.buffer.slice(0));
  const output = grayscale(input);
  imageData.data.set(output);
  ctx.putImageData(imageData, 0, 0);
}

Bu kod, canvas içindeki görseli alır, pikselleri grayscale fonksiyonundan geçirir ve yeniden kanvasa yazar. Geri dönüşte yeni bir Uint8Array aldığımız için doğrudan set ile kopyalamak yeterlidir.

Performans İpuçları

- Kopyalamaları azaltın: Sürekli yeni Uint8Array oluşturmak yerine, tek bir tamponu tekrar kullanacak bir API tasarlayın (ör. işaretçi ve uzunluk üzerinden, ileri düzey wasm-bindgen teknikleriyle).
- SIMD etkinleştirin: Rust’ta wasm32-unknown-unknown hedefi için SIMD desteği stabildir. Yapılandırmada RUSTFLAGS="-C target-feature=+simd128" kullanabilir, wasm-opt -O3 ile Binaryen optimizasyonlarına başvurabilirsiniz.
- İş yükünü ayırın: Büyük resimlerde ana iş parçacığını kilitlememek için Web Worker üzerinden çağrı yapın. Çok iş parçacığı (WASM threads) kullanacaksanız SharedArrayBuffer gerekeceğinden COOP/COEP ile Cross-Origin Isolation aktif olmalı.

Karşılaşılabilecek Sorunlar

- Paketleme: Bazı bundler’lar .wasm dosyalarının kopyalanması ve yüklenmesi için özel yapılandırma ister. --target web çıktısı, modern bundler’larla genelde sorunsuzdur.
- Tür uyumsuzluğu: ImageData.data Uint8ClampedArray döndürür. Bu nedenle Uint8Array dönüşümü yaptığımızdan emin olmalıyız.
- Boyut: WASM paketinin boyutunu düşük tutmak için gereksiz bağımlılıklardan kaçının ve wasm-opt kullanın.

Test ve Ölçüm

Basit bir FPS sayacı veya zaman damgası ile performance.now() ölçümleri alarak JavaScript ve WASM sürümlerini kıyaslayın. Büyük çözünürlükteki görsellerde, Rust + WebAssembly yaklaşımının belirgin şekilde daha düşük gecikme ve daha yüksek kare/saniye ürettiğini göreceksiniz.

Sonuç

Rust ve WebAssembly, tarayıcıda yüksek performanslı görüntü işleme için güçlü ve sürdürülebilir bir çözüm sunar. Bu rehberde, sıfırdan bir gri tonlama filtresi yazarak derleme, entegrasyon ve optimizasyon adımlarını gördük. Aynı yöntemi keskinleştirme, bulanıklaştırma, kenar algılama gibi farklı filtrelerle genişletebilir, hatta gerçek zamanlı kamera akışlarına uygulayabilirsiniz. Modern web uygulamalarında performansı öne çıkarmak istiyorsanız, Rust + WASM öğrenme eğrisine kesinlikle değer.

17 Ekim 2025 Cuma

Tarayıcıda WebGPU ile Yapay Zeka Modellerini Hızlandırma: ONNX Runtime Web ile Adım Adım Rehber

WebGPU ile Tarayıcıda Yapay Zeka Neden Önemli?

WebGPU, tarayıcıda GPU’ya neredeyse yerel erişim sağlayan modern bir web standardıdır. WebGL’in grafik odaklı doğasını aşarak hesaplama iş yüklerini de hızlandırır ve makine öğrenmesi modellerini doğrudan Chrome, Edge veya Safari gibi tarayıcılarda çalıştırırken belirgin performans kazancı sunar. Bu yazıda, ONNX Runtime Web kullanarak WebGPU üzerinden nasıl hızlandırma yapabileceğinizi, gerçek dünya ipuçları ve sorun giderme önerileriyle adım adım anlatıyorum.

Ön Koşullar ve Uyumluluk

WebGPU, Chrome 113+, Edge 113+ sürümlerinde yaygın olarak desteklenir. macOS’te Metal, Windows’ta Direct3D 12, Linux’ta ise Vulkan üzerinden çalışır. Güncel bir tarayıcı kullandığınızdan emin olun. Kurumsal cihazlarda GPU sürücüleri eskiyse veya politika kısıtları varsa WebGPU adaptörü bulunamayabilir; bu durumda ONNX Runtime Web otomatik olarak WASM (WebAssembly) yedek yoluna düşebilir. Eğer eski bir tarayıcı kullanıyorsanız, chrome://flags alanında WebGPU ile ilgili ayarları gözden geçirmeniz gerekebilir; ancak çoğu güncel sürümde ekstra bir işlem yapmadan çalışır.

Ne Kuracağız? Kısa Yol Haritası

Bu rehberde bir web sayfasına ONNX Runtime Web’i entegre edip, bir görüntü sınıflandırma modelini WebGPU üzerinde çalıştıracağız. Adımlar özetle şöyle: ONNX Runtime Web’i projeye eklemek, uygun bir ONNX modeli seçmek, girdi verisini hazırlamak, executionProviders: ["webgpu"] ile oturum açmak ve sonuçları yorumlamak.

Adım 1: Projeye ONNX Runtime Web Eklemek

İki yaygın yöntem var. NPM ile kurulum için modern bir paketleyici (Vite, Webpack, Parcel) kullanabilirsiniz. Komut satırında npm i onnxruntime-web diyerek kurduktan sonra uygulamanızda import * as ort from "onnxruntime-web" ifadesini kullanın. Hızlı denemeler için CDN ile de ilerleyebilirsiniz: HTML dosyanıza ONNX Runtime Web’in CDN bağlantısını eklemek yeterli olur. Her iki yöntemde de tarayıcınızda WebGPU destekliyse arka planda otomatik olarak GPU hızlandırma devreye alınabilir.

Adım 2: Model Seçimi ve Hazırlık

Başlangıç için ONNX Model Zoo’da bulunan hafif bir model tercih edin. Örneğin MobileNet veya SqueezeNet düşük bellek tüketimiyle iyi bir başlangıç sunar. İndirdiğiniz model dosyasını (örnek: model.onnx) sunucunuzdan statik olarak servis edin. Model boyutunu mümkün olduğunca düşük tutmak hem ilk yükleme süresini hem de bellek kullanımını azaltır. FP16 dönüştürülmüş modeller, GPU bellek ayak izini düşürerek performansa katkı sağlar.

Adım 3: WebGPU ile Oturum Oluşturma

ONNX Runtime Web ile bir oturum oluştururken executionProviders: ["webgpu"] parametresini geçerek GPU hızlandırmayı istersiniz. WebGPU uygun değilse kütüphane WASM’a otomatik geçebilir. Bu aşamada önemli nokta, oturumu yalnızca bir kez oluşturmanızdır; inference işlemleri sırasında aynı oturumu tekrar tekrar kullanmak, modelin yeniden yüklenmesini ve derlenmesini önleyerek ciddi zaman kazandırır.

Adım 4: Girdi Hazırlama ve İnference

Görüntü tabanlı bir model için girdiyi modele uygun boyuta ölçekleyip normalleştirmeniz gerekir. Bu işlem genellikle şu adımlardan oluşur: görseli kanallara ayırma (RGB), piksel değerlerini 0-1 aralığına ölçekleme, ortalama/standart sapma ile normalizasyon ve tensörü NCHW biçiminde düzenleme. ONNX Runtime Web için tensör oluştururken new ort.Tensor("float32", data, [1, 3, H, W]) biçimini kullanabilirsiniz. Çıktı yüzlerce sınıf ve olasılık içeriyorsa en yüksek olasılıklı birkaç etiketi seçip kullanıcıya sunmak idealdir.

Adım 5: Performans İyileştirme İpuçları

Performansı artırmak için birkaç pratik öneri: Oturum nesnesini yeniden kullanın ve model dosyasını önbelleğe alarak ilk yükleme süresini kısaltın. Girdi verisini oluştururken gereksiz kopyalardan kaçının; aynı Float32Array tamponunu yeniden kullanmak GC yükünü azaltır. Mümkünse daha küçük çözünürlükte girişler deneyin; bazı modeller 224x224 ile tatmin edici sonuç verir. Ağır iş yüklerini Web Worker içine taşıyarak ana iş parçacığını bloklamayın; UI donmalarını önlemek için hesaplama dilimlerini requestIdleCallback veya küçük partisyonlarla planlayın. Ölçüm için performance.now() ile yükleme, ön işleme, inference ve son işlem sürelerini ayrı ayrı izleyin; darboğazı nokta atışı bularak iyileştirin.

Güvenlik, Gizlilik ve Dağıtım

Tarayıcı içinde yerel inference çalıştırmak, verilerin sunucuya gitmeden işlenmesini sağlar; bu da gizlilik ve gecikme (latency) açısından avantajdır. WASM yedek yolunda iş parçacıkları ve SIMD kullanmayı planlıyorsanız COOP/COEP başlıklarıyla cross-origin isolated bir yapılandırma gerekir. İç ağda veya kurumsal ortamlarda dağıtım yaparken GPU sürücü sürümlerini ve tarayıcı versiyonlarını standardize etmek, destek çağrılarını ciddi ölçüde azaltır.

Yaygın Hatalar ve Çözümler

“Adapter is null” veya “No WebGPU device found” hataları alıyorsanız tarayıcınızı ve ekran kartı sürücünüzü güncelleyin; sanal makinelerde WebGPU kısıtlı olabilir. “Out of memory” uyarılarında giriş boyutunu küçültün, modelin FP16 sürümüne geçin veya daha hafif bir mimari deneyin. “Invalid model input shape” hatası, tensör boyutlarıyla modelin beklediği şeklin uyuşmadığını gösterir; modelin giriş ismini ve beklenen boyutları kontrol edin. WASM’a düşüşte performans çok geriliyorsa, WebGPU’nun gerçekten etkinleştiğini doğrulamak için oturum seçeneklerini ve tarayıcı destek sayfalarını inceleyin.

Gerçek Dünya Senaryoları

Perakende uygulamalarında raf denetimi veya barkod dışı ürün tanıma gibi görevler, mağaza içi tabletlerle çevrimdışı çalıştırılabilir. Eğitim teknolojilerinde çizim veya laboratuvar deneylerinde görüntü analizi, öğrenci cihazlarında gecikme olmadan yapılabilir. Yayıncılıkta canlı metin filtreleme veya basit duygu analizi, kullanıcı tarayıcısında gerçekleşerek sunucu maliyetlerini düşürür.

Sonuç ve Öneriler

WebGPU, tarayıcıda yapay zeka deneyimini yeni bir seviyeye taşıyor. ONNX Runtime Web ile birlikte kullanıldığında, çeşitli cihaz ve tarayıcı kombinasyonlarında tatmin edici performans ve düşük gecikme elde etmek mümkün. Küçük ve optimize edilmiş bir model, doğru ön işleme adımları ve tek seferde başlatılan bir oturum mimarisi, projelerinize stabilite ve hız kazandırır. İlk prototipinizi basit bir görüntü sınıflandırma modeliyle kurup, ardından model boyutu, giriş çözünürlüğü ve iş parçacığı stratejileri üzerinde iterasyon yaparak prodüksiyon seviyesine güvenle geçebilirsiniz.