Bu dosya, ödevinizin raporunu oluşturmanız için bir şablondur. Aşağıdaki başlıkları doldurarak kendi bulgularınızı, karşılaştırmalarınızı ve analizlerinizi ekleyin.
| Alan | Açıklama |
|---|---|
| Seçtiğim Depolama Sistemi | HDFS (Hadoop Distributed File System) |
| Gerekçem | Büyük hacimli log veriler (5 milyon kayıt) dağıtık ortamda güvenli ve ölçeklenebilir şekilde saklanılabiliyor. Apache Spark ile doğal entegrasyonu sayesinde analitik sorgular yüksek performansla çalıştırılabiliyor. |
| Kurulum Notları | Bir sorun yaşanmamıştır. |
| Erişilebilirlik Testi | Hem docker exec namenode hdfs dfs -ls /logs/raw komutu ile hem de Namenode UI ile dosyaların başarıyla yüklendiğini doğruladım. |
| Alan | Açıklama |
|---|---|
| Seçtiğim Depolama Sistemi | MinIO |
| Gerekçem | Veriler S3 uyumlu, hafif ve yüksek performanslı bir ortamda saklanabiliyor. Container tabanlı ortamlara uyumlu ve Parquet/ORC gibi sütun tabanlı dosya formatlarını doğrudan destekliyor. |
| Kurulum Notları | Bir sorun yaşanmamıştır. HDFS zaten docker compose -f docker-compose-hdfs.yml stop komutu ile önceden durdurulup MinIO kurulumu yapılmıştır. Çakışma olsaydı bile yine bu komutu çalıştırarak çözüm bulurdum. |
| Erişilebilirlik Testi | docker exec minio-client1 mc ls myminio komutu ile dosyaların başarıyla yüklendiğini doğruladım. Ayrıca docker exec minio-client1 mc stat myminio/logs/logs_***.json (logs_000.json, logs_001.json gibi) şeklinde komutlar yazarak nesnelerin bazı bilgileri de görüntüledim. |
Endpoint Bazında Yanıt Süresi & Hata Oranı Tablosu
| Endpoint | İstek Sayısı | Ortalama Yanıt Süresi (ms) | Median (50%) | 95. Yüzdelik (ms) | 99. Yüzdelik (ms) | Min (ms) | Max (ms) | Hata Oranı |
|---|---|---|---|---|---|---|---|---|
| /login | 2,250,531 | 163.44 | 155 | 277 | 295 | 50 | 299 | %7.74 |
| /checkout | 1,249,082 | 396.00 | 348 | 713 | 979 | 200 | 1499 | %7.76 |
| /cart | 750,327 | 213.88 | 199 | 363 | 392 | 80 | 399 | %7.77 |
| /pay | 599,878 | 496.99 | 448 | 816 | 1097 | 306 | 2985 | %7.82 |
| /inventory | 150,182 | 296.02 | 247 | 613 | 887 | 107 | 2477 | %7.82 |
Servis Bazında Hata Oranı Tablosu
| Servis | Toplam İstek | Hata Sayısı | Hata Oranı | Uyarı Sayısı | Uyarı Oranı |
|---|---|---|---|---|---|
| order-service | 1,249,192 | 99,859 | %7.99 | 249,209 | %19.94 |
| auth-service | 1,251,388 | 63,039 | %5.03 | 188,067 | %15.03 |
| payment-service | 1,249,698 | 187,806 | %15.02 | 311,876 | %24.95 |
| inventory-service | 1,249,722 | 37,470 | %2.99 | 124,278 | %9.94 |
Bölgeye Göre Trafik Dağılımı Tablosu
| Bölge | İstek Sayısı | Ortalama Yanıt Süresi (ms) |
|---|---|---|
| us-east | 1,249,955 | 273.11 |
| eu-central | 3,000,474 | 273.11 |
| ap-south | 749,571 | 273.14 |
En Çok İstek Yapan Kullanıcılar Tablosu
| Kullanıcı ID | İstek Sayısı |
|---|---|
| 38 | 50,401 |
| 33 | 50,311 |
| 35 | 50,282 |
| 48 | 50,239 |
| 30 | 50,225 |
| 11 | 50,212 |
| 32 | 50,206 |
| 49 | 50,176 |
| 17 | 50,138 |
| 3 | 50,128 |
| 37 | 50,102 |
| 16 | 50,101 |
| 8 | 50,098 |
| 29 | 50,098 |
| 1 | 50,094 |
| 44 | 50,085 |
| 20 | 50,064 |
| 19 | 50,062 |
| 6 | 50,035 |
| 43 | 50,017 |
En Çok İstek Yapan IP Adresleri Tablosu
| IP Adresi | İstek Sayısı | Benzersiz Kullanıcı |
|---|---|---|
| 192.168.1.6 | 200,837 | 1000 |
| 192.168.1.4 | 200,758 | 1000 |
| 192.168.1.1 | 200,189 | 1000 |
| 192.168.1.10 | 200,133 | 1000 |
| 192.168.1.9 | 200,133 | 1000 |
| 192.168.1.3 | 200,100 | 1000 |
| 192.168.1.7 | 200,090 | 1000 |
| 192.168.1.8 | 199,552 | 1000 |
| 192.168.1.5 | 199,507 | 1000 |
| 192.168.1.2 | 198,737 | 1000 |
| 192.168.1.18 | 44,228 | 1000 |
| 192.168.1.26 | 44,202 | 1000 |
| 192.168.1.34 | 44,186 | 1000 |
| 192.168.1.12 | 44,111 | 1000 |
| 192.168.1.28 | 44,008 | 1000 |
| 192.168.1.35 | 44,000 | 1000 |
| 192.168.1.48 | 43,936 | 1000 |
| 192.168.1.47 | 43,929 | 1000 |
| 192.168.1.23 | 43,898 | 1000 |
| 192.168.1.46 | 43,881 | 1000 |
| Format | Dosya Boyutu | Sorgu Süresi | Açıklama |
|---|---|---|---|
| JSON | 1.19 GB | 3.46 sn (HDFS) / 6.75 sn (MinIO) | Satır bazlı yapı, sıkıştırma yok |
| Parquet | 58 MB | 0.13 sn (HDFS) / 0.21 sn (MinIO) | Kolon bazlı sıkıştırma,dictionary encoding, seçmeli okuma |
| ORC | 50 MB | 0.12 sn (HDFS) / 0.18 sn (MinIO) | Kolon bazlı, bloom filter, en hızlı okuma |
-
Hangi formatın neden daha verimli olduğunu açıklayın. -> Parquet ve ORC, Json'daki gibi satır bazlı değil de sütun bazlı arama yapıyor ve gereksiz sütun bloklarını atlıyor bu sayede Json a göre daha hızlıdır. Metadata sayesinde işine yaramayan kolonları gezmekten kurtuluyor.
-> Parquet: örneğin tekrar eden 10 farklı istatistik değeri varsa dictionary enoding diye bir yöntemle bu 10 değeri sözlüğe yazıyor. Milyonlarca satırda uzun uzun tüm verileri değil de sadece sözlükteki kısacık kodları saklıyor. Veri boyutunu inanılmaz küçültüyor. Bu da çok verimli hale getiriyor.
-> ORC: Önce şerit seviyesindeki istatistiklere bakarak alakasız şeritleri toptan atlıyor. Sonra okuması gereken şeritin içine girdiğinde dahili satır indeksini kullanarak o şeridin içindeki onbinlerce satırlık küçük blokları da atlıyor. Bu şekilde iki aşamalı eleme yapıyor ve elde ettiğim sorgu süresine de bakacak olursak ORC daha verimli görünüyor.
-
Sıkıştırma ve bölümleme etkisini belirtin. -> Bu projede Parquet ve ORC formatları Snappy sıkıştırma ile yazılmıştır. Snappy hızlı sıkıştırma sağlar ve özellikle analitik sorgular için en verimli codec’lerden biridir.
| Sorgu Tipi | Süre (sn) | Bellek Kullanımı | Yanlış Pozitif Oranı |
|---|---|---|---|
| Standart Sorgu | 0.3244 | - | - |
| Bloom Filter ile | 0.4116 | 122.07 KB | 0.00% |
| Bitset ile | 0.5833 | 0.25 KB | 0.00% (ama farklı subnet nedeniyle 1 uyumsuzluk görüldü) |
-Bloom Filter 5 milyon log içinde 1000 farklı user_id olduğu için bu yapı çok verimli oldu.
Bloom Filter 122 KB bellek kullandı.
1000 kullanıcıyı ekledi ve yanlış pozitif oranı 0% olarak gerçekleşti.
Ancak bu veri setinde Spark’ın kendi filtresi zaten çok hızlı olduğu için Bloom Filter klasik filtreleme hızını geçemedi (0.79x speedup).
🔍 BLOOM FILTER OPTİMİZASYONU
- Bloom Filter oluşturuluyor ve user_id'ler ekleniyor...
➡ Toplam farklı user_id sayısı : 1000
➡ Bloom Filter oluşturma süresi : 1.6722 sn
➡ Bloom Filter bit boyutu : 1,000,000 bit (~122.07 KB)
➡ Set edilen bit sayısı : 2,996
➡ Doldurma oranı (fill_ratio) : 0.30%
- Bloom Filter üyelik testleri...
user_id= 1 -> Bloom: True , Gerçek: True [✅ Doğru Pozitif]
user_id= 5 -> Bloom: True , Gerçek: True [✅ Doğru Pozitif]
user_id= 10 -> Bloom: True , Gerçek: True [✅ Doğru Pozitif]
user_id= 25 -> Bloom: True , Gerçek: True [✅ Doğru Pozitif]
user_id= 50 -> Bloom: True , Gerçek: True [✅ Doğru Pozitif]
user_id= 100 -> Bloom: True , Gerçek: True [✅ Doğru Pozitif]
user_id= 200 -> Bloom: True , Gerçek: True [✅ Doğru Pozitif]
user_id= 500 -> Bloom: True , Gerçek: True [✅ Doğru Pozitif]
user_id= 999 -> Bloom: True , Gerçek: True [✅ Doğru Pozitif]
user_id= 9999 -> Bloom: False, Gerçek: False [✅ Doğru Negatif]
user_id=10000 -> Bloom: False, Gerçek: False [✅ Doğru Negatif]
user_id=50000 -> Bloom: False, Gerçek: False [✅ Doğru Negatif]
➡ Yanlış Pozitif Sayısı : 0 ➡ Yanlış Pozitif Oranı (≈) : 0.00%
- Performans Karşılaştırması: Standart Sorgu vs Bloom Filter Destekli Sorgu
➡ Standart Sorgu Süresi : 0.3244 sn (count=267381)
➡ Bloom Filter Destekli Sorgu : 0.4116 sn (count=267381)
➡ Hızlanma Oranı (speedup) : 0.79x
-Bitset IP adresi filtrelemesinde Bitset çok daha etkili çalıştı:
Sadece 0.25 KB bellek kullandı
200 IP’yi anında işaretledi
Sorgu süresini 0.7916 sn -> 0.5833 sn seviyesine düşürdü
1.36x hızlanma elde edildi
Bitset yapısında yanlış pozitif/negatif olmaz ancak: Veri setindeki bazı IP adresleri 192.168.1.xxx dışında olduğu için 1 yanlış eşleşme görüldü.
🎯 BITSET OPTİMİZASYONU
- IP Bitset oluşturuluyor ve IP'ler ekleniyor...
➡ Toplam farklı IP sayısı : 200
➡ Bitset oluşturma süresi : 0.5081 sn
➡ Slot sayısı (0-255) : 256
➡ Kayıtlı IP sayısı : 200
➡ Tahmini bellek kullanımı : 256 byte (~0.25 KB)
- Bitset üyelik testleri... ip=192.168.1.1 -> Bitset: True , Gerçek: True ✅
ip=192.168.1.5 -> Bitset: True , Gerçek: True ✅
ip=192.168.1.10 -> Bitset: True , Gerçek: True ✅
ip=192.168.1.100 -> Bitset: True , Gerçek: True ✅
ip=192.168.1.200 -> Bitset: True , Gerçek: True ✅
ip=10.0.0.1 -> Bitset: True , Gerçek: False ❌ (Tutarsız!)
- Performans Karşılaştırması: Standart Filtre vs Bitset Destekli Sorgu
➡ Standart Filtre Süresi : 0.7916 sn
➡ Bitset Destekli Filtre Süresi : 0.5833 sn
➡ Hızlanma Oranı (speedup) : 1.36x
Join Optimizasyonu
| Join Tipi | Süre (sn) |
|---|---|
| Normal Join | 2.0434 |
| Broadcast Join | 0.6583 |
Normal Join -> 2.0434 sn
Broadcast Join -> 0.6583 sn
3.10x hızlanma gerçekleşti.
Spark, küçük tabloyu tüm nod’lara dağıtarak shuffle maliyetini ortadan kaldırdı.
📡 BROADCAST JOIN OPTİMİZASYONU
- Servis Metadata Lookup Tablosu oluşturuluyor...
| service | description |
|---|---|
| auth-service | Authentication & Login |
| order-service | Order Management |
| payment-service | Payment Gateway |
| inventory-service | Stock & Inventory |
-
Normal Join (Broadcast YOK)... ➡ Normal Join Süresi : 2.0434 sn (count=5000000)
-
Broadcast Join (Küçük tablo broadcast ediliyor)... ➡ Broadcast Join Süresi : 0.6583 sn (count=5000000)
-
Performans Karşılaştırması: ➡ Hızlanma Oranı (speedup) : 3.10x
⏱️ Toplam Çalışma Süresi: 27.94 saniye
📊 ÖZET TABLO İÇİN METRİKLER
Standart user_id sorgu süresi : 0.3244 sn
Bloom Filter ile user_id sorgusu : 0.4116 sn
Bloom Yanlış Pozitif Oranı (≈) : 0.00%
Bloom Bellek Kullanımı (≈) : 122.07 KB
Standart IP filtre süresi : 0.7916 sn
Bitset ile IP filtre süresi : 0.5833 sn
Bitset Bellek Kullanımı (≈) : 0.2500 KB
Normal Join Süresi : 2.0434 sn
Broadcast Join Süresi : 0.6583 sn
- Satır anahtarı yapısı ve kolon aileleri hakkında kısa açıklama:
Tasarımımız, Spark'tan gelen analiz sonuçlarını sorgu verimliliğini artırmak amacıyla boyutlara göre ayırır. Satır Anahtarı Amacı: En kritik sorgu boyutuna (Endpoint, Servis, Saat veya Kullanıcı ID) göre belirlenir. HBase'in ilgili verileri disk üzerinde sıralı tutmasını sağlayarak hızlı okuma (Point Reads) işlemlerini optimize eder.
-
response_metrics Tablosu: Row Key: endpoint (Örn: endpoint_00001) Amaç: "Hangi endpoint yavaş çalışıyor?" veya "Endpoint 1'in performansı nasıl?" sorusuna anında cevap vermek. Mantık: Biz bu tabloda her endpoint için tek bir özet satırı tutuyoruz. Anahtar olarak endpoint adını (veya ID'sini) verdiğimizde, Spark veya API get('endpoint_00001') diyerek mili saniyeler içinde o veriyi çekebilir.
-
service_errors Tablosu: Row Key: service (Örn: auth-service, payment-service) Amaç: Servis bazlı sağlık durumunu görmek. Mantık: Bir dashboard yaptığını düşünelim; "Auth servisi çöküyor mu?" diye bakılır. Anahtar direkt servis adı olduğu için, HBase milyonlarca satırın arasından auth-service ismini eliyle koymuş gibi bulur. İsimler (String) burada doğal bir benzersiz kimliktir.
-
region_traffic Tablosu: Row Key: region (Örn: us-east, eu-west) Amaç: Coğrafi analiz yapmak. Mantık: Veriler Spark tarafında zaten bölgeye göre gruplandı (aggregate edildi). HBase'e yazarken her bölge için tek bir satır yazıyoruz. "Amerika bölgesinin verisini getir" dediğimizde get('us-east') komutuyla doğrudan o satıra ulaşırız.
-
hourly_traffic Tablosu: Row Key: hour (Örn: hour_00, hour_14) Amaç: Zaman serisi analizi yapmak ve grafiği sırayla çizdirmek. Sıralama Avantajı: HBase veriyi anahtara göre sıralı tutar. hour_00, hour_01, hour_02... şeklinde anahtar verirsek, veriyi çekerken saatleri karışık değil, kronolojik sırayla alırız. Bu da çizgi grafiği çizerken işimizi çok kolaylaştırır. Not: Ham veride sadece saat kullanmak "Hotspotting" (tek sunucuya yük binmesi) yapar ama biz burada özetlenmiş (aggregate) veri tuttuğumuz için (günde sadece 24 satır), bu anahtar en performanslı ve okunaklı yöntemdir.
-
top_users Tablosu: Row Key: user_id (Örn: user_105, user_999) Amaç: Belirli bir kullanıcının aktivitesini bulmak. Mantık: Kullanıcı ID'leri benzersizdir (Unique). Eğer "En çok istek atan kullanıcılar kim?" listesini Spark'ta hazırlayıp buraya yazarsak, anahtarın User ID olması, ileride "User 105 ne yapmış?" diye sorguladığımızda nokta atışı yapmamızı sağlar.
Kolon Aileleri Amacı: Birbiriyle ilişkili sütun gruplarını ayırarak disk yerleşimini düzenler ve okuma maliyetini düşürür.
-
Tablo: response_metrics Kolon Ailesi: metrics İçindeki Veriler: request_count, avg_response_time, median, p95, p99. Ne İşe Yarıyor: Bu aile, Performans Ölçümlerini bir arada tutar.
-
Tablo: service_errors Kolon Ailesi: stats (İstatistikler) İçindeki Veriler: total_requests, error_count, warn_count, oranlar. Ne İşe Yarıyor: Bu aile, Sağlık Durumu İstatistiklerini saklar.
-
Tablo: region_traffic Kolon Ailesi: traffic İçindeki Veriler: request_count, avg_response_time (Bölge bazlı). Ne İşe Yarıyor: Bu aile, Coğrafi Yük Bilgisini tutar.
-
Tablo: hourly_traffic Kolon Ailesi: traffic İçindeki Veriler: request_count, avg_response_time (Saat bazlı). Ne İşe Yarıyor: Bu aile, Zaman Serisi (Time-Series) Akışını tutar.
-
Tablo: top_users Kolon Ailesi: user İçindeki Veriler: request_count, user_id. Ne İşe Yarıyor: Bu aile, Kullanıcı Profil/Aktivite Verisini saklar.
- Veri yükleme adımları: Veri yükleme işlemi (hbase/load_data.py), HDFS'teki (Dağıtık Dosya Sistemi) işlenmiş Spark sonuçlarını alıp HBase tablolarına toplu olarak aktarır.
1.Bağlantı Kurulumu: hbase konteynerine HappyBase üzerinden bağlantı kurulur.
2.Şema Yönetimi: Gerekli 5 tablo, harici hbase/schema.py dosyasında tanımlanan CF'ler ile oluşturulur (varsa silinir).
3.Veri Transferi: Spark, HDFS'teki /analytics/results/ dizininden Parquet formatındaki büyük hacimli analiz sonuçlarını okur.
4.Toplu Yükleme (Batch Put): Veriler, performans için optimize edilmiş Row Key formatına dönüştürülür ve HappyBase'in table.batch().put() fonksiyonu kullanılarak tek bir ağ isteği ile toplu halde HBase'e yazılır. Bu, yüksek hacimli veri transferinde performansı kritik ölçüde artırır.
- Sorgu örnekleri:
| Amaçlanan Sorgu | Kullanılacak Tablo | Row Key Stratejisi | Örnek HappyBase Sorgusu (Mantıksal) |
|---|---|---|---|
| Belirli bir Endpoint'in P95 yanıt süresini alma. | response_metrics | Tam Row Key Eşleşmesi | table.row(b'endpoint_00002', columns=[b'metrics:p95_response_time']) |
| Hata oranı en yüksek servisin metriklerini çekme. | service_errors | Tam Row Key Eşleşmesi (Servis Adı) | table.row(b'order-service', columns=[b'stats:error_rate']) |
| Belirli bir saat aralığındaki tüm trafiği listeleme. | hourly_traffic | Sıralı Tarama | table.scan(row_start=b'hour_14', row_stop=b'hour_16') |
- Hangi grafikler ve görselleştirmeler kullandınız? Projenin görselleştirme aşamasında Streamlit kütüphanesi ve Plotly grafik motoru kullanılmıştır. Veriler HBase'den anlık olarak çekilerek aşağıdaki grafik türleri ile sunulmuştur:
Metrik Kartları : Genel bakış sayfasında toplam istek sayısı, toplam hata, ortalama hata oranı ve benzersiz bölge sayısı gibi kritik özet bilgileri göstermek için kullanıldı.
Pasta Grafik : Trafiğin coğrafi bölgelere dağılımı, toplam hata dağılımı,bölgeye göre istek sayısını oransal olarak göstermek için kullanıldı.
Çubuk Grafik :Servislerin hata oranlarını ve bölge bazlı ortalama gecikme karşılaştırmak ve en çok istek alan endpoint'leri hacimlerine göre sıralamak için kullanıldı.
Veri Tabloları: Analiz sonuçlarının sayısal detaylarını ve ham verileri incelemek için etkileşimli tablolar kullanıldı.
- Dashboard'un ekran görüntüsünü ekleyin (
reports/klasörüne görsel ekleyin ve buraya referans verin) 1. Genel Bakış:
4. Trafik ve Kullanıcı Analizleri:

- Dashboardda sunduğunuz filtreleme ve dışa aktarma özelliklerini açıklayın Navigasyon ve Görünüm Filtreleme: Sol menüde yer alan Radio Button yapısı sayesinde kullanıcılar "Genel Bakış", "Yanıt Süreleri", "Hatalar" gibi farklı analiz boyutları arasında hızlıca geçiş yapabilir. Her sayfa sadece ilgili veriyi HBase'den çeker.
Veri Yenileme : Veriyi Yenile butonu, Streamlit'in cache temizleyerek HBase'den en güncel verilerin tekrar çekilmesini sağlar. Bu sayede yeni loglar işlendiğinde dashboard anında güncellenebilir.
Ham Veri İnceleme ve Dışa Aktarma : "Ham Veri" sekmesinde kullanıcılar incelemek istedikleri HBase tablosunu açılır menüden seçebilirler. Yüklenen veriler, tablonun altında beliren "CSV Olarak İndir" butonu sayesinde lokal bilgisayara raporlama amacıyla indirilebilir.
- Kurulumda, kodda veya analizde yaşadığınız teknik sorunlar (varsa) Sorun1: HBase tabloları henüz doluyken Dashboard açıldığında AttributeError: 'NoneType' hatası alındı.
Sorun2: Veri yükleme aşamasında java.net.UnknownHostException: namenode hatası alındı.
Sorun3: MinIO ve HDFS servisleri aynı anda çalıştırılırken Docker üzerinde 9000 port çakışması yaşandı ve MinIO servisi başlatılamadı.
Sorun4: Spark üzerinden HDFS’e erişilmeye çalışıldığında java.net.UnknownHostException: namenode hatası alındı.
- Nasıl çözdüğünüzü ve öğrendiklerinizi yazın
Çözüm1: Veri çekme fonksiyonlarına try-except blokları eklendi. Veri yoksa hata vermek yerine boş bir DataFrame döndürülmesi sağlanarak Dashboard'un çökmesi engellendi
Çözüm2: Python scriptinin çalıştığı ortamın, HDFS konteynerine ağ üzerinden erişemediği tespit edildi.Docker Compose ile namenode, datanode yeniden başlatıldı ve ağ bağlantısı doğrulandıktan sonra işlem tekrarlandı.
Çözüm3: 9000 portunun HDFS NameNode tarafından kullanıldığı tespit edildi. MinIO için farklı bir port atanarak port çakışması giderildi ve Spark–MinIO bağlantı ayarları güncellendi.
Çözüm4: Spark ortamının HDFS servislerinin bulunduğu Docker ağına dahil olmadığı belirlendi. Docker Compose ile namenode ve datanode servisleri yeniden başlatıldı, ağ bağlantıları doğrulandıktan sonra Spark HDFS’e başarıyla bağlandı.





.jpg)
